From c620a20da58c4157f6257a53550c84be87c3b2cf Mon Sep 17 00:00:00 2001 From: katalx Date: Tue, 27 Jan 2026 18:46:06 -0500 Subject: initial commit --- sudo.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 sudo.c (limited to 'sudo.c') diff --git a/sudo.c b/sudo.c new file mode 100644 index 0000000..2165ea8 --- /dev/null +++ b/sudo.c @@ -0,0 +1,117 @@ +/* sudo.c + * small wrapper to run "su root -c COMMAND" with proper escaping + */ + +#include +#include +#include +#include +#include +#include + +/* string builders */ + +typedef struct { + char *s; + int n, c; +} StrBuilder; + +void +sb_fit(StrBuilder *b, int n) +{ + if (n <= b->c) return; + b->c += !b->c; + while (b->c < n) b->c <<= 1; + b->s = realloc(b->s, b->c); + if (!b->s) err(1, "sb_fit"); +} + +void +sb_cat(StrBuilder * restrict b, const char * restrict s) +{ + int sn = strlen(s); + sb_fit(b, b->n + sn); + memcpy(b->s + b->n, s, sn); + b->n += sn; +} + +void +sb_catc(StrBuilder *b, char c) +{ + sb_fit(b, b->n + 1); + b->s[b->n++] = c; +} + +char +*sb_str(StrBuilder *b) +{ + if (b->n == 0 || b->s[b->n-1] != '\0') { + sb_catc(b, '\0'); + b->n--; + } + return b->s; +} + +/* shell escape */ + +#define SPECIAL "\"\\'#$`~{}*?[; " +#define SPECIAL_DQUOT "\"\\`$" + +static inline int +is(char c, const char *chr) +{ + while (*chr) { + if (c == *chr) return 1; + chr++; + } + return 0; +} + +static inline int +has(const char * restrict s, const char * restrict chr) +{ + while (*s) { + if (is(*s, chr)) return 1; + s++; + } + return 0; +} + +void +shell_esc(StrBuilder * restrict b, const char * restrict src) +{ + if (has(src, SPECIAL)) { + if (!isspace(*(unsigned char*)src) && src[1] == '\0') { + sb_catc(b, '\\'); + sb_catc(b, src[0]); + } else if (strchr(src, '\'')) { + sb_catc(b, '"'); + while (*src) { + if (is(*src, SPECIAL_DQUOT)) + sb_catc(b, '\\'); + sb_catc(b, *src++); + } + sb_catc(b, '"'); + } else { + sb_catc(b, '\''); + sb_cat(b, src); + sb_catc(b, '\''); + } + } else { + sb_cat(b, src); + } +} + +int +main(int argc, const char **argv) +{ + StrBuilder b = { 0 }; + for (int i = 1; i < argc; i++) { + if (i > 1) + sb_catc(&b, ' '); + shell_esc(&b, argv[i]); + } + execl("/usr/bin/su", "su", "root", "-c", sb_str(&b), NULL); + free(b.s); + return 0; +} -- cgit v1.2.3