version 1.18, 2003/04/01 15:47:51 |
version 1.19, 2003/04/03 19:15:34 |
|
|
* with this distribution. |
* with this distribution. |
*/ |
*/ |
|
|
#define _SUDO_SUDO_C |
#define _SUDO_MAIN |
|
|
#include "config.h" |
#include "config.h" |
|
|
|
|
#ifdef HAVE_UNISTD_H |
#ifdef HAVE_UNISTD_H |
# include <unistd.h> |
# include <unistd.h> |
#endif /* HAVE_UNISTD_H */ |
#endif /* HAVE_UNISTD_H */ |
|
#ifdef HAVE_ERR_H |
|
# include <err.h> |
|
#else |
|
# include "emul/err.h" |
|
#endif /* HAVE_ERR_H */ |
#include <pwd.h> |
#include <pwd.h> |
#include <errno.h> |
#include <errno.h> |
#include <fcntl.h> |
#include <fcntl.h> |
|
|
#include "version.h" |
#include "version.h" |
|
|
#ifndef lint |
#ifndef lint |
static const char rcsid[] = "$Sudo: sudo.c,v 1.334 2003/04/01 15:02:49 millert Exp $"; |
static const char rcsid[] = "$Sudo: sudo.c,v 1.335 2003/04/02 18:25:19 millert Exp $"; |
#endif /* lint */ |
#endif /* lint */ |
|
|
/* |
/* |
* Prototypes |
* Prototypes |
*/ |
*/ |
static int init_vars __P((int)); |
static int init_vars __P((int)); |
static int parse_args __P((void)); |
static int parse_args __P((int, char **)); |
static void check_sudoers __P((void)); |
static void check_sudoers __P((void)); |
static void initial_setup __P((void)); |
static void initial_setup __P((void)); |
static void set_loginclass __P((struct passwd *)); |
static void set_loginclass __P((struct passwd *)); |
|
|
/* |
/* |
* Globals |
* Globals |
*/ |
*/ |
int Argc; |
int Argc, NewArgc; |
char **Argv; |
char **Argv, **NewArgv; |
int NewArgc = 0; |
|
char **NewArgv = NULL; |
|
struct sudo_user sudo_user; |
struct sudo_user sudo_user; |
struct passwd *auth_pw; |
struct passwd *auth_pw; |
FILE *sudoers_fp = NULL; |
FILE *sudoers_fp; |
struct interface *interfaces; |
struct interface *interfaces; |
int num_interfaces; |
int num_interfaces; |
int tgetpass_flags; |
int tgetpass_flags; |
|
|
extern int printmatches; |
extern int printmatches; |
extern char **environ; |
extern char **environ; |
|
|
|
Argc = argc; |
|
Argv = argv; |
|
|
/* Must be done as the first thing... */ |
/* Must be done as the first thing... */ |
#if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS) |
#if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS) |
(void) set_auth_parameters(argc, argv); |
(void) set_auth_parameters(Argc, Argv); |
# ifdef HAVE_INITPRIVS |
# ifdef HAVE_INITPRIVS |
initprivs(); |
initprivs(); |
# endif |
# endif |
|
|
/* Zero out the environment. */ |
/* Zero out the environment. */ |
environ = zero_env(envp); |
environ = zero_env(envp); |
|
|
Argv = argv; |
if (geteuid() != 0) |
Argc = argc; |
errx(1, "must be setuid root"); |
|
|
if (geteuid() != 0) { |
|
(void) fprintf(stderr, "Sorry, %s must be setuid root.\n", Argv[0]); |
|
exit(1); |
|
} |
|
|
|
/* |
/* |
* Signal setup: |
* Signal setup: |
* Ignore keyboard-generated signals so the user cannot interrupt |
* Ignore keyboard-generated signals so the user cannot interrupt |
|
|
setpwent(); |
setpwent(); |
|
|
/* Parse our arguments. */ |
/* Parse our arguments. */ |
sudo_mode = parse_args(); |
sudo_mode = parse_args(Argc, Argv); |
|
|
/* Setup defaults data structures. */ |
/* Setup defaults data structures. */ |
init_defaults(); |
init_defaults(); |
|
|
if (user_uid == 0 && !def_flag(I_ROOT_SUDO)) { |
if (user_uid == 0 && !def_flag(I_ROOT_SUDO)) { |
(void) fprintf(stderr, |
(void) fprintf(stderr, |
"Sorry, %s has been configured to not allow root to run it.\n", |
"Sorry, %s has been configured to not allow root to run it.\n", |
Argv[0]); |
getprogname()); |
exit(1); |
exit(1); |
} |
} |
|
|
|
|
if (validated & VALIDATE_OK) { |
if (validated & VALIDATE_OK) { |
/* Finally tell the user if the command did not exist. */ |
/* Finally tell the user if the command did not exist. */ |
if (cmnd_status == NOT_FOUND_DOT) { |
if (cmnd_status == NOT_FOUND_DOT) { |
(void) fprintf(stderr, "%s: ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.\n", Argv[0], user_cmnd, user_cmnd, user_cmnd); |
warnx("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.", user_cmnd, user_cmnd, user_cmnd); |
exit(1); |
exit(1); |
} else if (cmnd_status == NOT_FOUND) { |
} else if (cmnd_status == NOT_FOUND) { |
(void) fprintf(stderr, "%s: %s: command not found\n", Argv[0], |
warnx("%s: command not found", user_cmnd); |
user_cmnd); |
|
exit(1); |
exit(1); |
} |
} |
|
|
|
|
/* |
/* |
* If we got here then the exec() failed... |
* If we got here then the exec() failed... |
*/ |
*/ |
(void) fprintf(stderr, "%s: unable to exec %s: %s\n", |
warn("unable to execute %s", safe_cmnd); |
Argv[0], safe_cmnd, strerror(errno)); |
|
exit(127); |
exit(127); |
} else if ((validated & FLAG_NO_USER) || (validated & FLAG_NO_HOST)) { |
} else if ((validated & FLAG_NO_USER) || (validated & FLAG_NO_HOST)) { |
log_auth(validated, 1); |
log_auth(validated, 1); |
|
|
log_auth(validated, |
log_auth(validated, |
!(cmnd_status == NOT_FOUND_DOT || cmnd_status == NOT_FOUND)); |
!(cmnd_status == NOT_FOUND_DOT || cmnd_status == NOT_FOUND)); |
if (cmnd_status == NOT_FOUND) |
if (cmnd_status == NOT_FOUND) |
(void) fprintf(stderr, "%s: %s: command not found\n", Argv[0], |
warnx("%s: command not found", user_cmnd); |
user_cmnd); |
|
else if (cmnd_status == NOT_FOUND_DOT) |
else if (cmnd_status == NOT_FOUND_DOT) |
(void) fprintf(stderr, "%s: ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.\n", Argv[0], user_cmnd, user_cmnd, user_cmnd); |
warnx("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.", user_cmnd, user_cmnd, user_cmnd); |
} else { |
} else { |
/* Just tell the user they are not allowed to run foo. */ |
/* Just tell the user they are not allowed to run foo. */ |
log_auth(validated, 1); |
log_auth(validated, 1); |
|
|
int nohostname, rval; |
int nohostname, rval; |
|
|
/* Sanity check command from user. */ |
/* Sanity check command from user. */ |
if (user_cmnd == NULL && strlen(NewArgv[0]) >= MAXPATHLEN) { |
if (user_cmnd == NULL && strlen(NewArgv[0]) >= MAXPATHLEN) |
(void) fprintf(stderr, "%s: %s: Pathname too long\n", Argv[0], |
errx(1, "%s: File name too long", NewArgv[0]); |
NewArgv[0]); |
|
exit(1); |
|
} |
|
|
|
#ifdef HAVE_TZSET |
#ifdef HAVE_TZSET |
(void) tzset(); /* set the timezone if applicable */ |
(void) tzset(); /* set the timezone if applicable */ |
|
|
if (!getcwd(user_cwd, sizeof(user_cwd))) { |
if (!getcwd(user_cwd, sizeof(user_cwd))) { |
set_perms(PERM_ROOT); |
set_perms(PERM_ROOT); |
if (!getcwd(user_cwd, sizeof(user_cwd))) { |
if (!getcwd(user_cwd, sizeof(user_cwd))) { |
(void) fprintf(stderr, "%s: Can't get working directory!\n", |
warnx("cannot get working directory"); |
Argv[0]); |
|
(void) strlcpy(user_cwd, "unknown", sizeof(user_cwd)); |
(void) strlcpy(user_cwd, "unknown", sizeof(user_cwd)); |
} |
} |
} else |
} else |
|
|
NewArgv = (char **) emalloc2((++NewArgc + 1), sizeof(char *)); |
NewArgv = (char **) emalloc2((++NewArgc + 1), sizeof(char *)); |
if (user_shell && *user_shell) { |
if (user_shell && *user_shell) { |
NewArgv[0] = user_shell; |
NewArgv[0] = user_shell; |
} else { |
} else |
(void) fprintf(stderr, "%s: Unable to determine shell.", Argv[0]); |
errx(1, "unable to determine shell"); |
exit(1); |
|
} |
|
|
|
/* copy the args from Argv */ |
/* copy the args from NewArgv */ |
for (dst = NewArgv + 1; (*dst = *src) != NULL; ++src, ++dst) |
for (dst = NewArgv + 1; (*dst = *src) != NULL; ++src, ++dst) |
; |
; |
} |
} |
|
|
user_args = (char *) emalloc(size); |
user_args = (char *) emalloc(size); |
for (to = user_args, from = NewArgv + 1; *from; from++) { |
for (to = user_args, from = NewArgv + 1; *from; from++) { |
n = strlcpy(to, *from, size - (to - user_args)); |
n = strlcpy(to, *from, size - (to - user_args)); |
if (n >= size - (to - user_args)) { |
if (n >= size - (to - user_args)) |
(void) fprintf(stderr, |
errx(1, "internal error, init_vars() overflow"); |
"%s: internal error, init_vars() overflow\n", Argv[0]); |
|
exit(1); |
|
} |
|
to += n; |
to += n; |
*to++ = ' '; |
*to++ = ' '; |
} |
} |
|
|
* Command line argument parsing, can't use getopt(3). |
* Command line argument parsing, can't use getopt(3). |
*/ |
*/ |
static int |
static int |
parse_args() |
parse_args(argc, argv) |
|
int argc; |
|
char **argv; |
{ |
{ |
int rval = MODE_RUN; /* what mode is sudo to be run in? */ |
int rval = MODE_RUN; /* what mode is sudo to be run in? */ |
int excl = 0; /* exclusive arg, no others allowed */ |
int excl = 0; /* exclusive arg, no others allowed */ |
|
|
NewArgv = Argv + 1; |
NewArgv = argv + 1; |
NewArgc = Argc - 1; |
NewArgc = argc - 1; |
|
|
if (NewArgc == 0) { /* no options and no command */ |
if (NewArgc == 0) { /* no options and no command */ |
rval |= (MODE_IMPLIED_SHELL | MODE_SHELL); |
rval |= (MODE_IMPLIED_SHELL | MODE_SHELL); |
|
|
} |
} |
|
|
while (NewArgc > 0 && NewArgv[0][0] == '-') { |
while (NewArgc > 0 && NewArgv[0][0] == '-') { |
if (NewArgv[0][1] != '\0' && NewArgv[0][2] != '\0') { |
if (NewArgv[0][1] != '\0' && NewArgv[0][2] != '\0') |
(void) fprintf(stderr, "%s: Please use single character options\n", |
warnx("please use single character options"); |
Argv[0]); |
|
usage(1); |
|
} |
|
|
|
switch (NewArgv[0][1]) { |
switch (NewArgv[0][1]) { |
case 'p': |
case 'p': |
|
|
|
|
user_prompt = NewArgv[1]; |
user_prompt = NewArgv[1]; |
|
|
/* Shift Argv over and adjust Argc. */ |
|
NewArgc--; |
NewArgc--; |
NewArgv++; |
NewArgv++; |
break; |
break; |
|
|
|
|
user_runas = &NewArgv[1]; |
user_runas = &NewArgv[1]; |
|
|
/* Shift Argv over and adjust Argc. */ |
|
NewArgc--; |
NewArgc--; |
NewArgv++; |
NewArgv++; |
break; |
break; |
|
|
|
|
login_style = NewArgv[1]; |
login_style = NewArgv[1]; |
|
|
/* Shift Argv over and adjust Argc. */ |
|
NewArgc--; |
NewArgc--; |
NewArgv++; |
NewArgv++; |
break; |
break; |
|
|
login_class = NewArgv[1]; |
login_class = NewArgv[1]; |
def_flag(I_USE_LOGINCLASS) = TRUE; |
def_flag(I_USE_LOGINCLASS) = TRUE; |
|
|
/* Shift Argv over and adjust Argc. */ |
|
NewArgc--; |
NewArgc--; |
NewArgv++; |
NewArgv++; |
break; |
break; |
|
|
rval |= (MODE_IMPLIED_SHELL | MODE_SHELL); |
rval |= (MODE_IMPLIED_SHELL | MODE_SHELL); |
return(rval); |
return(rval); |
case '\0': |
case '\0': |
(void) fprintf(stderr, "%s: '-' requires an argument\n", |
warnx("'-' requires an argument"); |
Argv[0]); |
|
usage(1); |
usage(1); |
default: |
default: |
(void) fprintf(stderr, "%s: Illegal option %s\n", Argv[0], |
warnx("illegal option `%s'", NewArgv[0]); |
NewArgv[0]); |
|
usage(1); |
usage(1); |
} |
} |
NewArgc--; |
NewArgc--; |
|
|
(statbuf.st_mode & 0007777) == 0400) { |
(statbuf.st_mode & 0007777) == 0400) { |
|
|
if (chmod(_PATH_SUDOERS, SUDOERS_MODE) == 0) { |
if (chmod(_PATH_SUDOERS, SUDOERS_MODE) == 0) { |
(void) fprintf(stderr, "%s: fixed mode on %s\n", |
warnx("fixed mode on %s", _PATH_SUDOERS); |
Argv[0], _PATH_SUDOERS); |
|
statbuf.st_mode |= SUDOERS_MODE; |
statbuf.st_mode |= SUDOERS_MODE; |
if (statbuf.st_gid != SUDOERS_GID) { |
if (statbuf.st_gid != SUDOERS_GID) { |
if (!chown(_PATH_SUDOERS,(uid_t) -1,SUDOERS_GID)) { |
if (!chown(_PATH_SUDOERS,(uid_t) -1,SUDOERS_GID)) { |
(void) fprintf(stderr, "%s: set group on %s\n", |
warnx("set group on %s", _PATH_SUDOERS); |
Argv[0], _PATH_SUDOERS); |
|
statbuf.st_gid = SUDOERS_GID; |
statbuf.st_gid = SUDOERS_GID; |
} else { |
} else |
(void) fprintf(stderr,"%s: Unable to set group on %s: %s\n", |
warn("unable to set group on %s", _PATH_SUDOERS); |
Argv[0], _PATH_SUDOERS, strerror(errno)); |
|
} |
|
} |
} |
} else { |
} else |
(void) fprintf(stderr, "%s: Unable to fix mode on %s: %s\n", |
warn("unable to fix mode on %s", _PATH_SUDOERS); |
Argv[0], _PATH_SUDOERS, strerror(errno)); |
|
} |
|
} |
} |
|
|
/* |
/* |
|
|
errflags = NO_MAIL|MSG_ONLY|NO_EXIT; |
errflags = NO_MAIL|MSG_ONLY|NO_EXIT; |
|
|
if (login_class && strcmp(login_class, "-") != 0) { |
if (login_class && strcmp(login_class, "-") != 0) { |
if (strcmp(*user_runas, "root") != 0 && user_uid != 0) { |
if (strcmp(*user_runas, "root") != 0 && user_uid != 0) |
(void) fprintf(stderr, "%s: only root can use -c %s\n", |
errx(1, "only root can use -c %s", login_class); |
Argv[0], login_class); |
|
exit(1); |
|
} |
|
} else { |
} else { |
login_class = pw->pw_class; |
login_class = pw->pw_class; |
if (!login_class || !*login_class) |
if (!login_class || !*login_class) |