/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 | } |