version 1.26, 2005/06/19 22:00:08 |
version 1.27, 2007/07/26 16:10:16 |
|
|
/* |
/* |
* Copyright (c) 1993-1996,1998-2004 Todd C. Miller <Todd.Miller@courtesan.com> |
* Copyright (c) 1993-1996,1998-2007 Todd C. Miller <Todd.Miller@courtesan.com> |
* |
* |
* Permission to use, copy, modify, and distribute this software for any |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* purpose with or without fee is hereby granted, provided that the above |
|
|
# include <floss.h> |
# include <floss.h> |
#endif |
#endif |
|
|
#include "config.h" |
#include <config.h> |
|
|
#include <sys/types.h> |
#include <sys/types.h> |
#include <sys/stat.h> |
#include <sys/stat.h> |
|
|
#include <fcntl.h> |
#include <fcntl.h> |
#include <signal.h> |
#include <signal.h> |
#include <grp.h> |
#include <grp.h> |
#include <time.h> |
#if TIME_WITH_SYS_TIME |
|
# include <time.h> |
|
#endif |
|
#ifdef HAVE_SETLOCALE |
|
# include <locale.h> |
|
#endif |
#include <netinet/in.h> |
#include <netinet/in.h> |
#include <netdb.h> |
#include <netdb.h> |
#if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS) |
#if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS) |
|
|
# define LOGIN_DEFROOTCLASS "daemon" |
# define LOGIN_DEFROOTCLASS "daemon" |
# endif |
# endif |
#endif |
#endif |
|
#ifdef HAVE_PROJECT_H |
|
# include <project.h> |
|
# include <sys/task.h> |
|
#endif |
|
|
#include "sudo.h" |
#include "sudo.h" |
#include "interfaces.h" |
#include "interfaces.h" |
#include "version.h" |
#include "version.h" |
|
|
#ifndef lint |
#ifndef lint |
static const char rcsid[] = "$Sudo: sudo.c,v 1.370 2004/08/24 18:01:13 millert Exp $"; |
__unused __unused static const char rcsid[] = "$Sudo: sudo.c,v 1.369.2.26 2007/07/22 19:21:01 millert Exp $"; |
#endif /* lint */ |
#endif /* lint */ |
|
|
/* |
/* |
* Prototypes |
* Prototypes |
*/ |
*/ |
static int init_vars __P((int)); |
static int init_vars __P((int, char **)); |
static int parse_args __P((int, char **)); |
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 *)); |
static void usage __P((int)); |
static void set_project __P((struct passwd *)); |
|
static void usage __P((int)) |
|
__attribute__((__noreturn__)); |
|
static void usage_excl __P((int)) |
|
__attribute__((__noreturn__)); |
static void usage_excl __P((int)); |
static void usage_excl __P((int)); |
static struct passwd *get_authpw __P((void)); |
static struct passwd *get_authpw __P((void)); |
extern int sudo_edit __P((int, char **)); |
extern int sudo_edit __P((int, char **, char **)); |
extern void list_matches __P((void)); |
extern void list_matches __P((void)); |
extern char **rebuild_env __P((char **, int, int)); |
extern char **rebuild_env __P((char **, int, int)); |
extern char **zero_env __P((char **)); |
extern void validate_env_vars __P((struct list_member *)); |
|
extern char **insert_env_vars __P((char **, struct list_member *)); |
extern struct passwd *sudo_getpwnam __P((const char *)); |
extern struct passwd *sudo_getpwnam __P((const char *)); |
extern struct passwd *sudo_getpwuid __P((uid_t)); |
extern struct passwd *sudo_getpwuid __P((uid_t)); |
extern struct passwd *sudo_pwdup __P((const struct passwd *)); |
extern struct passwd *sudo_pwdup __P((const struct passwd *)); |
|
|
char *login_style; |
char *login_style; |
#endif /* HAVE_BSD_AUTH_H */ |
#endif /* HAVE_BSD_AUTH_H */ |
sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp, saved_sa_chld; |
sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp, saved_sa_chld; |
void (*set_perms) __P((int)); |
|
|
|
|
|
int |
int |
|
|
int cmnd_status; |
int cmnd_status; |
int sudo_mode; |
int sudo_mode; |
int pwflag; |
int pwflag; |
char **new_environ; |
|
sigaction_t sa; |
sigaction_t sa; |
extern int printmatches; |
extern int printmatches; |
extern char **environ; |
extern char **environ; |
|
|
|
#ifdef HAVE_SETLOCALE |
|
setlocale(LC_ALL, ""); |
|
#endif |
|
|
Argv = argv; |
Argv = argv; |
if ((Argc = argc) < 1) |
if ((Argc = argc) < 1) |
usage(1); |
usage(1); |
|
|
# endif |
# endif |
#endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */ |
#endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */ |
|
|
/* Zero out the environment. */ |
|
environ = zero_env(envp); |
|
|
|
if (geteuid() != 0) |
if (geteuid() != 0) |
errx(1, "must be setuid root"); |
errx(1, "must be setuid root"); |
|
|
|
|
(void) sigaction(SIGCHLD, &sa, &saved_sa_chld); |
(void) sigaction(SIGCHLD, &sa, &saved_sa_chld); |
|
|
/* |
/* |
* Turn off core dumps, close open files and setup set_perms(). |
* Turn off core dumps and close open files. |
*/ |
*/ |
initial_setup(); |
initial_setup(); |
setpwent(); |
setpwent(); |
|
|
(void) printf("Sudo version %s\n", version); |
(void) printf("Sudo version %s\n", version); |
if (getuid() == 0) { |
if (getuid() == 0) { |
putchar('\n'); |
putchar('\n'); |
|
(void) printf("Sudoers path: %s\n", _PATH_SUDOERS); |
dump_auth_methods(); |
dump_auth_methods(); |
dump_defaults(); |
dump_defaults(); |
dump_interfaces(); |
dump_interfaces(); |
|
|
if (user_cmnd == NULL && NewArgc == 0) |
if (user_cmnd == NULL && NewArgc == 0) |
usage(1); |
usage(1); |
|
|
cmnd_status = init_vars(sudo_mode); |
cmnd_status = init_vars(sudo_mode, environ); |
|
|
#ifdef HAVE_LDAP |
#ifdef HAVE_LDAP |
validated = sudo_ldap_check(pwflag); |
validated = sudo_ldap_check(pwflag); |
|
|
validated = sudoers_lookup(pwflag); |
validated = sudoers_lookup(pwflag); |
} |
} |
if (safe_cmnd == NULL) |
if (safe_cmnd == NULL) |
safe_cmnd = user_cmnd; |
safe_cmnd = estrdup(user_cmnd); |
|
|
/* |
/* |
* If we are using set_perms_posix() and the stay_setuid flag was not set, |
|
* set the real, effective and saved uids to 0 and use set_perms_nosuid() |
|
* instead of set_perms_posix(). |
|
*/ |
|
#if !defined(HAVE_SETRESUID) && !defined(HAVE_SETREUID) && \ |
|
!defined(NO_SAVED_IDS) && defined(_SC_SAVED_IDS) && defined(_SC_VERSION) |
|
if (!def_stay_setuid && set_perms == set_perms_posix) { |
|
if (setuid(0)) { |
|
perror("setuid(0)"); |
|
exit(1); |
|
} |
|
set_perms = set_perms_nosuid; |
|
} |
|
#endif |
|
|
|
/* |
|
* Look up the timestamp dir owner if one is specified. |
* Look up the timestamp dir owner if one is specified. |
*/ |
*/ |
if (def_timestampowner) { |
if (def_timestampowner) { |
|
|
if (ISSET(sudo_mode, MODE_IMPLIED_SHELL) && !def_shell_noargs) |
if (ISSET(sudo_mode, MODE_IMPLIED_SHELL) && !def_shell_noargs) |
usage(1); |
usage(1); |
|
|
/* May need to set $HOME to target user if we are running a command. */ |
|
if (ISSET(sudo_mode, MODE_RUN) && (def_always_set_home || |
|
(ISSET(sudo_mode, MODE_SHELL) && def_set_home))) |
|
SET(sudo_mode, MODE_RESET_HOME); |
|
|
|
/* Bail if a tty is required and we don't have one. */ |
/* Bail if a tty is required and we don't have one. */ |
if (def_requiretty) { |
if (def_requiretty) { |
if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) |
if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) |
|
|
(void) close(fd); |
(void) close(fd); |
} |
} |
|
|
|
/* User may have overriden environment resetting via the -E flag. */ |
|
if (ISSET(sudo_mode, MODE_PRESERVE_ENV) && ISSET(validated, FLAG_SETENV)) |
|
def_env_reset = FALSE; |
|
|
|
/* Build a new environment that avoids any nasty bits. */ |
|
environ = rebuild_env(environ, sudo_mode, ISSET(validated, FLAG_NOEXEC)); |
|
|
/* Fill in passwd struct based on user we are authenticating as. */ |
/* Fill in passwd struct based on user we are authenticating as. */ |
auth_pw = get_authpw(); |
auth_pw = get_authpw(); |
|
|
/* Require a password if sudoers says so. */ |
/* Require a password if sudoers says so. */ |
if (!ISSET(validated, FLAG_NOPASS)) |
if (!ISSET(validated, FLAG_NOPASS)) |
check_user(ISSET(validated, FLAG_CHECK_USER)); |
check_user(validated); |
|
|
/* If run as root with SUDO_USER set, set sudo_user.pw to that user. */ |
/* If run as root with SUDO_USER set, set sudo_user.pw to that user. */ |
if (user_uid == 0 && prev_user != NULL && strcmp(prev_user, "root") != 0) { |
if (user_uid == 0 && prev_user != NULL && strcmp(prev_user, "root") != 0) { |
struct passwd *pw; |
struct passwd *pw; |
|
|
if ((pw = sudo_getpwnam(prev_user)) != NULL) { |
if ((pw = sudo_getpwnam(prev_user)) != NULL) { |
free(sudo_user.pw); |
efree(sudo_user.pw); |
sudo_user.pw = pw; |
sudo_user.pw = pw; |
} |
} |
} |
} |
|
|
/* Build a new environment that avoids any nasty bits if we have a cmnd. */ |
|
if (ISSET(sudo_mode, MODE_RUN)) |
|
new_environ = rebuild_env(envp, sudo_mode, ISSET(validated, FLAG_NOEXEC)); |
|
else |
|
new_environ = envp; |
|
|
|
if (ISSET(validated, VALIDATE_OK)) { |
if (ISSET(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) { |
|
|
exit(1); |
exit(1); |
} |
} |
|
|
|
/* If user specified env vars make sure sudoers allows it. */ |
|
if (ISSET(sudo_mode, MODE_RUN) && !ISSET(validated, FLAG_SETENV)) { |
|
if (ISSET(sudo_mode, MODE_PRESERVE_ENV)) |
|
log_error(NO_MAIL, |
|
"sorry, you are not allowed to preserve the environment"); |
|
else |
|
validate_env_vars(sudo_user.env_vars); |
|
} |
|
|
log_auth(validated, 1); |
log_auth(validated, 1); |
if (sudo_mode == MODE_VALIDATE) |
if (sudo_mode == MODE_VALIDATE) |
exit(0); |
exit(0); |
|
|
endpwent(); |
endpwent(); |
endgrent(); |
endgrent(); |
|
|
/* Install the real environment. */ |
|
environ = new_environ; |
|
|
|
if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) { |
if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) { |
char *p; |
char *p; |
|
|
|
|
} |
} |
|
|
if (ISSET(sudo_mode, MODE_EDIT)) |
if (ISSET(sudo_mode, MODE_EDIT)) |
exit(sudo_edit(NewArgc, NewArgv)); |
exit(sudo_edit(NewArgc, NewArgv, envp)); |
|
|
|
/* Insert user-specified environment variables. */ |
|
environ = insert_env_vars(environ, sudo_user.env_vars); |
|
|
/* Restore signal handlers before we exec. */ |
/* Restore signal handlers before we exec. */ |
(void) sigaction(SIGINT, &saved_sa_int, NULL); |
(void) sigaction(SIGINT, &saved_sa_int, NULL); |
(void) sigaction(SIGQUIT, &saved_sa_quit, NULL); |
(void) sigaction(SIGQUIT, &saved_sa_quit, NULL); |
|
|
if (ISSET(sudo_mode, MODE_BACKGROUND) && fork() > 0) |
if (ISSET(sudo_mode, MODE_BACKGROUND) && fork() > 0) |
exit(0); |
exit(0); |
else |
else |
EXECV(safe_cmnd, NewArgv); /* run the command */ |
execve(safe_cmnd, NewArgv, environ); |
#else |
#else |
exit(0); |
exit(0); |
#endif /* PROFILING */ |
#endif /* PROFILING */ |
/* |
/* |
* If we got here then the exec() failed... |
* If we got here then the exec() failed... |
*/ |
*/ |
|
if (errno == ENOEXEC) { |
|
NewArgv--; /* at least one extra slot... */ |
|
NewArgv[0] = "sh"; |
|
NewArgv[1] = safe_cmnd; |
|
execve(_PATH_BSHELL, NewArgv, environ); |
|
} |
warn("unable to execute %s", safe_cmnd); |
warn("unable to execute %s", safe_cmnd); |
exit(127); |
exit(127); |
} else if (ISSET(validated, FLAG_NO_USER) || (validated & FLAG_NO_HOST)) { |
} else if (ISSET(validated, FLAG_NO_USER) || (validated & FLAG_NO_HOST)) { |
|
|
* load the ``interfaces'' array. |
* load the ``interfaces'' array. |
*/ |
*/ |
static int |
static int |
init_vars(sudo_mode) |
init_vars(sudo_mode, envp) |
int sudo_mode; |
int sudo_mode; |
|
char **envp; |
{ |
{ |
char *p, thost[MAXHOSTNAMELEN]; |
char *p, **ep, thost[MAXHOSTNAMELEN]; |
int nohostname, rval; |
int nohostname, rval; |
|
|
/* Sanity check command from user. */ |
/* Sanity check command from user. */ |
|
|
} else |
} else |
user_tty = "unknown"; |
user_tty = "unknown"; |
|
|
|
for (ep = envp; *ep; ep++) { |
|
switch (**ep) { |
|
case 'P': |
|
if (strncmp("PATH=", *ep, 5) == 0) |
|
user_path = *ep + 5; |
|
break; |
|
case 'S': |
|
if (strncmp("SHELL=", *ep, 6) == 0) |
|
user_shell = *ep + 6; |
|
else if (!user_prompt && strncmp("SUDO_PROMPT=", *ep, 12) == 0) |
|
user_prompt = *ep + 12; |
|
else if (strncmp("SUDO_USER=", *ep, 10) == 0) |
|
prev_user = *ep + 10; |
|
break; |
|
|
|
} |
|
} |
|
|
/* |
/* |
* Get a local copy of the user's struct passwd with the shadow password |
* Get a local copy of the user's struct passwd with the shadow password |
* if necessary. It is assumed that euid is 0 at this point so we |
* if necessary. It is assumed that euid is 0 at this point so we |
|
|
|
|
/* It is now safe to use log_error() and set_perms() */ |
/* It is now safe to use log_error() and set_perms() */ |
|
|
|
#ifdef HAVE_GETGROUPS |
|
if ((user_ngroups = getgroups(0, NULL)) > 0) { |
|
user_groups = emalloc2(user_ngroups, sizeof(gid_t)); |
|
if (getgroups(user_ngroups, user_groups) < 0) |
|
log_error(USE_ERRNO|MSG_ONLY, "can't get group vector"); |
|
} else |
|
user_ngroups = 0; |
|
#endif |
|
|
if (def_fqdn) |
if (def_fqdn) |
set_fqdn(); /* may call log_error() */ |
set_fqdn(); /* may call log_error() */ |
|
|
|
|
if ((sudo_mode & (MODE_SHELL | MODE_EDIT))) { |
if ((sudo_mode & (MODE_SHELL | MODE_EDIT))) { |
char **dst, **src = NewArgv; |
char **dst, **src = NewArgv; |
|
|
NewArgv = (char **) emalloc2((++NewArgc + 1), sizeof(char *)); |
/* Allocate an extra slot for execve() failure (ENOEXEC). */ |
|
NewArgv = (char **) emalloc2((++NewArgc + 2), sizeof(char *)); |
|
NewArgv++; |
if (ISSET(sudo_mode, MODE_EDIT)) |
if (ISSET(sudo_mode, MODE_EDIT)) |
NewArgv[0] = "sudoedit"; |
NewArgv[0] = "sudoedit"; |
else if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) |
else if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) |
|
|
|
|
/* copy the args from NewArgv */ |
/* copy the args from NewArgv */ |
for (dst = NewArgv + 1; (*dst = *src) != NULL; ++src, ++dst) |
for (dst = NewArgv + 1; (*dst = *src) != NULL; ++src, ++dst) |
; |
continue; |
} |
} |
|
|
/* Set login class if applicable. */ |
/* Set login class if applicable. */ |
set_loginclass(sudo_user.pw); |
set_loginclass(sudo_user.pw); |
|
|
|
/* Set project if applicable. */ |
|
set_project(runas_pw); |
|
|
/* Resolve the path and return. */ |
/* Resolve the path and return. */ |
rval = FOUND; |
rval = FOUND; |
user_stat = emalloc(sizeof(struct stat)); |
user_stat = emalloc(sizeof(struct stat)); |
|
|
} else |
} else |
rval = MODE_RUN; |
rval = MODE_RUN; |
|
|
if (NewArgc == 0 && rval == MODE_RUN) { /* no options and no command */ |
while (NewArgc > 0) { |
SET(rval, (MODE_IMPLIED_SHELL | MODE_SHELL)); |
if (NewArgv[0][0] == '-') { |
return(rval); |
if (NewArgv[0][1] != '\0' && NewArgv[0][2] != '\0') |
} |
warnx("please use single character options"); |
|
|
while (NewArgc > 0 && NewArgv[0][0] == '-') { |
switch (NewArgv[0][1]) { |
if (NewArgv[0][1] != '\0' && NewArgv[0][2] != '\0') |
case 'p': |
warnx("please use single character options"); |
/* Must have an associated prompt. */ |
|
if (NewArgv[1] == NULL) |
|
usage(1); |
|
|
switch (NewArgv[0][1]) { |
user_prompt = NewArgv[1]; |
case 'p': |
|
/* Must have an associated prompt. */ |
|
if (NewArgv[1] == NULL) |
|
usage(1); |
|
|
|
user_prompt = NewArgv[1]; |
NewArgc--; |
|
NewArgv++; |
|
break; |
|
case 'u': |
|
/* Must have an associated runas user. */ |
|
if (NewArgv[1] == NULL) |
|
usage(1); |
|
|
NewArgc--; |
user_runas = &NewArgv[1]; |
NewArgv++; |
|
break; |
|
case 'u': |
|
/* Must have an associated runas user. */ |
|
if (NewArgv[1] == NULL) |
|
usage(1); |
|
|
|
user_runas = &NewArgv[1]; |
NewArgc--; |
|
NewArgv++; |
NewArgc--; |
break; |
NewArgv++; |
|
break; |
|
#ifdef HAVE_BSD_AUTH_H |
#ifdef HAVE_BSD_AUTH_H |
case 'a': |
case 'a': |
/* Must have an associated authentication style. */ |
/* Must have an associated authentication style. */ |
if (NewArgv[1] == NULL) |
if (NewArgv[1] == NULL) |
usage(1); |
usage(1); |
|
|
login_style = NewArgv[1]; |
login_style = NewArgv[1]; |
|
|
NewArgc--; |
NewArgc--; |
NewArgv++; |
NewArgv++; |
break; |
break; |
#endif |
#endif |
#ifdef HAVE_LOGIN_CAP_H |
#ifdef HAVE_LOGIN_CAP_H |
case 'c': |
case 'c': |
/* Must have an associated login class. */ |
/* Must have an associated login class. */ |
if (NewArgv[1] == NULL) |
if (NewArgv[1] == NULL) |
usage(1); |
usage(1); |
|
|
login_class = NewArgv[1]; |
login_class = NewArgv[1]; |
def_use_loginclass = TRUE; |
def_use_loginclass = TRUE; |
|
|
NewArgc--; |
NewArgc--; |
NewArgv++; |
NewArgv++; |
break; |
break; |
#endif |
#endif |
case 'b': |
case 'b': |
SET(rval, MODE_BACKGROUND); |
SET(rval, MODE_BACKGROUND); |
break; |
break; |
case 'e': |
case 'e': |
rval = MODE_EDIT; |
rval = MODE_EDIT; |
if (excl && excl != 'e') |
if (excl && excl != 'e') |
usage_excl(1); |
usage_excl(1); |
excl = 'e'; |
excl = 'e'; |
break; |
break; |
case 'v': |
case 'v': |
rval = MODE_VALIDATE; |
rval = MODE_VALIDATE; |
if (excl && excl != 'v') |
if (excl && excl != 'v') |
usage_excl(1); |
usage_excl(1); |
excl = 'v'; |
excl = 'v'; |
break; |
break; |
case 'i': |
case 'i': |
SET(rval, (MODE_LOGIN_SHELL | MODE_SHELL)); |
SET(rval, (MODE_LOGIN_SHELL | MODE_SHELL)); |
def_env_reset = TRUE; |
def_env_reset = TRUE; |
if (excl && excl != 'i') |
if (excl && excl != 'i') |
usage_excl(1); |
usage_excl(1); |
excl = 'i'; |
excl = 'i'; |
break; |
break; |
case 'k': |
case 'k': |
rval = MODE_INVALIDATE; |
rval = MODE_INVALIDATE; |
if (excl && excl != 'k') |
if (excl && excl != 'k') |
usage_excl(1); |
usage_excl(1); |
excl = 'k'; |
excl = 'k'; |
break; |
break; |
case 'K': |
case 'K': |
rval = MODE_KILL; |
rval = MODE_KILL; |
if (excl && excl != 'K') |
if (excl && excl != 'K') |
usage_excl(1); |
usage_excl(1); |
excl = 'K'; |
excl = 'K'; |
break; |
break; |
case 'L': |
case 'L': |
rval = MODE_LISTDEFS; |
rval = MODE_LISTDEFS; |
if (excl && excl != 'L') |
if (excl && excl != 'L') |
usage_excl(1); |
usage_excl(1); |
excl = 'L'; |
excl = 'L'; |
break; |
break; |
case 'l': |
case 'l': |
rval = MODE_LIST; |
rval = MODE_LIST; |
if (excl && excl != 'l') |
if (excl && excl != 'l') |
usage_excl(1); |
usage_excl(1); |
excl = 'l'; |
excl = 'l'; |
break; |
break; |
case 'V': |
case 'V': |
rval = MODE_VERSION; |
rval = MODE_VERSION; |
if (excl && excl != 'V') |
if (excl && excl != 'V') |
usage_excl(1); |
usage_excl(1); |
excl = 'V'; |
excl = 'V'; |
break; |
break; |
case 'h': |
case 'h': |
rval = MODE_HELP; |
rval = MODE_HELP; |
if (excl && excl != 'h') |
if (excl && excl != 'h') |
usage_excl(1); |
usage_excl(1); |
excl = 'h'; |
excl = 'h'; |
break; |
break; |
case 's': |
case 's': |
SET(rval, MODE_SHELL); |
SET(rval, MODE_SHELL); |
if (excl && excl != 's') |
if (excl && excl != 's') |
usage_excl(1); |
usage_excl(1); |
excl = 's'; |
excl = 's'; |
break; |
break; |
case 'H': |
case 'H': |
SET(rval, MODE_RESET_HOME); |
SET(rval, MODE_RESET_HOME); |
break; |
break; |
case 'P': |
case 'P': |
SET(rval, MODE_PRESERVE_GROUPS); |
SET(rval, MODE_PRESERVE_GROUPS); |
break; |
break; |
case 'S': |
case 'S': |
SET(tgetpass_flags, TGP_STDIN); |
SET(tgetpass_flags, TGP_STDIN); |
break; |
break; |
case '-': |
case 'E': |
NewArgc--; |
SET(rval, MODE_PRESERVE_ENV); |
NewArgv++; |
break; |
if (rval == MODE_RUN) |
case '-': |
SET(rval, (MODE_IMPLIED_SHELL | MODE_SHELL)); |
NewArgc--; |
return(rval); |
NewArgv++; |
case '\0': |
goto args_done; |
warnx("'-' requires an argument"); |
case '\0': |
usage(1); |
warnx("'-' requires an argument"); |
default: |
usage(1); |
warnx("illegal option `%s'", NewArgv[0]); |
default: |
usage(1); |
warnx("illegal option `%s'", NewArgv[0]); |
|
usage(1); |
|
} |
|
} else if (NewArgv[0][0] != '/' && strchr(NewArgv[0], '=') != NULL) { |
|
/* Could be an environment variable. */ |
|
struct list_member *ev; |
|
ev = emalloc(sizeof(*ev)); |
|
ev->value = NewArgv[0]; |
|
ev->next = sudo_user.env_vars; |
|
sudo_user.env_vars = ev; |
|
} else { |
|
/* Not an arg */ |
|
break; |
} |
} |
NewArgc--; |
NewArgc--; |
NewArgv++; |
NewArgv++; |
} |
} |
|
args_done: |
|
|
|
if (ISSET(rval, MODE_EDIT) && |
|
(ISSET(rval, MODE_PRESERVE_ENV) || sudo_user.env_vars != NULL)) { |
|
if (ISSET(rval, MODE_PRESERVE_ENV)) |
|
warnx("the `-E' option is not valid in edit mode"); |
|
if (sudo_user.env_vars != NULL) |
|
warnx("you may not specify environment variables in edit mode"); |
|
usage(1); |
|
} |
|
|
if (user_runas != NULL && !ISSET(rval, (MODE_EDIT|MODE_RUN))) { |
if (user_runas != NULL && !ISSET(rval, (MODE_EDIT|MODE_RUN))) { |
if (excl != '\0') |
if (excl != '\0') |
warnx("the `-u' and '-%c' options may not be used together", excl); |
warnx("the `-u' and '-%c' options may not be used together", excl); |
usage(1); |
usage(1); |
} |
} |
|
|
if ((NewArgc == 0 && (rval & MODE_EDIT)) || |
if ((NewArgc == 0 && (rval & MODE_EDIT)) || |
(NewArgc > 0 && !(rval & (MODE_RUN | MODE_EDIT)))) |
(NewArgc > 0 && !(rval & (MODE_RUN | MODE_EDIT)))) |
usage(1); |
usage(1); |
|
if (NewArgc == 0 && rval == MODE_RUN) |
|
SET(rval, (MODE_IMPLIED_SHELL | MODE_SHELL)); |
|
|
return(rval); |
return(rval); |
} |
} |
|
|
log_error(0, "%s is zero length", _PATH_SUDOERS); |
log_error(0, "%s is zero length", _PATH_SUDOERS); |
else if ((statbuf.st_mode & 07777) != SUDOERS_MODE) |
else if ((statbuf.st_mode & 07777) != SUDOERS_MODE) |
log_error(0, "%s is mode 0%o, should be 0%o", _PATH_SUDOERS, |
log_error(0, "%s is mode 0%o, should be 0%o", _PATH_SUDOERS, |
(statbuf.st_mode & 07777), SUDOERS_MODE); |
(unsigned int) (statbuf.st_mode & 07777), |
|
(unsigned int) SUDOERS_MODE); |
else if (statbuf.st_uid != SUDOERS_UID) |
else if (statbuf.st_uid != SUDOERS_UID) |
log_error(0, "%s is owned by uid %lu, should be %lu", _PATH_SUDOERS, |
log_error(0, "%s is owned by uid %lu, should be %lu", _PATH_SUDOERS, |
(unsigned long) statbuf.st_uid, (unsigned long) SUDOERS_UID); |
(unsigned long) statbuf.st_uid, (unsigned long) SUDOERS_UID); |
|
|
|
|
/* |
/* |
* Close all open files (except std*) and turn off core dumps. |
* Close all open files (except std*) and turn off core dumps. |
* Also sets the set_perms() pointer to the correct function. |
|
*/ |
*/ |
static void |
static void |
initial_setup() |
initial_setup() |
{ |
{ |
|
int miss[3], devnull = -1; |
#if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL) |
#if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL) |
struct rlimit rl; |
struct rlimit rl; |
|
|
|
|
(void) setrlimit(RLIMIT_CORE, &rl); |
(void) setrlimit(RLIMIT_CORE, &rl); |
#endif /* RLIMIT_CORE && !SUDO_DEVEL */ |
#endif /* RLIMIT_CORE && !SUDO_DEVEL */ |
|
|
closefrom(STDERR_FILENO + 1); |
|
|
|
/* |
/* |
* Make set_perms point to the correct function. |
* stdin, stdout and stderr must be open; set them to /dev/null |
* If we are using setresuid() or setreuid() we only need to set this |
* if they are closed and close all other fds. |
* once. If we are using POSIX saved uids we will switch to |
|
* set_perms_nosuid after sudoers has been parsed if the "stay_suid" |
|
* option is not set. |
|
*/ |
*/ |
#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) |
miss[STDIN_FILENO] = fcntl(STDIN_FILENO, F_GETFL, 0) == -1; |
set_perms = set_perms_suid; |
miss[STDOUT_FILENO] = fcntl(STDOUT_FILENO, F_GETFL, 0) == -1; |
#else |
miss[STDERR_FILENO] = fcntl(STDERR_FILENO, F_GETFL, 0) == -1; |
# if !defined(NO_SAVED_IDS) && defined(_SC_SAVED_IDS) && defined(_SC_VERSION) |
if (miss[STDIN_FILENO] || miss[STDOUT_FILENO] || miss[STDERR_FILENO]) { |
if (sysconf(_SC_SAVED_IDS) == 1 && sysconf(_SC_VERSION) >= 199009) |
if ((devnull = open(_PATH_DEVNULL, O_RDWR, 0644)) != -1) { |
set_perms = set_perms_posix; |
if (miss[STDIN_FILENO]) |
else |
(void) dup2(devnull, STDIN_FILENO); |
# endif |
if (miss[STDOUT_FILENO]) |
set_perms = set_perms_nosuid; |
(void) dup2(devnull, STDOUT_FILENO); |
#endif /* HAVE_SETRESUID || HAVE_SETREUID */ |
if (miss[STDERR_FILENO]) |
|
(void) dup2(devnull, STDERR_FILENO); |
|
} |
|
} |
|
closefrom(STDERR_FILENO + 1); |
} |
} |
|
|
#ifdef HAVE_LOGIN_CAP_H |
#ifdef HAVE_LOGIN_CAP_H |
|
|
} |
} |
#endif /* HAVE_LOGIN_CAP_H */ |
#endif /* HAVE_LOGIN_CAP_H */ |
|
|
|
#ifdef HAVE_PROJECT_H |
|
static void |
|
set_project(pw) |
|
struct passwd *pw; |
|
{ |
|
int errflags = NO_MAIL|MSG_ONLY|NO_EXIT; |
|
int errval; |
|
struct project proj; |
|
struct project *resultp = '\0'; |
|
char buf[1024]; |
|
|
|
/* |
|
* Collect the default project for the user and settaskid |
|
*/ |
|
setprojent(); |
|
if (resultp = getdefaultproj(pw->pw_name, &proj, buf, sizeof(buf))) { |
|
errval = setproject(resultp->pj_name, pw->pw_name, TASK_NORMAL); |
|
if (errval != 0) { |
|
switch(errval) { |
|
case SETPROJ_ERR_TASK: |
|
if (errno == EAGAIN) |
|
log_error(errflags, "resource control limit has been reached"); |
|
else if (errno == ESRCH) |
|
log_error(errflags, "user \"%s\" is not a member of " |
|
"project \"%s\"", pw->pw_name, resultp->pj_name); |
|
else if (errno == EACCES) |
|
log_error(errflags, "the invoking task is final"); |
|
else |
|
log_error(errflags, "could not join project \"%s\"", |
|
resultp->pj_name); |
|
break; |
|
case SETPROJ_ERR_POOL: |
|
if (errno == EACCES) |
|
log_error(errflags, "no resource pool accepting " |
|
"default bindings exists for project \"%s\"", |
|
resultp->pj_name); |
|
else if (errno == ESRCH) |
|
log_error(errflags, "specified resource pool does " |
|
"not exist for project \"%s\"", resultp->pj_name); |
|
else |
|
log_error(errflags, "could not bind to default " |
|
"resource pool for project \"%s\"", resultp->pj_name); |
|
break; |
|
default: |
|
if (errval <= 0) { |
|
log_error(errflags, "setproject failed for project \"%s\"", |
|
resultp->pj_name); |
|
} else { |
|
log_error(errflags, "warning, resource control assignment " |
|
"failed for project \"%s\"", resultp->pj_name); |
|
} |
|
} |
|
} |
|
} else { |
|
log_error(errflags, "getdefaultproj() error: %s", strerror(errno)); |
|
} |
|
endprojent(); |
|
} |
|
#else |
|
static void |
|
set_project(pw) |
|
struct passwd *pw; |
|
{ |
|
} |
|
#endif /* HAVE_PROJECT_H */ |
|
|
/* |
/* |
* Look up the fully qualified domain name and set user_host and user_shost. |
* Look up the fully qualified domain name and set user_host and user_shost. |
*/ |
*/ |
|
|
"unable to lookup %s via gethostbyname()", user_host); |
"unable to lookup %s via gethostbyname()", user_host); |
} else { |
} else { |
if (user_shost != user_host) |
if (user_shost != user_host) |
free(user_shost); |
efree(user_shost); |
free(user_host); |
efree(user_host); |
user_host = estrdup(hp->h_name); |
user_host = estrdup(hp->h_name); |
} |
} |
if ((p = strchr(user_host, '.'))) { |
if ((p = strchr(user_host, '.'))) { |
|
|
if (runas_pw != NULL) { |
if (runas_pw != NULL) { |
if (user_runas != &def_runas_default) |
if (user_runas != &def_runas_default) |
return(TRUE); /* don't override -u option */ |
return(TRUE); /* don't override -u option */ |
free(runas_pw); |
efree(runas_pw); |
} |
} |
if (*user == '#') { |
if (*user == '#') { |
runas_pw = sudo_getpwuid(atoi(user + 1)); |
runas_pw = sudo_getpwuid(atoi(user + 1)); |
|
|
usage_excl(exit_val) |
usage_excl(exit_val) |
int exit_val; |
int exit_val; |
{ |
{ |
warnx("Only one of the -e, -h, -k, -K, -l, -s, -v or -V options may be used"); |
warnx("Only one of the -e, -h, i, -k, -K, -l, -s, -v or -V options may be used"); |
usage(exit_val); |
usage(exit_val); |
} |
} |
|
|
|
|
usage(exit_val) |
usage(exit_val) |
int exit_val; |
int exit_val; |
{ |
{ |
char **p; |
char **p, **uvec[4]; |
int linelen, linemax, ulen; |
int i, linelen, linemax, ulen; |
static char *uvec[] = { |
static char *uvec1[] = { |
" [-HPSb]", |
" -h | -K | -k | -L | -l | -V | -v", |
|
NULL |
|
}; |
|
static char *uvec2[] = { |
|
" [-bEHPS]", |
#ifdef HAVE_BSD_AUTH_H |
#ifdef HAVE_BSD_AUTH_H |
" [-a auth_type]", |
" [-a auth_type]", |
#endif |
#endif |
|
|
#endif |
#endif |
" [-p prompt]", |
" [-p prompt]", |
" [-u username|#uid]", |
" [-u username|#uid]", |
" { -e file [...] | -i | -s | <command> }", |
" [VAR=value]", |
|
" {-i | -s | <command>}", |
NULL |
NULL |
}; |
}; |
|
static char *uvec3[] = { |
|
" -e", |
|
" [-S]", |
|
#ifdef HAVE_BSD_AUTH_H |
|
" [-a auth_type]", |
|
#endif |
|
#ifdef HAVE_LOGIN_CAP_H |
|
" [-c class|-]", |
|
#endif |
|
" [-p prompt]", |
|
" [-u username|#uid]", |
|
" file ...", |
|
NULL |
|
}; |
|
|
/* |
/* |
* For sudoedit, replace the last entry in the usage vector. |
* Use usage vectors appropriate to the progname. |
* For sudo, print the secondary usage. |
|
*/ |
*/ |
if (strcmp(getprogname(), "sudoedit") == 0) { |
if (strcmp(getprogname(), "sudoedit") == 0) { |
/* Replace the last entry in the usage vector. */ |
uvec[0] = uvec3 + 1; |
for (p = uvec; p[1] != NULL; p++) |
uvec[1] = NULL; |
continue; |
|
*p = " file [...]"; |
|
} else { |
} else { |
fprintf(stderr, "usage: %s -K | -L | -V | -h | -k | -l | -v\n", |
uvec[0] = uvec1; |
getprogname()); |
uvec[1] = uvec2; |
|
uvec[2] = uvec3; |
|
uvec[3] = NULL; |
} |
} |
|
|
/* |
/* |
* Print the main usage and wrap lines as needed. |
* Print usage and wrap lines as needed. |
* Assumes an 80-character wide terminal, which is kind of bogus... |
* Assumes an 80-character wide terminal, which is kind of bogus... |
*/ |
*/ |
ulen = (int)strlen(getprogname()) + 7; |
ulen = (int)strlen(getprogname()) + 7; |
linemax = 80; |
linemax = 80; |
linelen = linemax - ulen; |
for (i = 0; uvec[i] != NULL; i++) { |
printf("usage: %s", getprogname()); |
linelen = linemax - ulen; |
for (p = uvec; *p != NULL; p++) { |
printf("usage: %s", getprogname()); |
if (linelen == linemax || (linelen -= strlen(*p)) >= 0) { |
for (p = uvec[i]; *p != NULL; p++) { |
fputs(*p, stdout); |
if (linelen == linemax || (linelen -= strlen(*p)) >= 0) { |
} else { |
fputs(*p, stdout); |
p--; |
} else { |
linelen = linemax; |
p--; |
printf("\n%*s", ulen, ""); |
linelen = linemax; |
|
printf("\n%*s", ulen, ""); |
|
} |
} |
} |
|
putchar('\n'); |
} |
} |
putchar('\n'); |
|
exit(exit_val); |
exit(exit_val); |
} |
} |