From b520654440b8162c886bde0270b2b7fe9e191125 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 4 Nov 2009 15:40:04 -0500 Subject: Fix and enhance initgroups call This call was failing and was defective because it didn't properly handle the various different schemas we support. Now the function does 2 things: - Updates the user entry to make sure it is still valid - Retrieves every group the user is member of --- server/providers/ldap/sdap_async.c | 857 ++++++++++++++++++++++++++++--------- 1 file changed, 662 insertions(+), 195 deletions(-) (limited to 'server') diff --git a/server/providers/ldap/sdap_async.c b/server/providers/ldap/sdap_async.c index d086e6936..63445f55b 100644 --- a/server/providers/ldap/sdap_async.c +++ b/server/providers/ldap/sdap_async.c @@ -1331,6 +1331,8 @@ static struct tevent_req *sdap_save_user_send(TALLOC_CTX *memctx, int i; char *val = NULL; + DEBUG(9, ("Save user\n")); + req = tevent_req_create(memctx, &state, struct sdap_save_user_state); if (!req) return NULL; @@ -1573,7 +1575,9 @@ static int sdap_save_user_recv(struct tevent_req *req, return err; } - *timestamp = talloc_steal(mem_ctx, state->timestamp); + if (timestamp) { + *timestamp = talloc_steal(mem_ctx, state->timestamp); + } return EOK; } @@ -2753,291 +2757,737 @@ int sdap_get_groups_recv(struct tevent_req *req, return EOK; } -/* ==Initgr-call-(groups-a-user-is-member-of)============================= */ +/* ==Initgr-call-(groups-a-user-is-member-of)-Save-Groups================= */ -struct sdap_get_initgr_state { +struct sdap_save_groups_state { struct tevent_context *ev; struct sysdb_ctx *sysdb; struct sdap_options *opts; struct sss_domain_info *dom; - struct sdap_handle *sh; - const char *name; - const char **grp_attrs; - const char *filter; + struct sysdb_attrs **groups; + int count; + int cur; + bool savemembers; struct sysdb_handle *handle; - struct sdap_op *op; }; -static void sdap_get_initgr_process(struct tevent_req *subreq); -static void sdap_get_initgr_transaction(struct tevent_req *subreq); -static void sdap_get_initgr_done(struct sdap_op *op, - struct sdap_msg *reply, - int error, void *pvt); -static void sdap_get_initgr_save_done(struct tevent_req *subreq); - -struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sss_domain_info *dom, - struct sysdb_ctx *sysdb, - struct sdap_options *opts, - struct sdap_handle *sh, - const char *name, - const char **grp_attrs) +static void sdap_save_groups_trans(struct tevent_req *subreq); +static void sdap_save_groups_store(struct tevent_req *req); +static void sdap_save_groups_process(struct tevent_req *subreq); +struct tevent_req *sdap_save_groups_send(TALLOC_CTX *memctx, + struct tevent_context *ev, + struct sss_domain_info *dom, + struct sysdb_ctx *sysdb, + struct sdap_options *opts, + struct sysdb_attrs **groups, + int num_groups) { struct tevent_req *req, *subreq; - struct sdap_get_initgr_state *state; - struct timeval tv = {0, 0}; - const char **attrs; - int ret; + struct sdap_save_groups_state *state; - req = tevent_req_create(memctx, &state, struct sdap_get_initgr_state); + req = tevent_req_create(memctx, &state, struct sdap_save_groups_state); if (!req) return NULL; state->ev = ev; state->opts = opts; state->sysdb = sysdb; state->dom = dom; - state->sh = sh; - state->name = name; - state->grp_attrs = grp_attrs; + state->groups = groups; + state->count = 0; + state->cur = 0; + state->handle = NULL; switch (opts->schema_type) { case SDAP_SCHEMA_RFC2307: - - subreq = tevent_wakeup_send(state, ev, tv); - if (!subreq) { - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(subreq, sdap_get_initgr_process, req); - break; - case SDAP_SCHEMA_RFC2307BIS: + state->savemembers = true; + break; - attrs = talloc_array(state, const char *, 2); - if (!attrs) { - ret = ENOMEM; - goto fail; - } - attrs[0] = SYSDB_ORIG_DN; - attrs[1] = NULL; - - subreq = sysdb_search_user_by_name_send(state, ev, sysdb, NULL, - dom, name, attrs); - if (!subreq) { - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(subreq, sdap_get_initgr_process, req); + case SDAP_SCHEMA_IPA_V1: + case SDAP_SCHEMA_AD: + state->savemembers = false; break; default: - ret = EINVAL; - goto fail; + tevent_req_error(req, EINVAL); + tevent_req_post(req, ev); + return req; } - return req; + subreq = sysdb_transaction_send(state, state->ev, state->sysdb); + if (!subreq) { + tevent_req_error(req, ENOMEM); + tevent_req_post(req, ev); + return req; + } + tevent_req_set_callback(subreq, sdap_save_groups_trans, req); -fail: - tevent_req_error(req, EIO); - tevent_req_post(req, ev); return req; } -static void sdap_get_initgr_process(struct tevent_req *subreq) +static void sdap_save_groups_trans(struct tevent_req *subreq) { - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_get_initgr_state *state = tevent_req_data(req, - struct sdap_get_initgr_state); - struct ldb_message *msg; - const char *user_dn; + struct tevent_req *req; + struct sdap_save_groups_state *state; int ret; - switch (state->opts->schema_type) { - case SDAP_SCHEMA_RFC2307: + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_save_groups_state); - if (!tevent_wakeup_recv(subreq)) { - tevent_req_error(req, EFAULT); - return; - } - talloc_zfree(subreq); + ret = sysdb_transaction_recv(subreq, state, &state->handle); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } - state->filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))", - state->opts->group_map[SDAP_AT_GROUP_MEMBER].name, - state->name, - state->opts->group_map[SDAP_OC_GROUP].name); - break; + sdap_save_groups_store(req); +} - case SDAP_SCHEMA_RFC2307BIS: +static void sdap_save_groups_store(struct tevent_req *req) +{ + struct tevent_req *subreq; + struct sdap_save_groups_state *state; - ret = sysdb_search_user_recv(subreq, state, &msg); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } + state = tevent_req_data(req, struct sdap_save_groups_state); + + /* 1st pass savemembers = false */ + /* 2nd pass savemembers = true */ + subreq = sdap_save_group_send(state, state->ev, state->handle, + state->opts, state->dom, + state->groups[state->cur], + state->savemembers); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sdap_save_groups_process, req); +} + +static void sdap_save_groups_process(struct tevent_req *subreq) +{ + struct tevent_req *req; + struct sdap_save_groups_state *state; + int ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_save_groups_state); + + ret = sdap_save_group_recv(subreq, NULL, NULL); + talloc_zfree(subreq); + + /* Do not fail completely on errors. + * Just report the failure to save and go on */ + if (ret) { + DEBUG(2, ("Failed to store group %d. Ignoring.\n", state->cur)); + } - user_dn = ldb_msg_find_attr_as_string(msg, SYSDB_ORIG_DN, NULL); - if (!user_dn) { - tevent_req_error(req, ENOENT); + state->cur++; + if (state->cur < state->count) { + sdap_save_groups_store(req); + } else if (state->savemembers == false) { + state->savemembers = true; + state->cur = 0; + sdap_save_groups_store(req); + } else { + subreq = sysdb_transaction_commit_send(state, state->ev, + state->handle); + if (!subreq) { + tevent_req_error(req, ENOMEM); return; } + /* sysdb_transaction_complete will call tevent_req_done(req) */ + tevent_req_set_callback(subreq, sysdb_transaction_complete, req); + } +} - state->filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))", - state->opts->group_map[SDAP_AT_GROUP_MEMBER].name, - user_dn, - state->opts->group_map[SDAP_OC_GROUP].name); - - talloc_free(msg); - break; +static int sdap_save_groups_recv(struct tevent_req *req) +{ + enum tevent_req_state tstate; + uint64_t err; - default: - tevent_req_error(req, EINVAL); - return; + if (tevent_req_is_error(req, &tstate, &err)) { + if (err) return err; + return EIO; } + return EOK; +} - if (!state->filter) { - tevent_req_error(req, ENOMEM); - return; + +/* ==Initgr-call-(groups-a-user-is-member-of)-RFC2307-Classic/BIS========= */ + +struct sdap_initgr_rfc2307_state { + struct tevent_context *ev; + struct sysdb_ctx *sysdb; + struct sdap_options *opts; + struct sss_domain_info *dom; + struct sdap_handle *sh; + + struct sdap_op *op; +}; + +static void sdap_initgr_rfc2307_process(struct tevent_req *subreq); +static void sdap_initgr_rfc2307_done(struct tevent_req *subreq); +struct tevent_req *sdap_initgr_rfc2307_send(TALLOC_CTX *memctx, + struct tevent_context *ev, + struct sdap_options *opts, + struct sysdb_ctx *sysdb, + struct sss_domain_info *dom, + struct sdap_handle *sh, + const char *base_dn, + const char *name, + const char **grp_attrs) +{ + struct tevent_req *req, *subreq; + struct sdap_initgr_rfc2307_state *state; + const char *filter; + + req = tevent_req_create(memctx, &state, struct sdap_initgr_rfc2307_state); + if (!req) return NULL; + + state->ev = ev; + state->opts = opts; + state->sysdb = sysdb; + state->dom = dom; + state->sh = sh; + state->op = NULL; + + filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))", + opts->group_map[SDAP_AT_GROUP_MEMBER].name, + name, opts->group_map[SDAP_OC_GROUP].name); + if (!filter) { + talloc_zfree(req); + return NULL; } - subreq = sysdb_transaction_send(state, state->ev, state->sysdb); + subreq = sdap_get_generic_send(state, state->ev, state->opts, + state->sh, base_dn, LDAP_SCOPE_SUBTREE, + filter, grp_attrs, + state->opts->group_map, SDAP_OPTS_GROUP); if (!subreq) { - tevent_req_error(req, ENOMEM); - return; + talloc_zfree(req); + return NULL; } - tevent_req_set_callback(subreq, sdap_get_initgr_transaction, req); + tevent_req_set_callback(subreq, sdap_initgr_rfc2307_process, req); + + return req; } -static void sdap_get_initgr_transaction(struct tevent_req *subreq) +static void sdap_initgr_rfc2307_process(struct tevent_req *subreq) { - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_get_initgr_state *state = tevent_req_data(req, - struct sdap_get_initgr_state); - int ret, lret; - int msgid; + struct tevent_req *req; + struct sdap_initgr_rfc2307_state *state; + struct sysdb_attrs **groups; + size_t count; + int ret; - ret = sysdb_transaction_recv(subreq, state, &state->handle); + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_initgr_rfc2307_state); + + ret = sdap_get_generic_recv(subreq, state, &count, &groups); talloc_zfree(subreq); if (ret) { tevent_req_error(req, ret); return; } - DEBUG(5, ("calling ldap_search_ext with filter:[%s].\n", state->filter)); + if (count == 0) { + tevent_req_done(req); + return; + } - lret = ldap_search_ext(state->sh->ldap, - dp_opt_get_string(state->opts->basic, - SDAP_GROUP_SEARCH_BASE), - LDAP_SCOPE_SUBTREE, state->filter, - discard_const(state->grp_attrs), - false, NULL, NULL, NULL, 0, &msgid); - if (lret != LDAP_SUCCESS) { - DEBUG(3, ("ldap_search_ext failed: %s\n", ldap_err2string(lret))); - tevent_req_error(req, EIO); + subreq = sdap_save_groups_send(state, state->ev, state->dom, + state->sysdb, state->opts, + groups, count); + if (!subreq) { + tevent_req_error(req, ENOMEM); return; } + tevent_req_set_callback(subreq, sdap_initgr_rfc2307_done, req); +} - DEBUG(8, ("ldap_search_ext called, msgid = %d\n", msgid)); +static void sdap_initgr_rfc2307_done(struct tevent_req *subreq) +{ + struct tevent_req *req; + int ret; - /* FIXME: get timeouts from configuration, for now 10 minutes */ - ret = sdap_op_add(state, state->ev, state->sh, msgid, - sdap_get_initgr_done, req, - dp_opt_get_int(state->opts->basic, - SDAP_SEARCH_TIMEOUT), - &state->op); + req = tevent_req_callback_data(subreq, struct tevent_req); + + ret = sdap_save_groups_recv(subreq); + talloc_zfree(subreq); if (ret) { - DEBUG(1, ("Failed to set up operation!\n")); tevent_req_error(req, ret); + return; } + + tevent_req_done(req); } -static void sdap_get_initgr_done(struct sdap_op *op, - struct sdap_msg *reply, - int error, void *pvt) +static int sdap_initgr_rfc2307_recv(struct tevent_req *req) { - struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); - struct sdap_get_initgr_state *state = tevent_req_data(req, - struct sdap_get_initgr_state); - struct tevent_req *subreq; - struct sysdb_attrs *grp_attrs; - char *errmsg; - int result; - int ret; + enum tevent_req_state tstate; + uint64_t err; - if (error) { - tevent_req_error(req, error); - return; + if (tevent_req_is_error(req, &tstate, &err)) { + if (err) return err; + return EIO; } + return EOK; +} - switch (ldap_msgtype(reply->msg)) { - case LDAP_RES_SEARCH_REFERENCE: - /* ignore references for now */ - talloc_free(reply); - /* unlock the operation so that we can proceed with the next result */ - sdap_unlock_next_reply(state->op); - break; +/* ==Initgr-call-(groups-a-user-is-member-of)-nested-groups=============== */ - case LDAP_RES_SEARCH_ENTRY: +struct sdap_initgr_nested_state { + struct tevent_context *ev; + struct sysdb_ctx *sysdb; + struct sdap_options *opts; + struct sss_domain_info *dom; + struct sdap_handle *sh; - /* allocate on reply so that it will be freed once the - * reply is processed. Remember to steal if you need something - * to stick longer */ - ret = sdap_parse_group(reply, state->opts, state->sh, - reply, &grp_attrs, NULL); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } + const char **grp_attrs; - subreq = sdap_save_group_send(state, state->ev, state->handle, - state->opts, state->dom, - grp_attrs, true); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; + char *filter; + char **group_dns; + int count; + int cur; + + struct sdap_op *op; + + struct sysdb_attrs **groups; + int groups_cur; +}; + +static void sdap_initgr_nested_search(struct tevent_req *subreq); +static void sdap_initgr_nested_store(struct tevent_req *req); +static void sdap_initgr_nested_done(struct tevent_req *subreq); +static struct tevent_req *sdap_initgr_nested_send(TALLOC_CTX *memctx, + struct tevent_context *ev, + struct sdap_options *opts, + struct sysdb_ctx *sysdb, + struct sss_domain_info *dom, + struct sdap_handle *sh, + struct sysdb_attrs *user, + const char **grp_attrs) +{ + struct tevent_req *req, *subreq; + struct sdap_initgr_nested_state *state; + struct ldb_message_element *el; + int i, ret; + + req = tevent_req_create(memctx, &state, struct sdap_initgr_nested_state); + if (!req) return NULL; + + state->ev = ev; + state->opts = opts; + state->sysdb = sysdb; + state->dom = dom; + state->sh = sh; + state->grp_attrs = grp_attrs; + state->op = NULL; + + state->filter = talloc_asprintf(state, "(objectclass=%s)", + opts->group_map[SDAP_OC_GROUP].name); + if (!state->filter) { + talloc_zfree(req); + return NULL; + } + + /* TODO: test rootDSE for deref support and use it if available */ + /* TODO: or test rootDSE for ASQ support and use it if available */ + + ret = sysdb_attrs_get_el(user, SYSDB_MEMBEROF, &el); + if (ret || !el || el->num_values == 0) { + DEBUG(4, ("User entry lacks original memberof ?\n")); + /* user with no groups ? */ + tevent_req_error(req, ENOENT); + tevent_req_post(req, ev); + } + state->count = el->num_values; + + state->groups = talloc_zero_array(state, struct sysdb_attrs *, + state->count + 1);; + if (!state->groups) { + talloc_zfree(req); + return NULL; + } + state->groups_cur = 0; + + state->group_dns = talloc_array(state, char *, state->count + 1); + if (!state->group_dns) { + talloc_zfree(req); + return NULL; + } + for (i = 0; i < state->count; i++) { + state->group_dns[i] = talloc_strdup(state->group_dns, + (char *)el->values[i].data); + if (!state->group_dns[i]) { + talloc_zfree(req); + return NULL; } - tevent_req_set_callback(subreq, sdap_get_initgr_save_done, req); + } + state->group_dns[i] = NULL; /* terminate */ + state->cur = 0; - break; + subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh, + state->group_dns[state->cur], + LDAP_SCOPE_BASE, + state->filter, state->grp_attrs, + state->opts->group_map, SDAP_OPTS_GROUP); + if (!subreq) { + talloc_zfree(req); + return NULL; + } + tevent_req_set_callback(subreq, sdap_initgr_nested_search, req); - case LDAP_RES_SEARCH_RESULT: - /* End of the story */ + return req; +} - ret = ldap_parse_result(state->sh->ldap, reply->msg, - &result, NULL, &errmsg, NULL, NULL, 0); - if (ret != LDAP_SUCCESS) { - DEBUG(2, ("ldap_parse_result failed (%d)\n", state->op->msgid)); - tevent_req_error(req, EIO); +static void sdap_initgr_nested_search(struct tevent_req *subreq) +{ + struct tevent_req *req; + struct sdap_initgr_nested_state *state; + struct sysdb_attrs **groups; + size_t count; + int ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_initgr_nested_state); + + ret = sdap_get_generic_recv(subreq, state, &count, &groups); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + if (count == 1) { + state->groups[state->groups_cur] = groups[0]; + state->groups_cur++; + } else { + DEBUG(2, ("Search for group %s, returned %d results. Skipping\n", + state->group_dns[state->cur], count)); + } + + state->cur++; + if (state->cur < state->count) { + subreq = sdap_get_generic_send(state, state->ev, + state->opts, state->sh, + state->group_dns[state->cur], + LDAP_SCOPE_BASE, + state->filter, state->grp_attrs, + state->opts->group_map, + SDAP_OPTS_GROUP); + if (!subreq) { + tevent_req_error(req, ENOMEM); return; } + tevent_req_set_callback(subreq, sdap_initgr_nested_search, req); + } else { + sdap_initgr_nested_store(req); + } +} - DEBUG(3, ("Search result: %s(%d), %s\n", - ldap_err2string(result), result, errmsg)); +static void sdap_initgr_nested_store(struct tevent_req *req) +{ + struct tevent_req *subreq; + struct sdap_initgr_nested_state *state; - subreq = sysdb_transaction_commit_send(state, state->ev, - state->handle); + state = tevent_req_data(req, struct sdap_initgr_nested_state); + + subreq = sdap_save_groups_send(state, state->ev, state->dom, + state->sysdb, state->opts, + state->groups, state->groups_cur); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sdap_initgr_nested_done, req); +} + +static void sdap_initgr_nested_done(struct tevent_req *subreq) +{ + struct tevent_req *req; + int ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); + + ret = sdap_save_groups_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + tevent_req_done(req); +} + +static int sdap_initgr_nested_recv(struct tevent_req *req) +{ + enum tevent_req_state tstate; + uint64_t err; + + if (tevent_req_is_error(req, &tstate, &err)) { + if (err) return err; + return EIO; + } + return EOK; +} + + +/* ==Initgr-call-(groups-a-user-is-member-of)============================= */ + +struct sdap_get_initgr_state { + struct tevent_context *ev; + struct sysdb_ctx *sysdb; + struct sdap_options *opts; + struct sss_domain_info *dom; + struct sdap_handle *sh; + const char *name; + const char **grp_attrs; + + struct sysdb_attrs *orig_user; + + struct sysdb_handle *handle; +}; + +static void sdap_get_initgr_user(struct tevent_req *subreq); +static void sdap_get_initgr_store(struct tevent_req *subreq); +static void sdap_get_initgr_commit(struct tevent_req *subreq); +static void sdap_get_initgr_process(struct tevent_req *subreq); +static void sdap_get_initgr_done(struct tevent_req *subreq); + +struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx, + struct tevent_context *ev, + struct sss_domain_info *dom, + struct sysdb_ctx *sysdb, + struct sdap_options *opts, + struct sdap_handle *sh, + const char *name, + const char **grp_attrs) +{ + struct tevent_req *req, *subreq; + struct sdap_get_initgr_state *state; + const char *base_dn; + char *filter; + const char **attrs; + int ret; + + DEBUG(9, ("Retrieving info for initgroups call\n")); + + req = tevent_req_create(memctx, &state, struct sdap_get_initgr_state); + if (!req) return NULL; + + state->ev = ev; + state->opts = opts; + state->sysdb = sysdb; + state->dom = dom; + state->sh = sh; + state->name = name; + state->grp_attrs = grp_attrs; + state->orig_user = NULL; + + filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))", + state->opts->user_map[SDAP_AT_USER_NAME].name, + state->name, + state->opts->user_map[SDAP_OC_USER].name); + if (!filter) { + talloc_zfree(req); + return NULL; + } + + base_dn = dp_opt_get_string(state->opts->basic, + SDAP_USER_SEARCH_BASE); + if (!base_dn) { + talloc_zfree(req); + return NULL; + } + + ret = build_attrs_from_map(state, state->opts->user_map, + SDAP_OPTS_USER, &attrs); + if (ret) { + talloc_zfree(req); + return NULL; + } + + subreq = sdap_get_generic_send(state, state->ev, + state->opts, state->sh, + base_dn, LDAP_SCOPE_SUBTREE, + filter, attrs, + state->opts->user_map, SDAP_OPTS_USER); + if (!subreq) { + talloc_zfree(req); + return NULL; + } + tevent_req_set_callback(subreq, sdap_get_initgr_user, req); + + return req; +} + +static void sdap_get_initgr_user(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sdap_get_initgr_state *state = tevent_req_data(req, + struct sdap_get_initgr_state); + struct sysdb_attrs **usr_attrs; + size_t count; + int ret; + + DEBUG(9, ("Receiving info for the user\n")); + + ret = sdap_get_generic_recv(subreq, state, &count, &usr_attrs); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + if (count != 1) { + DEBUG(2, ("Expected one user entry and got %d\n", count)); + tevent_req_error(req, ENOENT); + return; + } + + state->orig_user = usr_attrs[0]; + + subreq = sysdb_transaction_send(state, state->ev, state->sysdb); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sdap_get_initgr_store, req); +} + +static void sdap_get_initgr_store(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sdap_get_initgr_state *state = tevent_req_data(req, + struct sdap_get_initgr_state); + int ret; + + DEBUG(9, ("Storing the user\n")); + + ret = sysdb_transaction_recv(subreq, state, &state->handle); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + subreq = sdap_save_user_send(state, state->ev, state->handle, + state->opts, state->dom, + state->sh, state->orig_user); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sdap_get_initgr_commit, req); +} + +static void sdap_get_initgr_commit(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sdap_get_initgr_state *state = tevent_req_data(req, + struct sdap_get_initgr_state); + int ret; + + DEBUG(9, ("Commit change\n")); + + ret = sdap_save_user_recv(subreq, NULL, NULL); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + subreq = sysdb_transaction_commit_send(state, state->ev, state->handle); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sdap_get_initgr_process, req); +} + +static void sdap_get_initgr_process(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sdap_get_initgr_state *state = tevent_req_data(req, + struct sdap_get_initgr_state); + const char *user_dn; + int ret; + + DEBUG(9, ("Process user's groups\n")); + + ret = sysdb_transaction_commit_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + switch (state->opts->schema_type) { + case SDAP_SCHEMA_RFC2307: + subreq = sdap_initgr_rfc2307_send(state, state->ev, state->opts, + state->sysdb, state->dom, state->sh, + dp_opt_get_string(state->opts->basic, + SDAP_GROUP_SEARCH_BASE), + state->name, state->grp_attrs); if (!subreq) { tevent_req_error(req, ENOMEM); return; } - /* sysdb_transaction_complete will call tevent_req_done(req) */ - tevent_req_set_callback(subreq, sysdb_transaction_complete, req); + tevent_req_set_callback(subreq, sdap_get_initgr_done, req); break; + case SDAP_SCHEMA_RFC2307BIS: + + ret = sysdb_attrs_get_string(state->orig_user, + SYSDB_ORIG_DN, &user_dn); + if (ret) { + tevent_req_error(req, EINVAL); + return; + } + + subreq = sdap_initgr_rfc2307_send(state, state->ev, state->opts, + state->sysdb, state->dom, + state->sh, user_dn, + state->name, state->grp_attrs); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sdap_get_initgr_done, req); + return; + + case SDAP_SCHEMA_IPA_V1: + case SDAP_SCHEMA_AD: + /* TODO: AD uses a different member/memberof schema + * We need an AD specific call that is able to unroll + * nested groups by doing extensive recursive searches */ + + subreq = sdap_initgr_nested_send(state, state->ev, state->opts, + state->sysdb, state->dom, state->sh, + state->orig_user, state->grp_attrs); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sdap_get_initgr_done, req); + return; + default: - /* what is going on here !? */ - tevent_req_error(req, EIO); + tevent_req_error(req, EINVAL); return; } } -static void sdap_get_initgr_save_done(struct tevent_req *subreq) +static void sdap_get_initgr_done(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); @@ -3045,17 +3495,34 @@ static void sdap_get_initgr_save_done(struct tevent_req *subreq) struct sdap_get_initgr_state); int ret; - ret = sdap_save_group_recv(subreq, NULL, NULL); - talloc_zfree(subreq); + DEBUG(9, ("Initgroups done\n")); - /* Do not fail completely on errors. - * Just report the failure to save and go on */ + switch (state->opts->schema_type) { + case SDAP_SCHEMA_RFC2307: + case SDAP_SCHEMA_RFC2307BIS: + + ret = sdap_initgr_rfc2307_recv(subreq); + break; + + case SDAP_SCHEMA_IPA_V1: + case SDAP_SCHEMA_AD: + + ret = sdap_initgr_nested_recv(subreq); + break; + + default: + + ret = EINVAL; + break; + } + + talloc_zfree(subreq); if (ret) { - DEBUG(2, ("Failed to store group. Ignoring.\n")); + tevent_req_error(req, ret); + return; } - /* unlock the operation so that we can proceed with the next result */ - sdap_unlock_next_reply(state->op); + tevent_req_done(req); } int sdap_get_initgr_recv(struct tevent_req *req) -- cgit