diff options
author | aszlig <aszlig@redmoonstudios.org> | 2016-04-04 12:33:20 +0200 |
---|---|---|
committer | aszlig <aszlig@redmoonstudios.org> | 2016-04-04 12:42:31 +0200 |
commit | 16faa2ca67db71617f808d9d0bbad8a0a04bfd41 (patch) | |
tree | 28f790a47e76b0305999ff78bf3474d4cf0ad044 /modules/programs/gpg-agent/agent-wrapper.c | |
parent | e549839f61eeee87a575ccc132eff8099e333c32 (diff) |
modules: Rename gpg-agent to gnupg
We do things such as placing gnupg into environment.systemPackages, so calling this just "programs.gpg-agent" doesn't fit that. Especially if we really want to have a way to specify configuration values in case I'm getting masochistic someday ;-) Signed-off-by: aszlig <aszlig@redmoonstudios.org>
Diffstat (limited to 'modules/programs/gpg-agent/agent-wrapper.c')
-rw-r--r-- | modules/programs/gpg-agent/agent-wrapper.c | 233 |
1 files changed, 0 insertions, 233 deletions
diff --git a/modules/programs/gpg-agent/agent-wrapper.c b/modules/programs/gpg-agent/agent-wrapper.c deleted file mode 100644 index 86e44c1a..00000000 --- a/modules/programs/gpg-agent/agent-wrapper.c +++ /dev/null @@ -1,233 +0,0 @@ -#define _GNU_SOURCE -#include <dlfcn.h> - -#include <stddef.h> -#include <unistd.h> -#include <string.h> -#include <stdlib.h> -#include <errno.h> -#include <malloc.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <systemd/sd-daemon.h> - -static int main_fd = 0; -static int ssh_fd = 0; -static int scdaemon_fd = 0; - -/* Get the systemd file descriptor for a particular socket file. - * Returns -1 if there is an error or -2 if it is an unnamed socket. - */ -static int get_sd_fd_for(const struct sockaddr_un *addr) -{ - if (main_fd == 0 && ssh_fd == 0 && scdaemon_fd == 0) { - int num_fds; - char **fdmap = NULL; - void *libsystemd = NULL; - int (*_sd_listen_fds_with_names)(int, char ***); - - if ((libsystemd = dlopen(LIBSYSTEMD, RTLD_LAZY)) == NULL) { - fprintf(stderr, "dlopen %s\n", dlerror()); - return -1; - } - - _sd_listen_fds_with_names = - dlsym(libsystemd, "sd_listen_fds_with_names"); - - if (_sd_listen_fds_with_names == NULL) { - fprintf(stderr, "dlsym %s\n", dlerror()); - return -1; - } - - num_fds = _sd_listen_fds_with_names(0, &fdmap); - - if (num_fds <= 0) { - fputs("No suitable file descriptors in LISTEN_FDS.\n", stderr); - if (num_fds == 0) - errno = EADDRNOTAVAIL; - return -1; - } - - 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) - ssh_fd = SD_LISTEN_FDS_START + i; - else if (strncmp(fdmap[i], "scdaemon", 9) == 0) - scdaemon_fd = SD_LISTEN_FDS_START + i; - free(fdmap[i]); - } - free(fdmap); - } - - if (dlclose(libsystemd) != 0) - return -1; - } - - if (addr->sun_path == NULL || *(addr->sun_path) == 0) - return -2; - - char *basename = strrchr(addr->sun_path, '/'); - if (basename == NULL) { - fprintf(stderr, "Socket path %s is not absolute.\n", - addr->sun_path); - errno = EADDRNOTAVAIL; - return -1; - } else { - basename++; - } - - if (strncmp(basename, "S.gpg-agent", 12) == 0) { - return main_fd; - } else if (strncmp(basename, "S.gpg-agent.ssh", 16) == 0) { - return ssh_fd; - } else if (strncmp(basename, "S.scdaemon", 11) == 0) { - return scdaemon_fd; - } else { - fprintf(stderr, "Socket path %s is unknown.\n", addr->sun_path); - errno = EADDRNOTAVAIL; - return -1; - } -} - -/* Replace the systemd-provided socket FD with the one that is used by the - * agent, so that we can later look it up in our accept() wrapper. - */ -static void record_sockfd(int sysd_fd, int redir_fd) -{ - if (sysd_fd == main_fd) - main_fd = redir_fd; - else if (sysd_fd == ssh_fd) - ssh_fd = redir_fd; -} - -/* systemd is already listening on that socket, so we don't need to. */ -int listen(int sockfd, int backlog) -{ - return 0; -} - -/* The agent should already have called socket() before and we need to close the - * file descriptor that the socket() call has returned and replace it with the - * one provided by systemd. - */ -int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) -{ - int new_fd; - - new_fd = get_sd_fd_for((const struct sockaddr_un *)addr); - - switch (new_fd) { - case -1: return -1; - /* Unnamed socket, just pretend everything is fine */ - case -2: return 0; - } - - if ((new_fd = get_sd_fd_for((const struct sockaddr_un *)addr)) == -1) - return -1; - - fprintf(stderr, "bind: Redirecting FD %d to systemd-provided FD %d.\n", - sockfd, new_fd); - - if (dup2(new_fd, sockfd) == -1) - return -1; - else - record_sockfd(new_fd, sockfd); - - return 0; -} - -/* Avoid forking for the first time so we can properly track the agent using a - * systemd service (without the need to set Type="forking"). - */ -pid_t fork(void) -{ - static int first_fork = 1; - - static pid_t (*_fork)(void) = NULL; - if (_fork == NULL) - _fork = dlsym(RTLD_NEXT, "fork"); - - /* Unset the LD_PRELOAD environment variable to make sure we don't propagate - * it down to things like the pinentry. - */ - if (unsetenv("LD_PRELOAD") == -1) - return -1; - - if (first_fork) - return first_fork = 0; - - return _fork(); -} - -/* Get the PID of the client connected to the given socket FD. */ -static pid_t get_socket_pid(int sockfd) -{ - struct ucred pcred; - socklen_t pcred_len = sizeof(pcred); - - if (getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &pcred, &pcred_len) == -1) - return -1; - - return pcred.pid; -} - -static pid_t last_pid = 0; - -/* For the pinentry to work correctly with SSH, we need to record the process ID - * of the process communicating with the agent. That way we can get more - * information about the PTS/PTY/TTY the user is on and also know whether a - * DISPLAY is set for that process, because we will connect the pinentry's TTY - * to the TTY of the process on the other end of the socket. - */ -int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) -{ - int retval; - - static int (*_accept)(int, struct sockaddr *, socklen_t *) = NULL; - if (_accept == NULL) - _accept = dlsym(RTLD_NEXT, "accept"); - - retval = _accept(sockfd, addr, addrlen); - - last_pid = 0; - - if (retval != -1 && ssh_fd != 0 && sockfd == ssh_fd) { - pid_t client_pid = get_socket_pid(retval); - if (client_pid == -1) { - close(retval); - return -1; - } - last_pid = client_pid; - fprintf(stderr, "Socket endpoint PID for accepted socket %d is %d.\n", - retval, client_pid); - } - - return retval; -} - -/* Wrap the execv() that calls the pinentry program to include a special - * _CLIENT_PID environment variable, which contains the PID we gathered during - * accept(). Note that this is potentially racy if we have a lot of concurrent - * connections, but the worst that could happen is that we end up having a - * pinentry running on the wrong TTY/display. - */ -int execv(const char *path, char *const argv[]) -{ - static int (*_execv)(const char *, char *const[]) = NULL; - if (_execv == NULL) - _execv = dlsym(RTLD_NEXT, "execv"); - - if (last_pid != 0 && - strncmp(path, PINENTRY_WRAPPER, sizeof(PINENTRY_WRAPPER) + 1) == 0) { - char env_var[40]; - if (snprintf(env_var, 40, "_CLIENT_PID=%d", last_pid) < 0) - return -1; - if (putenv(env_var) < 0) - return -1; - } - - last_pid = 0; - return _execv(path, argv); -} |