Annotation of src/usr.bin/sudo/defaults.c, Revision 1.1.1.1
1.1 millert 1: /*
2: * Copyright (c) 1999 Todd C. Miller <Todd.Miller@courtesan.com>
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: *
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: *
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: *
16: * 3. The name of the author may not be used to endorse or promote products
17: * derived from this software without specific prior written permission.
18: *
19: * 4. Products derived from this software may not be called "Sudo" nor
20: * may "Sudo" appear in their names without specific prior written
21: * permission from the author.
22: *
23: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
25: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
26: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33: */
34:
35: #include "config.h"
36:
37: #include <stdio.h>
38: #ifdef STDC_HEADERS
39: #include <stdlib.h>
40: #endif /* STDC_HEADERS */
41: #ifdef HAVE_UNISTD_H
42: #include <unistd.h>
43: #endif /* HAVE_UNISTD_H */
44: #ifdef HAVE_STRING_H
45: #include <string.h>
46: #endif /* HAVE_STRING_H */
47: #ifdef HAVE_STRINGS_H
48: #include <strings.h>
49: #endif /* HAVE_STRINGS_H */
50: #include <sys/types.h>
51: #include <sys/param.h>
52:
53: #include "sudo.h"
54:
55: #ifndef lint
56: static const char rcsid[] = "$Sudo: defaults.c,v 1.12 1999/11/05 22:11:55 millert Exp $";
57: #endif /* lint */
58:
59: /*
60: * For converting between syslog numbers and strings.
61: */
62: struct strmap {
63: char *name;
64: int num;
65: };
66:
67: #ifdef LOG_NFACILITIES
68: static struct strmap facilities[] = {
69: #ifdef LOG_AUTHPRIV
70: { "authpriv", LOG_AUTHPRIV },
71: #endif
72: { "auth", LOG_AUTH },
73: { "daemon", LOG_DAEMON },
74: { "user", LOG_USER },
75: { "local0", LOG_LOCAL0 },
76: { "local1", LOG_LOCAL1 },
77: { "local2", LOG_LOCAL2 },
78: { "local3", LOG_LOCAL3 },
79: { "local4", LOG_LOCAL4 },
80: { "local5", LOG_LOCAL5 },
81: { "local6", LOG_LOCAL6 },
82: { "local7", LOG_LOCAL7 },
83: { NULL, -1 }
84: };
85: #endif /* LOG_NFACILITIES */
86:
87: static struct strmap priorities[] = {
88: { "alert", LOG_ALERT },
89: { "crit", LOG_CRIT },
90: { "debug", LOG_DEBUG },
91: { "emerg", LOG_EMERG },
92: { "err", LOG_ERR },
93: { "info", LOG_INFO },
94: { "notice", LOG_NOTICE },
95: { "warning", LOG_WARNING },
96: { NULL, -1 }
97: };
98:
99: extern int sudolineno;
100:
101: /*
102: * Local prototypes.
103: */
104: static int store_int __P((char *, struct sudo_defs_types *, int));
105: static int store_str __P((char *, struct sudo_defs_types *, int));
106: static int store_syslogfac __P((char *, struct sudo_defs_types *, int));
107: static int store_syslogpri __P((char *, struct sudo_defs_types *, int));
108: static int store_mode __P((char *, struct sudo_defs_types *, int));
109:
110: /*
111: * Table describing compile-time and run-time options.
112: */
113: struct sudo_defs_types sudo_defs_table[] = {
114: {
115: "syslog_ifac", T_INT, { 0 },
116: NULL
117: }, {
118: "syslog_igoodpri", T_INT, { 0 },
119: NULL
120: }, {
121: "syslog_ibadpri", T_INT, { 0 },
122: NULL
123: }, {
124: "syslog", T_LOGFAC|T_BOOL, { 0 },
125: "Syslog facility if syslog is being used for logging: %s"
126: }, {
127: "syslog_goodpri", T_LOGPRI, { 0 },
128: "Syslog priority to use when user authenticates successfully: %s"
129: }, {
130: "syslog_badpri", T_LOGPRI, { 0 },
131: "Syslog priority to use when user authenticates unsuccessfully: %s"
132: }, {
133: "long_otp_prompt", T_FLAG, { 0 },
134: "Put OTP prompt on its own line"
135: }, {
136: "ignore_dot", T_FLAG, { 0 },
137: "Ignore '.' in $PATH"
138: }, {
139: "mail_always", T_FLAG, { 0 },
140: "Always send mail when sudo is run"
141: }, {
142: "mail_no_user", T_FLAG, { 0 },
143: "Send mail if the user is not in sudoers"
144: }, {
145: "mail_no_host", T_FLAG, { 0 },
146: "Send mail if the user is not in sudoers for this host"
147: }, {
148: "mail_no_perms", T_FLAG, { 0 },
149: "Send mail if the user is not allowed to run a command"
150: }, {
151: "tty_tickets", T_FLAG, { 0 },
152: "Use a separate timestamp for each user/tty combo"
153: }, {
154: "lecture", T_FLAG, { 0 },
155: "Lecture user the first time they run sudo"
156: }, {
157: "authenticate", T_FLAG, { 0 },
158: "Require users to authenticate by default"
159: }, {
160: "root_sudo", T_FLAG, { 0 },
161: "Root may run sudo"
162: }, {
163: "log_host", T_FLAG, { 0 },
164: "Log the hostname in the (non-syslog) log file"
165: }, {
166: "log_year", T_FLAG, { 0 },
167: "Log the year in the (non-syslog) log file"
168: }, {
169: "shell_noargs", T_FLAG, { 0 },
170: "If sudo is invoked with no arguments, start a shell"
171: }, {
172: "set_home", T_FLAG, { 0 },
173: "Set $HOME to the target user when starting a shell with -s"
174: }, {
175: "path_info", T_FLAG, { 0 },
176: "Allow some information gathering to give useful error messages"
177: }, {
178: "fqdn", T_FLAG, { 0 },
179: "Require fully-qualified hsotnames in the sudoers file"
180: }, {
181: "insults", T_FLAG, { 0 },
182: "Insult the user when they enter an incorrect password"
183: }, {
184: "requiretty", T_FLAG, { 0 },
185: "Only allow the user to run sudo if they have a tty"
186: }, {
187: "loglinelen", T_INT|T_BOOL, { 0 },
188: "Length at which to wrap log file lines (0 for no wrap): %d"
189: }, {
190: "timestamp_timeout", T_INT|T_BOOL, { 0 },
191: "Authentication timestamp timeout: %d minutes"
192: }, {
193: "passwd_timeout", T_INT|T_BOOL, { 0 },
194: "Password prompt timeout: %d minutes"
195: }, {
196: "passwd_tries", T_INT, { 0 },
197: "Number of tries to enter a password: %d"
198: }, {
199: "umask", T_MODE|T_BOOL, { 0 },
200: "Umask to use or 0777 to use user's: 0%o"
201: }, {
202: "logfile", T_STR|T_BOOL|T_PATH, { 0 },
203: "Path to log file: %s"
204: }, {
205: "mailerpath", T_STR|T_BOOL|T_PATH, { 0 },
206: "Path to mail program: %s"
207: }, {
208: "mailerflags", T_STR|T_BOOL, { 0 },
209: "Flags for mail program: %s"
210: }, {
211: "mailto", T_STR|T_BOOL, { 0 },
212: "Address to send mail to: %s"
213: }, {
214: "mailsub", T_STR, { 0 },
215: "Subject line for mail messages: %s"
216: }, {
217: "badpass_message", T_STR, { 0 },
218: "Incorrect password message: %s"
219: }, {
220: "timestampdir", T_STR|T_PATH, { 0 },
221: "Path to authentication timestamp dir: %s"
222: }, {
223: "exempt_group", T_STR|T_BOOL, { 0 },
224: "Users in this group are exempt from password and PATH requirements: %s"
225: }, {
226: "passprompt", T_STR, { 0 },
227: "Default password prompt: %s"
228: }, {
229: "runas_default", T_STR, { 0 },
230: "Default user to run commands as: %s"
231: }, {
232: "secure_path", T_STR|T_BOOL, { 0 },
233: "Value to override user's $PATH with: %s"
234: }, {
235: NULL, 0, { 0 }, NULL
236: }
237: };
238:
239: /*
240: * Print version and configure info.
241: */
242: void
243: dump_defaults()
244: {
245: struct sudo_defs_types *cur;
246:
247: for (cur = sudo_defs_table; cur->name; cur++) {
248: if (cur->desc) {
249: switch (cur->type & T_MASK) {
250: case T_FLAG:
251: if (cur->sd_un.flag)
252: puts(cur->desc);
253: break;
254: case T_STR:
255: case T_LOGFAC:
256: case T_LOGPRI:
257: if (cur->sd_un.str) {
258: (void) printf(cur->desc, cur->sd_un.str);
259: putchar('\n');
260: }
261: break;
262: case T_INT:
263: (void) printf(cur->desc, cur->sd_un.ival);
264: putchar('\n');
265: break;
266: case T_MODE:
267: (void) printf(cur->desc, cur->sd_un.mode);
268: putchar('\n');
269: break;
270: }
271: }
272: }
273:
274: #ifdef ENV_EDITOR
275: (void) printf("Default editor for visudo: %s\n", EDITOR);
276: #else
277: (void) printf("Editor for visudo: %s\n", EDITOR);
278: #endif
279: }
280:
281: /*
282: * List each option along with its description.
283: */
284: void
285: list_options()
286: {
287: struct sudo_defs_types *cur;
288: char *p;
289:
290: (void) puts("Available options in a sudoers ``Defaults'' line:\n");
291: for (cur = sudo_defs_table; cur->name; cur++) {
292: if (cur->name && cur->desc) {
293: switch (cur->type & T_MASK) {
294: case T_FLAG:
295: (void) printf("%s: %s\n", cur->name, cur->desc);
296: break;
297: default:
298: p = strrchr(cur->desc, ':');
299: if (p)
300: (void) printf("%s: %.*s\n", cur->name, p - cur->desc,
301: cur->desc);
302: else
303: (void) printf("%s: %s\n", cur->name, cur->desc);
304: break;
305: }
306: }
307: }
308: }
309:
310: /*
311: * Sets/clears an entry in the defaults structure
312: * If a variable that takes a value is used in a boolean
313: * context with op == 0, disable that variable.
314: * Eg. you may want to turn off logging to a file for some hosts.
315: * This is only meaningful for variables that are *optional*.
316: */
317: int
318: set_default(var, val, op)
319: char *var;
320: char *val;
321: int op; /* TRUE or FALSE */
322: {
323: struct sudo_defs_types *cur;
324:
325: for (cur = sudo_defs_table; cur->name; cur++) {
326: if (strcmp(var, cur->name) == 0)
327: break;
328: }
329: if (!cur->name) {
330: (void) fprintf(stderr,
331: "%s: unknown defaults entry `%s' referenced near line %d\n", Argv[0],
332: var, sudolineno);
333: return(FALSE);
334: }
335:
336: switch (cur->type & T_MASK) {
337: case T_LOGFAC:
338: if (!store_syslogfac(val, cur, op)) {
339: if (val)
340: (void) fprintf(stderr,
341: "%s: value '%s' is invalid for option '%s'\n", Argv[0],
342: val, var);
343: else
344: (void) fprintf(stderr,
345: "%s: no value specified for `%s' on line %d\n", Argv[0],
346: var, sudolineno);
347: return(FALSE);
348: }
349: break;
350: case T_LOGPRI:
351: if (!store_syslogpri(val, cur, op)) {
352: if (val)
353: (void) fprintf(stderr,
354: "%s: value '%s' is invalid for option '%s'\n", Argv[0],
355: val, var);
356: else
357: (void) fprintf(stderr,
358: "%s: no value specified for `%s' on line %d\n", Argv[0],
359: var, sudolineno);
360: return(FALSE);
361: }
362: break;
363: case T_STR:
364: if (!val) {
365: /* Check for bogus boolean usage or lack of a value. */
366: if (!(cur->type & T_BOOL) || op != FALSE) {
367: (void) fprintf(stderr,
368: "%s: no value specified for `%s' on line %d\n", Argv[0],
369: var, sudolineno);
370: return(FALSE);
371: }
372: }
373: if ((cur->type & T_PATH) && *val != '/') {
374: (void) fprintf(stderr,
375: "%s: values for `%s' must start with a '/'\n", Argv[0],
376: var);
377: return(FALSE);
378: }
379: if (!store_str(val, cur, op)) {
380: (void) fprintf(stderr,
381: "%s: value '%s' is invalid for option '%s'\n", Argv[0],
382: val, var);
383: return(FALSE);
384: }
385: break;
386: case T_INT:
387: if (!val) {
388: /* Check for bogus boolean usage or lack of a value. */
389: if (!(cur->type & T_BOOL) || op != FALSE) {
390: (void) fprintf(stderr,
391: "%s: no value specified for `%s' on line %d\n", Argv[0],
392: var, sudolineno);
393: return(FALSE);
394: }
395: }
396: if (!store_int(val, cur, op)) {
397: (void) fprintf(stderr,
398: "%s: value '%s' is invalid for option '%s'\n", Argv[0],
399: val, var);
400: return(FALSE);
401: }
402: break;
403: case T_MODE:
404: if (!val) {
405: /* Check for bogus boolean usage or lack of a value. */
406: if (!(cur->type & T_BOOL) || op != FALSE) {
407: (void) fprintf(stderr,
408: "%s: no value specified for `%s' on line %d\n", Argv[0],
409: var, sudolineno);
410: return(FALSE);
411: }
412: }
413: if (!store_mode(val, cur, op)) {
414: (void) fprintf(stderr,
415: "%s: value '%s' is invalid for option '%s'\n", Argv[0],
416: val, var);
417: return(FALSE);
418: }
419: break;
420: case T_FLAG:
421: if (val) {
422: (void) fprintf(stderr,
423: "%s: option `%s' does not take a value on line %d\n",
424: Argv[0], var, sudolineno);
425: return(FALSE);
426: }
427: cur->sd_un.flag = op;
428: break;
429: }
430:
431: return(TRUE);
432: }
433:
434: /*
435: * Set default options to compiled-in values.
436: * Any of these may be overridden at runtime by a "Defaults" file.
437: */
438: void
439: init_defaults()
440: {
441: static int firsttime = 1;
442: struct sudo_defs_types *def;
443:
444: /* Free any strings that were set. */
445: if (!firsttime) {
446: for (def = sudo_defs_table; def->name; def++)
447: switch (def->type & T_MASK) {
448: case T_STR:
449: case T_LOGFAC:
450: case T_LOGPRI:
451: if (def->sd_un.str) {
452: free(def->sd_un.str);
453: def->sd_un.str = NULL;
454: }
455: break;
456: }
457: }
458:
459: /* First initialize the flags. */
460: #ifdef LONG_OTP_PROMPT
461: def_flag(I_LONG_OTP_PROMPT) = TRUE;
462: #endif
463: #ifdef IGNORE_DOT_PATH
464: def_flag(I_IGNORE_DOT) = TRUE;
465: #endif
466: #ifdef ALWAYS_SEND_MAIL
467: def_flag(I_MAIL_ALWAYS) = TRUE;
468: #endif
469: #ifdef SEND_MAIL_WHEN_NO_USER
470: def_flag(I_MAIL_NOUSER) = TRUE;
471: #endif
472: #ifdef SEND_MAIL_WHEN_NO_HOST
473: def_flag(I_MAIL_NOHOST) = TRUE;
474: #endif
475: #ifdef SEND_MAIL_WHEN_NOT_OK
476: def_flag(I_MAIL_NOPERMS) = TRUE;
477: #endif
478: #ifdef USE_TTY_TICKETS
479: def_flag(I_TTY_TICKETS) = TRUE;
480: #endif
481: #ifndef NO_LECTURE
482: def_flag(I_LECTURE) = TRUE;
483: #endif
484: #ifndef NO_AUTHENTICATION
485: def_flag(I_AUTHENTICATE) = TRUE;
486: #endif
487: #ifndef NO_ROOT_SUDO
488: def_flag(I_ROOT_SUDO) = TRUE;
489: #endif
490: #ifdef HOST_IN_LOG
491: def_flag(I_LOG_HOST) = TRUE;
492: #endif
493: #ifdef SHELL_IF_NO_ARGS
494: def_flag(I_SHELL_NOARGS) = TRUE;
495: #endif
496: #ifdef SHELL_SETS_HOME
497: def_flag(I_SET_HOME) = TRUE;
498: #endif
499: #ifndef DONT_LEAK_PATH_INFO
500: def_flag(I_PATH_INFO) = TRUE;
501: #endif
502: #ifdef FQDN
503: def_flag(I_FQDN) = TRUE;
504: #endif
505: #ifdef USE_INSULTS
506: def_flag(I_INSULTS) = TRUE;
507: #endif
508:
509: /* Syslog options need special care since they both strings and ints */
510: #if (LOGGING & SLOG_SYSLOG)
511: (void) store_syslogfac(LOGFAC, &sudo_defs_table[I_LOGFACSTR], TRUE);
512: (void) store_syslogpri(PRI_SUCCESS, &sudo_defs_table[I_GOODPRISTR], TRUE);
513: (void) store_syslogpri(PRI_FAILURE, &sudo_defs_table[I_BADPRISTR], TRUE);
514: #endif
515:
516: /* Then initialize the int-like things. */
517: #ifdef SUDO_UMASK
518: def_mode(I_UMASK) = SUDO_UMASK;
519: #else
520: def_mode(I_UMASK) = 0777;
521: #endif
522: def_ival(I_LOGLEN) = MAXLOGFILELEN;
523: def_ival(I_TS_TIMEOUT) = TIMEOUT;
524: def_ival(I_PW_TIMEOUT) = PASSWORD_TIMEOUT;
525: def_ival(I_PW_TRIES) = TRIES_FOR_PASSWORD;
526:
527: /* Finally do the strings */
528: def_str(I_MAILTO) = estrdup(MAILTO);
529: def_str(I_MAILSUB) = estrdup(MAILSUBJECT);
530: def_str(I_BADPASS_MSG) = estrdup(INCORRECT_PASSWORD);
531: def_str(I_TIMESTAMPDIR) = estrdup(_PATH_SUDO_TIMEDIR);
532: def_str(I_PASSPROMPT) = estrdup(PASSPROMPT);
533: def_str(I_RUNAS_DEF) = estrdup(RUNAS_DEFAULT);
534: #ifdef _PATH_SENDMAIL
535: def_str(I_MAILERPATH) = estrdup(_PATH_SENDMAIL);
536: def_str(I_MAILERFLAGS) = estrdup("-t");
537: #endif
538: #if (LOGGING & SLOG_FILE)
539: def_str(I_LOGFILE) = estrdup(_PATH_SUDO_LOGFILE);
540: #endif
541: #ifdef EXEMPTGROUP
542: def_str(I_EXEMPT_GRP) = estrdup(EXEMPTGROUP);
543: #endif
544: #ifdef SECURE_PATH
545: def_str(I_SECURE_PATH) = estrdup(SECURE_PATH);
546: #endif
547:
548: /*
549: * The following depend on the above values.
550: * We use a pointer to the string so that if its
551: * value changes we get the change.
552: */
553: if (user_runas == NULL)
554: user_runas = &def_str(I_RUNAS_DEF);
555:
556: firsttime = 0;
557: }
558:
559: static int
560: store_int(val, def, op)
561: char *val;
562: struct sudo_defs_types *def;
563: int op;
564: {
565: char *endp;
566: long l;
567:
568: if (op == FALSE) {
569: def->sd_un.ival = 0;
570: } else {
571: l = strtol(val, &endp, 10);
572: if (*endp != '\0' || l < 0)
573: return(FALSE);
574: /* XXX - should check against INT_MAX */
575: def->sd_un.ival = (unsigned int)l;
576: }
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: if (def->sd_un.str)
588: free(def->sd_un.str);
589: if (op == FALSE)
590: def->sd_un.str = NULL;
591: else
592: def->sd_un.str = estrdup(val);
593: return(TRUE);
594: }
595:
596: static int
597: store_syslogfac(val, def, op)
598: char *val;
599: struct sudo_defs_types *def;
600: int op;
601: {
602: struct strmap *fac;
603:
604: if (op == FALSE) {
605: free(def->sd_un.str);
606: def->sd_un.str = NULL;
607: return(TRUE);
608: }
609: #ifdef LOG_NFACILITIES
610: if (!val)
611: return(FALSE);
612: for (fac = facilities; fac->name && strcmp(val, fac->name); fac++)
613: ;
614: if (fac->name == NULL)
615: return(FALSE); /* not found */
616:
617: /* Store both name and number. */
618: if (def->sd_un.str)
619: free(def->sd_un.str);
620: def->sd_un.str = estrdup(fac->name);
621: sudo_defs_table[I_LOGFAC].sd_un.ival = fac->num;
622: #else
623: if (def->sd_un.str)
624: free(def->sd_un.str);
625: def->sd_un.str = estrdup("default");
626: #endif /* LOG_NFACILITIES */
627: return(TRUE);
628: }
629:
630: static int
631: store_syslogpri(val, def, op)
632: char *val;
633: struct sudo_defs_types *def;
634: int op;
635: {
636: struct strmap *pri;
637: struct sudo_defs_types *idef;
638:
639: if (op == FALSE || !val)
640: return(FALSE);
641: if (def == &sudo_defs_table[I_GOODPRISTR])
642: idef = &sudo_defs_table[I_GOODPRI];
643: else if (def == &sudo_defs_table[I_BADPRISTR])
644: idef = &sudo_defs_table[I_BADPRI];
645: else
646: return(FALSE);
647:
648: for (pri = priorities; pri->name && strcmp(val, pri->name); pri++)
649: ;
650: if (pri->name == NULL)
651: return(FALSE); /* not found */
652:
653: /* Store both name and number. */
654: if (def->sd_un.str)
655: free(def->sd_un.str);
656: def->sd_un.str = estrdup(pri->name);
657: idef->sd_un.ival = pri->num;
658: return(TRUE);
659: }
660:
661: static int
662: store_mode(val, def, op)
663: char *val;
664: struct sudo_defs_types *def;
665: int op;
666: {
667: char *endp;
668: long l;
669:
670: if (op == FALSE) {
671: def->sd_un.mode = (mode_t)0777;
672: } else {
673: l = strtol(val, &endp, 8);
674: if (*endp != '\0' || l < 0 || l >= 0777)
675: return(FALSE);
676: def->sd_un.mode = (mode_t)l;
677: }
678: return(TRUE);
679: }