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