From 11787a86f07d87ce51a4649f726580e38171e761 Mon Sep 17 00:00:00 2001
From: Pavel Reichl <preichl@redhat.com>
Date: Fri, 5 Feb 2016 07:31:45 -0500
Subject: [PATCH 2/3] PAM: Pass account lockout status and display message

Tested against Windows Server 2012.

Resolves:
https://fedorahosted.org/sssd/ticket/2839
---
 src/confdb/confdb.h                  |  1 +
 src/config/SSSDConfig/__init__.py.in |  1 +
 src/config/etc/sssd.api.conf         |  1 +
 src/man/sssd.conf.5.xml              | 21 +++++++++++++++++++++
 src/providers/dp_auth_util.c         | 20 ++++++++++++++++++++
 src/responder/pam/pamsrv_cmd.c       | 31 +++++++++++++++++++++++--------
 6 files changed, 67 insertions(+), 8 deletions(-)

diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index fcffcb5a6ff8b3f766ed9a693db874c7c6e3d9b9..e6789c8665cf677712d8e7fb72b6f0a41bca80b1 100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -118,6 +118,7 @@
 #define CONFDB_PAM_TRUSTED_USERS "pam_trusted_users"
 #define CONFDB_PAM_PUBLIC_DOMAINS "pam_public_domains"
 #define CONFDB_PAM_ACCOUNT_EXPIRED_MESSAGE "pam_account_expired_message"
+#define CONFDB_PAM_ACCOUNT_LOCKED_MESSAGE "pam_account_locked_message"
 #define CONFDB_PAM_CERT_AUTH "pam_cert_auth"
 #define CONFDB_PAM_CERT_DB_PATH "pam_cert_db_path"
 #define CONFDB_PAM_P11_CHILD_TIMEOUT "p11_child_timeout"
diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
index 1fdb907c5d010323c22b18b4c371c61e5928c40f..495cb650ee86e50031962a4fcf0c21aa79dc0142 100644
--- a/src/config/SSSDConfig/__init__.py.in
+++ b/src/config/SSSDConfig/__init__.py.in
@@ -91,6 +91,7 @@ option_strings = {
     'pam_trusted_users' : _('List of trusted uids or user\'s name'),
     'pam_public_domains' : _('List of domains accessible even for untrusted users.'),
     'pam_account_expired_message' : _('Message printed when user account is expired.'),
+    'pam_account_locked_message' : _('Message printed when user account is locked.'),
     'p11_child_timeout' : _('How many seconds will pam_sss wait for p11_child to finish'),
 
     # [sudo]
diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
index 89cf8634ffb8115d9e65cf66dc9b1ed630415c15..baa15539cbb5a925b19bac0452cde43ca9f71033 100644
--- a/src/config/etc/sssd.api.conf
+++ b/src/config/etc/sssd.api.conf
@@ -61,6 +61,7 @@ get_domains_timeout = int, None, false
 pam_trusted_users = str, None, false
 pam_public_domains = str, None, false
 pam_account_expired_message = str, None, false
+pam_account_locked_message = str, None, false
 p11_child_timeout = int, None, false
 
 [sudo]
diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
index 73a21bfa0049bc4d3cfacb49201707868c87e533..2dbc58a451686beda0faa9e9366bbc3b3b4c253e 100644
--- a/src/man/sssd.conf.5.xml
+++ b/src/man/sssd.conf.5.xml
@@ -1040,6 +1040,27 @@ pam_account_expired_message = Account expired, please call help desk.
                     </listitem>
                 </varlistentry>
                 <varlistentry>
+                    <term>pam_account_locked_message (string)</term>
+                    <listitem>
+                        <para>
+                           If user is authenticating and
+                           account is locked then by default
+                           'Permission denied' is output. This output will
+                           be changed to content of this variable if it is
+                           set.
+                        </para>
+                        <para>
+                            example:
+                            <programlisting>
+pam_account_locked_message = Account locked, please call help desk.
+                            </programlisting>
+                        </para>
+                        <para>
+                            Default: none
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
                     <term>p11_child_timeout (integer)</term>
                     <listitem>
                         <para>
diff --git a/src/providers/dp_auth_util.c b/src/providers/dp_auth_util.c
index f8a30c5d4e6da7ce6ac28723032241e2458ea473..647ab4889759dabe1a09cb522f9b7b4ffb8fae96 100644
--- a/src/providers/dp_auth_util.c
+++ b/src/providers/dp_auth_util.c
@@ -160,6 +160,15 @@ bool dp_pack_pam_response(DBusMessage *msg, struct pam_data *pd)
         return false;
     }
 
+
+    /* Append the lockout of account */
+    dbret = dbus_message_iter_append_basic(&iter,
+                                           DBUS_TYPE_UINT32,
+                                           &pd->account_locked);
+    if (!dbret) {
+        return false;
+    }
+
     /* Create an array of response structures */
     dbret = dbus_message_iter_open_container(&iter,
                                              DBUS_TYPE_ARRAY, "(uay)",
@@ -246,6 +255,17 @@ bool dp_unpack_pam_response(DBusMessage *msg, struct pam_data *pd, DBusError *db
         return false;
     }
 
+    if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "pam response format error.\n");
+        return false;
+    }
+    dbus_message_iter_get_basic(&iter, &(pd->account_locked));
+
+    if (!dbus_message_iter_next(&iter)) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "pam response has too few arguments.\n");
+        return false;
+    }
+
     /* After this point will be an array of pam data */
     if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
         DEBUG(SSSDBG_CRIT_FAILURE, "pam response format error.\n");
diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
index bfc534f577cf80d5acfab81db30550ab5b5bdd2b..d86807e79f98b04d9ab14505ad8b2e92677bd292 100644
--- a/src/responder/pam/pamsrv_cmd.c
+++ b/src/responder/pam/pamsrv_cmd.c
@@ -53,10 +53,10 @@ pam_get_last_online_auth_with_curr_token(struct sss_domain_info *domain,
 
 static void pam_reply(struct pam_auth_req *preq);
 
-static errno_t pack_user_info_account_expired(TALLOC_CTX *mem_ctx,
-                                              const char *user_error_message,
-                                              size_t *resp_len,
-                                              uint8_t **_resp)
+static errno_t pack_user_info_msg(TALLOC_CTX *mem_ctx,
+                                  const char *user_error_message,
+                                  size_t *resp_len,
+                                  uint8_t **_resp)
 {
     uint32_t resp_type = SSS_PAM_USER_INFO_ACCOUNT_EXPIRED;
     size_t err_len;
@@ -83,14 +83,13 @@ static errno_t pack_user_info_account_expired(TALLOC_CTX *mem_ctx,
     return EOK;
 }
 
-static void inform_account_expired(struct pam_data* pd,
-                                   const char *pam_message)
+static void inform_user(struct pam_data* pd, const char *pam_message)
 {
     size_t msg_len;
     uint8_t *msg;
     errno_t ret;
 
-    ret = pack_user_info_account_expired(pd, pam_message, &msg_len, &msg);
+    ret = pack_user_info_msg(pd, pam_message, &msg_len, &msg);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE,
               "pack_user_info_account_expired failed.\n");
@@ -601,6 +600,7 @@ static void pam_reply(struct pam_auth_req *preq)
     time_t exp_date = -1;
     time_t delay_until = -1;
     char* pam_account_expired_message;
+    char* pam_account_locked_message;
     int pam_verbosity;
 
     pd = preq->pd;
@@ -762,7 +762,22 @@ static void pam_reply(struct pam_auth_req *preq)
             goto done;
         }
 
-        inform_account_expired(pd, pam_account_expired_message);
+        inform_user(pd, pam_account_expired_message);
+    }
+
+    if (pd->account_locked) {
+
+        ret = confdb_get_string(pctx->rctx->cdb, pd, CONFDB_PAM_CONF_ENTRY,
+                                CONFDB_PAM_ACCOUNT_LOCKED_MESSAGE, "",
+                                &pam_account_locked_message);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_MINOR_FAILURE,
+                  "Failed to get expiration message: %d:[%s].\n",
+                  ret, sss_strerror(ret));
+            goto done;
+        }
+
+        inform_user(pd, pam_account_locked_message);
     }
 
     ret = filter_responses(pctx->rctx->cdb, pd->resp_list);
-- 
2.4.3

