diff --git a/apps/Makefile b/apps/Makefile index 77f72c52..76046766 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -17,6 +17,7 @@ build: $(REAL_APPS) install: $(REAL_APPS) @mkdir -p $(LUNA_ROOT)/initrd/bin cp $(REAL_APPS) $(LUNA_ROOT)/initrd/bin + @chmod a+s $(LUNA_ROOT)/initrd/bin/su clean: rm -f $(APPS_BIN)/* \ No newline at end of file diff --git a/apps/src/su.c b/apps/src/su.c index 804fb6a3..844ac07a 100644 --- a/apps/src/su.c +++ b/apps/src/su.c @@ -1,9 +1,10 @@ +#include +#include #include #include +#include #include -char* default_argv[] = {"/bin/sh", NULL}; - void run_program(char** argv) { execv(argv[0], argv); @@ -12,26 +13,64 @@ void run_program(char** argv) exit(EXIT_FAILURE); } +void strip_newline(char* str) +{ + size_t len = strlen(str); + if (str[len - 1] == '\n') str[len - 1] = 0; +} + int main(int argc, char** argv) { if (argc == 1) { - fprintf(stderr, "Usage: %s [uid] [command | sh]\n", argv[0]); + fprintf(stderr, "Usage: %s [username] [command | login shell]\n", argv[0]); return EXIT_FAILURE; } - if (setuid(atoi(argv[1])) < 0) + if (getuid() != 0) + { + fprintf(stderr, "%s must be setuid root", argv[0]); + return EXIT_FAILURE; + } + + struct passwd* user = getpwnam(argv[1]); + + if (!user) + { + if (errno) perror("getpwnam"); + else + fprintf(stderr, "Unknown user %s\n", argv[1]); + return EXIT_FAILURE; + } + + if (getuid() != geteuid()) // we were started from a non-root user + { + printf("Password: "); + char buf[BUFSIZ]; + fgets(buf, BUFSIZ, stdin); + strip_newline(buf); + putchar('\n'); + if (strcmp(buf, user->pw_passwd) != 0) + { + fprintf(stderr, "Invalid password\n"); + return EXIT_FAILURE; + } + } + + if (setuid(user->pw_uid) < 0) { perror("setuid"); return EXIT_FAILURE; } - if (setgid(atoi(argv[1])) < 0) + if (setgid(user->pw_gid) < 0) { perror("setgid"); return EXIT_FAILURE; } + char* default_argv[] = {user->pw_shell, NULL}; + if (argc == 2) run_program(default_argv); else run_program(argv + 2);