Pass a struct to the match functions to track the resolved command.
This makes it possible to update user_cmnd and cmnd_status modified by per-rule CHROOT settings.
This commit is contained in:
@@ -688,7 +688,7 @@ default_binding_matches(struct sudoers_parse_tree *parse_tree,
|
|||||||
debug_return_bool(true);
|
debug_return_bool(true);
|
||||||
break;
|
break;
|
||||||
case DEFAULTS_CMND:
|
case DEFAULTS_CMND:
|
||||||
if (cmndlist_matches(parse_tree, d->binding, NULL) == ALLOW)
|
if (cmndlist_matches(parse_tree, d->binding, NULL, NULL) == ALLOW)
|
||||||
debug_return_bool(true);
|
debug_return_bool(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -366,14 +366,15 @@ host_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw,
|
|||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
cmndlist_matches(struct sudoers_parse_tree *parse_tree,
|
cmndlist_matches(struct sudoers_parse_tree *parse_tree,
|
||||||
const struct member_list *list, const char *runchroot)
|
const struct member_list *list, const char *runchroot,
|
||||||
|
struct cmnd_info *info)
|
||||||
{
|
{
|
||||||
struct member *m;
|
struct member *m;
|
||||||
int matched = UNSPEC;
|
int matched = UNSPEC;
|
||||||
debug_decl(cmndlist_matches, SUDOERS_DEBUG_MATCH);
|
debug_decl(cmndlist_matches, SUDOERS_DEBUG_MATCH);
|
||||||
|
|
||||||
TAILQ_FOREACH_REVERSE(m, list, member_list, entries) {
|
TAILQ_FOREACH_REVERSE(m, list, member_list, entries) {
|
||||||
matched = cmnd_matches(parse_tree, m, runchroot);
|
matched = cmnd_matches(parse_tree, m, runchroot, info);
|
||||||
if (matched != UNSPEC)
|
if (matched != UNSPEC)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -386,7 +387,7 @@ cmndlist_matches(struct sudoers_parse_tree *parse_tree,
|
|||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
cmnd_matches(struct sudoers_parse_tree *parse_tree, const struct member *m,
|
cmnd_matches(struct sudoers_parse_tree *parse_tree, const struct member *m,
|
||||||
const char *runchroot)
|
const char *runchroot, struct cmnd_info *info)
|
||||||
{
|
{
|
||||||
struct alias *a;
|
struct alias *a;
|
||||||
struct sudo_command *c;
|
struct sudo_command *c;
|
||||||
@@ -402,13 +403,13 @@ cmnd_matches(struct sudoers_parse_tree *parse_tree, const struct member *m,
|
|||||||
FALLTHROUGH;
|
FALLTHROUGH;
|
||||||
case COMMAND:
|
case COMMAND:
|
||||||
c = (struct sudo_command *)m->name;
|
c = (struct sudo_command *)m->name;
|
||||||
if (command_matches(c->cmnd, c->args, runchroot, &c->digests))
|
if (command_matches(c->cmnd, c->args, runchroot, info, &c->digests))
|
||||||
matched = !m->negated;
|
matched = !m->negated;
|
||||||
break;
|
break;
|
||||||
case ALIAS:
|
case ALIAS:
|
||||||
a = alias_get(parse_tree, m->name, CMNDALIAS);
|
a = alias_get(parse_tree, m->name, CMNDALIAS);
|
||||||
if (a != NULL) {
|
if (a != NULL) {
|
||||||
rc = cmndlist_matches(parse_tree, &a->members, runchroot);
|
rc = cmndlist_matches(parse_tree, &a->members, runchroot, info);
|
||||||
if (rc != UNSPEC)
|
if (rc != UNSPEC)
|
||||||
matched = m->negated ? !rc : rc;
|
matched = m->negated ? !rc : rc;
|
||||||
alias_put(a);
|
alias_put(a);
|
||||||
|
@@ -528,8 +528,10 @@ command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args,
|
|||||||
|
|
||||||
/* If it ends in '/' it is a directory spec. */
|
/* If it ends in '/' it is a directory spec. */
|
||||||
dlen = strlen(sudoers_cmnd);
|
dlen = strlen(sudoers_cmnd);
|
||||||
if (sudoers_cmnd[dlen - 1] == '/')
|
if (sudoers_cmnd[dlen - 1] == '/') {
|
||||||
debug_return_bool(command_matches_dir(sudoers_cmnd, dlen, runchroot, digests));
|
debug_return_bool(command_matches_dir(sudoers_cmnd, dlen, runchroot,
|
||||||
|
digests));
|
||||||
|
}
|
||||||
|
|
||||||
/* Only proceed if user_base and basename(sudoers_cmnd) match */
|
/* Only proceed if user_base and basename(sudoers_cmnd) match */
|
||||||
if ((base = strrchr(sudoers_cmnd, '/')) == NULL)
|
if ((base = strrchr(sudoers_cmnd, '/')) == NULL)
|
||||||
@@ -584,7 +586,8 @@ bad:
|
|||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
command_matches(const char *sudoers_cmnd, const char *sudoers_args,
|
command_matches(const char *sudoers_cmnd, const char *sudoers_args,
|
||||||
const char *runchroot, const struct command_digest_list *digests)
|
const char *runchroot, struct cmnd_info *info,
|
||||||
|
const struct command_digest_list *digests)
|
||||||
{
|
{
|
||||||
char *saved_user_cmnd = NULL;
|
char *saved_user_cmnd = NULL;
|
||||||
struct stat saved_user_stat;
|
struct stat saved_user_stat;
|
||||||
@@ -605,11 +608,16 @@ command_matches(const char *sudoers_cmnd, const char *sudoers_args,
|
|||||||
runchroot = def_runchroot;
|
runchroot = def_runchroot;
|
||||||
} else {
|
} else {
|
||||||
/* Rule-specific runchroot, reset user_cmnd and user_stat. */
|
/* Rule-specific runchroot, reset user_cmnd and user_stat. */
|
||||||
|
int status;
|
||||||
|
|
||||||
saved_user_cmnd = user_cmnd;
|
saved_user_cmnd = user_cmnd;
|
||||||
if (user_stat != NULL)
|
if (user_stat != NULL)
|
||||||
saved_user_stat = *user_stat;
|
saved_user_stat = *user_stat;
|
||||||
if (set_cmnd_path(runchroot) != FOUND)
|
status = set_cmnd_path(runchroot);
|
||||||
|
if (status != FOUND)
|
||||||
saved_user_cmnd = NULL;
|
saved_user_cmnd = NULL;
|
||||||
|
if (info != NULL)
|
||||||
|
info->status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sudoers_cmnd == NULL) {
|
if (sudoers_cmnd == NULL) {
|
||||||
@@ -648,7 +656,13 @@ command_matches(const char *sudoers_cmnd, const char *sudoers_args,
|
|||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
if (saved_user_cmnd != NULL) {
|
if (saved_user_cmnd != NULL) {
|
||||||
free(user_cmnd);
|
if (info != NULL) {
|
||||||
|
info->cmnd_path = user_cmnd;
|
||||||
|
if (user_stat != NULL)
|
||||||
|
info->cmnd_stat = *user_stat;
|
||||||
|
} else {
|
||||||
|
free(user_cmnd);
|
||||||
|
}
|
||||||
user_cmnd = saved_user_cmnd;
|
user_cmnd = saved_user_cmnd;
|
||||||
if (user_stat != NULL)
|
if (user_stat != NULL)
|
||||||
*user_stat = saved_user_stat;
|
*user_stat = saved_user_stat;
|
||||||
|
@@ -92,7 +92,8 @@ sudoers_lookup_pseudo(struct sudo_nss_list *snl, struct passwd *pw,
|
|||||||
/* Only check the command when listing another user. */
|
/* Only check the command when listing another user. */
|
||||||
if (user_uid == 0 || list_pw == NULL ||
|
if (user_uid == 0 || list_pw == NULL ||
|
||||||
user_uid == list_pw->pw_uid ||
|
user_uid == list_pw->pw_uid ||
|
||||||
cmnd_matches(nss->parse_tree, cs->cmnd, cs->runchroot) == ALLOW)
|
cmnd_matches(nss->parse_tree, cs->cmnd, cs->runchroot,
|
||||||
|
NULL) == ALLOW)
|
||||||
match = ALLOW;
|
match = ALLOW;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,7 +113,7 @@ sudoers_lookup_pseudo(struct sudo_nss_list *snl, struct passwd *pw,
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
sudoers_lookup_check(struct sudo_nss *nss, struct passwd *pw,
|
sudoers_lookup_check(struct sudo_nss *nss, struct passwd *pw,
|
||||||
int *validated, struct cmndspec **matching_cs,
|
int *validated, struct cmnd_info *info, struct cmndspec **matching_cs,
|
||||||
struct defaults_list **defs, time_t now)
|
struct defaults_list **defs, time_t now)
|
||||||
{
|
{
|
||||||
int host_match, runas_match, cmnd_match;
|
int host_match, runas_match, cmnd_match;
|
||||||
@@ -122,6 +123,8 @@ sudoers_lookup_check(struct sudo_nss *nss, struct passwd *pw,
|
|||||||
struct member *matching_user;
|
struct member *matching_user;
|
||||||
debug_decl(sudoers_lookup_check, SUDOERS_DEBUG_PARSER);
|
debug_decl(sudoers_lookup_check, SUDOERS_DEBUG_PARSER);
|
||||||
|
|
||||||
|
memset(info, 0, sizeof(*info));
|
||||||
|
|
||||||
TAILQ_FOREACH_REVERSE(us, &nss->parse_tree->userspecs, userspec_list, entries) {
|
TAILQ_FOREACH_REVERSE(us, &nss->parse_tree->userspecs, userspec_list, entries) {
|
||||||
if (userlist_matches(nss->parse_tree, pw, &us->users) != ALLOW)
|
if (userlist_matches(nss->parse_tree, pw, &us->users) != ALLOW)
|
||||||
continue;
|
continue;
|
||||||
@@ -147,7 +150,7 @@ sudoers_lookup_check(struct sudo_nss *nss, struct passwd *pw,
|
|||||||
NULL);
|
NULL);
|
||||||
if (runas_match == ALLOW) {
|
if (runas_match == ALLOW) {
|
||||||
cmnd_match = cmnd_matches(nss->parse_tree, cs->cmnd,
|
cmnd_match = cmnd_matches(nss->parse_tree, cs->cmnd,
|
||||||
cs->runchroot);
|
cs->runchroot, info);
|
||||||
if (cmnd_match != UNSPEC) {
|
if (cmnd_match != UNSPEC) {
|
||||||
/*
|
/*
|
||||||
* If user is running command as himself,
|
* If user is running command as himself,
|
||||||
@@ -167,6 +170,8 @@ sudoers_lookup_check(struct sudo_nss *nss, struct passwd *pw,
|
|||||||
cmnd_match ? "allowed" : "denied");
|
cmnd_match ? "allowed" : "denied");
|
||||||
debug_return_int(cmnd_match);
|
debug_return_int(cmnd_match);
|
||||||
}
|
}
|
||||||
|
free(info->cmnd_path);
|
||||||
|
memset(info, 0, sizeof(*info));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -327,13 +332,15 @@ apply_cmndspec(struct cmndspec *cs)
|
|||||||
* allowed to run the specified command on this host as the target user.
|
* allowed to run the specified command on this host as the target user.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
sudoers_lookup(struct sudo_nss_list *snl, struct passwd *pw, int validated,
|
sudoers_lookup(struct sudo_nss_list *snl, struct passwd *pw, int *cmnd_status,
|
||||||
int pwflag)
|
int pwflag)
|
||||||
{
|
{
|
||||||
struct defaults_list *defs = NULL;
|
struct defaults_list *defs = NULL;
|
||||||
struct sudoers_parse_tree *parse_tree = NULL;
|
struct sudoers_parse_tree *parse_tree = NULL;
|
||||||
struct cmndspec *cs = NULL;
|
struct cmndspec *cs = NULL;
|
||||||
struct sudo_nss *nss;
|
struct sudo_nss *nss;
|
||||||
|
struct cmnd_info info;
|
||||||
|
int validated = FLAG_NO_USER | FLAG_NO_HOST;
|
||||||
int m, match = UNSPEC;
|
int m, match = UNSPEC;
|
||||||
time_t now;
|
time_t now;
|
||||||
debug_decl(sudoers_lookup, SUDOERS_DEBUG_PARSER);
|
debug_decl(sudoers_lookup, SUDOERS_DEBUG_PARSER);
|
||||||
@@ -357,7 +364,7 @@ sudoers_lookup(struct sudo_nss_list *snl, struct passwd *pw, int validated,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
m = sudoers_lookup_check(nss, pw, &validated, &cs, &defs, now);
|
m = sudoers_lookup_check(nss, pw, &validated, &info, &cs, &defs, now);
|
||||||
if (m != UNSPEC) {
|
if (m != UNSPEC) {
|
||||||
match = m;
|
match = m;
|
||||||
parse_tree = nss->parse_tree;
|
parse_tree = nss->parse_tree;
|
||||||
@@ -367,6 +374,14 @@ sudoers_lookup(struct sudo_nss_list *snl, struct passwd *pw, int validated,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (match != UNSPEC) {
|
if (match != UNSPEC) {
|
||||||
|
if (info.cmnd_path != NULL) {
|
||||||
|
/* Update user_cmnd, user_stat, cmnd_status from matching entry. */
|
||||||
|
free(user_cmnd);
|
||||||
|
user_cmnd = info.cmnd_path;
|
||||||
|
if (user_stat != NULL)
|
||||||
|
*user_stat = info.cmnd_stat;
|
||||||
|
*cmnd_status = info.status;
|
||||||
|
}
|
||||||
if (defs != NULL)
|
if (defs != NULL)
|
||||||
update_defaults(parse_tree, defs, SETDEF_GENERIC, false);
|
update_defaults(parse_tree, defs, SETDEF_GENERIC, false);
|
||||||
if (!apply_cmndspec(cs))
|
if (!apply_cmndspec(cs))
|
||||||
@@ -876,7 +891,7 @@ display_cmnd_check(struct sudoers_parse_tree *parse_tree, struct passwd *pw,
|
|||||||
cs->runasgrouplist, NULL, NULL);
|
cs->runasgrouplist, NULL, NULL);
|
||||||
if (runas_match == ALLOW) {
|
if (runas_match == ALLOW) {
|
||||||
cmnd_match = cmnd_matches(parse_tree, cs->cmnd,
|
cmnd_match = cmnd_matches(parse_tree, cs->cmnd,
|
||||||
cs->runchroot);
|
cs->runchroot, NULL);
|
||||||
if (cmnd_match != UNSPEC)
|
if (cmnd_match != UNSPEC)
|
||||||
debug_return_int(cmnd_match);
|
debug_return_int(cmnd_match);
|
||||||
}
|
}
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
#ifndef SUDOERS_PARSE_H
|
#ifndef SUDOERS_PARSE_H
|
||||||
#define SUDOERS_PARSE_H
|
#define SUDOERS_PARSE_H
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
#include "sudo_queue.h"
|
#include "sudo_queue.h"
|
||||||
|
|
||||||
/* Characters that must be quoted in sudoers. */
|
/* Characters that must be quoted in sudoers. */
|
||||||
@@ -281,6 +282,15 @@ struct sudoers_parse_tree {
|
|||||||
const char *shost, *lhost;
|
const char *shost, *lhost;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Info about the command being resolved.
|
||||||
|
*/
|
||||||
|
struct cmnd_info {
|
||||||
|
struct stat cmnd_stat;
|
||||||
|
char *cmnd_path;
|
||||||
|
int status;
|
||||||
|
};
|
||||||
|
|
||||||
/* alias.c */
|
/* alias.c */
|
||||||
struct rbtree *alloc_aliases(void);
|
struct rbtree *alloc_aliases(void);
|
||||||
void free_aliases(struct rbtree *aliases);
|
void free_aliases(struct rbtree *aliases);
|
||||||
@@ -312,7 +322,7 @@ void reparent_parse_tree(struct sudoers_parse_tree *new_tree);
|
|||||||
bool addr_matches(char *n);
|
bool addr_matches(char *n);
|
||||||
|
|
||||||
/* match_command.c */
|
/* match_command.c */
|
||||||
bool command_matches(const char *sudoers_cmnd, const char *sudoers_args, const char *runchroot, const struct command_digest_list *digests);
|
bool command_matches(const char *sudoers_cmnd, const char *sudoers_args, const char *runchroot, struct cmnd_info *info, const struct command_digest_list *digests);
|
||||||
|
|
||||||
/* match_digest.c */
|
/* match_digest.c */
|
||||||
bool digest_matches(int fd, const char *file, const struct command_digest_list *digests);
|
bool digest_matches(int fd, const char *file, const struct command_digest_list *digests);
|
||||||
@@ -325,8 +335,8 @@ bool hostname_matches(const char *shost, const char *lhost, const char *pattern)
|
|||||||
bool netgr_matches(const char *netgr, const char *lhost, const char *shost, const char *user);
|
bool netgr_matches(const char *netgr, const char *lhost, const char *shost, const char *user);
|
||||||
bool usergr_matches(const char *group, const char *user, const struct passwd *pw);
|
bool usergr_matches(const char *group, const char *user, const struct passwd *pw);
|
||||||
bool userpw_matches(const char *sudoers_user, const char *user, const struct passwd *pw);
|
bool userpw_matches(const char *sudoers_user, const char *user, const struct passwd *pw);
|
||||||
int cmnd_matches(struct sudoers_parse_tree *parse_tree, const struct member *m, const char *runchroot);
|
int cmnd_matches(struct sudoers_parse_tree *parse_tree, const struct member *m, const char *runchroot, struct cmnd_info *info);
|
||||||
int cmndlist_matches(struct sudoers_parse_tree *parse_tree, const struct member_list *list, const char *runchroot);
|
int cmndlist_matches(struct sudoers_parse_tree *parse_tree, const struct member_list *list, const char *runchroot, struct cmnd_info *info);
|
||||||
int host_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, const char *host, const char *shost, const struct member *m);
|
int host_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, const char *host, const char *shost, const struct member *m);
|
||||||
int hostlist_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, const struct member_list *list);
|
int hostlist_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, const struct member_list *list);
|
||||||
int runaslist_matches(struct sudoers_parse_tree *parse_tree, const struct member_list *user_list, const struct member_list *group_list, struct member **matching_user, struct member **matching_group);
|
int runaslist_matches(struct sudoers_parse_tree *parse_tree, const struct member_list *user_list, const struct member_list *group_list, struct member **matching_user, struct member **matching_group);
|
||||||
@@ -362,7 +372,7 @@ const char *digest_type_to_name(int digest_type);
|
|||||||
|
|
||||||
/* parse.c */
|
/* parse.c */
|
||||||
struct sudo_nss_list;
|
struct sudo_nss_list;
|
||||||
int sudoers_lookup(struct sudo_nss_list *snl, struct passwd *pw, int validated, int pwflag);
|
int sudoers_lookup(struct sudo_nss_list *snl, struct passwd *pw, int *cmnd_status, int pwflag);
|
||||||
int display_privs(struct sudo_nss_list *snl, struct passwd *pw, bool verbose);
|
int display_privs(struct sudo_nss_list *snl, struct passwd *pw, bool verbose);
|
||||||
int display_cmnd(struct sudo_nss_list *snl, struct passwd *pw);
|
int display_cmnd(struct sudo_nss_list *snl, struct passwd *pw);
|
||||||
|
|
||||||
|
@@ -418,8 +418,7 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
|
|||||||
* Check sudoers sources, using the locale specified in sudoers.
|
* Check sudoers sources, using the locale specified in sudoers.
|
||||||
*/
|
*/
|
||||||
sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
|
sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
|
||||||
validated = sudoers_lookup(snl, sudo_user.pw, FLAG_NO_USER | FLAG_NO_HOST,
|
validated = sudoers_lookup(snl, sudo_user.pw, &cmnd_status, pwflag);
|
||||||
pwflag);
|
|
||||||
if (ISSET(validated, VALIDATE_ERROR)) {
|
if (ISSET(validated, VALIDATE_ERROR)) {
|
||||||
/* The lookup function should have printed an error. */
|
/* The lookup function should have printed an error. */
|
||||||
goto done;
|
goto done;
|
||||||
|
@@ -337,7 +337,7 @@ main(int argc, char *argv[])
|
|||||||
if (runas_match == ALLOW) {
|
if (runas_match == ALLOW) {
|
||||||
puts("\trunas matched");
|
puts("\trunas matched");
|
||||||
cmnd_match = cmnd_matches(&parsed_policy, cs->cmnd,
|
cmnd_match = cmnd_matches(&parsed_policy, cs->cmnd,
|
||||||
cs->runchroot);
|
cs->runchroot, NULL);
|
||||||
if (cmnd_match != UNSPEC)
|
if (cmnd_match != UNSPEC)
|
||||||
match = cmnd_match;
|
match = cmnd_match;
|
||||||
printf("\tcmnd %s\n", match == ALLOW ? "allowed" :
|
printf("\tcmnd %s\n", match == ALLOW ? "allowed" :
|
||||||
|
Reference in New Issue
Block a user