Updated FSF's address.
[gnupg.git] / agent / gpg-agent.c
index 4ac995c..fc2a200 100644 (file)
@@ -16,7 +16,8 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
  */
 
 #include <config.h>
@@ -48,6 +49,7 @@
 #ifdef HAVE_W32_SYSTEM
 #include "../jnlib/w32-afunix.h"
 #endif
+#include "setenv.h"
 
 
 enum cmd_and_opt_values 
@@ -82,7 +84,9 @@ enum cmd_and_opt_values
   oLCmessages,
   oScdaemonProgram,
   oDefCacheTTL,
+  oDefCacheTTLSSH,
   oMaxCacheTTL,
+  oMaxCacheTTLSSH,
   oUseStandardSocket,
   oNoUseStandardSocket,
 
@@ -92,7 +96,8 @@ enum cmd_and_opt_values
   oKeepTTY,
   oKeepDISPLAY,
   oSSHSupport,
-  oDisableScdaemon
+  oDisableScdaemon,
+  oWriteEnvFile
 };
 
 
@@ -138,7 +143,9 @@ static ARGPARSE_OPTS opts[] = {
 
   { oDefCacheTTL, "default-cache-ttl", 4,
                                N_("|N|expire cached PINs after N seconds")},
+  { oDefCacheTTLSSH, "default-cache-ttl-ssh", 4, "@" },
   { oMaxCacheTTL, "max-cache-ttl", 4, "@" },
+  { oMaxCacheTTLSSH, "max-cache-ttl-ssh", 4, "@" },
   { oIgnoreCacheForSigning, "ignore-cache-for-signing", 0,
                                N_("do not use the PIN cache when signing")},
   { oAllowMarkTrusted, "allow-mark-trusted", 0,
@@ -146,12 +153,15 @@ static ARGPARSE_OPTS opts[] = {
   { oAllowPresetPassphrase, "allow-preset-passphrase", 0,
                              N_("allow presetting passphrase")},
   { oSSHSupport, "enable-ssh-support", 0, N_("enable ssh-agent emulation") },
+  { oWriteEnvFile, "write-env-file", 2|8,
+            N_("|FILE|write environment settings also to FILE")},
   {0}
 };
 
 
-#define DEFAULT_CACHE_TTL (10*60)  /* 10 minutes */
-#define MAX_CACHE_TTL     (120*60) /* 2 hours */
+#define DEFAULT_CACHE_TTL     (10*60)  /* 10 minutes */
+#define DEFAULT_CACHE_TTL_SSH (30*60)  /* 30 minutes */
+#define MAX_CACHE_TTL         (120*60) /* 2 hours */
 
 
 /* flag to indicate that a shutdown was requested */
@@ -363,7 +373,9 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
       opt.pinentry_program = NULL;
       opt.scdaemon_program = NULL;
       opt.def_cache_ttl = DEFAULT_CACHE_TTL;
+      opt.def_cache_ttl_ssh = DEFAULT_CACHE_TTL_SSH;
       opt.max_cache_ttl = MAX_CACHE_TTL;
+      opt.max_cache_ttl_ssh = MAX_CACHE_TTL;
       opt.ignore_cache_for_signing = 0;
       opt.allow_mark_trusted = 0;
       opt.disable_scdaemon = 0;
@@ -398,7 +410,9 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
     case oDisableScdaemon: opt.disable_scdaemon = 1; break;
 
     case oDefCacheTTL: opt.def_cache_ttl = pargs->r.ret_ulong; break;
+    case oDefCacheTTLSSH: opt.def_cache_ttl_ssh = pargs->r.ret_ulong; break;
     case oMaxCacheTTL: opt.max_cache_ttl = pargs->r.ret_ulong; break;
+    case oMaxCacheTTLSSH: opt.max_cache_ttl_ssh = pargs->r.ret_ulong; break;
       
     case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break;
 
@@ -409,6 +423,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
     default:
       return 0; /* not handled */
     }
+
   return 1; /* handled */
 }
 
@@ -437,6 +452,7 @@ main (int argc, char **argv )
   int gpgconf_list = 0;
   int standard_socket = 0;
   gpg_error_t err;
+  const char *env_file_name = NULL;
 
   set_strusage (my_strusage);
   gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
@@ -490,7 +506,7 @@ main (int argc, char **argv )
 
   opt.homedir = default_homedir ();
 
-  /* Record the some original Denvironment settings. */
+  /* Record some of the original environment strings. */
   opt.startup_display = getenv ("DISPLAY");
   if (opt.startup_display)
     opt.startup_display = xstrdup (opt.startup_display);
@@ -500,7 +516,7 @@ main (int argc, char **argv )
   opt.startup_ttytype = getenv ("TERM");
   if (opt.startup_ttytype)
     opt.startup_ttytype = xstrdup (opt.startup_ttytype);
-  /* Fixme: Neen to use the locale fucntion here.  */
+  /* Fixme: Better use the locale function here.  */
   opt.startup_lc_ctype = getenv ("LC_CTYPE");
   if (opt.startup_lc_ctype) 
     opt.startup_lc_ctype = xstrdup (opt.startup_lc_ctype);
@@ -618,6 +634,12 @@ main (int argc, char **argv )
         case oKeepDISPLAY: opt.keep_display = 1; break;
 
        case oSSHSupport:  opt.ssh_support = 1; break;
+        case oWriteEnvFile:
+          if (pargs.r_type)
+            env_file_name = pargs.r.ret_str;
+          else
+            env_file_name = make_filename ("~/.gpg-agent-info", NULL);
+          break;
 
         default : pargs.err = configfp? 1:2; break;
        }
@@ -776,9 +798,11 @@ main (int argc, char **argv )
       /* Remove the DISPLAY variable so that a pinentry does not
          default to a specific display.  There is still a default
          display when gpg-agent was started using --display or a
-         client requested this using an OPTION command. */
+         client requested this using an OPTION command.  Note, that we
+         don't do this when running in reverse daemon mode (i.e. when
+         exec the program given as arguments). */
 #ifndef HAVE_W32_SYSTEM
-      if (!opt.keep_display)
+      if (!opt.keep_display && !argc)
         unsetenv ("DISPLAY");
 #endif
 
@@ -852,6 +876,29 @@ main (int argc, char **argv )
          if (opt.ssh_support)
            *socket_name_ssh = 0;
 
+          if (env_file_name)
+            {
+              FILE *fp;
+              
+              fp = fopen (env_file_name, "w");
+              if (!fp)
+                log_error (_("error creating `%s': %s\n"),
+                             env_file_name, strerror (errno));
+              else
+                {
+                  fputs (infostr, fp);
+                  putc ('\n', fp);
+                  if (opt.ssh_support)
+                    {
+                      fputs (infostr_ssh_sock, fp);
+                      putc ('\n', fp);
+                      fputs (infostr_ssh_pid, fp);
+                      putc ('\n', fp);
+                    }
+                  fclose (fp);
+                }
+            }
+
 
           if (argc) 
             { /* Run the program given on the commandline.  */
@@ -1270,6 +1317,11 @@ create_directories (void)
 static void
 handle_tick (void)
 {
+  /* Check whether the scdaemon has died and cleanup in this case. */
+  agent_scd_check_aliveness ();
+
+  /* If we are running as a child of another process, check whether
+     the parent is still alive and shutdown if not. */
 #ifndef HAVE_W32_SYSTEM
   if (parent_pid != (pid_t)(-1))
     {
@@ -1301,7 +1353,10 @@ handle_signal (int signo)
       break;
       
     case SIGUSR1:
-      log_info ("SIGUSR1 received - no action defined\n");
+      log_info ("SIGUSR1 received - printing internal information:\n");
+      pth_ctrl (PTH_CTRL_DUMPSTATE, log_get_stream ());
+      agent_query_dump_state ();
+      agent_scd_dump_state ();
       break;
       
     case SIGUSR2:
@@ -1344,7 +1399,8 @@ start_connection_thread (void *arg)
   int fd = (int)arg;
 
   if (opt.verbose)
-    log_info (_("handler for fd %d started\n"), fd);
+    log_info (_("handler 0x%lx for fd %d started\n"), 
+              (long)pth_self (), fd);
 
   /* FIXME: Move this housekeeping into a ticker function.  Calling it
      for each connection should work but won't work anymore if our
@@ -1353,7 +1409,8 @@ start_connection_thread (void *arg)
 
   start_command_handler (-1, fd);
   if (opt.verbose)
-    log_info (_("handler for fd %d terminated\n"), fd);
+    log_info (_("handler 0x%lx for fd %d terminated\n"), 
+              (long)pth_self (), fd);
   
   return NULL;
 }
@@ -1366,13 +1423,15 @@ start_connection_thread_ssh (void *arg)
   int fd = (int)arg;
 
   if (opt.verbose)
-    log_info (_("ssh handler for fd %d started\n"), fd);
+    log_info (_("ssh handler 0x%lx for fd %d started\n"),
+              (long)pth_self (), fd);
 
   agent_trustlist_housekeeping ();
 
   start_command_handler_ssh (fd);
   if (opt.verbose)
-    log_info (_("ssh handler for fd %d terminated\n"), fd);
+    log_info (_("ssh handler 0x%lx for fd %d terminated\n"),
+              (long)pth_self (), fd);
   
   return NULL;
 }
@@ -1396,15 +1455,17 @@ handle_connections (int listen_fd, int listen_fd_ssh)
   tattr = pth_attr_new();
   pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
   pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024);
-  pth_attr_set (tattr, PTH_ATTR_NAME, "gpg-agent");
 
 #ifndef HAVE_W32_SYSTEM /* fixme */
+  /* Make sure that the signals we are going to handle are not blocked
+     and create an event object for them. */
   sigemptyset (&sigs );
   sigaddset (&sigs, SIGHUP);
   sigaddset (&sigs, SIGUSR1);
   sigaddset (&sigs, SIGUSR2);
   sigaddset (&sigs, SIGINT);
   sigaddset (&sigs, SIGTERM);
+  pth_sigmask (SIG_UNBLOCK, &sigs, NULL);
   ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
 #else
   ev = NULL;
@@ -1418,6 +1479,8 @@ handle_connections (int listen_fd, int listen_fd_ssh)
 
   for (;;)
     {
+      sigset_t oldsigs;
+
       if (shutdown_pending)
         {
           if (pth_ctrl (PTH_CTRL_GETTHREADS) == 1)
@@ -1479,6 +1542,12 @@ handle_connections (int listen_fd, int listen_fd_ssh)
           handle_tick ();
         }
 
+      
+      /* We now might create new threads and because we don't want any
+         signals - we are handling here - to be delivered to a new
+         thread. Thus we need to block those signals. */
+      pth_sigmask (SIG_BLOCK, &sigs, &oldsigs);
+
       if (FD_ISSET (listen_fd, &read_fdset))
        {
           plen = sizeof paddr;
@@ -1487,12 +1556,20 @@ handle_connections (int listen_fd, int listen_fd_ssh)
            {
              log_error ("accept failed: %s\n", strerror (errno));
            }
-          else if (!pth_spawn (tattr, start_connection_thread, (void*)fd))
-           {
-             log_error ("error spawning connection handler: %s\n",
-                        strerror (errno) );
-             close (fd);
-           }
+          else 
+            {
+              char threadname[50];
+              snprintf (threadname, sizeof threadname-1,
+                        "conn fd=%d (gpg)", fd);
+              threadname[sizeof threadname -1] = 0;
+              pth_attr_set (tattr, PTH_ATTR_NAME, threadname);
+              if (!pth_spawn (tattr, start_connection_thread, (void*)fd))
+                {
+                  log_error ("error spawning connection handler: %s\n",
+                             strerror (errno) );
+                  close (fd);
+                }
+            }
           fd = -1;
        }
 
@@ -1504,14 +1581,27 @@ handle_connections (int listen_fd, int listen_fd_ssh)
            {
              log_error ("accept failed for ssh: %s\n", strerror (errno));
            }
-          else if (!pth_spawn (tattr, start_connection_thread_ssh, (void*)fd))
-           {
-             log_error ("error spawning ssh connection handler: %s\n",
-                        strerror (errno) );
-             close (fd);
-           }
+          else
+            {
+              char threadname[50];
+              snprintf (threadname, sizeof threadname-1,
+                        "conn fd=%d (ssh)", fd);
+              threadname[sizeof threadname -1] = 0;
+              pth_attr_set (tattr, PTH_ATTR_NAME, threadname);
+
+              if (!pth_spawn (tattr, start_connection_thread_ssh, (void*)fd))
+                {
+                  log_error ("error spawning ssh connection handler: %s\n",
+                             strerror (errno) );
+                  close (fd);
+                }
+            }
           fd = -1;
        }
+
+      /* Restore the signal mask. */
+      pth_sigmask (SIG_SETMASK, &oldsigs, NULL);
+
     }
 
   pth_event_free (ev, PTH_FREE_ALL);