Coverage Report

Created: 2025-08-26 06:57

/src/sudo/plugins/sudoers/sudoers.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * SPDX-License-Identifier: ISC
3
 *
4
 * Copyright (c) 1993-1996, 1998-2023 Todd C. Miller <Todd.Miller@sudo.ws>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 *
18
 * Sponsored in part by the Defense Advanced Research Projects
19
 * Agency (DARPA) and Air Force Research Laboratory, Air Force
20
 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
21
 */
22
23
/*
24
 * This is an open source non-commercial project. Dear PVS-Studio, please check it.
25
 * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
26
 */
27
28
#ifdef __TANDEM
29
# include <floss.h>
30
#endif
31
32
#include <config.h>
33
34
#include <sys/types.h>
35
#include <sys/resource.h>
36
#include <sys/stat.h>
37
#include <sys/socket.h>
38
#include <stdio.h>
39
#include <stdlib.h>
40
#include <string.h>
41
#include <unistd.h>
42
#include <pwd.h>
43
#include <errno.h>
44
#include <fcntl.h>
45
#include <grp.h>
46
#include <netdb.h>
47
#ifdef HAVE_LOGIN_CAP_H
48
# include <login_cap.h>
49
# ifndef LOGIN_DEFROOTCLASS
50
#  define LOGIN_DEFROOTCLASS  "daemon"
51
# endif
52
# ifndef LOGIN_SETENV
53
#  define LOGIN_SETENV  0
54
# endif
55
#endif
56
#ifdef HAVE_SELINUX
57
# include <selinux/selinux.h>
58
#endif
59
#include <ctype.h>
60
#ifndef HAVE_GETADDRINFO
61
# include <compat/getaddrinfo.h>
62
#endif
63
64
#include <sudoers.h>
65
#include <timestamp.h>
66
#include <sudo_iolog.h>
67
68
/*
69
 * Prototypes
70
 */
71
static int set_cmnd(struct sudoers_context *ctx);
72
static bool init_vars(struct sudoers_context *ctx, char * const *);
73
static bool set_loginclass(struct sudoers_context *);
74
static bool set_runaspw(struct sudoers_context *ctx, const char *, bool);
75
static bool set_runasgr(struct sudoers_context *ctx, const char *, bool);
76
77
/*
78
 * Globals
79
 */
80
static char *prev_user;
81
static struct sudoers_context sudoers_ctx = SUDOERS_CONTEXT_INITIALIZER;
82
static struct sudo_nss_list *snl;
83
static bool unknown_runas_uid;
84
static bool unknown_runas_gid;
85
static int cmnd_status = NOT_FOUND_ERROR;
86
static struct defaults_list initial_defaults = TAILQ_HEAD_INITIALIZER(initial_defaults);
87
88
#ifdef __linux__
89
static struct rlimit nproclimit;
90
#endif
91
92
#ifdef SUDOERS_LOG_CLIENT
93
6.61k
# define remote_iologs  (!SLIST_EMPTY(&def_log_servers))
94
#else
95
# define remote_iologs  0
96
#endif
97
98
/*
99
 * Unlimit the number of processes since Linux's setuid() will
100
 * apply resource limits when changing uid and return EAGAIN if
101
 * nproc would be exceeded by the uid switch.
102
 */
103
static void
104
unlimit_nproc(void)
105
29.2k
{
106
29.2k
#ifdef __linux__
107
29.2k
    struct rlimit rl;
108
29.2k
    debug_decl(unlimit_nproc, SUDOERS_DEBUG_UTIL);
109
110
29.2k
    if (getrlimit(RLIMIT_NPROC, &nproclimit) != 0)
111
0
      sudo_warn("getrlimit(RLIMIT_NPROC)");
112
29.2k
    rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
113
29.2k
    if (setrlimit(RLIMIT_NPROC, &rl) != 0) {
114
0
  rl.rlim_cur = rl.rlim_max = nproclimit.rlim_max;
115
0
  if (setrlimit(RLIMIT_NPROC, &rl) != 0)
116
0
      sudo_warn("setrlimit(RLIMIT_NPROC)");
117
0
    }
118
29.2k
    debug_return;
119
29.2k
#endif /* __linux__ */
120
29.2k
}
121
122
/*
123
 * Restore saved value of RLIMIT_NPROC.
124
 */
125
static void
126
restore_nproc(void)
127
29.2k
{
128
29.2k
#ifdef __linux__
129
29.2k
    debug_decl(restore_nproc, SUDOERS_DEBUG_UTIL);
130
131
29.2k
    if (setrlimit(RLIMIT_NPROC, &nproclimit) != 0)
132
0
  sudo_warn("setrlimit(RLIMIT_NPROC)");
133
134
29.2k
    debug_return;
135
29.2k
#endif /* __linux__ */
136
29.2k
}
137
138
/*
139
 * Re-initialize Defaults settings.
140
 * We do not warn, log or send mail for errors when reinitializing,
141
 * this would have already been done the first time through.
142
 */
143
static bool
144
sudoers_reinit_defaults(struct sudoers_context *ctx)
145
6.39k
{
146
6.39k
    struct sudo_nss *nss, *nss_next;
147
6.39k
    sudoers_logger_t logger = sudoers_error_hook;
148
6.39k
    debug_decl(sudoers_reinit_defaults, SUDOERS_DEBUG_PLUGIN);
149
150
6.39k
    if (!init_defaults()) {
151
0
  sudo_warnx("%s", U_("unable to initialize sudoers default values"));
152
0
  debug_return_bool(false);
153
0
    }
154
155
    /* It should not be possible for the initial defaults to fail to apply. */
156
6.39k
    if (!update_defaults(ctx, NULL, &initial_defaults,
157
6.39k
      SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER|SETDEF_RUNAS, false))
158
0
  debug_return_bool(false);
159
160
    /* Disable error logging while re-processing defaults. */
161
6.39k
    sudoers_error_hook = NULL;
162
163
6.39k
    TAILQ_FOREACH_SAFE(nss, snl, entries, nss_next) {
164
  /* Missing/invalid defaults is not a fatal error. */
165
6.39k
  if (nss->getdefs(ctx, nss) != -1) {
166
6.39k
      (void)update_defaults(ctx, nss->parse_tree, NULL,
167
6.39k
    SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER|SETDEF_RUNAS, true);
168
6.39k
  }
169
6.39k
    }
170
171
    /* Restore error logging. */
172
6.39k
    sudoers_error_hook = logger;
173
174
    /* No need to check the admin flag file multiple times. */
175
6.39k
    if (ISSET(ctx->mode, MODE_POLICY_INTERCEPTED)) {
176
0
  free(def_admin_flag);
177
0
  def_admin_flag = NULL;
178
0
    }
179
180
6.39k
    debug_return_bool(true);
181
6.39k
}
182
183
int
184
sudoers_init(void *info, sudoers_logger_t logger, char * const envp[])
185
27.3k
{
186
27.3k
    struct sudo_nss *nss, *nss_next;
187
27.3k
    int oldlocale, sources = 0;
188
27.3k
    static int ret = -1;
189
27.3k
    debug_decl(sudoers_init, SUDOERS_DEBUG_PLUGIN);
190
191
    /* Only initialize once. */
192
27.3k
    if (snl != NULL)
193
0
  debug_return_int(ret);
194
195
27.3k
    bindtextdomain("sudoers", LOCALEDIR);
196
197
    /* Hook up logging function for parse errors. */
198
27.3k
    sudoers_error_hook = logger;
199
200
    /* Register fatal/fatalx callback. */
201
27.3k
    sudo_fatal_callback_register(sudoers_cleanup);
202
203
    /* Initialize environment functions (including replacements). */
204
27.3k
    if (!env_init(envp))
205
0
  debug_return_int(-1);
206
207
    /* Setup defaults data structures. */
208
27.3k
    if (!init_defaults()) {
209
0
  sudo_warnx("%s", U_("unable to initialize sudoers default values"));
210
0
  debug_return_int(-1);
211
0
    }
212
213
    /* Parse info from front-end. */
214
27.3k
    sudoers_ctx.mode = sudoers_policy_deserialize_info(&sudoers_ctx, info,
215
27.3k
  &initial_defaults);
216
27.3k
    if (ISSET(sudoers_ctx.mode, MODE_ERROR))
217
5.31k
  debug_return_int(-1);
218
219
21.9k
    if (!init_vars(&sudoers_ctx, envp))
220
421
  debug_return_int(-1);
221
222
    /* Parse nsswitch.conf for sudoers order. */
223
21.5k
    snl = sudo_read_nss();
224
225
    /* LDAP or NSS may modify the euid so we need to be root for the open. */
226
21.5k
    if (!set_perms(NULL, PERM_ROOT))
227
0
  debug_return_int(-1);
228
229
    /* Use the C locale unless another is specified in sudoers. */
230
21.5k
    sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
231
21.5k
    sudo_warn_set_locale_func(sudoers_warn_setlocale);
232
233
    /* Update defaults set by front-end. */
234
21.5k
    if (!update_defaults(&sudoers_ctx, NULL, &initial_defaults,
235
21.5k
      SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER|SETDEF_RUNAS, false)) {
236
0
  goto cleanup;
237
0
    }
238
239
    /* Open and parse sudoers, set global defaults.  */
240
21.5k
    TAILQ_FOREACH_SAFE(nss, snl, entries, nss_next) {
241
21.5k
  if (nss->open(&sudoers_ctx, nss) == -1 || (nss->parse_tree = nss->parse(&sudoers_ctx, nss)) == NULL) {
242
0
      TAILQ_REMOVE(snl, nss, entries);
243
0
      continue;
244
0
  }
245
21.5k
  sources++;
246
247
  /* Missing/invalid defaults is not a fatal error. */
248
21.5k
  if (nss->getdefs(&sudoers_ctx, nss) == -1) {
249
0
      log_warningx(&sudoers_ctx, SLOG_PARSE_ERROR|SLOG_NO_STDERR,
250
0
    N_("unable to get defaults from %s"), nss->source);
251
21.5k
  } else {
252
21.5k
      (void)update_defaults(&sudoers_ctx, nss->parse_tree, NULL,
253
21.5k
    SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER|SETDEF_RUNAS, false);
254
21.5k
  }
255
21.5k
    }
256
21.5k
    if (sources == 0) {
257
  /* Display an extra warning if there are multiple sudoers sources. */
258
0
  if (TAILQ_FIRST(snl) != TAILQ_LAST(snl, sudo_nss_list))
259
0
      sudo_warnx("%s", U_("no valid sudoers sources found, quitting"));
260
0
  goto cleanup;
261
0
    }
262
263
    /* Set login class if applicable (after sudoers is parsed). */
264
21.5k
    if (set_loginclass(&sudoers_ctx))
265
21.5k
  ret = true;
266
267
21.5k
cleanup:
268
21.5k
    mail_parse_errors(&sudoers_ctx);
269
270
21.5k
    if (!restore_perms())
271
0
  ret = -1;
272
273
    /* Restore user's locale. */
274
21.5k
    sudo_warn_set_locale_func(NULL);
275
21.5k
    sudoers_setlocale(oldlocale, NULL);
276
277
21.5k
    debug_return_int(ret);
278
21.5k
}
279
280
/*
281
 * Expand I/O log dir and file into a full path.
282
 * Returns the full I/O log path prefixed with "iolog_path=".
283
 * Sets ctx->iolog_file and ctx->iolog_path as a side effect.
284
 */
285
static char *
286
format_iolog_path(struct sudoers_context *ctx)
287
3.06k
{
288
3.06k
    char dir[PATH_MAX], file[PATH_MAX];
289
3.06k
    char *iolog_path = NULL;
290
3.06k
    int oldlocale;
291
3.06k
    bool ok;
292
3.06k
    debug_decl(format_iolog_path, SUDOERS_DEBUG_PLUGIN);
293
294
    /* Use sudoers locale for strftime() */
295
3.06k
    sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
296
3.06k
    ok = expand_iolog_path(def_iolog_dir, dir, sizeof(dir),
297
3.06k
  &sudoers_iolog_path_escapes[1], ctx);
298
3.06k
    if (ok) {
299
3.06k
  ctx->iolog_dir = dir;
300
3.06k
  ok = expand_iolog_path(def_iolog_file, file, sizeof(file),
301
3.06k
      &sudoers_iolog_path_escapes[0], ctx);
302
3.06k
  ctx->iolog_dir = NULL;
303
3.06k
    }
304
3.06k
    sudoers_setlocale(oldlocale, NULL);
305
3.06k
    if (!ok)
306
0
  goto done;
307
308
3.06k
    if (asprintf(&iolog_path, "iolog_path=%s/%s", dir, file) == -1) {
309
0
  iolog_path = NULL;
310
0
  goto done;
311
0
    }
312
313
    /* Stash pointer to the I/O log for the event log. */
314
3.06k
    ctx->iolog_path = iolog_path + sizeof("iolog_path=") - 1;
315
3.06k
    ctx->iolog_file = ctx->iolog_path + 1 + strlen(dir);
316
317
3.06k
done:
318
3.06k
    debug_return_str(iolog_path);
319
3.06k
}
320
321
static void
322
cb_lookup(const struct sudoers_parse_tree *parse_tree,
323
    const struct userspec *us, int user_match, const struct privilege *priv,
324
    int host_match, const struct cmndspec *cs, int date_match, int runas_match,
325
    int cmnd_match, void *closure)
326
0
{
327
0
    struct sudoers_match_info *info = closure;
328
329
0
    if (cmnd_match != UNSPEC) {
330
0
  info->us = us;
331
0
  info->priv = priv;
332
0
  info->cs = cs;
333
0
    }
334
0
}
335
336
/*
337
 * Find the command, perform a sudoers lookup, ask for a password as
338
 * needed, and perform post-lookup checks.  Logs success/failure.
339
 * This is used by the check, list and validate plugin methods.
340
 *
341
 * Returns true if allowed, false if denied, -1 on error and
342
 * -2 for usage error.
343
 */
344
static int
345
sudoers_check_common(struct sudoers_context *ctx, int pwflag)
346
29.2k
{
347
29.2k
    struct sudoers_match_info match_info = { NULL };
348
29.2k
    int oldlocale, ret = -1;
349
29.2k
    unsigned int validated;
350
29.2k
    time_t now;
351
29.2k
    debug_decl(sudoers_check_common, SUDOERS_DEBUG_PLUGIN);
352
353
    /* The user may only specify a host for "sudo -l". */
354
29.2k
    if (!ISSET(ctx->mode, MODE_LIST|MODE_CHECK)) {
355
18.5k
  if (strcmp(ctx->runas.host, ctx->user.host) != 0) {
356
0
      log_warningx(ctx, SLOG_NO_STDERR|SLOG_AUDIT,
357
0
    N_("user not allowed to set remote host for command"));
358
0
      sudo_warnx("%s",
359
0
    U_("a remote host may only be specified when listing privileges."));
360
0
      ret = false;
361
0
      goto done;
362
0
  }
363
18.5k
    }
364
365
    /* If given the -P option, set the "preserve_groups" flag. */
366
29.2k
    if (ISSET(ctx->mode, MODE_PRESERVE_GROUPS))
367
71
  def_preserve_groups = true;
368
369
    /* Find command in path and apply per-command Defaults. */
370
29.2k
    cmnd_status = set_cmnd(ctx);
371
29.2k
    if (cmnd_status == NOT_FOUND_ERROR)
372
0
  goto done;
373
374
    /* Is root even allowed to run sudo? */
375
29.2k
    if (ctx->user.uid == 0 && !def_root_sudo) {
376
  /* Not an audit event (should it be?). */
377
0
  sudo_warnx("%s",
378
0
      U_("sudoers specifies that root is not allowed to sudo"));
379
0
  ret = false;
380
0
  goto done;
381
0
    }
382
383
    /* Check for -C overriding def_closefrom. */
384
29.2k
    if (ctx->user.closefrom >= 0 && ctx->user.closefrom != def_closefrom) {
385
1.34k
  if (!def_closefrom_override) {
386
1.34k
      log_warningx(ctx, SLOG_NO_STDERR|SLOG_AUDIT,
387
1.34k
    N_("user not allowed to override closefrom limit"));
388
1.34k
      sudo_warnx("%s", U_("you are not permitted to use the -C option"));
389
1.34k
      goto bad;
390
1.34k
  }
391
0
  def_closefrom = ctx->user.closefrom;
392
0
    }
393
394
    /*
395
     * Check sudoers sources, using the locale specified in sudoers.
396
     */
397
27.9k
    time(&now);
398
27.9k
    sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
399
27.9k
    validated = sudoers_lookup(snl, ctx, now, cb_lookup, &match_info,
400
27.9k
  &cmnd_status, pwflag);
401
27.9k
    sudoers_setlocale(oldlocale, NULL);
402
27.9k
    if (ISSET(validated, VALIDATE_ERROR)) {
403
  /* The lookup function should have printed an error. */
404
0
  goto done;
405
0
    }
406
407
27.9k
    if (match_info.us != NULL && match_info.us->file != NULL) {
408
0
  free(ctx->source);
409
0
  if (match_info.us->line != 0) {
410
0
      if (asprintf(&ctx->source, "%s:%d:%d", match_info.us->file,
411
0
        match_info.us->line, match_info.us->column) == -1)
412
0
    ctx->source = NULL;
413
0
  } else {
414
0
      ctx->source = strdup(match_info.us->file);
415
0
  }
416
0
  if (ctx->source == NULL) {
417
0
      sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
418
0
      goto done;
419
0
  }
420
0
    }
421
422
27.9k
    if (ctx->runas.cmnd == NULL) {
423
27.9k
  if ((ctx->runas.cmnd = strdup(ctx->user.cmnd)) == NULL) {
424
0
      sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
425
0
      goto done;
426
0
  }
427
27.9k
    }
428
429
    /* Defer uid/gid checks until after defaults have been updated. */
430
27.9k
    if (unknown_runas_uid && !def_runas_allow_unknown_id) {
431
52
  log_warningx(ctx, SLOG_AUDIT, N_("unknown user %s"),
432
52
      ctx->runas.pw->pw_name);
433
52
  goto done;
434
52
    }
435
27.8k
    if (ctx->runas.gr != NULL) {
436
329
  if (unknown_runas_gid && !def_runas_allow_unknown_id) {
437
67
      log_warningx(ctx, SLOG_AUDIT, N_("unknown group %s"),
438
67
    ctx->runas.gr->gr_name);
439
67
      goto done;
440
67
  }
441
329
    }
442
443
    /* If no command line args and "shell_noargs" is not set, error out. */
444
27.8k
    if (ISSET(ctx->mode, MODE_IMPLIED_SHELL) && !def_shell_noargs) {
445
  /* Not an audit event. */
446
35
  ret = -2; /* usage error */
447
35
  goto done;
448
35
    }
449
450
    /* Bail if a tty is required and we don't have one. */
451
27.7k
    if (def_requiretty && !sudoers_tty_present(ctx)) {
452
0
  log_warningx(ctx, SLOG_NO_STDERR|SLOG_AUDIT, N_("no tty"));
453
0
  sudo_warnx("%s", U_("sorry, you must have a tty to run sudo"));
454
0
  goto bad;
455
0
    }
456
457
    /* Check runas user's shell if running (or checking) a command. */
458
27.7k
    if (ISSET(ctx->mode, MODE_RUN|MODE_CHECK)) {
459
16.1k
  if (!user_shell_valid(ctx->runas.pw)) {
460
0
      log_warningx(ctx, SLOG_RAW_MSG|SLOG_AUDIT,
461
0
    N_("invalid shell for user %s: %s"),
462
0
    ctx->runas.pw->pw_name, ctx->runas.pw->pw_shell);
463
0
      goto bad;
464
0
  }
465
16.1k
    }
466
467
    /*
468
     * We don't reset the environment for sudoedit or if the user
469
     * specified the -E command line flag and they have setenv privs.
470
     */
471
27.7k
    if (ISSET(ctx->mode, MODE_EDIT) ||
472
27.7k
  (ISSET(ctx->mode, MODE_PRESERVE_ENV) && def_setenv))
473
1.46k
  def_env_reset = false;
474
475
    /* Build a new environment that avoids any nasty bits. */
476
27.7k
    if (!rebuild_env(ctx))
477
0
  goto bad;
478
479
    /* Require a password if sudoers says so.  */
480
27.7k
    switch (check_user(ctx, validated, ctx->mode)) {
481
27.7k
    case AUTH_SUCCESS:
482
  /* user authenticated successfully. */
483
27.7k
  break;
484
0
    case AUTH_FAILURE:
485
  /* Note: log_denial() calls audit for us. */
486
0
  if (!ISSET(validated, VALIDATE_SUCCESS)) {
487
      /* Only display a denial message if no password was read. */
488
0
      if (!log_denial(ctx, validated, def_passwd_tries <= 0))
489
0
    goto done;
490
0
  }
491
0
  goto bad;
492
0
    default:
493
  /* some other error, ret is -1. */
494
0
  goto done;
495
27.7k
    }
496
497
    /* Check whether ctx->runas.chroot is permitted (if specified). */
498
27.7k
    switch (check_user_runchroot(ctx->runas.chroot)) {
499
27.7k
    case true:
500
27.7k
  break;
501
0
    case false:
502
0
  log_warningx(ctx, SLOG_NO_STDERR|SLOG_AUDIT,
503
0
      N_("user not allowed to change root directory to %s"),
504
0
      ctx->runas.chroot);
505
0
  sudo_warnx(U_("you are not permitted to use the -R option with %s"),
506
0
      ctx->user.cmnd);
507
0
  goto bad;
508
0
    default:
509
0
  goto done;
510
27.7k
    }
511
512
    /* Check whether ctx->runas.cwd is permitted (if specified). */
513
27.7k
    switch (check_user_runcwd(ctx->runas.cwd)) {
514
27.7k
    case true:
515
27.7k
  break;
516
0
    case false:
517
0
  log_warningx(ctx, SLOG_NO_STDERR|SLOG_AUDIT,
518
0
      N_("user not allowed to change directory to %s"), ctx->runas.cwd);
519
0
  sudo_warnx(U_("you are not permitted to use the -D option with %s"),
520
0
      ctx->user.cmnd);
521
0
  goto bad;
522
0
    default:
523
0
  goto done;
524
27.7k
    }
525
526
    /* If run as root with SUDO_USER set, set ctx->user.pw to that user. */
527
    /* XXX - causes confusion when root is not listed in sudoers */
528
27.7k
    if (ISSET(ctx->mode, MODE_RUN|MODE_EDIT) && prev_user != NULL) {
529
0
  if (ctx->user.uid == 0 && strcmp(prev_user, "root") != 0) {
530
0
      struct passwd *pw;
531
532
0
      if ((pw = sudo_getpwnam(prev_user)) != NULL) {
533
0
        if (ctx->user.pw != NULL)
534
0
      sudo_pw_delref(ctx->user.pw);
535
0
        ctx->user.pw = pw;
536
0
      }
537
0
  }
538
0
    }
539
540
    /* If the user was not allowed to run the command we are done. */
541
27.7k
    if (!ISSET(validated, VALIDATE_SUCCESS)) {
542
  /* Note: log_failure() calls audit for us. */
543
0
  if (!log_failure(ctx, validated, cmnd_status))
544
0
      goto done;
545
0
  goto bad;
546
0
    }
547
548
    /*
549
     * Check if the user is trying to run a setid binary in intercept mode.
550
     * For the DSO intercept_type, we reject attempts to run setid binaries
551
     * by default since the dynamic loader will clear LD_PRELOAD, defeating
552
     * intercept.
553
     */
554
27.7k
    if (def_intercept || ISSET(ctx->mode, MODE_POLICY_INTERCEPTED)) {
555
0
  if (!def_intercept_allow_setid && ctx->user.cmnd_stat != NULL) {
556
0
      if (ISSET(ctx->user.cmnd_stat->st_mode, S_ISUID|S_ISGID)) {
557
0
    CLR(validated, VALIDATE_SUCCESS);
558
0
    if (!log_denial(ctx, validated|FLAG_INTERCEPT_SETID, true))
559
0
        goto done;
560
0
    goto bad;
561
0
      }
562
0
  }
563
0
    }
564
565
    /* Create Ubuntu-style dot file to indicate sudo was successful. */
566
27.7k
    if (create_admin_success_flag(ctx) == -1)
567
0
  goto done;
568
569
    /* Finally tell the user if the command did not exist. */
570
27.7k
    if (cmnd_status == NOT_FOUND_DOT) {
571
3.73k
  audit_failure(ctx, ctx->runas.argv, N_("command in current directory"));
572
3.73k
  sudo_warnx(U_("ignoring \"%s\" found in '.'\nUse \"sudo ./%s\" if this is the \"%s\" you wish to run."), ctx->user.cmnd, ctx->user.cmnd, ctx->user.cmnd);
573
3.73k
  goto bad;
574
24.0k
    } else if (cmnd_status == NOT_FOUND) {
575
1.90k
  if (ISSET(ctx->mode, MODE_CHECK)) {
576
0
      audit_failure(ctx, ctx->runas.argv, N_("%s: command not found"),
577
0
    ctx->runas.argv[1]);
578
0
      sudo_warnx(U_("%s: command not found"), ctx->runas.argv[1]);
579
1.90k
  } else {
580
1.90k
      audit_failure(ctx, ctx->runas.argv, N_("%s: command not found"),
581
1.90k
    ctx->user.cmnd);
582
1.90k
      sudo_warnx(U_("%s: command not found"), ctx->user.cmnd);
583
1.90k
      if (strncmp(ctx->user.cmnd, "cd", 2) == 0 && (ctx->user.cmnd[2] == '\0' ||
584
0
        isblank((unsigned char)ctx->user.cmnd[2]))) {
585
0
    sudo_warnx("%s",
586
0
        U_("\"cd\" is a shell built-in command, it cannot be run directly."));
587
0
    sudo_warnx("%s",
588
0
        U_("the -s option may be used to run a privileged shell."));
589
0
    sudo_warnx("%s",
590
0
        U_("the -D option may be used to run a command in a specific directory."));
591
0
      }
592
1.90k
  }
593
1.90k
  goto bad;
594
1.90k
    }
595
596
    /* If user specified a timeout make sure sudoers allows it. */
597
22.1k
    if (!def_user_command_timeouts && ctx->user.timeout > 0) {
598
681
  log_warningx(ctx, SLOG_NO_STDERR|SLOG_AUDIT,
599
681
      N_("user not allowed to set a command timeout"));
600
681
  sudo_warnx("%s",
601
681
      U_("sorry, you are not allowed set a command timeout"));
602
681
  goto bad;
603
681
    }
604
605
    /* If user specified env vars make sure sudoers allows it. */
606
21.4k
    if (ISSET(ctx->mode, MODE_RUN) && !def_setenv) {
607
7.10k
  if (ISSET(ctx->mode, MODE_PRESERVE_ENV)) {
608
28
      log_warningx(ctx, SLOG_NO_STDERR|SLOG_AUDIT,
609
28
    N_("user not allowed to preserve the environment"));
610
28
      sudo_warnx("%s",
611
28
    U_("sorry, you are not allowed to preserve the environment"));
612
28
      goto bad;
613
7.07k
  } else {
614
7.07k
      if (!validate_env_vars(ctx, ctx->user.env_add))
615
1.75k
    goto bad;
616
7.07k
  }
617
7.10k
    }
618
619
19.6k
    ret = true;
620
19.6k
    goto done;
621
622
9.44k
bad:
623
9.44k
    ret = false;
624
29.2k
done:
625
29.2k
    debug_return_int(ret);
626
29.2k
}
627
628
static bool need_reinit;
629
630
/*
631
 * Check whether the user is allowed to run the specified command.
632
 * Returns true if allowed, false if denied, -1 on error and
633
 * -2 for usage error.
634
 */
635
int
636
sudoers_check_cmnd(int argc, char * const argv[], char *env_add[],
637
    void *closure)
638
14.9k
{
639
14.9k
    char *iolog_path = NULL;
640
14.9k
    mode_t cmnd_umask = ACCESSPERMS;
641
14.9k
    int ret = -1;
642
14.9k
    debug_decl(sudoers_check_cmnd, SUDOERS_DEBUG_PLUGIN);
643
644
14.9k
    sudo_warn_set_locale_func(sudoers_warn_setlocale);
645
646
14.9k
    if (argc == 0) {
647
0
  sudo_warnx("%s", U_("no command specified"));
648
0
  debug_return_int(-1);
649
0
    }
650
651
14.9k
    if (need_reinit) {
652
  /* Was previous command intercepted? */
653
6.39k
  if (ISSET(sudoers_ctx.mode, MODE_RUN) && def_intercept)
654
0
      SET(sudoers_ctx.mode, MODE_POLICY_INTERCEPTED);
655
656
  /* Only certain mode flags are legal for intercepted commands. */
657
6.39k
  if (ISSET(sudoers_ctx.mode, MODE_POLICY_INTERCEPTED))
658
0
      sudoers_ctx.mode &= MODE_INTERCEPT_MASK;
659
660
  /* Re-initialize defaults if we are called multiple times. */
661
6.39k
  if (!sudoers_reinit_defaults(&sudoers_ctx))
662
0
      debug_return_int(-1);
663
6.39k
    }
664
14.9k
    need_reinit = true;
665
666
14.9k
    unlimit_nproc();
667
668
14.9k
    if (!set_perms(&sudoers_ctx, PERM_INITIAL))
669
0
  goto bad;
670
671
    /* Environment variables specified on the command line. */
672
14.9k
    if (env_add != NULL && env_add[0] != NULL)
673
6.35k
  sudoers_ctx.user.env_add = env_add;
674
675
    /*
676
     * Make a local copy of argc/argv, with special handling for the
677
     * '-i' option.  We also allocate an extra slot for bash's --login.
678
     */
679
14.9k
    if (sudoers_ctx.runas.argv != NULL && sudoers_ctx.runas.argv != sudoers_ctx.runas.argv_saved) {
680
3.40k
  sudoers_gc_remove(GC_PTR, sudoers_ctx.runas.argv);
681
3.40k
  free(sudoers_ctx.runas.argv);
682
3.40k
    }
683
14.9k
    sudoers_ctx.runas.argv = reallocarray(NULL, (size_t)argc + 2, sizeof(char *));
684
14.9k
    if (sudoers_ctx.runas.argv == NULL) {
685
0
  sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
686
0
  goto error;
687
0
    }
688
14.9k
    sudoers_gc_add(GC_PTR, sudoers_ctx.runas.argv);
689
14.9k
    memcpy(sudoers_ctx.runas.argv, argv, (size_t)argc * sizeof(char *));
690
14.9k
    sudoers_ctx.runas.argc = argc;
691
14.9k
    sudoers_ctx.runas.argv[sudoers_ctx.runas.argc] = NULL;
692
14.9k
    if (ISSET(sudoers_ctx.mode, MODE_LOGIN_SHELL) && sudoers_ctx.runas.pw != NULL) {
693
308
  sudoers_ctx.runas.argv[0] = strdup(sudoers_ctx.runas.pw->pw_shell);
694
308
  if (sudoers_ctx.runas.argv[0] == NULL) {
695
0
      sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
696
0
      goto error;
697
0
  }
698
308
  sudoers_gc_add(GC_PTR, sudoers_ctx.runas.argv[0]);
699
308
    }
700
701
14.9k
    ret = sudoers_check_common(&sudoers_ctx, 0);
702
14.9k
    if (ret != true)
703
8.37k
  goto done;
704
705
6.61k
    if (!remote_iologs) {
706
3.06k
  if (iolog_enabled && def_iolog_file && def_iolog_dir) {
707
3.06k
      if ((iolog_path = format_iolog_path(&sudoers_ctx)) == NULL) {
708
0
    if (!def_ignore_iolog_errors)
709
0
        goto error;
710
    /* Unable to expand I/O log path, disable I/O logging. */
711
0
    def_log_input = false;
712
0
    def_log_output = false;
713
0
    def_log_stdin = false;
714
0
    def_log_stdout = false;
715
0
    def_log_stderr = false;
716
0
    def_log_ttyin = false;
717
0
    def_log_ttyout = false;
718
0
      }
719
3.06k
  }
720
3.06k
    }
721
722
    /*
723
     * Set umask based on sudoers.
724
     * If user's umask is more restrictive, OR in those bits too
725
     * unless umask_override is set.
726
     */
727
6.61k
    if (def_umask != ACCESSPERMS) {
728
6.61k
  cmnd_umask = def_umask;
729
6.61k
  if (!def_umask_override)
730
6.61k
      cmnd_umask |= sudoers_ctx.user.umask;
731
6.61k
    }
732
733
6.61k
    if (ISSET(sudoers_ctx.mode, MODE_LOGIN_SHELL)) {
734
144
  char *p;
735
736
  /* Convert /bin/sh -> -sh so shell knows it is a login shell */
737
144
  if ((p = strrchr(sudoers_ctx.runas.argv[0], '/')) == NULL)
738
0
      p = sudoers_ctx.runas.argv[0];
739
144
  *p = '-';
740
144
  sudoers_ctx.runas.argv[0] = p;
741
742
  /*
743
   * Newer versions of bash require the --login option to be used
744
   * in conjunction with the -c option even if the shell name starts
745
   * with a '-'.  Unfortunately, bash 1.x uses -login, not --login
746
   * so this will cause an error for that.
747
   */
748
144
  if (sudoers_ctx.runas.argc > 1 && strcmp(sudoers_ctx.runas.argv[0], "-bash") == 0 &&
749
144
      strcmp(sudoers_ctx.runas.argv[1], "-c") == 0) {
750
      /* We allocated extra space for the --login above. */
751
0
      memmove(&sudoers_ctx.runas.argv[2], &sudoers_ctx.runas.argv[1],
752
0
    (size_t)sudoers_ctx.runas.argc * sizeof(char *));
753
0
      sudoers_ctx.runas.argv[1] = (char *)"--login";
754
0
      sudoers_ctx.runas.argc++;
755
0
  }
756
757
144
#ifdef _PATH_ENVIRONMENT
758
  /* Insert system-wide environment variables. */
759
144
  if (!read_env_file(&sudoers_ctx, _PATH_ENVIRONMENT, true, false))
760
0
      sudo_warn("%s", _PATH_ENVIRONMENT);
761
144
#endif
762
#ifdef HAVE_LOGIN_CAP_H
763
  /* Set environment based on login class. */
764
  if (sudoers_ctx.runas.class) {
765
      login_cap_t *lc = login_getclass(sudoers_ctx.runas.class);
766
      if (lc != NULL) {
767
    setusercontext(lc, sudoers_ctx.runas.pw,
768
        sudoers_ctx.runas.pw->pw_uid, LOGIN_SETPATH|LOGIN_SETENV);
769
    login_close(lc);
770
      }
771
  }
772
#endif /* HAVE_LOGIN_CAP_H */
773
144
    }
774
775
    /* Insert system-wide environment variables. */
776
6.61k
    if (def_restricted_env_file) {
777
6.61k
  if (!read_env_file(&sudoers_ctx, def_restricted_env_file, false, true))
778
0
      sudo_warn("%s", def_restricted_env_file);
779
6.61k
    }
780
6.61k
    if (def_env_file) {
781
6.61k
  if (!read_env_file(&sudoers_ctx, def_env_file, false, false))
782
0
      sudo_warn("%s", def_env_file);
783
6.61k
    }
784
785
    /* Insert user-specified environment variables. */
786
6.61k
    if (!insert_env_vars(sudoers_ctx.user.env_add)) {
787
138
  sudo_warnx("%s",
788
138
      U_("error setting user-specified environment variables"));
789
138
  goto error;
790
138
    }
791
792
    /* Note: must call audit before uid change. */
793
6.48k
    if (ISSET(sudoers_ctx.mode, MODE_EDIT)) {
794
1.27k
  const char *env_editor = NULL;
795
1.27k
  char **edit_argv;
796
1.27k
  int edit_argc;
797
798
1.27k
  sudoers_ctx.sudoedit_nfiles = sudoers_ctx.runas.argc - 1;
799
1.27k
  free(sudoers_ctx.runas.cmnd);
800
1.27k
  sudoers_ctx.runas.cmnd = find_editor(sudoers_ctx.sudoedit_nfiles,
801
1.27k
      sudoers_ctx.runas.argv + 1, &edit_argc, &edit_argv, NULL, &env_editor);
802
1.27k
  if (sudoers_ctx.runas.cmnd == NULL) {
803
479
      switch (errno) {
804
479
      case ENOENT:
805
479
    audit_failure(&sudoers_ctx, sudoers_ctx.runas.argv,
806
479
        N_("%s: command not found"),
807
479
        env_editor ? env_editor : def_editor);
808
479
    sudo_warnx(U_("%s: command not found"),
809
479
        env_editor ? env_editor : def_editor);
810
479
    goto error;
811
0
      case EINVAL:
812
0
    if (def_env_editor && env_editor != NULL) {
813
        /* User tried to do something funny with the editor. */
814
0
        log_warningx(&sudoers_ctx,
815
0
      SLOG_NO_STDERR|SLOG_AUDIT|SLOG_SEND_MAIL,
816
0
      "invalid user-specified editor: %s", env_editor);
817
0
        goto error;
818
0
    }
819
0
    FALLTHROUGH;
820
0
      default:
821
0
    goto error;
822
479
      }
823
479
  }
824
  /* find_editor() already g/c'd edit_argv[] */
825
794
  if (sudoers_ctx.runas.argv != sudoers_ctx.runas.argv_saved) {
826
794
      sudoers_gc_remove(GC_PTR, sudoers_ctx.runas.argv);
827
794
      free(sudoers_ctx.runas.argv);
828
794
  }
829
794
  sudoers_ctx.runas.argv = edit_argv;
830
794
  sudoers_ctx.runas.argc = edit_argc;
831
832
  /* We want to run the editor with the unmodified environment. */
833
794
  env_swap_old();
834
794
    }
835
836
    /* Save the initial command and argv so we have it for exit logging. */
837
6.00k
    if (sudoers_ctx.runas.cmnd_saved == NULL) {
838
3.02k
  sudoers_ctx.runas.cmnd_saved = strdup(sudoers_ctx.runas.cmnd);
839
3.02k
  if (sudoers_ctx.runas.cmnd_saved == NULL) {
840
0
      sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
841
0
      goto error;
842
0
  }
843
3.02k
  sudoers_ctx.runas.argv_saved = sudoers_ctx.runas.argv;
844
3.02k
    }
845
846
6.00k
    ret = true;
847
6.00k
    goto done;
848
849
0
bad:
850
0
    ret = false;
851
0
    goto done;
852
853
617
error:
854
617
    ret = -1;
855
856
14.9k
done:
857
14.9k
    mail_parse_errors(&sudoers_ctx);
858
859
14.9k
    if (def_group_plugin)
860
0
  group_plugin_unload();
861
14.9k
    reset_parser();
862
863
14.9k
    if (ret == -1) {
864
  /* Free locally-allocated strings. */
865
680
  free(iolog_path);
866
14.3k
    } else {
867
  /* Store settings to pass back to front-end. */
868
14.3k
  if (!sudoers_policy_store_result(&sudoers_ctx, ret,
869
14.3k
      sudoers_ctx.runas.argv, env_get(), cmnd_umask, iolog_path, closure))
870
0
      ret = -1;
871
14.3k
    }
872
873
    /* Zero out stashed copy of environment, it is owned by the front-end. */
874
14.9k
    (void)env_init(NULL);
875
876
14.9k
    if (!rewind_perms())
877
0
  ret = -1;
878
879
14.9k
    restore_nproc();
880
881
14.9k
    sudo_warn_set_locale_func(NULL);
882
883
14.9k
    debug_return_int(ret);
884
14.9k
}
885
886
/*
887
 * Validate the user and update their timestamp file entry.
888
 * Returns true if allowed, false if denied, -1 on error and
889
 * -2 for usage error.
890
 */
891
int
892
sudoers_validate_user(void)
893
3.56k
{
894
3.56k
    int ret = -1;
895
3.56k
    debug_decl(sudoers_validate_user, SUDOERS_DEBUG_PLUGIN);
896
897
3.56k
    sudo_warn_set_locale_func(sudoers_warn_setlocale);
898
899
3.56k
    unlimit_nproc();
900
901
3.56k
    if (!set_perms(&sudoers_ctx, PERM_INITIAL))
902
0
  goto done;
903
904
3.56k
    sudoers_ctx.runas.argv = reallocarray(NULL, 2, sizeof(char *));
905
3.56k
    if (sudoers_ctx.runas.argv == NULL) {
906
0
  sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
907
0
  goto done;
908
0
    }
909
3.56k
    sudoers_gc_add(GC_PTR, sudoers_ctx.runas.argv);
910
3.56k
    sudoers_ctx.runas.argv[0] = (char *)"validate";
911
3.56k
    sudoers_ctx.runas.argv[1] = NULL;
912
3.56k
    sudoers_ctx.runas.argc = 2;
913
914
3.56k
    ret = sudoers_check_common(&sudoers_ctx, I_VERIFYPW);
915
916
3.56k
done:
917
3.56k
    mail_parse_errors(&sudoers_ctx);
918
919
3.56k
    if (def_group_plugin)
920
0
  group_plugin_unload();
921
3.56k
    reset_parser();
922
3.56k
    env_init(NULL);
923
924
3.56k
    if (!rewind_perms())
925
0
  ret = -1;
926
927
3.56k
    restore_nproc();
928
929
3.56k
    sudo_warn_set_locale_func(NULL);
930
931
3.56k
    debug_return_int(ret);
932
3.56k
}
933
934
/*
935
 * List a user's privileges or check whether a specific command may be run.
936
 * Returns true if allowed, false if denied, -1 on error and
937
 * -2 for usage error.
938
 */
939
int
940
sudoers_list(int argc, char * const argv[], const char *list_user, int verbose)
941
10.7k
{
942
10.7k
    struct passwd *pw;
943
10.7k
    int ret = -1;
944
10.7k
    debug_decl(sudoers_list, SUDOERS_DEBUG_PLUGIN);
945
946
10.7k
    sudo_warn_set_locale_func(sudoers_warn_setlocale);
947
948
10.7k
    unlimit_nproc();
949
950
10.7k
    if (!set_perms(&sudoers_ctx, PERM_INITIAL))
951
0
  goto done;
952
953
10.7k
    if (list_user) {
954
3.56k
  if (sudoers_ctx.runas.list_pw != NULL)
955
1.78k
      sudo_pw_delref(sudoers_ctx.runas.list_pw);
956
3.56k
  sudoers_ctx.runas.list_pw = sudo_getpwnam(list_user);
957
3.56k
  if (sudoers_ctx.runas.list_pw == NULL) {
958
0
      sudo_warnx(U_("unknown user %s"), list_user);
959
0
      goto done;
960
0
  }
961
3.56k
    }
962
963
10.7k
    sudoers_ctx.runas.argv = reallocarray(NULL, (size_t)argc + 2, sizeof(char *));
964
10.7k
    if (sudoers_ctx.runas.argv == NULL) {
965
0
  sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
966
0
  goto done;
967
0
    }
968
10.7k
    sudoers_gc_add(GC_PTR, sudoers_ctx.runas.argv);
969
10.7k
    sudoers_ctx.runas.argv[0] = (char *)"list";
970
10.7k
    if (argc != 0)
971
3.56k
  memcpy(sudoers_ctx.runas.argv + 1, argv, (size_t)argc * sizeof(char *));
972
10.7k
    sudoers_ctx.runas.argc = argc + 1;
973
10.7k
    sudoers_ctx.runas.argv[sudoers_ctx.runas.argc] = NULL;
974
975
10.7k
    ret = sudoers_check_common(&sudoers_ctx, I_LISTPW);
976
10.7k
    if (ret != true)
977
912
  goto done;
978
979
9.79k
    pw = sudoers_ctx.runas.list_pw ? sudoers_ctx.runas.list_pw : sudoers_ctx.user.pw;
980
9.79k
    if (ISSET(sudoers_ctx.mode, MODE_CHECK))
981
3.26k
  ret = display_cmnd(&sudoers_ctx, snl, pw, verbose);
982
6.52k
    else
983
6.52k
  ret = display_privs(&sudoers_ctx, snl, pw, verbose);
984
985
10.7k
done:
986
10.7k
    mail_parse_errors(&sudoers_ctx);
987
988
10.7k
    if (def_group_plugin)
989
0
  group_plugin_unload();
990
10.7k
    reset_parser();
991
10.7k
    env_init(NULL);
992
993
10.7k
    if (!rewind_perms())
994
0
  ret = -1;
995
996
10.7k
    restore_nproc();
997
998
10.7k
    sudo_warn_set_locale_func(NULL);
999
1000
10.7k
    debug_return_int(ret);
1001
10.7k
}
1002
1003
/*
1004
 * Initialize timezone and fill in ctx->user.
1005
 */
1006
static bool
1007
init_vars(struct sudoers_context *ctx, char * const envp[])
1008
21.9k
{
1009
21.9k
    char * const * ep;
1010
21.9k
    bool unknown_user = false;
1011
21.9k
    debug_decl(init_vars, SUDOERS_DEBUG_PLUGIN);
1012
1013
21.9k
    if (!sudoers_initlocale(setlocale(LC_ALL, NULL), def_sudoers_locale)) {
1014
0
  sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
1015
0
  debug_return_bool(false);
1016
0
    }
1017
1018
21.9k
#define MATCHES(s, v) \
1019
263k
    (strncmp((s), (v), sizeof(v) - 1) == 0 && (s)[sizeof(v) - 1] != '\0')
1020
1021
21.9k
    ctx->user.envp = envp;
1022
835k
    for (ep = ctx->user.envp; *ep; ep++) {
1023
813k
  switch (**ep) {
1024
21.9k
      case 'K':
1025
21.9k
    if (MATCHES(*ep, "KRB5CCNAME="))
1026
21.9k
        ctx->user.ccname = *ep + sizeof("KRB5CCNAME=") - 1;
1027
21.9k
    break;
1028
43.9k
      case 'P':
1029
43.9k
    if (MATCHES(*ep, "PATH="))
1030
21.9k
        ctx->user.path = *ep + sizeof("PATH=") - 1;
1031
43.9k
    break;
1032
109k
      case 'S':
1033
109k
    if (MATCHES(*ep, "SUDO_PROMPT=")) {
1034
        /* Don't override "sudo -p prompt" */
1035
21.9k
        if (ctx->user.prompt == NULL)
1036
21.5k
      ctx->user.prompt = *ep + sizeof("SUDO_PROMPT=") - 1;
1037
21.9k
        break;
1038
21.9k
    }
1039
87.9k
    if (MATCHES(*ep, "SUDO_USER="))
1040
0
        prev_user = *ep + sizeof("SUDO_USER=") - 1;
1041
87.9k
    break;
1042
813k
      }
1043
813k
    }
1044
21.9k
#undef MATCHES
1045
1046
21.9k
    if (ctx->user.pw == NULL) {
1047
  /* Fake a struct passwd for the call to log_warningx(). */
1048
258
  ctx->user.pw = sudo_mkpwent(ctx->user.name, ctx->user.uid,
1049
258
      ctx->user.gid, NULL, NULL);
1050
258
  unknown_user = true;
1051
258
    }
1052
21.9k
    if (ctx->user.gid_list == NULL)
1053
21.9k
  ctx->user.gid_list = sudo_get_gidlist(ctx->user.pw, ENTRY_TYPE_ANY);
1054
1055
    /* Store initialize permissions so we can restore them later. */
1056
21.9k
    if (!set_perms(ctx, PERM_INITIAL))
1057
0
  debug_return_bool(false);
1058
1059
    /* Set parse callbacks */
1060
21.9k
    set_callbacks();
1061
1062
    /* It is now safe to use log_warningx() and set_perms() */
1063
21.9k
    if (unknown_user) {
1064
258
  log_warningx(ctx, SLOG_SEND_MAIL, N_("unknown user %s"), ctx->user.name);
1065
258
  debug_return_bool(false);
1066
258
    }
1067
1068
    /*
1069
     * Set runas passwd/group entries based on command line or sudoers.
1070
     * Note that if runas_group was specified without runas_user we
1071
     * run the command as the invoking user.
1072
     */
1073
21.7k
    if (ctx->runas.group != NULL) {
1074
711
  if (!set_runasgr(ctx, ctx->runas.group, false))
1075
118
      debug_return_bool(false);
1076
593
  if (!set_runaspw(ctx, ctx->runas.user ?
1077
500
    ctx->runas.user : ctx->user.name, false))
1078
3
      debug_return_bool(false);
1079
21.0k
    } else {
1080
21.0k
  if (!set_runaspw(ctx, ctx->runas.user ?
1081
20.7k
    ctx->runas.user : def_runas_default, false))
1082
42
      debug_return_bool(false);
1083
21.0k
    }
1084
1085
21.5k
    debug_return_bool(true);
1086
21.5k
}
1087
1088
/*
1089
 * Fill in ctx->user.cmnd and ctx->user.cmnd_stat variables.
1090
 * Does not fill in ctx->user.cmnd_base.
1091
 */
1092
int
1093
set_cmnd_path(struct sudoers_context *ctx, const char *runchroot)
1094
23.7k
{
1095
23.7k
    const char *cmnd_in;
1096
23.7k
    char *cmnd_out = NULL;
1097
23.7k
    char *path = ctx->user.path;
1098
23.7k
    int ret;
1099
23.7k
    debug_decl(set_cmnd_path, SUDOERS_DEBUG_PLUGIN);
1100
1101
23.7k
    cmnd_in = ISSET(ctx->mode, MODE_CHECK) ?
1102
20.2k
  ctx->runas.argv[1] : ctx->runas.argv[0];
1103
1104
23.7k
    free(ctx->user.cmnd_list);
1105
23.7k
    ctx->user.cmnd_list = NULL;
1106
23.7k
    free(ctx->user.cmnd);
1107
23.7k
    ctx->user.cmnd = NULL;
1108
23.7k
    canon_path_free(ctx->user.cmnd_dir);
1109
23.7k
    ctx->user.cmnd_dir = NULL;
1110
23.7k
    if (def_secure_path && !user_is_exempt(ctx))
1111
0
  path = def_secure_path;
1112
1113
23.7k
    ret = resolve_cmnd(ctx, cmnd_in, &cmnd_out, path, runchroot);
1114
23.7k
    if (ret == FOUND) {
1115
15.7k
  char *slash = strrchr(cmnd_out, '/');
1116
15.7k
  if (slash != NULL) {
1117
15.7k
      *slash = '\0';
1118
15.7k
      ctx->user.cmnd_dir = canon_path(cmnd_out);
1119
15.7k
      if (ctx->user.cmnd_dir == NULL && errno == ENOMEM)
1120
0
    goto error;
1121
15.7k
      *slash = '/';
1122
15.7k
  }
1123
15.7k
    }
1124
1125
23.7k
    if (ISSET(ctx->mode, MODE_CHECK))
1126
3.56k
  ctx->user.cmnd_list = cmnd_out;
1127
20.2k
    else
1128
20.2k
  ctx->user.cmnd = cmnd_out;
1129
1130
23.7k
    debug_return_int(ret);
1131
0
error:
1132
0
    free(cmnd_out);
1133
0
    debug_return_int(NOT_FOUND_ERROR);
1134
0
}
1135
1136
/*
1137
 * Fill in ctx->user.cmnd, ctx->user.cmnd_stat and cmnd_status variables.
1138
 * Does not fill in ctx->user.cmnd_base.
1139
 */
1140
void
1141
set_cmnd_status(struct sudoers_context *ctx, const char *runchroot)
1142
6.39k
{
1143
6.39k
    cmnd_status = set_cmnd_path(ctx, runchroot);
1144
6.39k
}
1145
1146
/*
1147
 * Fill in ctx->user.cmnd, ctx->user.cmnd_args, ctx->user.cmnd_base and
1148
 * ctx->user.cmnd_stat variables and apply any command-specific defaults entries.
1149
 */
1150
static int
1151
set_cmnd(struct sudoers_context *ctx)
1152
29.2k
{
1153
29.2k
    struct sudo_nss *nss;
1154
29.2k
    int ret = FOUND;
1155
29.2k
    debug_decl(set_cmnd, SUDOERS_DEBUG_PLUGIN);
1156
1157
    /* Allocate ctx->user.cmnd_stat for find_path() and match functions. */
1158
29.2k
    free(ctx->user.cmnd_stat);
1159
29.2k
    ctx->user.cmnd_stat = calloc(1, sizeof(struct stat));
1160
29.2k
    if (ctx->user.cmnd_stat == NULL) {
1161
0
  sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
1162
0
  debug_return_int(NOT_FOUND_ERROR);
1163
0
    }
1164
1165
    /* Re-initialize for when we are called multiple times. */
1166
29.2k
    free(ctx->runas.cmnd);
1167
29.2k
    ctx->runas.cmnd = NULL;
1168
1169
29.2k
    if (ISSET(ctx->mode, MODE_RUN|MODE_EDIT|MODE_CHECK)) {
1170
18.5k
  if (!ISSET(ctx->mode, MODE_EDIT)) {
1171
17.3k
      const char *runchroot = ctx->runas.chroot;
1172
17.3k
      if (runchroot == NULL && def_runchroot != NULL &&
1173
17.3k
        strcmp(def_runchroot, "*") != 0)
1174
17.3k
    runchroot = def_runchroot;
1175
1176
17.3k
      ret = set_cmnd_path(ctx, runchroot);
1177
17.3k
      if (ret == NOT_FOUND_ERROR) {
1178
0
    if (errno == ENAMETOOLONG) {
1179
0
        audit_failure(ctx, ctx->runas.argv, N_("command too long"));
1180
0
    }
1181
0
    log_warning(ctx, 0, "%s", ctx->runas.argv[0]);
1182
0
    debug_return_int(ret);
1183
0
      }
1184
17.3k
  }
1185
1186
  /* set ctx->user.cmnd_args */
1187
18.5k
  free(ctx->user.cmnd_args);
1188
18.5k
  ctx->user.cmnd_args = NULL;
1189
18.5k
  if (ISSET(ctx->mode, MODE_CHECK)) {
1190
3.56k
      if (ctx->runas.argc > 2) {
1191
    /* Skip the command being listed in ctx->runas.argv[1]. */
1192
176
    ctx->user.cmnd_args = strvec_join(ctx->runas.argv + 2, ' ', NULL);
1193
176
    if (ctx->user.cmnd_args == NULL)
1194
0
        debug_return_int(NOT_FOUND_ERROR);
1195
176
      }
1196
14.9k
  } else if (ctx->runas.argc > 1) {
1197
1.41k
      if (ISSET(ctx->mode, MODE_SHELL|MODE_LOGIN_SHELL) &&
1198
1.41k
        ISSET(ctx->mode, MODE_RUN)) {
1199
    /*
1200
     * When running a command via a shell, the sudo front-end
1201
     * escapes potential meta chars.  We unescape non-spaces
1202
     * for sudoers matching and logging purposes.
1203
     * TODO: move escaping to the policy plugin instead
1204
     */
1205
725
    ctx->user.cmnd_args = strvec_join(ctx->runas.argv + 1, ' ',
1206
725
        strlcpy_unescape);
1207
725
      } else {
1208
690
    ctx->user.cmnd_args = strvec_join(ctx->runas.argv + 1, ' ',
1209
690
        NULL);
1210
690
      }
1211
1.41k
      if (ctx->user.cmnd_args == NULL)
1212
0
    debug_return_int(NOT_FOUND_ERROR);
1213
1.41k
  }
1214
18.5k
    }
1215
29.2k
    if (ctx->user.cmnd == NULL) {
1216
15.6k
  ctx->user.cmnd = strdup(ctx->runas.argv[0]);
1217
15.6k
  if (ctx->user.cmnd == NULL)
1218
0
      debug_return_int(NOT_FOUND_ERROR);
1219
15.6k
    }
1220
29.2k
    ctx->user.cmnd_base = sudo_basename(ctx->user.cmnd);
1221
1222
    /* Convert "sudo sudoedit" -> "sudoedit" */
1223
29.2k
    if (ISSET(ctx->mode, MODE_RUN) && strcmp(ctx->user.cmnd_base, "sudoedit") == 0) {
1224
288
  char *new_cmnd;
1225
1226
288
  CLR(ctx->mode, MODE_RUN);
1227
288
  SET(ctx->mode, MODE_EDIT);
1228
288
  sudo_warnx("%s", U_("sudoedit doesn't need to be run via sudo"));
1229
288
  if ((new_cmnd = strdup("sudoedit")) == NULL) {
1230
0
      sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
1231
0
      debug_return_int(NOT_FOUND_ERROR);
1232
0
  }
1233
288
  free(ctx->user.cmnd);
1234
288
  ctx->user.cmnd_base = ctx->user.cmnd = new_cmnd;
1235
288
    }
1236
1237
29.2k
    TAILQ_FOREACH(nss, snl, entries) {
1238
  /* Missing/invalid defaults is not a fatal error. */
1239
29.2k
  (void)update_defaults(ctx, nss->parse_tree, NULL, SETDEF_CMND, false);
1240
29.2k
    }
1241
1242
29.2k
    debug_return_int(ret);
1243
29.2k
}
1244
1245
static int
1246
open_file(const char *path, int flags)
1247
0
{
1248
0
    int fd;
1249
0
    debug_decl(open_file, SUDOERS_DEBUG_PLUGIN);
1250
1251
0
    if (!set_perms(NULL, PERM_SUDOERS))
1252
0
  debug_return_int(-1);
1253
1254
0
    fd = open(path, flags);
1255
0
    if (fd == -1 && errno == EACCES && geteuid() != ROOT_UID) {
1256
  /*
1257
   * If we tried to open sudoers as non-root but got EACCES,
1258
   * try again as root.
1259
   */
1260
0
  int serrno = errno;
1261
0
  if (restore_perms() && set_perms(NULL, PERM_ROOT))
1262
0
      fd = open(path, flags);
1263
0
  errno = serrno;
1264
0
    }
1265
0
    if (!restore_perms()) {
1266
  /* unable to change back to root */
1267
0
  if (fd != -1) {
1268
0
      close(fd);
1269
0
      fd = -1;
1270
0
  }
1271
0
    }
1272
1273
0
    debug_return_int(fd);
1274
0
}
1275
1276
/*
1277
 * Open sudoers file and check mode/owner/type.
1278
 * Returns a handle to the sudoers file or NULL on error.
1279
 */
1280
FILE *
1281
open_sudoers(const char *path, char **outfile, bool doedit, bool *keepopen)
1282
0
{
1283
0
    char fname[PATH_MAX];
1284
0
    FILE *fp = NULL;
1285
0
    struct stat sb;
1286
0
    int error, fd;
1287
0
    debug_decl(open_sudoers, SUDOERS_DEBUG_PLUGIN);
1288
1289
0
    fd = sudo_open_conf_path(path, fname, sizeof(fname), open_file);
1290
0
    if (sudoers_ctx.parser_conf.ignore_perms) {
1291
  /* Skip sudoers security checks when ignore_perms is set. */
1292
0
  if (fd == -1 || fstat(fd, &sb) == -1)
1293
0
      error = SUDO_PATH_MISSING;
1294
0
  else
1295
0
      error = SUDO_PATH_SECURE;
1296
0
    } else {
1297
0
  error = sudo_secure_fd(fd, S_IFREG, sudoers_file_uid(),
1298
0
      sudoers_file_gid(), &sb);
1299
0
    }
1300
0
    switch (error) {
1301
0
    case SUDO_PATH_SECURE:
1302
  /*
1303
   * Make sure we can read the file so we can present the
1304
   * user with a reasonable error message (unlike the lexer).
1305
   */
1306
0
  if ((fp = fdopen(fd, "r")) == NULL) {
1307
0
      log_warning(&sudoers_ctx, SLOG_PARSE_ERROR,
1308
0
    N_("unable to open %s"), fname);
1309
0
  } else {
1310
0
      fd = -1;
1311
0
      if (sb.st_size != 0 && fgetc(fp) == EOF) {
1312
0
    log_warning(&sudoers_ctx, SLOG_PARSE_ERROR,
1313
0
        N_("unable to read %s"), fname);
1314
0
    fclose(fp);
1315
0
    fp = NULL;
1316
0
      } else {
1317
    /* Rewind fp and set close on exec flag. */
1318
0
    rewind(fp);
1319
0
    (void)fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
1320
0
    if (outfile != NULL) {
1321
0
                    *outfile = sudo_rcstr_dup(fname);
1322
0
        if (*outfile == NULL) {
1323
0
      sudo_warnx(U_("%s: %s"), __func__,
1324
0
          U_("unable to allocate memory"));
1325
0
      fclose(fp);
1326
0
      fp = NULL;
1327
0
        }
1328
0
    }
1329
0
      }
1330
0
  }
1331
0
  break;
1332
0
    case SUDO_PATH_MISSING:
1333
0
  log_warning(&sudoers_ctx, SLOG_PARSE_ERROR,
1334
0
      N_("unable to open %s"), path);
1335
0
  break;
1336
0
    case SUDO_PATH_BAD_TYPE:
1337
0
  log_warningx(&sudoers_ctx, SLOG_PARSE_ERROR,
1338
0
      N_("%s is not a regular file"), fname);
1339
0
  break;
1340
0
    case SUDO_PATH_WRONG_OWNER:
1341
0
  log_warningx(&sudoers_ctx, SLOG_PARSE_ERROR,
1342
0
      N_("%s is owned by uid %u, should be %u"), fname,
1343
0
      (unsigned int)sb.st_uid, (unsigned int)sudoers_file_uid());
1344
0
  break;
1345
0
    case SUDO_PATH_WORLD_WRITABLE:
1346
0
  log_warningx(&sudoers_ctx, SLOG_PARSE_ERROR,
1347
0
      N_("%s is world writable"), fname);
1348
0
  break;
1349
0
    case SUDO_PATH_GROUP_WRITABLE:
1350
0
  log_warningx(&sudoers_ctx, SLOG_PARSE_ERROR,
1351
0
      N_("%s is owned by gid %u, should be %u"), fname,
1352
0
      (unsigned int)sb.st_gid, (unsigned int)sudoers_file_gid());
1353
0
  break;
1354
0
    default:
1355
0
  sudo_warnx("%s: internal error, unexpected error %d", __func__, error);
1356
0
  break;
1357
0
    }
1358
1359
0
    if (fp == NULL && fd != -1)
1360
0
  close(fd);
1361
1362
0
    debug_return_ptr(fp);
1363
0
}
1364
1365
#ifdef HAVE_LOGIN_CAP_H
1366
static bool
1367
set_loginclass(struct sudoers_context *ctx)
1368
{
1369
    const struct passwd *pw = ctx->runas.pw ? ctx->runas.pw : ctx->user.pw;
1370
    const unsigned int errflags = SLOG_RAW_MSG;
1371
    login_cap_t *lc;
1372
    bool ret = true;
1373
    debug_decl(set_loginclass, SUDOERS_DEBUG_PLUGIN);
1374
1375
    if (!def_use_loginclass)
1376
  goto done;
1377
1378
    if (ctx->runas.class && strcmp(ctx->runas.class, "-") != 0) {
1379
  if (ctx->user.uid != 0 && pw->pw_uid != 0) {
1380
      sudo_warnx(U_("only root can use \"-c %s\""), ctx->runas.class);
1381
      ret = false;
1382
      goto done;
1383
  }
1384
    } else {
1385
  ctx->runas.class = pw->pw_class;
1386
  if (!ctx->runas.class || !*ctx->runas.class)
1387
      ctx->runas.class = (char *)
1388
    ((pw->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS);
1389
    }
1390
1391
    /* Make sure specified login class is valid. */
1392
    lc = login_getclass(ctx->runas.class);
1393
    if (!lc || !lc->lc_class || strcmp(lc->lc_class, ctx->runas.class) != 0) {
1394
  /*
1395
   * Don't make it an error if the user didn't specify the login
1396
   * class themselves.  We do this because if login.conf gets
1397
   * corrupted we want the admin to be able to use sudo to fix it.
1398
   */
1399
  log_warningx(ctx, errflags, N_("unknown login class %s"),
1400
      ctx->runas.class);
1401
  def_use_loginclass = false;
1402
  if (ctx->runas.class)
1403
      ret = false;
1404
    }
1405
    login_close(lc);
1406
done:
1407
    debug_return_bool(ret);
1408
}
1409
#else
1410
static bool
1411
set_loginclass(struct sudoers_context *ctx)
1412
21.5k
{
1413
21.5k
    return true;
1414
21.5k
}
1415
#endif /* HAVE_LOGIN_CAP_H */
1416
1417
/*
1418
 * Get passwd entry for the user we are going to run commands as
1419
 * and store it in ctx->runas.pw.  By default, commands run as "root".
1420
 */
1421
static bool
1422
set_runaspw(struct sudoers_context *ctx, const char *user, bool quiet)
1423
48.4k
{
1424
48.4k
    struct passwd *pw = NULL;
1425
48.4k
    debug_decl(set_runaspw, SUDOERS_DEBUG_PLUGIN);
1426
1427
48.4k
    unknown_runas_uid = false;
1428
48.4k
    if (*user == '#') {
1429
293
  const char *errstr;
1430
293
  uid_t uid = sudo_strtoid(user + 1, &errstr);
1431
293
  if (errstr == NULL) {
1432
290
      if ((pw = sudo_getpwuid(uid)) == NULL) {
1433
90
    unknown_runas_uid = true;
1434
90
    pw = sudo_fakepwnam(user, ctx->user.gid);
1435
90
      }
1436
290
  }
1437
293
    }
1438
48.4k
    if (pw == NULL) {
1439
48.1k
  if ((pw = sudo_getpwnam(user)) == NULL) {
1440
45
      if (!quiet)
1441
45
    log_warningx(ctx, SLOG_AUDIT, N_("unknown user %s"), user);
1442
45
      debug_return_bool(false);
1443
45
  }
1444
48.1k
    }
1445
48.3k
    if (ctx->runas.pw != NULL)
1446
26.8k
  sudo_pw_delref(ctx->runas.pw);
1447
48.3k
    ctx->runas.pw = pw;
1448
48.3k
    debug_return_bool(true);
1449
48.3k
}
1450
1451
/*
1452
 * Get group entry for the group we are going to run commands as
1453
 * and store it in ctx->runas.gr.
1454
 */
1455
static bool
1456
set_runasgr(struct sudoers_context *ctx, const char *group, bool quiet)
1457
711
{
1458
711
    struct group *gr = NULL;
1459
711
    debug_decl(set_runasgr, SUDOERS_DEBUG_PLUGIN);
1460
1461
711
    unknown_runas_gid = false;
1462
711
    if (*group == '#') {
1463
543
  const char *errstr;
1464
543
  gid_t gid = sudo_strtoid(group + 1, &errstr);
1465
543
  if (errstr == NULL) {
1466
542
      if ((gr = sudo_getgrgid(gid)) == NULL) {
1467
411
    unknown_runas_gid = true;
1468
411
    gr = sudo_fakegrnam(group);
1469
411
      }
1470
542
  }
1471
543
    }
1472
711
    if (gr == NULL) {
1473
169
  if ((gr = sudo_getgrnam(group)) == NULL) {
1474
118
      if (!quiet)
1475
118
    log_warningx(ctx, SLOG_AUDIT, N_("unknown group %s"), group);
1476
118
      debug_return_bool(false);
1477
118
  }
1478
169
    }
1479
593
    if (ctx->runas.gr != NULL)
1480
0
  sudo_gr_delref(ctx->runas.gr);
1481
593
    ctx->runas.gr = gr;
1482
593
    debug_return_bool(true);
1483
593
}
1484
1485
/*
1486
 * Callback for runas_default sudoers setting.
1487
 */
1488
bool
1489
cb_runas_default(struct sudoers_context *ctx, const char *file, int line,
1490
    int column, const union sudo_defs_val *sd_un, int op)
1491
27.9k
{
1492
27.9k
    debug_decl(cb_runas_default, SUDOERS_DEBUG_PLUGIN);
1493
1494
    /* Only reset runaspw if user didn't specify one. */
1495
27.9k
    if (ctx->runas.user == NULL && ctx->runas.group == NULL)
1496
26.8k
  debug_return_bool(set_runaspw(ctx, sd_un->str, true));
1497
1.11k
    debug_return_bool(true);
1498
1.11k
}
1499
1500
/*
1501
 * Cleanup hook for sudo_fatal()/sudo_fatalx()
1502
 * Also called at policy close time.
1503
 */
1504
void
1505
sudoers_cleanup(void)
1506
27.3k
{
1507
27.3k
    struct sudo_nss *nss;
1508
27.3k
    struct defaults *def;
1509
27.3k
    debug_decl(sudoers_cleanup, SUDOERS_DEBUG_PLUGIN);
1510
1511
27.3k
    if (snl != NULL) {
1512
21.5k
  TAILQ_FOREACH(nss, snl, entries) {
1513
21.5k
      nss->close(&sudoers_ctx, nss);
1514
21.5k
  }
1515
21.5k
  snl = NULL;
1516
21.5k
  reset_parser();
1517
21.5k
    }
1518
45.1k
    while ((def = TAILQ_FIRST(&initial_defaults)) != NULL) {
1519
17.8k
  TAILQ_REMOVE(&initial_defaults, def, entries);
1520
17.8k
  free(def->var);
1521
17.8k
  free(def->val);
1522
17.8k
  free(def);
1523
17.8k
    }
1524
27.3k
    need_reinit = false;
1525
27.3k
    if (def_group_plugin)
1526
0
  group_plugin_unload();
1527
27.3k
    sudoers_ctx_free(&sudoers_ctx);
1528
27.3k
    sudo_freepwcache();
1529
27.3k
    sudo_freegrcache();
1530
27.3k
    canon_path_free_cache();
1531
1532
    /* We must free the cached environment before running g/c. */
1533
27.3k
    env_free();
1534
1535
    /* Run garbage collector. */
1536
27.3k
    sudoers_gc_run();
1537
1538
    /* Clear globals */
1539
27.3k
    prev_user = NULL;
1540
1541
27.3k
    debug_return;
1542
27.3k
}
1543
1544
bool
1545
sudoers_set_mode(unsigned int flags, unsigned int mask)
1546
36.6k
{
1547
36.6k
    SET(sudoers_ctx.mode, flags);
1548
36.6k
    return ((sudoers_ctx.mode & mask) == sudoers_ctx.mode);
1549
36.6k
}
1550
1551
const struct sudoers_context *
1552
sudoers_get_context(void)
1553
72.5k
{
1554
72.5k
    return &sudoers_ctx;
1555
72.5k
}
1556
1557
bool
1558
sudoers_set_log_format(enum def_tuple tuple)
1559
0
{
1560
0
    enum eventlog_format format;
1561
0
    debug_decl(cb_log_format, SUDOERS_DEBUG_PLUGIN);
1562
1563
    /* FFR - make "json" an alias for EVLOG_JSON_COMPACT instead. */
1564
0
    switch (tuple) {
1565
0
    case json_compact:
1566
0
        format = EVLOG_JSON_COMPACT;
1567
0
        break;
1568
0
    case json:
1569
0
    case json_pretty:
1570
0
        format = EVLOG_JSON_PRETTY;
1571
0
        break;
1572
0
    case sudo:
1573
0
        format = EVLOG_SUDO;
1574
0
        break;
1575
0
    default:
1576
0
  debug_return_bool(false);
1577
0
    }
1578
0
    eventlog_set_format(format);
1579
1580
0
    debug_return_bool(true);
1581
0
}