diff options
author | Todd C. Miller <Todd.Miller@sudo.ws> | 2023-05-02 10:37:38 -0600 |
---|---|---|
committer | Todd C. Miller <Todd.Miller@sudo.ws> | 2023-05-02 10:37:38 -0600 |
commit | d4c33b71898c9f4b122815c6826ad5cc8a69ff60 (patch) | |
tree | ffcee8f87a7ac8c5733b48925f19c6d60984382b | |
parent | b3a0d009b185e599622d4722010ae0278eeee5fc (diff) | |
download | sudo-d4c33b71898c9f4b122815c6826ad5cc8a69ff60.tar.gz |
Convert config file paths to colon-separated path list.
This means that _PATH_SUDO_CONF, _PATH_SUDOERS, _PATH_SUDO_LOGSRVD_CONF,
and _PATH_CVTSUDOERS_CONF can now specify multiple files. The first
file that exists is used.
-rwxr-xr-x | configure | 9 | ||||
-rw-r--r-- | configure.ac | 9 | ||||
-rw-r--r-- | include/sudo_util.h | 4 | ||||
-rw-r--r-- | lib/util/Makefile.in | 2 | ||||
-rw-r--r-- | lib/util/secure_path.c | 58 | ||||
-rw-r--r-- | lib/util/sudo_conf.c | 94 | ||||
-rw-r--r-- | lib/util/util.exp.in | 2 | ||||
-rw-r--r-- | logsrvd/Makefile.in | 2 | ||||
-rw-r--r-- | logsrvd/logsrvd.c | 5 | ||||
-rw-r--r-- | logsrvd/logsrvd_conf.c | 24 | ||||
-rw-r--r-- | plugins/sudoers/Makefile.in | 4 | ||||
-rw-r--r-- | plugins/sudoers/cvtsudoers.c | 47 | ||||
-rw-r--r-- | plugins/sudoers/sudoers.c | 123 | ||||
-rw-r--r-- | src/Makefile.in | 2 |
14 files changed, 258 insertions, 127 deletions
@@ -771,6 +771,10 @@ relay_dir logpath log_dir iolog_dir +sudoers_path +sudo_logsrvd_conf +sudo_conf +cvtsudoers_conf INTERCEPT_EXP FUZZ_LD FUZZ_ENGINE @@ -3626,7 +3630,10 @@ LOGSRVD_CONF='sudo_logsrvd.conf' LIBLOGSRV='$(top_builddir)/lib/logsrv/liblogsrv.la $(top_builddir)/lib/protobuf-c/libprotobuf-c.la' PPFILES='$(srcdir)/etc/sudo.pp' FUZZ_LD='$(CC)' - +cvtsudoers_conf='$(sysconfdir)/cvtsudoers.conf' +sudo_conf='$(sysconfdir)/sudo.conf' +sudo_logsrvd_conf='$(sysconfdir)/sudo_logsrvd.conf' +sudoers_path='$(sysconfdir)/sudoers' diff --git a/configure.ac b/configure.ac index fd3e033ec..a16afc9fd 100644 --- a/configure.ac +++ b/configure.ac @@ -123,7 +123,14 @@ AC_SUBST([PPFILES], ['$(srcdir)/etc/sudo.pp'])dnl AC_SUBST([FUZZ_ENGINE])dnl AC_SUBST([FUZZ_LD], ['$(CC)'])dnl AC_SUBST([INTERCEPT_EXP])dnl - +dnl +dnl Config file paths +dnl Either a single file or a colon-separated list of paths. +dnl +AC_SUBST([cvtsudoers_conf], ['$(sysconfdir)/cvtsudoers.conf'])dnl +AC_SUBST([sudo_conf], ['$(sysconfdir)/sudo.conf'])dnl +AC_SUBST([sudo_logsrvd_conf], ['$(sysconfdir)/sudo_logsrvd.conf'])dnl +AC_SUBST([sudoers_path], ['$(sysconfdir)/sudoers'])dnl dnl dnl Variables that get substituted in docs (not overridden by environment) dnl diff --git a/include/sudo_util.h b/include/sudo_util.h index e6ab20c45..bc8810e5f 100644 --- a/include/sudo_util.h +++ b/include/sudo_util.h @@ -273,12 +273,16 @@ sudo_dso_public unsigned int sudo_pow2_roundup_v1(unsigned int len); #define SUDO_PATH_GROUP_WRITABLE -5 sudo_dso_public int sudo_secure_dir_v1(const char *path, uid_t uid, gid_t gid, struct stat *sb); #define sudo_secure_dir(_a, _b, _c, _d) sudo_secure_dir_v1((_a), (_b), (_c), (_d)) +sudo_dso_public int sudo_secure_fd_v1(int fd, unsigned int type, uid_t uid, gid_t gid, struct stat *sb); +#define sudo_secure_fd(_a, _b, _c, _d, _e) sudo_secure_fd_v1((_a), (_b), (_c), (_d), (_e)) sudo_dso_public int sudo_secure_file_v1(const char *path, uid_t uid, gid_t gid, struct stat *sb); #define sudo_secure_file(_a, _b, _c, _d) sudo_secure_file_v1((_a), (_b), (_c), (_d)) sudo_dso_public int sudo_secure_open_file_v1(const char *path, uid_t uid, gid_t gid, struct stat *sb, int *error); #define sudo_secure_open_file(_a, _b, _c, _d, _e) sudo_secure_open_file_v1((_a), (_b), (_c), (_d), (_e)) sudo_dso_public int sudo_secure_open_dir_v1(const char *path, uid_t uid, gid_t gid, struct stat *sb, int *error); #define sudo_secure_open_dir(_a, _b, _c, _d, _e) sudo_secure_open_dir_v1((_a), (_b), (_c), (_d), (_e)) +sudo_dso_public int sudo_open_conf_path_v1(const char *path, char *name, size_t namesize, int (*fn)(const char *, int)); +#define sudo_open_conf_path(_a, _b, _c, _d) sudo_open_conf_path_v1((_a), (_b), (_c), (_d)) /* setgroups.c */ sudo_dso_public int sudo_setgroups_v1(int ngids, const GETGROUPS_T *gids); diff --git a/lib/util/Makefile.in b/lib/util/Makefile.in index 1b7eb11c9..71aeb5f06 100644 --- a/lib/util/Makefile.in +++ b/lib/util/Makefile.in @@ -65,7 +65,7 @@ INSTALL_OWNER = -o $(install_uid) -g $(install_gid) INSTALL_BACKUP = @INSTALL_BACKUP@ # C preprocessor defines -CPPDEFS = -D_PATH_SUDO_CONF=\"$(sysconfdir)/sudo.conf\" +CPPDEFS = -D_PATH_SUDO_CONF=\"@sudo_conf@\" # C preprocessor flags CPPFLAGS = -I$(incdir) -I$(top_builddir) -I. -I$(srcdir) $(CPPDEFS) \ diff --git a/lib/util/secure_path.c b/lib/util/secure_path.c index 89d21deee..31df507dc 100644 --- a/lib/util/secure_path.c +++ b/lib/util/secure_path.c @@ -24,6 +24,7 @@ #include <config.h> #include <sys/stat.h> +#include <errno.h> #include <fcntl.h> #include <string.h> #include <unistd.h> @@ -95,6 +96,21 @@ sudo_secure_dir_v1(const char *path, uid_t uid, gid_t gid, struct stat *sb) } /* + * Verify that fd matches type and not writable by other users. + */ +int +sudo_secure_fd_v1(int fd, unsigned int type, uid_t uid, gid_t gid, + struct stat *sb) +{ + int ret = SUDO_PATH_MISSING; + debug_decl(sudo_secure_fd, SUDO_DEBUG_UTIL); + + if (fd != -1 && fstat(fd, sb) == 0) + ret = sudo_check_secure(sb, type, uid, gid); + debug_return_int(ret); +} + +/* * Open path read-only as long as it is not writable by other users. * Returns an open file descriptor on success, else -1. * Sets error to SUDO_PATH_SECURE on success, and a value < 0 on failure. @@ -143,3 +159,45 @@ sudo_secure_open_dir_v1(const char *path, uid_t uid, gid_t gid, { return sudo_secure_open(path, S_IFDIR, uid, gid, sb, error); } + +/* + * Open the first file found in a colon-separated list of paths. + * Subsequent files in the path are only attempted if the + * previous file does not exist. Errors other than ENOENT are + * considered fatal and will stop processing the path. + * Sets name based on the last file it tried to open, even on error. + */ +int +sudo_open_conf_path_v1(const char *path, char *name, size_t namesize, + int (*fn)(const char *, int)) +{ + const char *cp, *ep, *path_end; + int fd = -1; + debug_decl(sudo_open_conf_path, SUDO_DEBUG_UTIL); + + path_end = path + strlen(path); + for (cp = sudo_strsplit(path, path_end, ":", &ep); + cp != NULL; cp = sudo_strsplit(NULL, path_end, ":", &ep)) { + + const size_t len = ep - cp; + if (len >= namesize) { + /* We always set name, even on error. */ + memcpy(name, cp, namesize - 1); + name[namesize - 1] = '\0'; + errno = ENAMETOOLONG; + break; + } + memcpy(name, cp, len); + name[len] = '\0'; + + fd = fn ? + fn(name, O_RDONLY|O_NONBLOCK) : open(name, O_RDONLY|O_NONBLOCK); + if (fd != -1) { + (void)fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK); + break; + } + if (errno != ENOENT) + break; + } + debug_return_int(fd); +} diff --git a/lib/util/sudo_conf.c b/lib/util/sudo_conf.c index 9c5612098..f1026f85e 100644 --- a/lib/util/sudo_conf.c +++ b/lib/util/sudo_conf.c @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: ISC * - * Copyright (c) 2009-2021 Todd C. Miller <Todd.Miller@sudo.ws> + * Copyright (c) 2009-2023 Todd C. Miller <Todd.Miller@sudo.ws> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -629,12 +629,13 @@ sudo_conf_init(int conf_types) * Read in /etc/sudo.conf and populates sudo_conf_data. */ int -sudo_conf_read_v1(const char *conf_file, int conf_types) +sudo_conf_read_v1(const char *path, int conf_types) { FILE *fp = NULL; - int fd, ret = false; + int fd = -1, ret = false; char *prev_locale, *line = NULL; unsigned int conf_lineno = 0; + char conf_file[PATH_MAX]; size_t linesize = 0; debug_decl(sudo_conf_read, SUDO_DEBUG_UTIL); @@ -651,57 +652,62 @@ sudo_conf_read_v1(const char *conf_file, int conf_types) if (prev_locale[0] != 'C' || prev_locale[1] != '\0') setlocale(LC_ALL, "C"); + if (path != NULL) { + /* Caller specified a single file, which must exist. */ + if (strlcpy(conf_file, path, sizeof(conf_file)) >= sizeof(conf_file)) { + errno = ENAMETOOLONG; + sudo_warn("%s", path); + goto done; + } + fd = open(conf_file, O_RDONLY); + if (fd == -1) { + sudo_warn(U_("unable to open %s"), conf_file); + goto done; + } + } else { #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - if (conf_file == NULL) { struct stat sb; int error; - conf_file = _PATH_SUDO_CONF; - fd = sudo_secure_open_file(conf_file, ROOT_UID, -1, &sb, &error); - if (fd == -1) { - switch (error) { - case SUDO_PATH_MISSING: - /* Root should always be able to read sudo.conf. */ - if (errno != ENOENT && geteuid() == ROOT_UID) - sudo_warn(U_("unable to open %s"), conf_file); - break; - case SUDO_PATH_BAD_TYPE: - sudo_warnx(U_("%s is not a regular file"), conf_file); - break; - case SUDO_PATH_WRONG_OWNER: - sudo_warnx(U_("%s is owned by uid %u, should be %u"), - conf_file, (unsigned int) sb.st_uid, ROOT_UID); - break; - case SUDO_PATH_WORLD_WRITABLE: - sudo_warnx(U_("%s is world writable"), conf_file); - break; - case SUDO_PATH_GROUP_WRITABLE: - sudo_warnx(U_("%s is group writable"), conf_file); - break; - default: - sudo_warnx("%s: internal error, unexpected error %d", - __func__, error); - break; - } + /* _PATH_SUDO_CONF is a colon-separated list of path. */ + fd = sudo_open_conf_path(_PATH_SUDO_CONF, conf_file, + sizeof(conf_file), NULL); + error = sudo_secure_fd(fd, S_IFREG, ROOT_UID, -1, &sb); + switch (error) { + case SUDO_PATH_SECURE: + /* OK! */ + break; + case SUDO_PATH_MISSING: + /* Root should always be able to read sudo.conf. */ + if (errno != ENOENT && geteuid() == ROOT_UID) + sudo_warn(U_("unable to open %s"), conf_file); + goto done; + case SUDO_PATH_BAD_TYPE: + sudo_warnx(U_("%s is not a regular file"), conf_file); + goto done; + case SUDO_PATH_WRONG_OWNER: + sudo_warnx(U_("%s is owned by uid %u, should be %u"), + conf_file, (unsigned int) sb.st_uid, ROOT_UID); + goto done; + case SUDO_PATH_WORLD_WRITABLE: + sudo_warnx(U_("%s is world writable"), conf_file); + goto done; + case SUDO_PATH_GROUP_WRITABLE: + sudo_warnx(U_("%s is group writable"), conf_file); + goto done; + default: + sudo_warnx("%s: internal error, unexpected error %d", + __func__, error); goto done; } - } else #else - if (conf_file == NULL) - conf_file = _PATH_SUDO_CONF; + /* No default sudo.conf when fuzzing. */ + goto done; #endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ - { - fd = open(conf_file, O_RDONLY); - if (fd == -1) { - sudo_warn(U_("unable to open %s"), conf_file); - goto done; - } } if ((fp = fdopen(fd, "r")) == NULL) { - if (errno != ENOENT && geteuid() == ROOT_UID) - sudo_warn(U_("unable to open %s"), conf_file); - close(fd); + sudo_warn(U_("unable to open %s"), conf_file); goto done; } @@ -749,6 +755,8 @@ sudo_conf_read_v1(const char *conf_file, int conf_types) done: if (fp != NULL) fclose(fp); + else if (fd != -1) + close(fd); free(line); /* Restore locale if needed. */ diff --git a/lib/util/util.exp.in b/lib/util/util.exp.in index 47e776c0d..ced75fb33 100644 --- a/lib/util/util.exp.in +++ b/lib/util/util.exp.in @@ -120,6 +120,7 @@ sudo_mmap_free_v1 sudo_mmap_protect_v1 sudo_mmap_strdup_v1 sudo_new_key_val_v1 +sudo_open_conf_path_v1 sudo_open_parent_dir_v1 sudo_parse_gids_v1 sudo_parseln_v1 @@ -131,6 +132,7 @@ sudo_rcstr_delref sudo_rcstr_dup sudo_regex_compile_v1 sudo_secure_dir_v1 +sudo_secure_fd_v1 sudo_secure_file_v1 sudo_secure_open_dir_v1 sudo_secure_open_file_v1 diff --git a/logsrvd/Makefile.in b/logsrvd/Makefile.in index 2a1f0d1a5..375c685b8 100644 --- a/logsrvd/Makefile.in +++ b/logsrvd/Makefile.in @@ -52,7 +52,7 @@ LT_LIBS = $(top_builddir)/lib/iolog/libsudo_iolog.la \ LIBS = $(LT_LIBS) @LIBTLS@ # C preprocessor defines -CPPDEFS = -D_PATH_SUDO_LOGSRVD_CONF=\"$(sysconfdir)/sudo_logsrvd.conf\" \ +CPPDEFS = -D_PATH_SUDO_LOGSRVD_CONF=\"@sudo_logsrvd_conf@\" \ -DLOCALEDIR=\"$(localedir)\" # C preprocessor flags diff --git a/logsrvd/logsrvd.c b/logsrvd/logsrvd.c index 891ce8115..25c94fc3d 100644 --- a/logsrvd/logsrvd.c +++ b/logsrvd/logsrvd.c @@ -85,7 +85,7 @@ TAILQ_HEAD(connection_list, connection_closure); static struct connection_list connections = TAILQ_HEAD_INITIALIZER(connections); static struct listener_list listeners = TAILQ_HEAD_INITIALIZER(listeners); static const char server_id[] = "Sudo Audit Server " PACKAGE_VERSION; -static const char *conf_file = _PATH_SUDO_LOGSRVD_CONF; +static const char *conf_file = NULL; /* Event loop callbacks. */ static void client_msg_cb(int fd, int what, void *v); @@ -1671,7 +1671,8 @@ server_dump_stats(void) debug_decl(server_dump_stats, SUDO_DEBUG_UTIL); sudo_debug_printf(SUDO_DEBUG_INFO, "%s", server_id); - sudo_debug_printf(SUDO_DEBUG_INFO, "configuration file: %s", conf_file); + sudo_debug_printf(SUDO_DEBUG_INFO, "configuration file: %s", + conf_file ? conf_file : _PATH_SUDO_LOGSRVD_CONF); sudo_debug_printf(SUDO_DEBUG_INFO, "listen addresses:"); n = 0; diff --git a/logsrvd/logsrvd_conf.c b/logsrvd/logsrvd_conf.c index 39bfa873b..99d092410 100644 --- a/logsrvd/logsrvd_conf.c +++ b/logsrvd/logsrvd_conf.c @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: ISC * - * Copyright (c) 2019-2022 Todd C. Miller <Todd.Miller@sudo.ws> + * Copyright (c) 2019-2023 Todd C. Miller <Todd.Miller@sudo.ws> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -1851,25 +1851,39 @@ logsrvd_conf_apply(struct logsrvd_config *config) /* * Read .ini style logsrvd.conf file. + * If path is NULL, use _PATH_SUDO_LOGSRVD_CONF. * Note that we use '#' not ';' for the comment character. */ bool logsrvd_conf_read(const char *path) { struct logsrvd_config *config; + char conf_file[PATH_MAX]; bool ret = false; FILE *fp = NULL; + int fd = -1; debug_decl(logsrvd_conf_read, SUDO_DEBUG_UTIL); config = logsrvd_conf_alloc(); - if ((fp = fopen(path, "r")) == NULL) { - if (errno != ENOENT) { - sudo_warn("%s", path); + if (path != NULL) { + if (strlcpy(conf_file, path, sizeof(conf_file)) >= sizeof(conf_file)) + errno = ENAMETOOLONG; + else + fd = open(conf_file, O_RDONLY); + } else { + fd = sudo_open_conf_path(_PATH_SUDO_LOGSRVD_CONF, conf_file, + sizeof(conf_file), NULL); + } + if (fd != -1) + fp = fdopen(fd, "r"); + if (fp == NULL) { + if (path != NULL || errno != ENOENT) { + sudo_warn("%s", conf_file); goto done; } } else { - if (!logsrvd_conf_parse(config, fp, path)) + if (!logsrvd_conf_parse(config, fp, conf_file)) goto done; } diff --git a/plugins/sudoers/Makefile.in b/plugins/sudoers/Makefile.in index 5e2fef27a..35788154f 100644 --- a/plugins/sudoers/Makefile.in +++ b/plugins/sudoers/Makefile.in @@ -72,8 +72,8 @@ TESTSUDOERS_LIBS = $(NET_LIBS) # C preprocessor defines CPPDEFS = -DLIBDIR=\"$(libdir)\" -DLOCALEDIR=\"$(localedir)\" \ - -D_PATH_SUDOERS=\"$(sysconfdir)/sudoers\" \ - -D_PATH_CVTSUDOERS_CONF=\"$(sysconfdir)/cvtsudoers.conf\" \ + -D_PATH_SUDOERS=\"@sudoers_path@\" \ + -D_PATH_CVTSUDOERS_CONF=\"@cvtsudoers_conf@\" \ -DSUDOERS_UID=$(sudoers_uid) -DSUDOERS_GID=$(sudoers_gid) \ -DSUDOERS_MODE=$(sudoers_mode) diff --git a/plugins/sudoers/cvtsudoers.c b/plugins/sudoers/cvtsudoers.c index fa52fa280..d45803aea 100644 --- a/plugins/sudoers/cvtsudoers.c +++ b/plugins/sudoers/cvtsudoers.c @@ -35,6 +35,7 @@ #endif /* HAVE_STRINGS_H */ #include <ctype.h> #include <errno.h> +#include <fcntl.h> #include <pwd.h> #include <unistd.h> #ifdef HAVE_GETOPT_LONG @@ -112,7 +113,7 @@ main(int argc, char *argv[]) enum sudoers_formats input_format = format_sudoers; const char *input_file = "-"; const char *output_file = "-"; - const char *conf_file = _PATH_CVTSUDOERS_CONF; + const char *conf_file = NULL; const char *grfile = NULL, *pwfile = NULL; const char *cp, *errstr; int ch, exitcode = EXIT_FAILURE; @@ -548,36 +549,56 @@ cvtsudoers_parse_keyword(const char *conf_file, const char *keyword, } static struct cvtsudoers_config * -cvtsudoers_conf_read(const char *conf_file) +cvtsudoers_conf_read(const char *path) { - char *line = NULL; + char conf_file[PATH_MAX], *line = NULL; size_t linesize = 0; - FILE *fp; + FILE *fp = NULL; + int fd = -1; debug_decl(cvtsudoers_conf_read, SUDOERS_DEBUG_UTIL); - if ((fp = fopen(conf_file, "r")) == NULL) + if (path != NULL) { + /* Empty string means use the defaults. */ + if (*path == '\0') + debug_return_ptr(&cvtsudoers_config); + if (strlcpy(conf_file, path, sizeof(conf_file)) >= sizeof(conf_file)) + errno = ENAMETOOLONG; + else + fd = open(conf_file, O_RDONLY); + } else { + fd = sudo_open_conf_path(_PATH_CVTSUDOERS_CONF, conf_file, + sizeof(conf_file), NULL); + } + if (fd != -1) + fp = fdopen(fd, "r"); + if (fp == NULL) { + if (path != NULL || errno != ENOENT) + sudo_warn("%s", conf_file); debug_return_ptr(&cvtsudoers_config); + } while (sudo_parseln(&line, &linesize, NULL, fp, 0) != -1) { - char *cp, *keyword, *value; + char *keyword, *value; + size_t len; if (*line == '\0') continue; /* skip empty line */ /* Parse keyword = value */ keyword = line; - if ((cp = strchr(line, '=')) == NULL) + if ((value = strchr(line, '=')) == NULL || value == line) continue; - value = cp-- + 1; + len = value - line; - /* Trim whitespace after keyword. */ - while (cp != line && isblank((unsigned char)cp[-1])) - cp--; - *cp = '\0'; + /* Trim whitespace after keyword and NUL-terminate. */ + while (len > 0 && isblank((unsigned char)line[len - 1])) + len--; + line[len] = '\0'; /* Trim whitespace before value. */ - while (isblank((unsigned char)*value)) + do { value++; + } while (isblank((unsigned char)*value)); /* Look up keyword in config tables */ if (!cvtsudoers_parse_keyword(conf_file, keyword, value, cvtsudoers_conf_vars)) diff --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c index 05f46a5a5..103080e47 100644 --- a/plugins/sudoers/sudoers.c +++ b/plugins/sudoers/sudoers.c @@ -1257,91 +1257,100 @@ set_cmnd(void) debug_return_int(ret); } +static int +open_file(const char *path, int flags) +{ + int fd; + debug_decl(open_file, SUDOERS_DEBUG_PLUGIN); + + if (!set_perms(PERM_SUDOERS)) + debug_return_int(-1); + + fd = open(path, flags); + if (fd == -1 && errno == EACCES && geteuid() != ROOT_UID) { + /* + * If we tried to open sudoers as non-root but got EACCES, + * try again as root. + */ + int serrno = errno; + if (restore_perms() && set_perms(PERM_ROOT)) + fd = open(path, flags); + errno = serrno; + } + if (!restore_perms()) { + /* unable to change back to root */ + if (fd != -1) { + close(fd); + fd = -1; + } + } + + debug_return_int(fd); +} + /* * Open sudoers file and check mode/owner/type. * Returns a handle to the sudoers file or NULL on error. */ FILE * -open_sudoers(const char *file, bool doedit, bool *keepopen) +open_sudoers(const char *path, bool doedit, bool *keepopen) { + char fname[PATH_MAX]; FILE *fp = NULL; struct stat sb; int error, fd; debug_decl(open_sudoers, SUDOERS_DEBUG_PLUGIN); - if (!set_perms(PERM_SUDOERS)) - debug_return_ptr(NULL); - -again: - fd = sudo_secure_open_file(file, sudoers_uid, sudoers_gid, &sb, &error); - if (fd != -1) { + fd = sudo_open_conf_path(path, fname, sizeof(fname), open_file); + error = sudo_secure_fd(fd, S_IFREG, sudoers_uid, sudoers_gid, &sb); + switch (error) { + case SUDO_PATH_SECURE: /* * Make sure we can read the file so we can present the * user with a reasonable error message (unlike the lexer). */ if ((fp = fdopen(fd, "r")) == NULL) { - log_warning(SLOG_PARSE_ERROR, N_("unable to open %s"), file); + log_warning(SLOG_PARSE_ERROR, N_("unable to open %s"), fname); close(fd); } else { if (sb.st_size != 0 && fgetc(fp) == EOF) { - log_warning(SLOG_PARSE_ERROR, N_("unable to read %s"), file); + log_warning(SLOG_PARSE_ERROR, N_("unable to read %s"), fname); fclose(fp); fp = NULL; + fd = -1; } else { /* Rewind fp and set close on exec flag. */ rewind(fp); - (void) fcntl(fileno(fp), F_SETFD, 1); + (void)fcntl(fileno(fp), F_SETFD, 1); } } - } else { - switch (error) { - case SUDO_PATH_MISSING: - /* - * If we tried to open sudoers as non-root but got EACCES, - * try again as root. - */ - if (errno == EACCES && geteuid() != ROOT_UID) { - int serrno = errno; - if (restore_perms()) { - if (!set_perms(PERM_ROOT)) - debug_return_ptr(NULL); - goto again; - } - errno = serrno; - } - log_warning(SLOG_PARSE_ERROR, N_("unable to open %s"), file); - break; - case SUDO_PATH_BAD_TYPE: - log_warningx(SLOG_PARSE_ERROR, - N_("%s is not a regular file"), file); - break; - case SUDO_PATH_WRONG_OWNER: - log_warningx(SLOG_PARSE_ERROR, - N_("%s is owned by uid %u, should be %u"), file, - (unsigned int) sb.st_uid, (unsigned int) sudoers_uid); - break; - case SUDO_PATH_WORLD_WRITABLE: - log_warningx(SLOG_PARSE_ERROR, N_("%s is world writable"), file); - break; - case SUDO_PATH_GROUP_WRITABLE: - log_warningx(SLOG_PARSE_ERROR, - N_("%s is owned by gid %u, should be %u"), file, - (unsigned int) sb.st_gid, (unsigned int) sudoers_gid); - break; - default: - sudo_warnx("%s: internal error, unexpected error %d", - __func__, error); - break; - } + break; + case SUDO_PATH_MISSING: + log_warning(SLOG_PARSE_ERROR, N_("unable to open %s"), fname); + break; + case SUDO_PATH_BAD_TYPE: + log_warningx(SLOG_PARSE_ERROR, N_("%s is not a regular file"), fname); + break; + case SUDO_PATH_WRONG_OWNER: + log_warningx(SLOG_PARSE_ERROR, + N_("%s is owned by uid %u, should be %u"), fname, + (unsigned int)sb.st_uid, (unsigned int)sudoers_uid); + break; + case SUDO_PATH_WORLD_WRITABLE: + log_warningx(SLOG_PARSE_ERROR, N_("%s is world writable"), fname); + break; + case SUDO_PATH_GROUP_WRITABLE: + log_warningx(SLOG_PARSE_ERROR, + N_("%s is owned by gid %u, should be %u"), fname, + (unsigned int)sb.st_gid, (unsigned int)sudoers_gid); + break; + default: + sudo_warnx("%s: internal error, unexpected error %d", __func__, error); + break; } - if (!restore_perms()) { - /* unable to change back to root */ - if (fp != NULL) { - fclose(fp); - fp = NULL; - } - } + if (fp == NULL && fd != -1) + close(fd); debug_return_ptr(fp); } diff --git a/src/Makefile.in b/src/Makefile.in index 07d0c8698..1d7dc5d67 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -51,7 +51,7 @@ LT_LIBS = $(LIBUTIL) $(LIBPROTOBUF_C) LIBS = @LIBS@ @SUDO_LIBS@ @GETGROUPS_LIB@ @NET_LIBS@ $(LT_LIBS) # C preprocessor defines -CPPDEFS = -D_PATH_SUDO_CONF=\"$(sysconfdir)/sudo.conf\" \ +CPPDEFS = -D_PATH_SUDO_CONF=\"@sudo_conf@\" \ -DLOCALEDIR=\"$(localedir)\" # C preprocessor flags |