Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 98 additions & 48 deletions src/envoy.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* Copyright (C) Simon Gomizelj, 2015
*/

#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
Expand All @@ -27,7 +28,10 @@
#include <unistd.h>
#include <termios.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/wait.h>

#include "agents.h"
#include "socket.h"
Expand All @@ -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)
Expand Down Expand Up @@ -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";
Expand All @@ -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)
Expand Down Expand Up @@ -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' },
Expand All @@ -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;

Expand All @@ -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;
Expand All @@ -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)
Expand All @@ -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;
Expand Down