summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd C. Miller <Todd.Miller@sudo.ws>2023-05-02 10:37:38 -0600
committerTodd C. Miller <Todd.Miller@sudo.ws>2023-05-02 10:37:38 -0600
commitd4c33b71898c9f4b122815c6826ad5cc8a69ff60 (patch)
treeffcee8f87a7ac8c5733b48925f19c6d60984382b
parentb3a0d009b185e599622d4722010ae0278eeee5fc (diff)
downloadsudo-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-xconfigure9
-rw-r--r--configure.ac9
-rw-r--r--include/sudo_util.h4
-rw-r--r--lib/util/Makefile.in2
-rw-r--r--lib/util/secure_path.c58
-rw-r--r--lib/util/sudo_conf.c94
-rw-r--r--lib/util/util.exp.in2
-rw-r--r--logsrvd/Makefile.in2
-rw-r--r--logsrvd/logsrvd.c5
-rw-r--r--logsrvd/logsrvd_conf.c24
-rw-r--r--plugins/sudoers/Makefile.in4
-rw-r--r--plugins/sudoers/cvtsudoers.c47
-rw-r--r--plugins/sudoers/sudoers.c123
-rw-r--r--src/Makefile.in2
14 files changed, 258 insertions, 127 deletions
diff --git a/configure b/configure
index 99d198130..7d997177d 100755
--- a/configure
+++ b/configure
@@ -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