From: Todd C. Miller Date: Fri, 24 Aug 2018 16:27:00 +0000 (-0600) Subject: Eliminate most use of parsed_sudoers in cvtsudoers X-Git-Tag: SUDO_1_8_25^2~28 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5d1dddc467dac05387acdfb4016924ab084e4a92;p=sudo Eliminate most use of parsed_sudoers in cvtsudoers --- diff --git a/plugins/sudoers/cvtsudoers.c b/plugins/sudoers/cvtsudoers.c index ad0e374f0..a2881f0d7 100644 --- a/plugins/sudoers/cvtsudoers.c +++ b/plugins/sudoers/cvtsudoers.c @@ -78,17 +78,17 @@ static struct option long_opts[] = { __dso_public int main(int argc, char *argv[]); static void help(void) __attribute__((__noreturn__)); static void usage(int); -static bool convert_sudoers_sudoers(const char *output_file, struct cvtsudoers_config *conf); +static bool convert_sudoers_sudoers(struct sudoers_parse_tree *parse_tree, const char *output_file, struct cvtsudoers_config *conf); static bool parse_sudoers(const char *input_file, struct cvtsudoers_config *conf); static bool cvtsudoers_parse_filter(char *expression); static struct cvtsudoers_config *cvtsudoers_conf_read(const char *conf_file); static void cvtsudoers_conf_free(struct cvtsudoers_config *conf); static int cvtsudoers_parse_defaults(char *expression); static int cvtsudoers_parse_suppression(char *expression); -static void filter_userspecs(struct cvtsudoers_config *conf); -static void filter_defaults(struct cvtsudoers_config *conf); -static void alias_remove_unused(void); -static void alias_prune(struct cvtsudoers_config *conf); +static void filter_userspecs(struct sudoers_parse_tree *parse_tree, struct cvtsudoers_config *conf); +static void filter_defaults(struct sudoers_parse_tree *parse_tree, struct cvtsudoers_config *conf); +static void alias_remove_unused(struct sudoers_parse_tree *parse_tree); +static void alias_prune(struct sudoers_parse_tree *parse_tree, struct cvtsudoers_config *conf); int main(int argc, char *argv[]) @@ -309,7 +309,7 @@ main(int argc, char *argv[]) switch (input_format) { case format_ldif: - if (!parse_ldif(input_file, conf)) + if (!parse_ldif(&parsed_policy, input_file, conf)) goto done; break; case format_sudoers: @@ -321,23 +321,23 @@ main(int argc, char *argv[]) } /* Apply filters. */ - filter_userspecs(conf); - filter_defaults(conf); + filter_userspecs(&parsed_policy, conf); + filter_defaults(&parsed_policy, conf); if (filters != NULL) { - alias_remove_unused(); + alias_remove_unused(&parsed_policy); if (conf->prune_matches && conf->expand_aliases) - alias_prune(conf); + alias_prune(&parsed_policy, conf); } switch (output_format) { case format_json: - exitcode = !convert_sudoers_json(output_file, conf); + exitcode = !convert_sudoers_json(&parsed_policy, output_file, conf); break; case format_ldif: - exitcode = !convert_sudoers_ldif(output_file, conf); + exitcode = !convert_sudoers_ldif(&parsed_policy, output_file, conf); break; case format_sudoers: - exitcode = !convert_sudoers_sudoers(output_file, conf); + exitcode = !convert_sudoers_sudoers(&parsed_policy, output_file, conf); break; default: sudo_fatalx("error: unhandled output format %d", output_format); @@ -677,7 +677,8 @@ open_sudoers(const char *sudoers, bool doedit, bool *keepopen) } static bool -userlist_matches_filter(struct member_list *users, struct cvtsudoers_config *conf) +userlist_matches_filter(struct sudoers_parse_tree *parse_tree, + struct member_list *users, struct cvtsudoers_config *conf) { struct cvtsudoers_string *s; struct member *m, *next; @@ -703,7 +704,7 @@ userlist_matches_filter(struct member_list *users, struct cvtsudoers_config *con pw.pw_uid = (uid_t)-1; pw.pw_gid = (gid_t)-1; - if (user_matches(&parsed_policy, &pw, m) == true) + if (user_matches(parse_tree, &pw, m) == true) matched = true; } else { STAILQ_FOREACH(s, &filters->users, entries) { @@ -729,7 +730,7 @@ userlist_matches_filter(struct member_list *users, struct cvtsudoers_config *con if (pw == NULL) continue; - if (user_matches(&parsed_policy, pw, m) == true) + if (user_matches(parse_tree, pw, m) == true) matched = true; sudo_pw_delref(pw); @@ -751,7 +752,8 @@ userlist_matches_filter(struct member_list *users, struct cvtsudoers_config *con } static bool -hostlist_matches_filter(struct member_list *hostlist, struct cvtsudoers_config *conf) +hostlist_matches_filter(struct sudoers_parse_tree *parse_tree, + struct member_list *hostlist, struct cvtsudoers_config *conf) { struct cvtsudoers_string *s; struct member *m, *next; @@ -804,7 +806,7 @@ hostlist_matches_filter(struct member_list *hostlist, struct cvtsudoers_config * /* Only need one host in the filter to match. */ /* XXX - can't use netgroup_tuple with NULL pw */ - if (host_matches(&parsed_policy, NULL, lhost, shost, m) == true) { + if (host_matches(parse_tree, NULL, lhost, shost, m) == true) { matched = true; break; } @@ -835,13 +837,14 @@ hostlist_matches_filter(struct member_list *hostlist, struct cvtsudoers_config * * Display Defaults entries */ static bool -print_defaults_sudoers(struct sudo_lbuf *lbuf, bool expand_aliases) +print_defaults_sudoers(struct sudoers_parse_tree *parse_tree, + struct sudo_lbuf *lbuf, bool expand_aliases) { struct defaults *def, *next; debug_decl(print_defaults_sudoers, SUDOERS_DEBUG_UTIL) - TAILQ_FOREACH_SAFE(def, &parsed_policy.defaults, entries, next) { - sudoers_format_default_line(lbuf, &parsed_policy, def, &next, + TAILQ_FOREACH_SAFE(def, &parse_tree->defaults, entries, next) { + sudoers_format_default_line(lbuf, parse_tree, def, &next, expand_aliases); } @@ -872,11 +875,12 @@ print_alias_sudoers(struct sudoers_parse_tree *parse_tree, struct alias *a, * Display aliases */ static bool -print_aliases_sudoers(struct sudo_lbuf *lbuf) +print_aliases_sudoers(struct sudoers_parse_tree *parse_tree, + struct sudo_lbuf *lbuf) { debug_decl(print_aliases_sudoers, SUDOERS_DEBUG_UTIL) - alias_apply(&parsed_policy, print_alias_sudoers, lbuf); + alias_apply(parse_tree, print_alias_sudoers, lbuf); debug_return_bool(!sudo_lbuf_error(lbuf)); } @@ -893,7 +897,8 @@ convert_sudoers_output(const char *buf) * Apply filters to userspecs, removing non-matching entries. */ static void -filter_userspecs(struct cvtsudoers_config *conf) +filter_userspecs(struct sudoers_parse_tree *parse_tree, + struct cvtsudoers_config *conf) { struct userspec *us, *next_us; struct privilege *priv, *next_priv; @@ -907,20 +912,20 @@ filter_userspecs(struct cvtsudoers_config *conf) * host lists. It acts more like a grep than a true filter. * In the future, we may want to add a prune option. */ - TAILQ_FOREACH_SAFE(us, &parsed_policy.userspecs, entries, next_us) { - if (!userlist_matches_filter(&us->users, conf)) { - TAILQ_REMOVE(&parsed_policy.userspecs, us, entries); + TAILQ_FOREACH_SAFE(us, &parse_tree->userspecs, entries, next_us) { + if (!userlist_matches_filter(parse_tree, &us->users, conf)) { + TAILQ_REMOVE(&parse_tree->userspecs, us, entries); free_userspec(us); continue; } TAILQ_FOREACH_SAFE(priv, &us->privileges, entries, next_priv) { - if (!hostlist_matches_filter(&priv->hostlist, conf)) { + if (!hostlist_matches_filter(parse_tree, &priv->hostlist, conf)) { TAILQ_REMOVE(&us->privileges, priv, entries); free_privilege(priv); } } if (TAILQ_EMPTY(&us->privileges)) { - TAILQ_REMOVE(&parsed_policy.userspecs, us, entries); + TAILQ_REMOVE(&parse_tree->userspecs, us, entries); free_userspec(us); continue; } @@ -934,7 +939,8 @@ filter_userspecs(struct cvtsudoers_config *conf) * Returns true if matched, else false. */ static bool -alias_matches(const char *name, const char *alias_name, int alias_type) +alias_matches(struct sudoers_parse_tree *parse_tree, const char *name, + const char *alias_name, int alias_type) { struct alias *a; struct member *m; @@ -944,12 +950,12 @@ alias_matches(const char *name, const char *alias_name, int alias_type) if (strcmp(name, alias_name) == 0) debug_return_bool(true); - a = alias_get(&parsed_policy, alias_name, alias_type); + a = alias_get(parse_tree, alias_name, alias_type); if (a != NULL) { TAILQ_FOREACH(m, &a->members, entries) { if (m->type != ALIAS) continue; - if (alias_matches(name, m->name, alias_type)) { + if (alias_matches(parse_tree, name, m->name, alias_type)) { ret = true; break; } @@ -966,9 +972,9 @@ alias_matches(const char *name, const char *alias_name, int alias_type) * This does *not* check Defaults for used aliases, only userspecs. */ static void -alias_used_by_userspecs(struct member_list *user_aliases, - struct member_list *runas_aliases, struct member_list *host_aliases, - struct member_list *cmnd_aliases) +alias_used_by_userspecs(struct sudoers_parse_tree *parse_tree, + struct member_list *user_aliases, struct member_list *runas_aliases, + struct member_list *host_aliases, struct member_list *cmnd_aliases) { struct privilege *priv, *priv_next; struct userspec *us, *us_next; @@ -978,12 +984,12 @@ alias_used_by_userspecs(struct member_list *user_aliases, debug_decl(alias_used_by_userspecs, SUDOERS_DEBUG_ALIAS) /* Iterate over the policy, checking for aliases. */ - TAILQ_FOREACH_SAFE(us, &parsed_policy.userspecs, entries, us_next) { + TAILQ_FOREACH_SAFE(us, &parse_tree->userspecs, entries, us_next) { TAILQ_FOREACH_SAFE(m, &us->users, entries, m_next) { if (m->type == ALIAS) { /* If alias is used, remove from user_aliases and free. */ TAILQ_FOREACH_SAFE(am, user_aliases, entries, am_next) { - if (alias_matches(am->name, m->name, USERALIAS)) { + if (alias_matches(parse_tree, am->name, m->name, USERALIAS)) { TAILQ_REMOVE(user_aliases, am, entries); free_member(am); } @@ -995,7 +1001,7 @@ alias_used_by_userspecs(struct member_list *user_aliases, if (m->type == ALIAS) { /* If alias is used, remove from host_aliases and free. */ TAILQ_FOREACH_SAFE(am, host_aliases, entries, am_next) { - if (alias_matches(am->name, m->name, HOSTALIAS)) { + if (alias_matches(parse_tree, am->name, m->name, HOSTALIAS)) { TAILQ_REMOVE(host_aliases, am, entries); free_member(am); } @@ -1008,7 +1014,7 @@ alias_used_by_userspecs(struct member_list *user_aliases, if (m->type == ALIAS) { /* If alias is used, remove from runas_aliases and free. */ TAILQ_FOREACH_SAFE(am, runas_aliases, entries, am_next) { - if (alias_matches(am->name, m->name, RUNASALIAS)) { + if (alias_matches(parse_tree, am->name, m->name, RUNASALIAS)) { TAILQ_REMOVE(runas_aliases, am, entries); free_member(am); } @@ -1021,7 +1027,7 @@ alias_used_by_userspecs(struct member_list *user_aliases, if (m->type == ALIAS) { /* If alias is used, remove from runas_aliases and free. */ TAILQ_FOREACH_SAFE(am, runas_aliases, entries, am_next) { - if (alias_matches(am->name, m->name, RUNASALIAS)) { + if (alias_matches(parse_tree, am->name, m->name, RUNASALIAS)) { TAILQ_REMOVE(runas_aliases, am, entries); free_member(am); } @@ -1032,7 +1038,7 @@ alias_used_by_userspecs(struct member_list *user_aliases, if ((m = cs->cmnd)->type == ALIAS) { /* If alias is used, remove from cmnd_aliases and free. */ TAILQ_FOREACH_SAFE(am, cmnd_aliases, entries, am_next) { - if (alias_matches(am->name, m->name, CMNDALIAS)) { + if (alias_matches(parse_tree, am->name, m->name, CMNDALIAS)) { TAILQ_REMOVE(cmnd_aliases, am, entries); free_member(am); } @@ -1049,7 +1055,8 @@ alias_used_by_userspecs(struct member_list *user_aliases, * Apply filters to host/user-based Defaults, removing non-matching entries. */ static void -filter_defaults(struct cvtsudoers_config *conf) +filter_defaults(struct sudoers_parse_tree *parse_tree, + struct cvtsudoers_config *conf) { struct member_list user_aliases = TAILQ_HEAD_INITIALIZER(user_aliases); struct member_list runas_aliases = TAILQ_HEAD_INITIALIZER(runas_aliases); @@ -1065,7 +1072,7 @@ filter_defaults(struct cvtsudoers_config *conf) if (filters == NULL && conf->defaults == CVT_DEFAULTS_ALL) debug_return; - TAILQ_FOREACH_SAFE(def, &parsed_policy.defaults, entries, def_next) { + TAILQ_FOREACH_SAFE(def, &parse_tree->defaults, entries, def_next) { bool keep = true; switch (def->type) { @@ -1076,7 +1083,7 @@ filter_defaults(struct cvtsudoers_config *conf) break; case DEFAULTS_USER: if (!ISSET(conf->defaults, CVT_DEFAULTS_USER) || - !userlist_matches_filter(def->binding, conf)) + !userlist_matches_filter(parse_tree, def->binding, conf)) keep = false; alias_type = USERALIAS; break; @@ -1087,7 +1094,7 @@ filter_defaults(struct cvtsudoers_config *conf) break; case DEFAULTS_HOST: if (!ISSET(conf->defaults, CVT_DEFAULTS_HOST) || - !hostlist_matches_filter(def->binding, conf)) + !hostlist_matches_filter(parse_tree, def->binding, conf)) keep = false; alias_type = HOSTALIAS; break; @@ -1129,14 +1136,14 @@ filter_defaults(struct cvtsudoers_config *conf) } } } - TAILQ_REMOVE(&parsed_policy.defaults, def, entries); + TAILQ_REMOVE(&parse_tree->defaults, def, entries); free_default(def, &prev_binding); if (prev_binding != NULL) { /* Remove and free Defaults that share the same binding. */ while (def_next != NULL && def_next->binding == prev_binding) { def = def_next; def_next = TAILQ_NEXT(def, entries); - TAILQ_REMOVE(&parsed_policy.defaults, def, entries); + TAILQ_REMOVE(&parse_tree->defaults, def, entries); free_default(def, &prev_binding); } } @@ -1146,25 +1153,25 @@ filter_defaults(struct cvtsudoers_config *conf) } /* Remove now-unreferenced aliases. */ - alias_used_by_userspecs(&user_aliases, &runas_aliases, &host_aliases, - &cmnd_aliases); + alias_used_by_userspecs(parse_tree, &user_aliases, &runas_aliases, + &host_aliases, &cmnd_aliases); TAILQ_FOREACH_SAFE(m, &user_aliases, entries, m_next) { - a = alias_remove(&parsed_policy, m->name, USERALIAS); + a = alias_remove(parse_tree, m->name, USERALIAS); alias_free(a); free_member(m); } TAILQ_FOREACH_SAFE(m, &runas_aliases, entries, m_next) { - a = alias_remove(&parsed_policy, m->name, RUNASALIAS); + a = alias_remove(parse_tree, m->name, RUNASALIAS); alias_free(a); free_member(m); } TAILQ_FOREACH_SAFE(m, &host_aliases, entries, m_next) { - a = alias_remove(&parsed_policy, m->name, HOSTALIAS); + a = alias_remove(parse_tree, m->name, HOSTALIAS); alias_free(a); free_member(m); } TAILQ_FOREACH_SAFE(m, &cmnd_aliases, entries, m_next) { - a = alias_remove(&parsed_policy, m->name, CMNDALIAS); + a = alias_remove(parse_tree, m->name, CMNDALIAS); alias_free(a); free_member(m); } @@ -1176,7 +1183,7 @@ filter_defaults(struct cvtsudoers_config *conf) * Remove unreferenced aliases. */ static void -alias_remove_unused(void) +alias_remove_unused(struct sudoers_parse_tree *parse_tree) { struct rbtree *used_aliases; debug_decl(alias_remove_unused, SUDOERS_DEBUG_ALIAS) @@ -1186,12 +1193,12 @@ alias_remove_unused(void) sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory")); /* Move all referenced aliases to used_aliases. */ - if (!alias_find_used(&parsed_policy, used_aliases)) + if (!alias_find_used(parse_tree, used_aliases)) sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory")); /* Only unreferenced aliases are left, swap and free the unused ones. */ - free_aliases(parsed_policy.aliases); - parsed_policy.aliases = used_aliases; + free_aliases(parse_tree->aliases); + parse_tree->aliases = used_aliases; debug_return; } @@ -1208,10 +1215,10 @@ alias_prune_helper(struct sudoers_parse_tree *parse_tree, struct alias *a, /* XXX - misue of these functions */ switch (a->type) { case USERALIAS: - userlist_matches_filter(&a->members, conf); + userlist_matches_filter(parse_tree, &a->members, conf); break; case HOSTALIAS: - hostlist_matches_filter(&a->members, conf); + hostlist_matches_filter(parse_tree, &a->members, conf); break; default: break; @@ -1224,11 +1231,12 @@ alias_prune_helper(struct sudoers_parse_tree *parse_tree, struct alias *a, * Prune out non-matching entries from within aliases. */ static void -alias_prune(struct cvtsudoers_config *conf) +alias_prune(struct sudoers_parse_tree *parse_tree, + struct cvtsudoers_config *conf) { debug_decl(alias_prune, SUDOERS_DEBUG_ALIAS) - alias_apply(&parsed_policy, alias_prune_helper, conf); + alias_apply(parse_tree, alias_prune_helper, conf); debug_return; } @@ -1237,7 +1245,8 @@ alias_prune(struct cvtsudoers_config *conf) * Convert back to sudoers. */ static bool -convert_sudoers_sudoers(const char *output_file, struct cvtsudoers_config *conf) +convert_sudoers_sudoers(struct sudoers_parse_tree *parse_tree, + const char *output_file, struct cvtsudoers_config *conf) { bool ret = true; struct sudo_lbuf lbuf; @@ -1255,7 +1264,7 @@ convert_sudoers_sudoers(const char *output_file, struct cvtsudoers_config *conf) /* Print Defaults */ if (!ISSET(conf->suppress, SUPPRESS_DEFAULTS)) { - if (!print_defaults_sudoers(&lbuf, conf->expand_aliases)) + if (!print_defaults_sudoers(parse_tree, &lbuf, conf->expand_aliases)) goto done; if (lbuf.len > 0) { sudo_lbuf_print(&lbuf); @@ -1265,7 +1274,7 @@ convert_sudoers_sudoers(const char *output_file, struct cvtsudoers_config *conf) /* Print Aliases */ if (!conf->expand_aliases && !ISSET(conf->suppress, SUPPRESS_ALIASES)) { - if (!print_aliases_sudoers(&lbuf)) + if (!print_aliases_sudoers(parse_tree, &lbuf)) goto done; if (lbuf.len > 1) { sudo_lbuf_print(&lbuf); @@ -1275,7 +1284,7 @@ convert_sudoers_sudoers(const char *output_file, struct cvtsudoers_config *conf) /* Print User_Specs, separated by blank lines. */ if (!ISSET(conf->suppress, SUPPRESS_PRIVS)) { - if (!sudoers_format_userspecs(&lbuf, &parsed_policy, "\n", + if (!sudoers_format_userspecs(&lbuf, parse_tree, "\n", conf->expand_aliases, true)) { goto done; } diff --git a/plugins/sudoers/cvtsudoers.h b/plugins/sudoers/cvtsudoers.h index cc3b4462b..1826b8463 100644 --- a/plugins/sudoers/cvtsudoers.h +++ b/plugins/sudoers/cvtsudoers.h @@ -94,11 +94,11 @@ struct cvtsudoers_string *cvtsudoers_string_alloc(const char *s); void cvtsudoers_string_free(struct cvtsudoers_string *ls); /* cvtsudoers_json.c */ -bool convert_sudoers_json(const char *output_file, struct cvtsudoers_config *conf); +bool convert_sudoers_json(struct sudoers_parse_tree *parse_tree, const char *output_file, struct cvtsudoers_config *conf); /* cvtsudoers_ldif.c */ -bool convert_sudoers_ldif(const char *output_file, struct cvtsudoers_config *conf); -bool parse_ldif(const char *input_file, struct cvtsudoers_config *conf); +bool convert_sudoers_ldif(struct sudoers_parse_tree *parse_tree, const char *output_file, struct cvtsudoers_config *conf); +bool parse_ldif(struct sudoers_parse_tree *parse_tree, const char *input_file, struct cvtsudoers_config *conf); void get_hostname(void); /* cvtsudoers_pwutil.c */ diff --git a/plugins/sudoers/cvtsudoers_json.c b/plugins/sudoers/cvtsudoers_json.c index 15942966e..9490579fc 100644 --- a/plugins/sudoers/cvtsudoers_json.c +++ b/plugins/sudoers/cvtsudoers_json.c @@ -330,8 +330,9 @@ defaults_to_word_type(int defaults_type) * that closes the object. */ static void -print_member_json_int(FILE *fp, char *name, int type, bool negated, - enum word_type word_type, bool last_one, int indent, bool expand_aliases) +print_member_json_int(FILE *fp, struct sudoers_parse_tree *parse_tree, + char *name, int type, bool negated, enum word_type word_type, + bool last_one, int indent, bool expand_aliases) { struct json_value value; const char *typestr = NULL; @@ -475,9 +476,9 @@ print_member_json_int(FILE *fp, char *name, int type, bool negated, struct alias *a; struct member *m; - if ((a = alias_get(&parsed_policy, value.u.string, alias_type)) != NULL) { + if ((a = alias_get(parse_tree, value.u.string, alias_type)) != NULL) { TAILQ_FOREACH(m, &a->members, entries) { - print_member_json_int(fp, m->name, m->type, + print_member_json_int(fp, parse_tree, m->name, m->type, negated ? !m->negated : m->negated, alias_to_word_type(alias_type), last_one && TAILQ_NEXT(m, entries) == NULL, indent, true); @@ -508,11 +509,12 @@ print_member_json_int(FILE *fp, char *name, int type, bool negated, } static void -print_member_json(FILE *fp, struct member *m, enum word_type word_type, - bool last_one, int indent, bool expand_aliases) +print_member_json(FILE *fp, struct sudoers_parse_tree *parse_tree, + struct member *m, enum word_type word_type, bool last_one, + int indent, bool expand_aliases) { - print_member_json_int(fp, m->name, m->type, m->negated, word_type, - last_one, indent, expand_aliases); + print_member_json_int(fp, parse_tree, m->name, m->type, m->negated, + word_type, last_one, indent, expand_aliases); } /* @@ -542,7 +544,7 @@ print_alias_json(struct sudoers_parse_tree *parse_tree, struct alias *a, void *v closure->indent += 4; TAILQ_FOREACH(m, &a->members, entries) { - print_member_json(closure->fp, m, + print_member_json(closure->fp, parse_tree, m, alias_to_word_type(closure->alias_type), TAILQ_NEXT(m, entries) == NULL, closure->indent, false); } @@ -554,7 +556,8 @@ print_alias_json(struct sudoers_parse_tree *parse_tree, struct alias *a, void *v * Print the binding for a Defaults entry of the specified type. */ static void -print_binding_json(FILE *fp, struct member_list *binding, int type, int indent, bool expand_aliases) +print_binding_json(FILE *fp, struct sudoers_parse_tree *parse_tree, + struct member_list *binding, int type, int indent, bool expand_aliases) { struct member *m; debug_decl(print_binding_json, SUDOERS_DEBUG_UTIL) @@ -567,7 +570,7 @@ print_binding_json(FILE *fp, struct member_list *binding, int type, int indent, /* Print each member object in binding. */ TAILQ_FOREACH(m, binding, entries) { - print_member_json(fp, m, defaults_to_word_type(type), + print_member_json(fp, parse_tree, m, defaults_to_word_type(type), TAILQ_NEXT(m, entries) == NULL, indent, expand_aliases); } @@ -653,20 +656,21 @@ get_defaults_type(struct defaults *def) * Export all Defaults in JSON format. */ static bool -print_defaults_json(FILE *fp, int indent, bool expand_aliases, bool need_comma) +print_defaults_json(FILE *fp, struct sudoers_parse_tree *parse_tree, + int indent, bool expand_aliases, bool need_comma) { struct json_value value; struct defaults *def, *next; int type; debug_decl(print_defaults_json, SUDOERS_DEBUG_UTIL) - if (TAILQ_EMPTY(&parsed_policy.defaults)) + if (TAILQ_EMPTY(&parse_tree->defaults)) debug_return_bool(need_comma); fprintf(fp, "%s\n%*s\"Defaults\": [\n", need_comma ? "," : "", indent, ""); indent += 4; - TAILQ_FOREACH_SAFE(def, &parsed_policy.defaults, entries, next) { + TAILQ_FOREACH_SAFE(def, &parse_tree->defaults, entries, next) { type = get_defaults_type(def); if (type == -1) { sudo_warnx(U_("unknown defaults entry \"%s\""), def->var); @@ -677,7 +681,8 @@ print_defaults_json(FILE *fp, int indent, bool expand_aliases, bool need_comma) /* Found it, print object container and binding (if any). */ fprintf(fp, "%*s{\n", indent, ""); indent += 4; - print_binding_json(fp, def->binding, def->type, indent, expand_aliases); + print_binding_json(fp, parse_tree, def->binding, def->type, + indent, expand_aliases); /* Validation checks. */ /* XXX - validate values in addition to names? */ @@ -732,8 +737,8 @@ print_defaults_json(FILE *fp, int indent, bool expand_aliases, bool need_comma) * Iterates through the entire aliases tree. */ static bool -print_aliases_by_type_json(FILE *fp, int alias_type, const char *title, - int indent, bool need_comma) +print_aliases_by_type_json(FILE *fp, struct sudoers_parse_tree *parse_tree, + int alias_type, const char *title, int indent, bool need_comma) { struct json_alias_closure closure; debug_decl(print_aliases_by_type_json, SUDOERS_DEBUG_UTIL) @@ -744,7 +749,7 @@ print_aliases_by_type_json(FILE *fp, int alias_type, const char *title, closure.alias_type = alias_type; closure.title = title; closure.need_comma = need_comma; - alias_apply(&parsed_policy, print_alias_json, &closure); + alias_apply(parse_tree, print_alias_json, &closure); if (closure.count != 0) { print_indent(fp, closure.indent); fputs("]\n", fp); @@ -761,18 +766,19 @@ print_aliases_by_type_json(FILE *fp, int alias_type, const char *title, * Export all aliases in JSON format. */ static bool -print_aliases_json(FILE *fp, int indent, bool need_comma) +print_aliases_json(FILE *fp, struct sudoers_parse_tree *parse_tree, + int indent, bool need_comma) { debug_decl(print_aliases_json, SUDOERS_DEBUG_UTIL) - need_comma = print_aliases_by_type_json(fp, USERALIAS, "User_Aliases", - indent, need_comma); - need_comma = print_aliases_by_type_json(fp, RUNASALIAS, "Runas_Aliases", - indent, need_comma); - need_comma = print_aliases_by_type_json(fp, HOSTALIAS, "Host_Aliases", - indent, need_comma); - need_comma = print_aliases_by_type_json(fp, CMNDALIAS, "Command_Aliases", - indent, need_comma); + need_comma = print_aliases_by_type_json(fp, parse_tree, USERALIAS, + "User_Aliases", indent, need_comma); + need_comma = print_aliases_by_type_json(fp, parse_tree, RUNASALIAS, + "Runas_Aliases", indent, need_comma); + need_comma = print_aliases_by_type_json(fp, parse_tree, HOSTALIAS, + "Host_Aliases", indent, need_comma); + need_comma = print_aliases_by_type_json(fp, parse_tree, CMNDALIAS, + "Command_Aliases", indent, need_comma); debug_return_bool(need_comma); } @@ -783,7 +789,8 @@ print_aliases_json(FILE *fp, int indent, bool need_comma) * merge adjacent entries that are identical in all but the command. */ static void -print_cmndspec_json(FILE *fp, struct cmndspec *cs, struct cmndspec **nextp, +print_cmndspec_json(FILE *fp, struct sudoers_parse_tree *parse_tree, + struct cmndspec *cs, struct cmndspec **nextp, struct defaults_list *options, bool expand_aliases, int indent) { struct cmndspec *next = *nextp; @@ -804,7 +811,7 @@ print_cmndspec_json(FILE *fp, struct cmndspec *cs, struct cmndspec **nextp, fprintf(fp, "%*s\"runasusers\": [\n", indent, ""); indent += 4; TAILQ_FOREACH(m, cs->runasuserlist, entries) { - print_member_json(fp, m, TYPE_RUNASUSER, + print_member_json(fp, parse_tree, m, TYPE_RUNASUSER, TAILQ_NEXT(m, entries) == NULL, indent, expand_aliases); } indent -= 4; @@ -816,7 +823,7 @@ print_cmndspec_json(FILE *fp, struct cmndspec *cs, struct cmndspec **nextp, fprintf(fp, "%*s\"runasgroups\": [\n", indent, ""); indent += 4; TAILQ_FOREACH(m, cs->runasgrouplist, entries) { - print_member_json(fp, m, TYPE_RUNASGROUP, + print_member_json(fp, parse_tree, m, TYPE_RUNASGROUP, TAILQ_NEXT(m, entries) == NULL, indent, expand_aliases); } indent -= 4; @@ -997,7 +1004,7 @@ print_cmndspec_json(FILE *fp, struct cmndspec *cs, struct cmndspec **nextp, #endif /* HAVE_SELINUX */ ; - print_member_json(fp, cs->cmnd, TYPE_COMMAND, + print_member_json(fp, parse_tree, cs->cmnd, TYPE_COMMAND, last_one, indent, expand_aliases); if (last_one) break; @@ -1020,7 +1027,8 @@ print_cmndspec_json(FILE *fp, struct cmndspec *cs, struct cmndspec **nextp, * Print a User_Spec in JSON format at the specified indent level. */ static void -print_userspec_json(FILE *fp, struct userspec *us, int indent, bool expand_aliases) +print_userspec_json(FILE *fp, struct sudoers_parse_tree *parse_tree, + struct userspec *us, int indent, bool expand_aliases) { struct privilege *priv; struct member *m; @@ -1041,7 +1049,7 @@ print_userspec_json(FILE *fp, struct userspec *us, int indent, bool expand_alias fprintf(fp, "%*s\"User_List\": [\n", indent, ""); indent += 4; TAILQ_FOREACH(m, &us->users, entries) { - print_member_json(fp, m, TYPE_USERNAME, + print_member_json(fp, parse_tree, m, TYPE_USERNAME, TAILQ_NEXT(m, entries) == NULL, indent, expand_aliases); } indent -= 4; @@ -1051,7 +1059,7 @@ print_userspec_json(FILE *fp, struct userspec *us, int indent, bool expand_alias fprintf(fp, "%*s\"Host_List\": [\n", indent, ""); indent += 4; TAILQ_FOREACH(m, &priv->hostlist, entries) { - print_member_json(fp, m, TYPE_HOSTNAME, + print_member_json(fp, parse_tree, m, TYPE_HOSTNAME, TAILQ_NEXT(m, entries) == NULL, indent, expand_aliases); } indent -= 4; @@ -1061,7 +1069,7 @@ print_userspec_json(FILE *fp, struct userspec *us, int indent, bool expand_alias fprintf(fp, "%*s\"Cmnd_Specs\": [\n", indent, ""); indent += 4; TAILQ_FOREACH_SAFE(cs, &priv->cmndlist, entries, next) { - print_cmndspec_json(fp, cs, &next, &priv->defaults, + print_cmndspec_json(fp, parse_tree, cs, &next, &priv->defaults, expand_aliases, indent); } indent -= 4; @@ -1077,18 +1085,19 @@ print_userspec_json(FILE *fp, struct userspec *us, int indent, bool expand_alias } static bool -print_userspecs_json(FILE *fp, int indent, bool expand_aliases, bool need_comma) +print_userspecs_json(FILE *fp, struct sudoers_parse_tree *parse_tree, + int indent, bool expand_aliases, bool need_comma) { struct userspec *us; debug_decl(print_userspecs_json, SUDOERS_DEBUG_UTIL) - if (TAILQ_EMPTY(&parsed_policy.userspecs)) + if (TAILQ_EMPTY(&parse_tree->userspecs)) debug_return_bool(need_comma); fprintf(fp, "%s\n%*s\"User_Specs\": [\n", need_comma ? "," : "", indent, ""); indent += 4; - TAILQ_FOREACH(us, &parsed_policy.userspecs, entries) { - print_userspec_json(fp, us, indent, expand_aliases); + TAILQ_FOREACH(us, &parse_tree->userspecs, entries) { + print_userspec_json(fp, parse_tree, us, indent, expand_aliases); } indent -= 4; fprintf(fp, "%*s]", indent, ""); @@ -1100,7 +1109,8 @@ print_userspecs_json(FILE *fp, int indent, bool expand_aliases, bool need_comma) * Export the parsed sudoers file in JSON format. */ bool -convert_sudoers_json(const char *output_file, struct cvtsudoers_config *conf) +convert_sudoers_json(struct sudoers_parse_tree *parse_tree, + const char *output_file, struct cvtsudoers_config *conf) { bool ret = true, need_comma = false; const int indent = 4; @@ -1117,18 +1127,20 @@ convert_sudoers_json(const char *output_file, struct cvtsudoers_config *conf) /* Dump Defaults in JSON format. */ if (!ISSET(conf->suppress, SUPPRESS_DEFAULTS)) { - need_comma = print_defaults_json(output_fp, indent, + need_comma = print_defaults_json(output_fp, parse_tree, indent, conf->expand_aliases, need_comma); } /* Dump Aliases in JSON format. */ - if (!conf->expand_aliases && !ISSET(conf->suppress, SUPPRESS_ALIASES)) - need_comma = print_aliases_json(output_fp, indent, need_comma); + if (!conf->expand_aliases && !ISSET(conf->suppress, SUPPRESS_ALIASES)) { + need_comma = print_aliases_json(output_fp, parse_tree, indent, + need_comma); + } /* Dump User_Specs in JSON format. */ if (!ISSET(conf->suppress, SUPPRESS_PRIVS)) { - print_userspecs_json(output_fp, indent, conf->expand_aliases, - need_comma); + print_userspecs_json(output_fp, parse_tree, indent, + conf->expand_aliases, need_comma); } /* Close JSON output. */ diff --git a/plugins/sudoers/cvtsudoers_ldif.c b/plugins/sudoers/cvtsudoers_ldif.c index 4e4473dad..f9cd522fd 100644 --- a/plugins/sudoers/cvtsudoers_ldif.c +++ b/plugins/sudoers/cvtsudoers_ldif.c @@ -157,7 +157,8 @@ print_options_ldif(FILE *fp, struct defaults_list *options) * Print global Defaults in a single sudoRole object. */ static bool -print_global_defaults_ldif(FILE *fp, const char *base) +print_global_defaults_ldif(FILE *fp, struct sudoers_parse_tree *parse_tree, + const char *base) { unsigned int count = 0; struct sudo_lbuf lbuf; @@ -167,14 +168,14 @@ print_global_defaults_ldif(FILE *fp, const char *base) sudo_lbuf_init(&lbuf, NULL, 0, NULL, 80); - TAILQ_FOREACH(opt, &parsed_policy.defaults, entries) { + TAILQ_FOREACH(opt, &parse_tree->defaults, entries) { /* Skip bound Defaults (unsupported). */ if (opt->type == DEFAULTS) { count++; } else { lbuf.len = 0; sudo_lbuf_append(&lbuf, "# "); - sudoers_format_default_line(&lbuf, &parsed_policy, opt, false, true); + sudoers_format_default_line(&lbuf, parse_tree, opt, false, true); fprintf(fp, "# Unable to translate %s:%d\n%s\n", opt->file, opt->lineno, lbuf.buf); } @@ -195,7 +196,7 @@ print_global_defaults_ldif(FILE *fp, const char *base) print_attribute_ldif(fp, "cn", "defaults"); print_attribute_ldif(fp, "description", "Default sudoOption's go here"); - print_options_ldif(fp, &parsed_policy.defaults); + print_options_ldif(fp, &parse_tree->defaults); putc('\n', fp); debug_return_bool(!ferror(fp)); @@ -206,8 +207,8 @@ print_global_defaults_ldif(FILE *fp, const char *base) * See print_member_int() in parse.c. */ static void -print_member_ldif(FILE *fp, char *name, int type, bool negated, - int alias_type, const char *attr_name) +print_member_ldif(FILE *fp, struct sudoers_parse_tree *parse_tree, char *name, + int type, bool negated, int alias_type, const char *attr_name) { struct alias *a; struct member *m; @@ -239,9 +240,9 @@ print_member_ldif(FILE *fp, char *name, int type, bool negated, free(attr_val); break; case ALIAS: - if ((a = alias_get(&parsed_policy, name, alias_type)) != NULL) { + if ((a = alias_get(parse_tree, name, alias_type)) != NULL) { TAILQ_FOREACH(m, &a->members, entries) { - print_member_ldif(fp, m->name, m->type, + print_member_ldif(fp, parse_tree, m->name, m->type, negated ? !m->negated : m->negated, alias_type, attr_name); } alias_put(a); @@ -268,7 +269,8 @@ print_member_ldif(FILE *fp, char *name, int type, bool negated, * merge adjacent entries that are identical in all but the command. */ static void -print_cmndspec_ldif(FILE *fp, struct cmndspec *cs, struct cmndspec **nextp, struct defaults_list *options) +print_cmndspec_ldif(FILE *fp, struct sudoers_parse_tree *parse_tree, + struct cmndspec *cs, struct cmndspec **nextp, struct defaults_list *options) { struct cmndspec *next = *nextp; struct member *m; @@ -280,7 +282,7 @@ print_cmndspec_ldif(FILE *fp, struct cmndspec *cs, struct cmndspec **nextp, stru /* Print runasuserlist as sudoRunAsUser attributes */ if (cs->runasuserlist != NULL) { TAILQ_FOREACH(m, cs->runasuserlist, entries) { - print_member_ldif(fp, m->name, m->type, m->negated, + print_member_ldif(fp, parse_tree, m->name, m->type, m->negated, RUNASALIAS, "sudoRunAsUser"); } } @@ -288,7 +290,7 @@ print_cmndspec_ldif(FILE *fp, struct cmndspec *cs, struct cmndspec **nextp, stru /* Print runasgrouplist as sudoRunAsGroup attributes */ if (cs->runasgrouplist != NULL) { TAILQ_FOREACH(m, cs->runasgrouplist, entries) { - print_member_ldif(fp, m->name, m->type, m->negated, + print_member_ldif(fp, parse_tree, m->name, m->type, m->negated, RUNASALIAS, "sudoRunAsGroup"); } } @@ -437,8 +439,8 @@ print_cmndspec_ldif(FILE *fp, struct cmndspec *cs, struct cmndspec **nextp, stru #endif /* HAVE_SELINUX */ ; - print_member_ldif(fp, cs->cmnd->name, cs->cmnd->type, cs->cmnd->negated, - CMNDALIAS, "sudoCommand"); + print_member_ldif(fp, parse_tree, cs->cmnd->name, cs->cmnd->type, + cs->cmnd->negated, CMNDALIAS, "sudoCommand"); if (last_one) break; cs = next; @@ -532,7 +534,8 @@ bad: * Print a single User_Spec. */ static bool -print_userspec_ldif(FILE *fp, struct userspec *us, struct cvtsudoers_config *conf) +print_userspec_ldif(FILE *fp, struct sudoers_parse_tree *parse_tree, + struct userspec *us, struct cvtsudoers_config *conf) { struct privilege *priv; struct member *m; @@ -568,16 +571,16 @@ print_userspec_ldif(FILE *fp, struct userspec *us, struct cvtsudoers_config *con free(dn); TAILQ_FOREACH(m, &us->users, entries) { - print_member_ldif(fp, m->name, m->type, m->negated, + print_member_ldif(fp, parse_tree, m->name, m->type, m->negated, USERALIAS, "sudoUser"); } TAILQ_FOREACH(m, &priv->hostlist, entries) { - print_member_ldif(fp, m->name, m->type, m->negated, + print_member_ldif(fp, parse_tree, m->name, m->type, m->negated, HOSTALIAS, "sudoHost"); } - print_cmndspec_ldif(fp, cs, &next, &priv->defaults); + print_cmndspec_ldif(fp, parse_tree, cs, &next, &priv->defaults); if (conf->sudo_order != 0) { char numbuf[(((sizeof(conf->sudo_order) * 8) + 2) / 3) + 2]; @@ -596,13 +599,14 @@ print_userspec_ldif(FILE *fp, struct userspec *us, struct cvtsudoers_config *con * Print User_Specs. */ static bool -print_userspecs_ldif(FILE *fp, struct cvtsudoers_config *conf) +print_userspecs_ldif(FILE *fp, struct sudoers_parse_tree *parse_tree, + struct cvtsudoers_config *conf) { struct userspec *us; debug_decl(print_userspecs_ldif, SUDOERS_DEBUG_UTIL) - TAILQ_FOREACH(us, &parsed_policy.userspecs, entries) { - if (!print_userspec_ldif(fp, us, conf)) + TAILQ_FOREACH(us, &parse_tree->userspecs, entries) { + if (!print_userspec_ldif(fp, parse_tree, us, conf)) debug_return_bool(false); } debug_return_bool(true); @@ -612,7 +616,8 @@ print_userspecs_ldif(FILE *fp, struct cvtsudoers_config *conf) * Export the parsed sudoers file in LDIF format. */ bool -convert_sudoers_ldif(const char *output_file, struct cvtsudoers_config *conf) +convert_sudoers_ldif(struct sudoers_parse_tree *parse_tree, + const char *output_file, struct cvtsudoers_config *conf) { bool ret = true; FILE *output_fp = stdout; @@ -632,11 +637,11 @@ convert_sudoers_ldif(const char *output_file, struct cvtsudoers_config *conf) /* Dump global Defaults in LDIF format. */ if (!ISSET(conf->suppress, SUPPRESS_DEFAULTS)) - print_global_defaults_ldif(output_fp, conf->sudoers_base); + print_global_defaults_ldif(output_fp, parse_tree, conf->sudoers_base); /* Dump User_Specs in LDIF format, expanding Aliases. */ if (!ISSET(conf->suppress, SUPPRESS_PRIVS)) - print_userspecs_ldif(output_fp, conf); + print_userspecs_ldif(output_fp, parse_tree, conf); /* Clean up. */ rbdestroy(seen_users, seen_user_free); @@ -834,7 +839,8 @@ role_order_cmp(const void *va, const void *vb) * Parse list of sudoOption and store in global defaults list. */ static void -ldif_store_options(struct cvtsudoers_str_list *options) +ldif_store_options(struct sudoers_parse_tree *parse_tree, + struct cvtsudoers_str_list *options) { struct defaults *d; struct cvtsudoers_string *ls; @@ -860,7 +866,7 @@ ldif_store_options(struct cvtsudoers_str_list *options) U_("unable to allocate memory")); } } - TAILQ_INSERT_TAIL(&parsed_policy.defaults, d, entries); + TAILQ_INSERT_TAIL(&parse_tree->defaults, d, entries); } debug_return; } @@ -913,8 +919,9 @@ str_list_cache(struct rbtree *cache, struct cvtsudoers_str_list **strlistp) * data structures. */ static void -role_to_sudoers(struct sudo_role *role, bool store_options, - bool reuse_userspec, bool reuse_privilege, bool reuse_runas) +role_to_sudoers(struct sudoers_parse_tree *parse_tree, struct sudo_role *role, + bool store_options, bool reuse_userspec, bool reuse_privilege, + bool reuse_runas) { struct privilege *priv; struct cvtsudoers_string *ls; @@ -928,7 +935,7 @@ role_to_sudoers(struct sudo_role *role, bool store_options, if (reuse_userspec) { /* Re-use the previous userspec */ - us = TAILQ_LAST(&parsed_policy.userspecs, userspec_list); + us = TAILQ_LAST(&parse_tree->userspecs, userspec_list); } else { /* Allocate a new userspec and fill in the user list. */ if ((us = calloc(1, sizeof(*us))) == NULL) { @@ -1039,7 +1046,7 @@ role_to_sudoers(struct sudo_role *role, bool store_options, /* Add finished userspec to the list if new. */ if (!reuse_userspec) - TAILQ_INSERT_TAIL(&parsed_policy.userspecs, us, entries); + TAILQ_INSERT_TAIL(&parse_tree->userspecs, us, entries); debug_return; } @@ -1049,8 +1056,8 @@ role_to_sudoers(struct sudo_role *role, bool store_options, * store in the global sudoers data structures. */ static void -ldif_to_sudoers(struct sudo_role_list *roles, unsigned int numroles, - bool store_options) +ldif_to_sudoers(struct sudoers_parse_tree *parse_tree, + struct sudo_role_list *roles, unsigned int numroles, bool store_options) { struct sudo_role **role_array, *role = NULL; unsigned int n; @@ -1098,7 +1105,7 @@ ldif_to_sudoers(struct sudo_role_list *roles, unsigned int numroles, } } - role_to_sudoers(role, store_options, reuse_userspec, + role_to_sudoers(parse_tree, role, store_options, reuse_userspec, reuse_privilege, reuse_runas); } @@ -1138,10 +1145,12 @@ char *unquote_cn(const char *src) /* * Parse a sudoers file in LDIF format, https://tools.ietf.org/html/rfc2849 - * Parsed sudoRole objects are stored in the global sudoers data structures. + * Parsed sudoRole objects are stored in the specified parse_tree which + * must already be initialized. */ bool -parse_ldif(const char *input_file, struct cvtsudoers_config *conf) +parse_ldif(struct sudoers_parse_tree *parse_tree, const char *input_file, + struct cvtsudoers_config *conf) { struct sudo_role_list roles = STAILQ_HEAD_INITIALIZER(roles); struct sudo_role *role = NULL; @@ -1161,7 +1170,9 @@ parse_ldif(const char *input_file, struct cvtsudoers_config *conf) input_file = "stdin"; } else if ((fp = fopen(input_file, "r")) == NULL) sudo_fatal(U_("unable to open %s"), input_file); - init_parser(input_file, false); + + /* Free old contents of the parse tree (if any). */ + free_parse_tree(parse_tree); /* * We cache user, group and host lists to make it eay to detect when there @@ -1188,7 +1199,7 @@ parse_ldif(const char *input_file, struct cvtsudoers_config *conf) if (len <= 0) { if (in_role) { if (role->cn != NULL && strcmp(role->cn, "defaults") == 0) { - ldif_store_options(role->options); + ldif_store_options(parse_tree, role->options); sudo_role_free(role); role = NULL; } else if (STAILQ_EMPTY(role->users) || @@ -1374,7 +1385,7 @@ parse_ldif(const char *input_file, struct cvtsudoers_config *conf) free(line); /* Convert from roles to sudoers data structures. */ - ldif_to_sudoers(&roles, numroles, conf->store_options); + ldif_to_sudoers(parse_tree, &roles, numroles, conf->store_options); /* Clean up. */ rbdestroy(usercache, str_list_free);