Coverage Report

Created: 2025-11-11 06:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/sudo/plugins/sudoers/defaults.c
Line
Count
Source
1
/*
2
 * SPDX-License-Identifier: ISC
3
 *
4
 * Copyright (c) 1999-2005, 2007-2023
5
 *  Todd C. Miller <Todd.Miller@sudo.ws>
6
 *
7
 * Permission to use, copy, modify, and distribute this software for any
8
 * purpose with or without fee is hereby granted, provided that the above
9
 * copyright notice and this permission notice appear in all copies.
10
 *
11
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
 *
19
 * Sponsored in part by the Defense Advanced Research Projects
20
 * Agency (DARPA) and Air Force Research Laboratory, Air Force
21
 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
22
 */
23
24
#include <config.h>
25
26
#include <sys/stat.h>
27
#include <stdio.h>
28
#include <stdlib.h>
29
#include <string.h>
30
#include <unistd.h>
31
#include <ctype.h>
32
#include <errno.h>
33
#include <limits.h>
34
#include <syslog.h>
35
36
#include <sudoers.h>
37
#include <sudo_eventlog.h>
38
#include <sudo_iolog.h>
39
#include <gram.h>
40
41
static struct early_default early_defaults[] = {
42
    { I_IGNORE_UNKNOWN_DEFAULTS },
43
#ifdef FQDN
44
    { I_FQDN, true },
45
#else
46
    { I_FQDN },
47
#endif
48
    { I_MATCH_GROUP_BY_GID },
49
    { I_GROUP_PLUGIN },
50
    { I_RUNAS_DEFAULT },
51
    { I_SUDOERS_LOCALE },
52
    { -1 }
53
};
54
55
/*
56
 * Local prototypes.
57
 */
58
static bool store_int(const char *str, struct sudo_defs_types *def);
59
static bool store_list(const char *str, struct sudo_defs_types *def, int op);
60
static bool store_mode(const char *str, struct sudo_defs_types *def);
61
static int  store_str(const char *str, struct sudo_defs_types *def);
62
static bool store_syslogfac(const char *str, struct sudo_defs_types *def);
63
static bool store_syslogpri(const char *str, struct sudo_defs_types *def);
64
static bool store_timeout(const char *str, struct sudo_defs_types *def);
65
static bool store_tuple(const char *str, struct sudo_defs_types *def, int op);
66
static bool store_uint(const char *str, struct sudo_defs_types *def);
67
static bool store_timespec(const char *str, struct sudo_defs_types *def);
68
static bool store_rlimit(const char *str, struct sudo_defs_types *def);
69
static bool store_plugin(const char *str, struct sudo_defs_types *def, int op);
70
static bool list_op(const char *str, size_t, struct list_members *list, enum list_ops op);
71
static bool valid_path(const struct sudoers_context *ctx, const struct sudo_defs_types *def, const char *val, const char *file, int line, int column, bool quiet);
72
73
/*
74
 * Table describing compile-time and run-time options.
75
 */
76
#include <def_data.c>
77
78
/*
79
 * Print version and configure info.
80
 */
81
void
82
dump_defaults(void)
83
0
{
84
0
    const struct sudo_defs_types *cur;
85
0
    const struct list_member *item;
86
0
    const struct def_values *def;
87
0
    const char *desc;
88
0
    debug_decl(dump_defaults, SUDOERS_DEBUG_DEFAULTS);
89
90
0
    for (cur = sudo_defs_table; cur->name; cur++) {
91
0
  if (cur->desc) {
92
0
      desc = _(cur->desc);
93
0
      switch (cur->type & T_MASK) {
94
0
    case T_FLAG:
95
0
        if (cur->sd_un.flag)
96
0
      sudo_printf(SUDO_CONV_INFO_MSG, "%s\n", desc);
97
0
        break;
98
0
    case T_STR:
99
0
    case T_RLIMIT:
100
0
        if (cur->sd_un.str) {
101
0
      sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.str);
102
0
      sudo_printf(SUDO_CONV_INFO_MSG, "\n");
103
0
        }
104
0
        break;
105
0
    case T_LOGFAC:
106
0
        if (cur->sd_un.ival) {
107
0
      sudo_printf(SUDO_CONV_INFO_MSG, desc,
108
0
          sudo_logfac2str(cur->sd_un.ival));
109
0
      sudo_printf(SUDO_CONV_INFO_MSG, "\n");
110
0
        }
111
0
        break;
112
0
    case T_LOGPRI:
113
0
        if (cur->sd_un.ival) {
114
0
      sudo_printf(SUDO_CONV_INFO_MSG, desc,
115
0
          sudo_logpri2str(cur->sd_un.ival));
116
0
      sudo_printf(SUDO_CONV_INFO_MSG, "\n");
117
0
        }
118
0
        break;
119
0
    case T_INT:
120
0
        sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.ival);
121
0
        sudo_printf(SUDO_CONV_INFO_MSG, "\n");
122
0
        break;
123
0
    case T_UINT:
124
0
        sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.uival);
125
0
        sudo_printf(SUDO_CONV_INFO_MSG, "\n");
126
0
        break;
127
0
    case T_TIMESPEC: {
128
        /* display timespec in minutes and 10ths of a minute */
129
0
        const int min = cur->sd_un.tspec.tv_sec / 60;
130
0
        int decimin =
131
0
      (((cur->sd_un.tspec.tv_sec % 60) * 10) + 30) / 60;
132
0
        decimin += cur->sd_un.tspec.tv_nsec / 100000000;
133
0
        sudo_printf(SUDO_CONV_INFO_MSG, desc, min, decimin);
134
0
        sudo_printf(SUDO_CONV_INFO_MSG, "\n");
135
0
        break;
136
0
    }
137
0
    case T_MODE:
138
0
        sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.mode);
139
0
        sudo_printf(SUDO_CONV_INFO_MSG, "\n");
140
0
        break;
141
0
    case T_LIST:
142
0
        if (!SLIST_EMPTY(&cur->sd_un.list)) {
143
0
      sudo_printf(SUDO_CONV_INFO_MSG, "%s\n", desc);
144
0
      SLIST_FOREACH(item, &cur->sd_un.list, entries) {
145
0
          sudo_printf(SUDO_CONV_INFO_MSG,
146
0
        "\t%s\n", item->value);
147
0
      }
148
0
        }
149
0
        break;
150
0
    case T_TIMEOUT:
151
0
        if (cur->sd_un.ival) {
152
0
      sudo_printf(SUDO_CONV_INFO_MSG, desc,
153
0
          cur->sd_un.ival);
154
0
      sudo_printf(SUDO_CONV_INFO_MSG, "\n");
155
0
        }
156
0
        break;
157
0
    case T_TUPLE:
158
0
        for (def = cur->values; def->sval; def++) {
159
0
      if (cur->sd_un.tuple == def->nval) {
160
0
          sudo_printf(SUDO_CONV_INFO_MSG, desc, def->sval);
161
0
          break;
162
0
      }
163
0
        }
164
0
        sudo_printf(SUDO_CONV_INFO_MSG, "\n");
165
0
        break;
166
0
      }
167
0
  }
168
0
    }
169
0
    debug_return;
170
0
}
171
172
static bool
173
defaults_warnx(const struct sudoers_context *ctx, const char *file, int line,
174
    int column, bool quiet, const char * restrict fmt, ...)
175
265
{
176
265
    va_list ap;
177
265
    bool ret;
178
265
    debug_decl(defaults_warnx, SUDOERS_DEBUG_DEFAULTS);
179
180
265
    va_start(ap, fmt);
181
265
    ret = parser_vwarnx(ctx, file, line, column, true, quiet, fmt, ap);
182
265
    va_end(ap);
183
184
265
    debug_return_bool(ret);
185
265
}
186
187
/*
188
 * Find the index of the specified Defaults name in sudo_defs_table[]
189
 * On success, returns the matching index or -1 on failure.
190
 */
191
static int
192
find_default(const struct sudoers_context *ctx, const char *name,
193
    const char *file, int line, int column, bool quiet)
194
16.3k
{
195
16.3k
    int i;
196
16.3k
    debug_decl(find_default, SUDOERS_DEBUG_DEFAULTS);
197
198
2.64M
    for (i = 0; sudo_defs_table[i].name != NULL; i++) {
199
2.62M
  if (strcmp(name, sudo_defs_table[i].name) == 0)
200
620
      debug_return_int(i);
201
2.62M
    }
202
15.6k
    if (!def_ignore_unknown_defaults) {
203
0
  defaults_warnx(ctx, file, line, column, quiet,
204
0
      N_("unknown defaults entry \"%s\""), name);
205
0
    }
206
15.6k
    debug_return_int(-1);
207
15.6k
}
208
209
/*
210
 * Parse a defaults entry, storing the parsed entry in sd_un.
211
 * Returns true on success or false on failure.
212
 */
213
static bool
214
parse_default_entry(const struct sudoers_context *ctx,
215
    struct sudo_defs_types *def, const char *val, int op,
216
    const char *file, int line, int column, bool quiet)
217
620
{
218
620
    int rc;
219
620
    debug_decl(parse_default_entry, SUDOERS_DEBUG_DEFAULTS);
220
221
620
    if (file == NULL)
222
0
  file = "front-end";
223
224
620
    sudo_debug_printf(SUDO_DEBUG_INFO, "%s: %s:%d:%d: %s=%s op=%d",
225
620
  __func__, file, line, column, def->name, val ? val : "", op);
226
227
    /*
228
     * If no value specified, the boolean flag must be set for non-flags.
229
     * Only flags and tuples support boolean "true".
230
     */
231
620
    if (val == NULL) {
232
110
  switch (def->type & T_MASK) {
233
45
  case T_LOGFAC:
234
45
      if (op == true) {
235
    /* Use default syslog facility if none specified. */
236
20
    val = LOGFAC;
237
20
      }
238
45
      break;
239
60
  case T_FLAG:
240
60
      break;
241
0
  case T_TUPLE:
242
0
      if (ISSET(def->type, T_BOOL))
243
0
    break;
244
0
      FALLTHROUGH;
245
5
  default:
246
5
      if (!ISSET(def->type, T_BOOL) || op != false) {
247
5
    defaults_warnx(ctx, file, line, column, quiet,
248
5
        N_("no value specified for \"%s\""), def->name);
249
5
    debug_return_bool(false);
250
5
      }
251
110
  }
252
110
    }
253
254
    /* Only lists support append/remove. */
255
615
    if ((op == '+' || op == '-') && (def->type & T_MASK) != T_LIST) {
256
0
  defaults_warnx(ctx, file, line, column, quiet,
257
0
      N_("invalid operator \"%c=\" for \"%s\""), op, def->name);
258
0
  debug_return_bool(false);
259
0
    }
260
261
615
    switch (def->type & T_MASK) {
262
70
  case T_LOGFAC:
263
70
      rc = store_syslogfac(val, def);
264
70
      break;
265
0
  case T_LOGPRI:
266
0
      rc = store_syslogpri(val, def);
267
0
      break;
268
15
  case T_STR:
269
15
      if (val != NULL && ISSET(def->type, T_PATH|T_CHPATH)) {
270
0
    if (!valid_path(ctx, def, val, file, line, column, quiet)) {
271
0
        rc = -1;
272
0
        break;
273
0
    }
274
0
      }
275
15
      rc = store_str(val, def);
276
15
      break;
277
0
  case T_INT:
278
0
      rc = store_int(val, def);
279
0
      break;
280
0
  case T_UINT:
281
0
      rc = store_uint(val, def);
282
0
      break;
283
0
  case T_MODE:
284
0
      rc = store_mode(val, def);
285
0
      break;
286
60
  case T_FLAG:
287
60
      if (val != NULL) {
288
0
    defaults_warnx(ctx, file, line, column, quiet,
289
0
        N_("option \"%s\" does not take a value"), def->name);
290
0
    rc = -1;
291
0
    break;
292
0
      }
293
60
      def->sd_un.flag = (bool)op;
294
60
      rc = true;
295
60
      break;
296
0
  case T_LIST:
297
0
      rc = store_list(val, def, op);
298
0
      break;
299
0
  case T_TIMEOUT:
300
0
      rc = store_timeout(val, def);
301
0
      break;
302
150
  case T_TUPLE:
303
150
      rc = store_tuple(val, def, op);
304
150
      break;
305
0
  case T_TIMESPEC:
306
0
      rc = store_timespec(val, def);
307
0
      break;
308
0
  case T_PLUGIN:
309
0
      rc = store_plugin(val, def, op);
310
0
      break;
311
320
  case T_RLIMIT:
312
320
      rc = store_rlimit(val, def);
313
320
      break;
314
0
  default:
315
0
      defaults_warnx(ctx, file, line, column, quiet,
316
0
    N_("invalid Defaults type 0x%x for option \"%s\""),
317
0
    def->type, def->name);
318
0
      rc = -1;
319
0
      break;
320
615
    }
321
615
    if (rc == false) {
322
260
  defaults_warnx(ctx, file, line, column, quiet,
323
260
      N_("value \"%s\" is invalid for option \"%s\""), val, def->name);
324
260
    }
325
326
615
    debug_return_bool(rc == true);
327
615
}
328
329
static struct early_default *
330
is_early_default(const char *name)
331
27.0k
{
332
27.0k
    struct early_default *early;
333
27.0k
    debug_decl(is_early_default, SUDOERS_DEBUG_DEFAULTS);
334
335
188k
    for (early = early_defaults; early->idx != -1; early++) {
336
161k
  if (strcmp(name, sudo_defs_table[early->idx].name) == 0)
337
112
      debug_return_ptr(early);
338
161k
    }
339
26.9k
    debug_return_ptr(NULL);
340
26.9k
}
341
342
static bool
343
run_callback(struct sudoers_context *ctx, const char *file, int line,
344
    int column, struct sudo_defs_types *def, int op)
345
244
{
346
244
    debug_decl(run_callback, SUDOERS_DEBUG_DEFAULTS);
347
348
244
    if (def->callback == NULL)
349
244
  debug_return_bool(true);
350
0
    debug_return_bool(def->callback(ctx, file, line, column, &def->sd_un, op));
351
0
}
352
353
/*
354
 * Sets/clears an entry in the defaults structure.
355
 * Runs the callback if present on success.
356
 */
357
bool
358
set_default(struct sudoers_context *ctx, const char *var, const char *val,
359
    int op, const char *file, int line, int column, bool quiet)
360
12.8k
{
361
12.8k
    int idx;
362
12.8k
    debug_decl(set_default, SUDOERS_DEBUG_DEFAULTS);
363
364
12.8k
    sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
365
12.8k
  "%s: setting Defaults %s -> %s", __func__, var, val ? val : "false");
366
367
12.8k
    idx = find_default(ctx, var, file, line, column, quiet);
368
12.8k
    if (idx != -1) {
369
  /* Set parsed value in sudo_defs_table and run callback (if any). */
370
440
  struct sudo_defs_types *def = &sudo_defs_table[idx];
371
440
  if (parse_default_entry(ctx, def, val, op, file, line, column, quiet))
372
228
      debug_return_bool(run_callback(ctx, file, line, column, def, op));
373
440
    }
374
12.6k
    debug_return_bool(false);
375
12.6k
}
376
377
/*
378
 * Like set_default() but stores the matching default value
379
 * and does not run callbacks.
380
 */
381
static bool
382
set_early_default(const struct sudoers_context *ctx, const char *var,
383
    const char *val, int op, const char *file, int line, int column,
384
    bool quiet, struct early_default *early)
385
56
{
386
56
    int idx;
387
56
    debug_decl(set_early_default, SUDOERS_DEBUG_DEFAULTS);
388
389
56
    idx = find_default(ctx, var, file, line, column, quiet);
390
56
    if (idx != -1) {
391
  /* Set parsed value in sudo_defs_table but defer callback (if any). */
392
56
  struct sudo_defs_types *def = &sudo_defs_table[idx];
393
56
  if (parse_default_entry(ctx, def, val, op, file, line, column, quiet)) {
394
56
      if (early->file != NULL)
395
52
    sudo_rcstr_delref(early->file);
396
56
      early->file = sudo_rcstr_addref(file);
397
56
      early->line = line;
398
56
      early->column = column;
399
56
      early->run_callback = true;
400
56
      debug_return_bool(true);
401
56
  }
402
56
    }
403
0
    debug_return_bool(false);
404
0
}
405
406
/*
407
 * Run callbacks for early defaults.
408
 */
409
static bool
410
run_early_defaults(struct sudoers_context *ctx)
411
12
{
412
12
    struct early_default *early;
413
12
    bool ret = true;
414
12
    debug_decl(run_early_defaults, SUDOERS_DEBUG_DEFAULTS);
415
416
84
    for (early = early_defaults; early->idx != -1; early++) {
417
72
  if (early->run_callback) {
418
16
      if (!run_callback(ctx, early->file, early->line, early->column,
419
16
        &sudo_defs_table[early->idx], true))
420
0
    ret = false;
421
16
      early->run_callback = false;
422
16
  }
423
72
    }
424
12
    debug_return_bool(ret);
425
12
}
426
427
static void
428
free_defs_val(int type, union sudo_defs_val *sd_un)
429
1.21k
{
430
1.21k
    switch (type & T_MASK) {
431
290
  case T_STR:
432
386
  case T_RLIMIT:
433
386
      free(sd_un->str);
434
386
      break;
435
35
  case T_LIST:
436
35
      (void)list_op(NULL, 0, &sd_un->list, freeall);
437
35
      break;
438
1.21k
    }
439
1.21k
    memset(sd_un, 0, sizeof(*sd_un));
440
1.21k
}
441
442
static bool
443
init_passprompt_regex(void)
444
8
{
445
8
    struct list_member *lm;
446
8
    debug_decl(init_passprompt_regex, SUDOERS_DEBUG_DEFAULTS);
447
448
    /* Add initial defaults setting. */
449
8
    lm = calloc(1, sizeof(struct list_member));
450
8
    if (lm == NULL || (lm->value = strdup(PASSPROMPT_REGEX)) == NULL) {
451
0
  free(lm);
452
0
  sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
453
0
  debug_return_bool(false);
454
0
    }
455
8
    SLIST_INSERT_HEAD(&def_passprompt_regex, lm, entries);
456
457
8
    debug_return_bool(true);
458
8
}
459
460
/*
461
 * Set default options to compiled-in values.
462
 * Any of these may be overridden at runtime by a "Defaults" file.
463
 */
464
bool
465
init_defaults(void)
466
8
{
467
8
    static bool firsttime = true;
468
8
    struct sudo_defs_types *def;
469
8
    debug_decl(init_defaults, SUDOERS_DEBUG_DEFAULTS);
470
471
    /* Clear any old settings. */
472
8
    if (!firsttime) {
473
1.14k
  for (def = sudo_defs_table; def->name != NULL; def++)
474
1.14k
      free_defs_val(def->type, &def->sd_un);
475
7
    }
476
477
    /* First initialize the flags. */
478
#ifdef LONG_OTP_PROMPT
479
    def_long_otp_prompt = true;
480
#endif
481
8
#ifndef ALLOW_DOT_PATH
482
8
    def_ignore_dot = true;
483
8
#endif
484
#ifdef ALWAYS_SEND_MAIL
485
    def_mail_always = true;
486
#endif
487
8
#ifdef SEND_MAIL_WHEN_NO_USER
488
8
    def_mail_no_user = true;
489
8
#endif
490
#ifdef SEND_MAIL_WHEN_NO_HOST
491
    def_mail_no_host = true;
492
#endif
493
#ifdef SEND_MAIL_WHEN_NOT_OK
494
    def_mail_no_perms = true;
495
#endif
496
8
#ifndef NO_LECTURE
497
8
    def_lecture = once;
498
8
#endif
499
8
#ifndef NO_AUTHENTICATION
500
8
    def_authenticate = true;
501
8
#endif
502
8
#ifndef NO_ROOT_SUDO
503
8
    def_root_sudo = true;
504
8
#endif
505
#ifdef HOST_IN_LOG
506
    def_log_host = true;
507
#endif
508
#ifdef SHELL_IF_NO_ARGS
509
    def_shell_noargs = true;
510
#endif
511
#ifdef SHELL_SETS_HOME
512
    def_set_home = true;
513
#endif
514
8
#ifndef DONT_LEAK_PATH_INFO
515
8
    def_path_info = true;
516
8
#endif
517
#ifdef USE_INSULTS
518
    def_insults = true;
519
#endif
520
#ifdef FQDN
521
    def_fqdn = true;
522
#endif
523
8
#ifdef ENV_EDITOR
524
8
    def_env_editor = true;
525
8
#endif
526
#ifdef UMASK_OVERRIDE
527
    def_umask_override = true;
528
#endif
529
8
#ifdef SUDOERS_NAME_MATCH
530
8
    def_fast_glob = true;
531
8
    def_fdexec = never;
532
#else
533
    def_fdexec = digest_only;
534
#endif
535
8
    def_timestamp_type = TIMESTAMP_TYPE;
536
8
    if ((def_iolog_file = strdup(IOLOG_FILE)) == NULL)
537
0
  goto oom;
538
8
    if ((def_iolog_dir = strdup(_PATH_SUDO_IO_LOGDIR)) == NULL)
539
0
  goto oom;
540
8
    if ((def_sudoers_locale = strdup("C")) == NULL)
541
0
  goto oom;
542
8
    def_env_reset = ENV_RESET;
543
8
    def_set_logname = true;
544
8
    def_closefrom = STDERR_FILENO + 1;
545
8
    def_pam_ruser = true;
546
#ifdef __sun__
547
    def_pam_rhost = true;
548
#endif
549
8
    if ((def_pam_service = strdup("sudo")) == NULL)
550
0
  goto oom;
551
#ifdef HAVE_PAM_LOGIN
552
    if ((def_pam_login_service = strdup("sudo-i")) == NULL)
553
  goto oom;
554
#else
555
8
    if ((def_pam_login_service = strdup("sudo")) == NULL)
556
0
  goto oom;
557
8
#endif
558
#ifdef NO_PAM_SESSION
559
    def_pam_session = false;
560
#else
561
8
    def_pam_session = true;
562
8
#endif
563
#ifdef HAVE_SELINUX
564
    def_selinux = true;
565
#endif
566
#ifdef _PATH_SUDO_ADMIN_FLAG
567
    if ((def_admin_flag = strdup(_PATH_SUDO_ADMIN_FLAG)) == NULL)
568
  goto oom;
569
#endif
570
8
    if ((def_rlimit_core = strdup("0,0")) == NULL)
571
0
  goto oom;
572
8
    def_intercept_type = dso;
573
8
    def_intercept_verify = true;
574
8
    def_use_netgroups = true;
575
8
    def_netgroup_tuple = false;
576
8
    def_sudoedit_checkdir = true;
577
8
    def_iolog_mode = S_IRUSR|S_IWUSR;
578
8
    def_log_allowed = true;
579
8
    def_log_denied = true;
580
8
    def_log_format = sudo;
581
8
    def_runas_allow_unknown_id = false;
582
8
    def_noninteractive_auth = false;
583
8
    def_use_pty = true;
584
585
    /* Syslog options need special care since they both strings and ints */
586
8
#if (LOGGING & SLOG_SYSLOG)
587
8
    (void) store_syslogfac(LOGFAC, &sudo_defs_table[I_SYSLOG]);
588
8
    (void) store_syslogpri(PRI_SUCCESS, &sudo_defs_table[I_SYSLOG_GOODPRI]);
589
8
    (void) store_syslogpri(PRI_FAILURE, &sudo_defs_table[I_SYSLOG_BADPRI]);
590
8
#endif
591
592
    /* Password flags also have a string and integer component. */
593
8
    (void) store_tuple("any", &sudo_defs_table[I_LISTPW], 0);
594
8
    (void) store_tuple("all", &sudo_defs_table[I_VERIFYPW], 0);
595
596
    /* Then initialize the int-like things. */
597
8
#ifdef SUDO_UMASK
598
8
    def_umask = SUDO_UMASK;
599
#else
600
    def_umask = ACCESSPERMS;
601
#endif
602
8
    def_loglinelen = MAXLOGFILELEN;
603
8
    def_timestamp_timeout.tv_sec = TIMEOUT * 60;
604
8
    def_passwd_timeout.tv_sec = PASSWORD_TIMEOUT * 60;
605
8
    def_passwd_tries = TRIES_FOR_PASSWORD;
606
#ifdef HAVE_ZLIB_H
607
    def_compress_io = true;
608
#endif
609
8
    def_ignore_audit_errors = true;
610
8
    def_ignore_iolog_errors = false;
611
8
    def_ignore_logfile_errors = true;
612
8
    def_log_passwords = false;
613
8
#ifdef SUDOERS_LOG_CLIENT
614
8
    def_log_server_timeout = 30;
615
8
    def_log_server_verify = true;
616
8
    def_log_server_keepalive = true;
617
8
#endif
618
619
    /* Now do the strings */
620
8
    if ((def_mailto = strdup(MAILTO)) == NULL)
621
0
  goto oom;
622
8
    if ((def_mailsub = strdup(N_(MAILSUBJECT))) == NULL)
623
0
  goto oom;
624
8
    if ((def_badpass_message = strdup(_(INCORRECT_PASSWORD))) == NULL)
625
0
  goto oom;
626
8
#ifdef _PATH_SUDO_LECTURE_DIR
627
8
    if ((def_lecture_status_dir = strdup(_PATH_SUDO_LECTURE_DIR)) == NULL)
628
0
  goto oom;
629
8
#endif
630
8
#ifdef _PATH_SUDO_TIMEDIR
631
8
    if ((def_timestampdir = strdup(_PATH_SUDO_TIMEDIR)) == NULL)
632
0
  goto oom;
633
8
#endif
634
8
    if ((def_passprompt = strdup(_(PASSPROMPT))) == NULL)
635
0
  goto oom;
636
8
    if ((def_runas_default = strdup(RUNAS_DEFAULT)) == NULL)
637
0
  goto oom;
638
#ifdef _PATH_SUDO_SENDMAIL
639
    if ((def_mailerpath = strdup(_PATH_SUDO_SENDMAIL)) == NULL)
640
  goto oom;
641
#endif
642
8
    if ((def_mailerflags = strdup("-t")) == NULL)
643
0
  goto oom;
644
#if (LOGGING & SLOG_FILE)
645
    if ((def_logfile = strdup(_PATH_SUDO_LOGFILE)) == NULL)
646
  goto oom;
647
#endif
648
#ifdef EXEMPTGROUP
649
    if ((def_exempt_group = strdup(EXEMPTGROUP)) == NULL)
650
  goto oom;
651
#endif
652
#ifdef SECURE_PATH
653
    if ((def_secure_path = strdup(SECURE_PATH)) == NULL)
654
  goto oom;
655
#endif
656
8
    if ((def_editor = strdup(EDITOR)) == NULL)
657
0
  goto oom;
658
8
    def_set_utmp = true;
659
8
    def_pam_acct_mgmt = true;
660
8
    def_pam_setcred = true;
661
8
    def_pam_silent = true;
662
8
    def_syslog_maxlen = MAXSYSLOGLEN;
663
8
    def_case_insensitive_user = true;
664
8
    def_case_insensitive_group = true;
665
666
    /* Reset the locale. */
667
8
    if (!firsttime) {
668
7
  if (!sudoers_initlocale(NULL, def_sudoers_locale))
669
0
      goto oom;
670
7
    }
671
672
    /* Finally do the lists (currently just environment tables). */
673
8
    if (!init_envtables())
674
0
  goto oom;
675
676
    /* Init eventlog config. */
677
8
    init_eventlog_config();
678
679
    /* Initial iolog password prompt regex. */
680
8
    if (!init_passprompt_regex())
681
0
  debug_return_bool(false);
682
683
8
    firsttime = false;
684
685
8
    debug_return_bool(true);
686
0
oom:
687
0
    sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
688
0
    debug_return_bool(false);
689
0
}
690
691
/*
692
 * Check whether a defaults entry matches the specified type.
693
 * Returns true if it matches, else false.
694
 */
695
static bool
696
default_type_matches(const struct defaults *d, int what)
697
13.5k
{
698
13.5k
    debug_decl(default_type_matches, SUDOERS_DEBUG_DEFAULTS);
699
700
13.5k
    switch (d->type) {
701
12.6k
    case DEFAULTS:
702
12.6k
  if (ISSET(what, SETDEF_GENERIC))
703
12.6k
      debug_return_bool(true);
704
0
  break;
705
324
    case DEFAULTS_USER:
706
324
  if (ISSET(what, SETDEF_USER))
707
324
      debug_return_bool(true);
708
0
  break;
709
288
    case DEFAULTS_RUNAS:
710
288
  if (ISSET(what, SETDEF_RUNAS))
711
288
      debug_return_bool(true);
712
0
  break;
713
0
    case DEFAULTS_HOST:
714
0
  if (ISSET(what, SETDEF_HOST))
715
0
      debug_return_bool(true);
716
0
  break;
717
240
    case DEFAULTS_CMND:
718
240
  if (ISSET(what, SETDEF_CMND))
719
240
      debug_return_bool(true);
720
0
  break;
721
13.5k
    }
722
0
    debug_return_bool(false);
723
0
}
724
725
/*
726
 * Check whether a defaults entry's binding matches.
727
 * Returns true if it matches, else false.
728
 */
729
static bool
730
default_binding_matches(const struct sudoers_context *ctx,
731
    struct sudoers_parse_tree *parse_tree, const struct defaults *d, int what)
732
13.5k
{
733
13.5k
    debug_decl(default_binding_matches, SUDOERS_DEBUG_DEFAULTS);
734
735
13.5k
    switch (d->type) {
736
12.6k
    case DEFAULTS:
737
12.6k
  debug_return_bool(true);
738
324
    case DEFAULTS_USER:
739
324
  if (userlist_matches(parse_tree, ctx->user.pw, &d->binding->members) == ALLOW)
740
81
      debug_return_bool(true);
741
243
  break;
742
288
    case DEFAULTS_RUNAS:
743
288
  if (runaslist_matches(parse_tree, &d->binding->members, NULL) == ALLOW)
744
0
      debug_return_bool(true);
745
288
  break;
746
288
    case DEFAULTS_HOST:
747
0
  if (hostlist_matches(parse_tree, ctx->user.pw, &d->binding->members) == ALLOW)
748
0
      debug_return_bool(true);
749
0
  break;
750
240
    case DEFAULTS_CMND:
751
240
  if (cmndlist_matches(parse_tree, &d->binding->members, NULL, NULL) == ALLOW)
752
184
      debug_return_bool(true);
753
56
  break;
754
13.5k
    }
755
587
    debug_return_bool(false);
756
587
}
757
758
/*
759
 * Update the global defaults based on the given defaults list.
760
 * Pass in an OR'd list of which default types to update.
761
 */
762
bool
763
update_defaults(struct sudoers_context *ctx,
764
    struct sudoers_parse_tree *parse_tree,
765
    const struct defaults_list *defs, int what, bool quiet)
766
14
{
767
14
    const struct defaults *d;
768
14
    bool global_defaults = false;
769
14
    bool ret = true;
770
14
    debug_decl(update_defaults, SUDOERS_DEBUG_DEFAULTS);
771
772
14
    sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
773
14
  "what: 0x%02x", what);
774
775
    /* If no defaults list specified, use the global one in the parse tree. */
776
14
    if (defs == NULL) {
777
12
  defs = &parse_tree->defaults;
778
12
  global_defaults = true;
779
12
    }
780
781
    /*
782
     * If using the global defaults list, apply Defaults values marked as early.
783
     */
784
14
    if (global_defaults) {
785
13.5k
  TAILQ_FOREACH(d, defs, entries) {
786
13.5k
      struct early_default *early = is_early_default(d->var);
787
13.5k
      if (early == NULL)
788
13.4k
    continue;
789
790
      /* Defaults type and binding must match. */
791
56
      if (!default_type_matches(d, what) ||
792
56
    !default_binding_matches(ctx, parse_tree, d, what))
793
0
    continue;
794
795
      /* Copy the value to sudo_defs_table and mark as early. */
796
56
      if (!set_early_default(ctx, d->var, d->val, d->op, d->file, d->line,
797
56
    d->column, quiet, early))
798
0
    ret = false;
799
56
  }
800
801
  /* Run callbacks for early defaults (if any) */
802
12
  if (!run_early_defaults(ctx))
803
0
      ret = false;
804
12
    }
805
806
    /*
807
     * Set the rest of the defaults and run their callbacks, if any.
808
     */
809
13.5k
    TAILQ_FOREACH(d, defs, entries) {
810
13.5k
  if (global_defaults) {
811
      /* Skip Defaults marked as early, we already did them. */
812
13.5k
      if (is_early_default(d->var))
813
56
    continue;
814
13.5k
  }
815
816
  /* Defaults type and binding must match. */
817
13.4k
  if (!default_type_matches(d, what) ||
818
13.4k
      !default_binding_matches(ctx, parse_tree, d, what))
819
587
      continue;
820
821
  /* Copy the value to sudo_defs_table and run callback (if any) */
822
12.8k
  if (!set_default(ctx, d->var, d->val, d->op, d->file, d->line, d->column, quiet))
823
12.6k
      ret = false;
824
12.8k
    }
825
826
14
    debug_return_bool(ret);
827
14
}
828
829
/*
830
 * Check all defaults entries without actually setting them.
831
 */
832
bool
833
check_defaults(const struct sudoers_parse_tree *parse_tree, bool quiet)
834
3
{
835
3
    const struct defaults *d;
836
3
    bool ret = true;
837
3
    int idx;
838
3
    debug_decl(check_defaults, SUDOERS_DEBUG_DEFAULTS);
839
840
3.37k
    TAILQ_FOREACH(d, &parse_tree->defaults, entries) {
841
3.37k
  idx = find_default(parse_tree->ctx, d->var, d->file, d->line,
842
3.37k
      d->column, quiet);
843
3.37k
  if (idx != -1) {
844
124
      struct sudo_defs_types def = sudo_defs_table[idx];
845
124
      memset(&def.sd_un, 0, sizeof(def.sd_un));
846
124
      if (parse_default_entry(parse_tree->ctx, &def, d->val, d->op,
847
124
        d->file, d->line, d->column, quiet)) {
848
71
    free_defs_val(def.type, &def.sd_un);
849
71
    continue;
850
71
      }
851
124
  }
852
  /* There was an error in the entry. */
853
3.30k
  ret = false;
854
3.30k
    }
855
3
    debug_return_bool(ret);
856
3
}
857
858
static bool
859
store_int(const char *str, struct sudo_defs_types *def)
860
0
{
861
0
    const char *errstr;
862
0
    int i;
863
0
    debug_decl(store_int, SUDOERS_DEBUG_DEFAULTS);
864
865
0
    if (str == NULL) {
866
0
  def->sd_un.ival = 0;
867
0
    } else {
868
0
  i = (int)sudo_strtonum(str, INT_MIN, INT_MAX, &errstr);
869
0
  if (errstr != NULL) {
870
0
      sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
871
0
    "%s: %s", str, errstr);
872
0
      debug_return_bool(false);
873
0
  }
874
0
  def->sd_un.ival = i;
875
0
    }
876
0
    debug_return_bool(true);
877
0
}
878
879
static bool
880
store_uint(const char *str, struct sudo_defs_types *def)
881
0
{
882
0
    const char *errstr;
883
0
    unsigned int u;
884
0
    debug_decl(store_uint, SUDOERS_DEBUG_DEFAULTS);
885
886
0
    if (str == NULL) {
887
0
  def->sd_un.uival = 0;
888
0
    } else {
889
0
  u = (unsigned int)sudo_strtonum(str, 0, UINT_MAX, &errstr);
890
0
  if (errstr != NULL) {
891
0
      sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
892
0
    "%s: %s", str, errstr);
893
0
      debug_return_bool(false);
894
0
  }
895
0
  def->sd_un.uival = u;
896
0
    }
897
0
    debug_return_bool(true);
898
0
}
899
900
/* Check resource limit syntax, does not save as rlim_t. */
901
static bool
902
check_rlimit(const char *str, bool soft)
903
415
{
904
415
    const size_t inflen = sizeof("infinity") - 1;
905
415
    debug_decl(check_rlimit, SUDOERS_DEBUG_DEFAULTS);
906
907
415
    if (isdigit((unsigned char)*str)) {
908
0
  unsigned long long ullval;
909
0
  char *ep;
910
911
0
  errno = 0;
912
0
#ifdef HAVE_STRTOULL
913
0
  ullval = strtoull(str, &ep, 10);
914
0
  if (str == ep || (errno == ERANGE && ullval == ULLONG_MAX))
915
0
      debug_return_bool(false);
916
#else
917
  ullval = strtoul(str, &ep, 10);
918
  if (str == ep || (errno == ERANGE && ullval == ULONG_MAX))
919
      debug_return_bool(false);
920
#endif
921
0
  if (*ep == '\0' || (soft && *ep == ','))
922
0
      debug_return_bool(true);
923
0
  debug_return_bool(false);
924
0
    }
925
415
    if (strncmp(str, "infinity", inflen) == 0) {
926
190
  if (str[inflen] == '\0' || (soft && str[inflen] == ','))
927
190
      debug_return_bool(true);
928
190
    }
929
225
    debug_return_bool(false);
930
225
}
931
932
static bool
933
store_rlimit(const char *str, struct sudo_defs_types *def)
934
320
{
935
320
    debug_decl(store_rlimit, SUDOERS_DEBUG_DEFAULTS);
936
937
    /* The special values "user" and "default" are not compound. */
938
320
    if (str != NULL && strcmp(str, "user") != 0 && strcmp(str, "default") != 0) {
939
320
  const char *hard, *soft = str;
940
  /*
941
   * Expect a limit in the form "soft,hard" or "limit" (both soft+hard).
942
   */
943
320
  hard = strchr(str, ',');
944
320
  if (hard != NULL)
945
0
      hard++;
946
320
  else
947
320
      hard = soft;
948
949
320
  if (!check_rlimit(soft, true))
950
225
      debug_return_bool(false);
951
95
  if (!check_rlimit(hard, false))
952
0
      debug_return_bool(false);
953
95
    }
954
955
    /* Store as string, front-end will parse it as a limit. */
956
95
    debug_return_bool(store_str(str, def));
957
95
}
958
959
static bool
960
store_timespec(const char *str, struct sudo_defs_types *def)
961
0
{
962
0
    struct timespec ts;
963
0
    char sign = '+';
964
0
    long i;
965
0
    debug_decl(store_timespec, SUDOERS_DEBUG_DEFAULTS);
966
967
0
    sudo_timespecclear(&ts);
968
0
    if (str != NULL) {
969
  /* Convert from minutes to seconds. */
970
0
  if (*str == '+' || *str == '-')
971
0
      sign = *str++;
972
0
  while (*str != '\0' && *str != '.') {
973
0
    if (!isdigit((unsigned char)*str))
974
0
        debug_return_bool(false);  /* invalid number */
975
976
    /* Verify (ts.tv_sec * 10) + (digit * 60) <= TIME_T_MAX. */
977
0
    i = (*str++ - '0') * 60L;
978
0
    if (ts.tv_sec > (TIME_T_MAX - i) / 10)
979
0
        debug_return_bool(false);  /* overflow */
980
0
    ts.tv_sec *= 10;
981
0
    ts.tv_sec += i;
982
0
  }
983
0
  if (*str++ == '.') {
984
0
      long long nsec = 0;
985
986
      /* Convert optional fractional component to seconds and nanosecs. */
987
0
      for (i = 100000000; i > 0; i /= 10) {
988
0
    if (*str == '\0')
989
0
        break;
990
0
    if (!isdigit((unsigned char)*str))
991
0
        debug_return_bool(false);  /* invalid number */
992
0
    nsec += i * (*str++ - '0') * 60LL;
993
0
      }
994
0
      while (nsec >= 1000000000) {
995
0
    if (ts.tv_sec == TIME_T_MAX)
996
0
        debug_return_bool(false);  /* overflow */
997
0
    ts.tv_sec++;
998
0
    nsec -= 1000000000;
999
0
      }
1000
0
      ts.tv_nsec = (long)nsec;
1001
0
  }
1002
0
    }
1003
0
    if (sign == '-') {
1004
0
  def->sd_un.tspec.tv_sec = -ts.tv_sec;
1005
0
  def->sd_un.tspec.tv_nsec = -ts.tv_nsec;
1006
0
    } else {
1007
0
  def->sd_un.tspec.tv_sec = ts.tv_sec;
1008
0
  def->sd_un.tspec.tv_nsec = ts.tv_nsec;
1009
0
    }
1010
0
    debug_return_bool(true);
1011
0
}
1012
1013
static bool
1014
store_tuple(const char *str, struct sudo_defs_types *def, int op)
1015
166
{
1016
166
    const struct def_values *v;
1017
166
    debug_decl(store_tuple, SUDOERS_DEBUG_DEFAULTS);
1018
1019
    /*
1020
     * Look up tuple value by name to find enum def_tuple value.
1021
     * A tuple must have at least two possible values.
1022
     */
1023
166
    if (str == NULL) {
1024
  /*
1025
   * Boolean context: true maps to values[1], false maps to values[0].
1026
   */
1027
0
  if (op == true) {
1028
0
      v = &def->values[1];
1029
0
      def->sd_un.ival = v->nval;
1030
0
  } else if (op == false) {
1031
0
      v = &def->values[0];
1032
0
      def->sd_un.ival = v->nval;
1033
0
  } else {
1034
0
      debug_return_bool(false);
1035
0
  }
1036
166
    } else {
1037
517
  for (v = def->values; v->sval != NULL; v++) {
1038
482
      if (strcmp(v->sval, str) == 0) {
1039
131
    def->sd_un.tuple = v->nval;
1040
131
    break;
1041
131
      }
1042
482
  }
1043
166
  if (v->sval == NULL)
1044
35
      debug_return_bool(false);
1045
166
    }
1046
131
    debug_return_bool(true);
1047
131
}
1048
1049
static int
1050
store_str(const char *str, struct sudo_defs_types *def)
1051
110
{
1052
110
    debug_decl(store_str, SUDOERS_DEBUG_DEFAULTS);
1053
1054
110
    free(def->sd_un.str);
1055
110
    if (str == NULL) {
1056
0
  def->sd_un.str = NULL;
1057
110
    } else {
1058
110
  if ((def->sd_un.str = strdup(str)) == NULL) {
1059
0
      sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
1060
0
      debug_return_int(-1);
1061
0
  }
1062
110
    }
1063
110
    debug_return_int(true);
1064
110
}
1065
1066
static bool
1067
store_list(const char *str, struct sudo_defs_types *def, int op)
1068
0
{
1069
0
    debug_decl(store_list, SUDOERS_DEBUG_DEFAULTS);
1070
1071
    /* Remove all old members. */
1072
0
    if (op == false || op == true)
1073
0
  (void)list_op(NULL, 0, &def->sd_un.list, freeall);
1074
1075
    /* Split str into multiple space-separated words and act on each one. */
1076
0
    if (str != NULL) {
1077
0
  const char *cp, *ep;
1078
0
  const char *end = str + strlen(str);
1079
0
  const enum list_ops lop = op == '-' ? delete : add;
1080
1081
0
  if (ISSET(def->type, T_SPACE)) {
1082
0
      if (!list_op(str, strlen(str), &def->sd_un.list, lop))
1083
0
    debug_return_bool(false);
1084
0
  } else {
1085
0
      for (cp = sudo_strsplit(str, end, " \t", &ep); cp != NULL;
1086
0
    cp = sudo_strsplit(NULL, end, " \t", &ep)) {
1087
0
    if (!list_op(cp, (size_t)(ep - cp), &def->sd_un.list, lop))
1088
0
        debug_return_bool(false);
1089
0
      }
1090
0
  }
1091
0
    }
1092
0
    debug_return_bool(true);
1093
0
}
1094
1095
static bool
1096
store_plugin(const char *str, struct sudo_defs_types *def, int op)
1097
0
{
1098
0
    const enum list_ops lop = op == '-' ? delete : add;
1099
0
    debug_decl(store_plugin, SUDOERS_DEBUG_DEFAULTS);
1100
1101
    /* Remove all old members. */
1102
0
    if (op == false || op == true)
1103
0
  (void)list_op(NULL, 0, &def->sd_un.list, freeall);
1104
1105
0
    if (str != NULL) {
1106
0
  if (!list_op(str, strlen(str), &def->sd_un.list, lop))
1107
0
      debug_return_bool(false);
1108
0
    }
1109
1110
0
    debug_return_bool(true);
1111
0
}
1112
1113
static bool
1114
store_syslogfac(const char *str, struct sudo_defs_types *def)
1115
78
{
1116
78
    debug_decl(store_syslogfac, SUDOERS_DEBUG_DEFAULTS);
1117
1118
78
    if (str == NULL) {
1119
25
  def->sd_un.ival = false;
1120
25
  debug_return_bool(true);
1121
25
    }
1122
53
    debug_return_bool(sudo_str2logfac(str, &def->sd_un.ival));
1123
53
}
1124
1125
static bool
1126
store_syslogpri(const char *str, struct sudo_defs_types *def)
1127
16
{
1128
16
    debug_decl(store_syslogpri, SUDOERS_DEBUG_DEFAULTS);
1129
1130
16
    if (str == NULL) {
1131
0
  def->sd_un.ival = -1;
1132
0
  debug_return_bool(true);
1133
0
    }
1134
16
    debug_return_bool(sudo_str2logpri(str, &def->sd_un.ival));
1135
16
}
1136
1137
static bool
1138
store_mode(const char *str, struct sudo_defs_types *def)
1139
0
{
1140
0
    mode_t mode;
1141
0
    const char *errstr;
1142
0
    debug_decl(store_mode, SUDOERS_DEBUG_DEFAULTS);
1143
1144
0
    if (str == NULL) {
1145
0
  def->sd_un.mode = ACCESSPERMS;
1146
0
    } else {
1147
0
  mode = sudo_strtomode(str, &errstr);
1148
0
  if (errstr != NULL) {
1149
0
      sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
1150
0
    "%s is %s", str, errstr);
1151
0
      debug_return_bool(false);
1152
0
  }
1153
0
  def->sd_un.mode = mode;
1154
0
    }
1155
0
    debug_return_bool(true);
1156
0
}
1157
1158
static bool
1159
store_timeout(const char *str, struct sudo_defs_types *def)
1160
0
{
1161
0
    debug_decl(store_mode, SUDOERS_DEBUG_DEFAULTS);
1162
1163
0
    if (str == NULL) {
1164
0
  def->sd_un.ival = 0;
1165
0
    } else {
1166
0
  int seconds = parse_timeout(str);
1167
0
  if (seconds == -1) {
1168
0
      sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO,
1169
0
    "%s", str);
1170
0
      debug_return_bool(false);
1171
0
  }
1172
0
  def->sd_un.ival = seconds;
1173
0
    }
1174
0
    debug_return_bool(true);
1175
0
}
1176
1177
static bool
1178
valid_path(const struct sudoers_context *ctx, const struct sudo_defs_types *def,
1179
    const char *val, const char *file, int line, int column, bool quiet)
1180
0
{
1181
0
    bool ret = true;
1182
0
    debug_decl(valid_path, SUDOERS_DEBUG_DEFAULTS);
1183
1184
0
    if (strlen(val) >= PATH_MAX) {
1185
0
  defaults_warnx(ctx, file, line, column, quiet,
1186
0
      N_("path name for \"%s\" too long"), def->name);
1187
0
  ret = false;
1188
0
    }
1189
0
    if (ISSET(def->type, T_CHPATH)) {
1190
0
  if (val[0] != '/' && val[0] != '~' && (val[0] != '*' || val[1] != '\0')) {
1191
0
      defaults_warnx(ctx, file, line, column, quiet,
1192
0
    N_("values for \"%s\" must start with a '/', '~', or '*'"),
1193
0
    def->name);
1194
0
      ret = false;
1195
0
  }
1196
0
    } else {
1197
0
  if (val[0] != '/') {
1198
0
      defaults_warnx(ctx, file, line, column, quiet,
1199
0
    N_("values for \"%s\" must start with a '/'"), def->name);
1200
0
      ret = false;
1201
0
  }
1202
1203
0
    }
1204
0
    debug_return_bool(ret);
1205
0
}
1206
1207
static bool
1208
list_op(const char *str, size_t len, struct list_members *list,
1209
    enum list_ops op)
1210
35
{
1211
35
    struct list_member *cur, *prev = NULL;
1212
35
    debug_decl(list_op, SUDOERS_DEBUG_DEFAULTS);
1213
1214
35
    if (op == freeall) {
1215
42
  while ((cur = SLIST_FIRST(list)) != NULL) {
1216
7
      SLIST_REMOVE_HEAD(list, entries);
1217
7
      free(cur->value);
1218
7
      free(cur);
1219
7
  }
1220
35
  debug_return_bool(true);
1221
35
    }
1222
1223
0
    SLIST_FOREACH(cur, list, entries) {
1224
0
  if ((strncmp(cur->value, str, len) == 0 && cur->value[len] == '\0')) {
1225
1226
0
      if (op == add)
1227
0
    debug_return_bool(true); /* already exists */
1228
1229
      /* Delete node */
1230
0
      if (prev == NULL)
1231
0
    SLIST_REMOVE_HEAD(list, entries);
1232
0
      else
1233
0
    SLIST_REMOVE_AFTER(prev, entries);
1234
0
      free(cur->value);
1235
0
      free(cur);
1236
0
      break;
1237
0
  }
1238
0
  prev = cur;
1239
0
    }
1240
1241
    /* Add new node to the head of the list. */
1242
0
    if (op == add) {
1243
0
  cur = calloc(1, sizeof(struct list_member));
1244
0
  if (cur == NULL || (cur->value = strndup(str, len)) == NULL) {
1245
0
      sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
1246
0
      free(cur);
1247
0
      debug_return_bool(false);
1248
0
  }
1249
0
  SLIST_INSERT_HEAD(list, cur, entries);
1250
0
    }
1251
0
    debug_return_bool(true);
1252
0
}
1253
1254
bool
1255
append_default(const char *var, const char *val, int op,
1256
    char *source, struct defaults_list *defs)
1257
0
{
1258
0
    struct defaults *def;
1259
0
    debug_decl(append_default, SUDOERS_DEBUG_DEFAULTS);
1260
1261
0
    if ((def = calloc(1, sizeof(*def))) == NULL)
1262
0
  goto oom;
1263
1264
0
    def->type = DEFAULTS;
1265
0
    def->op = op;
1266
0
    if ((def->var = strdup(var)) == NULL) {
1267
0
  goto oom;
1268
0
    }
1269
0
    if (val != NULL) {
1270
0
  if ((def->val = strdup(val)) == NULL)
1271
0
      goto oom;
1272
0
    }
1273
0
    def->file = source;
1274
0
    sudo_rcstr_addref(source);
1275
0
    TAILQ_INSERT_TAIL(defs, def, entries);
1276
0
    debug_return_bool(true);
1277
1278
0
oom:
1279
0
    if (def != NULL) {
1280
0
  free(def->var);
1281
0
  free(def->val);
1282
0
  free(def);
1283
0
    }
1284
0
    debug_return_bool(false);
1285
0
}
1286
1287
bool
1288
cb_passprompt_regex(struct sudoers_context *ctx, const char *file,
1289
    int line, int column, const union sudo_defs_val *sd_un, int op)
1290
0
{
1291
0
    struct list_member *lm;
1292
0
    const char *errstr;
1293
0
    debug_decl(cb_passprompt_regex, SUDOERS_DEBUG_DEFAULTS);
1294
1295
    /* If adding one or more regexps, make sure they are valid. */
1296
0
    if (op == '+' || op == true) {
1297
0
  SLIST_FOREACH(lm, &sd_un->list, entries) {
1298
0
      if (!sudo_regex_compile(NULL, lm->value, &errstr)) {
1299
0
    defaults_warnx(ctx, file, line, column, false,
1300
0
        U_("invalid regular expression \"%s\": %s"),
1301
0
        lm->value, U_(errstr));
1302
0
    debug_return_bool(false);
1303
0
      }
1304
0
  }
1305
0
    }
1306
1307
0
    debug_return_bool(true);
1308
0
}