summaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorSumit Bose <sbose@redhat.com>2010-02-08 09:25:53 +0100
committerStephen Gallagher <sgallagh@redhat.com>2010-02-10 08:46:48 -0500
commit3a4aa5e5006decc100a2d8f2db54c46b482afd7c (patch)
tree273e3e311e04aa7b090dd51db264b130deba34af /server
parentc56dde8fd199071ef2674d287162404b4f1b545e (diff)
downloadsssd-3a4aa5e5006decc100a2d8f2db54c46b482afd7c.tar.gz
sssd-3a4aa5e5006decc100a2d8f2db54c46b482afd7c.tar.xz
sssd-3a4aa5e5006decc100a2d8f2db54c46b482afd7c.zip
Send a message to the user if the login is delayed
Diffstat (limited to 'server')
-rw-r--r--server/db/sysdb.h6
-rw-r--r--server/db/sysdb_ops.c30
-rw-r--r--server/responder/pam/pamsrv_cmd.c27
-rw-r--r--server/tests/auth-tests.c51
-rw-r--r--server/tests/sysdb-tests.c12
5 files changed, 91 insertions, 35 deletions
diff --git a/server/db/sysdb.h b/server/db/sysdb.h
index a6d9e69e4..cf97ed62d 100644
--- a/server/db/sysdb.h
+++ b/server/db/sysdb.h
@@ -548,7 +548,8 @@ int sysdb_cache_password_recv(struct tevent_req *req);
errno_t check_failed_login_attempts(TALLOC_CTX *mem_ctx, struct confdb_ctx *cdb,
struct ldb_message *ldb_msg,
- uint32_t *failed_login_attempts);
+ 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,
@@ -557,7 +558,8 @@ struct tevent_req *sysdb_cache_auth_send(TALLOC_CTX *mem_ctx,
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);
+int sysdb_cache_auth_recv(struct tevent_req *req, time_t *expire_date,
+ time_t *delayed_until);
struct tevent_req *sysdb_store_custom_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
diff --git a/server/db/sysdb_ops.c b/server/db/sysdb_ops.c
index ccb581591..33cfd91f5 100644
--- a/server/db/sysdb_ops.c
+++ b/server/db/sysdb_ops.c
@@ -4649,17 +4649,21 @@ struct sysdb_cache_auth_state {
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,
struct ldb_message *ldb_msg,
- uint32_t *failed_login_attempts)
+ uint32_t *failed_login_attempts,
+ time_t *delayed_until)
{
int ret;
int allowed_failed_login_attempts;
int failed_login_delay;
time_t last_failed_login;
+ time_t end;
+ *delayed_until = -1;
*failed_login_attempts = ldb_msg_find_attr_as_uint(ldb_msg,
SYSDB_FAILED_LOGIN_ATTEMPTS, 0);
last_failed_login = (time_t) ldb_msg_find_attr_as_int64(ldb_msg,
@@ -4687,11 +4691,17 @@ errno_t check_failed_login_attempts(TALLOC_CTX *mem_ctx, struct confdb_ctx *cdb,
if (allowed_failed_login_attempts) {
if (*failed_login_attempts >= allowed_failed_login_attempts) {
- if (failed_login_delay &&
- last_failed_login + (failed_login_delay * 60) < time(NULL)) {
- DEBUG(7, ("failed_login_delay has passed, "
- "resetting failed_login_attempts.\n"));
- *failed_login_attempts = 0;
+ if (failed_login_delay) {
+ end = last_failed_login + (failed_login_delay * 60);
+ if (end < time(NULL)) {
+ DEBUG(7, ("failed_login_delay has passed, "
+ "resetting failed_login_attempts.\n"));
+ *failed_login_attempts = 0;
+ } else {
+ DEBUG(7, ("login delayed until %lld.\n", (long long) end));
+ *delayed_until = end;
+ return EACCES;
+ }
} else {
DEBUG(4, ("Too many failed logins.\n"));
return EACCES;
@@ -4768,6 +4778,7 @@ struct tevent_req *sysdb_cache_auth_send(TALLOC_CTX *mem_ctx,
state->authentication_successful = false;
state->handle = NULL;
state->expire_date = -1;
+ state->delayed_until = -1;
subreq = sysdb_search_user_by_name_send(state, ev, sysdb, NULL, domain,
name, attrs);
@@ -4836,7 +4847,8 @@ static void sysdb_cache_auth_get_attrs_done(struct tevent_req *subreq)
}
ret = check_failed_login_attempts(state, state->cdb, ldb_msg,
- &failed_login_attempts);
+ &failed_login_attempts,
+ &state->delayed_until);
if (ret != EOK) {
goto done;
}
@@ -5034,10 +5046,12 @@ static void sysdb_cache_auth_done(struct tevent_req *subreq)
return;
}
-int sysdb_cache_auth_recv(struct tevent_req *req, time_t *expire_date) {
+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);
diff --git a/server/responder/pam/pamsrv_cmd.c b/server/responder/pam/pamsrv_cmd.c
index a4573e60d..3172a97dd 100644
--- a/server/responder/pam/pamsrv_cmd.c
+++ b/server/responder/pam/pamsrv_cmd.c
@@ -626,18 +626,22 @@ 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);
- const uint32_t resp_type = SSS_PAM_USER_INFO_OFFLINE_AUTH;
- const size_t resp_len = sizeof(uint32_t) + sizeof(long long);
+ 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);
+ ret = sysdb_cache_auth_recv(req, &expire_date, &delayed_until);
talloc_zfree(req);
switch (ret) {
case EOK:
preq->pd->pam_status = PAM_SUCCESS;
+
+ resp_type = SSS_PAM_USER_INFO_OFFLINE_AUTH;
+ resp_len = sizeof(uint32_t) + sizeof(long long);
resp = talloc_size(preq->pd, resp_len);
if (resp == NULL) {
DEBUG(1, ("talloc_size failed, cannot prepare user info.\n"));
@@ -660,6 +664,23 @@ static void pam_cache_auth_done(struct tevent_req *req)
break;
case EACCES:
preq->pd->pam_status = PAM_PERM_DENIED;
+ if (delayed_until >= 0) {
+ resp_type = SSS_PAM_USER_INFO_OFFLINE_AUTH_DELAYED;
+ resp_len = sizeof(uint32_t) + sizeof(long long);
+ resp = talloc_size(preq->pd, resp_len);
+ if (resp == NULL) {
+ DEBUG(1, ("talloc_size failed, cannot prepare user info.\n"));
+ } else {
+ memcpy(resp, &resp_type, sizeof(uint32_t));
+ dummy = (long long) delayed_until;
+ memcpy(resp+sizeof(uint32_t), &dummy, sizeof(long long));
+ ret = pam_add_response(preq->pd, SSS_PAM_USER_INFO, resp_len,
+ (const uint8_t *) resp);
+ if (ret != EOK) {
+ DEBUG(1, ("pam_add_response failed.\n"));
+ }
+ }
+ }
break;
default:
preq->pd->pam_status = PAM_SYSTEM_ERR;
diff --git a/server/tests/auth-tests.c b/server/tests/auth-tests.c
index 0cb64533c..71215bcd2 100644
--- a/server/tests/auth-tests.c
+++ b/server/tests/auth-tests.c
@@ -157,7 +157,8 @@ static void do_failed_login_test(uint32_t failed_login_attempts,
int offline_failed_login_attempts,
int offline_failed_login_delay,
int expected_result,
- int expected_counter)
+ int expected_counter,
+ time_t expected_delay)
{
struct sysdb_test_ctx *test_ctx;
int ret;
@@ -165,6 +166,7 @@ static void do_failed_login_test(uint32_t failed_login_attempts,
val[1] = NULL;
struct ldb_message *ldb_msg;
uint32_t returned_failed_login_attempts;
+ time_t delayed_until;
/* Setup */
ret = setup_sysdb_tests(&test_ctx);
@@ -193,48 +195,57 @@ static void do_failed_login_test(uint32_t failed_login_attempts,
fail_unless(ret == EOK, "ldb_msg_add_string failed");
ret = check_failed_login_attempts(test_ctx, test_ctx->confdb, ldb_msg,
- &returned_failed_login_attempts);
+ &returned_failed_login_attempts,
+ &delayed_until);
fail_unless(ret == expected_result,
"check_failed_login_attempts returned wrong error code, "
- "excected [%d], got [%d]", expected_result, ret);
+ "expected [%d], got [%d]", expected_result, ret);
+
fail_unless(returned_failed_login_attempts == expected_counter,
"check_failed_login_attempts returned wrong number of failed "
- "login attempts, excected [%d], got [%d]",
+ "login attempts, expected [%d], got [%d]",
expected_counter, failed_login_attempts);
+ fail_unless(delayed_until == expected_delay,
+ "check_failed_login_attempts wrong delay, "
+ "expected [%d], got [%d]",
+ expected_delay, delayed_until);
+
talloc_free(test_ctx);
}
START_TEST(test_failed_login_attempts)
{
+ time_t now;
/* if offline_failed_login_attempts == 0 a login is never denied */
- do_failed_login_test(0, 0, 0, 5, EOK, 0);
- do_failed_login_test(0, time(NULL), 0, 5, EOK, 0);
- do_failed_login_test(2, 0, 0, 5, EOK, 2);
- do_failed_login_test(2, time(NULL), 0, 5, EOK, 2);
+ do_failed_login_test(0, 0, 0, 5, EOK, 0, -1);
+ do_failed_login_test(0, time(NULL), 0, 5, EOK, 0, -1);
+ do_failed_login_test(2, 0, 0, 5, EOK, 2, -1);
+ do_failed_login_test(2, time(NULL), 0, 5, EOK, 2, -1);
- do_failed_login_test(0, 0, 0, 0, EOK, 0);
- do_failed_login_test(0, time(NULL), 0, 0, EOK, 0);
- do_failed_login_test(2, 0, 0, 0, EOK, 2);
- do_failed_login_test(2, time(NULL), 0, 0, EOK, 2);
+ do_failed_login_test(0, 0, 0, 0, EOK, 0, -1);
+ do_failed_login_test(0, time(NULL), 0, 0, EOK, 0, -1);
+ do_failed_login_test(2, 0, 0, 0, EOK, 2, -1);
+ do_failed_login_test(2, time(NULL), 0, 0, EOK, 2, -1);
/* if offline_failed_login_attempts != 0 and
* offline_failed_login_delay == 0 a login is denied if the number of
* failed attempts >= offline_failed_login_attempts */
- do_failed_login_test(0, 0, 2, 0, EOK, 0);
- do_failed_login_test(0, time(NULL), 2, 0, EOK, 0);
- do_failed_login_test(2, 0, 2, 0, EACCES, 2);
- do_failed_login_test(2, time(NULL), 2, 0, EACCES, 2);
+ do_failed_login_test(0, 0, 2, 0, EOK, 0, -1);
+ do_failed_login_test(0, time(NULL), 2, 0, EOK, 0, -1);
+ do_failed_login_test(2, 0, 2, 0, EACCES, 2, -1);
+ do_failed_login_test(2, time(NULL), 2, 0, EACCES, 2, -1);
/* if offline_failed_login_attempts != 0 and
* offline_failed_login_delay != 0 a login is denied only if the number of
* failed attempts >= offline_failed_login_attempts AND the last failed
* login attempt is not longer than offline_failed_login_delay ago */
- do_failed_login_test(0, 0, 2, 5, EOK, 0);
- do_failed_login_test(0, time(NULL), 2, 5, EOK, 0);
- do_failed_login_test(2, 0, 2, 5, EOK, 0);
- do_failed_login_test(2, time(NULL), 2, 5, EACCES, 2);
+ do_failed_login_test(0, 0, 2, 5, EOK, 0, -1);
+ do_failed_login_test(0, time(NULL), 2, 5, EOK, 0, -1);
+ do_failed_login_test(2, 0, 2, 5, EOK, 0, -1);
+ now = time(NULL);
+ do_failed_login_test(2, now, 2, 5, EACCES, 2, (now + 5 * 60));
}
END_TEST
diff --git a/server/tests/sysdb-tests.c b/server/tests/sysdb-tests.c
index 978764480..8b486b691 100644
--- a/server/tests/sysdb-tests.c
+++ b/server/tests/sysdb-tests.c
@@ -2287,6 +2287,7 @@ static void cached_authentication_without_expiration(const char *username,
struct tevent_req *req;
int ret;
time_t expire_date;
+ time_t delayed_until;
const char *val[2];
val[1] = NULL;
@@ -2319,7 +2320,7 @@ static void cached_authentication_without_expiration(const char *username,
ret = test_loop(data);
fail_unless(ret == EOK, "test_loop failed.");
- ret = sysdb_cache_auth_recv(req, &expire_date);
+ 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);
@@ -2327,6 +2328,9 @@ static void cached_authentication_without_expiration(const char *username,
fail_unless(expire_date == 0, "Wrong expire date, expected [%d], got [%d]",
0, expire_date);
+ fail_unless(delayed_until == -1, "Wrong delay, expected [%d], got [%d]",
+ -1, delayed_until);
+
talloc_free(test_ctx);
}
@@ -2343,6 +2347,7 @@ static void cached_authentication_with_expiration(const char *username,
val[1] = NULL;
time_t now;
time_t expected_expire_date;
+ time_t delayed_until;
/* Setup */
ret = setup_sysdb_tests(&test_ctx);
@@ -2390,7 +2395,7 @@ static void cached_authentication_with_expiration(const char *username,
ret = test_loop(data);
fail_unless(ret == EOK, "test_loop failed.");
- ret = sysdb_cache_auth_recv(req, &expire_date);
+ 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);
@@ -2399,6 +2404,9 @@ static void cached_authentication_with_expiration(const char *username,
"Wrong expire date, expected [%d], got [%d]",
expected_expire_date, expire_date);
+ fail_unless(delayed_until == -1, "Wrong delay, expected [%d], got [%d]",
+ -1, delayed_until);
+
talloc_free(test_ctx);
}