Imported Upstream version 1.6.8p5
[debian/sudo] / defaults.c
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
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                     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
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
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
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
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
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
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 *
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
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 *
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
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
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 }