=== modified file 'Makefile' --- Makefile 2008-09-21 12:04:02 +0000 +++ Makefile 2008-09-23 18:46:17 +0000 @@ -55,7 +55,8 @@ # DocBook-to-man post-processing to fix a '\n' escape bug MANPOST=sed --in-place --expression='s,\\\\en,\\en,g;s,\\n,\\en,g' -PLUGINS=plugins.d/password-prompt plugins.d/mandos-client +PLUGINS=plugins.d/password-prompt plugins.d/mandos-client \ + plugins.d/splashy PROGS=plugin-runner $(PLUGINS) DOCS=mandos.8 plugin-runner.8mandos mandos-keygen.8 \ plugins.d/mandos-client.8mandos \ @@ -182,6 +183,9 @@ install --mode=u=rwx,go=rx \ --target-directory=$(PREFIX)/lib/mandos/plugins.d \ plugins.d/usplash + install --mode=u=rwxs,go=rx \ + --target-directory=$(PREFIX)/lib/mandos/plugins.d \ + plugins.d/splashy install initramfs-tools-hook \ $(INITRAMFSTOOLS)/hooks/mandos install --mode=u=rw,go=r initramfs-tools-hook-conf \ @@ -224,6 +228,7 @@ $(PREFIX)/lib/mandos/plugins.d/password-prompt \ $(PREFIX)/lib/mandos/plugins.d/mandos-client \ $(PREFIX)/lib/mandos/plugins.d/usplash \ + $(PREFIX)/lib/mandos/plugins.d/splashy \ $(INITRAMFSTOOLS)/hooks/mandos \ $(INITRAMFSTOOLS)/conf-hooks.d/mandos \ $(INITRAMFSTOOLS)/scripts/local-top/mandos \ === modified file 'plugin-runner.c' --- plugin-runner.c 2008-09-19 20:42:17 +0000 +++ plugin-runner.c 2008-09-23 18:46:17 +0000 @@ -27,8 +27,8 @@ #include /* malloc(), exit(), EXIT_FAILURE, EXIT_SUCCESS, realloc() */ #include /* bool, true, false */ -#include /* perror, popen(), fileno(), - fprintf(), stderr, STDOUT_FILENO */ +#include /* perror, fileno(), fprintf(), + stderr, STDOUT_FILENO */ #include /* DIR, opendir(), stat(), struct stat, waitpid(), WIFEXITED(), WEXITSTATUS(), wait(), pid_t, @@ -46,7 +46,7 @@ fcntl(), setuid(), setgid(), F_GETFD, F_SETFD, FD_CLOEXEC, access(), pipe(), fork(), close() - dup2, STDOUT_FILENO, _exit(), + dup2(), STDOUT_FILENO, _exit(), execv(), write(), read(), close() */ #include /* fcntl(), F_GETFD, F_SETFD, === removed file 'plugins.d/splashy' --- plugins.d/splashy 2008-09-22 07:37:53 +0000 +++ plugins.d/splashy 1970-01-01 00:00:00 +0000 @@ -1,28 +0,0 @@ -#!/bin/sh -e - -# If not on a tty, then get rid of possibly disrupting stderr output -if ! tty -s; then - exec 2>/dev/null -fi - -test -x /sbin/splashy_update - -# We get some variables from cryptsetup: -# $cryptsource the device node, like "/dev/sda3" -# $crypttarget the device mapper name, like "sda3_crypt". - -prompt="Enter passphrase to unlock" -if [ -n "$crypttarget" ]; then - prompt="$prompt the disk $crypttarget" -fi -if [ -n "$cryptsource" ]; then - prompt="$prompt ($cryptsource)" -fi - -splash_input_password(){ - /sbin/splashy_update "getpass $1" -} - -password="`splash_input_password \"$prompt: \"`" - -echo -n "$password" === added file 'plugins.d/splashy.c' --- plugins.d/splashy.c 1970-01-01 00:00:00 +0000 +++ plugins.d/splashy.c 2008-09-23 18:46:17 +0000 @@ -0,0 +1,215 @@ +#define _GNU_SOURCE /* asprintf() */ +#include /* sig_atomic_t, struct sigaction, + sigemptyset(), sigaddset(), + sigaction, SIGINT, SIG_IGN, SIGHUP, + SIGTERM, kill(), SIGKILL */ +#include /* NULL */ +#include /* getenv() */ +#include /* asprintf(), perror() */ +#include /* EXIT_FAILURE, EXIT_SUCCESS, + strtoul(), free() */ +#include /* pid_t, DIR, struct dirent, + ssize_t */ +#include /* opendir(), readdir(), closedir() */ +#include /* readlink(), fork(), execl(), + _exit */ +#include /* memcmp() */ +#include /* and */ +#include /* errno */ +#include /* waitpid(), WIFEXITED(), + WEXITSTATUS() */ + +sig_atomic_t interrupted_by_signal = 0; + +static void termination_handler(__attribute__((unused))int signum){ + interrupted_by_signal = 1; +} + +int main(__attribute__((unused))int argc, char **argv){ + int ret = 0; + + /* Create prompt string */ + char *prompt = NULL; + { + const char *const cryptsource = getenv("cryptsource"); + const char *const crypttarget = getenv("crypttarget"); + const char *const prompt_start = "getpass " + "Enter passphrase to unlock the disk"; + + if(cryptsource == NULL){ + if(crypttarget == NULL){ + ret = asprintf(&prompt, "%s: ", prompt_start); + } else { + ret = asprintf(&prompt, "%s (%s): ", prompt_start, + crypttarget); + } + } else { + if(crypttarget == NULL){ + ret = asprintf(&prompt, "%s %s: ", prompt_start, cryptsource); + } else { + ret = asprintf(&prompt, "%s %s (%s): ", prompt_start, + cryptsource, crypttarget); + } + } + if(ret == -1){ + return EXIT_FAILURE; + } + } + + /* Find splashy process */ + pid_t splashy_pid = 0; + { + const char splashy_name[] = "/sbin/splashy"; + DIR *proc_dir = opendir("/proc"); + if(proc_dir == NULL){ + free(prompt); + perror("opendir"); + return EXIT_FAILURE; + } + for(struct dirent *proc_ent = readdir(proc_dir); + proc_ent != NULL; + proc_ent = readdir(proc_dir)){ + pid_t pid = (pid_t) strtoul(proc_ent->d_name, NULL, 10); + if(pid == 0){ + /* Not a process */ + continue; + } + /* Find the executable name by doing readlink() on the + /proc//exe link */ + char *exe_link; + ret = asprintf(&exe_link, "/proc/%s/exe", proc_ent->d_name); + if(ret == -1){ + perror("asprintf"); + free(prompt); + closedir(proc_dir); + return EXIT_FAILURE; + } + char exe_target[sizeof(splashy_name)]; + ssize_t sret = readlink(exe_link, exe_target, + sizeof(exe_target)); + if((sret == ((ssize_t)sizeof(exe_target)-1)) + and (memcmp(splashy_name, exe_target, + sizeof(exe_target)-1) == 0)){ + splashy_pid = pid; + break; + } + } + closedir(proc_dir); + } + if(splashy_pid == 0){ + free(prompt); + return EXIT_FAILURE; + } + + /* Set up the signal handler */ + { + struct sigaction old_action, + new_action = { .sa_handler = termination_handler, + .sa_flags = 0 }; + sigemptyset(&new_action.sa_mask); + sigaddset(&new_action.sa_mask, SIGINT); + sigaddset(&new_action.sa_mask, SIGHUP); + sigaddset(&new_action.sa_mask, SIGTERM); + ret = sigaction(SIGINT, NULL, &old_action); + if(ret == -1){ + perror("sigaction"); + free(prompt); + return EXIT_FAILURE; + } + if (old_action.sa_handler != SIG_IGN){ + ret = sigaction(SIGINT, &new_action, NULL); + if(ret == -1){ + perror("sigaction"); + free(prompt); + return EXIT_FAILURE; + } + } + ret = sigaction(SIGHUP, NULL, &old_action); + if(ret == -1){ + perror("sigaction"); + free(prompt); + return EXIT_FAILURE; + } + if (old_action.sa_handler != SIG_IGN){ + ret = sigaction(SIGHUP, &new_action, NULL); + if(ret == -1){ + perror("sigaction"); + free(prompt); + return EXIT_FAILURE; + } + } + ret = sigaction(SIGTERM, NULL, &old_action); + if(ret == -1){ + perror("sigaction"); + free(prompt); + return EXIT_FAILURE; + } + if (old_action.sa_handler != SIG_IGN){ + ret = sigaction(SIGTERM, &new_action, NULL); + if(ret == -1){ + perror("sigaction"); + free(prompt); + return EXIT_FAILURE; + } + } + } + + /* Fork off the splashy command to prompt for password */ + pid_t splashy_command_pid = 0; + if(not interrupted_by_signal){ + splashy_command_pid = fork(); + if(splashy_command_pid == -1){ + if(not interrupted_by_signal){ + perror("fork"); + } + return EXIT_FAILURE; + } + /* Child */ + if(splashy_command_pid == 0){ + const char splashy_command[] = "/sbin/splashy_update"; + ret = execl(splashy_command, splashy_command, prompt, + (char *)NULL); + if(not interrupted_by_signal and errno != ENOENT){ + /* Don't report "File not found", since splashy might not be + installed. */ + perror("execl"); + } + free(prompt); + return EXIT_FAILURE; + } + } + + /* Parent */ + free(prompt); + + /* Wait for command to complete */ + int status; + while(not interrupted_by_signal){ + waitpid(splashy_command_pid, &status, 0); + if(not interrupted_by_signal + and WIFEXITED(status) and WEXITSTATUS(status)==0){ + return EXIT_SUCCESS; + } + } + kill(splashy_pid, SIGTERM); + if(interrupted_by_signal){ + kill(splashy_command_pid, SIGTERM); + } + + pid_t new_splashy_pid = fork(); + if(new_splashy_pid == 0){ + while(kill(splashy_pid, 0)){ + sleep(2); + kill(splashy_pid, SIGKILL); + sleep(1); + } + ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */ + if(ret == -1){ + perror("dup2"); + _exit(EXIT_FAILURE); + } + execl("/sbin/splashy", "/sbin/splashy", "boot", (char *)NULL); + } + + return EXIT_FAILURE; +}