From 8d57d3c74d5f6199a4a5896e8f3354aaf17e228a Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Mon, 2 Jul 2012 10:34:52 -0400
Subject: [PATCH 8/8] AD: Add AD access-control provider

This patch adds support for checking whether a user is expired or
disabled in AD.
---
 Makefile.am                  |    2 +
 src/providers/ad/ad_access.c |   96 ++++++++++++++++++++++++++++++++++++++++++
 src/providers/ad/ad_access.h |   35 +++++++++++++++
 src/providers/ad/ad_init.c   |   56 ++++++++++++++++++++++++
 src/providers/ad/ad_opts.h   |    2 +-
 5 files changed, 190 insertions(+), 1 deletion(-)
 create mode 100644 src/providers/ad/ad_access.c
 create mode 100644 src/providers/ad/ad_access.h

diff --git a/Makefile.am b/Makefile.am
index 211656c55056a8cd1cc72ea058e16e3b52ad3ce8..1c2501d9b9275dd52c56b202b54c10dc5bc569a7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1353,6 +1353,8 @@ libsss_ad_la_SOURCES = \
     src/providers/ad/ad_init.c \
     src/providers/ad/ad_id.c \
     src/providers/ad/ad_id.h \
+    src/providers/ad/ad_access.c \
+    src/providers/ad/ad_access.h \
     src/providers/ad/ad_opts.h \
     src/util/find_uid.c \
     src/util/user_info_msg.c \
diff --git a/src/providers/ad/ad_access.c b/src/providers/ad/ad_access.c
new file mode 100644
index 0000000000000000000000000000000000000000..314cdcfadf0a675535fcafa98c54837920305c73
--- /dev/null
+++ b/src/providers/ad/ad_access.c
@@ -0,0 +1,96 @@
+/*
+    SSSD
+
+    Authors:
+        Stephen Gallagher <sgallagh@redhat.com>
+
+    Copyright (C) 2012 Red Hat
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <security/pam_modules.h>
+#include "src/util/util.h"
+#include "src/providers/data_provider.h"
+#include "src/providers/dp_backend.h"
+#include "src/providers/ad/ad_access.h"
+#include "src/providers/ldap/sdap_access.h"
+
+static void
+ad_access_done(struct tevent_req *req);
+
+void
+ad_access_handler(struct be_req *breq)
+{
+    struct tevent_req *req;
+    struct ad_access_ctx *access_ctx =
+            talloc_get_type(breq->be_ctx->bet_info[BET_ACCESS].pvt_bet_data,
+                            struct ad_access_ctx);
+
+    struct pam_data *pd = talloc_get_type(breq->req_data, struct pam_data);
+
+    /* Handle subdomains */
+    if (strcasecmp(pd->domain, breq->be_ctx->domain->name) != 0) {
+        breq->domain = new_subdomain(breq, breq->be_ctx->domain, pd->domain,
+                                     NULL, NULL);
+        if (breq->domain == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, ("new_subdomain failed.\n"));
+            breq->fn(breq, DP_ERR_FATAL, PAM_SYSTEM_ERR, NULL);
+            return;
+        }
+        breq->sysdb = breq->domain->sysdb;
+    }
+
+    /* Verify that the account is not locked */
+    req = sdap_access_send(breq,
+                           breq->be_ctx->ev,
+                           breq,
+                           access_ctx->sdap_access_ctx,
+                           pd);
+    if (!req) {
+        breq->fn(breq, DP_ERR_FATAL, PAM_SYSTEM_ERR, NULL);
+        return;
+    }
+    tevent_req_set_callback(req, ad_access_done, breq);
+}
+
+static void
+ad_access_done(struct tevent_req *req)
+{
+    errno_t ret;
+    int pam_status;
+    struct be_req *breq =
+            tevent_req_callback_data(req, struct be_req);
+    struct pam_data *pd = talloc_get_type(breq->req_data, struct pam_data);
+
+    ret = sdap_access_recv(req, &pam_status);
+    talloc_zfree(req);
+    if (ret != EOK) {
+        breq->fn(breq, DP_ERR_FATAL, PAM_SYSTEM_ERR, strerror(ret));
+        return;
+    }
+
+    pd->pam_status = pam_status;
+
+    if (pam_status == PAM_SUCCESS || pam_status == PAM_PERM_DENIED) {
+        /* We got the proper approval or denial */
+        breq->fn(breq, DP_ERR_OK, pam_status, NULL);
+        return;
+    }
+
+    /* Something went wrong */
+    pd->pam_status = PAM_SYSTEM_ERR;
+    breq->fn(breq, DP_ERR_FATAL, pam_status, pam_strerror(NULL, pam_status));
+    return;
+}
diff --git a/src/providers/ad/ad_access.h b/src/providers/ad/ad_access.h
new file mode 100644
index 0000000000000000000000000000000000000000..62259265dfea8083dbb0a98f64e424bb819c6d04
--- /dev/null
+++ b/src/providers/ad/ad_access.h
@@ -0,0 +1,35 @@
+/*
+    SSSD
+
+    Authors:
+        Stephen Gallagher <sgallagh@redhat.com>
+
+    Copyright (C) 2012 Red Hat
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef AD_ACCESS_H_
+#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;
+};
+
+void
+ad_access_handler(struct be_req *breq);
+
+#endif /* AD_ACCESS_H_ */
diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
index 89101a5b16ffb254d19f0bcc2082a9e0cb20d712..6baae0ce5cb835e92bf0b139c7acd90bc413bad5 100644
--- a/src/providers/ad/ad_init.c
+++ b/src/providers/ad/ad_init.c
@@ -28,7 +28,9 @@
 
 #include "util/util.h"
 #include "providers/ad/ad_common.h"
+#include "providers/ad/ad_access.h"
 #include "providers/ldap/ldap_common.h"
+#include "providers/ldap/sdap_access.h"
 #include "providers/ldap/sdap_idmap.h"
 #include "providers/krb5/krb5_auth.h"
 #include "providers/krb5/krb5_init_shared.h"
@@ -55,6 +57,11 @@ struct bet_ops ad_chpass_ops = {
     .finalize = NULL
 };
 
+struct bet_ops ad_access_ops = {
+    .handler = ad_access_handler,
+    .finalize = NULL
+};
+
 static errno_t
 common_ad_init(struct be_ctx *bectx)
 {
@@ -261,6 +268,55 @@ sssm_ad_chpass_init(struct be_ctx *bectx,
     return ret;
 }
 
+int
+sssm_ad_access_init(struct be_ctx *bectx,
+                    struct bet_ops **ops,
+                    void **pvt_data)
+{
+    errno_t ret;
+    struct ad_access_ctx *access_ctx;
+    struct ad_id_ctx *ad_id_ctx;
+
+    access_ctx = talloc_zero(bectx, struct ad_access_ctx);
+    if (!access_ctx) return ENOMEM;
+
+    ret = sssm_ad_id_init(bectx, ops, (void **)&ad_id_ctx);
+    if (ret != EOK) {
+        goto fail;
+    }
+    access_ctx->sdap_ctx = ad_id_ctx->sdap_id_ctx;
+
+    ret = dp_copy_options(access_ctx, ad_options->basic, AD_OPTS_BASIC,
+                          &access_ctx->ad_options);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_FATAL_FAILURE,
+              ("Could not initialize access provider options: [%s]\n",
+               strerror(ret)));
+        goto fail;
+    }
+
+    /* Set up an sdap_access_ctx for checking expired/locked accounts */
+    access_ctx->sdap_access_ctx =
+            talloc_zero(access_ctx, struct sdap_access_ctx);
+    if (!access_ctx->sdap_access_ctx) {
+        ret = ENOMEM;
+        goto fail;
+    }
+
+    access_ctx->sdap_access_ctx->id_ctx = access_ctx->sdap_ctx;
+    access_ctx->sdap_access_ctx->access_rule[0] = LDAP_ACCESS_EXPIRE;
+    access_ctx->sdap_access_ctx->access_rule[1] = LDAP_ACCESS_EMPTY;
+
+    *ops = &ad_access_ops;
+    *pvt_data = access_ctx;
+
+    return EOK;
+
+fail:
+    talloc_free(access_ctx);
+    return ret;
+}
+
 static void
 ad_shutdown(struct be_req *req)
 {
diff --git a/src/providers/ad/ad_opts.h b/src/providers/ad/ad_opts.h
index a4dbea01b352d8e76500165e80d8ff67c4c78e77..e23b41feeeec890048f94c8b63f2aae0f2476189 100644
--- a/src/providers/ad/ad_opts.h
+++ b/src/providers/ad/ad_opts.h
@@ -91,7 +91,7 @@ struct dp_option ad_def_ldap_opts[] = {
     { "ldap_netgroup_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_group_nesting_level", DP_OPT_NUMBER, { .number = 2 }, NULL_NUMBER },
     { "ldap_deref", DP_OPT_STRING, NULL_STRING, NULL_STRING },
-    { "ldap_account_expire_policy", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+    { "ldap_account_expire_policy", DP_OPT_STRING, { "ad" }, NULL_STRING },
     { "ldap_access_order", DP_OPT_STRING, { "filter" }, NULL_STRING },
     { "ldap_chpass_uri", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_chpass_dns_service_name", DP_OPT_STRING, NULL_STRING, NULL_STRING },
-- 
1.7.10.2

