From 2658ae5b7ed743d6d66c3a7c858c5e9f28a748fe Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Wed, 22 Dec 2010 11:00:22 -0500
Subject: [PATCH 2/2] Update the ID cache for any PAM request

Also adds an option to limit how often we check the ID provider,
so that conversations with multiple PAM requests won't update the
cache multiple times.

https://fedorahosted.org/sssd/ticket/749
---
 src/confdb/confdb.h              |    1 +
 src/config/SSSDConfig.py         |    1 +
 src/config/etc/sssd.api.conf     |    1 +
 src/man/sssd.conf.5.xml          |   22 ++++++++++++++++++++++
 src/responder/common/responder.h |    2 ++
 src/responder/pam/pamsrv.c       |    9 +++++++++
 src/responder/pam/pamsrv.h       |    1 +
 src/responder/pam/pamsrv_cmd.c   |   19 +++++++++++--------
 8 files changed, 48 insertions(+), 8 deletions(-)

diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index eccb98d369cfbf78f89b09f42aa61e3a91af14e4..5e55f2558a12f84cdf97116551102b9aa83a2b81 100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -81,6 +81,7 @@
 #define CONFDB_PAM_FAILED_LOGIN_DELAY "offline_failed_login_delay"
 #define CONFDB_DEFAULT_PAM_FAILED_LOGIN_DELAY 5
 #define CONFDB_PAM_VERBOSITY "pam_verbosity"
+#define CONFDB_PAM_ID_TIMEOUT "pam_id_timeout"
 
 /* Data Provider */
 #define CONFDB_DP_CONF_ENTRY "config/dp"
diff --git a/src/config/SSSDConfig.py b/src/config/SSSDConfig.py
index b117717882193c206be88332abf2698d68052943..d23641c9dd602fe98de9c58b2bde8cd166c1acad 100644
--- a/src/config/SSSDConfig.py
+++ b/src/config/SSSDConfig.py
@@ -64,6 +64,7 @@ option_strings = {
     'offline_failed_login_attempts' : _('How many failed logins attempts are allowed when offline'),
     'offline_failed_login_delay' : _('How long (minutes) to deny login after offline_failed_login_attempts has been reached'),
     'pam_verbosity' : _('What kind of messages are displayed to the user during authentication'),
+    'pam_id_timeout' : _('How many seconds to keep identity information cached for PAM requests'),
 
     # [provider]
     'id_provider' : _('Identity provider'),
diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
index 3bd0cc490ad1fbb365a7bf9f55d6cb08b5bb569e..5127b852df90da9fcca5bb6f2cec667100903523 100644
--- a/src/config/etc/sssd.api.conf
+++ b/src/config/etc/sssd.api.conf
@@ -34,6 +34,7 @@ offline_credentials_expiration = int, None, false
 offline_failed_login_attempts = int, None, false
 offline_failed_login_delay = int, None, false
 pam_verbosity = int, None, false
+pam_id_timeout = int, None, false
 
 [provider]
 #Available provider types
diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
index 7392dd0931ab015a58520eea93f34d798758b441..96b7a4c3c6e39ff27ef1ad3ea7f1a3770b0285ed 100644
--- a/src/man/sssd.conf.5.xml
+++ b/src/man/sssd.conf.5.xml
@@ -440,6 +440,28 @@
                         </para>
                     </listitem>
                 </varlistentry>
+                <varlistentry>
+                  <term>pam_id_timeout (integer)</term>
+                  <listitem>
+                    <para>
+                      For any PAM request while SSSD is online, the SSSD will
+                      attempt to immediately update the cached identity
+                      information for the user in order to ensure that
+                      authentication takes place with the latest information.
+                    </para>
+                    <para>
+                      A complete PAM conversation may perform multiple PAM
+                      requests, such as account management and session
+                      opening. This option controls (on a
+                      per-client-application basis) how long (in seconds) we
+                      can cache the identity information to avoid excessive
+                      round-trips to the identity provider.
+                    </para>
+                    <para>
+                      Default: 5
+                    </para>
+                  </listitem>
+                </varlistentry>
             </variablelist>
         </refsect2>
     </refsect1>
diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
index 783f9e4057b2f0af4d141455688ea1e52e6c65a6..6b81aadacc2f4c47afb8363523e6cf00dbe4f6b6 100644
--- a/src/responder/common/responder.h
+++ b/src/responder/common/responder.h
@@ -118,6 +118,8 @@ struct cli_ctx {
 
     char *netgr_name;
     int netgrent_cur;
+
+    time_t pam_timeout;
 };
 
 struct sss_cmd_table {
diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c
index 61e7ce7a360daaa494e1ea23c15b8cf6016b0ab7..91ee4a899aebbf9646a796f1e31a16797360de86 100644
--- a/src/responder/pam/pamsrv.c
+++ b/src/responder/pam/pamsrv.c
@@ -108,6 +108,7 @@ static int pam_process_init(TALLOC_CTX *mem_ctx,
     struct be_conn *iter;
     struct pam_ctx *pctx;
     int ret, max_retries;
+    int id_timeout;
 
     pctx = talloc_zero(mem_ctx, struct pam_ctx);
     if (!pctx) {
@@ -153,6 +154,14 @@ static int pam_process_init(TALLOC_CTX *mem_ctx,
                          &pctx->neg_timeout);
     if (ret != EOK) goto done;
 
+    /* Set up the PAM identity timeout */
+    ret = confdb_get_int(cdb, pctx, CONFDB_PAM_CONF_ENTRY,
+                         CONFDB_PAM_ID_TIMEOUT, 5,
+                         &id_timeout);
+    if (ret != EOK) goto done;
+
+    pctx->id_timeout = (size_t)id_timeout;
+
     ret = sss_ncache_init(pctx, &pctx->ncache);
     if (ret != EOK) {
         DEBUG(0, ("fatal error initializing negative cache\n"));
diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h
index 3ada4cfd812844656889fc9e09c453b913a87d72..3ffc17087445a5314d5a85f471bb557fdbc94e7b 100644
--- a/src/responder/pam/pamsrv.h
+++ b/src/responder/pam/pamsrv.h
@@ -35,6 +35,7 @@ struct pam_ctx {
     struct resp_ctx *rctx;
     struct sss_nc_ctx *ncache;
     int neg_timeout;
+    time_t id_timeout;
 };
 
 struct pam_auth_req {
diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
index 48341aab4d6e0fbe031c68b67030338e65b6ac71..6a8f1dbb515c63125c810dca15ac186c58b1bafb 100644
--- a/src/responder/pam/pamsrv_cmd.c
+++ b/src/responder/pam/pamsrv_cmd.c
@@ -790,14 +790,12 @@ static int pam_check_user_search(struct pam_auth_req *preq)
         /* make sure to update the preq if we changed domain */
         preq->domain = dom;
 
-        /* TODO: check negative cache ? */
-
-        /* Always try to refresh the cache first on authentication */
-        if (preq->check_provider &&
-            (preq->pd->cmd == SSS_PAM_AUTHENTICATE ||
-             preq->pd->cmd == SSS_PAM_SETCRED)) {
-
-            /* call provider first */
+        /* Refresh the user's cache entry on any PAM query
+         * We put a timeout in the client context so that we limit
+         * the number of updates within a reasonable timeout
+         */
+        if (preq->check_provider && cctx->pam_timeout < time(NULL)) {
+            /* Call provider first */
             break;
         }
 
@@ -909,6 +907,8 @@ static void pam_check_user_dp_callback(uint16_t err_maj, uint32_t err_min,
 {
     struct pam_auth_req *preq = talloc_get_type(ptr, struct pam_auth_req);
     int ret;
+    struct pam_ctx *pctx =
+            talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
 
     if (err_maj) {
         DEBUG(2, ("Unable to get information from Data Provider\n"
@@ -916,6 +916,9 @@ static void pam_check_user_dp_callback(uint16_t err_maj, uint32_t err_min,
                   (unsigned int)err_maj, (unsigned int)err_min, err_msg));
     }
 
+    /* Make sure we don't go to the ID provider too often */
+    preq->cctx->pam_timeout = time(NULL) + pctx->id_timeout;
+
     ret = pam_check_user_search(preq);
     if (ret == EOK) {
         pam_dom_forwarder(preq);
-- 
1.7.3.3

