>From fca6a4275a4cfb298641949cd5b8b799d5eddd22 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          | 10 ++++++
 src/db/sysdb_ops.c      | 95 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/db/sysdb_private.h  |  5 +++
 src/tests/sysdb-tests.c | 76 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 186 insertions(+)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 4dc382f6fb3f1b6bd084312463edf1b6189ebba9..2319a0cae1bdff65453f69c4a5667fb178556fce 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"
@@ -904,6 +905,15 @@ int sysdb_cache_password_ex(struct sss_domain_info *domain,
                             enum sss_authtok_type authtok_type,
                             size_t second_factor_size);
 
+errno_t
+sysdb_null_last_online_auth_with_curr_token(struct sss_domain_info *domain,
+                                            const char *username);
+
+errno_t
+sysdb_get_last_online_auth_with_curr_token(struct sss_domain_info *domain,
+                                           const char *name,
+                                           uint64_t *_value);
+
 errno_t check_failed_login_attempts(struct confdb_ctx *cdb,
                                     struct ldb_message *ldb_msg,
                                     uint32_t *failed_login_attempts,
diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
index 6d0aede8ad376e1dfca98b531095804a63dd240e..bc51c40fb33bbbeda2a872f3d71ec8ff6de1af57 100644
--- a/src/db/sysdb_ops.c
+++ b/src/db/sysdb_ops.c
@@ -2302,6 +2302,101 @@ int sysdb_cache_password(struct sss_domain_info *domain,
                                    SSS_AUTHTOK_TYPE_PASSWORD, 0);
 }
 
+errno_t
+sysdb_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) {
+        ERROR_OUT(ret, ENOMEM, done);
+    }
+
+    attrs = sysdb_new_attrs(tmp_ctx);
+    if (attrs == NULL) {
+        ERROR_OUT(ret, ENOMEM, 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
+sysdb_null_last_online_auth_with_curr_token(struct sss_domain_info *domain,
+                                            const char *username)
+{
+    return sysdb_set_last_online_auth_with_curr_token(domain, username, 0);
+}
+
+errno_t
+sysdb_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;
+}
+
 /* =Custom Search================== */
 
 int sysdb_search_custom(TALLOC_CTX *mem_ctx,
diff --git a/src/db/sysdb_private.h b/src/db/sysdb_private.h
index 2adb9ff9166441014a8b446ffc170225f2a9629d..934710ff042a9f09ed95900ea82836498f4b37e5 100644
--- a/src/db/sysdb_private.h
+++ b/src/db/sysdb_private.h
@@ -142,4 +142,9 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx,
                                       const char *forest,
                                       uint32_t trust_direction);
 
+errno_t
+sysdb_set_last_online_auth_with_curr_token(struct sss_domain_info *domain,
+                                           const char *username,
+                                           uint64_t value);
+
 #endif /* __INT_SYS_DB_H__ */
diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
index 522a44aa4d5c0da6d10bba10d960fff9426200c1..9580011a85345e3392a871772213ffcf5c81acf2 100644
--- a/src/tests/sysdb-tests.c
+++ b/src/tests/sysdb-tests.c
@@ -2033,6 +2033,80 @@ START_TEST (test_sysdb_cached_authentication)
 }
 END_TEST
 
+START_TEST (test_sysdb_online_auth_with_curr_token)
+{
+    struct sysdb_test_ctx *test_ctx;
+    errno_t ret;
+    const char *username;
+    const char *non_exist_username;
+    uint64_t value;
+
+    /* Setup */
+    ret = setup_sysdb_tests(&test_ctx);
+    if (ret != EOK) {
+        fail("Could not set up the test");
+        return;
+    }
+
+    username = "testuser_newid";
+    non_exist_username = "non_existing_user";
+
+    ret = sysdb_add_user(test_ctx->domain, username,
+                         0, 0, username, "/", "/bin/bash",
+                         NULL, NULL,/* attrs */ 0, 0);
+    fail_if(ret != EOK, "Could not store user %s", username);
+
+    /* null & get */
+    ret = sysdb_null_last_online_auth_with_curr_token(test_ctx->domain,
+                                                      username);
+    fail_if(ret != EOK,
+            "sysdb_set_last_online_auth_with_curr_token failed for "
+            "%s - %s:[%d]", username, sss_strerror(ret), ret);
+
+    ret = sysdb_get_last_online_auth_with_curr_token(test_ctx->domain,
+                                                     username, &value);
+    fail_if(ret != EOK,
+            "sysdb_get_last_online_auth_with_curr_token failed for "
+            "%s - %s:[%d]", username, sss_strerror(ret), ret);
+    ck_assert_int_eq(value, 0);
+
+
+    /* set & get */
+    ret = sysdb_set_last_online_auth_with_curr_token(test_ctx->domain,
+                                                     username, 12345);
+    fail_if(ret != EOK,
+            "sysdb_set_last_online_auth_with_curr_token failed for "
+            "%s - %s:[%d]", username, sss_strerror(ret), ret);
+
+    ret = sysdb_get_last_online_auth_with_curr_token(test_ctx->domain,
+                                                     username, &value);
+    fail_if(ret != EOK,
+            "sysdb_get_last_online_auth_with_curr_token failed for "
+            "%s - %s:[%d]", username, sss_strerror(ret), ret);
+    ck_assert_int_eq(value, 12345);
+
+    /* set & get non_existing_user */
+    ret = sysdb_set_last_online_auth_with_curr_token(test_ctx->domain,
+                                                     non_exist_username, 12345);
+    fail_if(ret != ENOENT,
+            "sysdb_set_last_online_auth_with_curr_token failed for "
+            "%s - %s:[%d]", non_exist_username, sss_strerror(ret), ret);
+
+    ret = sysdb_get_last_online_auth_with_curr_token(test_ctx->domain,
+                                                     non_exist_username,
+                                                     &value);
+    fail_if(ret != ENOENT,
+            "sysdb_get_last_online_auth_with_curr_token failed for "
+            "%s - %s:[%d]", non_exist_username, sss_strerror(ret), ret);
+
+    ret = sysdb_delete_user(test_ctx->domain, username, 0);
+    fail_unless(ret == EOK, "sysdb_delete_user error [%d][%s]",
+                            ret, strerror(ret));
+
+    talloc_free(test_ctx);
+}
+END_TEST
+
 START_TEST (test_sysdb_prepare_asq_test_user)
 {
     struct sysdb_test_ctx *test_ctx;
@@ -6312,6 +6386,8 @@ Suite *create_sysdb_suite(void)
 
     tcase_add_loop_test(tc_sysdb, test_sysdb_cache_password_ex, 27010, 27011);
 
+    tcase_add_test(tc_sysdb, test_sysdb_online_auth_with_curr_token);
+
     /* ASQ search test */
     tcase_add_loop_test(tc_sysdb, test_sysdb_prepare_asq_test_user, 28011, 28020);
     tcase_add_test(tc_sysdb, test_sysdb_asq_search);
-- 
2.1.0

