From f6f5430e5014f90b685420447dffe89b220e2663 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 7 Jul 2009 10:02:41 +0000 Subject: [PATCH] Reworked passing of envars to Pinentry. --- NEWS | 7 +- agent/ChangeLog | 18 ++ agent/agent.h | 14 +- agent/call-pinentry.c | 41 +++- agent/command-ssh.c | 44 +++-- agent/command.c | 115 ++++++------ agent/gpg-agent.c | 120 ++++++------ agent/protect-tool.c | 2 +- common/ChangeLog | 17 ++ common/Makefile.am | 7 +- common/asshelp.c | 109 ++++------- common/asshelp.h | 16 +- common/get-passphrase.c | 23 +-- common/get-passphrase.h | 8 +- common/session-env.c | 384 ++++++++++++++++++++++++++++++++++++++ common/session-env.h | 43 +++++ common/t-exechelp.c | 4 +- common/t-session-env.c | 294 +++++++++++++++++++++++++++++ doc/gpgsm.texi | 4 +- g10/ChangeLog | 14 +- g10/call-agent.c | 3 +- g10/gpg.c | 34 +++- g10/options.h | 9 +- sm/ChangeLog | 12 ++ sm/call-agent.c | 3 +- sm/gpgsm.c | 42 ++++- sm/gpgsm.h | 11 +- sm/misc.c | 29 +-- sm/server.c | 78 ++++---- tools/ChangeLog | 8 +- tools/gpg-connect-agent.c | 8 +- 31 files changed, 1169 insertions(+), 352 deletions(-) create mode 100644 common/session-env.c create mode 100644 common/session-env.h create mode 100644 common/t-session-env.c diff --git a/NEWS b/NEWS index b08e2501d..aa3e6d544 100644 --- 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) ------------------------------------------------- diff --git a/agent/ChangeLog b/agent/ChangeLog index 4829ff2d4..d0c1a7f45 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,3 +1,21 @@ +2009-07-06 Werner Koch + + * 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 * genkey.c (agent_protect_and_store): Return RC and not 0. diff --git a/agent/agent.h b/agent/agent.h index 323c1c123..c7d8e02dd 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -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]; diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c index b956ef463..5e9685f61 100644 --- a/agent/call-pinentry.c +++ b/agent/call-pinentry.c @@ -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); diff --git a/agent/command-ssh.c b/agent/command-ssh.c index 76f310a33..12fe60a15 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -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. */ diff --git a/agent/command.c b/agent/command.c index 9238a2219..e3de085dd 100644 --- a/agent/command.c +++ b/agent/command.c @@ -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; + 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 @@ 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: + Delete envvar NAME + = Set envvar NAME to the empty string + = 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; } diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index eccf44539..31d79d508 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -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]; diff --git a/agent/protect-tool.c b/agent/protect-tool.c index 0e48124d8..27f4f9d0a 100644 --- a/agent/protect-tool.c +++ b/agent/protect-tool.c @@ -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); diff --git a/common/ChangeLog b/common/ChangeLog index 40faa541e..75c79c6f6 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,3 +1,20 @@ +2009-07-06 Werner Koch + + * 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 * sexputil.c (get_pk_algo_from_canon_sexp): New. diff --git a/common/Makefile.am b/common/Makefile.am index 2ef324e18..dd3661dac 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -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) diff --git a/common/asshelp.c b/common/asshelp.c index 6663241ae..b373baf98 100644 --- a/common/asshelp.c +++ b/common/asshelp.c @@ -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 @@ 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); + value = session_env_getenv_or_default (session_env, name, NULL); + if (!value) + continue; + + 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 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 (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); diff --git a/common/asshelp.h b/common/asshelp.h index dfed3ac50..f7bc88bad 100644 --- a/common/asshelp.h +++ b/common/asshelp.h @@ -23,31 +23,25 @@ #include #include +#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); diff --git a/common/get-passphrase.c b/common/get-passphrase.c index 68d7b706a..e1a11482e 100644 --- a/common/get-passphrase.c +++ b/common/get-passphrase.c @@ -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) { diff --git a/common/get-passphrase.h b/common/get-passphrase.h index 9457cdd3a..603ac81b9 100644 --- a/common/get-passphrase.h +++ b/common/get-passphrase.h @@ -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, diff --git a/common/session-env.c b/common/session-env.c new file mode 100644 index 000000000..ef36dbcbf --- /dev/null +++ b/common/session-env.c @@ -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 . + */ + +#include +#include +#include +#include +#include +#include + +#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: + + Delete envvar NAME + = Set envvar NAME to the empty string + = 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 index 000000000..031fe1d7c --- /dev/null +++ b/common/session-env.h @@ -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 . + */ + +#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*/ diff --git a/common/t-exechelp.c b/common/t-exechelp.c index 7ab6bbe0a..600379b69 100644 --- a/common/t-exechelp.c +++ b/common/t-exechelp.c @@ -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 index 000000000..94b668328 --- /dev/null +++ b/common/t-session-env.c @@ -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 . + */ + +#include +#include +#include +#include +#include + +#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; +} + diff --git a/doc/gpgsm.texi b/doc/gpgsm.texi index d1898133c..e784f71f4 100644 --- a/doc/gpgsm.texi +++ b/doc/gpgsm.texi @@ -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 diff --git a/g10/ChangeLog b/g10/ChangeLog index fcf759041..ca1b53dd6 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,6 +1,18 @@ +2009-07-07 Werner Koch + + * 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 - * 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. diff --git a/g10/call-agent.c b/g10/call-agent.c index 0590514df..071be2a09 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -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) diff --git a/g10/gpg.c b/g10/gpg.c index 00d903438..1e902aa22 100644 --- 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: diff --git a/g10/options.h b/g10/options.h index 40bd23029..a99ca22e8 100644 --- a/g10/options.h +++ b/g10/options.h @@ -24,6 +24,7 @@ #include #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; diff --git a/sm/ChangeLog b/sm/ChangeLog index 216791556..a2c06753c 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,15 @@ +2009-07-07 Werner Koch + + * 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 * certreqgen-ui.c (gpgsm_gencertreq_tty): Allow using a key from a diff --git a/sm/call-agent.c b/sm/call-agent.c index 777c44cec..47e45aba3 100644 --- a/sm/call-agent.c +++ b/sm/call-agent.c @@ -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); diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 6b2684abe..b5f18d767 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -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); diff --git a/sm/gpgsm.h b/sm/gpgsm.h index d2c38fb25..900e6dd5e 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -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. */ diff --git a/sm/misc.c b/sm/misc.c index 38994725e..628b321eb 100644 --- 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*/ } diff --git a/sm/server.c b/sm/server.c index dfd4f690f..7ba5b683e 100644 --- a/sm/server.c +++ b/sm/server.c @@ -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: + Delete envvar NAME + = Set envvar NAME to the empty string + = 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; } diff --git a/tools/ChangeLog b/tools/ChangeLog index 5f716e320..fceb649f9 100644 --- a/tools/ChangeLog +++ b/tools/ChangeLog @@ -1,3 +1,8 @@ +2009-07-07 Werner Koch + + * gpg-connect-agent.c (start_agent): Adjust for changed args of + send_pinentry_environment. + 2009-06-30 Werner Koch * 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 diff --git a/tools/gpg-connect-agent.c b/tools/gpg-connect-agent.c index 06dafd5c9..90f54a44d 100644 --- a/tools/gpg-connect-agent.c +++ b/tools/gpg-connect-agent.c @@ -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));