sup.c (2238B)
1 /* See LICENSE file for copyright and license details. */ 2 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <string.h> 6 #include <sys/stat.h> 7 #include <unistd.h> 8 9 #include "arg.h" 10 #include "sha256.h" 11 12 #define nelem(x) (sizeof (x) / sizeof *(x)) 13 #define CHUNK 1048576 /* 1MiB */ 14 15 struct rule_t { 16 const int uid; 17 const char *cmd; 18 const char *path; 19 const char *hash; 20 }; 21 22 #include "config.h" 23 24 char *argv0; 25 26 static void die(char *msg) 27 { 28 fprintf(stderr, "%s\n", msg); 29 exit(1); 30 } 31 32 static uint32 getsha(const char *path, unsigned char *dest) 33 { 34 static sha256_context sha; 35 unsigned char buf[CHUNK]; 36 uint32 len, tot = 0; 37 FILE *fd; 38 39 fd = fopen(path, "r"); 40 if (!fd) 41 die("Can not read binary file."); 42 43 sha256_starts(&sha); 44 45 while ((len = fread(buf, 1, CHUNK, fd))) { 46 sha256_update(&sha, buf, len); 47 tot += len; 48 } 49 fclose(fd); 50 51 sha256_finish(&sha, dest); 52 return tot; 53 } 54 55 int main(int argc, char *argv[]) 56 { 57 unsigned int c, i, lflag = 0; 58 unsigned char digest[32]; 59 char output[65]; 60 struct stat st; 61 62 ARGBEGIN { 63 case 'l': 64 lflag = 1; 65 break; 66 default: 67 die("Usage: sup [-l] command [ args ... ]"); 68 } ARGEND; 69 70 if (lflag) { 71 printf("List of compiled authorizations:\n"); 72 for (i = 0; i < nelem(rules); i++) 73 printf("\nuser: %d\ncmd: %s\nbinary: %s\nsha256: %s\n", 74 rules[i].uid, rules[i].cmd, rules[i].path, 75 rules[i].hash); 76 return 0; 77 } 78 79 if (argc < 1) 80 die("Usage: sup [-l] command [ args ... ]"); 81 82 for (i = 0; i < nelem(rules); i++) { 83 if (!strcmp(argv[0], rules[i].cmd)) { 84 85 if (rules[i].uid != getuid() && rules[i].uid != -1) 86 die("Unauthorized user."); 87 88 if (stat(rules[i].path, &st) == -1) 89 die("Can not stat program."); 90 91 if (st.st_mode & 0022) 92 die("Can not run writable binaries."); 93 94 if (getsha(rules[i].path, digest) != st.st_size) 95 die("Binary file differs from size read."); 96 97 for (c = 0; c < 32; c++) 98 sprintf(output + (c * 2), "%02x", digest[c]); 99 output[64] = '\0'; 100 101 if (strncmp(rules[i].hash, output, 64)) 102 die("Checksums do not match."); 103 104 if (setgid(SETGID) < 0) 105 die("setgid failed"); 106 if (setuid(SETUID) < 0) 107 die("setuid failed"); 108 109 if (execv(rules[i].path, argv) < 0) 110 die("execv failed."); 111 } 112 } 113 die("Unauthorized command."); 114 }