aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--LICENSE15
-rw-r--r--Makefile29
-rw-r--r--arg.h45
-rw-r--r--asroot.c180
-rw-r--r--config.mk6
6 files changed, 280 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c48cd59
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+*\#*
+*~
+*.o
+*.su
+/asroot
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..c44b2d9
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,15 @@
+ISC License
+
+© 2021 Mattias Andrée <maandree@kth.se>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..9bbde8c
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,29 @@
+.POSIX:
+
+CONFIGFILE = config.mk
+include $(CONFIGFILE)
+
+all: asroot
+asroot.o: asroot.c arg.h
+
+asroot: asroot.o
+ $(CC) -o $@ asroot.o $(LDFLAGS)
+
+install: asroot
+ mkdir -p -- "$(DESTDIR)$(PREFIX)/bin/"
+ mkdir -p -- "$(DESTDIR)$(MANPREFIX)/man8/"
+ cp -- asroot "$(DESTDIR)$(PREFIX)/bin/asroot"
+ cp -- asroot.8 "$(DESTDIR)$(MANPREFIX)/man8/asroot.8"
+
+post-install:
+ chown -- 'root:wheel' "$(DESTDIR)$(PREFIX)/bin/asroot"
+ chmod -- 4750 "$(DESTDIR)$(PREFIX)/bin/asroot"
+
+uninstall:
+ -rm -f -- "$(DESTDIR)$(PREFIX)/bin/asroot"
+ -rm -f -- "$(DESTDIR)$(MANPREFIX)/man8/asroot.8"
+
+clean:
+ -rm -f -- asroot.o asroot
+
+.PHONY: all install post-install uninstall clean
diff --git a/arg.h b/arg.h
new file mode 100644
index 0000000..4f7b6c0
--- /dev/null
+++ b/arg.h
@@ -0,0 +1,45 @@
+/*
+ * Copy me if you can.
+ * by 20h
+ */
+
+#ifndef ARG_H__
+#define ARG_H__
+
+extern char *argv0;
+
+/* use main(int argc, char *argv[]) */
+#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\
+ argv[0] && argv[0][0] && argv[0][1];\
+ argc--, argv++) {\
+ char argc_;\
+ char **argv_;\
+ int brk_;\
+ if (argv[0][0] == '-') {\
+ if (argv[0][1] == '-' && argv[0][2] == '\0') {\
+ argv++;\
+ argc--;\
+ break;\
+ }\
+ for (brk_ = 0, argv[0]++, argv_ = argv;\
+ argv[0][0] && !brk_;\
+ argv[0]++) {\
+ if (argv_ != argv)\
+ break;\
+ argc_ = argv[0][0];\
+ switch (argc_)
+
+#define ARGEND }\
+ } else {\
+ break;\
+ }\
+ }
+
+#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\
+ ((x), abort(), (char *)0) :\
+ (brk_ = 1, (argv[0][1] != '\0')?\
+ (&argv[0][1]) :\
+ (argc--, argv++, argv[0])))
+
+
+#endif
diff --git a/asroot.c b/asroot.c
new file mode 100644
index 0000000..5f03b42
--- /dev/null
+++ b/asroot.c
@@ -0,0 +1,180 @@
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "arg.h"
+
+
+char *argv0;
+
+extern char **environ;
+
+static const char *env_whitelist[] = {
+ "DISPLAY=",
+ "WAYLAND_DISPLAY=",
+ "PATH=",
+ "TERM=",
+ "COLORTERM=",
+ "XAUTHORITY=",
+ "LANG=",
+ "LANGUAGE=",
+ "LOCALE=",
+ "LC_CTYPE=",
+ "LC_NUMERIC=",
+ "LC_TIME=",
+ "LC_COLLATE=",
+ "LC_MONETARY=",
+ "LC_MESSAGES=",
+ "LC_PAPER=",
+ "LC_NAME=",
+ "LC_ADDRESS=",
+ "LC_TELEPHONE=",
+ "LC_MEASUREMENT=",
+ "LC_IDENTIFICATION=",
+ "LC_ALL=",
+ "LOCPATH=",
+ "NLSPATH=",
+ "TZ=",
+ "TZDIR=",
+ "SDL_VIDEO_FULLSCREEN_DISPLAY=",
+ "EDITOR=",
+ "VISUAL=",
+ "BROWSER=",
+ "DESKTOP_SESSION=",
+ "LS_COLORS=",
+ "GTK_THEME=",
+ "QT_STYLE_OVERRIDE=",
+ "PWD=",
+ "OLDPWD=",
+ "JAVA_HOME=",
+ "_JAVA_AWT_WM_NONREPARENTING=",
+ "_JAVA_OPTIONS=",
+ "MAIN_ALSA_MIXER=",
+ "MAIN_ALSA_CARD=",
+ "XDG_SEAT=",
+ "XDG_SESSION_TYPE=",
+ "XDG_SESSION_CLASS=",
+ "XDG_VTNR=",
+ "XDG_SESSION_ID=",
+ "XDG_DATA_DIRS=",
+ "XDG_CONFIG_DIRS=",
+ "MANPATH=",
+ "INFODIR=",
+ "PAGER=",
+ "ftp_proxy=",
+ "http_proxy=",
+ NULL
+};
+
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: %s [-e] command [argument] ...\n", argv0);
+ exit(125);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ int keep_env = 0;
+ char **new_environ = NULL;
+ size_t i, j, n, len;
+ struct passwd *pw;
+
+ ARGBEGIN {
+ case 'e':
+ keep_env = 1;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if (!argc)
+ usage();
+
+ /* TODO check password */
+
+ if (setgid(0)) {
+ fprintf(stderr, "%s: setgid 0: %s\n", argv0, strerror(errno));
+ return 125;
+ }
+ if (setuid(0)) {
+ fprintf(stderr, "%s: setuid 0: %s\n", argv0, strerror(errno));
+ return 125;
+ }
+
+ if (!keep_env) {
+ new_environ = calloc(sizeof(env_whitelist) / sizeof(*env_whitelist) + 5, sizeof(*env_whitelist));
+ if (!new_environ) {
+ fprintf(stderr, "%s: calloc %zu %zu: %s\n",
+ argv0, sizeof(env_whitelist) / sizeof(*env_whitelist) + 5, sizeof(*env_whitelist), strerror(errno));
+ return errno == ENOENT ? 127 : 126;
+ }
+ for (i = 0, n = 0; env_whitelist[i]; i++) {
+ len = strlen(env_whitelist[i]);
+ for (j = 0; environ[j]; j++) {
+ if (!strncmp(environ[j], env_whitelist[i], len)) {
+ new_environ[n++] = environ[j];
+ break;
+ }
+ }
+ }
+ errno = 0;
+ pw = getpwuid(0);
+ if (!pw) {
+ if (errno)
+ fprintf(stderr, "%s: getpwuid 0: %s\n", argv0, strerror(errno));
+ else
+ fprintf(stderr, "%s: cannot find root user\n", argv0);
+ exit(125);
+ }
+ if (pw->pw_dir && *pw->pw_dir) {
+ len = strlen(pw->pw_dir);
+ len += sizeof("HOME=");
+ new_environ[n] = malloc(len);
+ if (!new_environ[n])
+ fprintf(stderr, "%s: malloc %zu: %s\n", argv0, len, strerror(errno));
+ stpcpy(stpcpy(new_environ[n++], "HOME="), pw->pw_dir);
+ }
+ if (pw->pw_name && *pw->pw_name) {
+ len = strlen(pw->pw_name);
+ len += sizeof("LOGNAME=");
+ new_environ[n] = malloc(len);
+ if (!new_environ[n])
+ fprintf(stderr, "%s: malloc %zu: %s\n", argv0, len, strerror(errno));
+ stpcpy(stpcpy(new_environ[n++], "LOGNAME="), pw->pw_name);
+
+ len -= sizeof("LOGNAME=");
+ len += sizeof("USER=");
+ new_environ[n] = malloc(len);
+ if (!new_environ[n])
+ fprintf(stderr, "%s: malloc %zu: %s\n", argv0, len, strerror(errno));
+ stpcpy(stpcpy(new_environ[n++], "USER="), pw->pw_name);
+
+ len -= sizeof("USER=");
+ len += sizeof("MAIL=/var/spool/mail/");
+ new_environ[n] = malloc(len);
+ if (!new_environ[n])
+ fprintf(stderr, "%s: malloc %zu: %s\n", argv0, len, strerror(errno));
+ stpcpy(stpcpy(new_environ[n++], "MAIL=/var/spool/mail/"), pw->pw_name);
+ }
+ if (pw->pw_shell && *pw->pw_shell) {
+ len = strlen(pw->pw_dir);
+ len += sizeof("SHELL=");
+ new_environ[n] = malloc(len);
+ if (!new_environ[n])
+ fprintf(stderr, "%s: malloc %zu: %s\n", argv0, len, strerror(errno));
+ stpcpy(stpcpy(new_environ[n++], "SHELL="), pw->pw_dir);
+ }
+ new_environ[n] = NULL;
+ }
+
+ execvpe(argv[0], argv, new_environ ? new_environ : environ);
+ fprintf(stderr, "%s: execvpe %s: %s\n", argv0, argv[0], strerror(errno));
+ return errno == ENOENT ? 127 : 126;
+}
diff --git a/config.mk b/config.mk
new file mode 100644
index 0000000..1f3b2b5
--- /dev/null
+++ b/config.mk
@@ -0,0 +1,6 @@
+PREFIX = /usr
+MANPREFIX = $(PREFIX)/share/man
+
+CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_GNU_SOURCE
+CFLAGS = -std=c99 -Wall -O2 $(CPPFLAGS)
+LDFLAGS = -s