/src/sudo/plugins/sudoers/defaults.c
Line | Count | Source |
1 | | /* |
2 | | * SPDX-License-Identifier: ISC |
3 | | * |
4 | | * Copyright (c) 1999-2005, 2007-2023 |
5 | | * Todd C. Miller <Todd.Miller@sudo.ws> |
6 | | * |
7 | | * Permission to use, copy, modify, and distribute this software for any |
8 | | * purpose with or without fee is hereby granted, provided that the above |
9 | | * copyright notice and this permission notice appear in all copies. |
10 | | * |
11 | | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
12 | | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
13 | | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
14 | | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
15 | | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
16 | | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
17 | | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
18 | | * |
19 | | * Sponsored in part by the Defense Advanced Research Projects |
20 | | * Agency (DARPA) and Air Force Research Laboratory, Air Force |
21 | | * Materiel Command, USAF, under agreement number F39502-99-1-0512. |
22 | | */ |
23 | | |
24 | | #include <config.h> |
25 | | |
26 | | #include <sys/stat.h> |
27 | | #include <stdio.h> |
28 | | #include <stdlib.h> |
29 | | #include <string.h> |
30 | | #include <unistd.h> |
31 | | #include <ctype.h> |
32 | | #include <errno.h> |
33 | | #include <limits.h> |
34 | | #include <syslog.h> |
35 | | |
36 | | #include <sudoers.h> |
37 | | #include <sudo_eventlog.h> |
38 | | #include <sudo_iolog.h> |
39 | | #include <gram.h> |
40 | | |
41 | | static struct early_default early_defaults[] = { |
42 | | { I_IGNORE_UNKNOWN_DEFAULTS }, |
43 | | #ifdef FQDN |
44 | | { I_FQDN, true }, |
45 | | #else |
46 | | { I_FQDN }, |
47 | | #endif |
48 | | { I_MATCH_GROUP_BY_GID }, |
49 | | { I_GROUP_PLUGIN }, |
50 | | { I_RUNAS_DEFAULT }, |
51 | | { I_SUDOERS_LOCALE }, |
52 | | { -1 } |
53 | | }; |
54 | | |
55 | | /* |
56 | | * Local prototypes. |
57 | | */ |
58 | | static bool store_int(const char *str, struct sudo_defs_types *def); |
59 | | static bool store_list(const char *str, struct sudo_defs_types *def, int op); |
60 | | static bool store_mode(const char *str, struct sudo_defs_types *def); |
61 | | static int store_str(const char *str, struct sudo_defs_types *def); |
62 | | static bool store_syslogfac(const char *str, struct sudo_defs_types *def); |
63 | | static bool store_syslogpri(const char *str, struct sudo_defs_types *def); |
64 | | static bool store_timeout(const char *str, struct sudo_defs_types *def); |
65 | | static bool store_tuple(const char *str, struct sudo_defs_types *def, int op); |
66 | | static bool store_uint(const char *str, struct sudo_defs_types *def); |
67 | | static bool store_timespec(const char *str, struct sudo_defs_types *def); |
68 | | static bool store_rlimit(const char *str, struct sudo_defs_types *def); |
69 | | static bool store_plugin(const char *str, struct sudo_defs_types *def, int op); |
70 | | static bool list_op(const char *str, size_t, struct list_members *list, enum list_ops op); |
71 | | static bool valid_path(const struct sudoers_context *ctx, const struct sudo_defs_types *def, const char *val, const char *file, int line, int column, bool quiet); |
72 | | |
73 | | /* |
74 | | * Table describing compile-time and run-time options. |
75 | | */ |
76 | | #include <def_data.c> |
77 | | |
78 | | /* |
79 | | * Print version and configure info. |
80 | | */ |
81 | | void |
82 | | dump_defaults(void) |
83 | 2.01k | { |
84 | 2.01k | const struct sudo_defs_types *cur; |
85 | 2.01k | const struct list_member *item; |
86 | 2.01k | const struct def_values *def; |
87 | 2.01k | const char *desc; |
88 | 2.01k | debug_decl(dump_defaults, SUDOERS_DEBUG_DEFAULTS); |
89 | | |
90 | 329k | for (cur = sudo_defs_table; cur->name; cur++) { |
91 | 327k | if (cur->desc) { |
92 | 327k | desc = _(cur->desc); |
93 | 327k | switch (cur->type & T_MASK) { |
94 | 172k | case T_FLAG: |
95 | 172k | if (cur->sd_un.flag) |
96 | 90.5k | sudo_printf(SUDO_CONV_INFO_MSG, "%s\n", desc); |
97 | 172k | break; |
98 | 82.4k | case T_STR: |
99 | 104k | case T_RLIMIT: |
100 | 104k | if (cur->sd_un.str) { |
101 | 54.2k | sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.str); |
102 | 54.2k | sudo_printf(SUDO_CONV_INFO_MSG, "\n"); |
103 | 54.2k | } |
104 | 104k | break; |
105 | 2.01k | case T_LOGFAC: |
106 | 2.01k | if (cur->sd_un.ival) { |
107 | 2.01k | sudo_printf(SUDO_CONV_INFO_MSG, desc, |
108 | 2.01k | sudo_logfac2str(cur->sd_un.ival)); |
109 | 2.01k | sudo_printf(SUDO_CONV_INFO_MSG, "\n"); |
110 | 2.01k | } |
111 | 2.01k | break; |
112 | 4.02k | case T_LOGPRI: |
113 | 4.02k | if (cur->sd_un.ival) { |
114 | 4.02k | sudo_printf(SUDO_CONV_INFO_MSG, desc, |
115 | 4.02k | sudo_logpri2str(cur->sd_un.ival)); |
116 | 4.02k | sudo_printf(SUDO_CONV_INFO_MSG, "\n"); |
117 | 4.02k | } |
118 | 4.02k | break; |
119 | 2.01k | case T_INT: |
120 | 2.01k | sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.ival); |
121 | 2.01k | sudo_printf(SUDO_CONV_INFO_MSG, "\n"); |
122 | 2.01k | break; |
123 | 6.03k | case T_UINT: |
124 | 6.03k | sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.uival); |
125 | 6.03k | sudo_printf(SUDO_CONV_INFO_MSG, "\n"); |
126 | 6.03k | break; |
127 | 4.02k | case T_TIMESPEC: { |
128 | | /* display timespec in minutes and 10ths of a minute */ |
129 | 4.02k | const int min = cur->sd_un.tspec.tv_sec / 60; |
130 | 4.02k | int decimin = |
131 | 4.02k | (((cur->sd_un.tspec.tv_sec % 60) * 10) + 30) / 60; |
132 | 4.02k | decimin += cur->sd_un.tspec.tv_nsec / 100000000; |
133 | 4.02k | sudo_printf(SUDO_CONV_INFO_MSG, desc, min, decimin); |
134 | 4.02k | sudo_printf(SUDO_CONV_INFO_MSG, "\n"); |
135 | 4.02k | break; |
136 | 82.4k | } |
137 | 4.02k | case T_MODE: |
138 | 4.02k | sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.mode); |
139 | 4.02k | sudo_printf(SUDO_CONV_INFO_MSG, "\n"); |
140 | 4.02k | break; |
141 | 10.0k | case T_LIST: |
142 | 10.0k | if (!SLIST_EMPTY(&cur->sd_un.list)) { |
143 | 10.0k | sudo_printf(SUDO_CONV_INFO_MSG, "%s\n", desc); |
144 | 114k | SLIST_FOREACH(item, &cur->sd_un.list, entries) { |
145 | 114k | sudo_printf(SUDO_CONV_INFO_MSG, |
146 | 114k | "\t%s\n", item->value); |
147 | 114k | } |
148 | 10.0k | } |
149 | 10.0k | break; |
150 | 4.02k | case T_TIMEOUT: |
151 | 4.02k | if (cur->sd_un.ival) { |
152 | 2.01k | sudo_printf(SUDO_CONV_INFO_MSG, desc, |
153 | 2.01k | cur->sd_un.ival); |
154 | 2.01k | sudo_printf(SUDO_CONV_INFO_MSG, "\n"); |
155 | 2.01k | } |
156 | 4.02k | break; |
157 | 14.0k | case T_TUPLE: |
158 | 24.1k | for (def = cur->values; def->sval; def++) { |
159 | 24.1k | if (cur->sd_un.tuple == def->nval) { |
160 | 14.0k | sudo_printf(SUDO_CONV_INFO_MSG, desc, def->sval); |
161 | 14.0k | break; |
162 | 14.0k | } |
163 | 24.1k | } |
164 | 14.0k | sudo_printf(SUDO_CONV_INFO_MSG, "\n"); |
165 | 14.0k | break; |
166 | 327k | } |
167 | 327k | } |
168 | 327k | } |
169 | 2.01k | debug_return; |
170 | 2.01k | } |
171 | | |
172 | | static bool |
173 | | defaults_warnx(const struct sudoers_context *ctx, const char *file, int line, |
174 | | int column, bool quiet, const char * restrict fmt, ...) |
175 | 0 | { |
176 | 0 | va_list ap; |
177 | 0 | bool ret; |
178 | 0 | debug_decl(defaults_warnx, SUDOERS_DEBUG_DEFAULTS); |
179 | |
|
180 | 0 | va_start(ap, fmt); |
181 | 0 | ret = parser_vwarnx(ctx, file, line, column, true, quiet, fmt, ap); |
182 | 0 | va_end(ap); |
183 | |
|
184 | 0 | debug_return_bool(ret); |
185 | 0 | } |
186 | | |
187 | | /* |
188 | | * Find the index of the specified Defaults name in sudo_defs_table[] |
189 | | * On success, returns the matching index or -1 on failure. |
190 | | */ |
191 | | static int |
192 | | find_default(const struct sudoers_context *ctx, const char *name, |
193 | | const char *file, int line, int column, bool quiet) |
194 | 1.17M | { |
195 | 1.17M | int i; |
196 | 1.17M | debug_decl(find_default, SUDOERS_DEBUG_DEFAULTS); |
197 | | |
198 | 85.5M | for (i = 0; sudo_defs_table[i].name != NULL; i++) { |
199 | 85.5M | if (strcmp(name, sudo_defs_table[i].name) == 0) |
200 | 1.17M | debug_return_int(i); |
201 | 85.5M | } |
202 | 0 | if (!def_ignore_unknown_defaults) { |
203 | 0 | defaults_warnx(ctx, file, line, column, quiet, |
204 | 0 | N_("unknown defaults entry \"%s\""), name); |
205 | 0 | } |
206 | 0 | debug_return_int(-1); |
207 | 0 | } |
208 | | |
209 | | /* |
210 | | * Parse a defaults entry, storing the parsed entry in sd_un. |
211 | | * Returns true on success or false on failure. |
212 | | */ |
213 | | static bool |
214 | | parse_default_entry(const struct sudoers_context *ctx, |
215 | | struct sudo_defs_types *def, const char *val, int op, |
216 | | const char *file, int line, int column, bool quiet) |
217 | 1.17M | { |
218 | 1.17M | int rc; |
219 | 1.17M | debug_decl(parse_default_entry, SUDOERS_DEBUG_DEFAULTS); |
220 | | |
221 | 1.17M | if (file == NULL) |
222 | 22.2k | file = "front-end"; |
223 | | |
224 | 1.17M | sudo_debug_printf(SUDO_DEBUG_INFO, "%s: %s:%d:%d: %s=%s op=%d", |
225 | 1.17M | __func__, file, line, column, def->name, val ? val : "", op); |
226 | | |
227 | | /* |
228 | | * If no value specified, the boolean flag must be set for non-flags. |
229 | | * Only flags and tuples support boolean "true". |
230 | | */ |
231 | 1.17M | if (val == NULL) { |
232 | 542k | switch (def->type & T_MASK) { |
233 | 0 | case T_LOGFAC: |
234 | 0 | if (op == true) { |
235 | | /* Use default syslog facility if none specified. */ |
236 | 0 | val = LOGFAC; |
237 | 0 | } |
238 | 0 | break; |
239 | 464k | case T_FLAG: |
240 | 464k | break; |
241 | 0 | case T_TUPLE: |
242 | 0 | if (ISSET(def->type, T_BOOL)) |
243 | 0 | break; |
244 | 0 | FALLTHROUGH; |
245 | 78.1k | default: |
246 | 78.1k | if (!ISSET(def->type, T_BOOL) || op != false) { |
247 | 0 | defaults_warnx(ctx, file, line, column, quiet, |
248 | 0 | N_("no value specified for \"%s\""), def->name); |
249 | 0 | debug_return_bool(false); |
250 | 0 | } |
251 | 542k | } |
252 | 542k | } |
253 | | |
254 | | /* Only lists support append/remove. */ |
255 | 1.17M | if ((op == '+' || op == '-') && (def->type & T_MASK) != T_LIST) { |
256 | 0 | defaults_warnx(ctx, file, line, column, quiet, |
257 | 0 | N_("invalid operator \"%c=\" for \"%s\""), op, def->name); |
258 | 0 | debug_return_bool(false); |
259 | 0 | } |
260 | | |
261 | 1.17M | switch (def->type & T_MASK) { |
262 | 26.0k | case T_LOGFAC: |
263 | 26.0k | rc = store_syslogfac(val, def); |
264 | 26.0k | break; |
265 | 52.0k | case T_LOGPRI: |
266 | 52.0k | rc = store_syslogpri(val, def); |
267 | 52.0k | break; |
268 | 482k | case T_STR: |
269 | 482k | if (val != NULL && ISSET(def->type, T_PATH|T_CHPATH)) { |
270 | 196k | if (!valid_path(ctx, def, val, file, line, column, quiet)) { |
271 | 0 | rc = -1; |
272 | 0 | break; |
273 | 0 | } |
274 | 196k | } |
275 | 482k | rc = store_str(val, def); |
276 | 482k | break; |
277 | 0 | case T_INT: |
278 | 0 | rc = store_int(val, def); |
279 | 0 | break; |
280 | 52.0k | case T_UINT: |
281 | 52.0k | rc = store_uint(val, def); |
282 | 52.0k | break; |
283 | 52.0k | case T_MODE: |
284 | 52.0k | rc = store_mode(val, def); |
285 | 52.0k | break; |
286 | 464k | case T_FLAG: |
287 | 464k | if (val != NULL) { |
288 | 0 | defaults_warnx(ctx, file, line, column, quiet, |
289 | 0 | N_("option \"%s\" does not take a value"), def->name); |
290 | 0 | rc = -1; |
291 | 0 | break; |
292 | 0 | } |
293 | 464k | def->sd_un.flag = (bool)op; |
294 | 464k | rc = true; |
295 | 464k | break; |
296 | 22.0k | case T_LIST: |
297 | 22.0k | rc = store_list(val, def, op); |
298 | 22.0k | break; |
299 | 22.0k | case T_TIMEOUT: |
300 | 22.0k | rc = store_timeout(val, def); |
301 | 22.0k | break; |
302 | 62 | case T_TUPLE: |
303 | 62 | rc = store_tuple(val, def, op); |
304 | 62 | break; |
305 | 0 | case T_TIMESPEC: |
306 | 0 | rc = store_timespec(val, def); |
307 | 0 | break; |
308 | 0 | case T_PLUGIN: |
309 | 0 | rc = store_plugin(val, def, op); |
310 | 0 | break; |
311 | 0 | case T_RLIMIT: |
312 | 0 | rc = store_rlimit(val, def); |
313 | 0 | break; |
314 | 0 | default: |
315 | 0 | defaults_warnx(ctx, file, line, column, quiet, |
316 | 0 | N_("invalid Defaults type 0x%x for option \"%s\""), |
317 | 0 | def->type, def->name); |
318 | 0 | rc = -1; |
319 | 0 | break; |
320 | 1.17M | } |
321 | 1.17M | if (rc == false) { |
322 | 0 | defaults_warnx(ctx, file, line, column, quiet, |
323 | 0 | N_("value \"%s\" is invalid for option \"%s\""), val, def->name); |
324 | 0 | } |
325 | | |
326 | 1.17M | debug_return_bool(rc == true); |
327 | 1.17M | } |
328 | | |
329 | | static struct early_default * |
330 | | is_early_default(const char *name) |
331 | 0 | { |
332 | 0 | struct early_default *early; |
333 | 0 | debug_decl(is_early_default, SUDOERS_DEBUG_DEFAULTS); |
334 | |
|
335 | 0 | for (early = early_defaults; early->idx != -1; early++) { |
336 | 0 | if (strcmp(name, sudo_defs_table[early->idx].name) == 0) |
337 | 0 | debug_return_ptr(early); |
338 | 0 | } |
339 | 0 | debug_return_ptr(NULL); |
340 | 0 | } |
341 | | |
342 | | static bool |
343 | | run_callback(struct sudoers_context *ctx, const char *file, int line, |
344 | | int column, struct sudo_defs_types *def, int op) |
345 | 1.17M | { |
346 | 1.17M | debug_decl(run_callback, SUDOERS_DEBUG_DEFAULTS); |
347 | | |
348 | 1.17M | if (def->callback == NULL) |
349 | 522k | debug_return_bool(true); |
350 | 651k | debug_return_bool(def->callback(ctx, file, line, column, &def->sd_un, op)); |
351 | 651k | } |
352 | | |
353 | | /* |
354 | | * Sets/clears an entry in the defaults structure. |
355 | | * Runs the callback if present on success. |
356 | | */ |
357 | | bool |
358 | | set_default(struct sudoers_context *ctx, const char *var, const char *val, |
359 | | int op, const char *file, int line, int column, bool quiet) |
360 | 1.17M | { |
361 | 1.17M | int idx; |
362 | 1.17M | debug_decl(set_default, SUDOERS_DEBUG_DEFAULTS); |
363 | | |
364 | 1.17M | sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, |
365 | 1.17M | "%s: setting Defaults %s -> %s", __func__, var, val ? val : "false"); |
366 | | |
367 | 1.17M | idx = find_default(ctx, var, file, line, column, quiet); |
368 | 1.17M | if (idx != -1) { |
369 | | /* Set parsed value in sudo_defs_table and run callback (if any). */ |
370 | 1.17M | struct sudo_defs_types *def = &sudo_defs_table[idx]; |
371 | 1.17M | if (parse_default_entry(ctx, def, val, op, file, line, column, quiet)) |
372 | 1.17M | debug_return_bool(run_callback(ctx, file, line, column, def, op)); |
373 | 1.17M | } |
374 | 0 | debug_return_bool(false); |
375 | 0 | } |
376 | | |
377 | | /* |
378 | | * Like set_default() but stores the matching default value |
379 | | * and does not run callbacks. |
380 | | */ |
381 | | static bool |
382 | | set_early_default(const struct sudoers_context *ctx, const char *var, |
383 | | const char *val, int op, const char *file, int line, int column, |
384 | | bool quiet, struct early_default *early) |
385 | 0 | { |
386 | 0 | int idx; |
387 | 0 | debug_decl(set_early_default, SUDOERS_DEBUG_DEFAULTS); |
388 | |
|
389 | 0 | idx = find_default(ctx, var, file, line, column, quiet); |
390 | 0 | if (idx != -1) { |
391 | | /* Set parsed value in sudo_defs_table but defer callback (if any). */ |
392 | 0 | struct sudo_defs_types *def = &sudo_defs_table[idx]; |
393 | 0 | if (parse_default_entry(ctx, def, val, op, file, line, column, quiet)) { |
394 | 0 | if (early->file != NULL) |
395 | 0 | sudo_rcstr_delref(early->file); |
396 | 0 | early->file = sudo_rcstr_addref(file); |
397 | 0 | early->line = line; |
398 | 0 | early->column = column; |
399 | 0 | early->run_callback = true; |
400 | 0 | debug_return_bool(true); |
401 | 0 | } |
402 | 0 | } |
403 | 0 | debug_return_bool(false); |
404 | 0 | } |
405 | | |
406 | | /* |
407 | | * Run callbacks for early defaults. |
408 | | */ |
409 | | static bool |
410 | | run_early_defaults(struct sudoers_context *ctx) |
411 | 52.9k | { |
412 | 52.9k | struct early_default *early; |
413 | 52.9k | bool ret = true; |
414 | 52.9k | debug_decl(run_early_defaults, SUDOERS_DEBUG_DEFAULTS); |
415 | | |
416 | 370k | for (early = early_defaults; early->idx != -1; early++) { |
417 | 317k | if (early->run_callback) { |
418 | 0 | if (!run_callback(ctx, early->file, early->line, early->column, |
419 | 0 | &sudo_defs_table[early->idx], true)) |
420 | 0 | ret = false; |
421 | 0 | early->run_callback = false; |
422 | 0 | } |
423 | 317k | } |
424 | 52.9k | debug_return_bool(ret); |
425 | 52.9k | } |
426 | | |
427 | | static void |
428 | | free_defs_val(int type, union sudo_defs_val *sd_un) |
429 | 5.94M | { |
430 | 5.94M | switch (type & T_MASK) { |
431 | 1.49M | case T_STR: |
432 | 1.89M | case T_RLIMIT: |
433 | 1.89M | free(sd_un->str); |
434 | 1.89M | break; |
435 | 182k | case T_LIST: |
436 | 182k | (void)list_op(NULL, 0, &sd_un->list, freeall); |
437 | 182k | break; |
438 | 5.94M | } |
439 | 5.94M | memset(sd_un, 0, sizeof(*sd_un)); |
440 | 5.94M | } |
441 | | |
442 | | static bool |
443 | | init_passprompt_regex(void) |
444 | 36.4k | { |
445 | 36.4k | struct list_member *lm; |
446 | 36.4k | debug_decl(init_passprompt_regex, SUDOERS_DEBUG_DEFAULTS); |
447 | | |
448 | | /* Add initial defaults setting. */ |
449 | 36.4k | lm = calloc(1, sizeof(struct list_member)); |
450 | 36.4k | if (lm == NULL || (lm->value = strdup(PASSPROMPT_REGEX)) == NULL) { |
451 | 0 | free(lm); |
452 | 0 | sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); |
453 | 0 | debug_return_bool(false); |
454 | 0 | } |
455 | 36.4k | SLIST_INSERT_HEAD(&def_passprompt_regex, lm, entries); |
456 | | |
457 | 36.4k | debug_return_bool(true); |
458 | 36.4k | } |
459 | | |
460 | | /* |
461 | | * Set default options to compiled-in values. |
462 | | * Any of these may be overridden at runtime by a "Defaults" file. |
463 | | */ |
464 | | bool |
465 | | init_defaults(void) |
466 | 36.4k | { |
467 | 36.4k | static bool firsttime = true; |
468 | 36.4k | struct sudo_defs_types *def; |
469 | 36.4k | debug_decl(init_defaults, SUDOERS_DEBUG_DEFAULTS); |
470 | | |
471 | | /* Clear any old settings. */ |
472 | 36.4k | if (!firsttime) { |
473 | 5.97M | for (def = sudo_defs_table; def->name != NULL; def++) |
474 | 5.94M | free_defs_val(def->type, &def->sd_un); |
475 | 36.4k | } |
476 | | |
477 | | /* First initialize the flags. */ |
478 | | #ifdef LONG_OTP_PROMPT |
479 | | def_long_otp_prompt = true; |
480 | | #endif |
481 | 36.4k | #ifndef ALLOW_DOT_PATH |
482 | 36.4k | def_ignore_dot = true; |
483 | 36.4k | #endif |
484 | | #ifdef ALWAYS_SEND_MAIL |
485 | | def_mail_always = true; |
486 | | #endif |
487 | 36.4k | #ifdef SEND_MAIL_WHEN_NO_USER |
488 | 36.4k | def_mail_no_user = true; |
489 | 36.4k | #endif |
490 | | #ifdef SEND_MAIL_WHEN_NO_HOST |
491 | | def_mail_no_host = true; |
492 | | #endif |
493 | | #ifdef SEND_MAIL_WHEN_NOT_OK |
494 | | def_mail_no_perms = true; |
495 | | #endif |
496 | 36.4k | #ifndef NO_LECTURE |
497 | 36.4k | def_lecture = once; |
498 | 36.4k | #endif |
499 | 36.4k | #ifndef NO_AUTHENTICATION |
500 | 36.4k | def_authenticate = true; |
501 | 36.4k | #endif |
502 | 36.4k | #ifndef NO_ROOT_SUDO |
503 | 36.4k | def_root_sudo = true; |
504 | 36.4k | #endif |
505 | | #ifdef HOST_IN_LOG |
506 | | def_log_host = true; |
507 | | #endif |
508 | | #ifdef SHELL_IF_NO_ARGS |
509 | | def_shell_noargs = true; |
510 | | #endif |
511 | | #ifdef SHELL_SETS_HOME |
512 | | def_set_home = true; |
513 | | #endif |
514 | 36.4k | #ifndef DONT_LEAK_PATH_INFO |
515 | 36.4k | def_path_info = true; |
516 | 36.4k | #endif |
517 | | #ifdef USE_INSULTS |
518 | | def_insults = true; |
519 | | #endif |
520 | | #ifdef FQDN |
521 | | def_fqdn = true; |
522 | | #endif |
523 | 36.4k | #ifdef ENV_EDITOR |
524 | 36.4k | def_env_editor = true; |
525 | 36.4k | #endif |
526 | | #ifdef UMASK_OVERRIDE |
527 | | def_umask_override = true; |
528 | | #endif |
529 | 36.4k | #ifdef SUDOERS_NAME_MATCH |
530 | 36.4k | def_fast_glob = true; |
531 | 36.4k | def_fdexec = never; |
532 | | #else |
533 | | def_fdexec = digest_only; |
534 | | #endif |
535 | 36.4k | def_timestamp_type = TIMESTAMP_TYPE; |
536 | 36.4k | if ((def_iolog_file = strdup(IOLOG_FILE)) == NULL) |
537 | 0 | goto oom; |
538 | 36.4k | if ((def_iolog_dir = strdup(_PATH_SUDO_IO_LOGDIR)) == NULL) |
539 | 0 | goto oom; |
540 | 36.4k | if ((def_sudoers_locale = strdup("C")) == NULL) |
541 | 0 | goto oom; |
542 | 36.4k | def_env_reset = ENV_RESET; |
543 | 36.4k | def_set_logname = true; |
544 | 36.4k | def_closefrom = STDERR_FILENO + 1; |
545 | 36.4k | def_pam_ruser = true; |
546 | | #ifdef __sun__ |
547 | | def_pam_rhost = true; |
548 | | #endif |
549 | 36.4k | if ((def_pam_service = strdup("sudo")) == NULL) |
550 | 0 | goto oom; |
551 | | #ifdef HAVE_PAM_LOGIN |
552 | | if ((def_pam_login_service = strdup("sudo-i")) == NULL) |
553 | | goto oom; |
554 | | #else |
555 | 36.4k | if ((def_pam_login_service = strdup("sudo")) == NULL) |
556 | 0 | goto oom; |
557 | 36.4k | #endif |
558 | | #ifdef NO_PAM_SESSION |
559 | | def_pam_session = false; |
560 | | #else |
561 | 36.4k | def_pam_session = true; |
562 | 36.4k | #endif |
563 | | #ifdef HAVE_SELINUX |
564 | | def_selinux = true; |
565 | | #endif |
566 | | #ifdef _PATH_SUDO_ADMIN_FLAG |
567 | | if ((def_admin_flag = strdup(_PATH_SUDO_ADMIN_FLAG)) == NULL) |
568 | | goto oom; |
569 | | #endif |
570 | 36.4k | if ((def_rlimit_core = strdup("0,0")) == NULL) |
571 | 0 | goto oom; |
572 | 36.4k | def_intercept_type = dso; |
573 | 36.4k | def_intercept_verify = true; |
574 | 36.4k | def_use_netgroups = true; |
575 | 36.4k | def_netgroup_tuple = false; |
576 | 36.4k | def_sudoedit_checkdir = true; |
577 | 36.4k | def_iolog_mode = S_IRUSR|S_IWUSR; |
578 | 36.4k | def_log_allowed = true; |
579 | 36.4k | def_log_denied = true; |
580 | 36.4k | def_log_format = sudo; |
581 | 36.4k | def_runas_allow_unknown_id = false; |
582 | 36.4k | def_noninteractive_auth = false; |
583 | 36.4k | def_use_pty = true; |
584 | | |
585 | | /* Syslog options need special care since they both strings and ints */ |
586 | 36.4k | #if (LOGGING & SLOG_SYSLOG) |
587 | 36.4k | (void) store_syslogfac(LOGFAC, &sudo_defs_table[I_SYSLOG]); |
588 | 36.4k | (void) store_syslogpri(PRI_SUCCESS, &sudo_defs_table[I_SYSLOG_GOODPRI]); |
589 | 36.4k | (void) store_syslogpri(PRI_FAILURE, &sudo_defs_table[I_SYSLOG_BADPRI]); |
590 | 36.4k | #endif |
591 | | |
592 | | /* Password flags also have a string and integer component. */ |
593 | 36.4k | (void) store_tuple("any", &sudo_defs_table[I_LISTPW], 0); |
594 | 36.4k | (void) store_tuple("all", &sudo_defs_table[I_VERIFYPW], 0); |
595 | | |
596 | | /* Then initialize the int-like things. */ |
597 | 36.4k | #ifdef SUDO_UMASK |
598 | 36.4k | def_umask = SUDO_UMASK; |
599 | | #else |
600 | | def_umask = ACCESSPERMS; |
601 | | #endif |
602 | 36.4k | def_loglinelen = MAXLOGFILELEN; |
603 | 36.4k | def_timestamp_timeout.tv_sec = TIMEOUT * 60; |
604 | 36.4k | def_passwd_timeout.tv_sec = PASSWORD_TIMEOUT * 60; |
605 | 36.4k | def_passwd_tries = TRIES_FOR_PASSWORD; |
606 | | #ifdef HAVE_ZLIB_H |
607 | | def_compress_io = true; |
608 | | #endif |
609 | 36.4k | def_ignore_audit_errors = true; |
610 | 36.4k | def_ignore_iolog_errors = false; |
611 | 36.4k | def_ignore_logfile_errors = true; |
612 | 36.4k | def_log_passwords = true; |
613 | 36.4k | #ifdef SUDOERS_LOG_CLIENT |
614 | 36.4k | def_log_server_timeout = 30; |
615 | 36.4k | def_log_server_verify = true; |
616 | 36.4k | def_log_server_keepalive = true; |
617 | 36.4k | #endif |
618 | | |
619 | | /* Now do the strings */ |
620 | 36.4k | if ((def_mailto = strdup(MAILTO)) == NULL) |
621 | 0 | goto oom; |
622 | 36.4k | if ((def_mailsub = strdup(N_(MAILSUBJECT))) == NULL) |
623 | 0 | goto oom; |
624 | 36.4k | if ((def_badpass_message = strdup(_(INCORRECT_PASSWORD))) == NULL) |
625 | 0 | goto oom; |
626 | 36.4k | #ifdef _PATH_SUDO_LECTURE_DIR |
627 | 36.4k | if ((def_lecture_status_dir = strdup(_PATH_SUDO_LECTURE_DIR)) == NULL) |
628 | 0 | goto oom; |
629 | 36.4k | #endif |
630 | 36.4k | #ifdef _PATH_SUDO_TIMEDIR |
631 | 36.4k | if ((def_timestampdir = strdup(_PATH_SUDO_TIMEDIR)) == NULL) |
632 | 0 | goto oom; |
633 | 36.4k | #endif |
634 | 36.4k | if ((def_passprompt = strdup(_(PASSPROMPT))) == NULL) |
635 | 0 | goto oom; |
636 | 36.4k | if ((def_runas_default = strdup(RUNAS_DEFAULT)) == NULL) |
637 | 0 | goto oom; |
638 | | #ifdef _PATH_SUDO_SENDMAIL |
639 | | if ((def_mailerpath = strdup(_PATH_SUDO_SENDMAIL)) == NULL) |
640 | | goto oom; |
641 | | #endif |
642 | 36.4k | if ((def_mailerflags = strdup("-t")) == NULL) |
643 | 0 | goto oom; |
644 | | #if (LOGGING & SLOG_FILE) |
645 | | if ((def_logfile = strdup(_PATH_SUDO_LOGFILE)) == NULL) |
646 | | goto oom; |
647 | | #endif |
648 | | #ifdef EXEMPTGROUP |
649 | | if ((def_exempt_group = strdup(EXEMPTGROUP)) == NULL) |
650 | | goto oom; |
651 | | #endif |
652 | | #ifdef SECURE_PATH |
653 | | if ((def_secure_path = strdup(SECURE_PATH)) == NULL) |
654 | | goto oom; |
655 | | #endif |
656 | 36.4k | if ((def_editor = strdup(EDITOR)) == NULL) |
657 | 0 | goto oom; |
658 | 36.4k | def_set_utmp = true; |
659 | 36.4k | def_pam_acct_mgmt = true; |
660 | 36.4k | def_pam_setcred = true; |
661 | 36.4k | def_pam_silent = true; |
662 | 36.4k | def_syslog_maxlen = MAXSYSLOGLEN; |
663 | 36.4k | def_case_insensitive_user = true; |
664 | 36.4k | def_case_insensitive_group = true; |
665 | | |
666 | | /* Reset the locale. */ |
667 | 36.4k | if (!firsttime) { |
668 | 36.4k | if (!sudoers_initlocale(NULL, def_sudoers_locale)) |
669 | 0 | goto oom; |
670 | 36.4k | } |
671 | | |
672 | | /* Finally do the lists (currently just environment tables). */ |
673 | 36.4k | if (!init_envtables()) |
674 | 0 | goto oom; |
675 | | |
676 | | /* Init eventlog config. */ |
677 | 36.4k | init_eventlog_config(); |
678 | | |
679 | | /* Initial iolog password prompt regex. */ |
680 | 36.4k | if (!init_passprompt_regex()) |
681 | 0 | debug_return_bool(false); |
682 | | |
683 | 36.4k | firsttime = false; |
684 | | |
685 | 36.4k | debug_return_bool(true); |
686 | 0 | oom: |
687 | 0 | sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); |
688 | 0 | debug_return_bool(false); |
689 | 0 | } |
690 | | |
691 | | /* |
692 | | * Check whether a defaults entry matches the specified type. |
693 | | * Returns true if it matches, else false. |
694 | | */ |
695 | | static bool |
696 | | default_type_matches(const struct defaults *d, int what) |
697 | 22.2k | { |
698 | 22.2k | debug_decl(default_type_matches, SUDOERS_DEBUG_DEFAULTS); |
699 | | |
700 | 22.2k | switch (d->type) { |
701 | 22.2k | case DEFAULTS: |
702 | 22.2k | if (ISSET(what, SETDEF_GENERIC)) |
703 | 22.2k | debug_return_bool(true); |
704 | 0 | break; |
705 | 0 | case DEFAULTS_USER: |
706 | 0 | if (ISSET(what, SETDEF_USER)) |
707 | 0 | debug_return_bool(true); |
708 | 0 | break; |
709 | 0 | case DEFAULTS_RUNAS: |
710 | 0 | if (ISSET(what, SETDEF_RUNAS)) |
711 | 0 | debug_return_bool(true); |
712 | 0 | break; |
713 | 0 | case DEFAULTS_HOST: |
714 | 0 | if (ISSET(what, SETDEF_HOST)) |
715 | 0 | debug_return_bool(true); |
716 | 0 | break; |
717 | 0 | case DEFAULTS_CMND: |
718 | 0 | if (ISSET(what, SETDEF_CMND)) |
719 | 0 | debug_return_bool(true); |
720 | 0 | break; |
721 | 22.2k | } |
722 | 0 | debug_return_bool(false); |
723 | 0 | } |
724 | | |
725 | | /* |
726 | | * Check whether a defaults entry's binding matches. |
727 | | * Returns true if it matches, else false. |
728 | | */ |
729 | | static bool |
730 | | default_binding_matches(const struct sudoers_context *ctx, |
731 | | struct sudoers_parse_tree *parse_tree, const struct defaults *d, int what) |
732 | 22.2k | { |
733 | 22.2k | debug_decl(default_binding_matches, SUDOERS_DEBUG_DEFAULTS); |
734 | | |
735 | 22.2k | switch (d->type) { |
736 | 22.2k | case DEFAULTS: |
737 | 22.2k | debug_return_bool(true); |
738 | 0 | case DEFAULTS_USER: |
739 | 0 | if (userlist_matches(parse_tree, ctx->user.pw, &d->binding->members) == ALLOW) |
740 | 0 | debug_return_bool(true); |
741 | 0 | break; |
742 | 0 | case DEFAULTS_RUNAS: |
743 | 0 | if (runaslist_matches(parse_tree, &d->binding->members, NULL) == ALLOW) |
744 | 0 | debug_return_bool(true); |
745 | 0 | break; |
746 | 0 | case DEFAULTS_HOST: |
747 | 0 | if (hostlist_matches(parse_tree, ctx->user.pw, &d->binding->members) == ALLOW) |
748 | 0 | debug_return_bool(true); |
749 | 0 | break; |
750 | 0 | case DEFAULTS_CMND: |
751 | 0 | if (cmndlist_matches(parse_tree, &d->binding->members, NULL, NULL) == ALLOW) |
752 | 0 | debug_return_bool(true); |
753 | 0 | break; |
754 | 22.2k | } |
755 | 0 | debug_return_bool(false); |
756 | 0 | } |
757 | | |
758 | | /* |
759 | | * Update the global defaults based on the given defaults list. |
760 | | * Pass in an OR'd list of which default types to update. |
761 | | */ |
762 | | bool |
763 | | update_defaults(struct sudoers_context *ctx, |
764 | | struct sudoers_parse_tree *parse_tree, |
765 | | const struct defaults_list *defs, int what, bool quiet) |
766 | 78.9k | { |
767 | 78.9k | const struct defaults *d; |
768 | 78.9k | bool global_defaults = false; |
769 | 78.9k | bool ret = true; |
770 | 78.9k | debug_decl(update_defaults, SUDOERS_DEBUG_DEFAULTS); |
771 | | |
772 | 78.9k | sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, |
773 | 78.9k | "what: 0x%02x", what); |
774 | | |
775 | | /* If no defaults list specified, use the global one in the parse tree. */ |
776 | 78.9k | if (defs == NULL) { |
777 | 52.9k | defs = &parse_tree->defaults; |
778 | 52.9k | global_defaults = true; |
779 | 52.9k | } |
780 | | |
781 | | /* |
782 | | * If using the global defaults list, apply Defaults values marked as early. |
783 | | */ |
784 | 78.9k | if (global_defaults) { |
785 | 52.9k | TAILQ_FOREACH(d, defs, entries) { |
786 | 0 | struct early_default *early = is_early_default(d->var); |
787 | 0 | if (early == NULL) |
788 | 0 | continue; |
789 | | |
790 | | /* Defaults type and binding must match. */ |
791 | 0 | if (!default_type_matches(d, what) || |
792 | 0 | !default_binding_matches(ctx, parse_tree, d, what)) |
793 | 0 | continue; |
794 | | |
795 | | /* Copy the value to sudo_defs_table and mark as early. */ |
796 | 0 | if (!set_early_default(ctx, d->var, d->val, d->op, d->file, d->line, |
797 | 0 | d->column, quiet, early)) |
798 | 0 | ret = false; |
799 | 0 | } |
800 | | |
801 | | /* Run callbacks for early defaults (if any) */ |
802 | 52.9k | if (!run_early_defaults(ctx)) |
803 | 0 | ret = false; |
804 | 52.9k | } |
805 | | |
806 | | /* |
807 | | * Set the rest of the defaults and run their callbacks, if any. |
808 | | */ |
809 | 78.9k | TAILQ_FOREACH(d, defs, entries) { |
810 | 22.2k | if (global_defaults) { |
811 | | /* Skip Defaults marked as early, we already did them. */ |
812 | 0 | if (is_early_default(d->var)) |
813 | 0 | continue; |
814 | 0 | } |
815 | | |
816 | | /* Defaults type and binding must match. */ |
817 | 22.2k | if (!default_type_matches(d, what) || |
818 | 22.2k | !default_binding_matches(ctx, parse_tree, d, what)) |
819 | 0 | continue; |
820 | | |
821 | | /* Copy the value to sudo_defs_table and run callback (if any) */ |
822 | 22.2k | if (!set_default(ctx, d->var, d->val, d->op, d->file, d->line, d->column, quiet)) |
823 | 0 | ret = false; |
824 | 22.2k | } |
825 | | |
826 | 78.9k | debug_return_bool(ret); |
827 | 78.9k | } |
828 | | |
829 | | /* |
830 | | * Check all defaults entries without actually setting them. |
831 | | */ |
832 | | bool |
833 | | check_defaults(const struct sudoers_parse_tree *parse_tree, bool quiet) |
834 | 2 | { |
835 | 2 | const struct defaults *d; |
836 | 2 | bool ret = true; |
837 | 2 | int idx; |
838 | 2 | debug_decl(check_defaults, SUDOERS_DEBUG_DEFAULTS); |
839 | | |
840 | 2 | TAILQ_FOREACH(d, &parse_tree->defaults, entries) { |
841 | 0 | idx = find_default(parse_tree->ctx, d->var, d->file, d->line, |
842 | 0 | d->column, quiet); |
843 | 0 | if (idx != -1) { |
844 | 0 | struct sudo_defs_types def = sudo_defs_table[idx]; |
845 | 0 | memset(&def.sd_un, 0, sizeof(def.sd_un)); |
846 | 0 | if (parse_default_entry(parse_tree->ctx, &def, d->val, d->op, |
847 | 0 | d->file, d->line, d->column, quiet)) { |
848 | 0 | free_defs_val(def.type, &def.sd_un); |
849 | 0 | continue; |
850 | 0 | } |
851 | 0 | } |
852 | | /* There was an error in the entry. */ |
853 | 0 | ret = false; |
854 | 0 | } |
855 | 2 | debug_return_bool(ret); |
856 | 2 | } |
857 | | |
858 | | static bool |
859 | | store_int(const char *str, struct sudo_defs_types *def) |
860 | 0 | { |
861 | 0 | const char *errstr; |
862 | 0 | int i; |
863 | 0 | debug_decl(store_int, SUDOERS_DEBUG_DEFAULTS); |
864 | |
|
865 | 0 | if (str == NULL) { |
866 | 0 | def->sd_un.ival = 0; |
867 | 0 | } else { |
868 | 0 | i = (int)sudo_strtonum(str, INT_MIN, INT_MAX, &errstr); |
869 | 0 | if (errstr != NULL) { |
870 | 0 | sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, |
871 | 0 | "%s: %s", str, errstr); |
872 | 0 | debug_return_bool(false); |
873 | 0 | } |
874 | 0 | def->sd_un.ival = i; |
875 | 0 | } |
876 | 0 | debug_return_bool(true); |
877 | 0 | } |
878 | | |
879 | | static bool |
880 | | store_uint(const char *str, struct sudo_defs_types *def) |
881 | 52.0k | { |
882 | 52.0k | const char *errstr; |
883 | 52.0k | unsigned int u; |
884 | 52.0k | debug_decl(store_uint, SUDOERS_DEBUG_DEFAULTS); |
885 | | |
886 | 52.0k | if (str == NULL) { |
887 | 0 | def->sd_un.uival = 0; |
888 | 52.0k | } else { |
889 | 52.0k | u = (unsigned int)sudo_strtonum(str, 0, UINT_MAX, &errstr); |
890 | 52.0k | if (errstr != NULL) { |
891 | 0 | sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, |
892 | 0 | "%s: %s", str, errstr); |
893 | 0 | debug_return_bool(false); |
894 | 0 | } |
895 | 52.0k | def->sd_un.uival = u; |
896 | 52.0k | } |
897 | 52.0k | debug_return_bool(true); |
898 | 52.0k | } |
899 | | |
900 | | /* Check resource limit syntax, does not save as rlim_t. */ |
901 | | static bool |
902 | | check_rlimit(const char *str, bool soft) |
903 | 0 | { |
904 | 0 | const size_t inflen = sizeof("infinity") - 1; |
905 | 0 | debug_decl(check_rlimit, SUDOERS_DEBUG_DEFAULTS); |
906 | |
|
907 | 0 | if (isdigit((unsigned char)*str)) { |
908 | 0 | unsigned long long ullval; |
909 | 0 | char *ep; |
910 | |
|
911 | 0 | errno = 0; |
912 | 0 | #ifdef HAVE_STRTOULL |
913 | 0 | ullval = strtoull(str, &ep, 10); |
914 | 0 | if (str == ep || (errno == ERANGE && ullval == ULLONG_MAX)) |
915 | 0 | debug_return_bool(false); |
916 | | #else |
917 | | ullval = strtoul(str, &ep, 10); |
918 | | if (str == ep || (errno == ERANGE && ullval == ULONG_MAX)) |
919 | | debug_return_bool(false); |
920 | | #endif |
921 | 0 | if (*ep == '\0' || (soft && *ep == ',')) |
922 | 0 | debug_return_bool(true); |
923 | 0 | debug_return_bool(false); |
924 | 0 | } |
925 | 0 | if (strncmp(str, "infinity", inflen) == 0) { |
926 | 0 | if (str[inflen] == '\0' || (soft && str[inflen] == ',')) |
927 | 0 | debug_return_bool(true); |
928 | 0 | } |
929 | 0 | debug_return_bool(false); |
930 | 0 | } |
931 | | |
932 | | static bool |
933 | | store_rlimit(const char *str, struct sudo_defs_types *def) |
934 | 0 | { |
935 | 0 | debug_decl(store_rlimit, SUDOERS_DEBUG_DEFAULTS); |
936 | | |
937 | | /* The special values "user" and "default" are not compound. */ |
938 | 0 | if (str != NULL && strcmp(str, "user") != 0 && strcmp(str, "default") != 0) { |
939 | 0 | const char *hard, *soft = str; |
940 | | /* |
941 | | * Expect a limit in the form "soft,hard" or "limit" (both soft+hard). |
942 | | */ |
943 | 0 | hard = strchr(str, ','); |
944 | 0 | if (hard != NULL) |
945 | 0 | hard++; |
946 | 0 | else |
947 | 0 | hard = soft; |
948 | |
|
949 | 0 | if (!check_rlimit(soft, true)) |
950 | 0 | debug_return_bool(false); |
951 | 0 | if (!check_rlimit(hard, false)) |
952 | 0 | debug_return_bool(false); |
953 | 0 | } |
954 | | |
955 | | /* Store as string, front-end will parse it as a limit. */ |
956 | 0 | debug_return_bool(store_str(str, def)); |
957 | 0 | } |
958 | | |
959 | | static bool |
960 | | store_timespec(const char *str, struct sudo_defs_types *def) |
961 | 0 | { |
962 | 0 | struct timespec ts; |
963 | 0 | char sign = '+'; |
964 | 0 | long i; |
965 | 0 | debug_decl(store_timespec, SUDOERS_DEBUG_DEFAULTS); |
966 | |
|
967 | 0 | sudo_timespecclear(&ts); |
968 | 0 | if (str != NULL) { |
969 | | /* Convert from minutes to seconds. */ |
970 | 0 | if (*str == '+' || *str == '-') |
971 | 0 | sign = *str++; |
972 | 0 | while (*str != '\0' && *str != '.') { |
973 | 0 | if (!isdigit((unsigned char)*str)) |
974 | 0 | debug_return_bool(false); /* invalid number */ |
975 | | |
976 | | /* Verify (ts.tv_sec * 10) + (digit * 60) <= TIME_T_MAX. */ |
977 | 0 | i = (*str++ - '0') * 60L; |
978 | 0 | if (ts.tv_sec > (TIME_T_MAX - i) / 10) |
979 | 0 | debug_return_bool(false); /* overflow */ |
980 | 0 | ts.tv_sec *= 10; |
981 | 0 | ts.tv_sec += i; |
982 | 0 | } |
983 | 0 | if (*str++ == '.') { |
984 | 0 | long long nsec = 0; |
985 | | |
986 | | /* Convert optional fractional component to seconds and nanosecs. */ |
987 | 0 | for (i = 100000000; i > 0; i /= 10) { |
988 | 0 | if (*str == '\0') |
989 | 0 | break; |
990 | 0 | if (!isdigit((unsigned char)*str)) |
991 | 0 | debug_return_bool(false); /* invalid number */ |
992 | 0 | nsec += i * (*str++ - '0') * 60LL; |
993 | 0 | } |
994 | 0 | while (nsec >= 1000000000) { |
995 | 0 | if (ts.tv_sec == TIME_T_MAX) |
996 | 0 | debug_return_bool(false); /* overflow */ |
997 | 0 | ts.tv_sec++; |
998 | 0 | nsec -= 1000000000; |
999 | 0 | } |
1000 | 0 | ts.tv_nsec = (long)nsec; |
1001 | 0 | } |
1002 | 0 | } |
1003 | 0 | if (sign == '-') { |
1004 | 0 | def->sd_un.tspec.tv_sec = -ts.tv_sec; |
1005 | 0 | def->sd_un.tspec.tv_nsec = -ts.tv_nsec; |
1006 | 0 | } else { |
1007 | 0 | def->sd_un.tspec.tv_sec = ts.tv_sec; |
1008 | 0 | def->sd_un.tspec.tv_nsec = ts.tv_nsec; |
1009 | 0 | } |
1010 | 0 | debug_return_bool(true); |
1011 | 0 | } |
1012 | | |
1013 | | static bool |
1014 | | store_tuple(const char *str, struct sudo_defs_types *def, int op) |
1015 | 72.9k | { |
1016 | 72.9k | const struct def_values *v; |
1017 | 72.9k | debug_decl(store_tuple, SUDOERS_DEBUG_DEFAULTS); |
1018 | | |
1019 | | /* |
1020 | | * Look up tuple value by name to find enum def_tuple value. |
1021 | | * A tuple must have at least two possible values. |
1022 | | */ |
1023 | 72.9k | if (str == NULL) { |
1024 | | /* |
1025 | | * Boolean context: true maps to values[1], false maps to values[0]. |
1026 | | */ |
1027 | 0 | if (op == true) { |
1028 | 0 | v = &def->values[1]; |
1029 | 0 | def->sd_un.ival = v->nval; |
1030 | 0 | } else if (op == false) { |
1031 | 0 | v = &def->values[0]; |
1032 | 0 | def->sd_un.ival = v->nval; |
1033 | 0 | } else { |
1034 | 0 | debug_return_bool(false); |
1035 | 0 | } |
1036 | 72.9k | } else { |
1037 | 145k | for (v = def->values; v->sval != NULL; v++) { |
1038 | 145k | if (strcmp(v->sval, str) == 0) { |
1039 | 72.9k | def->sd_un.tuple = v->nval; |
1040 | 72.9k | break; |
1041 | 72.9k | } |
1042 | 145k | } |
1043 | 72.9k | if (v->sval == NULL) |
1044 | 0 | debug_return_bool(false); |
1045 | 72.9k | } |
1046 | 72.9k | debug_return_bool(true); |
1047 | 72.9k | } |
1048 | | |
1049 | | static int |
1050 | | store_str(const char *str, struct sudo_defs_types *def) |
1051 | 482k | { |
1052 | 482k | debug_decl(store_str, SUDOERS_DEBUG_DEFAULTS); |
1053 | | |
1054 | 482k | free(def->sd_un.str); |
1055 | 482k | if (str == NULL) { |
1056 | 78.1k | def->sd_un.str = NULL; |
1057 | 404k | } else { |
1058 | 404k | if ((def->sd_un.str = strdup(str)) == NULL) { |
1059 | 0 | sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); |
1060 | 0 | debug_return_int(-1); |
1061 | 0 | } |
1062 | 404k | } |
1063 | 482k | debug_return_int(true); |
1064 | 482k | } |
1065 | | |
1066 | | static bool |
1067 | | store_list(const char *str, struct sudo_defs_types *def, int op) |
1068 | 22.0k | { |
1069 | 22.0k | debug_decl(store_list, SUDOERS_DEBUG_DEFAULTS); |
1070 | | |
1071 | | /* Remove all old members. */ |
1072 | 22.0k | if (op == false || op == true) |
1073 | 22.0k | (void)list_op(NULL, 0, &def->sd_un.list, freeall); |
1074 | | |
1075 | | /* Split str into multiple space-separated words and act on each one. */ |
1076 | 22.0k | if (str != NULL) { |
1077 | 22.0k | const char *cp, *ep; |
1078 | 22.0k | const char *end = str + strlen(str); |
1079 | 22.0k | const enum list_ops lop = op == '-' ? delete : add; |
1080 | | |
1081 | 22.0k | if (ISSET(def->type, T_SPACE)) { |
1082 | 0 | if (!list_op(str, strlen(str), &def->sd_un.list, lop)) |
1083 | 0 | debug_return_bool(false); |
1084 | 22.0k | } else { |
1085 | 44.1k | for (cp = sudo_strsplit(str, end, " \t", &ep); cp != NULL; |
1086 | 22.0k | cp = sudo_strsplit(NULL, end, " \t", &ep)) { |
1087 | 22.0k | if (!list_op(cp, (size_t)(ep - cp), &def->sd_un.list, lop)) |
1088 | 0 | debug_return_bool(false); |
1089 | 22.0k | } |
1090 | 22.0k | } |
1091 | 22.0k | } |
1092 | 22.0k | debug_return_bool(true); |
1093 | 22.0k | } |
1094 | | |
1095 | | static bool |
1096 | | store_plugin(const char *str, struct sudo_defs_types *def, int op) |
1097 | 0 | { |
1098 | 0 | const enum list_ops lop = op == '-' ? delete : add; |
1099 | 0 | debug_decl(store_plugin, SUDOERS_DEBUG_DEFAULTS); |
1100 | | |
1101 | | /* Remove all old members. */ |
1102 | 0 | if (op == false || op == true) |
1103 | 0 | (void)list_op(NULL, 0, &def->sd_un.list, freeall); |
1104 | |
|
1105 | 0 | if (str != NULL) { |
1106 | 0 | if (!list_op(str, strlen(str), &def->sd_un.list, lop)) |
1107 | 0 | debug_return_bool(false); |
1108 | 0 | } |
1109 | | |
1110 | 0 | debug_return_bool(true); |
1111 | 0 | } |
1112 | | |
1113 | | static bool |
1114 | | store_syslogfac(const char *str, struct sudo_defs_types *def) |
1115 | 62.5k | { |
1116 | 62.5k | debug_decl(store_syslogfac, SUDOERS_DEBUG_DEFAULTS); |
1117 | | |
1118 | 62.5k | if (str == NULL) { |
1119 | 0 | def->sd_un.ival = false; |
1120 | 0 | debug_return_bool(true); |
1121 | 0 | } |
1122 | 62.5k | debug_return_bool(sudo_str2logfac(str, &def->sd_un.ival)); |
1123 | 62.5k | } |
1124 | | |
1125 | | static bool |
1126 | | store_syslogpri(const char *str, struct sudo_defs_types *def) |
1127 | 125k | { |
1128 | 125k | debug_decl(store_syslogpri, SUDOERS_DEBUG_DEFAULTS); |
1129 | | |
1130 | 125k | if (str == NULL) { |
1131 | 0 | def->sd_un.ival = -1; |
1132 | 0 | debug_return_bool(true); |
1133 | 0 | } |
1134 | 125k | debug_return_bool(sudo_str2logpri(str, &def->sd_un.ival)); |
1135 | 125k | } |
1136 | | |
1137 | | static bool |
1138 | | store_mode(const char *str, struct sudo_defs_types *def) |
1139 | 52.0k | { |
1140 | 52.0k | mode_t mode; |
1141 | 52.0k | const char *errstr; |
1142 | 52.0k | debug_decl(store_mode, SUDOERS_DEBUG_DEFAULTS); |
1143 | | |
1144 | 52.0k | if (str == NULL) { |
1145 | 0 | def->sd_un.mode = ACCESSPERMS; |
1146 | 52.0k | } else { |
1147 | 52.0k | mode = sudo_strtomode(str, &errstr); |
1148 | 52.0k | if (errstr != NULL) { |
1149 | 0 | sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, |
1150 | 0 | "%s is %s", str, errstr); |
1151 | 0 | debug_return_bool(false); |
1152 | 0 | } |
1153 | 52.0k | def->sd_un.mode = mode; |
1154 | 52.0k | } |
1155 | 52.0k | debug_return_bool(true); |
1156 | 52.0k | } |
1157 | | |
1158 | | static bool |
1159 | | store_timeout(const char *str, struct sudo_defs_types *def) |
1160 | 22.0k | { |
1161 | 22.0k | debug_decl(store_mode, SUDOERS_DEBUG_DEFAULTS); |
1162 | | |
1163 | 22.0k | if (str == NULL) { |
1164 | 0 | def->sd_un.ival = 0; |
1165 | 22.0k | } else { |
1166 | 22.0k | int seconds = parse_timeout(str); |
1167 | 22.0k | if (seconds == -1) { |
1168 | 0 | sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO, |
1169 | 0 | "%s", str); |
1170 | 0 | debug_return_bool(false); |
1171 | 0 | } |
1172 | 22.0k | def->sd_un.ival = seconds; |
1173 | 22.0k | } |
1174 | 22.0k | debug_return_bool(true); |
1175 | 22.0k | } |
1176 | | |
1177 | | static bool |
1178 | | valid_path(const struct sudoers_context *ctx, const struct sudo_defs_types *def, |
1179 | | const char *val, const char *file, int line, int column, bool quiet) |
1180 | 196k | { |
1181 | 196k | bool ret = true; |
1182 | 196k | debug_decl(valid_path, SUDOERS_DEBUG_DEFAULTS); |
1183 | | |
1184 | 196k | if (strlen(val) >= PATH_MAX) { |
1185 | 0 | defaults_warnx(ctx, file, line, column, quiet, |
1186 | 0 | N_("path name for \"%s\" too long"), def->name); |
1187 | 0 | ret = false; |
1188 | 0 | } |
1189 | 196k | if (ISSET(def->type, T_CHPATH)) { |
1190 | 52.0k | if (val[0] != '/' && val[0] != '~' && (val[0] != '*' || val[1] != '\0')) { |
1191 | 0 | defaults_warnx(ctx, file, line, column, quiet, |
1192 | 0 | N_("values for \"%s\" must start with a '/', '~', or '*'"), |
1193 | 0 | def->name); |
1194 | 0 | ret = false; |
1195 | 0 | } |
1196 | 144k | } else { |
1197 | 144k | if (val[0] != '/') { |
1198 | 0 | defaults_warnx(ctx, file, line, column, quiet, |
1199 | 0 | N_("values for \"%s\" must start with a '/'"), def->name); |
1200 | 0 | ret = false; |
1201 | 0 | } |
1202 | | |
1203 | 144k | } |
1204 | 196k | debug_return_bool(ret); |
1205 | 196k | } |
1206 | | |
1207 | | static bool |
1208 | | list_op(const char *str, size_t len, struct list_members *list, |
1209 | | enum list_ops op) |
1210 | 226k | { |
1211 | 226k | struct list_member *cur, *prev = NULL; |
1212 | 226k | debug_decl(list_op, SUDOERS_DEBUG_DEFAULTS); |
1213 | | |
1214 | 226k | if (op == freeall) { |
1215 | 2.00M | while ((cur = SLIST_FIRST(list)) != NULL) { |
1216 | 1.80M | SLIST_REMOVE_HEAD(list, entries); |
1217 | 1.80M | free(cur->value); |
1218 | 1.80M | free(cur); |
1219 | 1.80M | } |
1220 | 204k | debug_return_bool(true); |
1221 | 204k | } |
1222 | | |
1223 | 22.0k | SLIST_FOREACH(cur, list, entries) { |
1224 | 0 | if ((strncmp(cur->value, str, len) == 0 && cur->value[len] == '\0')) { |
1225 | |
|
1226 | 0 | if (op == add) |
1227 | 0 | debug_return_bool(true); /* already exists */ |
1228 | | |
1229 | | /* Delete node */ |
1230 | 0 | if (prev == NULL) |
1231 | 0 | SLIST_REMOVE_HEAD(list, entries); |
1232 | 0 | else |
1233 | 0 | SLIST_REMOVE_AFTER(prev, entries); |
1234 | 0 | free(cur->value); |
1235 | 0 | free(cur); |
1236 | 0 | break; |
1237 | 0 | } |
1238 | 0 | prev = cur; |
1239 | 0 | } |
1240 | | |
1241 | | /* Add new node to the head of the list. */ |
1242 | 22.0k | if (op == add) { |
1243 | 22.0k | cur = calloc(1, sizeof(struct list_member)); |
1244 | 22.0k | if (cur == NULL || (cur->value = strndup(str, len)) == NULL) { |
1245 | 0 | sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); |
1246 | 0 | free(cur); |
1247 | 0 | debug_return_bool(false); |
1248 | 0 | } |
1249 | 22.0k | SLIST_INSERT_HEAD(list, cur, entries); |
1250 | 22.0k | } |
1251 | 22.0k | debug_return_bool(true); |
1252 | 22.0k | } |
1253 | | |
1254 | | bool |
1255 | | append_default(const char *var, const char *val, int op, |
1256 | | char *source, struct defaults_list *defs) |
1257 | 154k | { |
1258 | 154k | struct defaults *def; |
1259 | 154k | debug_decl(append_default, SUDOERS_DEBUG_DEFAULTS); |
1260 | | |
1261 | 154k | if ((def = calloc(1, sizeof(*def))) == NULL) |
1262 | 0 | goto oom; |
1263 | | |
1264 | 154k | def->type = DEFAULTS; |
1265 | 154k | def->op = op; |
1266 | 154k | if ((def->var = strdup(var)) == NULL) { |
1267 | 0 | goto oom; |
1268 | 0 | } |
1269 | 154k | if (val != NULL) { |
1270 | 1.12k | if ((def->val = strdup(val)) == NULL) |
1271 | 0 | goto oom; |
1272 | 1.12k | } |
1273 | 154k | def->file = source; |
1274 | 154k | sudo_rcstr_addref(source); |
1275 | 154k | TAILQ_INSERT_TAIL(defs, def, entries); |
1276 | 154k | debug_return_bool(true); |
1277 | | |
1278 | 0 | oom: |
1279 | 0 | if (def != NULL) { |
1280 | 0 | free(def->var); |
1281 | 0 | free(def->val); |
1282 | 0 | free(def); |
1283 | 0 | } |
1284 | 0 | debug_return_bool(false); |
1285 | 0 | } |
1286 | | |
1287 | | bool |
1288 | | cb_passprompt_regex(struct sudoers_context *ctx, const char *file, |
1289 | | int line, int column, const union sudo_defs_val *sd_un, int op) |
1290 | 0 | { |
1291 | 0 | struct list_member *lm; |
1292 | 0 | const char *errstr; |
1293 | 0 | debug_decl(cb_passprompt_regex, SUDOERS_DEBUG_DEFAULTS); |
1294 | | |
1295 | | /* If adding one or more regexps, make sure they are valid. */ |
1296 | 0 | if (op == '+' || op == true) { |
1297 | 0 | SLIST_FOREACH(lm, &sd_un->list, entries) { |
1298 | 0 | if (!sudo_regex_compile(NULL, lm->value, &errstr)) { |
1299 | 0 | defaults_warnx(ctx, file, line, column, false, |
1300 | 0 | U_("invalid regular expression \"%s\": %s"), |
1301 | 0 | lm->value, U_(errstr)); |
1302 | 0 | debug_return_bool(false); |
1303 | 0 | } |
1304 | 0 | } |
1305 | 0 | } |
1306 | | |
1307 | 0 | debug_return_bool(true); |
1308 | 0 | } |