summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--server/Makefile.am1
-rw-r--r--server/db/sysdb.h11
-rw-r--r--server/db/sysdb_ops.c173
-rw-r--r--server/responder/pam/pam_LOCAL_domain.c31
-rw-r--r--server/responder/pam/pamsrv.h2
-rw-r--r--server/responder/pam/pamsrv_cache.c180
-rw-r--r--server/responder/pam/pamsrv_cmd.c62
-rw-r--r--server/tests/sysdb-tests.c135
8 files changed, 378 insertions, 217 deletions
diff --git a/server/Makefile.am b/server/Makefile.am
index fc521c85..989b39e6 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -343,7 +343,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 641ec680..4c255492 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 86a9d33e..36b58673 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 b98459d6..9d3738c5 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 d87e166f..60f9c66a 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 1e1c5444..00000000
--- a/server/responder/pam/pamsrv_cache.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- SSSD
-
- PAM cache credentials
-
- Copyright (C) Simo Sorce <ssorce@redhat.com> 2009
- Copyright (C) Sumit Bose <sbose@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@%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@%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 69cbf55d..ca41d641 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 ace03439..11fde6fe 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);