Add PERM_IOLOG so we can create I/O log files on an NFS-mounted

filesystem where root is remapped to an unprivileged user.
This commit is contained in:
Todd C. Miller
2017-03-21 13:41:14 -06:00
parent cfb15106e3
commit 8d57491dc1
8 changed files with 294 additions and 120 deletions

View File

@@ -1626,9 +1626,11 @@ SSUUDDOOEERRSS OOPPTTIIOONNSS
higher. higher.
iolog_group The group name to look up when setting the group ID on iolog_group The group name to look up when setting the group ID on
new I/O log files and directories. By default, I/O log new I/O log files and directories. If _i_o_l_o_g___g_r_o_u_p is
files and directories inherit the group ID of the not set, the primary group ID of the user specified by
parent directory. _i_o_l_o_g___u_s_e_r is used. If neither _i_o_l_o_g___g_r_o_u_p nor
_i_o_l_o_g___u_s_e_r are set, I/O log files and directories are
created with group ID 0.
This setting is only supported by version 1.8.19 or This setting is only supported by version 1.8.19 or
higher. higher.
@@ -1646,10 +1648,11 @@ SSUUDDOOEERRSS OOPPTTIIOONNSS
This setting is only supported by version 1.8.19 or This setting is only supported by version 1.8.19 or
higher. higher.
iolog_user The user name to look up when setting the user ID on iolog_user The user name to look up when setting the user and
new I/O log files and directories. By default, I/O log group IDs on new I/O log files and directories. If
files and directories are owned by the superuser (user _i_o_l_o_g___g_r_o_u_p is set, it will be used instead of the
ID 0). user's primary group ID. By default, I/O log files and
directories are created with user and group ID 0.
This setting is only supported by version 1.8.19 or This setting is only supported by version 1.8.19 or
higher. higher.
@@ -2760,4 +2763,4 @@ DDIISSCCLLAAIIMMEERR
file distributed with ssuuddoo or https://www.sudo.ws/license.html for file distributed with ssuuddoo or https://www.sudo.ws/license.html for
complete details. complete details.
Sudo 1.8.20 March 20, 2017 Sudo 1.8.20 Sudo 1.8.20 March 21, 2017 Sudo 1.8.20

View File

@@ -21,7 +21,7 @@
.\" Agency (DARPA) and Air Force Research Laboratory, Air Force .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
.\" Materiel Command, USAF, under agreement number F39502-99-1-0512. .\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
.\" .\"
.TH "SUDOERS" "5" "March 20, 2017" "Sudo @PACKAGE_VERSION@" "File Formats Manual" .TH "SUDOERS" "5" "March 21, 2017" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
.nh .nh
.if n .ad l .if n .ad l
.SH "NAME" .SH "NAME"
@@ -3331,8 +3331,17 @@ This setting is only supported by version 1.8.20 or higher.
iolog_group iolog_group
The group name to look up when setting the group ID on new I/O log The group name to look up when setting the group ID on new I/O log
files and directories. files and directories.
By default, I/O log files and directories inherit the group ID of If
the parent directory. \fIiolog_group\fR
is not set,
the primary group ID of the user specified by
\fIiolog_user\fR
is used.
If neither
\fIiolog_group\fR
nor
\fIiolog_user\fR
are set, I/O log files and directories are created with group ID 0.
.sp .sp
This setting is only supported by version 1.8.19 or higher. This setting is only supported by version 1.8.19 or higher.
.TP 18n .TP 18n
@@ -3350,10 +3359,13 @@ Defaults to 0600 (read and write by user only).
This setting is only supported by version 1.8.19 or higher. This setting is only supported by version 1.8.19 or higher.
.TP 18n .TP 18n
iolog_user iolog_user
The user name to look up when setting the user ID on new I/O log The user name to look up when setting the user and group IDs on new
files and directories. I/O log files and directories.
By default, I/O log files and directories are owned by the superuser If
(user ID 0). \fIiolog_group\fR
is set, it will be used instead of the user's primary group ID.
By default, I/O log files and directories are created with user and
group ID 0.
.sp .sp
This setting is only supported by version 1.8.19 or higher. This setting is only supported by version 1.8.19 or higher.
.TP 18n .TP 18n

View File

@@ -19,7 +19,7 @@
.\" Agency (DARPA) and Air Force Research Laboratory, Air Force .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
.\" Materiel Command, USAF, under agreement number F39502-99-1-0512. .\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
.\" .\"
.Dd March 20, 2017 .Dd March 21, 2017
.Dt SUDOERS @mansectform@ .Dt SUDOERS @mansectform@
.Os Sudo @PACKAGE_VERSION@ .Os Sudo @PACKAGE_VERSION@
.Sh NAME .Sh NAME
@@ -3124,8 +3124,17 @@ This setting is only supported by version 1.8.20 or higher.
.It iolog_group .It iolog_group
The group name to look up when setting the group ID on new I/O log The group name to look up when setting the group ID on new I/O log
files and directories. files and directories.
By default, I/O log files and directories inherit the group ID of If
the parent directory. .Em iolog_group
is not set,
the primary group ID of the user specified by
.Em iolog_user
is used.
If neither
.Em iolog_group
nor
.Em iolog_user
are set, I/O log files and directories are created with group ID 0.
.Pp .Pp
This setting is only supported by version 1.8.19 or higher. This setting is only supported by version 1.8.19 or higher.
.It iolog_mode .It iolog_mode
@@ -3141,10 +3150,13 @@ Defaults to 0600 (read and write by user only).
.Pp .Pp
This setting is only supported by version 1.8.19 or higher. This setting is only supported by version 1.8.19 or higher.
.It iolog_user .It iolog_user
The user name to look up when setting the user ID on new I/O log The user name to look up when setting the user and group IDs on new
files and directories. I/O log files and directories.
By default, I/O log files and directories are owned by the superuser If
(user ID 0). .Em iolog_group
is set, it will be used instead of the user's primary group ID.
By default, I/O log files and directories are created with user and
group ID 0.
.Pp .Pp
This setting is only supported by version 1.8.19 or higher. This setting is only supported by version 1.8.19 or higher.
.It lecture_status_dir .It lecture_status_dir

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2016 Todd C. Miller <Todd.Miller@courtesan.com> * Copyright (c) 2009-2017 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
@@ -71,10 +71,13 @@ static bool iolog_compress = false;
static bool warned = false; static bool warned = false;
static struct timeval last_time; static struct timeval last_time;
static unsigned int sessid_max = SESSID_MAX; static unsigned int sessid_max = SESSID_MAX;
static uid_t iolog_uid = ROOT_UID;
static gid_t iolog_gid = (gid_t)-1;
static mode_t iolog_filemode = S_IRUSR|S_IWUSR; static mode_t iolog_filemode = S_IRUSR|S_IWUSR;
static mode_t iolog_dirmode = S_IRWXU; static mode_t iolog_dirmode = S_IRWXU;
static bool iolog_gid_set;
/* shared with set_perms.c */
uid_t iolog_uid = ROOT_UID;
gid_t iolog_gid = ROOT_GID;
/* sudoers_io is declared at the end of this file. */ /* sudoers_io is declared at the end of this file. */
extern __dso_public struct io_plugin sudoers_io; extern __dso_public struct io_plugin sudoers_io;
@@ -83,18 +86,27 @@ extern __dso_public struct io_plugin sudoers_io;
* Create directory and any parent directories as needed. * Create directory and any parent directories as needed.
*/ */
static bool static bool
io_mkdirs(char *path, uid_t uid, gid_t *gidp, mode_t mode, bool set_intermediate) io_mkdirs(char *path)
{ {
struct stat sb; struct stat sb;
uid_t parent_uid; bool ok, uid_changed = false;
gid_t parent_gid;
mode_t parent_mode;
bool ok = true;
debug_decl(io_mkdirs, SUDOERS_DEBUG_UTIL) debug_decl(io_mkdirs, SUDOERS_DEBUG_UTIL)
if (stat(path, &sb) == 0) { ok = stat(path, &sb) == 0;
if (!ok) {
/* Try again as the I/O log owner (for NFS). */
if (set_perms(PERM_IOLOG)) {
ok = stat(path, &sb) == 0;
if (!restore_perms())
ok = false;
}
}
if (ok) {
if (S_ISDIR(sb.st_mode)) { if (S_ISDIR(sb.st_mode)) {
parent_gid = sb.st_gid; if ((sb.st_mode & ALLPERMS) != iolog_dirmode)
ignore_result(chmod(path, iolog_dirmode));
if (sb.st_uid != iolog_uid || sb.st_gid != iolog_gid)
ignore_result(chown(path, iolog_uid, iolog_gid));
} else { } else {
sudo_warnx(U_("%s exists but is not a directory (0%o)"), sudo_warnx(U_("%s exists but is not a directory (0%o)"),
path, (unsigned int) sb.st_mode); path, (unsigned int) sb.st_mode);
@@ -103,35 +115,28 @@ io_mkdirs(char *path, uid_t uid, gid_t *gidp, mode_t mode, bool set_intermediate
goto done; goto done;
} }
/* Parent directory ownership and mode. */ ok = sudo_mkdir_parents(path, iolog_uid, iolog_gid, iolog_dirmode, true);
if (!set_intermediate) { if (!ok) {
parent_mode = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; /* Try again as the I/O log owner (for NFS). */
parent_uid = ROOT_UID; uid_changed = set_perms(PERM_IOLOG);
parent_gid = (gid_t)-1; ok = sudo_mkdir_parents(path, -1, -1, iolog_dirmode, false);
} else {
parent_mode = mode;
parent_uid = uid;
parent_gid = *gidp;
} }
ok = sudo_mkdir_parents(path, parent_uid, &parent_gid, parent_mode, false);
if (ok) { if (ok) {
/* Use group ID if specified, else parent gid. */
gid_t gid = *gidp != (gid_t)-1 ? *gidp : parent_gid;
/* Create final path component. */ /* Create final path component. */
sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
"mkdir %s, mode 0%o", path, (unsigned int) mode); "mkdir %s, mode 0%o", path, (unsigned int) iolog_dirmode);
if (mkdir(path, mode) != 0 && errno != EEXIST) { if (mkdir(path, iolog_dirmode) != 0 && errno != EEXIST) {
sudo_warnx(U_("unable to mkdir %s"), path); sudo_warn(U_("unable to mkdir %s"), path);
ok = false; ok = false;
} else { } else {
ignore_result(chown(path, uid, gid)); ignore_result(chown(path, iolog_uid, iolog_gid));
} }
} }
if (uid_changed) {
if (!restore_perms())
ok = false;
}
done: done:
if (ok && *gidp == (gid_t)-1)
*gidp = parent_gid;
debug_return_bool(ok); debug_return_bool(ok);
} }
@@ -139,30 +144,19 @@ done:
* Create temporary directory and any parent directories as needed. * Create temporary directory and any parent directories as needed.
*/ */
static bool static bool
io_mkdtemp(char *path, uid_t uid, gid_t *gidp, mode_t mode, bool set_intermediate) io_mkdtemp(char *path)
{ {
uid_t parent_uid;
gid_t parent_gid;
mode_t parent_mode;
bool ok = true; bool ok = true;
bool uid_changed = false;
debug_decl(io_mkdtemp, SUDOERS_DEBUG_UTIL) debug_decl(io_mkdtemp, SUDOERS_DEBUG_UTIL)
/* Parent directory ownership and mode. */ ok = sudo_mkdir_parents(path, iolog_uid, iolog_gid, iolog_dirmode, true);
if (!set_intermediate) { if (!ok) {
parent_mode = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; /* Try again as the I/O log owner (for NFS). */
parent_uid = ROOT_UID; uid_changed = set_perms(PERM_IOLOG);
parent_gid = (gid_t)-1; ok = sudo_mkdir_parents(path, -1, -1, iolog_dirmode, false);
} else {
parent_mode = mode;
parent_uid = uid;
parent_gid = *gidp;
} }
ok = sudo_mkdir_parents(path, parent_uid, &parent_gid, parent_mode, false);
if (ok) { if (ok) {
/* Use group ID if specified, else parent gid. */
gid_t gid = *gidp != (gid_t)-1 ? *gidp : parent_gid;
/* Create final path component. */ /* Create final path component. */
sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
"mkdtemp %s", path); "mkdtemp %s", path);
@@ -170,12 +164,18 @@ io_mkdtemp(char *path, uid_t uid, gid_t *gidp, mode_t mode, bool set_intermediat
sudo_warn(U_("unable to mkdir %s"), path); sudo_warn(U_("unable to mkdir %s"), path);
ok = false; ok = false;
} else { } else {
ignore_result(chown(path, uid, gid)); ignore_result(chown(path, iolog_uid, iolog_gid));
if (chmod(path, iolog_dirmode) != 0) {
sudo_warn(U_("unable to change mode of %s to 0%o"),
path, iolog_dirmode);
}
} }
} }
if (ok && *gidp == (gid_t)-1) if (uid_changed) {
*gidp = parent_gid; if (!restore_perms())
ok = false;
}
debug_return_bool(ok); debug_return_bool(ok);
} }
@@ -217,25 +217,31 @@ cb_maxseq(const union sudo_defs_val *sd_un)
} }
/* /*
* Look up I/O log user ID from user name. * Look up I/O log user ID from user name. Sets iolog_uid.
* Also sets iolog_gid if iolog_group not specified.
*/ */
static bool static bool
iolog_set_uid(const char *name) iolog_set_user(const char *name)
{ {
struct passwd *pw; struct passwd *pw;
debug_decl(iolog_set_uid, SUDOERS_DEBUG_UTIL) debug_decl(iolog_set_user, SUDOERS_DEBUG_UTIL)
if (name != NULL) { if (name != NULL) {
pw = sudo_getpwnam(name); pw = sudo_getpwnam(name);
if (pw != NULL) { if (pw != NULL) {
iolog_uid = pw->pw_uid; iolog_uid = pw->pw_uid;
if (!iolog_gid_set)
iolog_gid = pw->pw_gid;
sudo_pw_delref(pw); sudo_pw_delref(pw);
} else { } else {
log_warningx(SLOG_SEND_MAIL, log_warningx(SLOG_SEND_MAIL,
N_("unknown user: %s"), name); N_("unknown user: %s"), name);
} }
} else { } else {
/* Reset to default. */
iolog_uid = ROOT_UID; iolog_uid = ROOT_UID;
if (!iolog_gid_set)
iolog_gid = ROOT_GID;
} }
debug_return_bool(true); debug_return_bool(true);
@@ -247,29 +253,33 @@ iolog_set_uid(const char *name)
bool bool
cb_iolog_user(const union sudo_defs_val *sd_un) cb_iolog_user(const union sudo_defs_val *sd_un)
{ {
return iolog_set_uid(sd_un->str); return iolog_set_user(sd_un->str);
} }
/* /*
* Look up I/O log group ID from group name. * Look up I/O log group ID from group name.
* Sets iolog_gid.
*/ */
static bool static bool
iolog_set_gid(const char *name) iolog_set_group(const char *name)
{ {
struct group *gr; struct group *gr;
debug_decl(iolog_set_gid, SUDOERS_DEBUG_UTIL) debug_decl(iolog_set_group, SUDOERS_DEBUG_UTIL)
if (name != NULL) { if (name != NULL) {
gr = sudo_getgrnam(name); gr = sudo_getgrnam(name);
if (gr != NULL) { if (gr != NULL) {
iolog_gid = gr->gr_gid; iolog_gid = gr->gr_gid;
iolog_gid_set = true;
sudo_gr_delref(gr); sudo_gr_delref(gr);
} else { } else {
log_warningx(SLOG_SEND_MAIL, log_warningx(SLOG_SEND_MAIL,
N_("unknown group: %s"), name); N_("unknown group: %s"), name);
} }
} else { } else {
iolog_gid = (mode_t)-1; /* Reset to default. */
iolog_gid = ROOT_GID;
iolog_gid_set = false;
} }
debug_return_bool(true); debug_return_bool(true);
@@ -281,7 +291,7 @@ iolog_set_gid(const char *name)
bool bool
cb_iolog_group(const union sudo_defs_val *sd_un) cb_iolog_group(const union sudo_defs_val *sd_un)
{ {
return iolog_set_gid(sd_un->str); return iolog_set_group(sd_un->str);
} }
/* /*
@@ -338,9 +348,8 @@ io_nextid(char *iolog_dir, char *iolog_dir_fallback, char sessid[7])
/* /*
* Create I/O log directory if it doesn't already exist. * Create I/O log directory if it doesn't already exist.
* Avoid modifying iolog_gid at this point.
*/ */
if (!io_mkdirs(iolog_dir, iolog_uid, &gid, iolog_dirmode, false)) if (!io_mkdirs(iolog_dir))
goto done; goto done;
/* /*
@@ -353,12 +362,18 @@ io_nextid(char *iolog_dir, char *iolog_dir_fallback, char sessid[7])
goto done; goto done;
} }
fd = open(pathbuf, O_RDWR|O_CREAT, iolog_filemode); fd = open(pathbuf, O_RDWR|O_CREAT, iolog_filemode);
if (fd == -1) {
/* Try again as the I/O log owner (for NFS). */
set_perms(PERM_IOLOG);
fd = open(pathbuf, O_RDWR|O_CREAT, iolog_filemode);
restore_perms();
}
if (fd == -1) { if (fd == -1) {
log_warning(SLOG_SEND_MAIL, N_("unable to open %s"), pathbuf); log_warning(SLOG_SEND_MAIL, N_("unable to open %s"), pathbuf);
goto done; goto done;
} }
sudo_lock_file(fd, SUDO_LOCK); sudo_lock_file(fd, SUDO_LOCK);
ignore_result(fchown(fd, iolog_uid, gid)); ignore_result(fchown(fd, iolog_uid, iolog_gid));
/* /*
* If there is no seq file in iolog_dir and a fallback dir was * If there is no seq file in iolog_dir and a fallback dir was
@@ -372,7 +387,14 @@ io_nextid(char *iolog_dir, char *iolog_dir_fallback, char sessid[7])
len = snprintf(fallback, sizeof(fallback), "%s/seq", len = snprintf(fallback, sizeof(fallback), "%s/seq",
iolog_dir_fallback); iolog_dir_fallback);
if (len > 0 && (size_t)len < sizeof(fallback)) { if (len > 0 && (size_t)len < sizeof(fallback)) {
int fd2 = open(fallback, O_RDWR|O_CREAT, iolog_filemode); int fd2;
fd2 = open(fallback, O_RDWR|O_CREAT, iolog_filemode);
if (fd == -1) {
/* Try again as the I/O log owner (for NFS). */
set_perms(PERM_IOLOG);
fd2 = open(fallback, O_RDWR|O_CREAT, iolog_filemode);
restore_perms();
}
if (fd2 != -1) { if (fd2 != -1) {
ignore_result(fchown(fd2, iolog_uid, gid)); ignore_result(fchown(fd2, iolog_uid, gid));
nread = read(fd2, buf, sizeof(buf) - 1); nread = read(fd2, buf, sizeof(buf) - 1);
@@ -470,9 +492,9 @@ mkdir_iopath(const char *iolog_path, char *pathbuf, size_t pathsize)
* Sets iolog_gid (if it is not already set) as a side effect. * Sets iolog_gid (if it is not already set) as a side effect.
*/ */
if (len >= 6 && strcmp(&pathbuf[len - 6], "XXXXXX") == 0) if (len >= 6 && strcmp(&pathbuf[len - 6], "XXXXXX") == 0)
ok = io_mkdtemp(pathbuf, iolog_uid, &iolog_gid, iolog_dirmode, true); ok = io_mkdtemp(pathbuf);
else else
ok = io_mkdirs(pathbuf, iolog_uid, &iolog_gid, iolog_dirmode, true); ok = io_mkdirs(pathbuf);
debug_return_size_t(ok ? len : (size_t)-1); debug_return_size_t(ok ? len : (size_t)-1);
} }
@@ -492,6 +514,12 @@ open_io_fd(char *pathbuf, size_t len, struct io_log_file *iol, bool docompress)
strlcat(pathbuf, iol->suffix, PATH_MAX); strlcat(pathbuf, iol->suffix, PATH_MAX);
if (iol->enabled) { if (iol->enabled) {
int fd = open(pathbuf, O_CREAT|O_TRUNC|O_WRONLY, iolog_filemode); int fd = open(pathbuf, O_CREAT|O_TRUNC|O_WRONLY, iolog_filemode);
if (fd == -1) {
/* Try again as the I/O log owner (for NFS). */
set_perms(PERM_IOLOG);
fd = open(pathbuf, O_CREAT|O_TRUNC|O_WRONLY, iolog_filemode);
restore_perms();
}
if (fd != -1) { if (fd != -1) {
ignore_result(fchown(fd, iolog_uid, iolog_gid)); ignore_result(fchown(fd, iolog_uid, iolog_gid));
(void)fcntl(fd, F_SETFD, FD_CLOEXEC); (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
@@ -630,11 +658,11 @@ iolog_deserialize_info(struct iolog_details *details, char * const user_info[],
continue; continue;
} }
if (strncmp(*cur, "iolog_group=", sizeof("iolog_group=") - 1) == 0) { if (strncmp(*cur, "iolog_group=", sizeof("iolog_group=") - 1) == 0) {
iolog_set_gid(*cur + sizeof("iolog_group=") - 1); iolog_set_group(*cur + sizeof("iolog_group=") - 1);
continue; continue;
} }
if (strncmp(*cur, "iolog_user=", sizeof("iolog_user=") - 1) == 0) { if (strncmp(*cur, "iolog_user=", sizeof("iolog_user=") - 1) == 0) {
iolog_set_uid(*cur + sizeof("iolog_user=") - 1); iolog_set_user(*cur + sizeof("iolog_user=") - 1);
continue; continue;
} }
break; break;
@@ -725,6 +753,12 @@ write_info_log(char *pathbuf, size_t len, struct iolog_details *details,
pathbuf[len] = '\0'; pathbuf[len] = '\0';
strlcat(pathbuf, "/log", PATH_MAX); strlcat(pathbuf, "/log", PATH_MAX);
fd = open(pathbuf, O_CREAT|O_TRUNC|O_WRONLY, iolog_filemode); fd = open(pathbuf, O_CREAT|O_TRUNC|O_WRONLY, iolog_filemode);
if (fd == -1) {
/* Try again as the I/O log owner (for NFS). */
set_perms(PERM_IOLOG);
fd = open(pathbuf, O_CREAT|O_TRUNC|O_WRONLY, iolog_filemode);
restore_perms();
}
if (fd == -1 || (fp = fdopen(fd, "w")) == NULL) { if (fd == -1 || (fp = fdopen(fd, "w")) == NULL) {
log_warning(SLOG_SEND_MAIL, N_("unable to create %s"), pathbuf); log_warning(SLOG_SEND_MAIL, N_("unable to create %s"), pathbuf);
debug_return_bool(false); debug_return_bool(false);

View File

@@ -38,27 +38,21 @@
* Note that path is modified but is restored before it returns. * Note that path is modified but is restored before it returns.
*/ */
bool bool
sudo_mkdir_parents(char *path, uid_t uid, gid_t *gidp, mode_t mode, bool quiet) sudo_mkdir_parents(char *path, uid_t uid, gid_t gid, mode_t mode, bool quiet)
{ {
struct stat sb; struct stat sb;
gid_t parent_gid = 0;
char *slash = path; char *slash = path;
debug_decl(sudo_mkdir_parents, SUDOERS_DEBUG_UTIL) debug_decl(sudo_mkdir_parents, SUDOERS_DEBUG_UTIL)
/* If no gid specified, inherit from parent dir. */
if (*gidp != (gid_t)-1)
parent_gid = *gidp;
else if (stat("/", &sb) == 0)
parent_gid = sb.st_gid;
/* Create parent directories as needed. */ /* Create parent directories as needed. */
while ((slash = strchr(slash + 1, '/')) != NULL) { while ((slash = strchr(slash + 1, '/')) != NULL) {
*slash = '\0'; *slash = '\0';
sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
"mkdir %s, mode 0%o, uid %d, gid %d", path, (unsigned int)mode, "mkdir %s, mode 0%o, uid %d, gid %d", path, (unsigned int)mode,
(int)uid, (int)parent_gid); (int)uid, (int)gid);
if (mkdir(path, mode) == 0) { if (mkdir(path, mode) == 0) {
ignore_result(chown(path, uid, parent_gid)); if (uid != (uid_t)-1 && gid != (gid_t)-1)
ignore_result(chown(path, uid, gid));
} else { } else {
if (errno != EEXIST) { if (errno != EEXIST) {
if (!quiet) if (!quiet)
@@ -77,16 +71,10 @@ sudo_mkdir_parents(char *path, uid_t uid, gid_t *gidp, mode_t mode, bool quiet)
path, (unsigned int) sb.st_mode); path, (unsigned int) sb.st_mode);
goto bad; goto bad;
} }
/* Inherit gid of parent dir for ownership. */
if (*gidp == (gid_t)-1)
parent_gid = sb.st_gid;
} }
*slash = '/'; *slash = '/';
} }
/* Return parent gid if none was specified by caller. */
if (*gidp == (gid_t)-1)
*gidp = parent_gid;
debug_return_bool(true); debug_return_bool(true);
bad: bad:
/* We must restore the path before we return. */ /* We must restore the path before we return. */

View File

@@ -347,6 +347,37 @@ set_perms(int perm)
goto bad; goto bad;
} }
break; break;
case PERM_IOLOG:
state->gidlist = ostate->gidlist;
sudo_gidlist_addref(state->gidlist);
state->rgid = ostate->rgid;
state->egid = iolog_gid;
state->sgid = ostate->sgid;
state->ruid = ROOT_UID;
state->euid = iolog_uid;
state->suid = ROOT_UID;
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_IOLOG: gid: "
"[%d, %d, %d] -> [%d, %d, %d]", __func__,
(int)ostate->rgid, (int)ostate->egid, (int)ostate->sgid,
(int)state->rgid, (int)state->egid, (int)state->sgid);
if (GID_CHANGED && setresgid(ID(rgid), ID(egid), ID(sgid))) {
snprintf(errbuf, sizeof(errbuf),
"PERM_IOLOG: setresgid(%d, %d, %d)",
(int)ID(rgid), (int)ID(egid), (int)ID(sgid));
goto bad;
}
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_IOLOG: uid: "
"[%d, %d, %d] -> [%d, %d, %d]", __func__,
(int)ostate->ruid, (int)ostate->euid, (int)ostate->suid,
(int)state->ruid, (int)state->euid, (int)state->suid);
if (UID_CHANGED && setresuid(ID(ruid), ID(euid), ID(suid))) {
snprintf(errbuf, sizeof(errbuf),
"PERM_IOLOG: setresuid(%d, %d, %d)",
(int)ID(ruid), (int)ID(euid), (int)ID(suid));
goto bad;
}
break;
} }
perm_stack_depth++; perm_stack_depth++;
@@ -390,12 +421,6 @@ restore_perms(void)
goto bad; goto bad;
} }
} }
if (setresuid(OID(ruid), OID(euid), OID(suid))) {
sudo_warn("setresuid() [%d, %d, %d] -> [%d, %d, %d]",
(int)state->ruid, (int)state->euid, (int)state->suid,
(int)OID(ruid), (int)OID(euid), (int)OID(suid));
goto bad;
}
if (setresgid(OID(rgid), OID(egid), OID(sgid))) { if (setresgid(OID(rgid), OID(egid), OID(sgid))) {
sudo_warn("setresgid() [%d, %d, %d] -> [%d, %d, %d]", sudo_warn("setresgid() [%d, %d, %d] -> [%d, %d, %d]",
(int)state->rgid, (int)state->egid, (int)state->sgid, (int)state->rgid, (int)state->egid, (int)state->sgid,
@@ -408,6 +433,12 @@ restore_perms(void)
goto bad; goto bad;
} }
} }
if (setresuid(OID(ruid), OID(euid), OID(suid))) {
sudo_warn("setresuid() [%d, %d, %d] -> [%d, %d, %d]",
(int)state->ruid, (int)state->euid, (int)state->suid,
(int)OID(ruid), (int)OID(euid), (int)OID(suid));
goto bad;
}
sudo_gidlist_delref(state->gidlist); sudo_gidlist_delref(state->gidlist);
debug_return_bool(true); debug_return_bool(true);
@@ -686,6 +717,46 @@ set_perms(int perm)
} }
} }
break; break;
case PERM_IOLOG:
state->gidlist = ostate->gidlist;
sudo_gidlist_addref(state->gidlist);
state->rgid = ostate->rgid;
state->egid = iolog_gid;
state->sgid = ostate->sgid;
state->ruid = ROOT_UID;
state->euid = iolog_uid;
state->suid = ROOT_UID;
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_IOLOG: gid: "
"[%d, %d, %d] -> [%d, %d, %d]", __func__,
(int)ostate->rgid, (int)ostate->egid, (int)ostate->sgid,
(int)state->rgid, (int)state->egid, (int)state->sgid);
if (GID_CHANGED && setgidx(ID_EFFECTIVE, iolog_gid)) {
snprintf(errbuf, sizeof(errbuf),
"PERM_IOLOG: setgidx(ID_EFFECTIVE, %d)", (int)iolog_gid);
goto bad;
}
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_IOLOG: uid: "
"[%d, %d, %d] -> [%d, %d, %d]", __func__,
(int)ostate->ruid, (int)ostate->euid, (int)ostate->suid,
(int)state->ruid, (int)state->euid, (int)state->suid);
if (UID_CHANGED) {
if (ostate->ruid != ROOT_UID || ostate->suid != ROOT_UID) {
if (setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, ROOT_UID)) {
snprintf(errbuf, sizeof(errbuf),
"PERM_IOLOG: setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, %d)",
ROOT_UID);
goto bad;
}
}
if (setuidx(ID_EFFECTIVE, timestamp_uid)) {
snprintf(errbuf, sizeof(errbuf),
"PERM_IOLOG: setuidx(ID_EFFECTIVE, %d)",
(int)timestamp_uid);
goto bad;
}
}
break;
} }
perm_stack_depth++; perm_stack_depth++;
@@ -1045,6 +1116,31 @@ set_perms(int perm)
goto bad; goto bad;
} }
break; break;
case PERM_IOLOG:
state->gidlist = ostate->gidlist;
sudo_gidlist_addref(state->gidlist);
state->rgid = ostate->rgid;
state->egid = iolog_gid;
state->ruid = ROOT_UID;
state->euid = iolog_uid;
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_IOLOG: gid: "
"[%d, %d] -> [%d, %d]", __func__, (int)ostate->rgid,
(int)ostate->egid, (int)state->rgid, (int)state->egid);
if (GID_CHANGED && setregid(ID(rgid), ID(egid))) {
snprintf(errbuf, sizeof(errbuf), "PERM_IOLOG: setregid(%d, %d)",
(int)ID(rgid), (int)ID(egid));
goto bad;
}
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_IOLOG: uid: "
"[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid,
(int)ostate->euid, (int)state->ruid, (int)state->euid);
if (UID_CHANGED && setreuid(ID(ruid), ID(euid))) {
snprintf(errbuf, sizeof(errbuf), "PERM_IOLOG: setreuid(%d, %d)",
(int)ID(ruid), (int)ID(euid));
goto bad;
}
break;
} }
perm_stack_depth++; perm_stack_depth++;
@@ -1341,6 +1437,31 @@ set_perms(int perm)
goto bad; goto bad;
} }
break; break;
case PERM_IOLOG:
state->gidlist = ostate->gidlist;
sudo_gidlist_addref(state->gidlist);
state->rgid = ostate->rgid;
state->egid = iolog_gid;
state->ruid = ROOT_UID;
state->euid = iolog_uid;
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_IOLOG: gid: "
"[%d, %d] -> [%d, %d]", __func__, (int)ostate->rgid,
(int)ostate->egid, (int)state->rgid, (int)state->egid);
if (GID_CHANGED && setegid(iolog_gid)) {
snprintf(errbuf, sizeof(errbuf),
"PERM_IOLOG: setegid(%d)", (int)iolog_gid);
goto bad;
}
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_IOLOG: uid: "
"[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid,
(int)ostate->euid, (int)state->ruid, (int)state->euid);
if (seteuid(timestamp_uid)) {
snprintf(errbuf, sizeof(errbuf),
"PERM_IOLOG: seteuid(%d)", (int)timestamp_uid);
goto bad;
}
break;
} }
perm_stack_depth++; perm_stack_depth++;
@@ -1499,6 +1620,7 @@ set_perms(int perm)
case PERM_SUDOERS: case PERM_SUDOERS:
case PERM_RUNAS: case PERM_RUNAS:
case PERM_TIMESTAMP: case PERM_TIMESTAMP:
case PERM_IOLOG:
/* Unsupported since we can't set euid. */ /* Unsupported since we can't set euid. */
state->ruid = ostate->ruid; state->ruid = ostate->ruid;
state->rgid = ostate->rgid; state->rgid = ostate->rgid;

View File

@@ -170,13 +170,14 @@ struct sudo_user {
/* /*
* Used with set_perms() * Used with set_perms()
*/ */
#define PERM_INITIAL 0x00 #define PERM_INITIAL 0x00
#define PERM_ROOT 0x01 #define PERM_ROOT 0x01
#define PERM_USER 0x02 #define PERM_USER 0x02
#define PERM_FULL_USER 0x03 #define PERM_FULL_USER 0x03
#define PERM_SUDOERS 0x04 #define PERM_SUDOERS 0x04
#define PERM_RUNAS 0x05 #define PERM_RUNAS 0x05
#define PERM_TIMESTAMP 0x06 #define PERM_TIMESTAMP 0x06
#define PERM_IOLOG 0x07
/* /*
* Shortcuts for sudo_user contents. * Shortcuts for sudo_user contents.
@@ -333,6 +334,8 @@ bool cb_maxseq(const union sudo_defs_val *sd_un);
bool cb_iolog_user(const union sudo_defs_val *sd_un); bool cb_iolog_user(const union sudo_defs_val *sd_un);
bool cb_iolog_group(const union sudo_defs_val *sd_un); bool cb_iolog_group(const union sudo_defs_val *sd_un);
bool cb_iolog_mode(const union sudo_defs_val *sd_un); bool cb_iolog_mode(const union sudo_defs_val *sd_un);
extern uid_t iolog_uid;
extern gid_t iolog_gid;
/* iolog_path.c */ /* iolog_path.c */
char *expand_iolog_path(const char *prefix, const char *dir, const char *file, char *expand_iolog_path(const char *prefix, const char *dir, const char *file,
@@ -394,7 +397,7 @@ char *resolve_editor(const char *ed, size_t edlen, int nfiles, char **files,
int *argc_out, char ***argv_out, char * const *whitelist); int *argc_out, char ***argv_out, char * const *whitelist);
/* mkdir_parents.c */ /* mkdir_parents.c */
bool sudo_mkdir_parents(char *path, uid_t uid, gid_t *gidp, mode_t mode, bool quiet); bool sudo_mkdir_parents(char *path, uid_t uid, gid_t gid, mode_t mode, bool quiet);
/* gc.c */ /* gc.c */
enum sudoers_gc_types { enum sudoers_gc_types {

View File

@@ -156,7 +156,7 @@ ts_mkdirs(char *path, uid_t owner, gid_t group, mode_t mode,
bool ret; bool ret;
debug_decl(ts_mkdirs, SUDOERS_DEBUG_AUTH) debug_decl(ts_mkdirs, SUDOERS_DEBUG_AUTH)
ret = sudo_mkdir_parents(path, owner, &group, parent_mode, quiet); ret = sudo_mkdir_parents(path, owner, group, parent_mode, quiet);
if (ret) { if (ret) {
/* Create final path component. */ /* Create final path component. */
sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,