diff options
-rw-r--r-- | src/providers/ad/ad_access.c | 164 | ||||
-rw-r--r-- | src/providers/ad/ad_access.h | 4 | ||||
-rw-r--r-- | src/providers/ad/ad_init.c | 5 |
3 files changed, 163 insertions, 10 deletions
diff --git a/src/providers/ad/ad_access.c b/src/providers/ad/ad_access.c index cf6412f22..51c872c3b 100644 --- a/src/providers/ad/ad_access.c +++ b/src/providers/ad/ad_access.c @@ -25,10 +25,162 @@ #include "src/providers/data_provider.h" #include "src/providers/dp_backend.h" #include "src/providers/ad/ad_access.h" +#include "src/providers/ad/ad_common.h" #include "src/providers/ldap/sdap_access.h" static void ad_access_done(struct tevent_req *req); +static errno_t +ad_access_step(struct tevent_req *req, struct sdap_id_conn_ctx *conn); + +struct ad_access_state { + struct tevent_context *ev; + struct ad_access_ctx *ctx; + struct pam_data *pd; + struct be_ctx *be_ctx; + struct sss_domain_info *domain; + + struct sdap_id_conn_ctx **clist; + int cindex; +}; + +static struct tevent_req * +ad_access_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct be_ctx *be_ctx, + struct sss_domain_info *domain, + struct ad_access_ctx *ctx, + struct pam_data *pd) +{ + struct tevent_req *req; + struct ad_access_state *state; + errno_t ret; + + req = tevent_req_create(mem_ctx, &state, struct ad_access_state); + if (req == NULL) { + return NULL; + } + + state->ev = ev; + state->ctx = ctx; + state->pd = pd; + state->be_ctx = be_ctx; + state->domain = domain; + + state->clist = talloc_zero_array(state, struct sdap_id_conn_ctx *, 3); + if (state->clist == NULL) { + ret = ENOMEM; + goto done; + } + + /* Always try GC first */ + ctx->gc_ctx->ignore_mark_offline = false; + state->clist[0] = ctx->gc_ctx; + if (IS_SUBDOMAIN(domain) == false) { + /* fall back to ldap if gc is not available */ + state->clist[0]->ignore_mark_offline = true; + + /* With root domain users we have the option to + * fall back to LDAP in case ie POSIX attributes + * are used but not replicated to GC + */ + state->clist[1] = ctx->ldap_ctx; + } + + ret = ad_access_step(req, state->clist[state->cindex]); + if (ret != EOK) { + goto done; + } + + ret = EOK; +done: + if (ret != EOK) { + tevent_req_error(req, ret); + tevent_req_post(req, ev); + } + return req; +} + +static errno_t +ad_access_step(struct tevent_req *req, struct sdap_id_conn_ctx *conn) +{ + struct tevent_req *subreq; + struct ad_access_state *state; + + state = tevent_req_data(req, struct ad_access_state); + + subreq = sdap_access_send(req, state->ev, state->be_ctx, + state->domain, state->ctx->sdap_access_ctx, + conn, state->pd); + if (req == NULL) { + return ENOMEM; + } + tevent_req_set_callback(subreq, ad_access_done, req); + return EOK; +} + +static void +ad_access_done(struct tevent_req *subreq) +{ + struct tevent_req *req; + struct ad_access_state *state; + errno_t ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct ad_access_state); + + ret = sdap_access_recv(subreq); + talloc_zfree(subreq); + switch (ret) { + case EOK: + tevent_req_done(req); + return; + + case ERR_ACCOUNT_EXPIRED: + tevent_req_error(req, ret); + return; + + case ERR_ACCESS_DENIED: + /* Retry on ACCESS_DENIED, too, to make sure that we don't + * miss out any attributes not present in GC + * FIXME - this is slow. We should retry only if GC failed + * and LDAP succeeded after the first ACCESS_DENIED + */ + break; + + default: + break; + } + + /* If possible, retry with LDAP */ + state->cindex++; + if (state->clist[state->cindex] == NULL) { + DEBUG(SSSDBG_OP_FAILURE, + ("Error retrieving access check result: %s\n", + sss_strerror(ret))); + tevent_req_error(req, ret); + return; + } + + ret = ad_access_step(req, state->clist[state->cindex]); + if (ret != EOK) { + tevent_req_error(req, ret); + return; + } + + /* Another check in progress */ +} + +static errno_t +ad_access_recv(struct tevent_req *req) +{ + TEVENT_REQ_RETURN_ON_ERROR(req); + + return EOK; +} + +static void +ad_access_check_done(struct tevent_req *req); void ad_access_handler(struct be_req *breq) @@ -55,19 +207,17 @@ ad_access_handler(struct be_req *breq) } /* Verify that the account is not locked */ - req = sdap_access_send(breq, be_ctx->ev, be_ctx, domain, - access_ctx->sdap_access_ctx, - access_ctx->sdap_access_ctx->id_ctx->conn, - pd); + req = ad_access_send(breq, be_ctx->ev, be_ctx, domain, + access_ctx, pd); if (!req) { be_req_terminate(breq, DP_ERR_FATAL, PAM_SYSTEM_ERR, NULL); return; } - tevent_req_set_callback(req, ad_access_done, breq); + tevent_req_set_callback(req, ad_access_check_done, breq); } static void -ad_access_done(struct tevent_req *req) +ad_access_check_done(struct tevent_req *req) { errno_t ret; struct be_req *breq = @@ -75,7 +225,7 @@ ad_access_done(struct tevent_req *req) struct pam_data *pd = talloc_get_type(be_req_get_data(breq), struct pam_data); - ret = sdap_access_recv(req); + ret = ad_access_recv(req); talloc_zfree(req); switch (ret) { case EOK: diff --git a/src/providers/ad/ad_access.h b/src/providers/ad/ad_access.h index 62259265d..ca5e69729 100644 --- a/src/providers/ad/ad_access.h +++ b/src/providers/ad/ad_access.h @@ -24,9 +24,11 @@ #define AD_ACCESS_H_ struct ad_access_ctx { - struct sdap_id_ctx *sdap_ctx; struct dp_option *ad_options; struct sdap_access_ctx *sdap_access_ctx; + + struct sdap_id_conn_ctx *ldap_ctx; + struct sdap_id_conn_ctx *gc_ctx; }; void diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c index d744c2a05..d7f41a563 100644 --- a/src/providers/ad/ad_init.c +++ b/src/providers/ad/ad_init.c @@ -375,7 +375,8 @@ sssm_ad_access_init(struct be_ctx *bectx, if (ret != EOK) { goto fail; } - access_ctx->sdap_ctx = ad_id_ctx->sdap_id_ctx; + access_ctx->ldap_ctx = ad_id_ctx->ldap_ctx; + access_ctx->gc_ctx = ad_id_ctx->gc_ctx; ret = dp_copy_options(access_ctx, ad_options->basic, AD_OPTS_BASIC, &access_ctx->ad_options); @@ -393,7 +394,7 @@ sssm_ad_access_init(struct be_ctx *bectx, ret = ENOMEM; goto fail; } - access_ctx->sdap_access_ctx->id_ctx = access_ctx->sdap_ctx; + access_ctx->sdap_access_ctx->id_ctx = ad_id_ctx->sdap_id_ctx; /* If ad_access_filter is set, the value of ldap_acess_order is * expire, filter, otherwise only expire |