about summary refs log tree commit diff
path: root/modules/programs
diff options
context:
space:
mode:
authoraszlig <aszlig@redmoonstudios.org>2016-11-28 07:23:27 +0100
committeraszlig <aszlig@redmoonstudios.org>2016-11-28 07:23:27 +0100
commit676e914486e42eaa7743901638817ba6c203c05e (patch)
tree142852348a8a97acd4d30a024cacabf2955ef4d1 /modules/programs
parent0552f647960ce5164cbae4556000baf7e8bc9906 (diff)
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 <aszlig@redmoonstudios.org>
Diffstat (limited to 'modules/programs')
-rw-r--r--modules/programs/gnupg/agent-wrapper.c54
-rw-r--r--modules/programs/gnupg/default.nix18
2 files changed, 52 insertions, 20 deletions
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 <sys/un.h>
 #include <systemd/sd-daemon.h>
 
+#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 [