From 94a756f3a9f9b04d55d0efc4c9c6074ece997750 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 2 Feb 2020 18:52:10 +0000 Subject: [PATCH] Unix Pageant: add a --symlink option. I've often found it useful that you can make symlinks to Unix-domain sockets, and then connect() on the symlink path will redirect to the original socket. This commit adds an option to Unix Pageant which will make it symlink its socket path to a link location of your choice. My initial use case is when running Pageant in debug mode during development: if you run a new copy of it every few minutes after making a code change, then it's annoying to have it change its socket path every time so you have to keep pasting its setup command into your test shell. Not any more! Now you can run 'pageant --debug --symlink fixed-location', and then your test shell can point its SSH_AUTH_SOCK at the fixed location all the time. There are very likely other use cases too, but that's the one that motivated me to add the option. --- unix/uxpgnt.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index 6c8c5b7c..e73e5f0b 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -775,7 +776,7 @@ static const PlugVtable X11Connection_plugvt = { NULL }; -void run_agent(FILE *logfp) +void run_agent(FILE *logfp, const char *symlink_path) { const char *err; char *errw; @@ -826,6 +827,29 @@ void run_agent(FILE *logfp) } pageant_listener_got_socket(pl, sock); + if (symlink_path) { + /* + * Try to make a symlink to the Unix socket, in a location of + * the user's choosing. + * + * If the link already exists, we want to replace it. There + * are two ways we could do this: either make it under another + * name and then rename it over the top, or remove the old + * link first. The former is what 'ln -sf' does, on the + * grounds that it's more atomic. But I think in this case, + * where the expected use case is that the previous agent has + * long since shut down, atomicity isn't a critical concern + * compared to not accidentally overwriting some non-symlink + * that might have important data in it! + */ + struct stat st; + if (lstat(symlink_path, &st) == 0 && S_ISLNK(st.st_mode)) + unlink(symlink_path); + if (symlink(socketname, symlink_path) < 0) + fprintf(stderr, "pageant: making symlink %s: %s\n", + symlink_path, strerror(errno)); + } + conf = conf_new(); conf_set_int(conf, CONF_proxy_type, PROXY_NONE); @@ -1117,6 +1141,7 @@ int main(int argc, char **argv) bool doing_opts = true; keyact curr_keyact = KEYACT_AGENT_LOAD; const char *standalone_askpass_prompt = NULL; + const char *symlink_path = NULL; FILE *logfp = NULL; /* @@ -1179,8 +1204,19 @@ int main(int argc, char **argv) "after --askpass\n"); exit(1); } + } else if (!strcmp(p, "--symlink")) { + if (--argc > 0) { + symlink_path = *++argv; + } else { + fprintf(stderr, "pageant: expected a pathname " + "after --symlink\n"); + exit(1); + } } else if (!strcmp(p, "--")) { doing_opts = false; + } else { + fprintf(stderr, "pageant: unrecognised option '%s'\n", p); + exit(1); } } else { /* @@ -1268,7 +1304,7 @@ int main(int argc, char **argv) } if (has_lifetime) { - run_agent(logfp); + run_agent(logfp, symlink_path); } else if (has_client_actions) { run_client(); }