diff options
| -rw-r--r-- | Makefile | 23 | ||||
| -rw-r--r-- | sudo.c | 117 |
2 files changed, 140 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7ea1a7b --- /dev/null +++ b/Makefile @@ -0,0 +1,23 @@ +CFLAGS += -Wall -Wpedantic +LDFLAGS += -s + +PREFIX ?= ${HOME} +BINDIR ?= ${PREFIX}/bin + +EXE != find . -name '*.c' | sed -e 's/\.c$$//' -e 's|^\./||' + +.PHONY: all install clean + +all: ${EXE} + +install: ${EXE} + install -d ${BINDIR} + @for e in ${EXE}; do echo install $$e ${BINDIR};\ + install $$e ${BINDIR}; done + +uninstall: + @for e in ${EXE}; do echo rm -f ${BINDIR}/$$e;\ + rm -f ${BINDIR}/$$e; done + +clean: + rm -fv ${EXE} @@ -0,0 +1,117 @@ +/* sudo.c + * small wrapper to run "su root -c COMMAND" with proper escaping + */ + +#include <err.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <stdio.h> +#include <ctype.h> + +/* 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; +} |
