Imported Debian patch 1.6.8p7-1.4
[debian/sudo] / sudo.c
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
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
279     /*
280      * If we are using set_perms_posix() and the stay_setuid flag was not set,
281      * set the real, effective and saved uids to 0 and use set_perms_nosuid()
282      * instead of set_perms_posix().
283      */
284 #if !defined(HAVE_SETRESUID) && !defined(HAVE_SETREUID) && \
285     !defined(NO_SAVED_IDS) && defined(_SC_SAVED_IDS) && defined(_SC_VERSION)
286     if (!def_stay_setuid && set_perms == set_perms_posix) {
287         if (setuid(0)) {
288             perror("setuid(0)");
289             exit(1);
290         }
291         set_perms = set_perms_nosuid;
292     }
293 #endif
294
295     /*
296      * Look up the timestamp dir owner if one is specified.
297      */
298     if (def_timestampowner) {
299         struct passwd *pw;
300
301         if (*def_timestampowner == '#')
302             pw = getpwuid(atoi(def_timestampowner + 1));
303         else
304             pw = getpwnam(def_timestampowner);
305         if (!pw)
306             log_error(0, "timestamp owner (%s): No such user",
307                 def_timestampowner);
308         timestamp_uid = pw->pw_uid;
309     }
310
311     /* This goes after the sudoers parse since we honor sudoers options. */
312     if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE) {
313         remove_timestamp((sudo_mode == MODE_KILL));
314         exit(0);
315     }
316
317     if (ISSET(validated, VALIDATE_ERROR))
318         log_error(0, "parse error in %s near line %d", _PATH_SUDOERS,
319             errorlineno);
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     }
328
329     /* If given the -P option, set the "preserve_groups" flag. */
330     if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS))
331         def_preserve_groups = TRUE;
332
333     /* If no command line args and "set_home" is not set, error out. */
334     if (ISSET(sudo_mode, MODE_IMPLIED_SHELL) && !def_shell_noargs)
335         usage(1);
336
337     /* May need to set $HOME to target user if we are running a command. */
338     if (ISSET(sudo_mode, MODE_RUN) && (def_always_set_home ||
339         (ISSET(sudo_mode, MODE_SHELL) && def_set_home)))
340         SET(sudo_mode, MODE_RESET_HOME);
341
342     /* Bail if a tty is required and we don't have one.  */
343     if (def_requiretty) {
344         if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1)
345             log_error(NO_MAIL, "sorry, you must have a tty to run sudo");
346         else
347             (void) close(fd);
348     }
349
350     /* Fill in passwd struct based on user we are authenticating as.  */
351     auth_pw = get_authpw();
352
353     /* Require a password if sudoers says so.  */
354     if (!ISSET(validated, FLAG_NOPASS))
355         check_user(ISSET(validated, FLAG_CHECK_USER));
356
357     /* If run as root with SUDO_USER set, set sudo_user.pw to that user. */
358     if (user_uid == 0 && prev_user != NULL && strcmp(prev_user, "root") != 0) {
359             struct passwd *pw;
360
361             if ((pw = sudo_getpwnam(prev_user)) != NULL) {
362                     free(sudo_user.pw);
363                     sudo_user.pw = pw;
364             }
365     }
366
367     /* Build a new environment that avoids any nasty bits if we have a cmnd. */
368     if (ISSET(sudo_mode, MODE_RUN))
369         new_environ = rebuild_env(envp, sudo_mode, ISSET(validated, FLAG_NOEXEC));
370     else
371         new_environ = envp;
372
373     if (ISSET(validated, VALIDATE_OK)) {
374         /* Finally tell the user if the command did not exist. */
375         if (cmnd_status == NOT_FOUND_DOT) {
376             warnx("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.", user_cmnd, user_cmnd, user_cmnd);
377             exit(1);
378         } else if (cmnd_status == NOT_FOUND) {
379             warnx("%s: command not found", user_cmnd);
380             exit(1);
381         }
382
383         log_auth(validated, 1);
384         if (sudo_mode == MODE_VALIDATE)
385             exit(0);
386         else if (sudo_mode == MODE_LIST) {
387             list_matches();
388 #ifdef HAVE_LDAP
389             sudo_ldap_list_matches();
390 #endif
391             exit(0);
392         }
393
394         /* This *must* have been set if we got a match but... */
395         if (safe_cmnd == NULL) {
396             log_error(MSG_ONLY,
397                 "internal error, safe_cmnd never got set for %s; %s",
398                 user_cmnd,
399                 "please report this error at http://courtesan.com/sudo/bugs/");
400         }
401
402         /* Override user's umask if configured to do so. */
403         if (def_umask != 0777)
404             (void) umask(def_umask);
405
406         /* Restore coredumpsize resource limit. */
407 #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
408         (void) setrlimit(RLIMIT_CORE, &corelimit);
409 #endif /* RLIMIT_CORE && !SUDO_DEVEL */
410
411         /* Become specified user or root if executing a command. */
412         if (ISSET(sudo_mode, MODE_RUN))
413             set_perms(PERM_FULL_RUNAS);
414
415         /* Close the password and group files */
416         endpwent();
417         endgrent();
418
419         /* Install the real environment. */
420         environ = new_environ;
421
422         if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
423             char *p;
424
425             /* Convert /bin/sh -> -sh so shell knows it is a login shell */
426             if ((p = strrchr(NewArgv[0], '/')) == NULL)
427                 p = NewArgv[0];
428             *p = '-';
429             NewArgv[0] = p;
430
431             /* Change to target user's homedir. */
432             if (chdir(runas_pw->pw_dir) == -1)
433                 warn("unable to change directory to %s", runas_pw->pw_dir);
434         }
435
436         if (ISSET(sudo_mode, MODE_EDIT))
437             exit(sudo_edit(NewArgc, NewArgv));
438
439         /* Restore signal handlers before we exec. */
440         (void) sigaction(SIGINT, &saved_sa_int, NULL);
441         (void) sigaction(SIGQUIT, &saved_sa_quit, NULL);
442         (void) sigaction(SIGTSTP, &saved_sa_tstp, NULL);
443         (void) sigaction(SIGCHLD, &saved_sa_chld, NULL);
444
445 #ifndef PROFILING
446         if (ISSET(sudo_mode, MODE_BACKGROUND) && fork() > 0)
447             exit(0);
448         else
449             EXECV(safe_cmnd, NewArgv);  /* run the command */
450 #else
451         exit(0);
452 #endif /* PROFILING */
453         /*
454          * If we got here then the exec() failed...
455          */
456         warn("unable to execute %s", safe_cmnd);
457         exit(127);
458     } else if (ISSET(validated, FLAG_NO_USER) || (validated & FLAG_NO_HOST)) {
459         log_auth(validated, 1);
460         exit(1);
461     } else if (ISSET(validated, VALIDATE_NOT_OK)) {
462         if (def_path_info) {
463             /*
464              * We'd like to not leak path info at all here, but that can
465              * *really* confuse the users.  To really close the leak we'd
466              * have to say "not allowed to run foo" even when the problem
467              * is just "no foo in path" since the user can trivially set
468              * their path to just contain a single dir.
469              */
470             log_auth(validated,
471                 !(cmnd_status == NOT_FOUND_DOT || cmnd_status == NOT_FOUND));
472             if (cmnd_status == NOT_FOUND)
473                 warnx("%s: command not found", user_cmnd);
474             else if (cmnd_status == NOT_FOUND_DOT)
475                 warnx("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.", user_cmnd, user_cmnd, user_cmnd);
476         } else {
477             /* Just tell the user they are not allowed to run foo. */
478             log_auth(validated, 1);
479         }
480         exit(1);
481     } else {
482         /* should never get here */
483         log_auth(validated, 1);
484         exit(1);
485     }
486     exit(0);    /* not reached */
487 }
488
489 /*
490  * Initialize timezone, set umask, fill in ``sudo_user'' struct and
491  * load the ``interfaces'' array.
492  */
493 static int
494 init_vars(sudo_mode)
495     int sudo_mode;
496 {
497     char *p, thost[MAXHOSTNAMELEN];
498     int nohostname, rval;
499
500     /* Sanity check command from user. */
501     if (user_cmnd == NULL && strlen(NewArgv[0]) >= PATH_MAX)
502         errx(1, "%s: File name too long", NewArgv[0]);
503
504 #ifdef HAVE_TZSET
505     (void) tzset();             /* set the timezone if applicable */
506 #endif /* HAVE_TZSET */
507
508     /* Default value for cmnd and cwd, overridden later. */
509     if (user_cmnd == NULL)
510         user_cmnd = NewArgv[0];
511     (void) strlcpy(user_cwd, "unknown", sizeof(user_cwd));
512
513     /*
514      * We avoid gethostbyname() if possible since we don't want
515      * sudo to block if DNS or NIS is hosed.
516      * "host" is the (possibly fully-qualified) hostname and
517      * "shost" is the unqualified form of the hostname.
518      */
519     nohostname = gethostname(thost, sizeof(thost));
520     if (nohostname)
521         user_host = user_shost = "localhost";
522     else {
523         user_host = estrdup(thost);
524         if (def_fqdn) {
525             /* Defer call to set_fqdn() until log_error() is safe. */
526             user_shost = user_host;
527         } else {
528             if ((p = strchr(user_host, '.'))) {
529                 *p = '\0';
530                 user_shost = estrdup(user_host);
531                 *p = '.';
532             } else {
533                 user_shost = user_host;
534             }
535         }
536     }
537
538     if ((p = ttyname(STDIN_FILENO)) || (p = ttyname(STDOUT_FILENO))) {
539         if (strncmp(p, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
540             p += sizeof(_PATH_DEV) - 1;
541         user_tty = estrdup(p);
542     } else
543         user_tty = "unknown";
544
545     /*
546      * Get a local copy of the user's struct passwd with the shadow password
547      * if necessary.  It is assumed that euid is 0 at this point so we
548      * can read the shadow passwd file if necessary.
549      */
550     if ((sudo_user.pw = sudo_getpwuid(getuid())) == NULL) {
551         /* Need to make a fake struct passwd for logging to work. */
552         struct passwd pw;
553         char pw_name[MAX_UID_T_LEN + 1];
554
555         pw.pw_uid = getuid();
556         (void) snprintf(pw_name, sizeof(pw_name), "%lu",
557             (unsigned long) pw.pw_uid);
558         pw.pw_name = pw_name;
559         sudo_user.pw = &pw;
560
561         /*
562          * If we are in -k/-K mode, just spew to stderr.  It is not unusual for
563          * users to place "sudo -k" in a .logout file which can cause sudo to
564          * be run during reboot after the YP/NIS/NIS+/LDAP/etc daemon has died.
565          */
566         if (sudo_mode & (MODE_INVALIDATE|MODE_KILL))
567             errx(1, "uid %s does not exist in the passwd file!", pw_name);
568         log_error(0, "uid %s does not exist in the passwd file!", pw_name);
569     }
570     if (user_shell == NULL || *user_shell == '\0')
571         user_shell = sudo_user.pw->pw_shell;
572
573     /* It is now safe to use log_error() and set_perms() */
574
575     if (def_fqdn)
576         set_fqdn();                     /* may call log_error() */
577
578     if (nohostname)
579         log_error(USE_ERRNO|MSG_ONLY, "can't get hostname");
580
581     set_runaspw(*user_runas);           /* may call log_error() */
582     if (*user_runas[0] == '#' && runas_pw->pw_name && runas_pw->pw_name[0])
583         *user_runas = estrdup(runas_pw->pw_name);
584
585     /*
586      * Get current working directory.  Try as user, fall back to root.
587      */
588     set_perms(PERM_USER);
589     if (!getcwd(user_cwd, sizeof(user_cwd))) {
590         set_perms(PERM_ROOT);
591         if (!getcwd(user_cwd, sizeof(user_cwd))) {
592             warnx("cannot get working directory");
593             (void) strlcpy(user_cwd, "unknown", sizeof(user_cwd));
594         }
595     } else
596         set_perms(PERM_ROOT);
597
598     /*
599      * If we were given the '-e', '-i' or '-s' options we need to redo
600      * NewArgv and NewArgc.
601      */
602     if ((sudo_mode & (MODE_SHELL | MODE_EDIT))) {
603         char **dst, **src = NewArgv;
604
605         NewArgv = (char **) emalloc2((++NewArgc + 1), sizeof(char *));
606         if (ISSET(sudo_mode, MODE_EDIT))
607             NewArgv[0] = "sudoedit";
608         else if (ISSET(sudo_mode, MODE_LOGIN_SHELL))
609             NewArgv[0] = runas_pw->pw_shell;
610         else if (user_shell && *user_shell)
611             NewArgv[0] = user_shell;
612         else
613             errx(1, "unable to determine shell");
614
615         /* copy the args from NewArgv */
616         for (dst = NewArgv + 1; (*dst = *src) != NULL; ++src, ++dst)
617             ;
618     }
619
620     /* Set login class if applicable. */
621     set_loginclass(sudo_user.pw);
622
623     /* Resolve the path and return. */
624     rval = FOUND;
625     user_stat = emalloc(sizeof(struct stat));
626     if (sudo_mode & (MODE_RUN | MODE_EDIT)) {
627         if (ISSET(sudo_mode, MODE_RUN)) {
628             /* XXX - default_runas may be modified during parsing of sudoers */
629             set_perms(PERM_RUNAS);
630             rval = find_path(NewArgv[0], &user_cmnd, user_stat, user_path);
631             set_perms(PERM_ROOT);
632             if (rval != FOUND) {
633                 /* Failed as root, try as invoking user. */
634                 set_perms(PERM_USER);
635                 rval = find_path(NewArgv[0], &user_cmnd, user_stat, user_path);
636                 set_perms(PERM_ROOT);
637             }
638         }
639
640         /* set user_args */
641         if (NewArgc > 1) {
642             char *to, **from;
643             size_t size, n;
644
645             /* If we didn't realloc NewArgv it is contiguous so just count. */
646             if (!(sudo_mode & (MODE_SHELL | MODE_EDIT))) {
647                 size = (size_t) (NewArgv[NewArgc-1] - NewArgv[1]) +
648                         strlen(NewArgv[NewArgc-1]) + 1;
649             } else {
650                 for (size = 0, from = NewArgv + 1; *from; from++)
651                     size += strlen(*from) + 1;
652             }
653
654             /* Alloc and build up user_args. */
655             user_args = (char *) emalloc(size);
656             for (to = user_args, from = NewArgv + 1; *from; from++) {
657                 n = strlcpy(to, *from, size - (to - user_args));
658                 if (n >= size - (to - user_args))
659                     errx(1, "internal error, init_vars() overflow");
660                 to += n;
661                 *to++ = ' ';
662             }
663             *--to = '\0';
664         }
665     }
666     if ((user_base = strrchr(user_cmnd, '/')) != NULL)
667         user_base++;
668     else
669         user_base = user_cmnd;
670
671     return(rval);
672 }
673
674 /*
675  * Command line argument parsing, can't use getopt(3).
676  */
677 static int
678 parse_args(argc, argv)
679     int argc;
680     char **argv;
681 {
682     int rval = MODE_RUN;                /* what mode is sudo to be run in? */
683     int excl = 0;                       /* exclusive arg, no others allowed */
684
685     NewArgv = argv + 1;
686     NewArgc = argc - 1;
687
688     /* First, check to see if we were invoked as "sudoedit". */
689     if (strcmp(getprogname(), "sudoedit") == 0) {
690         rval = MODE_EDIT;
691         excl = 'e';
692     } else
693         rval = MODE_RUN;
694
695     if (NewArgc == 0 && rval == MODE_RUN) {     /* no options and no command */
696         SET(rval, (MODE_IMPLIED_SHELL | MODE_SHELL));
697         return(rval);
698     }
699
700     /* New default: reset the environment */
701     def_env_reset = TRUE;
702     while (NewArgc > 0 && NewArgv[0][0] == '-') {
703         if (NewArgv[0][1] != '\0' && NewArgv[0][2] != '\0')
704             warnx("please use single character options");
705
706         switch (NewArgv[0][1]) {
707             case 'p':
708                 /* Must have an associated prompt. */
709                 if (NewArgv[1] == NULL)
710                     usage(1);
711
712                 user_prompt = NewArgv[1];
713
714                 NewArgc--;
715                 NewArgv++;
716                 break;
717             case 'u':
718                 /* Must have an associated runas user. */
719                 if (NewArgv[1] == NULL)
720                     usage(1);
721
722                 user_runas = &NewArgv[1];
723
724                 NewArgc--;
725                 NewArgv++;
726                 break;
727 #ifdef HAVE_BSD_AUTH_H
728             case 'a':
729                 /* Must have an associated authentication style. */
730                 if (NewArgv[1] == NULL)
731                     usage(1);
732
733                 login_style = NewArgv[1];
734
735                 NewArgc--;
736                 NewArgv++;
737                 break;
738 #endif
739 #ifdef HAVE_LOGIN_CAP_H
740             case 'c':
741                 /* Must have an associated login class. */
742                 if (NewArgv[1] == NULL)
743                     usage(1);
744
745                 login_class = NewArgv[1];
746                 def_use_loginclass = TRUE;
747
748                 NewArgc--;
749                 NewArgv++;
750                 break;
751 #endif
752             case 'b':
753                 SET(rval, MODE_BACKGROUND);
754                 break;
755             case 'e':
756                 rval = MODE_EDIT;
757                 if (excl && excl != 'e')
758                     usage_excl(1);
759                 excl = 'e';
760                 break;
761             case 'v':
762                 rval = MODE_VALIDATE;
763                 if (excl && excl != 'v')
764                     usage_excl(1);
765                 excl = 'v';
766                 break;
767             case 'i':
768                 SET(rval, (MODE_LOGIN_SHELL | MODE_SHELL));
769                 def_env_reset = TRUE;
770                 if (excl && excl != 'i')
771                     usage_excl(1);
772                 excl = 'i';
773                 break;
774             case 'k':
775                 rval = MODE_INVALIDATE;
776                 if (excl && excl != 'k')
777                     usage_excl(1);
778                 excl = 'k';
779                 break;
780             case 'K':
781                 rval = MODE_KILL;
782                 if (excl && excl != 'K')
783                     usage_excl(1);
784                 excl = 'K';
785                 break;
786             case 'L':
787                 rval = MODE_LISTDEFS;
788                 if (excl && excl != 'L')
789                     usage_excl(1);
790                 excl = 'L';
791                 break;
792             case 'l':
793                 rval = MODE_LIST;
794                 if (excl && excl != 'l')
795                     usage_excl(1);
796                 excl = 'l';
797                 break;
798             case 'V':
799                 rval = MODE_VERSION;
800                 if (excl && excl != 'V')
801                     usage_excl(1);
802                 excl = 'V';
803                 break;
804             case 'h':
805                 rval = MODE_HELP;
806                 if (excl && excl != 'h')
807                     usage_excl(1);
808                 excl = 'h';
809                 break;
810             case 's':
811                 SET(rval, MODE_SHELL);
812                 if (excl && excl != 's')
813                     usage_excl(1);
814                 excl = 's';
815                 break;
816             case 'H':
817                 SET(rval, MODE_RESET_HOME);
818                 break;
819             case 'P':
820                 SET(rval, MODE_PRESERVE_GROUPS);
821                 break;
822             case 'S':
823                 SET(tgetpass_flags, TGP_STDIN);
824                 break;
825             case '-':
826                 NewArgc--;
827                 NewArgv++;
828                 if (rval == MODE_RUN)
829                     SET(rval, (MODE_IMPLIED_SHELL | MODE_SHELL));
830                 return(rval);
831             case '\0':
832                 warnx("'-' requires an argument");
833                 usage(1);
834             default:
835                 warnx("illegal option `%s'", NewArgv[0]);
836                 usage(1);
837         }
838         NewArgc--;
839         NewArgv++;
840     }
841
842     if (user_runas != NULL && !ISSET(rval, (MODE_EDIT|MODE_RUN))) {
843         if (excl != '\0')
844             warnx("the `-u' and '-%c' options may not be used together", excl);
845         usage(1);
846     }
847
848     if ((NewArgc == 0 && (rval & MODE_EDIT)) ||
849         (NewArgc > 0 && !(rval & (MODE_RUN | MODE_EDIT))))
850         usage(1);
851
852     return(rval);
853 }
854
855 /*
856  * Sanity check sudoers mode/owner/type.
857  * Leaves a file pointer to the sudoers file open in ``fp''.
858  */
859 static void
860 check_sudoers()
861 {
862     struct stat statbuf;
863     int rootstat, i;
864     char c;
865
866     /*
867      * Fix the mode and group on sudoers file from old default.
868      * Only works if file system is readable/writable by root.
869      */
870     if ((rootstat = stat_sudoers(_PATH_SUDOERS, &statbuf)) == 0 &&
871         SUDOERS_UID == statbuf.st_uid && SUDOERS_MODE != 0400 &&
872         (statbuf.st_mode & 0007777) == 0400) {
873
874         if (chmod(_PATH_SUDOERS, SUDOERS_MODE) == 0) {
875             warnx("fixed mode on %s", _PATH_SUDOERS);
876             SET(statbuf.st_mode, SUDOERS_MODE);
877             if (statbuf.st_gid != SUDOERS_GID) {
878                 if (!chown(_PATH_SUDOERS,(uid_t) -1,SUDOERS_GID)) {
879                     warnx("set group on %s", _PATH_SUDOERS);
880                     statbuf.st_gid = SUDOERS_GID;
881                 } else
882                     warn("unable to set group on %s", _PATH_SUDOERS);
883             }
884         } else
885             warn("unable to fix mode on %s", _PATH_SUDOERS);
886     }
887
888     /*
889      * Sanity checks on sudoers file.  Must be done as sudoers
890      * file owner.  We already did a stat as root, so use that
891      * data if we can't stat as sudoers file owner.
892      */
893     set_perms(PERM_SUDOERS);
894
895     if (rootstat != 0 && stat_sudoers(_PATH_SUDOERS, &statbuf) != 0)
896         log_error(USE_ERRNO, "can't stat %s", _PATH_SUDOERS);
897     else if (!S_ISREG(statbuf.st_mode))
898         log_error(0, "%s is not a regular file", _PATH_SUDOERS);
899     else if (statbuf.st_size == 0)
900         log_error(0, "%s is zero length", _PATH_SUDOERS);
901     else if ((statbuf.st_mode & 07777) != SUDOERS_MODE)
902         log_error(0, "%s is mode 0%o, should be 0%o", _PATH_SUDOERS,
903             (statbuf.st_mode & 07777), SUDOERS_MODE);
904     else if (statbuf.st_uid != SUDOERS_UID)
905         log_error(0, "%s is owned by uid %lu, should be %lu", _PATH_SUDOERS,
906             (unsigned long) statbuf.st_uid, SUDOERS_UID);
907     else if (statbuf.st_gid != SUDOERS_GID)
908         log_error(0, "%s is owned by gid %lu, should be %lu", _PATH_SUDOERS,
909             (unsigned long) statbuf.st_gid, SUDOERS_GID);
910     else {
911         /* Solaris sometimes returns EAGAIN so try 10 times */
912         for (i = 0; i < 10 ; i++) {
913             errno = 0;
914             if ((sudoers_fp = fopen(_PATH_SUDOERS, "r")) == NULL ||
915                 fread(&c, sizeof(c), 1, sudoers_fp) != 1) {
916                 sudoers_fp = NULL;
917                 if (errno != EAGAIN && errno != EWOULDBLOCK)
918                     break;
919             } else
920                 break;
921             sleep(1);
922         }
923         if (sudoers_fp == NULL)
924             log_error(USE_ERRNO, "can't open %s", _PATH_SUDOERS);
925     }
926
927     set_perms(PERM_ROOT);               /* change back to root */
928 }
929
930 /*
931  * Close all open files (except std*) and turn off core dumps.
932  * Also sets the set_perms() pointer to the correct function.
933  */
934 static void
935 initial_setup()
936 {
937 #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
938     struct rlimit rl;
939
940     /*
941      * Turn off core dumps.
942      */
943     (void) getrlimit(RLIMIT_CORE, &corelimit);
944     memcpy(&rl, &corelimit, sizeof(struct rlimit));
945     rl.rlim_cur = 0;
946     (void) setrlimit(RLIMIT_CORE, &rl);
947 #endif /* RLIMIT_CORE && !SUDO_DEVEL */
948
949     closefrom(STDERR_FILENO + 1);
950
951     /*
952      * Make set_perms point to the correct function.
953      * If we are using setresuid() or setreuid() we only need to set this
954      * once.  If we are using POSIX saved uids we will switch to
955      * set_perms_nosuid after sudoers has been parsed if the "stay_suid"
956      * option is not set.
957      */
958 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID)
959     set_perms = set_perms_suid;
960 #else
961 # if !defined(NO_SAVED_IDS) && defined(_SC_SAVED_IDS) && defined(_SC_VERSION)
962     if (sysconf(_SC_SAVED_IDS) == 1 && sysconf(_SC_VERSION) >= 199009)
963         set_perms = set_perms_posix;
964     else
965 # endif
966         set_perms = set_perms_nosuid;
967 #endif /* HAVE_SETRESUID || HAVE_SETREUID */
968 }
969
970 #ifdef HAVE_LOGIN_CAP_H
971 static void
972 set_loginclass(pw)
973     struct passwd *pw;
974 {
975     int errflags;
976
977     /*
978      * Don't make it a fatal error if the user didn't specify the login
979      * class themselves.  We do this because if login.conf gets
980      * corrupted we want the admin to be able to use sudo to fix it.
981      */
982     if (login_class)
983         errflags = NO_MAIL|MSG_ONLY;
984     else
985         errflags = NO_MAIL|MSG_ONLY|NO_EXIT;
986
987     if (login_class && strcmp(login_class, "-") != 0) {
988         if (strcmp(*user_runas, "root") != 0 && user_uid != 0)
989             errx(1, "only root can use -c %s", login_class);
990     } else {
991         login_class = pw->pw_class;
992         if (!login_class || !*login_class)
993             login_class =
994                 (pw->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS;
995     }
996
997     lc = login_getclass(login_class);
998     if (!lc || !lc->lc_class || strcmp(lc->lc_class, login_class) != 0) {
999         log_error(errflags, "unknown login class: %s", login_class);
1000         if (!lc)
1001             lc = login_getclass(NULL);  /* needed for login_getstyle() later */
1002     }
1003 }
1004 #else
1005 static void
1006 set_loginclass(pw)
1007     struct passwd *pw;
1008 {
1009 }
1010 #endif /* HAVE_LOGIN_CAP_H */
1011
1012 /*
1013  * Look up the fully qualified domain name and set user_host and user_shost.
1014  */
1015 void
1016 set_fqdn()
1017 {
1018     struct hostent *hp;
1019     char *p;
1020
1021     if (!(hp = gethostbyname(user_host))) {
1022         log_error(MSG_ONLY|NO_EXIT,
1023             "unable to lookup %s via gethostbyname()", user_host);
1024     } else {
1025         if (user_shost != user_host)
1026             free(user_shost);
1027         free(user_host);
1028         user_host = estrdup(hp->h_name);
1029     }
1030     if ((p = strchr(user_host, '.'))) {
1031         *p = '\0';
1032         user_shost = estrdup(user_host);
1033         *p = '.';
1034     } else {
1035         user_shost = user_host;
1036     }
1037 }
1038
1039 /*
1040  * Get passwd entry for the user we are going to run commands as.
1041  * By default, this is "root".  Updates runas_pw as a side effect.
1042  */
1043 int
1044 set_runaspw(user)
1045     char *user;
1046 {
1047     if (runas_pw != NULL) {
1048         if (user_runas != &def_runas_default)
1049             return(TRUE);               /* don't override -u option */
1050         free(runas_pw);
1051     }
1052     if (*user == '#') {
1053         runas_pw = sudo_getpwuid(atoi(user + 1));
1054         if (runas_pw == NULL) {
1055             runas_pw = emalloc(sizeof(struct passwd));
1056             (void) memset((VOID *)runas_pw, 0, sizeof(struct passwd));
1057             runas_pw->pw_uid = atoi(user + 1);
1058         }
1059     } else {
1060         runas_pw = sudo_getpwnam(user);
1061         if (runas_pw == NULL)
1062             log_error(NO_MAIL|MSG_ONLY, "no passwd entry for %s!", user);
1063     }
1064     return(TRUE);
1065 }
1066
1067 /*
1068  * Get passwd entry for the user we are going to authenticate as.
1069  * By default, this is the user invoking sudo.  In the most common
1070  * case, this matches sudo_user.pw or runas_pw.
1071  */
1072 static struct passwd *
1073 get_authpw()
1074 {
1075     struct passwd *pw;
1076
1077     if (def_rootpw) {
1078         if (runas_pw->pw_uid == 0)
1079             pw = runas_pw;
1080         else if ((pw = sudo_getpwuid(0)) == NULL)
1081             log_error(0, "uid 0 does not exist in the passwd file!");
1082     } else if (def_runaspw) {
1083         if (strcmp(def_runas_default, *user_runas) == 0)
1084             pw = runas_pw;
1085         else if ((pw = sudo_getpwnam(def_runas_default)) == NULL)
1086             log_error(0, "user %s does not exist in the passwd file!",
1087                 def_runas_default);
1088     } else if (def_targetpw) {
1089         if (runas_pw->pw_name == NULL)
1090             log_error(NO_MAIL|MSG_ONLY, "no passwd entry for %lu!",
1091                 runas_pw->pw_uid);
1092         pw = runas_pw;
1093     } else
1094         pw = sudo_user.pw;
1095
1096     return(pw);
1097 }
1098
1099 /*
1100  * Tell which options are mutually exclusive and exit.
1101  */
1102 static void
1103 usage_excl(exit_val)
1104     int exit_val;
1105 {
1106     warnx("Only one of the -e, -h, -k, -K, -l, -s, -v or -V options may be used");
1107     usage(exit_val);
1108 }
1109
1110 /*
1111  * Give usage message and exit.
1112  */
1113 static void
1114 usage(exit_val)
1115     int exit_val;
1116 {
1117     char **p;
1118     int linelen, linemax, ulen;
1119     static char *uvec[] = {
1120         " [-HPSb]",
1121 #ifdef HAVE_BSD_AUTH_H
1122         " [-a auth_type]",
1123 #endif
1124 #ifdef HAVE_LOGIN_CAP_H
1125         " [-c class|-]",
1126 #endif
1127         " [-p prompt]",
1128         " [-u username|#uid]",
1129         " { -e file [...] | -i | -s | <command> }",
1130         NULL
1131     };
1132
1133     /*
1134      * For sudoedit, replace the last entry in the usage vector.
1135      * For sudo, print the secondary usage.
1136      */
1137     if (strcmp(getprogname(), "sudoedit") == 0) {
1138         /* Replace the last entry in the usage vector. */
1139         for (p = uvec; p[1] != NULL; p++)
1140             continue;
1141         *p = " file [...]";
1142     } else {
1143         fprintf(stderr, "usage: %s -K | -L | -V | -h | -k | -l | -v\n",
1144             getprogname());
1145     }
1146
1147     /*
1148      * Print the main usage and wrap lines as needed.
1149      * Assumes an 80-character wide terminal, which is kind of bogus...
1150      */
1151     ulen = (int)strlen(getprogname()) + 7;
1152     linemax = 80;
1153     linelen = linemax - ulen;
1154     printf("usage: %s", getprogname());
1155     for (p = uvec; *p != NULL; p++) {
1156         if (linelen == linemax || (linelen -= strlen(*p)) >= 0) {
1157             fputs(*p, stdout);
1158         } else {
1159             p--;
1160             linelen = linemax;
1161             printf("\n%*s", ulen, "");
1162         }
1163     }
1164     putchar('\n');
1165     exit(exit_val);
1166 }