Imported Upstream version 1.6.6
[debian/sudo] / defaults.c
1 /*
2  * Copyright (c) 1999-2001 Todd C. Miller <Todd.Miller@courtesan.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * 4. Products derived from this software may not be called "Sudo" nor
20  *    may "Sudo" appear in their names without specific prior written
21  *    permission from the author.
22  *
23  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
25  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
26  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 #include "config.h"
36
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <stdio.h>
40 #ifdef STDC_HEADERS
41 # include <stdlib.h>
42 # include <stddef.h>
43 #else
44 # ifdef HAVE_STDLIB_H
45 #  include <stdlib.h>
46 # endif
47 #endif /* STDC_HEADERS */
48 #ifdef HAVE_STRING_H
49 # include <string.h>
50 #else
51 # ifdef HAVE_STRINGS_H
52 #  include <strings.h>
53 # endif
54 #endif /* HAVE_STRING_H */
55 # ifdef HAVE_UNISTD_H
56 #include <unistd.h>
57 #endif /* HAVE_UNISTD_H */
58 #include <ctype.h>
59
60 #include "sudo.h"
61
62 #ifndef lint
63 static const char rcsid[] = "$Sudo: defaults.c,v 1.38 2001/12/30 18:40:09 millert Exp $";
64 #endif /* lint */
65
66 /*
67  * For converting between syslog numbers and strings.
68  */
69 struct strmap {
70     char *name;
71     int num;
72 };
73
74 #ifdef LOG_NFACILITIES
75 static struct strmap facilities[] = {
76 #ifdef LOG_AUTHPRIV
77         { "authpriv",   LOG_AUTHPRIV },
78 #endif
79         { "auth",       LOG_AUTH },
80         { "daemon",     LOG_DAEMON },
81         { "user",       LOG_USER },
82         { "local0",     LOG_LOCAL0 },
83         { "local1",     LOG_LOCAL1 },
84         { "local2",     LOG_LOCAL2 },
85         { "local3",     LOG_LOCAL3 },
86         { "local4",     LOG_LOCAL4 },
87         { "local5",     LOG_LOCAL5 },
88         { "local6",     LOG_LOCAL6 },
89         { "local7",     LOG_LOCAL7 },
90         { NULL,         -1 }
91 };
92 #endif /* LOG_NFACILITIES */
93
94 static struct strmap priorities[] = {
95         { "alert",      LOG_ALERT },
96         { "crit",       LOG_CRIT },
97         { "debug",      LOG_DEBUG },
98         { "emerg",      LOG_EMERG },
99         { "err",        LOG_ERR },
100         { "info",       LOG_INFO },
101         { "notice",     LOG_NOTICE },
102         { "warning",    LOG_WARNING },
103         { NULL,         -1 }
104 };
105
106 extern int sudolineno;
107
108 /*
109  * Local prototypes.
110  */
111 static int store_int __P((char *, struct sudo_defs_types *, int));
112 static int store_uint __P((char *, struct sudo_defs_types *, int));
113 static int store_str __P((char *, struct sudo_defs_types *, int));
114 static int store_syslogfac __P((char *, struct sudo_defs_types *, int));
115 static int store_syslogpri __P((char *, struct sudo_defs_types *, int));
116 static int store_mode __P((char *, struct sudo_defs_types *, int));
117 static int store_pwflag __P((char *, struct sudo_defs_types *, int));
118 static int store_list __P((char *, struct sudo_defs_types *, int));
119 static void list_op __P((char *, size_t, struct sudo_defs_types *, enum list_ops));
120
121 /*
122  * Table describing compile-time and run-time options.
123  */
124 #include <def_data.c>
125
126 /*
127  * Print version and configure info.
128  */
129 void
130 dump_defaults()
131 {
132     struct sudo_defs_types *cur;
133     struct list_member *item;
134
135     for (cur = sudo_defs_table; cur->name; cur++) {
136         if (cur->desc) {
137             switch (cur->type & T_MASK) {
138                 case T_FLAG:
139                     if (cur->sd_un.flag)
140                         puts(cur->desc);
141                     break;
142                 case T_STR:
143                 case T_LOGFAC:
144                 case T_LOGPRI:
145                 case T_PWFLAG:
146                     if (cur->sd_un.str) {
147                         (void) printf(cur->desc, cur->sd_un.str);
148                         putchar('\n');
149                     }
150                     break;
151                 case T_UINT:
152                 case T_INT:
153                     (void) printf(cur->desc, cur->sd_un.ival);
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             }
168         }
169     }
170 }
171
172 /*
173  * List each option along with its description.
174  */
175 void
176 list_options()
177 {
178     struct sudo_defs_types *cur;
179     char *p;
180
181     (void) puts("Available options in a sudoers ``Defaults'' line:\n");
182     for (cur = sudo_defs_table; cur->name; cur++) {
183         if (cur->name && cur->desc) {
184             switch (cur->type & T_MASK) {
185                 case T_FLAG:
186                     (void) printf("%s: %s\n", cur->name, cur->desc);
187                     break;
188                 default:
189                     p = strrchr(cur->desc, ':');
190                     if (p)
191                         (void) printf("%s: %.*s\n", cur->name,
192                             (int) (p - cur->desc), cur->desc);
193                     else
194                         (void) printf("%s: %s\n", cur->name, cur->desc);
195                     break;
196             }
197         }
198     }
199 }
200
201 /*
202  * Sets/clears an entry in the defaults structure
203  * If a variable that takes a value is used in a boolean
204  * context with op == 0, disable that variable.
205  * Eg. you may want to turn off logging to a file for some hosts.
206  * This is only meaningful for variables that are *optional*.
207  */
208 int
209 set_default(var, val, op)
210     char *var;
211     char *val;
212     int op;     /* TRUE or FALSE */
213 {
214     struct sudo_defs_types *cur;
215     int num;
216
217     for (cur = sudo_defs_table, num = 0; cur->name; cur++, num++) {
218         if (strcmp(var, cur->name) == 0)
219             break;
220     }
221     if (!cur->name) {
222         (void) fprintf(stderr,
223             "%s: unknown defaults entry `%s' referenced near line %d\n", Argv[0],
224             var, sudolineno);
225         return(FALSE);
226     }
227
228     switch (cur->type & T_MASK) {
229         case T_LOGFAC:
230             if (!store_syslogfac(val, cur, op)) {
231                 if (val)
232                     (void) fprintf(stderr,
233                         "%s: value '%s' is invalid for option '%s'\n", Argv[0],
234                         val, var);
235                 else
236                     (void) fprintf(stderr,
237                         "%s: no value specified for `%s' on line %d\n", Argv[0],
238                         var, sudolineno);
239                 return(FALSE);
240             }
241             break;
242         case T_LOGPRI:
243             if (!store_syslogpri(val, cur, op)) {
244                 if (val)
245                     (void) fprintf(stderr,
246                         "%s: value '%s' is invalid for option '%s'\n", Argv[0],
247                         val, var);
248                 else
249                     (void) fprintf(stderr,
250                         "%s: no value specified for `%s' on line %d\n", Argv[0],
251                         var, sudolineno);
252                 return(FALSE);
253             }
254             break;
255         case T_PWFLAG:
256             if (!store_pwflag(val, cur, op)) {
257                 if (val)
258                     (void) fprintf(stderr,
259                         "%s: value '%s' is invalid for option '%s'\n", Argv[0],
260                         val, var);
261                 else
262                     (void) fprintf(stderr,
263                         "%s: no value specified for `%s' on line %d\n", Argv[0],
264                         var, sudolineno);
265                 return(FALSE);
266             }
267             break;
268         case T_STR:
269             if (!val) {
270                 /* Check for bogus boolean usage or lack of a value. */
271                 if (!(cur->type & T_BOOL) || op != FALSE) {
272                     (void) fprintf(stderr,
273                         "%s: no value specified for `%s' on line %d\n", Argv[0],
274                         var, sudolineno);
275                     return(FALSE);
276                 }
277             }
278             if ((cur->type & T_PATH) && val && *val != '/') {
279                 (void) fprintf(stderr,
280                     "%s: values for `%s' must start with a '/'\n", Argv[0],
281                     var);
282                 return(FALSE);
283             }
284             if (!store_str(val, cur, op)) {
285                 (void) fprintf(stderr,
286                     "%s: value '%s' is invalid for option '%s'\n", Argv[0],
287                     val, var);
288                 return(FALSE);
289             }
290             break;
291         case T_INT:
292             if (!val) {
293                 /* Check for bogus boolean usage or lack of a value. */
294                 if (!(cur->type & T_BOOL) || op != FALSE) {
295                     (void) fprintf(stderr,
296                         "%s: no value specified for `%s' on line %d\n", Argv[0],
297                         var, sudolineno);
298                     return(FALSE);
299                 }
300             }
301             if (!store_int(val, cur, op)) {
302                 (void) fprintf(stderr,
303                     "%s: value '%s' is invalid for option '%s'\n", Argv[0],
304                     val, var);
305                 return(FALSE);
306             }
307             break;
308         case T_UINT:
309             if (!val) {
310                 /* Check for bogus boolean usage or lack of a value. */
311                 if (!(cur->type & T_BOOL) || op != FALSE) {
312                     (void) fprintf(stderr,
313                         "%s: no value specified for `%s' on line %d\n", Argv[0],
314                         var, sudolineno);
315                     return(FALSE);
316                 }
317             }
318             if (!store_uint(val, cur, op)) {
319                 (void) fprintf(stderr,
320                     "%s: value '%s' is invalid for option '%s'\n", Argv[0],
321                     val, var);
322                 return(FALSE);
323             }
324             break;
325         case T_MODE:
326             if (!val) {
327                 /* Check for bogus boolean usage or lack of a value. */
328                 if (!(cur->type & T_BOOL) || op != FALSE) {
329                     (void) fprintf(stderr,
330                         "%s: no value specified for `%s' on line %d\n", Argv[0],
331                         var, sudolineno);
332                     return(FALSE);
333                 }
334             }
335             if (!store_mode(val, cur, op)) {
336                 (void) fprintf(stderr,
337                     "%s: value '%s' is invalid for option '%s'\n", Argv[0],
338                     val, var);
339                 return(FALSE);
340             }
341             break;
342         case T_FLAG:
343             if (val) {
344                 (void) fprintf(stderr,
345                     "%s: option `%s' does not take a value on line %d\n",
346                     Argv[0], var, sudolineno);
347                 return(FALSE);
348             }
349             cur->sd_un.flag = op;
350
351             /* Special action for I_FQDN.  Move to own switch if we get more */
352             if (num == I_FQDN && op)
353                 set_fqdn();
354             break;
355         case T_LIST:
356             if (!val) {
357                 /* Check for bogus boolean usage or lack of a value. */
358                 if (!(cur->type & T_BOOL) || op != FALSE) {
359                     (void) fprintf(stderr,
360                         "%s: no value specified for `%s' on line %d\n", Argv[0],
361                         var, sudolineno);
362                     return(FALSE);
363                 }
364             }
365             if (!store_list(val, cur, op)) {
366                 (void) fprintf(stderr,
367                     "%s: value '%s' is invalid for option '%s'\n", Argv[0],
368                     val, var);
369                 return(FALSE);
370             }
371     }
372
373     return(TRUE);
374 }
375
376 /*
377  * Set default options to compiled-in values.
378  * Any of these may be overridden at runtime by a "Defaults" file.
379  */
380 void
381 init_defaults()
382 {
383     static int firsttime = 1;
384     struct sudo_defs_types *def;
385
386     /* Free any strings that were set. */
387     if (!firsttime) {
388         for (def = sudo_defs_table; def->name; def++)
389             switch (def->type & T_MASK) {
390                 case T_STR:
391                 case T_LOGFAC:
392                 case T_LOGPRI:
393                 case T_PWFLAG:
394                     if (def->sd_un.str) {
395                         free(def->sd_un.str);
396                         def->sd_un.str = NULL;
397                     }
398                     break;
399                 case T_LIST:
400                     list_op(NULL, 0, def, freeall);
401                     break;
402             }
403     }
404
405     /* First initialize the flags. */
406 #ifdef LONG_OTP_PROMPT
407     def_flag(I_LONG_OTP_PROMPT) = TRUE;
408 #endif
409 #ifdef IGNORE_DOT_PATH
410     def_flag(I_IGNORE_DOT) = TRUE;
411 #endif
412 #ifdef ALWAYS_SEND_MAIL
413     def_flag(I_MAIL_ALWAYS) = TRUE;
414 #endif
415 #ifdef SEND_MAIL_WHEN_NO_USER
416     def_flag(I_MAIL_NO_USER) = TRUE;
417 #endif
418 #ifdef SEND_MAIL_WHEN_NO_HOST
419     def_flag(I_MAIL_NO_HOST) = TRUE;
420 #endif
421 #ifdef SEND_MAIL_WHEN_NOT_OK
422     def_flag(I_MAIL_NO_PERMS) = TRUE;
423 #endif
424 #ifdef USE_TTY_TICKETS
425     def_flag(I_TTY_TICKETS) = TRUE;
426 #endif
427 #ifndef NO_LECTURE
428     def_flag(I_LECTURE) = TRUE;
429 #endif
430 #ifndef NO_AUTHENTICATION
431     def_flag(I_AUTHENTICATE) = TRUE;
432 #endif
433 #ifndef NO_ROOT_SUDO
434     def_flag(I_ROOT_SUDO) = TRUE;
435 #endif
436 #ifdef HOST_IN_LOG
437     def_flag(I_LOG_HOST) = TRUE;
438 #endif
439 #ifdef SHELL_IF_NO_ARGS
440     def_flag(I_SHELL_NOARGS) = TRUE;
441 #endif
442 #ifdef SHELL_SETS_HOME
443     def_flag(I_SET_HOME) = TRUE;
444 #endif
445 #ifndef DONT_LEAK_PATH_INFO
446     def_flag(I_PATH_INFO) = TRUE;
447 #endif
448 #ifdef FQDN
449     def_flag(I_FQDN) = TRUE;
450 #endif
451 #ifdef USE_INSULTS
452     def_flag(I_INSULTS) = TRUE;
453 #endif
454 #ifdef ENV_EDITOR
455     def_flag(I_ENV_EDITOR) = TRUE;
456 #endif
457     def_flag(I_SET_LOGNAME) = TRUE;
458
459     /* Syslog options need special care since they both strings and ints */
460 #if (LOGGING & SLOG_SYSLOG)
461     (void) store_syslogfac(LOGFAC, &sudo_defs_table[I_SYSLOG], TRUE);
462     (void) store_syslogpri(PRI_SUCCESS, &sudo_defs_table[I_SYSLOG_GOODPRI],
463         TRUE);
464     (void) store_syslogpri(PRI_FAILURE, &sudo_defs_table[I_SYSLOG_BADPRI],
465         TRUE);
466 #endif
467
468     /* Password flags also have a string and integer component. */
469     (void) store_pwflag("any", &sudo_defs_table[I_LISTPW], TRUE);
470     (void) store_pwflag("all", &sudo_defs_table[I_VERIFYPW], TRUE);
471
472     /* Then initialize the int-like things. */
473 #ifdef SUDO_UMASK
474     def_mode(I_UMASK) = SUDO_UMASK;
475 #else
476     def_mode(I_UMASK) = 0777;
477 #endif
478     def_ival(I_LOGLINELEN) = MAXLOGFILELEN;
479     def_ival(I_TIMESTAMP_TIMEOUT) = TIMEOUT;
480     def_ival(I_PASSWD_TIMEOUT) = PASSWORD_TIMEOUT;
481     def_ival(I_PASSWD_TRIES) = TRIES_FOR_PASSWORD;
482
483     /* Now do the strings */
484     def_str(I_MAILTO) = estrdup(MAILTO);
485     def_str(I_MAILSUB) = estrdup(MAILSUBJECT);
486     def_str(I_BADPASS_MESSAGE) = estrdup(INCORRECT_PASSWORD);
487     def_str(I_TIMESTAMPDIR) = estrdup(_PATH_SUDO_TIMEDIR);
488     def_str(I_PASSPROMPT) = estrdup(PASSPROMPT);
489     def_str(I_RUNAS_DEFAULT) = estrdup(RUNAS_DEFAULT);
490 #ifdef _PATH_SUDO_SENDMAIL
491     def_str(I_MAILERPATH) = estrdup(_PATH_SUDO_SENDMAIL);
492     def_str(I_MAILERFLAGS) = estrdup("-t");
493 #endif
494 #if (LOGGING & SLOG_FILE)
495     def_str(I_LOGFILE) = estrdup(_PATH_SUDO_LOGFILE);
496 #endif
497 #ifdef EXEMPTGROUP
498     def_str(I_EXEMPT_GROUP) = estrdup(EXEMPTGROUP);
499 #endif
500     def_str(I_EDITOR) = estrdup(EDITOR);
501
502     /* Finally do the lists (currently just environment tables). */
503     init_envtables();
504
505     /*
506      * The following depend on the above values.
507      * We use a pointer to the string so that if its
508      * value changes we get the change.
509      */
510     if (user_runas == NULL)
511         user_runas = &def_str(I_RUNAS_DEFAULT);
512
513     firsttime = 0;
514 }
515
516 static int
517 store_int(val, def, op)
518     char *val;
519     struct sudo_defs_types *def;
520     int op;
521 {
522     char *endp;
523     long l;
524
525     if (op == FALSE) {
526         def->sd_un.ival = 0;
527     } else {
528         l = strtol(val, &endp, 10);
529         if (*endp != '\0')
530             return(FALSE);
531         /* XXX - should check against INT_MAX */
532         def->sd_un.ival = (unsigned int)l;
533     }
534     return(TRUE);
535 }
536
537 static int
538 store_uint(val, def, op)
539     char *val;
540     struct sudo_defs_types *def;
541     int op;
542 {
543     char *endp;
544     long l;
545
546     if (op == FALSE) {
547         def->sd_un.ival = 0;
548     } else {
549         l = strtol(val, &endp, 10);
550         if (*endp != '\0' || l < 0)
551             return(FALSE);
552         /* XXX - should check against INT_MAX */
553         def->sd_un.ival = (unsigned int)l;
554     }
555     return(TRUE);
556 }
557
558 static int
559 store_str(val, def, op)
560     char *val;
561     struct sudo_defs_types *def;
562     int op;
563 {
564
565     if (def->sd_un.str)
566         free(def->sd_un.str);
567     if (op == FALSE)
568         def->sd_un.str = NULL;
569     else
570         def->sd_un.str = estrdup(val);
571     return(TRUE);
572 }
573
574 static int
575 store_list(str, def, op)
576     char *str;
577     struct sudo_defs_types *def;
578     int op;
579 {
580     char *start, *end;
581
582     /* Remove all old members. */
583     if (op == FALSE || op == TRUE)
584         list_op(NULL, 0, def, freeall);
585
586     /* Split str into multiple space-separated words and act on each one. */
587     if (op != FALSE) {
588         end = str;
589         do {
590             /* Remove leading blanks, if nothing but blanks we are done. */
591             for (start = end; isblank(*start); start++)
592                 ;
593             if (*start == '\0')
594                 break;
595
596             /* Find end position and perform operation. */
597             for (end = start; *end && !isblank(*end); end++) 
598                 ;
599             list_op(start, end - start, def, op == '-' ? delete : add);
600         } while (*end++ != '\0');
601     }
602     return(TRUE);
603 }
604
605 static int
606 store_syslogfac(val, def, op)
607     char *val;
608     struct sudo_defs_types *def;
609     int op;
610 {
611     struct strmap *fac;
612
613     if (op == FALSE) {
614         if (def->sd_un.str) {
615             free(def->sd_un.str);
616             def->sd_un.str = NULL;
617         }
618         return(TRUE);
619     }
620 #ifdef LOG_NFACILITIES
621     if (!val)
622         return(FALSE);
623     for (fac = facilities; fac->name && strcmp(val, fac->name); fac++)
624         ;
625     if (fac->name == NULL)
626         return(FALSE);                          /* not found */
627
628     /* Store both name and number. */
629     if (def->sd_un.str)
630         free(def->sd_un.str);
631     def->sd_un.str = estrdup(fac->name);
632     sudo_defs_table[I_LOGFAC].sd_un.ival = fac->num;
633 #else
634     if (def->sd_un.str)
635         free(def->sd_un.str);
636     def->sd_un.str = estrdup("default");
637 #endif /* LOG_NFACILITIES */
638     return(TRUE);
639 }
640
641 static int
642 store_syslogpri(val, def, op)
643     char *val;
644     struct sudo_defs_types *def;
645     int op;
646 {
647     struct strmap *pri;
648     struct sudo_defs_types *idef;
649
650     if (op == FALSE || !val)
651         return(FALSE);
652     if (def == &sudo_defs_table[I_SYSLOG_GOODPRI])
653         idef = &sudo_defs_table[I_GOODPRI];
654     else if (def == &sudo_defs_table[I_SYSLOG_BADPRI])
655         idef = &sudo_defs_table[I_BADPRI];
656     else
657         return(FALSE);
658
659     for (pri = priorities; pri->name && strcmp(val, pri->name); pri++)
660         ;
661     if (pri->name == NULL)
662         return(FALSE);                          /* not found */
663
664     /* Store both name and number. */
665     if (def->sd_un.str)
666         free(def->sd_un.str);
667     def->sd_un.str = estrdup(pri->name);
668     idef->sd_un.ival = pri->num;
669     return(TRUE);
670 }
671
672 static int
673 store_mode(val, def, op)
674     char *val;
675     struct sudo_defs_types *def;
676     int op;
677 {
678     char *endp;
679     long l;
680
681     if (op == FALSE) {
682         def->sd_un.mode = (mode_t)0777;
683     } else {
684         l = strtol(val, &endp, 8);
685         if (*endp != '\0' || l < 0 || l > 0777)
686             return(FALSE);
687         def->sd_un.mode = (mode_t)l;
688     }
689     return(TRUE);
690 }
691
692 static int
693 store_pwflag(val, def, op)
694     char *val;
695     struct sudo_defs_types *def;
696     int op;
697 {
698     int isub, flags;
699
700     if (strcmp(def->name, "verifypw") == 0)
701         isub = I_VERIFYPW_I;
702     else
703         isub = I_LISTPW_I;
704
705     /* Handle !foo. */
706     if (op == FALSE) {
707         if (def->sd_un.str) {
708             free(def->sd_un.str);
709             def->sd_un.str = NULL;
710         }
711         def->sd_un.str = estrdup("never");
712         sudo_defs_table[isub].sd_un.ival = PWCHECK_NEVER;
713         return(TRUE);
714     }
715     if (!val)
716         return(FALSE);
717
718     /* Convert strings to integer values. */
719     if (strcmp(val, "all") == 0)
720         flags = PWCHECK_ALL;
721     else if (strcmp(val, "any") == 0)
722         flags = PWCHECK_ANY;
723     else if (strcmp(val, "never") == 0)
724         flags = PWCHECK_NEVER;
725     else if (strcmp(val, "always") == 0)
726         flags = PWCHECK_ALWAYS;
727     else
728         return(FALSE);
729
730     /* Store both name and number. */
731     if (def->sd_un.str)
732         free(def->sd_un.str);
733     def->sd_un.str = estrdup(val);
734     sudo_defs_table[isub].sd_un.ival = flags;
735
736     return(TRUE);
737 }
738
739 static void
740 list_op(val, len, def, op)
741     char *val;
742     size_t len;
743     struct sudo_defs_types *def;
744     enum list_ops op;
745 {
746     struct list_member *cur, *prev, *tmp;
747
748     if (op == freeall) {
749         for (cur = def->sd_un.list; cur; ) {
750             tmp = cur;
751             cur = tmp->next;
752             free(tmp->value);
753             free(tmp);
754         }
755         def->sd_un.list = NULL;
756         return;
757     }
758
759     for (cur = def->sd_un.list, prev = NULL; cur; prev = cur, cur = cur->next) {
760         if ((strncmp(cur->value, val, len) == 0 && cur->value[len] == '\0')) {
761
762             if (op == add)
763                 return;                 /* already exists */
764
765             /* Delete node */
766             if (prev != NULL)
767                 prev->next = cur->next;
768             else
769                 def->sd_un.list = cur->next;
770             free(cur->value);
771             free(cur);
772             break;
773         }
774     }
775
776     /* Add new node to the head of the list. */
777     if (op == add) {
778         cur = emalloc(sizeof(struct list_member));
779         cur->value = emalloc(len + 1);
780         (void) memcpy(cur->value, val, len);
781         cur->value[len] = '\0';
782         cur->next = def->sd_un.list;
783         def->sd_un.list = cur;
784     }
785 }