Annotation of src/usr.bin/sudo/sudo.c, Revision 1.48
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. */
1.45 millert 308: set_loginclass(runas_pw ? runas_pw : 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;
1.1 millert 1093:
1094: /*
1095: * Sanity checks on sudoers file. Must be done as sudoers
1096: * file owner. We already did a stat as root, so use that
1097: * data if we can't stat as sudoers file owner.
1098: */
1.17 millert 1099: set_perms(PERM_SUDOERS);
1.1 millert 1100:
1.44 millert 1101: if (stat_sudoers(sudoers, &statbuf) != 0)
1.34 millert 1102: log_error(USE_ERRNO|NO_EXIT, "can't stat %s", sudoers);
1.1 millert 1103: else if (!S_ISREG(statbuf.st_mode))
1.34 millert 1104: log_error(NO_EXIT, "%s is not a regular file", sudoers);
1.1 millert 1105: else if ((statbuf.st_mode & 07777) != SUDOERS_MODE)
1.34 millert 1106: log_error(NO_EXIT, "%s is mode 0%o, should be 0%o", sudoers,
1.27 millert 1107: (unsigned int) (statbuf.st_mode & 07777),
1108: (unsigned int) SUDOERS_MODE);
1.1 millert 1109: else if (statbuf.st_uid != SUDOERS_UID)
1.34 millert 1110: log_error(NO_EXIT, "%s is owned by uid %lu, should be %lu", sudoers,
1.25 millert 1111: (unsigned long) statbuf.st_uid, (unsigned long) SUDOERS_UID);
1.1 millert 1112: else if (statbuf.st_gid != SUDOERS_GID)
1.34 millert 1113: log_error(NO_EXIT, "%s is owned by gid %lu, should be %lu", sudoers,
1.25 millert 1114: (unsigned long) statbuf.st_gid, (unsigned long) SUDOERS_GID);
1.34 millert 1115: else if ((fp = fopen(sudoers, "r")) == NULL)
1.40 millert 1116: log_error(USE_ERRNO|NO_EXIT, "can't open %s", sudoers);
1.37 millert 1117: else {
1.34 millert 1118: /*
1119: * Make sure we can actually read sudoers so we can present the
1.37 millert 1120: * user with a reasonable error message (unlike the lexer).
1.34 millert 1121: */
1.40 millert 1122: if (statbuf.st_size != 0 && fgetc(fp) == EOF) {
1123: log_error(USE_ERRNO|NO_EXIT, "can't read %s", sudoers);
1124: fclose(fp);
1125: fp = NULL;
1.37 millert 1126: }
1.40 millert 1127: }
1128:
1129: if (fp != NULL) {
1130: rewind(fp);
1.46 okan 1131: (void) fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
1.1 millert 1132: }
1133:
1.17 millert 1134: set_perms(PERM_ROOT); /* change back to root */
1.34 millert 1135: return(fp);
1.1 millert 1136: }
1137:
1138: /*
1139: * Close all open files (except std*) and turn off core dumps.
1.34 millert 1140: * Also sets the set_perms() pointer to the correct function.
1.1 millert 1141: */
1142: static void
1143: initial_setup()
1144: {
1.27 millert 1145: int miss[3], devnull = -1;
1.33 millert 1146: #if defined(__linux__) || (defined(RLIMIT_CORE) && !defined(SUDO_DEVEL))
1.1 millert 1147: struct rlimit rl;
1.33 millert 1148: #endif
1.1 millert 1149:
1.33 millert 1150: #if defined(__linux__)
1151: /*
1152: * Unlimit the number of processes since Linux's setuid() will
1153: * apply resource limits when changing uid and return EAGAIN if
1154: * nproc would be violated by the uid switch.
1155: */
1156: rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
1157: if (setrlimit(RLIMIT_NPROC, &rl)) {
1158: if (getrlimit(RLIMIT_NPROC, &rl) == 0) {
1159: rl.rlim_cur = rl.rlim_max;
1160: (void)setrlimit(RLIMIT_NPROC, &rl);
1161: }
1162: }
1163: #endif /* __linux__ */
1164: #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
1.1 millert 1165: /*
1166: * Turn off core dumps.
1167: */
1.4 millert 1168: (void) getrlimit(RLIMIT_CORE, &corelimit);
1.20 millert 1169: memcpy(&rl, &corelimit, sizeof(struct rlimit));
1170: rl.rlim_cur = 0;
1.1 millert 1171: (void) setrlimit(RLIMIT_CORE, &rl);
1.20 millert 1172: #endif /* RLIMIT_CORE && !SUDO_DEVEL */
1.1 millert 1173:
1.17 millert 1174: /*
1.27 millert 1175: * stdin, stdout and stderr must be open; set them to /dev/null
1176: * if they are closed and close all other fds.
1.17 millert 1177: */
1.27 millert 1178: miss[STDIN_FILENO] = fcntl(STDIN_FILENO, F_GETFL, 0) == -1;
1179: miss[STDOUT_FILENO] = fcntl(STDOUT_FILENO, F_GETFL, 0) == -1;
1180: miss[STDERR_FILENO] = fcntl(STDERR_FILENO, F_GETFL, 0) == -1;
1181: if (miss[STDIN_FILENO] || miss[STDOUT_FILENO] || miss[STDERR_FILENO]) {
1182: if ((devnull = open(_PATH_DEVNULL, O_RDWR, 0644)) != -1) {
1183: if (miss[STDIN_FILENO])
1184: (void) dup2(devnull, STDIN_FILENO);
1185: if (miss[STDOUT_FILENO])
1186: (void) dup2(devnull, STDOUT_FILENO);
1187: if (miss[STDERR_FILENO])
1188: (void) dup2(devnull, STDERR_FILENO);
1.34 millert 1189: if (devnull > STDERR_FILENO)
1190: close(devnull);
1.27 millert 1191: }
1192: }
1.1 millert 1193: }
1194:
1.8 millert 1195: #ifdef HAVE_LOGIN_CAP_H
1196: static void
1.4 millert 1197: set_loginclass(pw)
1198: struct passwd *pw;
1199: {
1200: int errflags;
1201:
1.47 millert 1202: if (!def_use_loginclass)
1203: return;
1204:
1.4 millert 1205: /*
1206: * Don't make it a fatal error if the user didn't specify the login
1207: * class themselves. We do this because if login.conf gets
1208: * corrupted we want the admin to be able to use sudo to fix it.
1209: */
1210: if (login_class)
1211: errflags = NO_MAIL|MSG_ONLY;
1212: else
1213: errflags = NO_MAIL|MSG_ONLY|NO_EXIT;
1214:
1215: if (login_class && strcmp(login_class, "-") != 0) {
1.48 ! millert 1216: if (user_uid != 0 && pw->pw_uid != 0)
1.34 millert 1217: errorx(1, "only root can use -c %s", login_class);
1.4 millert 1218: } else {
1219: login_class = pw->pw_class;
1220: if (!login_class || !*login_class)
1221: login_class =
1222: (pw->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS;
1223: }
1224:
1.47 millert 1225: /* Make sure specified login class is valid. */
1.4 millert 1226: lc = login_getclass(login_class);
1.10 millert 1227: if (!lc || !lc->lc_class || strcmp(lc->lc_class, login_class) != 0) {
1.4 millert 1228: log_error(errflags, "unknown login class: %s", login_class);
1.47 millert 1229: def_use_loginclass = FALSE;
1.10 millert 1230: }
1.4 millert 1231: }
1232: #else
1.8 millert 1233: static void
1.4 millert 1234: set_loginclass(pw)
1235: struct passwd *pw;
1236: {
1237: }
1.8 millert 1238: #endif /* HAVE_LOGIN_CAP_H */
1.4 millert 1239:
1.27 millert 1240: #ifdef HAVE_PROJECT_H
1241: static void
1242: set_project(pw)
1243: struct passwd *pw;
1244: {
1245: int errflags = NO_MAIL|MSG_ONLY|NO_EXIT;
1246: int errval;
1247: struct project proj;
1248: struct project *resultp = '\0';
1249: char buf[1024];
1250:
1251: /*
1252: * Collect the default project for the user and settaskid
1253: */
1254: setprojent();
1255: if (resultp = getdefaultproj(pw->pw_name, &proj, buf, sizeof(buf))) {
1256: errval = setproject(resultp->pj_name, pw->pw_name, TASK_NORMAL);
1257: if (errval != 0) {
1258: switch(errval) {
1259: case SETPROJ_ERR_TASK:
1260: if (errno == EAGAIN)
1261: log_error(errflags, "resource control limit has been reached");
1262: else if (errno == ESRCH)
1263: log_error(errflags, "user \"%s\" is not a member of "
1264: "project \"%s\"", pw->pw_name, resultp->pj_name);
1265: else if (errno == EACCES)
1266: log_error(errflags, "the invoking task is final");
1267: else
1268: log_error(errflags, "could not join project \"%s\"",
1269: resultp->pj_name);
1270: break;
1271: case SETPROJ_ERR_POOL:
1272: if (errno == EACCES)
1273: log_error(errflags, "no resource pool accepting "
1274: "default bindings exists for project \"%s\"",
1275: resultp->pj_name);
1276: else if (errno == ESRCH)
1277: log_error(errflags, "specified resource pool does "
1278: "not exist for project \"%s\"", resultp->pj_name);
1279: else
1280: log_error(errflags, "could not bind to default "
1281: "resource pool for project \"%s\"", resultp->pj_name);
1282: break;
1283: default:
1284: if (errval <= 0) {
1285: log_error(errflags, "setproject failed for project \"%s\"",
1286: resultp->pj_name);
1287: } else {
1288: log_error(errflags, "warning, resource control assignment "
1289: "failed for project \"%s\"", resultp->pj_name);
1290: }
1291: }
1292: }
1293: } else {
1294: log_error(errflags, "getdefaultproj() error: %s", strerror(errno));
1295: }
1296: endprojent();
1297: }
1298: #else
1299: static void
1300: set_project(pw)
1301: struct passwd *pw;
1302: {
1303: }
1304: #endif /* HAVE_PROJECT_H */
1305:
1.1 millert 1306: /*
1.2 millert 1307: * Look up the fully qualified domain name and set user_host and user_shost.
1308: */
1309: void
1310: set_fqdn()
1311: {
1.28 millert 1312: #ifdef HAVE_GETADDRINFO
1313: struct addrinfo *res0, hint;
1314: #else
1.2 millert 1315: struct hostent *hp;
1.28 millert 1316: #endif
1.2 millert 1317: char *p;
1318:
1.28 millert 1319: #ifdef HAVE_GETADDRINFO
1.34 millert 1320: zero_bytes(&hint, sizeof(hint));
1.28 millert 1321: hint.ai_family = PF_UNSPEC;
1322: hint.ai_flags = AI_CANONNAME;
1323: if (getaddrinfo(user_host, NULL, &hint, &res0) != 0) {
1324: #else
1.14 millert 1325: if (!(hp = gethostbyname(user_host))) {
1.28 millert 1326: #endif
1.14 millert 1327: log_error(MSG_ONLY|NO_EXIT,
1.28 millert 1328: "unable to resolve host %s", user_host);
1.14 millert 1329: } else {
1330: if (user_shost != user_host)
1.27 millert 1331: efree(user_shost);
1332: efree(user_host);
1.28 millert 1333: #ifdef HAVE_GETADDRINFO
1334: user_host = estrdup(res0->ai_canonname);
1335: freeaddrinfo(res0);
1336: #else
1.14 millert 1337: user_host = estrdup(hp->h_name);
1.28 millert 1338: #endif
1.2 millert 1339: }
1340: if ((p = strchr(user_host, '.'))) {
1341: *p = '\0';
1342: user_shost = estrdup(user_host);
1343: *p = '.';
1344: } else {
1345: user_shost = user_host;
1346: }
1347: }
1348:
1349: /*
1.23 millert 1350: * Get passwd entry for the user we are going to run commands as.
1351: * By default, this is "root". Updates runas_pw as a side effect.
1352: */
1.34 millert 1353: static void
1.23 millert 1354: set_runaspw(user)
1355: char *user;
1356: {
1.34 millert 1357: if (*user == '#') {
1358: if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL)
1359: runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0);
1360: } else {
1.38 millert 1361: if ((runas_pw = sudo_getpwnam(user)) == NULL) {
1362: audit_failure(NewArgv, "unknown user: %s", user);
1.34 millert 1363: log_error(NO_MAIL|MSG_ONLY, "unknown user: %s", user);
1.38 millert 1364: }
1.23 millert 1365: }
1.34 millert 1366: }
1367:
1368: /*
1369: * Get group entry for the group we are going to run commands as.
1370: * Updates runas_pw as a side effect.
1371: */
1372: static void
1373: set_runasgr(group)
1374: char *group;
1375: {
1376: if (*group == '#') {
1377: if ((runas_gr = sudo_getgrgid(atoi(group + 1))) == NULL)
1378: runas_gr = sudo_fakegrnam(group);
1.23 millert 1379: } else {
1.34 millert 1380: if ((runas_gr = sudo_getgrnam(group)) == NULL)
1381: log_error(NO_MAIL|MSG_ONLY, "unknown group: %s", group);
1.23 millert 1382: }
1383: }
1384:
1385: /*
1.6 millert 1386: * Get passwd entry for the user we are going to authenticate as.
1.23 millert 1387: * By default, this is the user invoking sudo. In the most common
1388: * case, this matches sudo_user.pw or runas_pw.
1.4 millert 1389: */
1.6 millert 1390: static struct passwd *
1391: get_authpw()
1.4 millert 1392: {
1393: struct passwd *pw;
1394:
1.23 millert 1395: if (def_rootpw) {
1.34 millert 1396: if ((pw = sudo_getpwuid(0)) == NULL)
1397: log_error(0, "unknown uid: 0");
1.23 millert 1398: } else if (def_runaspw) {
1.34 millert 1399: if ((pw = sudo_getpwnam(def_runas_default)) == NULL)
1400: log_error(0, "unknown user: %s", def_runas_default);
1.23 millert 1401: } else if (def_targetpw) {
1402: if (runas_pw->pw_name == NULL)
1.34 millert 1403: log_error(NO_MAIL|MSG_ONLY, "unknown uid: %lu",
1.25 millert 1404: (unsigned long) runas_pw->pw_uid);
1.23 millert 1405: pw = runas_pw;
1.6 millert 1406: } else
1407: pw = sudo_user.pw;
1408:
1409: return(pw);
1.4 millert 1410: }
1411:
1412: /*
1.34 millert 1413: * Cleanup hook for error()/errorx()
1414: */
1415: void
1416: cleanup(gotsignal)
1417: int gotsignal;
1418: {
1419: struct sudo_nss *nss;
1420:
1421: if (!gotsignal) {
1422: if (snl != NULL) {
1423: tq_foreach_fwd(snl, nss)
1424: nss->close(nss);
1425: }
1.43 millert 1426: #ifdef USING_NONUNIX_GROUPS
1427: sudo_nonunix_groupcheck_cleanup();
1428: #endif
1.34 millert 1429: sudo_endpwent();
1430: sudo_endgrent();
1431: }
1432: }
1433:
1434: static void
1435: show_version()
1436: {
1.39 millert 1437: (void) printf("Sudo version %s\n", PACKAGE_VERSION);
1.34 millert 1438: if (getuid() == 0) {
1439: putchar('\n');
1440: (void) printf("Sudoers path: %s\n", _PATH_SUDOERS);
1441: #ifdef HAVE_LDAP
1442: # ifdef _PATH_NSSWITCH_CONF
1443: (void) printf("nsswitch path: %s\n", _PATH_NSSWITCH_CONF);
1444: # endif
1445: (void) printf("ldap.conf path: %s\n", _PATH_LDAP_CONF);
1446: (void) printf("ldap.secret path: %s\n", _PATH_LDAP_SECRET);
1447: #endif
1448: dump_auth_methods();
1449: dump_defaults();
1450: dump_interfaces();
1451: }
1452: exit(0);
1453: }
1454:
1455: /*
1.1 millert 1456: * Tell which options are mutually exclusive and exit.
1457: */
1458: static void
1459: usage_excl(exit_val)
1460: int exit_val;
1461: {
1.38 millert 1462: warningx("Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified");
1.1 millert 1463: usage(exit_val);
1464: }
1465:
1466: /*
1467: * Give usage message and exit.
1.34 millert 1468: * The actual usage strings are in sudo_usage.h for configure substitution.
1.1 millert 1469: */
1470: static void
1471: usage(exit_val)
1472: int exit_val;
1473: {
1.34 millert 1474: struct lbuf lbuf;
1.38 millert 1475: char *uvec[6];
1.34 millert 1476: int i, ulen;
1.23 millert 1477:
1478: /*
1.27 millert 1479: * Use usage vectors appropriate to the progname.
1.23 millert 1480: */
1481: if (strcmp(getprogname(), "sudoedit") == 0) {
1.38 millert 1482: uvec[0] = SUDO_USAGE5 + 3;
1.27 millert 1483: uvec[1] = NULL;
1.23 millert 1484: } else {
1.34 millert 1485: uvec[0] = SUDO_USAGE1;
1486: uvec[1] = SUDO_USAGE2;
1487: uvec[2] = SUDO_USAGE3;
1488: uvec[3] = SUDO_USAGE4;
1.38 millert 1489: uvec[4] = SUDO_USAGE5;
1490: uvec[5] = NULL;
1.23 millert 1491: }
1492:
1493: /*
1.34 millert 1494: * Print usage and wrap lines as needed, depending on the
1495: * tty width.
1.23 millert 1496: */
1.34 millert 1497: ulen = (int)strlen(getprogname()) + 8;
1498: lbuf_init(&lbuf, NULL, ulen, 0);
1.27 millert 1499: for (i = 0; uvec[i] != NULL; i++) {
1.34 millert 1500: lbuf_append(&lbuf, "usage: ", getprogname(), uvec[i], NULL);
1501: lbuf_print(&lbuf);
1.23 millert 1502: }
1.34 millert 1503: lbuf_destroy(&lbuf);
1.1 millert 1504: exit(exit_val);
1505: }