diff options
Diffstat (limited to 'src/responder/pac/pacsrv_cmd.c')
-rw-r--r-- | src/responder/pac/pacsrv_cmd.c | 588 |
1 files changed, 455 insertions, 133 deletions
diff --git a/src/responder/pac/pacsrv_cmd.c b/src/responder/pac/pacsrv_cmd.c index 8f5617c7..c3f1115e 100644 --- a/src/responder/pac/pacsrv_cmd.c +++ b/src/responder/pac/pacsrv_cmd.c @@ -53,31 +53,39 @@ struct pac_req_ctx { struct pac_ctx *pac_ctx; const char *domain_name; const char *user_name; - char *fq_name; struct sss_domain_info *dom; struct PAC_LOGON_INFO *logon_info; struct dom_sid2 *domain_sid; - size_t gid_count; - struct pac_dom_grps *gids; - - size_t current_grp_count; - struct grp_info *current_grp_list; + size_t del_grp_count; + struct grp_info *del_grp_list; - size_t add_gid_count; - struct pac_dom_grps *add_gids; + size_t add_sid_count; + char **add_sids; - size_t del_grp_count; - struct grp_info **del_grp_list; + hash_table_t *sid_table; + char *user_sid_str; + char *user_dom_sid_str; + char *primary_group_sid_str; }; -static errno_t pac_add_user_next(struct pac_req_ctx *pr_ctx); +static errno_t pac_resolve_sids_next(struct pac_req_ctx *pr_ctx); +static void pac_lookup_sids_done(struct tevent_req *req); +static struct tevent_req *pac_lookup_sids_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct pac_req_ctx *pr_ctx, + struct pac_ctx *pac_ctx, + hash_table_t *sid_table); +static errno_t pac_lookup_sids_recv(struct tevent_req *req); +static void pac_add_user_next(struct pac_req_ctx *pr_ctx); static void pac_get_domains_done(struct tevent_req *req); static errno_t pac_user_get_grp_info(TALLOC_CTX *mem_ctx, struct pac_req_ctx *pr_ctx, - size_t *_current_grp_count, - struct grp_info **_current_grp_list); + size_t *_del_grp_count, + struct grp_info **_del_grp_list, + size_t *_add_sid_count, + char ***_add_sids); static errno_t save_pac_user(struct pac_req_ctx *pr_ctx); static void pac_get_group_done(struct tevent_req *subreq); static errno_t pac_save_memberships_next(struct tevent_req *req); @@ -96,6 +104,7 @@ static errno_t pac_add_pac_user(struct cli_ctx *cctx) size_t blen; struct pac_req_ctx *pr_ctx; struct tevent_req *req; + enum idmap_error_code err; sss_packet_get_body(cctx->creq->in, &body, &blen); @@ -143,8 +152,18 @@ static errno_t pac_add_pac_user(struct cli_ctx *cctx) goto done; } - pr_ctx->dom = responder_get_domain(cctx->rctx, pr_ctx->domain_name); - if (pr_ctx->dom == NULL) { + err = sss_idmap_smb_sid_to_sid(pr_ctx->pac_ctx->idmap_ctx, + pr_ctx->logon_info->info3.base.domain_sid, + &pr_ctx->user_dom_sid_str); + if (err != IDMAP_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, ("sss_idmap_smb_sid_to_sid failed.\n")); + ret = EFAULT; + goto done; + } + + ret = responder_get_domain_by_id(cctx->rctx, pr_ctx->user_dom_sid_str, + &pr_ctx->dom); + if (ret == EAGAIN || ret == ENOENT) { req = sss_dp_get_domains_send(cctx->rctx, cctx->rctx, true, pr_ctx->domain_name); if (req == NULL) { @@ -154,9 +173,12 @@ static errno_t pac_add_pac_user(struct cli_ctx *cctx) ret = EAGAIN; } goto done; + } else if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("responder_get_domain_by_id failed.\n")); + goto done; } - ret = pac_add_user_next(pr_ctx); + ret = pac_resolve_sids_next(pr_ctx); done: if (ret != EAGAIN) { @@ -178,15 +200,16 @@ static void pac_get_domains_done(struct tevent_req *req) goto done; } - pr_ctx->dom = responder_get_domain(cctx->rctx, pr_ctx->domain_name); - if (pr_ctx->dom == NULL) { + ret = responder_get_domain_by_id(cctx->rctx, pr_ctx->user_dom_sid_str, + &pr_ctx->dom); + if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Corresponding domain [%s] has not been " - "found\n", pr_ctx->domain_name)); + "found\n", pr_ctx->user_dom_sid_str)); ret = ENOENT; goto done; } - ret = pac_add_user_next(pr_ctx); + ret = pac_resolve_sids_next(pr_ctx); done: if (ret != EAGAIN) { @@ -195,58 +218,140 @@ done: pac_cmd_done(cctx, ret); } -static errno_t pac_add_user_next(struct pac_req_ctx *pr_ctx) +static errno_t pac_resolve_sids_next(struct pac_req_ctx *pr_ctx) { int ret; struct tevent_req *req; - struct dom_sid *my_dom_sid; - struct local_mapping_ranges *my_range_map; - - /* this is a subdomain so we need to search for the fully qualified - * name in the database */ - pr_ctx->fq_name= sss_tc_fqname(pr_ctx, pr_ctx->dom->names, - pr_ctx->dom, pr_ctx->user_name); - if (!pr_ctx->fq_name) { - ret = ENOMEM; - DEBUG(SSSDBG_OP_FAILURE, ("talloc_sprintf failed.\n")); - goto done; + + ret = get_sids_from_pac(pr_ctx, pr_ctx->pac_ctx, pr_ctx->logon_info, + &pr_ctx->user_sid_str, + &pr_ctx->primary_group_sid_str, + &pr_ctx->sid_table); + if (ret != 0) { + DEBUG(SSSDBG_OP_FAILURE, ("get_sids_from_pac failed.\n")); + return ret; } - ret = save_pac_user(pr_ctx); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, ("save_pac_user failed.\n")); - goto done; + req = pac_lookup_sids_send(pr_ctx, pr_ctx->cctx->ev, pr_ctx, + pr_ctx->pac_ctx, pr_ctx->sid_table); + if (req == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("pac_lookup_sids_send failed.\n")); + return ENOMEM; } - ret = pac_user_get_grp_info(pr_ctx, pr_ctx, &pr_ctx->current_grp_count, - &pr_ctx->current_grp_list); + tevent_req_set_callback(req, pac_lookup_sids_done, pr_ctx); + + ret = EAGAIN; + + + return ret; +} + +static void pac_lookup_sids_done(struct tevent_req *req) +{ + struct pac_req_ctx *pr_ctx = tevent_req_callback_data(req, struct pac_req_ctx); + struct cli_ctx *cctx = pr_ctx->cctx; + errno_t ret; + unsigned long count; + hash_entry_t *entries; + hash_key_t key; + hash_value_t value; + size_t c; + struct sss_domain_info *dom; + uint64_t id; + struct ldb_result *msg; + + ret = pac_lookup_sids_recv(req); + talloc_zfree(req); + if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, ("pac_user_get_grp_info failed.\n")); - goto done; + talloc_free(pr_ctx); + pac_cmd_done(cctx, ret); + return; } - ret = get_parent_domain_data(pr_ctx->pac_ctx, pr_ctx->dom, - &my_dom_sid, &my_range_map); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, ("get_parent_domain_data failed.\n")); - goto done; + key.type = HASH_KEY_STRING; + value.type = HASH_VALUE_ULONG; + + ret = hash_entries(pr_ctx->sid_table, &count, &entries); + for (c = 0; c < count; c++) { + if (entries[c].value.ul == 0) { + ret =responder_get_domain_by_id(cctx->rctx, + entries[c].key.str, &dom); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("No domain found for SID [%s].\n", + entries[c].key.str)); + continue; + } + + msg = NULL; + ret = sysdb_search_object_by_sid(pr_ctx, dom->sysdb, dom, + entries[c].key.str, NULL, &msg); + if (ret != EOK) { + if (ret == ENOENT) { + DEBUG(SSSDBG_OP_FAILURE, ("No entry found for SID [%s].\n", + entries[c].key.str)); + } else { + DEBUG(SSSDBG_OP_FAILURE, ("sysdb_search_object_by_sid " \ + "failed.\n")); + } + continue; + } + if (msg->count > 1) { + DEBUG(SSSDBG_CRIT_FAILURE, ("More then one result returned " \ + "for SID [%s].\n", + entries[c].key.str)); + talloc_free(msg); + pac_cmd_done(cctx, EINVAL); + return; + } + + id = ldb_msg_find_attr_as_uint64(msg->msgs[0], + SYSDB_UIDNUM, 0); + if (id == 0) { + id = ldb_msg_find_attr_as_uint64(msg->msgs[0], + SYSDB_GIDNUM, 0); + } + + if (id == 0) { + DEBUG(SSSDBG_OP_FAILURE, ("No ID found in entry.\n")); + talloc_free(msg); + continue; + } + + key.str = entries[c].key.str; + value.ul = id; + + ret = hash_enter(pr_ctx->sid_table, &key, &value); + if (ret != HASH_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, ("hash_enter failed [%d][%s].\n", + ret, hash_error_string(ret))); + continue; + } + talloc_free(msg); + } } - ret = get_gids_from_pac(pr_ctx, pr_ctx->pac_ctx, - my_range_map, my_dom_sid, pr_ctx->logon_info, - &pr_ctx->gid_count, &pr_ctx->gids); + pac_add_user_next(pr_ctx); +} + +static void pac_add_user_next(struct pac_req_ctx *pr_ctx) +{ + int ret; + struct tevent_req *req; + struct cli_ctx *cctx = pr_ctx->cctx; + + ret = save_pac_user(pr_ctx); if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, ("get_gids_from_pac failed.\n")); + DEBUG(SSSDBG_OP_FAILURE, ("save_pac_user failed.\n")); goto done; } - ret = diff_gid_lists(pr_ctx, - pr_ctx->current_grp_count, pr_ctx->current_grp_list, - pr_ctx->gid_count, pr_ctx->gids, - &pr_ctx->add_gid_count, &pr_ctx->add_gids, - &pr_ctx->del_grp_count, &pr_ctx->del_grp_list); + ret = pac_user_get_grp_info(pr_ctx, pr_ctx, &pr_ctx->del_grp_count, + &pr_ctx->del_grp_list, + &pr_ctx->add_sid_count, &pr_ctx->add_sids); if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, ("diff_gid_lists failed.\n")); + DEBUG(SSSDBG_OP_FAILURE, ("pac_user_get_grp_info failed.\n")); goto done; } @@ -261,23 +366,40 @@ static errno_t pac_add_user_next(struct pac_req_ctx *pr_ctx) ret = EAGAIN; done: - return ret; + if (ret != EAGAIN) { + talloc_free(pr_ctx); + } + pac_cmd_done(cctx, ret); } static errno_t pac_user_get_grp_info(TALLOC_CTX *mem_ctx, struct pac_req_ctx *pr_ctx, - size_t *_current_grp_count, - struct grp_info **_current_grp_list) + size_t *_del_grp_count, + struct grp_info **_del_grp_list, + size_t *_add_sid_count, + char ***_add_sids) { struct sysdb_ctx *sysdb; int ret; TALLOC_CTX *tmp_ctx = NULL; struct ldb_result *res = NULL; - struct grp_info *current_grp_list = NULL; - size_t current_grp_count = 0; size_t c; const char *tmp_str; + size_t add_sid_count = 0; + char **add_sids = NULL; + + size_t del_idx; + size_t del_grp_count = 0; + struct grp_info *del_grp_list = NULL; + + const char *cur_sid; + hash_key_t key; + hash_value_t value; + + struct hash_iter_context_t *iter = NULL; + hash_entry_t *entry; + sysdb = pr_ctx->dom->sysdb; if (sysdb == NULL) { ret = EINVAL; @@ -299,55 +421,118 @@ static errno_t pac_user_get_grp_info(TALLOC_CTX *mem_ctx, goto done; } + if (res->count == 0) { + DEBUG(SSSDBG_OP_FAILURE, ("sysdb_initgroups did not found [%s].\n", + pr_ctx->user_name)); + ret = ENOENT; + goto done; + } + /* First result is the user entry then the groups follow */ if (res->count > 1) { - current_grp_count = res->count - 1; - current_grp_list = talloc_array(tmp_ctx, struct grp_info, - current_grp_count); - if (current_grp_list == NULL) { + del_grp_count = res->count - 1; + del_grp_list = talloc_zero_array(tmp_ctx, struct grp_info, + del_grp_count); + if (del_grp_list == NULL) { DEBUG(SSSDBG_OP_FAILURE, ("talloc_array failed.\n")); ret = ENOMEM; goto done; } + del_idx = 0; - for (c = 0; c < current_grp_count; c++) { - current_grp_list[c].gid = - ldb_msg_find_attr_as_uint64(res->msgs[c + 1], - SYSDB_GIDNUM, 0); - if (current_grp_list[c].gid == 0) { - DEBUG(SSSDBG_OP_FAILURE, ("Missing GID.\n")); + key.type = HASH_KEY_STRING; + + for (c = 0; c < (res->count - 1); c++) { + cur_sid = ldb_msg_find_attr_as_string(res->msgs[c + 1], + SYSDB_SID_STR, NULL); + if (cur_sid == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("Missing SID in group entry.\n")); ret = EINVAL; goto done; } - tmp_str = ldb_msg_find_attr_as_string(res->msgs[c + 1], - SYSDB_ORIG_DN, NULL); - if (tmp_str != NULL) { - current_grp_list[c].orig_dn = talloc_strdup(current_grp_list, - tmp_str); - if (current_grp_list[c].orig_dn == NULL) { - DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n")); + key.str = discard_const(cur_sid); + ret = hash_lookup(pr_ctx->sid_table, &key, &value); + if (ret == HASH_SUCCESS) { + /* user is already member of the group */ + ret = hash_delete(pr_ctx->sid_table, &key); + if (ret != HASH_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, ("Failed to remove hash entry.\n")); + ret = EIO; + goto done; + } + } else if (ret == HASH_ERROR_KEY_NOT_FOUND) { + /* group is not in the PAC anymore, membership must be removed */ + del_grp_list[del_idx].gid = + ldb_msg_find_attr_as_uint64(res->msgs[c + 1], + SYSDB_GIDNUM, 0); + if (del_grp_list[del_idx].gid == 0) { + DEBUG(SSSDBG_OP_FAILURE, ("Missing GID.\n")); + ret = EINVAL; + goto done; + } + + tmp_str = ldb_msg_find_attr_as_string(res->msgs[c + 1], + SYSDB_ORIG_DN, NULL); + if (tmp_str != NULL) { + del_grp_list[del_idx].orig_dn = talloc_strdup(del_grp_list, + tmp_str); + if (del_grp_list[del_idx].orig_dn == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n")); + ret = ENOMEM; + goto done; + } + } + + del_grp_list[del_idx].dn = ldb_dn_copy(del_grp_list, + res->msgs[c + 1]->dn); + if (del_grp_list[del_idx].dn == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("ldb_dn_copy failed.\n")); ret = ENOMEM; goto done; } + + del_idx++; } + } + del_grp_count = del_idx; + } - current_grp_list[c].dn = ldb_dn_copy(current_grp_list, - res->msgs[c + 1]->dn); - if (current_grp_list[c].dn == NULL) { - DEBUG(SSSDBG_OP_FAILURE, ("ldb_dn_copy failed.\n")); - ret = ENOMEM; - goto done; + add_sid_count = hash_count(pr_ctx->sid_table); + if (add_sid_count > 0) { + add_sids = talloc_array(tmp_ctx, char *, add_sid_count); + if (add_sids == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("talloc_array failed.\n")); + ret = ENOMEM; + goto done; + } + + iter = new_hash_iter_context(pr_ctx->sid_table); + c = 0; + while ((entry = iter->next(iter)) != NULL) { + if (strcmp(entry->key.str, pr_ctx->user_sid_str) != 0) { + add_sids[c] = talloc_strdup(add_sids, entry->key.str); + if (add_sids[c] == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n")); + ret = ENOMEM; + goto done; + } + c++; } } + add_sid_count = c; } - *_current_grp_count = current_grp_count; - *_current_grp_list = talloc_steal(mem_ctx, current_grp_list); + + *_del_grp_count = del_grp_count; + *_del_grp_list = talloc_steal(mem_ctx, del_grp_list); + *_add_sid_count = add_sid_count; + *_add_sids = talloc_steal(mem_ctx, add_sids); ret = EOK; done: + talloc_free(iter); talloc_free(tmp_ctx); return ret; @@ -357,7 +542,9 @@ static errno_t save_pac_user(struct pac_req_ctx *pr_ctx) { struct sysdb_ctx *sysdb; int ret; - const char *attrs[] = {SYSDB_NAME, SYSDB_UIDNUM, SYSDB_GIDNUM, NULL}; + const char *attrs[] = {SYSDB_NAME, SYSDB_NAME_ALIAS, SYSDB_UIDNUM, + SYSDB_GIDNUM, SYSDB_GECOS, SYSDB_HOMEDIR, + SYSDB_SHELL, NULL}; struct ldb_message *msg; struct passwd *pwd = NULL; TALLOC_CTX *tmp_ctx = NULL; @@ -377,7 +564,8 @@ static errno_t save_pac_user(struct pac_req_ctx *pr_ctx) goto done; } - ret = get_pwd_from_pac(tmp_ctx, pr_ctx->pac_ctx, pr_ctx->dom, + ret = get_pwd_from_pac(tmp_ctx, pr_ctx->dom, pr_ctx->user_sid_str, + pr_ctx->primary_group_sid_str, pr_ctx->sid_table, pr_ctx->logon_info, &pwd, &user_attrs); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("get_pwd_from_pac failed.\n")); @@ -420,12 +608,10 @@ done: } struct pac_save_memberships_state { - size_t gid_iter; - size_t dom_iter; + size_t sid_iter; struct ldb_dn *user_dn; struct pac_req_ctx *pr_ctx; - struct sss_domain_info *group_dom; }; static errno_t @@ -437,28 +623,34 @@ struct tevent_req *pac_save_memberships_send(struct pac_req_ctx *pr_ctx) struct sss_domain_info *dom = pr_ctx->dom; struct tevent_req *req; errno_t ret; + char *fq_name = NULL; req = tevent_req_create(pr_ctx, &state, struct pac_save_memberships_state); if (req == NULL) { return NULL; } - state->gid_iter = 0; - state->dom_iter = 0; - state->user_dn = sysdb_user_dn(dom->sysdb, state, dom, pr_ctx->fq_name); + state->sid_iter = 0; + if (IS_SUBDOMAIN(dom)) { + fq_name = sss_tc_fqname(pr_ctx, pr_ctx->dom->names, pr_ctx->dom, + pr_ctx->user_name); + if (fq_name == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("talloc_sprintf failed.\n")); + ret = ENOMEM; + goto done; + } + + state->user_dn = sysdb_user_dn(dom->sysdb, state, dom, fq_name); + } else { + state->user_dn = sysdb_user_dn(dom->sysdb, state, dom, + pr_ctx->user_name); + } if (state->user_dn == NULL) { ret = ENOMEM; goto done; } state->pr_ctx = pr_ctx; - /* Remote users are members of local groups */ - if (IS_SUBDOMAIN(pr_ctx->dom)) { - state->group_dom = pr_ctx->dom->parent; - } else { - state->group_dom = pr_ctx->dom; - } - ret = pac_save_memberships_delete(state); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("pac_save_memberships_delete failed.\n")); @@ -472,6 +664,7 @@ struct tevent_req *pac_save_memberships_send(struct pac_req_ctx *pr_ctx) } done: + talloc_free(fq_name); if (ret != EOK && ret != EAGAIN) { tevent_req_error(req, ret); tevent_req_post(req, pr_ctx->cctx->ev); @@ -515,7 +708,7 @@ pac_save_memberships_delete(struct pac_save_memberships_state *state) goto done; } - ret = sysdb_transaction_start(state->group_dom->sysdb); + ret = sysdb_transaction_start(pr_ctx->dom->sysdb); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("sysdb_transaction_start failed.\n")); goto done; @@ -523,17 +716,17 @@ pac_save_memberships_delete(struct pac_save_memberships_state *state) in_transaction = true; for (c = 0; c < pr_ctx->del_grp_count; c++) { - ret = sysdb_mod_group_member(state->group_dom->sysdb, state->user_dn, - pr_ctx->del_grp_list[c]->dn, + ret = sysdb_mod_group_member(pr_ctx->dom->sysdb, state->user_dn, + pr_ctx->del_grp_list[c].dn, LDB_FLAG_MOD_DELETE); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("sysdb_mod_group_member failed.\n")); goto done; } - if (pr_ctx->del_grp_list[c]->orig_dn != NULL) { + if (pr_ctx->del_grp_list[c].orig_dn != NULL) { ret = sysdb_attrs_add_string(user_attrs, SYSDB_ORIG_MEMBEROF, - pr_ctx->del_grp_list[c]->orig_dn); + pr_ctx->del_grp_list[c].orig_dn); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_add_string failed.\n")); goto done; @@ -548,7 +741,7 @@ pac_save_memberships_delete(struct pac_save_memberships_state *state) goto done; } - ret = sysdb_transaction_commit(state->group_dom->sysdb); + ret = sysdb_transaction_commit(pr_ctx->dom->sysdb); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("sysdb_transaction_commit failed.\n")); goto done; @@ -558,7 +751,7 @@ pac_save_memberships_delete(struct pac_save_memberships_state *state) ret = EOK; done: if (in_transaction) { - sret = sysdb_transaction_cancel(state->group_dom->sysdb); + sret = sysdb_transaction_cancel(pr_ctx->dom->sysdb); if (sret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("sysdb_transaction_cancel failed.\n")); } @@ -573,43 +766,46 @@ static errno_t pac_save_memberships_next(struct tevent_req *req) { errno_t ret; uint32_t gid; + char *sid; struct sss_domain_info *grp_dom; struct tevent_req *subreq; struct pac_save_memberships_state *state; struct pac_req_ctx *pr_ctx; + hash_key_t key; + hash_value_t value; + + key.type = HASH_KEY_STRING; state = tevent_req_data(req, struct pac_save_memberships_state); pr_ctx = state->pr_ctx; - if (pr_ctx->add_gid_count == 0) { + if (pr_ctx->add_sid_count == 0) { return EOK; } - if (pr_ctx->add_gids == NULL) { - DEBUG(SSSDBG_OP_FAILURE, ("Missing group list.\n")); + if (pr_ctx->add_sids == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("Missing list of SIDs.\n")); return EINVAL; } - while (pr_ctx->add_gids[state->dom_iter].grp_dom != NULL) { - - if (pr_ctx->add_gids[state->dom_iter].gids == NULL || - pr_ctx->add_gids[state->dom_iter].gid_count == 0) { - state->dom_iter++; - state->gid_iter = 0; - continue; + while (state->sid_iter < pr_ctx->add_sid_count) { + sid = pr_ctx->add_sids[state->sid_iter]; + ret = responder_get_domain_by_id(pr_ctx->pac_ctx->rctx, sid, &grp_dom); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("responder_get_domain_by_id failed.\n")); + return ret; } - - - gid = pr_ctx->add_gids[state->dom_iter].gids[state->gid_iter]; - grp_dom = pr_ctx->add_gids[state->dom_iter].grp_dom; + key.str = sid; + ret = hash_lookup(pr_ctx->sid_table, &key, &value); + if (ret != HASH_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, ("hash_lookup failed.\n")); + return EIO; + } + gid = value.ul; ret = pac_store_membership(state->pr_ctx, state->user_dn, gid, grp_dom); if (ret == EOK) { - state->gid_iter++; - if (state->gid_iter >= pr_ctx->add_gids[state->dom_iter].gid_count) { - state->dom_iter++; - state->gid_iter = 0; - } + state->sid_iter++; continue; } else if (ret == ENOENT) { subreq = sss_dp_get_account_send(state, pr_ctx->cctx->rctx, @@ -646,8 +842,13 @@ static void pac_get_group_done(struct tevent_req *subreq) dbus_uint32_t err_min; char *err_msg; gid_t gid; + char *sid; struct sss_domain_info *grp_dom; struct pac_req_ctx *pr_ctx = state->pr_ctx; + hash_key_t key; + hash_value_t value; + + key.type = HASH_KEY_STRING; ret = sss_dp_get_account_recv(req, subreq, &err_maj, &err_min, @@ -658,17 +859,27 @@ static void pac_get_group_done(struct tevent_req *subreq) goto error; } - gid = pr_ctx->add_gids[state->dom_iter].gids[state->gid_iter]; - grp_dom = pr_ctx->add_gids[state->dom_iter].grp_dom; - ret = pac_store_membership(state->pr_ctx, state->user_dn, gid, grp_dom); + sid = pr_ctx->add_sids[state->sid_iter]; + ret = responder_get_domain_by_id(pr_ctx->pac_ctx->rctx,sid, &grp_dom); if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("responder_get_domain_by_id failed.\n")); goto error; } - state->gid_iter++; - if (state->gid_iter >= pr_ctx->add_gids[state->dom_iter].gid_count) { - state->dom_iter++; - state->gid_iter = 0; + + key.str = sid; + ret = hash_lookup(pr_ctx->sid_table, &key, &value); + if (ret != HASH_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, ("hash_lookup failed.\n")); + ret = EIO; + goto error; } + gid = value.ul; + + ret = pac_store_membership(state->pr_ctx, state->user_dn, gid, grp_dom); + if (ret != EOK) { + goto error; + } + state->sid_iter++; ret = pac_save_memberships_next(req); if (ret == EOK) { @@ -765,6 +976,117 @@ static void pac_save_memberships_done(struct tevent_req *req) pac_cmd_done(cctx, ret); } +struct pac_lookup_sids_state { + struct pac_ctx *pac_ctx; + struct pac_req_ctx *pr_ctx; + hash_table_t *sid_table; + struct hash_iter_context_t *iter; +}; + +static errno_t pac_lookup_sids_next(struct tevent_req *req); +static void pac_lookup_sids_next_done(struct tevent_req *subreq); + +static struct tevent_req *pac_lookup_sids_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct pac_req_ctx *pr_ctx, + struct pac_ctx *pac_ctx, + hash_table_t *sid_table) +{ + struct tevent_req *req; + struct pac_lookup_sids_state *state; + int ret; + + req = tevent_req_create(mem_ctx, &state, struct pac_lookup_sids_state); + if (req == NULL) { + return NULL; + } + + state->pac_ctx = pac_ctx; + state->pr_ctx = pr_ctx; + state->sid_table = sid_table; + state->iter = talloc_steal(state, new_hash_iter_context(state->sid_table)); + + ret = pac_lookup_sids_next(req); + + if (ret != EAGAIN) { + if (ret == EOK) { + tevent_req_done(req); + } else { + tevent_req_error(req, ret); + } + tevent_req_post(req, ev); + } + + return req; +} + + +static errno_t pac_lookup_sids_next(struct tevent_req *req) +{ + struct pac_lookup_sids_state *state; + state = tevent_req_data(req, struct pac_lookup_sids_state); + hash_entry_t *entry; + struct tevent_req *subreq; + struct sss_domain_info *dom; + int ret; + + while ((entry = state->iter->next(state->iter)) != NULL) { + if (entry->value.ul == 0) { + ret = responder_get_domain_by_id(state->pac_ctx->rctx, + entry->key.str, &dom); + if (ret == EOK && dom != NULL) { + subreq = sss_dp_get_account_send(state, + state->pr_ctx->cctx->rctx, + dom, true, + SSS_DP_SECID, entry->key.str, + 0, NULL); + if (subreq == NULL) { + return ENOMEM; + } + tevent_req_set_callback(subreq, pac_lookup_sids_next_done, req); + return EAGAIN; + } + } + } + + return EOK; +} + +static void pac_lookup_sids_next_done(struct tevent_req *subreq) +{ + struct tevent_req *req; + + req = tevent_req_callback_data(subreq, struct tevent_req); + + errno_t ret; + dbus_uint16_t err_maj; + dbus_uint32_t err_min; + char *err_msg; + + ret = sss_dp_get_account_recv(req, subreq, + &err_maj, &err_min, + &err_msg); + talloc_zfree(subreq); + talloc_zfree(err_msg); + /* Errors during individual lookups are ignored. */ + + ret = pac_lookup_sids_next(req); + if (ret == EOK) { + tevent_req_done(req); + } else if (ret != EAGAIN) { + tevent_req_error(req, ret); + } + + return; +} + +static errno_t pac_lookup_sids_recv(struct tevent_req *req) +{ + TEVENT_REQ_RETURN_ON_ERROR(req); + + return EOK; +} + struct cli_protocol_version *register_cli_protocol_version(void) { static struct cli_protocol_version pac_cli_protocol_version[] = { |