From 74802794554e0f87d1354b6788f1719cd7d80a6c Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Sat, 24 Aug 2013 15:45:57 +0200 Subject: AD: Download master domain info when enumerating https://fedorahosted.org/sssd/ticket/2068 With the current design, downloading master domain data was tied to subdomains refresh, triggered by responders. But because enumeration is a background task that can't be triggered on its own, we can't rely on responders to download the master domain data and we need to check the master domain on each enumeration request. --- src/providers/ad/ad_id.c | 185 ++++++++++++++++++++++++++++++++++++++ src/providers/ad/ad_id.h | 10 +++ src/providers/ad/ad_init.c | 6 +- src/providers/ldap/ldap_common.h | 11 +++ src/providers/ldap/ldap_id_enum.c | 6 -- 5 files changed, 211 insertions(+), 7 deletions(-) diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c index 48ad8425..1d45440e 100644 --- a/src/providers/ad/ad_id.c +++ b/src/providers/ad/ad_id.c @@ -22,6 +22,8 @@ #include "util/util.h" #include "providers/ad/ad_common.h" #include "providers/ad/ad_id.h" +#include "providers/ad/ad_domain_info.h" +#include "providers/ldap/sdap_async_enum.h" struct ad_handle_acct_info_state { struct be_req *breq; @@ -309,3 +311,186 @@ ad_check_online(struct be_req *be_req) return sdap_do_online_check(be_req, ad_ctx->sdap_id_ctx); } + +struct ad_enumeration_state { + struct ldap_enum_ctx *ectx; + struct sdap_id_op *sdap_op; + struct tevent_context *ev; + + struct sdap_domain *sdom; +}; + +static void ad_enumeration_conn_done(struct tevent_req *subreq); +static void ad_enumeration_master_done(struct tevent_req *subreq); +static void ad_enumeration_done(struct tevent_req *subreq); + +struct tevent_req * +ad_enumeration_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct be_ctx *be_ctx, + struct be_ptask *be_ptask, + void *pvt) +{ + struct tevent_req *req; + struct tevent_req *subreq; + struct ad_enumeration_state *state; + struct ldap_enum_ctx *ectx; + errno_t ret; + + req = tevent_req_create(mem_ctx, &state, struct ad_enumeration_state); + if (req == NULL) return NULL; + + ectx = talloc_get_type(pvt, struct ldap_enum_ctx); + if (ectx == NULL) { + ret = EFAULT; + goto fail; + } + + state->ectx = ectx; + state->ev = ev; + state->sdom = ectx->sdom; + + state->sdap_op = sdap_id_op_create(state, ectx->conn->conn_cache); + if (state->sdap_op == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("sdap_id_op_create failed.\n")); + ret = ENOMEM; + goto fail; + } + + subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret); + if (subreq == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("sdap_id_op_connect_send failed: %d(%s).\n", + ret, strerror(ret))); + goto fail; + } + tevent_req_set_callback(subreq, ad_enumeration_conn_done, req); + + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} + +static void +ad_enumeration_conn_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct ad_enumeration_state *state = tevent_req_data(req, + struct ad_enumeration_state); + int ret, dp_error; + + ret = sdap_id_op_connect_recv(subreq, &dp_error); + talloc_zfree(subreq); + if (ret != EOK) { + if (dp_error == DP_ERR_OFFLINE) { + DEBUG(SSSDBG_TRACE_FUNC, + ("Backend is marked offline, retry later!\n")); + tevent_req_done(req); + } else { + DEBUG(SSSDBG_MINOR_FAILURE, + ("Domain enumeration failed to connect to " \ + "LDAP server: (%d)[%s]\n", ret, strerror(ret))); + tevent_req_error(req, ret); + } + return; + } + + subreq = ad_master_domain_send(state, state->ev, + state->ectx->conn, + state->sdap_op, + state->sdom->dom->name); + if (subreq == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("ad_master_domain_send failed.\n")); + tevent_req_error(req, ret); + return; + } + tevent_req_set_callback(subreq, ad_enumeration_master_done, req); +} + +static void +ad_enumeration_master_done(struct tevent_req *subreq) +{ + errno_t ret; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct ad_enumeration_state *state = tevent_req_data(req, + struct ad_enumeration_state); + char *flat_name; + char *master_sid; + + ret = ad_master_domain_recv(subreq, state, + &flat_name, &master_sid); + talloc_zfree(subreq); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Cannot retrieve master domain info\n")); + tevent_req_error(req, ret); + return; + } + + DEBUG(SSSDBG_TRACE_FUNC, ("Found flat name [%s].\n", flat_name)); + DEBUG(SSSDBG_TRACE_FUNC, ("Found master SID [%s].\n", master_sid)); + + ret = sysdb_master_domain_add_info(state->sdom->dom, + flat_name, master_sid); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Cannot save master domain info\n")); + tevent_req_error(req, ret); + return; + } + + subreq = sdap_dom_enum_send(state, state->ev, state->ectx->ctx, + state->sdom, state->ectx->conn); + if (subreq == NULL) { + /* The ptask API will reschedule the enumeration on its own on + * failure */ + DEBUG(SSSDBG_OP_FAILURE, + ("Failed to schedule enumeration, retrying later!\n")); + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, ad_enumeration_done, req); +} + +static void +ad_enumeration_done(struct tevent_req *subreq) +{ + errno_t ret; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct ad_enumeration_state *state = tevent_req_data(req, + struct ad_enumeration_state); + + ret = sdap_dom_enum_recv(subreq); + talloc_zfree(subreq); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + ("Could not enumerate domain %s\n", state->sdom->dom->name)); + tevent_req_error(req, ret); + return; + } + + /* Ok, we've completed an enumeration. Save this to the + * sysdb so we can postpone starting up the enumeration + * process on the next SSSD service restart (to avoid + * slowing down system boot-up + */ + ret = sysdb_set_enumerated(state->sdom->dom->sysdb, + state->sdom->dom, true); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + ("Could not mark domain as having enumerated.\n")); + /* This error is non-fatal, so continue */ + } + + tevent_req_done(req); +} + +errno_t +ad_enumeration_recv(struct tevent_req *req) +{ + TEVENT_REQ_RETURN_ON_ERROR(req); + return EOK; +} diff --git a/src/providers/ad/ad_id.h b/src/providers/ad/ad_id.h index 1fd6b599..74b85645 100644 --- a/src/providers/ad/ad_id.h +++ b/src/providers/ad/ad_id.h @@ -37,6 +37,16 @@ errno_t ad_handle_acct_info_recv(struct tevent_req *req, int *_dp_error, const char **_err); +struct tevent_req * +ad_enumeration_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct be_ctx *be_ctx, + struct be_ptask *be_ptask, + void *pvt); + +errno_t +ad_enumeration_recv(struct tevent_req *req); + void ad_check_online(struct be_req *be_req); #endif /* AD_ID_H_ */ diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c index 99288195..c829cc86 100644 --- a/src/providers/ad/ad_init.c +++ b/src/providers/ad/ad_init.c @@ -205,7 +205,11 @@ sssm_ad_id_init(struct be_ctx *bectx, goto done; } - ret = ldap_id_setup_tasks(ad_ctx->sdap_id_ctx); + ret = sdap_id_setup_tasks(ad_ctx->sdap_id_ctx, + ad_ctx->sdap_id_ctx->conn, + ad_ctx->sdap_id_ctx->opts->sdom, + ad_enumeration_send, + ad_enumeration_recv); if (ret != EOK) { goto done; } diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h index b21de002..0d565fc6 100644 --- a/src/providers/ldap/ldap_common.h +++ b/src/providers/ldap/ldap_common.h @@ -169,6 +169,17 @@ int ldap_get_autofs_options(TALLOC_CTX *memctx, const char *conf_path, struct sdap_options *opts); +/* Calling ldap_setup_enumeration will set up a periodic task + * that would periodically call send_fn/recv_fn request. The + * send_fn's pvt parameter will be a pointer to ldap_enum_ctx + * structure that contains the request data + */ +struct ldap_enum_ctx { + struct sdap_id_ctx *ctx; + struct sdap_domain *sdom; + struct sdap_id_conn_ctx *conn; +}; + errno_t ldap_setup_enumeration(struct sdap_id_ctx *ctx, struct sdap_id_conn_ctx *conn, struct sdap_domain *sdom, diff --git a/src/providers/ldap/ldap_id_enum.c b/src/providers/ldap/ldap_id_enum.c index 2a42fdaf..8cccaa91 100644 --- a/src/providers/ldap/ldap_id_enum.c +++ b/src/providers/ldap/ldap_id_enum.c @@ -27,12 +27,6 @@ #include "providers/ldap/ldap_common.h" #include "providers/ldap/sdap_async_enum.h" -struct ldap_enum_ctx { - struct sdap_id_ctx *ctx; - struct sdap_domain *sdom; - struct sdap_id_conn_ctx *conn; -}; - errno_t ldap_setup_enumeration(struct sdap_id_ctx *ctx, struct sdap_id_conn_ctx *conn, struct sdap_domain *sdom, -- cgit