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