diff options
-rw-r--r-- | src/db/sysdb.h | 22 | ||||
-rw-r--r-- | src/db/sysdb_ops.c | 235 | ||||
-rw-r--r-- | src/responder/pam/pamsrv_cmd.c | 86 | ||||
-rw-r--r-- | src/tests/sysdb-tests.c | 57 |
4 files changed, 136 insertions, 264 deletions
diff --git a/src/db/sysdb.h b/src/db/sysdb.h index b39d26c99..6d8e4770d 100644 --- a/src/db/sysdb.h +++ b/src/db/sysdb.h @@ -501,20 +501,20 @@ int sysdb_cache_password(TALLOC_CTX *mem_ctx, const char *username, const char *password); -errno_t check_failed_login_attempts(TALLOC_CTX *mem_ctx, struct confdb_ctx *cdb, +errno_t check_failed_login_attempts(TALLOC_CTX *mem_ctx, + struct confdb_ctx *cdb, struct ldb_message *ldb_msg, uint32_t *failed_login_attempts, time_t *delayed_until); -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, time_t *expire_date, - time_t *delayed_until); +int sysdb_cache_auth(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *sysdb, + struct sss_domain_info *domain, + const char *name, + const uint8_t *authtok, + size_t authtok_size, + struct confdb_ctx *cdb, + time_t *_expire_date, + time_t *_delayed_until); int sysdb_store_custom(TALLOC_CTX *mem_ctx, struct sysdb_ctx *ctx, diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c index 19427d443..137ca8c09 100644 --- a/src/db/sysdb_ops.c +++ b/src/db/sysdb_ops.c @@ -1970,22 +1970,9 @@ fail: /* ========= 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; - struct sysdb_attrs *update_attrs; - bool authentication_successful; - struct sysdb_handle *handle; - time_t expire_date; - time_t delayed_until; -}; -errno_t check_failed_login_attempts(TALLOC_CTX *mem_ctx, struct confdb_ctx *cdb, +errno_t check_failed_login_attempts(TALLOC_CTX *mem_ctx, + struct confdb_ctx *cdb, struct ldb_message *ldb_msg, uint32_t *failed_login_attempts, time_t *delayed_until) @@ -2045,21 +2032,17 @@ errno_t check_failed_login_attempts(TALLOC_CTX *mem_ctx, struct confdb_ctx *cdb, return EOK; } -static void sysdb_cache_auth_transaction_start_done(struct tevent_req *subreq); -static void sysdb_cache_auth_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) +int sysdb_cache_auth(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *sysdb, + struct sss_domain_info *domain, + const char *name, + const uint8_t *authtok, + size_t authtok_size, + struct confdb_ctx *cdb, + time_t *_expire_date, + time_t *_delayed_until) { - struct tevent_req *req; - struct tevent_req *subreq; - struct sysdb_cache_auth_state *state; + TALLOC_CTX *tmpctx; const char *attrs[] = { SYSDB_NAME, SYSDB_CACHEDPWD, SYSDB_DISABLED, SYSDB_LAST_LOGIN, SYSDB_LAST_ONLINE_AUTH, "lastCachedPasswordChange", @@ -2072,53 +2055,47 @@ struct tevent_req *sysdb_cache_auth_send(TALLOC_CTX *mem_ctx, uint64_t lastLogin = 0; int cred_expiration; uint32_t failed_login_attempts = 0; + struct sysdb_attrs *update_attrs; + bool authentication_successful = false; + time_t expire_date = -1; + time_t delayed_until = -1; int ret; int i; - req = tevent_req_create(mem_ctx, &state, struct sysdb_cache_auth_state); - if (req == NULL) { - DEBUG(1, ("tevent_req_create failed.\n")); - return NULL; - } - if (name == NULL || *name == '\0') { DEBUG(1, ("Missing user name.\n")); - ret = EINVAL; - goto done; + return EINVAL; } if (cdb == NULL) { DEBUG(1, ("Missing config db context.\n")); - ret = EINVAL; - goto done; + return EINVAL; } if (sysdb == NULL) { DEBUG(1, ("Missing sysdb db context.\n")); - ret = EINVAL; - goto done; + return EINVAL; } if (!domain->cache_credentials) { DEBUG(3, ("Cached credentials not available.\n")); - ret = EINVAL; - goto done; + return EINVAL; } - state->ev = ev; - state->name = name; - state->authtok = authtok; - state->authtok_size = authtok_size; - state->domain = domain; - state->sysdb = sysdb; - state->cdb = cdb; - state->update_attrs = NULL; - state->authentication_successful = false; - state->handle = NULL; - state->expire_date = -1; - state->delayed_until = -1; + tmpctx = talloc_new(mem_ctx); + if (!tmpctx) { + return ENOMEM; + } - ret = sysdb_search_user_by_name(state, sysdb, domain, name, attrs, &ldb_msg); + ret = ldb_transaction_start(sysdb->ldb); + if (ret) { + talloc_zfree(tmpctx); + ret = sysdb_error_to_errno(ret); + return ret; + } + + ret = sysdb_search_user_by_name(tmpctx, sysdb, + domain, name, attrs, &ldb_msg); if (ret != EOK) { DEBUG(1, ("sysdb_search_user_by_name failed [%d][%s].\n", ret, strerror(ret))); @@ -2130,7 +2107,7 @@ struct tevent_req *sysdb_cache_auth_send(TALLOC_CTX *mem_ctx, SYSDB_LAST_ONLINE_AUTH, 0); - ret = confdb_get_int(state->cdb, state, CONFDB_PAM_CONF_ENTRY, + ret = confdb_get_int(cdb, tmpctx, 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")); @@ -2140,20 +2117,20 @@ struct tevent_req *sysdb_cache_auth_send(TALLOC_CTX *mem_ctx, cred_expiration)); if (cred_expiration) { - state->expire_date = lastLogin + (cred_expiration * 86400); - if (state->expire_date < time(NULL)) { + expire_date = lastLogin + (cred_expiration * 86400); + if (expire_date < time(NULL)) { DEBUG(4, ("Cached user entry is too old.\n")); - state->expire_date = 0; + expire_date = 0; ret = EACCES; goto done; } } else { - state->expire_date = 0; + expire_date = 0; } - ret = check_failed_login_attempts(state, state->cdb, ldb_msg, + ret = check_failed_login_attempts(tmpctx, cdb, ldb_msg, &failed_login_attempts, - &state->delayed_until); + &delayed_until); if (ret != EOK) { DEBUG(1, ("Failed to check login attempts\n")); goto done; @@ -2161,8 +2138,7 @@ struct tevent_req *sysdb_cache_auth_send(TALLOC_CTX *mem_ctx, /* TODO: verify user account (disabled, expired ...) */ - password = talloc_strndup(state, (const char *) state->authtok, - state->authtok_size); + password = talloc_strndup(tmpctx, (const char *)authtok, authtok_size); if (password == NULL) { DEBUG(1, ("talloc_strndup failed.\n")); ret = ENOMEM; @@ -2176,15 +2152,15 @@ struct tevent_req *sysdb_cache_auth_send(TALLOC_CTX *mem_ctx, goto done; } - ret = s3crypt_sha512(state, password, userhash, &comphash); + ret = s3crypt_sha512(tmpctx, password, userhash, &comphash); if (ret) { DEBUG(4, ("Failed to create password hash.\n")); ret = EFAULT; goto done; } - state->update_attrs = sysdb_new_attrs(state); - if (state->update_attrs == NULL) { + update_attrs = sysdb_new_attrs(tmpctx); + if (update_attrs == NULL) { DEBUG(1, ("sysdb_new_attrs failed.\n")); ret = ENOMEM; goto done; @@ -2193,10 +2169,10 @@ struct tevent_req *sysdb_cache_auth_send(TALLOC_CTX *mem_ctx, if (strcmp(userhash, comphash) == 0) { /* TODO: probable good point for audit logging */ DEBUG(4, ("Hashes do match!\n")); - state->authentication_successful = true; + authentication_successful = true; - ret = sysdb_attrs_add_time_t(state->update_attrs, SYSDB_LAST_LOGIN, - time(NULL)); + ret = sysdb_attrs_add_time_t(update_attrs, + SYSDB_LAST_LOGIN, time(NULL)); if (ret != EOK) { DEBUG(3, ("sysdb_attrs_add_time_t failed, " "but authentication is successful.\n")); @@ -2204,7 +2180,7 @@ struct tevent_req *sysdb_cache_auth_send(TALLOC_CTX *mem_ctx, goto done; } - ret = sysdb_attrs_add_uint32(state->update_attrs, + ret = sysdb_attrs_add_uint32(update_attrs, SYSDB_FAILED_LOGIN_ATTEMPTS, 0U); if (ret != EOK) { DEBUG(3, ("sysdb_attrs_add_uint32 failed, " @@ -2216,9 +2192,9 @@ struct tevent_req *sysdb_cache_auth_send(TALLOC_CTX *mem_ctx, } else { DEBUG(4, ("Authentication failed.\n")); - state->authentication_successful = false; + authentication_successful = false; - ret = sysdb_attrs_add_time_t(state->update_attrs, + ret = sysdb_attrs_add_time_t(update_attrs, SYSDB_LAST_FAILED_LOGIN, time(NULL)); if (ret != EOK) { @@ -2226,7 +2202,7 @@ struct tevent_req *sysdb_cache_auth_send(TALLOC_CTX *mem_ctx, goto done; } - ret = sysdb_attrs_add_uint32(state->update_attrs, + ret = sysdb_attrs_add_uint32(update_attrs, SYSDB_FAILED_LOGIN_ATTEMPTS, ++failed_login_attempts); if (ret != EOK) { @@ -2235,106 +2211,31 @@ struct tevent_req *sysdb_cache_auth_send(TALLOC_CTX *mem_ctx, } } - subreq = sysdb_transaction_send(state, state->ev, state->sysdb); - if (subreq == NULL) { - DEBUG(1, ("sysdb_transaction_send failed.\n")); - goto done; + ret = sysdb_set_user_attr(tmpctx, sysdb, + domain, name, update_attrs, + LDB_FLAG_MOD_REPLACE); + if (ret) { + DEBUG(1, ("Failed to update Login attempt information!\n")); } - tevent_req_set_callback(subreq, - sysdb_cache_auth_transaction_start_done, req); - - return req; done: + *_expire_date = expire_date; + *_delayed_until = delayed_until; if (password) for (i = 0; password[i]; i++) password[i] = 0; if (ret) { - tevent_req_error(req, ret); + ldb_transaction_cancel(sysdb->ldb); } else { - tevent_req_done(req); - } - tevent_req_post(req, ev); - return req; -} - -static void sysdb_cache_auth_transaction_start_done(struct tevent_req *subreq) -{ - int ret; - 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_transaction_recv(subreq, state, &state->handle); - talloc_zfree(subreq); - if (ret != EOK) { - DEBUG(1, ("sysdb_transaction_send failed [%d][%s].\n", - ret, strerror(ret))); - goto done; - } - - - ret = sysdb_set_user_attr(state, state->handle->ctx, - state->domain, state->name, - state->update_attrs, - LDB_FLAG_MOD_REPLACE); - if (ret) { - DEBUG(1, ("sysdb_set_user_attr request failed [%d][%s].\n", - ret, strerror(ret))); - if (!state->authentication_successful) { - goto done; + ret = ldb_transaction_commit(sysdb->ldb); + if (ret) { + DEBUG(2, ("Failed to commit transaction!\n")); } } - - subreq = sysdb_transaction_commit_send(state, state->ev, state->handle); - if (subreq == NULL) { - DEBUG(1, ("sysdb_transaction_commit_send failed.\n")); - goto done; - } - tevent_req_set_callback(subreq, sysdb_cache_auth_done, req); - return; - -done: - if (state->authentication_successful) { - tevent_req_done(req); - } else { - tevent_req_error(req, EINVAL); - } - return; -} - -static void sysdb_cache_auth_done(struct tevent_req *subreq) -{ - int ret; - 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_transaction_commit_recv(subreq); - talloc_zfree(subreq); - if (ret != EOK) { - DEBUG(1, ("sysdb_transaction_commit_send failed [%d][%s].\n", - ret, strerror(ret))); - } - - if (state->authentication_successful) { - tevent_req_done(req); + if (authentication_successful) { + ret = EOK; } else { - tevent_req_error(req, EINVAL); + if (ret == EOK) { + ret = EINVAL; + } } - return; -} - -int sysdb_cache_auth_recv(struct tevent_req *req, time_t *expire_date, - time_t *delayed_until) { - struct sysdb_cache_auth_state *state = tevent_req_data(req, - struct sysdb_cache_auth_state); - *expire_date = state->expire_date; - *delayed_until = state->delayed_until; - - TEVENT_REQ_RETURN_ON_ERROR(req); - - return (state->authentication_successful ? EOK : EINVAL); + return ret; } diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index 168efb84d..77f29ec8c 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -453,7 +453,8 @@ 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_cache_auth_done(struct pam_auth_req *preq, int ret, + time_t expire_date, time_t delayed_until); static void pam_reply(struct pam_auth_req *preq) { @@ -468,10 +469,11 @@ 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; uint32_t user_info_type; + time_t exp_date = -1; + time_t delay_until = -1; pd = preq->pd; cctx = preq->cctx; @@ -480,10 +482,10 @@ static void pam_reply(struct pam_auth_req *preq) if (pd->pam_status == PAM_AUTHINFO_UNAVAIL) { switch(pd->cmd) { - case SSS_PAM_AUTHENTICATE: - if ((preq->domain != NULL) && - (preq->domain->cache_credentials == true) && - (pd->offline_auth == false)) { + case SSS_PAM_AUTHENTICATE: + if ((preq->domain != NULL) && + (preq->domain->cache_credentials == true) && + (pd->offline_auth == false)) { /* do auth with offline credentials */ pd->offline_auth = true; @@ -499,40 +501,37 @@ static void pam_reply(struct pam_auth_req *preq) 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.\n")); - /* this error is not fatal, continue */ - } else { - tevent_req_set_callback(req, pam_cache_auth_done, preq); - return; - } - } - break; - case SSS_PAM_CHAUTHTOK_PRELIM: - case SSS_PAM_CHAUTHTOK: - DEBUG(5, ("Password change not possible while offline.\n")); - pd->pam_status = PAM_AUTHTOK_ERR; - user_info_type = SSS_PAM_USER_INFO_OFFLINE_CHPASS; - pam_add_response(pd, SSS_PAM_USER_INFO, sizeof(uint32_t), - (const uint8_t *) &user_info_type); - break; + ret = sysdb_cache_auth(preq, sysdb, + preq->domain, pd->user, + pd->authtok, pd->authtok_size, + pctx->rctx->cdb, + &exp_date, &delay_until); + + pam_cache_auth_done(preq, ret, exp_date, delay_until); + return; + } + break; + case SSS_PAM_CHAUTHTOK_PRELIM: + case SSS_PAM_CHAUTHTOK: + DEBUG(5, ("Password change not possible while offline.\n")); + pd->pam_status = PAM_AUTHTOK_ERR; + user_info_type = SSS_PAM_USER_INFO_OFFLINE_CHPASS; + pam_add_response(pd, SSS_PAM_USER_INFO, sizeof(uint32_t), + (const uint8_t *) &user_info_type); + break; /* TODO: we need the pam session cookie here to make sure that cached * authentication was successful */ - case SSS_PAM_SETCRED: - case SSS_PAM_ACCT_MGMT: - case SSS_PAM_OPEN_SESSION: - case SSS_PAM_CLOSE_SESSION: - DEBUG(2, ("Assuming offline authentication setting status for " - "pam call %d to PAM_SUCCESS.\n", pd->cmd)); - pd->pam_status = PAM_SUCCESS; - break; - default: - DEBUG(1, ("Unknown PAM call [%d].\n", pd->cmd)); - pd->pam_status = PAM_MODULE_UNKNOWN; + case SSS_PAM_SETCRED: + case SSS_PAM_ACCT_MGMT: + case SSS_PAM_OPEN_SESSION: + case SSS_PAM_CLOSE_SESSION: + DEBUG(2, ("Assuming offline authentication setting status for " + "pam call %d to PAM_SUCCESS.\n", pd->cmd)); + pd->pam_status = PAM_SUCCESS; + break; + default: + DEBUG(1, ("Unknown PAM call [%d].\n", pd->cmd)); + pd->pam_status = PAM_MODULE_UNKNOWN; } } @@ -625,21 +624,14 @@ done: sss_cmd_done(cctx, preq); } -static void pam_cache_auth_done(struct tevent_req *req) +static void pam_cache_auth_done(struct pam_auth_req *preq, int ret, + time_t expire_date, time_t delayed_until) { - int ret; - struct pam_auth_req *preq = tevent_req_callback_data(req, - struct pam_auth_req); uint32_t resp_type; size_t resp_len; uint8_t *resp; - time_t expire_date = 0; - time_t delayed_until = -1; long long dummy; - ret = sysdb_cache_auth_recv(req, &expire_date, &delayed_until); - talloc_zfree(req); - switch (ret) { case EOK: preq->pd->pam_status = PAM_SUCCESS; diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c index 9b935d13a..c2219ca48 100644 --- a/src/tests/sysdb-tests.c +++ b/src/tests/sysdb-tests.c @@ -1950,10 +1950,9 @@ static void cached_authentication_without_expiration(const char *username, { struct sysdb_test_ctx *test_ctx; struct test_data *data; - struct tevent_req *req; int ret; - time_t expire_date; - time_t delayed_until; + time_t expire_date = -1; + time_t delayed_until = -1; const char *val[2]; val[1] = NULL; @@ -1975,18 +1974,11 @@ static void cached_authentication_without_expiration(const char *username, return; } - 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(data, test_ctx->sysdb, + test_ctx->domain, data->username, + (const uint8_t *)password, strlen(password), + test_ctx->confdb, &expire_date, &delayed_until); - ret = sysdb_cache_auth_recv(req, &expire_date, &delayed_until); fail_unless(ret == expected_result, "sysdb_cache_auth request does not " "return expected result [%d].", expected_result); @@ -2006,14 +1998,13 @@ static void cached_authentication_with_expiration(const char *username, { struct sysdb_test_ctx *test_ctx; struct test_data *data; - struct tevent_req *req; int ret; - time_t expire_date; + time_t expire_date = -1; const char *val[2]; val[1] = NULL; time_t now; time_t expected_expire_date; - time_t delayed_until; + time_t delayed_until = -1; /* Setup */ ret = setup_sysdb_tests(&test_ctx); @@ -2040,31 +2031,19 @@ static void cached_authentication_with_expiration(const char *username, data->attrs = sysdb_new_attrs(data); ret = sysdb_attrs_add_time_t(data->attrs, SYSDB_LAST_ONLINE_AUTH, now); - req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb); - fail_unless(req != NULL, "sysdb_transaction_send failed."); - - tevent_req_set_callback(req, test_set_user_attr, data); - - ret = test_loop(data); + ret = sysdb_set_user_attr(data, data->ctx->sysdb, + data->ctx->domain, data->username, + data->attrs, SYSDB_MOD_REP); fail_unless(ret == EOK, "Could not modify user %s", data->username); - talloc_zfree(req); - data->finished = false; - 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."); + ret = sysdb_cache_auth(data, test_ctx->sysdb, + test_ctx->domain, data->username, + (const uint8_t *) password, strlen(password), + test_ctx->confdb, &expire_date, &delayed_until); - 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, &expire_date, &delayed_until); - fail_unless(ret == expected_result, "sysdb_cache_auth request does not " - "return expected result [%d], got [%d].", - expected_result, ret); + fail_unless(ret == expected_result, + "sysdb_cache_auth request does not return expected " + "result [%d], got [%d].", expected_result, ret); fail_unless(expire_date == expected_expire_date, "Wrong expire date, expected [%d], got [%d]", |