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 initally to 0 and then call this function until it returns
101 : NULL. */
102 : const char *
103 4334 : session_env_list_stdenvnames (int *iterator, const char **r_assname)
104 : {
105 4334 : int idx = *iterator;
106 :
107 4334 : if (idx < 0 || idx >= DIM (stdenvnames))
108 394 : return NULL;
109 3940 : *iterator = idx + 1;
110 3940 : if (r_assname)
111 3940 : *r_assname = stdenvnames[idx].assname;
112 3940 : 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 1746 : session_env_new (void)
120 : {
121 : session_env_t se;
122 :
123 1746 : se = xtrycalloc (1, sizeof *se);
124 1746 : if (se)
125 : {
126 3492 : se->arraysize = (lastallocatedarraysize?
127 1746 : lastallocatedarraysize : INITIAL_ARRAYSIZE);
128 1746 : se->array = xtrycalloc (se->arraysize, sizeof *se->array);
129 1746 : if (!se->array)
130 : {
131 0 : xfree (se);
132 0 : se = NULL;
133 : }
134 : }
135 :
136 1746 : return se;
137 : }
138 :
139 :
140 : /* Release a session environment object. */
141 : void
142 408 : session_env_release (session_env_t se)
143 : {
144 : int idx;
145 :
146 408 : if (!se)
147 408 : return;
148 :
149 408 : if (se->arraysize > INITIAL_ARRAYSIZE
150 2 : && se->arraysize <= MAXDEFAULT_ARRAYSIZE
151 1 : && se->arraysize > lastallocatedarraysize)
152 1 : lastallocatedarraysize = se->arraysize;
153 :
154 2488 : for (idx=0; idx < se->arrayused; idx++)
155 2080 : if (se->array[idx])
156 1629 : xfree (se->array[idx]);
157 408 : xfree (se->array);
158 408 : xfree (se);
159 : }
160 :
161 :
162 : static gpg_error_t
163 2121 : delete_var (session_env_t se, const char *name)
164 : {
165 : int idx;
166 :
167 253935 : for (idx=0; idx < se->arrayused; idx++)
168 251814 : 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 2121 : return 0;
174 : }
175 :
176 :
177 : static gpg_error_t
178 4076 : 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 4076 : int freeidx = -1;
183 : const char *value;
184 : size_t valuelen;
185 : struct variable_s *var;
186 :
187 4076 : if (explicit_value)
188 3122 : value = explicit_value;
189 : else
190 954 : value = string + namelen + 1;
191 4076 : valuelen = strlen (value);
192 :
193 159565 : for (idx=0; idx < se->arrayused; idx++)
194 : {
195 155892 : if (!se->array[idx])
196 23826 : freeidx = idx;
197 132066 : else if (!strncmp (se->array[idx]->name, string, namelen)
198 406 : && strlen (se->array[idx]->name) == namelen)
199 : {
200 406 : if (strlen (se->array[idx]->value) == valuelen)
201 : {
202 : /* The new value has the same length. We can update it
203 : in-place. */
204 403 : memcpy (se->array[idx]->value, value, valuelen);
205 403 : se->array[idx]->is_default = !!set_default;
206 403 : return 0;
207 : }
208 : /* Prepare for update. */
209 3 : freeidx = idx;
210 : }
211 : }
212 :
213 3673 : if (freeidx == -1)
214 : {
215 3619 : 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 3619 : 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 3673 : var = xtrymalloc (sizeof *var + namelen + 1 + valuelen);
239 3673 : if (!var)
240 0 : return gpg_error_from_syserror ();
241 3673 : var->is_default = !!set_default;
242 3673 : memcpy (var->name, string, namelen);
243 3673 : var->name[namelen] = '\0';
244 3673 : var->value = var->name + namelen + 1;
245 3673 : strcpy (var->value, value);
246 :
247 3673 : xfree (se->array[freeidx]);
248 3673 : se->array[freeidx] = var;
249 3673 : 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 1461 : session_env_putenv (session_env_t se, const char *string)
264 : {
265 : const char *s;
266 :
267 1461 : if (!string || !*string)
268 2 : return gpg_error (GPG_ERR_INV_VALUE);
269 1459 : s = strchr (string, '=');
270 1459 : if (s == string)
271 1 : return gpg_error (GPG_ERR_INV_VALUE);
272 1458 : if (!s)
273 504 : return delete_var (se, string);
274 : else
275 954 : 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 3203 : session_env_setenv (session_env_t se, const char *name, const char *value)
283 : {
284 3203 : if (!name || !*name)
285 0 : return gpg_error (GPG_ERR_INV_VALUE);
286 3203 : if (!value)
287 1617 : return delete_var (se, name);
288 : else
289 1586 : 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 2 : session_env_getenv (session_env_t se, const char *name)
302 : {
303 : int idx;
304 :
305 2 : if (!se || !name || !*name)
306 0 : return NULL;
307 :
308 12 : for (idx=0; idx < se->arrayused; idx++)
309 12 : if (se->array[idx] && !strcmp (se->array[idx]->name, name))
310 2 : return se->array[idx]->is_default? NULL : se->array[idx]->value;
311 0 : 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 4326 : 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 4326 : if (r_default)
331 393 : *r_default = 0;
332 4326 : if (!se || !name || !*name)
333 0 : return NULL;
334 :
335 14424 : for (idx=0; idx < se->arrayused; idx++)
336 10405 : if (se->array[idx] && !strcmp (se->array[idx]->name, name))
337 : {
338 307 : if (r_default && se->array[idx]->is_default)
339 305 : *r_default = 1;
340 307 : return se->array[idx]->value;
341 : }
342 :
343 : /* Get the default value with an additional fallback for GPG_TTY. */
344 4019 : defvalue = getenv (name);
345 4019 : if ((!defvalue || !*defvalue) && !strcmp (name, "GPG_TTY")
346 481 : && gnupg_ttyname (0))
347 : {
348 305 : defvalue = gnupg_ttyname (0);
349 : }
350 4019 : 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 1536 : update_var (se, name, strlen (name), defvalue, 1);
359 :
360 3839 : for (idx=0; idx < se->arrayused; idx++)
361 3839 : if (se->array[idx] && !strcmp (se->array[idx]->name, name))
362 : {
363 1536 : if (r_default && se->array[idx]->is_default)
364 0 : *r_default = 1;
365 1536 : return se->array[idx]->value;
366 : }
367 : }
368 :
369 2483 : 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 : }
|