diff options
Diffstat (limited to 'agent/gpg-agent.c')
-rw-r--r-- | agent/gpg-agent.c | 79 |
1 files changed, 71 insertions, 8 deletions
diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index 113489306..7c682ada7 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -94,7 +94,8 @@ enum cmd_and_opt_values oAllowPresetPassphrase, oKeepTTY, oKeepDISPLAY, - oSSHSupport + oSSHSupport, + oDisableScdaemon }; @@ -128,6 +129,7 @@ static ARGPARSE_OPTS opts[] = { N_("|PGM|use PGM as the PIN-Entry program") }, { oScdaemonProgram, "scdaemon-program", 2 , N_("|PGM|use PGM as the SCdaemon program") }, + { oDisableScdaemon, "disable-scdaemon", 0, N_("do not use the SCdaemon") }, { oDisplay, "display", 2, "@" }, { oTTYname, "ttyname", 2, "@" }, @@ -187,6 +189,11 @@ static const char *debug_level; the log file after a SIGHUP if it didn't changed. Malloced. */ static char *current_logfile; +/* The handle_tick() function may test whether a parent is still + runing. We record the PID of the parent here or -1 if it should be + watched. */ +static pid_t parent_pid = (pid_t)(-1); + /* Local prototypes. */ @@ -387,6 +394,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread) opt.max_cache_ttl = MAX_CACHE_TTL; opt.ignore_cache_for_signing = 0; opt.allow_mark_trusted = 0; + opt.disable_scdaemon = 0; return 1; } @@ -415,6 +423,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread) case oPinentryProgram: opt.pinentry_program = pargs->r.ret_str; break; case oScdaemonProgram: opt.scdaemon_program = pargs->r.ret_str; break; + case oDisableScdaemon: opt.disable_scdaemon = 1; break; case oDefCacheTTL: opt.def_cache_ttl = pargs->r.ret_ulong; break; case oMaxCacheTTL: opt.max_cache_ttl = pargs->r.ret_ulong; break; @@ -740,6 +749,8 @@ main (int argc, char **argv ) GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME); printf ("allow-mark-trusted:%lu:\n", GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME); + printf ("disable-scdaemon:%lu:\n", + GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME); agent_exit (0); } @@ -819,6 +830,11 @@ main (int argc, char **argv ) else fd_ssh = -1; + /* If we are going to exec a program in the parent, we record + the PID, so that the child may check whether the program is + still alive. */ + if (argc) + parent_pid = getpid (); fflush (NULL); #ifdef HAVE_W32_SYSTEM @@ -878,14 +894,14 @@ main (int argc, char **argv ) kill (pid, SIGTERM ); exit (1); } - if (putenv (infostr_ssh_sock)) + if (opt.ssh_support && putenv (infostr_ssh_sock)) { log_error ("failed to set environment: %s\n", strerror (errno) ); kill (pid, SIGTERM ); exit (1); } - if (putenv (infostr_ssh_pid)) + if (opt.ssh_support && putenv (infostr_ssh_pid)) { log_error ("failed to set environment: %s\n", strerror (errno) ); @@ -922,8 +938,7 @@ main (int argc, char **argv ) printf ("%s; export SSH_AGENT_PID;\n", infostr_ssh_pid); } } - /* Note: teh standard free is here correct. */ - free (infostr); + free (infostr); /* (Note that a vanilla free is here correct.) */ if (opt.ssh_support) { free (infostr_ssh_sock); @@ -1311,6 +1326,27 @@ create_directories (void) #ifdef USE_GNU_PTH +/* This is the worker for the ticker. It is called every few seconds + and may only do fast operations. */ +static void +handle_tick (void) +{ +#ifndef HAVE_W32_SYSTEM + if (parent_pid != (pid_t)(-1)) + { + if (kill (parent_pid, 0)) + { + shutdown_pending = 2; + log_info ("parent process died - shutting down\n"); + log_info ("%s %s stopped\n", strusage(11), strusage(13) ); + cleanup (); + agent_exit (0); + } + } +#endif /*HAVE_W32_SYSTEM*/ +} + + static void handle_signal (int signo) { @@ -1409,7 +1445,7 @@ static void handle_connections (int listen_fd, int listen_fd_ssh) { pth_attr_t tattr; - pth_event_t ev; + pth_event_t ev, time_ev; sigset_t sigs; int signo; struct sockaddr_un paddr; @@ -1434,6 +1470,7 @@ handle_connections (int listen_fd, int listen_fd_ssh) #else ev = NULL; #endif + time_ev = NULL; FD_ZERO (&fdset); FD_SET (listen_fd, &fdset); @@ -1456,16 +1493,33 @@ handle_connections (int listen_fd, int listen_fd_ssh) continue; } + /* Create a timeout event if needed. */ + if (!time_ev) + time_ev = pth_event (PTH_EVENT_TIME, pth_timeout (2, 0)); + /* POSIX says that fd_set should be implemented as a structure, thus a simple assignment is fine to copy the entire set. */ read_fdset = fdset; + if (time_ev) + pth_event_concat (ev, time_ev, NULL); ret = pth_select_ev (FD_SETSIZE, &read_fdset, NULL, NULL, NULL, ev); + if (time_ev) + pth_event_isolate (time_ev); + if (ret == -1) { - if (pth_event_occurred (ev)) + if (pth_event_occurred (ev) + || (time_ev && pth_event_occurred (time_ev))) { - handle_signal (signo); + if (pth_event_occurred (ev)) + handle_signal (signo); + if (time_ev && pth_event_occurred (time_ev)) + { + pth_event_free (time_ev, PTH_FREE_ALL); + time_ev = NULL; + handle_tick (); + } continue; } log_error (_("pth_select failed: %s - waiting 1s\n"), @@ -1479,6 +1533,13 @@ handle_connections (int listen_fd, int listen_fd_ssh) handle_signal (signo); } + if (time_ev && pth_event_occurred (time_ev)) + { + pth_event_free (time_ev, PTH_FREE_ALL); + time_ev = NULL; + handle_tick (); + } + if (FD_ISSET (listen_fd, &read_fdset)) { plen = sizeof paddr; @@ -1515,6 +1576,8 @@ handle_connections (int listen_fd, int listen_fd_ssh) } pth_event_free (ev, PTH_FREE_ALL); + if (time_ev) + pth_event_free (time_ev, PTH_FREE_ALL); cleanup (); log_info (_("%s %s stopped\n"), strusage(11), strusage(13)); } |