mirror of
git://git.gnupg.org/gnupg.git
synced 2025-07-02 22:46:30 +02:00
Reworked passing of envars to Pinentry.
This commit is contained in:
parent
58e6e28bb1
commit
f6f5430e50
31 changed files with 1169 additions and 352 deletions
|
@ -1,3 +1,20 @@
|
|||
2009-07-06 Werner Koch <wk@g10code.com>
|
||||
|
||||
* get-passphrase.c (struct agentargs): Add SESSION_ENV and remove
|
||||
obsolete args.
|
||||
(gnupg_prepare_get_passphrase): Ditto.
|
||||
|
||||
* session-env.c, session-env.h: New.
|
||||
* t-session-env.c: New.
|
||||
* Makefile.am (common_sources, module_tests): Add them.
|
||||
* asshelp.h: Include "session-env.h"
|
||||
* asshelp.c (send_one_option): Add arg PUTENV.
|
||||
(send_pinentry_environment): Replace most args by SESSION_ENV and
|
||||
rewrite fucntion.
|
||||
(start_new_gpg_agent): Likewise.
|
||||
|
||||
* t-exechelp.c (test_close_all_fds): Remove debug code.
|
||||
|
||||
2009-07-01 Werner Koch <wk@g10code.com>
|
||||
|
||||
* sexputil.c (get_pk_algo_from_canon_sexp): New.
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
109
common/asshelp.c
109
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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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,
|
||||
|
|
384
common/session-env.c
Normal file
384
common/session-env.c
Normal file
|
@ -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;
|
||||
}
|
||||
|
||||
|
43
common/session-env.h
Normal file
43
common/session-env.h
Normal file
|
@ -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*/
|
|
@ -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 ());
|
||||
|
|
294
common/t-session-env.c
Normal file
294
common/t-session-env.c
Normal file
|
@ -0,0 +1,294 @@
|
|||
/* t-session-env.c - Module test for session-env.c
|
||||
* Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "session-env.h"
|
||||
|
||||
#define pass() do { ; } while(0)
|
||||
#define fail(e) do { fprintf (stderr, "%s:%d: function failed: %s\n", \
|
||||
__FILE__,__LINE__, gpg_strerror (e)); \
|
||||
exit (1); \
|
||||
} while(0)
|
||||
|
||||
static int verbose;
|
||||
|
||||
static void
|
||||
listall (session_env_t se)
|
||||
{
|
||||
int iterator = 0;
|
||||
const char *name, *value;
|
||||
int def;
|
||||
|
||||
if (verbose)
|
||||
printf ("environment of %p\n", se);
|
||||
while ( (name = session_env_listenv (se, &iterator, &value, &def)) )
|
||||
if (verbose)
|
||||
printf (" %s%s=%s\n", def? "[def] ":" ", name, value);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
show_stdnames (void)
|
||||
{
|
||||
const char *name, *assname;
|
||||
int iterator = 0;
|
||||
|
||||
printf ("Known envvars:");
|
||||
while ((name = session_env_list_stdenvnames (&iterator, &assname)))
|
||||
{
|
||||
printf ( " %s", name);
|
||||
if (assname)
|
||||
printf ( "(%s)", assname);
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
test_all (void)
|
||||
{
|
||||
gpg_error_t err;
|
||||
session_env_t se_0, se;
|
||||
const char *s, *s2;
|
||||
int idx;
|
||||
|
||||
se_0 = session_env_new ();
|
||||
if (!se_0)
|
||||
fail (gpg_error_from_syserror ());
|
||||
se = session_env_new ();
|
||||
if (!se)
|
||||
fail (gpg_error_from_syserror ());
|
||||
|
||||
err = session_env_putenv (se, NULL);
|
||||
if (gpg_err_code (err) != GPG_ERR_INV_VALUE)
|
||||
fail (err);
|
||||
err = session_env_putenv (se, "");
|
||||
if (gpg_err_code (err) != GPG_ERR_INV_VALUE)
|
||||
fail (err);
|
||||
err = session_env_putenv (se, "=");
|
||||
if (gpg_err_code (err) != GPG_ERR_INV_VALUE)
|
||||
fail (err);
|
||||
|
||||
/* Delete some nonexistant variables. */
|
||||
err = session_env_putenv (se, "A");
|
||||
if (err)
|
||||
fail (err);
|
||||
err = session_env_putenv (se, "a");
|
||||
if (err)
|
||||
fail (err);
|
||||
err = session_env_putenv (se, "_aaaa aaaaaasssssssssssss\nddd");
|
||||
if (err)
|
||||
fail (err);
|
||||
|
||||
/* Create a few variables. */
|
||||
err = session_env_putenv (se, "EMPTY=");
|
||||
if (err)
|
||||
fail (err);
|
||||
err = session_env_putenv (se, "foo=value_of_foo");
|
||||
if (err)
|
||||
fail (err);
|
||||
err = session_env_putenv (se, "bar=the value_of_bar");
|
||||
if (err)
|
||||
fail (err);
|
||||
err = session_env_putenv (se, "baz=this-is-baz");
|
||||
if (err)
|
||||
fail (err);
|
||||
err = session_env_putenv (se, "BAZ=this-is-big-baz");
|
||||
if (err)
|
||||
fail (err);
|
||||
|
||||
listall (se);
|
||||
|
||||
/* Update one. */
|
||||
err = session_env_putenv (se, "baz=this-is-another-baz");
|
||||
if (err)
|
||||
fail (err);
|
||||
|
||||
listall (se);
|
||||
|
||||
/* Delete one. */
|
||||
err = session_env_putenv (se, "bar");
|
||||
if (err)
|
||||
fail (err);
|
||||
|
||||
listall (se);
|
||||
|
||||
/* Insert a new one. */
|
||||
err = session_env_putenv (se, "FOO=value_of_foo");
|
||||
if (err)
|
||||
fail (err);
|
||||
|
||||
listall (se);
|
||||
|
||||
/* Retrieve a default one. */
|
||||
s = session_env_getenv_or_default (se, "HOME", NULL);
|
||||
if (!s)
|
||||
{
|
||||
fprintf (stderr, "failed to get default of HOME\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
s = session_env_getenv (se, "HOME");
|
||||
if (s)
|
||||
fail(0); /* This is a default value, thus we should not see it. */
|
||||
|
||||
s = session_env_getenv_or_default (se, "HOME", NULL);
|
||||
if (!s)
|
||||
fail(0); /* But here we should see it. */
|
||||
|
||||
/* Add a few more. */
|
||||
err = session_env_putenv (se, "X1=A value");
|
||||
if (err)
|
||||
fail (err);
|
||||
err = session_env_putenv (se, "X2=Another value");
|
||||
if (err)
|
||||
fail (err);
|
||||
err = session_env_putenv (se, "X3=A value");
|
||||
if (err)
|
||||
fail (err);
|
||||
|
||||
listall (se);
|
||||
|
||||
/* Check that we can overwrite a default value. */
|
||||
err = session_env_putenv (se, "HOME=/this/is/my/new/home");
|
||||
if (err)
|
||||
fail (err);
|
||||
/* And that we get this string back. */
|
||||
s = session_env_getenv (se, "HOME");
|
||||
if (!s)
|
||||
fail (0);
|
||||
if (strcmp (s, "/this/is/my/new/home"))
|
||||
fail (0);
|
||||
/* A new get default should return the very same string. */
|
||||
s2 = session_env_getenv_or_default (se, "HOME", NULL);
|
||||
if (!s2)
|
||||
fail (0);
|
||||
if (s2 != s)
|
||||
fail (0);
|
||||
|
||||
listall (se);
|
||||
|
||||
/* Check that the other object is clean. */
|
||||
{
|
||||
int iterator = 0;
|
||||
|
||||
if (session_env_listenv (se_0, &iterator, NULL, NULL))
|
||||
fail (0);
|
||||
}
|
||||
|
||||
|
||||
session_env_release (se);
|
||||
|
||||
/* Use a new session for quick mass test. */
|
||||
se = session_env_new ();
|
||||
if (!se)
|
||||
fail (gpg_error_from_syserror ());
|
||||
|
||||
/* Create. */
|
||||
for (idx=0; idx < 500; idx++)
|
||||
{
|
||||
char buf[100];
|
||||
|
||||
snprintf (buf, sizeof buf, "FOO_%d=Value for %x", idx, idx);
|
||||
err = session_env_putenv (se, buf);
|
||||
if (err)
|
||||
fail (err);
|
||||
}
|
||||
err = session_env_setenv (se, "TEST1", "value1");
|
||||
if (err)
|
||||
fail (err);
|
||||
err = session_env_setenv (se, "TEST1", "value1-updated");
|
||||
if (err)
|
||||
fail (err);
|
||||
|
||||
listall (se);
|
||||
|
||||
/* Delete all. */
|
||||
for (idx=0; idx < 500; idx++)
|
||||
{
|
||||
char buf[100];
|
||||
|
||||
snprintf (buf, sizeof buf, "FOO_%d", idx);
|
||||
err = session_env_putenv (se, buf);
|
||||
if (err)
|
||||
fail (err);
|
||||
}
|
||||
err = session_env_setenv (se, "TEST1", NULL);
|
||||
if (err)
|
||||
fail (err);
|
||||
|
||||
/* Check that all are deleted. */
|
||||
{
|
||||
int iterator = 0;
|
||||
|
||||
if (session_env_listenv (se, &iterator, NULL, NULL))
|
||||
fail (0);
|
||||
}
|
||||
|
||||
/* Add a few strings again. */
|
||||
for (idx=0; idx < 500; idx++)
|
||||
{
|
||||
char buf[100];
|
||||
|
||||
if (!(idx % 10))
|
||||
{
|
||||
if ( !(idx % 3))
|
||||
snprintf (buf, sizeof buf, "FOO_%d=", idx);
|
||||
else
|
||||
snprintf (buf, sizeof buf, "FOO_%d=new value for %x", idx, idx);
|
||||
err = session_env_putenv (se, buf);
|
||||
if (err)
|
||||
fail (err);
|
||||
}
|
||||
}
|
||||
|
||||
listall (se);
|
||||
|
||||
session_env_release (se);
|
||||
|
||||
session_env_release (se_0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
if (argc)
|
||||
{ argc--; argv++; }
|
||||
if (argc && !strcmp (argv[0], "--verbose"))
|
||||
{
|
||||
verbose = 1;
|
||||
argc--; argv++;
|
||||
}
|
||||
|
||||
|
||||
show_stdnames ();
|
||||
test_all ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue