Coverage Report

Created: 2023-11-19 06:12

/src/p11-kit/p11-kit/conf.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2005 Stefan Walter
3
 * Copyright (c) 2011 Collabora Ltd.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 *
9
 *     * Redistributions of source code must retain the above
10
 *       copyright notice, this list of conditions and the
11
 *       following disclaimer.
12
 *     * Redistributions in binary form must reproduce the
13
 *       above copyright notice, this list of conditions and
14
 *       the following disclaimer in the documentation and/or
15
 *       other materials provided with the distribution.
16
 *     * The names of contributors to this software may not be
17
 *       used to endorse or promote products derived from this
18
 *       software without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30
 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31
 * DAMAGE.
32
 *
33
 *
34
 * CONTRIBUTORS
35
 *  Stef Walter <stef@memberwebs.com>
36
 */
37
38
#include "config.h"
39
40
#include "conf.h"
41
0
#define P11_DEBUG_FLAG P11_DEBUG_CONF
42
#include "debug.h"
43
#include "lexer.h"
44
#include "message.h"
45
#include "path.h"
46
#include "private.h"
47
48
#include <sys/param.h>
49
#include <sys/stat.h>
50
#include <sys/types.h>
51
#ifdef OS_UNIX
52
#include <unistd.h>
53
#endif
54
55
#include <assert.h>
56
#include <ctype.h>
57
#include <dirent.h>
58
#include <errno.h>
59
#include <stdio.h>
60
#include <stdlib.h>
61
#include <string.h>
62
63
#ifdef ENABLE_NLS
64
#include <libintl.h>
65
0
#define _(x) dgettext(PACKAGE_NAME, x)
66
#else
67
#define _(x) (x)
68
#endif
69
70
/* For testing, when the tests assuming user config are run as root. */
71
bool p11_conf_force_user_config = false;
72
73
static int
74
strequal (const char *one, const char *two)
75
0
{
76
0
  return strcmp (one, two) == 0;
77
0
}
78
79
/* -----------------------------------------------------------------------------
80
 * CONFIG PARSER
81
 */
82
83
bool
84
_p11_conf_merge_defaults (p11_dict *map,
85
                          p11_dict *defaults)
86
0
{
87
0
  p11_dictiter iter;
88
0
  void *key;
89
0
  void *value;
90
91
0
  p11_dict_iterate (defaults, &iter);
92
0
  while (p11_dict_next (&iter, &key, &value)) {
93
    /* Only override if not set */
94
0
    if (p11_dict_get (map, key))
95
0
      continue;
96
0
    key = strdup (key);
97
0
    return_val_if_fail (key != NULL, false);
98
0
    value = strdup (value);
99
0
    return_val_if_fail (key != NULL, false);
100
0
    if (!p11_dict_set (map, key, value))
101
0
      return_val_if_reached (false);
102
0
  }
103
104
0
  return true;
105
0
}
106
107
p11_dict *
108
_p11_conf_parse_file (const char* filename,
109
                      struct stat *sb,
110
                      int flags)
111
0
{
112
0
  p11_dict *map = NULL;
113
0
  void *data;
114
0
  p11_lexer lexer;
115
0
  bool failed = false;
116
0
  size_t length;
117
0
  p11_mmap *mmap;
118
0
  int error;
119
120
0
  assert (filename);
121
122
0
  p11_debug ("reading config file: %s", filename);
123
124
0
  mmap = p11_mmap_open (filename, sb, &data, &length);
125
0
  if (mmap == NULL) {
126
0
    error = errno;
127
0
    if ((flags & CONF_IGNORE_MISSING) &&
128
0
        (error == ENOENT || error == ENOTDIR)) {
129
0
      p11_debug ("config file does not exist");
130
131
0
    } else if ((flags & CONF_IGNORE_ACCESS_DENIED) &&
132
0
               (error == EPERM || error == EACCES)) {
133
0
      p11_debug ("config file is inaccessible");
134
135
0
    } else {
136
0
      p11_message_err (error, "couldn't open config file: %s", filename);
137
0
      errno = error;
138
0
      return NULL;
139
0
    }
140
0
  }
141
142
0
  map = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, free, free);
143
0
  return_val_if_fail (map != NULL, NULL);
144
145
  /* Empty config fall through above */
146
0
  if (mmap == NULL)
147
0
    return map;
148
149
0
  p11_lexer_init (&lexer, filename, data, length);
150
0
  while (p11_lexer_next (&lexer, &failed)) {
151
0
    switch (lexer.tok_type) {
152
0
    case TOK_FIELD:
153
0
      p11_debug ("config value: %s: %s", lexer.tok.field.name,
154
0
                 lexer.tok.field.value);
155
0
      if (!p11_dict_set (map, lexer.tok.field.name, lexer.tok.field.value))
156
0
        return_val_if_reached (NULL);
157
0
      lexer.tok.field.name = NULL;
158
0
      lexer.tok.field.value = NULL;
159
0
      break;
160
0
    case TOK_PEM:
161
0
      p11_message (_("%s: unexpected pem block"), filename);
162
0
      failed = true;
163
0
      break;
164
0
    case TOK_SECTION:
165
0
      p11_message (_("%s: unexpected section header"), filename);
166
0
      failed = true;
167
0
      break;
168
0
    case TOK_EOF:
169
0
      assert_not_reached ();
170
0
      break;
171
0
    }
172
173
0
    if (failed)
174
0
      break;
175
0
  }
176
177
0
  p11_lexer_done (&lexer);
178
0
  p11_mmap_close (mmap);
179
180
0
  if (failed) {
181
0
    p11_dict_free (map);
182
0
    map = NULL;
183
0
    errno = EINVAL;
184
0
  }
185
186
0
  return map;
187
0
}
188
189
static int
190
user_config_mode (p11_dict *config,
191
                  int defmode)
192
0
{
193
0
  const char *mode;
194
195
  /* Whether we should use or override from user directory */
196
0
  mode = p11_dict_get (config, "user-config");
197
0
  if (mode == NULL) {
198
0
    return defmode;
199
0
  } else if (strequal (mode, "none")) {
200
0
    return CONF_USER_NONE;
201
0
  } else if (strequal (mode, "merge")) {
202
0
    return CONF_USER_MERGE;
203
0
  } else if (strequal (mode, "only")) {
204
0
    return CONF_USER_ONLY;
205
0
  } else if (strequal (mode, "override")) {
206
0
    return CONF_USER_ONLY;
207
0
  } else {
208
0
    p11_message (_("invalid mode for 'user-config': %s"), mode);
209
0
    return CONF_USER_INVALID;
210
0
  }
211
0
}
212
213
p11_dict *
214
_p11_conf_load_globals (const char *system_conf, const char *user_conf,
215
                        int *user_mode)
216
0
{
217
0
  p11_dict *config = NULL;
218
0
  p11_dict *uconfig = NULL;
219
0
  p11_dict *result = NULL;
220
0
  char *path = NULL;
221
0
  int error = 0;
222
0
  int flags;
223
0
  int mode;
224
225
  /*
226
   * This loads the system and user configs. This depends on the user-config
227
   * value in both the system and user configs. A bit more complex than
228
   * you might imagine, since user-config can be set to 'none' in the
229
   * user configuration, essentially turning itself off.
230
   */
231
232
  /* Load the main configuration */
233
0
  config = _p11_conf_parse_file (system_conf, NULL, CONF_IGNORE_MISSING);
234
0
  if (!config)
235
0
    goto finished;
236
237
  /* Whether we should use or override from user directory */
238
0
  mode = user_config_mode (config, CONF_USER_MERGE);
239
0
  if (mode == CONF_USER_INVALID) {
240
0
    error = EINVAL;
241
0
    goto finished;
242
0
  }
243
244
0
  if (mode != CONF_USER_NONE && !p11_conf_force_user_config) {
245
0
    if (getauxval (AT_SECURE)) {
246
0
      p11_debug ("skipping user config in setuid or setgid program");
247
0
      mode = CONF_USER_NONE;
248
0
#ifdef OS_UNIX
249
0
    } else if (getuid () == 0) {
250
0
      p11_debug ("skipping user config in program running as root");
251
0
      mode = CONF_USER_NONE;
252
0
#endif
253
0
    } else if (secure_getenv ("P11_KIT_NO_USER_CONFIG")) {
254
0
      p11_debug ("skipping user config due to P11_NO_USER_CONFIG");
255
0
      mode = CONF_USER_NONE;
256
0
    }
257
0
  }
258
259
0
  if (mode != CONF_USER_NONE) {
260
0
    path = p11_path_expand (user_conf);
261
0
    if (!path) {
262
0
      error = errno;
263
0
      goto finished;
264
0
    }
265
266
    /* Load up the user configuration, ignore selinux denying us access */
267
0
    flags = CONF_IGNORE_MISSING | CONF_IGNORE_ACCESS_DENIED;
268
0
    uconfig = _p11_conf_parse_file (path, NULL, flags);
269
0
    if (!uconfig) {
270
0
      error = errno;
271
0
      goto finished;
272
0
    }
273
274
    /* Figure out what the user mode is, defaulting to system mode if not set */
275
0
    mode = user_config_mode (uconfig, mode);
276
0
    if (mode == CONF_USER_INVALID) {
277
0
      error = EINVAL;
278
0
      goto finished;
279
0
    }
280
281
    /* If merging, then supplement user config with system values */
282
0
    if (mode == CONF_USER_MERGE) {
283
0
      if (!_p11_conf_merge_defaults (uconfig, config)) {
284
0
        error = errno;
285
0
        goto finished;
286
0
      }
287
0
    }
288
289
    /* If user config valid at all, then replace system with what we have */
290
0
    if (mode != CONF_USER_NONE) {
291
0
      p11_dict_free (config);
292
0
      config = uconfig;
293
0
      uconfig = NULL;
294
0
    }
295
0
  }
296
297
0
  if (user_mode)
298
0
    *user_mode = mode;
299
300
0
  result = config;
301
0
  config = NULL;
302
303
0
finished:
304
0
  free (path);
305
0
  p11_dict_free (config);
306
0
  p11_dict_free (uconfig);
307
0
  errno = error;
308
0
  return result;
309
0
}
310
311
static char *
312
calc_name_from_filename (const char *fname)
313
0
{
314
  /* We eventually want to settle on .module */
315
0
  static const char *const suffix = ".module";
316
0
  static const size_t suffix_len = 7;
317
0
  const char *c = fname;
318
0
  size_t fname_len;
319
0
  size_t name_len;
320
0
  char *name;
321
322
0
  assert (fname);
323
324
  /* Make sure the filename starts with an alphanumeric */
325
0
  if (!isalnum(*c))
326
0
    return NULL;
327
0
  ++c;
328
329
  /* Only allow alnum, _, -, and . */
330
0
  while (*c) {
331
0
    if (!isalnum(*c) && *c != '_' && *c != '-' && *c != '.')
332
0
      return NULL;
333
0
    ++c;
334
0
  }
335
336
  /* Make sure we have one of the suffixes */
337
0
  fname_len = strlen (fname);
338
0
  if (suffix_len >= fname_len)
339
0
    return NULL;
340
0
  name_len = (fname_len - suffix_len);
341
0
  if (strcmp (fname + name_len, suffix) != 0)
342
0
    return NULL;
343
344
0
  name = malloc (name_len + 1);
345
0
  return_val_if_fail (name != NULL, NULL);
346
0
  memcpy (name, fname, name_len);
347
0
  name[name_len] = 0;
348
0
  return name;
349
0
}
350
351
static bool
352
load_config_from_file (const char *configfile,
353
                       struct stat *sb,
354
                       const char *name,
355
                       p11_dict *configs,
356
                       int flags)
357
0
{
358
0
  p11_dict *config;
359
0
  p11_dict *prev;
360
0
  char *key;
361
0
  int error = 0;
362
363
0
  assert (configfile);
364
365
0
  key = calc_name_from_filename (name);
366
0
  if (key == NULL) {
367
0
    p11_message (_("invalid config filename, will be ignored in the future: %s"), configfile);
368
0
    key = strdup (name);
369
0
    return_val_if_fail (key != NULL, false);
370
0
  }
371
372
0
  config = _p11_conf_parse_file (configfile, sb, flags);
373
0
  if (!config) {
374
0
    free (key);
375
0
    return false;
376
0
  }
377
378
0
  prev = p11_dict_get (configs, key);
379
0
  if (prev == NULL) {
380
0
    if (!p11_dict_set (configs, key, config))
381
0
      return_val_if_reached (false);
382
0
    config = NULL;
383
0
  } else {
384
0
    if (!_p11_conf_merge_defaults (prev, config))
385
0
      error = errno;
386
0
    free (key);
387
0
  }
388
389
  /* If still set */
390
0
  p11_dict_free (config);
391
392
0
  if (error) {
393
0
    errno = error;
394
0
    return false;
395
0
  }
396
397
0
  return true;
398
0
}
399
400
static bool
401
load_configs_from_directory (const char *directory,
402
                             p11_dict *configs,
403
                             int flags)
404
0
{
405
0
  struct dirent *dp;
406
0
  struct stat st;
407
0
  DIR *dir;
408
0
  int error = 0;
409
0
  bool is_dir;
410
0
  char *path;
411
412
0
  p11_debug ("loading module configs in: %s", directory);
413
414
  /* First we load all the modules */
415
0
  dir = opendir (directory);
416
0
  if (!dir) {
417
0
    error = errno;
418
0
    if ((flags & CONF_IGNORE_MISSING) &&
419
0
        (errno == ENOENT || errno == ENOTDIR)) {
420
0
      p11_debug ("module configs do not exist");
421
0
      return true;
422
0
    } else if ((flags & CONF_IGNORE_ACCESS_DENIED) &&
423
0
               (errno == EPERM || errno == EACCES)) {
424
0
      p11_debug ("couldn't list inacessible module configs");
425
0
      return true;
426
0
    }
427
0
    p11_message_err (error, _("couldn't list directory: %s"), directory);
428
0
    errno = error;
429
0
    return false;
430
0
  }
431
432
0
  while ((dp = readdir(dir)) != NULL) {
433
0
    path = p11_path_build (directory, dp->d_name, NULL);
434
0
    return_val_if_fail (path != NULL, false);
435
436
0
    if (stat (path, &st) < 0) {
437
0
      error = errno;
438
0
      p11_message_err (error, _("couldn't stat path: %s"), path);
439
0
      free (path);
440
0
      break;
441
0
    }
442
443
0
    is_dir = S_ISDIR (st.st_mode);
444
445
0
    if (!is_dir && !load_config_from_file (path, &st, dp->d_name, configs, flags)) {
446
0
      error = errno;
447
0
      free (path);
448
0
      break;
449
0
    }
450
451
0
    free (path);
452
0
  }
453
454
0
  closedir (dir);
455
456
0
  if (error) {
457
0
    errno = error;
458
0
    return false;
459
0
  }
460
461
0
  return true;
462
0
}
463
464
p11_dict *
465
_p11_conf_load_modules (int mode,
466
                        const char *package_dir,
467
                        const char *system_dir,
468
                        const char *user_dir)
469
0
{
470
0
  p11_dict *configs;
471
0
  char *path;
472
0
  int error = 0;
473
0
  int flags;
474
475
  /* A hash table of name -> config */
476
0
  configs = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal,
477
0
                          free, (p11_destroyer)p11_dict_free);
478
479
  /* Load each user config first, if user config is allowed */
480
0
  if (mode != CONF_USER_NONE) {
481
0
    flags = CONF_IGNORE_MISSING | CONF_IGNORE_ACCESS_DENIED;
482
0
    path = p11_path_expand (user_dir);
483
0
    if (!path)
484
0
      error = errno;
485
0
    else if (!load_configs_from_directory (path, configs, flags))
486
0
      error = errno;
487
0
    free (path);
488
0
    if (error != 0) {
489
0
      p11_dict_free (configs);
490
0
      errno = error;
491
0
      return NULL;
492
0
    }
493
0
  }
494
495
  /*
496
   * Now unless user config is overriding, load system modules.
497
   * Basically if a value for the same config name is not already
498
   * loaded above (in the user configs) then they're loaded here.
499
   */
500
0
  if (mode != CONF_USER_ONLY) {
501
0
    flags = CONF_IGNORE_MISSING;
502
0
    if (!load_configs_from_directory (system_dir, configs, flags) ||
503
0
        !load_configs_from_directory (package_dir, configs, flags)) {
504
0
      error = errno;
505
0
      p11_dict_free (configs);
506
0
      errno = error;
507
0
      return NULL;
508
0
    }
509
0
  }
510
511
0
  return configs;
512
0
}
513
514
bool
515
_p11_conf_parse_boolean (const char *string,
516
                         bool default_value)
517
0
{
518
0
  if (!string)
519
0
    return default_value;
520
521
0
  if (strcmp (string, "yes") == 0) {
522
0
    return true;
523
0
  } else if (strcmp (string, "no") == 0) {
524
0
    return false;
525
0
  } else {
526
0
    p11_message (_("invalid setting '%s' defaulting to '%s'"),
527
0
                 string, default_value ? "yes" : "no");
528
0
    return default_value;
529
0
  }
530
0
}