Coverage Report

Created: 2025-08-09 06:14

/src/sudo/plugins/sudoers/lookup.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * SPDX-License-Identifier: ISC
3
 *
4
 * Copyright (c) 2004-2005, 2007-2024 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
19
/*
20
 * This is an open source non-commercial project. Dear PVS-Studio, please check it.
21
 * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
22
 */
23
24
#include <config.h>
25
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <string.h>
29
#include <unistd.h>
30
#include <pwd.h>
31
32
#include <sudoers.h>
33
#include <gram.h>
34
35
static int
36
runas_matches_pw(struct sudoers_parse_tree *parse_tree,
37
    const struct cmndspec *cs, const struct passwd *pw)
38
0
{
39
0
    debug_decl(runas_matches_pw, SUDOERS_DEBUG_PARSER);
40
41
0
    if (cs->runasuserlist != NULL)
42
0
  debug_return_int(userlist_matches(parse_tree, pw, cs->runasuserlist));
43
44
0
    if (cs->runasgrouplist == NULL) {
45
  /* No explicit runas user or group, use default. */
46
0
  if (userpw_matches(def_runas_default, pw->pw_name, pw) == ALLOW)
47
0
      debug_return_int(ALLOW);
48
0
    }
49
0
    debug_return_int(UNSPEC);
50
0
}
51
52
/*
53
 * Look up the user in the sudoers parse tree for pseudo-commands like
54
 * list, verify and kill.
55
 */
56
static unsigned int
57
sudoers_lookup_pseudo(struct sudo_nss_list *snl, struct sudoers_context *ctx,
58
    time_t now, sudoers_lookup_callback_fn_t callback, void *cb_data,
59
    int pwflag)
60
8
{
61
8
    char *saved_runchroot;
62
8
    struct passwd *root_pw = NULL;
63
8
    struct sudo_nss *nss;
64
8
    struct cmndspec *cs;
65
8
    struct privilege *priv;
66
8
    struct userspec *us;
67
8
    struct defaults *def;
68
8
    int nopass, match = UNSPEC;
69
8
    unsigned int validated = 0;
70
8
    enum def_tuple pwcheck;
71
8
    debug_decl(sudoers_lookup_pseudo, SUDOERS_DEBUG_PARSER);
72
73
8
    pwcheck = (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
74
8
    nopass = (pwcheck == never || pwcheck == all) ? true : false;
75
76
8
    if (ctx->runas.list_pw != NULL) {
77
0
  root_pw = sudo_getpwuid(ROOT_UID);
78
0
  if (root_pw == NULL)
79
0
      sudo_warnx(U_("unknown uid %u"), ROOT_UID);
80
8
    } else {
81
8
  SET(validated, FLAG_NO_CHECK);
82
8
    }
83
84
    /* Don't use chroot setting for pseudo-commands. */
85
8
    saved_runchroot = def_runchroot;
86
8
    def_runchroot = NULL;
87
88
8
    TAILQ_FOREACH(nss, snl, entries) {
89
8
  if (nss->query(ctx, nss, ctx->user.pw) == -1) {
90
      /* The query function should have printed an error message. */
91
0
      SET(validated, VALIDATE_ERROR);
92
0
      break;
93
0
  }
94
95
  /*
96
   * We have to traverse the policy forwards, not in reverse,
97
   * to support the "pwcheck == all" case.
98
   */
99
8
  TAILQ_FOREACH(us, &nss->parse_tree->userspecs, entries) {
100
0
      const int user_match = userlist_matches(nss->parse_tree,
101
0
    ctx->user.pw, &us->users);
102
0
      if (user_match != ALLOW) {
103
0
    if (callback != NULL && user_match == DENY) {
104
0
        callback(nss->parse_tree, us, user_match, NULL, UNSPEC,
105
0
      NULL, UNSPEC, UNSPEC, UNSPEC, cb_data);
106
0
    }
107
0
    continue;
108
0
      }
109
0
      TAILQ_FOREACH(priv, &us->privileges, entries) {
110
0
    int priv_nopass = UNSPEC;
111
0
    const int host_match = hostlist_matches(nss->parse_tree,
112
0
        ctx->user.pw, &priv->hostlist);
113
0
    if (host_match != ALLOW) {
114
0
        if (callback != NULL) {
115
0
      callback(nss->parse_tree, us, user_match, priv,
116
0
          host_match, NULL, UNSPEC, UNSPEC, UNSPEC, cb_data);
117
0
        }
118
0
        continue;
119
0
    }
120
0
    TAILQ_FOREACH(def, &priv->defaults, entries) {
121
0
        if (strcmp(def->var, "authenticate") == 0) {
122
0
      priv_nopass = !def->op;
123
0
      break;
124
0
        }
125
0
    }
126
0
    TAILQ_FOREACH(cs, &priv->cmndlist, entries) {
127
0
        int cmnd_match = UNSPEC;
128
0
        int date_match = UNSPEC;
129
0
        int runas_match = UNSPEC;
130
131
0
        if (pwcheck == any) {
132
0
      if (cs->tags.nopasswd == true || priv_nopass == true)
133
0
          nopass = true;
134
0
        } else if (pwcheck == all) {
135
0
      if (cs->tags.nopasswd != true && priv_nopass != true)
136
0
          nopass = false;
137
0
        }
138
139
0
        if (cs->notbefore != UNSPEC) {
140
0
      date_match = now < cs->notbefore ? DENY : ALLOW;
141
0
        }
142
0
        if (cs->notafter != UNSPEC) {
143
0
      date_match = now > cs->notafter ? DENY : ALLOW;
144
0
        }
145
        /*
146
         * Root can list any user's privileges.
147
         * A user may always list their own privileges.
148
         */
149
0
        if (ctx->user.uid == 0 || ctx->runas.list_pw == NULL ||
150
0
          ctx->user.uid == ctx->runas.list_pw->pw_uid) {
151
0
      cmnd_match = ALLOW;
152
0
      runas_match = ALLOW;
153
0
        } else if (date_match != DENY) {
154
      /*
155
       * To list another user's privileges, the runas
156
       * user must match the list user or root.
157
       */
158
0
      runas_match = runas_matches_pw(nss->parse_tree, cs,
159
0
          ctx->runas.list_pw);
160
0
      switch (runas_match) {
161
0
      case DENY:
162
0
          break;
163
0
      case ALLOW:
164
          /*
165
           * RunAs user matches list user.
166
           * Match on command "list" or ALL.
167
           */
168
0
          cmnd_match = cmnd_matches(nss->parse_tree,
169
0
        cs->cmnd, cs->runchroot, NULL);
170
0
          break;
171
0
      default:
172
          /*
173
           * RunAs user doesn't match list user.
174
           * Only allow listing if the user has
175
           * "sudo ALL" for root.
176
           */
177
0
          if (root_pw != NULL &&
178
0
            runas_matches_pw(nss->parse_tree, cs,
179
0
            root_pw) == ALLOW) {
180
0
        runas_match = ALLOW;
181
0
        cmnd_match = cmnd_matches_all(nss->parse_tree,
182
0
            cs->cmnd, cs->runchroot, NULL);
183
0
          }
184
0
          break;
185
0
      }
186
0
        }
187
0
        if (callback != NULL) {
188
0
      callback(nss->parse_tree, us, user_match, priv,
189
0
          host_match, cs, date_match, runas_match,
190
0
          cmnd_match, cb_data);
191
0
        }
192
0
        if (SPECIFIED(cmnd_match)) {
193
      /*
194
       * We take the last match but must process
195
       * the entire policy for pwcheck == all.
196
       */
197
0
      match = cmnd_match;
198
0
        }
199
0
    }
200
0
      }
201
0
  }
202
8
  if (!sudo_nss_can_continue(nss, match))
203
0
      break;
204
8
    }
205
8
    if (root_pw != NULL)
206
0
  sudo_pw_delref(root_pw);
207
8
    if (match == ALLOW || ctx->user.uid == 0) {
208
  /* User has an entry for this host. */
209
8
  SET(validated, VALIDATE_SUCCESS);
210
8
    } else {
211
  /* No entry or user is not allowed to list other users. */
212
0
  SET(validated, VALIDATE_FAILURE);
213
0
    }
214
8
    if (pwcheck == always && def_authenticate)
215
0
  SET(validated, FLAG_CHECK_USER);
216
8
    else if (nopass == true)
217
0
  def_authenticate = false;
218
219
    /* Restore original def_runchroot. */
220
8
    def_runchroot = saved_runchroot;
221
222
8
    debug_return_uint(validated);
223
8
}
224
225
static int
226
sudoers_lookup_check(struct sudo_nss *nss, struct sudoers_context *ctx,
227
    unsigned int *validated, struct cmnd_info *info, time_t now,
228
    sudoers_lookup_callback_fn_t callback, void *cb_data,
229
    struct cmndspec **matching_cs, struct defaults_list **defs)
230
8
{
231
8
    struct cmndspec *cs;
232
8
    struct privilege *priv;
233
8
    struct userspec *us;
234
8
    struct member *matching_user;
235
8
    debug_decl(sudoers_lookup_check, SUDOERS_DEBUG_PARSER);
236
237
8
    memset(info, 0, sizeof(*info));
238
239
8
    TAILQ_FOREACH_REVERSE(us, &nss->parse_tree->userspecs, userspec_list, entries) {
240
0
  const int user_match = userlist_matches(nss->parse_tree, ctx->user.pw,
241
0
      &us->users);
242
0
  if (user_match != ALLOW) {
243
0
      if (callback != NULL && user_match == DENY) {
244
0
    callback(nss->parse_tree, us, user_match, NULL, UNSPEC, NULL,
245
0
        UNSPEC, UNSPEC, UNSPEC, cb_data);
246
0
      }
247
0
      continue;
248
0
  }
249
0
  CLR(*validated, FLAG_NO_USER);
250
0
  TAILQ_FOREACH_REVERSE(priv, &us->privileges, privilege_list, entries) {
251
0
      const int host_match = hostlist_matches(nss->parse_tree,
252
0
    ctx->user.pw, &priv->hostlist);
253
0
      if (host_match == ALLOW) {
254
0
    CLR(*validated, FLAG_NO_HOST);
255
0
      } else {
256
0
    if (callback != NULL) {
257
0
        callback(nss->parse_tree, us, user_match, priv, host_match,
258
0
      NULL, UNSPEC, UNSPEC, UNSPEC, cb_data);
259
0
    }
260
0
    continue;
261
0
      }
262
0
      TAILQ_FOREACH_REVERSE(cs, &priv->cmndlist, cmndspec_list, entries) {
263
0
    int cmnd_match = UNSPEC;
264
0
    int date_match = UNSPEC;
265
0
    int runas_match = UNSPEC;
266
267
0
    if (cs->notbefore != UNSPEC) {
268
0
        date_match = now < cs->notbefore ? DENY : ALLOW;
269
0
    }
270
0
    if (cs->notafter != UNSPEC) {
271
0
        date_match = now > cs->notafter ? DENY : ALLOW;
272
0
    }
273
0
    if (date_match != DENY) {
274
0
        matching_user = NULL;
275
0
        runas_match = runaslist_matches(nss->parse_tree,
276
0
      cs->runasuserlist, cs->runasgrouplist, &matching_user,
277
0
      NULL);
278
0
        if (runas_match == ALLOW) {
279
0
      cmnd_match = cmnd_matches(nss->parse_tree, cs->cmnd,
280
0
          cs->runchroot, info);
281
0
        }
282
0
    }
283
0
    if (callback != NULL) {
284
0
        callback(nss->parse_tree, us, user_match, priv, host_match,
285
0
      cs, date_match, runas_match, cmnd_match, cb_data);
286
0
    }
287
288
0
    if (SPECIFIED(cmnd_match)) {
289
        /*
290
         * If user is running command as themselves,
291
         * set ctx->runas.pw = ctx->user.pw.
292
         * XXX - hack, want more general solution
293
         */
294
0
        if (matching_user && matching_user->type == MYSELF) {
295
0
      sudo_pw_delref(ctx->runas.pw);
296
0
      sudo_pw_addref(ctx->user.pw);
297
0
      ctx->runas.pw = ctx->user.pw;
298
0
        }
299
0
        *matching_cs = cs;
300
0
        *defs = &priv->defaults;
301
0
        sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
302
0
      "userspec matched @ %s:%d:%d: %s",
303
0
      us->file ? us->file : "???", us->line, us->column,
304
0
      cmnd_match ? "allowed" : "denied");
305
0
        debug_return_int(cmnd_match);
306
0
    }
307
0
    free(info->cmnd_path);
308
0
    memset(info, 0, sizeof(*info));
309
0
      }
310
0
  }
311
0
    }
312
8
    debug_return_int(UNSPEC);
313
8
}
314
315
/*
316
 * Apply cmndspec-specific settings including SELinux role/type,
317
 * AppArmor profile, Solaris privs, and command tags.
318
 */
319
static bool
320
apply_cmndspec(struct sudoers_context *ctx, struct cmndspec *cs)
321
0
{
322
0
    debug_decl(apply_cmndspec, SUDOERS_DEBUG_PARSER);
323
324
0
    if (cs != NULL) {
325
  /* Set role and type if not specified on command line. */
326
0
  if (ctx->runas.role == NULL) {
327
0
      if (cs->role != NULL) {
328
0
    ctx->runas.role = strdup(cs->role);
329
0
    if (ctx->runas.role == NULL) {
330
0
        sudo_warnx(U_("%s: %s"), __func__,
331
0
      U_("unable to allocate memory"));
332
0
        debug_return_bool(false);
333
0
    }
334
0
      } else {
335
0
    ctx->runas.role = def_role;
336
0
    def_role = NULL;
337
0
      }
338
0
      if (ctx->runas.role != NULL) {
339
0
    sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
340
0
        "ctx->runas.role -> %s", ctx->runas.role);
341
0
      }
342
0
  }
343
0
  if (ctx->runas.type == NULL) {
344
0
      if (cs->type != NULL) {
345
0
    ctx->runas.type = strdup(cs->type);
346
0
    if (ctx->runas.type == NULL) {
347
0
        sudo_warnx(U_("%s: %s"), __func__,
348
0
      U_("unable to allocate memory"));
349
0
        debug_return_bool(false);
350
0
    }
351
0
      } else {
352
0
    ctx->runas.type = def_type;
353
0
    def_type = NULL;
354
0
      }
355
0
      if (ctx->runas.type != NULL) {
356
0
    sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
357
0
        "ctx->runas.type -> %s", ctx->runas.type);
358
0
      }
359
0
  }
360
  /* Set AppArmor profile, if specified */
361
0
  if (cs->apparmor_profile != NULL) {
362
0
      free(ctx->runas.apparmor_profile);
363
0
      ctx->runas.apparmor_profile = strdup(cs->apparmor_profile);
364
0
      if (ctx->runas.apparmor_profile == NULL) {
365
0
    sudo_warnx(U_("%s: %s"), __func__,
366
0
        U_("unable to allocate memory"));
367
0
    debug_return_bool(false);
368
0
      }
369
0
  } else {
370
0
      free(ctx->runas.apparmor_profile);
371
0
      ctx->runas.apparmor_profile = def_apparmor_profile;
372
0
      def_apparmor_profile = NULL;
373
0
  }
374
0
  if (ctx->runas.apparmor_profile != NULL) {
375
0
      sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
376
0
    "ctx->runas.apparmor_profile -> %s", ctx->runas.apparmor_profile);
377
0
  }
378
  /* Set Solaris privilege sets */
379
0
  if (cs->privs != NULL) {
380
0
      free(ctx->runas.privs);
381
0
      ctx->runas.privs = strdup(cs->privs);
382
0
      if (ctx->runas.privs == NULL) {
383
0
    sudo_warnx(U_("%s: %s"), __func__,
384
0
        U_("unable to allocate memory"));
385
0
    debug_return_bool(false);
386
0
      }
387
0
  } else {
388
0
      free(ctx->runas.privs);
389
0
      ctx->runas.privs = def_privs;
390
0
      def_privs = NULL;
391
0
  }
392
0
  if (ctx->runas.privs != NULL) {
393
0
      sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
394
0
    "ctx->runas.privs -> %s", ctx->runas.privs);
395
0
  }
396
0
  if (cs->limitprivs != NULL) {
397
0
      free(ctx->runas.limitprivs);
398
0
      ctx->runas.limitprivs = strdup(cs->limitprivs);
399
0
      if (ctx->runas.limitprivs == NULL) {
400
0
    sudo_warnx(U_("%s: %s"), __func__,
401
0
        U_("unable to allocate memory"));
402
0
    debug_return_bool(false);
403
0
      }
404
0
  } else {
405
0
      free(ctx->runas.limitprivs);
406
0
      ctx->runas.limitprivs = def_limitprivs;
407
0
      def_limitprivs = NULL;
408
0
  }
409
0
  if (ctx->runas.limitprivs != NULL) {
410
0
      sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
411
0
    "ctx->runas.limitprivs -> %s", ctx->runas.limitprivs);
412
0
  }
413
0
  if (cs->timeout > 0) {
414
0
      def_command_timeout = cs->timeout;
415
0
      sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
416
0
    "def_command_timeout -> %d", def_command_timeout);
417
0
  }
418
0
  if (cs->runcwd != NULL) {
419
0
      free(def_runcwd);
420
0
      def_runcwd = strdup(cs->runcwd);
421
0
      if (def_runcwd == NULL) {
422
0
    sudo_warnx(U_("%s: %s"), __func__,
423
0
        U_("unable to allocate memory"));
424
0
    debug_return_bool(false);
425
0
      }
426
0
      sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
427
0
    "def_runcwd -> %s", def_runcwd);
428
0
  }
429
0
  if (cs->runchroot != NULL) {
430
0
      free(def_runchroot);
431
0
      def_runchroot = strdup(cs->runchroot);
432
0
      if (def_runchroot == NULL) {
433
0
    sudo_warnx(U_("%s: %s"), __func__,
434
0
        U_("unable to allocate memory"));
435
0
    debug_return_bool(false);
436
0
      }
437
0
      sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
438
0
    "def_runchroot -> %s", def_runchroot);
439
0
  }
440
0
  if (cs->tags.nopasswd != UNSPEC) {
441
0
      def_authenticate = !cs->tags.nopasswd;
442
0
      sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
443
0
    "def_authenticate -> %s", def_authenticate ? "true" : "false");
444
0
  }
445
0
  if (cs->tags.noexec != UNSPEC) {
446
0
      def_noexec = cs->tags.noexec;
447
0
      sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
448
0
    "def_noexec -> %s", def_noexec ? "true" : "false");
449
0
  }
450
0
  if (cs->tags.intercept != UNSPEC) {
451
0
      def_intercept = cs->tags.intercept;
452
0
      sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
453
0
    "def_intercept -> %s", def_intercept ? "true" : "false");
454
0
  }
455
0
  if (cs->tags.setenv != UNSPEC) {
456
0
      def_setenv = cs->tags.setenv;
457
0
      sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
458
0
    "def_setenv -> %s", def_setenv ? "true" : "false");
459
0
  }
460
0
  if (cs->tags.log_input != UNSPEC) {
461
0
      def_log_input = cs->tags.log_input;
462
0
      cb_log_input(ctx, NULL, 0, 0, NULL, cs->tags.log_input);
463
0
      sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
464
0
    "def_log_input -> %s", def_log_input ? "true" : "false");
465
0
  }
466
0
  if (cs->tags.log_output != UNSPEC) {
467
0
      def_log_output = cs->tags.log_output;
468
0
      cb_log_output(ctx, NULL, 0, 0, NULL, cs->tags.log_output);
469
0
      sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
470
0
    "def_log_output -> %s", def_log_output ? "true" : "false");
471
0
  }
472
0
  if (cs->tags.send_mail != UNSPEC) {
473
0
      if (cs->tags.send_mail) {
474
0
    def_mail_all_cmnds = true;
475
0
    sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
476
0
        "def_mail_all_cmnds -> true");
477
0
      } else {
478
0
    def_mail_all_cmnds = false;
479
0
    def_mail_always = false;
480
0
    def_mail_no_perms = false;
481
0
    sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
482
0
        "def_mail_all_cmnds -> false, def_mail_always -> false, "
483
0
        "def_mail_no_perms -> false");
484
0
      }
485
0
  }
486
0
  if (cs->tags.follow != UNSPEC) {
487
0
      def_sudoedit_follow = cs->tags.follow;
488
0
      sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
489
0
    "def_sudoedit_follow -> %s", def_sudoedit_follow ? "true" : "false");
490
0
  }
491
0
    }
492
493
0
    debug_return_bool(true);
494
0
}
495
496
/*
497
 * Look up the user in the sudoers parse tree and check to see if they are
498
 * allowed to run the specified command on this host as the target user.
499
 */
500
unsigned int
501
sudoers_lookup(struct sudo_nss_list *snl, struct sudoers_context *ctx,
502
    time_t now, sudoers_lookup_callback_fn_t callback, void *cb_data,
503
    int *cmnd_status, int pwflag)
504
16
{
505
16
    struct defaults_list *defs = NULL;
506
16
    struct sudoers_parse_tree *parse_tree = NULL;
507
16
    struct cmndspec *cs = NULL;
508
16
    struct sudo_nss *nss;
509
16
    struct cmnd_info info;
510
16
    unsigned int validated = FLAG_NO_USER | FLAG_NO_HOST;
511
16
    int m, match = UNSPEC;
512
16
    debug_decl(sudoers_lookup, SUDOERS_DEBUG_PARSER);
513
514
    /*
515
     * Special case checking the "validate", "list" and "kill" pseudo-commands.
516
     */
517
16
    if (pwflag) {
518
8
  debug_return_uint(sudoers_lookup_pseudo(snl, ctx, now, callback,
519
8
      cb_data, pwflag));
520
8
    }
521
522
    /* Need to be runas user while stat'ing things. */
523
8
    if (!set_perms(ctx, PERM_RUNAS))
524
0
  debug_return_uint(validated);
525
526
    /* Query each sudoers source and check the user. */
527
8
    TAILQ_FOREACH(nss, snl, entries) {
528
8
  if (nss->query(ctx, nss, ctx->user.pw) == -1) {
529
      /* The query function should have printed an error message. */
530
0
      SET(validated, VALIDATE_ERROR);
531
0
      break;
532
0
  }
533
534
8
  m = sudoers_lookup_check(nss, ctx, &validated, &info, now, callback,
535
8
      cb_data, &cs, &defs);
536
8
  if (SPECIFIED(m)) {
537
0
      match = m;
538
0
      parse_tree = nss->parse_tree;
539
0
  }
540
541
8
  if (!sudo_nss_can_continue(nss, m))
542
0
      break;
543
8
    }
544
8
    if (SPECIFIED(match)) {
545
0
  if (info.cmnd_path != NULL) {
546
      /* Update cmnd, cmnd_stat, cmnd_status from matching entry. */
547
0
      free(ctx->user.cmnd);
548
0
      ctx->user.cmnd = info.cmnd_path;
549
0
      if (ctx->user.cmnd_stat != NULL)
550
0
    *ctx->user.cmnd_stat = info.cmnd_stat;
551
0
      *cmnd_status = info.status;
552
0
  }
553
0
  if (defs != NULL)
554
0
      (void)update_defaults(ctx, parse_tree, defs, SETDEF_GENERIC, false);
555
0
  if (!apply_cmndspec(ctx, cs))
556
0
      SET(validated, VALIDATE_ERROR);
557
0
  else if (match == ALLOW)
558
0
      SET(validated, VALIDATE_SUCCESS);
559
0
  else
560
0
      SET(validated, VALIDATE_FAILURE);
561
0
    }
562
8
    if (!restore_perms())
563
0
  SET(validated, VALIDATE_ERROR);
564
8
    debug_return_uint(validated);
565
8
}