From fa948e2068ee16090dec9d618cbba4b7092e0181 Mon Sep 17 00:00:00 2001 From: Evan Klitzke Date: Fri, 15 Jan 2016 22:16:20 -0800 Subject: [PATCH] allow adding and printing keys at the same time --- src/envoy.c | 146 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 98 insertions(+), 48 deletions(-) diff --git a/src/envoy.c b/src/envoy.c index 5c011c7..10d5829 100644 --- a/src/envoy.c +++ b/src/envoy.c @@ -15,6 +15,7 @@ * Copyright (C) Simon Gomizelj, 2015 */ +#include #include #include #include @@ -27,7 +28,10 @@ #include #include #include +#include +#include #include +#include #include "agents.h" #include "socket.h" @@ -45,7 +49,8 @@ enum action { ACTION_RELOAD, ACTION_LIST, ACTION_UNLOCK, - ACTION_INVALID + ACTION_INVALID, + NR_ITEMS /* to count the number of actions, must be the last enum value */ }; static void term_cleanup(void) @@ -118,31 +123,56 @@ static char *get_key_path(const char *home, const char *fragment) return joinpath(home, ".ssh", fragment, NULL); } -static _noreturn_ void add_keys(char **keys, int count) +static void add_keys(char **keys, int count, bool quiet_mode) { /* command + end-of-opts + NULL + keys */ const char *home_dir = get_home_dir(); char *args[count + 3]; - int i; + int i, wait_status; args[0] = "/usr/bin/ssh-add"; args[1] = "--"; - for (i = 0; i < count; i++) + for (i = 0; i < count; i++) { args[2 + i] = get_key_path(home_dir, keys[i]); + } args[2 + count] = NULL; - execv(args[0], args); - err(EXIT_FAILURE, "failed to launch ssh-add"); + pid_t child = fork(); + switch (child) { + case -1: + err(EXIT_FAILURE, "failed to fork when starting ssh-add"); + break; + case 0: + if (quiet_mode) { + int devnull = open("/dev/null", O_WRONLY); + if (devnull < 1 ) { + err(EXIT_FAILURE, "failed to open /dev/null"); + return; + } + if (dup2(devnull, STDOUT_FILENO) == -1) + err(EXIT_FAILURE, "failed to dup2() stdout to /dev/null"); + if (dup2(devnull, STDERR_FILENO) == -1) + err(EXIT_FAILURE, "failed to dup2() stderr to /dev/null"); + } + execv(args[0], args); + err(EXIT_FAILURE, "failed to launch ssh-add"); + break; + default: + waitpid(child, &wait_status, 0); + if (WIFEXITED(wait_status) && WEXITSTATUS(wait_status)) + err(EXIT_FAILURE, "ssh-add terminated with non-zero exit status"); + break; + } } -static _noreturn_ void expunge_keys(char **keys, int count) +static void expunge_keys(char **keys, int count) { /* command + -d + end-of-opts + NULL + keys */ const char *home_dir = get_home_dir(); char *args[count + 4]; - int i; + int i, wait_status; args[0] = "/usr/bin/ssh-add"; args[1] = "-d"; @@ -153,8 +183,21 @@ static _noreturn_ void expunge_keys(char **keys, int count) args[3 + count] = NULL; - execv(args[0], args); - err(EXIT_FAILURE, "failed to launch ssh-add"); + pid_t child = fork(); + switch (child) { + case -1: + err(EXIT_FAILURE, "failed to fork when starting ssh-add"); + break; + case 0: + execv(args[0], args); + err(EXIT_FAILURE, "failed to launch ssh-add"); + break; + default: + waitpid(child, &wait_status, 0); + if (WIFEXITED(wait_status) && WEXITSTATUS(wait_status)) + err(EXIT_FAILURE, "ssh-add terminated with non-zero exit status"); + break; + } } static void print_sh_env(struct agent_data_t *data) @@ -258,11 +301,13 @@ int main(int argc, char *argv[]) { bool source = true; bool defer = false; + bool quiet_mode = false; struct agent_data_t data; char *password = NULL; - enum action verb = ACTION_NONE; enum agent type = AGENT_DEFAULT; void (*print_env)(struct agent_data_t *data) = print_sh_env; + enum action verbs[NR_ITEMS]; + size_t i, verbs_sz = 0; static const struct option opts[] = { { "help", no_argument, 0, 'h' }, @@ -283,7 +328,7 @@ int main(int argc, char *argv[]) }; while (true) { - int opt = getopt_long(argc, argv, "hvdaxkrlu::pscft:", opts, NULL); + int opt = getopt_long(argc, argv, "hvdaxkrlqu::pscft:", opts, NULL); if (opt == -1) break; @@ -298,30 +343,30 @@ int main(int argc, char *argv[]) defer = true; break; case 'a': - verb = ACTION_FORCE_ADD; + verbs[verbs_sz++] = ACTION_FORCE_ADD; defer = false; break; case 'x': - verb = ACTION_FORCE_EXPUNGE; + verbs[verbs_sz++] = ACTION_FORCE_EXPUNGE; defer = false; break; case 'k': - verb = ACTION_KILL; + verbs[verbs_sz++] = ACTION_KILL; source = false; break; case 'r': - verb = ACTION_RELOAD; + verbs[verbs_sz++] = ACTION_RELOAD; source = false; break; case 'l': - verb = ACTION_LIST; + verbs[verbs_sz++] = ACTION_LIST; break; case 'u': - verb = ACTION_UNLOCK; + verbs[verbs_sz++] = ACTION_UNLOCK; password = optarg; break; case 'p': - verb = ACTION_PRINT; + verbs[verbs_sz++] = ACTION_PRINT; break; case 's': print_env = print_sh_env; @@ -332,6 +377,9 @@ int main(int argc, char *argv[]) case 'f': print_env = print_fish_env; break; + case 'q': + quiet_mode = true; + break; case 't': type = lookup_agent(optarg); if (type < 0) @@ -351,37 +399,39 @@ int main(int argc, char *argv[]) if (source) source_env(&data); - switch (verb) { - case ACTION_PRINT: - print_env(&data); - /* fall through */ - case ACTION_NONE: - if (data.type == AGENT_GPG_AGENT || !agent_started(&data)) + for (i = 0; i < verbs_sz; i++) { + switch (verbs[i]) { + case ACTION_PRINT: + print_env(&data); + /* fall through */ + case ACTION_NONE: + if (data.type == AGENT_GPG_AGENT || !agent_started(&data)) + break; + if (defer) + break; + /* fall through */ + case ACTION_FORCE_ADD: + add_keys(&argv[optind], argc - optind, quiet_mode); break; - if (defer) + case ACTION_FORCE_EXPUNGE: + expunge_keys(&argv[optind], argc - optind); break; - /* fall through */ - case ACTION_FORCE_ADD: - add_keys(&argv[optind], argc - optind); - break; - case ACTION_FORCE_EXPUNGE: - expunge_keys(&argv[optind], argc - optind); - break; - case ACTION_KILL: - if (envoy_kill_agent(type) < 0) - errx(EXIT_FAILURE, "failed to kill agent"); - break; - case ACTION_RELOAD: - reload_agent(&data); - break; - case ACTION_LIST: - execlp("ssh-add", "ssh-add", "-l", NULL); - err(EXIT_FAILURE, "failed to launch ssh-add"); - case ACTION_UNLOCK: - unlock(&data, password); - break; - default: - break; + case ACTION_KILL: + if (envoy_kill_agent(type) < 0) + errx(EXIT_FAILURE, "failed to kill agent"); + break; + case ACTION_RELOAD: + reload_agent(&data); + break; + case ACTION_LIST: + execlp("ssh-add", "ssh-add", "-l", NULL); + err(EXIT_FAILURE, "failed to launch ssh-add"); + case ACTION_UNLOCK: + unlock(&data, password); + break; + default: + break; + } } return 0;