From 57fb139375c003cf966ef2bc9f0ee5de6cff2c83 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Thu, 8 Mar 2012 15:19:07 -0500
Subject: [PATCH 2/2] IPA: Check nsAccountLock during PAM_ACCT_MGMT

https://fedorahosted.org/sssd/ticket/1227
---
 Makefile.am                    |    1 +
 src/providers/ipa/ipa_access.c |   56 ++++++++++++++++++++++++++++++++++++++++
 src/providers/ipa/ipa_access.h |    1 +
 src/providers/ipa/ipa_common.c |    2 +-
 src/providers/ipa/ipa_init.c   |   11 ++++++++
 5 files changed, 70 insertions(+), 1 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index ce00ef2ff5fe9444b30b84b5a82ae4e0a0db9757..64f5c42e8b50a600e88ee6e965b8764a2157c522 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1147,6 +1147,7 @@ libsss_ipa_la_SOURCES = \
     src/providers/ldap/ldap_id_services.c \
     src/providers/ldap/ldap_auth.c \
     src/providers/ldap/ldap_common.c \
+    src/providers/ldap/sdap_access.c \
     src/providers/ldap/sdap_async.c \
     src/providers/ldap/sdap_async_users.c \
     src/providers/ldap/sdap_async_groups.c \
diff --git a/src/providers/ipa/ipa_access.c b/src/providers/ipa/ipa_access.c
index 523bba258daac428415dd085129bfffcb5259ac8..5a967a4d87c3a2e550d4b3612fd2521259711301 100644
--- a/src/providers/ipa/ipa_access.c
+++ b/src/providers/ipa/ipa_access.c
@@ -27,6 +27,7 @@
 
 #include "util/util.h"
 #include "providers/ldap/sdap_async.h"
+#include "providers/ldap/sdap_access.h"
 #include "providers/ipa/ipa_common.h"
 #include "providers/ipa/ipa_access.h"
 #include "providers/ipa/ipa_hbac.h"
@@ -63,6 +64,7 @@ enum check_result {
     RULE_ERROR
 };
 
+static void ipa_hbac_check(struct tevent_req *req);
 static int hbac_retry(struct hbac_ctx *hbac_ctx);
 static void hbac_connect_done(struct tevent_req *subreq);
 static bool hbac_check_step_result(struct hbac_ctx *hbac_ctx, int ret);
@@ -74,14 +76,68 @@ static void ipa_hbac_evaluate_rules(struct hbac_ctx *hbac_ctx);
 void ipa_access_handler(struct be_req *be_req)
 {
     struct pam_data *pd;
+    struct ipa_access_ctx *ipa_access_ctx;
+    struct tevent_req *req;
+
+    pd = talloc_get_type(be_req->req_data, struct pam_data);
+
+    ipa_access_ctx = talloc_get_type(
+                              be_req->be_ctx->bet_info[BET_ACCESS].pvt_bet_data,
+                              struct ipa_access_ctx);
+
+    /* First, verify that this account isn't locked.
+     * We need to do this in case the auth phase was
+     * skipped (such as during GSSAPI single-sign-on
+     * or SSH public key exchange.
+     */
+    req = sdap_access_send(be_req,
+                           be_req->be_ctx->ev,
+                           be_req->be_ctx,
+                           ipa_access_ctx->sdap_access_ctx,
+                           pd);
+    if (!req) {
+        be_req->fn(be_req, DP_ERR_FATAL, PAM_SYSTEM_ERR, NULL);
+        return;
+    }
+    tevent_req_set_callback(req, ipa_hbac_check, be_req);
+}
+
+static void ipa_hbac_check(struct tevent_req *req)
+{
+    struct be_req *be_req;
+    struct pam_data *pd;
     struct hbac_ctx *hbac_ctx;
     const char *deny_method;
     int pam_status = PAM_SYSTEM_ERR;
     struct ipa_access_ctx *ipa_access_ctx;
     int ret;
 
+    be_req = tevent_req_callback_data(req, struct be_req);
     pd = talloc_get_type(be_req->req_data, struct pam_data);
 
+    ret = sdap_access_recv(req, &pam_status);
+    if (ret != EOK) goto fail;
+
+    switch(pam_status) {
+    case PAM_SUCCESS:
+        /* Account wasn't locked. Continue below
+         * to HBAC processing.
+         */
+        break;
+    case PAM_PERM_DENIED:
+        /* Account was locked. Return permission denied
+         * here.
+         */
+        pd->pam_status = PAM_PERM_DENIED;
+        be_req->fn(be_req, DP_ERR_OK, PAM_PERM_DENIED, NULL);
+        return;
+    default:
+        /* We got an unexpected error. Return it as-is */
+        pd->pam_status = PAM_SYSTEM_ERR;
+        be_req->fn(be_req, DP_ERR_FATAL, pam_status, NULL);
+        return;
+    }
+
     hbac_ctx = talloc_zero(be_req, struct hbac_ctx);
     if (hbac_ctx == NULL) {
         DEBUG(1, ("talloc failed.\n"));
diff --git a/src/providers/ipa/ipa_access.h b/src/providers/ipa/ipa_access.h
index f6b08af3c8da95c8b06d5220d8cdcd16b0c5ac0e..35a8b3e7bfbea512ddcff8b6851c4323e2a59419 100644
--- a/src/providers/ipa/ipa_access.h
+++ b/src/providers/ipa/ipa_access.h
@@ -37,6 +37,7 @@ struct ipa_access_ctx {
     struct dp_option *ipa_options;
     struct time_rules_ctx *tr_ctx;
     time_t last_update;
+    struct sdap_access_ctx *sdap_access_ctx;
 
     struct sdap_attr_map *host_map;
     struct sdap_attr_map *hostgroup_map;
diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c
index 72d7c65c1fd1dbc9df8aeb641c488a5196b834fd..39e44ef1711e153b0a648642d5a62463f9ec8a4d 100644
--- a/src/providers/ipa/ipa_common.c
+++ b/src/providers/ipa/ipa_common.c
@@ -100,7 +100,7 @@ struct dp_option ipa_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, { "ipa" }, NULL_STRING },
     { "ldap_access_order", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_chpass_uri", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_chpass_dns_service_name", DP_OPT_STRING, NULL_STRING, NULL_STRING },
diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c
index bb85632df741324e1c3c9bb6b5713164e4ceb915..fca23f349770af4fd97b988b543ffd4b1d77e48f 100644
--- a/src/providers/ipa/ipa_init.c
+++ b/src/providers/ipa/ipa_init.c
@@ -36,6 +36,7 @@
 #include "providers/ipa/ipa_hostid.h"
 #include "providers/ipa/ipa_dyndns.h"
 #include "providers/ipa/ipa_session.h"
+#include "providers/ldap/sdap_access.h"
 
 struct ipa_options *ipa_options = NULL;
 
@@ -398,6 +399,16 @@ int sssm_ipa_access_init(struct be_ctx *bectx,
         goto done;
     }
 
+    /* Set up an sdap_access_ctx for checking expired/locked
+     * accounts.
+     */
+    ipa_access_ctx->sdap_access_ctx =
+            talloc_zero(ipa_access_ctx, struct sdap_access_ctx);
+
+    ipa_access_ctx->sdap_access_ctx->id_ctx = ipa_access_ctx->sdap_ctx;
+    ipa_access_ctx->sdap_access_ctx->access_rule[0] = LDAP_ACCESS_EXPIRE;
+    ipa_access_ctx->sdap_access_ctx->access_rule[1] = LDAP_ACCESS_EMPTY;
+
     *ops = &ipa_access_ops;
     *pvt_data = ipa_access_ctx;
 
-- 
1.7.7.6

