Hi,

this patch move the validation against cached password from the PAM
responder code to a sysdb tevent request. This allows e.g. the Kerberos
provider to check a password on it own when offline. This is needed for
features like 'kinit when going online' or 'automatic ticket renewal'
where the Kerberos provider needs to keep the password in memory.

I think this is no material for 1.0.x, but for 1.1.x.

bye,
Sumit
>From bc8d8ce024a0f56ee6323197b4b9b21077d651a7 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sb...@redhat.com>
Date: Thu, 7 Jan 2010 10:26:50 +0100
Subject: [PATCH] Add sysdb request to authenticate against a cached password

The code for authentication against a cached password is moved from the
pam responder to a generic sysdb tevent request. The new code can be
used by other components of sssd to verify passwords on their own.

Tests for the sysdb_cache_password and sysdb_cache_auth request are
added and some unneeded or unused code and variables are removed.
---
 server/Makefile.am                      |    1 -
 server/db/sysdb.h                       |   11 ++
 server/db/sysdb_ops.c                   |  173 +++++++++++++++++++++++++++++
 server/responder/pam/pam_LOCAL_domain.c |   31 ++----
 server/responder/pam/pamsrv.h           |    2 -
 server/responder/pam/pamsrv_cache.c     |  180 -------------------------------
 server/responder/pam/pamsrv_cmd.c       |   62 +++++++++--
 server/tests/sysdb-tests.c              |  135 +++++++++++++++++++++++
 8 files changed, 378 insertions(+), 217 deletions(-)
 delete mode 100644 server/responder/pam/pamsrv_cache.c

diff --git a/server/Makefile.am b/server/Makefile.am
index 9d17ee7..370af75 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -342,7 +342,6 @@ sssd_nss_LDADD = \
 sssd_pam_SOURCES = \
     responder/pam/pam_LOCAL_domain.c \
     responder/pam/pamsrv.c \
-    responder/pam/pamsrv_cache.c \
     responder/pam/pamsrv_cmd.c \
     responder/pam/pamsrv_dp.c \
     $(SSSD_UTIL_OBJ) \
diff --git a/server/db/sysdb.h b/server/db/sysdb.h
index 641ec68..4c25549 100644
--- a/server/db/sysdb.h
+++ b/server/db/sysdb.h
@@ -542,6 +542,17 @@ struct tevent_req *sysdb_cache_password_send(TALLOC_CTX 
*mem_ctx,
                                              const char *password);
 int sysdb_cache_password_recv(struct tevent_req *req);
 
+
+struct tevent_req *sysdb_cache_auth_send(TALLOC_CTX *mem_ctx,
+                                         struct tevent_context *ev,
+                                         struct sysdb_ctx *sysdb,
+                                         struct sss_domain_info *domain,
+                                         const char *name,
+                                         const uint8_t *authtok,
+                                         size_t authtok_size,
+                                         struct confdb_ctx *cdb);
+int sysdb_cache_auth_recv(struct tevent_req *req);
+
 struct tevent_req *sysdb_store_custom_send(TALLOC_CTX *mem_ctx,
                                          struct tevent_context *ev,
                                          struct sysdb_handle *handle,
diff --git a/server/db/sysdb_ops.c b/server/db/sysdb_ops.c
index 86a9d33..36b5867 100644
--- a/server/db/sysdb_ops.c
+++ b/server/db/sysdb_ops.c
@@ -4632,4 +4632,177 @@ int sysdb_delete_group_recv(struct tevent_req *req)
     return sysdb_op_default_recv(req);
 }
 
+/* ========= Authentication against cached password ============ */
 
+struct sysdb_cache_auth_state {
+    struct tevent_context *ev;
+    const char *name;
+    const uint8_t *authtok;
+    size_t authtok_size;
+    struct sss_domain_info *domain;
+    struct sysdb_ctx *sysdb;
+    struct confdb_ctx *cdb;
+};
+
+static void sysdb_cache_auth_get_attrs_done(struct tevent_req *subreq);
+
+struct tevent_req *sysdb_cache_auth_send(TALLOC_CTX *mem_ctx,
+                                         struct tevent_context *ev,
+                                         struct sysdb_ctx *sysdb,
+                                         struct sss_domain_info *domain,
+                                         const char *name,
+                                         const uint8_t *authtok,
+                                         size_t authtok_size,
+                                         struct confdb_ctx *cdb)
+{
+    struct tevent_req *req;
+    struct tevent_req *subreq;
+    struct sysdb_cache_auth_state *state;
+
+    if (name == NULL || *name == '\0') {
+        DEBUG(1, ("Missing user name.\n"));
+        return NULL;
+    }
+
+    if (cdb == NULL) {
+        DEBUG(1, ("Missing config db context.\n"));
+        return NULL;
+    }
+
+    if (sysdb == NULL) {
+        DEBUG(1, ("Missing sysdb db context.\n"));
+        return NULL;
+    }
+
+    static const char *attrs[] = {SYSDB_NAME,
+                                  SYSDB_CACHEDPWD,
+                                  SYSDB_DISABLED,
+                                  SYSDB_LAST_LOGIN,
+                                  SYSDB_LAST_ONLINE_AUTH,
+                                  "lastCachedPasswordChange",
+                                  "accountExpires",
+                                  "failedLoginAttempts",
+                                  "lastFailedLogin",
+                                  NULL};
+
+    req = tevent_req_create(mem_ctx, &state, struct sysdb_cache_auth_state);
+    if (req == NULL) {
+        DEBUG(1, ("tevent_req_create failed.\n"));
+        return NULL;
+    }
+
+    state->ev = ev;
+    state->name = name;
+    state->authtok = authtok;
+    state->authtok_size = authtok_size;
+    state->domain = domain;
+    state->sysdb = sysdb;
+    state->cdb = cdb;
+
+    subreq = sysdb_search_user_by_name_send(state, ev, sysdb, NULL, domain,
+                                            name, attrs);
+    if (subreq == NULL) {
+        DEBUG(1, ("sysdb_search_user_by_name_send failed.\n"));
+        talloc_zfree(req);
+        return NULL;
+    }
+    tevent_req_set_callback(subreq, sysdb_cache_auth_get_attrs_done, req);
+
+    return req;
+}
+
+static void sysdb_cache_auth_get_attrs_done(struct tevent_req *subreq)
+{
+    struct ldb_message *ldb_msg;
+    const char *userhash;
+    char *comphash;
+    char *password = NULL;
+    int i;
+    int ret;
+    uint64_t lastLogin = 0;
+    int cred_expiration;
+
+    struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                      struct tevent_req);
+
+    struct sysdb_cache_auth_state *state = tevent_req_data(req,
+                                                 struct 
sysdb_cache_auth_state);
+
+    ret = sysdb_search_user_recv(subreq, state, &ldb_msg);
+    talloc_zfree(subreq);
+    if (ret != EOK) {
+        DEBUG(1, ("sysdb_search_user_by_name_send failed [%d][%s].\n",
+                  ret, strerror(ret)));
+        tevent_req_error(req, ENOENT);
+        return;
+    }
+
+    /* Check offline_auth_cache_timeout */
+    lastLogin = ldb_msg_find_attr_as_uint64(ldb_msg,
+                                            SYSDB_LAST_ONLINE_AUTH,
+                                            0);
+
+    ret = confdb_get_int(state->cdb, state, CONFDB_PAM_CONF_ENTRY,
+                         CONFDB_PAM_CRED_TIMEOUT, 0, &cred_expiration);
+    if (ret != EOK) {
+        DEBUG(1, ("Failed to read expiration time of offline credentials.\n"));
+        ret = EACCES;
+        goto done;
+    }
+    DEBUG(9, ("Offline credentials expiration is [%d] days.\n",
+              cred_expiration));
+
+    if (cred_expiration && lastLogin + (cred_expiration * 86400) < time(NULL)) 
{
+        DEBUG(4, ("Cached user entry is too old."));
+        ret = EACCES;
+        goto done;
+    }
+
+    /* TODO: verify user account (failed logins, disabled, expired ...) */
+
+    password = talloc_strndup(state, (const char *) state->authtok,
+                              state->authtok_size);
+    if (password == NULL) {
+        DEBUG(1, ("talloc_strndup failed.\n"));
+        ret = ENOMEM;
+        goto done;
+    }
+
+    userhash = ldb_msg_find_attr_as_string(ldb_msg, SYSDB_CACHEDPWD, NULL);
+    if (userhash == NULL || *userhash == '\0') {
+        DEBUG(4, ("Cached credentials not available.\n"));
+        ret = ENOENT;
+        goto done;
+    }
+
+    ret = s3crypt_sha512(state, password, userhash, &comphash);
+    if (ret) {
+        DEBUG(4, ("Failed to create password hash.\n"));
+        ret = EFAULT;
+        goto done;
+    }
+
+    if (strcmp(userhash, comphash) == 0) {
+        /* TODO: probable good point for audit logging */
+        DEBUG(4, ("Hashes do match!\n"));
+        ret = EOK;
+        goto done;
+    }
+
+    DEBUG(4, ("Authentication failed.\n"));
+    ret = EINVAL;
+
+done:
+    if (password) for (i = 0; password[i]; i++) password[i] = 0;
+    if (ret == EOK) {
+        tevent_req_done(req);
+    } else {
+        tevent_req_error(req, ret);
+    }
+    return;
+}
+
+int sysdb_cache_auth_recv(struct tevent_req *req) {
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+    return EOK;
+}
diff --git a/server/responder/pam/pam_LOCAL_domain.c 
b/server/responder/pam/pam_LOCAL_domain.c
index b98459d..9d3738c 100644
--- a/server/responder/pam/pam_LOCAL_domain.c
+++ b/server/responder/pam/pam_LOCAL_domain.c
@@ -58,23 +58,6 @@ struct LOCAL_request {
     struct pam_auth_req *preq;
 };
 
-static int authtok2str(const void *mem_ctx, uint8_t *src, const int src_size, 
char **dest)
-{
-    if ((src == NULL && src_size != 0) ||
-        (src != NULL && *src != '\0' && src_size == 0)) {
-        return EINVAL;
-    }
-
-    *dest = talloc_size(mem_ctx, src_size + 1);
-    if (*dest == NULL) {
-        return ENOMEM;
-    }
-    memcpy(*dest, src, src_size);
-    (*dest)[src_size]='\0';
-
-    return EOK;
-}
-
 static void prepare_reply(struct LOCAL_request *lreq)
 {
     struct pam_data *pd;
@@ -273,9 +256,10 @@ static void do_pam_chauthtok(struct LOCAL_request *lreq)
 
     pd = lreq->preq->pd;
 
-    ret = authtok2str(lreq, pd->newauthtok, pd->newauthtok_size, &newauthtok);
-    NEQ_CHECK_OR_JUMP(ret, EOK, ("authtok2str failed.\n"),
-                      lreq->error, ret, done);
+    newauthtok = talloc_strndup(lreq, (char *) pd->newauthtok,
+                                pd->newauthtok_size);
+    NULL_CHECK_OR_JUMP(newauthtok, ("talloc_strndup failed.\n"), lreq->error,
+                       ENOMEM, done);
     memset(pd->newauthtok, 0, pd->newauthtok_size);
 
     if (strlen(newauthtok) == 0) {
@@ -375,9 +359,10 @@ static void local_handler_callback(void *pvt, int 
ldb_status,
                 DEBUG(4, ("allowing root to reset a password.\n"));
                 break;
             }
-            ret = authtok2str(lreq, pd->authtok, pd->authtok_size, &authtok);
-            NEQ_CHECK_OR_JUMP(ret, EOK, ("authtok2str failed.\n"),
-                              lreq->error, ret, done);
+            authtok = talloc_strndup(lreq, (char *) pd->authtok,
+                                     pd->authtok_size);
+            NULL_CHECK_OR_JUMP(authtok, ("talloc_strndup failed.\n"),
+                               lreq->error, ENOMEM, done);
             memset(pd->authtok, 0, pd->authtok_size);
 
             password = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_PWD, 
NULL);
diff --git a/server/responder/pam/pamsrv.h b/server/responder/pam/pamsrv.h
index d87e166..60f9c66 100644
--- a/server/responder/pam/pamsrv.h
+++ b/server/responder/pam/pamsrv.h
@@ -52,8 +52,6 @@ struct sss_cmd_table *get_pam_cmds(void);
 
 int pam_dp_send_req(struct pam_auth_req *preq, int timeout);
 
-int pam_cache_auth(struct pam_auth_req *preq);
-
 int LOCAL_pam_handler(struct pam_auth_req *preq);
 
 #endif /* __PAMSRV_H__ */
diff --git a/server/responder/pam/pamsrv_cache.c 
b/server/responder/pam/pamsrv_cache.c
deleted file mode 100644
index 1e1c544..0000000
--- a/server/responder/pam/pamsrv_cache.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
-   SSSD
-
-   PAM cache credentials
-
-   Copyright (C) Simo Sorce <sso...@redhat.com>        2009
-   Copyright (C) Sumit Bose <sb...@redhat.com> 2009
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <security/pam_modules.h>
-#include <time.h>
-#include "util/util.h"
-#include "db/sysdb.h"
-#include "util/nss_sha512crypt.h"
-#include "providers/data_provider.h"
-#include "responder/pam/pamsrv.h"
-
-static int authtok2str(const void *mem_ctx,
-                       uint8_t *src, const int src_size,
-                       char **_dest)
-{
-    char *dest;
-
-    if ((src == NULL && src_size != 0) ||
-        (src != NULL && *src != '\0' && src_size == 0)) {
-        return EINVAL;
-    }
-
-    dest = talloc_size(mem_ctx, src_size + 1);
-    if (dest == NULL) {
-        return ENOMEM;
-    }
-
-    memcpy(dest, src, src_size);
-    dest[src_size]='\0';
-
-    *_dest = dest;
-    return EOK;
-}
-
-static void pam_cache_auth_return(struct pam_auth_req *preq, int error)
-{
-    preq->pd->pam_status = error;
-    preq->callback(preq);
-}
-
-static void pam_cache_auth_callback(void *pvt, int ldb_status,
-                                    struct ldb_result *res)
-{
-    struct pam_auth_req *preq;
-    struct pam_ctx *pctx;
-    struct pam_data *pd;
-    const char *userhash;
-    char *comphash;
-    char *password = NULL;
-    int i, ret;
-    uint64_t lastLogin = 0;
-
-    preq = talloc_get_type(pvt, struct pam_auth_req);
-    pd = preq->pd;
-
-    pctx = talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
-
-    if (ldb_status != LDB_SUCCESS) {
-        DEBUG(4, ("User info retrieval failed! (%d [%s])\n",
-                  ldb_status, sysdb_error_to_errno(ldb_status)));
-
-        ret = PAM_SYSTEM_ERR;
-        goto done;
-    }
-
-    if (res->count == 0) {
-        DEBUG(4, ("User [...@%s] not found.\n",
-                  pd->user, preq->domain->name));
-        ret = PAM_USER_UNKNOWN;
-        goto done;
-    }
-
-    if (res->count != 1) {
-        DEBUG(4, ("Too many results for user [...@%s].\n",
-                  pd->user, preq->domain->name));
-        ret = PAM_SYSTEM_ERR;
-        goto done;
-    }
-
-    /* Check offline_auth_cache_timeout */
-    lastLogin = ldb_msg_find_attr_as_uint64(res->msgs[0],
-                                            SYSDB_LAST_ONLINE_AUTH,
-                                            0);
-    if (pctx->cred_expiration &&
-        lastLogin + (pctx->cred_expiration * 86400) < time(NULL)) {
-        DEBUG(4, ("Cached user entry is too old."));
-        ret = PAM_AUTHINFO_UNAVAIL;
-        goto done;
-    }
-
-    /* TODO: verify user account (failed logins, disabled, expired ...) */
-
-    ret = authtok2str(preq, pd->authtok, pd->authtok_size, &password);
-    if (ret) {
-        DEBUG(4, ("Invalid auth token.\n"));
-        ret = PAM_AUTH_ERR;
-        goto done;
-    }
-
-    userhash = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_CACHEDPWD, 
NULL);
-    if (userhash == NULL || *userhash == '\0') {
-        DEBUG(4, ("Cached credentials not available.\n"));
-        ret = PAM_AUTHINFO_UNAVAIL;
-        goto done;
-    }
-
-    ret = s3crypt_sha512(preq, password, userhash, &comphash);
-    if (ret) {
-        DEBUG(4, ("Failed to create password hash.\n"));
-        ret = PAM_SYSTEM_ERR;
-        goto done;
-    }
-
-    if (strcmp(userhash, comphash) == 0) {
-        /* TODO: probable good point for audit logging */
-        DEBUG(4, ("Hashes do match!\n"));
-        ret = PAM_SUCCESS;
-        goto done;
-    }
-
-    DEBUG(4, ("Authentication failed.\n"));
-    ret = PAM_AUTH_ERR;
-
-done:
-    if (password) for (i = 0; password[i]; i++) password[i] = 0;
-    pam_cache_auth_return(preq, ret);
-}
-
-int pam_cache_auth(struct pam_auth_req *preq)
-{
-    struct sysdb_ctx *sysdb;
-    int ret;
-
-    static const char *attrs[] = {SYSDB_NAME,
-                                  SYSDB_CACHEDPWD,
-                                  SYSDB_DISABLED,
-                                  SYSDB_LAST_LOGIN,
-                                  SYSDB_LAST_ONLINE_AUTH,
-                                  "lastCachedPasswordChange",
-                                  "accountExpires",
-                                  "failedLoginAttempts",
-                                  "lastFailedLogin",
-                                  NULL};
-
-    ret = sysdb_get_ctx_from_list(preq->cctx->rctx->db_list,
-                                  preq->domain, &sysdb);
-    if (ret != EOK) {
-        DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n"));
-        return ret;
-    }
-    ret = sysdb_get_user_attr(preq, sysdb,
-                              preq->domain, preq->pd->user, attrs,
-                              pam_cache_auth_callback, preq);
-
-    if (ret != EOK) {
-        DEBUG(2, ("sysdb_get_user_attr failed.\n"));
-    }
-
-    return ret;
-}
-
diff --git a/server/responder/pam/pamsrv_cmd.c 
b/server/responder/pam/pamsrv_cmd.c
index 69cbf55..ca41d64 100644
--- a/server/responder/pam/pamsrv_cmd.c
+++ b/server/responder/pam/pamsrv_cmd.c
@@ -465,13 +465,14 @@ static void pam_reply_delay(struct tevent_context *ev, 
struct tevent_timer *te,
     pam_reply(preq);
 }
 
+static void pam_cache_auth_done(struct tevent_req *req);
+
 static void pam_reply(struct pam_auth_req *preq)
 {
     struct cli_ctx *cctx;
     uint8_t *body;
     size_t blen;
     int ret;
-    int err = EOK;
     int32_t resp_c;
     int32_t resp_size;
     struct response_data *resp;
@@ -479,6 +480,9 @@ static void pam_reply(struct pam_auth_req *preq)
     struct timeval tv;
     struct tevent_timer *te;
     struct pam_data *pd;
+    struct tevent_req *req;
+    struct sysdb_ctx *sysdb;
+    struct pam_ctx *pctx;
 
     pd = preq->pd;
 
@@ -492,14 +496,25 @@ static void pam_reply(struct pam_auth_req *preq)
         if (pd->pam_status == PAM_AUTHINFO_UNAVAIL) {
             /* do auth with offline credentials */
             pd->offline_auth = true;
-            preq->callback = pam_reply;
-            ret = pam_cache_auth(preq);
-            if (ret == EOK) {
-                return;
+
+            ret = sysdb_get_ctx_from_list(preq->cctx->rctx->db_list,
+                                          preq->domain, &sysdb);
+            if (ret != EOK) {
+                DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n"));
+                goto done;
             }
-            else {
+
+            pctx = talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
+
+            req = sysdb_cache_auth_send(preq, preq->cctx->ev, sysdb,
+                                        preq->domain, pd->user, pd->authtok,
+                                        pd->authtok_size, pctx->rctx->cdb);
+            if (req == NULL) {
                 DEBUG(1, ("Failed to setup offline auth"));
                 /* this error is not fatal, continue */
+            } else {
+                tevent_req_set_callback(req, pam_cache_auth_done, preq);
+                return;
             }
         }
     }
@@ -521,7 +536,6 @@ static void pam_reply(struct pam_auth_req *preq)
         if (ret != EOK) {
             DEBUG(1, ("gettimeofday failed [%d][%s].\n",
                       errno, strerror(errno)));
-            err = ret;
             goto done;
         }
         tv.tv_sec += pd->response_delay;
@@ -531,7 +545,6 @@ static void pam_reply(struct pam_auth_req *preq)
         te = tevent_add_timer(cctx->ev, cctx, tv, pam_reply_delay, preq);
         if (te == NULL) {
             DEBUG(1, ("Failed to add event pam_reply_delay.\n"));
-            err = ENOMEM;
             goto done;
         }
 
@@ -547,7 +560,6 @@ static void pam_reply(struct pam_auth_req *preq)
         NEED_CHECK_PROVIDER(preq->domain->provider)) {
         ret = set_last_login(preq);
         if (ret != EOK) {
-            err = ret;
             goto done;
         }
 
@@ -557,7 +569,6 @@ static void pam_reply(struct pam_auth_req *preq)
     ret = sss_packet_new(cctx->creq, 0, sss_packet_get_cmd(cctx->creq->in),
                          &cctx->creq->out);
     if (ret != EOK) {
-        err = ret;
         goto done;
     }
 
@@ -580,7 +591,6 @@ static void pam_reply(struct pam_auth_req *preq)
                                            resp_c * 2* sizeof(int32_t) +
                                            resp_size);
     if (ret != EOK) {
-        err = ret;
         goto done;
     }
 
@@ -610,6 +620,36 @@ done:
     sss_cmd_done(cctx, preq);
 }
 
+static void pam_cache_auth_done(struct tevent_req *req)
+{
+    int ret;
+    struct pam_auth_req *preq = tevent_req_callback_data(req,
+                                                         struct pam_auth_req);
+
+    ret = sysdb_cache_auth_recv(req);
+    talloc_zfree(req);
+
+    switch (ret) {
+        case EOK:
+            preq->pd->pam_status = PAM_SUCCESS;
+            break;
+        case ENOENT:
+            preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL;
+            break;
+        case EINVAL:
+            preq->pd->pam_status = PAM_AUTH_ERR;
+            break;
+        case EACCES:
+            preq->pd->pam_status = PAM_PERM_DENIED;
+            break;
+        default:
+            preq->pd->pam_status = PAM_SYSTEM_ERR;
+    }
+
+    pam_reply(preq);
+    return;
+}
+
 static void pam_check_user_dp_callback(uint16_t err_maj, uint32_t err_min,
                                        const char *err_msg, void *ptr);
 static void pam_check_user_callback(void *ptr, int status,
diff --git a/server/tests/sysdb-tests.c b/server/tests/sysdb-tests.c
index ace0343..11fde6f 100644
--- a/server/tests/sysdb-tests.c
+++ b/server/tests/sysdb-tests.c
@@ -2236,6 +2236,129 @@ START_TEST (test_sysdb_delete_custom)
 }
 END_TEST
 
+START_TEST (test_sysdb_cache_password)
+{
+    struct sysdb_test_ctx *test_ctx;
+    struct test_data *data;
+    struct tevent_req *req;
+    int ret;
+
+    /* Setup */
+    ret = setup_sysdb_tests(&test_ctx);
+    fail_unless(ret == EOK, "Could not set up the test");
+
+    data = talloc_zero(test_ctx, struct test_data);
+    data->ctx = test_ctx;
+    data->ev = test_ctx->ev;
+    data->username = talloc_asprintf(data, "testuser%d", _i);
+
+    req = sysdb_cache_password_send(data, test_ctx->ev, test_ctx->sysdb, NULL,
+                                    test_ctx->domain, data->username,
+                                    data->username);
+    fail_unless(req != NULL, "sysdb_cache_password_send failed [%d].", ret);
+
+    tevent_req_set_callback(req, test_search_done, data);
+
+    ret = test_loop(data);
+    fail_unless(ret == EOK, "test_loop failed [%d].", ret);
+
+    ret = sysdb_cache_password_recv(req);
+    fail_unless(ret == EOK, "sysdb_cache_password request failed [%d].", ret);
+
+    talloc_free(test_ctx);
+}
+END_TEST
+
+static void cached_authentication(const char *username, const char *password,
+                                  int expected_result)
+{
+    struct sysdb_test_ctx *test_ctx;
+    struct test_data *data;
+    struct tevent_req *req;
+    int ret;
+
+    /* Setup */
+    ret = setup_sysdb_tests(&test_ctx);
+    fail_unless(ret == EOK, "Could not set up the test");
+
+    data = talloc_zero(test_ctx, struct test_data);
+    data->ctx = test_ctx;
+    data->ev = test_ctx->ev;
+    data->username = username;
+
+    req = sysdb_cache_auth_send(data, test_ctx->ev, test_ctx->sysdb,
+                                test_ctx->domain, data->username,
+                                (const uint8_t *) password, strlen(password),
+                                test_ctx->confdb);
+    fail_unless(req != NULL, "sysdb_cache_password_send failed.");
+
+    tevent_req_set_callback(req, test_search_done, data);
+
+    ret = test_loop(data);
+    fail_unless(ret == EOK, "test_loop failed.");
+
+    ret = sysdb_cache_auth_recv(req);
+    fail_unless(ret == expected_result, "sysdb_cache_auth request does not "
+                                        "return expected result [%d].",
+                                        expected_result);
+
+    talloc_free(test_ctx);
+}
+
+START_TEST (test_sysdb_cached_authentication_missing_password)
+{
+    TALLOC_CTX *tmp_ctx;
+    char *username;
+
+    tmp_ctx = talloc_new(NULL);
+    fail_unless(tmp_ctx != NULL, "talloc_new failed.");
+
+    username = talloc_asprintf(tmp_ctx, "testuser%d", _i);
+    fail_unless(username != NULL, "talloc_asprintf failed.");
+
+    cached_authentication(username, "abc", ENOENT);
+
+    talloc_free(tmp_ctx);
+
+}
+END_TEST
+
+START_TEST (test_sysdb_cached_authentication_wrong_password)
+{
+    TALLOC_CTX *tmp_ctx;
+    char *username;
+
+    tmp_ctx = talloc_new(NULL);
+    fail_unless(tmp_ctx != NULL, "talloc_new failed.");
+
+    username = talloc_asprintf(tmp_ctx, "testuser%d", _i);
+    fail_unless(username != NULL, "talloc_asprintf failed.");
+
+    cached_authentication(username, "abc", EINVAL);
+
+    talloc_free(tmp_ctx);
+
+}
+END_TEST
+
+START_TEST (test_sysdb_cached_authentication)
+{
+    TALLOC_CTX *tmp_ctx;
+    char *username;
+
+    tmp_ctx = talloc_new(NULL);
+    fail_unless(tmp_ctx != NULL, "talloc_new failed.");
+
+    username = talloc_asprintf(tmp_ctx, "testuser%d", _i);
+    fail_unless(username != NULL, "talloc_asprintf failed.");
+
+    cached_authentication(username, username, EOK);
+
+    talloc_free(tmp_ctx);
+
+}
+END_TEST
+
 START_TEST (test_sysdb_prepare_asq_test_user)
 {
     struct sysdb_test_ctx *test_ctx;
@@ -2954,6 +3077,18 @@ Suite *create_sysdb_suite(void)
     /* Add some members to the groups */
     tcase_add_loop_test(tc_sysdb, test_sysdb_add_group_member, 28010, 28020);
 
+    /* Authenticate with missing cached password */
+    tcase_add_loop_test(tc_sysdb, 
test_sysdb_cached_authentication_missing_password,
+                        27010, 27011);
+
+    /* Add a cached password */
+    tcase_add_loop_test(tc_sysdb, test_sysdb_cache_password, 27010, 27011);
+
+    /* Authenticate against cached password */
+    tcase_add_loop_test(tc_sysdb, 
test_sysdb_cached_authentication_wrong_password,
+                        27010, 27011);
+    tcase_add_loop_test(tc_sysdb, test_sysdb_cached_authentication, 27010, 
27011);
+
     /* 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);
-- 
1.6.5.2

_______________________________________________
sssd-devel mailing list
sssd-devel@lists.fedorahosted.org
https://fedorahosted.org/mailman/listinfo/sssd-devel

Reply via email to