From f4db9196da28d7d85772690d33faf02ab516d60a Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 14 Oct 2018 18:48:02 +0100 Subject: [PATCH] Factor out Unix Pageant's socket creation. The code in Pageant that sets up the Unix socket and its containing directory now lives in a separate file, uxagentsock.c, where it will also be callable from the upcoming new SSH server when it wants to create a similar socket for agent forwarding. While I'm at it, I've also added a feature to create a watchdog subprocess that will try to clean up the socket and directory once Pageant itself terminates, in the hope of leaving less cruft lying around /tmp. --- Recipe | 2 +- ssh.h | 3 ++ unix/unix.h | 4 ++- unix/uxagentsock.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++ unix/uxpgnt.c | 22 ++++-------- 5 files changed, 98 insertions(+), 18 deletions(-) create mode 100644 unix/uxagentsock.c diff --git a/Recipe b/Recipe index f276b86f..b819c546 100644 --- a/Recipe +++ b/Recipe @@ -349,7 +349,7 @@ psftp : [U] psftp uxsftp uxcons UXSSH BE_SSH SFTP wildcard UXMISC uxnogtk pageant : [X] uxpgnt uxagentc aqsync pageant sshrsa sshpubk sshdes sshbn + sshmd5 version tree234 misc sshaes sshsha sshdss sshsh256 sshsh512 + sshecc CONF uxsignal nocproxy nogss be_none x11fwd ux_x11 uxcons - + gtkask gtkmisc nullplug logging UXMISC + + gtkask gtkmisc nullplug logging UXMISC uxagentsock ptermapp : [XT] GTKTERM uxmisc misc ldisc settings uxpty uxsel BE_NONE uxstore + uxsignal CHARSET uxpterm version time xpmpterm xpmptcfg diff --git a/ssh.h b/ssh.h index bf7eda97..3e61de15 100644 --- a/ssh.h +++ b/ssh.h @@ -344,6 +344,9 @@ char *portfwdmgr_connect(PortFwdManager *mgr, Channel **chan_ret, char *hostname, int port, SshChannel *c, int addressfamily); +Socket *platform_make_agent_socket(Plug *plug, const char *dirprefix, + char **error, char **name); + LogContext *ssh_get_logctx(Ssh *ssh); /* Communications back to ssh.c from connection layers */ diff --git a/unix/unix.h b/unix/unix.h index 71dfc953..521c5a87 100644 --- a/unix/unix.h +++ b/unix/unix.h @@ -321,9 +321,11 @@ int init_ucs(struct unicode_data *ucsdata, char *line_codepage, int utf8_override, int font_charset, int vtmode); /* - * Spare function exported directly from uxnet.c. + * Spare functions exported directly from uxnet.c. */ void *sk_getxdmdata(Socket *sock, int *lenp); +SockAddr *unix_sock_addr(const char *path); +Socket *new_unix_listener(SockAddr *listenaddr, Plug *plug); /* * General helpful Unix stuff: more helpful version of the FD_SET diff --git a/unix/uxagentsock.c b/unix/uxagentsock.c new file mode 100644 index 00000000..90e701ff --- /dev/null +++ b/unix/uxagentsock.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include "putty.h" +#include "ssh.h" +#include "misc.h" +#include "pageant.h" + +Socket *platform_make_agent_socket( + Plug *plug, const char *dirprefix, char **error, char **name) +{ + char *username, *socketdir, *socketname, *errw; + const char *errr; + Socket *sock; + + *name = NULL; + + username = get_username(); + socketdir = dupprintf("%s.%s", dirprefix, username); + sfree(username); + + assert(*socketdir == '/'); + if ((errw = make_dir_and_check_ours(socketdir)) != NULL) { + *error = dupprintf("%s: %s\n", socketdir, errw); + sfree(errw); + return NULL; + } + + socketname = dupprintf("%s/pageant.%d", socketdir, (int)getpid()); + sock = new_unix_listener(unix_sock_addr(socketname), plug); + if ((errr = sk_socket_error(sock)) != NULL) { + *error = dupprintf("%s: %s\n", socketname, errr); + sk_close(sock); + sfree(socketname); + rmdir(socketdir); + sfree(socketdir); + return NULL; + } + + /* + * Spawn a subprocess which will try to reliably delete our socket + * and its containing directory when we terminate, in case we die + * unexpectedly. + */ + { + int cleanup_pipe[2]; + pid_t pid; + + /* Don't worry if pipe or fork fails; it's not _that_ critical. */ + if (!pipe(cleanup_pipe)) { + if ((pid = fork()) == 0) { + int buf[1024]; + /* + * Our parent process holds the writing end of + * this pipe, and writes nothing to it. Hence, + * we expect read() to return EOF as soon as + * that process terminates. + */ + setpgid(0, 0); + close(cleanup_pipe[1]); + while (read(cleanup_pipe[0], buf, sizeof(buf)) > 0); + unlink(socketname); + rmdir(socketdir); + _exit(0); + } else if (pid < 0) { + close(cleanup_pipe[0]); + close(cleanup_pipe[1]); + } else { + close(cleanup_pipe[0]); + cloexec(cleanup_pipe[1]); + } + } + } + + *name = socketname; + *error = NULL; + sfree(socketdir); + return sock; +} diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index a0c48ca3..86d4e2c1 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -20,9 +20,6 @@ #include "misc.h" #include "pageant.h" -SockAddr *unix_sock_addr(const char *path); -Socket *new_unix_listener(SockAddr *listenaddr, Plug *plug); - void cmdline_error(const char *fmt, ...) { va_list ap; @@ -711,7 +708,7 @@ static const PlugVtable X11Connection_plugvt = { void run_agent(void) { const char *err; - char *username, *socketdir; + char *errw; struct pageant_listen_state *pl; Plug *pl_plug; Socket *sock; @@ -743,19 +740,12 @@ void run_agent(void) /* * Set up a listening socket and run Pageant on it. */ - username = get_username(); - socketdir = dupprintf("%s.%s", PAGEANT_DIR_PREFIX, username); - sfree(username); - assert(*socketdir == '/'); - if ((err = make_dir_and_check_ours(socketdir)) != NULL) { - fprintf(stderr, "pageant: %s: %s\n", socketdir, err); - exit(1); - } - socketname = dupprintf("%s/pageant.%d", socketdir, (int)getpid()); pl = pageant_listener_new(&pl_plug); - sock = new_unix_listener(unix_sock_addr(socketname), pl_plug); - if ((err = sk_socket_error(sock)) != NULL) { - fprintf(stderr, "pageant: %s: %s\n", socketname, err); + sock = platform_make_agent_socket(pl_plug, PAGEANT_DIR_PREFIX, + &errw, &socketname); + if (!sock) { + fprintf(stderr, "pageant: %s\n", errw); + sfree(errw); exit(1); } pageant_listener_got_socket(pl, sock);