diff options
-rw-r--r-- | server/Makefile.am | 1 | ||||
-rw-r--r-- | server/db/sysdb.h | 11 | ||||
-rw-r--r-- | server/db/sysdb_ops.c | 173 | ||||
-rw-r--r-- | server/responder/pam/pam_LOCAL_domain.c | 31 | ||||
-rw-r--r-- | server/responder/pam/pamsrv.h | 2 | ||||
-rw-r--r-- | server/responder/pam/pamsrv_cache.c | 180 | ||||
-rw-r--r-- | server/responder/pam/pamsrv_cmd.c | 62 | ||||
-rw-r--r-- | server/tests/sysdb-tests.c | 135 |
8 files changed, 378 insertions, 217 deletions
diff --git a/server/Makefile.am b/server/Makefile.am index fc521c852..989b39e6c 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 641ec6803..4c2554927 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 86a9d33e8..36b586733 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 b98459d69..9d3738c53 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 d87e166f3..60f9c66ae 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 1e1c54443..000000000 --- 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 69cbf55d8..ca41d6419 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 ace034390..11fde6fe2 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); |