LCOV - code coverage report
Current view: top level - common - session-env.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 121 132 91.7 %
Date: 2016-09-12 13:01:59 Functions: 10 10 100.0 %

          Line data    Source code
       1             : /* session-env.c - Session environment helper functions.
       2             :  * Copyright (C) 2009 Free Software Foundation, Inc.
       3             :  *
       4             :  * This file is part of GnuPG.
       5             :  *
       6             :  * This file is free software; you can redistribute it and/or modify
       7             :  * it under the terms of either
       8             :  *
       9             :  *   - the GNU Lesser General Public License as published by the Free
      10             :  *     Software Foundation; either version 3 of the License, or (at
      11             :  *     your option) any later version.
      12             :  *
      13             :  * or
      14             :  *
      15             :  *   - the GNU General Public License as published by the Free
      16             :  *     Software Foundation; either version 2 of the License, or (at
      17             :  *     your option) any later version.
      18             :  *
      19             :  * or both in parallel, as here.
      20             :  *
      21             :  * This file is distributed in the hope that it will be useful,
      22             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      23             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      24             :  * GNU General Public License for more details.
      25             :  *
      26             :  * You should have received a copy of the GNU General Public License
      27             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      28             :  */
      29             : 
      30             : #include <config.h>
      31             : #include <stdlib.h>
      32             : #include <errno.h>
      33             : #include <ctype.h>
      34             : #include <assert.h>
      35             : #include <unistd.h>
      36             : 
      37             : #include "util.h"
      38             : #include "session-env.h"
      39             : 
      40             : 
      41             : struct variable_s
      42             : {
      43             :   char *value;    /* Pointer into NAME to the Nul terminated value. */
      44             :   int is_default; /* The value is a default one.  */
      45             :   char name[1];   /* Nul terminated Name and space for the value.  */
      46             : };
      47             : 
      48             : 
      49             : 
      50             : /* The session environment object.  */
      51             : struct session_environment_s
      52             : {
      53             :   size_t arraysize;          /* Allocated size or ARRAY.  */
      54             :   size_t arrayused;          /* Used size of ARRAY.  */
      55             :   struct variable_s **array; /* Array of variables.  NULL slots are unused.  */
      56             : };
      57             : 
      58             : 
      59             : /* A list of environment variables we pass from the actual user
      60             :   (e.g. gpgme) down to the pinentry.  We do not handle the locale
      61             :   settings because they do not only depend on envvars.  */
      62             : static struct
      63             : {
      64             :   const char *name;
      65             :   const char *assname;  /* Name used by Assuan or NULL.  */
      66             : } stdenvnames[] = {
      67             :   { "GPG_TTY", "ttyname" },      /* GnuPG specific envvar.  */
      68             :   { "TERM",    "ttytype" },      /* Used to set ttytype. */
      69             :   { "DISPLAY", "display" },      /* The X-Display.  */
      70             :   { "XAUTHORITY","xauthority"},  /* Xlib Authentication.  */
      71             :   { "XMODIFIERS" },              /* Used by Xlib to select X input
      72             :                                       modules (eg "@im=SCIM").  */
      73             :   { "GTK_IM_MODULE" },           /* Used by gtk to select gtk input
      74             :                                     modules (eg "scim-bridge").  */
      75             :   { "DBUS_SESSION_BUS_ADDRESS" },/* Used by GNOME3 to talk to gcr over
      76             :                                     dbus */
      77             :   { "QT_IM_MODULE" },            /* Used by Qt to select qt input
      78             :                                       modules (eg "xim").  */
      79             :   { "INSIDE_EMACS" },            /* Set by Emacs before running a
      80             :                                     process.  */
      81             :   { "PINENTRY_USER_DATA", "pinentry-user-data"}
      82             :                                  /* Used for communication with
      83             :                                     non-standard Pinentries.  */
      84             : };
      85             : 
      86             : 
      87             : /* Track last allocated arraysize of all objects ever created.  If
      88             :    nothing has ever been allocated we use INITIAL_ARRAYSIZE and we
      89             :    will never use more than MAXDEFAULT_ARRAYSIZE for initial
      90             :    allocation.  Note that this is not reentrant if used with a
      91             :    preemptive thread model.  */
      92             : static size_t lastallocatedarraysize;
      93             : #define INITIAL_ARRAYSIZE 8  /* Let's use the number of stdenvnames.  */
      94             : #define CHUNK_ARRAYSIZE 10
      95             : #define MAXDEFAULT_ARRAYSIZE (INITIAL_ARRAYSIZE + CHUNK_ARRAYSIZE * 5)
      96             : 
      97             : 
      98             : /* Return the names of standard environment variables one after the
      99             :    other.  The caller needs to set the value at the address of
     100             :    ITERATOR initially to 0 and then call this function until it returns
     101             :    NULL.  */
     102             : const char *
     103        5808 : session_env_list_stdenvnames (int *iterator, const char **r_assname)
     104             : {
     105        5808 :   int idx = *iterator;
     106             : 
     107        5808 :   if (idx < 0 || idx >= DIM (stdenvnames))
     108         528 :     return NULL;
     109        5280 :   *iterator = idx + 1;
     110        5280 :   if (r_assname)
     111        5280 :     *r_assname = stdenvnames[idx].assname;
     112        5280 :   return stdenvnames[idx].name;
     113             : }
     114             : 
     115             : 
     116             : /* Create a new session environment object.  Return NULL and sets
     117             :    ERRNO on failure. */
     118             : session_env_t
     119        2696 : session_env_new (void)
     120             : {
     121             :   session_env_t se;
     122             : 
     123        2696 :   se = xtrycalloc (1, sizeof *se);
     124        2696 :   if (se)
     125             :     {
     126        5392 :       se->arraysize = (lastallocatedarraysize?
     127        2696 :                        lastallocatedarraysize : INITIAL_ARRAYSIZE);
     128        2696 :       se->array = xtrycalloc (se->arraysize, sizeof *se->array);
     129        2696 :       if (!se->array)
     130             :         {
     131           0 :           xfree (se);
     132           0 :           se = NULL;
     133             :         }
     134             :     }
     135             : 
     136        2696 :   return se;
     137             : }
     138             : 
     139             : 
     140             : /* Release a session environment object.  */
     141             : void
     142         776 : session_env_release (session_env_t se)
     143             : {
     144             :   int idx;
     145             : 
     146         776 :   if (!se)
     147         776 :     return;
     148             : 
     149         776 :   if (se->arraysize > INITIAL_ARRAYSIZE
     150           2 :       && se->arraysize <= MAXDEFAULT_ARRAYSIZE
     151           1 :       && se->arraysize > lastallocatedarraysize)
     152           1 :     lastallocatedarraysize = se->arraysize;
     153             : 
     154        3419 :   for (idx=0; idx < se->arrayused; idx++)
     155        2643 :     if (se->array[idx])
     156        2192 :       xfree (se->array[idx]);
     157         776 :   xfree (se->array);
     158         776 :   xfree (se);
     159             : }
     160             : 
     161             : 
     162             : static gpg_error_t
     163        3429 : delete_var (session_env_t se, const char *name)
     164             : {
     165             :   int idx;
     166             : 
     167      255897 :   for (idx=0; idx < se->arrayused; idx++)
     168      252468 :     if (se->array[idx] && !strcmp (se->array[idx]->name, name))
     169             :       {
     170         502 :         xfree (se->array[idx]);
     171         502 :         se->array[idx] = NULL;
     172             :       }
     173        3429 :   return 0;
     174             : }
     175             : 
     176             : 
     177             : static gpg_error_t
     178        4834 : update_var (session_env_t se, const char *string, size_t namelen,
     179             :             const char *explicit_value, int set_default)
     180             : {
     181             :   int idx;
     182        4834 :   int freeidx = -1;
     183             :   const char *value;
     184             :   size_t valuelen;
     185             :   struct variable_s *var;
     186             : 
     187        4834 :   if (explicit_value)
     188        3754 :     value = explicit_value;
     189             :   else
     190        1080 :     value = string + namelen + 1;
     191        4834 :   valuelen = strlen (value);
     192             : 
     193      159399 :   for (idx=0; idx < se->arrayused; idx++)
     194             :     {
     195      155094 :       if (!se->array[idx])
     196       23826 :         freeidx = idx;
     197      131268 :       else if (!strncmp (se->array[idx]->name, string, namelen)
     198         532 :                && strlen (se->array[idx]->name) == namelen)
     199             :         {
     200         532 :           if (strlen (se->array[idx]->value) == valuelen)
     201             :             {
     202             :               /* The new value has the same length.  We can update it
     203             :                  in-place.  */
     204         529 :               memcpy (se->array[idx]->value, value, valuelen);
     205         529 :               se->array[idx]->is_default = !!set_default;
     206         529 :               return 0;
     207             :             }
     208             :           /* Prepare for update.  */
     209           3 :           freeidx = idx;
     210             :         }
     211             :     }
     212             : 
     213        4305 :   if (freeidx == -1)
     214             :     {
     215        4251 :       if (se->arrayused == se->arraysize)
     216             :         {
     217             :           /* Reallocate the array. */
     218             :           size_t newsize;
     219             :           struct variable_s **newarray;
     220             : 
     221          50 :           newsize = se->arraysize + CHUNK_ARRAYSIZE;
     222          50 :           newarray = xtrycalloc (newsize, sizeof *newarray);
     223          50 :           if (!newarray)
     224           0 :             return gpg_error_from_syserror ();
     225       12700 :           for (idx=0; idx < se->arrayused; idx++)
     226       12650 :             newarray[idx] = se->array[idx];
     227          50 :           se->arraysize = newsize;
     228          50 :           xfree (se->array);
     229          50 :           se->array = newarray;
     230             :         }
     231        4251 :       freeidx = se->arrayused++;
     232             :     }
     233             : 
     234             :   /* Allocate new memory and return an error if that didn't worked.
     235             :      Allocating it first allows us to keep the old value; it doesn't
     236             :      matter that arrayused has already been incremented in case of a
     237             :      new entry - it will then pint to a NULL slot.  */
     238        4305 :   var = xtrymalloc (sizeof *var + namelen + 1 + valuelen);
     239        4305 :   if (!var)
     240           0 :     return gpg_error_from_syserror ();
     241        4305 :   var->is_default = !!set_default;
     242        4305 :   memcpy (var->name, string, namelen);
     243        4305 :   var->name[namelen] = '\0';
     244        4305 :   var->value = var->name + namelen + 1;
     245        4305 :   strcpy (var->value, value);
     246             : 
     247        4305 :   xfree (se->array[freeidx]);
     248        4305 :   se->array[freeidx] = var;
     249        4305 :   return 0;
     250             : }
     251             : 
     252             : 
     253             : /* Set or update an environment variable of the session environment.
     254             :    String is similar to the putval(3) function but it is reentrant and
     255             :    takes a copy.  In particular it exhibits this behaviour:
     256             : 
     257             :           <NAME>            Delete envvar NAME
     258             :           <KEY>=            Set envvar NAME to the empty string
     259             :           <KEY>=<VALUE>     Set envvar NAME to VALUE
     260             : 
     261             :    On success 0 is returned; on error an gpg-error code.  */
     262             : gpg_error_t
     263        1587 : session_env_putenv (session_env_t se, const char *string)
     264             : {
     265             :   const char *s;
     266             : 
     267        1587 :   if (!string || !*string)
     268           2 :     return gpg_error (GPG_ERR_INV_VALUE);
     269        1585 :   s = strchr (string, '=');
     270        1585 :   if (s == string)
     271           1 :     return gpg_error (GPG_ERR_INV_VALUE);
     272        1584 :   if (!s)
     273         504 :     return delete_var (se, string);
     274             :   else
     275        1080 :     return update_var (se, string, s - string, NULL, 0);
     276             : }
     277             : 
     278             : 
     279             : /* Same as session_env_putenv but with name and value given as distict
     280             :    values.  */
     281             : gpg_error_t
     282        5040 : session_env_setenv (session_env_t se, const char *name, const char *value)
     283             : {
     284        5040 :   if (!name || !*name)
     285           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     286        5040 :   if (!value)
     287        2925 :     return delete_var (se, name);
     288             :   else
     289        2115 :     return update_var (se, name, strlen (name), value, 0);
     290             : }
     291             : 
     292             : 
     293             : 
     294             : 
     295             : /* Return the value of the environment variable NAME from the SE
     296             :    object.  If the variable does not exist, NULL is returned.  The
     297             :    returned value is valid as long as SE is valid and as long it has
     298             :    not been removed or updated by a call to session_env_putenv.  The
     299             :    caller MUST not change the returned value. */
     300             : char *
     301          79 : session_env_getenv (session_env_t se, const char *name)
     302             : {
     303             :   int idx;
     304             : 
     305          79 :   if (!se || !name || !*name)
     306           0 :     return NULL;
     307             : 
     308         188 :   for (idx=0; idx < se->arrayused; idx++)
     309         149 :     if (se->array[idx] && !strcmp (se->array[idx]->name, name))
     310          40 :       return se->array[idx]->is_default? NULL : se->array[idx]->value;
     311          39 :   return NULL;
     312             : }
     313             : 
     314             : 
     315             : /* Return the value of the environment variable NAME from the SE
     316             :    object.  The returned value is valid as long as SE is valid and as
     317             :    long it has not been removed or updated by a call to
     318             :    session_env_putenv.  If the variable does not exist, the function
     319             :    tries to return the value trough a call to getenv; if that returns
     320             :    a value, this value is recorded and and used.  If no value could be
     321             :    found, returns NULL.  The caller must not change the returned
     322             :    value. */
     323             : char *
     324        5800 : session_env_getenv_or_default (session_env_t se, const char *name,
     325             :                                int *r_default)
     326             : {
     327             :   int idx;
     328             :   char *defvalue;
     329             : 
     330        5800 :   if (r_default)
     331         527 :     *r_default = 0;
     332        5800 :   if (!se || !name || !*name)
     333           0 :     return NULL;
     334             : 
     335       16939 :   for (idx=0; idx < se->arrayused; idx++)
     336       11141 :     if (se->array[idx] && !strcmp (se->array[idx]->name, name))
     337             :       {
     338           2 :         if (r_default && se->array[idx]->is_default)
     339           0 :           *r_default = 1;
     340           2 :         return se->array[idx]->value;
     341             :       }
     342             : 
     343             :   /* Get the default value with an additional fallback for GPG_TTY.  */
     344        5798 :   defvalue = getenv (name);
     345        5798 :   if ((!defvalue || !*defvalue) && !strcmp (name, "GPG_TTY")
     346        1054 :       && gnupg_ttyname (0))
     347             :     {
     348           0 :       defvalue = gnupg_ttyname (0);
     349             :     }
     350        5798 :   if (defvalue)
     351             :     {
     352             :       /* Record the default value for later use so that we are safe
     353             :          from later modifications of the environment.  We need to take
     354             :          a copy to better cope with the rules of putenv(3).  We ignore
     355             :          the error of the update function because we can't return an
     356             :          explicit error anyway and the following scan would then fail
     357             :          anyway. */
     358        1639 :       update_var (se, name, strlen (name), defvalue, 1);
     359             : 
     360        3396 :       for (idx=0; idx < se->arrayused; idx++)
     361        3396 :         if (se->array[idx] && !strcmp (se->array[idx]->name, name))
     362             :           {
     363        1639 :             if (r_default && se->array[idx]->is_default)
     364           0 :               *r_default = 1;
     365        1639 :             return se->array[idx]->value;
     366             :           }
     367             :     }
     368             : 
     369        4159 :   return NULL;
     370             : }
     371             : 
     372             : 
     373             : /* List the entire environment stored in SE.  The caller initially
     374             :    needs to set the value of ITERATOR to 0 and then call this function
     375             :    until it returns NULL.  The value is retruned at R_VALUE.  If
     376             :    R_DEFAULT is not NULL, the default flag is stored on return.  The
     377             :    default flag indicates that the value has been taken from the
     378             :    process' environment.  The caller must not change the returned
     379             :    name or value.  */
     380             : char *
     381         598 : session_env_listenv (session_env_t se, int *iterator,
     382             :                      const char **r_value, int *r_default)
     383             : {
     384         598 :   int idx = *iterator;
     385             : 
     386         598 :   if (!se || idx < 0)
     387           0 :     return NULL;
     388             : 
     389        1551 :   for (; idx < se->arrayused; idx++)
     390        1541 :     if (se->array[idx])
     391             :       {
     392         588 :         *iterator = idx+1;
     393         588 :         if (r_default)
     394         588 :           *r_default = se->array[idx]->is_default;
     395         588 :         if (r_value)
     396         588 :           *r_value = se->array[idx]->value;
     397         588 :         return se->array[idx]->name;
     398             :       }
     399          10 :   return NULL;
     400             : }

Generated by: LCOV version 1.11