From 2a189d522c0c22c77a8a95ab16f3bf46cdab8926 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sun, 31 Jan 2021 14:04:54 +0100 Subject: First commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- .gitignore | 5 ++ LICENSE | 15 ++++++ Makefile | 29 ++++++++++ arg.h | 45 ++++++++++++++++ asroot.c | 180 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ config.mk | 6 +++ 6 files changed, 280 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 arg.h create mode 100644 asroot.c create mode 100644 config.mk 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 + +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 +#include +#include +#include +#include +#include + +#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 -- cgit v1.2.3-70-g09d2