>From 38dc66b619d6838610940f23ef84e0851a003319 Mon Sep 17 00:00:00 2001
From: Pavel Reichl <preichl@redhat.com>
Date: Wed, 24 Jun 2015 09:07:55 -0400
Subject: [PATCH 1/3] sysdb: new attribute lastOnlineAuthWithCurrentToken

Introduce new user attribute lastOnlineAuthWithCurrentToken.

Resolves:
https://fedorahosted.org/sssd/ticket/1807
---
 src/db/sysdb.h                  |  1 +
 src/responder/pam/pam_helpers.c | 98 ++++++++++++++++++++++++++++++++++++++++-
 src/responder/pam/pam_helpers.h | 15 +++++++
 src/tests/cmocka/test_pam_srv.c | 37 ++++++++++++++++
 4 files changed, 150 insertions(+), 1 deletion(-)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 4dc382f6fb3f1b6bd084312463edf1b6189ebba9..f309c9e0c542f8b9c02e48f74a9cefdb1e0a1752 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -87,6 +87,7 @@
 #define SYSDB_LAST_ONLINE_AUTH "lastOnlineAuth"
 #define SYSDB_LAST_FAILED_LOGIN "lastFailedLogin"
 #define SYSDB_FAILED_LOGIN_ATTEMPTS "failedLoginAttempts"
+#define SYSDB_LAST_ONLINE_AUTH_WITH_CURR_TOKEN "lastOnlineAuthWithCurrentToken"
 
 #define SYSDB_LAST_UPDATE "lastUpdate"
 #define SYSDB_CACHE_EXPIRE "dataExpireTimestamp"
diff --git a/src/responder/pam/pam_helpers.c b/src/responder/pam/pam_helpers.c
index 586888cae48ced8d6a6f47234fbec0ef89dd84d2..23242bb9e559d912455669a0ab7251c155f8b6e7 100644
--- a/src/responder/pam/pam_helpers.c
+++ b/src/responder/pam/pam_helpers.c
@@ -21,8 +21,8 @@
 */
 
 
-#include "util/util.h"
 #include "src/responder/pam/pam_helpers.h"
+#include "db/sysdb.h"
 
 struct pam_initgr_table_ctx {
     hash_table_t *id_table;
@@ -155,3 +155,99 @@ errno_t pam_initgr_check_timeout(hash_table_t *id_table,
     return EOK;
 }
 
+errno_t
+pam_set_last_online_auth_with_curr_token(struct sss_domain_info *domain,
+                                         const char *username,
+                                         uint64_t value)
+{
+    TALLOC_CTX *tmp_ctx;
+    struct sysdb_attrs *attrs;
+    int ret;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    attrs = sysdb_new_attrs(tmp_ctx);
+    if (attrs == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = sysdb_attrs_add_time_t(attrs,
+                                 SYSDB_LAST_ONLINE_AUTH_WITH_CURR_TOKEN,
+                                 value);
+    if (ret != EOK) { goto done; }
+
+    ret = sysdb_set_user_attr(domain, username, attrs, SYSDB_MOD_REP);
+    if (ret != EOK) { goto done; }
+
+done:
+    if (ret != EOK) {
+        DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, sss_strerror(ret));
+    }
+
+    talloc_zfree(tmp_ctx);
+    return ret;
+}
+
+errno_t
+pam_null_last_online_auth_with_curr_token(struct sss_domain_info *domain,
+                                          const char *username)
+{
+    return pam_set_last_online_auth_with_curr_token(domain, username, 0);
+}
+
+errno_t
+pam_get_last_online_auth_with_curr_token(struct sss_domain_info *domain,
+                                         const char *name,
+                                         uint64_t *_value)
+{
+    TALLOC_CTX *tmp_ctx = NULL;
+    const char *attrs[] = { SYSDB_LAST_ONLINE_AUTH_WITH_CURR_TOKEN, NULL };
+    struct ldb_message *ldb_msg;
+    uint64_t value;
+    errno_t ret;
+
+    if (name == NULL || *name == '\0') {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Missing user name.\n");
+        ret = EINVAL;
+        goto done;
+    }
+
+    if (domain->sysdb == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Missing sysdb db context.\n");
+        ret = EINVAL;
+        goto done;
+    }
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = sysdb_search_user_by_name(tmp_ctx, domain, name, attrs, &ldb_msg);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "sysdb_search_user_by_name failed [%d][%s].\n",
+              ret, strerror(ret));
+        goto done;
+    }
+
+    /* Check offline_auth_cache_timeout */
+    value = ldb_msg_find_attr_as_uint64(ldb_msg,
+                                        SYSDB_LAST_ONLINE_AUTH_WITH_CURR_TOKEN,
+                                        0);
+    ret = EOK;
+
+done:
+    if (ret == EOK) {
+        *_value = value;
+    }
+
+    talloc_free(tmp_ctx);
+    return ret;
+}
diff --git a/src/responder/pam/pam_helpers.h b/src/responder/pam/pam_helpers.h
index 1e1d914dfe3cd358972cc1ba6deb683a49b68235..b23713c2b51185ca11369b17f1ca30e295d1cb21 100644
--- a/src/responder/pam/pam_helpers.h
+++ b/src/responder/pam/pam_helpers.h
@@ -23,6 +23,8 @@
 #ifndef PAM_HELPERS_H_
 #define PAM_HELPERS_H_
 
+#include "util/util.h"
+
 errno_t pam_initgr_cache_set(struct tevent_context *ev,
                              hash_table_t *id_table,
                              char *name,
@@ -35,4 +37,17 @@ errno_t pam_initgr_cache_set(struct tevent_context *ev,
 errno_t pam_initgr_check_timeout(hash_table_t *id_table,
                               char *name);
 
+errno_t
+pam_null_last_online_auth_with_curr_token(struct sss_domain_info *domain,
+                                          const char *username);
+
+errno_t
+pam_get_last_online_auth_with_curr_token(struct sss_domain_info *domain,
+                                         const char *name,
+                                         uint64_t *_value);
+errno_t
+pam_set_last_online_auth_with_curr_token(struct sss_domain_info *domain,
+                                         const char *username,
+                                         uint64_t value);
+
 #endif /* PAM_HELPERS_H_ */
diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c
index 03faea249a31359d721e82cfd5bc2f9f375d0592..82e8c2ed82d9e0b2fd56081eba1e3e52f87d4c78 100644
--- a/src/tests/cmocka/test_pam_srv.c
+++ b/src/tests/cmocka/test_pam_srv.c
@@ -859,6 +859,41 @@ void test_pam_offline_chauthtok(void **state)
     assert_int_equal(ret, EOK);
 }
 
+void test_pam_online_auth_with_curr_token(void **state)
+{
+    errno_t ret;
+    const char *username;
+    const char *non_exist_username;
+    uint64_t value;
+    struct sss_domain_info *domain = pam_test_ctx->tctx->dom;
+
+    username = "pamuser";
+    non_exist_username = "non_existing_user";
+
+    /* null & get */
+    ret = pam_null_last_online_auth_with_curr_token(domain, username);
+    assert_int_equal(ret, EOK);
+
+    ret = pam_get_last_online_auth_with_curr_token(domain, username, &value);
+    assert_int_equal(ret, 0);
+
+    /* set & get */
+    ret = pam_set_last_online_auth_with_curr_token(domain, username, 12345);
+    assert_int_equal(ret, EOK);
+
+    ret = pam_get_last_online_auth_with_curr_token(domain, username, &value);
+    assert_int_equal(ret, EOK);
+    assert_int_equal(value, 12345);
+
+    /* set & get non_existing_user */
+    ret = pam_set_last_online_auth_with_curr_token(domain, non_exist_username,
+                                                   12345);
+    assert_int_equal(ret, ENOENT);
+
+    ret = pam_get_last_online_auth_with_curr_token(domain, non_exist_username,
+                                                   &value);
+    assert_int_equal(ret, ENOENT);
+}
 
 int main(int argc, const char *argv[])
 {
@@ -926,6 +961,8 @@ int main(int argc, const char *argv[])
                                         pam_test_setup, pam_test_teardown),
         cmocka_unit_test_setup_teardown(test_pam_offline_chauthtok,
                                         pam_test_setup, pam_test_teardown),
+        cmocka_unit_test_setup_teardown(test_pam_online_auth_with_curr_token,
+                                        pam_test_setup, pam_test_teardown),
     };
 
     /* Set debug level to invalid value so we can deside if -d 0 was used. */
-- 
2.1.0

