summaryrefslogtreecommitdiffstats
path: root/src/providers/ad/ad_access.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/providers/ad/ad_access.c')
-rw-r--r--src/providers/ad/ad_access.c137
1 files changed, 96 insertions, 41 deletions
diff --git a/src/providers/ad/ad_access.c b/src/providers/ad/ad_access.c
index cae075d42..06ad47417 100644
--- a/src/providers/ad/ad_access.c
+++ b/src/providers/ad/ad_access.c
@@ -25,14 +25,10 @@
#include "src/providers/data_provider.h"
#include "src/providers/dp_backend.h"
#include "src/providers/ad/ad_access.h"
+#include "providers/ad/ad_gpo.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);
-
/*
* More advanced format can be used to restrict the filter to a specific
* domain or a specific forest. This format is KEYWORD:NAME:FILTER
@@ -168,6 +164,7 @@ ad_parse_access_filter(TALLOC_CTX *mem_ctx,
char *spec;
int flags;
TALLOC_CTX *tmp_ctx;
+ int i = 0;
if (_filter == NULL) return EINVAL;
@@ -193,7 +190,7 @@ ad_parse_access_filter(TALLOC_CTX *mem_ctx,
best_match = NULL;
best_flags = 0;
- for (int i=0; i < nfilters; i++) {
+ for (i=0; i < nfilters; i++) {
ret = parse_filter(tmp_ctx, filters[i], &filter, &spec, &flags);
if (ret != EOK) {
/* Skip the faulty filter. At worst, the user won't be
@@ -243,6 +240,11 @@ struct ad_access_state {
int cindex;
};
+static errno_t
+ad_sdap_access_step(struct tevent_req *req, struct sdap_id_conn_ctx *conn);
+static void
+ad_sdap_access_done(struct tevent_req *req);
+
static struct tevent_req *
ad_access_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
@@ -280,7 +282,7 @@ ad_access_send(TALLOC_CTX *mem_ctx,
goto done;
}
- ret = ad_access_step(req, state->clist[state->cindex]);
+ ret = ad_sdap_access_step(req, state->clist[state->cindex]);
if (ret != EOK) {
goto done;
}
@@ -289,13 +291,14 @@ ad_access_send(TALLOC_CTX *mem_ctx,
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)
+ad_sdap_access_step(struct tevent_req *req, struct sdap_id_conn_ctx *conn)
{
struct tevent_req *subreq;
struct ad_access_state *state;
@@ -313,19 +316,22 @@ ad_access_step(struct tevent_req *req, struct sdap_id_conn_ctx *conn)
state->ctx->sdap_access_ctx->access_rule,
sizeof(int) * LDAP_ACCESS_LAST);
- subreq = sdap_access_send(req, state->ev, state->be_ctx,
+ subreq = sdap_access_send(state, state->ev, state->be_ctx,
state->domain, req_ctx,
conn, state->pd);
if (req == NULL) {
talloc_free(req_ctx);
return ENOMEM;
}
- tevent_req_set_callback(subreq, ad_access_done, req);
+ tevent_req_set_callback(subreq, ad_sdap_access_done, req);
return EOK;
}
static void
-ad_access_done(struct tevent_req *subreq)
+ad_gpo_access_done(struct tevent_req *subreq);
+
+static void
+ad_sdap_access_done(struct tevent_req *subreq)
{
struct tevent_req *req;
struct ad_access_state *state;
@@ -336,44 +342,93 @@ ad_access_done(struct tevent_req *subreq)
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);
+ if (ret != EOK) {
+ switch (ret) {
+ 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_sdap_access_step(req, state->clist[state->cindex]);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ /* Another check in progress */
+
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
- */
+ switch (state->ctx->gpo_access_control_mode) {
+ case GPO_ACCESS_CONTROL_DISABLED:
+ /* do not evaluate gpos; mark request done */
+ tevent_req_done(req);
+ return;
+ case GPO_ACCESS_CONTROL_PERMISSIVE:
+ case GPO_ACCESS_CONTROL_ENFORCING:
+ /* continue on to evaluate gpos */
break;
-
default:
- break;
+ tevent_req_error(req, EINVAL);
+ return;
}
- /* 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);
+ subreq = ad_gpo_access_send(state,
+ state->be_ctx->ev,
+ state->domain,
+ state->ctx,
+ state->pd->user);
+
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
return;
}
- ret = ad_access_step(req, state->clist[state->cindex]);
- if (ret != EOK) {
+ tevent_req_set_callback(subreq, ad_gpo_access_done, req);
+
+}
+
+static void
+ad_gpo_access_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+
+ ret = ad_gpo_access_recv(subreq);
+ talloc_zfree(subreq);
+
+ if (ret == EOK) {
+ DEBUG(SSSDBG_TRACE_FUNC, "GPO-based access control successful.\n");
+ tevent_req_done(req);
+ } else {
+ DEBUG(SSSDBG_OP_FAILURE, "GPO-based access control failed.\n");
tevent_req_error(req, ret);
- return;
}
-
- /* Another check in progress */
}
static errno_t
@@ -385,7 +440,7 @@ ad_access_recv(struct tevent_req *req)
}
static void
-ad_access_check_done(struct tevent_req *req);
+ad_access_done(struct tevent_req *req);
void
ad_access_handler(struct be_req *breq)
@@ -411,18 +466,18 @@ ad_access_handler(struct be_req *breq)
domain = be_ctx->domain;
}
- /* Verify that the account is not locked */
+ /* Verify access control: locked accounts, ldap policies, GPOs, etc */
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_check_done, breq);
+ tevent_req_set_callback(req, ad_access_done, breq);
}
static void
-ad_access_check_done(struct tevent_req *req)
+ad_access_done(struct tevent_req *req)
{
errno_t ret;
struct be_req *breq =