Annotation of src/usr.bin/sudo/sudo.c, Revision 1.43
1.1 millert 1: /*
1.39 millert 2: * Copyright (c) 1993-1996, 1998-2009 Todd C. Miller <Todd.Miller@courtesan.com>
1.1 millert 3: *
1.23 millert 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.
1.1 millert 7: *
1.23 millert 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.
1.1 millert 15: *
1.20 millert 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: *
1.1 millert 20: * For a brief history of sudo, please see the HISTORY file included
21: * with this distribution.
22: */
23:
1.19 millert 24: #define _SUDO_MAIN
1.1 millert 25:
1.23 millert 26: #ifdef __TANDEM
27: # include <floss.h>
28: #endif
29:
1.27 millert 30: #include <config.h>
1.1 millert 31:
1.11 millert 32: #include <sys/types.h>
33: #include <sys/stat.h>
34: #include <sys/param.h>
35: #include <sys/socket.h>
36: #ifdef HAVE_SETRLIMIT
37: # include <sys/time.h>
38: # include <sys/resource.h>
39: #endif
1.1 millert 40: #include <stdio.h>
41: #ifdef STDC_HEADERS
1.11 millert 42: # include <stdlib.h>
43: # include <stddef.h>
44: #else
45: # ifdef HAVE_STDLIB_H
46: # include <stdlib.h>
47: # endif
1.1 millert 48: #endif /* STDC_HEADERS */
1.11 millert 49: #ifdef HAVE_STRING_H
50: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
51: # include <memory.h>
52: # endif
53: # include <string.h>
54: #else
55: # ifdef HAVE_STRINGS_H
56: # include <strings.h>
57: # endif
58: #endif /* HAVE_STRING_H */
1.1 millert 59: #ifdef HAVE_UNISTD_H
1.11 millert 60: # include <unistd.h>
1.1 millert 61: #endif /* HAVE_UNISTD_H */
62: #include <pwd.h>
63: #include <errno.h>
64: #include <fcntl.h>
65: #include <signal.h>
66: #include <grp.h>
1.27 millert 67: #if TIME_WITH_SYS_TIME
68: # include <time.h>
69: #endif
70: #ifdef HAVE_SETLOCALE
71: # include <locale.h>
72: #endif
1.1 millert 73: #include <netinet/in.h>
74: #include <netdb.h>
75: #if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS)
76: # ifdef __hpux
77: # undef MAXINT
78: # include <hpsecurity.h>
79: # else
80: # include <sys/security.h>
81: # endif /* __hpux */
82: # include <prot.h>
83: #endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */
1.8 millert 84: #ifdef HAVE_LOGIN_CAP_H
1.4 millert 85: # include <login_cap.h>
86: # ifndef LOGIN_DEFROOTCLASS
87: # define LOGIN_DEFROOTCLASS "daemon"
88: # endif
89: #endif
1.27 millert 90: #ifdef HAVE_PROJECT_H
91: # include <project.h>
92: # include <sys/task.h>
93: #endif
1.33 millert 94: #ifdef HAVE_SELINUX
95: # include <selinux/selinux.h>
96: #endif
1.1 millert 97:
1.38 millert 98: #include <sudo_usage.h>
1.1 millert 99: #include "sudo.h"
1.34 millert 100: #include "lbuf.h"
1.1 millert 101: #include "interfaces.h"
1.39 millert 102:
103: #ifdef USING_NONUNIX_GROUPS
104: # include "nonunix.h"
105: #endif
1.1 millert 106:
107: /*
108: * Prototypes
109: */
1.34 millert 110: static void init_vars __P((int, char **));
111: static int set_cmnd __P((int));
1.19 millert 112: static int parse_args __P((int, char **));
1.11 millert 113: static void initial_setup __P((void));
114: static void set_loginclass __P((struct passwd *));
1.27 millert 115: static void set_project __P((struct passwd *));
1.34 millert 116: static void set_runasgr __P((char *));
117: static void set_runaspw __P((char *));
118: static void show_version __P((void));
1.27 millert 119: static void usage __P((int))
120: __attribute__((__noreturn__));
121: static void usage_excl __P((int))
122: __attribute__((__noreturn__));
1.6 millert 123: static struct passwd *get_authpw __P((void));
1.27 millert 124: extern int sudo_edit __P((int, char **, char **));
1.34 millert 125: extern void rebuild_env __P((int, int));
126: void validate_env_vars __P((struct list_member *));
127: void insert_env_vars __P((struct list_member *));
1.1 millert 128:
129: /*
130: * Globals
131: */
1.19 millert 132: int Argc, NewArgc;
133: char **Argv, **NewArgv;
1.23 millert 134: char *prev_user;
1.34 millert 135: static int user_closefrom = -1;
1.1 millert 136: struct sudo_user sudo_user;
1.34 millert 137: struct passwd *auth_pw, *list_pw;
1.1 millert 138: struct interface *interfaces;
139: int num_interfaces;
1.4 millert 140: int tgetpass_flags;
1.34 millert 141: int long_list;
1.17 millert 142: uid_t timestamp_uid;
1.1 millert 143: extern int errorlineno;
1.34 millert 144: extern int parse_error;
145: extern char *errorfile;
1.4 millert 146: #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
147: static struct rlimit corelimit;
1.20 millert 148: #endif /* RLIMIT_CORE && !SUDO_DEVEL */
1.8 millert 149: #ifdef HAVE_LOGIN_CAP_H
150: login_cap_t *lc;
151: #endif /* HAVE_LOGIN_CAP_H */
152: #ifdef HAVE_BSD_AUTH_H
153: char *login_style;
154: #endif /* HAVE_BSD_AUTH_H */
1.33 millert 155: sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp;
1.34 millert 156: static char *runas_user;
157: static char *runas_group;
158: static struct sudo_nss_list *snl;
159:
160: /* For getopt(3) */
161: extern char *optarg;
162: extern int optind;
1.1 millert 163:
164: int
1.11 millert 165: main(argc, argv, envp)
1.1 millert 166: int argc;
167: char **argv;
1.11 millert 168: char **envp;
1.1 millert 169: {
1.34 millert 170: int sources = 0, validated;
171: int fd, cmnd_status, sudo_mode, pwflag, rc = 0;
1.23 millert 172: sigaction_t sa;
1.35 deraadt 173: struct sudo_nss *nss;
1.34 millert 174: #if defined(SUDO_DEVEL) && defined(__OpenBSD__)
175: extern char *malloc_options;
176: malloc_options = "AFGJPR";
177: #endif
1.1 millert 178:
1.27 millert 179: #ifdef HAVE_SETLOCALE
180: setlocale(LC_ALL, "");
181: #endif
182:
1.19 millert 183: Argv = argv;
1.23 millert 184: if ((Argc = argc) < 1)
185: usage(1);
1.19 millert 186:
1.1 millert 187: /* Must be done as the first thing... */
188: #if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS)
1.19 millert 189: (void) set_auth_parameters(Argc, Argv);
1.1 millert 190: # ifdef HAVE_INITPRIVS
191: initprivs();
192: # endif
193: #endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */
194:
1.19 millert 195: if (geteuid() != 0)
1.34 millert 196: errorx(1, "must be setuid root");
1.1 millert 197:
198: /*
1.17 millert 199: * Signal setup:
200: * Ignore keyboard-generated signals so the user cannot interrupt
201: * us at some point and avoid the logging.
202: * Install handler to wait for children when they exit.
1.1 millert 203: */
1.34 millert 204: zero_bytes(&sa, sizeof(sa));
1.11 millert 205: sigemptyset(&sa.sa_mask);
206: sa.sa_flags = SA_RESTART;
207: sa.sa_handler = SIG_IGN;
1.17 millert 208: (void) sigaction(SIGINT, &sa, &saved_sa_int);
209: (void) sigaction(SIGQUIT, &sa, &saved_sa_quit);
210: (void) sigaction(SIGTSTP, &sa, &saved_sa_tstp);
1.1 millert 211:
212: /*
1.34 millert 213: * Turn off core dumps and make sure fds 0-2 are open.
1.1 millert 214: */
215: initial_setup();
1.34 millert 216: sudo_setpwent();
217: sudo_setgrent();
1.1 millert 218:
219: /* Parse our arguments. */
1.19 millert 220: sudo_mode = parse_args(Argc, Argv);
1.1 millert 221:
222: /* Setup defaults data structures. */
223: init_defaults();
224:
1.11 millert 225: /* Load the list of local ip addresses and netmasks. */
226: load_interfaces();
227:
228: pwflag = 0;
1.23 millert 229: if (ISSET(sudo_mode, MODE_SHELL))
1.1 millert 230: user_cmnd = "shell";
1.23 millert 231: else if (ISSET(sudo_mode, MODE_EDIT))
232: user_cmnd = "sudoedit";
1.38 millert 233: else {
1.1 millert 234: switch (sudo_mode) {
235: case MODE_VERSION:
1.34 millert 236: show_version();
1.1 millert 237: break;
238: case MODE_HELP:
239: usage(0);
240: break;
241: case MODE_VALIDATE:
1.38 millert 242: case MODE_VALIDATE|MODE_INVALIDATE:
1.1 millert 243: user_cmnd = "validate";
1.23 millert 244: pwflag = I_VERIFYPW;
1.1 millert 245: break;
246: case MODE_KILL:
247: case MODE_INVALIDATE:
248: user_cmnd = "kill";
1.11 millert 249: pwflag = -1;
1.1 millert 250: break;
251: case MODE_LISTDEFS:
252: list_options();
253: exit(0);
254: break;
255: case MODE_LIST:
1.38 millert 256: case MODE_LIST|MODE_INVALIDATE:
1.1 millert 257: user_cmnd = "list";
1.23 millert 258: pwflag = I_LISTPW;
1.34 millert 259: break;
260: case MODE_CHECK:
1.38 millert 261: case MODE_CHECK|MODE_INVALIDATE:
1.34 millert 262: pwflag = I_LISTPW;
1.1 millert 263: break;
264: }
1.38 millert 265: }
1.1 millert 266:
267: /* Must have a command to run... */
268: if (user_cmnd == NULL && NewArgc == 0)
269: usage(1);
270:
1.34 millert 271: init_vars(sudo_mode, envp); /* XXX - move this later? */
272:
1.39 millert 273: #ifdef USING_NONUNIX_GROUPS
274: sudo_nonunix_groupcheck_init(); /* initialise nonunix groups impl */
275: #endif /* USING_NONUNIX_GROUPS */
276:
1.34 millert 277: /* Parse nsswitch.conf for sudoers order. */
278: snl = sudo_read_nss();
279:
280: /* Open and parse sudoers, set global defaults */
281: tq_foreach_fwd(snl, nss) {
282: if (nss->open(nss) == 0 && nss->parse(nss) == 0) {
283: sources++;
284: nss->setdefs(nss);
285: }
286: }
287: if (sources == 0)
288: log_error(0, "no valid sudoers sources found, quitting");
289:
290: /* XXX - collect post-sudoers parse settings into a function */
291:
292: /*
293: * Set runas passwd/group entries based on command line or sudoers.
294: * Note that if runas_group was specified without runas_user we
295: * defer setting runas_pw so the match routines know to ignore it.
296: */
297: if (runas_group != NULL) {
298: set_runasgr(runas_group);
299: if (runas_user != NULL)
300: set_runaspw(runas_user);
301: } else
302: set_runaspw(runas_user ? runas_user : def_runas_default);
303:
304: if (!update_defaults(SETDEF_RUNAS))
305: log_error(NO_STDERR|NO_EXIT, "problem with defaults entries");
306:
307: /* Set login class if applicable. */
308: set_loginclass(sudo_user.pw);
1.1 millert 309:
1.34 millert 310: /* Update initial shell now that runas is set. */
311: if (ISSET(sudo_mode, MODE_LOGIN_SHELL))
312: NewArgv[0] = runas_pw->pw_shell;
313:
314: /* This goes after sudoers is parsed since it may have timestamp options. */
315: if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE) {
316: remove_timestamp((sudo_mode == MODE_KILL));
317: cleanup(0);
318: exit(0);
319: }
320:
321: /* Is root even allowed to run sudo? */
322: if (user_uid == 0 && !def_root_sudo) {
323: (void) fprintf(stderr,
324: "Sorry, %s has been configured to not allow root to run it.\n",
325: getprogname());
326: exit(1);
327: }
1.23 millert 328:
1.34 millert 329: /* Check for -C overriding def_closefrom. */
330: if (user_closefrom >= 0 && user_closefrom != def_closefrom) {
331: if (!def_closefrom_override)
332: errorx(1, "you are not permitted to use the -C option");
333: else
334: def_closefrom = user_closefrom;
1.23 millert 335: }
1.33 millert 336:
1.34 millert 337: cmnd_status = set_cmnd(sudo_mode);
338:
339: #ifdef HAVE_SETLOCALE
340: if (!setlocale(LC_ALL, def_sudoers_locale)) {
341: warningx("unable to set locale to \"%s\", using \"C\"",
342: def_sudoers_locale);
343: setlocale(LC_ALL, "C");
344: }
1.23 millert 345: #endif
1.34 millert 346:
347: validated = FLAG_NO_USER | FLAG_NO_HOST;
348: tq_foreach_fwd(snl, nss) {
349: validated = nss->lookup(nss, validated, pwflag);
350:
1.38 millert 351: if (ISSET(validated, VALIDATE_OK)) {
352: /* Handle "= auth" in netsvc.conf */
353: if (nss->ret_if_found)
354: break;
355: } else {
356: /* Handle [NOTFOUND=return] */
357: if (nss->ret_if_notfound)
358: break;
359: }
1.34 millert 360: }
1.39 millert 361:
1.26 millert 362: if (safe_cmnd == NULL)
1.27 millert 363: safe_cmnd = estrdup(user_cmnd);
1.1 millert 364:
1.34 millert 365: #ifdef HAVE_SETLOCALE
366: setlocale(LC_ALL, "");
367: #endif
368:
369: /* If only a group was specified, set runas_pw based on invoking user. */
370: if (runas_pw == NULL)
371: set_runaspw(user_name);
372:
1.11 millert 373: /*
1.17 millert 374: * Look up the timestamp dir owner if one is specified.
375: */
1.23 millert 376: if (def_timestampowner) {
1.17 millert 377: struct passwd *pw;
378:
1.23 millert 379: if (*def_timestampowner == '#')
1.34 millert 380: pw = sudo_getpwuid(atoi(def_timestampowner + 1));
1.17 millert 381: else
1.34 millert 382: pw = sudo_getpwnam(def_timestampowner);
1.17 millert 383: if (!pw)
384: log_error(0, "timestamp owner (%s): No such user",
1.23 millert 385: def_timestampowner);
1.17 millert 386: timestamp_uid = pw->pw_uid;
387: }
388:
1.11 millert 389: /* If given the -P option, set the "preserve_groups" flag. */
1.23 millert 390: if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS))
391: def_preserve_groups = TRUE;
1.11 millert 392:
1.3 millert 393: /* If no command line args and "set_home" is not set, error out. */
1.23 millert 394: if (ISSET(sudo_mode, MODE_IMPLIED_SHELL) && !def_shell_noargs)
1.3 millert 395: usage(1);
396:
1.1 millert 397: /* Bail if a tty is required and we don't have one. */
1.23 millert 398: if (def_requiretty) {
1.38 millert 399: if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) {
400: audit_failure(NewArgv, "no tty");
1.1 millert 401: log_error(NO_MAIL, "sorry, you must have a tty to run sudo");
1.38 millert 402: } else
1.1 millert 403: (void) close(fd);
404: }
405:
1.34 millert 406: /* Use askpass value from sudoers unless user specified their own. */
407: if (def_askpass && !user_askpass)
408: user_askpass = def_askpass;
409:
410: /* User may have overridden environment resetting via the -E flag. */
411: if (ISSET(sudo_mode, MODE_PRESERVE_ENV) && def_setenv)
1.27 millert 412: def_env_reset = FALSE;
413:
414: /* Build a new environment that avoids any nasty bits. */
1.34 millert 415: rebuild_env(sudo_mode, def_noexec);
1.27 millert 416:
1.6 millert 417: /* Fill in passwd struct based on user we are authenticating as. */
418: auth_pw = get_authpw();
1.4 millert 419:
1.23 millert 420: /* Require a password if sudoers says so. */
1.34 millert 421: if (def_authenticate)
1.38 millert 422: check_user(validated, sudo_mode);
1.23 millert 423:
424: /* If run as root with SUDO_USER set, set sudo_user.pw to that user. */
1.34 millert 425: /* XXX - causes confusion when root is not listed in sudoers */
426: if (sudo_mode & (MODE_RUN | MODE_EDIT) && prev_user != NULL) {
427: if (user_uid == 0 && strcmp(prev_user, "root") != 0) {
1.23 millert 428: struct passwd *pw;
429:
1.34 millert 430: if ((pw = sudo_getpwnam(prev_user)) != NULL)
1.23 millert 431: sudo_user.pw = pw;
1.34 millert 432: }
1.23 millert 433: }
1.1 millert 434:
1.23 millert 435: if (ISSET(validated, VALIDATE_OK)) {
1.1 millert 436: /* Finally tell the user if the command did not exist. */
1.38 millert 437: if (cmnd_status == NOT_FOUND_DOT) {
438: audit_failure(NewArgv, "command in current directory");
1.34 millert 439: errorx(1, "ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.", user_cmnd, user_cmnd, user_cmnd);
1.38 millert 440: } else if (cmnd_status == NOT_FOUND) {
441: audit_failure(NewArgv, "%s: command not found", user_cmnd);
1.34 millert 442: errorx(1, "%s: command not found", user_cmnd);
1.38 millert 443: }
1.1 millert 444:
1.27 millert 445: /* If user specified env vars make sure sudoers allows it. */
1.34 millert 446: if (ISSET(sudo_mode, MODE_RUN) && !def_setenv) {
1.27 millert 447: if (ISSET(sudo_mode, MODE_PRESERVE_ENV))
448: log_error(NO_MAIL,
449: "sorry, you are not allowed to preserve the environment");
450: else
451: validate_env_vars(sudo_user.env_vars);
452: }
453:
1.34 millert 454: log_allowed(validated);
1.38 millert 455: if (ISSET(sudo_mode, MODE_CHECK))
1.34 millert 456: rc = display_cmnd(snl, list_pw ? list_pw : sudo_user.pw);
1.38 millert 457: else if (ISSET(sudo_mode, MODE_LIST))
1.34 millert 458: display_privs(snl, list_pw ? list_pw : sudo_user.pw);
459:
460: /* Cleanup sudoers sources */
461: tq_foreach_fwd(snl, nss)
462: nss->close(nss);
463:
1.43 ! millert 464: #ifdef USING_NONUNIX_GROUPS
! 465: /* Finished with the groupcheck code */
! 466: sudo_nonunix_groupcheck_cleanup();
! 467: #endif
! 468:
1.34 millert 469: /* Deferred exit due to sudo_ldap_close() */
1.38 millert 470: if (ISSET(sudo_mode, (MODE_VALIDATE|MODE_CHECK|MODE_LIST)))
1.34 millert 471: exit(rc);
472:
473: /*
1.38 millert 474: * Set umask based on sudoers.
475: * If user's umask is more restrictive, OR in those bits too
476: * unless umask_override is set.
1.34 millert 477: */
478: if (def_umask != 0777) {
1.38 millert 479: if (def_umask_override) {
480: umask(def_umask);
481: } else {
482: mode_t mask = umask(def_umask);
483: mask |= def_umask;
484: if (mask != def_umask)
485: umask(mask);
486: }
1.1 millert 487: }
488:
1.4 millert 489: /* Restore coredumpsize resource limit. */
490: #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
491: (void) setrlimit(RLIMIT_CORE, &corelimit);
1.20 millert 492: #endif /* RLIMIT_CORE && !SUDO_DEVEL */
1.4 millert 493:
1.39 millert 494: /* Must audit before uid change. */
495: audit_success(NewArgv);
496:
1.23 millert 497: /* Become specified user or root if executing a command. */
498: if (ISSET(sudo_mode, MODE_RUN))
499: set_perms(PERM_FULL_RUNAS);
1.16 millert 500:
1.23 millert 501: if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
502: char *p;
503:
504: /* Convert /bin/sh -> -sh so shell knows it is a login shell */
505: if ((p = strrchr(NewArgv[0], '/')) == NULL)
506: p = NewArgv[0];
507: *p = '-';
508: NewArgv[0] = p;
509:
510: /* Change to target user's homedir. */
511: if (chdir(runas_pw->pw_dir) == -1)
1.34 millert 512: warning("unable to change directory to %s", runas_pw->pw_dir);
513:
514: #if defined(__linux__) || defined(_AIX)
515: /* Insert system-wide environment variables. */
516: read_env_file(_PATH_ENVIRONMENT, TRUE);
517: #endif
1.23 millert 518: }
519:
520: if (ISSET(sudo_mode, MODE_EDIT))
1.27 millert 521: exit(sudo_edit(NewArgc, NewArgv, envp));
522:
1.34 millert 523: /* Insert system-wide environment variables. */
524: if (def_env_file)
525: read_env_file(def_env_file, FALSE);
526:
1.27 millert 527: /* Insert user-specified environment variables. */
1.34 millert 528: insert_env_vars(sudo_user.env_vars);
1.23 millert 529:
1.17 millert 530: /* Restore signal handlers before we exec. */
531: (void) sigaction(SIGINT, &saved_sa_int, NULL);
532: (void) sigaction(SIGQUIT, &saved_sa_quit, NULL);
533: (void) sigaction(SIGTSTP, &saved_sa_tstp, NULL);
534:
1.34 millert 535: /* Close the password and group files and free up memory. */
536: sudo_endpwent();
537: sudo_endgrent();
538:
1.42 halex 539: closefrom(def_closefrom);
1.34 millert 540:
1.1 millert 541: #ifndef PROFILING
1.38 millert 542: if (ISSET(sudo_mode, MODE_BACKGROUND) && fork() > 0) {
543: syslog(LOG_AUTH|LOG_ERR, "fork");
1.1 millert 544: exit(0);
1.38 millert 545: } else {
1.33 millert 546: #ifdef HAVE_SELINUX
547: if (is_selinux_enabled() > 0 && user_role != NULL)
1.34 millert 548: selinux_exec(user_role, user_type, NewArgv,
1.33 millert 549: ISSET(sudo_mode, MODE_LOGIN_SHELL));
550: #endif
1.34 millert 551: execv(safe_cmnd, NewArgv);
1.33 millert 552: }
1.1 millert 553: #else
554: exit(0);
555: #endif /* PROFILING */
556: /*
1.34 millert 557: * If we got here then execve() failed...
1.1 millert 558: */
1.27 millert 559: if (errno == ENOEXEC) {
560: NewArgv--; /* at least one extra slot... */
561: NewArgv[0] = "sh";
562: NewArgv[1] = safe_cmnd;
1.34 millert 563: execv(_PATH_BSHELL, NewArgv);
1.38 millert 564: }
565: warning("unable to execute %s", safe_cmnd);
1.11 millert 566: exit(127);
1.34 millert 567: } else if (ISSET(validated, FLAG_NO_USER | FLAG_NO_HOST)) {
1.38 millert 568: audit_failure(NewArgv, "No user or host");
1.34 millert 569: log_denial(validated, 1);
1.1 millert 570: exit(1);
1.34 millert 571: } else {
1.23 millert 572: if (def_path_info) {
1.1 millert 573: /*
574: * We'd like to not leak path info at all here, but that can
575: * *really* confuse the users. To really close the leak we'd
576: * have to say "not allowed to run foo" even when the problem
577: * is just "no foo in path" since the user can trivially set
578: * their path to just contain a single dir.
579: */
1.34 millert 580: log_denial(validated,
1.1 millert 581: !(cmnd_status == NOT_FOUND_DOT || cmnd_status == NOT_FOUND));
582: if (cmnd_status == NOT_FOUND)
1.34 millert 583: warningx("%s: command not found", user_cmnd);
1.1 millert 584: else if (cmnd_status == NOT_FOUND_DOT)
1.34 millert 585: warningx("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.", user_cmnd, user_cmnd, user_cmnd);
1.1 millert 586: } else {
587: /* Just tell the user they are not allowed to run foo. */
1.34 millert 588: log_denial(validated, 1);
1.1 millert 589: }
1.38 millert 590: audit_failure(NewArgv, "validation failure");
1.1 millert 591: exit(1);
592: }
593: exit(0); /* not reached */
594: }
595:
596: /*
597: * Initialize timezone, set umask, fill in ``sudo_user'' struct and
598: * load the ``interfaces'' array.
599: */
1.34 millert 600: static void
1.27 millert 601: init_vars(sudo_mode, envp)
1.1 millert 602: int sudo_mode;
1.27 millert 603: char **envp;
1.1 millert 604: {
1.34 millert 605: char *p, **ep, thost[MAXHOSTNAMELEN + 1];
606: int nohostname;
1.1 millert 607:
608: /* Sanity check command from user. */
1.23 millert 609: if (user_cmnd == NULL && strlen(NewArgv[0]) >= PATH_MAX)
1.34 millert 610: errorx(1, "%s: File name too long", NewArgv[0]);
1.1 millert 611:
612: #ifdef HAVE_TZSET
613: (void) tzset(); /* set the timezone if applicable */
614: #endif /* HAVE_TZSET */
615:
616: /* Default value for cmnd and cwd, overridden later. */
617: if (user_cmnd == NULL)
618: user_cmnd = NewArgv[0];
1.17 millert 619: (void) strlcpy(user_cwd, "unknown", sizeof(user_cwd));
1.1 millert 620:
621: /*
622: * We avoid gethostbyname() if possible since we don't want
623: * sudo to block if DNS or NIS is hosed.
624: * "host" is the (possibly fully-qualified) hostname and
625: * "shost" is the unqualified form of the hostname.
626: */
1.11 millert 627: nohostname = gethostname(thost, sizeof(thost));
628: if (nohostname)
629: user_host = user_shost = "localhost";
630: else {
1.34 millert 631: thost[sizeof(thost) - 1] = '\0';
1.1 millert 632: user_host = estrdup(thost);
1.23 millert 633: if (def_fqdn) {
1.11 millert 634: /* Defer call to set_fqdn() until log_error() is safe. */
635: user_shost = user_host;
1.1 millert 636: } else {
1.11 millert 637: if ((p = strchr(user_host, '.'))) {
638: *p = '\0';
639: user_shost = estrdup(user_host);
640: *p = '.';
641: } else {
642: user_shost = user_host;
643: }
1.1 millert 644: }
645: }
646:
1.40 millert 647: if ((p = ttyname(STDIN_FILENO)) || (p = ttyname(STDOUT_FILENO)) ||
648: (p = ttyname(STDERR_FILENO))) {
1.30 millert 649: user_tty = user_ttypath = estrdup(p);
650: if (strncmp(user_tty, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
651: user_tty += sizeof(_PATH_DEV) - 1;
1.1 millert 652: } else
653: user_tty = "unknown";
654:
1.27 millert 655: for (ep = envp; *ep; ep++) {
1.34 millert 656: /* XXX - don't fill in if empty string */
1.27 millert 657: switch (**ep) {
1.34 millert 658: case 'D':
659: if (strncmp("DISPLAY=", *ep, 8) == 0)
660: user_display = *ep + 8;
661: break;
662: case 'K':
663: if (strncmp("KRB5CCNAME=", *ep, 11) == 0)
664: user_ccname = *ep + 11;
665: break;
1.27 millert 666: case 'P':
667: if (strncmp("PATH=", *ep, 5) == 0)
668: user_path = *ep + 5;
669: break;
670: case 'S':
671: if (strncmp("SHELL=", *ep, 6) == 0)
672: user_shell = *ep + 6;
673: else if (!user_prompt && strncmp("SUDO_PROMPT=", *ep, 12) == 0)
674: user_prompt = *ep + 12;
675: else if (strncmp("SUDO_USER=", *ep, 10) == 0)
676: prev_user = *ep + 10;
1.34 millert 677: else if (strncmp("SUDO_ASKPASS=", *ep, 13) == 0)
678: user_askpass = *ep + 13;
1.27 millert 679: break;
680: }
681: }
682:
1.1 millert 683: /*
684: * Get a local copy of the user's struct passwd with the shadow password
685: * if necessary. It is assumed that euid is 0 at this point so we
686: * can read the shadow passwd file if necessary.
687: */
688: if ((sudo_user.pw = sudo_getpwuid(getuid())) == NULL) {
689: /* Need to make a fake struct passwd for logging to work. */
690: struct passwd pw;
691: char pw_name[MAX_UID_T_LEN + 1];
692:
693: pw.pw_uid = getuid();
1.17 millert 694: (void) snprintf(pw_name, sizeof(pw_name), "%lu",
695: (unsigned long) pw.pw_uid);
1.1 millert 696: pw.pw_name = pw_name;
697: sudo_user.pw = &pw;
698:
1.21 millert 699: /*
700: * If we are in -k/-K mode, just spew to stderr. It is not unusual for
701: * users to place "sudo -k" in a .logout file which can cause sudo to
702: * be run during reboot after the YP/NIS/NIS+/LDAP/etc daemon has died.
703: */
1.38 millert 704: if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE)
1.34 millert 705: errorx(1, "unknown uid: %s", pw_name);
706: log_error(0, "unknown uid: %s", pw_name);
1.1 millert 707: }
1.15 millert 708: if (user_shell == NULL || *user_shell == '\0')
1.34 millert 709: user_shell = estrdup(sudo_user.pw->pw_shell);
1.1 millert 710:
711: /* It is now safe to use log_error() and set_perms() */
712:
1.27 millert 713: #ifdef HAVE_GETGROUPS
714: if ((user_ngroups = getgroups(0, NULL)) > 0) {
1.31 millert 715: user_groups = emalloc2(user_ngroups, sizeof(GETGROUPS_T));
1.27 millert 716: if (getgroups(user_ngroups, user_groups) < 0)
717: log_error(USE_ERRNO|MSG_ONLY, "can't get group vector");
718: } else
719: user_ngroups = 0;
720: #endif
721:
1.23 millert 722: if (def_fqdn)
723: set_fqdn(); /* may call log_error() */
1.11 millert 724:
725: if (nohostname)
726: log_error(USE_ERRNO|MSG_ONLY, "can't get hostname");
727:
728: /*
1.1 millert 729: * Get current working directory. Try as user, fall back to root.
730: */
1.17 millert 731: set_perms(PERM_USER);
1.1 millert 732: if (!getcwd(user_cwd, sizeof(user_cwd))) {
1.17 millert 733: set_perms(PERM_ROOT);
1.1 millert 734: if (!getcwd(user_cwd, sizeof(user_cwd))) {
1.34 millert 735: warningx("cannot get working directory");
1.17 millert 736: (void) strlcpy(user_cwd, "unknown", sizeof(user_cwd));
1.1 millert 737: }
738: } else
1.17 millert 739: set_perms(PERM_ROOT);
1.1 millert 740:
741: /*
1.23 millert 742: * If we were given the '-e', '-i' or '-s' options we need to redo
1.1 millert 743: * NewArgv and NewArgc.
744: */
1.34 millert 745: if (ISSET(sudo_mode, MODE_EDIT)) {
746: NewArgv--;
747: NewArgc++;
748: NewArgv[0] = "sudoedit";
749: } else if (ISSET(sudo_mode, MODE_SHELL)) {
750: char **av;
1.1 millert 751:
1.27 millert 752: /* Allocate an extra slot for execve() failure (ENOEXEC). */
1.34 millert 753: av = (char **) emalloc2(5, sizeof(char *));
754: av++;
1.1 millert 755:
1.34 millert 756: av[0] = user_shell; /* may be updated later */
757: if (NewArgc > 0) {
758: size_t size;
759: char *cmnd, *src, *dst, *end;
760: size = (size_t) (NewArgv[NewArgc - 1] - NewArgv[0]) +
761: strlen(NewArgv[NewArgc - 1]) + 1;
762: cmnd = emalloc(size);
763: src = NewArgv[0];
764: dst = cmnd;
765: for (end = src + size - 1; src < end; src++, dst++)
766: *dst = *src == 0 ? ' ' : *src;
767: *dst = '\0';
768: av[1] = "-c";
769: av[2] = cmnd;
770: NewArgc = 2;
771: }
772: av[++NewArgc] = NULL;
773: NewArgv = av;
1.1 millert 774: }
1.34 millert 775: }
1.1 millert 776:
1.34 millert 777: /*
778: * Fill in user_cmnd, user_args, user_base and user_stat variables
779: * and apply any command-specific defaults entries.
780: */
781: static int
782: set_cmnd(sudo_mode)
783: int sudo_mode;
784: {
785: int rval;
1.8 millert 786:
1.27 millert 787: /* Set project if applicable. */
788: set_project(runas_pw);
789:
1.1 millert 790: /* Resolve the path and return. */
1.23 millert 791: rval = FOUND;
792: user_stat = emalloc(sizeof(struct stat));
1.34 millert 793: if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) {
794: if (ISSET(sudo_mode, MODE_RUN | MODE_CHECK)) {
1.23 millert 795: set_perms(PERM_RUNAS);
796: rval = find_path(NewArgv[0], &user_cmnd, user_stat, user_path);
1.17 millert 797: set_perms(PERM_ROOT);
1.23 millert 798: if (rval != FOUND) {
799: /* Failed as root, try as invoking user. */
800: set_perms(PERM_USER);
801: rval = find_path(NewArgv[0], &user_cmnd, user_stat, user_path);
802: set_perms(PERM_ROOT);
803: }
1.11 millert 804: }
805:
806: /* set user_args */
807: if (NewArgc > 1) {
808: char *to, **from;
1.17 millert 809: size_t size, n;
1.11 millert 810:
1.23 millert 811: /* If we didn't realloc NewArgv it is contiguous so just count. */
1.34 millert 812: if (!ISSET(sudo_mode, MODE_SHELL)) {
1.11 millert 813: size = (size_t) (NewArgv[NewArgc-1] - NewArgv[1]) +
814: strlen(NewArgv[NewArgc-1]) + 1;
815: } else {
816: for (size = 0, from = NewArgv + 1; *from; from++)
817: size += strlen(*from) + 1;
818: }
819:
1.23 millert 820: /* Alloc and build up user_args. */
1.17 millert 821: user_args = (char *) emalloc(size);
822: for (to = user_args, from = NewArgv + 1; *from; from++) {
823: n = strlcpy(to, *from, size - (to - user_args));
1.19 millert 824: if (n >= size - (to - user_args))
1.34 millert 825: errorx(1, "internal error, init_vars() overflow");
1.17 millert 826: to += n;
1.11 millert 827: *to++ = ' ';
828: }
829: *--to = '\0';
830: }
1.23 millert 831: }
832: if ((user_base = strrchr(user_cmnd, '/')) != NULL)
833: user_base++;
834: else
835: user_base = user_cmnd;
1.11 millert 836:
1.34 millert 837: if (!update_defaults(SETDEF_CMND))
838: log_error(NO_STDERR|NO_EXIT, "problem with defaults entries");
839:
1.39 millert 840: if (!runas_user && !runas_group)
1.38 millert 841: set_runaspw(def_runas_default); /* may have been updated above */
842:
1.11 millert 843: return(rval);
1.1 millert 844: }
845:
846: /*
1.34 millert 847: * Command line argument parsing.
848: * Sets NewArgc and NewArgv which corresponds to the argc/argv we'll use
849: * for the command to be run (if we are running one).
1.1 millert 850: */
851: static int
1.19 millert 852: parse_args(argc, argv)
853: int argc;
854: char **argv;
1.1 millert 855: {
1.34 millert 856: int mode = 0; /* what mode is sudo to be run in? */
857: int flags = 0; /* mode flags */
1.38 millert 858: int valid_flags, ch;
1.1 millert 859:
1.23 millert 860: /* First, check to see if we were invoked as "sudoedit". */
1.34 millert 861: if (strcmp(getprogname(), "sudoedit") == 0)
862: mode = MODE_EDIT;
1.23 millert 863:
1.34 millert 864: /* Returns true if the last option string was "--" */
865: #define got_end_of_args (optind > 1 && argv[optind - 1][0] == '-' && \
866: argv[optind - 1][1] == '-' && argv[optind - 1][2] == '\0')
867:
868: /* Returns true if next option is an environment variable */
869: #define is_envar (optind < argc && argv[optind][0] != '/' && \
870: strchr(argv[optind], '=') != NULL)
1.27 millert 871:
1.38 millert 872: /* Flags allowed when running a command */
873: valid_flags = MODE_BACKGROUND|MODE_PRESERVE_ENV|MODE_RESET_HOME|
874: MODE_LOGIN_SHELL|MODE_INVALIDATE|MODE_NONINTERACTIVE|
875: MODE_PRESERVE_GROUPS|MODE_SHELL;
1.34 millert 876: for (;;) {
877: /*
878: * We disable arg permutation for GNU getopt().
879: * Some trickiness is required to allow environment variables
880: * to be interspersed with command line options.
881: */
882: if ((ch = getopt(argc, argv, "+Aa:bC:c:Eeg:HhiKkLlnPp:r:Sst:U:u:Vv")) != -1) {
883: switch (ch) {
884: case 'A':
885: SET(tgetpass_flags, TGP_ASKPASS);
1.27 millert 886: break;
1.8 millert 887: #ifdef HAVE_BSD_AUTH_H
1.27 millert 888: case 'a':
1.34 millert 889: login_style = optarg;
890: break;
891: #endif
892: case 'b':
893: SET(flags, MODE_BACKGROUND);
894: break;
895: case 'C':
896: if ((user_closefrom = atoi(optarg)) < 3) {
897: warningx("the argument to -C must be at least 3");
1.27 millert 898: usage(1);
1.34 millert 899: }
1.27 millert 900: break;
1.8 millert 901: #ifdef HAVE_LOGIN_CAP_H
1.27 millert 902: case 'c':
1.34 millert 903: login_class = optarg;
1.27 millert 904: def_use_loginclass = TRUE;
905: break;
1.4 millert 906: #endif
1.34 millert 907: case 'E':
908: SET(flags, MODE_PRESERVE_ENV);
1.27 millert 909: break;
910: case 'e':
1.34 millert 911: if (mode && mode != MODE_EDIT)
1.27 millert 912: usage_excl(1);
1.34 millert 913: mode = MODE_EDIT;
1.38 millert 914: valid_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE;
1.34 millert 915: break;
916: case 'g':
917: runas_group = optarg;
918: break;
919: case 'H':
920: SET(flags, MODE_RESET_HOME);
1.27 millert 921: break;
1.34 millert 922: case 'h':
1.38 millert 923: if (mode && mode != MODE_HELP) {
924: if (strcmp(getprogname(), "sudoedit") != 0)
925: usage_excl(1);
926: }
1.34 millert 927: mode = MODE_HELP;
1.38 millert 928: valid_flags = 0;
1.27 millert 929: break;
930: case 'i':
1.34 millert 931: SET(flags, MODE_LOGIN_SHELL);
1.27 millert 932: def_env_reset = TRUE;
933: break;
934: case 'k':
1.38 millert 935: SET(flags, MODE_INVALIDATE);
1.27 millert 936: break;
937: case 'K':
1.34 millert 938: if (mode && mode != MODE_KILL)
1.27 millert 939: usage_excl(1);
1.34 millert 940: mode = MODE_KILL;
1.38 millert 941: valid_flags = 0;
1.27 millert 942: break;
943: case 'L':
1.34 millert 944: if (mode && mode != MODE_LISTDEFS)
1.27 millert 945: usage_excl(1);
1.34 millert 946: mode = MODE_LISTDEFS;
1.38 millert 947: valid_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE;
1.27 millert 948: break;
949: case 'l':
1.34 millert 950: if (mode) {
951: if (mode == MODE_LIST)
952: long_list = 1;
953: else
954: usage_excl(1);
955: }
956: mode = MODE_LIST;
1.38 millert 957: valid_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE;
1.27 millert 958: break;
1.34 millert 959: case 'n':
960: SET(flags, MODE_NONINTERACTIVE);
1.27 millert 961: break;
1.34 millert 962: case 'P':
963: SET(flags, MODE_PRESERVE_GROUPS);
1.27 millert 964: break;
1.34 millert 965: case 'p':
966: user_prompt = optarg;
967: def_passprompt_override = TRUE;
1.27 millert 968: break;
1.34 millert 969: #ifdef HAVE_SELINUX
970: case 'r':
971: user_role = optarg;
1.27 millert 972: break;
1.34 millert 973: case 't':
974: user_type = optarg;
1.27 millert 975: break;
1.34 millert 976: #endif
1.27 millert 977: case 'S':
978: SET(tgetpass_flags, TGP_STDIN);
979: break;
1.34 millert 980: case 's':
981: SET(flags, MODE_SHELL);
982: break;
983: case 'U':
984: if ((list_pw = sudo_getpwnam(optarg)) == NULL)
985: errorx(1, "unknown user: %s", optarg);
986: break;
987: case 'u':
988: runas_user = optarg;
1.27 millert 989: break;
1.34 millert 990: case 'v':
991: if (mode && mode != MODE_VALIDATE)
992: usage_excl(1);
993: mode = MODE_VALIDATE;
1.38 millert 994: valid_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE;
1.33 millert 995: break;
1.34 millert 996: case 'V':
997: if (mode && mode != MODE_VERSION)
998: usage_excl(1);
999: mode = MODE_VERSION;
1.38 millert 1000: valid_flags = 0;
1.33 millert 1001: break;
1.27 millert 1002: default:
1003: usage(1);
1004: }
1.34 millert 1005: } else if (!got_end_of_args && is_envar) {
1.27 millert 1006: struct list_member *ev;
1.34 millert 1007:
1008: /* Store environment variable. */
1.27 millert 1009: ev = emalloc(sizeof(*ev));
1.34 millert 1010: ev->value = argv[optind];
1.27 millert 1011: ev->next = sudo_user.env_vars;
1012: sudo_user.env_vars = ev;
1.34 millert 1013:
1014: /* Crank optind and resume getopt. */
1015: optind++;
1.27 millert 1016: } else {
1.34 millert 1017: /* Not an option or an environment variable -- we're done. */
1.27 millert 1018: break;
1.1 millert 1019: }
1020: }
1.27 millert 1021:
1.34 millert 1022: NewArgc = argc - optind;
1023: NewArgv = argv + optind;
1024:
1.38 millert 1025: if (!mode) {
1026: /* Defer -k mode setting until we know whether it is a flag or not */
1027: if (ISSET(flags, MODE_INVALIDATE) && NewArgc == 0) {
1028: mode = MODE_INVALIDATE; /* -k by itself */
1029: CLR(flags, MODE_INVALIDATE);
1030: valid_flags = 0;
1031: } else {
1032: mode = MODE_RUN; /* running a command */
1033: }
1034: }
1.34 millert 1035:
1036: if (NewArgc > 0 && mode == MODE_LIST)
1037: mode = MODE_CHECK;
1038:
1039: if (ISSET(flags, MODE_LOGIN_SHELL)) {
1040: if (ISSET(flags, MODE_SHELL)) {
1041: warningx("you may not specify both the `-i' and `-s' options");
1042: usage(1);
1043: }
1044: if (ISSET(flags, MODE_PRESERVE_ENV)) {
1045: warningx("you may not specify both the `-i' and `-E' options");
1046: usage(1);
1047: }
1048: SET(flags, MODE_SHELL);
1049: }
1.38 millert 1050: if ((flags & valid_flags) != flags)
1051: usage(1);
1.34 millert 1052: if (mode == MODE_EDIT &&
1053: (ISSET(flags, MODE_PRESERVE_ENV) || sudo_user.env_vars != NULL)) {
1054: if (ISSET(mode, MODE_PRESERVE_ENV))
1055: warningx("the `-E' option is not valid in edit mode");
1.27 millert 1056: if (sudo_user.env_vars != NULL)
1.34 millert 1057: warningx("you may not specify environment variables in edit mode");
1058: usage(1);
1059: }
1060: if ((runas_user != NULL || runas_group != NULL) &&
1061: !ISSET(mode, MODE_EDIT | MODE_RUN | MODE_CHECK)) {
1.27 millert 1062: usage(1);
1063: }
1.34 millert 1064: if (list_pw != NULL && mode != MODE_LIST && mode != MODE_CHECK) {
1065: warningx("the `-U' option may only be used with the `-l' option");
1.33 millert 1066: usage(1);
1067: }
1.34 millert 1068: if (ISSET(tgetpass_flags, TGP_STDIN) && ISSET(tgetpass_flags, TGP_ASKPASS)) {
1069: warningx("the `-A' and `-S' options may not be used together");
1.24 millert 1070: usage(1);
1071: }
1.34 millert 1072: if ((NewArgc == 0 && mode == MODE_EDIT) ||
1073: (NewArgc > 0 && !ISSET(mode, MODE_RUN | MODE_EDIT | MODE_CHECK)))
1.1 millert 1074: usage(1);
1.34 millert 1075: if (NewArgc == 0 && mode == MODE_RUN && !ISSET(flags, MODE_SHELL))
1076: SET(flags, (MODE_IMPLIED_SHELL | MODE_SHELL));
1.1 millert 1077:
1.34 millert 1078: return(mode | flags);
1.1 millert 1079: }
1080:
1081: /*
1.34 millert 1082: * Open sudoers and sanity check mode/owner/type.
1083: * Returns a handle to the sudoers file or NULL on error.
1.1 millert 1084: */
1.34 millert 1085: FILE *
1.39 millert 1086: open_sudoers(sudoers, doedit, keepopen)
1.34 millert 1087: const char *sudoers;
1.39 millert 1088: int doedit;
1.34 millert 1089: int *keepopen;
1.1 millert 1090: {
1091: struct stat statbuf;
1.34 millert 1092: FILE *fp = NULL;
1093: int rootstat;
1.1 millert 1094:
1095: /*
1096: * Fix the mode and group on sudoers file from old default.
1.23 millert 1097: * Only works if file system is readable/writable by root.
1.1 millert 1098: */
1.34 millert 1099: if ((rootstat = stat_sudoers(sudoers, &statbuf)) == 0 &&
1.1 millert 1100: SUDOERS_UID == statbuf.st_uid && SUDOERS_MODE != 0400 &&
1101: (statbuf.st_mode & 0007777) == 0400) {
1102:
1.34 millert 1103: if (chmod(sudoers, SUDOERS_MODE) == 0) {
1104: warningx("fixed mode on %s", sudoers);
1.23 millert 1105: SET(statbuf.st_mode, SUDOERS_MODE);
1.1 millert 1106: if (statbuf.st_gid != SUDOERS_GID) {
1.34 millert 1107: if (chown(sudoers, (uid_t) -1, SUDOERS_GID) == 0) {
1108: warningx("set group on %s", sudoers);
1.1 millert 1109: statbuf.st_gid = SUDOERS_GID;
1.19 millert 1110: } else
1.34 millert 1111: warning("unable to set group on %s", sudoers);
1.1 millert 1112: }
1.19 millert 1113: } else
1.34 millert 1114: warning("unable to fix mode on %s", sudoers);
1.1 millert 1115: }
1116:
1117: /*
1118: * Sanity checks on sudoers file. Must be done as sudoers
1119: * file owner. We already did a stat as root, so use that
1120: * data if we can't stat as sudoers file owner.
1121: */
1.17 millert 1122: set_perms(PERM_SUDOERS);
1.1 millert 1123:
1.34 millert 1124: if (rootstat != 0 && stat_sudoers(sudoers, &statbuf) != 0)
1125: log_error(USE_ERRNO|NO_EXIT, "can't stat %s", sudoers);
1.1 millert 1126: else if (!S_ISREG(statbuf.st_mode))
1.34 millert 1127: log_error(NO_EXIT, "%s is not a regular file", sudoers);
1.1 millert 1128: else if ((statbuf.st_mode & 07777) != SUDOERS_MODE)
1.34 millert 1129: log_error(NO_EXIT, "%s is mode 0%o, should be 0%o", sudoers,
1.27 millert 1130: (unsigned int) (statbuf.st_mode & 07777),
1131: (unsigned int) SUDOERS_MODE);
1.1 millert 1132: else if (statbuf.st_uid != SUDOERS_UID)
1.34 millert 1133: log_error(NO_EXIT, "%s is owned by uid %lu, should be %lu", sudoers,
1.25 millert 1134: (unsigned long) statbuf.st_uid, (unsigned long) SUDOERS_UID);
1.1 millert 1135: else if (statbuf.st_gid != SUDOERS_GID)
1.34 millert 1136: log_error(NO_EXIT, "%s is owned by gid %lu, should be %lu", sudoers,
1.25 millert 1137: (unsigned long) statbuf.st_gid, (unsigned long) SUDOERS_GID);
1.34 millert 1138: else if ((fp = fopen(sudoers, "r")) == NULL)
1.40 millert 1139: log_error(USE_ERRNO|NO_EXIT, "can't open %s", sudoers);
1.37 millert 1140: else {
1.34 millert 1141: /*
1142: * Make sure we can actually read sudoers so we can present the
1.37 millert 1143: * user with a reasonable error message (unlike the lexer).
1.34 millert 1144: */
1.40 millert 1145: if (statbuf.st_size != 0 && fgetc(fp) == EOF) {
1146: log_error(USE_ERRNO|NO_EXIT, "can't read %s", sudoers);
1147: fclose(fp);
1148: fp = NULL;
1.37 millert 1149: }
1.40 millert 1150: }
1151:
1152: if (fp != NULL) {
1153: rewind(fp);
1.37 millert 1154: (void) fcntl(fileno(fp), F_SETFD, 1);
1.1 millert 1155: }
1156:
1.17 millert 1157: set_perms(PERM_ROOT); /* change back to root */
1.34 millert 1158: return(fp);
1.1 millert 1159: }
1160:
1161: /*
1162: * Close all open files (except std*) and turn off core dumps.
1.34 millert 1163: * Also sets the set_perms() pointer to the correct function.
1.1 millert 1164: */
1165: static void
1166: initial_setup()
1167: {
1.27 millert 1168: int miss[3], devnull = -1;
1.33 millert 1169: #if defined(__linux__) || (defined(RLIMIT_CORE) && !defined(SUDO_DEVEL))
1.1 millert 1170: struct rlimit rl;
1.33 millert 1171: #endif
1.1 millert 1172:
1.33 millert 1173: #if defined(__linux__)
1174: /*
1175: * Unlimit the number of processes since Linux's setuid() will
1176: * apply resource limits when changing uid and return EAGAIN if
1177: * nproc would be violated by the uid switch.
1178: */
1179: rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
1180: if (setrlimit(RLIMIT_NPROC, &rl)) {
1181: if (getrlimit(RLIMIT_NPROC, &rl) == 0) {
1182: rl.rlim_cur = rl.rlim_max;
1183: (void)setrlimit(RLIMIT_NPROC, &rl);
1184: }
1185: }
1186: #endif /* __linux__ */
1187: #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
1.1 millert 1188: /*
1189: * Turn off core dumps.
1190: */
1.4 millert 1191: (void) getrlimit(RLIMIT_CORE, &corelimit);
1.20 millert 1192: memcpy(&rl, &corelimit, sizeof(struct rlimit));
1193: rl.rlim_cur = 0;
1.1 millert 1194: (void) setrlimit(RLIMIT_CORE, &rl);
1.20 millert 1195: #endif /* RLIMIT_CORE && !SUDO_DEVEL */
1.1 millert 1196:
1.17 millert 1197: /*
1.27 millert 1198: * stdin, stdout and stderr must be open; set them to /dev/null
1199: * if they are closed and close all other fds.
1.17 millert 1200: */
1.27 millert 1201: miss[STDIN_FILENO] = fcntl(STDIN_FILENO, F_GETFL, 0) == -1;
1202: miss[STDOUT_FILENO] = fcntl(STDOUT_FILENO, F_GETFL, 0) == -1;
1203: miss[STDERR_FILENO] = fcntl(STDERR_FILENO, F_GETFL, 0) == -1;
1204: if (miss[STDIN_FILENO] || miss[STDOUT_FILENO] || miss[STDERR_FILENO]) {
1205: if ((devnull = open(_PATH_DEVNULL, O_RDWR, 0644)) != -1) {
1206: if (miss[STDIN_FILENO])
1207: (void) dup2(devnull, STDIN_FILENO);
1208: if (miss[STDOUT_FILENO])
1209: (void) dup2(devnull, STDOUT_FILENO);
1210: if (miss[STDERR_FILENO])
1211: (void) dup2(devnull, STDERR_FILENO);
1.34 millert 1212: if (devnull > STDERR_FILENO)
1213: close(devnull);
1.27 millert 1214: }
1215: }
1.1 millert 1216: }
1217:
1.8 millert 1218: #ifdef HAVE_LOGIN_CAP_H
1219: static void
1.4 millert 1220: set_loginclass(pw)
1221: struct passwd *pw;
1222: {
1223: int errflags;
1224:
1225: /*
1226: * Don't make it a fatal error if the user didn't specify the login
1227: * class themselves. We do this because if login.conf gets
1228: * corrupted we want the admin to be able to use sudo to fix it.
1229: */
1230: if (login_class)
1231: errflags = NO_MAIL|MSG_ONLY;
1232: else
1233: errflags = NO_MAIL|MSG_ONLY|NO_EXIT;
1234:
1235: if (login_class && strcmp(login_class, "-") != 0) {
1.34 millert 1236: if (user_uid != 0 &&
1237: strcmp(runas_user ? runas_user : def_runas_default, "root") != 0)
1238: errorx(1, "only root can use -c %s", login_class);
1.4 millert 1239: } else {
1240: login_class = pw->pw_class;
1241: if (!login_class || !*login_class)
1242: login_class =
1243: (pw->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS;
1244: }
1245:
1246: lc = login_getclass(login_class);
1.10 millert 1247: if (!lc || !lc->lc_class || strcmp(lc->lc_class, login_class) != 0) {
1.4 millert 1248: log_error(errflags, "unknown login class: %s", login_class);
1.11 millert 1249: if (!lc)
1250: lc = login_getclass(NULL); /* needed for login_getstyle() later */
1.10 millert 1251: }
1.4 millert 1252: }
1253: #else
1.8 millert 1254: static void
1.4 millert 1255: set_loginclass(pw)
1256: struct passwd *pw;
1257: {
1258: }
1.8 millert 1259: #endif /* HAVE_LOGIN_CAP_H */
1.4 millert 1260:
1.27 millert 1261: #ifdef HAVE_PROJECT_H
1262: static void
1263: set_project(pw)
1264: struct passwd *pw;
1265: {
1266: int errflags = NO_MAIL|MSG_ONLY|NO_EXIT;
1267: int errval;
1268: struct project proj;
1269: struct project *resultp = '\0';
1270: char buf[1024];
1271:
1272: /*
1273: * Collect the default project for the user and settaskid
1274: */
1275: setprojent();
1276: if (resultp = getdefaultproj(pw->pw_name, &proj, buf, sizeof(buf))) {
1277: errval = setproject(resultp->pj_name, pw->pw_name, TASK_NORMAL);
1278: if (errval != 0) {
1279: switch(errval) {
1280: case SETPROJ_ERR_TASK:
1281: if (errno == EAGAIN)
1282: log_error(errflags, "resource control limit has been reached");
1283: else if (errno == ESRCH)
1284: log_error(errflags, "user \"%s\" is not a member of "
1285: "project \"%s\"", pw->pw_name, resultp->pj_name);
1286: else if (errno == EACCES)
1287: log_error(errflags, "the invoking task is final");
1288: else
1289: log_error(errflags, "could not join project \"%s\"",
1290: resultp->pj_name);
1291: break;
1292: case SETPROJ_ERR_POOL:
1293: if (errno == EACCES)
1294: log_error(errflags, "no resource pool accepting "
1295: "default bindings exists for project \"%s\"",
1296: resultp->pj_name);
1297: else if (errno == ESRCH)
1298: log_error(errflags, "specified resource pool does "
1299: "not exist for project \"%s\"", resultp->pj_name);
1300: else
1301: log_error(errflags, "could not bind to default "
1302: "resource pool for project \"%s\"", resultp->pj_name);
1303: break;
1304: default:
1305: if (errval <= 0) {
1306: log_error(errflags, "setproject failed for project \"%s\"",
1307: resultp->pj_name);
1308: } else {
1309: log_error(errflags, "warning, resource control assignment "
1310: "failed for project \"%s\"", resultp->pj_name);
1311: }
1312: }
1313: }
1314: } else {
1315: log_error(errflags, "getdefaultproj() error: %s", strerror(errno));
1316: }
1317: endprojent();
1318: }
1319: #else
1320: static void
1321: set_project(pw)
1322: struct passwd *pw;
1323: {
1324: }
1325: #endif /* HAVE_PROJECT_H */
1326:
1.1 millert 1327: /*
1.2 millert 1328: * Look up the fully qualified domain name and set user_host and user_shost.
1329: */
1330: void
1331: set_fqdn()
1332: {
1.28 millert 1333: #ifdef HAVE_GETADDRINFO
1334: struct addrinfo *res0, hint;
1335: #else
1.2 millert 1336: struct hostent *hp;
1.28 millert 1337: #endif
1.2 millert 1338: char *p;
1339:
1.28 millert 1340: #ifdef HAVE_GETADDRINFO
1.34 millert 1341: zero_bytes(&hint, sizeof(hint));
1.28 millert 1342: hint.ai_family = PF_UNSPEC;
1343: hint.ai_flags = AI_CANONNAME;
1344: if (getaddrinfo(user_host, NULL, &hint, &res0) != 0) {
1345: #else
1.14 millert 1346: if (!(hp = gethostbyname(user_host))) {
1.28 millert 1347: #endif
1.14 millert 1348: log_error(MSG_ONLY|NO_EXIT,
1.28 millert 1349: "unable to resolve host %s", user_host);
1.14 millert 1350: } else {
1351: if (user_shost != user_host)
1.27 millert 1352: efree(user_shost);
1353: efree(user_host);
1.28 millert 1354: #ifdef HAVE_GETADDRINFO
1355: user_host = estrdup(res0->ai_canonname);
1356: freeaddrinfo(res0);
1357: #else
1.14 millert 1358: user_host = estrdup(hp->h_name);
1.28 millert 1359: #endif
1.2 millert 1360: }
1361: if ((p = strchr(user_host, '.'))) {
1362: *p = '\0';
1363: user_shost = estrdup(user_host);
1364: *p = '.';
1365: } else {
1366: user_shost = user_host;
1367: }
1368: }
1369:
1370: /*
1.23 millert 1371: * Get passwd entry for the user we are going to run commands as.
1372: * By default, this is "root". Updates runas_pw as a side effect.
1373: */
1.34 millert 1374: static void
1.23 millert 1375: set_runaspw(user)
1376: char *user;
1377: {
1.34 millert 1378: if (*user == '#') {
1379: if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL)
1380: runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0);
1381: } else {
1.38 millert 1382: if ((runas_pw = sudo_getpwnam(user)) == NULL) {
1383: audit_failure(NewArgv, "unknown user: %s", user);
1.34 millert 1384: log_error(NO_MAIL|MSG_ONLY, "unknown user: %s", user);
1.38 millert 1385: }
1.23 millert 1386: }
1.34 millert 1387: }
1388:
1389: /*
1390: * Get group entry for the group we are going to run commands as.
1391: * Updates runas_pw as a side effect.
1392: */
1393: static void
1394: set_runasgr(group)
1395: char *group;
1396: {
1397: if (*group == '#') {
1398: if ((runas_gr = sudo_getgrgid(atoi(group + 1))) == NULL)
1399: runas_gr = sudo_fakegrnam(group);
1.23 millert 1400: } else {
1.34 millert 1401: if ((runas_gr = sudo_getgrnam(group)) == NULL)
1402: log_error(NO_MAIL|MSG_ONLY, "unknown group: %s", group);
1.23 millert 1403: }
1404: }
1405:
1406: /*
1.6 millert 1407: * Get passwd entry for the user we are going to authenticate as.
1.23 millert 1408: * By default, this is the user invoking sudo. In the most common
1409: * case, this matches sudo_user.pw or runas_pw.
1.4 millert 1410: */
1.6 millert 1411: static struct passwd *
1412: get_authpw()
1.4 millert 1413: {
1414: struct passwd *pw;
1415:
1.23 millert 1416: if (def_rootpw) {
1.34 millert 1417: if ((pw = sudo_getpwuid(0)) == NULL)
1418: log_error(0, "unknown uid: 0");
1.23 millert 1419: } else if (def_runaspw) {
1.34 millert 1420: if ((pw = sudo_getpwnam(def_runas_default)) == NULL)
1421: log_error(0, "unknown user: %s", def_runas_default);
1.23 millert 1422: } else if (def_targetpw) {
1423: if (runas_pw->pw_name == NULL)
1.34 millert 1424: log_error(NO_MAIL|MSG_ONLY, "unknown uid: %lu",
1.25 millert 1425: (unsigned long) runas_pw->pw_uid);
1.23 millert 1426: pw = runas_pw;
1.6 millert 1427: } else
1428: pw = sudo_user.pw;
1429:
1430: return(pw);
1.4 millert 1431: }
1432:
1433: /*
1.34 millert 1434: * Cleanup hook for error()/errorx()
1435: */
1436: void
1437: cleanup(gotsignal)
1438: int gotsignal;
1439: {
1440: struct sudo_nss *nss;
1441:
1442: if (!gotsignal) {
1443: if (snl != NULL) {
1444: tq_foreach_fwd(snl, nss)
1445: nss->close(nss);
1446: }
1.43 ! millert 1447: #ifdef USING_NONUNIX_GROUPS
! 1448: sudo_nonunix_groupcheck_cleanup();
! 1449: #endif
1.34 millert 1450: sudo_endpwent();
1451: sudo_endgrent();
1452: }
1453: }
1454:
1455: static void
1456: show_version()
1457: {
1.39 millert 1458: (void) printf("Sudo version %s\n", PACKAGE_VERSION);
1.34 millert 1459: if (getuid() == 0) {
1460: putchar('\n');
1461: (void) printf("Sudoers path: %s\n", _PATH_SUDOERS);
1462: #ifdef HAVE_LDAP
1463: # ifdef _PATH_NSSWITCH_CONF
1464: (void) printf("nsswitch path: %s\n", _PATH_NSSWITCH_CONF);
1465: # endif
1466: (void) printf("ldap.conf path: %s\n", _PATH_LDAP_CONF);
1467: (void) printf("ldap.secret path: %s\n", _PATH_LDAP_SECRET);
1468: #endif
1469: dump_auth_methods();
1470: dump_defaults();
1471: dump_interfaces();
1472: }
1473: exit(0);
1474: }
1475:
1476: /*
1.1 millert 1477: * Tell which options are mutually exclusive and exit.
1478: */
1479: static void
1480: usage_excl(exit_val)
1481: int exit_val;
1482: {
1.38 millert 1483: warningx("Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified");
1.1 millert 1484: usage(exit_val);
1485: }
1486:
1487: /*
1488: * Give usage message and exit.
1.34 millert 1489: * The actual usage strings are in sudo_usage.h for configure substitution.
1.1 millert 1490: */
1491: static void
1492: usage(exit_val)
1493: int exit_val;
1494: {
1.34 millert 1495: struct lbuf lbuf;
1.38 millert 1496: char *uvec[6];
1.34 millert 1497: int i, ulen;
1.23 millert 1498:
1499: /*
1.27 millert 1500: * Use usage vectors appropriate to the progname.
1.23 millert 1501: */
1502: if (strcmp(getprogname(), "sudoedit") == 0) {
1.38 millert 1503: uvec[0] = SUDO_USAGE5 + 3;
1.27 millert 1504: uvec[1] = NULL;
1.23 millert 1505: } else {
1.34 millert 1506: uvec[0] = SUDO_USAGE1;
1507: uvec[1] = SUDO_USAGE2;
1508: uvec[2] = SUDO_USAGE3;
1509: uvec[3] = SUDO_USAGE4;
1.38 millert 1510: uvec[4] = SUDO_USAGE5;
1511: uvec[5] = NULL;
1.23 millert 1512: }
1513:
1514: /*
1.34 millert 1515: * Print usage and wrap lines as needed, depending on the
1516: * tty width.
1.23 millert 1517: */
1.34 millert 1518: ulen = (int)strlen(getprogname()) + 8;
1519: lbuf_init(&lbuf, NULL, ulen, 0);
1.27 millert 1520: for (i = 0; uvec[i] != NULL; i++) {
1.34 millert 1521: lbuf_append(&lbuf, "usage: ", getprogname(), uvec[i], NULL);
1522: lbuf_print(&lbuf);
1.23 millert 1523: }
1.34 millert 1524: lbuf_destroy(&lbuf);
1.1 millert 1525: exit(exit_val);
1526: }