#include "log.h" #include "common.h" #include #include #include #include #include #include #include struct auth_env a_env; struct proc_env p_env = { .in = STDIN_FILENO, .out = STDOUT_FILENO, .err = STDERR_FILENO, .vt = -1 }; static void interrupt_int(int signum) { } int main(int argc, char **argv, char **envp) { setproctitle_init(argc, argv, envp); if (argc != 2 && argc != 3) { fprintf(stderr, "Usage: %s consent|password|auth [prompt]\n", argv[0]); return 64; } if (!strcmp(argv[1], "consent")) { a_env.mode = mode_consent; } else if (!strcmp(argv[1], "password")) { a_env.mode = mode_password; } else if (!strcmp(argv[1], "auth")) { a_env.mode = mode_auth; } else { fprintf(stderr, "Unknown mode: %s\n", argv[1]); return 64; } if ((a_env.prompt = argv[2])) { char *p = argv[2]; do { if ((*p != '\n') && ((*p) < 32 || (*p) > 126)) { fprintf(stderr, "The given prompt is illegal.\n"); return 64; } } while (*(++ p)); } a_env.pid = getppid(); a_env.usr = getuid(); setproctitle("master"); ssize_t len; snprintf(a_env.exe, sizeof(a_env.exe) - 1, "/proc/%d/exe", a_env.pid); if ((len = readlink(a_env.exe, a_env.exe, sizeof(a_env.exe) - 1)) == -1) { LOGFV("Read caller binary: %m.", errno); return errno; } a_env.exe[len] = '\0'; pid_t chld; /* Detach from the current session. */ if (!(chld = fork())) { setproctitle("auth"); /* Because we need to frequently dup(2). */ setbuf(stdout, NULL); signal(SIGHUP, SIG_IGN); struct sigaction sa = { .sa_flags = 0, .sa_handler = interrupt_int }; sigemptyset(&sa.sa_mask); /* Return EINTR on these signals to exit safely. */ sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); int r; /* Very naive way to determine console and remote sessions. * Better to use PAM_RHOST, ConsoleKit, or systemd-logind. */ if (getenv("SSH_CONNECTION")) { r = main_consent(0); } else { r = sd_setup(); if (r == -1) { sd_cleanup(); return 13; } if (r) { sd_cleanup(); r = main_consent(0); } else { dprintf(p_env.err, "Complete authorization on TTY %d by running `chvt %d`.\n", p_env.vt, p_env.vt); r = main_consent(1); sd_cleanup(); } } return r; } if (chld == -1) { LOGFV("Cannot fork: %m", errno); return errno; } int status; if (waitpid(chld, &status, 0) == -1) { LOGFV("Cannot wait for child: %m", errno); return errno; } if (WIFEXITED(status)) { return WEXITSTATUS(status); } else { return 255; } }