initial commit
This commit is contained in:
commit
704272cfeb
6 changed files with 172 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/bin
|
19
Makefile
Normal file
19
Makefile
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
CFLAGS=-O3 -Wall -lpam -lpam_misc
|
||||||
|
BIN=udo
|
||||||
|
|
||||||
|
all:
|
||||||
|
mkdir -p bin
|
||||||
|
gcc $(CFLAGS) $(wildcard src/*.c) -o bin/udo
|
||||||
|
|
||||||
|
install: all
|
||||||
|
cp bin/udo /usr/local/bin/udo
|
||||||
|
chown root:root /usr/local/bin/udo
|
||||||
|
chmod 6755 /usr/local/bin/udo
|
||||||
|
cp pam.d_udo /etc/pam.d/udo
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
rm /usr/local/bin/udo
|
||||||
|
rm /etc/pam.d/udo
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -r bin/*
|
19
README.md
Normal file
19
README.md
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# udo
|
||||||
|
|
||||||
|
`udo` is an extremely stripped-down sudo/doas imitation.
|
||||||
|
|
||||||
|
## config
|
||||||
|
|
||||||
|
the config file is located at `/etc/udo.conf`. it is a space-separated list of UIDs that are allowed to use `udo`. this file should probably contain `0` at some point.
|
||||||
|
|
||||||
|
## installation
|
||||||
|
|
||||||
|
`sudo make install`
|
||||||
|
|
||||||
|
## uninstallation
|
||||||
|
|
||||||
|
`sudo make uninstall`, but why would you want to?
|
||||||
|
|
||||||
|
## why does it segfault?
|
||||||
|
|
||||||
|
it only segfaults if you have done something wrong. do not do wrong things.
|
4
pam.d_udo
Normal file
4
pam.d_udo
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#%PAM-1.0
|
||||||
|
auth include system-auth
|
||||||
|
account include system-auth
|
||||||
|
session include system-auth
|
115
src/main.c
Normal file
115
src/main.c
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "main.h"
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <security/pam_appl.h>
|
||||||
|
#include <security/pam_misc.h>
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
if(argc == 1) {
|
||||||
|
printf("insufficient\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
uid_t uid = getuid();
|
||||||
|
Config config = load_config();
|
||||||
|
|
||||||
|
struct passwd* pwd = getpwuid(uid);
|
||||||
|
char* user = pwd->pw_name;
|
||||||
|
|
||||||
|
int result = validate(user);
|
||||||
|
if(result) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* cmd = argv[1];
|
||||||
|
char* args[argc];
|
||||||
|
|
||||||
|
for(int i = 0; i < argc-1; i++) {
|
||||||
|
args[i] = malloc(strlen(argv[i+1]));
|
||||||
|
strcpy(args[i], argv[i+1]);
|
||||||
|
}
|
||||||
|
args[argc-1] = NULL;
|
||||||
|
|
||||||
|
if(allowed(uid, &config)) {
|
||||||
|
setuid(geteuid());
|
||||||
|
setgid(getegid());
|
||||||
|
int x = execvp(cmd, args);
|
||||||
|
return x;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "nope\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int validate(char* user) {
|
||||||
|
pam_handle_t *pamh = NULL;
|
||||||
|
struct pam_conv conv = {misc_conv, NULL};
|
||||||
|
|
||||||
|
int status = pam_start("udo", user, &conv, &pamh);
|
||||||
|
if(status != PAM_SUCCESS) {
|
||||||
|
printf("bad: %d\n", status);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = pam_authenticate(pamh, 0);
|
||||||
|
if(status != PAM_SUCCESS) {
|
||||||
|
printf("wrong: %d\n", status);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
status = pam_acct_mgmt(pamh, 0);
|
||||||
|
|
||||||
|
if (pam_end(pamh,status) != PAM_SUCCESS) {
|
||||||
|
pamh = NULL;
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(status != PAM_SUCCESS) {
|
||||||
|
printf("don't: %d\n", status);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int allowed(uid_t uid, Config* config) {
|
||||||
|
for(int i = 0; i < config->len; i++) {
|
||||||
|
if(config->uids[i] == uid) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Config load_config() {
|
||||||
|
FILE* fp = fopen("/etc/udo.conf", "r");
|
||||||
|
char* contents = malloc(CHUNK_SIZE + 1);
|
||||||
|
int offset = 0;
|
||||||
|
char buf[CHUNK_SIZE];
|
||||||
|
int read = CHUNK_SIZE;
|
||||||
|
while(read == CHUNK_SIZE) {
|
||||||
|
read = fread(buf, 1, CHUNK_SIZE, fp);
|
||||||
|
memcpy(contents + offset, buf, read);
|
||||||
|
offset += read;
|
||||||
|
if(read == CHUNK_SIZE) {
|
||||||
|
contents = realloc(contents, offset + CHUNK_SIZE + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
contents[offset] = '\0';
|
||||||
|
|
||||||
|
Config config;
|
||||||
|
config.uids = malloc(1 * sizeof(uid_t));
|
||||||
|
config.len = 0;
|
||||||
|
|
||||||
|
char* ctx;
|
||||||
|
char* word = strtok_r(contents, " ", &ctx);
|
||||||
|
while(word != NULL) {
|
||||||
|
uid_t uid = atoi(word);
|
||||||
|
config.uids = realloc(config.uids, (config.len+1) * sizeof(uid_t));
|
||||||
|
config.uids[config.len++] = uid;
|
||||||
|
word = strtok_r(NULL, "\n", &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
14
src/main.h
Normal file
14
src/main.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#define CHUNK_SIZE 10
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uid_t* uids;
|
||||||
|
int len;
|
||||||
|
} Config;
|
||||||
|
|
||||||
|
int main(int argc, char** argv);
|
||||||
|
int allowed(uid_t uid, Config* config);
|
||||||
|
int validate(char* user);
|
||||||
|
Config load_config();
|
Loading…
Reference in a new issue