sup

simple user privilege escalation
git clone git://git.suckless.org/sup
Log | Files | Refs

sup.c (2591B)


      1 /* pancake <nopcode.org> -- Copyleft 2009-2011 */
      2 
      3 #include <errno.h>
      4 #include <unistd.h>
      5 #include <stdio.h>
      6 #include <string.h>
      7 #include <stdlib.h>
      8 #include <sys/stat.h>
      9 
     10 #define HELP "sup [-hlv] [cmd ..]"
     11 #define VERSION "sup 0.1 pancake <nopcode.org> copyleft 2011"
     12 
     13 struct rule_t {
     14 	int uid;
     15 	int gid;
     16 	const char *cmd;
     17 	const char *path;
     18 };
     19 
     20 #include "config.h"
     21 
     22 static int die(int ret, const char *org, const char *str) {
     23 	fprintf (stderr, "%s%s%s\n", org?org:"", org?": ":"", str);
     24 	return ret;
     25 }
     26 
     27 static char *getpath(const char *str) {
     28 	struct stat st;
     29 	static char file[4096];
     30 	char *p, *path = getenv ("PATH");
     31 	if (path)
     32 	for (p = path; *p; p++) {
     33 		if (*p==':' && (p>path&&*(p-1)!='\\')) {
     34 			*p = 0;
     35 			snprintf (file, sizeof (file)-1, "%s/%s", path, str);
     36 			if (!lstat (file, &st))
     37 				return file;
     38 			*p = ':';
     39 			path = p+1;
     40 		}
     41 	}
     42 	return NULL;
     43 }
     44 
     45 int main(int argc, char **argv) {
     46 	const char *cmd;
     47 	int i, uid, gid, ret;
     48 
     49 	if (argc < 2 || !strcmp (argv[1], "-h"))
     50 		return die (1, NULL, HELP);
     51 
     52 	if (!strcmp (argv[1], "-v"))
     53 		return die (1, NULL, VERSION);
     54 
     55 	if (!strcmp (argv[1], "-l")) {
     56 		for (i = 0; rules[i].cmd != NULL; i++)
     57 			printf ("%d %d %10s %s\n", rules[i].uid, rules[i].gid,
     58 				rules[i].cmd, rules[i].path);
     59 		return 0;
     60 	}
     61 
     62 	uid = getuid ();
     63 	gid = getgid ();
     64 
     65 	for (i = 0; rules[i].cmd != NULL; i++) {
     66 		if (*rules[i].cmd=='*' || !strcmp (argv[1], rules[i].cmd)) {
     67 #if ENFORCE	
     68 			struct stat st;
     69 			if (*rules[i].path=='*') {
     70 				if (*argv[1]=='.' || *argv[1]=='/')
     71 					cmd = argv[1];
     72 				else if (!(cmd = getpath (argv[1])))
     73 					return die (1, "execv", "cannot find program");
     74 			} else cmd = rules[i].path;
     75 			if (lstat (cmd, &st) == -1)
     76 				return die (1, "lstat", "cannot stat program");
     77 			if (st.st_mode & 0222)
     78 				return die (1, "stat", "cannot run writable binaries.");
     79 #endif
     80 			if (uid != SETUID && rules[i].uid != -1 && rules[i].uid != uid)
     81 				return die (1, "urule", "user does not match");
     82 
     83 			if (gid != SETGID && rules[i].gid != -1 && rules[i].gid != gid)
     84 				return die (1, "grule", "group id does not match");
     85 
     86 			if (setuid (SETUID) == -1 || setgid (SETGID) == -1 ||
     87 			    seteuid (SETUID) == -1 || setegid (SETGID) == -1)
     88 				return die (1, "set[e][ug]id", strerror (errno));
     89 #ifdef CHROOT
     90 			if (*CHROOT)
     91 				if (chdir (CHROOT) == -1 || chroot (".") == -1)
     92 					return die (1, "chroot", strerror (errno));
     93 			if (*CHRDIR)
     94 				if (chdir (CHRDIR) == -1)
     95 					return die (1, "chdir", strerror (errno));
     96 #endif
     97 			ret = execv (cmd, argv+1);
     98 			return die (ret, "execv", strerror (errno));
     99 		}
    100 	}
    101 
    102 	return die (1, NULL, "Sorry");
    103 }