summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/providers/ad/ad_access.c164
-rw-r--r--src/providers/ad/ad_access.h4
-rw-r--r--src/providers/ad/ad_init.c5
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