[svn] GnuPG - r5064 - in trunk: . agent common doc g10 sm tools

svn author wk cvs at cvs.gnupg.org
Tue Jul 7 12:02:43 CEST 2009


Author: wk
Date: 2009-07-07 12:02:41 +0200 (Tue, 07 Jul 2009)
New Revision: 5064

Added:
   trunk/common/session-env.c
   trunk/common/session-env.h
   trunk/common/t-session-env.c
Modified:
   trunk/NEWS
   trunk/agent/ChangeLog
   trunk/agent/agent.h
   trunk/agent/call-pinentry.c
   trunk/agent/command-ssh.c
   trunk/agent/command.c
   trunk/agent/gpg-agent.c
   trunk/agent/protect-tool.c
   trunk/common/ChangeLog
   trunk/common/Makefile.am
   trunk/common/asshelp.c
   trunk/common/asshelp.h
   trunk/common/get-passphrase.c
   trunk/common/get-passphrase.h
   trunk/common/t-exechelp.c
   trunk/doc/gpgsm.texi
   trunk/g10/ChangeLog
   trunk/g10/call-agent.c
   trunk/g10/gpg.c
   trunk/g10/options.h
   trunk/sm/ChangeLog
   trunk/sm/call-agent.c
   trunk/sm/gpgsm.c
   trunk/sm/gpgsm.h
   trunk/sm/misc.c
   trunk/sm/server.c
   trunk/tools/ChangeLog
   trunk/tools/gpg-connect-agent.c
Log:
Reworked passing of envars to Pinentry.


[The diff below has been truncated]

Modified: trunk/agent/ChangeLog
===================================================================
--- trunk/agent/ChangeLog	2009-07-06 21:33:34 UTC (rev 5063)
+++ trunk/agent/ChangeLog	2009-07-07 10:02:41 UTC (rev 5064)
@@ -1,3 +1,21 @@
+2009-07-06  Werner Koch  <wk at 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 at g10code.com>
 
 	* genkey.c (agent_protect_and_store): Return RC and not 0.

Modified: trunk/common/ChangeLog
===================================================================
--- trunk/common/ChangeLog	2009-07-06 21:33:34 UTC (rev 5063)
+++ trunk/common/ChangeLog	2009-07-07 10:02:41 UTC (rev 5064)
@@ -1,3 +1,20 @@
+2009-07-06  Werner Koch  <wk at 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 at g10code.com>
 
 	* sexputil.c (get_pk_algo_from_canon_sexp): New.

Modified: trunk/g10/ChangeLog
===================================================================
--- trunk/g10/ChangeLog	2009-07-06 21:33:34 UTC (rev 5063)
+++ trunk/g10/ChangeLog	2009-07-07 10:02:41 UTC (rev 5064)
@@ -1,6 +1,18 @@
+2009-07-07  Werner Koch  <wk at 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 at 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.

Modified: trunk/sm/ChangeLog
===================================================================
--- trunk/sm/ChangeLog	2009-07-06 21:33:34 UTC (rev 5063)
+++ trunk/sm/ChangeLog	2009-07-07 10:02:41 UTC (rev 5064)
@@ -1,3 +1,15 @@
+2009-07-07  Werner Koch  <wk at 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 at g10code.com>
 
 	* certreqgen-ui.c (gpgsm_gencertreq_tty): Allow using a key from a

Modified: trunk/tools/ChangeLog
===================================================================
--- trunk/tools/ChangeLog	2009-07-06 21:33:34 UTC (rev 5063)
+++ trunk/tools/ChangeLog	2009-07-07 10:02:41 UTC (rev 5064)
@@ -1,3 +1,8 @@
+2009-07-07  Werner Koch  <wk at g10code.com>
+
+	* gpg-connect-agent.c (start_agent): Adjust for changed args of
+	send_pinentry_environment.
+
 2009-06-30  Werner Koch  <wk at g10code.com>
 
 	* ccidmon.c (parse_line_sniffusb): Take also TAB as delimiter.
@@ -1022,7 +1027,8 @@
 	* 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

Modified: trunk/NEWS
===================================================================
--- trunk/NEWS	2009-07-06 21:33:34 UTC (rev 5063)
+++ trunk/NEWS	2009-07-07 10:02:41 UTC (rev 5064)
@@ -1,15 +1,16 @@
 Noteworthy changes in version 2.0.13
 -------------------------------------------------
 
- This is a BETA version!
+ * The envvars XMODIFIERS, GTK_IM_MODULE and QT_IM_MODULE are now
+   passed to the Pinentry to make SCIM work.
 
- * Minor bug fixes.
-
  * 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)
 -------------------------------------------------
 

Modified: trunk/agent/agent.h
===================================================================
--- trunk/agent/agent.h	2009-07-06 21:33:34 UTC (rev 5063)
+++ trunk/agent/agent.h	2009-07-07 10:02:41 UTC (rev 5064)
@@ -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 @@
 
   /* 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 @@
   /* 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];

Modified: trunk/agent/call-pinentry.c
===================================================================
--- trunk/agent/call-pinentry.c	2009-07-06 21:33:34 UTC (rev 5063)
+++ trunk/agent/call-pinentry.c	2009-07-07 10:02:41 UTC (rev 5064)
@@ -172,14 +172,30 @@
 
   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 @@
   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 @@
   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 @@
                         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 @@
       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);

Modified: trunk/agent/command-ssh.c
===================================================================
--- trunk/agent/command-ssh.c	2009-07-06 21:33:34 UTC (rev 5063)
+++ trunk/agent/command-ssh.c	2009-07-07 10:02:41 UTC (rev 5064)
@@ -2906,29 +2906,41 @@
 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.  */
   stream_sock = es_fdopen (FD2INT(sock_client), "r+");
   if (!stream_sock)

Modified: trunk/agent/command.c
===================================================================
--- trunk/agent/command.c	2009-07-06 21:33:34 UTC (rev 5063)
+++ trunk/agent/command.c	2009-07-07 10:02:41 UTC (rev 5064)
@@ -1520,33 +1520,53 @@
 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;
+  se = session_env_new ();
+  if (!se)
+    err = gpg_error_from_syserror ();
 
-  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);
+  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);
+    }
 
-  return 0;
+  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 @@
 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 @@
     }
   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;
 }
 
 

Modified: trunk/agent/gpg-agent.c
===================================================================
--- trunk/agent/gpg-agent.c	2009-07-06 21:33:34 UTC (rev 5063)
+++ trunk/agent/gpg-agent.c	2009-07-07 10:02:41 UTC (rev 5064)
@@ -609,29 +609,41 @@
   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;
   orig_argv = argv;
@@ -924,6 +936,14 @@
                      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 @@
   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 @@
                          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 @@
                          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];

Modified: trunk/agent/protect-tool.c
===================================================================
--- trunk/agent/protect-tool.c	2009-07-06 21:33:34 UTC (rev 5063)
+++ trunk/agent/protect-tool.c	2009-07-07 10:02:41 UTC (rev 5064)
@@ -1086,7 +1086,7 @@
                                 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);

Modified: trunk/common/Makefile.am
===================================================================
--- trunk/common/Makefile.am	2009-07-06 21:33:34 UTC (rev 5063)
+++ trunk/common/Makefile.am	2009-07-07 10:02:41 UTC (rev 5064)
@@ -69,6 +69,7 @@
 	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 @@
 #
 # 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_sexputil_LDADD = $(t_common_ldadd)
 t_b64_LDADD = $(t_common_ldadd)
 t_exechelp_LDADD = $(t_common_ldadd)
+t_session_env_LDADD = $(t_common_ldadd)
 
-
-

Modified: trunk/common/asshelp.c
===================================================================
--- trunk/common/asshelp.c	2009-07-06 21:33:34 UTC (rev 5063)
+++ trunk/common/asshelp.c	2009-07-07 10:02:41 UTC (rev 5064)
@@ -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.
  *
@@ -34,10 +34,9 @@
 #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 @@
 
   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,58 +64,44 @@
 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)
   old_lc = setlocale (LC_CTYPE, NULL);
@@ -130,7 +116,7 @@
   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 @@
   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 @@
   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 @@
                      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 @@
                         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);

Modified: trunk/common/asshelp.h
===================================================================
--- trunk/common/asshelp.h	2009-07-06 21:33:34 UTC (rev 5063)
+++ trunk/common/asshelp.h	2009-07-07 10:02:41 UTC (rev 5064)
@@ -23,31 +23,25 @@
 #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);

Modified: trunk/common/get-passphrase.c
===================================================================
--- trunk/common/get-passphrase.c	2009-07-06 21:33:34 UTC (rev 5063)
+++ trunk/common/get-passphrase.c	2009-07-07 10:02:41 UTC (rev 5064)
@@ -39,12 +39,9 @@
   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 @@
                               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 @@
                              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)
     {

Modified: trunk/common/get-passphrase.h
===================================================================
--- trunk/common/get-passphrase.h	2009-07-06 21:33:34 UTC (rev 5063)
+++ trunk/common/get-passphrase.h	2009-07-07 10:02:41 UTC (rev 5064)
@@ -20,17 +20,15 @@
 #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,

Added: trunk/common/session-env.c
===================================================================
--- trunk/common/session-env.c	                        (rev 0)
+++ trunk/common/session-env.c	2009-07-07 10:02:41 UTC (rev 5064)
@@ -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;
+}
+
+

Added: trunk/common/session-env.h
===================================================================
--- trunk/common/session-env.h	                        (rev 0)
+++ trunk/common/session-env.h	2009-07-07 10:02:41 UTC (rev 5064)
@@ -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*/

Modified: trunk/common/t-exechelp.c
===================================================================
--- trunk/common/t-exechelp.c	2009-07-06 21:33:34 UTC (rev 5063)
+++ trunk/common/t-exechelp.c	2009-07-07 10:02:41 UTC (rev 5064)
@@ -69,7 +69,7 @@
 
 /* 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 @@
   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 ());

Added: trunk/common/t-session-env.c
===================================================================
--- trunk/common/t-session-env.c	                        (rev 0)
+++ trunk/common/t-session-env.c	2009-07-07 10:02:41 UTC (rev 5064)
@@ -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, "");




More information about the Gnupg-commits mailing list