Make it possible to call the sudoers policy check function multiple times.

We need to reset the Defaults values to their original state.
This commit is contained in:
Todd C. Miller
2021-08-09 15:50:25 -06:00
parent a556b373c9
commit 132936f8f0
13 changed files with 150 additions and 70 deletions

View File

@@ -192,8 +192,12 @@ bsdauth_cleanup(struct passwd *pw, sudo_auth *auth, bool force)
if (state != NULL) {
auth_close(state->as);
state->as = NULL;
login_close(state->lc);
state->lc = NULL;
auth->data = NULL;
}
login_style = NULL;
debug_return_int(AUTH_SUCCESS);
}

View File

@@ -528,7 +528,6 @@ sudo_pam_begin_session(struct passwd *pw, char **user_envp[], sudo_auth *auth)
if (!env_init(*user_envp) || !env_merge(pam_envp))
status = AUTH_FATAL;
*user_envp = env_get();
(void)env_init(NULL);
free(pam_envp);
/* XXX - we leak any duplicates that were in pam_envp */
}

View File

@@ -450,7 +450,7 @@ free_defs_val(int type, union sudo_defs_val *sd_un)
bool
init_defaults(void)
{
static int firsttime = 1;
static bool firsttime = true;
struct sudo_defs_types *def;
debug_decl(init_defaults, SUDOERS_DEBUG_DEFAULTS);
@@ -645,7 +645,7 @@ init_defaults(void)
/* Init eventlog config. */
init_eventlog_config();
firsttime = 0;
firsttime = false;
debug_return_bool(true);
oom:
@@ -1127,3 +1127,36 @@ list_op(const char *str, size_t len, union sudo_defs_val *sd_un,
}
debug_return_bool(true);
}
bool
append_default(const char *var, const char *val, int op,
char *source, struct defaults_list *defs)
{
struct defaults *def;
debug_decl(append_default, SUDOERS_DEBUG_DEFAULTS);
if ((def = calloc(1, sizeof(*def))) == NULL)
goto oom;
def->type = DEFAULTS;
def->op = op;
if ((def->var = strdup(var)) == NULL) {
goto oom;
}
if (val != NULL) {
if ((def->val = strdup(val)) == NULL)
goto oom;
}
def->file = source;
sudo_rcstr_addref(source);
TAILQ_INSERT_TAIL(defs, def, entries);
debug_return_bool(true);
oom:
if (def != NULL) {
free(def->var);
free(def->val);
free(def);
}
debug_return_bool(false);
}

View File

@@ -137,6 +137,7 @@ bool set_early_default(const char *var, const char *val, int op, const char *fil
bool set_default(const char *var, const char *val, int op, const char *file, int line, int column, bool quiet);
bool update_defaults(struct sudoers_parse_tree *parse_tree, struct defaults_list *defs, int what, bool quiet);
bool check_defaults(struct sudoers_parse_tree *parse_tree, bool quiet);
bool append_default(const char *var, const char *val, int op, char *source, struct defaults_list *defs);
extern struct sudo_defs_types sudo_defs_table[];

View File

@@ -60,6 +60,7 @@ sudo_file_open(struct sudo_nss *nss)
debug_decl(sudo_file_open, SUDOERS_DEBUG_NSS);
struct sudo_file_handle *handle;
/* Note: relies on defaults being initialized early. */
if (def_ignore_local_sudoers)
debug_return_int(-1);

View File

@@ -449,7 +449,7 @@ sudo_ldap_parse_options(LDAP *ld, LDAPMessage *entry, struct defaults_list *defs
int op;
op = sudo_ldap_parse_option((*p)->bv_val, &var, &val);
if (!sudo_ldap_add_default(var, val, op, source, defs)) {
if (!append_default(var, val, op, source, defs)) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
goto done;
}

View File

@@ -242,39 +242,6 @@ oom:
debug_return_ptr(NULL);
}
bool
sudo_ldap_add_default(const char *var, const char *val, int op,
char *source, struct defaults_list *defs)
{
struct defaults *def;
debug_decl(sudo_ldap_add_default, SUDOERS_DEBUG_LDAP);
if ((def = calloc(1, sizeof(*def))) == NULL)
goto oom;
def->type = DEFAULTS;
def->op = op;
if ((def->var = strdup(var)) == NULL) {
goto oom;
}
if (val != NULL) {
if ((def->val = strdup(val)) == NULL)
goto oom;
}
def->file = source;
sudo_rcstr_addref(source);
TAILQ_INSERT_TAIL(defs, def, entries);
debug_return_bool(true);
oom:
if (def != NULL) {
free(def->var);
free(def->val);
free(def);
}
debug_return_bool(false);
}
/*
* If a digest prefix is present, add it to struct command_digest_list
* and update cmnd to point to the command after the digest.
@@ -583,7 +550,7 @@ sudo_ldap_role_to_priv(const char *cn, void *hosts, void *runasusers,
break;
#endif /* HAVE_PRIV_SET */
} else if (store_options) {
if (!sudo_ldap_add_default(var, val, op, source,
if (!append_default(var, val, op, source,
&priv->defaults)) {
break;
}

View File

@@ -59,7 +59,7 @@ static bool session_opened;
extern sudo_dso_public struct policy_plugin sudoers_policy;
#ifdef HAVE_BSD_AUTH_H
extern char *login_style;
char *login_style;
#endif /* HAVE_BSD_AUTH_H */
static int
@@ -92,7 +92,7 @@ parse_bool(const char *line, int varlen, int *flags, int fval)
* Fills in struct sudo_user and other common sudoers state.
*/
int
sudoers_policy_deserialize_info(void *v)
sudoers_policy_deserialize_info(void *v, struct defaults_list *defaults)
{
struct sudoers_open_info *info = v;
const char *p, *errstr, *groups = NULL;
@@ -221,7 +221,8 @@ sudoers_policy_deserialize_info(void *v)
if (MATCHES(*cur, "prompt=")) {
/* Allow epmpty prompt. */
user_prompt = *cur + sizeof("prompt=") - 1;
def_passprompt_override = true;
if (!append_default("passprompt_override", "true", true, NULL, defaults))
goto oom;
continue;
}
if (MATCHES(*cur, "set_home=")) {
@@ -281,7 +282,8 @@ sudoers_policy_deserialize_info(void *v)
if (MATCHES(*cur, "login_class=")) {
CHECK(*cur, "login_class=");
login_class = *cur + sizeof("login_class=") - 1;
def_use_loginclass = true;
if (!append_default("use_loginclass", "true", true, NULL, defaults))
goto oom;
continue;
}
#ifdef HAVE_SELINUX
@@ -304,7 +306,7 @@ sudoers_policy_deserialize_info(void *v)
#endif /* HAVE_SELINUX */
#ifdef HAVE_BSD_AUTH_H
if (MATCHES(*cur, "bsdauth_type=")) {
CHECK(*cur, "login_style=");
CHECK(*cur, "bsdauth_type=");
login_style = *cur + sizeof("bsdauth_type=") - 1;
continue;
}
@@ -965,6 +967,7 @@ sudoers_policy_open(unsigned int version, sudo_conv_t conversation,
if (sudo_version >= SUDO_API_MKVERSION(1, 15))
*errstr = audit_msg;
}
debug_return_int(ret);
}

View File

@@ -383,21 +383,24 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
sudoers_policy.show_version(true);
break;
case PASS_CHECK_LOG_LOCAL: {
struct list_members savedlist;
/* sudo command w/ local I/O logging (MODE_RUN) */
memcpy(&savedlist, &def_log_servers, sizeof(savedlist));
SLIST_INIT(&def_log_servers);
sudoers_policy.check_policy(argv.len, argv.entries,
env_add.entries, &command_info, &argv_out, &user_env_out,
&errstr);
/* call check_policy() again to check for leaks. */
sudoers_policy.check_policy(argv.len, argv.entries,
env_add.entries, &command_info, &argv_out, &user_env_out,
&errstr);
/* sudo_auth_begin_session() is stubbed out below. */
sudoers_policy.init_session(NULL, NULL, NULL);
memcpy(&def_log_servers, &savedlist, sizeof(savedlist));
break;
}
case PASS_CHECK_LOG_REMOTE:
/* sudo command w/ remote I/O logging (MODE_RUN) */
sudoers_policy.check_policy(argv.len, argv.entries,
env_add.entries, &command_info, &argv_out, &user_env_out,
&errstr);
/* call check_policy() again to check for leaks. */
sudoers_policy.check_policy(argv.len, argv.entries,
env_add.entries, &command_info, &argv_out, &user_env_out,
&errstr);
@@ -414,6 +417,10 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
break;
case PASS_CHECK_NOT_FOUND_DOT:
/* sudo command (found but in cwd) */
sudoers_policy.check_policy(argv.len, argv.entries,
env_add.entries, &command_info, &argv_out, &user_env_out,
&errstr);
/* call check_policy() again to check for leaks. */
sudoers_policy.check_policy(argv.len, argv.entries,
env_add.entries, &command_info, &argv_out, &user_env_out,
&errstr);
@@ -423,23 +430,34 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
case PASS_LIST:
/* sudo -l (MODE_LIST) */
sudoers_policy.list(0, NULL, false, NULL, &errstr);
/* call list() again to check for leaks. */
sudoers_policy.list(0, NULL, false, NULL, &errstr);
break;
case PASS_LIST_OTHER:
/* sudo -l -U root (MODE_LIST) */
sudoers_policy.list(0, NULL, false, "root", &errstr);
/* call list() again to check for leaks. */
sudoers_policy.list(0, NULL, false, "root", &errstr);
break;
case PASS_LIST_CHECK:
/* sudo -l command (MODE_CHECK) */
sudoers_policy.list(argv.len, argv.entries, false, NULL,
&errstr);
/* call list() again to check for leaks. */
sudoers_policy.list(argv.len, argv.entries, false, NULL,
&errstr);
break;
case PASS_VALIDATE:
/* sudo -v (MODE_VALIDATE) */
sudoers_policy.validate(&errstr);
/* call validate() again to check for leaks. */
sudoers_policy.validate(&errstr);
break;
case PASS_INVALIDATE:
/* sudo -k */
sudoers_policy.invalidate(false);
/* call invalidate() again to check for leaks. */
sudoers_policy.invalidate(false);
break;
}
}
@@ -608,11 +626,13 @@ sudo_file_getdefs(struct sudo_nss *nss)
set_default("iolog_mode", "0640", true, "sudoers", 1, 1, false);
set_default("iolog_user", NULL, false, "sudoers", 1, 1, false);
set_default("iolog_group", NULL, false, "sudoers", 1, 1, false);
if (pass != PASS_CHECK_LOG_LOCAL) {
set_default("log_servers", "localhost", true, "sudoers", 1, 1, false);
set_default("log_server_timeout", "30", true, "sudoers", 1, 1, false);
set_default("log_server_cabundle", "/etc/ssl/cacert.pem", true, "sudoers", 1, 1, false);
set_default("log_server_peer_cert", "/etc/ssl/localhost.crt", true, "sudoers", 1, 1, false);
set_default("log_server_peer_key", "/etc/ssl/private/localhost.key", true, "sudoers", 1, 1, false);
}
return 0;
}

View File

@@ -460,7 +460,7 @@ sudo_sss_parse_options(struct sudo_sss_handle *handle, struct sss_sudo_rule *rul
int op;
op = sudo_ldap_parse_option(val_array[i], &var, &val);
if (!sudo_ldap_add_default(var, val, op, source, defs))
if (!append_default(var, val, op, source, defs))
goto oom;
}
ret = true;

View File

@@ -24,7 +24,6 @@ typedef char * (*sudo_ldap_iter_t)(void **);
/* ldap_util.c */
bool sudo_ldap_is_negated(char **valp);
bool sudo_ldap_add_default(const char *var, const char *val, int op, char *source, struct defaults_list *defs);
int sudo_ldap_parse_option(char *optstr, char **varp, char **valp);
struct privilege *sudo_ldap_role_to_priv(const char *cn, void *hosts, void *runasusers, void *runasgroups, void *cmnds, void *opts, const char *notbefore, const char *notafter, bool warnings, bool store_options, sudo_ldap_iter_t iter);
struct member *sudo_ldap_new_member_all(void);

View File

@@ -85,9 +85,6 @@ struct sudo_user sudo_user;
struct passwd *list_pw;
uid_t timestamp_uid;
gid_t timestamp_gid;
#ifdef HAVE_BSD_AUTH_H
char *login_style;
#endif /* HAVE_BSD_AUTH_H */
bool force_umask;
int sudo_mode;
@@ -96,6 +93,7 @@ static struct sudo_nss_list *snl;
static bool unknown_runas_uid;
static bool unknown_runas_gid;
static int cmnd_status = -1;
static struct defaults_list initial_defaults = TAILQ_HEAD_INITIALIZER(initial_defaults);
#ifdef __linux__
static struct rlimit nproclimit;
@@ -151,6 +149,36 @@ restore_nproc(void)
#endif /* __linux__ */
}
static bool
sudoers_reinit_defaults(void)
{
struct sudo_nss *nss, *nss_next;
debug_decl(sudoers_reinit_defaults, SUDOERS_DEBUG_PLUGIN);
if (!init_defaults()) {
sudo_warnx("%s", U_("unable to initialize sudoers default values"));
debug_return_bool(false);
}
if (!update_defaults(NULL, &initial_defaults,
SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER|SETDEF_RUNAS, false)) {
log_warningx(SLOG_SEND_MAIL|SLOG_NO_STDERR,
N_("problem with defaults entries"));
debug_return_bool(false);
}
TAILQ_FOREACH_SAFE(nss, snl, entries, nss_next) {
if (nss->getdefs(nss) == -1 || !update_defaults(nss->parse_tree, NULL,
SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER|SETDEF_RUNAS, false)) {
log_warningx(SLOG_SEND_MAIL|SLOG_NO_STDERR,
N_("problem with defaults entries"));
/* not a fatal error */
}
}
debug_return_int(true);
}
int
sudoers_init(void *info, char * const envp[])
{
@@ -179,7 +207,7 @@ sudoers_init(void *info, char * const envp[])
}
/* Parse info from front-end. */
sudo_mode = sudoers_policy_deserialize_info(info);
sudo_mode = sudoers_policy_deserialize_info(info, &initial_defaults);
if (ISSET(sudo_mode, MODE_ERROR))
debug_return_int(-1);
@@ -193,6 +221,14 @@ sudoers_init(void *info, char * const envp[])
if (!set_perms(PERM_ROOT))
debug_return_int(-1);
/* Update defaults set by front-end. */
if (!update_defaults(NULL, &initial_defaults,
SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER|SETDEF_RUNAS, false)) {
log_warningx(SLOG_SEND_MAIL|SLOG_NO_STDERR,
N_("problem with defaults entries"));
debug_return_int(-1);
}
/*
* Open and parse sudoers, set global defaults.
* Uses the C locale unless another is specified in sudoers.
@@ -329,13 +365,14 @@ check_user_runcwd(void)
debug_return_bool(true);
}
static bool need_reinit;
int
sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
bool verbose, void *closure)
{
char *iolog_path = NULL;
mode_t cmnd_umask = ACCESSPERMS;
struct sudo_nss *nss;
int oldlocale, validated, ret = -1;
debug_decl(sudoers_policy_main, SUDOERS_DEBUG_PLUGIN);
@@ -346,6 +383,13 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
debug_return_int(-1);
}
/* Re-initialize defaults if we are called multiple times. */
if (need_reinit) {
if (!sudoers_reinit_defaults())
debug_return_int(-1);
}
need_reinit = true;
unlimit_nproc();
/* Is root even allowed to run sudo? */
@@ -740,11 +784,6 @@ bad:
ret = false;
done:
/* Cleanup sudoers sources */
TAILQ_FOREACH(nss, snl, entries) {
nss->close(nss);
}
snl = NULL;
if (def_group_plugin)
group_plugin_unload();
init_parser(NULL, false, false);
@@ -764,10 +803,6 @@ done:
restore_nproc();
/* Destroy the password and group caches and free the contents. */
sudo_freepwcache();
sudo_freegrcache();
sudo_warn_set_locale_func(NULL);
debug_return_int(ret);
@@ -884,6 +919,8 @@ set_cmnd_path(const char *runchroot)
int ret;
debug_decl(set_cmnd_path, SUDOERS_DEBUG_PLUGIN);
free(user_cmnd);
user_cmnd = NULL;
if (def_secure_path && !user_is_exempt())
path = def_secure_path;
if (!set_perms(PERM_RUNAS))
@@ -917,12 +954,17 @@ set_cmnd(void)
debug_decl(set_cmnd, SUDOERS_DEBUG_PLUGIN);
/* Allocate user_stat for find_path() and match functions. */
free(user_stat);
user_stat = calloc(1, sizeof(struct stat));
if (user_stat == NULL) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
debug_return_int(NOT_FOUND_ERROR);
}
/* Re-initialize for when we are called multiple times. */
free(safe_cmnd);
safe_cmnd = NULL;
if (ISSET(sudo_mode, MODE_RUN|MODE_EDIT|MODE_CHECK)) {
if (!ISSET(sudo_mode, MODE_EDIT)) {
const char *runchroot = user_runchroot;
@@ -941,6 +983,8 @@ set_cmnd(void)
}
/* set user_args */
free(user_args);
user_args = NULL;
if (NewArgc > 1) {
if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL) &&
ISSET(sudo_mode, MODE_RUN)) {
@@ -1600,11 +1644,13 @@ set_callbacks(void)
/*
* Cleanup hook for sudo_fatal()/sudo_fatalx()
* Also called at policy close time.
*/
void
sudoers_cleanup(void)
{
struct sudo_nss *nss;
struct defaults *def;
debug_decl(sudoers_cleanup, SUDOERS_DEBUG_PLUGIN);
if (snl != NULL) {
@@ -1614,6 +1660,13 @@ sudoers_cleanup(void)
snl = NULL;
init_parser(NULL, false, false);
}
while ((def = TAILQ_FIRST(&initial_defaults)) != NULL) {
TAILQ_REMOVE(&initial_defaults, def, entries);
free(def->var);
free(def->val);
free(def);
}
need_reinit = false;
if (def_group_plugin)
group_plugin_unload();
sudo_user_free();

View File

@@ -426,7 +426,7 @@ bool sudoers_debug_register(const char *plugin_path, struct sudo_conf_debug_file
void sudoers_debug_deregister(void);
/* policy.c */
int sudoers_policy_deserialize_info(void *v);
int sudoers_policy_deserialize_info(void *v, struct defaults_list *defaults);
bool sudoers_policy_store_result(bool accepted, char *argv[], char *envp[], mode_t cmnd_umask, char *iolog_path, void *v);
extern const char *path_ldap_conf;
extern const char *path_ldap_secret;