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.
This commit is contained in:
9
configure
vendored
9
configure
vendored
@@ -771,6 +771,10 @@ relay_dir
|
|||||||
logpath
|
logpath
|
||||||
log_dir
|
log_dir
|
||||||
iolog_dir
|
iolog_dir
|
||||||
|
sudoers_path
|
||||||
|
sudo_logsrvd_conf
|
||||||
|
sudo_conf
|
||||||
|
cvtsudoers_conf
|
||||||
INTERCEPT_EXP
|
INTERCEPT_EXP
|
||||||
FUZZ_LD
|
FUZZ_LD
|
||||||
FUZZ_ENGINE
|
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'
|
LIBLOGSRV='$(top_builddir)/lib/logsrv/liblogsrv.la $(top_builddir)/lib/protobuf-c/libprotobuf-c.la'
|
||||||
PPFILES='$(srcdir)/etc/sudo.pp'
|
PPFILES='$(srcdir)/etc/sudo.pp'
|
||||||
FUZZ_LD='$(CC)'
|
FUZZ_LD='$(CC)'
|
||||||
|
cvtsudoers_conf='$(sysconfdir)/cvtsudoers.conf'
|
||||||
|
sudo_conf='$(sysconfdir)/sudo.conf'
|
||||||
|
sudo_logsrvd_conf='$(sysconfdir)/sudo_logsrvd.conf'
|
||||||
|
sudoers_path='$(sysconfdir)/sudoers'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -123,7 +123,14 @@ AC_SUBST([PPFILES], ['$(srcdir)/etc/sudo.pp'])dnl
|
|||||||
AC_SUBST([FUZZ_ENGINE])dnl
|
AC_SUBST([FUZZ_ENGINE])dnl
|
||||||
AC_SUBST([FUZZ_LD], ['$(CC)'])dnl
|
AC_SUBST([FUZZ_LD], ['$(CC)'])dnl
|
||||||
AC_SUBST([INTERCEPT_EXP])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
|
||||||
dnl Variables that get substituted in docs (not overridden by environment)
|
dnl Variables that get substituted in docs (not overridden by environment)
|
||||||
dnl
|
dnl
|
||||||
|
@@ -273,12 +273,16 @@ sudo_dso_public unsigned int sudo_pow2_roundup_v1(unsigned int len);
|
|||||||
#define SUDO_PATH_GROUP_WRITABLE -5
|
#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);
|
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))
|
#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);
|
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))
|
#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);
|
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))
|
#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);
|
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))
|
#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 */
|
/* setgroups.c */
|
||||||
sudo_dso_public int sudo_setgroups_v1(int ngids, const GETGROUPS_T *gids);
|
sudo_dso_public int sudo_setgroups_v1(int ngids, const GETGROUPS_T *gids);
|
||||||
|
@@ -65,7 +65,7 @@ INSTALL_OWNER = -o $(install_uid) -g $(install_gid)
|
|||||||
INSTALL_BACKUP = @INSTALL_BACKUP@
|
INSTALL_BACKUP = @INSTALL_BACKUP@
|
||||||
|
|
||||||
# C preprocessor defines
|
# C preprocessor defines
|
||||||
CPPDEFS = -D_PATH_SUDO_CONF=\"$(sysconfdir)/sudo.conf\"
|
CPPDEFS = -D_PATH_SUDO_CONF=\"@sudo_conf@\"
|
||||||
|
|
||||||
# C preprocessor flags
|
# C preprocessor flags
|
||||||
CPPFLAGS = -I$(incdir) -I$(top_builddir) -I. -I$(srcdir) $(CPPDEFS) \
|
CPPFLAGS = -I$(incdir) -I$(top_builddir) -I. -I$(srcdir) $(CPPDEFS) \
|
||||||
|
@@ -24,6 +24,7 @@
|
|||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -94,6 +95,21 @@ sudo_secure_dir_v1(const char *path, uid_t uid, gid_t gid, struct stat *sb)
|
|||||||
return sudo_secure_path(path, S_IFDIR, uid, gid, sb);
|
return sudo_secure_path(path, S_IFDIR, uid, gid, 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.
|
* Open path read-only as long as it is not writable by other users.
|
||||||
* Returns an open file descriptor on success, else -1.
|
* Returns an open file descriptor on success, else -1.
|
||||||
@@ -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);
|
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);
|
||||||
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: ISC
|
* 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
|
* 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
|
||||||
@@ -629,12 +629,13 @@ sudo_conf_init(int conf_types)
|
|||||||
* Read in /etc/sudo.conf and populates sudo_conf_data.
|
* Read in /etc/sudo.conf and populates sudo_conf_data.
|
||||||
*/
|
*/
|
||||||
int
|
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;
|
FILE *fp = NULL;
|
||||||
int fd, ret = false;
|
int fd = -1, ret = false;
|
||||||
char *prev_locale, *line = NULL;
|
char *prev_locale, *line = NULL;
|
||||||
unsigned int conf_lineno = 0;
|
unsigned int conf_lineno = 0;
|
||||||
|
char conf_file[PATH_MAX];
|
||||||
size_t linesize = 0;
|
size_t linesize = 0;
|
||||||
debug_decl(sudo_conf_read, SUDO_DEBUG_UTIL);
|
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')
|
if (prev_locale[0] != 'C' || prev_locale[1] != '\0')
|
||||||
setlocale(LC_ALL, "C");
|
setlocale(LC_ALL, "C");
|
||||||
|
|
||||||
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
if (path != NULL) {
|
||||||
if (conf_file == NULL) {
|
/* Caller specified a single file, which must exist. */
|
||||||
struct stat sb;
|
if (strlcpy(conf_file, path, sizeof(conf_file)) >= sizeof(conf_file)) {
|
||||||
int error;
|
errno = ENAMETOOLONG;
|
||||||
|
sudo_warn("%s", path);
|
||||||
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;
|
|
||||||
}
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
} else
|
|
||||||
#else
|
|
||||||
if (conf_file == NULL)
|
|
||||||
conf_file = _PATH_SUDO_CONF;
|
|
||||||
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
|
|
||||||
{
|
|
||||||
fd = open(conf_file, O_RDONLY);
|
fd = open(conf_file, O_RDONLY);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
sudo_warn(U_("unable to open %s"), conf_file);
|
sudo_warn(U_("unable to open %s"), conf_file);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||||
|
struct stat sb;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/* _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
|
||||||
|
/* No default sudo.conf when fuzzing. */
|
||||||
|
goto done;
|
||||||
|
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((fp = fdopen(fd, "r")) == NULL) {
|
if ((fp = fdopen(fd, "r")) == NULL) {
|
||||||
if (errno != ENOENT && geteuid() == ROOT_UID)
|
sudo_warn(U_("unable to open %s"), conf_file);
|
||||||
sudo_warn(U_("unable to open %s"), conf_file);
|
|
||||||
close(fd);
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -749,6 +755,8 @@ sudo_conf_read_v1(const char *conf_file, int conf_types)
|
|||||||
done:
|
done:
|
||||||
if (fp != NULL)
|
if (fp != NULL)
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
else if (fd != -1)
|
||||||
|
close(fd);
|
||||||
free(line);
|
free(line);
|
||||||
|
|
||||||
/* Restore locale if needed. */
|
/* Restore locale if needed. */
|
||||||
|
@@ -120,6 +120,7 @@ sudo_mmap_free_v1
|
|||||||
sudo_mmap_protect_v1
|
sudo_mmap_protect_v1
|
||||||
sudo_mmap_strdup_v1
|
sudo_mmap_strdup_v1
|
||||||
sudo_new_key_val_v1
|
sudo_new_key_val_v1
|
||||||
|
sudo_open_conf_path_v1
|
||||||
sudo_open_parent_dir_v1
|
sudo_open_parent_dir_v1
|
||||||
sudo_parse_gids_v1
|
sudo_parse_gids_v1
|
||||||
sudo_parseln_v1
|
sudo_parseln_v1
|
||||||
@@ -131,6 +132,7 @@ sudo_rcstr_delref
|
|||||||
sudo_rcstr_dup
|
sudo_rcstr_dup
|
||||||
sudo_regex_compile_v1
|
sudo_regex_compile_v1
|
||||||
sudo_secure_dir_v1
|
sudo_secure_dir_v1
|
||||||
|
sudo_secure_fd_v1
|
||||||
sudo_secure_file_v1
|
sudo_secure_file_v1
|
||||||
sudo_secure_open_dir_v1
|
sudo_secure_open_dir_v1
|
||||||
sudo_secure_open_file_v1
|
sudo_secure_open_file_v1
|
||||||
|
@@ -52,7 +52,7 @@ LT_LIBS = $(top_builddir)/lib/iolog/libsudo_iolog.la \
|
|||||||
LIBS = $(LT_LIBS) @LIBTLS@
|
LIBS = $(LT_LIBS) @LIBTLS@
|
||||||
|
|
||||||
# C preprocessor defines
|
# C preprocessor defines
|
||||||
CPPDEFS = -D_PATH_SUDO_LOGSRVD_CONF=\"$(sysconfdir)/sudo_logsrvd.conf\" \
|
CPPDEFS = -D_PATH_SUDO_LOGSRVD_CONF=\"@sudo_logsrvd_conf@\" \
|
||||||
-DLOCALEDIR=\"$(localedir)\"
|
-DLOCALEDIR=\"$(localedir)\"
|
||||||
|
|
||||||
# C preprocessor flags
|
# C preprocessor flags
|
||||||
|
@@ -85,7 +85,7 @@ TAILQ_HEAD(connection_list, connection_closure);
|
|||||||
static struct connection_list connections = TAILQ_HEAD_INITIALIZER(connections);
|
static struct connection_list connections = TAILQ_HEAD_INITIALIZER(connections);
|
||||||
static struct listener_list listeners = TAILQ_HEAD_INITIALIZER(listeners);
|
static struct listener_list listeners = TAILQ_HEAD_INITIALIZER(listeners);
|
||||||
static const char server_id[] = "Sudo Audit Server " PACKAGE_VERSION;
|
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. */
|
/* Event loop callbacks. */
|
||||||
static void client_msg_cb(int fd, int what, void *v);
|
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);
|
debug_decl(server_dump_stats, SUDO_DEBUG_UTIL);
|
||||||
|
|
||||||
sudo_debug_printf(SUDO_DEBUG_INFO, "%s", server_id);
|
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:");
|
sudo_debug_printf(SUDO_DEBUG_INFO, "listen addresses:");
|
||||||
n = 0;
|
n = 0;
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: ISC
|
* 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
|
* 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
|
||||||
@@ -1851,25 +1851,39 @@ logsrvd_conf_apply(struct logsrvd_config *config)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Read .ini style logsrvd.conf file.
|
* Read .ini style logsrvd.conf file.
|
||||||
|
* If path is NULL, use _PATH_SUDO_LOGSRVD_CONF.
|
||||||
* Note that we use '#' not ';' for the comment character.
|
* Note that we use '#' not ';' for the comment character.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
logsrvd_conf_read(const char *path)
|
logsrvd_conf_read(const char *path)
|
||||||
{
|
{
|
||||||
struct logsrvd_config *config;
|
struct logsrvd_config *config;
|
||||||
|
char conf_file[PATH_MAX];
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
FILE *fp = NULL;
|
FILE *fp = NULL;
|
||||||
|
int fd = -1;
|
||||||
debug_decl(logsrvd_conf_read, SUDO_DEBUG_UTIL);
|
debug_decl(logsrvd_conf_read, SUDO_DEBUG_UTIL);
|
||||||
|
|
||||||
config = logsrvd_conf_alloc();
|
config = logsrvd_conf_alloc();
|
||||||
|
|
||||||
if ((fp = fopen(path, "r")) == NULL) {
|
if (path != NULL) {
|
||||||
if (errno != ENOENT) {
|
if (strlcpy(conf_file, path, sizeof(conf_file)) >= sizeof(conf_file))
|
||||||
sudo_warn("%s", path);
|
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;
|
goto done;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!logsrvd_conf_parse(config, fp, path))
|
if (!logsrvd_conf_parse(config, fp, conf_file))
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -72,8 +72,8 @@ TESTSUDOERS_LIBS = $(NET_LIBS)
|
|||||||
|
|
||||||
# C preprocessor defines
|
# C preprocessor defines
|
||||||
CPPDEFS = -DLIBDIR=\"$(libdir)\" -DLOCALEDIR=\"$(localedir)\" \
|
CPPDEFS = -DLIBDIR=\"$(libdir)\" -DLOCALEDIR=\"$(localedir)\" \
|
||||||
-D_PATH_SUDOERS=\"$(sysconfdir)/sudoers\" \
|
-D_PATH_SUDOERS=\"@sudoers_path@\" \
|
||||||
-D_PATH_CVTSUDOERS_CONF=\"$(sysconfdir)/cvtsudoers.conf\" \
|
-D_PATH_CVTSUDOERS_CONF=\"@cvtsudoers_conf@\" \
|
||||||
-DSUDOERS_UID=$(sudoers_uid) -DSUDOERS_GID=$(sudoers_gid) \
|
-DSUDOERS_UID=$(sudoers_uid) -DSUDOERS_GID=$(sudoers_gid) \
|
||||||
-DSUDOERS_MODE=$(sudoers_mode)
|
-DSUDOERS_MODE=$(sudoers_mode)
|
||||||
|
|
||||||
|
@@ -35,6 +35,7 @@
|
|||||||
#endif /* HAVE_STRINGS_H */
|
#endif /* HAVE_STRINGS_H */
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#ifdef HAVE_GETOPT_LONG
|
#ifdef HAVE_GETOPT_LONG
|
||||||
@@ -112,7 +113,7 @@ main(int argc, char *argv[])
|
|||||||
enum sudoers_formats input_format = format_sudoers;
|
enum sudoers_formats input_format = format_sudoers;
|
||||||
const char *input_file = "-";
|
const char *input_file = "-";
|
||||||
const char *output_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 *grfile = NULL, *pwfile = NULL;
|
||||||
const char *cp, *errstr;
|
const char *cp, *errstr;
|
||||||
int ch, exitcode = EXIT_FAILURE;
|
int ch, exitcode = EXIT_FAILURE;
|
||||||
@@ -548,36 +549,56 @@ cvtsudoers_parse_keyword(const char *conf_file, const char *keyword,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct cvtsudoers_config *
|
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;
|
size_t linesize = 0;
|
||||||
FILE *fp;
|
FILE *fp = NULL;
|
||||||
|
int fd = -1;
|
||||||
debug_decl(cvtsudoers_conf_read, SUDOERS_DEBUG_UTIL);
|
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);
|
debug_return_ptr(&cvtsudoers_config);
|
||||||
|
}
|
||||||
|
|
||||||
while (sudo_parseln(&line, &linesize, NULL, fp, 0) != -1) {
|
while (sudo_parseln(&line, &linesize, NULL, fp, 0) != -1) {
|
||||||
char *cp, *keyword, *value;
|
char *keyword, *value;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
if (*line == '\0')
|
if (*line == '\0')
|
||||||
continue; /* skip empty line */
|
continue; /* skip empty line */
|
||||||
|
|
||||||
/* Parse keyword = value */
|
/* Parse keyword = value */
|
||||||
keyword = line;
|
keyword = line;
|
||||||
if ((cp = strchr(line, '=')) == NULL)
|
if ((value = strchr(line, '=')) == NULL || value == line)
|
||||||
continue;
|
continue;
|
||||||
value = cp-- + 1;
|
len = value - line;
|
||||||
|
|
||||||
/* Trim whitespace after keyword. */
|
/* Trim whitespace after keyword and NUL-terminate. */
|
||||||
while (cp != line && isblank((unsigned char)cp[-1]))
|
while (len > 0 && isblank((unsigned char)line[len - 1]))
|
||||||
cp--;
|
len--;
|
||||||
*cp = '\0';
|
line[len] = '\0';
|
||||||
|
|
||||||
/* Trim whitespace before value. */
|
/* Trim whitespace before value. */
|
||||||
while (isblank((unsigned char)*value))
|
do {
|
||||||
value++;
|
value++;
|
||||||
|
} while (isblank((unsigned char)*value));
|
||||||
|
|
||||||
/* Look up keyword in config tables */
|
/* Look up keyword in config tables */
|
||||||
if (!cvtsudoers_parse_keyword(conf_file, keyword, value, cvtsudoers_conf_vars))
|
if (!cvtsudoers_parse_keyword(conf_file, keyword, value, cvtsudoers_conf_vars))
|
||||||
|
@@ -1257,91 +1257,100 @@ set_cmnd(void)
|
|||||||
debug_return_int(ret);
|
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.
|
* Open sudoers file and check mode/owner/type.
|
||||||
* Returns a handle to the sudoers file or NULL on error.
|
* Returns a handle to the sudoers file or NULL on error.
|
||||||
*/
|
*/
|
||||||
FILE *
|
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;
|
FILE *fp = NULL;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
int error, fd;
|
int error, fd;
|
||||||
debug_decl(open_sudoers, SUDOERS_DEBUG_PLUGIN);
|
debug_decl(open_sudoers, SUDOERS_DEBUG_PLUGIN);
|
||||||
|
|
||||||
if (!set_perms(PERM_SUDOERS))
|
fd = sudo_open_conf_path(path, fname, sizeof(fname), open_file);
|
||||||
debug_return_ptr(NULL);
|
error = sudo_secure_fd(fd, S_IFREG, sudoers_uid, sudoers_gid, &sb);
|
||||||
|
switch (error) {
|
||||||
again:
|
case SUDO_PATH_SECURE:
|
||||||
fd = sudo_secure_open_file(file, sudoers_uid, sudoers_gid, &sb, &error);
|
|
||||||
if (fd != -1) {
|
|
||||||
/*
|
/*
|
||||||
* Make sure we can read the file so we can present the
|
* Make sure we can read the file so we can present the
|
||||||
* user with a reasonable error message (unlike the lexer).
|
* user with a reasonable error message (unlike the lexer).
|
||||||
*/
|
*/
|
||||||
if ((fp = fdopen(fd, "r")) == NULL) {
|
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);
|
close(fd);
|
||||||
} else {
|
} else {
|
||||||
if (sb.st_size != 0 && fgetc(fp) == EOF) {
|
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);
|
fclose(fp);
|
||||||
fp = NULL;
|
fp = NULL;
|
||||||
|
fd = -1;
|
||||||
} else {
|
} else {
|
||||||
/* Rewind fp and set close on exec flag. */
|
/* Rewind fp and set close on exec flag. */
|
||||||
rewind(fp);
|
rewind(fp);
|
||||||
(void) fcntl(fileno(fp), F_SETFD, 1);
|
(void)fcntl(fileno(fp), F_SETFD, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
break;
|
||||||
switch (error) {
|
case SUDO_PATH_MISSING:
|
||||||
case SUDO_PATH_MISSING:
|
log_warning(SLOG_PARSE_ERROR, N_("unable to open %s"), fname);
|
||||||
/*
|
break;
|
||||||
* If we tried to open sudoers as non-root but got EACCES,
|
case SUDO_PATH_BAD_TYPE:
|
||||||
* try again as root.
|
log_warningx(SLOG_PARSE_ERROR, N_("%s is not a regular file"), fname);
|
||||||
*/
|
break;
|
||||||
if (errno == EACCES && geteuid() != ROOT_UID) {
|
case SUDO_PATH_WRONG_OWNER:
|
||||||
int serrno = errno;
|
log_warningx(SLOG_PARSE_ERROR,
|
||||||
if (restore_perms()) {
|
N_("%s is owned by uid %u, should be %u"), fname,
|
||||||
if (!set_perms(PERM_ROOT))
|
(unsigned int)sb.st_uid, (unsigned int)sudoers_uid);
|
||||||
debug_return_ptr(NULL);
|
break;
|
||||||
goto again;
|
case SUDO_PATH_WORLD_WRITABLE:
|
||||||
}
|
log_warningx(SLOG_PARSE_ERROR, N_("%s is world writable"), fname);
|
||||||
errno = serrno;
|
break;
|
||||||
}
|
case SUDO_PATH_GROUP_WRITABLE:
|
||||||
log_warning(SLOG_PARSE_ERROR, N_("unable to open %s"), file);
|
log_warningx(SLOG_PARSE_ERROR,
|
||||||
break;
|
N_("%s is owned by gid %u, should be %u"), fname,
|
||||||
case SUDO_PATH_BAD_TYPE:
|
(unsigned int)sb.st_gid, (unsigned int)sudoers_gid);
|
||||||
log_warningx(SLOG_PARSE_ERROR,
|
break;
|
||||||
N_("%s is not a regular file"), file);
|
default:
|
||||||
break;
|
sudo_warnx("%s: internal error, unexpected error %d", __func__, error);
|
||||||
case SUDO_PATH_WRONG_OWNER:
|
break;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!restore_perms()) {
|
if (fp == NULL && fd != -1)
|
||||||
/* unable to change back to root */
|
close(fd);
|
||||||
if (fp != NULL) {
|
|
||||||
fclose(fp);
|
|
||||||
fp = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
debug_return_ptr(fp);
|
debug_return_ptr(fp);
|
||||||
}
|
}
|
||||||
|
@@ -51,7 +51,7 @@ LT_LIBS = $(LIBUTIL) $(LIBPROTOBUF_C)
|
|||||||
LIBS = @LIBS@ @SUDO_LIBS@ @GETGROUPS_LIB@ @NET_LIBS@ $(LT_LIBS)
|
LIBS = @LIBS@ @SUDO_LIBS@ @GETGROUPS_LIB@ @NET_LIBS@ $(LT_LIBS)
|
||||||
|
|
||||||
# C preprocessor defines
|
# C preprocessor defines
|
||||||
CPPDEFS = -D_PATH_SUDO_CONF=\"$(sysconfdir)/sudo.conf\" \
|
CPPDEFS = -D_PATH_SUDO_CONF=\"@sudo_conf@\" \
|
||||||
-DLOCALEDIR=\"$(localedir)\"
|
-DLOCALEDIR=\"$(localedir)\"
|
||||||
|
|
||||||
# C preprocessor flags
|
# C preprocessor flags
|
||||||
|
Reference in New Issue
Block a user