Reworked passing of envars to Pinentry.
authorWerner Koch <wk@gnupg.org>
Tue, 7 Jul 2009 10:02:41 +0000 (10:02 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 7 Jul 2009 10:02:41 +0000 (10:02 +0000)
31 files changed:
NEWS
agent/ChangeLog
agent/agent.h
agent/call-pinentry.c
agent/command-ssh.c
agent/command.c
agent/gpg-agent.c
agent/protect-tool.c
common/ChangeLog
common/Makefile.am
common/asshelp.c
common/asshelp.h
common/get-passphrase.c
common/get-passphrase.h
common/session-env.c [new file with mode: 0644]
common/session-env.h [new file with mode: 0644]
common/t-exechelp.c
common/t-session-env.c [new file with mode: 0644]
doc/gpgsm.texi
g10/ChangeLog
g10/call-agent.c
g10/gpg.c
g10/options.h
sm/ChangeLog
sm/call-agent.c
sm/gpgsm.c
sm/gpgsm.h
sm/misc.c
sm/server.c
tools/ChangeLog
tools/gpg-connect-agent.c

diff --git a/NEWS b/NEWS
index b08e250..aa3e6d5 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,14 +1,15 @@
 Noteworthy changes in version 2.0.13
 -------------------------------------------------
 
- This is a BETA version!
-
- * Minor bug fixes.
+ * The envvars XMODIFIERS, GTK_IM_MODULE and QT_IM_MODULE are now
+   passed to the Pinentry to make SCIM work.
 
  * gpgsm --gen-key implements a --batch mode.
 
  * gpgsm --gen-key implements all features of gpgsm-gencert.sh.
 
+ * Minor bug fixes.
+
 
 Noteworthy changes in version 2.0.12 (2009-06-17)
 -------------------------------------------------
index 4829ff2..d0c1a7f 100644 (file)
@@ -1,3 +1,21 @@
+2009-07-06  Werner Koch  <wk@g10code.com>
+
+       * agent.h: Include session-env.h.
+       (opt): Replace most of the startup_xxx fields by a session_env_t.
+       (struct server_control_s): Likewise.
+       * gpg-agent.c (main): Rewrite setting of the startup fields.
+       (handle_connections, main): Allocate SESSION_ENV.
+       (agent_init_default_ctrl, agent_deinit_default_ctrl): Change
+       accordingly.
+       * command.c (option_handler): Ditto.
+       (cmd_updatestartuptty): Change accordingly.  Protect old values
+       from out of core failures.
+       * command-ssh.c (start_command_handler_ssh): Ditto.
+       (start_command_handler_ssh): Replace strdup by xtrystrdup.
+       * call-pinentry.c (atfork_cb): Pass new envrinmnet variables.
+       (start_pinentry): Use session_env stuff.
+       * protect-tool.c (main): Adjust call to gnupg_prepare_get_passphrase.
+
 2009-06-24  Werner Koch  <wk@g10code.com>
 
        * genkey.c (agent_protect_and_store): Return RC and not 0.
index 323c1c1..c7d8e02 100644 (file)
@@ -33,6 +33,7 @@
 #include "../common/util.h"
 #include "../common/membuf.h"
 #include "../common/sysutils.h" /* (gnupg_fd_t) */
+#include "../common/session-env.h"
 
 /* To convey some special hash algorithms we use algorithm numbers
    reserved for application use. */
@@ -56,13 +57,9 @@ struct
 
   /* Environment setting gathered at program start or changed using the
      Assuan command UPDATESTARTUPTTY. */
-  char *startup_display;
-  char *startup_ttyname;
-  char *startup_ttytype;
+  session_env_t startup_env;
   char *startup_lc_ctype;
   char *startup_lc_messages;
-  char *startup_xauthority;   
-  char *startup_pinentry_user_data; 
 
 
   const char *pinentry_program; /* Filename of the program to start as
@@ -142,13 +139,10 @@ struct server_control_s
   /* Private data of the SCdaemon (call-scd.c). */
   struct scd_local_s *scd_local;
 
-  char *display;
-  char *ttyname;
-  char *ttytype;
+  session_env_t session_env;
   char *lc_ctype;
   char *lc_messages;
-  char *xauthority;   
-  char *pinentry_user_data; 
+
   struct {
     int algo;
     unsigned char value[MAX_DIGEST_LEN];
index b956ef4..5e9685f 100644 (file)
@@ -172,14 +172,30 @@ atfork_cb (void *opaque, int where)
 
   if (!where)
     {
+      int iterator = 0;
+      const char *name, *assname, *value;
+      
       gcry_control (GCRYCTL_TERM_SECMEM);
-      if (ctrl->xauthority)
-        setenv ("XAUTHORITY", ctrl->xauthority, 1);
-      if (ctrl->pinentry_user_data)
-        setenv ("PINENTRY_USER_DATA", ctrl->pinentry_user_data, 1 );
+
+      while ((name = session_env_list_stdenvnames (&iterator, &assname)))
+        {
+          /* For all new envvars (!ASSNAME) and the two medium old
+             ones which do have an assuan name but are conveyed using
+             environment variables, update the environment of the
+             forked process.  */
+          if (!assname 
+              || !strcmp (name, "XAUTHORITY")
+              || !strcmp (name, "PINENTRY_USER_DATA"))
+            {
+              value = session_env_getenv (ctrl->session_env, name);
+              if (value)
+                setenv (name, value, 1);
+            }
+        }
     }
 }
 
+
 static int
 getinfo_pid_cb (void *opaque, const void *buffer, size_t length)
 {
@@ -214,6 +230,7 @@ start_pinentry (ctrl_t ctrl)
   pth_event_t evt;
   const char *tmpstr;
   unsigned long pinentry_pid;
+  const char *value;
 
   evt = pth_event (PTH_EVENT_TIME, pth_timeout (LOCK_TIMEOUT, 0));
   if (!pth_mutex_acquire (&entry_lock, 0, evt))
@@ -273,10 +290,11 @@ start_pinentry (ctrl_t ctrl)
   argv[0] = pgmname;
 #endif /*__APPLE__*/
 
-  if (ctrl->display && !opt.keep_display)
+  if (!opt.keep_display
+      && (value = session_env_getenv (ctrl->session_env, "DISPLAY")))
     {
       argv[1] = "--display";
-      argv[2] = ctrl->display;
+      argv[2] = value;
       argv[3] = NULL;
     }
   else
@@ -313,10 +331,12 @@ start_pinentry (ctrl_t ctrl)
                         NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc)
     return unlock_pinentry (rc);
-  if (ctrl->ttyname)
+
+  value = session_env_getenv (ctrl->session_env, "GPG_TTY");
+  if (value)
     {
       char *optstr;
-      if (asprintf (&optstr, "OPTION ttyname=%s", ctrl->ttyname) < 0 )
+      if (asprintf (&optstr, "OPTION ttyname=%s", value) < 0 )
        return unlock_pinentry (out_of_core ());
       rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
                            NULL);
@@ -324,10 +344,11 @@ start_pinentry (ctrl_t ctrl)
       if (rc)
        return unlock_pinentry (rc);
     }
-  if (ctrl->ttytype)
+  value = session_env_getenv (ctrl->session_env, "TERM");
+  if (value)
     {
       char *optstr;
-      if (asprintf (&optstr, "OPTION ttytype=%s", ctrl->ttytype) < 0 )
+      if (asprintf (&optstr, "OPTION ttytype=%s", value) < 0 )
        return unlock_pinentry (out_of_core ());
       rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
                            NULL);
index 76f310a..12fe60a 100644 (file)
@@ -2906,27 +2906,39 @@ ssh_request_process (ctrl_t ctrl, estream_t stream_sock)
 void
 start_command_handler_ssh (ctrl_t ctrl, gnupg_fd_t sock_client)
 {
-  estream_t stream_sock;
-  gpg_error_t err;
+  estream_t stream_sock = NULL;
+  gpg_error_t err = 0;
   int ret;
 
   /* Because the ssh protocol does not send us information about the
      the current TTY setting, we resort here to use those from startup
      or those explictly set.  */
-  if (!ctrl->display && opt.startup_display)
-    ctrl->display = strdup (opt.startup_display);
-  if (!ctrl->ttyname && opt.startup_ttyname)
-    ctrl->ttyname = strdup (opt.startup_ttyname);
-  if (!ctrl->ttytype && opt.startup_ttytype)
-    ctrl->ttytype = strdup (opt.startup_ttytype);
-  if (!ctrl->lc_ctype && opt.startup_lc_ctype)
-    ctrl->lc_ctype = strdup (opt.startup_lc_ctype);
-  if (!ctrl->lc_messages && opt.startup_lc_messages)
-    ctrl->lc_messages = strdup (opt.startup_lc_messages);
-  if (!ctrl->xauthority && opt.startup_xauthority)
-    ctrl->xauthority = strdup (opt.startup_xauthority);
-  if (!ctrl->pinentry_user_data && opt.startup_pinentry_user_data)
-    ctrl->pinentry_user_data = strdup (opt.startup_pinentry_user_data);
+  {
+    static const char *names[] = 
+      {"GPG_TTY", "DISPLAY", "TERM", "XAUTHORITY", "PINENTRY_USER_DATA", NULL};
+    int idx;
+    const char *value;
+
+    for (idx=0; !err && names[idx]; idx++)
+      if (!session_env_getenv (ctrl->session_env, names[idx])
+          && (value = session_env_getenv (opt.startup_env, names[idx])))
+        err = session_env_setenv (ctrl->session_env, names[idx], value);
+    
+    if (!err && !ctrl->lc_ctype && opt.startup_lc_ctype)
+      if (!(ctrl->lc_ctype = xtrystrdup (opt.startup_lc_ctype)))
+        err = gpg_error_from_syserror ();
+
+    if (!err && !ctrl->lc_messages && opt.startup_lc_messages)
+      if (!(ctrl->lc_messages = xtrystrdup (opt.startup_lc_messages)))
+        err = gpg_error_from_syserror ();
+
+    if (err)
+      {
+        log_error ("error setting default session environment: %s\n", 
+                   gpg_strerror (err));
+        goto out;
+      }
+  }
 
 
   /* Create stream from socket.  */
index 9238a22..e3de085 100644 (file)
@@ -1520,33 +1520,53 @@ cmd_putval (assuan_context_t ctx, char *line)
 static int
 cmd_updatestartuptty (assuan_context_t ctx, char *line)
 {
+  static const char *names[] = 
+    { "GPG_TTY", "DISPLAY", "TERM", "XAUTHORITY", "PINENTRY_USER_DATA", NULL };
   ctrl_t ctrl = assuan_get_pointer (ctx);
-
+  gpg_error_t err = 0;
+  session_env_t se;
+  int idx;
+  char *lc_ctype = NULL;
+  char *lc_messages = NULL;
+  
   (void)line;
 
-  xfree (opt.startup_display); opt.startup_display = NULL;
-  xfree (opt.startup_ttyname); opt.startup_ttyname = NULL;
-  xfree (opt.startup_ttytype); opt.startup_ttytype = NULL;
-  xfree (opt.startup_lc_ctype); opt.startup_lc_ctype = NULL;
-  xfree (opt.startup_lc_messages); opt.startup_lc_messages = NULL;
-  xfree (opt.startup_xauthority); opt.startup_xauthority = NULL;
-
-  if (ctrl->display)
-    opt.startup_display = xtrystrdup (ctrl->display);
-  if (ctrl->ttyname)
-    opt.startup_ttyname = xtrystrdup (ctrl->ttyname);
-  if (ctrl->ttytype)
-    opt.startup_ttytype = xtrystrdup (ctrl->ttytype);
-  if (ctrl->lc_ctype) 
-    opt.startup_lc_ctype = xtrystrdup (ctrl->lc_ctype);
-  if (ctrl->lc_messages)
-    opt.startup_lc_messages = xtrystrdup (ctrl->lc_messages);
-  if (ctrl->xauthority)
-    opt.startup_xauthority = xtrystrdup (ctrl->xauthority);
-  if (ctrl->pinentry_user_data)
-    opt.startup_pinentry_user_data = xtrystrdup (ctrl->pinentry_user_data);
+  se = session_env_new ();
+  if (!se)
+    err = gpg_error_from_syserror ();
 
-  return 0;
+  for (idx=0; !err && names[idx]; idx++)
+    {
+      const char *value = session_env_getenv (ctrl->session_env, names[idx]);
+      if (value)
+        err = session_env_setenv (se, names[idx], value);
+    }
+
+  if (!err && ctrl->lc_ctype) 
+    if (!(lc_ctype = xtrystrdup (ctrl->lc_ctype)))
+      err = gpg_error_from_syserror ();
+
+  if (!err && ctrl->lc_messages)
+    if (!(lc_messages = xtrystrdup (ctrl->lc_messages)))
+      err = gpg_error_from_syserror ();
+   
+  if (err)
+    {
+      session_env_release (se);
+      xfree (lc_ctype);
+      xfree (lc_messages);
+    }
+  else
+    {
+      session_env_release (opt.startup_env);
+      opt.startup_env = se;
+      xfree (opt.startup_lc_ctype);
+      opt.startup_lc_ctype = lc_ctype;
+      xfree (opt.startup_lc_messages);
+      opt.startup_lc_messages = lc_messages;
+    }
+
+  return err;
 }
 
 
@@ -1680,36 +1700,31 @@ static int
 option_handler (assuan_context_t ctx, const char *key, const char *value)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
+  gpg_error_t err = 0;
 
-  if (!strcmp (key, "display"))
+  if (!strcmp (key, "putenv"))
     {
-      if (ctrl->display)
-        xfree (ctrl->display);
-      ctrl->display = xtrystrdup (value);
-      if (!ctrl->display)
-        return out_of_core ();
+      /* Change the session's environment to be used for the
+         Pinentry.  Valid values are:
+          <NAME>            Delete envvar NAME
+          <KEY>=            Set envvar NAME to the empty string
+          <KEY>=<VALUE>     Set envvar NAME to VALUE
+      */
+      err = session_env_putenv (ctrl->session_env, value);
+    }
+  else if (!strcmp (key, "display"))
+    {
+      err = session_env_setenv (ctrl->session_env, "DISPLAY", value);
     }
   else if (!strcmp (key, "ttyname"))
     {
       if (!opt.keep_tty)
-        {
-          if (ctrl->ttyname)
-            xfree (ctrl->ttyname);
-          ctrl->ttyname = xtrystrdup (value);
-          if (!ctrl->ttyname)
-            return out_of_core ();
-        }
+        err = session_env_setenv (ctrl->session_env, "GPG_TTY", value);
     }
   else if (!strcmp (key, "ttytype"))
     {
       if (!opt.keep_tty)
-        {
-          if (ctrl->ttytype)
-            xfree (ctrl->ttytype);
-          ctrl->ttytype = xtrystrdup (value);
-          if (!ctrl->ttytype)
-            return out_of_core ();
-        }
+        err = session_env_setenv (ctrl->session_env, "TERM", value);
     }
   else if (!strcmp (key, "lc-ctype"))
     {
@@ -1729,28 +1744,20 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
     }
   else if (!strcmp (key, "xauthority"))
     {
-      if (ctrl->xauthority)
-        xfree (ctrl->xauthority);
-      ctrl->xauthority = xtrystrdup (value);
-      if (!ctrl->xauthority)
-        return out_of_core ();
+      err = session_env_setenv (ctrl->session_env, "XAUTHORITY", value);
     }
   else if (!strcmp (key, "pinentry-user-data"))
     {
-      if (ctrl->pinentry_user_data)
-        xfree (ctrl->pinentry_user_data);
-      ctrl->pinentry_user_data = xtrystrdup (value);
-      if (!ctrl->pinentry_user_data)
-        return out_of_core ();
+      err = session_env_setenv (ctrl->session_env, "PINENTRY_USER_DATA", value);
     }
   else if (!strcmp (key, "use-cache-for-signing"))
     ctrl->server_local->use_cache_for_signing = *value? atoi (value) : 0;
   else if (!strcmp (key, "allow-pinentry-notify"))
     ctrl->server_local->allow_pinentry_notify = 1;
   else
-    return gpg_error (GPG_ERR_UNKNOWN_OPTION);
+    err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
 
-  return 0;
+  return err;
 }
 
 
index eccf445..31d79d5 100644 (file)
@@ -609,28 +609,40 @@ main (int argc, char **argv )
   opt.homedir = default_homedir ();
 
   /* Record some of the original environment strings. */
-  opt.startup_display = getenv ("DISPLAY");
-  if (opt.startup_display)
-    opt.startup_display = xstrdup (opt.startup_display);
-  opt.startup_ttyname = ttyname (0);
-  if (opt.startup_ttyname)
-    opt.startup_ttyname = xstrdup (opt.startup_ttyname);
-  opt.startup_ttytype = getenv ("TERM");
-  if (opt.startup_ttytype)
-    opt.startup_ttytype = xstrdup (opt.startup_ttytype);
-  /* 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);
-  opt.startup_lc_messages = getenv ("LC_MESSAGES");
-  if (opt.startup_lc_messages)
-    opt.startup_lc_messages = xstrdup (opt.startup_lc_messages);
-  opt.startup_xauthority = getenv ("XAUTHORITY");
-  if (opt.startup_xauthority)
-    opt.startup_xauthority = xstrdup (opt.startup_xauthority);
-  opt.startup_pinentry_user_data = getenv ("PINENTRY_USER_DATA");
-  if (opt.startup_pinentry_user_data)
-    opt.startup_pinentry_user_data = xstrdup (opt.startup_pinentry_user_data);
+  {
+    const char *s;
+    int idx;
+    static const char *names[] = 
+      { "DISPLAY", "TERM", "XAUTHORITY", "PINENTRY_USER_DATA", NULL };
+
+    err = 0;
+    opt.startup_env = session_env_new ();
+    if (!opt.startup_env)
+      err = gpg_error_from_syserror ();
+    for (idx=0; !err && names[idx]; idx++)
+      {
+        s = getenv (names[idx]);
+        if (s)
+          err = session_env_setenv (opt.startup_env, names[idx], s);
+      }
+    if (!err)
+      {
+        s = ttyname (0);
+        if (s)
+          err = session_env_setenv (opt.startup_env, "GPG_TTY", s);
+      }
+    if (err)
+      log_fatal ("error recording startup environment: %s\n",
+                 gpg_strerror (err));
+    
+    /* 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);
+    opt.startup_lc_messages = getenv ("LC_MESSAGES");
+    if (opt.startup_lc_messages)
+      opt.startup_lc_messages = xstrdup (opt.startup_lc_messages);
+  }
 
   /* Check whether we have a config file on the commandline */
   orig_argc = argc;
@@ -924,6 +936,14 @@ main (int argc, char **argv )
                      strerror (errno) );
           agent_exit (1);
         }
+      ctrl->session_env = session_env_new ();
+      if (!ctrl->session_env)
+        {
+          log_error ("error allocating session environment block: %s\n",
+                     strerror (errno) );
+          xfree (ctrl);
+          agent_exit (1);
+        }
       agent_init_default_ctrl (ctrl);
       start_command_handler (ctrl, GNUPG_INVALID_FD, GNUPG_INVALID_FD);
       agent_deinit_default_ctrl (ctrl);
@@ -1218,63 +1238,43 @@ agent_exit (int rc)
   exit (rc);
 }
 
+
 static void
 agent_init_default_ctrl (ctrl_t ctrl)
 {
   /* Note we ignore malloc errors because we can't do much about it
      and the request will fail anyway shortly after this
      initialization. */
-  if (ctrl->display)
-    xfree (ctrl->display);
-  ctrl->display = default_display? xtrystrdup (default_display) : NULL;
-
-  if (ctrl->ttyname)
-    xfree (ctrl->ttyname);
-  ctrl->ttyname = default_ttyname? xtrystrdup (default_ttyname) : NULL;
-
-  if (ctrl->ttytype)
-    xfree (ctrl->ttytype);
-  ctrl->ttytype = default_ttytype? xtrystrdup (default_ttytype) : NULL;
-
+  session_env_setenv (ctrl->session_env, "DISPLAY", default_display);
+  session_env_setenv (ctrl->session_env, "GPG_TTY", default_ttyname);
+  session_env_setenv (ctrl->session_env, "TERM", default_ttytype);
+  session_env_setenv (ctrl->session_env, "XAUTHORITY", default_xauthority);
+  session_env_setenv (ctrl->session_env, "PINENTRY_USER_DATA", NULL);
+  
   if (ctrl->lc_ctype)
     xfree (ctrl->lc_ctype);
   ctrl->lc_ctype = default_lc_ctype? xtrystrdup (default_lc_ctype) : NULL;
-
+  
   if (ctrl->lc_messages)
     xfree (ctrl->lc_messages);
   ctrl->lc_messages = default_lc_messages? xtrystrdup (default_lc_messages)
                                     /**/ : NULL;
 
-  if (ctrl->xauthority)
-    xfree (ctrl->xauthority);
-  ctrl->xauthority = default_xauthority? xtrystrdup (default_xauthority)
-                                   /**/: NULL;
-
-  if (ctrl->pinentry_user_data)
-    xfree (ctrl->pinentry_user_data);
-  ctrl->pinentry_user_data = NULL;
 }
 
 
 static void
 agent_deinit_default_ctrl (ctrl_t ctrl)
 {
-  if (ctrl->display)
-    xfree (ctrl->display);
-  if (ctrl->ttyname)
-    xfree (ctrl->ttyname);
-  if (ctrl->ttytype)
-    xfree (ctrl->ttytype);
+  session_env_release (ctrl->session_env);
+
   if (ctrl->lc_ctype)
     xfree (ctrl->lc_ctype);
   if (ctrl->lc_messages)
     xfree (ctrl->lc_messages);
-  if (ctrl->xauthority)
-    xfree (ctrl->xauthority);
-  if (ctrl->pinentry_user_data)
-    xfree (ctrl->pinentry_user_data);
 }
 
+
 /* Reread parts of the configuration.  Note, that this function is
    obviously not thread-safe and should only be called from the PTH
    signal handler. 
@@ -1961,6 +1961,13 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
                          strerror (errno) );
               assuan_sock_close (fd);
             }
+          else if ( !(ctrl->session_env = session_env_new ()) )
+            {
+              log_error ("error allocating session environment block: %s\n",
+                         strerror (errno) );
+              xfree (ctrl);
+              assuan_sock_close (fd);
+            }
           else 
             {
               char threadname[50];
@@ -1999,6 +2006,13 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
                          strerror (errno) );
               assuan_sock_close (fd);
             }
+          else if ( !(ctrl->session_env = session_env_new ()) )
+            {
+              log_error ("error allocating session environment block: %s\n",
+                         strerror (errno) );
+              xfree (ctrl);
+              assuan_sock_close (fd);
+            }
           else
             {
               char threadname[50];
index 0e48124..27f4f9d 100644 (file)
@@ -1086,7 +1086,7 @@ main (int argc, char **argv )
                                 opt.verbose,
                                 opt_homedir,
                                 opt_agent_program,
-                                NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+                                NULL, NULL, NULL);
 
   if (opt_prompt)
     opt_prompt = percent_plus_unescape (opt_prompt, 0);
index 40faa54..75c79c6 100644 (file)
@@ -1,3 +1,20 @@
+2009-07-06  Werner Koch  <wk@g10code.com>
+
+       * get-passphrase.c (struct agentargs): Add SESSION_ENV and remove
+       obsolete args.
+       (gnupg_prepare_get_passphrase): Ditto.
+
+       * session-env.c, session-env.h: New.
+       * t-session-env.c: New.
+       * Makefile.am (common_sources, module_tests): Add them.
+       * asshelp.h: Include "session-env.h"
+       * asshelp.c (send_one_option): Add arg PUTENV.
+       (send_pinentry_environment): Replace most args by SESSION_ENV and
+       rewrite fucntion.
+       (start_new_gpg_agent): Likewise.
+
+       * t-exechelp.c (test_close_all_fds): Remove debug code.
+
 2009-07-01  Werner Koch  <wk@g10code.com>
 
        * sexputil.c (get_pk_algo_from_canon_sexp): New.
index 2ef324e..dd3661d 100644 (file)
@@ -69,6 +69,7 @@ common_sources = \
        pka.c pka.h \
        http.c http.h \
        localename.c \
+       session-env.c session-env.h \
        helpfile.c
 
 # Sources only useful without PTH.
@@ -111,7 +112,8 @@ status-codes.h: Makefile mkstrtable.awk exstatus.awk status.h
 #
 # Module tests
 #
-module_tests = t-convert t-percent t-gettime t-sysutils t-sexputil t-exechelp
+module_tests = t-convert t-percent t-gettime t-sysutils t-sexputil t-exechelp \
+              t-session-env
 module_maint_tests = t-helpfile t-b64
 
 t_common_ldadd = libcommon.a ../jnlib/libjnlib.a ../gl/libgnu.a \
@@ -125,6 +127,5 @@ t_helpfile_LDADD = $(t_common_ldadd)
 t_sexputil_LDADD = $(t_common_ldadd)
 t_b64_LDADD = $(t_common_ldadd)
 t_exechelp_LDADD = $(t_common_ldadd)
-
-
+t_session_env_LDADD = $(t_common_ldadd)
 
index 6663241..b373baf 100644 (file)
@@ -1,5 +1,5 @@
 /* asshelp.c - Helper functions for Assuan
- * Copyright (C) 2002, 2004, 2007 Free Software Foundation, Inc.
+ * Copyright (C) 2002, 2004, 2007, 2009 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 #include "status.h" 
 #include "asshelp.h"
 
-
 static gpg_error_t
 send_one_option (assuan_context_t ctx, gpg_err_source_t errsource,
-                 const char *name, const char *value)
+                 const char *name, const char *value, int use_putenv)
 {
   gpg_error_t err;
   char *optstr;
@@ -46,7 +45,8 @@ send_one_option (assuan_context_t ctx, gpg_err_source_t errsource,
 
   if (!value || !*value)
     err = 0;  /* Avoid sending empty strings.  */
-  else if (asprintf (&optstr, "OPTION %s=%s", name, value ) < 0)
+  else if (asprintf (&optstr, "OPTION %s%s=%s", 
+                     use_putenv? "putenv=":"", name, value) < 0)
     err = gpg_error_from_syserror ();
   else
     {
@@ -64,57 +64,43 @@ send_one_option (assuan_context_t ctx, gpg_err_source_t errsource,
 gpg_error_t
 send_pinentry_environment (assuan_context_t ctx,
                            gpg_err_source_t errsource,
-                           const char *opt_display,
-                           const char *opt_ttyname,
-                           const char *opt_ttytype,
                            const char *opt_lc_ctype,
                            const char *opt_lc_messages,
-                           const char *opt_xauthority,
-                           const char *opt_pinentry_user_data)
+                           session_env_t session_env)
+
 {
   gpg_error_t err = 0;
-  char *dft_display = NULL;
-  char *dft_ttyname = NULL;
-  char *dft_ttytype = NULL;
   char *old_lc = NULL; 
   char *dft_lc = NULL;
-  char *dft_xauthority = NULL;
-  char *dft_pinentry_user_data = NULL;
+  const char *dft_ttyname;
+  int iterator;
+  const char *name, *assname, *value;
+  int is_default;
 
-  /* Send the DISPLAY variable.  */
-  dft_display = getenv ("DISPLAY");
-  if (opt_display || dft_display)
+  iterator = 0; 
+  while ((name = session_env_list_stdenvnames (&iterator, &assname)))
     {
-      err = send_one_option (ctx, errsource, "display", 
-                             opt_display ? opt_display : dft_display);
-      if (err)
-        return err;
-    }
+      value = session_env_getenv_or_default (session_env, name, NULL);
+      if (!value)
+        continue;
 
-  /* Send the name of the TTY.  */
-  if (!opt_ttyname)
-    {
-      dft_ttyname = getenv ("GPG_TTY");
-      if ((!dft_ttyname || !*dft_ttyname) && ttyname (0))
-        dft_ttyname = ttyname (0);
-    }
-  if (opt_ttyname || dft_ttyname)
-    {
-      err = send_one_option (ctx, errsource, "ttyname", 
-                             opt_ttyname ? opt_ttyname : dft_ttyname);
+      if (assname)
+        err = send_one_option (ctx, errsource, assname, value, 0);
+      else
+        {
+          err = send_one_option (ctx, errsource, name, value, 1);
+          if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
+            err = 0;  /* Server too old; can't pass the new envvars.  */
+        }
       if (err)
         return err;
     }
 
-  /* Send the type of the TTY.  */
-  dft_ttytype = getenv ("TERM");
-  if (opt_ttytype || (dft_ttyname && dft_ttytype))
-    {
-      err = send_one_option (ctx, errsource, "ttytype", 
-                             opt_ttyname ? opt_ttytype : dft_ttytype);
-      if (err)
-        return err;
-    }
+
+  dft_ttyname = session_env_getenv_or_default (session_env, "GPG_TTY", 
+                                               &is_default);
+  if (dft_ttyname && !is_default)
+    dft_ttyname = NULL;  /* We need the default value.  */
 
   /* Send the value for LC_CTYPE.  */
 #if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
@@ -130,7 +116,7 @@ send_pinentry_environment (assuan_context_t ctx,
   if (opt_lc_ctype || (dft_ttyname && dft_lc))
     {
       err = send_one_option (ctx, errsource, "lc-ctype", 
-                             opt_lc_ctype ? opt_lc_ctype : dft_lc);
+                             opt_lc_ctype ? opt_lc_ctype : dft_lc, 0);
     }
 #if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
   if (old_lc)
@@ -156,7 +142,7 @@ send_pinentry_environment (assuan_context_t ctx,
   if (opt_lc_messages || (dft_ttyname && dft_lc))
     {
       err = send_one_option (ctx, errsource, "lc-messages", 
-                             opt_lc_messages ? opt_lc_messages : dft_lc);
+                             opt_lc_messages ? opt_lc_messages : dft_lc, 0);
     }
 #if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
   if (old_lc)
@@ -168,31 +154,6 @@ send_pinentry_environment (assuan_context_t ctx,
   if (err)
     return err;
 
-  /* Send the XAUTHORITY variable.  */
-  dft_xauthority = getenv ("XAUTHORITY");
-  if (opt_xauthority || dft_xauthority)
-    {
-      err = send_one_option (ctx, errsource, "xauthority", 
-                             opt_xauthority ? opt_xauthority : dft_xauthority);
-      if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
-        err = 0;
-      if (err)
-        return err;
-    }
-
-  /* Send the PINENTRY_USER_DATA variable.  */
-  dft_pinentry_user_data = getenv ("PINENTRY_USER_DATA");
-  if (opt_pinentry_user_data || dft_pinentry_user_data)
-    {
-      err = send_one_option (ctx, errsource, "pinentry-user-data", 
-                             opt_pinentry_user_data ?
-                             opt_pinentry_user_data : dft_pinentry_user_data);
-      if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
-        err = 0;
-      if (err)
-        return err;
-    }
-
   return 0;
 }
 
@@ -205,13 +166,9 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
                      gpg_err_source_t errsource,
                      const char *homedir,
                      const char *agent_program,
-                     const char *opt_display,
-                     const char *opt_ttyname,
-                     const char *opt_ttytype,
                      const char *opt_lc_ctype,
                      const char *opt_lc_messages,
-                     const char *opt_xauthority,
-                     const char *opt_pinentry_user_data,
+                     session_env_t session_env,
                      int verbose, int debug,
                      gpg_error_t (*status_cb)(ctrl_t, int, ...),
                      ctrl_t status_cb_arg)
@@ -365,10 +322,8 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
                         NULL, NULL, NULL, NULL, NULL, NULL);
   if (!rc)
     rc = send_pinentry_environment (ctx, errsource,
-                                    opt_display, opt_ttyname, opt_ttytype,
                                     opt_lc_ctype, opt_lc_messages,
-                                    opt_xauthority,
-                                    opt_pinentry_user_data);
+                                    session_env);
   if (rc)
     {
       assuan_disconnect (ctx);
index dfed3ac..f7bc88b 100644 (file)
 #include <assuan.h>
 #include <gpg-error.h>
 
+#include "session-env.h"
+
 gpg_error_t
 send_pinentry_environment (assuan_context_t ctx,
                            gpg_err_source_t errsource,
-                           const char *opt_display,
-                           const char *opt_ttyname,
-                           const char *opt_ttytype,
                            const char *opt_lc_ctype,
                            const char *opt_lc_messages,
-                           const char *opt_xauthority,
-                           const char *opt_pinentry_user_data);
+                           session_env_t session_env);
 
 /* This fucntion is used by the call-agent.c modules to fire up a new
-   agent.  What a parameter list ;-).  */
+   agent.  */
 gpg_error_t
 start_new_gpg_agent (assuan_context_t *r_ctx,
                      gpg_err_source_t errsource,
                      const char *homedir,
                      const char *agent_program,
-                     const char *opt_display,
-                     const char *opt_ttyname,
-                     const char *opt_ttytype,
                      const char *opt_lc_ctype,
                      const char *opt_lc_messages,
-                     const char *opt_xauthority,
-                     const char *opt_pinentry_user_data,
+                     session_env_t session_env,
                      int verbose, int debug,
                      gpg_error_t (*status_cb)(ctrl_t, int, ...),
                      ctrl_t status_cb_arg);
index 68d7b70..e1a1148 100644 (file)
@@ -39,12 +39,9 @@ static struct
   int verbosity;
   const char *homedir;
   const char *agent_program;
-  const char *display;
-  const char *ttyname;
-  const char *ttytype;
   const char *lc_ctype;
   const char *lc_messages;
-  const char *xauthority;
+  session_env_t session_env;
   const char *pinentry_user_data;
 } agentargs;
 
@@ -57,25 +54,17 @@ gnupg_prepare_get_passphrase (gpg_err_source_t errsource,
                               int verbosity,
                               const char *homedir,
                               const char *agent_program,
-                              const char *opt_display,
-                              const char *opt_ttyname,
-                              const char *opt_ttytype,
                               const char *opt_lc_ctype,
                               const char *opt_lc_messages,
-                              const char *opt_xauthority,
-                              const char *opt_pinentry_user_data)
+                              session_env_t session_env)
 {
   agentargs.errsource          = errsource;
   agentargs.verbosity          = verbosity;
   agentargs.homedir            = homedir;
   agentargs.agent_program      = agent_program;
-  agentargs.display            = opt_display;
-  agentargs.ttyname            = opt_ttyname;
-  agentargs.ttytype            = opt_ttytype;
   agentargs.lc_ctype           = opt_lc_ctype;
   agentargs.lc_messages        = opt_lc_messages;
-  agentargs.xauthority         = opt_xauthority;
-  agentargs.pinentry_user_data = opt_pinentry_user_data;
+  agentargs.session_env        = session_env;
 }
 
 
@@ -96,13 +85,9 @@ start_agent (void)
                              agentargs.errsource,
                              agentargs.homedir,
                              agentargs.agent_program,
-                             agentargs.display, 
-                             agentargs.ttyname,
-                             agentargs.ttytype,
                              agentargs.lc_ctype,
                              agentargs.lc_messages,
-                             agentargs.xauthority,
-                             agentargs.pinentry_user_data,
+                             agentargs.session_env,
                              agentargs.verbosity, 0, NULL, NULL);
   if (!err)
     {
index 9457cdd..603ac81 100644 (file)
 #ifndef GNUPG_COMMON_GET_PASSPHRASE_H
 #define GNUPG_COMMON_GET_PASSPHRASE_H
 
+#include "session-env.h"
+
 void gnupg_prepare_get_passphrase (gpg_err_source_t errsource,
                                    int verbosity,
                                    const char *homedir,
                                    const char *agent_program,
-                                   const char *opt_display,
-                                   const char *opt_ttyname,
-                                   const char *opt_ttytype,
                                    const char *opt_lc_ctype,
                                    const char *opt_lc_messages,
-                                   const char *opt_xauthority,
-                                   const char *opt_pinentry_user_data);
+                                   session_env_t session_env);
 
 gpg_error_t gnupg_get_passphrase (const char *cache_id,
                                   const char *err_msg,
diff --git a/common/session-env.c b/common/session-env.c
new file mode 100644 (file)
index 0000000..ef36dbc
--- /dev/null
@@ -0,0 +1,384 @@
+/* se4ssiobn-env.c - session environment helper functions.
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <assert.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "session-env.h"
+
+
+struct variable_s
+{
+  char *value;    /* Pointer into NAME to the Nul terminated value. */
+  int is_default; /* The value is a default one.  */
+  char name[1];   /* Nul terminated Name and space for the value.  */
+};
+
+
+
+/* The session environment object.  */
+struct session_environment_s
+{
+  size_t arraysize;          /* Allocated size or ARRAY.  */
+  size_t arrayused;          /* Used size of ARRAY.  */
+  struct variable_s **array; /* Array of variables.  NULL slots are unused.  */
+};
+
+
+/* A list of environment vribales we pass from the acual user
+  (e.g. gpgme) down to the pinentry.  We do not handle the locale
+  settings because they do not only depend on envvars.  */
+static struct 
+{ 
+  const char *name;
+  const char *assname;  /* Name used by Assuan or NULL.  */
+} stdenvnames[] = {
+  { "GPG_TTY", "ttyname" },      /* GnuPG specific envvar.  */
+  { "TERM",    "ttytype" },      /* Used to set ttytype. */
+  { "DISPLAY", "display" },      /* The X-Display.  */
+  { "XAUTHORITY","xauthority"},  /* Xlib Authentication.  */
+  { "XMODIFIERS" },              /* Used by Xlib to select X input
+                                      modules (eg "@im=SCIM").  */
+  { "GTK_IM_MODULE" },           /* Used by gtk to select gtk input
+                                    modules (eg "scim-bridge").  */
+  { "QT_IM_MODULE" },            /* Used by Qt to select qt input
+                                      modules (eg "xim").  */
+  { "PINENTRY_USER_DATA", "pinentry-user-data"} 
+                                 /* Used for communication with
+                                    non-standard Pinentries.  */
+};
+
+
+/* Track last allocated arraysize of all objects ever created.  If
+   nothing has ever been allocated we use INITIAL_ARRAYSIZE and we
+   will never use more than MAXDEFAULT_ARRAYSIZE for initial
+   allocation.  Note that this is not reentrant if used with a
+   preemptive thread model.  */
+static size_t lastallocatedarraysize;
+#define INITIAL_ARRAYSIZE 8  /* Let's use the number of stdenvnames.  */
+#define CHUNK_ARRAYSIZE 10
+#define MAXDEFAULT_ARRAYSIZE (INITIAL_ARRAYSIZE + CHUNK_ARRAYSIZE * 5)
+
+
+/* Return the names of standard environment variables one after the
+   other.  The caller needs to set the value at the address of
+   ITERATOR initally to 0 and then call this function until it returns
+   NULL.  */
+const char *
+session_env_list_stdenvnames (int *iterator, const char **r_assname)
+{
+  int idx = *iterator;
+
+  if (idx < 0 || idx >= DIM (stdenvnames))
+    return NULL;
+  *iterator = idx + 1;
+  if (r_assname)
+    *r_assname = stdenvnames[idx].assname;
+  return stdenvnames[idx].name;
+}
+
+
+/* Create a new session environment object.  Return NULL and sets
+   ERRNO on failure. */
+session_env_t
+session_env_new (void)
+{
+  session_env_t se;
+
+  se = xtrycalloc (1, sizeof *se);
+  if (se)
+    {
+      se->arraysize = (lastallocatedarraysize? 
+                       lastallocatedarraysize : INITIAL_ARRAYSIZE);
+      se->array = xtrycalloc (se->arraysize, sizeof *se->array);
+      if (!se->array)
+        {
+          xfree (se);
+          se = NULL;
+        }
+    }
+
+  return se;
+}
+
+
+/* Release a session environment object.  */
+void
+session_env_release (session_env_t se)
+{
+  int idx;
+
+  if (!se)
+    return;
+
+  if (se->arraysize > INITIAL_ARRAYSIZE 
+      && se->arraysize <= MAXDEFAULT_ARRAYSIZE
+      && se->arraysize > lastallocatedarraysize)
+    lastallocatedarraysize = se->arraysize;
+
+  for (idx=0; idx < se->arrayused; idx++)
+    if (se->array[idx])
+      xfree (se->array[idx]);
+  xfree (se->array);
+  xfree (se);
+}
+
+
+static gpg_error_t
+delete_var (session_env_t se, const char *name)
+{
+  int idx;
+
+  for (idx=0; idx < se->arrayused; idx++)
+    if (se->array[idx] && !strcmp (se->array[idx]->name, name))
+      {
+        xfree (se->array[idx]);
+        se->array[idx] = NULL;
+      }
+  return 0;
+}
+
+
+static gpg_error_t
+update_var (session_env_t se, const char *string, size_t namelen,
+            const char *explicit_value, int set_default)
+{
+  int idx;
+  int freeidx = -1;
+  const char *value;
+  size_t valuelen;
+  struct variable_s *var;
+
+  if (explicit_value)
+    value = explicit_value;
+  else
+    value = string + namelen + 1;
+  valuelen = strlen (value);
+
+  for (idx=0; idx < se->arrayused; idx++)
+    {
+      if (!se->array[idx])
+        freeidx = idx;
+      else if (!strncmp (se->array[idx]->name, string, namelen)
+               && strlen (se->array[idx]->name) == namelen)
+        {
+          /* Check if the value is the same; no need to update it,
+             except for updating the default flag.  */
+          if (strlen (se->array[idx]->value) == valuelen)
+            {
+              se->array[idx]->is_default = !!set_default;
+              return 0;
+            }
+          /* Prepare for update.  */
+          freeidx = idx;
+        }
+    }
+
+  if (freeidx == -1)
+    {
+      if (se->arrayused == se->arraysize)
+        {
+          /* Reallocate the array. */
+          size_t newsize;
+          struct variable_s **newarray;
+
+          newsize = se->arraysize + CHUNK_ARRAYSIZE;
+          newarray = xtrycalloc (newsize, sizeof *newarray);
+          if (!newarray)
+            return gpg_error_from_syserror ();
+          for (idx=0; idx < se->arrayused; idx++)
+            newarray[idx] = se->array[idx];
+          se->arraysize = newsize;
+          xfree (se->array);
+          se->array = newarray;
+        }
+      freeidx = se->arrayused++;
+    }
+
+  /* Allocate new memory and return an error if that didn't worked.
+     Allocating it first allows us to keep the old value; it doesn't
+     matter that arrayused has already been incremented in case of a
+     new entry - it will then pint to a NULL slot.  */
+  var = xtrymalloc (sizeof *var + namelen + 1 + valuelen);
+  if (!var)
+    return gpg_error_from_syserror ();
+  var->is_default = !!set_default;
+  memcpy (var->name, string, namelen);
+  var->name[namelen] = '\0';
+  var->value = var->name + namelen + 1;
+  strcpy (var->value, value);
+
+  xfree (se->array[freeidx]);
+  se->array[freeidx] = var;
+  return 0;
+}
+
+
+/* Set or update an environment variable of the session environment.
+   String is similar to the putval(3) function but it is reentrant and
+   takes a copy.  In particular it exhibits this behaviour:
+
+          <NAME>            Delete envvar NAME
+          <KEY>=            Set envvar NAME to the empty string
+          <KEY>=<VALUE>     Set envvar NAME to VALUE
+
+   On success 0 is returned; on error an gpg-error code.  */
+gpg_error_t
+session_env_putenv (session_env_t se, const char *string)
+{
+  const char *s;
+  
+  if (!string || !*string)
+    return gpg_error (GPG_ERR_INV_VALUE);
+  s = strchr (string, '=');
+  if (s == string)
+    return gpg_error (GPG_ERR_INV_VALUE);
+  if (!s)
+    return delete_var (se, string);
+  else
+    return update_var (se, string, s - string, NULL, 0);
+}
+
+
+/* Same as session_env_putenv but with name and value given as distict
+   values.  */
+gpg_error_t
+session_env_setenv (session_env_t se, const char *name, const char *value)
+{
+  if (!name || !*name)
+    return gpg_error (GPG_ERR_INV_VALUE);
+  if (!value)
+    return delete_var (se, name);
+  else
+    return update_var (se, name, strlen (name), value, 0);
+}
+
+
+
+
+/* Return the value of the environment variable NAME from the SE
+   object.  If the variable does not exist, NULL is returned.  The
+   returned value is valid as long as SE is valid and as long it has
+   not been removed or updated by a call to session_env_putenv.  The
+   caller MUST not change the returned value. */
+char *
+session_env_getenv (session_env_t se, const char *name)
+{
+  int idx;
+
+  if (!se || !name || !*name)
+    return NULL;
+
+  for (idx=0; idx < se->arrayused; idx++)
+    if (se->array[idx] && !strcmp (se->array[idx]->name, name))
+      return se->array[idx]->is_default? NULL : se->array[idx]->value;
+  return NULL;
+}
+
+
+/* Return the value of the environment variable NAME from the SE
+   object.  The returned value is valid as long as SE is valid and as
+   long it has not been removed or updated by a call to
+   session_env_putenv.  If the variable does not exist, the fucntion
+   tries to return the value trough a call to getenv; if that returns
+   a value, this value is recorded and and used.  If no value could be
+   found, returns NULL.  The caller must not change the returned
+   value. */
+char *
+session_env_getenv_or_default (session_env_t se, const char *name,
+                               int *r_default)
+{
+  int idx;
+  char *defvalue;
+
+  if (r_default)
+    *r_default = 0;
+  if (!se || !name || !*name)
+    return NULL;
+
+  for (idx=0; idx < se->arrayused; idx++)
+    if (se->array[idx] && !strcmp (se->array[idx]->name, name))
+      {
+        if (r_default && se->array[idx]->is_default)
+          *r_default = 1;
+        return se->array[idx]->value;
+      }
+  
+  /* Get the default value with and additional fallback for GPG_TTY.  */
+  defvalue = getenv (name);
+  if ((!defvalue || !*defvalue) && !strcmp (name, "GPG_TTY") && ttyname (0))
+    defvalue = ttyname (0);
+  if (defvalue)
+    {
+      /* Record the default value for later use so that we are safe
+         from later modifications of the environment.  We need to take
+         a copy to better cope with the rules of putenv(3).  We ignore
+         the error of the update function because we can't return an
+         explicit error anyway and the following scan would then fail
+         anyway. */
+      update_var (se, name, strlen (name), defvalue, 1);
+      
+      for (idx=0; idx < se->arrayused; idx++)
+        if (se->array[idx] && !strcmp (se->array[idx]->name, name))
+          {
+            if (r_default && se->array[idx]->is_default)
+              *r_default = 1;
+            return se->array[idx]->value;
+          }
+    }
+
+  return NULL;
+}
+
+
+/* List the entire environment stored in SE.  The caller initially
+   needs to set the value of ITERATOR to 0 and then call this function
+   until it returns NULL.  The value is retruned at R_VALUE.  If
+   R_DEFAULT is not NULL, the default flag is stored on return.  The
+   default flag indicates that the value has been taken from the
+   process' environment.  The caller must not change the returned
+   name or value.  */ 
+char *
+session_env_listenv (session_env_t se, int *iterator,
+                     const char **r_value, int *r_default)
+{
+  int idx = *iterator;
+
+  if (!se || idx < 0)
+    return NULL;
+
+  for (; idx < se->arrayused; idx++)
+    if (se->array[idx])
+      {
+        *iterator = idx+1;
+        if (r_default)
+          *r_default = se->array[idx]->is_default;
+        if (r_value)
+          *r_value = se->array[idx]->value;
+        return se->array[idx]->name;
+      }
+  return NULL;
+}
+
+
diff --git a/common/session-env.h b/common/session-env.h
new file mode 100644 (file)
index 0000000..031fe1d
--- /dev/null
@@ -0,0 +1,43 @@
+/* session-env.h - Definitions for session environment functions
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_SESSION_ENV_H
+#define GNUPG_COMMON_SESSION_ENV_H
+
+struct session_environment_s;
+typedef struct session_environment_s *session_env_t;
+
+const char *session_env_list_stdenvnames (int *iterator, 
+                                          const char **r_assname);
+
+session_env_t session_env_new (void);
+void session_env_release (session_env_t se);
+
+gpg_error_t session_env_putenv (session_env_t se, const char *string);
+gpg_error_t session_env_setenv (session_env_t se, 
+                                const char *name, const char *value);
+
+char *session_env_getenv (session_env_t se, const char *name);
+char *session_env_getenv_or_default (session_env_t se, const char *name,
+                                     int *r_default);
+char *session_env_listenv (session_env_t se, int *iterator, 
+                           const char **r_value, int *r_default);
+
+
+#endif /*GNUPG_COMMON_SESSION_ENV_H*/
index 7ab6bbe..600379b 100644 (file)
@@ -69,7 +69,7 @@ xget_all_open_fds (void)
 
 /* That is a very crude test.  To do a proper test we would need to
    fork a test process and best return information by some other means
-   that file descriptors. */
+   than file descriptors. */
 static void
 test_close_all_fds (void)
 {
@@ -77,7 +77,7 @@ test_close_all_fds (void)
   int *array;
   int fd;
   int initial_count, count, n;
-#if 1
+#if 0
   char buffer[100];
 
   snprintf (buffer, sizeof buffer, "/bin/ls -l /proc/%d/fd", (int)getpid ());
diff --git a/common/t-session-env.c b/common/t-session-env.c
new file mode 100644 (file)
index 0000000..94b6683
--- /dev/null
@@ -0,0 +1,294 @@
+/* t-session-env.c - Module test for session-env.c
+ *     Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "util.h"
+#include "session-env.h"
+
+#define pass()  do { ; } while(0)
+#define fail(e) do { fprintf (stderr, "%s:%d: function failed: %s\n",  \
+                               __FILE__,__LINE__, gpg_strerror (e));  \
+                     exit (1);                                        \
+                   } while(0)
+
+static int verbose;
+
+static void
+listall (session_env_t se)
+{
+  int iterator = 0;
+  const char *name, *value;
+  int def;
+
+  if (verbose)
+    printf ("environment of %p\n", se);
+  while ( (name = session_env_listenv (se, &iterator, &value, &def)) )
+    if (verbose)
+      printf ("  %s%s=%s\n",  def? "[def] ":"      ", name, value);
+          
+}
+
+
+static void
+show_stdnames (void)
+{
+  const char *name, *assname;
+  int iterator = 0;
+
+  printf ("Known envvars:");
+  while ((name = session_env_list_stdenvnames (&iterator, &assname)))
+    {
+      printf ( " %s", name);
+      if (assname)
+        printf ( "(%s)", assname);
+    }
+  putchar('\n');
+}
+
+
+static void
+test_all (void)
+{
+  gpg_error_t err;
+  session_env_t se_0, se;
+  const char *s, *s2;
+  int idx;
+
+  se_0 = session_env_new ();
+  if (!se_0)
+    fail (gpg_error_from_syserror ());
+  se = session_env_new ();
+  if (!se)
+    fail (gpg_error_from_syserror ());
+
+  err = session_env_putenv (se, NULL);
+  if (gpg_err_code (err) != GPG_ERR_INV_VALUE)
+    fail (err);
+  err = session_env_putenv (se, "");
+  if (gpg_err_code (err) != GPG_ERR_INV_VALUE)
+    fail (err);
+  err = session_env_putenv (se, "=");
+  if (gpg_err_code (err) != GPG_ERR_INV_VALUE)
+    fail (err);
+
+  /* Delete some nonexistant variables.  */
+  err = session_env_putenv (se, "A");
+  if (err)
+    fail (err);
+  err = session_env_putenv (se, "a");
+  if (err)
+    fail (err);
+  err = session_env_putenv (se, "_aaaa aaaaaasssssssssssss\nddd");
+  if (err)
+    fail (err);
+
+  /* Create a few variables.  */
+  err = session_env_putenv (se, "EMPTY=");
+  if (err)
+    fail (err);
+  err = session_env_putenv (se, "foo=value_of_foo");
+  if (err)
+    fail (err);
+  err = session_env_putenv (se, "bar=the value_of_bar");
+  if (err)
+    fail (err);
+  err = session_env_putenv (se, "baz=this-is-baz");
+  if (err)
+    fail (err);
+  err = session_env_putenv (se, "BAZ=this-is-big-baz");
+  if (err)
+    fail (err);
+
+  listall (se);
+
+  /* Update one.  */
+  err = session_env_putenv (se, "baz=this-is-another-baz");
+  if (err)
+    fail (err);
+
+  listall (se);
+
+  /* Delete one.  */
+  err = session_env_putenv (se, "bar");
+  if (err)
+    fail (err);
+
+  listall (se);
+
+  /* Insert a new one.  */
+  err = session_env_putenv (se, "FOO=value_of_foo");
+  if (err)
+    fail (err);
+
+  listall (se);
+
+  /* Retrieve a default one.  */
+  s = session_env_getenv_or_default (se, "HOME", NULL);
+  if (!s)
+    {
+      fprintf (stderr, "failed to get default of HOME\n");
+      exit (1);
+    }
+      
+  s = session_env_getenv (se, "HOME");
+  if (s)
+    fail(0);  /* This is a default value, thus we should not see it.  */
+
+  s = session_env_getenv_or_default (se, "HOME", NULL);
+  if (!s)
+    fail(0);  /* But here we should see it.  */
+
+  /* Add a few more.  */
+  err = session_env_putenv (se, "X1=A value");
+  if (err)
+    fail (err);
+  err = session_env_putenv (se, "X2=Another value");
+  if (err)
+    fail (err);
+  err = session_env_putenv (se, "X3=A value");
+  if (err)
+    fail (err);
+
+  listall (se);
+
+  /* Check that we can overwrite a default value.  */
+  err = session_env_putenv (se, "HOME=/this/is/my/new/home");
+  if (err)
+    fail (err);
+  /* And that we get this string back.  */
+  s = session_env_getenv (se, "HOME");
+  if (!s)
+    fail (0);
+  if (strcmp (s, "/this/is/my/new/home"))
+    fail (0);
+  /* A new get default should return the very same string.  */
+  s2 = session_env_getenv_or_default (se, "HOME", NULL);
+  if (!s2)
+    fail (0);
+  if (s2 != s)
+    fail (0);
+
+  listall (se);
+
+  /* Check that the other object is clean.  */
+  {
+    int iterator = 0;
+    
+    if (session_env_listenv (se_0, &iterator, NULL, NULL))
+      fail (0);
+  }
+
+
+  session_env_release (se);
+
+  /* Use a new session for quick mass test.  */
+  se = session_env_new ();
+  if (!se)
+    fail (gpg_error_from_syserror ());
+
+  /* Create.  */
+  for (idx=0; idx < 500; idx++)
+    {
+      char buf[100];
+      
+      snprintf (buf, sizeof buf, "FOO_%d=Value for %x", idx, idx);
+      err = session_env_putenv (se, buf);
+      if (err)
+        fail (err);
+    }
+  err = session_env_setenv (se, "TEST1", "value1");
+  if (err)
+    fail (err);
+  err = session_env_setenv (se, "TEST1", "value1-updated");
+  if (err)
+    fail (err);
+
+  listall (se);
+
+  /* Delete all.  */
+  for (idx=0; idx < 500; idx++)
+    {
+      char buf[100];
+      
+      snprintf (buf, sizeof buf, "FOO_%d", idx);
+      err = session_env_putenv (se, buf);
+      if (err)
+        fail (err);
+    }
+  err = session_env_setenv (se, "TEST1", NULL);
+  if (err)
+    fail (err);
+
+  /* Check that all are deleted.  */
+  {
+    int iterator = 0;
+    
+    if (session_env_listenv (se, &iterator, NULL, NULL))
+      fail (0);
+  }
+
+  /* Add a few strings again.  */
+  for (idx=0; idx < 500; idx++)
+    {
+      char buf[100];
+      
+      if (!(idx % 10))
+        {
+          if ( !(idx % 3))
+            snprintf (buf, sizeof buf, "FOO_%d=", idx);
+          else
+            snprintf (buf, sizeof buf, "FOO_%d=new value for %x", idx, idx);
+          err = session_env_putenv (se, buf);
+          if (err)
+            fail (err);
+        }
+    }
+
+  listall (se);
+  
+  session_env_release (se);
+
+  session_env_release (se_0);
+}
+
+
+
+int
+main (int argc, char **argv)
+{
+  if (argc)
+    { argc--; argv++; }
+  if (argc && !strcmp (argv[0], "--verbose"))
+    {
+      verbose = 1;
+      argc--; argv++;
+    }
+
+
+  show_stdnames ();
+  test_all ();
+
+  return 0;
+}
+
index d189813..e784f71 100644 (file)
@@ -167,8 +167,8 @@ use @samp{--help} to get a list of supported operations.
 @opindex gen-key
 This command allows the creation of a certificate signing request.  It
 is commonly used along with the @option{--output} option to save the
-created CSR into a file.  If used with the @option{--batch} the signing
-is requested from a parameter file.
+created CSR into a file.  If used with the @option{--batch} a parameter
+file is used to create the CSR.
 
 @item --list-keys
 @itemx -k 
index fcf7590..ca1b53d 100644 (file)
@@ -1,6 +1,18 @@
+2009-07-07  Werner Koch  <wk@g10code.com>
+
+       * gpg.c (set_opt_session_env): New.
+       (main): Allocate opt.session_env.  Use it for oDisplay, oTTYname,
+       oTTYtype and oXauthority.
+
+       * options.h: Include session_env.h.
+       (opt): Add field SESSION_ENV, remove obsolete fields.
+       
+       * call-agent.c (start_agent): Adjust start_new_gpg_agent for
+       changed args.
+
 2009-06-24  Werner Koch  <wk@g10code.com>
 
-       * keyedit.c (menu_select_key): Renmove dead assign to I.
+       * keyedit.c (menu_select_key): Remove dead assign to I.
        (menu_select_uid): Ditto.
        * keyring.c (keyring_search): Remove dead assign to NAME.
        * card-util.c (card_edit): Remove useless DID_CHECKPIN.
index 0590514..071be2a 100644 (file)
@@ -91,9 +91,8 @@ start_agent (void)
                             GPG_ERR_SOURCE_DEFAULT,
                             opt.homedir,
                             opt.agent_program,
-                            opt.display, opt.ttyname, opt.ttytype,
                             opt.lc_ctype, opt.lc_messages,
-                            opt.xauthority, opt.pinentry_user_data,
+                            opt.session_env,
                             opt.verbose, DBG_ASSUAN,
                             NULL, NULL);
   if (!rc)
index 00d9034..1e902aa 100644 (file)
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -955,6 +955,17 @@ make_username( const char *string )
 }
 
 
+static void
+set_opt_session_env (const char *name, const char *value)
+{
+  gpg_error_t err;
+  
+  err = session_env_setenv (opt.session_env, name, value);
+  if (err)
+    log_fatal ("error setting session environment: %s\n",
+               gpg_strerror (err));
+}
+
 /* Setup the debugging.  With a LEVEL of NULL only the active debug
    flags are propagated to the subsystems.  With LEVEL set, a specific
    set of debug flags is set; thus overriding all flags already
@@ -1935,6 +1946,10 @@ main (int argc, char **argv)
 
     create_dotlock(NULL); /* Register locking cleanup. */
 
+    opt.session_env = session_env_new ();
+    if (!opt.session_env)
+      log_fatal ("error allocating session environment block: %s\n",
+                 strerror (errno));
 
     opt.command_fd = -1; /* no command fd */
     opt.compress_level = -1; /* defaults to standard compress level */
@@ -2820,12 +2835,23 @@ main (int argc, char **argv)
            pers_compress_list=pargs.r.ret_str;
            break;
           case oAgentProgram: opt.agent_program = pargs.r.ret_str;  break;
-          case oDisplay: opt.display = pargs.r.ret_str; break;
-          case oTTYname: opt.ttyname = pargs.r.ret_str; break;
-          case oTTYtype: opt.ttytype = pargs.r.ret_str; break;
+
+          case oDisplay:
+            set_opt_session_env ("DISPLAY", pargs.r.ret_str);
+            break;
+          case oTTYname:
+            set_opt_session_env ("GPG_TTY", pargs.r.ret_str);
+            break;
+          case oTTYtype:
+            set_opt_session_env ("TERM", pargs.r.ret_str);
+            break;
+          case oXauthority:
+            set_opt_session_env ("XAUTHORITY", pargs.r.ret_str);
+            break;
+
           case oLCctype: opt.lc_ctype = pargs.r.ret_str; break;
           case oLCmessages: opt.lc_messages = pargs.r.ret_str; break;
-          case oXauthority: opt.xauthority = pargs.r.ret_str; break;
+
          case oGroup: add_group(pargs.r.ret_str); break;
          case oUnGroup: rm_group(pargs.r.ret_str); break;
          case oNoGroups:
index 40bd230..a99ca22 100644 (file)
@@ -24,6 +24,7 @@
 #include <types.h>
 #include "main.h"
 #include "packet.h"
+#include "../common/session-env.h"
 
 #ifndef EXTERN_UNLESS_MAIN_MODULE
 /* Norcraft can't cope with common symbols */
@@ -85,13 +86,11 @@ struct
   int max_cert_depth;
   const char *homedir;
   const char *agent_program; 
-  char *display;      /* 5 options to be passed to the gpg-agent */
-  char *ttyname;     
-  char *ttytype;
+
+  /* Options to be passed to the gpg-agent */
+  session_env_t session_env;
   char *lc_ctype;
   char *lc_messages;
-  char *xauthority;
-  char *pinentry_user_data;
 
   int skip_verify;
   int compress_keys;
index 2167915..a2c0675 100644 (file)
@@ -1,3 +1,15 @@
+2009-07-07  Werner Koch  <wk@g10code.com>
+
+       * gpgsm.h: Include session-env.h.
+       (opt): Add field SESSION_ENV.  Remove obsolete fields.
+       * server.c (option_handler): Rewrite setting of option fields.
+       Replace strdup by xtrystrdup.
+       * gpgsm.c (set_opt_session_env): New.
+       (main): Use it for oDisplay, oTTYname, oTTYtype and oXauthority.
+       * call-agent.c (start_agent): Adjust start_new_gpg_agent for
+       changed args.
+       * misc.c (setup_pinentry_env): Use new session_env stuff.
+
 2009-07-02  Werner Koch  <wk@g10code.com>
 
        * certreqgen-ui.c (gpgsm_gencertreq_tty): Allow using a key from a
index 777c44c..47e45ab 100644 (file)
@@ -85,9 +85,8 @@ start_agent (ctrl_t ctrl)
                                 GPG_ERR_SOURCE_DEFAULT,
                                 opt.homedir,
                                 opt.agent_program,
-                                opt.display, opt.ttyname, opt.ttytype,
                                 opt.lc_ctype, opt.lc_messages,
-                                opt.xauthority, opt.pinentry_user_data,
+                                opt.session_env,
                                 opt.verbose, DBG_ASSUAN,
                                 gpgsm_status2, ctrl);
       
index 6b2684a..b5f18d7 100644 (file)
@@ -196,7 +196,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_c (aListSecretKeys, "list-secret-keys", N_("list secret keys")),
   ARGPARSE_c (aListChain,   "list-chain",  N_("list certificate chain")), 
   ARGPARSE_c (aFingerprint, "fingerprint", N_("list keys and fingerprints")),
-  ARGPARSE_c (aKeygen, "gen-key", "@"),
+  ARGPARSE_c (aKeygen, "gen-key", N_("generate a new key pair")),
   ARGPARSE_c (aDeleteKey, "delete-keys", 
               N_("remove keys from the public keyring")),
   ARGPARSE_c (aSendKeys, "send-keys", N_("export keys to a key server")),
@@ -614,6 +614,18 @@ wrong_args (const char *text)
 }
 
 
+static void
+set_opt_session_env (const char *name, const char *value)
+{
+  gpg_error_t err;
+  
+  err = session_env_setenv (opt.session_env, name, value);
+  if (err)
+    log_fatal ("error setting session environment: %s\n",
+               gpg_strerror (err));
+}
+
+
 /* Setup the debugging.  With a DEBUG_LEVEL of NULL only the active
    debug flags are propagated to the subsystems.  With DEBUG_LEVEL
    set, a specific set of debug flags is set; and individual debugging
@@ -890,6 +902,11 @@ main ( int argc, char **argv)
   
   create_dotlock (NULL); /* register locking cleanup */
 
+  opt.session_env = session_env_new ();
+  if (!opt.session_env)
+    log_fatal ("error allocating session environment block: %s\n",
+               strerror (errno));
+
   /* Note: If you change this default cipher algorithm , please
      remember to update the Gpgconflist entry as well.  */
   opt.def_cipher_algoid = "3DES";  /*des-EDE3-CBC*/
@@ -943,7 +960,7 @@ main ( int argc, char **argv)
   memset (&ctrl, 0, sizeof ctrl);
   gpgsm_init_default_ctrl (&ctrl);
   ctrl.no_server = 1;
-  ctrl.status_fd = -1; /* not status output */
+  ctrl.status_fd = -1; /* No status output. */
   ctrl.autodetect_encoding = 1;
 
   /* Set the default option file */
@@ -1208,12 +1225,23 @@ main ( int argc, char **argv)
         case oNoOptions: break; /* no-options */
         case oHomedir: opt.homedir = pargs.r.ret_str; break;
         case oAgentProgram: opt.agent_program = pargs.r.ret_str;  break;
-        case oDisplay: opt.display = xstrdup (pargs.r.ret_str); break;
-        case oTTYname: opt.ttyname = xstrdup (pargs.r.ret_str); break;
-        case oTTYtype: opt.ttytype = xstrdup (pargs.r.ret_str); break;
+
+        case oDisplay:
+          set_opt_session_env ("DISPLAY", pargs.r.ret_str);
+          break;
+        case oTTYname:
+          set_opt_session_env ("GPG_TTY", pargs.r.ret_str);
+          break;
+        case oTTYtype:
+          set_opt_session_env ("TERM", pargs.r.ret_str);
+          break;
+        case oXauthority:
+          set_opt_session_env ("XAUTHORITY", pargs.r.ret_str);
+          break;
+
         case oLCctype: opt.lc_ctype = xstrdup (pargs.r.ret_str); break;
         case oLCmessages: opt.lc_messages = xstrdup (pargs.r.ret_str); break;
-        case oXauthority: opt.xauthority = xstrdup (pargs.r.ret_str); break;
+
         case oDirmngrProgram: opt.dirmngr_program = pargs.r.ret_str;  break;
         case oDisableDirmngr: opt.disable_dirmngr = 1;  break;
         case oPreferSystemDirmngr: opt.prefer_system_dirmngr = 1; break;
@@ -1357,7 +1385,7 @@ main ( int argc, char **argv)
   if (log_get_errorcount(0))
     gpgsm_exit(2);
 
-  /* Now that we have the optiosn parsed we need to update the default
+  /* Now that we have the options parsed we need to update the default
      control structure.  */
   gpgsm_init_default_ctrl (&ctrl);
 
index d2c38fb..900e6dd 100644 (file)
@@ -1,5 +1,5 @@
 /* gpgsm.h - Global definitions for GpgSM
- * Copyright (C) 2001, 2003, 2004, 2007 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2003, 2004, 2007, 2009 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -32,6 +32,8 @@
 #include "../common/status.h"
 #include "../common/estream.h"
 #include "../common/audit.h"
+#include "../common/session-env.h"
+
 
 #define MAX_DIGEST_LEN 64
 
@@ -61,13 +63,10 @@ struct
   const char *homedir;         /* Configuration directory name */
   const char *config_filename; /* Name of the used config file. */
   const char *agent_program; 
-  char *display;
-  char *ttyname;
-  char *ttytype;
+
+  session_env_t session_env;
   char *lc_ctype;
   char *lc_messages;
-  char *xauthority;
-  char *pinentry_user_data;
 
   const char *dirmngr_program;
   int prefer_system_dirmngr;  /* Prefer using a system wide drimngr.  */
index 3899472..628b321 100644 (file)
--- a/sm/misc.c
+++ b/sm/misc.c
@@ -1,5 +1,5 @@
 /* misc.c - Miscellaneous fucntions
- *     Copyright (C) 2004 Free Software Foundation, Inc.
+ * Copyright (C) 2004, 2009 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -40,16 +40,16 @@ setup_pinentry_env (void)
 {
 #ifndef HAVE_W32_SYSTEM
   char *lc;
-
-  if (opt.display)
-    setenv ("DISPLAY", opt.display, 1);
+  const char *name, *value;
+  int iterator;
 
   /* Try to make sure that GPG_TTY has been set.  This is needed if we
      call for example the protect-tools with redirected stdin and thus
      it won't be able to ge a default by itself.  Try to do it here
      but print a warning.  */
-  if (opt.ttyname)
-    setenv ("GPG_TTY", opt.ttyname, 1);
+  value = session_env_getenv (opt.session_env, "GPG_TTY");
+  if (value)
+    setenv ("GPG_TTY", value, 1);
   else if (!(lc=getenv ("GPG_TTY")) || !*lc)
     {
       log_error (_("GPG_TTY has not been set - "
@@ -60,9 +60,6 @@ setup_pinentry_env (void)
       setenv ("GPG_TTY", lc, 1);
     }
 
-  if (opt.ttytype)
-    setenv ("TERM", opt.ttytype, 1);
-
   if (opt.lc_ctype)
     setenv ("LC_CTYPE", opt.lc_ctype, 1);
 #if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
@@ -77,11 +74,15 @@ setup_pinentry_env (void)
     setenv ("LC_MESSAGES", lc, 1);
 #endif
 
-  if (opt.xauthority)
-    setenv ("XAUTHORITY", opt.xauthority, 1);
-
-  if (opt.pinentry_user_data)
-    setenv ("PINENTRY_USER_DATA", opt.pinentry_user_data, 1);
+  iterator = 0;
+  while ((name = session_env_list_stdenvnames (&iterator, NULL)))
+    {
+      if (!strcmp (name, "GPG_TTY"))
+        continue;  /* Already set.  */
+      value = session_env_getenv (opt.session_env, name);
+      if (value)
+        setenv (name, value, 1);
+    }
 
 #endif /*!HAVE_W32_SYSTEM*/
 }
index dfd4f69..7ba5b68 100644 (file)
@@ -183,69 +183,59 @@ static int
 option_handler (assuan_context_t ctx, const char *key, const char *value)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
+  gpg_error_t err = 0;
 
-  if (!strcmp (key, "include-certs"))
+  if (!strcmp (key, "putenv"))
     {
-      int i = *value? atoi (value) : -1;
-      if (ctrl->include_certs < -2)
-        return gpg_error (GPG_ERR_ASS_PARAMETER);
-      ctrl->include_certs = i;
+      /* Change the session's environment to be used for the
+         Pinentry.  Valid values are:
+          <NAME>            Delete envvar NAME
+          <KEY>=            Set envvar NAME to the empty string
+          <KEY>=<VALUE>     Set envvar NAME to VALUE
+      */
+      err = session_env_putenv (opt.session_env, value);
     }
   else if (!strcmp (key, "display"))
     {
-      if (opt.display)
-        free (opt.display);
-      opt.display = strdup (value);
-      if (!opt.display)
-        return out_of_core ();
+      err = session_env_setenv (opt.session_env, "DISPLAY", value);
     }
   else if (!strcmp (key, "ttyname"))
     {
-      if (opt.ttyname)
-        free (opt.ttyname);
-      opt.ttyname = strdup (value);
-      if (!opt.ttyname)
-        return out_of_core ();
+      err = session_env_setenv (opt.session_env, "GPG_TTY", value);
     }
   else if (!strcmp (key, "ttytype"))
     {
-      if (opt.ttytype)
-        free (opt.ttytype);
-      opt.ttytype = strdup (value);
-      if (!opt.ttytype)
-        return out_of_core ();
+      err = session_env_setenv (opt.session_env, "TERM", value);
     }
   else if (!strcmp (key, "lc-ctype"))
     {
-      if (opt.lc_ctype)
-        free (opt.lc_ctype);
-      opt.lc_ctype = strdup (value);
+      xfree (opt.lc_ctype);
+      opt.lc_ctype = xtrystrdup (value);
       if (!opt.lc_ctype)
-        return out_of_core ();
+        err = gpg_error_from_syserror ();
     }
   else if (!strcmp (key, "lc-messages"))
     {
-      if (opt.lc_messages)
-        free (opt.lc_messages);
-      opt.lc_messages = strdup (value);
+      xfree (opt.lc_messages);
+      opt.lc_messages = xtrystrdup (value);
       if (!opt.lc_messages)
-        return out_of_core ();
+        err = gpg_error_from_syserror ();
     }
   else if (!strcmp (key, "xauthority"))
     {
-      if (opt.xauthority)
-        free (opt.xauthority);
-      opt.xauthority = strdup (value);
-      if (!opt.xauthority)
-        return out_of_core ();
+      err = session_env_setenv (opt.session_env, "XAUTHORITY", value);
     }
   else if (!strcmp (key, "pinentry-user-data"))
     {
-      if (opt.pinentry_user_data)
-        free (opt.pinentry_user_data);
-      opt.pinentry_user_data = strdup (value);
-      if (!opt.pinentry_user_data)
-        return out_of_core ();
+      err = session_env_setenv (opt.session_env, "PINENTRY_USER_DATA", value);
+    }
+  else if (!strcmp (key, "include-certs"))
+    {
+      int i = *value? atoi (value) : -1;
+      if (ctrl->include_certs < -2)
+        err = gpg_error (GPG_ERR_ASS_PARAMETER);
+      else
+        ctrl->include_certs = i;
     }
   else if (!strcmp (key, "list-mode"))
     {
@@ -266,7 +256,7 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
           ctrl->server_local->list_external = 1;
         }
       else
-        return gpg_error (GPG_ERR_ASS_PARAMETER);
+        err = gpg_error (GPG_ERR_ASS_PARAMETER);
     }
   else if (!strcmp (key, "list-to-output"))
     {
@@ -284,7 +274,7 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
       if ( i >= 0 && i <= 1 )
         ctrl->validation_model = i;
       else
-        return gpg_error (GPG_ERR_ASS_PARAMETER);
+        err = gpg_error (GPG_ERR_ASS_PARAMETER);
     }
   else if (!strcmp (key, "with-key-data"))
     {
@@ -296,7 +286,9 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
       ctrl->server_local->enable_audit_log = i;
     }
   else if (!strcmp (key, "allow-pinentry-notify"))
-    ctrl->server_local->allow_pinentry_notify = 1;
+    {
+      ctrl->server_local->allow_pinentry_notify = 1;
+    }
   else if (!strcmp (key, "with-ephemeral-keys"))
     {
       int i = *value? atoi (value) : 0;
@@ -307,9 +299,9 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
       ctrl->server_local->no_encrypt_to = 1;
     }
   else
-    return gpg_error (GPG_ERR_UNKNOWN_OPTION);
+    err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
 
-  return 0;
+  return err;
 }
 
 
index 5f716e3..fceb649 100644 (file)
@@ -1,3 +1,8 @@
+2009-07-07  Werner Koch  <wk@g10code.com>
+
+       * gpg-connect-agent.c (start_agent): Adjust for changed args of
+       send_pinentry_environment.
+
 2009-06-30  Werner Koch  <wk@g10code.com>
 
        * ccidmon.c (parse_line_sniffusb): Take also TAB as delimiter.
        * watchgnupg.c: New.
 
 
- Copyright 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+ Copyright 2003, 2004, 2005, 2006, 2007, 2008,
+          2009 Free Software Foundation, Inc.
 
  This file is free software; as a special exception the author gives
  unlimited permission to copy and/or distribute it, with or without
index 06dafd5..90f54a4 100644 (file)
@@ -2079,6 +2079,12 @@ start_agent (void)
   int rc = 0;
   char *infostr, *p;
   assuan_context_t ctx;
+  session_env_t session_env;
+
+  session_env = session_env_new ();
+  if (!session_env)
+    log_fatal ("error allocating session environment block: %s\n",
+               strerror (errno));
 
   infostr = getenv ("GPG_AGENT_INFO");
   if (!infostr || !*infostr)
@@ -2169,7 +2175,7 @@ start_agent (void)
     }
 
   rc = send_pinentry_environment (ctx, GPG_ERR_SOURCE_DEFAULT,
-                                  NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+                                  NULL, NULL, session_env);
   if (rc)
     {
       log_error (_("error sending standard options: %s\n"), gpg_strerror (rc));