/* 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; }