1 /*
2  * Copyright (c) 1993-1996,1998-2004 Todd C. Miller <Todd.Miller@courtesan.com>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  *
16  * Sponsored in part by the Defense Advanced Research Projects
17  * Agency (DARPA) and Air Force Research Laboratory, Air Force
18  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
19  *
20  * For a brief history of sudo, please see the HISTORY file included
21  * with this distribution.
22  */
23 
24 #define _SUDO_MAIN
25 
26 #ifdef __TANDEM
27 # include <floss.h>
28 #endif
29 
30 #include "config.h"
31 
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
40 #include <stdio.h>
41 #ifdef STDC_HEADERS
42 # include <stdlib.h>
43 # include <stddef.h>
44 #else
45 # ifdef HAVE_STDLIB_H
46 #  include <stdlib.h>
47 # endif
48 #endif /* STDC_HEADERS */
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 */
59 #ifdef HAVE_UNISTD_H
60 # include <unistd.h>
61 #endif /* HAVE_UNISTD_H */
62 #ifdef HAVE_ERR_H
63 # include <err.h>
64 #else
65 # include "emul/err.h"
66 #endif /* HAVE_ERR_H */
67 #include <pwd.h>
68 #include <errno.h>
69 #include <fcntl.h>
70 #include <signal.h>
71 #include <grp.h>
72 #include <time.h>
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 */
84 #ifdef HAVE_LOGIN_CAP_H
85 # include <login_cap.h>
86 # ifndef LOGIN_DEFROOTCLASS
87 #  define LOGIN_DEFROOTCLASS	"daemon"
88 # endif
89 #endif
90 
91 #include "sudo.h"
92 #include "interfaces.h"
93 #include "version.h"
94 
95 #ifndef lint
96 static const char rcsid[] = "$Sudo: sudo.c,v 1.370 2004/08/24 18:01:13 millert Exp $";
97 #endif /* lint */
98 
99 /*
100  * Prototypes
101  */
102 static int init_vars			__P((int));
103 static int parse_args			__P((int, char **));
104 static void check_sudoers		__P((void));
105 static void initial_setup		__P((void));
106 static void set_loginclass		__P((struct passwd *));
107 static void usage			__P((int));
108 static void usage_excl			__P((int));
109 static struct passwd *get_authpw	__P((void));
110 extern int sudo_edit			__P((int, char **));
111 extern void list_matches		__P((void));
112 extern char **rebuild_env		__P((char **, int, int));
113 extern char **zero_env			__P((char **));
114 extern struct passwd *sudo_getpwnam	__P((const char *));
115 extern struct passwd *sudo_getpwuid	__P((uid_t));
116 extern struct passwd *sudo_pwdup	__P((const struct passwd *));
117 
118 /*
119  * Globals
120  */
121 int Argc, NewArgc;
122 char **Argv, **NewArgv;
123 char *prev_user;
124 struct sudo_user sudo_user;
125 struct passwd *auth_pw;
126 FILE *sudoers_fp;
127 struct interface *interfaces;
128 int num_interfaces;
129 int tgetpass_flags;
130 uid_t timestamp_uid;
131 extern int errorlineno;
132 #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
133 static struct rlimit corelimit;
134 #endif /* RLIMIT_CORE && !SUDO_DEVEL */
135 #ifdef HAVE_LOGIN_CAP_H
136 login_cap_t *lc;
137 #endif /* HAVE_LOGIN_CAP_H */
138 #ifdef HAVE_BSD_AUTH_H
139 char *login_style;
140 #endif /* HAVE_BSD_AUTH_H */
141 sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp, saved_sa_chld;
142 void (*set_perms) __P((int));
143 
144 
145 int
main(argc,argv,envp)146 main(argc, argv, envp)
147     int argc;
148     char **argv;
149     char **envp;
150 {
151     int validated;
152     int fd;
153     int cmnd_status;
154     int sudo_mode;
155     int pwflag;
156     char **new_environ;
157     sigaction_t sa;
158     extern int printmatches;
159     extern char **environ;
160 
161     Argv = argv;
162     if ((Argc = argc) < 1)
163 	usage(1);
164 
165     /* Must be done as the first thing... */
166 #if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS)
167     (void) set_auth_parameters(Argc, Argv);
168 # ifdef HAVE_INITPRIVS
169     initprivs();
170 # endif
171 #endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */
172 
173     /* Zero out the environment. */
174     environ = zero_env(envp);
175 
176     if (geteuid() != 0)
177 	errx(1, "must be setuid root");
178 
179     /*
180      * Signal setup:
181      *	Ignore keyboard-generated signals so the user cannot interrupt
182      *  us at some point and avoid the logging.
183      *  Install handler to wait for children when they exit.
184      */
185     sigemptyset(&sa.sa_mask);
186     sa.sa_flags = SA_RESTART;
187     sa.sa_handler = SIG_IGN;
188     (void) sigaction(SIGINT, &sa, &saved_sa_int);
189     (void) sigaction(SIGQUIT, &sa, &saved_sa_quit);
190     (void) sigaction(SIGTSTP, &sa, &saved_sa_tstp);
191     sa.sa_handler = reapchild;
192     (void) sigaction(SIGCHLD, &sa, &saved_sa_chld);
193 
194     /*
195      * Turn off core dumps, close open files and setup set_perms().
196      */
197     initial_setup();
198     setpwent();
199 
200     /* Parse our arguments. */
201     sudo_mode = parse_args(Argc, Argv);
202 
203     /* Setup defaults data structures. */
204     init_defaults();
205 
206     /* Load the list of local ip addresses and netmasks.  */
207     load_interfaces();
208 
209     pwflag = 0;
210     if (ISSET(sudo_mode, MODE_SHELL))
211 	user_cmnd = "shell";
212     else if (ISSET(sudo_mode, MODE_EDIT))
213 	user_cmnd = "sudoedit";
214     else
215 	switch (sudo_mode) {
216 	    case MODE_VERSION:
217 		(void) printf("Sudo version %s\n", version);
218 		if (getuid() == 0) {
219 		    putchar('\n');
220 		    dump_auth_methods();
221 		    dump_defaults();
222 		    dump_interfaces();
223 		}
224 		exit(0);
225 		break;
226 	    case MODE_HELP:
227 		usage(0);
228 		break;
229 	    case MODE_VALIDATE:
230 		user_cmnd = "validate";
231 		pwflag = I_VERIFYPW;
232 		break;
233 	    case MODE_KILL:
234 	    case MODE_INVALIDATE:
235 		user_cmnd = "kill";
236 		pwflag = -1;
237 		break;
238 	    case MODE_LISTDEFS:
239 		list_options();
240 		exit(0);
241 		break;
242 	    case MODE_LIST:
243 		user_cmnd = "list";
244 		pwflag = I_LISTPW;
245 		printmatches = 1;
246 		break;
247 	}
248 
249     /* Must have a command to run... */
250     if (user_cmnd == NULL && NewArgc == 0)
251 	usage(1);
252 
253     cmnd_status = init_vars(sudo_mode);
254 
255 #ifdef HAVE_LDAP
256     validated = sudo_ldap_check(pwflag);
257 
258     /* Skip reading /etc/sudoers if LDAP told us to */
259     if (def_ignore_local_sudoers); /* skips */
260     else if (ISSET(validated, VALIDATE_OK) && !printmatches); /* skips */
261     else if (ISSET(validated, VALIDATE_OK) && printmatches)
262     {
263 	check_sudoers();	/* check mode/owner on _PATH_SUDOERS */
264 
265 	/* User is found in LDAP and we want a list of all sudo commands the
266 	 * user can do, so consult sudoers but throw away result.
267 	 */
268 	sudoers_lookup(pwflag);
269     }
270     else
271 #endif
272     {
273 	check_sudoers();	/* check mode/owner on _PATH_SUDOERS */
274 
275 	/* Validate the user but don't search for pseudo-commands. */
276 	validated = sudoers_lookup(pwflag);
277     }
278     if (safe_cmnd == NULL)
279 	safe_cmnd = user_cmnd;
280 
281     /*
282      * If we are using set_perms_posix() and the stay_setuid flag was not set,
283      * set the real, effective and saved uids to 0 and use set_perms_nosuid()
284      * instead of set_perms_posix().
285      */
286 #if !defined(HAVE_SETRESUID) && !defined(HAVE_SETREUID) && \
287     !defined(NO_SAVED_IDS) && defined(_SC_SAVED_IDS) && defined(_SC_VERSION)
288     if (!def_stay_setuid && set_perms == set_perms_posix) {
289 	if (setuid(0)) {
290 	    perror("setuid(0)");
291 	    exit(1);
292 	}
293 	set_perms = set_perms_nosuid;
294     }
295 #endif
296 
297     /*
298      * Look up the timestamp dir owner if one is specified.
299      */
300     if (def_timestampowner) {
301 	struct passwd *pw;
302 
303 	if (*def_timestampowner == '#')
304 	    pw = getpwuid(atoi(def_timestampowner + 1));
305 	else
306 	    pw = getpwnam(def_timestampowner);
307 	if (!pw)
308 	    log_error(0, "timestamp owner (%s): No such user",
309 		def_timestampowner);
310 	timestamp_uid = pw->pw_uid;
311     }
312 
313     /* This goes after the sudoers parse since we honor sudoers options. */
314     if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE) {
315 	remove_timestamp((sudo_mode == MODE_KILL));
316 	exit(0);
317     }
318 
319     if (ISSET(validated, VALIDATE_ERROR))
320 	log_error(0, "parse error in %s near line %d", _PATH_SUDOERS,
321 	    errorlineno);
322 
323     /* Is root even allowed to run sudo? */
324     if (user_uid == 0 && !def_root_sudo) {
325 	(void) fprintf(stderr,
326 	    "Sorry, %s has been configured to not allow root to run it.\n",
327 	    getprogname());
328 	exit(1);
329     }
330 
331     /* If given the -P option, set the "preserve_groups" flag. */
332     if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS))
333 	def_preserve_groups = TRUE;
334 
335     /* If no command line args and "set_home" is not set, error out. */
336     if (ISSET(sudo_mode, MODE_IMPLIED_SHELL) && !def_shell_noargs)
337 	usage(1);
338 
339     /* May need to set $HOME to target user if we are running a command. */
340     if (ISSET(sudo_mode, MODE_RUN) && (def_always_set_home ||
341 	(ISSET(sudo_mode, MODE_SHELL) && def_set_home)))
342 	SET(sudo_mode, MODE_RESET_HOME);
343 
344     /* Bail if a tty is required and we don't have one.  */
345     if (def_requiretty) {
346 	if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1)
347 	    log_error(NO_MAIL, "sorry, you must have a tty to run sudo");
348 	else
349 	    (void) close(fd);
350     }
351 
352     /* Fill in passwd struct based on user we are authenticating as.  */
353     auth_pw = get_authpw();
354 
355     /* Require a password if sudoers says so.  */
356     if (!ISSET(validated, FLAG_NOPASS))
357 	check_user(ISSET(validated, FLAG_CHECK_USER));
358 
359     /* If run as root with SUDO_USER set, set sudo_user.pw to that user. */
360     if (user_uid == 0 && prev_user != NULL && strcmp(prev_user, "root") != 0) {
361 	    struct passwd *pw;
362 
363 	    if ((pw = sudo_getpwnam(prev_user)) != NULL) {
364 		    free(sudo_user.pw);
365 		    sudo_user.pw = pw;
366 	    }
367     }
368 
369     /* Build a new environment that avoids any nasty bits if we have a cmnd. */
370     if (ISSET(sudo_mode, MODE_RUN))
371 	new_environ = rebuild_env(envp, sudo_mode, ISSET(validated, FLAG_NOEXEC));
372     else
373 	new_environ = envp;
374 
375     if (ISSET(validated, VALIDATE_OK)) {
376 	/* Finally tell the user if the command did not exist. */
377 	if (cmnd_status == NOT_FOUND_DOT) {
378 	    warnx("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.", user_cmnd, user_cmnd, user_cmnd);
379 	    exit(1);
380 	} else if (cmnd_status == NOT_FOUND) {
381 	    warnx("%s: command not found", user_cmnd);
382 	    exit(1);
383 	}
384 
385 	log_auth(validated, 1);
386 	if (sudo_mode == MODE_VALIDATE)
387 	    exit(0);
388 	else if (sudo_mode == MODE_LIST) {
389 	    list_matches();
390 #ifdef HAVE_LDAP
391 	    sudo_ldap_list_matches();
392 #endif
393 	    exit(0);
394 	}
395 
396 	/* Override user's umask if configured to do so. */
397 	if (def_umask != 0777)
398 	    (void) umask(def_umask);
399 
400 	/* Restore coredumpsize resource limit. */
401 #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
402 	(void) setrlimit(RLIMIT_CORE, &corelimit);
403 #endif /* RLIMIT_CORE && !SUDO_DEVEL */
404 
405 	/* Become specified user or root if executing a command. */
406 	if (ISSET(sudo_mode, MODE_RUN))
407 	    set_perms(PERM_FULL_RUNAS);
408 
409 	/* Close the password and group files */
410 	endpwent();
411 	endgrent();
412 
413 	/* Install the real environment. */
414 	environ = new_environ;
415 
416 	if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
417 	    char *p;
418 
419 	    /* Convert /bin/sh -> -sh so shell knows it is a login shell */
420 	    if ((p = strrchr(NewArgv[0], '/')) == NULL)
421 		p = NewArgv[0];
422 	    *p = '-';
423 	    NewArgv[0] = p;
424 
425 	    /* Change to target user's homedir. */
426 	    if (chdir(runas_pw->pw_dir) == -1)
427 		warn("unable to change directory to %s", runas_pw->pw_dir);
428 	}
429 
430 	if (ISSET(sudo_mode, MODE_EDIT))
431 	    exit(sudo_edit(NewArgc, NewArgv));
432 
433 	/* Restore signal handlers before we exec. */
434 	(void) sigaction(SIGINT, &saved_sa_int, NULL);
435 	(void) sigaction(SIGQUIT, &saved_sa_quit, NULL);
436 	(void) sigaction(SIGTSTP, &saved_sa_tstp, NULL);
437 	(void) sigaction(SIGCHLD, &saved_sa_chld, NULL);
438 
439 #ifndef PROFILING
440 	if (ISSET(sudo_mode, MODE_BACKGROUND) && fork() > 0)
441 	    exit(0);
442 	else
443 	    EXECV(safe_cmnd, NewArgv);	/* run the command */
444 #else
445 	exit(0);
446 #endif /* PROFILING */
447 	/*
448 	 * If we got here then the exec() failed...
449 	 */
450 	warn("unable to execute %s", safe_cmnd);
451 	exit(127);
452     } else if (ISSET(validated, FLAG_NO_USER) || (validated & FLAG_NO_HOST)) {
453 	log_auth(validated, 1);
454 	exit(1);
455     } else if (ISSET(validated, VALIDATE_NOT_OK)) {
456 	if (def_path_info) {
457 	    /*
458 	     * We'd like to not leak path info at all here, but that can
459 	     * *really* confuse the users.  To really close the leak we'd
460 	     * have to say "not allowed to run foo" even when the problem
461 	     * is just "no foo in path" since the user can trivially set
462 	     * their path to just contain a single dir.
463 	     */
464 	    log_auth(validated,
465 		!(cmnd_status == NOT_FOUND_DOT || cmnd_status == NOT_FOUND));
466 	    if (cmnd_status == NOT_FOUND)
467 		warnx("%s: command not found", user_cmnd);
468 	    else if (cmnd_status == NOT_FOUND_DOT)
469 		warnx("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.", user_cmnd, user_cmnd, user_cmnd);
470 	} else {
471 	    /* Just tell the user they are not allowed to run foo. */
472 	    log_auth(validated, 1);
473 	}
474 	exit(1);
475     } else {
476 	/* should never get here */
477 	log_auth(validated, 1);
478 	exit(1);
479     }
480     exit(0);	/* not reached */
481 }
482 
483 /*
484  * Initialize timezone, set umask, fill in ``sudo_user'' struct and
485  * load the ``interfaces'' array.
486  */
487 static int
init_vars(sudo_mode)488 init_vars(sudo_mode)
489     int sudo_mode;
490 {
491     char *p, thost[MAXHOSTNAMELEN];
492     int nohostname, rval;
493 
494     /* Sanity check command from user. */
495     if (user_cmnd == NULL && strlen(NewArgv[0]) >= PATH_MAX)
496 	errx(1, "%s: File name too long", NewArgv[0]);
497 
498 #ifdef HAVE_TZSET
499     (void) tzset();		/* set the timezone if applicable */
500 #endif /* HAVE_TZSET */
501 
502     /* Default value for cmnd and cwd, overridden later. */
503     if (user_cmnd == NULL)
504 	user_cmnd = NewArgv[0];
505     (void) strlcpy(user_cwd, "unknown", sizeof(user_cwd));
506 
507     /*
508      * We avoid gethostbyname() if possible since we don't want
509      * sudo to block if DNS or NIS is hosed.
510      * "host" is the (possibly fully-qualified) hostname and
511      * "shost" is the unqualified form of the hostname.
512      */
513     nohostname = gethostname(thost, sizeof(thost));
514     if (nohostname)
515 	user_host = user_shost = "localhost";
516     else {
517 	user_host = estrdup(thost);
518 	if (def_fqdn) {
519 	    /* Defer call to set_fqdn() until log_error() is safe. */
520 	    user_shost = user_host;
521 	} else {
522 	    if ((p = strchr(user_host, '.'))) {
523 		*p = '\0';
524 		user_shost = estrdup(user_host);
525 		*p = '.';
526 	    } else {
527 		user_shost = user_host;
528 	    }
529 	}
530     }
531 
532     if ((p = ttyname(STDIN_FILENO)) || (p = ttyname(STDOUT_FILENO))) {
533 	if (strncmp(p, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
534 	    p += sizeof(_PATH_DEV) - 1;
535 	user_tty = estrdup(p);
536     } else
537 	user_tty = "unknown";
538 
539     /*
540      * Get a local copy of the user's struct passwd with the shadow password
541      * if necessary.  It is assumed that euid is 0 at this point so we
542      * can read the shadow passwd file if necessary.
543      */
544     if ((sudo_user.pw = sudo_getpwuid(getuid())) == NULL) {
545 	/* Need to make a fake struct passwd for logging to work. */
546 	struct passwd pw;
547 	char pw_name[MAX_UID_T_LEN + 1];
548 
549 	pw.pw_uid = getuid();
550 	(void) snprintf(pw_name, sizeof(pw_name), "%lu",
551 	    (unsigned long) pw.pw_uid);
552 	pw.pw_name = pw_name;
553 	sudo_user.pw = &pw;
554 
555 	/*
556 	 * If we are in -k/-K mode, just spew to stderr.  It is not unusual for
557 	 * users to place "sudo -k" in a .logout file which can cause sudo to
558 	 * be run during reboot after the YP/NIS/NIS+/LDAP/etc daemon has died.
559 	 */
560 	if (sudo_mode & (MODE_INVALIDATE|MODE_KILL))
561 	    errx(1, "uid %s does not exist in the passwd file!", pw_name);
562 	log_error(0, "uid %s does not exist in the passwd file!", pw_name);
563     }
564     if (user_shell == NULL || *user_shell == '\0')
565 	user_shell = sudo_user.pw->pw_shell;
566 
567     /* It is now safe to use log_error() and set_perms() */
568 
569     if (def_fqdn)
570 	set_fqdn();			/* may call log_error() */
571 
572     if (nohostname)
573 	log_error(USE_ERRNO|MSG_ONLY, "can't get hostname");
574 
575     set_runaspw(*user_runas);		/* may call log_error() */
576     if (*user_runas[0] == '#' && runas_pw->pw_name && runas_pw->pw_name[0])
577 	*user_runas = estrdup(runas_pw->pw_name);
578 
579     /*
580      * Get current working directory.  Try as user, fall back to root.
581      */
582     set_perms(PERM_USER);
583     if (!getcwd(user_cwd, sizeof(user_cwd))) {
584 	set_perms(PERM_ROOT);
585 	if (!getcwd(user_cwd, sizeof(user_cwd))) {
586 	    warnx("cannot get working directory");
587 	    (void) strlcpy(user_cwd, "unknown", sizeof(user_cwd));
588 	}
589     } else
590 	set_perms(PERM_ROOT);
591 
592     /*
593      * If we were given the '-e', '-i' or '-s' options we need to redo
594      * NewArgv and NewArgc.
595      */
596     if ((sudo_mode & (MODE_SHELL | MODE_EDIT))) {
597 	char **dst, **src = NewArgv;
598 
599 	NewArgv = (char **) emalloc2((++NewArgc + 1), sizeof(char *));
600 	if (ISSET(sudo_mode, MODE_EDIT))
601 	    NewArgv[0] = "sudoedit";
602 	else if (ISSET(sudo_mode, MODE_LOGIN_SHELL))
603 	    NewArgv[0] = runas_pw->pw_shell;
604 	else if (user_shell && *user_shell)
605 	    NewArgv[0] = user_shell;
606 	else
607 	    errx(1, "unable to determine shell");
608 
609 	/* copy the args from NewArgv */
610 	for (dst = NewArgv + 1; (*dst = *src) != NULL; ++src, ++dst)
611 	    ;
612     }
613 
614     /* Set login class if applicable. */
615     set_loginclass(sudo_user.pw);
616 
617     /* Resolve the path and return. */
618     rval = FOUND;
619     user_stat = emalloc(sizeof(struct stat));
620     if (sudo_mode & (MODE_RUN | MODE_EDIT)) {
621 	if (ISSET(sudo_mode, MODE_RUN)) {
622 	    /* XXX - default_runas may be modified during parsing of sudoers */
623 	    set_perms(PERM_RUNAS);
624 	    rval = find_path(NewArgv[0], &user_cmnd, user_stat, user_path);
625 	    set_perms(PERM_ROOT);
626 	    if (rval != FOUND) {
627 		/* Failed as root, try as invoking user. */
628 		set_perms(PERM_USER);
629 		rval = find_path(NewArgv[0], &user_cmnd, user_stat, user_path);
630 		set_perms(PERM_ROOT);
631 	    }
632 	}
633 
634 	/* set user_args */
635 	if (NewArgc > 1) {
636 	    char *to, **from;
637 	    size_t size, n;
638 
639 	    /* If we didn't realloc NewArgv it is contiguous so just count. */
640 	    if (!(sudo_mode & (MODE_SHELL | MODE_EDIT))) {
641 		size = (size_t) (NewArgv[NewArgc-1] - NewArgv[1]) +
642 			strlen(NewArgv[NewArgc-1]) + 1;
643 	    } else {
644 		for (size = 0, from = NewArgv + 1; *from; from++)
645 		    size += strlen(*from) + 1;
646 	    }
647 
648 	    /* Alloc and build up user_args. */
649 	    user_args = (char *) emalloc(size);
650 	    for (to = user_args, from = NewArgv + 1; *from; from++) {
651 		n = strlcpy(to, *from, size - (to - user_args));
652 		if (n >= size - (to - user_args))
653 		    errx(1, "internal error, init_vars() overflow");
654 		to += n;
655 		*to++ = ' ';
656 	    }
657 	    *--to = '\0';
658 	}
659     }
660     if ((user_base = strrchr(user_cmnd, '/')) != NULL)
661 	user_base++;
662     else
663 	user_base = user_cmnd;
664 
665     return(rval);
666 }
667 
668 /*
669  * Command line argument parsing, can't use getopt(3).
670  */
671 static int
parse_args(argc,argv)672 parse_args(argc, argv)
673     int argc;
674     char **argv;
675 {
676     int rval = MODE_RUN;		/* what mode is sudo to be run in? */
677     int excl = 0;			/* exclusive arg, no others allowed */
678 
679     NewArgv = argv + 1;
680     NewArgc = argc - 1;
681 
682     /* First, check to see if we were invoked as "sudoedit". */
683     if (strcmp(getprogname(), "sudoedit") == 0) {
684 	rval = MODE_EDIT;
685 	excl = 'e';
686     } else
687 	rval = MODE_RUN;
688 
689     if (NewArgc == 0 && rval == MODE_RUN) {	/* no options and no command */
690 	SET(rval, (MODE_IMPLIED_SHELL | MODE_SHELL));
691 	return(rval);
692     }
693 
694     while (NewArgc > 0 && NewArgv[0][0] == '-') {
695 	if (NewArgv[0][1] != '\0' && NewArgv[0][2] != '\0')
696 	    warnx("please use single character options");
697 
698 	switch (NewArgv[0][1]) {
699 	    case 'p':
700 		/* Must have an associated prompt. */
701 		if (NewArgv[1] == NULL)
702 		    usage(1);
703 
704 		user_prompt = NewArgv[1];
705 
706 		NewArgc--;
707 		NewArgv++;
708 		break;
709 	    case 'u':
710 		/* Must have an associated runas user. */
711 		if (NewArgv[1] == NULL)
712 		    usage(1);
713 
714 		user_runas = &NewArgv[1];
715 
716 		NewArgc--;
717 		NewArgv++;
718 		break;
719 #ifdef HAVE_BSD_AUTH_H
720 	    case 'a':
721 		/* Must have an associated authentication style. */
722 		if (NewArgv[1] == NULL)
723 		    usage(1);
724 
725 		login_style = NewArgv[1];
726 
727 		NewArgc--;
728 		NewArgv++;
729 		break;
730 #endif
731 #ifdef HAVE_LOGIN_CAP_H
732 	    case 'c':
733 		/* Must have an associated login class. */
734 		if (NewArgv[1] == NULL)
735 		    usage(1);
736 
737 		login_class = NewArgv[1];
738 		def_use_loginclass = TRUE;
739 
740 		NewArgc--;
741 		NewArgv++;
742 		break;
743 #endif
744 	    case 'b':
745 		SET(rval, MODE_BACKGROUND);
746 		break;
747 	    case 'e':
748 		rval = MODE_EDIT;
749 		if (excl && excl != 'e')
750 		    usage_excl(1);
751 		excl = 'e';
752 		break;
753 	    case 'v':
754 		rval = MODE_VALIDATE;
755 		if (excl && excl != 'v')
756 		    usage_excl(1);
757 		excl = 'v';
758 		break;
759 	    case 'i':
760 		SET(rval, (MODE_LOGIN_SHELL | MODE_SHELL));
761 		def_env_reset = TRUE;
762 		if (excl && excl != 'i')
763 		    usage_excl(1);
764 		excl = 'i';
765 		break;
766 	    case 'k':
767 		rval = MODE_INVALIDATE;
768 		if (excl && excl != 'k')
769 		    usage_excl(1);
770 		excl = 'k';
771 		break;
772 	    case 'K':
773 		rval = MODE_KILL;
774 		if (excl && excl != 'K')
775 		    usage_excl(1);
776 		excl = 'K';
777 		break;
778 	    case 'L':
779 		rval = MODE_LISTDEFS;
780 		if (excl && excl != 'L')
781 		    usage_excl(1);
782 		excl = 'L';
783 		break;
784 	    case 'l':
785 		rval = MODE_LIST;
786 		if (excl && excl != 'l')
787 		    usage_excl(1);
788 		excl = 'l';
789 		break;
790 	    case 'V':
791 		rval = MODE_VERSION;
792 		if (excl && excl != 'V')
793 		    usage_excl(1);
794 		excl = 'V';
795 		break;
796 	    case 'h':
797 		rval = MODE_HELP;
798 		if (excl && excl != 'h')
799 		    usage_excl(1);
800 		excl = 'h';
801 		break;
802 	    case 's':
803 		SET(rval, MODE_SHELL);
804 		if (excl && excl != 's')
805 		    usage_excl(1);
806 		excl = 's';
807 		break;
808 	    case 'H':
809 		SET(rval, MODE_RESET_HOME);
810 		break;
811 	    case 'P':
812 		SET(rval, MODE_PRESERVE_GROUPS);
813 		break;
814 	    case 'S':
815 		SET(tgetpass_flags, TGP_STDIN);
816 		break;
817 	    case '-':
818 		NewArgc--;
819 		NewArgv++;
820 		if (rval == MODE_RUN)
821 		    SET(rval, (MODE_IMPLIED_SHELL | MODE_SHELL));
822 		return(rval);
823 	    case '\0':
824 		warnx("'-' requires an argument");
825 		usage(1);
826 	    default:
827 		warnx("illegal option `%s'", NewArgv[0]);
828 		usage(1);
829 	}
830 	NewArgc--;
831 	NewArgv++;
832     }
833 
834     if (user_runas != NULL && !ISSET(rval, (MODE_EDIT|MODE_RUN))) {
835 	if (excl != '\0')
836 	    warnx("the `-u' and '-%c' options may not be used together", excl);
837 	usage(1);
838     }
839 
840     if ((NewArgc == 0 && (rval & MODE_EDIT)) ||
841 	(NewArgc > 0 && !(rval & (MODE_RUN | MODE_EDIT))))
842 	usage(1);
843 
844     return(rval);
845 }
846 
847 /*
848  * Sanity check sudoers mode/owner/type.
849  * Leaves a file pointer to the sudoers file open in ``fp''.
850  */
851 static void
check_sudoers()852 check_sudoers()
853 {
854     struct stat statbuf;
855     int rootstat, i;
856     char c;
857 
858     /*
859      * Fix the mode and group on sudoers file from old default.
860      * Only works if file system is readable/writable by root.
861      */
862     if ((rootstat = stat_sudoers(_PATH_SUDOERS, &statbuf)) == 0 &&
863 	SUDOERS_UID == statbuf.st_uid && SUDOERS_MODE != 0400 &&
864 	(statbuf.st_mode & 0007777) == 0400) {
865 
866 	if (chmod(_PATH_SUDOERS, SUDOERS_MODE) == 0) {
867 	    warnx("fixed mode on %s", _PATH_SUDOERS);
868 	    SET(statbuf.st_mode, SUDOERS_MODE);
869 	    if (statbuf.st_gid != SUDOERS_GID) {
870 		if (!chown(_PATH_SUDOERS,(uid_t) -1,SUDOERS_GID)) {
871 		    warnx("set group on %s", _PATH_SUDOERS);
872 		    statbuf.st_gid = SUDOERS_GID;
873 		} else
874 		    warn("unable to set group on %s", _PATH_SUDOERS);
875 	    }
876 	} else
877 	    warn("unable to fix mode on %s", _PATH_SUDOERS);
878     }
879 
880     /*
881      * Sanity checks on sudoers file.  Must be done as sudoers
882      * file owner.  We already did a stat as root, so use that
883      * data if we can't stat as sudoers file owner.
884      */
885     set_perms(PERM_SUDOERS);
886 
887     if (rootstat != 0 && stat_sudoers(_PATH_SUDOERS, &statbuf) != 0)
888 	log_error(USE_ERRNO, "can't stat %s", _PATH_SUDOERS);
889     else if (!S_ISREG(statbuf.st_mode))
890 	log_error(0, "%s is not a regular file", _PATH_SUDOERS);
891     else if (statbuf.st_size == 0)
892 	log_error(0, "%s is zero length", _PATH_SUDOERS);
893     else if ((statbuf.st_mode & 07777) != SUDOERS_MODE)
894 	log_error(0, "%s is mode 0%o, should be 0%o", _PATH_SUDOERS,
895 	    (statbuf.st_mode & 07777), SUDOERS_MODE);
896     else if (statbuf.st_uid != SUDOERS_UID)
897 	log_error(0, "%s is owned by uid %lu, should be %lu", _PATH_SUDOERS,
898 	    (unsigned long) statbuf.st_uid, (unsigned long) SUDOERS_UID);
899     else if (statbuf.st_gid != SUDOERS_GID)
900 	log_error(0, "%s is owned by gid %lu, should be %lu", _PATH_SUDOERS,
901 	    (unsigned long) statbuf.st_gid, (unsigned long) SUDOERS_GID);
902     else {
903 	/* Solaris sometimes returns EAGAIN so try 10 times */
904 	for (i = 0; i < 10 ; i++) {
905 	    errno = 0;
906 	    if ((sudoers_fp = fopen(_PATH_SUDOERS, "r")) == NULL ||
907 		fread(&c, sizeof(c), 1, sudoers_fp) != 1) {
908 		sudoers_fp = NULL;
909 		if (errno != EAGAIN && errno != EWOULDBLOCK)
910 		    break;
911 	    } else
912 		break;
913 	    sleep(1);
914 	}
915 	if (sudoers_fp == NULL)
916 	    log_error(USE_ERRNO, "can't open %s", _PATH_SUDOERS);
917     }
918 
919     set_perms(PERM_ROOT);		/* change back to root */
920 }
921 
922 /*
923  * Close all open files (except std*) and turn off core dumps.
924  * Also sets the set_perms() pointer to the correct function.
925  */
926 static void
initial_setup()927 initial_setup()
928 {
929 #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
930     struct rlimit rl;
931 
932     /*
933      * Turn off core dumps.
934      */
935     (void) getrlimit(RLIMIT_CORE, &corelimit);
936     memcpy(&rl, &corelimit, sizeof(struct rlimit));
937     rl.rlim_cur = 0;
938     (void) setrlimit(RLIMIT_CORE, &rl);
939 #endif /* RLIMIT_CORE && !SUDO_DEVEL */
940 
941     closefrom(STDERR_FILENO + 1);
942 
943     /*
944      * Make set_perms point to the correct function.
945      * If we are using setresuid() or setreuid() we only need to set this
946      * once.  If we are using POSIX saved uids we will switch to
947      * set_perms_nosuid after sudoers has been parsed if the "stay_suid"
948      * option is not set.
949      */
950 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID)
951     set_perms = set_perms_suid;
952 #else
953 # if !defined(NO_SAVED_IDS) && defined(_SC_SAVED_IDS) && defined(_SC_VERSION)
954     if (sysconf(_SC_SAVED_IDS) == 1 && sysconf(_SC_VERSION) >= 199009)
955 	set_perms = set_perms_posix;
956     else
957 # endif
958 	set_perms = set_perms_nosuid;
959 #endif /* HAVE_SETRESUID || HAVE_SETREUID */
960 }
961 
962 #ifdef HAVE_LOGIN_CAP_H
963 static void
set_loginclass(pw)964 set_loginclass(pw)
965     struct passwd *pw;
966 {
967     int errflags;
968 
969     /*
970      * Don't make it a fatal error if the user didn't specify the login
971      * class themselves.  We do this because if login.conf gets
972      * corrupted we want the admin to be able to use sudo to fix it.
973      */
974     if (login_class)
975 	errflags = NO_MAIL|MSG_ONLY;
976     else
977 	errflags = NO_MAIL|MSG_ONLY|NO_EXIT;
978 
979     if (login_class && strcmp(login_class, "-") != 0) {
980 	if (strcmp(*user_runas, "root") != 0 && user_uid != 0)
981 	    errx(1, "only root can use -c %s", login_class);
982     } else {
983 	login_class = pw->pw_class;
984 	if (!login_class || !*login_class)
985 	    login_class =
986 		(pw->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS;
987     }
988 
989     lc = login_getclass(login_class);
990     if (!lc || !lc->lc_class || strcmp(lc->lc_class, login_class) != 0) {
991 	log_error(errflags, "unknown login class: %s", login_class);
992 	if (!lc)
993 	    lc = login_getclass(NULL);	/* needed for login_getstyle() later */
994     }
995 }
996 #else
997 static void
set_loginclass(pw)998 set_loginclass(pw)
999     struct passwd *pw;
1000 {
1001 }
1002 #endif /* HAVE_LOGIN_CAP_H */
1003 
1004 /*
1005  * Look up the fully qualified domain name and set user_host and user_shost.
1006  */
1007 void
set_fqdn()1008 set_fqdn()
1009 {
1010     struct hostent *hp;
1011     char *p;
1012 
1013     if (!(hp = gethostbyname(user_host))) {
1014 	log_error(MSG_ONLY|NO_EXIT,
1015 	    "unable to lookup %s via gethostbyname()", user_host);
1016     } else {
1017 	if (user_shost != user_host)
1018 	    free(user_shost);
1019 	free(user_host);
1020 	user_host = estrdup(hp->h_name);
1021     }
1022     if ((p = strchr(user_host, '.'))) {
1023 	*p = '\0';
1024 	user_shost = estrdup(user_host);
1025 	*p = '.';
1026     } else {
1027 	user_shost = user_host;
1028     }
1029 }
1030 
1031 /*
1032  * Get passwd entry for the user we are going to run commands as.
1033  * By default, this is "root".  Updates runas_pw as a side effect.
1034  */
1035 int
set_runaspw(user)1036 set_runaspw(user)
1037     char *user;
1038 {
1039     if (runas_pw != NULL) {
1040 	if (user_runas != &def_runas_default)
1041 	    return(TRUE);		/* don't override -u option */
1042 	free(runas_pw);
1043     }
1044     if (*user == '#') {
1045 	runas_pw = sudo_getpwuid(atoi(user + 1));
1046 	if (runas_pw == NULL) {
1047 	    runas_pw = emalloc(sizeof(struct passwd));
1048 	    (void) memset((VOID *)runas_pw, 0, sizeof(struct passwd));
1049 	    runas_pw->pw_uid = atoi(user + 1);
1050 	}
1051     } else {
1052 	runas_pw = sudo_getpwnam(user);
1053 	if (runas_pw == NULL)
1054 	    log_error(NO_MAIL|MSG_ONLY, "no passwd entry for %s!", user);
1055     }
1056     return(TRUE);
1057 }
1058 
1059 /*
1060  * Get passwd entry for the user we are going to authenticate as.
1061  * By default, this is the user invoking sudo.  In the most common
1062  * case, this matches sudo_user.pw or runas_pw.
1063  */
1064 static struct passwd *
get_authpw()1065 get_authpw()
1066 {
1067     struct passwd *pw;
1068 
1069     if (def_rootpw) {
1070 	if (runas_pw->pw_uid == 0)
1071 	    pw = runas_pw;
1072 	else if ((pw = sudo_getpwuid(0)) == NULL)
1073 	    log_error(0, "uid 0 does not exist in the passwd file!");
1074     } else if (def_runaspw) {
1075 	if (strcmp(def_runas_default, *user_runas) == 0)
1076 	    pw = runas_pw;
1077 	else if ((pw = sudo_getpwnam(def_runas_default)) == NULL)
1078 	    log_error(0, "user %s does not exist in the passwd file!",
1079 		def_runas_default);
1080     } else if (def_targetpw) {
1081 	if (runas_pw->pw_name == NULL)
1082 	    log_error(NO_MAIL|MSG_ONLY, "no passwd entry for %lu!",
1083 		(unsigned long) runas_pw->pw_uid);
1084 	pw = runas_pw;
1085     } else
1086 	pw = sudo_user.pw;
1087 
1088     return(pw);
1089 }
1090 
1091 /*
1092  * Tell which options are mutually exclusive and exit.
1093  */
1094 static void
usage_excl(exit_val)1095 usage_excl(exit_val)
1096     int exit_val;
1097 {
1098     warnx("Only one of the -e, -h, -k, -K, -l, -s, -v or -V options may be used");
1099     usage(exit_val);
1100 }
1101 
1102 /*
1103  * Give usage message and exit.
1104  */
1105 static void
usage(exit_val)1106 usage(exit_val)
1107     int exit_val;
1108 {
1109     char **p;
1110     int linelen, linemax, ulen;
1111     static char *uvec[] = {
1112 	" [-HPSb]",
1113 #ifdef HAVE_BSD_AUTH_H
1114 	" [-a auth_type]",
1115 #endif
1116 #ifdef HAVE_LOGIN_CAP_H
1117 	" [-c class|-]",
1118 #endif
1119 	" [-p prompt]",
1120 	" [-u username|#uid]",
1121 	" { -e file [...] | -i | -s | <command> }",
1122 	NULL
1123     };
1124 
1125     /*
1126      * For sudoedit, replace the last entry in the usage vector.
1127      * For sudo, print the secondary usage.
1128      */
1129     if (strcmp(getprogname(), "sudoedit") == 0) {
1130 	/* Replace the last entry in the usage vector. */
1131 	for (p = uvec; p[1] != NULL; p++)
1132 	    continue;
1133 	*p = " file [...]";
1134     } else {
1135 	fprintf(stderr, "usage: %s -K | -L | -V | -h | -k | -l | -v\n",
1136 	    getprogname());
1137     }
1138 
1139     /*
1140      * Print the main usage and wrap lines as needed.
1141      * Assumes an 80-character wide terminal, which is kind of bogus...
1142      */
1143     ulen = (int)strlen(getprogname()) + 7;
1144     linemax = 80;
1145     linelen = linemax - ulen;
1146     printf("usage: %s", getprogname());
1147     for (p = uvec; *p != NULL; p++) {
1148 	if (linelen == linemax || (linelen -= strlen(*p)) >= 0) {
1149 	    fputs(*p, stdout);
1150 	} else {
1151 	    p--;
1152 	    linelen = linemax;
1153 	    printf("\n%*s", ulen, "");
1154 	}
1155     }
1156     putchar('\n');
1157     exit(exit_val);
1158 }
1159