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:
Todd C. Miller
2023-05-02 10:37:38 -06:00
parent a7e906ff66
commit 4363d03ef7
14 changed files with 259 additions and 128 deletions

View File

@@ -24,6 +24,7 @@
#include <config.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <string.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);
}
/*
* 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.
@@ -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);
}