Skip to content

Instantly share code, notes, and snippets.

@dotsam
Last active February 16, 2020 06:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dotsam/30d179ef9e005a149b118b72a13e32e7 to your computer and use it in GitHub Desktop.
Save dotsam/30d179ef9e005a149b118b72a13e32e7 to your computer and use it in GitHub Desktop.
launchd gpg-agent wrapper
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>ca.samedwards.gpg-agent</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/gpg-agent-wrapper</string>
<string>/usr/local/bin/gpg-agent</string>
<string>--homedir</string>
<string>/Users/sam/.gnupg</string>
<string>--supervised</string>
</array>
<key>Sockets</key>
<dict>
<key>ssh</key>
<dict>
<key>SecureSocketWithKey</key>
<string>SSH_AUTH_SOCK</string>
<key>SockPathMode</key>
<integer>448</integer>
</dict>
<key>browser</key>
<dict>
<key>SocketFamily</key>
<string>Unix</string>
<key>SockPathMode</key>
<integer>448</integer>
<key>SockPathName</key>
<string>/Users/sam/.gnupg/S.gpg-agent.browser</string>
</dict>
<key>extra</key>
<dict>
<key>SocketFamily</key>
<string>Unix</string>
<key>SockPathMode</key>
<integer>448</integer>
<key>SockPathName</key>
<string>/Users/sam/.gnupg/S.gpg-agent.extra</string>
</dict>
<key>std</key>
<dict>
<key>SocketFamily</key>
<string>Unix</string>
<key>SockPathMode</key>
<integer>448</integer>
<key>SockPathName</key>
<string>/Users/sam/.gnupg/S.gpg-agent</string>
</dict>
</dict>
</dict>
</plist>
// Simple wrapper to activate launchd sockets
// and set them up in the same way systemd would
// so that we can use gpg-agent in --supervised mode
#include <errno.h>
#include <err.h>
#include <unistd.h>
#include <launch.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
int get_launchd_socket(const char *sockName)
{
// Get our sockets from launchd
int *fds = NULL;
size_t count = 0;
errno = launch_activate_socket(sockName, &fds, &count);
if (errno != 0 || fds == NULL || count < 1)
{
warn("Error getting socket FD from launchd");
return 0;
}
if (count != 1)
{
warnx("Expected one FD from launchd, got %zu. Only using first socket.", count);
}
// Unset FD_CLOEXEC bit
fcntl(fds[0], F_SETFD, fcntl(fds[0], F_GETFD, 0) & ~FD_CLOEXEC);
if (fds)
{
free(fds);
}
return 1;
}
int main(int argc, char **argv)
{
// List of sockets we're going to check for
const char *sockets[] = {
"ssh",
"browser",
"extra",
"std"};
int fds = 0;
char *fdsString = NULL;
char *fdNames = NULL;
char *tmpfdNames = NULL;
// Activate the sockets and count and store names
for (int i = 0; i < sizeof(sockets) / sizeof(sockets[0]); i++)
{
if (get_launchd_socket(sockets[i]))
{
fds++;
asprintf(&fdNames, (tmpfdNames == NULL ? "%s%s" : "%s:%s"), (tmpfdNames == NULL ? "" : tmpfdNames), sockets[i]);
if (tmpfdNames)
{
free(tmpfdNames);
}
tmpfdNames = fdNames;
}
}
// Set the ENV var for our PID
char *pidString = NULL;
asprintf(&pidString, "%ld", (long)getpid());
setenv("LISTEN_PID", pidString, 0);
free(pidString);
// Set the number of FDs we've opened
asprintf(&fdsString, "%d", fds);
setenv("LISTEN_FDS", fdsString, 0);
free(fdsString);
// And their names
setenv("LISTEN_FDNAMES", (fdNames == NULL ? "" : fdNames), 0);
free(fdNames);
// Launch the command we were passed
++argv;
if (*argv)
{
execvp(*argv, argv);
err(1, "Error executing command");
}
else
{
errx(1, "No command specified");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment