From 82131449b4cd77267db47205b810b76dffd328ba Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Sun, 6 Jan 2013 23:52:19 +0100 Subject: SELINUX: Process maps even when offline Changes the ipa_get_selinux{send,recv} request so that it only delivers data and moves processing to the IPA selinux handler. --- src/providers/ipa/ipa_selinux.c | 655 ++++++++++++++++++++++++++-------------- 1 file changed, 429 insertions(+), 226 deletions(-) diff --git a/src/providers/ipa/ipa_selinux.c b/src/providers/ipa/ipa_selinux.c index b64de90b1..909ef056c 100644 --- a/src/providers/ipa/ipa_selinux.c +++ b/src/providers/ipa/ipa_selinux.c @@ -37,52 +37,53 @@ #include "providers/ipa/ipa_selinux_common.h" #include "providers/ipa/ipa_selinux_maps.h" -struct ipa_get_selinux_state { - struct be_req *be_req; - struct pam_data *pd; - struct ipa_selinux_ctx *selinux_ctx; - struct sdap_id_op *op; - - const char *hostname; - struct sysdb_attrs *host; - struct sysdb_attrs *user; - - struct sysdb_attrs *defaults; - struct sysdb_attrs **selinuxmaps; - size_t nmaps; - - struct sysdb_attrs **possible_match; - size_t possible_matches; -}; - -static struct -tevent_req *ipa_get_selinux_send(struct be_req *breq, - struct pam_data *pd, - struct ipa_selinux_ctx *selinux_ctx); -static void ipa_selinux_handler_done(struct tevent_req *subreq); +static struct tevent_req * +ipa_get_selinux_send(struct be_req *breq, + struct sysdb_attrs *user, + struct sysdb_attrs *host, + struct ipa_selinux_ctx *selinux_ctx); static errno_t ipa_get_selinux_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, size_t *count, struct sysdb_attrs ***maps, + size_t *hbac_count, + struct sysdb_attrs ***hbac_rules, char **default_user, char **map_order); +static struct ipa_selinux_op_ctx * +ipa_selinux_create_op_ctx(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, + struct be_req *be_req, const char *username, + const char *hostname); +static void ipa_selinux_handler_done(struct tevent_req *subreq); + static void ipa_get_selinux_connect_done(struct tevent_req *subreq); static void ipa_get_selinux_hosts_done(struct tevent_req *subreq); static void ipa_get_config_step(struct tevent_req *req); static void ipa_get_selinux_config_done(struct tevent_req *subreq); static void ipa_get_selinux_maps_done(struct tevent_req *subreq); static void ipa_get_selinux_hbac_done(struct tevent_req *subreq); -static int -ipa_get_selinux_hbac_process(struct ipa_get_selinux_state *state, - struct sysdb_attrs **rules, - size_t rule_count); +static errno_t ipa_selinux_process_maps(struct sysdb_attrs *user, + struct sysdb_attrs *host, + struct sysdb_attrs **selinux_maps, + size_t selinux_map_count, + struct sysdb_attrs **hbac_rules, + size_t hbac_rule_count); + +struct ipa_selinux_op_ctx { + struct be_req *be_req; + + struct sysdb_attrs *user; + struct sysdb_attrs *host; +}; void ipa_selinux_handler(struct be_req *be_req) { struct ipa_selinux_ctx *selinux_ctx; + struct ipa_selinux_op_ctx *op_ctx; struct tevent_req *req; struct pam_data *pd; + const char *hostname; pd = talloc_get_type(be_req->req_data, struct pam_data); @@ -90,23 +91,96 @@ void ipa_selinux_handler(struct be_req *be_req) be_req->be_ctx->bet_info[BET_SELINUX].pvt_bet_data, struct ipa_selinux_ctx); + hostname = dp_opt_get_string(selinux_ctx->id_ctx->ipa_options->basic, + IPA_HOSTNAME); + if (!hostname) { + DEBUG(SSSDBG_OP_FAILURE, ("Cannot determine this machine's host name\n")); + goto fail; + } - req = ipa_get_selinux_send(be_req, pd, selinux_ctx); - if (req == NULL) { + op_ctx = ipa_selinux_create_op_ctx(be_req, be_req->sysdb, be_req, + pd->user, hostname); + if (op_ctx == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("Cannot create op context\n")); goto fail; } - tevent_req_set_callback(req, ipa_selinux_handler_done, be_req); + req = ipa_get_selinux_send(be_req, op_ctx->user, op_ctx->host, selinux_ctx); + if (req == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("Cannot initiate the search\n")); + goto fail; + } + tevent_req_set_callback(req, ipa_selinux_handler_done, op_ctx); return; fail: be_req->fn(be_req, DP_ERR_FATAL, PAM_SYSTEM_ERR, NULL); } +static struct ipa_selinux_op_ctx * +ipa_selinux_create_op_ctx(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, + struct be_req *be_req, const char *username, + const char *hostname) +{ + struct ipa_selinux_op_ctx *op_ctx; + struct ldb_dn *host_dn; + const char *attrs[] = { SYSDB_ORIG_DN, + SYSDB_ORIG_MEMBEROF, + NULL }; + size_t count; + struct ldb_message **msgs; + struct sysdb_attrs **hosts; + errno_t ret; + + op_ctx = talloc_zero(mem_ctx, struct ipa_selinux_op_ctx); + if (op_ctx == NULL) { + return NULL; + } + op_ctx->be_req = be_req; + + ret = sss_selinux_extract_user(op_ctx, sysdb, username, &op_ctx->user); + if (ret != EOK) { + goto fail; + } + + host_dn = sysdb_custom_dn(sysdb, op_ctx, hostname, HBAC_HOSTS_SUBDIR); + if (host_dn == NULL) { + goto fail; + } + + /* Look up the host to get its originalMemberOf entries */ + ret = sysdb_search_entry(op_ctx, sysdb, host_dn, + LDB_SCOPE_BASE, NULL, + attrs, &count, &msgs); + if (ret == ENOENT || count == 0) { + op_ctx->host = NULL; + return op_ctx; + } else if (ret != EOK) { + goto fail; + } else if (count > 1) { + DEBUG(SSSDBG_OP_FAILURE, ("More than one result for a BASE search!\n")); + goto fail; + } + + ret = sysdb_msg2attrs(op_ctx, count, msgs, &hosts); + talloc_free(msgs); + if (ret != EOK) { + goto fail; + } + + op_ctx->host = hosts[0]; + return op_ctx; + +fail: + talloc_free(op_ctx); + return NULL; +} + static void ipa_selinux_handler_done(struct tevent_req *req) { - struct be_req *breq = tevent_req_callback_data(req, struct be_req); + struct ipa_selinux_op_ctx *op_ctx = tevent_req_callback_data(req, struct ipa_selinux_op_ctx); + struct be_req *breq = op_ctx->be_req; struct sysdb_ctx *sysdb = breq->be_ctx->sysdb; errno_t ret, sret; size_t map_count = 0; @@ -115,13 +189,23 @@ static void ipa_selinux_handler_done(struct tevent_req *req) char *default_user = NULL; struct pam_data *pd = talloc_get_type(breq->req_data, struct pam_data); char *map_order = NULL; + size_t hbac_count = 0; + struct sysdb_attrs **hbac_rules = 0; ret = ipa_get_selinux_recv(req, breq, &map_count, &maps, + &hbac_count, &hbac_rules, &default_user, &map_order); if (ret != EOK) { goto fail; } + ret = ipa_selinux_process_maps(op_ctx->user, op_ctx->host, + maps, map_count, + hbac_rules, hbac_count); + if (ret != EOK) { + goto fail; + } + ret = sysdb_transaction_start(sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n")); @@ -153,11 +237,8 @@ static void ipa_selinux_handler_done(struct tevent_req *req) DEBUG(SSSDBG_OP_FAILURE, ("Could not commit transaction\n")); goto fail; } - - /* Just in case more code will follow after this place in the future */ in_transaction = false; - pd->pam_status = PAM_SUCCESS; breq->fn(breq, DP_ERR_OK, EOK, "Success"); return; @@ -176,9 +257,195 @@ fail: } } -static struct tevent_req *ipa_get_selinux_send(struct be_req *breq, - struct pam_data *pd, - struct ipa_selinux_ctx *selinux_ctx) +static errno_t +ipa_selinux_process_seealso_maps(struct sysdb_attrs *user, + struct sysdb_attrs *host, + struct sysdb_attrs **seealso_rules, + size_t seealso_rules_count, + struct sysdb_attrs **hbac_rules, + size_t hbac_rule_count); +static errno_t +ipa_selinux_process_maps(struct sysdb_attrs *user, + struct sysdb_attrs *host, + struct sysdb_attrs **selinux_maps, + size_t selinux_map_count, + struct sysdb_attrs **hbac_rules, + size_t hbac_rule_count) +{ + TALLOC_CTX *tmp_ctx; + int i; + errno_t ret; + uint32_t priority = 0; + struct sysdb_attrs **seealso_rules; + size_t num_seealso_rules; + const char *seealso_str; + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) { + return ENOMEM; + } + + seealso_rules = talloc_zero_array(tmp_ctx, struct sysdb_attrs *, + selinux_map_count + 1); + if (seealso_rules == NULL) { + ret = ENOMEM; + goto done; + } + num_seealso_rules = 0; + + for (i = 0; i < selinux_map_count; i++) { + if (sss_selinux_match(selinux_maps[i], user, + host, &priority)) { + priority &= ~(SELINUX_PRIORITY_USER_NAME | + SELINUX_PRIORITY_USER_GROUP | + SELINUX_PRIORITY_USER_CAT); + ret = sysdb_attrs_add_uint32(selinux_maps[i], + SYSDB_SELINUX_HOST_PRIORITY, + priority); + if (ret != EOK) { + goto done; + } + continue; + } + + ret = sysdb_attrs_get_string(selinux_maps[i], + SYSDB_SELINUX_SEEALSO, &seealso_str); + if (ret == ENOENT) { + continue; + } else if (ret != EOK) { + goto done; + } + + seealso_rules[num_seealso_rules] = selinux_maps[i]; + num_seealso_rules++; + } + + ret = ipa_selinux_process_seealso_maps(user, host, + seealso_rules, num_seealso_rules, + hbac_rules, hbac_rule_count); + if (ret != EOK) { + goto done; + } + + ret = EOK; +done: + talloc_free(tmp_ctx); + return ret; +} + +static errno_t +ipa_selinux_process_seealso_maps(struct sysdb_attrs *user, + struct sysdb_attrs *host, + struct sysdb_attrs **seealso_rules, + size_t seealso_rules_count, + struct sysdb_attrs **hbac_rules, + size_t hbac_rule_count) +{ + int i, j; + errno_t ret; + struct ldb_message_element *el; + uint32_t priority = 0; + struct sysdb_attrs *usermap; + const char *seealso_dn; + const char *hbac_dn; + + for (i = 0; i < hbac_rule_count; i++) { + ret = sysdb_attrs_get_string(hbac_rules[i], SYSDB_ORIG_DN, &hbac_dn); + if (ret != EOK) { + return ret; + } + + /* We need to do this translation for further processing. We have to + * do it manually because no map was used to retrieve HBAC rules. + */ + ret = sysdb_attrs_get_el(hbac_rules[i], IPA_MEMBER_HOST, &el); + if (ret != EOK) return ret; + el->name = SYSDB_ORIG_MEMBER_HOST; + + ret = sysdb_attrs_get_el(hbac_rules[i], IPA_MEMBER_USER, &el); + if (ret != EOK) return ret; + el->name = SYSDB_ORIG_MEMBER_USER; + + DEBUG(SSSDBG_TRACE_ALL, + ("Matching HBAC rule %s with SELinux mappings\n", hbac_dn)); + + if (!sss_selinux_match(hbac_rules[i], user, host, &priority)) { + DEBUG(SSSDBG_TRACE_ALL, ("Rule did not match\n")); + continue; + } + + /* HBAC rule matched, find if it is in the "possible" list */ + for (j = 0; j < seealso_rules_count; j++) { + usermap = seealso_rules[j]; + if (usermap == NULL) { + continue; + } + + ret = sysdb_attrs_get_string(usermap, SYSDB_SELINUX_SEEALSO, &seealso_dn); + if (ret != EOK) { + return ret; + } + + if (strcasecmp(hbac_dn, seealso_dn) == 0) { + DEBUG(SSSDBG_TRACE_FUNC, ("HBAC rule [%s] matched, copying its" + "attributes to SELinux user map [%s]\n", + hbac_dn, seealso_dn)); + priority &= ~(SELINUX_PRIORITY_USER_NAME | + SELINUX_PRIORITY_USER_GROUP | + SELINUX_PRIORITY_USER_CAT); + ret = sysdb_attrs_add_uint32(usermap, + SYSDB_SELINUX_HOST_PRIORITY, + priority); + if (ret != EOK) { + return ret; + } + + ret = sysdb_attrs_copy_values(hbac_rules[i], usermap, SYSDB_ORIG_MEMBER_USER); + if (ret != EOK) { + return ret; + } + + ret = sysdb_attrs_copy_values(hbac_rules[i], usermap, SYSDB_USER_CATEGORY); + if (ret != EOK) { + return ret; + } + + /* Speed up the next iteration */ + seealso_rules[j] = NULL; + } + } + } + + return EOK; +} + +/* A more generic request to gather all SELinux and HBAC rules. Updates + * cache if necessary + */ +struct ipa_get_selinux_state { + struct be_req *be_req; + struct ipa_selinux_ctx *selinux_ctx; + struct sdap_id_op *op; + + struct sysdb_attrs *host; + struct sysdb_attrs *user; + + struct sysdb_attrs *defaults; + struct sysdb_attrs **selinuxmaps; + size_t nmaps; + + struct sysdb_attrs **hbac_rules; + size_t hbac_rule_count; +}; + +static errno_t +ipa_get_selinux_maps_offline(struct tevent_req *req); + +static struct tevent_req * +ipa_get_selinux_send(struct be_req *breq, + struct sysdb_attrs *user, + struct sysdb_attrs *host, + struct ipa_selinux_ctx *selinux_ctx) { struct tevent_req *req; struct tevent_req *subreq; @@ -194,8 +461,9 @@ static struct tevent_req *ipa_get_selinux_send(struct be_req *breq, } state->be_req = breq; - state->pd = pd; state->selinux_ctx = selinux_ctx; + state->user = user; + state->host = host; offline = be_is_offline(bctx); DEBUG(SSSDBG_TRACE_INTERNAL, ("Connection status is [%s].\n", @@ -219,7 +487,7 @@ static struct tevent_req *ipa_get_selinux_send(struct be_req *breq, tevent_req_set_callback(subreq, ipa_get_selinux_connect_done, req); } else { - ret = EAGAIN; + ret = ipa_get_selinux_maps_offline(req); goto immediate; } @@ -248,67 +516,45 @@ static void ipa_get_selinux_connect_done(struct tevent_req *subreq) const char *access_name; const char *selinux_name; - struct ldb_dn *host_dn; - const char *attrs[] = { SYSDB_ORIG_DN, - SYSDB_ORIG_MEMBEROF, - NULL }; - size_t count; - struct ldb_message **msgs; - struct sysdb_attrs **hosts; + const char *hostname; ret = sdap_id_op_connect_recv(subreq, &dp_error); talloc_zfree(subreq); if (dp_error == DP_ERR_OFFLINE) { talloc_zfree(state->op); - ret = EAGAIN; + ret = ipa_get_selinux_maps_offline(req); + if (ret == EOK) { + tevent_req_done(req); + return; + } + goto fail; } if (ret != EOK) { goto fail; } - state->hostname = dp_opt_get_string(state->selinux_ctx->id_ctx->ipa_options->basic, - IPA_HOSTNAME); - access_name = state->be_req->be_ctx->bet_info[BET_ACCESS].mod_name; selinux_name = state->be_req->be_ctx->bet_info[BET_SELINUX].mod_name; - if (strcasecmp(access_name, selinux_name) == 0) { - host_dn = sysdb_custom_dn(bctx->sysdb, state, state->hostname, HBAC_HOSTS_SUBDIR); - if (host_dn == NULL) { - ret = ENOMEM; - goto fail; - } - - /* Look up the host to get its originalMemberOf entries */ - ret = sysdb_search_entry(state, bctx->sysdb, host_dn, - LDB_SCOPE_BASE, NULL, - attrs, &count, &msgs); - if (ret == ENOENT || count == 0) { - /* We need to query the server */ - goto server; - } else if (ret != EOK) { - goto fail; - } else if (count > 1) { - DEBUG(SSSDBG_OP_FAILURE, ("More than one result for a BASE search!\n")); - ret = EIO; - goto fail; - } - - ret = sysdb_msg2attrs(state, count, msgs, &hosts); - if (ret != EOK) { - goto fail; - } - - state->host = hosts[0]; + if (strcasecmp(access_name, selinux_name) == 0 && state->host != NULL) { + /* If the access control module is the same as the selinux module + * and the access control had already discovered the host + */ return ipa_get_config_step(req); } -server: + hostname = dp_opt_get_string(state->selinux_ctx->id_ctx->ipa_options->basic, + IPA_HOSTNAME); + if (hostname == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot determine the host name\n")); + goto fail; + } + subreq = ipa_host_info_send(state, bctx->ev, bctx->sysdb, sdap_id_op_handle(state->op), id_ctx->sdap_id_ctx->opts, - state->hostname, + hostname, id_ctx->ipa_options->host_map, NULL, state->selinux_ctx->host_search_bases); @@ -318,13 +564,92 @@ server: } tevent_req_set_callback(subreq, ipa_get_selinux_hosts_done, req); - return; fail: tevent_req_error(req, ret); } +static errno_t +ipa_get_selinux_maps_offline(struct tevent_req *req) +{ + errno_t ret; + size_t nmaps; + struct ldb_message **maps; + struct ldb_message *defaults; + const char *attrs[] = { SYSDB_NAME, + SYSDB_USER_CATEGORY, + SYSDB_HOST_CATEGORY, + SYSDB_ORIG_MEMBER_USER, + SYSDB_ORIG_MEMBER_HOST, + SYSDB_SELINUX_SEEALSO, + SYSDB_SELINUX_USER, + NULL }; + const char *default_user; + const char *order; + + struct ipa_get_selinux_state *state = tevent_req_data(req, + struct ipa_get_selinux_state); + + /* read the config entry */ + ret = sysdb_search_selinux_config(state, state->be_req->be_ctx->sysdb, + NULL, &defaults); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("sysdb_search_selinux_config failed [%d]: %s\n", + ret, strerror(ret))); + return ret; + } + + default_user = ldb_msg_find_attr_as_string(defaults, + SYSDB_SELINUX_DEFAULT_USER, + NULL); + order = ldb_msg_find_attr_as_string(defaults, SYSDB_SELINUX_DEFAULT_ORDER, + NULL); + + state->defaults = sysdb_new_attrs(state); + if (state->defaults == NULL) { + return ENOMEM; + } + + ret = sysdb_attrs_add_string(state->defaults, + IPA_CONFIG_SELINUX_DEFAULT_MAP, default_user); + if (ret != EOK) { + return ret; + } + + ret = sysdb_attrs_add_string(state->defaults, + IPA_CONFIG_SELINUX_MAP_ORDER, order); + if (ret != EOK) { + return ret; + } + + /* read all the SELinux rules */ + ret = sysdb_get_selinux_usermaps(state, state->be_req->be_ctx->sysdb, + attrs, &nmaps, &maps); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("sysdb_get_selinux_usermaps failed [%d]: %s\n", + ret, strerror(ret))); + return ret; + } + + ret = sysdb_msg2attrs(state, nmaps, maps, &state->selinuxmaps); + if (ret != EOK) { + return ret; + } + state->nmaps = nmaps; + + /* read all the HBAC rules */ + ret = hbac_get_cached_rules(state, state->be_req->be_ctx->sysdb, + &state->hbac_rule_count, &state->hbac_rules); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("hbac_get_cached_rules failed [%d]: %s\n", + ret, strerror(ret))); + return ret; + } + + return EOK; +} + static void ipa_get_selinux_hosts_done(struct tevent_req *subreq) { errno_t ret; @@ -354,7 +679,6 @@ done: static void ipa_get_config_step(struct tevent_req *req) { - errno_t ret; const char *domain; struct tevent_req *subreq; struct ipa_get_selinux_state *state = tevent_req_data(req, @@ -362,13 +686,6 @@ static void ipa_get_config_step(struct tevent_req *req) struct be_ctx *bctx = state->be_req->be_ctx; struct ipa_id_ctx *id_ctx = state->selinux_ctx->id_ctx; - ret = sss_selinux_extract_user(state, bctx->sysdb, - state->pd->user, &state->user); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - domain = dp_opt_get_string(state->selinux_ctx->id_ctx->ipa_options->basic, IPA_KRB5_REALM); subreq = ipa_get_config_send(state, bctx->ev, @@ -428,11 +745,9 @@ static void ipa_get_selinux_maps_done(struct tevent_req *subreq) char *selinux_name; char *access_name; - struct sysdb_attrs **rules; - size_t rule_count; const char *tmp_str; - uint32_t priority = 0; + bool check_hbac; errno_t ret; int i; @@ -456,54 +771,29 @@ static void ipa_get_selinux_maps_done(struct tevent_req *subreq) DEBUG(SSSDBG_TRACE_FUNC, ("Found %d SELinux user maps\n", state->nmaps)); - state->possible_match = talloc_zero_array(state, struct sysdb_attrs *, - state->nmaps + 1); - if (state->possible_match == NULL) { - ret = ENOMEM; - goto done; - } + check_hbac = false; for (i = 0; i < state->nmaps; i++) { - if (sss_selinux_match(state->selinuxmaps[i], state->user, - state->host, &priority)) { - priority &= ~(SELINUX_PRIORITY_USER_NAME | - SELINUX_PRIORITY_USER_GROUP | - SELINUX_PRIORITY_USER_CAT); - ret = sysdb_attrs_add_uint32(state->selinuxmaps[i], - SYSDB_SELINUX_HOST_PRIORITY, - priority); - if (ret != EOK) { - goto done; - } - continue; - } - ret = sysdb_attrs_get_string(state->selinuxmaps[i], SYSDB_SELINUX_SEEALSO, &tmp_str); - if (ret == ENOENT) { - continue; + if (ret == EOK) { + check_hbac = true; + break; } - - state->possible_match[state->possible_matches] = state->selinuxmaps[i]; - state->possible_matches++; } - if (state->possible_matches) { + if (check_hbac) { access_name = state->be_req->be_ctx->bet_info[BET_ACCESS].mod_name; selinux_name = state->be_req->be_ctx->bet_info[BET_SELINUX].mod_name; if (strcasecmp(access_name, selinux_name) == 0) { ret = hbac_get_cached_rules(state, state->be_req->be_ctx->sysdb, - &rule_count, &rules); - if (ret != EOK) { - goto done; - } - - ret = ipa_get_selinux_hbac_process(state, rules, rule_count); + &state->hbac_rule_count, &state->hbac_rules); + /* Terminates the request */ goto done; } - DEBUG(SSSDBG_TRACE_FUNC, ("%d SELinux maps referenced an HBAC rule. " - "Need to refresh HBAC rules\n", state->possible_matches)); + DEBUG(SSSDBG_TRACE_FUNC, ("SELinux maps referenced an HBAC rule. " + "Need to refresh HBAC rules\n")); subreq = ipa_hbac_rule_info_send(state, false, bctx->ev, sdap_id_op_handle(state->op), id_ctx->sdap_id_ctx->opts, @@ -533,22 +823,14 @@ static void ipa_get_selinux_hbac_done(struct tevent_req *subreq) struct tevent_req); struct ipa_get_selinux_state *state = tevent_req_data(req, struct ipa_get_selinux_state); - struct sysdb_attrs **rules; - size_t rule_count; errno_t ret; - ret = ipa_hbac_rule_info_recv(subreq, state, &rule_count, - &rules); + ret = ipa_hbac_rule_info_recv(subreq, state, &state->hbac_rule_count, + &state->hbac_rules); DEBUG(SSSDBG_TRACE_INTERNAL, - ("Received %d HBAC rules\n", rule_count)); + ("Received %d HBAC rules\n", state->hbac_rule_count)); talloc_free(subreq); - if (ret != EOK) { - goto done; - } - - ret = ipa_get_selinux_hbac_process(state, rules, rule_count); -done: if (ret != EOK) { tevent_req_error(req, ret); } else { @@ -556,100 +838,13 @@ done: } } -static int -ipa_get_selinux_hbac_process(struct ipa_get_selinux_state *state, - struct sysdb_attrs **rules, - size_t rule_count) -{ - int i, j; - errno_t ret; - uint32_t priority = 0; - const char *hbac_dn; - const char *seealso_dn; - struct sysdb_attrs *usermap; - struct ldb_message_element *el; - - for (i = 0; i < rule_count; i++) { - ret = sysdb_attrs_get_string(rules[i], SYSDB_ORIG_DN, &hbac_dn); - if (ret != EOK) { - goto done; - } - - /* We need to do this translation for further processing. We have to - * do it manually because no map was used to retrieve HBAC rules. - */ - ret = sysdb_attrs_get_el(rules[i], IPA_MEMBER_HOST, &el); - if (ret != EOK) goto done; - el->name = SYSDB_ORIG_MEMBER_HOST; - - ret = sysdb_attrs_get_el(rules[i], IPA_MEMBER_USER, &el); - if (ret != EOK) goto done; - el->name = SYSDB_ORIG_MEMBER_USER; - - DEBUG(SSSDBG_TRACE_ALL, - ("Matching HBAC rule %s with SELinux mappings\n", hbac_dn)); - - if (!sss_selinux_match(rules[i], state->user, state->host, &priority)) { - DEBUG(SSSDBG_TRACE_ALL, ("Rule did not match\n")); - continue; - } - - - /* HBAC rule matched, find if it is in the "possible" list */ - for (j = 0; j < state->possible_matches; j++) { - usermap = state->possible_match[j]; - if (usermap == NULL) { - continue; - } - - ret = sysdb_attrs_get_string(usermap, SYSDB_SELINUX_SEEALSO, &seealso_dn); - if (ret != EOK) { - goto done; - } - - if (strcasecmp(hbac_dn, seealso_dn) == 0) { - DEBUG(SSSDBG_TRACE_FUNC, ("HBAC rule [%s] matched, copying its" - "attributes to SELinux user map [%s]\n", - hbac_dn, seealso_dn)); - priority &= ~(SELINUX_PRIORITY_USER_NAME | - SELINUX_PRIORITY_USER_GROUP | - SELINUX_PRIORITY_USER_CAT); - ret = sysdb_attrs_add_uint32(usermap, - SYSDB_SELINUX_HOST_PRIORITY, - priority); - if (ret != EOK) { - goto done; - } - - ret = sysdb_attrs_copy_values(rules[i], usermap, SYSDB_ORIG_MEMBER_USER); - if (ret != EOK) { - goto done; - } - - ret = sysdb_attrs_copy_values(rules[i], usermap, SYSDB_USER_CATEGORY); - if (ret != EOK) { - goto done; - } - - /* Just to boost the following lookup */ - state->possible_match[j] = NULL; - } - } - } - - /* Now we can dispose all possible rules, since they aren't possible any more */ - talloc_zfree(state->possible_match); - - ret = EOK; -done: - return ret; -} - static errno_t ipa_get_selinux_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, size_t *count, struct sysdb_attrs ***maps, + size_t *hbac_count, + struct sysdb_attrs ***hbac_rules, char **default_user, char **map_order) { @@ -698,5 +893,13 @@ ipa_get_selinux_recv(struct tevent_req *req, *maps = NULL; } + if (state->hbac_rules != NULL) { + *hbac_count = state->hbac_rule_count; + *hbac_rules = talloc_steal(mem_ctx, state->hbac_rules); + } else { + *hbac_count = 0; + *hbac_rules = NULL; + } + return EOK; } -- cgit