switch from rcS.d to rc[0-6].d
[debian/sudo] / defaults.c
1 /*
2  * Copyright (c) 1999-2005, 2007-2008
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 #else
38 # ifdef HAVE_STRINGS_H
39 #  include <strings.h>
40 # endif
41 #endif /* HAVE_STRING_H */
42 # ifdef HAVE_UNISTD_H
43 #include <unistd.h>
44 #endif /* HAVE_UNISTD_H */
45 #include <pwd.h>
46 #include <ctype.h>
47
48 #include "sudo.h"
49 #include "parse.h"
50 #include <gram.h>
51
52 #ifndef lint
53 __unused static const char rcsid[] = "$Sudo: defaults.c,v 1.73 2008/11/09 14:13:12 millert Exp $";
54 #endif /* lint */
55
56 /*
57  * For converting between syslog numbers and strings.
58  */
59 struct strmap {
60     char *name;
61     int num;
62 };
63
64 #ifdef LOG_NFACILITIES
65 static struct strmap facilities[] = {
66 #ifdef LOG_AUTHPRIV
67         { "authpriv",   LOG_AUTHPRIV },
68 #endif
69         { "auth",       LOG_AUTH },
70         { "daemon",     LOG_DAEMON },
71         { "user",       LOG_USER },
72         { "local0",     LOG_LOCAL0 },
73         { "local1",     LOG_LOCAL1 },
74         { "local2",     LOG_LOCAL2 },
75         { "local3",     LOG_LOCAL3 },
76         { "local4",     LOG_LOCAL4 },
77         { "local5",     LOG_LOCAL5 },
78         { "local6",     LOG_LOCAL6 },
79         { "local7",     LOG_LOCAL7 },
80         { NULL,         -1 }
81 };
82 #endif /* LOG_NFACILITIES */
83
84 static struct strmap priorities[] = {
85         { "alert",      LOG_ALERT },
86         { "crit",       LOG_CRIT },
87         { "debug",      LOG_DEBUG },
88         { "emerg",      LOG_EMERG },
89         { "err",        LOG_ERR },
90         { "info",       LOG_INFO },
91         { "notice",     LOG_NOTICE },
92         { "warning",    LOG_WARNING },
93         { NULL,         -1 }
94 };
95
96 /*
97  * Local prototypes.
98  */
99 static int store_int __P((char *, struct sudo_defs_types *, int));
100 static int store_list __P((char *, struct sudo_defs_types *, int));
101 static int store_mode __P((char *, struct sudo_defs_types *, int));
102 static int store_str __P((char *, struct sudo_defs_types *, int));
103 static int store_syslogfac __P((char *, struct sudo_defs_types *, int));
104 static int store_syslogpri __P((char *, struct sudo_defs_types *, int));
105 static int store_tuple __P((char *, struct sudo_defs_types *, int));
106 static int store_uint __P((char *, struct sudo_defs_types *, int));
107 static void list_op __P((char *, size_t, struct sudo_defs_types *, enum list_ops));
108 static const char *logfac2str __P((int));
109 static const char *logpri2str __P((int));
110
111 /*
112  * Table describing compile-time and run-time options.
113  */
114 #include <def_data.c>
115
116 /*
117  * Print version and configure info.
118  */
119 void
120 dump_defaults()
121 {
122     struct sudo_defs_types *cur;
123     struct list_member *item;
124     struct def_values *def;
125
126     for (cur = sudo_defs_table; cur->name; cur++) {
127         if (cur->desc) {
128             switch (cur->type & T_MASK) {
129                 case T_FLAG:
130                     if (cur->sd_un.flag)
131                         puts(cur->desc);
132                     break;
133                 case T_STR:
134                     if (cur->sd_un.str) {
135                         (void) printf(cur->desc, cur->sd_un.str);
136                         putchar('\n');
137                     }
138                     break;
139                 case T_LOGFAC:
140                     if (cur->sd_un.ival) {
141                         (void) printf(cur->desc, logfac2str(cur->sd_un.ival));
142                         putchar('\n');
143                     }
144                     break;
145                 case T_LOGPRI:
146                     if (cur->sd_un.ival) {
147                         (void) printf(cur->desc, logpri2str(cur->sd_un.ival));
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                 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_MODE:
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_mode(val, cur, op)) {
306                 warningx("value `%s' is invalid for option `%s'", val, var);
307                 return(FALSE);
308             }
309             break;
310         case T_FLAG:
311             if (val) {
312                 warningx("option `%s' does not take a value", var);
313                 return(FALSE);
314             }
315             cur->sd_un.flag = op;
316
317             /* Special action for I_FQDN.  Move to own switch if we get more */
318             if (num == I_FQDN && op)
319                 set_fqdn();
320             break;
321         case T_LIST:
322             if (!val) {
323                 /* Check for bogus boolean usage or lack of a value. */
324                 if (!ISSET(cur->type, T_BOOL) || op != FALSE) {
325                     warningx("no value specified for `%s'", var);
326                     return(FALSE);
327                 }
328             }
329             if (!store_list(val, cur, op)) {
330                 warningx("value `%s' is invalid for option `%s'", val, var);
331                 return(FALSE);
332             }
333             break;
334         case T_TUPLE:
335             if (!val && !ISSET(cur->type, T_BOOL)) {
336                 warningx("no value specified for `%s'", var);
337                 return(FALSE);
338             }
339             if (!store_tuple(val, cur, op)) {
340                 warningx("value `%s' is invalid for option `%s'", val, var);
341                 return(FALSE);
342             }
343             break;
344     }
345
346     return(TRUE);
347 }
348
349 /*
350  * Set default options to compiled-in values.
351  * Any of these may be overridden at runtime by a "Defaults" file.
352  */
353 void
354 init_defaults()
355 {
356     static int firsttime = 1;
357     struct sudo_defs_types *def;
358
359     /* Clear any old settings. */
360     if (!firsttime) {
361         for (def = sudo_defs_table; def->name; def++) {
362             switch (def->type & T_MASK) {
363                 case T_STR:
364                     efree(def->sd_un.str);
365                     def->sd_un.str = NULL;
366                     break;
367                 case T_LIST:
368                     list_op(NULL, 0, def, freeall);
369                     break;
370             }
371             zero_bytes(&def->sd_un, sizeof(def->sd_un));
372         }
373     }
374
375     /* First initialize the flags. */
376 #ifdef LONG_OTP_PROMPT
377     def_long_otp_prompt = TRUE;
378 #endif
379 #ifdef IGNORE_DOT_PATH
380     def_ignore_dot = TRUE;
381 #endif
382 #ifdef ALWAYS_SEND_MAIL
383     def_mail_always = TRUE;
384 #endif
385 #ifdef SEND_MAIL_WHEN_NO_USER
386     def_mail_no_user = TRUE;
387 #endif
388 #ifdef SEND_MAIL_WHEN_NO_HOST
389     def_mail_no_host = TRUE;
390 #endif
391 #ifdef SEND_MAIL_WHEN_NOT_OK
392     def_mail_no_perms = TRUE;
393 #endif
394 #ifdef USE_TTY_TICKETS
395     def_tty_tickets = TRUE;
396 #endif
397 #ifndef NO_LECTURE
398     def_lecture = once;
399 #endif
400 #ifndef NO_AUTHENTICATION
401     def_authenticate = TRUE;
402 #endif
403 #ifndef NO_ROOT_SUDO
404     def_root_sudo = TRUE;
405 #endif
406 #ifdef HOST_IN_LOG
407     def_log_host = TRUE;
408 #endif
409 #ifdef SHELL_IF_NO_ARGS
410     def_shell_noargs = TRUE;
411 #endif
412 #ifdef SHELL_SETS_HOME
413     def_set_home = TRUE;
414 #endif
415 #ifndef DONT_LEAK_PATH_INFO
416     def_path_info = TRUE;
417 #endif
418 #ifdef FQDN
419     def_fqdn = TRUE;
420 #endif
421 #ifdef USE_INSULTS
422     def_insults = TRUE;
423 #endif
424 #ifdef ENV_EDITOR
425     def_env_editor = TRUE;
426 #endif
427 #ifdef _PATH_SUDO_ASKPASS
428     def_askpass = estrdup(_PATH_SUDO_ASKPASS);
429 #endif
430     def_sudoers_locale = estrdup("C");
431     def_env_reset = TRUE;
432     def_set_logname = TRUE;
433     def_closefrom = STDERR_FILENO + 1;
434
435     /* Syslog options need special care since they both strings and ints */
436 #if (LOGGING & SLOG_SYSLOG)
437     (void) store_syslogfac(LOGFAC, &sudo_defs_table[I_SYSLOG], TRUE);
438     (void) store_syslogpri(PRI_SUCCESS, &sudo_defs_table[I_SYSLOG_GOODPRI],
439         TRUE);
440     (void) store_syslogpri(PRI_FAILURE, &sudo_defs_table[I_SYSLOG_BADPRI],
441         TRUE);
442 #endif
443
444     /* Password flags also have a string and integer component. */
445     (void) store_tuple("any", &sudo_defs_table[I_LISTPW], TRUE);
446     (void) store_tuple("all", &sudo_defs_table[I_VERIFYPW], TRUE);
447
448     /* Then initialize the int-like things. */
449 #ifdef SUDO_UMASK
450     def_umask = SUDO_UMASK;
451 #else
452     def_umask = 0777;
453 #endif
454     def_loglinelen = MAXLOGFILELEN;
455     def_timestamp_timeout = TIMEOUT;
456     def_passwd_timeout = PASSWORD_TIMEOUT;
457     def_passwd_tries = TRIES_FOR_PASSWORD;
458
459     /* Now do the strings */
460     def_mailto = estrdup(MAILTO);
461     def_mailsub = estrdup(MAILSUBJECT);
462     def_badpass_message = estrdup(INCORRECT_PASSWORD);
463     def_timestampdir = estrdup(_PATH_SUDO_TIMEDIR);
464     def_passprompt = estrdup(PASSPROMPT);
465     def_runas_default = estrdup(RUNAS_DEFAULT);
466 #ifdef _PATH_SUDO_SENDMAIL
467     def_mailerpath = estrdup(_PATH_SUDO_SENDMAIL);
468     def_mailerflags = estrdup("-t");
469 #endif
470 #if (LOGGING & SLOG_FILE)
471     def_logfile = estrdup(_PATH_SUDO_LOGFILE);
472 #endif
473 #ifdef EXEMPTGROUP
474     def_exempt_group = estrdup(EXEMPTGROUP);
475 #endif
476 #ifdef SECURE_PATH
477     def_secure_path = estrdup(SECURE_PATH);
478 #endif
479     def_editor = estrdup(EDITOR);
480 #ifdef _PATH_SUDO_NOEXEC
481     def_noexec_file = estrdup(_PATH_SUDO_NOEXEC);
482 #endif
483
484     /* Finally do the lists (currently just environment tables). */
485     init_envtables();
486
487     firsttime = 0;
488 }
489
490 /*
491  * Update the defaults based on what was set by sudoers.
492  * Pass in a an OR'd list of which default types to update.
493  */
494 int
495 update_defaults(what)
496     int what;
497 {
498     struct defaults *def;
499
500     tq_foreach_fwd(&defaults, def) {
501         switch (def->type) {
502             case DEFAULTS:
503                 if (ISSET(what, SETDEF_GENERIC) &&
504                     !set_default(def->var, def->val, def->op))
505                     return(FALSE);
506                 break;
507             case DEFAULTS_USER:
508                 if (ISSET(what, SETDEF_USER) &&
509                     userlist_matches(sudo_user.pw, &def->binding) == ALLOW &&
510                     !set_default(def->var, def->val, def->op))
511                     return(FALSE);
512                 break;
513             case DEFAULTS_RUNAS:
514                 if (ISSET(what, SETDEF_RUNAS) &&
515                     runaslist_matches(&def->binding, NULL) == ALLOW &&
516                     !set_default(def->var, def->val, def->op))
517                     return(FALSE);
518                 break;
519             case DEFAULTS_HOST:
520                 if (ISSET(what, SETDEF_HOST) &&
521                     hostlist_matches(&def->binding) == ALLOW &&
522                     !set_default(def->var, def->val, def->op))
523                     return(FALSE);
524                 break;
525             case DEFAULTS_CMND:
526                 if (ISSET(what, SETDEF_CMND) &&
527                     cmndlist_matches(&def->binding) == ALLOW &&
528                     !set_default(def->var, def->val, def->op))
529                     return(FALSE);
530                 break;
531         }
532     }
533     return(TRUE);
534 }
535
536 static int
537 store_int(val, def, op)
538     char *val;
539     struct sudo_defs_types *def;
540     int op;
541 {
542     char *endp;
543     long l;
544
545     if (op == FALSE) {
546         def->sd_un.ival = 0;
547     } else {
548         l = strtol(val, &endp, 10);
549         if (*endp != '\0')
550             return(FALSE);
551         /* XXX - should check against INT_MAX */
552         def->sd_un.ival = (unsigned int)l;
553     }
554     if (def->callback)
555         return(def->callback(val));
556     return(TRUE);
557 }
558
559 static int
560 store_uint(val, def, op)
561     char *val;
562     struct sudo_defs_types *def;
563     int op;
564 {
565     char *endp;
566     long l;
567
568     if (op == FALSE) {
569         def->sd_un.ival = 0;
570     } else {
571         l = strtol(val, &endp, 10);
572         if (*endp != '\0' || l < 0)
573             return(FALSE);
574         /* XXX - should check against INT_MAX */
575         def->sd_un.ival = (unsigned int)l;
576     }
577     if (def->callback)
578         return(def->callback(val));
579     return(TRUE);
580 }
581
582 static int
583 store_tuple(val, def, op)
584     char *val;
585     struct sudo_defs_types *def;
586     int op;
587 {
588     struct def_values *v;
589
590     /*
591      * Since enums are really just ints we store the value as an ival.
592      * In the future, there may be multiple enums for different tuple
593      * types we want to avoid and special knowledge of the tuple type.
594      * This does assume that the first entry in the tuple enum will
595      * be the equivalent to a boolean "false".
596      */
597     if (!val) {
598         def->sd_un.ival = (op == FALSE) ? 0 : 1;
599     } else {
600         for (v = def->values; v->sval != NULL; v++) {
601             if (strcmp(v->sval, val) == 0) {
602                 def->sd_un.ival = v->ival;
603                 break;
604             }
605         }
606         if (v->sval == NULL)
607             return(FALSE);
608     }
609     if (def->callback)
610         return(def->callback(val));
611     return(TRUE);
612 }
613
614 static int
615 store_str(val, def, op)
616     char *val;
617     struct sudo_defs_types *def;
618     int op;
619 {
620
621     efree(def->sd_un.str);
622     if (op == FALSE)
623         def->sd_un.str = NULL;
624     else
625         def->sd_un.str = estrdup(val);
626     if (def->callback)
627         return(def->callback(val));
628     return(TRUE);
629 }
630
631 static int
632 store_list(str, def, op)
633     char *str;
634     struct sudo_defs_types *def;
635     int op;
636 {
637     char *start, *end;
638
639     /* Remove all old members. */
640     if (op == FALSE || op == TRUE)
641         list_op(NULL, 0, def, freeall);
642
643     /* Split str into multiple space-separated words and act on each one. */
644     if (op != FALSE) {
645         end = str;
646         do {
647             /* Remove leading blanks, if nothing but blanks we are done. */
648             for (start = end; isblank(*start); start++)
649                 ;
650             if (*start == '\0')
651                 break;
652
653             /* Find end position and perform operation. */
654             for (end = start; *end && !isblank(*end); end++)
655                 ;
656             list_op(start, end - start, def, op == '-' ? delete : add);
657         } while (*end++ != '\0');
658     }
659     return(TRUE);
660 }
661
662 static int
663 store_syslogfac(val, def, op)
664     char *val;
665     struct sudo_defs_types *def;
666     int op;
667 {
668     struct strmap *fac;
669
670     if (op == FALSE) {
671         def->sd_un.ival = FALSE;
672         return(TRUE);
673     }
674 #ifdef LOG_NFACILITIES
675     if (!val)
676         return(FALSE);
677     for (fac = facilities; fac->name && strcmp(val, fac->name); fac++)
678         ;
679     if (fac->name == NULL)
680         return(FALSE);                          /* not found */
681
682     def->sd_un.ival = fac->num;
683 #else
684     def->sd_un.ival = -1;
685 #endif /* LOG_NFACILITIES */
686     return(TRUE);
687 }
688
689 static const char *
690 logfac2str(n)
691     int n;
692 {
693 #ifdef LOG_NFACILITIES
694     struct strmap *fac;
695
696     for (fac = facilities; fac->name && fac->num != n; fac++)
697         ;
698     return(fac->name);
699 #else
700     return("default");
701 #endif /* LOG_NFACILITIES */
702 }
703
704 static int
705 store_syslogpri(val, def, op)
706     char *val;
707     struct sudo_defs_types *def;
708     int op;
709 {
710     struct strmap *pri;
711
712     if (op == FALSE || !val)
713         return(FALSE);
714
715     for (pri = priorities; pri->name && strcmp(val, pri->name); pri++)
716         ;
717     if (pri->name == NULL)
718         return(FALSE);                          /* not found */
719
720     def->sd_un.ival = pri->num;
721     return(TRUE);
722 }
723
724 static const char *
725 logpri2str(n)
726     int n;
727 {
728     struct strmap *pri;
729
730     for (pri = priorities; pri->name && pri->num != n; pri++)
731         ;
732     return(pri->name);
733 }
734
735 static int
736 store_mode(val, def, op)
737     char *val;
738     struct sudo_defs_types *def;
739     int op;
740 {
741     char *endp;
742     long l;
743
744     if (op == FALSE) {
745         def->sd_un.mode = (mode_t)0777;
746     } else {
747         l = strtol(val, &endp, 8);
748         if (*endp != '\0' || l < 0 || l > 0777)
749             return(FALSE);
750         def->sd_un.mode = (mode_t)l;
751     }
752     if (def->callback)
753         return(def->callback(val));
754     return(TRUE);
755 }
756
757 static void
758 list_op(val, len, def, op)
759     char *val;
760     size_t len;
761     struct sudo_defs_types *def;
762     enum list_ops op;
763 {
764     struct list_member *cur, *prev, *tmp;
765
766     if (op == freeall) {
767         for (cur = def->sd_un.list; cur; ) {
768             tmp = cur;
769             cur = tmp->next;
770             efree(tmp->value);
771             efree(tmp);
772         }
773         def->sd_un.list = NULL;
774         return;
775     }
776
777     for (cur = def->sd_un.list, prev = NULL; cur; prev = cur, cur = cur->next) {
778         if ((strncmp(cur->value, val, len) == 0 && cur->value[len] == '\0')) {
779
780             if (op == add)
781                 return;                 /* already exists */
782
783             /* Delete node */
784             if (prev != NULL)
785                 prev->next = cur->next;
786             else
787                 def->sd_un.list = cur->next;
788             efree(cur->value);
789             efree(cur);
790             break;
791         }
792     }
793
794     /* Add new node to the head of the list. */
795     if (op == add) {
796         cur = emalloc(sizeof(struct list_member));
797         cur->value = emalloc(len + 1);
798         (void) memcpy(cur->value, val, len);
799         cur->value[len] = '\0';
800         cur->next = def->sd_un.list;
801         def->sd_un.list = cur;
802     }
803 }