aboutsummaryrefslogtreecommitdiffstats
path: root/asroot.c
diff options
context:
space:
mode:
Diffstat (limited to 'asroot.c')
-rw-r--r--asroot.c180
1 files changed, 180 insertions, 0 deletions
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;
+}