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