Coverage Report

Created: 2025-10-10 07:09

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
2.01k
{
84
2.01k
    const struct sudo_defs_types *cur;
85
2.01k
    const struct list_member *item;
86
2.01k
    const struct def_values *def;
87
2.01k
    const char *desc;
88
2.01k
    debug_decl(dump_defaults, SUDOERS_DEBUG_DEFAULTS);
89
90
329k
    for (cur = sudo_defs_table; cur->name; cur++) {
91
327k
  if (cur->desc) {
92
327k
      desc = _(cur->desc);
93
327k
      switch (cur->type & T_MASK) {
94
172k
    case T_FLAG:
95
172k
        if (cur->sd_un.flag)
96
90.5k
      sudo_printf(SUDO_CONV_INFO_MSG, "%s\n", desc);
97
172k
        break;
98
82.4k
    case T_STR:
99
104k
    case T_RLIMIT:
100
104k
        if (cur->sd_un.str) {
101
54.2k
      sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.str);
102
54.2k
      sudo_printf(SUDO_CONV_INFO_MSG, "\n");
103
54.2k
        }
104
104k
        break;
105
2.01k
    case T_LOGFAC:
106
2.01k
        if (cur->sd_un.ival) {
107
2.01k
      sudo_printf(SUDO_CONV_INFO_MSG, desc,
108
2.01k
          sudo_logfac2str(cur->sd_un.ival));
109
2.01k
      sudo_printf(SUDO_CONV_INFO_MSG, "\n");
110
2.01k
        }
111
2.01k
        break;
112
4.02k
    case T_LOGPRI:
113
4.02k
        if (cur->sd_un.ival) {
114
4.02k
      sudo_printf(SUDO_CONV_INFO_MSG, desc,
115
4.02k
          sudo_logpri2str(cur->sd_un.ival));
116
4.02k
      sudo_printf(SUDO_CONV_INFO_MSG, "\n");
117
4.02k
        }
118
4.02k
        break;
119
2.01k
    case T_INT:
120
2.01k
        sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.ival);
121
2.01k
        sudo_printf(SUDO_CONV_INFO_MSG, "\n");
122
2.01k
        break;
123
6.03k
    case T_UINT:
124
6.03k
        sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.uival);
125
6.03k
        sudo_printf(SUDO_CONV_INFO_MSG, "\n");
126
6.03k
        break;
127
4.02k
    case T_TIMESPEC: {
128
        /* display timespec in minutes and 10ths of a minute */
129
4.02k
        const int min = cur->sd_un.tspec.tv_sec / 60;
130
4.02k
        int decimin =
131
4.02k
      (((cur->sd_un.tspec.tv_sec % 60) * 10) + 30) / 60;
132
4.02k
        decimin += cur->sd_un.tspec.tv_nsec / 100000000;
133
4.02k
        sudo_printf(SUDO_CONV_INFO_MSG, desc, min, decimin);
134
4.02k
        sudo_printf(SUDO_CONV_INFO_MSG, "\n");
135
4.02k
        break;
136
82.4k
    }
137
4.02k
    case T_MODE:
138
4.02k
        sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.mode);
139
4.02k
        sudo_printf(SUDO_CONV_INFO_MSG, "\n");
140
4.02k
        break;
141
10.0k
    case T_LIST:
142
10.0k
        if (!SLIST_EMPTY(&cur->sd_un.list)) {
143
10.0k
      sudo_printf(SUDO_CONV_INFO_MSG, "%s\n", desc);
144
114k
      SLIST_FOREACH(item, &cur->sd_un.list, entries) {
145
114k
          sudo_printf(SUDO_CONV_INFO_MSG,
146
114k
        "\t%s\n", item->value);
147
114k
      }
148
10.0k
        }
149
10.0k
        break;
150
4.02k
    case T_TIMEOUT:
151
4.02k
        if (cur->sd_un.ival) {
152
2.01k
      sudo_printf(SUDO_CONV_INFO_MSG, desc,
153
2.01k
          cur->sd_un.ival);
154
2.01k
      sudo_printf(SUDO_CONV_INFO_MSG, "\n");
155
2.01k
        }
156
4.02k
        break;
157
14.0k
    case T_TUPLE:
158
24.1k
        for (def = cur->values; def->sval; def++) {
159
24.1k
      if (cur->sd_un.tuple == def->nval) {
160
14.0k
          sudo_printf(SUDO_CONV_INFO_MSG, desc, def->sval);
161
14.0k
          break;
162
14.0k
      }
163
24.1k
        }
164
14.0k
        sudo_printf(SUDO_CONV_INFO_MSG, "\n");
165
14.0k
        break;
166
327k
      }
167
327k
  }
168
327k
    }
169
2.01k
    debug_return;
170
2.01k
}
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
1.17M
{
195
1.17M
    int i;
196
1.17M
    debug_decl(find_default, SUDOERS_DEBUG_DEFAULTS);
197
198
85.5M
    for (i = 0; sudo_defs_table[i].name != NULL; i++) {
199
85.5M
  if (strcmp(name, sudo_defs_table[i].name) == 0)
200
1.17M
      debug_return_int(i);
201
85.5M
    }
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
1.17M
{
218
1.17M
    int rc;
219
1.17M
    debug_decl(parse_default_entry, SUDOERS_DEBUG_DEFAULTS);
220
221
1.17M
    if (file == NULL)
222
22.2k
  file = "front-end";
223
224
1.17M
    sudo_debug_printf(SUDO_DEBUG_INFO, "%s: %s:%d:%d: %s=%s op=%d",
225
1.17M
  __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
1.17M
    if (val == NULL) {
232
542k
  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
464k
  case T_FLAG:
240
464k
      break;
241
0
  case T_TUPLE:
242
0
      if (ISSET(def->type, T_BOOL))
243
0
    break;
244
0
      FALLTHROUGH;
245
78.1k
  default:
246
78.1k
      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
542k
  }
252
542k
    }
253
254
    /* Only lists support append/remove. */
255
1.17M
    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
1.17M
    switch (def->type & T_MASK) {
262
26.0k
  case T_LOGFAC:
263
26.0k
      rc = store_syslogfac(val, def);
264
26.0k
      break;
265
52.0k
  case T_LOGPRI:
266
52.0k
      rc = store_syslogpri(val, def);
267
52.0k
      break;
268
482k
  case T_STR:
269
482k
      if (val != NULL && ISSET(def->type, T_PATH|T_CHPATH)) {
270
196k
    if (!valid_path(ctx, def, val, file, line, column, quiet)) {
271
0
        rc = -1;
272
0
        break;
273
0
    }
274
196k
      }
275
482k
      rc = store_str(val, def);
276
482k
      break;
277
0
  case T_INT:
278
0
      rc = store_int(val, def);
279
0
      break;
280
52.0k
  case T_UINT:
281
52.0k
      rc = store_uint(val, def);
282
52.0k
      break;
283
52.0k
  case T_MODE:
284
52.0k
      rc = store_mode(val, def);
285
52.0k
      break;
286
464k
  case T_FLAG:
287
464k
      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
464k
      def->sd_un.flag = (bool)op;
294
464k
      rc = true;
295
464k
      break;
296
22.0k
  case T_LIST:
297
22.0k
      rc = store_list(val, def, op);
298
22.0k
      break;
299
22.0k
  case T_TIMEOUT:
300
22.0k
      rc = store_timeout(val, def);
301
22.0k
      break;
302
62
  case T_TUPLE:
303
62
      rc = store_tuple(val, def, op);
304
62
      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
1.17M
    }
321
1.17M
    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
1.17M
    debug_return_bool(rc == true);
327
1.17M
}
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
1.17M
{
346
1.17M
    debug_decl(run_callback, SUDOERS_DEBUG_DEFAULTS);
347
348
1.17M
    if (def->callback == NULL)
349
522k
  debug_return_bool(true);
350
651k
    debug_return_bool(def->callback(ctx, file, line, column, &def->sd_un, op));
351
651k
}
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
1.17M
{
361
1.17M
    int idx;
362
1.17M
    debug_decl(set_default, SUDOERS_DEBUG_DEFAULTS);
363
364
1.17M
    sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
365
1.17M
  "%s: setting Defaults %s -> %s", __func__, var, val ? val : "false");
366
367
1.17M
    idx = find_default(ctx, var, file, line, column, quiet);
368
1.17M
    if (idx != -1) {
369
  /* Set parsed value in sudo_defs_table and run callback (if any). */
370
1.17M
  struct sudo_defs_types *def = &sudo_defs_table[idx];
371
1.17M
  if (parse_default_entry(ctx, def, val, op, file, line, column, quiet))
372
1.17M
      debug_return_bool(run_callback(ctx, file, line, column, def, op));
373
1.17M
    }
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
52.9k
{
412
52.9k
    struct early_default *early;
413
52.9k
    bool ret = true;
414
52.9k
    debug_decl(run_early_defaults, SUDOERS_DEBUG_DEFAULTS);
415
416
370k
    for (early = early_defaults; early->idx != -1; early++) {
417
317k
  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
317k
    }
424
52.9k
    debug_return_bool(ret);
425
52.9k
}
426
427
static void
428
free_defs_val(int type, union sudo_defs_val *sd_un)
429
5.94M
{
430
5.94M
    switch (type & T_MASK) {
431
1.49M
  case T_STR:
432
1.89M
  case T_RLIMIT:
433
1.89M
      free(sd_un->str);
434
1.89M
      break;
435
182k
  case T_LIST:
436
182k
      (void)list_op(NULL, 0, &sd_un->list, freeall);
437
182k
      break;
438
5.94M
    }
439
5.94M
    memset(sd_un, 0, sizeof(*sd_un));
440
5.94M
}
441
442
static bool
443
init_passprompt_regex(void)
444
36.4k
{
445
36.4k
    struct list_member *lm;
446
36.4k
    debug_decl(init_passprompt_regex, SUDOERS_DEBUG_DEFAULTS);
447
448
    /* Add initial defaults setting. */
449
36.4k
    lm = calloc(1, sizeof(struct list_member));
450
36.4k
    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
36.4k
    SLIST_INSERT_HEAD(&def_passprompt_regex, lm, entries);
456
457
36.4k
    debug_return_bool(true);
458
36.4k
}
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
36.4k
{
467
36.4k
    static bool firsttime = true;
468
36.4k
    struct sudo_defs_types *def;
469
36.4k
    debug_decl(init_defaults, SUDOERS_DEBUG_DEFAULTS);
470
471
    /* Clear any old settings. */
472
36.4k
    if (!firsttime) {
473
5.97M
  for (def = sudo_defs_table; def->name != NULL; def++)
474
5.94M
      free_defs_val(def->type, &def->sd_un);
475
36.4k
    }
476
477
    /* First initialize the flags. */
478
#ifdef LONG_OTP_PROMPT
479
    def_long_otp_prompt = true;
480
#endif
481
36.4k
#ifndef ALLOW_DOT_PATH
482
36.4k
    def_ignore_dot = true;
483
36.4k
#endif
484
#ifdef ALWAYS_SEND_MAIL
485
    def_mail_always = true;
486
#endif
487
36.4k
#ifdef SEND_MAIL_WHEN_NO_USER
488
36.4k
    def_mail_no_user = true;
489
36.4k
#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
36.4k
#ifndef NO_LECTURE
497
36.4k
    def_lecture = once;
498
36.4k
#endif
499
36.4k
#ifndef NO_AUTHENTICATION
500
36.4k
    def_authenticate = true;
501
36.4k
#endif
502
36.4k
#ifndef NO_ROOT_SUDO
503
36.4k
    def_root_sudo = true;
504
36.4k
#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
36.4k
#ifndef DONT_LEAK_PATH_INFO
515
36.4k
    def_path_info = true;
516
36.4k
#endif
517
#ifdef USE_INSULTS
518
    def_insults = true;
519
#endif
520
#ifdef FQDN
521
    def_fqdn = true;
522
#endif
523
36.4k
#ifdef ENV_EDITOR
524
36.4k
    def_env_editor = true;
525
36.4k
#endif
526
#ifdef UMASK_OVERRIDE
527
    def_umask_override = true;
528
#endif
529
36.4k
#ifdef SUDOERS_NAME_MATCH
530
36.4k
    def_fast_glob = true;
531
36.4k
    def_fdexec = never;
532
#else
533
    def_fdexec = digest_only;
534
#endif
535
36.4k
    def_timestamp_type = TIMESTAMP_TYPE;
536
36.4k
    if ((def_iolog_file = strdup(IOLOG_FILE)) == NULL)
537
0
  goto oom;
538
36.4k
    if ((def_iolog_dir = strdup(_PATH_SUDO_IO_LOGDIR)) == NULL)
539
0
  goto oom;
540
36.4k
    if ((def_sudoers_locale = strdup("C")) == NULL)
541
0
  goto oom;
542
36.4k
    def_env_reset = ENV_RESET;
543
36.4k
    def_set_logname = true;
544
36.4k
    def_closefrom = STDERR_FILENO + 1;
545
36.4k
    def_pam_ruser = true;
546
#ifdef __sun__
547
    def_pam_rhost = true;
548
#endif
549
36.4k
    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
36.4k
    if ((def_pam_login_service = strdup("sudo")) == NULL)
556
0
  goto oom;
557
36.4k
#endif
558
#ifdef NO_PAM_SESSION
559
    def_pam_session = false;
560
#else
561
36.4k
    def_pam_session = true;
562
36.4k
#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
36.4k
    if ((def_rlimit_core = strdup("0,0")) == NULL)
571
0
  goto oom;
572
36.4k
    def_intercept_type = dso;
573
36.4k
    def_intercept_verify = true;
574
36.4k
    def_use_netgroups = true;
575
36.4k
    def_netgroup_tuple = false;
576
36.4k
    def_sudoedit_checkdir = true;
577
36.4k
    def_iolog_mode = S_IRUSR|S_IWUSR;
578
36.4k
    def_log_allowed = true;
579
36.4k
    def_log_denied = true;
580
36.4k
    def_log_format = sudo;
581
36.4k
    def_runas_allow_unknown_id = false;
582
36.4k
    def_noninteractive_auth = false;
583
36.4k
    def_use_pty = true;
584
585
    /* Syslog options need special care since they both strings and ints */
586
36.4k
#if (LOGGING & SLOG_SYSLOG)
587
36.4k
    (void) store_syslogfac(LOGFAC, &sudo_defs_table[I_SYSLOG]);
588
36.4k
    (void) store_syslogpri(PRI_SUCCESS, &sudo_defs_table[I_SYSLOG_GOODPRI]);
589
36.4k
    (void) store_syslogpri(PRI_FAILURE, &sudo_defs_table[I_SYSLOG_BADPRI]);
590
36.4k
#endif
591
592
    /* Password flags also have a string and integer component. */
593
36.4k
    (void) store_tuple("any", &sudo_defs_table[I_LISTPW], 0);
594
36.4k
    (void) store_tuple("all", &sudo_defs_table[I_VERIFYPW], 0);
595
596
    /* Then initialize the int-like things. */
597
36.4k
#ifdef SUDO_UMASK
598
36.4k
    def_umask = SUDO_UMASK;
599
#else
600
    def_umask = ACCESSPERMS;
601
#endif
602
36.4k
    def_loglinelen = MAXLOGFILELEN;
603
36.4k
    def_timestamp_timeout.tv_sec = TIMEOUT * 60;
604
36.4k
    def_passwd_timeout.tv_sec = PASSWORD_TIMEOUT * 60;
605
36.4k
    def_passwd_tries = TRIES_FOR_PASSWORD;
606
#ifdef HAVE_ZLIB_H
607
    def_compress_io = true;
608
#endif
609
36.4k
    def_ignore_audit_errors = true;
610
36.4k
    def_ignore_iolog_errors = false;
611
36.4k
    def_ignore_logfile_errors = true;
612
36.4k
    def_log_passwords = true;
613
36.4k
#ifdef SUDOERS_LOG_CLIENT
614
36.4k
    def_log_server_timeout = 30;
615
36.4k
    def_log_server_verify = true;
616
36.4k
    def_log_server_keepalive = true;
617
36.4k
#endif
618
619
    /* Now do the strings */
620
36.4k
    if ((def_mailto = strdup(MAILTO)) == NULL)
621
0
  goto oom;
622
36.4k
    if ((def_mailsub = strdup(N_(MAILSUBJECT))) == NULL)
623
0
  goto oom;
624
36.4k
    if ((def_badpass_message = strdup(_(INCORRECT_PASSWORD))) == NULL)
625
0
  goto oom;
626
36.4k
#ifdef _PATH_SUDO_LECTURE_DIR
627
36.4k
    if ((def_lecture_status_dir = strdup(_PATH_SUDO_LECTURE_DIR)) == NULL)
628
0
  goto oom;
629
36.4k
#endif
630
36.4k
#ifdef _PATH_SUDO_TIMEDIR
631
36.4k
    if ((def_timestampdir = strdup(_PATH_SUDO_TIMEDIR)) == NULL)
632
0
  goto oom;
633
36.4k
#endif
634
36.4k
    if ((def_passprompt = strdup(_(PASSPROMPT))) == NULL)
635
0
  goto oom;
636
36.4k
    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
36.4k
    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
36.4k
    if ((def_editor = strdup(EDITOR)) == NULL)
657
0
  goto oom;
658
36.4k
    def_set_utmp = true;
659
36.4k
    def_pam_acct_mgmt = true;
660
36.4k
    def_pam_setcred = true;
661
36.4k
    def_pam_silent = true;
662
36.4k
    def_syslog_maxlen = MAXSYSLOGLEN;
663
36.4k
    def_case_insensitive_user = true;
664
36.4k
    def_case_insensitive_group = true;
665
666
    /* Reset the locale. */
667
36.4k
    if (!firsttime) {
668
36.4k
  if (!sudoers_initlocale(NULL, def_sudoers_locale))
669
0
      goto oom;
670
36.4k
    }
671
672
    /* Finally do the lists (currently just environment tables). */
673
36.4k
    if (!init_envtables())
674
0
  goto oom;
675
676
    /* Init eventlog config. */
677
36.4k
    init_eventlog_config();
678
679
    /* Initial iolog password prompt regex. */
680
36.4k
    if (!init_passprompt_regex())
681
0
  debug_return_bool(false);
682
683
36.4k
    firsttime = false;
684
685
36.4k
    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
22.2k
{
698
22.2k
    debug_decl(default_type_matches, SUDOERS_DEBUG_DEFAULTS);
699
700
22.2k
    switch (d->type) {
701
22.2k
    case DEFAULTS:
702
22.2k
  if (ISSET(what, SETDEF_GENERIC))
703
22.2k
      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
22.2k
    }
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
22.2k
{
733
22.2k
    debug_decl(default_binding_matches, SUDOERS_DEBUG_DEFAULTS);
734
735
22.2k
    switch (d->type) {
736
22.2k
    case DEFAULTS:
737
22.2k
  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
0
  if (runaslist_matches(parse_tree, &d->binding->members, NULL) == ALLOW)
744
0
      debug_return_bool(true);
745
0
  break;
746
0
    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
0
    case DEFAULTS_CMND:
751
0
  if (cmndlist_matches(parse_tree, &d->binding->members, NULL, NULL) == ALLOW)
752
0
      debug_return_bool(true);
753
0
  break;
754
22.2k
    }
755
0
    debug_return_bool(false);
756
0
}
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
78.9k
{
767
78.9k
    const struct defaults *d;
768
78.9k
    bool global_defaults = false;
769
78.9k
    bool ret = true;
770
78.9k
    debug_decl(update_defaults, SUDOERS_DEBUG_DEFAULTS);
771
772
78.9k
    sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
773
78.9k
  "what: 0x%02x", what);
774
775
    /* If no defaults list specified, use the global one in the parse tree. */
776
78.9k
    if (defs == NULL) {
777
52.9k
  defs = &parse_tree->defaults;
778
52.9k
  global_defaults = true;
779
52.9k
    }
780
781
    /*
782
     * If using the global defaults list, apply Defaults values marked as early.
783
     */
784
78.9k
    if (global_defaults) {
785
52.9k
  TAILQ_FOREACH(d, defs, entries) {
786
0
      struct early_default *early = is_early_default(d->var);
787
0
      if (early == NULL)
788
0
    continue;
789
790
      /* Defaults type and binding must match. */
791
0
      if (!default_type_matches(d, what) ||
792
0
    !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
0
      if (!set_early_default(ctx, d->var, d->val, d->op, d->file, d->line,
797
0
    d->column, quiet, early))
798
0
    ret = false;
799
0
  }
800
801
  /* Run callbacks for early defaults (if any) */
802
52.9k
  if (!run_early_defaults(ctx))
803
0
      ret = false;
804
52.9k
    }
805
806
    /*
807
     * Set the rest of the defaults and run their callbacks, if any.
808
     */
809
78.9k
    TAILQ_FOREACH(d, defs, entries) {
810
22.2k
  if (global_defaults) {
811
      /* Skip Defaults marked as early, we already did them. */
812
0
      if (is_early_default(d->var))
813
0
    continue;
814
0
  }
815
816
  /* Defaults type and binding must match. */
817
22.2k
  if (!default_type_matches(d, what) ||
818
22.2k
      !default_binding_matches(ctx, parse_tree, d, what))
819
0
      continue;
820
821
  /* Copy the value to sudo_defs_table and run callback (if any) */
822
22.2k
  if (!set_default(ctx, d->var, d->val, d->op, d->file, d->line, d->column, quiet))
823
0
      ret = false;
824
22.2k
    }
825
826
78.9k
    debug_return_bool(ret);
827
78.9k
}
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
2
{
835
2
    const struct defaults *d;
836
2
    bool ret = true;
837
2
    int idx;
838
2
    debug_decl(check_defaults, SUDOERS_DEBUG_DEFAULTS);
839
840
2
    TAILQ_FOREACH(d, &parse_tree->defaults, entries) {
841
0
  idx = find_default(parse_tree->ctx, d->var, d->file, d->line,
842
0
      d->column, quiet);
843
0
  if (idx != -1) {
844
0
      struct sudo_defs_types def = sudo_defs_table[idx];
845
0
      memset(&def.sd_un, 0, sizeof(def.sd_un));
846
0
      if (parse_default_entry(parse_tree->ctx, &def, d->val, d->op,
847
0
        d->file, d->line, d->column, quiet)) {
848
0
    free_defs_val(def.type, &def.sd_un);
849
0
    continue;
850
0
      }
851
0
  }
852
  /* There was an error in the entry. */
853
0
  ret = false;
854
0
    }
855
2
    debug_return_bool(ret);
856
2
}
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
52.0k
{
882
52.0k
    const char *errstr;
883
52.0k
    unsigned int u;
884
52.0k
    debug_decl(store_uint, SUDOERS_DEBUG_DEFAULTS);
885
886
52.0k
    if (str == NULL) {
887
0
  def->sd_un.uival = 0;
888
52.0k
    } else {
889
52.0k
  u = (unsigned int)sudo_strtonum(str, 0, UINT_MAX, &errstr);
890
52.0k
  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
52.0k
  def->sd_un.uival = u;
896
52.0k
    }
897
52.0k
    debug_return_bool(true);
898
52.0k
}
899
900
/* Check resource limit syntax, does not save as rlim_t. */
901
static bool
902
check_rlimit(const char *str, bool soft)
903
0
{
904
0
    const size_t inflen = sizeof("infinity") - 1;
905
0
    debug_decl(check_rlimit, SUDOERS_DEBUG_DEFAULTS);
906
907
0
    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
0
    if (strncmp(str, "infinity", inflen) == 0) {
926
0
  if (str[inflen] == '\0' || (soft && str[inflen] == ','))
927
0
      debug_return_bool(true);
928
0
    }
929
0
    debug_return_bool(false);
930
0
}
931
932
static bool
933
store_rlimit(const char *str, struct sudo_defs_types *def)
934
0
{
935
0
    debug_decl(store_rlimit, SUDOERS_DEBUG_DEFAULTS);
936
937
    /* The special values "user" and "default" are not compound. */
938
0
    if (str != NULL && strcmp(str, "user") != 0 && strcmp(str, "default") != 0) {
939
0
  const char *hard, *soft = str;
940
  /*
941
   * Expect a limit in the form "soft,hard" or "limit" (both soft+hard).
942
   */
943
0
  hard = strchr(str, ',');
944
0
  if (hard != NULL)
945
0
      hard++;
946
0
  else
947
0
      hard = soft;
948
949
0
  if (!check_rlimit(soft, true))
950
0
      debug_return_bool(false);
951
0
  if (!check_rlimit(hard, false))
952
0
      debug_return_bool(false);
953
0
    }
954
955
    /* Store as string, front-end will parse it as a limit. */
956
0
    debug_return_bool(store_str(str, def));
957
0
}
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
72.9k
{
1016
72.9k
    const struct def_values *v;
1017
72.9k
    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
72.9k
    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
72.9k
    } else {
1037
145k
  for (v = def->values; v->sval != NULL; v++) {
1038
145k
      if (strcmp(v->sval, str) == 0) {
1039
72.9k
    def->sd_un.tuple = v->nval;
1040
72.9k
    break;
1041
72.9k
      }
1042
145k
  }
1043
72.9k
  if (v->sval == NULL)
1044
0
      debug_return_bool(false);
1045
72.9k
    }
1046
72.9k
    debug_return_bool(true);
1047
72.9k
}
1048
1049
static int
1050
store_str(const char *str, struct sudo_defs_types *def)
1051
482k
{
1052
482k
    debug_decl(store_str, SUDOERS_DEBUG_DEFAULTS);
1053
1054
482k
    free(def->sd_un.str);
1055
482k
    if (str == NULL) {
1056
78.1k
  def->sd_un.str = NULL;
1057
404k
    } else {
1058
404k
  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
404k
    }
1063
482k
    debug_return_int(true);
1064
482k
}
1065
1066
static bool
1067
store_list(const char *str, struct sudo_defs_types *def, int op)
1068
22.0k
{
1069
22.0k
    debug_decl(store_list, SUDOERS_DEBUG_DEFAULTS);
1070
1071
    /* Remove all old members. */
1072
22.0k
    if (op == false || op == true)
1073
22.0k
  (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
22.0k
    if (str != NULL) {
1077
22.0k
  const char *cp, *ep;
1078
22.0k
  const char *end = str + strlen(str);
1079
22.0k
  const enum list_ops lop = op == '-' ? delete : add;
1080
1081
22.0k
  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
22.0k
  } else {
1085
44.1k
      for (cp = sudo_strsplit(str, end, " \t", &ep); cp != NULL;
1086
22.0k
    cp = sudo_strsplit(NULL, end, " \t", &ep)) {
1087
22.0k
    if (!list_op(cp, (size_t)(ep - cp), &def->sd_un.list, lop))
1088
0
        debug_return_bool(false);
1089
22.0k
      }
1090
22.0k
  }
1091
22.0k
    }
1092
22.0k
    debug_return_bool(true);
1093
22.0k
}
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
62.5k
{
1116
62.5k
    debug_decl(store_syslogfac, SUDOERS_DEBUG_DEFAULTS);
1117
1118
62.5k
    if (str == NULL) {
1119
0
  def->sd_un.ival = false;
1120
0
  debug_return_bool(true);
1121
0
    }
1122
62.5k
    debug_return_bool(sudo_str2logfac(str, &def->sd_un.ival));
1123
62.5k
}
1124
1125
static bool
1126
store_syslogpri(const char *str, struct sudo_defs_types *def)
1127
125k
{
1128
125k
    debug_decl(store_syslogpri, SUDOERS_DEBUG_DEFAULTS);
1129
1130
125k
    if (str == NULL) {
1131
0
  def->sd_un.ival = -1;
1132
0
  debug_return_bool(true);
1133
0
    }
1134
125k
    debug_return_bool(sudo_str2logpri(str, &def->sd_un.ival));
1135
125k
}
1136
1137
static bool
1138
store_mode(const char *str, struct sudo_defs_types *def)
1139
52.0k
{
1140
52.0k
    mode_t mode;
1141
52.0k
    const char *errstr;
1142
52.0k
    debug_decl(store_mode, SUDOERS_DEBUG_DEFAULTS);
1143
1144
52.0k
    if (str == NULL) {
1145
0
  def->sd_un.mode = ACCESSPERMS;
1146
52.0k
    } else {
1147
52.0k
  mode = sudo_strtomode(str, &errstr);
1148
52.0k
  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
52.0k
  def->sd_un.mode = mode;
1154
52.0k
    }
1155
52.0k
    debug_return_bool(true);
1156
52.0k
}
1157
1158
static bool
1159
store_timeout(const char *str, struct sudo_defs_types *def)
1160
22.0k
{
1161
22.0k
    debug_decl(store_mode, SUDOERS_DEBUG_DEFAULTS);
1162
1163
22.0k
    if (str == NULL) {
1164
0
  def->sd_un.ival = 0;
1165
22.0k
    } else {
1166
22.0k
  int seconds = parse_timeout(str);
1167
22.0k
  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
22.0k
  def->sd_un.ival = seconds;
1173
22.0k
    }
1174
22.0k
    debug_return_bool(true);
1175
22.0k
}
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
196k
{
1181
196k
    bool ret = true;
1182
196k
    debug_decl(valid_path, SUDOERS_DEBUG_DEFAULTS);
1183
1184
196k
    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
196k
    if (ISSET(def->type, T_CHPATH)) {
1190
52.0k
  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
144k
    } else {
1197
144k
  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
144k
    }
1204
196k
    debug_return_bool(ret);
1205
196k
}
1206
1207
static bool
1208
list_op(const char *str, size_t len, struct list_members *list,
1209
    enum list_ops op)
1210
226k
{
1211
226k
    struct list_member *cur, *prev = NULL;
1212
226k
    debug_decl(list_op, SUDOERS_DEBUG_DEFAULTS);
1213
1214
226k
    if (op == freeall) {
1215
2.00M
  while ((cur = SLIST_FIRST(list)) != NULL) {
1216
1.80M
      SLIST_REMOVE_HEAD(list, entries);
1217
1.80M
      free(cur->value);
1218
1.80M
      free(cur);
1219
1.80M
  }
1220
204k
  debug_return_bool(true);
1221
204k
    }
1222
1223
22.0k
    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
22.0k
    if (op == add) {
1243
22.0k
  cur = calloc(1, sizeof(struct list_member));
1244
22.0k
  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
22.0k
  SLIST_INSERT_HEAD(list, cur, entries);
1250
22.0k
    }
1251
22.0k
    debug_return_bool(true);
1252
22.0k
}
1253
1254
bool
1255
append_default(const char *var, const char *val, int op,
1256
    char *source, struct defaults_list *defs)
1257
154k
{
1258
154k
    struct defaults *def;
1259
154k
    debug_decl(append_default, SUDOERS_DEBUG_DEFAULTS);
1260
1261
154k
    if ((def = calloc(1, sizeof(*def))) == NULL)
1262
0
  goto oom;
1263
1264
154k
    def->type = DEFAULTS;
1265
154k
    def->op = op;
1266
154k
    if ((def->var = strdup(var)) == NULL) {
1267
0
  goto oom;
1268
0
    }
1269
154k
    if (val != NULL) {
1270
1.12k
  if ((def->val = strdup(val)) == NULL)
1271
0
      goto oom;
1272
1.12k
    }
1273
154k
    def->file = source;
1274
154k
    sudo_rcstr_addref(source);
1275
154k
    TAILQ_INSERT_TAIL(defs, def, entries);
1276
154k
    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
}