tsup.c - sup - small tool for privilege escalation
 (HTM) git clone https://git.parazyd.org/sup
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       tsup.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 }