From 676e914486e42eaa7743901638817ba6c203c05e Mon Sep 17 00:00:00 2001 From: aszlig Date: Mon, 28 Nov 2016 07:23:27 +0100 Subject: modules/gnupg: Support --supervised since 2.1.16 See the release announcement at: https://lists.gnupg.org/pipermail/gnupg-announce/2016q4/000398.html Unfortunately we still need the wrapper, because we need to pick up the PID of the socket endpoint in order to gather various information we can pass to pinentry (which then for example can recognize that the actual SSH client is using X or is using a particular TTY). On the upside however, this is a step into a direction I didn't imagine to happen anytime soon, given the following statement from Werner Koch back then: https://lists.gnupg.org/pipermail/gnupg-devel/2014-November/029104.html However I don't think the way I'm picking up the PID and doing inspection of /proc/PID is going to happen in upstream GnuPG anytime soon. But after cleaning up and doing it as a patch I might now consider upstreaming it. Signed-off-by: aszlig --- modules/programs/gnupg/agent-wrapper.c | 54 +++++++++++++++++++++++++--------- modules/programs/gnupg/default.nix | 18 ++++++++---- 2 files changed, 52 insertions(+), 20 deletions(-) (limited to 'modules/programs') diff --git a/modules/programs/gnupg/agent-wrapper.c b/modules/programs/gnupg/agent-wrapper.c index b5e623bc..d9cb7a0e 100644 --- a/modules/programs/gnupg/agent-wrapper.c +++ b/modules/programs/gnupg/agent-wrapper.c @@ -11,21 +11,19 @@ #include #include +#ifndef SUPERVISOR_SUPPORT static int main_fd = 0; -static int ssh_fd = 0; static int scdaemon_fd = 0; +#endif -/* Get a systemd file descriptor corresponding to the specified socket path. - * - * Return values: - * -1 Socket path not a systemd socket - * -2 Provided socket path is not absolute - * -3 No suitable file descriptors in LISTEN_FDS - * -4 Error while determining LISTEN_FDS - */ -static int get_sd_fd(const char *sockpath) -{ +static int ssh_fd = 0; + +static int gather_sd_fds(void) { +#ifdef SUPERVISOR_SUPPORT + if (ssh_fd == 0) { +#else if (main_fd == 0 && ssh_fd == 0 && scdaemon_fd == 0) { +#endif int num_fds; char **fdmap = NULL; void *libsystemd = NULL; @@ -55,12 +53,14 @@ static int get_sd_fd(const char *sockpath) if (fdmap != NULL) { for (int i = 0; i < num_fds; i++) { - if (strncmp(fdmap[i], "main", 5) == 0) - main_fd = SD_LISTEN_FDS_START + i; - else if (strncmp(fdmap[i], "ssh", 4) == 0) + if (strncmp(fdmap[i], "ssh", 4) == 0) ssh_fd = SD_LISTEN_FDS_START + i; +#ifndef SUPERVISOR_SUPPORT + else if (strncmp(fdmap[i], "main", 5) == 0) + main_fd = SD_LISTEN_FDS_START + i; else if (strncmp(fdmap[i], "scdaemon", 9) == 0) scdaemon_fd = SD_LISTEN_FDS_START + i; +#endif free(fdmap[i]); } free(fdmap); @@ -70,6 +70,26 @@ static int get_sd_fd(const char *sockpath) return -1; } + return 0; +} + +#ifndef SUPERVISOR_SUPPORT + +/* Get a systemd file descriptor corresponding to the specified socket path. + * + * Return values: + * -1 Socket path not a systemd socket + * -2 Provided socket path is not absolute + * -3 No suitable file descriptors in LISTEN_FDS + * -4 Error while determining LISTEN_FDS + */ +static int get_sd_fd(const char *sockpath) +{ + int ret; + + if ((ret = gather_sd_fds()) != 0) + return ret; + char *basename = strrchr(sockpath, '/'); if (basename == NULL) return -2; @@ -215,6 +235,8 @@ pid_t fork(void) return _fork(); } +#endif /* !SUPERVISOR_SUPPORT */ + /* Get the PID of the client connected to the given socket FD. */ static pid_t get_socket_pid(int sockfd) { @@ -247,6 +269,10 @@ int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) last_pid = 0; +#ifdef SUPERVISOR_SUPPORT + if (ssh_fd == 0) gather_sd_fds(); +#endif + if (retval != -1 && ssh_fd != 0 && sockfd == ssh_fd) { pid_t client_pid = get_socket_pid(retval); if (client_pid == -1) { diff --git a/modules/programs/gnupg/default.nix b/modules/programs/gnupg/default.nix index d938a184..db9bdc6b 100644 --- a/modules/programs/gnupg/default.nix +++ b/modules/programs/gnupg/default.nix @@ -8,6 +8,8 @@ let hasXdgSupport = versionAtLeast (getVersion cfg.package) "2.1.13"; isDefaultHome = cfg.homeDir == ".gnupg"; + hasSupervisorSupport = versionAtLeast (getVersion cfg.package) "2.1.16"; + sockDir = if hasXdgSupport && isDefaultHome then "%t/gnupg" else "%h/${cfg.homeDir}"; @@ -28,11 +30,12 @@ let UNIX-CONNECT:"${shellSockDir}/S.scdaemon" ''; - agentWrapper = pkgs.runCommandCC "gpg-agent-wrapper" { + agentWrapper = withSupervisor: pkgs.runCommandCC "gpg-agent-wrapper" { buildInputs = with pkgs; [ pkgconfig systemd ]; inherit pinentryWrapper; } '' cc -Wall -shared -std=c11 \ + ${optionalString withSupervisor "-DSUPERVISOR_SUPPORT=1"} \ -DLIBSYSTEMD=\"${pkgs.systemd.lib}/lib/libsystemd.so\" \ -DPINENTRY_WRAPPER=\"$pinentryWrapper\" \ $(pkg-config --cflags libsystemd) -ldl \ @@ -110,7 +113,7 @@ in { (mkIf (cfg.enable && cfg.agent.enable) { systemd.user.services.gpg-agent = { description = "GnuPG Agent"; - environment.LD_PRELOAD = agentWrapper; + environment.LD_PRELOAD = agentWrapper hasSupervisorSupport; environment.GNUPGHOME = "~/${cfg.homeDir}"; serviceConfig.ExecStart = toString ([ @@ -119,8 +122,9 @@ in { (if cfg.agent.scdaemon.enable then "--scdaemon-program=${scdaemonRedirector}" else "--disable-scdaemon") - "--no-detach" - "--daemon" + (if hasSupervisorSupport + then "--supervised" + else "--no-detach --daemon") ] ++ optional cfg.agent.sshSupport "--enable-ssh-support"); serviceConfig.ExecReload = toString [ @@ -134,7 +138,9 @@ in { wantedBy = [ "sockets.target" ]; description = "Main Socket For GnuPG Agent"; listenStreams = singleton "${sockDir}/S.gpg-agent"; - socketConfig = agentSocketConfig "main"; + socketConfig = let + sockName = if hasSupervisorSupport then "std" else "main"; + in agentSocketConfig sockName; }; }) (mkIf (cfg.enable && cfg.agent.enable && cfg.agent.scdaemon.enable) { @@ -151,7 +157,7 @@ in { systemd.user.services.gnupg-scdaemon = { description = "GnuPG Smartcard Daemon"; - environment.LD_PRELOAD = agentWrapper; + environment.LD_PRELOAD = agentWrapper false; environment.GNUPGHOME = "~/${cfg.homeDir}"; serviceConfig.ExecStart = toString [ -- cgit 1.4.1