|
version 1.1.1.4, 2013/07/22 10:46:13
|
version 1.1.1.5, 2013/10/14 07:56:35
|
|
Line 83
|
Line 83
|
| # include <prot.h> |
# include <prot.h> |
| #endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */ |
#endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */ |
| |
|
| |
#include <sudo_usage.h> |
| #include "sudo.h" |
#include "sudo.h" |
| #include "sudo_plugin.h" |
#include "sudo_plugin.h" |
| #include "sudo_plugin_int.h" |
#include "sudo_plugin_int.h" |
| #include "sudo_usage.h" |
|
| |
|
| /* |
/* |
| * Local variables |
* Local variables |
|
Line 94
|
Line 94
|
| struct plugin_container policy_plugin; |
struct plugin_container policy_plugin; |
| struct plugin_container_list io_plugins; |
struct plugin_container_list io_plugins; |
| struct user_details user_details; |
struct user_details user_details; |
| const char *list_user, *runas_user, *runas_group; /* extern for parse_args.c */ | const char *list_user; /* extern for parse_args.c */ |
| static struct command_details command_details; |
static struct command_details command_details; |
| static int sudo_mode; |
static int sudo_mode; |
| |
|
|
Line 133 static void iolog_unlink(struct plugin_container *plug
|
Line 133 static void iolog_unlink(struct plugin_container *plug
|
| |
|
| #ifdef RLIMIT_CORE |
#ifdef RLIMIT_CORE |
| static struct rlimit corelimit; |
static struct rlimit corelimit; |
| #endif /* RLIMIT_CORE */ | #endif |
| #if defined(__linux__) | #ifdef __linux__ |
| static struct rlimit nproclimit; |
static struct rlimit nproclimit; |
| #endif |
#endif |
| |
|
|
Line 354 fill_group_list(struct user_details *ud, int system_ma
|
Line 354 fill_group_list(struct user_details *ud, int system_ma
|
| * trying getgrouplist() until we have enough room in the array. |
* trying getgrouplist() until we have enough room in the array. |
| */ |
*/ |
| ud->ngroups = sudo_conf_max_groups(); |
ud->ngroups = sudo_conf_max_groups(); |
| if (ud->ngroups != -1) { | if (ud->ngroups > 0) { |
| ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T)); |
ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T)); |
| /* No error on insufficient space if user specified max_groups. */ |
/* No error on insufficient space if user specified max_groups. */ |
| (void)getgrouplist(ud->username, ud->gid, ud->groups, &ud->ngroups); |
(void)getgrouplist(ud->username, ud->gid, ud->groups, &ud->ngroups); |
|
Line 467 get_user_info(struct user_details *ud)
|
Line 467 get_user_info(struct user_details *ud)
|
| |
|
| user_info[i] = fmt_string("user", pw->pw_name); |
user_info[i] = fmt_string("user", pw->pw_name); |
| if (user_info[i] == NULL) |
if (user_info[i] == NULL) |
| fatalx(NULL); | fatal(NULL); |
| ud->username = user_info[i] + sizeof("user=") - 1; |
ud->username = user_info[i] + sizeof("user=") - 1; |
| |
|
| /* Stash user's shell for use with the -s flag; don't pass to plugin. */ |
/* Stash user's shell for use with the -s flag; don't pass to plugin. */ |
|
Line 493 get_user_info(struct user_details *ud)
|
Line 493 get_user_info(struct user_details *ud)
|
| if (getcwd(cwd, sizeof(cwd)) != NULL) { |
if (getcwd(cwd, sizeof(cwd)) != NULL) { |
| user_info[++i] = fmt_string("cwd", cwd); |
user_info[++i] = fmt_string("cwd", cwd); |
| if (user_info[i] == NULL) |
if (user_info[i] == NULL) |
| fatalx(NULL); | fatal(NULL); |
| ud->cwd = user_info[i] + sizeof("cwd=") - 1; |
ud->cwd = user_info[i] + sizeof("cwd=") - 1; |
| } |
} |
| |
|
| if ((cp = get_process_ttyname()) != NULL) { |
if ((cp = get_process_ttyname()) != NULL) { |
| user_info[++i] = fmt_string("tty", cp); |
user_info[++i] = fmt_string("tty", cp); |
| if (user_info[i] == NULL) |
if (user_info[i] == NULL) |
| fatalx(NULL); | fatal(NULL); |
| ud->tty = user_info[i] + sizeof("tty=") - 1; |
ud->tty = user_info[i] + sizeof("tty=") - 1; |
| efree(cp); |
efree(cp); |
| } |
} |
|
Line 511 get_user_info(struct user_details *ud)
|
Line 511 get_user_info(struct user_details *ud)
|
| strlcpy(host, "localhost", sizeof(host)); |
strlcpy(host, "localhost", sizeof(host)); |
| user_info[++i] = fmt_string("host", host); |
user_info[++i] = fmt_string("host", host); |
| if (user_info[i] == NULL) |
if (user_info[i] == NULL) |
| fatalx(NULL); | fatal(NULL); |
| ud->host = user_info[i] + sizeof("host=") - 1; |
ud->host = user_info[i] + sizeof("host=") - 1; |
| |
|
| get_ttysize(&ud->ts_lines, &ud->ts_cols); |
get_ttysize(&ud->ts_lines, &ud->ts_cols); |
|
Line 530 static void
|
Line 530 static void
|
| command_info_to_details(char * const info[], struct command_details *details) |
command_info_to_details(char * const info[], struct command_details *details) |
| { |
{ |
| int i; |
int i; |
| |
id_t id; |
| long lval; |
long lval; |
| unsigned long ulval; |
|
| char *cp, *ep; |
char *cp, *ep; |
| |
const char *errstr; |
| debug_decl(command_info_to_details, SUDO_DEBUG_PCOMM) |
debug_decl(command_info_to_details, SUDO_DEBUG_PCOMM) |
| |
|
| memset(details, 0, sizeof(*details)); |
memset(details, 0, sizeof(*details)); |
|
Line 553 command_info_to_details(char * const info[], struct co
|
Line 554 command_info_to_details(char * const info[], struct co
|
| SET_STRING("command=", command) |
SET_STRING("command=", command) |
| SET_STRING("cwd=", cwd) |
SET_STRING("cwd=", cwd) |
| if (strncmp("closefrom=", info[i], sizeof("closefrom=") - 1) == 0) { |
if (strncmp("closefrom=", info[i], sizeof("closefrom=") - 1) == 0) { |
| cp = info[i] + sizeof("closefrom=") - 1; |
|
| if (*cp == '\0') |
|
| break; |
|
| errno = 0; |
errno = 0; |
| lval = strtol(cp, &ep, 0); | cp = info[i] + sizeof("closefrom=") - 1; |
| if (*cp != '\0' && *ep == '\0' && | lval = strtol(cp, &ep, 10); |
| !(errno == ERANGE && | if (*cp == '\0' || *ep != '\0') |
| (lval == LONG_MAX || lval == LONG_MIN)) && | fatalx(_("%s: %s"), info[i], _("invalid value")); |
| lval < INT_MAX && lval > INT_MIN) { | if ((errno == ERANGE && |
| details->closefrom = (int)lval; | (lval == LONG_MAX || lval == LONG_MIN)) || |
| } | (lval > INT_MAX || lval < 0)) |
| | fatalx(_("%s: %s"), info[i], _("value out of range")); |
| | details->closefrom = (int)lval; |
| break; |
break; |
| } |
} |
| break; |
break; |
|
Line 578 command_info_to_details(char * const info[], struct co
|
Line 578 command_info_to_details(char * const info[], struct co
|
| SET_STRING("login_class=", login_class) |
SET_STRING("login_class=", login_class) |
| break; |
break; |
| case 'n': |
case 'n': |
| /* XXX - bounds check -NZERO to NZERO (inclusive). */ |
|
| if (strncmp("nice=", info[i], sizeof("nice=") - 1) == 0) { |
if (strncmp("nice=", info[i], sizeof("nice=") - 1) == 0) { |
| cp = info[i] + sizeof("nice=") - 1; |
|
| if (*cp == '\0') |
|
| break; |
|
| errno = 0; |
errno = 0; |
| lval = strtol(cp, &ep, 0); | cp = info[i] + sizeof("nice=") - 1; |
| if (*cp != '\0' && *ep == '\0' && | lval = strtol(cp, &ep, 10); |
| !(errno == ERANGE && | if (*cp == '\0' || *ep != '\0') |
| (lval == LONG_MAX || lval == LONG_MIN)) && | fatalx(_("%s: %s"), info[i], _("invalid value")); |
| lval < INT_MAX && lval > INT_MIN) { | if ((errno == ERANGE && |
| details->priority = (int)lval; | (lval == LONG_MAX || lval == LONG_MIN)) || |
| SET(details->flags, CD_SET_PRIORITY); | (lval > INT_MAX || lval < INT_MIN)) |
| } | fatalx(_("%s: %s"), info[i], _("value out of range")); |
| | details->priority = (int)lval; |
| | SET(details->flags, CD_SET_PRIORITY); |
| break; |
break; |
| } |
} |
| if (strncmp("noexec=", info[i], sizeof("noexec=") - 1) == 0) { |
if (strncmp("noexec=", info[i], sizeof("noexec=") - 1) == 0) { |
|
Line 610 command_info_to_details(char * const info[], struct co
|
Line 608 command_info_to_details(char * const info[], struct co
|
| case 'r': |
case 'r': |
| if (strncmp("runas_egid=", info[i], sizeof("runas_egid=") - 1) == 0) { |
if (strncmp("runas_egid=", info[i], sizeof("runas_egid=") - 1) == 0) { |
| cp = info[i] + sizeof("runas_egid=") - 1; |
cp = info[i] + sizeof("runas_egid=") - 1; |
| if (*cp == '\0') | id = atoid(cp, NULL, NULL, &errstr); |
| break; | if (errstr != NULL) |
| errno = 0; | fatalx(_("%s: %s"), info[i], _(errstr)); |
| ulval = strtoul(cp, &ep, 0); | details->egid = (gid_t)id; |
| if (*cp != '\0' && *ep == '\0' && | SET(details->flags, CD_SET_EGID); |
| (errno != ERANGE || ulval != ULONG_MAX)) { | |
| details->egid = (gid_t)ulval; | |
| SET(details->flags, CD_SET_EGID); | |
| } | |
| break; |
break; |
| } |
} |
| if (strncmp("runas_euid=", info[i], sizeof("runas_euid=") - 1) == 0) { |
if (strncmp("runas_euid=", info[i], sizeof("runas_euid=") - 1) == 0) { |
| cp = info[i] + sizeof("runas_euid=") - 1; |
cp = info[i] + sizeof("runas_euid=") - 1; |
| if (*cp == '\0') | id = atoid(cp, NULL, NULL, &errstr); |
| break; | if (errstr != NULL) |
| errno = 0; | fatalx(_("%s: %s"), info[i], _(errstr)); |
| ulval = strtoul(cp, &ep, 0); | details->euid = (uid_t)id; |
| if (*cp != '\0' && *ep == '\0' && | SET(details->flags, CD_SET_EUID); |
| (errno != ERANGE || ulval != ULONG_MAX)) { | |
| details->euid = (uid_t)ulval; | |
| SET(details->flags, CD_SET_EUID); | |
| } | |
| break; |
break; |
| } |
} |
| if (strncmp("runas_gid=", info[i], sizeof("runas_gid=") - 1) == 0) { |
if (strncmp("runas_gid=", info[i], sizeof("runas_gid=") - 1) == 0) { |
| cp = info[i] + sizeof("runas_gid=") - 1; |
cp = info[i] + sizeof("runas_gid=") - 1; |
| if (*cp == '\0') | id = atoid(cp, NULL, NULL, &errstr); |
| break; | if (errstr != NULL) |
| errno = 0; | fatalx(_("%s: %s"), info[i], _(errstr)); |
| ulval = strtoul(cp, &ep, 0); | details->gid = (gid_t)id; |
| if (*cp != '\0' && *ep == '\0' && | SET(details->flags, CD_SET_GID); |
| (errno != ERANGE || ulval != ULONG_MAX)) { | |
| details->gid = (gid_t)ulval; | |
| SET(details->flags, CD_SET_GID); | |
| } | |
| break; |
break; |
| } |
} |
| if (strncmp("runas_groups=", info[i], sizeof("runas_groups=") - 1) == 0) { |
if (strncmp("runas_groups=", info[i], sizeof("runas_groups=") - 1) == 0) { |
| int j; | /* parse_gid_list() will call fatalx() on error. */ |
| |
| /* count groups, alloc and fill in */ | |
| cp = info[i] + sizeof("runas_groups=") - 1; |
cp = info[i] + sizeof("runas_groups=") - 1; |
| if (*cp == '\0') | details->ngroups = parse_gid_list(cp, NULL, &details->groups); |
| break; | |
| for (;;) { | |
| details->ngroups++; | |
| if ((cp = strchr(cp, ',')) == NULL) | |
| break; | |
| cp++; | |
| } | |
| if (details->ngroups != 0) { | |
| details->groups = | |
| emalloc2(details->ngroups, sizeof(GETGROUPS_T)); | |
| cp = info[i] + sizeof("runas_groups=") - 1; | |
| for (j = 0; j < details->ngroups;) { | |
| errno = 0; | |
| ulval = strtoul(cp, &ep, 0); | |
| if (*cp == '\0' || (*ep != ',' && *ep != '\0') || | |
| (ulval == ULONG_MAX && errno == ERANGE)) { | |
| break; | |
| } | |
| details->groups[j++] = (gid_t)ulval; | |
| cp = ep + 1; | |
| } | |
| details->ngroups = j; | |
| } | |
| break; |
break; |
| } |
} |
| if (strncmp("runas_uid=", info[i], sizeof("runas_uid=") - 1) == 0) { |
if (strncmp("runas_uid=", info[i], sizeof("runas_uid=") - 1) == 0) { |
| cp = info[i] + sizeof("runas_uid=") - 1; |
cp = info[i] + sizeof("runas_uid=") - 1; |
| if (*cp == '\0') | id = atoid(cp, NULL, NULL, &errstr); |
| break; | if (errstr != NULL) |
| errno = 0; | fatalx(_("%s: %s"), info[i], _(errstr)); |
| ulval = strtoul(cp, &ep, 0); | details->uid = (uid_t)id; |
| if (*cp != '\0' && *ep == '\0' && | SET(details->flags, CD_SET_UID); |
| (errno != ERANGE || ulval != ULONG_MAX)) { | |
| details->uid = (uid_t)ulval; | |
| SET(details->flags, CD_SET_UID); | |
| } | |
| break; |
break; |
| } |
} |
| #ifdef HAVE_PRIV_SET |
#ifdef HAVE_PRIV_SET |
| if (strncmp("runas_privs=", info[i], sizeof("runas_privs=") - 1) == 0) { |
if (strncmp("runas_privs=", info[i], sizeof("runas_privs=") - 1) == 0) { |
| const char *endp; |
const char *endp; |
| cp = info[i] + sizeof("runas_privs=") - 1; |
cp = info[i] + sizeof("runas_privs=") - 1; |
| if (*cp == '\0') | if (*cp != '\0') { |
| break; | details->privs = priv_str_to_set(cp, ",", &endp); |
| errno = 0; | if (details->privs == NULL) |
| details->privs = priv_str_to_set(cp, ",", &endp); | |
| if (details->privs == NULL) | |
| warning("invalid runas_privs %s", endp); |
warning("invalid runas_privs %s", endp); |
| |
} |
| |
break; |
| } |
} |
| if (strncmp("runas_limitprivs=", info[i], sizeof("runas_limitprivs=") - 1) == 0) { |
if (strncmp("runas_limitprivs=", info[i], sizeof("runas_limitprivs=") - 1) == 0) { |
| const char *endp; |
const char *endp; |
| cp = info[i] + sizeof("runas_limitprivs=") - 1; |
cp = info[i] + sizeof("runas_limitprivs=") - 1; |
| if (*cp == '\0') | if (*cp != '\0') { |
| break; | details->limitprivs = priv_str_to_set(cp, ",", &endp); |
| errno = 0; | if (details->limitprivs == NULL) |
| details->limitprivs = priv_str_to_set(cp, ",", &endp); | |
| if (details->limitprivs == NULL) | |
| warning("invalid runas_limitprivs %s", endp); |
warning("invalid runas_limitprivs %s", endp); |
| |
} |
| |
break; |
| } |
} |
| #endif /* HAVE_PRIV_SET */ |
#endif /* HAVE_PRIV_SET */ |
| break; |
break; |
|
Line 730 command_info_to_details(char * const info[], struct co
|
Line 687 command_info_to_details(char * const info[], struct co
|
| break; |
break; |
| case 't': |
case 't': |
| if (strncmp("timeout=", info[i], sizeof("timeout=") - 1) == 0) { |
if (strncmp("timeout=", info[i], sizeof("timeout=") - 1) == 0) { |
| cp = info[i] + sizeof("timeout=") - 1; |
|
| if (*cp == '\0') |
|
| break; |
|
| errno = 0; |
errno = 0; |
| lval = strtol(cp, &ep, 0); | cp = info[i] + sizeof("timeout=") - 1; |
| if (*cp != '\0' && *ep == '\0' && | lval = strtol(cp, &ep, 10); |
| !(errno == ERANGE && | if (*cp == '\0' || *ep != '\0') |
| (lval == LONG_MAX || lval == LONG_MIN)) && | fatalx(_("%s: %s"), info[i], _("invalid value")); |
| lval <= INT_MAX && lval >= 0) { | if ((errno == ERANGE && |
| details->timeout = (int)lval; | (lval == LONG_MAX || lval == LONG_MIN)) || |
| SET(details->flags, CD_SET_TIMEOUT); | (lval > INT_MAX || lval < 0)) |
| } | fatalx(_("%s: %s"), info[i], _("value out of range")); |
| | details->timeout = (int)lval; |
| | SET(details->flags, CD_SET_TIMEOUT); |
| break; |
break; |
| } |
} |
| break; |
break; |
| case 'u': |
case 'u': |
| if (strncmp("umask=", info[i], sizeof("umask=") - 1) == 0) { |
if (strncmp("umask=", info[i], sizeof("umask=") - 1) == 0) { |
| cp = info[i] + sizeof("umask=") - 1; |
|
| if (*cp == '\0') |
|
| break; |
|
| errno = 0; |
errno = 0; |
| ulval = strtoul(cp, &ep, 8); | cp = info[i] + sizeof("umask=") - 1; |
| if (*cp != '\0' && *ep == '\0' && | lval = strtol(cp, &ep, 8); |
| (errno != ERANGE || ulval != ULONG_MAX)) { | if (*cp == '\0' || *ep != '\0') |
| details->umask = (uid_t)ulval; | fatalx(_("%s: %s"), info[i], _("invalid value")); |
| SET(details->flags, CD_SET_UMASK); | if ((errno == ERANGE && |
| } | (lval == LONG_MAX || lval == LONG_MIN)) || |
| | (lval > 0777 || lval < 0)) |
| | fatalx(_("%s: %s"), info[i], _("value out of range")); |
| | details->umask = (mode_t)lval; |
| | SET(details->flags, CD_SET_UMASK); |
| break; |
break; |
| } |
} |
| if (strncmp("use_pty=", info[i], sizeof("use_pty=") - 1) == 0) { |
if (strncmp("use_pty=", info[i], sizeof("use_pty=") - 1) == 0) { |
|
Line 777 command_info_to_details(char * const info[], struct co
|
Line 734 command_info_to_details(char * const info[], struct co
|
| #endif |
#endif |
| details->pw = getpwuid(details->euid); |
details->pw = getpwuid(details->euid); |
| if (details->pw != NULL && (details->pw = pw_dup(details->pw)) == NULL) |
if (details->pw != NULL && (details->pw = pw_dup(details->pw)) == NULL) |
| fatalx(NULL); | fatal(NULL); |
| #ifdef HAVE_SETAUTHDB |
#ifdef HAVE_SETAUTHDB |
| aix_restoreauthdb(); |
aix_restoreauthdb(); |
| #endif |
#endif |
|
Line 790 command_info_to_details(char * const info[], struct co
|
Line 747 command_info_to_details(char * const info[], struct co
|
| } |
} |
| |
|
| static void |
static void |
| sudo_check_suid(const char *path) | sudo_check_suid(const char *sudo) |
| { |
{ |
| |
char pathbuf[PATH_MAX]; |
| struct stat sb; |
struct stat sb; |
| |
bool qualified; |
| debug_decl(sudo_check_suid, SUDO_DEBUG_PCOMM) |
debug_decl(sudo_check_suid, SUDO_DEBUG_PCOMM) |
| |
|
| if (geteuid() != 0) { |
if (geteuid() != 0) { |
| if (strchr(path, '/') != NULL && stat(path, &sb) == 0) { | /* Search for sudo binary in PATH if not fully qualified. */ |
| | qualified = strchr(sudo, '/') != NULL; |
| | if (!qualified) { |
| | char *path = getenv_unhooked("PATH"); |
| | if (path != NULL) { |
| | int len; |
| | char *cp, *colon; |
| | |
| | cp = path = estrdup(path); |
| | do { |
| | if ((colon = strchr(cp, ':'))) |
| | *colon = '\0'; |
| | len = snprintf(pathbuf, sizeof(pathbuf), "%s/%s", cp, sudo); |
| | if (len <= 0 || len >= sizeof(pathbuf)) |
| | continue; |
| | if (access(pathbuf, X_OK) == 0) { |
| | sudo = pathbuf; |
| | qualified = true; |
| | break; |
| | } |
| | cp = colon + 1; |
| | } while (colon); |
| | efree(path); |
| | } |
| | } |
| | |
| | if (qualified && stat(sudo, &sb) == 0) { |
| /* Try to determine why sudo was not running as root. */ |
/* Try to determine why sudo was not running as root. */ |
| if (sb.st_uid != ROOT_UID || !ISSET(sb.st_mode, S_ISUID)) { |
if (sb.st_uid != ROOT_UID || !ISSET(sb.st_mode, S_ISUID)) { |
| fatalx( |
fatalx( |
| _("%s must be owned by uid %d and have the setuid bit set"), |
_("%s must be owned by uid %d and have the setuid bit set"), |
| path, ROOT_UID); | sudo, ROOT_UID); |
| } else { |
} else { |
| fatalx(_("effective uid is not %d, is %s on a file system " |
fatalx(_("effective uid is not %d, is %s on a file system " |
| "with the 'nosuid' option set or an NFS file system without" |
"with the 'nosuid' option set or an NFS file system without" |
| " root privileges?"), ROOT_UID, path); | " root privileges?"), ROOT_UID, sudo); |
| } |
} |
| } else { |
} else { |
| fatalx( |
fatalx( |
|
Line 824 sudo_check_suid(const char *path)
|
Line 809 sudo_check_suid(const char *path)
|
| static void |
static void |
| disable_coredumps(void) |
disable_coredumps(void) |
| { |
{ |
| #if defined(__linux__) || defined(RLIMIT_CORE) | #if defined(RLIMIT_CORE) |
| struct rlimit rl; |
struct rlimit rl; |
| #endif |
|
| debug_decl(disable_coredumps, SUDO_DEBUG_UTIL) |
debug_decl(disable_coredumps, SUDO_DEBUG_UTIL) |
| |
|
| #if defined(__linux__) |
|
| /* |
/* |
| * Unlimit the number of processes since Linux's setuid() will |
|
| * apply resource limits when changing uid and return EAGAIN if |
|
| * nproc would be violated by the uid switch. |
|
| */ |
|
| (void) getrlimit(RLIMIT_NPROC, &nproclimit); |
|
| rl.rlim_cur = rl.rlim_max = RLIM_INFINITY; |
|
| if (setrlimit(RLIMIT_NPROC, &rl)) { |
|
| memcpy(&rl, &nproclimit, sizeof(struct rlimit)); |
|
| rl.rlim_cur = rl.rlim_max; |
|
| (void)setrlimit(RLIMIT_NPROC, &rl); |
|
| } |
|
| #endif /* __linux__ */ |
|
| #ifdef RLIMIT_CORE |
|
| /* |
|
| * Turn off core dumps? |
* Turn off core dumps? |
| */ |
*/ |
| if (sudo_conf_disable_coredump()) { |
if (sudo_conf_disable_coredump()) { |
|
Line 853 disable_coredumps(void)
|
Line 822 disable_coredumps(void)
|
| rl.rlim_cur = 0; |
rl.rlim_cur = 0; |
| (void) setrlimit(RLIMIT_CORE, &rl); |
(void) setrlimit(RLIMIT_CORE, &rl); |
| } |
} |
| |
debug_return; |
| #endif /* RLIMIT_CORE */ |
#endif /* RLIMIT_CORE */ |
| |
} |
| |
|
| |
/* |
| |
* Unlimit the number of processes since Linux's setuid() will |
| |
* apply resource limits when changing uid and return EAGAIN if |
| |
* nproc would be exceeded by the uid switch. |
| |
*/ |
| |
static void |
| |
unlimit_nproc(void) |
| |
{ |
| |
#ifdef __linux__ |
| |
struct rlimit rl; |
| |
debug_decl(unlimit_nproc, SUDO_DEBUG_UTIL) |
| |
|
| |
(void) getrlimit(RLIMIT_NPROC, &nproclimit); |
| |
rl.rlim_cur = rl.rlim_max = RLIM_INFINITY; |
| |
if (setrlimit(RLIMIT_NPROC, &rl) != 0) { |
| |
memcpy(&rl, &nproclimit, sizeof(struct rlimit)); |
| |
rl.rlim_cur = rl.rlim_max; |
| |
(void)setrlimit(RLIMIT_NPROC, &rl); |
| |
} |
| debug_return; |
debug_return; |
| |
#endif /* __linux__ */ |
| } |
} |
| |
|
| /* |
/* |
| |
* Restore saved value of RLIMIT_NPROC. |
| |
*/ |
| |
static void |
| |
restore_nproc(void) |
| |
{ |
| |
#ifdef __linux__ |
| |
debug_decl(restore_nproc, SUDO_DEBUG_UTIL) |
| |
|
| |
(void) setrlimit(RLIMIT_NPROC, &nproclimit); |
| |
|
| |
debug_return; |
| |
#endif /* __linux__ */ |
| |
} |
| |
|
| |
/* |
| * Setup the execution environment immediately prior to the call to execve() |
* Setup the execution environment immediately prior to the call to execve() |
| * Returns true on success and false on failure. |
* Returns true on success and false on failure. |
| */ |
*/ |
|
Line 926 exec_setup(struct command_details *details, const char
|
Line 933 exec_setup(struct command_details *details, const char
|
| flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY; |
flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY; |
| } |
} |
| if (setusercontext(lc, details->pw, details->pw->pw_uid, flags)) { |
if (setusercontext(lc, details->pw, details->pw->pw_uid, flags)) { |
| if (details->pw->pw_uid != ROOT_UID) { | warning(_("unable to set user context")); |
| warning(_("unable to set user context")); | if (details->pw->pw_uid != ROOT_UID) |
| goto done; |
goto done; |
| } else |
|
| warning(_("unable to set user context")); |
|
| } |
} |
| } |
} |
| #endif /* HAVE_LOGIN_CAP_H */ |
#endif /* HAVE_LOGIN_CAP_H */ |
|
Line 975 exec_setup(struct command_details *details, const char
|
Line 980 exec_setup(struct command_details *details, const char
|
| } |
} |
| } |
} |
| |
|
| |
/* |
| |
* Unlimit the number of processes since Linux's setuid() will |
| |
* return EAGAIN if RLIMIT_NPROC would be exceeded by the uid switch. |
| |
*/ |
| |
unlimit_nproc(); |
| |
|
| #ifdef HAVE_SETRESUID |
#ifdef HAVE_SETRESUID |
| if (setresuid(details->uid, details->euid, details->euid) != 0) { |
if (setresuid(details->uid, details->euid, details->euid) != 0) { |
| warning(_("unable to change to runas uid (%u, %u)"), details->uid, |
warning(_("unable to change to runas uid (%u, %u)"), details->uid, |
|
Line 995 exec_setup(struct command_details *details, const char
|
Line 1006 exec_setup(struct command_details *details, const char
|
| } |
} |
| #endif /* !HAVE_SETRESUID && !HAVE_SETREUID */ |
#endif /* !HAVE_SETRESUID && !HAVE_SETREUID */ |
| |
|
| |
/* Restore previous value of RLIMIT_NPROC. */ |
| |
restore_nproc(); |
| |
|
| /* |
/* |
| * Only change cwd if we have chroot()ed or the policy modules |
* Only change cwd if we have chroot()ed or the policy modules |
| * specifies a different cwd. Must be done after uid change. |
* specifies a different cwd. Must be done after uid change. |
|
Line 1008 exec_setup(struct command_details *details, const char
|
Line 1022 exec_setup(struct command_details *details, const char
|
| } |
} |
| } |
} |
| } |
} |
| |
|
| /* |
|
| * SuSE Enterprise Linux uses RLIMIT_NPROC and _SC_CHILD_MAX |
|
| * interchangably. This causes problems when setting RLIMIT_NPROC |
|
| * to RLIM_INFINITY due to a bug in bash where bash tries to honor |
|
| * the value of _SC_CHILD_MAX but treats a value of -1 as an error, |
|
| * and uses a default value of 32 instead. |
|
| * |
|
| * To work around this problem, we restore the nproc resource limit |
|
| * if sysconf(_SC_CHILD_MAX) is negative. In most cases, pam_limits |
|
| * will set RLIMIT_NPROC for us. |
|
| * |
|
| * We must do this *after* the uid change to avoid potential EAGAIN |
|
| * from setuid(). |
|
| */ |
|
| #if defined(__linux__) && defined(_SC_CHILD_MAX) |
|
| { |
|
| struct rlimit rl; |
|
| long l; |
|
| errno = 0; |
|
| l = sysconf(_SC_CHILD_MAX); |
|
| if (l == -1 && errno == 0 && getrlimit(RLIMIT_NPROC, &rl) == 0) { |
|
| if (rl.rlim_cur == RLIM_INFINITY && rl.rlim_max == RLIM_INFINITY) |
|
| (void) setrlimit(RLIMIT_NPROC, &nproclimit); |
|
| } |
|
| } |
|
| #endif |
|
| |
|
| rval = true; |
rval = true; |
| |
|