Imported Upstream version 1.8.7
[debian/sudo] / plugins / sudoers / defaults.c
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 }