2009-12-08 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / common / session-env.c
1 /* se4ssiobn-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           /* Check if the value is the same; no need to update it,
187              except for updating the default flag.  */
188           if (strlen (se->array[idx]->value) == valuelen)
189             {
190               se->array[idx]->is_default = !!set_default;
191               return 0;
192             }
193           /* Prepare for update.  */
194           freeidx = idx;
195         }
196     }
197
198   if (freeidx == -1)
199     {
200       if (se->arrayused == se->arraysize)
201         {
202           /* Reallocate the array. */
203           size_t newsize;
204           struct variable_s **newarray;
205
206           newsize = se->arraysize + CHUNK_ARRAYSIZE;
207           newarray = xtrycalloc (newsize, sizeof *newarray);
208           if (!newarray)
209             return gpg_error_from_syserror ();
210           for (idx=0; idx < se->arrayused; idx++)
211             newarray[idx] = se->array[idx];
212           se->arraysize = newsize;
213           xfree (se->array);
214           se->array = newarray;
215         }
216       freeidx = se->arrayused++;
217     }
218
219   /* Allocate new memory and return an error if that didn't worked.
220      Allocating it first allows us to keep the old value; it doesn't
221      matter that arrayused has already been incremented in case of a
222      new entry - it will then pint to a NULL slot.  */
223   var = xtrymalloc (sizeof *var + namelen + 1 + valuelen);
224   if (!var)
225     return gpg_error_from_syserror ();
226   var->is_default = !!set_default;
227   memcpy (var->name, string, namelen);
228   var->name[namelen] = '\0';
229   var->value = var->name + namelen + 1;
230   strcpy (var->value, value);
231
232   xfree (se->array[freeidx]);
233   se->array[freeidx] = var;
234   return 0;
235 }
236
237
238 /* Set or update an environment variable of the session environment.
239    String is similar to the putval(3) function but it is reentrant and
240    takes a copy.  In particular it exhibits this behaviour:
241
242           <NAME>            Delete envvar NAME
243           <KEY>=            Set envvar NAME to the empty string
244           <KEY>=<VALUE>     Set envvar NAME to VALUE
245
246    On success 0 is returned; on error an gpg-error code.  */
247 gpg_error_t
248 session_env_putenv (session_env_t se, const char *string)
249 {
250   const char *s;
251   
252   if (!string || !*string)
253     return gpg_error (GPG_ERR_INV_VALUE);
254   s = strchr (string, '=');
255   if (s == string)
256     return gpg_error (GPG_ERR_INV_VALUE);
257   if (!s)
258     return delete_var (se, string);
259   else
260     return update_var (se, string, s - string, NULL, 0);
261 }
262
263
264 /* Same as session_env_putenv but with name and value given as distict
265    values.  */
266 gpg_error_t
267 session_env_setenv (session_env_t se, const char *name, const char *value)
268 {
269   if (!name || !*name)
270     return gpg_error (GPG_ERR_INV_VALUE);
271   if (!value)
272     return delete_var (se, name);
273   else
274     return update_var (se, name, strlen (name), value, 0);
275 }
276
277
278
279
280 /* Return the value of the environment variable NAME from the SE
281    object.  If the variable does not exist, NULL is returned.  The
282    returned value is valid as long as SE is valid and as long it has
283    not been removed or updated by a call to session_env_putenv.  The
284    caller MUST not change the returned value. */
285 char *
286 session_env_getenv (session_env_t se, const char *name)
287 {
288   int idx;
289
290   if (!se || !name || !*name)
291     return NULL;
292
293   for (idx=0; idx < se->arrayused; idx++)
294     if (se->array[idx] && !strcmp (se->array[idx]->name, name))
295       return se->array[idx]->is_default? NULL : se->array[idx]->value;
296   return NULL;
297 }
298
299
300 /* Return the value of the environment variable NAME from the SE
301    object.  The returned value is valid as long as SE is valid and as
302    long it has not been removed or updated by a call to
303    session_env_putenv.  If the variable does not exist, the fucntion
304    tries to return the value trough a call to getenv; if that returns
305    a value, this value is recorded and and used.  If no value could be
306    found, returns NULL.  The caller must not change the returned
307    value. */
308 char *
309 session_env_getenv_or_default (session_env_t se, const char *name,
310                                int *r_default)
311 {
312   int idx;
313   char *defvalue;
314
315   if (r_default)
316     *r_default = 0;
317   if (!se || !name || !*name)
318     return NULL;
319
320   for (idx=0; idx < se->arrayused; idx++)
321     if (se->array[idx] && !strcmp (se->array[idx]->name, name))
322       {
323         if (r_default && se->array[idx]->is_default)
324           *r_default = 1;
325         return se->array[idx]->value;
326       }
327   
328   /* Get the default value with and additional fallback for GPG_TTY.  */
329   defvalue = getenv (name);
330   if ((!defvalue || !*defvalue) && !strcmp (name, "GPG_TTY") && ttyname (0))
331     defvalue = ttyname (0);
332   if (defvalue)
333     {
334       /* Record the default value for later use so that we are safe
335          from later modifications of the environment.  We need to take
336          a copy to better cope with the rules of putenv(3).  We ignore
337          the error of the update function because we can't return an
338          explicit error anyway and the following scan would then fail
339          anyway. */
340       update_var (se, name, strlen (name), defvalue, 1);
341       
342       for (idx=0; idx < se->arrayused; idx++)
343         if (se->array[idx] && !strcmp (se->array[idx]->name, name))
344           {
345             if (r_default && se->array[idx]->is_default)
346               *r_default = 1;
347             return se->array[idx]->value;
348           }
349     }
350
351   return NULL;
352 }
353
354
355 /* List the entire environment stored in SE.  The caller initially
356    needs to set the value of ITERATOR to 0 and then call this function
357    until it returns NULL.  The value is retruned at R_VALUE.  If
358    R_DEFAULT is not NULL, the default flag is stored on return.  The
359    default flag indicates that the value has been taken from the
360    process' environment.  The caller must not change the returned
361    name or value.  */ 
362 char *
363 session_env_listenv (session_env_t se, int *iterator,
364                      const char **r_value, int *r_default)
365 {
366   int idx = *iterator;
367
368   if (!se || idx < 0)
369     return NULL;
370
371   for (; idx < se->arrayused; idx++)
372     if (se->array[idx])
373       {
374         *iterator = idx+1;
375         if (r_default)
376           *r_default = se->array[idx]->is_default;
377         if (r_value)
378           *r_value = se->array[idx]->value;
379         return se->array[idx]->name;
380       }
381   return NULL;
382 }
383
384