1: /*
2: * Copyright (c) 1999-2005, 2007-2013
3: * Todd C. Miller <Todd.Miller@courtesan.com>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: *
17: * Sponsored in part by the Defense Advanced Research Projects
18: * Agency (DARPA) and Air Force Research Laboratory, Air Force
19: * Materiel Command, USAF, under agreement number F39502-99-1-0512.
20: */
21:
22: #include <config.h>
23:
24: #include <sys/types.h>
25: #include <stdio.h>
26: #ifdef STDC_HEADERS
27: # include <stdlib.h>
28: # include <stddef.h>
29: #else
30: # ifdef HAVE_STDLIB_H
31: # include <stdlib.h>
32: # endif
33: #endif /* STDC_HEADERS */
34: #ifdef HAVE_STRING_H
35: # include <string.h>
36: #endif /* HAVE_STRING_H */
37: #ifdef HAVE_STRINGS_H
38: # include <strings.h>
39: #endif /* HAVE_STRINGS_H */
40: # ifdef HAVE_UNISTD_H
41: #include <unistd.h>
42: #endif /* HAVE_UNISTD_H */
43: #include <pwd.h>
44: #include <ctype.h>
45:
46: #include "sudoers.h"
47: #include "parse.h"
48: #include <gram.h>
49:
50: /*
51: * For converting between syslog numbers and strings.
52: */
53: struct strmap {
54: char *name;
55: int num;
56: };
57:
58: #ifdef LOG_NFACILITIES
59: static struct strmap facilities[] = {
60: #ifdef LOG_AUTHPRIV
61: { "authpriv", LOG_AUTHPRIV },
62: #endif
63: { "auth", LOG_AUTH },
64: { "daemon", LOG_DAEMON },
65: { "user", LOG_USER },
66: { "local0", LOG_LOCAL0 },
67: { "local1", LOG_LOCAL1 },
68: { "local2", LOG_LOCAL2 },
69: { "local3", LOG_LOCAL3 },
70: { "local4", LOG_LOCAL4 },
71: { "local5", LOG_LOCAL5 },
72: { "local6", LOG_LOCAL6 },
73: { "local7", LOG_LOCAL7 },
74: { NULL, -1 }
75: };
76: #endif /* LOG_NFACILITIES */
77:
78: static struct strmap priorities[] = {
79: { "alert", LOG_ALERT },
80: { "crit", LOG_CRIT },
81: { "debug", LOG_DEBUG },
82: { "emerg", LOG_EMERG },
83: { "err", LOG_ERR },
84: { "info", LOG_INFO },
85: { "notice", LOG_NOTICE },
86: { "warning", LOG_WARNING },
87: { NULL, -1 }
88: };
89:
90: /*
91: * Local prototypes.
92: */
93: static bool store_int(char *, struct sudo_defs_types *, int);
94: static bool store_list(char *, struct sudo_defs_types *, int);
95: static bool store_mode(char *, struct sudo_defs_types *, int);
96: static bool store_str(char *, struct sudo_defs_types *, int);
97: static bool store_syslogfac(char *, struct sudo_defs_types *, int);
98: static bool store_syslogpri(char *, struct sudo_defs_types *, int);
99: static bool store_tuple(char *, struct sudo_defs_types *, int);
100: static bool store_uint(char *, struct sudo_defs_types *, int);
101: static bool store_float(char *, struct sudo_defs_types *, int);
102: static void list_op(char *, size_t, struct sudo_defs_types *, enum list_ops);
103: static const char *logfac2str(int);
104: static const char *logpri2str(int);
105:
106: /*
107: * Table describing compile-time and run-time options.
108: */
109: #include <def_data.c>
110:
111: /*
112: * Print version and configure info.
113: */
114: void
115: dump_defaults(void)
116: {
117: struct sudo_defs_types *cur;
118: struct list_member *item;
119: struct def_values *def;
120: char *desc;
121: debug_decl(dump_defaults, SUDO_DEBUG_DEFAULTS)
122:
123: for (cur = sudo_defs_table; cur->name; cur++) {
124: if (cur->desc) {
125: desc = _(cur->desc);
126: switch (cur->type & T_MASK) {
127: case T_FLAG:
128: if (cur->sd_un.flag)
129: sudo_printf(SUDO_CONV_INFO_MSG, "%s\n", desc);
130: break;
131: case T_STR:
132: if (cur->sd_un.str) {
133: sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.str);
134: sudo_printf(SUDO_CONV_INFO_MSG, "\n");
135: }
136: break;
137: case T_LOGFAC:
138: if (cur->sd_un.ival) {
139: sudo_printf(SUDO_CONV_INFO_MSG, desc,
140: logfac2str(cur->sd_un.ival));
141: sudo_printf(SUDO_CONV_INFO_MSG, "\n");
142: }
143: break;
144: case T_LOGPRI:
145: if (cur->sd_un.ival) {
146: sudo_printf(SUDO_CONV_INFO_MSG, desc,
147: logpri2str(cur->sd_un.ival));
148: sudo_printf(SUDO_CONV_INFO_MSG, "\n");
149: }
150: break;
151: case T_UINT:
152: case T_INT:
153: sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.ival);
154: sudo_printf(SUDO_CONV_INFO_MSG, "\n");
155: break;
156: case T_FLOAT:
157: sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.fval);
158: sudo_printf(SUDO_CONV_INFO_MSG, "\n");
159: break;
160: case T_MODE:
161: sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.mode);
162: sudo_printf(SUDO_CONV_INFO_MSG, "\n");
163: break;
164: case T_LIST:
165: if (cur->sd_un.list) {
166: sudo_printf(SUDO_CONV_INFO_MSG, "%s\n", desc);
167: for (item = cur->sd_un.list; item; item = item->next) {
168: sudo_printf(SUDO_CONV_INFO_MSG,
169: "\t%s\n", item->value);
170: }
171: }
172: break;
173: case T_TUPLE:
174: for (def = cur->values; def->sval; def++) {
175: if (cur->sd_un.ival == def->ival) {
176: sudo_printf(SUDO_CONV_INFO_MSG, desc, def->sval);
177: break;
178: }
179: }
180: sudo_printf(SUDO_CONV_INFO_MSG, "\n");
181: break;
182: }
183: }
184: }
185: debug_return;
186: }
187:
188: /*
189: * Sets/clears an entry in the defaults structure
190: * If a variable that takes a value is used in a boolean
191: * context with op == 0, disable that variable.
192: * Eg. you may want to turn off logging to a file for some hosts.
193: * This is only meaningful for variables that are *optional*.
194: */
195: bool
196: set_default(char *var, char *val, int op)
197: {
198: struct sudo_defs_types *cur;
199: int num;
200: debug_decl(set_default, SUDO_DEBUG_DEFAULTS)
201:
202: for (cur = sudo_defs_table, num = 0; cur->name; cur++, num++) {
203: if (strcmp(var, cur->name) == 0)
204: break;
205: }
206: if (!cur->name) {
207: warningx(_("unknown defaults entry `%s'"), var);
208: debug_return_bool(false);
209: }
210:
211: switch (cur->type & T_MASK) {
212: case T_LOGFAC:
213: if (!store_syslogfac(val, cur, op)) {
214: if (val)
215: warningx(_("value `%s' is invalid for option `%s'"),
216: val, var);
217: else
218: warningx(_("no value specified for `%s'"), var);
219: debug_return_bool(false);
220: }
221: break;
222: case T_LOGPRI:
223: if (!store_syslogpri(val, cur, op)) {
224: if (val)
225: warningx(_("value `%s' is invalid for option `%s'"),
226: val, var);
227: else
228: warningx(_("no value specified for `%s'"), var);
229: debug_return_bool(false);
230: }
231: break;
232: case T_STR:
233: if (!val) {
234: /* Check for bogus boolean usage or lack of a value. */
235: if (!ISSET(cur->type, T_BOOL) || op != false) {
236: warningx(_("no value specified for `%s'"), var);
237: debug_return_bool(false);
238: }
239: }
240: if (ISSET(cur->type, T_PATH) && val && *val != '/') {
241: warningx(_("values for `%s' must start with a '/'"), var);
242: debug_return_bool(false);
243: }
244: if (!store_str(val, cur, op)) {
245: warningx(_("value `%s' is invalid for option `%s'"), val, var);
246: debug_return_bool(false);
247: }
248: break;
249: case T_INT:
250: if (!val) {
251: /* Check for bogus boolean usage or lack of a value. */
252: if (!ISSET(cur->type, T_BOOL) || op != false) {
253: warningx(_("no value specified for `%s'"), var);
254: debug_return_bool(false);
255: }
256: }
257: if (!store_int(val, cur, op)) {
258: warningx(_("value `%s' is invalid for option `%s'"), val, var);
259: debug_return_bool(false);
260: }
261: break;
262: case T_UINT:
263: if (!val) {
264: /* Check for bogus boolean usage or lack of a value. */
265: if (!ISSET(cur->type, T_BOOL) || op != false) {
266: warningx(_("no value specified for `%s'"), var);
267: debug_return_bool(false);
268: }
269: }
270: if (!store_uint(val, cur, op)) {
271: warningx(_("value `%s' is invalid for option `%s'"), val, var);
272: debug_return_bool(false);
273: }
274: break;
275: case T_FLOAT:
276: if (!val) {
277: /* Check for bogus boolean usage or lack of a value. */
278: if (!ISSET(cur->type, T_BOOL) || op != false) {
279: warningx(_("no value specified for `%s'"), var);
280: debug_return_bool(false);
281: }
282: }
283: if (!store_float(val, cur, op)) {
284: warningx(_("value `%s' is invalid for option `%s'"), val, var);
285: debug_return_bool(false);
286: }
287: break;
288: case T_MODE:
289: if (!val) {
290: /* Check for bogus boolean usage or lack of a value. */
291: if (!ISSET(cur->type, T_BOOL) || op != false) {
292: warningx(_("no value specified for `%s'"), var);
293: debug_return_bool(false);
294: }
295: }
296: if (!store_mode(val, cur, op)) {
297: warningx(_("value `%s' is invalid for option `%s'"), val, var);
298: debug_return_bool(false);
299: }
300: break;
301: case T_FLAG:
302: if (val) {
303: warningx(_("option `%s' does not take a value"), var);
304: debug_return_bool(false);
305: }
306: cur->sd_un.flag = op;
307: break;
308: case T_LIST:
309: if (!val) {
310: /* Check for bogus boolean usage or lack of a value. */
311: if (!ISSET(cur->type, T_BOOL) || op != false) {
312: warningx(_("no value specified for `%s'"), var);
313: debug_return_bool(false);
314: }
315: }
316: if (!store_list(val, cur, op)) {
317: warningx(_("value `%s' is invalid for option `%s'"), val, var);
318: debug_return_bool(false);
319: }
320: break;
321: case T_TUPLE:
322: if (!val && !ISSET(cur->type, T_BOOL)) {
323: warningx(_("no value specified for `%s'"), var);
324: debug_return_bool(false);
325: }
326: if (!store_tuple(val, cur, op)) {
327: warningx(_("value `%s' is invalid for option `%s'"), val, var);
328: debug_return_bool(false);
329: }
330: break;
331: }
332:
333: debug_return_bool(true);
334: }
335:
336: /*
337: * Set default options to compiled-in values.
338: * Any of these may be overridden at runtime by a "Defaults" file.
339: */
340: void
341: init_defaults(void)
342: {
343: static int firsttime = 1;
344: struct sudo_defs_types *def;
345: debug_decl(init_defaults, SUDO_DEBUG_DEFAULTS)
346:
347: /* Clear any old settings. */
348: if (!firsttime) {
349: for (def = sudo_defs_table; def->name; def++) {
350: switch (def->type & T_MASK) {
351: case T_STR:
352: efree(def->sd_un.str);
353: def->sd_un.str = NULL;
354: break;
355: case T_LIST:
356: list_op(NULL, 0, def, freeall);
357: break;
358: }
359: zero_bytes(&def->sd_un, sizeof(def->sd_un));
360: }
361: }
362:
363: /* First initialize the flags. */
364: #ifdef LONG_OTP_PROMPT
365: def_long_otp_prompt = true;
366: #endif
367: #ifdef IGNORE_DOT_PATH
368: def_ignore_dot = true;
369: #endif
370: #ifdef ALWAYS_SEND_MAIL
371: def_mail_always = true;
372: #endif
373: #ifdef SEND_MAIL_WHEN_NO_USER
374: def_mail_no_user = true;
375: #endif
376: #ifdef SEND_MAIL_WHEN_NO_HOST
377: def_mail_no_host = true;
378: #endif
379: #ifdef SEND_MAIL_WHEN_NOT_OK
380: def_mail_no_perms = true;
381: #endif
382: #ifndef NO_TTY_TICKETS
383: def_tty_tickets = true;
384: #endif
385: #ifndef NO_LECTURE
386: def_lecture = once;
387: #endif
388: #ifndef NO_AUTHENTICATION
389: def_authenticate = true;
390: #endif
391: #ifndef NO_ROOT_SUDO
392: def_root_sudo = true;
393: #endif
394: #ifdef HOST_IN_LOG
395: def_log_host = true;
396: #endif
397: #ifdef SHELL_IF_NO_ARGS
398: def_shell_noargs = true;
399: #endif
400: #ifdef SHELL_SETS_HOME
401: def_set_home = true;
402: #endif
403: #ifndef DONT_LEAK_PATH_INFO
404: def_path_info = true;
405: #endif
406: #ifdef FQDN
407: def_fqdn = true;
408: #endif
409: #ifdef USE_INSULTS
410: def_insults = true;
411: #endif
412: #ifdef ENV_EDITOR
413: def_env_editor = true;
414: #endif
415: #ifdef UMASK_OVERRIDE
416: def_umask_override = true;
417: #endif
418: def_iolog_file = estrdup("%{seq}");
419: def_iolog_dir = estrdup(_PATH_SUDO_IO_LOGDIR);
420: def_sudoers_locale = estrdup("C");
421: def_env_reset = ENV_RESET;
422: def_set_logname = true;
423: def_closefrom = STDERR_FILENO + 1;
424: #ifdef NO_PAM_SESSION
425: def_pam_session = false;
426: #else
427: def_pam_session = true;
428: #endif
429:
430: /* Syslog options need special care since they both strings and ints */
431: #if (LOGGING & SLOG_SYSLOG)
432: (void) store_syslogfac(LOGFAC, &sudo_defs_table[I_SYSLOG], true);
433: (void) store_syslogpri(PRI_SUCCESS, &sudo_defs_table[I_SYSLOG_GOODPRI],
434: true);
435: (void) store_syslogpri(PRI_FAILURE, &sudo_defs_table[I_SYSLOG_BADPRI],
436: true);
437: #endif
438:
439: /* Password flags also have a string and integer component. */
440: (void) store_tuple("any", &sudo_defs_table[I_LISTPW], true);
441: (void) store_tuple("all", &sudo_defs_table[I_VERIFYPW], true);
442:
443: /* Then initialize the int-like things. */
444: #ifdef SUDO_UMASK
445: def_umask = SUDO_UMASK;
446: #else
447: def_umask = 0777;
448: #endif
449: def_loglinelen = MAXLOGFILELEN;
450: def_timestamp_timeout = TIMEOUT;
451: def_passwd_timeout = PASSWORD_TIMEOUT;
452: def_passwd_tries = TRIES_FOR_PASSWORD;
453: #ifdef HAVE_ZLIB_H
454: def_compress_io = true;
455: #endif
456:
457: /* Now do the strings */
458: def_mailto = estrdup(MAILTO);
459: def_mailsub = estrdup(N_(MAILSUBJECT));
460: def_badpass_message = estrdup(_(INCORRECT_PASSWORD));
461: def_timestampdir = estrdup(_PATH_SUDO_TIMEDIR);
462: def_passprompt = estrdup(_(PASSPROMPT));
463: def_runas_default = estrdup(RUNAS_DEFAULT);
464: #ifdef _PATH_SUDO_SENDMAIL
465: def_mailerpath = estrdup(_PATH_SUDO_SENDMAIL);
466: def_mailerflags = estrdup("-t");
467: #endif
468: #if (LOGGING & SLOG_FILE)
469: def_logfile = estrdup(_PATH_SUDO_LOGFILE);
470: #endif
471: #ifdef EXEMPTGROUP
472: def_exempt_group = estrdup(EXEMPTGROUP);
473: #endif
474: #ifdef SECURE_PATH
475: def_secure_path = estrdup(SECURE_PATH);
476: #endif
477: def_editor = estrdup(EDITOR);
478: def_set_utmp = true;
479:
480: /* Finally do the lists (currently just environment tables). */
481: init_envtables();
482:
483: firsttime = 0;
484:
485: debug_return;
486: }
487:
488: /*
489: * Update the defaults based on what was set by sudoers.
490: * Pass in an OR'd list of which default types to update.
491: */
492: bool
493: update_defaults(int what)
494: {
495: struct defaults *def;
496: bool rc = true;
497: debug_decl(update_defaults, SUDO_DEBUG_DEFAULTS)
498:
499: tq_foreach_fwd(&defaults, def) {
500: switch (def->type) {
501: case DEFAULTS:
502: if (ISSET(what, SETDEF_GENERIC) &&
503: !set_default(def->var, def->val, def->op))
504: rc = false;
505: break;
506: case DEFAULTS_USER:
507: #if 1
508: if (ISSET(what, SETDEF_USER)) {
509: int m;
510: m = userlist_matches(sudo_user.pw, &def->binding);
511: if (m == ALLOW) {
512: if (!set_default(def->var, def->val, def->op))
513: rc = false;
514: }
515: }
516: #else
517: if (ISSET(what, SETDEF_USER) &&
518: userlist_matches(sudo_user.pw, &def->binding) == ALLOW &&
519: !set_default(def->var, def->val, def->op))
520: rc = false;
521: #endif
522: break;
523: case DEFAULTS_RUNAS:
524: if (ISSET(what, SETDEF_RUNAS) &&
525: runaslist_matches(&def->binding, NULL, NULL, NULL) == ALLOW &&
526: !set_default(def->var, def->val, def->op))
527: rc = false;
528: break;
529: case DEFAULTS_HOST:
530: if (ISSET(what, SETDEF_HOST) &&
531: hostlist_matches(&def->binding) == ALLOW &&
532: !set_default(def->var, def->val, def->op))
533: rc = false;
534: break;
535: case DEFAULTS_CMND:
536: if (ISSET(what, SETDEF_CMND) &&
537: cmndlist_matches(&def->binding) == ALLOW &&
538: !set_default(def->var, def->val, def->op))
539: rc = false;
540: break;
541: }
542: }
543: debug_return_bool(rc);
544: }
545:
546: /*
547: * Check the defaults entries without actually setting them.
548: * Pass in an OR'd list of which default types to check.
549: */
550: bool
551: check_defaults(int what, bool quiet)
552: {
553: struct sudo_defs_types *cur;
554: struct defaults *def;
555: bool rc = true;
556: debug_decl(check_defaults, SUDO_DEBUG_DEFAULTS)
557:
558: tq_foreach_fwd(&defaults, def) {
559: switch (def->type) {
560: case DEFAULTS:
561: if (!ISSET(what, SETDEF_GENERIC))
562: continue;
563: break;
564: case DEFAULTS_USER:
565: if (!ISSET(what, SETDEF_USER))
566: continue;
567: break;
568: case DEFAULTS_RUNAS:
569: if (!ISSET(what, SETDEF_RUNAS))
570: continue;
571: break;
572: case DEFAULTS_HOST:
573: if (!ISSET(what, SETDEF_HOST))
574: continue;
575: break;
576: case DEFAULTS_CMND:
577: if (!ISSET(what, SETDEF_CMND))
578: continue;
579: break;
580: }
581: for (cur = sudo_defs_table; cur->name != NULL; cur++) {
582: if (strcmp(def->var, cur->name) == 0)
583: break;
584: }
585: if (cur->name == NULL) {
586: if (!quiet)
587: warningx(_("unknown defaults entry `%s'"), def->var);
588: rc = false;
589: }
590: }
591: debug_return_bool(rc);
592: }
593:
594: static bool
595: store_int(char *val, struct sudo_defs_types *def, int op)
596: {
597: char *endp;
598: long l;
599: debug_decl(store_int, SUDO_DEBUG_DEFAULTS)
600:
601: if (op == false) {
602: def->sd_un.ival = 0;
603: } else {
604: l = strtol(val, &endp, 10);
605: if (*endp != '\0')
606: debug_return_bool(false);
607: /* XXX - should check against INT_MAX */
608: def->sd_un.ival = (int)l;
609: }
610: if (def->callback)
611: debug_return_bool(def->callback(val));
612: debug_return_bool(true);
613: }
614:
615: static bool
616: store_uint(char *val, struct sudo_defs_types *def, int op)
617: {
618: char *endp;
619: long l;
620: debug_decl(store_uint, SUDO_DEBUG_DEFAULTS)
621:
622: if (op == false) {
623: def->sd_un.ival = 0;
624: } else {
625: l = strtol(val, &endp, 10);
626: if (*endp != '\0' || l < 0)
627: debug_return_bool(false);
628: /* XXX - should check against INT_MAX */
629: def->sd_un.ival = (unsigned int)l;
630: }
631: if (def->callback)
632: debug_return_bool(def->callback(val));
633: debug_return_bool(true);
634: }
635:
636: static bool
637: store_float(char *val, struct sudo_defs_types *def, int op)
638: {
639: char *endp;
640: double d;
641: debug_decl(store_float, SUDO_DEBUG_DEFAULTS)
642:
643: if (op == false) {
644: def->sd_un.fval = 0.0;
645: } else {
646: d = strtod(val, &endp);
647: if (*endp != '\0')
648: debug_return_bool(false);
649: /* XXX - should check against HUGE_VAL */
650: def->sd_un.fval = d;
651: }
652: if (def->callback)
653: debug_return_bool(def->callback(val));
654: debug_return_bool(true);
655: }
656:
657: static bool
658: store_tuple(char *val, struct sudo_defs_types *def, int op)
659: {
660: struct def_values *v;
661: debug_decl(store_tuple, SUDO_DEBUG_DEFAULTS)
662:
663: /*
664: * Since enums are really just ints we store the value as an ival.
665: * In the future, there may be multiple enums for different tuple
666: * types we want to avoid and special knowledge of the tuple type.
667: * This does assume that the first entry in the tuple enum will
668: * be the equivalent to a boolean "false".
669: */
670: if (!val) {
671: def->sd_un.ival = (op == false) ? 0 : 1;
672: } else {
673: for (v = def->values; v->sval != NULL; v++) {
674: if (strcmp(v->sval, val) == 0) {
675: def->sd_un.ival = v->ival;
676: break;
677: }
678: }
679: if (v->sval == NULL)
680: debug_return_bool(false);
681: }
682: if (def->callback)
683: debug_return_bool(def->callback(val));
684: debug_return_bool(true);
685: }
686:
687: static bool
688: store_str(char *val, struct sudo_defs_types *def, int op)
689: {
690: debug_decl(store_str, SUDO_DEBUG_DEFAULTS)
691:
692: efree(def->sd_un.str);
693: if (op == false)
694: def->sd_un.str = NULL;
695: else
696: def->sd_un.str = estrdup(val);
697: if (def->callback)
698: debug_return_bool(def->callback(val));
699: debug_return_bool(true);
700: }
701:
702: static bool
703: store_list(char *str, struct sudo_defs_types *def, int op)
704: {
705: char *start, *end;
706: debug_decl(store_list, SUDO_DEBUG_DEFAULTS)
707:
708: /* Remove all old members. */
709: if (op == false || op == true)
710: list_op(NULL, 0, def, freeall);
711:
712: /* Split str into multiple space-separated words and act on each one. */
713: if (op != false) {
714: end = str;
715: do {
716: /* Remove leading blanks, if nothing but blanks we are done. */
717: for (start = end; isblank((unsigned char)*start); start++)
718: ;
719: if (*start == '\0')
720: break;
721:
722: /* Find end position and perform operation. */
723: for (end = start; *end && !isblank((unsigned char)*end); end++)
724: ;
725: list_op(start, end - start, def, op == '-' ? delete : add);
726: } while (*end++ != '\0');
727: }
728: debug_return_bool(true);
729: }
730:
731: static bool
732: store_syslogfac(char *val, struct sudo_defs_types *def, int op)
733: {
734: struct strmap *fac;
735: debug_decl(store_syslogfac, SUDO_DEBUG_DEFAULTS)
736:
737: if (op == false) {
738: def->sd_un.ival = false;
739: debug_return_bool(true);
740: }
741: #ifdef LOG_NFACILITIES
742: if (!val)
743: debug_return_bool(false);
744: for (fac = facilities; fac->name && strcmp(val, fac->name); fac++)
745: ;
746: if (fac->name == NULL)
747: debug_return_bool(false); /* not found */
748:
749: def->sd_un.ival = fac->num;
750: #else
751: def->sd_un.ival = -1;
752: #endif /* LOG_NFACILITIES */
753: debug_return_bool(true);
754: }
755:
756: static const char *
757: logfac2str(int n)
758: {
759: #ifdef LOG_NFACILITIES
760: struct strmap *fac;
761: debug_decl(logfac2str, SUDO_DEBUG_DEFAULTS)
762:
763: for (fac = facilities; fac->name && fac->num != n; fac++)
764: ;
765: debug_return_str(fac->name);
766: #else
767: return "default";
768: #endif /* LOG_NFACILITIES */
769: }
770:
771: static bool
772: store_syslogpri(char *val, struct sudo_defs_types *def, int op)
773: {
774: struct strmap *pri;
775: debug_decl(store_syslogpri, SUDO_DEBUG_DEFAULTS)
776:
777: if (op == false || !val)
778: debug_return_bool(false);
779:
780: for (pri = priorities; pri->name && strcmp(val, pri->name); pri++)
781: ;
782: if (pri->name == NULL)
783: debug_return_bool(false); /* not found */
784:
785: def->sd_un.ival = pri->num;
786: debug_return_bool(true);
787: }
788:
789: static const char *
790: logpri2str(int n)
791: {
792: struct strmap *pri;
793: debug_decl(logpri2str, SUDO_DEBUG_DEFAULTS)
794:
795: for (pri = priorities; pri->name && pri->num != n; pri++)
796: ;
797: debug_return_str(pri->name);
798: }
799:
800: static bool
801: store_mode(char *val, struct sudo_defs_types *def, int op)
802: {
803: char *endp;
804: long l;
805: debug_decl(store_mode, SUDO_DEBUG_DEFAULTS)
806:
807: if (op == false) {
808: def->sd_un.mode = (mode_t)0777;
809: } else {
810: l = strtol(val, &endp, 8);
811: if (*endp != '\0' || l < 0 || l > 0777)
812: debug_return_bool(false);
813: def->sd_un.mode = (mode_t)l;
814: }
815: if (def->callback)
816: debug_return_bool(def->callback(val));
817: debug_return_bool(true);
818: }
819:
820: static void
821: list_op(char *val, size_t len, struct sudo_defs_types *def, enum list_ops op)
822: {
823: struct list_member *cur, *prev, *tmp;
824: debug_decl(list_op, SUDO_DEBUG_DEFAULTS)
825:
826: if (op == freeall) {
827: for (cur = def->sd_un.list; cur; ) {
828: tmp = cur;
829: cur = tmp->next;
830: efree(tmp->value);
831: efree(tmp);
832: }
833: def->sd_un.list = NULL;
834: debug_return;
835: }
836:
837: for (cur = def->sd_un.list, prev = NULL; cur; prev = cur, cur = cur->next) {
838: if ((strncmp(cur->value, val, len) == 0 && cur->value[len] == '\0')) {
839:
840: if (op == add)
841: debug_return; /* already exists */
842:
843: /* Delete node */
844: if (prev != NULL)
845: prev->next = cur->next;
846: else
847: def->sd_un.list = cur->next;
848: efree(cur->value);
849: efree(cur);
850: break;
851: }
852: }
853:
854: /* Add new node to the head of the list. */
855: if (op == add) {
856: cur = ecalloc(1, sizeof(struct list_member));
857: cur->value = estrndup(val, len);
858: cur->next = def->sd_un.list;
859: def->sd_un.list = cur;
860: }
861: debug_return;
862: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>