summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkatalx2026-01-27 18:46:06 -0500
committerkatalx2026-01-27 18:46:06 -0500
commitc620a20da58c4157f6257a53550c84be87c3b2cf (patch)
treef061b11b051d0cf64404a40e9e10010ce2392e58
initial commitHEADmaster
-rw-r--r--Makefile23
-rw-r--r--sudo.c117
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}
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 <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;
+}