From 8d57491dc1c923d585cf48e6b21cbec83e768677 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Tue, 21 Mar 2017 13:41:14 -0600 Subject: [PATCH] Add PERM_IOLOG so we can create I/O log files on an NFS-mounted filesystem where root is remapped to an unprivileged user. --- doc/sudoers.cat | 19 ++-- doc/sudoers.man.in | 26 +++-- doc/sudoers.mdoc.in | 26 +++-- plugins/sudoers/iolog.c | 168 +++++++++++++++++++------------- plugins/sudoers/mkdir_parents.c | 20 +--- plugins/sudoers/set_perms.c | 134 +++++++++++++++++++++++-- plugins/sudoers/sudoers.h | 19 ++-- plugins/sudoers/timestamp.c | 2 +- 8 files changed, 294 insertions(+), 120 deletions(-) diff --git a/doc/sudoers.cat b/doc/sudoers.cat index b0caee934..5c5c3c8db 100644 --- a/doc/sudoers.cat +++ b/doc/sudoers.cat @@ -1626,9 +1626,11 @@ SSUUDDOOEERRSS OOPPTTIIOONNSS higher. 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 - files and directories inherit the group ID of the - parent directory. + new I/O log files and directories. If _i_o_l_o_g___g_r_o_u_p is + not set, the primary group ID of the user specified by + _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 higher. @@ -1646,10 +1648,11 @@ SSUUDDOOEERRSS OOPPTTIIOONNSS This setting is only supported by version 1.8.19 or higher. - iolog_user The user name to look up when setting the user ID on - new I/O log files and directories. By default, I/O log - files and directories are owned by the superuser (user - ID 0). + iolog_user The user name to look up when setting the user and + group IDs on new I/O log files and directories. If + _i_o_l_o_g___g_r_o_u_p 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. This setting is only supported by version 1.8.19 or higher. @@ -2760,4 +2763,4 @@ DDIISSCCLLAAIIMMEERR file distributed with ssuuddoo or https://www.sudo.ws/license.html for complete details. -Sudo 1.8.20 March 20, 2017 Sudo 1.8.20 +Sudo 1.8.20 March 21, 2017 Sudo 1.8.20 diff --git a/doc/sudoers.man.in b/doc/sudoers.man.in index 49dbd77ad..a5bd2fe3b 100644 --- a/doc/sudoers.man.in +++ b/doc/sudoers.man.in @@ -21,7 +21,7 @@ .\" Agency (DARPA) and Air Force Research Laboratory, Air Force .\" 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 .if n .ad l .SH "NAME" @@ -3331,8 +3331,17 @@ This setting is only supported by version 1.8.20 or higher. 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 files and directories inherit the group ID of -the parent directory. +If +\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 This setting is only supported by version 1.8.19 or higher. .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. .TP 18n iolog_user -The user name to look up when setting the user ID on new I/O log -files and directories. -By default, I/O log files and directories are owned by the superuser -(user ID 0). +The user name to look up when setting the user and group IDs on new +I/O log files and directories. +If +\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 This setting is only supported by version 1.8.19 or higher. .TP 18n diff --git a/doc/sudoers.mdoc.in b/doc/sudoers.mdoc.in index e872b7c6a..44b05b0b5 100644 --- a/doc/sudoers.mdoc.in +++ b/doc/sudoers.mdoc.in @@ -19,7 +19,7 @@ .\" Agency (DARPA) and Air Force Research Laboratory, Air Force .\" Materiel Command, USAF, under agreement number F39502-99-1-0512. .\" -.Dd March 20, 2017 +.Dd March 21, 2017 .Dt SUDOERS @mansectform@ .Os Sudo @PACKAGE_VERSION@ .Sh NAME @@ -3124,8 +3124,17 @@ This setting is only supported by version 1.8.20 or higher. .It 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 files and directories inherit the group ID of -the parent directory. +If +.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 This setting is only supported by version 1.8.19 or higher. .It iolog_mode @@ -3141,10 +3150,13 @@ Defaults to 0600 (read and write by user only). .Pp This setting is only supported by version 1.8.19 or higher. .It iolog_user -The user name to look up when setting the user ID on new I/O log -files and directories. -By default, I/O log files and directories are owned by the superuser -(user ID 0). +The user name to look up when setting the user and group IDs on new +I/O log files and directories. +If +.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 This setting is only supported by version 1.8.19 or higher. .It lecture_status_dir diff --git a/plugins/sudoers/iolog.c b/plugins/sudoers/iolog.c index 058659d51..2c09f9588 100644 --- a/plugins/sudoers/iolog.c +++ b/plugins/sudoers/iolog.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2016 Todd C. Miller + * Copyright (c) 2009-2017 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * 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 struct timeval last_time; 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_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. */ 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. */ 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; - uid_t parent_uid; - gid_t parent_gid; - mode_t parent_mode; - bool ok = true; + bool ok, uid_changed = false; 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)) { - 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 { sudo_warnx(U_("%s exists but is not a directory (0%o)"), 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; } - /* Parent directory ownership and mode. */ - if (!set_intermediate) { - parent_mode = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; - parent_uid = ROOT_UID; - parent_gid = (gid_t)-1; - } else { - parent_mode = mode; - parent_uid = uid; - parent_gid = *gidp; + ok = sudo_mkdir_parents(path, iolog_uid, iolog_gid, iolog_dirmode, true); + if (!ok) { + /* Try again as the I/O log owner (for NFS). */ + uid_changed = set_perms(PERM_IOLOG); + ok = sudo_mkdir_parents(path, -1, -1, iolog_dirmode, false); } - - ok = sudo_mkdir_parents(path, parent_uid, &parent_gid, parent_mode, false); if (ok) { - /* Use group ID if specified, else parent gid. */ - gid_t gid = *gidp != (gid_t)-1 ? *gidp : parent_gid; - /* Create final path component. */ sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, - "mkdir %s, mode 0%o", path, (unsigned int) mode); - if (mkdir(path, mode) != 0 && errno != EEXIST) { - sudo_warnx(U_("unable to mkdir %s"), path); + "mkdir %s, mode 0%o", path, (unsigned int) iolog_dirmode); + if (mkdir(path, iolog_dirmode) != 0 && errno != EEXIST) { + sudo_warn(U_("unable to mkdir %s"), path); ok = false; } else { - ignore_result(chown(path, uid, gid)); + ignore_result(chown(path, iolog_uid, iolog_gid)); } } + if (uid_changed) { + if (!restore_perms()) + ok = false; + } done: - if (ok && *gidp == (gid_t)-1) - *gidp = parent_gid; debug_return_bool(ok); } @@ -139,30 +144,19 @@ done: * Create temporary directory and any parent directories as needed. */ 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 uid_changed = false; debug_decl(io_mkdtemp, SUDOERS_DEBUG_UTIL) - /* Parent directory ownership and mode. */ - if (!set_intermediate) { - parent_mode = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; - parent_uid = ROOT_UID; - parent_gid = (gid_t)-1; - } else { - parent_mode = mode; - parent_uid = uid; - parent_gid = *gidp; + ok = sudo_mkdir_parents(path, iolog_uid, iolog_gid, iolog_dirmode, true); + if (!ok) { + /* Try again as the I/O log owner (for NFS). */ + uid_changed = set_perms(PERM_IOLOG); + ok = sudo_mkdir_parents(path, -1, -1, iolog_dirmode, false); } - - ok = sudo_mkdir_parents(path, parent_uid, &parent_gid, parent_mode, false); if (ok) { - /* Use group ID if specified, else parent gid. */ - gid_t gid = *gidp != (gid_t)-1 ? *gidp : parent_gid; - /* Create final path component. */ sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, "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); ok = false; } 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) - *gidp = parent_gid; + if (uid_changed) { + if (!restore_perms()) + ok = false; + } 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 -iolog_set_uid(const char *name) +iolog_set_user(const char *name) { struct passwd *pw; - debug_decl(iolog_set_uid, SUDOERS_DEBUG_UTIL) + debug_decl(iolog_set_user, SUDOERS_DEBUG_UTIL) if (name != NULL) { pw = sudo_getpwnam(name); if (pw != NULL) { iolog_uid = pw->pw_uid; + if (!iolog_gid_set) + iolog_gid = pw->pw_gid; sudo_pw_delref(pw); } else { log_warningx(SLOG_SEND_MAIL, N_("unknown user: %s"), name); } } else { + /* Reset to default. */ iolog_uid = ROOT_UID; + if (!iolog_gid_set) + iolog_gid = ROOT_GID; } debug_return_bool(true); @@ -247,29 +253,33 @@ iolog_set_uid(const char *name) bool 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. + * Sets iolog_gid. */ static bool -iolog_set_gid(const char *name) +iolog_set_group(const char *name) { struct group *gr; - debug_decl(iolog_set_gid, SUDOERS_DEBUG_UTIL) + debug_decl(iolog_set_group, SUDOERS_DEBUG_UTIL) if (name != NULL) { gr = sudo_getgrnam(name); if (gr != NULL) { iolog_gid = gr->gr_gid; + iolog_gid_set = true; sudo_gr_delref(gr); } else { log_warningx(SLOG_SEND_MAIL, N_("unknown group: %s"), name); } } else { - iolog_gid = (mode_t)-1; + /* Reset to default. */ + iolog_gid = ROOT_GID; + iolog_gid_set = false; } debug_return_bool(true); @@ -281,7 +291,7 @@ iolog_set_gid(const char *name) bool 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. - * 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; /* @@ -353,12 +362,18 @@ io_nextid(char *iolog_dir, char *iolog_dir_fallback, char sessid[7]) goto done; } 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) { log_warning(SLOG_SEND_MAIL, N_("unable to open %s"), pathbuf); goto done; } 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 @@ -372,7 +387,14 @@ io_nextid(char *iolog_dir, char *iolog_dir_fallback, char sessid[7]) len = snprintf(fallback, sizeof(fallback), "%s/seq", iolog_dir_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) { ignore_result(fchown(fd2, iolog_uid, gid)); 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. */ 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 - ok = io_mkdirs(pathbuf, iolog_uid, &iolog_gid, iolog_dirmode, true); + ok = io_mkdirs(pathbuf); 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); if (iol->enabled) { 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) { ignore_result(fchown(fd, iolog_uid, iolog_gid)); (void)fcntl(fd, F_SETFD, FD_CLOEXEC); @@ -630,11 +658,11 @@ iolog_deserialize_info(struct iolog_details *details, char * const user_info[], continue; } 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; } 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; } break; @@ -725,6 +753,12 @@ write_info_log(char *pathbuf, size_t len, struct iolog_details *details, pathbuf[len] = '\0'; strlcat(pathbuf, "/log", PATH_MAX); 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) { log_warning(SLOG_SEND_MAIL, N_("unable to create %s"), pathbuf); debug_return_bool(false); diff --git a/plugins/sudoers/mkdir_parents.c b/plugins/sudoers/mkdir_parents.c index 40d888191..335a35704 100644 --- a/plugins/sudoers/mkdir_parents.c +++ b/plugins/sudoers/mkdir_parents.c @@ -38,27 +38,21 @@ * Note that path is modified but is restored before it returns. */ 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; - gid_t parent_gid = 0; char *slash = path; 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. */ while ((slash = strchr(slash + 1, '/')) != NULL) { *slash = '\0'; sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, "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) { - ignore_result(chown(path, uid, parent_gid)); + if (uid != (uid_t)-1 && gid != (gid_t)-1) + ignore_result(chown(path, uid, gid)); } else { if (errno != EEXIST) { 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); goto bad; } - /* Inherit gid of parent dir for ownership. */ - if (*gidp == (gid_t)-1) - parent_gid = sb.st_gid; } *slash = '/'; } - /* Return parent gid if none was specified by caller. */ - if (*gidp == (gid_t)-1) - *gidp = parent_gid; debug_return_bool(true); bad: /* We must restore the path before we return. */ diff --git a/plugins/sudoers/set_perms.c b/plugins/sudoers/set_perms.c index 9e6f86fcd..000f33f2c 100644 --- a/plugins/sudoers/set_perms.c +++ b/plugins/sudoers/set_perms.c @@ -347,6 +347,37 @@ set_perms(int perm) goto bad; } 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++; @@ -390,12 +421,6 @@ restore_perms(void) 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))) { sudo_warn("setresgid() [%d, %d, %d] -> [%d, %d, %d]", (int)state->rgid, (int)state->egid, (int)state->sgid, @@ -408,6 +433,12 @@ restore_perms(void) 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); debug_return_bool(true); @@ -686,6 +717,46 @@ set_perms(int perm) } } 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++; @@ -1045,6 +1116,31 @@ set_perms(int perm) goto bad; } 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++; @@ -1341,6 +1437,31 @@ set_perms(int perm) goto bad; } 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++; @@ -1499,6 +1620,7 @@ set_perms(int perm) case PERM_SUDOERS: case PERM_RUNAS: case PERM_TIMESTAMP: + case PERM_IOLOG: /* Unsupported since we can't set euid. */ state->ruid = ostate->ruid; state->rgid = ostate->rgid; diff --git a/plugins/sudoers/sudoers.h b/plugins/sudoers/sudoers.h index 745619e83..37b69a561 100644 --- a/plugins/sudoers/sudoers.h +++ b/plugins/sudoers/sudoers.h @@ -170,13 +170,14 @@ struct sudo_user { /* * Used with set_perms() */ -#define PERM_INITIAL 0x00 -#define PERM_ROOT 0x01 -#define PERM_USER 0x02 -#define PERM_FULL_USER 0x03 -#define PERM_SUDOERS 0x04 -#define PERM_RUNAS 0x05 -#define PERM_TIMESTAMP 0x06 +#define PERM_INITIAL 0x00 +#define PERM_ROOT 0x01 +#define PERM_USER 0x02 +#define PERM_FULL_USER 0x03 +#define PERM_SUDOERS 0x04 +#define PERM_RUNAS 0x05 +#define PERM_TIMESTAMP 0x06 +#define PERM_IOLOG 0x07 /* * 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_group(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 */ 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); /* 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 */ enum sudoers_gc_types { diff --git a/plugins/sudoers/timestamp.c b/plugins/sudoers/timestamp.c index 8343c1a5c..f3c7bf58e 100644 --- a/plugins/sudoers/timestamp.c +++ b/plugins/sudoers/timestamp.c @@ -156,7 +156,7 @@ ts_mkdirs(char *path, uid_t owner, gid_t group, mode_t mode, bool ret; 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) { /* Create final path component. */ sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, -- 2.40.0