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: memset(&def->sd_un, 0, 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: def_pam_service = estrdup("sudo");
425: #ifdef HAVE_PAM_LOGIN
426: def_pam_login_service = estrdup("sudo-i");
427: #else
428: def_pam_login_service = estrdup("sudo");
429: #endif
430: #ifdef NO_PAM_SESSION
431: def_pam_session = false;
432: #else
433: def_pam_session = true;
434: #endif
435:
436: /* Syslog options need special care since they both strings and ints */
437: #if (LOGGING & SLOG_SYSLOG)
438: (void) store_syslogfac(LOGFAC, &sudo_defs_table[I_SYSLOG], true);
439: (void) store_syslogpri(PRI_SUCCESS, &sudo_defs_table[I_SYSLOG_GOODPRI],
440: true);
441: (void) store_syslogpri(PRI_FAILURE, &sudo_defs_table[I_SYSLOG_BADPRI],
442: true);
443: #endif
444:
445: /* Password flags also have a string and integer component. */
446: (void) store_tuple("any", &sudo_defs_table[I_LISTPW], true);
447: (void) store_tuple("all", &sudo_defs_table[I_VERIFYPW], true);
448:
449: /* Then initialize the int-like things. */
450: #ifdef SUDO_UMASK
451: def_umask = SUDO_UMASK;
452: #else
453: def_umask = 0777;
454: #endif
455: def_loglinelen = MAXLOGFILELEN;
456: def_timestamp_timeout = TIMEOUT;
457: def_passwd_timeout = PASSWORD_TIMEOUT;
458: def_passwd_tries = TRIES_FOR_PASSWORD;
459: #ifdef HAVE_ZLIB_H
460: def_compress_io = true;
461: #endif
462:
463: /* Now do the strings */
464: def_mailto = estrdup(MAILTO);
465: def_mailsub = estrdup(N_(MAILSUBJECT));
466: def_badpass_message = estrdup(_(INCORRECT_PASSWORD));
467: def_timestampdir = estrdup(_PATH_SUDO_TIMEDIR);
468: def_passprompt = estrdup(_(PASSPROMPT));
469: def_runas_default = estrdup(RUNAS_DEFAULT);
470: #ifdef _PATH_SUDO_SENDMAIL
471: def_mailerpath = estrdup(_PATH_SUDO_SENDMAIL);
472: def_mailerflags = estrdup("-t");
473: #endif
474: #if (LOGGING & SLOG_FILE)
475: def_logfile = estrdup(_PATH_SUDO_LOGFILE);
476: #endif
477: #ifdef EXEMPTGROUP
478: def_exempt_group = estrdup(EXEMPTGROUP);
479: #endif
480: #ifdef SECURE_PATH
481: def_secure_path = estrdup(SECURE_PATH);
482: #endif
483: def_editor = estrdup(EDITOR);
484: def_set_utmp = true;
485:
486: /* Finally do the lists (currently just environment tables). */
487: init_envtables();
488:
489: firsttime = 0;
490:
491: debug_return;
492: }
493:
494: /*
495: * Update the defaults based on what was set by sudoers.
496: * Pass in an OR'd list of which default types to update.
497: */
498: bool
499: update_defaults(int what)
500: {
501: struct defaults *def;
502: bool rc = true;
503: debug_decl(update_defaults, SUDO_DEBUG_DEFAULTS)
504:
505: tq_foreach_fwd(&defaults, def) {
506: switch (def->type) {
507: case DEFAULTS:
508: if (ISSET(what, SETDEF_GENERIC) &&
509: !set_default(def->var, def->val, def->op))
510: rc = false;
511: break;
512: case DEFAULTS_USER:
513: #if 1
514: if (ISSET(what, SETDEF_USER)) {
515: int m;
516: m = userlist_matches(sudo_user.pw, &def->binding);
517: if (m == ALLOW) {
518: if (!set_default(def->var, def->val, def->op))
519: rc = false;
520: }
521: }
522: #else
523: if (ISSET(what, SETDEF_USER) &&
524: userlist_matches(sudo_user.pw, &def->binding) == ALLOW &&
525: !set_default(def->var, def->val, def->op))
526: rc = false;
527: #endif
528: break;
529: case DEFAULTS_RUNAS:
530: if (ISSET(what, SETDEF_RUNAS) &&
531: runaslist_matches(&def->binding, NULL, NULL, NULL) == ALLOW &&
532: !set_default(def->var, def->val, def->op))
533: rc = false;
534: break;
535: case DEFAULTS_HOST:
536: if (ISSET(what, SETDEF_HOST) &&
537: hostlist_matches(&def->binding) == ALLOW &&
538: !set_default(def->var, def->val, def->op))
539: rc = false;
540: break;
541: case DEFAULTS_CMND:
542: if (ISSET(what, SETDEF_CMND) &&
543: cmndlist_matches(&def->binding) == ALLOW &&
544: !set_default(def->var, def->val, def->op))
545: rc = false;
546: break;
547: }
548: }
549: debug_return_bool(rc);
550: }
551:
552: /*
553: * Check the defaults entries without actually setting them.
554: * Pass in an OR'd list of which default types to check.
555: */
556: bool
557: check_defaults(int what, bool quiet)
558: {
559: struct sudo_defs_types *cur;
560: struct defaults *def;
561: bool rc = true;
562: debug_decl(check_defaults, SUDO_DEBUG_DEFAULTS)
563:
564: tq_foreach_fwd(&defaults, def) {
565: switch (def->type) {
566: case DEFAULTS:
567: if (!ISSET(what, SETDEF_GENERIC))
568: continue;
569: break;
570: case DEFAULTS_USER:
571: if (!ISSET(what, SETDEF_USER))
572: continue;
573: break;
574: case DEFAULTS_RUNAS:
575: if (!ISSET(what, SETDEF_RUNAS))
576: continue;
577: break;
578: case DEFAULTS_HOST:
579: if (!ISSET(what, SETDEF_HOST))
580: continue;
581: break;
582: case DEFAULTS_CMND:
583: if (!ISSET(what, SETDEF_CMND))
584: continue;
585: break;
586: }
587: for (cur = sudo_defs_table; cur->name != NULL; cur++) {
588: if (strcmp(def->var, cur->name) == 0)
589: break;
590: }
591: if (cur->name == NULL) {
592: if (!quiet)
593: warningx(_("unknown defaults entry `%s'"), def->var);
594: rc = false;
595: }
596: }
597: debug_return_bool(rc);
598: }
599:
600: static bool
601: store_int(char *val, struct sudo_defs_types *def, int op)
602: {
603: char *endp;
604: long l;
605: debug_decl(store_int, SUDO_DEBUG_DEFAULTS)
606:
607: if (op == false) {
608: def->sd_un.ival = 0;
609: } else {
610: l = strtol(val, &endp, 10);
611: if (*endp != '\0')
612: debug_return_bool(false);
613: /* XXX - should check against INT_MAX */
614: def->sd_un.ival = (int)l;
615: }
616: if (def->callback)
617: debug_return_bool(def->callback(val));
618: debug_return_bool(true);
619: }
620:
621: static bool
622: store_uint(char *val, struct sudo_defs_types *def, int op)
623: {
624: char *endp;
625: long l;
626: debug_decl(store_uint, SUDO_DEBUG_DEFAULTS)
627:
628: if (op == false) {
629: def->sd_un.ival = 0;
630: } else {
631: l = strtol(val, &endp, 10);
632: if (*endp != '\0' || l < 0)
633: debug_return_bool(false);
634: /* XXX - should check against INT_MAX */
635: def->sd_un.ival = (unsigned int)l;
636: }
637: if (def->callback)
638: debug_return_bool(def->callback(val));
639: debug_return_bool(true);
640: }
641:
642: static bool
643: store_float(char *val, struct sudo_defs_types *def, int op)
644: {
645: char *endp;
646: double d;
647: debug_decl(store_float, SUDO_DEBUG_DEFAULTS)
648:
649: if (op == false) {
650: def->sd_un.fval = 0.0;
651: } else {
652: d = strtod(val, &endp);
653: if (*endp != '\0')
654: debug_return_bool(false);
655: /* XXX - should check against HUGE_VAL */
656: def->sd_un.fval = d;
657: }
658: if (def->callback)
659: debug_return_bool(def->callback(val));
660: debug_return_bool(true);
661: }
662:
663: static bool
664: store_tuple(char *val, struct sudo_defs_types *def, int op)
665: {
666: struct def_values *v;
667: debug_decl(store_tuple, SUDO_DEBUG_DEFAULTS)
668:
669: /*
670: * Since enums are really just ints we store the value as an ival.
671: * In the future, there may be multiple enums for different tuple
672: * types we want to avoid and special knowledge of the tuple type.
673: * This does assume that the first entry in the tuple enum will
674: * be the equivalent to a boolean "false".
675: */
676: if (!val) {
677: def->sd_un.ival = (op == false) ? 0 : 1;
678: } else {
679: for (v = def->values; v->sval != NULL; v++) {
680: if (strcmp(v->sval, val) == 0) {
681: def->sd_un.ival = v->ival;
682: break;
683: }
684: }
685: if (v->sval == NULL)
686: debug_return_bool(false);
687: }
688: if (def->callback)
689: debug_return_bool(def->callback(val));
690: debug_return_bool(true);
691: }
692:
693: static bool
694: store_str(char *val, struct sudo_defs_types *def, int op)
695: {
696: debug_decl(store_str, SUDO_DEBUG_DEFAULTS)
697:
698: efree(def->sd_un.str);
699: if (op == false)
700: def->sd_un.str = NULL;
701: else
702: def->sd_un.str = estrdup(val);
703: if (def->callback)
704: debug_return_bool(def->callback(val));
705: debug_return_bool(true);
706: }
707:
708: static bool
709: store_list(char *str, struct sudo_defs_types *def, int op)
710: {
711: char *start, *end;
712: debug_decl(store_list, SUDO_DEBUG_DEFAULTS)
713:
714: /* Remove all old members. */
715: if (op == false || op == true)
716: list_op(NULL, 0, def, freeall);
717:
718: /* Split str into multiple space-separated words and act on each one. */
719: if (op != false) {
720: end = str;
721: do {
722: /* Remove leading blanks, if nothing but blanks we are done. */
723: for (start = end; isblank((unsigned char)*start); start++)
724: ;
725: if (*start == '\0')
726: break;
727:
728: /* Find end position and perform operation. */
729: for (end = start; *end && !isblank((unsigned char)*end); end++)
730: ;
731: list_op(start, end - start, def, op == '-' ? delete : add);
732: } while (*end++ != '\0');
733: }
734: debug_return_bool(true);
735: }
736:
737: static bool
738: store_syslogfac(char *val, struct sudo_defs_types *def, int op)
739: {
740: struct strmap *fac;
741: debug_decl(store_syslogfac, SUDO_DEBUG_DEFAULTS)
742:
743: if (op == false) {
744: def->sd_un.ival = false;
745: debug_return_bool(true);
746: }
747: #ifdef LOG_NFACILITIES
748: if (!val)
749: debug_return_bool(false);
750: for (fac = facilities; fac->name && strcmp(val, fac->name); fac++)
751: ;
752: if (fac->name == NULL)
753: debug_return_bool(false); /* not found */
754:
755: def->sd_un.ival = fac->num;
756: #else
757: def->sd_un.ival = -1;
758: #endif /* LOG_NFACILITIES */
759: debug_return_bool(true);
760: }
761:
762: static const char *
763: logfac2str(int n)
764: {
765: #ifdef LOG_NFACILITIES
766: struct strmap *fac;
767: debug_decl(logfac2str, SUDO_DEBUG_DEFAULTS)
768:
769: for (fac = facilities; fac->name && fac->num != n; fac++)
770: ;
771: debug_return_str(fac->name);
772: #else
773: return "default";
774: #endif /* LOG_NFACILITIES */
775: }
776:
777: static bool
778: store_syslogpri(char *val, struct sudo_defs_types *def, int op)
779: {
780: struct strmap *pri;
781: debug_decl(store_syslogpri, SUDO_DEBUG_DEFAULTS)
782:
783: if (op == false || !val)
784: debug_return_bool(false);
785:
786: for (pri = priorities; pri->name && strcmp(val, pri->name); pri++)
787: ;
788: if (pri->name == NULL)
789: debug_return_bool(false); /* not found */
790:
791: def->sd_un.ival = pri->num;
792: debug_return_bool(true);
793: }
794:
795: static const char *
796: logpri2str(int n)
797: {
798: struct strmap *pri;
799: debug_decl(logpri2str, SUDO_DEBUG_DEFAULTS)
800:
801: for (pri = priorities; pri->name && pri->num != n; pri++)
802: ;
803: debug_return_str(pri->name);
804: }
805:
806: static bool
807: store_mode(char *val, struct sudo_defs_types *def, int op)
808: {
809: char *endp;
810: long l;
811: debug_decl(store_mode, SUDO_DEBUG_DEFAULTS)
812:
813: if (op == false) {
814: def->sd_un.mode = (mode_t)0777;
815: } else {
816: l = strtol(val, &endp, 8);
817: if (*endp != '\0' || l < 0 || l > 0777)
818: debug_return_bool(false);
819: def->sd_un.mode = (mode_t)l;
820: }
821: if (def->callback)
822: debug_return_bool(def->callback(val));
823: debug_return_bool(true);
824: }
825:
826: static void
827: list_op(char *val, size_t len, struct sudo_defs_types *def, enum list_ops op)
828: {
829: struct list_member *cur, *prev, *tmp;
830: debug_decl(list_op, SUDO_DEBUG_DEFAULTS)
831:
832: if (op == freeall) {
833: for (cur = def->sd_un.list; cur; ) {
834: tmp = cur;
835: cur = tmp->next;
836: efree(tmp->value);
837: efree(tmp);
838: }
839: def->sd_un.list = NULL;
840: debug_return;
841: }
842:
843: for (cur = def->sd_un.list, prev = NULL; cur; prev = cur, cur = cur->next) {
844: if ((strncmp(cur->value, val, len) == 0 && cur->value[len] == '\0')) {
845:
846: if (op == add)
847: debug_return; /* already exists */
848:
849: /* Delete node */
850: if (prev != NULL)
851: prev->next = cur->next;
852: else
853: def->sd_un.list = cur->next;
854: efree(cur->value);
855: efree(cur);
856: break;
857: }
858: }
859:
860: /* Add new node to the head of the list. */
861: if (op == add) {
862: cur = ecalloc(1, sizeof(struct list_member));
863: cur->value = estrndup(val, len);
864: cur->next = def->sd_un.list;
865: def->sd_un.list = cur;
866: }
867: debug_return;
868: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>