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