2
0
mirror of https://github.com/sudo-project/sudo.git synced 2025-09-02 15:25:58 +00:00

Allow a list of digests to be specified for a command.

This commit is contained in:
Todd C. Miller
2020-03-11 11:17:52 -06:00
parent 8c08f5ef03
commit 4eca443246
19 changed files with 662 additions and 520 deletions

View File

@@ -126,18 +126,18 @@ is_script(int fd)
* Returns false on error, else true.
*/
static bool
open_cmnd(const char *path, const struct command_digest *digest, int *fdp)
open_cmnd(const char *path, const struct command_digest_list *digests, int *fdp)
{
int fd = -1;
debug_decl(open_cmnd, SUDOERS_DEBUG_MATCH);
/* Only open the file for fdexec or for digest matching. */
if (def_fdexec != always && digest == NULL)
if (def_fdexec != always && TAILQ_EMPTY(digests))
debug_return_bool(true);
fd = open(path, O_RDONLY|O_NONBLOCK);
# ifdef O_EXEC
if (fd == -1 && errno == EACCES && digest == NULL) {
if (fd == -1 && errno == EACCES && TAILQ_EMPTY(digests))
/* Try again with O_EXEC if no digest is specified. */
const int saved_errno = errno;
if ((fd = open(path, O_EXEC)) == -1)
@@ -197,7 +197,7 @@ set_cmnd_fd(int fd)
*/
static bool
command_matches_dir(const char *sudoers_dir, size_t dlen,
const struct command_digest *digest)
const struct command_digest_list *digests)
{
struct stat sudoers_stat;
struct dirent *dent;
@@ -233,7 +233,7 @@ command_matches_dir(const char *sudoers_dir, size_t dlen,
continue;
/* Open the file for fdexec or for digest matching. */
if (!open_cmnd(buf, digest, &fd))
if (!open_cmnd(buf, digests, &fd))
continue;
if (!do_stat(fd, buf, &sudoers_stat))
continue;
@@ -241,7 +241,7 @@ command_matches_dir(const char *sudoers_dir, size_t dlen,
if (user_stat == NULL ||
(user_stat->st_dev == sudoers_stat.st_dev &&
user_stat->st_ino == sudoers_stat.st_ino)) {
if (digest != NULL && !digest_matches(fd, buf, digest))
if (!digest_matches(fd, buf, digests))
continue;
free(safe_cmnd);
if ((safe_cmnd = strdup(buf)) == NULL) {
@@ -265,7 +265,7 @@ command_matches_dir(const char *sudoers_dir, size_t dlen,
static bool
command_matches_fnmatch(const char *sudoers_cmnd, const char *sudoers_args,
const struct command_digest *digest)
const struct command_digest_list *digests)
{
struct stat sb; /* XXX - unused */
int fd = -1;
@@ -282,12 +282,12 @@ command_matches_fnmatch(const char *sudoers_cmnd, const char *sudoers_args,
debug_return_bool(false);
if (command_args_match(sudoers_cmnd, sudoers_args)) {
/* Open the file for fdexec or for digest matching. */
if (!open_cmnd(user_cmnd, digest, &fd))
if (!open_cmnd(user_cmnd, digests, &fd))
goto bad;
if (!do_stat(fd, user_cmnd, &sb))
goto bad;
/* Check digest of user_cmnd since sudoers_cmnd is a pattern. */
if (digest != NULL && !digest_matches(fd, user_cmnd, digest))
if (!digest_matches(fd, user_cmnd, digests))
goto bad;
set_cmnd_fd(fd);
@@ -305,7 +305,7 @@ bad:
static bool
command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args,
const struct command_digest *digest)
const struct command_digest_list *digests)
{
struct stat sudoers_stat;
bool bad_digest = false;
@@ -349,7 +349,7 @@ command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args,
if (strcmp(cp, user_cmnd) != 0)
continue;
/* Open the file for fdexec or for digest matching. */
if (!open_cmnd(cp, digest, &fd))
if (!open_cmnd(cp, digests, &fd))
continue;
if (!do_stat(fd, cp, &sudoers_stat))
continue;
@@ -357,7 +357,7 @@ command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args,
(user_stat->st_dev == sudoers_stat.st_dev &&
user_stat->st_ino == sudoers_stat.st_ino)) {
/* There could be multiple matches, check digest early. */
if (digest != NULL && !digest_matches(fd, cp, digest)) {
if (!digest_matches(fd, cp, digests)) {
bad_digest = true;
continue;
}
@@ -385,7 +385,7 @@ command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args,
/* If it ends in '/' it is a directory spec. */
dlen = strlen(cp);
if (cp[dlen - 1] == '/') {
if (command_matches_dir(cp, dlen, digest))
if (command_matches_dir(cp, dlen, digests))
debug_return_bool(true);
continue;
}
@@ -399,14 +399,14 @@ command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args,
continue;
/* Open the file for fdexec or for digest matching. */
if (!open_cmnd(cp, digest, &fd))
if (!open_cmnd(cp, digests, &fd))
continue;
if (!do_stat(fd, cp, &sudoers_stat))
continue;
if (user_stat == NULL ||
(user_stat->st_dev == sudoers_stat.st_dev &&
user_stat->st_ino == sudoers_stat.st_ino)) {
if (digest != NULL && !digest_matches(fd, cp, digest))
if (!digest_matches(fd, cp, digests))
continue;
free(safe_cmnd);
if ((safe_cmnd = strdup(cp)) == NULL) {
@@ -433,7 +433,7 @@ done:
}
static bool
command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args, const struct command_digest *digest)
command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args, const struct command_digest_list *digests)
{
struct stat sudoers_stat;
const char *base;
@@ -444,7 +444,7 @@ command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args, const
/* If it ends in '/' it is a directory spec. */
dlen = strlen(sudoers_cmnd);
if (sudoers_cmnd[dlen - 1] == '/')
debug_return_bool(command_matches_dir(sudoers_cmnd, dlen, digest));
debug_return_bool(command_matches_dir(sudoers_cmnd, dlen, digests));
/* Only proceed if user_base and basename(sudoers_cmnd) match */
if ((base = strrchr(sudoers_cmnd, '/')) == NULL)
@@ -455,7 +455,7 @@ command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args, const
debug_return_bool(false);
/* Open the file for fdexec or for digest matching. */
if (!open_cmnd(sudoers_cmnd, digest, &fd))
if (!open_cmnd(sudoers_cmnd, digests, &fd))
goto bad;
/*
@@ -476,7 +476,7 @@ command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args, const
}
if (!command_args_match(sudoers_cmnd, sudoers_args))
goto bad;
if (digest != NULL && !digest_matches(fd, sudoers_cmnd, digest)) {
if (!digest_matches(fd, sudoers_cmnd, digests)) {
/* XXX - log functions not available but we should log very loudly */
goto bad;
}
@@ -498,7 +498,7 @@ bad:
* otherwise, return true if user_cmnd names one of the inodes in path.
*/
bool
command_matches(const char *sudoers_cmnd, const char *sudoers_args, const struct command_digest *digest)
command_matches(const char *sudoers_cmnd, const char *sudoers_args, const struct command_digest_list *digests)
{
bool rc = false;
debug_decl(command_matches, SUDOERS_DEBUG_MATCH);
@@ -526,11 +526,11 @@ command_matches(const char *sudoers_cmnd, const char *sudoers_args, const struct
* use glob(3) and/or fnmatch(3) to do the matching.
*/
if (def_fast_glob)
rc = command_matches_fnmatch(sudoers_cmnd, sudoers_args, digest);
rc = command_matches_fnmatch(sudoers_cmnd, sudoers_args, digests);
else
rc = command_matches_glob(sudoers_cmnd, sudoers_args, digest);
rc = command_matches_glob(sudoers_cmnd, sudoers_args, digests);
} else {
rc = command_matches_normal(sudoers_cmnd, sudoers_args, digest);
rc = command_matches_normal(sudoers_cmnd, sudoers_args, digests);
}
done:
sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,