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