aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--key2root.c205
1 files changed, 203 insertions, 2 deletions
diff --git a/key2root.c b/key2root.c
index 69b7dc6..5a152ab 100644
--- a/key2root.c
+++ b/key2root.c
@@ -1,18 +1,164 @@
/* See LICENSE file for copyright and license details. */
+#include <sys/mman.h>
+#include <errno.h>
+#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
#include "arg.h"
+#define EXIT_AUTH 124
+#define EXIT_ERROR 125
+#define EXIT_EXEC 126
+#define EXIT_NOENT 127
+
+
char *argv0;
+/* Keep list in sync with asroot(8)'s list */
+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 [-k key-name] [-e] command [argument] ...\n", argv0);
- exit(125);
+ exit(EXIT_ERROR);
+}
+
+
+static char **
+set_environ(void)
+{
+ char **new_environ;
+ size_t i, j, n, len;
+ struct passwd *pw;
+
+ 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));
+ exit(EXIT_ERROR);
+ }
+ 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(EXIT_ERROR);
+ }
+
+ 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_shell);
+ 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_shell);
+ }
+ new_environ[n] = NULL;
+
+ return new_environ;
}
@@ -20,7 +166,12 @@ int
main(int argc, char *argv[])
{
int keep_env = 0;
+ char **new_environ = NULL;
const char *key_name = NULL;
+ char *key = NULL, *key_new;
+ size_t key_len = 0;
+ size_t key_size = 0;
+ ssize_t r;
ARGBEGIN {
case 'e':
@@ -38,5 +189,55 @@ main(int argc, char *argv[])
if (!argc)
usage();
- return 0;
+ if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
+ fprintf(stderr, "%s: mlockall MCL_CURRENT|MCL_FUTURE: %s\n", argv0, strerror(errno));
+ exit(EXIT_ERROR);
+ }
+
+ for (;;) {
+ if (key_len == key_size) {
+ key_new = malloc(key_size += 1024);
+ if (!key_new) {
+ explicit_bzero(key, key_len);
+ fprintf(stderr, "%s: malloc: %s\n", argv0, strerror(errno));
+ exit(EXIT_ERROR);
+ }
+ memcpy(key_new, key, key_len);
+ explicit_bzero(key, key_len);
+ free(key);
+ key = key_new;
+ }
+ r = read(STDIN_FILENO, &key[key_len], key_size - key_len);
+ if (r <= 0) {
+ if (!r)
+ break;
+ explicit_bzero(key, key_len);
+ fprintf(stderr, "%s: read <stdin>: %s\n", argv0, strerror(errno));
+ exit(EXIT_ERROR);
+ }
+ key_len += (size_t)r;
+ }
+
+ /* TODO authenticate */
+ /* TODO forward */
+
+ explicit_bzero(key, key_len);
+
+ if (!keep_env)
+ new_environ = set_environ();
+
+ if (setgid(0)) {
+ fprintf(stderr, "%s: setgid 0: %s\n", argv0, strerror(errno));
+ exit(EXIT_ERROR);
+ }
+ if (setuid(0)) {
+ fprintf(stderr, "%s: setuid 0: %s\n", argv0, strerror(errno));
+ exit(EXIT_ERROR);
+ }
+
+ if (new_environ)
+ environ = new_environ;
+ execvp(argv[0], argv);
+ fprintf(stderr, "%s: execvpe %s: %s\n", argv0, argv[0], strerror(errno));
+ return errno == ENOENT ? EXIT_NOENT : EXIT_EXEC;
}