Make struct sudoers_context private to sudoers.c.

We now pass a pointer to the context where necessary.  There are a
few cases where we need to request the context from sudoers via
sudoers_get_context() for the plugin API functions.  If the plugin
API was able to pass around a closure pointer this would not be
necessary.
This commit is contained in:
Todd C. Miller
2023-08-21 09:21:49 -06:00
parent 2d2529a15e
commit 2440174954
68 changed files with 2293 additions and 2104 deletions

View File

@@ -79,9 +79,10 @@ regex_matches(const char *pattern, const char *str)
}
static bool
command_args_match(const char *sudoers_cmnd, const char *sudoers_args)
command_args_match(struct sudoers_context *ctx, const char *sudoers_cmnd,
const char *sudoers_args)
{
const char *args = ctx.user.cmnd_args ? ctx.user.cmnd_args : "";
const char *args = ctx->user.cmnd_args ? ctx->user.cmnd_args : "";
int flags = 0;
debug_decl(command_args_match, SUDOERS_DEBUG_MATCH);
@@ -92,7 +93,7 @@ command_args_match(const char *sudoers_cmnd, const char *sudoers_args)
if (sudoers_args == NULL)
debug_return_bool(true);
if (strcmp("\"\"", sudoers_args) == 0)
debug_return_bool(ctx.user.cmnd_args ? false : true);
debug_return_bool(ctx->user.cmnd_args ? false : true);
/*
* If args are specified in sudoers, they must match the user args.
@@ -198,12 +199,12 @@ open_cmnd(const char *path, const struct command_digest_list *digests, int *fdp)
}
static void
set_cmnd_fd(int fd, int rootfd)
set_cmnd_fd(struct sudoers_context *ctx, int fd, int rootfd)
{
debug_decl(set_cmnd_fd, SUDOERS_DEBUG_MATCH);
if (ctx.runas.execfd != -1)
close(ctx.runas.execfd);
if (ctx->runas.execfd != -1)
close(ctx->runas.execfd);
if (fd != -1) {
if (def_fdexec == never) {
@@ -240,18 +241,18 @@ set_cmnd_fd(int fd, int rootfd)
}
}
ctx.runas.execfd = fd;
ctx->runas.execfd = fd;
debug_return;
}
#ifndef SUDOERS_NAME_MATCH
/*
* Return true if ctx.user.cmnd names one of the inodes in dir, else false.
* Return true if ctx->user.cmnd names one of the inodes in dir, else false.
*/
static bool
command_matches_dir(const char *sudoers_dir, size_t dlen, int rootfd,
bool intercepted, const struct command_digest_list *digests)
command_matches_dir(struct sudoers_context *ctx, const char *sudoers_dir,
size_t dlen, int rootfd, bool intercepted, const struct command_digest_list *digests)
{
struct stat sudoers_stat;
char path[PATH_MAX];
@@ -260,10 +261,10 @@ command_matches_dir(const char *sudoers_dir, size_t dlen, int rootfd,
debug_decl(command_matches_dir, SUDOERS_DEBUG_MATCH);
/* Compare the canonicalized directories, if possible. */
if (ctx.user.cmnd_dir != NULL) {
if (ctx->user.cmnd_dir != NULL) {
char *resolved = canon_path(sudoers_dir);
if (resolved != NULL) {
if (strcmp(resolved, ctx.user.cmnd_dir) != 0) {
if (strcmp(resolved, ctx->user.cmnd_dir) != 0) {
canon_path_free(resolved);
goto done;
}
@@ -272,7 +273,7 @@ command_matches_dir(const char *sudoers_dir, size_t dlen, int rootfd,
}
/* Check for command in sudoers_dir. */
len = snprintf(path, sizeof(path), "%s/%s", sudoers_dir, ctx.user.cmnd_base);
len = snprintf(path, sizeof(path), "%s/%s", sudoers_dir, ctx->user.cmnd_base);
if (len < 0 || len >= ssizeof(path))
goto done;
@@ -284,13 +285,13 @@ command_matches_dir(const char *sudoers_dir, size_t dlen, int rootfd,
if (!intercept_ok(path, intercepted, &sudoers_stat))
goto done;
if (ctx.user.cmnd_stat == NULL ||
(ctx.user.cmnd_stat->st_dev == sudoers_stat.st_dev &&
ctx.user.cmnd_stat->st_ino == sudoers_stat.st_ino)) {
if (ctx->user.cmnd_stat == NULL ||
(ctx->user.cmnd_stat->st_dev == sudoers_stat.st_dev &&
ctx->user.cmnd_stat->st_ino == sudoers_stat.st_ino)) {
if (!digest_matches(fd, path, digests))
goto done;
free(ctx.runas.cmnd);
if ((ctx.runas.cmnd = strdup(path)) == NULL) {
free(ctx->runas.cmnd);
if ((ctx->runas.cmnd = strdup(path)) == NULL) {
sudo_warnx(U_("%s: %s"), __func__,
U_("unable to allocate memory"));
}
@@ -304,29 +305,30 @@ done:
}
#else /* SUDOERS_NAME_MATCH */
/*
* Return true if ctx.user.cmnd names one of the inodes in dir, else false.
* Return true if ctx->user.cmnd names one of the inodes in dir, else false.
*/
static bool
command_matches_dir(const char *sudoers_dir, size_t dlen, int rootfd,
bool intercepted, const struct command_digest_list *digests)
command_matches_dir(struct sudoers_context *ctx, const char *sudoers_dir,
size_t dlen, int rootfd, bool intercepted,
const struct command_digest_list *digests)
{
int fd = -1;
debug_decl(command_matches_dir, SUDOERS_DEBUG_MATCH);
/* Match ctx.user.cmnd against sudoers_dir. */
if (strncmp(ctx.user.cmnd, sudoers_dir, dlen) != 0 || ctx.user.cmnd[dlen] != '/')
/* Match ctx->user.cmnd against sudoers_dir. */
if (strncmp(ctx->user.cmnd, sudoers_dir, dlen) != 0 || ctx->user.cmnd[dlen] != '/')
goto bad;
/* Make sure ctx.user.cmnd is not in a subdir of sudoers_dir. */
if (strchr(ctx.user.cmnd + dlen + 1, '\0') != NULL)
/* Make sure ctx->user.cmnd is not in a subdir of sudoers_dir. */
if (strchr(ctx->user.cmnd + dlen + 1, '\0') != NULL)
goto bad;
/* Open the file for fdexec or for digest matching. */
if (!open_cmnd(ctx.user.cmnd, digests, &fd))
if (!open_cmnd(ctx->user.cmnd, digests, &fd))
goto bad;
if (!digest_matches(fd, ctx.user.cmnd, digests))
if (!digest_matches(fd, ctx->user.cmnd, digests))
goto bad;
set_cmnd_fd(fd, rootfd);
set_cmnd_fd(ctx, fd, rootfd);
debug_return_bool(true);
bad:
@@ -337,7 +339,7 @@ bad:
#endif /* SUDOERS_NAME_MATCH */
static bool
command_matches_all(int rootfd, bool intercepted,
command_matches_all(struct sudoers_context *ctx, int rootfd, bool intercepted,
const struct command_digest_list *digests)
{
#ifndef SUDOERS_NAME_MATCH
@@ -346,32 +348,32 @@ command_matches_all(int rootfd, bool intercepted,
int fd = -1;
debug_decl(command_matches_all, SUDOERS_DEBUG_MATCH);
if (strchr(ctx.user.cmnd, '/') != NULL) {
if (strchr(ctx->user.cmnd, '/') != NULL) {
#ifndef SUDOERS_NAME_MATCH
/* Open the file for fdexec or for digest matching. */
bool open_error = !open_cmnd(ctx.user.cmnd, digests, &fd);
bool open_error = !open_cmnd(ctx->user.cmnd, digests, &fd);
/* A non-existent file is not an error for "sudo ALL". */
if (do_stat(fd, ctx.user.cmnd, &sb)) {
if (do_stat(fd, ctx->user.cmnd, &sb)) {
if (open_error) {
/* File exists but we couldn't open it above? */
goto bad;
}
if (!intercept_ok(ctx.user.cmnd, intercepted, &sb))
if (!intercept_ok(ctx->user.cmnd, intercepted, &sb))
goto bad;
}
#else
/* Open the file for fdexec or for digest matching. */
(void)open_cmnd(ctx.user.cmnd, digests, &fd);
(void)open_cmnd(ctx->user.cmnd, digests, &fd);
#endif
}
/* Check digest of ctx.user.cmnd since we have no sudoers_cmnd for ALL. */
if (!digest_matches(fd, ctx.user.cmnd, digests))
/* Check digest of ctx->user.cmnd since we have no sudoers_cmnd for ALL. */
if (!digest_matches(fd, ctx->user.cmnd, digests))
goto bad;
set_cmnd_fd(fd, rootfd);
set_cmnd_fd(ctx, fd, rootfd);
/* No need to set ctx.runas.cmnd for ALL. */
/* No need to set ctx->runas.cmnd for ALL. */
debug_return_bool(true);
bad:
if (fd != -1)
@@ -380,10 +382,11 @@ bad:
}
static bool
command_matches_fnmatch(const char *sudoers_cmnd, const char *sudoers_args,
int rootfd, bool intercepted, const struct command_digest_list *digests)
command_matches_fnmatch(struct sudoers_context *ctx, const char *sudoers_cmnd,
const char *sudoers_args, int rootfd, bool intercepted,
const struct command_digest_list *digests)
{
const char *cmnd = ctx.user.cmnd;
const char *cmnd = ctx->user.cmnd;
char buf[PATH_MAX];
int len, fd = -1;
#ifndef SUDOERS_NAME_MATCH
@@ -391,12 +394,12 @@ command_matches_fnmatch(const char *sudoers_cmnd, const char *sudoers_args,
#endif
debug_decl(command_matches_fnmatch, SUDOERS_DEBUG_MATCH);
/* A relative ctx.user.cmnd will not match, try canonicalized version. */
if (ctx.user.cmnd[0] != '/') {
if (ctx.user.cmnd_dir == NULL)
/* A relative ctx->user.cmnd will not match, try canonicalized version. */
if (ctx->user.cmnd[0] != '/') {
if (ctx->user.cmnd_dir == NULL)
debug_return_bool(false);
len = snprintf(buf, sizeof(buf), "%s/%s", ctx.user.cmnd_dir,
ctx.user.cmnd_base);
len = snprintf(buf, sizeof(buf), "%s/%s", ctx->user.cmnd_dir,
ctx->user.cmnd_base);
if (len < 0 || len >= ssizeof(buf))
debug_return_bool(false);
cmnd = buf;
@@ -412,7 +415,7 @@ command_matches_fnmatch(const char *sudoers_cmnd, const char *sudoers_args,
if (fnmatch(sudoers_cmnd, cmnd, FNM_PATHNAME) != 0)
debug_return_bool(false);
if (command_args_match(sudoers_cmnd, sudoers_args)) {
if (command_args_match(ctx, sudoers_cmnd, sudoers_args)) {
/* Open the file for fdexec or for digest matching. */
if (!open_cmnd(cmnd, digests, &fd))
goto bad;
@@ -425,9 +428,9 @@ command_matches_fnmatch(const char *sudoers_cmnd, const char *sudoers_args,
/* Check digest of cmnd since sudoers_cmnd is a pattern. */
if (!digest_matches(fd, cmnd, digests))
goto bad;
set_cmnd_fd(fd, rootfd);
set_cmnd_fd(ctx, fd, rootfd);
/* No need to set ctx.runas.cmnd since cmnd matches sudoers_cmnd */
/* No need to set ctx->runas.cmnd since cmnd matches sudoers_cmnd */
debug_return_bool(true);
bad:
if (fd != -1)
@@ -438,10 +441,11 @@ bad:
}
static bool
command_matches_regex(const char *sudoers_cmnd, const char *sudoers_args,
int rootfd, bool intercepted, const struct command_digest_list *digests)
command_matches_regex(struct sudoers_context *ctx, const char *sudoers_cmnd,
const char *sudoers_args, int rootfd, bool intercepted,
const struct command_digest_list *digests)
{
const char *cmnd = ctx.user.cmnd;
const char *cmnd = ctx->user.cmnd;
char buf[PATH_MAX];
int len, fd = -1;
#ifndef SUDOERS_NAME_MATCH
@@ -449,12 +453,12 @@ command_matches_regex(const char *sudoers_cmnd, const char *sudoers_args,
#endif
debug_decl(command_matches_regex, SUDOERS_DEBUG_MATCH);
/* A relative ctx.user.cmnd will not match, try canonicalized version. */
if (ctx.user.cmnd[0] != '/') {
if (ctx.user.cmnd_dir == NULL)
/* A relative ctx->user.cmnd will not match, try canonicalized version. */
if (ctx->user.cmnd[0] != '/') {
if (ctx->user.cmnd_dir == NULL)
debug_return_bool(false);
len = snprintf(buf, sizeof(buf), "%s/%s", ctx.user.cmnd_dir,
ctx.user.cmnd_base);
len = snprintf(buf, sizeof(buf), "%s/%s", ctx->user.cmnd_dir,
ctx->user.cmnd_base);
if (len < 0 || len >= ssizeof(buf))
debug_return_bool(false);
cmnd = buf;
@@ -470,7 +474,7 @@ command_matches_regex(const char *sudoers_cmnd, const char *sudoers_args,
if (!regex_matches(sudoers_cmnd, cmnd))
debug_return_bool(false);
if (command_args_match(sudoers_cmnd, sudoers_args)) {
if (command_args_match(ctx, sudoers_cmnd, sudoers_args)) {
/* Open the file for fdexec or for digest matching. */
if (!open_cmnd(cmnd, digests, &fd))
goto bad;
@@ -483,9 +487,9 @@ command_matches_regex(const char *sudoers_cmnd, const char *sudoers_args,
/* Check digest of cmnd since sudoers_cmnd is a pattern. */
if (!digest_matches(fd, cmnd, digests))
goto bad;
set_cmnd_fd(fd, rootfd);
set_cmnd_fd(ctx, fd, rootfd);
/* No need to set ctx.runas.cmnd since cmnd matches sudoers_cmnd */
/* No need to set ctx->runas.cmnd since cmnd matches sudoers_cmnd */
debug_return_bool(true);
bad:
if (fd != -1)
@@ -497,8 +501,9 @@ bad:
#ifndef SUDOERS_NAME_MATCH
static bool
command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args,
int rootfd, bool intercepted, const struct command_digest_list *digests)
command_matches_glob(struct sudoers_context *ctx, const char *sudoers_cmnd,
const char *sudoers_args, int rootfd, bool intercepted,
const struct command_digest_list *digests)
{
struct stat sudoers_stat;
bool bad_digest = false;
@@ -511,12 +516,12 @@ command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args,
/*
* First check to see if we can avoid the call to glob(3).
* Short circuit if there are no meta chars in the command itself
* and ctx.user.cmnd_base and basename(sudoers_cmnd) don't match.
* and ctx->user.cmnd_base and basename(sudoers_cmnd) don't match.
*/
dlen = strlen(sudoers_cmnd);
if (sudoers_cmnd[dlen - 1] != '/') {
base = sudo_basename(sudoers_cmnd);
if (!has_meta(base) && strcmp(ctx.user.cmnd_base, base) != 0)
if (!has_meta(base) && strcmp(ctx->user.cmnd_base, base) != 0)
debug_return_bool(false);
}
@@ -532,15 +537,15 @@ command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args,
debug_return_bool(false);
}
/* If ctx.user.cmnd is fully-qualified, check for an exact match. */
if (ctx.user.cmnd[0] == '/') {
/* If ctx->user.cmnd is fully-qualified, check for an exact match. */
if (ctx->user.cmnd[0] == '/') {
for (ap = gl.gl_pathv; (cp = *ap) != NULL; ap++) {
if (fd != -1) {
close(fd);
fd = -1;
}
if (strcmp(cp, ctx.user.cmnd) != 0)
if (strcmp(cp, ctx->user.cmnd) != 0)
continue;
/* Open the file for fdexec or for digest matching. */
if (!open_cmnd(cp, digests, &fd))
@@ -549,16 +554,16 @@ command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args,
continue;
if (!intercept_ok(cp, intercepted, &sudoers_stat))
continue;
if (ctx.user.cmnd_stat == NULL ||
(ctx.user.cmnd_stat->st_dev == sudoers_stat.st_dev &&
ctx.user.cmnd_stat->st_ino == sudoers_stat.st_ino)) {
if (ctx->user.cmnd_stat == NULL ||
(ctx->user.cmnd_stat->st_dev == sudoers_stat.st_dev &&
ctx->user.cmnd_stat->st_ino == sudoers_stat.st_ino)) {
/* There could be multiple matches, check digest early. */
if (!digest_matches(fd, cp, digests)) {
bad_digest = true;
continue;
}
free(ctx.runas.cmnd);
if ((ctx.runas.cmnd = strdup(cp)) == NULL) {
free(ctx->runas.cmnd);
if ((ctx->runas.cmnd = strdup(cp)) == NULL) {
sudo_warnx(U_("%s: %s"), __func__,
U_("unable to allocate memory"));
cp = NULL; /* fail closed */
@@ -581,20 +586,21 @@ 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, rootfd, intercepted, digests)) {
if (command_matches_dir(ctx, cp, dlen, rootfd, intercepted,
digests)) {
globfree(&gl);
debug_return_bool(true);
}
continue;
}
/* Only proceed if ctx.user.cmnd_base and basename(cp) match */
/* Only proceed if ctx->user.cmnd_base and basename(cp) match */
base = sudo_basename(cp);
if (strcmp(ctx.user.cmnd_base, base) != 0)
if (strcmp(ctx->user.cmnd_base, base) != 0)
continue;
/* Compare the canonicalized parent directories, if possible. */
if (ctx.user.cmnd_dir != NULL) {
if (ctx->user.cmnd_dir != NULL) {
char *slash = strchr(cp, '/');
if (slash != NULL) {
char *resolved;
@@ -603,7 +609,7 @@ command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args,
*slash = '/';
if (resolved != NULL) {
/* Canonicalized directories must match. */
int result = strcmp(resolved, ctx.user.cmnd_dir);
int result = strcmp(resolved, ctx->user.cmnd_dir);
canon_path_free(resolved);
if (result != 0)
continue;
@@ -618,13 +624,13 @@ command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args,
continue;
if (!intercept_ok(cp, intercepted, &sudoers_stat))
continue;
if (ctx.user.cmnd_stat == NULL ||
(ctx.user.cmnd_stat->st_dev == sudoers_stat.st_dev &&
ctx.user.cmnd_stat->st_ino == sudoers_stat.st_ino)) {
if (ctx->user.cmnd_stat == NULL ||
(ctx->user.cmnd_stat->st_dev == sudoers_stat.st_dev &&
ctx->user.cmnd_stat->st_ino == sudoers_stat.st_ino)) {
if (!digest_matches(fd, cp, digests))
continue;
free(ctx.runas.cmnd);
if ((ctx.runas.cmnd = strdup(cp)) == NULL) {
free(ctx->runas.cmnd);
if ((ctx->runas.cmnd = strdup(cp)) == NULL) {
sudo_warnx(U_("%s: %s"), __func__,
U_("unable to allocate memory"));
cp = NULL; /* fail closed */
@@ -636,9 +642,9 @@ command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args,
done:
globfree(&gl);
if (cp != NULL) {
if (command_args_match(sudoers_cmnd, sudoers_args)) {
/* ctx.runas.cmnd was set above. */
set_cmnd_fd(fd, rootfd);
if (command_args_match(ctx, sudoers_cmnd, sudoers_args)) {
/* ctx->runas.cmnd was set above. */
set_cmnd_fd(ctx, fd, rootfd);
debug_return_bool(true);
}
}
@@ -648,8 +654,9 @@ done:
}
static bool
command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args,
int rootfd, bool intercepted, const struct command_digest_list *digests)
command_matches_normal(struct sudoers_context *ctx, const char *sudoers_cmnd,
const char *sudoers_args, int rootfd, bool intercepted,
const struct command_digest_list *digests)
{
struct stat sudoers_stat;
const char *base;
@@ -660,17 +667,17 @@ command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args,
/* 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, rootfd,
debug_return_bool(command_matches_dir(ctx, sudoers_cmnd, dlen, rootfd,
intercepted, digests));
}
/* Only proceed if ctx.user.cmnd_base and basename(sudoers_cmnd) match */
/* Only proceed if ctx->user.cmnd_base and basename(sudoers_cmnd) match */
base = sudo_basename(sudoers_cmnd);
if (strcmp(ctx.user.cmnd_base, base) != 0)
if (strcmp(ctx->user.cmnd_base, base) != 0)
debug_return_bool(false);
/* Compare the canonicalized parent directories, if possible. */
if (ctx.user.cmnd_dir != NULL) {
if (ctx->user.cmnd_dir != NULL) {
const char *slash = strrchr(sudoers_cmnd, '/');
if (slash != NULL) {
char sudoers_cmnd_dir[PATH_MAX], *resolved;
@@ -682,7 +689,7 @@ command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args,
sudoers_cmnd_dir[len] = '\0';
resolved = canon_path(sudoers_cmnd_dir);
if (resolved != NULL) {
if (strcmp(resolved, ctx.user.cmnd_dir) != 0) {
if (strcmp(resolved, ctx->user.cmnd_dir) != 0) {
canon_path_free(resolved);
goto bad;
}
@@ -702,29 +709,29 @@ command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args,
* c) there are args in sudoers and on command line and they match
* d) there is a digest and it matches
*/
if (ctx.user.cmnd_stat != NULL && do_stat(fd, sudoers_cmnd, &sudoers_stat)) {
if (ctx->user.cmnd_stat != NULL && do_stat(fd, sudoers_cmnd, &sudoers_stat)) {
if (!intercept_ok(sudoers_cmnd, intercepted, &sudoers_stat))
goto bad;
if (ctx.user.cmnd_stat->st_dev != sudoers_stat.st_dev ||
ctx.user.cmnd_stat->st_ino != sudoers_stat.st_ino)
if (ctx->user.cmnd_stat->st_dev != sudoers_stat.st_dev ||
ctx->user.cmnd_stat->st_ino != sudoers_stat.st_ino)
goto bad;
} else {
/* Either user or sudoers command does not exist, match by name. */
if (strcmp(ctx.user.cmnd, sudoers_cmnd) != 0)
if (strcmp(ctx->user.cmnd, sudoers_cmnd) != 0)
goto bad;
}
if (!command_args_match(sudoers_cmnd, sudoers_args))
if (!command_args_match(ctx, sudoers_cmnd, sudoers_args))
goto bad;
if (!digest_matches(fd, sudoers_cmnd, digests)) {
/* XXX - log functions not available but we should log very loudly */
goto bad;
}
free(ctx.runas.cmnd);
if ((ctx.runas.cmnd = strdup(sudoers_cmnd)) == NULL) {
free(ctx->runas.cmnd);
if ((ctx->runas.cmnd = strdup(sudoers_cmnd)) == NULL) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
goto bad;
}
set_cmnd_fd(fd, rootfd);
set_cmnd_fd(ctx, fd, rootfd);
debug_return_bool(true);
bad:
if (fd != -1)
@@ -733,16 +740,18 @@ bad:
}
#else /* SUDOERS_NAME_MATCH */
static bool
command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args,
int rootfd, bool intercepted, const struct command_digest_list *digests)
command_matches_glob(struct sudoers_context *ctx, const char *sudoers_cmnd,
const char *sudoers_args, int rootfd, bool intercepted,
const struct command_digest_list *digests)
{
return command_matches_fnmatch(sudoers_cmnd, sudoers_args, rootfd,
return command_matches_fnmatch(ctx, sudoers_cmnd, sudoers_args, rootfd,
intercepted, digests);
}
static bool
command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args,
int rootfd, bool intercepted, const struct command_digest_list *digests)
command_matches_normal(struct sudoers_context *ctx, const char *sudoers_cmnd,
const char *sudoers_args, int rootfd, bool intercepted,
const struct command_digest_list *digests)
{
size_t dlen;
int fd = -1;
@@ -751,26 +760,26 @@ command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args,
/* 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, rootfd,
debug_return_bool(command_matches_dir(ctx, sudoers_cmnd, dlen, rootfd,
intercepted, digests));
}
if (strcmp(ctx.user.cmnd, sudoers_cmnd) == 0) {
if (command_args_match(sudoers_cmnd, sudoers_args)) {
if (strcmp(ctx->user.cmnd, sudoers_cmnd) == 0) {
if (command_args_match(ctx, sudoers_cmnd, sudoers_args)) {
/* Open the file for fdexec or for digest matching. */
if (!open_cmnd(ctx.user.cmnd, digests, &fd))
if (!open_cmnd(ctx->user.cmnd, digests, &fd))
goto bad;
if (!digest_matches(fd, ctx.user.cmnd, digests))
if (!digest_matches(fd, ctx->user.cmnd, digests))
goto bad;
/* Successful match. */
free(ctx.runas.cmnd);
if ((ctx.runas.cmnd = strdup(sudoers_cmnd)) == NULL) {
free(ctx->runas.cmnd);
if ((ctx->runas.cmnd = strdup(sudoers_cmnd)) == NULL) {
sudo_warnx(U_("%s: %s"), __func__,
U_("unable to allocate memory"));
goto bad;
}
set_cmnd_fd(fd, rootfd);
set_cmnd_fd(ctx, fd, rootfd);
debug_return_bool(true);
}
}
@@ -783,11 +792,11 @@ bad:
/*
* If path doesn't end in /, return true iff cmnd & path name the same inode;
* otherwise, return true if ctx.user.cmnd names one of the inodes in path.
* otherwise, return true if ctx->user.cmnd names one of the inodes in path.
*/
bool
command_matches(const char *sudoers_cmnd, const char *sudoers_args,
const char *runchroot, struct cmnd_info *info,
command_matches(struct sudoers_context *ctx, const char *sudoers_cmnd,
const char *sudoers_args, const char *runchroot, struct cmnd_info *info,
const struct command_digest_list *digests)
{
const bool intercepted = info ? info->intercepted : false;
@@ -798,14 +807,14 @@ command_matches(const char *sudoers_cmnd, const char *sudoers_args,
bool rc = false;
debug_decl(command_matches, SUDOERS_DEBUG_MATCH);
if (ctx.runas.chroot != NULL) {
if (ctx->runas.chroot != NULL) {
if (runchroot != NULL && strcmp(runchroot, "*") != 0 &&
strcmp(runchroot, ctx.runas.chroot) != 0) {
strcmp(runchroot, ctx->runas.chroot) != 0) {
/* CHROOT mismatch */
goto done;
}
/* User-specified runchroot (cmnd_stat already set appropriately). */
runchroot = ctx.runas.chroot;
runchroot = ctx->runas.chroot;
} else if (runchroot == NULL) {
/* No rule-specific runchroot, use global (cmnd_stat already set). */
if (def_runchroot != NULL && strcmp(def_runchroot, "*") != '\0')
@@ -825,14 +834,14 @@ command_matches(const char *sudoers_cmnd, const char *sudoers_args,
/* Rule-specific runchroot, set cmnd and cmnd_stat after pivot. */
int status;
/* Save old ctx.user.cmnd first, set_cmnd_path() will free it. */
saved_user_cmnd = ctx.user.cmnd;
ctx.user.cmnd = NULL;
if (ctx.user.cmnd_stat != NULL)
saved_user_stat = *ctx.user.cmnd_stat;
status = set_cmnd_path(NULL);
/* Save old ctx->user.cmnd first, set_cmnd_path() will free it. */
saved_user_cmnd = ctx->user.cmnd;
ctx->user.cmnd = NULL;
if (ctx->user.cmnd_stat != NULL)
saved_user_stat = *ctx->user.cmnd_stat;
status = set_cmnd_path(ctx, NULL);
if (status != FOUND) {
ctx.user.cmnd = saved_user_cmnd;
ctx->user.cmnd = saved_user_cmnd;
saved_user_cmnd = NULL;
}
if (info != NULL)
@@ -841,14 +850,14 @@ command_matches(const char *sudoers_cmnd, const char *sudoers_args,
if (sudoers_cmnd == NULL) {
sudoers_cmnd = "ALL";
rc = command_matches_all(pivot_fds[0], intercepted, digests);
rc = command_matches_all(ctx, pivot_fds[0], intercepted, digests);
goto done;
}
/* Check for regular expressions first. */
if (sudoers_cmnd[0] == '^') {
rc = command_matches_regex(sudoers_cmnd, sudoers_args, pivot_fds[0],
intercepted, digests);
rc = command_matches_regex(ctx, sudoers_cmnd, sudoers_args,
pivot_fds[0], intercepted, digests);
goto done;
}
@@ -862,9 +871,9 @@ command_matches(const char *sudoers_cmnd, const char *sudoers_args,
*/
if (strcmp(sudoers_cmnd, "list") == 0 ||
strcmp(sudoers_cmnd, "sudoedit") == 0) {
if (strcmp(ctx.user.cmnd, sudoers_cmnd) == 0 &&
command_args_match(sudoers_cmnd, sudoers_args)) {
/* No need to set ctx.user.cmnd since cmnd == sudoers_cmnd */
if (strcmp(ctx->user.cmnd, sudoers_cmnd) == 0 &&
command_args_match(ctx, sudoers_cmnd, sudoers_args)) {
/* No need to set ctx->user.cmnd since cmnd == sudoers_cmnd */
rc = true;
}
}
@@ -877,39 +886,39 @@ command_matches(const char *sudoers_cmnd, const char *sudoers_args,
* use glob(3) and/or fnmatch(3) to do the matching.
*/
if (def_fast_glob) {
rc = command_matches_fnmatch(sudoers_cmnd, sudoers_args,
rc = command_matches_fnmatch(ctx, sudoers_cmnd, sudoers_args,
pivot_fds[0], intercepted, digests);
} else {
rc = command_matches_glob(sudoers_cmnd, sudoers_args, pivot_fds[0],
intercepted, digests);
rc = command_matches_glob(ctx, sudoers_cmnd, sudoers_args,
pivot_fds[0], intercepted, digests);
}
} else {
rc = command_matches_normal(sudoers_cmnd, sudoers_args, pivot_fds[0],
intercepted, digests);
rc = command_matches_normal(ctx, sudoers_cmnd, sudoers_args,
pivot_fds[0], intercepted, digests);
}
done:
/* Restore root. */
if (runchroot != NULL)
(void)unpivot_root(pivot_fds);
/* Restore ctx.user.cmnd and ctx.user.cmnd_stat. */
/* Restore ctx->user.cmnd and ctx->user.cmnd_stat. */
if (saved_user_cmnd != NULL) {
if (info != NULL) {
free(info->cmnd_path);
info->cmnd_path = ctx.user.cmnd;
if (ctx.user.cmnd_stat != NULL)
info->cmnd_stat = *ctx.user.cmnd_stat;
info->cmnd_path = ctx->user.cmnd;
if (ctx->user.cmnd_stat != NULL)
info->cmnd_stat = *ctx->user.cmnd_stat;
} else {
free(ctx.user.cmnd);
free(ctx->user.cmnd);
}
ctx.user.cmnd = saved_user_cmnd;
if (ctx.user.cmnd_stat != NULL)
*ctx.user.cmnd_stat = saved_user_stat;
ctx->user.cmnd = saved_user_cmnd;
if (ctx->user.cmnd_stat != NULL)
*ctx->user.cmnd_stat = saved_user_stat;
}
sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
"user command \"%s%s%s\" matches sudoers command \"%s%s%s\"%s%s: %s",
ctx.user.cmnd, ctx.user.cmnd_args ? " " : "",
ctx.user.cmnd_args ? ctx.user.cmnd_args : "", sudoers_cmnd,
ctx->user.cmnd, ctx->user.cmnd_args ? " " : "",
ctx->user.cmnd_args ? ctx->user.cmnd_args : "", sudoers_cmnd,
sudoers_args ? " " : "", sudoers_args ? sudoers_args : "",
runchroot ? ", chroot " : "", runchroot ? runchroot : "",
rc ? "true" : "false");