diff options
Diffstat (limited to 'agent/gpg-agent.c')
-rw-r--r-- | agent/gpg-agent.c | 117 |
1 files changed, 93 insertions, 24 deletions
diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index 5f7b6f843..a02ddba00 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -78,15 +78,17 @@ enum cmd_and_opt_values oLCctype, oLCmessages, oScdaemonProgram, - oDefCacheTTL, oDisablePth, + oDefCacheTTL, + oMaxCacheTTL, oIgnoreCacheForSigning, oAllowMarkTrusted, oKeepTTY, oKeepDISPLAY, - aTest, - oSSHSupport }; + oSSHSupport, + +aTest }; @@ -128,17 +130,18 @@ static ARGPARSE_OPTS opts[] = { { oDefCacheTTL, "default-cache-ttl", 4, N_("|N|expire cached PINs after N seconds")}, + { oMaxCacheTTL, "max-cache-ttl", 4, "@" }, { oIgnoreCacheForSigning, "ignore-cache-for-signing", 0, N_("do not use the PIN cache when signing")}, { oAllowMarkTrusted, "allow-mark-trusted", 0, N_("allow clients to mark keys as \"trusted\"")}, { oSSHSupport, "ssh-support", 0, "Enable SSH-Agent emulation" }, - {0} }; -#define DEFAULT_CACHE_TTL (10*60) /* 10 minutes */ +#define DEFAULT_CACHE_TTL (10*60) /* 10 minutes */ +#define MAX_CACHE_TTL (120*60) /* 2 hours */ static volatile int caught_fatal_sig = 0; @@ -181,6 +184,7 @@ static void handle_connections (int listen_fd, int listen_fd_ssh); GCRY_THREAD_OPTION_PTH_IMPL; #endif /*USE_GNU_PTH*/ +static void check_for_running_agent (void); @@ -286,6 +290,7 @@ set_debug (void) gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1); gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose); } + static void cleanup_do (char *name) @@ -353,6 +358,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread) opt.pinentry_program = NULL; opt.scdaemon_program = NULL; opt.def_cache_ttl = DEFAULT_CACHE_TTL; + opt.max_cache_ttl = MAX_CACHE_TTL; opt.ignore_cache_for_signing = 0; opt.allow_mark_trusted = 0; return 1; @@ -368,8 +374,9 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread) case oDebugLevel: debug_level = pargs->r.ret_str; break; case oLogFile: - if (!current_logfile || !pargs->r.ret_str - || strcmp (current_logfile, pargs->r.ret_str)) + if (reread + && (!current_logfile || !pargs->r.ret_str + || strcmp (current_logfile, pargs->r.ret_str))) { log_set_file (pargs->r.ret_str); xfree (current_logfile); @@ -383,6 +390,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread) case oScdaemonProgram: opt.scdaemon_program = pargs->r.ret_str; break; case oDefCacheTTL: opt.def_cache_ttl = pargs->r.ret_ulong; break; + case oMaxCacheTTL: opt.max_cache_ttl = pargs->r.ret_ulong; break; case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break; @@ -394,6 +402,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread) return 1; /* handled */ } + static void server_socket_create (int *sock, const char *identifier, char *name, int name_size) @@ -681,7 +690,9 @@ main (int argc, char **argv ) fprintf (stderr, "%s\n", strusage(15) ); } #ifdef IS_DEVELOPMENT_VERSION - log_info ("NOTE: this is a development version!\n"); + /* We don't want to print it here because gpg-agent is useful of its + own and quite matured. */ + /*log_info ("NOTE: this is a development version!\n");*/ #endif set_debug (); @@ -751,9 +762,15 @@ main (int argc, char **argv ) agent_exit (0); } + /* If this has been called without any options, we merely check + whether an agent is already running. We do this here so that we + don't clobber a logfile but print it directly to stderr. */ if (!pipe_server && !is_daemon) - log_info (_("please use the option `--daemon'" - " to run the program in the background\n")); + { + log_set_prefix (NULL, JNLIB_LOG_WITH_PREFIX); + check_for_running_agent (); + agent_exit (0); + } #ifdef ENABLE_NLS /* gpg-agent usually does not output any messages because it runs in @@ -787,12 +804,11 @@ main (int argc, char **argv ) start_command_handler (-1, -1); } else if (!is_daemon) - ; + ; /* NOTREACHED */ else - { /* regular server mode */ + { /* Regular server mode */ int fd = -1, fd_ssh = -1; pid_t pid; - //char *p; /* Remove the DISPLAY variable so that a pinentry does not default to a specific display. There is still a default @@ -806,7 +822,6 @@ main (int argc, char **argv ) server_socket_create (&fd_ssh, "-ssh", socket_name_ssh, sizeof (socket_name_ssh)); - if (opt.verbose) { log_info ("listening on socket `%s'\n", socket_name); @@ -814,6 +829,7 @@ main (int argc, char **argv ) log_info ("listening on socket `%s'\n", socket_name_ssh); } + fflush (NULL); pid = fork (); if (pid == (pid_t)-1) @@ -826,8 +842,6 @@ main (int argc, char **argv ) char *infostr, *infostr_ssh_sock, *infostr_ssh_pid; close (fd); - if (opt.ssh_support) - close (fd_ssh); /* create the info string: <name>:<pid>:<protocol_version> */ if (asprintf (&infostr, "GPG_AGENT_INFO=%s:%lu:1", @@ -858,7 +872,7 @@ main (int argc, char **argv ) *socket_name = 0; /* don't let cleanup() remove the socket - the child should do this from now on */ *socket_name_ssh = 0; - + if (argc) { /* run the program given on the commandline */ if (putenv (infostr)) @@ -994,7 +1008,7 @@ main (int argc, char **argv ) } close (fd); } - + return 0; } @@ -1235,6 +1249,7 @@ start_connection_thread (void *arg) return NULL; } + static void * start_connection_thread_ssh (void *arg) { @@ -1268,7 +1283,12 @@ handle_connections (int listen_fd, int listen_fd_ssh) int ret = -1; int fd; - sigemptyset (&sigs); + tattr = pth_attr_new(); + pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0); + pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 64); + pth_attr_set (tattr, PTH_ATTR_NAME, "gpg-agent"); + + sigemptyset (&sigs ); sigaddset (&sigs, SIGHUP); sigaddset (&sigs, SIGUSR1); sigaddset (&sigs, SIGUSR2); @@ -1276,11 +1296,6 @@ handle_connections (int listen_fd, int listen_fd_ssh) sigaddset (&sigs, SIGTERM); ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo); - tattr = pth_attr_new(); - pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0); - pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 32*1024); - pth_attr_set (tattr, PTH_ATTR_NAME, "gpg-agent"); - FD_ZERO (&fdset); FD_SET (listen_fd, &fdset); if (listen_fd_ssh != -1) @@ -1370,4 +1385,58 @@ handle_connections (int listen_fd, int listen_fd_ssh) cleanup (); log_info ("%s %s stopped\n", strusage(11), strusage(13)); } + #endif /*USE_GNU_PTH*/ + + +/* Figure out whether an agent is available and running. Prints an + error if not. */ +static void +check_for_running_agent () +{ + int rc; + char *infostr, *p; + assuan_context_t ctx; + int prot, pid; + + infostr = getenv ("GPG_AGENT_INFO"); + if (!infostr || !*infostr) + { + log_error (_("no gpg-agent running in this session\n")); + return; + } + + infostr = xstrdup (infostr); + if ( !(p = strchr (infostr, ':')) || p == infostr) + { + log_error (_("malformed GPG_AGENT_INFO environment variable\n")); + xfree (infostr); + return; + } + + *p++ = 0; + pid = atoi (p); + while (*p && *p != ':') + p++; + prot = *p? atoi (p+1) : 0; + if (prot != 1) + { + log_error (_("gpg-agent protocol version %d is not supported\n"), + prot); + xfree (infostr); + return; + } + + rc = assuan_socket_connect (&ctx, infostr, pid); + xfree (infostr); + if (rc) + { + log_error ("can't connect to the agent: %s\n", assuan_strerror (rc)); + return; + } + + if (!opt.quiet) + log_info ("gpg-agent running and available\n"); + + assuan_disconnect (ctx); +} |