Imported Upstream version 1.6.9p6
[debian/sudo] / defaults.c
1 /*
2  * Copyright (c) 1999-2005 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 __unused static const char rcsid[] = "$Sudo: defaults.c,v 1.48.2.5 2007/06/18 15:51:35 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
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
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
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
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                     efree(def->sd_un.str);
379                     def->sd_un.str = NULL;
380                     break;
381                 case T_LIST:
382                     list_op(NULL, 0, def, freeall);
383                     break;
384             }
385     }
386
387     /* First initialize the flags. */
388 #ifdef LONG_OTP_PROMPT
389     def_long_otp_prompt = TRUE;
390 #endif
391 #ifdef IGNORE_DOT_PATH
392     def_ignore_dot = TRUE;
393 #endif
394 #ifdef ALWAYS_SEND_MAIL
395     def_mail_always = TRUE;
396 #endif
397 #ifdef SEND_MAIL_WHEN_NO_USER
398     def_mail_no_user = TRUE;
399 #endif
400 #ifdef SEND_MAIL_WHEN_NO_HOST
401     def_mail_no_host = TRUE;
402 #endif
403 #ifdef SEND_MAIL_WHEN_NOT_OK
404     def_mail_no_perms = TRUE;
405 #endif
406 #ifdef USE_TTY_TICKETS
407     def_tty_tickets = TRUE;
408 #endif
409 #ifndef NO_LECTURE
410     def_lecture = once;
411 #endif
412 #ifndef NO_AUTHENTICATION
413     def_authenticate = TRUE;
414 #endif
415 #ifndef NO_ROOT_SUDO
416     def_root_sudo = TRUE;
417 #endif
418 #ifdef HOST_IN_LOG
419     def_log_host = TRUE;
420 #endif
421 #ifdef SHELL_IF_NO_ARGS
422     def_shell_noargs = TRUE;
423 #endif
424 #ifdef SHELL_SETS_HOME
425     def_set_home = TRUE;
426 #endif
427 #ifndef DONT_LEAK_PATH_INFO
428     def_path_info = TRUE;
429 #endif
430 #ifdef FQDN
431     def_fqdn = TRUE;
432 #endif
433 #ifdef USE_INSULTS
434     def_insults = TRUE;
435 #endif
436 #ifdef ENV_EDITOR
437     def_env_editor = TRUE;
438 #endif
439     def_env_reset = TRUE;
440     def_set_logname = TRUE;
441
442     /* Syslog options need special care since they both strings and ints */
443 #if (LOGGING & SLOG_SYSLOG)
444     (void) store_syslogfac(LOGFAC, &sudo_defs_table[I_SYSLOG], TRUE);
445     (void) store_syslogpri(PRI_SUCCESS, &sudo_defs_table[I_SYSLOG_GOODPRI],
446         TRUE);
447     (void) store_syslogpri(PRI_FAILURE, &sudo_defs_table[I_SYSLOG_BADPRI],
448         TRUE);
449 #endif
450
451     /* Password flags also have a string and integer component. */
452     (void) store_tuple("any", &sudo_defs_table[I_LISTPW], TRUE);
453     (void) store_tuple("all", &sudo_defs_table[I_VERIFYPW], TRUE);
454
455     /* Then initialize the int-like things. */
456 #ifdef SUDO_UMASK
457     def_umask = SUDO_UMASK;
458 #else
459     def_umask = 0777;
460 #endif
461     def_loglinelen = MAXLOGFILELEN;
462     def_timestamp_timeout = TIMEOUT;
463     def_passwd_timeout = PASSWORD_TIMEOUT;
464     def_passwd_tries = TRIES_FOR_PASSWORD;
465
466     /* Now do the strings */
467     def_mailto = estrdup(MAILTO);
468     def_mailsub = estrdup(MAILSUBJECT);
469     def_badpass_message = estrdup(INCORRECT_PASSWORD);
470     def_timestampdir = estrdup(_PATH_SUDO_TIMEDIR);
471     def_passprompt = estrdup(PASSPROMPT);
472     def_runas_default = estrdup(RUNAS_DEFAULT);
473 #ifdef _PATH_SUDO_SENDMAIL
474     def_mailerpath = estrdup(_PATH_SUDO_SENDMAIL);
475     def_mailerflags = estrdup("-t");
476 #endif
477 #if (LOGGING & SLOG_FILE)
478     def_logfile = estrdup(_PATH_SUDO_LOGFILE);
479 #endif
480 #ifdef EXEMPTGROUP
481     def_exempt_group = estrdup(EXEMPTGROUP);
482 #endif
483     def_editor = estrdup(EDITOR);
484 #ifdef _PATH_SUDO_NOEXEC
485     def_noexec_file = estrdup(_PATH_SUDO_NOEXEC);
486 #endif
487
488     /* Finally do the lists (currently just environment tables). */
489     init_envtables();
490
491     /*
492      * The following depend on the above values.
493      * We use a pointer to the string so that if its
494      * value changes we get the change.
495      */
496     if (user_runas == NULL)
497         user_runas = &def_runas_default;
498
499     firsttime = 0;
500 }
501
502 static int
503 store_int(val, def, op)
504     char *val;
505     struct sudo_defs_types *def;
506     int op;
507 {
508     char *endp;
509     long l;
510
511     if (op == FALSE) {
512         def->sd_un.ival = 0;
513     } else {
514         l = strtol(val, &endp, 10);
515         if (*endp != '\0')
516             return(FALSE);
517         /* XXX - should check against INT_MAX */
518         def->sd_un.ival = (unsigned int)l;
519     }
520     if (def->callback)
521         return(def->callback(val));
522     return(TRUE);
523 }
524
525 static int
526 store_uint(val, def, op)
527     char *val;
528     struct sudo_defs_types *def;
529     int op;
530 {
531     char *endp;
532     long l;
533
534     if (op == FALSE) {
535         def->sd_un.ival = 0;
536     } else {
537         l = strtol(val, &endp, 10);
538         if (*endp != '\0' || l < 0)
539             return(FALSE);
540         /* XXX - should check against INT_MAX */
541         def->sd_un.ival = (unsigned int)l;
542     }
543     if (def->callback)
544         return(def->callback(val));
545     return(TRUE);
546 }
547
548 static int
549 store_tuple(val, def, op)
550     char *val;
551     struct sudo_defs_types *def;
552     int op;
553 {
554     struct def_values *v;
555
556     /*
557      * Since enums are really just ints we store the value as an ival.
558      * In the future, there may be multiple enums for different tuple
559      * types we want to avoid and special knowledge of the tuple type.
560      * This does assume that the first entry in the tuple enum will
561      * be the equivalent to a boolean "false".
562      */
563     if (!val) {
564         def->sd_un.ival = (op == FALSE) ? 0 : 1;
565     } else {
566         for (v = def->values; v->sval != NULL; v++) {
567             if (strcmp(v->sval, val) == 0) {
568                 def->sd_un.ival = v->ival;
569                 break;
570             }
571         }
572         if (v->sval == NULL)
573             return(FALSE);
574     }
575     if (def->callback)
576         return(def->callback(val));
577     return(TRUE);
578 }
579
580 static int
581 store_str(val, def, op)
582     char *val;
583     struct sudo_defs_types *def;
584     int op;
585 {
586
587     efree(def->sd_un.str);
588     if (op == FALSE)
589         def->sd_un.str = NULL;
590     else
591         def->sd_un.str = estrdup(val);
592     if (def->callback)
593         return(def->callback(val));
594     return(TRUE);
595 }
596
597 static int
598 store_list(str, def, op)
599     char *str;
600     struct sudo_defs_types *def;
601     int op;
602 {
603     char *start, *end;
604
605     /* Remove all old members. */
606     if (op == FALSE || op == TRUE)
607         list_op(NULL, 0, def, freeall);
608
609     /* Split str into multiple space-separated words and act on each one. */
610     if (op != FALSE) {
611         end = str;
612         do {
613             /* Remove leading blanks, if nothing but blanks we are done. */
614             for (start = end; isblank(*start); start++)
615                 ;
616             if (*start == '\0')
617                 break;
618
619             /* Find end position and perform operation. */
620             for (end = start; *end && !isblank(*end); end++)
621                 ;
622             list_op(start, end - start, def, op == '-' ? delete : add);
623         } while (*end++ != '\0');
624     }
625     return(TRUE);
626 }
627
628 static int
629 store_syslogfac(val, def, op)
630     char *val;
631     struct sudo_defs_types *def;
632     int op;
633 {
634     struct strmap *fac;
635
636     if (op == FALSE) {
637         def->sd_un.ival = FALSE;
638         return(TRUE);
639     }
640 #ifdef LOG_NFACILITIES
641     if (!val)
642         return(FALSE);
643     for (fac = facilities; fac->name && strcmp(val, fac->name); fac++)
644         ;
645     if (fac->name == NULL)
646         return(FALSE);                          /* not found */
647
648     def->sd_un.ival = fac->num;
649 #else
650     def->sd_un.ival = -1;
651 #endif /* LOG_NFACILITIES */
652     return(TRUE);
653 }
654
655 static const char *
656 logfac2str(n)
657     int n;
658 {
659 #ifdef LOG_NFACILITIES
660     struct strmap *fac;
661
662     for (fac = facilities; fac->name && fac->num != n; fac++)
663         ;
664     return (fac->name);
665 #else
666     return ("default");
667 #endif /* LOG_NFACILITIES */
668 }
669
670 static int
671 store_syslogpri(val, def, op)
672     char *val;
673     struct sudo_defs_types *def;
674     int op;
675 {
676     struct strmap *pri;
677
678     if (op == FALSE || !val)
679         return(FALSE);
680
681     for (pri = priorities; pri->name && strcmp(val, pri->name); pri++)
682         ;
683     if (pri->name == NULL)
684         return(FALSE);                          /* not found */
685
686     def->sd_un.ival = pri->num;
687     return(TRUE);
688 }
689
690 static const char *
691 logpri2str(n)
692     int n;
693 {
694     struct strmap *pri;
695
696     for (pri = priorities; pri->name && pri->num != n; pri++)
697         ;
698     return (pri->name);
699 }
700
701 static int
702 store_mode(val, def, op)
703     char *val;
704     struct sudo_defs_types *def;
705     int op;
706 {
707     char *endp;
708     long l;
709
710     if (op == FALSE) {
711         def->sd_un.mode = (mode_t)0777;
712     } else {
713         l = strtol(val, &endp, 8);
714         if (*endp != '\0' || l < 0 || l > 0777)
715             return(FALSE);
716         def->sd_un.mode = (mode_t)l;
717     }
718     if (def->callback)
719         return(def->callback(val));
720     return(TRUE);
721 }
722
723 static void
724 list_op(val, len, def, op)
725     char *val;
726     size_t len;
727     struct sudo_defs_types *def;
728     enum list_ops op;
729 {
730     struct list_member *cur, *prev, *tmp;
731
732     if (op == freeall) {
733         for (cur = def->sd_un.list; cur; ) {
734             tmp = cur;
735             cur = tmp->next;
736             efree(tmp->value);
737             efree(tmp);
738         }
739         def->sd_un.list = NULL;
740         return;
741     }
742
743     for (cur = def->sd_un.list, prev = NULL; cur; prev = cur, cur = cur->next) {
744         if ((strncmp(cur->value, val, len) == 0 && cur->value[len] == '\0')) {
745
746             if (op == add)
747                 return;                 /* already exists */
748
749             /* Delete node */
750             if (prev != NULL)
751                 prev->next = cur->next;
752             else
753                 def->sd_un.list = cur->next;
754             efree(cur->value);
755             efree(cur);
756             break;
757         }
758     }
759
760     /* Add new node to the head of the list. */
761     if (op == add) {
762         cur = emalloc(sizeof(struct list_member));
763         cur->value = emalloc(len + 1);
764         (void) memcpy(cur->value, val, len);
765         cur->value[len] = '\0';
766         cur->next = def->sd_un.list;
767         def->sd_un.list = cur;
768     }
769 }