Coverage Report

Created: 2022-12-08 06:09

/src/gnupg/common/session-env.c
Line
Count
Source (jump to first uncovered line)
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 <https://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
  { "WAYLAND_DISPLAY" },         /* For the Wayland display engine.  */
74
  { "XDG_SESSION_TYPE" },        /* Used by Qt and other non-GTK toolkits
75
                                    to check for x11 or wayland.  */
76
  { "QT_QPA_PLATFORM" },         /* Used by Qt to explicitly request
77
                                    x11 or wayland; in particular, needed
78
                                    to make Qt use Wayland on Gnome.  */
79
  { "GTK_IM_MODULE" },           /* Used by gtk to select gtk input
80
                                    modules (eg "scim-bridge").  */
81
  { "DBUS_SESSION_BUS_ADDRESS" },/* Used by GNOME3 to talk to gcr over
82
                                    dbus */
83
  { "QT_IM_MODULE" },            /* Used by Qt to select qt input
84
                                      modules (eg "xim").  */
85
  { "INSIDE_EMACS" },            /* Set by Emacs before running a
86
                                    process.  */
87
  { "PINENTRY_USER_DATA", "pinentry-user-data"}
88
                                 /* Used for communication with
89
                                    non-standard Pinentries.  */
90
};
91
92
93
/* Track last allocated arraysize of all objects ever created.  If
94
   nothing has ever been allocated we use INITIAL_ARRAYSIZE and we
95
   will never use more than MAXDEFAULT_ARRAYSIZE for initial
96
   allocation.  Note that this is not reentrant if used with a
97
   preemptive thread model.  */
98
static size_t lastallocatedarraysize;
99
0
#define INITIAL_ARRAYSIZE 8  /* Let's use the number of stdenvnames.  */
100
0
#define CHUNK_ARRAYSIZE 10
101
0
#define MAXDEFAULT_ARRAYSIZE (INITIAL_ARRAYSIZE + CHUNK_ARRAYSIZE * 5)
102
103
104
/* Return the names of standard environment variables one after the
105
   other.  The caller needs to set the value at the address of
106
   ITERATOR initially to 0 and then call this function until it
107
   returns NULL.  If ITERATOR is NULL, a single comma delimited string
108
   with the names is returned; NULL is never returned in this case and
109
   R_ASSNAME is ignored.  */
110
const char *
111
session_env_list_stdenvnames (int *iterator, const char **r_assname)
112
0
{
113
0
  int idx;
114
0
  static char *commastring;
115
116
0
  if (!iterator)
117
0
    {
118
0
      if (!commastring)
119
0
        {
120
0
          size_t len = 0;
121
0
          char *p;
122
123
0
          for (idx = 0; idx < DIM (stdenvnames); idx++)
124
0
            len += strlen (stdenvnames[idx].name) + 1;
125
0
          commastring = xtrymalloc (len);
126
0
          if (!commastring)
127
0
            {
128
0
              log_error ("%s: error allocating string: %s\n", __func__,
129
0
                         gpg_strerror (gpg_error_from_syserror ()));
130
0
              return "GPG_TTY,TERM,DISPLAY";
131
0
            }
132
0
          p = commastring;
133
0
          for (idx = 0; idx < DIM (stdenvnames); idx++)
134
0
            {
135
0
              if (idx)
136
0
                *p++ = ',';
137
0
              p = stpcpy (p, stdenvnames[idx].name);
138
0
            }
139
0
          gpgrt_annotate_leaked_object (commastring);
140
0
        }
141
0
      return commastring;
142
0
    }
143
144
0
  idx = *iterator;
145
0
  if (idx < 0 || idx >= DIM (stdenvnames))
146
0
    return NULL;
147
0
  *iterator = idx + 1;
148
0
  if (r_assname)
149
0
    *r_assname = stdenvnames[idx].assname;
150
0
  return stdenvnames[idx].name;
151
0
}
152
153
154
/* Create a new session environment object.  Return NULL and sets
155
   ERRNO on failure. */
156
session_env_t
157
session_env_new (void)
158
0
{
159
0
  session_env_t se;
160
161
0
  se = xtrycalloc (1, sizeof *se);
162
0
  if (se)
163
0
    {
164
0
      se->arraysize = (lastallocatedarraysize?
165
0
                       lastallocatedarraysize : INITIAL_ARRAYSIZE);
166
0
      se->array = xtrycalloc (se->arraysize, sizeof *se->array);
167
0
      if (!se->array)
168
0
        {
169
0
          xfree (se);
170
0
          se = NULL;
171
0
        }
172
0
    }
173
174
0
  return se;
175
0
}
176
177
178
/* Release a session environment object.  */
179
void
180
session_env_release (session_env_t se)
181
0
{
182
0
  int idx;
183
184
0
  if (!se)
185
0
    return;
186
187
0
  if (se->arraysize > INITIAL_ARRAYSIZE
188
0
      && se->arraysize <= MAXDEFAULT_ARRAYSIZE
189
0
      && se->arraysize > lastallocatedarraysize)
190
0
    lastallocatedarraysize = se->arraysize;
191
192
0
  for (idx=0; idx < se->arrayused; idx++)
193
0
    if (se->array[idx])
194
0
      xfree (se->array[idx]);
195
0
  xfree (se->array);
196
0
  xfree (se);
197
0
}
198
199
200
static gpg_error_t
201
delete_var (session_env_t se, const char *name)
202
0
{
203
0
  int idx;
204
205
0
  for (idx=0; idx < se->arrayused; idx++)
206
0
    if (se->array[idx] && !strcmp (se->array[idx]->name, name))
207
0
      {
208
0
        xfree (se->array[idx]);
209
0
        se->array[idx] = NULL;
210
0
      }
211
0
  return 0;
212
0
}
213
214
215
static gpg_error_t
216
update_var (session_env_t se, const char *string, size_t namelen,
217
            const char *explicit_value, int set_default)
218
0
{
219
0
  int idx;
220
0
  int freeidx = -1;
221
0
  const char *value;
222
0
  size_t valuelen;
223
0
  struct variable_s *var;
224
225
0
  if (explicit_value)
226
0
    value = explicit_value;
227
0
  else
228
0
    value = string + namelen + 1;
229
0
  valuelen = strlen (value);
230
231
0
  for (idx=0; idx < se->arrayused; idx++)
232
0
    {
233
0
      if (!se->array[idx])
234
0
        freeidx = idx;
235
0
      else if (!strncmp (se->array[idx]->name, string, namelen)
236
0
               && strlen (se->array[idx]->name) == namelen)
237
0
        {
238
0
          if (strlen (se->array[idx]->value) == valuelen)
239
0
            {
240
              /* The new value has the same length.  We can update it
241
                 in-place.  */
242
0
              memcpy (se->array[idx]->value, value, valuelen);
243
0
              se->array[idx]->is_default = !!set_default;
244
0
              return 0;
245
0
            }
246
          /* Prepare for update.  */
247
0
          freeidx = idx;
248
0
        }
249
0
    }
250
251
0
  if (freeidx == -1)
252
0
    {
253
0
      if (se->arrayused == se->arraysize)
254
0
        {
255
          /* Reallocate the array. */
256
0
          size_t newsize;
257
0
          struct variable_s **newarray;
258
259
0
          newsize = se->arraysize + CHUNK_ARRAYSIZE;
260
0
          newarray = xtrycalloc (newsize, sizeof *newarray);
261
0
          if (!newarray)
262
0
            return gpg_error_from_syserror ();
263
0
          for (idx=0; idx < se->arrayused; idx++)
264
0
            newarray[idx] = se->array[idx];
265
0
          se->arraysize = newsize;
266
0
          xfree (se->array);
267
0
          se->array = newarray;
268
0
        }
269
0
      freeidx = se->arrayused++;
270
0
    }
271
272
  /* Allocate new memory and return an error if that didn't worked.
273
     Allocating it first allows us to keep the old value; it doesn't
274
     matter that arrayused has already been incremented in case of a
275
     new entry - it will then pint to a NULL slot.  */
276
0
  var = xtrymalloc (sizeof *var + namelen + 1 + valuelen);
277
0
  if (!var)
278
0
    return gpg_error_from_syserror ();
279
0
  var->is_default = !!set_default;
280
0
  memcpy (var->name, string, namelen);
281
0
  var->name[namelen] = '\0';
282
0
  var->value = var->name + namelen + 1;
283
0
  strcpy (var->value, value);
284
285
0
  xfree (se->array[freeidx]);
286
0
  se->array[freeidx] = var;
287
0
  return 0;
288
0
}
289
290
291
/* Set or update an environment variable of the session environment.
292
   String is similar to the putval(3) function but it is reentrant and
293
   takes a copy.  In particular it exhibits this behaviour:
294
295
          <NAME>            Delete envvar NAME
296
          <KEY>=            Set envvar NAME to the empty string
297
          <KEY>=<VALUE>     Set envvar NAME to VALUE
298
299
   On success 0 is returned; on error an gpg-error code.  */
300
gpg_error_t
301
session_env_putenv (session_env_t se, const char *string)
302
0
{
303
0
  const char *s;
304
305
0
  if (!string || !*string)
306
0
    return gpg_error (GPG_ERR_INV_VALUE);
307
0
  s = strchr (string, '=');
308
0
  if (s == string)
309
0
    return gpg_error (GPG_ERR_INV_VALUE);
310
0
  if (!s)
311
0
    return delete_var (se, string);
312
0
  else
313
0
    return update_var (se, string, s - string, NULL, 0);
314
0
}
315
316
317
/* Same as session_env_putenv but with name and value given as distict
318
   values.  */
319
gpg_error_t
320
session_env_setenv (session_env_t se, const char *name, const char *value)
321
0
{
322
0
  if (!name || !*name)
323
0
    return gpg_error (GPG_ERR_INV_VALUE);
324
0
  if (!value)
325
0
    return delete_var (se, name);
326
0
  else
327
0
    return update_var (se, name, strlen (name), value, 0);
328
0
}
329
330
331
332
333
/* Return the value of the environment variable NAME from the SE
334
   object.  If the variable does not exist, NULL is returned.  The
335
   returned value is valid as long as SE is valid and as long it has
336
   not been removed or updated by a call to session_env_putenv.  The
337
   caller MUST not change the returned value. */
338
char *
339
session_env_getenv (session_env_t se, const char *name)
340
0
{
341
0
  int idx;
342
343
0
  if (!se || !name || !*name)
344
0
    return NULL;
345
346
0
  for (idx=0; idx < se->arrayused; idx++)
347
0
    if (se->array[idx] && !strcmp (se->array[idx]->name, name))
348
0
      return se->array[idx]->is_default? NULL : se->array[idx]->value;
349
0
  return NULL;
350
0
}
351
352
353
/* Return the value of the environment variable NAME from the SE
354
   object.  The returned value is valid as long as SE is valid and as
355
   long it has not been removed or updated by a call to
356
   session_env_putenv.  If the variable does not exist, the function
357
   tries to return the value trough a call to getenv; if that returns
358
   a value, this value is recorded and used.  If no value could be
359
   found, returns NULL.  The caller must not change the returned
360
   value. */
361
char *
362
session_env_getenv_or_default (session_env_t se, const char *name,
363
                               int *r_default)
364
0
{
365
0
  int idx;
366
0
  char *defvalue;
367
368
0
  if (r_default)
369
0
    *r_default = 0;
370
0
  if (!se || !name || !*name)
371
0
    return NULL;
372
373
0
  for (idx=0; idx < se->arrayused; idx++)
374
0
    if (se->array[idx] && !strcmp (se->array[idx]->name, name))
375
0
      {
376
0
        if (r_default && se->array[idx]->is_default)
377
0
          *r_default = 1;
378
0
        return se->array[idx]->value;
379
0
      }
380
381
  /* Get the default value with an additional fallback for GPG_TTY.  */
382
0
  defvalue = getenv (name);
383
0
  if ((!defvalue || !*defvalue) && !strcmp (name, "GPG_TTY")
384
0
      && gnupg_ttyname (0))
385
0
    {
386
0
      defvalue = gnupg_ttyname (0);
387
0
    }
388
0
  if (defvalue)
389
0
    {
390
      /* Record the default value for later use so that we are safe
391
         from later modifications of the environment.  We need to take
392
         a copy to better cope with the rules of putenv(3).  We ignore
393
         the error of the update function because we can't return an
394
         explicit error anyway and the following scan would then fail
395
         anyway. */
396
0
      update_var (se, name, strlen (name), defvalue, 1);
397
398
0
      for (idx=0; idx < se->arrayused; idx++)
399
0
        if (se->array[idx] && !strcmp (se->array[idx]->name, name))
400
0
          {
401
0
            if (r_default && se->array[idx]->is_default)
402
0
              *r_default = 1;
403
0
            return se->array[idx]->value;
404
0
          }
405
0
    }
406
407
0
  return NULL;
408
0
}
409
410
411
/* List the entire environment stored in SE.  The caller initially
412
   needs to set the value of ITERATOR to 0 and then call this function
413
   until it returns NULL.  The value is returned at R_VALUE.  If
414
   R_DEFAULT is not NULL, the default flag is stored on return.  The
415
   default flag indicates that the value has been taken from the
416
   process's environment.  The caller must not change the returned
417
   name or value.  */
418
char *
419
session_env_listenv (session_env_t se, int *iterator,
420
                     const char **r_value, int *r_default)
421
0
{
422
0
  int idx = *iterator;
423
424
0
  if (!se || idx < 0)
425
0
    return NULL;
426
427
0
  for (; idx < se->arrayused; idx++)
428
0
    if (se->array[idx])
429
0
      {
430
0
        *iterator = idx+1;
431
0
        if (r_default)
432
0
          *r_default = se->array[idx]->is_default;
433
0
        if (r_value)
434
0
          *r_value = se->array[idx]->value;
435
0
        return se->array[idx]->name;
436
0
      }
437
0
  return NULL;
438
0
}