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 */
54struct strmap {
55    char *name;
56    int num;
57};
58
59#ifdef LOG_NFACILITIES
60static 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
79static 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 */
94static int store_int __P((char *, struct sudo_defs_types *, int));
95static int store_list __P((char *, struct sudo_defs_types *, int));
96static int store_mode __P((char *, struct sudo_defs_types *, int));
97static int store_str __P((char *, struct sudo_defs_types *, int));
98static int store_syslogfac __P((char *, struct sudo_defs_types *, int));
99static int store_syslogpri __P((char *, struct sudo_defs_types *, int));
100static int store_tuple __P((char *, struct sudo_defs_types *, int));
101static int store_uint __P((char *, struct sudo_defs_types *, int));
102static int store_float __P((char *, struct sudo_defs_types *, int));
103static void list_op __P((char *, size_t, struct sudo_defs_types *, enum list_ops));
104static const char *logfac2str __P((int));
105static 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 */
115void
116dump_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 */
184void
185list_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 */
217int
218set_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 */
362void
363init_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 = FALSE;
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#ifdef _PATH_SUDO_IO_LOGDIR
443    def_iolog_dir = estrdup(_PATH_SUDO_IO_LOGDIR);
444#endif
445    def_sudoers_locale = estrdup("C");
446    def_env_reset = ENV_RESET;
447    def_set_logname = TRUE;
448    def_closefrom = STDERR_FILENO + 1;
449
450    /* Syslog options need special care since they both strings and ints */
451#if (LOGGING & SLOG_SYSLOG)
452    (void) store_syslogfac(LOGFAC, &sudo_defs_table[I_SYSLOG], TRUE);
453    (void) store_syslogpri(PRI_SUCCESS, &sudo_defs_table[I_SYSLOG_GOODPRI],
454	TRUE);
455    (void) store_syslogpri(PRI_FAILURE, &sudo_defs_table[I_SYSLOG_BADPRI],
456	TRUE);
457#endif
458
459    /* Password flags also have a string and integer component. */
460    (void) store_tuple("any", &sudo_defs_table[I_LISTPW], TRUE);
461    (void) store_tuple("all", &sudo_defs_table[I_VERIFYPW], TRUE);
462
463    /* Then initialize the int-like things. */
464#ifdef SUDO_UMASK
465    def_umask = SUDO_UMASK;
466#else
467    def_umask = 0777;
468#endif
469    def_loglinelen = MAXLOGFILELEN;
470    def_timestamp_timeout = TIMEOUT;
471    def_passwd_timeout = PASSWORD_TIMEOUT;
472    def_passwd_tries = TRIES_FOR_PASSWORD;
473#ifdef HAVE_ZLIB_H
474    def_compress_io = TRUE;
475#endif
476
477    /* Now do the strings */
478    def_mailto = estrdup(MAILTO);
479    def_mailsub = estrdup(MAILSUBJECT);
480    def_badpass_message = estrdup(INCORRECT_PASSWORD);
481    def_timestampdir = estrdup(_PATH_SUDO_TIMEDIR);
482    def_passprompt = estrdup(PASSPROMPT);
483    def_runas_default = estrdup(RUNAS_DEFAULT);
484#ifdef _PATH_SUDO_SENDMAIL
485    def_mailerpath = estrdup(_PATH_SUDO_SENDMAIL);
486    def_mailerflags = estrdup("-t");
487#endif
488#if (LOGGING & SLOG_FILE)
489    def_logfile = estrdup(_PATH_SUDO_LOGFILE);
490#endif
491#ifdef EXEMPTGROUP
492    def_exempt_group = estrdup(EXEMPTGROUP);
493#endif
494#ifdef SECURE_PATH
495    def_secure_path = estrdup(SECURE_PATH);
496#endif
497    def_editor = estrdup(EDITOR);
498#ifdef _PATH_SUDO_NOEXEC
499    def_noexec_file = estrdup(_PATH_SUDO_NOEXEC);
500#endif
501
502    /* Finally do the lists (currently just environment tables). */
503    init_envtables();
504
505    firsttime = 0;
506}
507
508/*
509 * Update the defaults based on what was set by sudoers.
510 * Pass in an OR'd list of which default types to update.
511 */
512int
513update_defaults(what)
514    int what;
515{
516    struct defaults *def;
517    int rc = TRUE;
518
519    tq_foreach_fwd(&defaults, def) {
520	switch (def->type) {
521	    case DEFAULTS:
522		if (ISSET(what, SETDEF_GENERIC) &&
523		    !set_default(def->var, def->val, def->op))
524		    rc = FALSE;
525		break;
526	    case DEFAULTS_USER:
527		if (ISSET(what, SETDEF_USER) &&
528		    userlist_matches(sudo_user.pw, &def->binding) == ALLOW &&
529		    !set_default(def->var, def->val, def->op))
530		    rc = FALSE;
531		break;
532	    case DEFAULTS_RUNAS:
533		if (ISSET(what, SETDEF_RUNAS) &&
534		    runaslist_matches(&def->binding, NULL) == ALLOW &&
535		    !set_default(def->var, def->val, def->op))
536		    rc = FALSE;
537		break;
538	    case DEFAULTS_HOST:
539		if (ISSET(what, SETDEF_HOST) &&
540		    hostlist_matches(&def->binding) == ALLOW &&
541		    !set_default(def->var, def->val, def->op))
542		    rc = FALSE;
543		break;
544	    case DEFAULTS_CMND:
545		if (ISSET(what, SETDEF_CMND) &&
546		    cmndlist_matches(&def->binding) == ALLOW &&
547		    !set_default(def->var, def->val, def->op))
548		    rc = FALSE;
549		break;
550	}
551    }
552    return rc;
553}
554
555/*
556 * Check the defaults entries without actually setting them.
557 * Pass in an OR'd list of which default types to check.
558 */
559int
560check_defaults(what, quiet)
561    int what;
562    int quiet;
563{
564    struct sudo_defs_types *cur;
565    struct defaults *def;
566    int rc = TRUE;
567
568    tq_foreach_fwd(&defaults, def) {
569	switch (def->type) {
570	    case DEFAULTS:
571		if (!ISSET(what, SETDEF_GENERIC))
572		    continue;
573		break;
574	    case DEFAULTS_USER:
575		if (!ISSET(what, SETDEF_USER))
576		    continue;
577		break;
578	    case DEFAULTS_RUNAS:
579		if (!ISSET(what, SETDEF_RUNAS))
580		    continue;
581		break;
582	    case DEFAULTS_HOST:
583		if (!ISSET(what, SETDEF_HOST))
584		    continue;
585		break;
586	    case DEFAULTS_CMND:
587		if (!ISSET(what, SETDEF_CMND))
588		    continue;
589		break;
590	}
591	for (cur = sudo_defs_table; cur->name != NULL; cur++) {
592	    if (strcmp(def->var, cur->name) == 0)
593		break;
594	}
595	if (cur->name == NULL) {
596	    if (!quiet)
597		warningx("unknown defaults entry `%s'", def->var);
598	    rc = FALSE;
599	}
600    }
601    return rc;
602}
603
604static int
605store_int(val, def, op)
606    char *val;
607    struct sudo_defs_types *def;
608    int op;
609{
610    char *endp;
611    long l;
612
613    if (op == FALSE) {
614	def->sd_un.ival = 0;
615    } else {
616	l = strtol(val, &endp, 10);
617	if (*endp != '\0')
618	    return FALSE;
619	/* XXX - should check against INT_MAX */
620	def->sd_un.ival = (int)l;
621    }
622    if (def->callback)
623	return def->callback(val);
624    return TRUE;
625}
626
627static int
628store_uint(val, def, op)
629    char *val;
630    struct sudo_defs_types *def;
631    int op;
632{
633    char *endp;
634    long l;
635
636    if (op == FALSE) {
637	def->sd_un.ival = 0;
638    } else {
639	l = strtol(val, &endp, 10);
640	if (*endp != '\0' || l < 0)
641	    return FALSE;
642	/* XXX - should check against INT_MAX */
643	def->sd_un.ival = (unsigned int)l;
644    }
645    if (def->callback)
646	return def->callback(val);
647    return TRUE;
648}
649
650static int
651store_float(val, def, op)
652    char *val;
653    struct sudo_defs_types *def;
654    int op;
655{
656    char *endp;
657    double d;
658
659    if (op == FALSE) {
660	def->sd_un.fval = 0.0;
661    } else {
662	d = strtod(val, &endp);
663	if (*endp != '\0')
664	    return FALSE;
665	/* XXX - should check against HUGE_VAL */
666	def->sd_un.fval = d;
667    }
668    if (def->callback)
669	return def->callback(val);
670    return TRUE;
671}
672
673static int
674store_tuple(val, def, op)
675    char *val;
676    struct sudo_defs_types *def;
677    int op;
678{
679    struct def_values *v;
680
681    /*
682     * Since enums are really just ints we store the value as an ival.
683     * In the future, there may be multiple enums for different tuple
684     * types we want to avoid and special knowledge of the tuple type.
685     * This does assume that the first entry in the tuple enum will
686     * be the equivalent to a boolean "false".
687     */
688    if (!val) {
689	def->sd_un.ival = (op == FALSE) ? 0 : 1;
690    } else {
691	for (v = def->values; v->sval != NULL; v++) {
692	    if (strcmp(v->sval, val) == 0) {
693		def->sd_un.ival = v->ival;
694		break;
695	    }
696	}
697	if (v->sval == NULL)
698	    return FALSE;
699    }
700    if (def->callback)
701	return def->callback(val);
702    return TRUE;
703}
704
705static int
706store_str(val, def, op)
707    char *val;
708    struct sudo_defs_types *def;
709    int op;
710{
711
712    efree(def->sd_un.str);
713    if (op == FALSE)
714	def->sd_un.str = NULL;
715    else
716	def->sd_un.str = estrdup(val);
717    if (def->callback)
718	return def->callback(val);
719    return TRUE;
720}
721
722static int
723store_list(str, def, op)
724    char *str;
725    struct sudo_defs_types *def;
726    int op;
727{
728    char *start, *end;
729
730    /* Remove all old members. */
731    if (op == FALSE || op == TRUE)
732	list_op(NULL, 0, def, freeall);
733
734    /* Split str into multiple space-separated words and act on each one. */
735    if (op != FALSE) {
736	end = str;
737	do {
738	    /* Remove leading blanks, if nothing but blanks we are done. */
739	    for (start = end; isblank((unsigned char)*start); start++)
740		;
741	    if (*start == '\0')
742		break;
743
744	    /* Find end position and perform operation. */
745	    for (end = start; *end && !isblank((unsigned char)*end); end++)
746		;
747	    list_op(start, end - start, def, op == '-' ? delete : add);
748	} while (*end++ != '\0');
749    }
750    return TRUE;
751}
752
753static int
754store_syslogfac(val, def, op)
755    char *val;
756    struct sudo_defs_types *def;
757    int op;
758{
759    struct strmap *fac;
760
761    if (op == FALSE) {
762	def->sd_un.ival = FALSE;
763	return TRUE;
764    }
765#ifdef LOG_NFACILITIES
766    if (!val)
767	return FALSE;
768    for (fac = facilities; fac->name && strcmp(val, fac->name); fac++)
769	;
770    if (fac->name == NULL)
771	return FALSE;				/* not found */
772
773    def->sd_un.ival = fac->num;
774#else
775    def->sd_un.ival = -1;
776#endif /* LOG_NFACILITIES */
777    return TRUE;
778}
779
780static const char *
781logfac2str(n)
782    int n;
783{
784#ifdef LOG_NFACILITIES
785    struct strmap *fac;
786
787    for (fac = facilities; fac->name && fac->num != n; fac++)
788	;
789    return fac->name;
790#else
791    return "default";
792#endif /* LOG_NFACILITIES */
793}
794
795static int
796store_syslogpri(val, def, op)
797    char *val;
798    struct sudo_defs_types *def;
799    int op;
800{
801    struct strmap *pri;
802
803    if (op == FALSE || !val)
804	return FALSE;
805
806    for (pri = priorities; pri->name && strcmp(val, pri->name); pri++)
807	;
808    if (pri->name == NULL)
809	return FALSE;				/* not found */
810
811    def->sd_un.ival = pri->num;
812    return TRUE;
813}
814
815static const char *
816logpri2str(n)
817    int n;
818{
819    struct strmap *pri;
820
821    for (pri = priorities; pri->name && pri->num != n; pri++)
822	;
823    return pri->name;
824}
825
826static int
827store_mode(val, def, op)
828    char *val;
829    struct sudo_defs_types *def;
830    int op;
831{
832    char *endp;
833    long l;
834
835    if (op == FALSE) {
836	def->sd_un.mode = (mode_t)0777;
837    } else {
838	l = strtol(val, &endp, 8);
839	if (*endp != '\0' || l < 0 || l > 0777)
840	    return FALSE;
841	def->sd_un.mode = (mode_t)l;
842    }
843    if (def->callback)
844	return def->callback(val);
845    return TRUE;
846}
847
848static void
849list_op(val, len, def, op)
850    char *val;
851    size_t len;
852    struct sudo_defs_types *def;
853    enum list_ops op;
854{
855    struct list_member *cur, *prev, *tmp;
856
857    if (op == freeall) {
858	for (cur = def->sd_un.list; cur; ) {
859	    tmp = cur;
860	    cur = tmp->next;
861	    efree(tmp->value);
862	    efree(tmp);
863	}
864	def->sd_un.list = NULL;
865	return;
866    }
867
868    for (cur = def->sd_un.list, prev = NULL; cur; prev = cur, cur = cur->next) {
869	if ((strncmp(cur->value, val, len) == 0 && cur->value[len] == '\0')) {
870
871	    if (op == add)
872		return;			/* already exists */
873
874	    /* Delete node */
875	    if (prev != NULL)
876		prev->next = cur->next;
877	    else
878		def->sd_un.list = cur->next;
879	    efree(cur->value);
880	    efree(cur);
881	    break;
882	}
883    }
884
885    /* Add new node to the head of the list. */
886    if (op == add) {
887	cur = ecalloc(1, sizeof(struct list_member));
888	cur->value = emalloc(len + 1);
889	(void) memcpy(cur->value, val, len);
890	cur->value[len] = '\0';
891	cur->next = def->sd_un.list;
892	def->sd_un.list = cur;
893    }
894}
895