initial commit

This commit is contained in:
TriMill 2022-11-08 00:21:44 -05:00
commit 704272cfeb
6 changed files with 172 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/bin

19
Makefile Normal file
View 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
View 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
View 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
View 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
View 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();