Rename run_cred -> cur_cred and stash existing creds in set_tmpdir().
For sudo_edit_open() et al what we need is a copy of the current cred to restore after dir_is_writable() changes to the user cred.
This commit is contained in:
@@ -74,7 +74,7 @@ switch_user(uid_t euid, gid_t egid, int ngroups, GETGROUPS_T *groups)
|
|||||||
* Returns true if the open directory fd is owned or writable by the user.
|
* Returns true if the open directory fd is owned or writable by the user.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
dir_is_writable(int dfd, struct sudo_cred *user_cred, struct sudo_cred *run_cred)
|
dir_is_writable(int dfd, struct sudo_cred *user_cred, struct sudo_cred *cur_cred)
|
||||||
{
|
{
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
int rc;
|
int rc;
|
||||||
@@ -92,7 +92,7 @@ dir_is_writable(int dfd, struct sudo_cred *user_cred, struct sudo_cred *run_cred
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Change uid/gid/groups to invoking user, usually needs root perms. */
|
/* Change uid/gid/groups to invoking user, usually needs root perms. */
|
||||||
if (run_cred->euid != ROOT_UID) {
|
if (cur_cred->euid != ROOT_UID) {
|
||||||
if (seteuid(ROOT_UID) != 0)
|
if (seteuid(ROOT_UID) != 0)
|
||||||
sudo_fatal("seteuid(ROOT_UID)");
|
sudo_fatal("seteuid(ROOT_UID)");
|
||||||
}
|
}
|
||||||
@@ -102,13 +102,13 @@ dir_is_writable(int dfd, struct sudo_cred *user_cred, struct sudo_cred *run_cred
|
|||||||
/* Access checks are done using the euid/egid and group vector. */
|
/* Access checks are done using the euid/egid and group vector. */
|
||||||
rc = faccessat(dfd, ".", W_OK, AT_EACCESS);
|
rc = faccessat(dfd, ".", W_OK, AT_EACCESS);
|
||||||
|
|
||||||
/* Change uid/gid/groups back to target user, may need root perms. */
|
/* Restore uid/gid/groups, may need root perms. */
|
||||||
if (user_cred->uid != ROOT_UID) {
|
if (user_cred->uid != ROOT_UID) {
|
||||||
if (seteuid(ROOT_UID) != 0)
|
if (seteuid(ROOT_UID) != 0)
|
||||||
sudo_fatal("seteuid(ROOT_UID)");
|
sudo_fatal("seteuid(ROOT_UID)");
|
||||||
}
|
}
|
||||||
switch_user(run_cred->euid, run_cred->egid, run_cred->ngroups,
|
switch_user(cur_cred->euid, cur_cred->egid, cur_cred->ngroups,
|
||||||
run_cred->groups);
|
cur_cred->groups);
|
||||||
|
|
||||||
if (rc == 0)
|
if (rc == 0)
|
||||||
debug_return_int(true);
|
debug_return_int(true);
|
||||||
@@ -144,7 +144,7 @@ group_matches(gid_t target, struct sudo_cred *cred)
|
|||||||
* Returns true if the open directory fd is owned or writable by the user.
|
* Returns true if the open directory fd is owned or writable by the user.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
dir_is_writable(int dfd, struct sudo_cred *user_cred, struct sudo_cred *run_cred)
|
dir_is_writable(int dfd, struct sudo_cred *user_cred, struct sudo_cred *cur_cred)
|
||||||
{
|
{
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
debug_decl(dir_is_writable, SUDO_DEBUG_EDIT);
|
debug_decl(dir_is_writable, SUDO_DEBUG_EDIT);
|
||||||
@@ -272,7 +272,7 @@ done:
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
sudo_edit_open_nonwritable(char *path, int oflags, mode_t mode,
|
sudo_edit_open_nonwritable(char *path, int oflags, mode_t mode,
|
||||||
struct sudo_cred *user_cred, struct sudo_cred *run_cred)
|
struct sudo_cred *user_cred, struct sudo_cred *cur_cred)
|
||||||
{
|
{
|
||||||
const int dflags = DIR_OPEN_FLAGS;
|
const int dflags = DIR_OPEN_FLAGS;
|
||||||
int dfd, fd, is_writable;
|
int dfd, fd, is_writable;
|
||||||
@@ -297,7 +297,7 @@ sudo_edit_open_nonwritable(char *path, int oflags, mode_t mode,
|
|||||||
* Look up one component at a time, avoiding symbolic links in
|
* Look up one component at a time, avoiding symbolic links in
|
||||||
* writable directories.
|
* writable directories.
|
||||||
*/
|
*/
|
||||||
is_writable = dir_is_writable(dfd, user_cred, run_cred);
|
is_writable = dir_is_writable(dfd, user_cred, cur_cred);
|
||||||
if (is_writable == -1) {
|
if (is_writable == -1) {
|
||||||
close(dfd);
|
close(dfd);
|
||||||
debug_return_int(-1);
|
debug_return_int(-1);
|
||||||
@@ -339,7 +339,7 @@ sudo_edit_open_nonwritable(char *path, int oflags, mode_t mode,
|
|||||||
#ifdef O_NOFOLLOW
|
#ifdef O_NOFOLLOW
|
||||||
int
|
int
|
||||||
sudo_edit_open(char *path, int oflags, mode_t mode, int sflags,
|
sudo_edit_open(char *path, int oflags, mode_t mode, int sflags,
|
||||||
struct sudo_cred *user_cred, struct sudo_cred *run_cred)
|
struct sudo_cred *user_cred, struct sudo_cred *cur_cred)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
debug_decl(sudo_edit_open, SUDO_DEBUG_EDIT);
|
debug_decl(sudo_edit_open, SUDO_DEBUG_EDIT);
|
||||||
@@ -348,7 +348,7 @@ sudo_edit_open(char *path, int oflags, mode_t mode, int sflags,
|
|||||||
oflags |= O_NOFOLLOW;
|
oflags |= O_NOFOLLOW;
|
||||||
if (ISSET(sflags, CD_SUDOEDIT_CHECKDIR) && user_cred->uid != ROOT_UID) {
|
if (ISSET(sflags, CD_SUDOEDIT_CHECKDIR) && user_cred->uid != ROOT_UID) {
|
||||||
fd = sudo_edit_open_nonwritable(path, oflags|O_NONBLOCK, mode,
|
fd = sudo_edit_open_nonwritable(path, oflags|O_NONBLOCK, mode,
|
||||||
user_cred, run_cred);
|
user_cred, cur_cred);
|
||||||
} else {
|
} else {
|
||||||
fd = open(path, oflags|O_NONBLOCK, mode);
|
fd = open(path, oflags|O_NONBLOCK, mode);
|
||||||
}
|
}
|
||||||
@@ -359,7 +359,7 @@ sudo_edit_open(char *path, int oflags, mode_t mode, int sflags,
|
|||||||
#else
|
#else
|
||||||
int
|
int
|
||||||
sudo_edit_open(char *path, int oflags, mode_t mode, int sflags,
|
sudo_edit_open(char *path, int oflags, mode_t mode, int sflags,
|
||||||
struct sudo_cred *user_cred, struct sudo_cred *run_cred)
|
struct sudo_cred *user_cred, struct sudo_cred *cur_cred)
|
||||||
{
|
{
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
int fd;
|
int fd;
|
||||||
@@ -380,7 +380,7 @@ sudo_edit_open(char *path, int oflags, mode_t mode, int sflags,
|
|||||||
|
|
||||||
if (ISSET(sflags, CD_SUDOEDIT_CHECKDIR) && user_cred->uid != ROOT_UID) {
|
if (ISSET(sflags, CD_SUDOEDIT_CHECKDIR) && user_cred->uid != ROOT_UID) {
|
||||||
fd = sudo_edit_open_nonwritable(path, oflags|O_NONBLOCK, mode,
|
fd = sudo_edit_open_nonwritable(path, oflags|O_NONBLOCK, mode,
|
||||||
user_cred, run_cred);
|
user_cred, cur_cred);
|
||||||
} else {
|
} else {
|
||||||
fd = open(path, oflags|O_NONBLOCK, mode);
|
fd = open(path, oflags|O_NONBLOCK, mode);
|
||||||
}
|
}
|
||||||
@@ -412,7 +412,7 @@ sudo_edit_open(char *path, int oflags, mode_t mode, int sflags,
|
|||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
sudo_edit_parent_valid(char *path, int sflags, struct sudo_cred *user_cred,
|
sudo_edit_parent_valid(char *path, int sflags, struct sudo_cred *user_cred,
|
||||||
struct sudo_cred *run_cred)
|
struct sudo_cred *cur_cred)
|
||||||
{
|
{
|
||||||
const int serrno = errno;
|
const int serrno = errno;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
@@ -438,7 +438,7 @@ sudo_edit_parent_valid(char *path, int sflags, struct sudo_cred *user_cred,
|
|||||||
* *its* parent is writable and CD_SUDOEDIT_CHECK is set.
|
* *its* parent is writable and CD_SUDOEDIT_CHECK is set.
|
||||||
*/
|
*/
|
||||||
dfd = sudo_edit_open(path, DIR_OPEN_FLAGS, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH,
|
dfd = sudo_edit_open(path, DIR_OPEN_FLAGS, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH,
|
||||||
sflags|CD_SUDOEDIT_FOLLOW, user_cred, run_cred);
|
sflags|CD_SUDOEDIT_FOLLOW, user_cred, cur_cred);
|
||||||
if (dfd != -1) {
|
if (dfd != -1) {
|
||||||
if (fstat(dfd, &sb) == 0 && S_ISDIR(sb.st_mode))
|
if (fstat(dfd, &sb) == 0 && S_ISDIR(sb.st_mode))
|
||||||
ret = true;
|
ret = true;
|
||||||
|
@@ -251,6 +251,9 @@ sesh_sudoedit(int argc, char *argv[])
|
|||||||
sudo_warn("%s", U_("unable to get group list"));
|
sudo_warn("%s", U_("unable to get group list"));
|
||||||
debug_return_int(SESH_ERR_FAILURE);
|
debug_return_int(SESH_ERR_FAILURE);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
run_cred.ngroups = 0;
|
||||||
|
run_cred.groups = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < argc - 1; i += 2) {
|
for (i = 0; i < argc - 1; i += 2) {
|
||||||
|
@@ -60,7 +60,7 @@ static char edit_tmpdir[MAX(sizeof(_PATH_VARTMP), sizeof(_PATH_TMP))];
|
|||||||
* Returns true on success, else false;
|
* Returns true on success, else false;
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
set_tmpdir(struct command_details *command_details)
|
set_tmpdir(struct sudo_cred *user_cred)
|
||||||
{
|
{
|
||||||
const char *tdir = NULL;
|
const char *tdir = NULL;
|
||||||
const char *tmpdirs[] = {
|
const char *tmpdirs[] = {
|
||||||
@@ -70,21 +70,49 @@ set_tmpdir(struct command_details *command_details)
|
|||||||
#endif
|
#endif
|
||||||
_PATH_TMP
|
_PATH_TMP
|
||||||
};
|
};
|
||||||
|
struct sudo_cred saved_cred;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
size_t len;
|
size_t len;
|
||||||
int dfd;
|
int dfd;
|
||||||
debug_decl(set_tmpdir, SUDO_DEBUG_EDIT);
|
debug_decl(set_tmpdir, SUDO_DEBUG_EDIT);
|
||||||
|
|
||||||
|
/* Stash old credentials. */
|
||||||
|
saved_cred.uid = getuid();
|
||||||
|
saved_cred.euid = geteuid();
|
||||||
|
saved_cred.gid = getgid();
|
||||||
|
saved_cred.egid = getegid();
|
||||||
|
saved_cred.ngroups = getgroups(0, NULL);
|
||||||
|
if (saved_cred.ngroups > 0) {
|
||||||
|
saved_cred.groups =
|
||||||
|
reallocarray(NULL, saved_cred.ngroups, sizeof(GETGROUPS_T));
|
||||||
|
if (saved_cred.groups == NULL) {
|
||||||
|
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
||||||
|
debug_return_bool(false);
|
||||||
|
}
|
||||||
|
if (getgroups(saved_cred.ngroups, saved_cred.groups) < 0) {
|
||||||
|
sudo_warn("%s", U_("unable to get group list"));
|
||||||
|
free(saved_cred.groups);
|
||||||
|
debug_return_bool(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
saved_cred.ngroups = 0;
|
||||||
|
saved_cred.groups = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; tdir == NULL && i < nitems(tmpdirs); i++) {
|
for (i = 0; tdir == NULL && i < nitems(tmpdirs); i++) {
|
||||||
if ((dfd = open(tmpdirs[i], O_RDONLY)) != -1) {
|
if ((dfd = open(tmpdirs[i], O_RDONLY)) != -1) {
|
||||||
if (dir_is_writable(dfd, &user_details.cred, &command_details->cred) == true)
|
if (dir_is_writable(dfd, user_cred, &saved_cred) == true)
|
||||||
tdir = tmpdirs[i];
|
tdir = tmpdirs[i];
|
||||||
close(dfd);
|
close(dfd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tdir == NULL)
|
free(saved_cred.groups);
|
||||||
sudo_fatalx("%s", U_("no writable temporary directory found"));
|
|
||||||
|
if (tdir == NULL) {
|
||||||
|
sudo_warnx("%s", U_("no writable temporary directory found"));
|
||||||
|
debug_return_bool(false);
|
||||||
|
}
|
||||||
|
|
||||||
len = strlcpy(edit_tmpdir, tdir, sizeof(edit_tmpdir));
|
len = strlcpy(edit_tmpdir, tdir, sizeof(edit_tmpdir));
|
||||||
if (len >= sizeof(edit_tmpdir)) {
|
if (len >= sizeof(edit_tmpdir)) {
|
||||||
errno = ENAMETOOLONG;
|
errno = ENAMETOOLONG;
|
||||||
@@ -609,9 +637,6 @@ sudo_edit(struct command_details *command_details)
|
|||||||
struct tempfile *tf = NULL;
|
struct tempfile *tf = NULL;
|
||||||
debug_decl(sudo_edit, SUDO_DEBUG_EDIT);
|
debug_decl(sudo_edit, SUDO_DEBUG_EDIT);
|
||||||
|
|
||||||
if (!set_tmpdir(command_details))
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set real, effective and saved uids to root.
|
* Set real, effective and saved uids to root.
|
||||||
* We will change the euid as needed below.
|
* We will change the euid as needed below.
|
||||||
@@ -623,6 +648,10 @@ sudo_edit(struct command_details *command_details)
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Find a temporary directory writable by the user. */
|
||||||
|
if (!set_tmpdir(&user_details.cred))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The user's editor must be separated from the files to be
|
* The user's editor must be separated from the files to be
|
||||||
* edited by a "--" option.
|
* edited by a "--" option.
|
||||||
|
@@ -48,8 +48,8 @@ bool sudo_check_temp_file(int tfd, const char *tname, uid_t uid, struct stat *sb
|
|||||||
/* edit_open.c */
|
/* edit_open.c */
|
||||||
struct sudo_cred;
|
struct sudo_cred;
|
||||||
void switch_user(uid_t euid, gid_t egid, int ngroups, GETGROUPS_T *groups);
|
void switch_user(uid_t euid, gid_t egid, int ngroups, GETGROUPS_T *groups);
|
||||||
int sudo_edit_open(char *path, int oflags, mode_t mode, int sflags, struct sudo_cred *user_cred, struct sudo_cred *run_cred);
|
int sudo_edit_open(char *path, int oflags, mode_t mode, int sflags, struct sudo_cred *user_cred, struct sudo_cred *cur_cred);
|
||||||
int dir_is_writable(int dfd, struct sudo_cred *user_cred, struct sudo_cred *run_cred);
|
int dir_is_writable(int dfd, struct sudo_cred *user_cred, struct sudo_cred *cur_cred);
|
||||||
bool sudo_edit_parent_valid(char *path, int sflags, struct sudo_cred *user_cred, struct sudo_cred *run_cred);
|
bool sudo_edit_parent_valid(char *path, int sflags, struct sudo_cred *user_cred, struct sudo_cred *cur_cred);
|
||||||
|
|
||||||
#endif /* SUDO_EDIT_H */
|
#endif /* SUDO_EDIT_H */
|
||||||
|
Reference in New Issue
Block a user