aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--asroot.c358
-rw-r--r--config.mk4
2 files changed, 288 insertions, 74 deletions
diff --git a/asroot.c b/asroot.c
index 5f03b42..13e2904 100644
--- a/asroot.c
+++ b/asroot.c
@@ -1,13 +1,33 @@
#include <errno.h>
+#include <fcntl.h>
#include <pwd.h>
+#include <shadow.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
+#ifdef WITH_LIBPASSPHRASE
+# include <passphrase.h>
+#endif
+
#include "arg.h"
+#define EXIT_ERROR 125
+#define EXIT_EXEC 126
+#define EXIT_NOENT 127
+
+#ifndef ERROR_SLEEP
+# define ERROR_SLEEP 1
+#endif
+
+#ifndef PROMPT
+# define PROMPT "%s (%s@%s) password: ", argv0, pwd->pw_name, hostname
+#endif
+
+
char *argv0;
extern char **environ;
@@ -74,7 +94,264 @@ static void
usage(void)
{
fprintf(stderr, "usage: %s [-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(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(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_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;
+
+ return new_environ;
+}
+
+
+#ifndef WITH_LIBPASSPHRASE
+static char *
+read_passphrase(int fd)
+{
+ char *passphrase = NULL, *new;
+ size_t size = 0, len = 0;
+ ssize_t r;
+
+ for (;;) {
+ if (len == size) {
+ new = realloc(passphrase, size += 32);
+ if (!new) {
+ fprintf(stderr, "\n%s: realloc %zu: %s\n", argv0, size, strerror(errno));
+ if (passphrase) {
+ memset(passphrase, 0, len);
+ free(passphrase);
+ }
+ return NULL;
+ }
+ passphrase = new;
+ }
+ r = read(fd, &passphrase[len], 1);
+ if (r < 0) {
+ fprintf(stderr, "\n%s: read /dev/tty 1: %s\n", argv0, strerror(errno));
+ memset(passphrase, 0, len);
+ free(passphrase);
+ return NULL;
+ } else if (!r || passphrase[len] == '\n') {
+ break;
+ } else {
+ len += 1;
+ }
+ }
+
+ fprintf(stderr, "\n");
+ passphrase[len] = 0;
+ return passphrase;
+}
+#endif
+
+
+static void
+check_password(void)
+{
+ struct passwd *pwd;
+ struct spwd *shdw;
+ const char *expected, *got;
+ char *hostname = NULL;
+ char *passphrase;
+ size_t size = 8;
+#ifndef WITH_LIBPASSPHRASE
+ struct termios stty_original;
+#endif
+ struct termios stty_enter, stty_sleep;
+ int fd;
+
+ errno = 0;
+ for (;;) {
+ hostname = realloc(hostname, size *= 2);
+ if (!hostname) {
+ fprintf(stderr, "%s: realloc %zu: %s\n", argv0, size, strerror(errno));
+ }
+ *hostname = 0;
+ if (!gethostname(hostname, size)) {
+ break;
+ } else if (errno != ENAMETOOLONG) {
+ fprintf(stderr, "%s: gethostname %zu: %s\n", argv0, size, strerror(errno));
+ exit(EXIT_ERROR);
+ }
+ }
+
+ errno = 0;
+ pwd = getpwuid(getuid());
+ if (!pwd || !pwd->pw_name || !*pwd->pw_name) {
+ if (errno)
+ fprintf(stderr, "%s: getpwuid: %s\n", argv0, strerror(errno));
+ else
+ fprintf(stderr, "%s: your user does not exist\n", argv0);
+ exit(EXIT_ERROR);
+ }
+
+ shdw = getspnam(pwd->pw_name);
+ if (!shdw || !shdw->sp_pwdp) {
+ if (errno)
+ fprintf(stderr, "%s: getspnam: %s\n", argv0, strerror(errno));
+ else
+ fprintf(stderr, "%s: your user does not have a shadow entry\n", argv0);
+ exit(EXIT_ERROR);
+ }
+
+ expected = shdw->sp_pwdp;
+
+ if (!*expected) {
+ fprintf(stderr, "%s: your user does not have a password\n", argv0);
+ exit(EXIT_ERROR);
+ } else if (expected[expected[0] == '!'] == '*' || expected[expected[0] == '!'] == 'x') {
+ fprintf(stderr, "%s: login to your account is disabled\n", argv0);
+ exit(EXIT_ERROR);
+ } else if (expected[0] == '!') {
+ fprintf(stderr, "%s: your account is currently locked\n", argv0);
+ exit(EXIT_ERROR);
+ }
+
+ fd = open("/dev/tty", O_RDWR);
+ if (fd < 0) {
+ fprintf(stderr, "%s: open /dev/tty O_RDWR: %s\n", argv0, strerror(errno));
+ exit(EXIT_ERROR);
+ }
+
+#ifdef WITH_LIBPASSPHRASE
+ passphrase_disable_echo1(fd);
+
+ memset(&stty_enter, 0, sizeof(stty_enter));
+ if (tcgetattr(fd, &stty_enter)) {
+ fprintf(stderr, "%s: tcgetattr /dev/tty: %s\n", argv0, strerror(errno));
+ passphrase_reenable_echo1(fd);
+ close(fd);
+ exit(EXIT_ERROR);
+ }
+#else
+ memset(&stty_original, 0, sizeof(stty_original));
+ if (tcgetattr(fd, &stty_original)) {
+ fprintf(stderr, "%s: tcgetattr /dev/tty: %s\n", argv0, strerror(errno));
+ close(fd);
+ exit(EXIT_ERROR);
+ }
+ memcpy(&stty_enter, &stty_original, sizeof(stty_original));
+ stty_enter.c_lflag &= (tcflag_t)~ECHO;
+ tcsetattr(fd, TCSAFLUSH, &stty_enter);
+#endif
+
+ memcpy(&stty_sleep, &stty_enter, sizeof(stty_enter));
+ stty_sleep.c_lflag = 0;
+
+again:
+ fprintf(stderr, PROMPT);
+ fflush(stderr);
+
+#ifdef WITH_LIBPASSPHRASE
+ passphrase = passphrase_read2(fd, PASSPHRASE_READ_EXISTING);
+ if (!passphrase) {
+ fprintf(stderr, "%s: passphrase_read2 /dev/tty PASSPHRASE_READ_EXISTING: %s\n", argv0, strerror(errno));
+ passphrase_reenable_echo1(fd);
+ close(fd);
+ exit(EXIT_ERROR);
+ }
+#else
+ passphrase = read_passphrase(fd);
+ if (!passphrase) {
+ tcsetattr(fd, TCSAFLUSH, &stty_original);
+ close(fd);
+ exit(EXIT_ERROR);
+ }
+#endif
+
+ got = crypt(passphrase, expected);
+#ifdef WITH_LIBPASSPHRASE
+ passphrase_wipe1(passphrase);
+#else
+ memset(passphrase, 0, strlen(passphrase));
+#endif
+ free(passphrase);
+
+ if (strcmp(got, expected)) {
+ fprintf(stderr, "%s: incorrect password, please try again\n", argv0);
+ tcsetattr(fd, TCSAFLUSH, &stty_sleep);
+ sleep(ERROR_SLEEP);
+ tcsetattr(fd, TCSAFLUSH, &stty_enter);
+ goto again;
+ }
+
+#ifdef WITH_LIBPASSPHRASE
+ passphrase_reenable_echo1(fd);
+#else
+ tcsetattr(fd, TCSAFLUSH, &stty_original);
+#endif
+ close(fd);
}
@@ -83,8 +360,6 @@ 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':
@@ -97,84 +372,21 @@ main(int argc, char *argv[])
if (!argc)
usage();
- /* TODO check password */
+ check_password();
+
+ if (!keep_env)
+ new_environ = set_environ();
if (setgid(0)) {
fprintf(stderr, "%s: setgid 0: %s\n", argv0, strerror(errno));
- return 125;
+ exit(EXIT_ERROR);
}
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;
+ exit(EXIT_ERROR);
}
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;
+ return errno == ENOENT ? EXIT_NOENT : EXIT_EXEC;
}
diff --git a/config.mk b/config.mk
index 1f3b2b5..47b82f7 100644
--- a/config.mk
+++ b/config.mk
@@ -3,4 +3,6 @@ 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
+LDFLAGS = -s -lcrypt
+
+# To use libpassphrase, add -DWITH_LIBPASSPHRASE to CPPFLAGS and -lpassphrase to LDFLAGS