commit cec5f362b273867f23126ccb7a756905c640c856
parent 96b227c7bf3acc15c0de695b074f2b32fcabe21e
Author: parazyd <parazyd@dyne.org>
Date: Tue, 2 Jul 2019 13:00:38 +0200
Rewrite C code and add SHA256 support.
Diffstat:
M | config.def.h | | | 33 | ++++++++++++++++++++------------- |
M | sup.c | | | 158 | +++++++++++++++++++++++++++++++++++++++++-------------------------------------- |
2 files changed, 103 insertions(+), 88 deletions(-)
diff --git a/config.def.h b/config.def.h
@@ -1,20 +1,27 @@
-#define USER 1000
-#define GROUP -1
+/* See LICENSE file for copyright and license details. */
+/* User and group to run as */
#define SETUID 0
#define SETGID 0
-#define CHROOT ""
-#define CHRDIR ""
+/* sup authorizations
+ *
+ * The format is as follows:
+ * - UID allowed to run the command (-1 means anyone)
+ * - Alias/command used to call the executable
+ * - Path to the executable to run
+ * - SHA256 checksum of the executable
+ */
+static struct rule_t rules[] = {
+ { 1000, "ls", "/bin/ls",
+ "87e8fd7d813c135875aca43a4da43d3ced41d325ed2931906444471b4e93e017" },
-#define ENFORCE 1
+ { -1, "grep", "/bin/grep",
+ "fedeb344d1be24f4a340591cd25ed81f7e46ea12772f563c9c9f43773028e23a" },
-static struct rule_t rules[] = {
- { USER, GROUP, "whoami", "/usr/bin/whoami" },
- { USER, GROUP, "ifconfig", "/sbin/ifconfig" },
- { USER, GROUP, "ls", "/bin/ls" },
- { USER, GROUP, "wifi", "/root/wifi.sh" },
- { USER, GROUP, "cp", "*"}, // allow to run this program in PATH
- { USER, GROUP, "*", "*"}, // allow to run any program in PATH
- { 0 },
+ { 1000, "tar", "/bin/tar",
+ "fedeb344d1be24f4a340591cd25ed81f7e46ea12772f563c9c9f43773028e23a" },
+
+ { 1001, "test", "./a.out",
+ "254260b676a44f1529f7c855f0126a57a3fbd7ec8a74de08835f08e8e6ed21be" },
};
diff --git a/sup.c b/sup.c
@@ -1,103 +1,111 @@
-/* pancake <nopcode.org> -- Copyleft 2009-2011 */
+/* See LICENSE file for copyright and license details. */
-#include <errno.h>
-#include <unistd.h>
#include <stdio.h>
-#include <string.h>
#include <stdlib.h>
+#include <string.h>
#include <sys/stat.h>
+#include <unistd.h>
+
+#include "arg.h"
+#include "sha256.h"
-#define HELP "sup [-hlv] [cmd ..]"
-#define VERSION "sup 0.1 pancake <nopcode.org> copyleft 2011"
+#define nelem(x) (sizeof (x) / sizeof *(x))
struct rule_t {
- int uid;
- int gid;
+ const int uid;
const char *cmd;
const char *path;
+ const char *hash;
};
#include "config.h"
-static int die(int ret, const char *org, const char *str) {
- fprintf (stderr, "%s%s%s\n", org?org:"", org?": ":"", str);
- return ret;
+char *argv0;
+
+void die(char *msg) {
+ fprintf(stderr, "%s\n", msg);
+ exit(1);
}
-static char *getpath(const char *str) {
- struct stat st;
- static char file[4096];
- char *p, *path = getenv ("PATH");
- if (path)
- for (p = path; *p; p++) {
- if (*p==':' && (p>path&&*(p-1)!='\\')) {
- *p = 0;
- snprintf (file, sizeof (file)-1, "%s/%s", path, str);
- if (!lstat (file, &st))
- return file;
- *p = ':';
- path = p+1;
- }
+#define CHUNK 1048576 /* 1MiB */
+static uint32 getsha(const char *path, unsigned char *dest) {
+ static sha256_context sha;
+
+ unsigned char buf[CHUNK];
+ uint32 len, tot = 0;
+ FILE *fd;
+
+ fd = fopen(path, "r");
+ if (!fd)
+ die("Can not read binary file.");
+
+ sha256_starts(&sha);
+
+ while ((len = fread(buf, 1, CHUNK, fd))) {
+ sha256_update(&sha, buf, len);
+ tot += len;
}
- return NULL;
+ fclose(fd);
+
+ sha256_finish(&sha, dest);
+ return tot;
}
-int main(int argc, char **argv) {
- const char *cmd;
- int i, uid, gid, ret;
+int main(int argc, char *argv[]) {
+ unsigned int c, i, lflag = 0;
+ unsigned char digest[32];
+ char output[65];
+ struct stat st;
- if (argc < 2 || !strcmp (argv[1], "-h"))
- return die (1, NULL, HELP);
+ ARGBEGIN {
+ case 'l':
+ lflag = 1;
+ break;
+ default:
+ die("Usage: sup [-l] command [ args ... ]");
+ } ARGEND;
- if (!strcmp (argv[1], "-v"))
- return die (1, NULL, VERSION);
+ if (lflag) {
+ printf("List of compiled authorizations:\n");
+ for (i = 0; i < nelem(rules); i++)
+ printf("\nuser: %d\ncmd: %s\nbinary: %s\nsha256: %s\n",
+ rules[i].uid, rules[i].cmd, rules[i].path, rules[i].hash);
- if (!strcmp (argv[1], "-l")) {
- for (i = 0; rules[i].cmd != NULL; i++)
- printf ("%d %d %10s %s\n", rules[i].uid, rules[i].gid,
- rules[i].cmd, rules[i].path);
return 0;
}
- uid = getuid ();
- gid = getgid ();
-
- for (i = 0; rules[i].cmd != NULL; i++) {
- if (*rules[i].cmd=='*' || !strcmp (argv[1], rules[i].cmd)) {
-#if ENFORCE
- struct stat st;
- if (*rules[i].path=='*') {
- if (*argv[1]=='.' || *argv[1]=='/')
- cmd = argv[1];
- else if (!(cmd = getpath (argv[1])))
- return die (1, "execv", "cannot find program");
- } else cmd = rules[i].path;
- if (lstat (cmd, &st) == -1)
- return die (1, "lstat", "cannot stat program");
- if (st.st_mode & 0222)
- return die (1, "stat", "cannot run writable binaries.");
-#endif
- if (uid != SETUID && rules[i].uid != -1 && rules[i].uid != uid)
- return die (1, "urule", "user does not match");
-
- if (gid != SETGID && rules[i].gid != -1 && rules[i].gid != gid)
- return die (1, "grule", "group id does not match");
-
- if (setuid (SETUID) == -1 || setgid (SETGID) == -1 ||
- seteuid (SETUID) == -1 || setegid (SETGID) == -1)
- return die (1, "set[e][ug]id", strerror (errno));
-#ifdef CHROOT
- if (*CHROOT)
- if (chdir (CHROOT) == -1 || chroot (".") == -1)
- return die (1, "chroot", strerror (errno));
- if (*CHRDIR)
- if (chdir (CHRDIR) == -1)
- return die (1, "chdir", strerror (errno));
-#endif
- ret = execv (cmd, argv+1);
- return die (ret, "execv", strerror (errno));
+ if (argc < 1)
+ die("Usage: sup [-l] command [ args ... ]");
+
+ for (i = 0; i < nelem(rules); i++) {
+ if (!strcmp(argv[0], rules[i].cmd)) {
+
+ if (rules[i].uid != getuid() && rules[i].uid != -1)
+ die("Unauthorized user.");
+
+ if (stat(rules[i].path, &st) == -1)
+ die("Can not stat program.");
+
+ if (st.st_mode & 0022)
+ die("Can not run binaries others can write.");
+
+ if (getsha(rules[i].path, digest) != st.st_size)
+ die("Binary file differs from size read.");
+
+ for (c = 0; c < 32; c++)
+ sprintf(output + (c*2), "%02x", digest[c]);
+ output[64] = '\0';
+
+ if (strncmp(rules[i].hash, output, 64))
+ die("Checksums do not match.");
+
+ if (setgid(SETGID) < 0) die("setgid failed");
+ if (setuid(SETUID) < 0) die("setuid failed");
+
+ if (execv(rules[i].path, argv) < 0)
+ die("execv failed.");
}
}
- return die (1, NULL, "Sorry");
+ die("Unauthorized command.");
}