Mac launchd socket activation
Tomas Zahradnicky
tomas.zahradnicky at boxtrap.net
Fri Jun 15 19:09:05 CEST 2018
Hi everyone,
I was trying to run gpg-agent in the supervised mode from macOS launchd.
There seem to be at leasttwo problems with this approach:
1. launchd prohibits forking [1];
2. in order to receive sockets from launchd, its
launchd_activate_socket API must be used.
The supervised mode does not break [1] but expects sockets to be
configured from file descriptor 3 on along with LISTEN_FDNAMES and
LISTEN_FDS environment variables configured. The proper way to acquire
sockets from launchd should be by using its API. Here's our patch for
gpg-agent using launchd_activate_socket against the master revision
including a sample launchd plist file using the socket activation.
All the best,
Tomas
References
---------
1. Apple, Inc. launchd.plist excerpt:
A daemon or agent launched by launchd MUST NOT do the following in the
process directly launched by launchd:
o Call daemon(3).
o Do the moral equivalent of daemon(3) by calling fork(2)
and have the parent process exit(3) or _exit(2).
Patch
-----
diff --git a/agent/agent.h b/agent/agent.h
index 9fdbc76d3..7ff2580d8 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -175,6 +175,10 @@ struct
/* The value of the option --s2k-count. If this option is not given
* or 0 an auto-calibrated value is used. */
unsigned long s2k_count;
+ /* Launchd activation. macOS only. When enabled, the sockets will
+ * be acquired from launchd by calling launch_activate_socket.
+ * Usable in the supervised mode. */
+ int launchd_activate_sockets;
} opt;
diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c
index 1fdc94d0f..6dfb10f35 100644
--- a/agent/gpg-agent.c
+++ b/agent/gpg-agent.c
@@ -30,6 +30,9 @@
#include <time.h>
#include <fcntl.h>
#include <sys/stat.h>
+#ifdef __APPLE__
+#include <launch.h>
+#endif
#ifdef HAVE_W32_SYSTEM
# ifndef WINVER
# define WINVER 0x0500 /* Same as in common/sysutils.c */
@@ -137,6 +140,7 @@ enum cmd_and_opt_values
oS2KCount,
oAutoExpandSecmem,
oListenBacklog,
+ oLaunchdActivateSockets,
oWriteEnvFile
};
@@ -263,6 +267,9 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_n (oUseStandardSocket, "use-standard-socket", "@"),
ARGPARSE_s_n (oNoUseStandardSocket, "no-use-standard-socket", "@"),
+ /* Launchd activation */
+ ARGPARSE_s_n (oLaunchdActivateSockets, "launchd-activate-sockets",
N_("activate sockets from launchd")),
+
ARGPARSE_end () /* End of list */
};
@@ -732,6 +739,30 @@ map_supervised_sockets (gnupg_fd_t *r_fd,
if (!strcmp (fdnames[i], tbl[j].label) || j == DIM(tbl)-1)
{
fd = 3 + i;
+#if __APPLE__
+ if( opt.launchd_activate_sockets )
+ {
+ int* fds = NULL;
+ size_t cnt = 0;
+ int err = launch_activate_socket( fdnames[i],
&fds, &cnt );
+ if( err != 0 )
+ {
+ log_error("cannot activate socket %s
because of error %d\n", fdnames[i], err);
+ break;
+ }
+ if( cnt > 0 )
+ {
+ fd = fds[0];
+ free(fds);
+ }
+ else
+ {
+ log_error("no socket returned for
activation of socket %s\n", fdnames[i]);
+ continue;
+ }
+ }
+#endif
+
if (**tbl[j].fdaddr == -1)
{
name = gnupg_get_socket_name (fd);
@@ -834,6 +865,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int
reread)
/* Note: When changing the next line, change also gpgconf_list. */
opt.ssh_fingerprint_digest = GCRY_MD_MD5;
opt.s2k_count = 0;
+ opt.launchd_activate_sockets = 0;
return 1;
}
@@ -1260,6 +1292,10 @@ main (int argc, char **argv )
/* Only used by the first stage command line parser. */
break;
+ case oLaunchdActivateSockets:
+ opt.launchd_activate_sockets = 1;
+ break;
+
case oWriteEnvFile:
obsolete_option (configname, configlineno, "write-env-file");
break;
My ~/Library/LaunchAgents/net.boxtrap.gpg-agent.plist file
----------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>net.boxtrap.gpg-agent</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/MacGPG2/bin/gpg-agent</string>
<string>--supervised</string>
<string>--launchd-activate-sockets</string>
<string>--homedir</string>
<string>/Users/zahradt/.gnupg/</string>
<string>--enable-ssh-support</string>
<string>--log-file</string>
<string>/Users/zahradt/Library/Logs/gpg-agent.log</string>
</array>
<key>Sockets</key>
<dict>
<key>std</key>
<dict>
<key>SockFamily</key>
<string>Unix</string>
<key>SockPathMode</key>
<integer>448</integer>
<key>SockPathName</key>
<string>/Users/zahradt/.gnupg/S.gpg-agent</string>
<key>SockType</key>
<string>Stream</string>
</dict>
<key>browser</key>
<dict>
<key>SockFamily</key>
<string>Unix</string>
<key>SockPathMode</key>
<integer>448</integer>
<key>SockPathName</key>
<string>/Users/zahradt/.gnupg/S.gpg-browser</string>
<key>SockType</key>
<string>Stream</string>
</dict>
<key>extra</key>
<dict>
<key>SockFamily</key>
<string>Unix</string>
<key>SockPathMode</key>
<integer>448</integer>
<key>SockPathName</key>
<string>/Users/zahradt/.gnupg/S.gpg-extra</string>
<key>SockType</key>
<string>Stream</string>
</dict>
<key>ssh</key>
<dict>
<key>SockFamily</key>
<string>Unix</string>
<key>SockPathMode</key>
<integer>448</integer>
<key>SockPathName</key>
<string>/Users/zahradt/.gnupg/S.gpg-ssh</string>
<key>SockType</key>
<string>Stream</string>
</dict>
</dict>
<key>EnvironmentVariables</key>
<dict>
<key>LISTEN_FDNAMES</key>
<string>std:browser:extra:ssh</string>
<key>LISTEN_FDS</key>
<string>4</string>
</dict>
<key>StandardOutPath</key>
<string>/Users/zahradt/Library/Logs/gpg-agent.stdout.log</string>
<key>StandardErrorPath</key>
<string>/Users/zahradt/Library/Logs/gpg-agent.error.log</string>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
More information about the Gnupg-devel
mailing list