Browse Source

sudo: support euids with setuid binaries

K. Lange 2 years ago
parent
commit
b42c185421

+ 1 - 1
apps/hostname.c

@@ -18,7 +18,7 @@ int main(int argc, char * argv[]) {
 		printf("%s\n", tmp);
 		return 0;
 	} else {
-		if (getuid() != 0) {
+		if (geteuid() != 0) {
 			fprintf(stderr,"Must be root to set hostname.\n");
 			return 1;
 		} else {

+ 1 - 1
apps/live-session.c

@@ -22,7 +22,7 @@
 int main(int argc, char * argv[]) {
 	int pid;
 
-	if (getuid() != 0) {
+	if (geteuid() != 0) {
 		return 1;
 	}
 

+ 42 - 6
apps/sudo.c

@@ -16,6 +16,7 @@
 #include <signal.h>
 #include <termios.h>
 #include <errno.h>
+#include <pwd.h>
 #include <sys/wait.h>
 #include <sys/utsname.h>
 #include <toaru/auth.h>
@@ -36,12 +37,15 @@ int main(int argc, char ** argv) {
 	}
 
 	while (1) {
-		/*
-		 * This is not very secure, but I'm lazy and just want this to exist.
-		 * It's not like we have file system permissions or anything like
-		 * that sitting around anyway... So, XXX: make this not dumb.
-		 */
-		char * username = getenv("USER");
+		uid_t me = getuid();
+		if (me == 0) goto _do_it;
+
+		struct passwd * p = getpwuid(me);
+		if (!p) {
+			fprintf(stderr, "%s: unable to obtain username for real uid=%d\n", argv[0], getuid());
+			return 1;
+		}
+		char * username = p->pw_name;
 		char * password = malloc(sizeof(char) * 1024);
 
 		fprintf(stderr, "[%s] password for %s: ", argv[0], username);
@@ -71,9 +75,41 @@ int main(int argc, char ** argv) {
 			continue;
 		}
 
+		/* Determine if this user is in the sudoers file */
+		FILE * sudoers = fopen("/etc/sudoers","r");
+		if (!sudoers) {
+			fprintf(stderr, "%s: /etc/sudoers is not available\n", argv[0]);
+			return 1;
+		}
+
+		/* Read each line */
+		int in_sudoers = 0;
+		while (!feof(sudoers)) {
+			char line[1024];
+			fgets(line, 1024, sudoers);
+			char * nl = strchr(line, '\n');
+			if (nl) {
+				*nl = '\0';
+			}
+			if (!strncmp(line,username,1024)) {
+				in_sudoers = 1;
+				break;
+			}
+		}
+		fclose(sudoers);
+
+		if (!in_sudoers) {
+			fprintf(stderr, "%s is not in sudoers file.\n", username);
+			return 1;
+		}
+
+_do_it:
 		/* Set username to root */
 		putenv("USER=root");
 
+		/* Actually become root, so real user id = 0 */
+		setuid(0);
+
 		if (!strcmp(argv[1], "-s")) {
 			argv[1] = getenv("SHELL");
 		}

+ 1 - 1
apps/whoami.c

@@ -13,7 +13,7 @@
 #include <pwd.h>
 
 int main(int argc, char ** argv) {
-	struct passwd * p = getpwuid(getuid());
+	struct passwd * p = getpwuid(geteuid());
 	if (!p) return 0;
 
 	fprintf(stdout, "%s\n", p->pw_name);

+ 1 - 0
base/etc/sudoers

@@ -0,0 +1 @@
+local

+ 1 - 0
base/usr/include/kernel/process.h

@@ -74,6 +74,7 @@ typedef struct process {
 	char *        name;              /* Process Name */
 	char *        description;       /* Process description */
 	user_t        user;              /* Effective user */
+	user_t        real_user;         /* Real user ID */
 	int           mask;              /* Umask */
 
 	char **       cmdline;

+ 1 - 0
base/usr/include/syscall.h

@@ -120,6 +120,7 @@ DECL_SYSCALL3(readlink, char *, char *, int);
 DECL_SYSCALL0(setsid);
 DECL_SYSCALL2(setpgid,int,int);
 DECL_SYSCALL1(getpgid,int);
+DECL_SYSCALL0(geteuid);
 
 _End_C_Header
 

+ 1 - 0
base/usr/include/syscall_nums.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #define SYS_EXT 0
+#define SYS_GETEUID 1
 #define SYS_OPEN 2
 #define SYS_READ 3
 #define SYS_WRITE 4

+ 2 - 0
kernel/sys/process.c

@@ -271,6 +271,7 @@ process_t * spawn_init(void) {
 	init->name    = strdup("init");  /* Um, duh. */
 	init->cmdline = NULL;
 	init->user    = 0;       /* UID 0 */
+	init->real_user = 0;
 	init->mask    = 022;     /* umask */
 	init->status  = 0;       /* Run status */
 	init->fds = malloc(sizeof(fd_table_t));
@@ -389,6 +390,7 @@ process_t * spawn_process(volatile process_t * parent, int reuse_fds) {
 
 	/* Copy permissions */
 	proc->user  = parent->user;
+	proc->real_user = parent->real_user;
 	proc->mask = parent->mask;
 
 	/* Until specified otherwise */

+ 6 - 0
kernel/sys/syscall.c

@@ -411,12 +411,17 @@ static int sys_dup2(int old, int new) {
 }
 
 static int sys_getuid(void) {
+	return current_process->real_user;
+}
+
+static int sys_geteuid(void) {
 	return current_process->user;
 }
 
 static int sys_setuid(user_t new_uid) {
 	if (current_process->user == USER_ROOT_UID) {
 		current_process->user = new_uid;
+		current_process->real_user = new_uid;
 		return 0;
 	}
 	return -EPERM;
@@ -1008,6 +1013,7 @@ static int sys_getpgid(pid_t pid) {
 static int (*syscalls[])() = {
 	/* System Call Table */
 	[SYS_EXT]          = sys_exit,
+	[SYS_GETEUID]      = sys_geteuid,
 	[SYS_OPEN]         = sys_open,
 	[SYS_READ]         = sys_read,
 	[SYS_WRITE]        = sys_write,

+ 6 - 2
libc/unistd/geteuid.c

@@ -1,5 +1,9 @@
 #include <unistd.h>
+#include <syscall.h>
+#include <syscall_nums.h>
 
-int geteuid() {
-	return getuid();
+DEFN_SYSCALL0(geteuid, SYS_GETEUID);
+
+uid_t geteuid(void) {
+	return syscall_geteuid();
 }

+ 4 - 2
libc/unistd/getuid.c

@@ -1,8 +1,10 @@
 #include <unistd.h>
 #include <syscall.h>
+#include <syscall_nums.h>
 
-DEFN_SYSCALL0(getuid, 23);
+DEFN_SYSCALL0(getuid, SYS_GETUID);
 
-int getuid() {
+uid_t getuid(void) {
 	return syscall_getuid();
 }
+

+ 1 - 0
util/update-devtable.py

@@ -19,6 +19,7 @@ with open('util/devtable','w') as devtable:
 
     # Set master.passwd to not be visible except by root
     devtable.write('/etc/master.passwd f 600 0 0 - - - - -\n') # /etc/master.passwd should be restricted
+    devtable.write('/etc/sudoers f 600 0 0 - - - - -\n')
 
     # Copy permissions and set ownership for user files
     for user_details in [('local',1000)]: