Coverage Report

Created: 2026-11-12 06:41

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
0
{
176
0
    va_list ap;
177
0
    bool ret;
178
0
    debug_decl(defaults_warnx, SUDOERS_DEBUG_DEFAULTS);
179
180
0
    va_start(ap, fmt);
181
0
    ret = parser_vwarnx(ctx, file, line, column, true, quiet, fmt, ap);
182
0
    va_end(ap);
183
184
0
    debug_return_bool(ret);
185
0
}
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
0
{
195
0
    int i;
196
0
    debug_decl(find_default, SUDOERS_DEBUG_DEFAULTS);
197
198
0
    for (i = 0; sudo_defs_table[i].name != NULL; i++) {
199
0
  if (strcmp(name, sudo_defs_table[i].name) == 0)
200
0
      debug_return_int(i);
201
0
    }
202
0
    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
0
    debug_return_int(-1);
207
0
}
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
0
{
218
0
    int rc;
219
0
    debug_decl(parse_default_entry, SUDOERS_DEBUG_DEFAULTS);
220
221
0
    if (file == NULL)
222
0
  file = "front-end";
223
224
0
    sudo_debug_printf(SUDO_DEBUG_INFO, "%s: %s:%d:%d: %s=%s op=%d",
225
0
  __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
0
    if (val == NULL) {
232
0
  switch (def->type & T_MASK) {
233
0
  case T_LOGFAC:
234
0
      if (op == true) {
235
    /* Use default syslog facility if none specified. */
236
0
    val = LOGFAC;
237
0
      }
238
0
      break;
239
0
  case T_FLAG:
240
0
      break;
241
0
  case T_TUPLE:
242
0
      if (ISSET(def->type, T_BOOL))
243
0
    break;
244
0
      FALLTHROUGH;
245
0
  default:
246
0
      if (!ISSET(def->type, T_BOOL) || op != false) {
247
0
    defaults_warnx(ctx, file, line, column, quiet,
248
0
        N_("no value specified for \"%s\""), def->name);
249
0
    debug_return_bool(false);
250
0
      }
251
0
  }
252
0
    }
253
254
    /* Only lists support append/remove. */
255
0
    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
0
    switch (def->type & T_MASK) {
262
0
  case T_LOGFAC:
263
0
      rc = store_syslogfac(val, def);
264
0
      break;
265
0
  case T_LOGPRI:
266
0
      rc = store_syslogpri(val, def);
267
0
      break;
268
0
  case T_STR:
269
0
      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
0
      rc = store_str(val, def);
276
0
      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
0
  case T_FLAG:
287
0
      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
0
      def->sd_un.flag = (bool)op;
294
0
      rc = true;
295
0
      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
0
  case T_TUPLE:
303
0
      rc = store_tuple(val, def, op);
304
0
      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
0
  case T_RLIMIT:
312
0
      rc = store_rlimit(val, def);
313
0
      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
0
    }
321
0
    if (rc == false) {
322
0
  defaults_warnx(ctx, file, line, column, quiet,
323
0
      N_("value \"%s\" is invalid for option \"%s\""), val, def->name);
324
0
    }
325
326
0
    debug_return_bool(rc == true);
327
0
}
328
329
static struct early_default *
330
is_early_default(const char *name)
331
0
{
332
0
    struct early_default *early;
333
0
    debug_decl(is_early_default, SUDOERS_DEBUG_DEFAULTS);
334
335
0
    for (early = early_defaults; early->idx != -1; early++) {
336
0
  if (strcmp(name, sudo_defs_table[early->idx].name) == 0)
337
0
      debug_return_ptr(early);
338
0
    }
339
0
    debug_return_ptr(NULL);
340
0
}
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
0
{
346
0
    debug_decl(run_callback, SUDOERS_DEBUG_DEFAULTS);
347
348
0
    if (def->callback == NULL)
349
0
  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
0
{
361
0
    int idx;
362
0
    debug_decl(set_default, SUDOERS_DEBUG_DEFAULTS);
363
364
0
    sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
365
0
  "%s: setting Defaults %s -> %s", __func__, var, val ? val : "false");
366
367
0
    idx = find_default(ctx, var, file, line, column, quiet);
368
0
    if (idx != -1) {
369
  /* Set parsed value in sudo_defs_table and run callback (if any). */
370
0
  struct sudo_defs_types *def = &sudo_defs_table[idx];
371
0
  if (parse_default_entry(ctx, def, val, op, file, line, column, quiet))
372
0
      debug_return_bool(run_callback(ctx, file, line, column, def, op));
373
0
    }
374
0
    debug_return_bool(false);
375
0
}
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
0
{
386
0
    int idx;
387
0
    debug_decl(set_early_default, SUDOERS_DEBUG_DEFAULTS);
388
389
0
    idx = find_default(ctx, var, file, line, column, quiet);
390
0
    if (idx != -1) {
391
  /* Set parsed value in sudo_defs_table but defer callback (if any). */
392
0
  struct sudo_defs_types *def = &sudo_defs_table[idx];
393
0
  if (parse_default_entry(ctx, def, val, op, file, line, column, quiet)) {
394
0
      if (early->file != NULL)
395
0
    sudo_rcstr_delref(early->file);
396
0
      early->file = sudo_rcstr_addref(file);
397
0
      early->line = line;
398
0
      early->column = column;
399
0
      early->run_callback = true;
400
0
      debug_return_bool(true);
401
0
  }
402
0
    }
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
4
{
412
4
    struct early_default *early;
413
4
    bool ret = true;
414
4
    debug_decl(run_early_defaults, SUDOERS_DEBUG_DEFAULTS);
415
416
28
    for (early = early_defaults; early->idx != -1; early++) {
417
24
  if (early->run_callback) {
418
0
      if (!run_callback(ctx, early->file, early->line, early->column,
419
0
        &sudo_defs_table[early->idx], true))
420
0
    ret = false;
421
0
      early->run_callback = false;
422
0
  }
423
24
    }
424
4
    debug_return_bool(ret);
425
4
}
426
427
static void
428
free_defs_val(int type, union sudo_defs_val *sd_un)
429
1.14k
{
430
1.14k
    switch (type & T_MASK) {
431
287
  case T_STR:
432
364
  case T_RLIMIT:
433
364
      free(sd_un->str);
434
364
      break;
435
35
  case T_LIST:
436
35
      (void)list_op(NULL, 0, &sd_un->list, freeall);
437
35
      break;
438
1.14k
    }
439
1.14k
    memset(sd_un, 0, sizeof(*sd_un));
440
1.14k
}
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
0
{
698
0
    debug_decl(default_type_matches, SUDOERS_DEBUG_DEFAULTS);
699
700
0
    switch (d->type) {
701
0
    case DEFAULTS:
702
0
  if (ISSET(what, SETDEF_GENERIC))
703
0
      debug_return_bool(true);
704
0
  break;
705
0
    case DEFAULTS_USER:
706
0
  if (ISSET(what, SETDEF_USER))
707
0
      debug_return_bool(true);
708
0
  break;
709
0
    case DEFAULTS_RUNAS:
710
0
  if (ISSET(what, SETDEF_RUNAS))
711
0
      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
0
    case DEFAULTS_CMND:
718
0
  if (ISSET(what, SETDEF_CMND))
719
0
      debug_return_bool(true);
720
0
  break;
721
0
    }
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
0
{
733
0
    debug_decl(default_binding_matches, SUDOERS_DEBUG_DEFAULTS);
734
735
0
    switch (d->type) {
736
0
    case DEFAULTS:
737
0
  debug_return_bool(true);
738
0
    case DEFAULTS_USER:
739
0
  if (userlist_matches(parse_tree, ctx->user.pw, &d->binding->members) == ALLOW)
740
0
      debug_return_bool(true);
741
0
  break;
742
0
    case DEFAULTS_RUNAS:
743
  /* Only the runas user is matched, not the runas group. */
744
0
  if (runas_userlist_matches(parse_tree, &d->binding->members) == ALLOW)
745
0
      debug_return_bool(true);
746
0
  break;
747
0
    case DEFAULTS_HOST:
748
0
  if (hostlist_matches(parse_tree, ctx->user.pw, &d->binding->members) == ALLOW)
749
0
      debug_return_bool(true);
750
0
  break;
751
0
    case DEFAULTS_CMND:
752
0
  if (cmndlist_matches(parse_tree, &d->binding->members, NULL, NULL) == ALLOW)
753
0
      debug_return_bool(true);
754
0
  break;
755
0
    }
756
0
    debug_return_bool(false);
757
0
}
758
759
/*
760
 * Update the global defaults based on the given defaults list.
761
 * Pass in an OR'd list of which default types to update.
762
 */
763
bool
764
update_defaults(struct sudoers_context *ctx,
765
    struct sudoers_parse_tree *parse_tree,
766
    const struct defaults_list *defs, int what, bool quiet)
767
4
{
768
4
    const struct defaults *d;
769
4
    bool global_defaults = false;
770
4
    bool ret = true;
771
4
    debug_decl(update_defaults, SUDOERS_DEBUG_DEFAULTS);
772
773
4
    sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
774
4
  "what: 0x%02x", what);
775
776
    /* If no defaults list specified, use the global one in the parse tree. */
777
4
    if (defs == NULL) {
778
4
  defs = &parse_tree->defaults;
779
4
  global_defaults = true;
780
4
    }
781
782
    /*
783
     * If using the global defaults list, apply Defaults values marked as early.
784
     */
785
4
    if (global_defaults) {
786
4
  TAILQ_FOREACH(d, defs, entries) {
787
0
      struct early_default *early = is_early_default(d->var);
788
0
      if (early == NULL)
789
0
    continue;
790
791
      /* Defaults type and binding must match. */
792
0
      if (!default_type_matches(d, what) ||
793
0
    !default_binding_matches(ctx, parse_tree, d, what))
794
0
    continue;
795
796
      /* Copy the value to sudo_defs_table and mark as early. */
797
0
      if (!set_early_default(ctx, d->var, d->val, d->op, d->file, d->line,
798
0
    d->column, quiet, early))
799
0
    ret = false;
800
0
  }
801
802
  /* Run callbacks for early defaults (if any) */
803
4
  if (!run_early_defaults(ctx))
804
0
      ret = false;
805
4
    }
806
807
    /*
808
     * Set the rest of the defaults and run their callbacks, if any.
809
     */
810
4
    TAILQ_FOREACH(d, defs, entries) {
811
0
  if (global_defaults) {
812
      /* Skip Defaults marked as early, we already did them. */
813
0
      if (is_early_default(d->var))
814
0
    continue;
815
0
  }
816
817
  /* Defaults type and binding must match. */
818
0
  if (!default_type_matches(d, what) ||
819
0
      !default_binding_matches(ctx, parse_tree, d, what))
820
0
      continue;
821
822
  /* Copy the value to sudo_defs_table and run callback (if any) */
823
0
  if (!set_default(ctx, d->var, d->val, d->op, d->file, d->line, d->column, quiet))
824
0
      ret = false;
825
0
    }
826
827
4
    debug_return_bool(ret);
828
4
}
829
830
/*
831
 * Check all defaults entries without actually setting them.
832
 */
833
bool
834
check_defaults(const struct sudoers_parse_tree *parse_tree, bool quiet)
835
1
{
836
1
    const struct defaults *d;
837
1
    bool ret = true;
838
1
    int idx;
839
1
    debug_decl(check_defaults, SUDOERS_DEBUG_DEFAULTS);
840
841
1
    TAILQ_FOREACH(d, &parse_tree->defaults, entries) {
842
0
  idx = find_default(parse_tree->ctx, d->var, d->file, d->line,
843
0
      d->column, quiet);
844
0
  if (idx != -1) {
845
0
      struct sudo_defs_types def = sudo_defs_table[idx];
846
0
      memset(&def.sd_un, 0, sizeof(def.sd_un));
847
0
      if (parse_default_entry(parse_tree->ctx, &def, d->val, d->op,
848
0
        d->file, d->line, d->column, quiet)) {
849
0
    free_defs_val(def.type, &def.sd_un);
850
0
    continue;
851
0
      }
852
0
  }
853
  /* There was an error in the entry. */
854
0
  ret = false;
855
0
    }
856
1
    debug_return_bool(ret);
857
1
}
858
859
static bool
860
store_int(const char *str, struct sudo_defs_types *def)
861
0
{
862
0
    const char *errstr;
863
0
    int i;
864
0
    debug_decl(store_int, SUDOERS_DEBUG_DEFAULTS);
865
866
0
    if (str == NULL) {
867
0
  def->sd_un.ival = 0;
868
0
    } else {
869
0
  i = (int)sudo_strtonum(str, INT_MIN, INT_MAX, &errstr);
870
0
  if (errstr != NULL) {
871
0
      sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
872
0
    "%s: %s", str, errstr);
873
0
      debug_return_bool(false);
874
0
  }
875
0
  def->sd_un.ival = i;
876
0
    }
877
0
    debug_return_bool(true);
878
0
}
879
880
static bool
881
store_uint(const char *str, struct sudo_defs_types *def)
882
0
{
883
0
    const char *errstr;
884
0
    unsigned int u;
885
0
    debug_decl(store_uint, SUDOERS_DEBUG_DEFAULTS);
886
887
0
    if (str == NULL) {
888
0
  def->sd_un.uival = 0;
889
0
    } else {
890
0
  u = (unsigned int)sudo_strtonum(str, 0, UINT_MAX, &errstr);
891
0
  if (errstr != NULL) {
892
0
      sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
893
0
    "%s: %s", str, errstr);
894
0
      debug_return_bool(false);
895
0
  }
896
0
  def->sd_un.uival = u;
897
0
    }
898
0
    debug_return_bool(true);
899
0
}
900
901
/* Check resource limit syntax, does not save as rlim_t. */
902
static bool
903
check_rlimit(const char *str, bool soft)
904
0
{
905
0
    const size_t inflen = sizeof("infinity") - 1;
906
0
    debug_decl(check_rlimit, SUDOERS_DEBUG_DEFAULTS);
907
908
0
    if (isdigit((unsigned char)*str)) {
909
0
  unsigned long long ullval;
910
0
  char *ep;
911
912
0
  errno = 0;
913
0
#ifdef HAVE_STRTOULL
914
0
  ullval = strtoull(str, &ep, 10);
915
0
  if (str == ep || (errno == ERANGE && ullval == ULLONG_MAX))
916
0
      debug_return_bool(false);
917
#else
918
  ullval = strtoul(str, &ep, 10);
919
  if (str == ep || (errno == ERANGE && ullval == ULONG_MAX))
920
      debug_return_bool(false);
921
#endif
922
0
  if (*ep == '\0' || (soft && *ep == ','))
923
0
      debug_return_bool(true);
924
0
  debug_return_bool(false);
925
0
    }
926
0
    if (strncmp(str, "infinity", inflen) == 0) {
927
0
  if (str[inflen] == '\0' || (soft && str[inflen] == ','))
928
0
      debug_return_bool(true);
929
0
    }
930
0
    debug_return_bool(false);
931
0
}
932
933
static bool
934
store_rlimit(const char *str, struct sudo_defs_types *def)
935
0
{
936
0
    debug_decl(store_rlimit, SUDOERS_DEBUG_DEFAULTS);
937
938
    /* The special values "user" and "default" are not compound. */
939
0
    if (str != NULL && strcmp(str, "user") != 0 && strcmp(str, "default") != 0) {
940
0
  const char *hard, *soft = str;
941
  /*
942
   * Expect a limit in the form "soft,hard" or "limit" (both soft+hard).
943
   */
944
0
  hard = strchr(str, ',');
945
0
  if (hard != NULL)
946
0
      hard++;
947
0
  else
948
0
      hard = soft;
949
950
0
  if (!check_rlimit(soft, true))
951
0
      debug_return_bool(false);
952
0
  if (!check_rlimit(hard, false))
953
0
      debug_return_bool(false);
954
0
    }
955
956
    /* Store as string, front-end will parse it as a limit. */
957
0
    debug_return_bool(store_str(str, def));
958
0
}
959
960
static bool
961
store_timespec(const char *str, struct sudo_defs_types *def)
962
0
{
963
0
    struct timespec ts;
964
0
    char sign = '+';
965
0
    long i;
966
0
    debug_decl(store_timespec, SUDOERS_DEBUG_DEFAULTS);
967
968
0
    sudo_timespecclear(&ts);
969
0
    if (str != NULL) {
970
  /* Convert from minutes to seconds. */
971
0
  if (*str == '+' || *str == '-')
972
0
      sign = *str++;
973
0
  while (*str != '\0' && *str != '.') {
974
0
    if (!isdigit((unsigned char)*str))
975
0
        debug_return_bool(false);  /* invalid number */
976
977
    /* Verify (ts.tv_sec * 10) + (digit * 60) <= TIME_T_MAX. */
978
0
    i = (*str++ - '0') * 60L;
979
0
    if (ts.tv_sec > (TIME_T_MAX - i) / 10)
980
0
        debug_return_bool(false);  /* overflow */
981
0
    ts.tv_sec *= 10;
982
0
    ts.tv_sec += i;
983
0
  }
984
0
  if (*str++ == '.') {
985
0
      long long nsec = 0;
986
987
      /* Convert optional fractional component to seconds and nanosecs. */
988
0
      for (i = 100000000; i > 0; i /= 10) {
989
0
    if (*str == '\0')
990
0
        break;
991
0
    if (!isdigit((unsigned char)*str))
992
0
        debug_return_bool(false);  /* invalid number */
993
0
    nsec += i * (*str++ - '0') * 60LL;
994
0
      }
995
0
      while (nsec >= 1000000000) {
996
0
    if (ts.tv_sec == TIME_T_MAX)
997
0
        debug_return_bool(false);  /* overflow */
998
0
    ts.tv_sec++;
999
0
    nsec -= 1000000000;
1000
0
      }
1001
0
      ts.tv_nsec = (long)nsec;
1002
0
  }
1003
0
    }
1004
0
    if (sign == '-') {
1005
0
  def->sd_un.tspec.tv_sec = -ts.tv_sec;
1006
0
  def->sd_un.tspec.tv_nsec = -ts.tv_nsec;
1007
0
    } else {
1008
0
  def->sd_un.tspec.tv_sec = ts.tv_sec;
1009
0
  def->sd_un.tspec.tv_nsec = ts.tv_nsec;
1010
0
    }
1011
0
    debug_return_bool(true);
1012
0
}
1013
1014
static bool
1015
store_tuple(const char *str, struct sudo_defs_types *def, int op)
1016
16
{
1017
16
    const struct def_values *v;
1018
16
    debug_decl(store_tuple, SUDOERS_DEBUG_DEFAULTS);
1019
1020
    /*
1021
     * Look up tuple value by name to find enum def_tuple value.
1022
     * A tuple must have at least two possible values.
1023
     */
1024
16
    if (str == NULL) {
1025
  /*
1026
   * Boolean context: true maps to values[1], false maps to values[0].
1027
   */
1028
0
  if (op == true) {
1029
0
      v = &def->values[1];
1030
0
      def->sd_un.ival = v->nval;
1031
0
  } else if (op == false) {
1032
0
      v = &def->values[0];
1033
0
      def->sd_un.ival = v->nval;
1034
0
  } else {
1035
0
      debug_return_bool(false);
1036
0
  }
1037
16
    } else {
1038
32
  for (v = def->values; v->sval != NULL; v++) {
1039
32
      if (strcmp(v->sval, str) == 0) {
1040
16
    def->sd_un.tuple = v->nval;
1041
16
    break;
1042
16
      }
1043
32
  }
1044
16
  if (v->sval == NULL)
1045
0
      debug_return_bool(false);
1046
16
    }
1047
16
    debug_return_bool(true);
1048
16
}
1049
1050
static int
1051
store_str(const char *str, struct sudo_defs_types *def)
1052
0
{
1053
0
    debug_decl(store_str, SUDOERS_DEBUG_DEFAULTS);
1054
1055
0
    free(def->sd_un.str);
1056
0
    if (str == NULL) {
1057
0
  def->sd_un.str = NULL;
1058
0
    } else {
1059
0
  if ((def->sd_un.str = strdup(str)) == NULL) {
1060
0
      sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
1061
0
      debug_return_int(-1);
1062
0
  }
1063
0
    }
1064
0
    debug_return_int(true);
1065
0
}
1066
1067
static bool
1068
store_list(const char *str, struct sudo_defs_types *def, int op)
1069
0
{
1070
0
    debug_decl(store_list, SUDOERS_DEBUG_DEFAULTS);
1071
1072
    /* Remove all old members. */
1073
0
    if (op == false || op == true)
1074
0
  (void)list_op(NULL, 0, &def->sd_un.list, freeall);
1075
1076
    /* Split str into multiple space-separated words and act on each one. */
1077
0
    if (str != NULL) {
1078
0
  const char *cp, *ep;
1079
0
  const char *end = str + strlen(str);
1080
0
  const enum list_ops lop = op == '-' ? delete : add;
1081
1082
0
  if (ISSET(def->type, T_SPACE)) {
1083
0
      if (!list_op(str, strlen(str), &def->sd_un.list, lop))
1084
0
    debug_return_bool(false);
1085
0
  } else {
1086
0
      for (cp = sudo_strsplit(str, end, " \t", &ep); cp != NULL;
1087
0
    cp = sudo_strsplit(NULL, end, " \t", &ep)) {
1088
0
    if (!list_op(cp, (size_t)(ep - cp), &def->sd_un.list, lop))
1089
0
        debug_return_bool(false);
1090
0
      }
1091
0
  }
1092
0
    }
1093
0
    debug_return_bool(true);
1094
0
}
1095
1096
static bool
1097
store_plugin(const char *str, struct sudo_defs_types *def, int op)
1098
0
{
1099
0
    const enum list_ops lop = op == '-' ? delete : add;
1100
0
    debug_decl(store_plugin, SUDOERS_DEBUG_DEFAULTS);
1101
1102
    /* Remove all old members. */
1103
0
    if (op == false || op == true)
1104
0
  (void)list_op(NULL, 0, &def->sd_un.list, freeall);
1105
1106
0
    if (str != NULL) {
1107
0
  if (!list_op(str, strlen(str), &def->sd_un.list, lop))
1108
0
      debug_return_bool(false);
1109
0
    }
1110
1111
0
    debug_return_bool(true);
1112
0
}
1113
1114
static bool
1115
store_syslogfac(const char *str, struct sudo_defs_types *def)
1116
8
{
1117
8
    debug_decl(store_syslogfac, SUDOERS_DEBUG_DEFAULTS);
1118
1119
8
    if (str == NULL) {
1120
0
  def->sd_un.ival = false;
1121
0
  debug_return_bool(true);
1122
0
    }
1123
8
    debug_return_bool(sudo_str2logfac(str, &def->sd_un.ival));
1124
8
}
1125
1126
static bool
1127
store_syslogpri(const char *str, struct sudo_defs_types *def)
1128
16
{
1129
16
    debug_decl(store_syslogpri, SUDOERS_DEBUG_DEFAULTS);
1130
1131
16
    if (str == NULL) {
1132
0
  def->sd_un.ival = -1;
1133
0
  debug_return_bool(true);
1134
0
    }
1135
16
    debug_return_bool(sudo_str2logpri(str, &def->sd_un.ival));
1136
16
}
1137
1138
static bool
1139
store_mode(const char *str, struct sudo_defs_types *def)
1140
0
{
1141
0
    mode_t mode;
1142
0
    const char *errstr;
1143
0
    debug_decl(store_mode, SUDOERS_DEBUG_DEFAULTS);
1144
1145
0
    if (str == NULL) {
1146
0
  def->sd_un.mode = ACCESSPERMS;
1147
0
    } else {
1148
0
  mode = sudo_strtomode(str, &errstr);
1149
0
  if (errstr != NULL) {
1150
0
      sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
1151
0
    "%s is %s", str, errstr);
1152
0
      debug_return_bool(false);
1153
0
  }
1154
0
  def->sd_un.mode = mode;
1155
0
    }
1156
0
    debug_return_bool(true);
1157
0
}
1158
1159
static bool
1160
store_timeout(const char *str, struct sudo_defs_types *def)
1161
0
{
1162
0
    debug_decl(store_mode, SUDOERS_DEBUG_DEFAULTS);
1163
1164
0
    if (str == NULL) {
1165
0
  def->sd_un.ival = 0;
1166
0
    } else {
1167
0
  int seconds = parse_timeout(str);
1168
0
  if (seconds == -1) {
1169
0
      sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO,
1170
0
    "%s", str);
1171
0
      debug_return_bool(false);
1172
0
  }
1173
0
  def->sd_un.ival = seconds;
1174
0
    }
1175
0
    debug_return_bool(true);
1176
0
}
1177
1178
static bool
1179
valid_path(const struct sudoers_context *ctx, const struct sudo_defs_types *def,
1180
    const char *val, const char *file, int line, int column, bool quiet)
1181
0
{
1182
0
    bool ret = true;
1183
0
    debug_decl(valid_path, SUDOERS_DEBUG_DEFAULTS);
1184
1185
0
    if (strlen(val) >= PATH_MAX) {
1186
0
  defaults_warnx(ctx, file, line, column, quiet,
1187
0
      N_("path name for \"%s\" too long"), def->name);
1188
0
  ret = false;
1189
0
    }
1190
0
    if (ISSET(def->type, T_CHPATH)) {
1191
0
  if (val[0] != '/' && val[0] != '~' && (val[0] != '*' || val[1] != '\0')) {
1192
0
      defaults_warnx(ctx, file, line, column, quiet,
1193
0
    N_("values for \"%s\" must begin with a '/' or '~', or be '*'"),
1194
0
    def->name);
1195
0
      ret = false;
1196
0
  }
1197
0
    } else {
1198
0
  if (val[0] != '/') {
1199
0
      defaults_warnx(ctx, file, line, column, quiet,
1200
0
    N_("values for \"%s\" must start with a '/'"), def->name);
1201
0
      ret = false;
1202
0
  }
1203
1204
0
    }
1205
0
    debug_return_bool(ret);
1206
0
}
1207
1208
static bool
1209
list_op(const char *str, size_t len, struct list_members *list,
1210
    enum list_ops op)
1211
35
{
1212
35
    struct list_member *cur, *prev = NULL;
1213
35
    debug_decl(list_op, SUDOERS_DEBUG_DEFAULTS);
1214
1215
35
    if (op == freeall) {
1216
42
  while ((cur = SLIST_FIRST(list)) != NULL) {
1217
7
      SLIST_REMOVE_HEAD(list, entries);
1218
7
      free(cur->value);
1219
7
      free(cur);
1220
7
  }
1221
35
  debug_return_bool(true);
1222
35
    }
1223
1224
0
    SLIST_FOREACH(cur, list, entries) {
1225
0
  if ((strncmp(cur->value, str, len) == 0 && cur->value[len] == '\0')) {
1226
1227
0
      if (op == add)
1228
0
    debug_return_bool(true); /* already exists */
1229
1230
      /* Delete node */
1231
0
      if (prev == NULL)
1232
0
    SLIST_REMOVE_HEAD(list, entries);
1233
0
      else
1234
0
    SLIST_REMOVE_AFTER(prev, entries);
1235
0
      free(cur->value);
1236
0
      free(cur);
1237
0
      break;
1238
0
  }
1239
0
  prev = cur;
1240
0
    }
1241
1242
    /* Add new node to the head of the list. */
1243
0
    if (op == add) {
1244
0
  cur = calloc(1, sizeof(struct list_member));
1245
0
  if (cur == NULL || (cur->value = strndup(str, len)) == NULL) {
1246
0
      sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
1247
0
      free(cur);
1248
0
      debug_return_bool(false);
1249
0
  }
1250
0
  SLIST_INSERT_HEAD(list, cur, entries);
1251
0
    }
1252
0
    debug_return_bool(true);
1253
0
}
1254
1255
bool
1256
append_default(const char *var, const char *val, int op,
1257
    char *source, struct defaults_list *defs)
1258
0
{
1259
0
    struct defaults *def;
1260
0
    debug_decl(append_default, SUDOERS_DEBUG_DEFAULTS);
1261
1262
0
    if ((def = calloc(1, sizeof(*def))) == NULL)
1263
0
  goto oom;
1264
1265
0
    def->type = DEFAULTS;
1266
0
    def->op = op;
1267
0
    if ((def->var = strdup(var)) == NULL) {
1268
0
  goto oom;
1269
0
    }
1270
0
    if (val != NULL) {
1271
0
  if ((def->val = strdup(val)) == NULL)
1272
0
      goto oom;
1273
0
    }
1274
0
    def->file = source;
1275
0
    sudo_rcstr_addref(source);
1276
0
    TAILQ_INSERT_TAIL(defs, def, entries);
1277
0
    debug_return_bool(true);
1278
1279
0
oom:
1280
0
    if (def != NULL) {
1281
0
  free(def->var);
1282
0
  free(def->val);
1283
0
  free(def);
1284
0
    }
1285
0
    debug_return_bool(false);
1286
0
}
1287
1288
bool
1289
cb_passprompt_regex(struct sudoers_context *ctx, const char *file,
1290
    int line, int column, const union sudo_defs_val *sd_un, int op)
1291
0
{
1292
0
    struct list_member *lm;
1293
0
    const char *errstr;
1294
0
    debug_decl(cb_passprompt_regex, SUDOERS_DEBUG_DEFAULTS);
1295
1296
    /* If adding one or more regexps, make sure they are valid. */
1297
0
    if (op == '+' || op == true) {
1298
0
  SLIST_FOREACH(lm, &sd_un->list, entries) {
1299
0
      if (!sudo_regex_compile(NULL, lm->value, &errstr)) {
1300
0
    defaults_warnx(ctx, file, line, column, false,
1301
0
        U_("invalid regular expression \"%s\": %s"),
1302
0
        lm->value, U_(errstr));
1303
0
    debug_return_bool(false);
1304
0
      }
1305
0
  }
1306
0
    }
1307
1308
0
    debug_return_bool(true);
1309
0
}