Hello,
please see attached patches. Every patch is documented in its commit
message.
Generally speaking the first 6 patches are preparation for patch #8.
Thanks,
Pavel Reichl
PS: I also attached output of my testing to make it more obvious how the
patches are supposed to work.
------------------------------------------------------------------------
# john, people, example.com
dn: uid=john,ou=people,dc=example,dc=com
pwdAccountLockedTime: 000001010000Z
# max, people, example.com
dn: uid=max,ou=people,dc=example,dc=com
# dick, people, example.com
dn: uid=dick,ou=people,dc=example,dc=com
pwdAccountLockedTime: 20140801115742Z
--------------------------------------------------------------------------
$ ssh -l john@openldap `hostname`
Connection closed by UNKNOWN
$ ssh -l max@openldap `hostname`
Last login: Fri Aug 1 15:16:21 2014 from sssd.dev.work
$ ssh -l dick@openldap `hostname`
Last login: Fri Aug 1 12:57:33 2014
>From bd6148d96eb972d55d5aacf9f3d64acac3da84dd Mon Sep 17 00:00:00 2001
From: Pavel Reichl <[email protected]>
Date: Fri, 1 Aug 2014 09:15:59 +0100
Subject: [PATCH 1/8] SDAP: split sdap_access_filter_get_access_done
As a preparation for ticket #2364 separate code for storing user bool
values into sysdb to a new function sdap_save_user_cache_bool().
---
src/providers/ldap/sdap_access.c | 67 ++++++++++++++++++++++++++++------------
1 file changed, 47 insertions(+), 20 deletions(-)
diff --git a/src/providers/ldap/sdap_access.c b/src/providers/ldap/sdap_access.c
index 89d37e52fa27b14be6bf702ebf0bc18b3fe59da6..6e612950326c42914a98b1436a9b36936cce3133 100644
--- a/src/providers/ldap/sdap_access.c
+++ b/src/providers/ldap/sdap_access.c
@@ -40,6 +40,11 @@
#include "providers/data_provider.h"
#include "providers/dp_backend.h"
+static errno_t sdap_save_user_cache_bool(struct sss_domain_info *domain,
+ const char *username,
+ const char *attr_name,
+ bool value);
+
static struct tevent_req *sdap_access_filter_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct be_ctx *be_ctx,
@@ -856,7 +861,6 @@ static void sdap_access_filter_get_access_done(struct tevent_req *subreq)
int ret, tret, dp_error;
size_t num_results;
bool found = false;
- struct sysdb_attrs *attrs;
struct sysdb_attrs **results;
struct tevent_req *req =
tevent_req_callback_data(subreq, struct tevent_req);
@@ -935,25 +939,8 @@ static void sdap_access_filter_get_access_done(struct tevent_req *subreq)
ret = ERR_ACCESS_DENIED;
}
- attrs = sysdb_new_attrs(state);
- if (attrs == NULL) {
- ret = ENOMEM;
- DEBUG(SSSDBG_CRIT_FAILURE, "Could not set up attrs\n");
- goto done;
- }
-
- tret = sysdb_attrs_add_bool(attrs, SYSDB_LDAP_ACCESS_FILTER,
- ret == EOK ? true : false);
- if (tret != EOK) {
- /* Failing to save to the cache is non-fatal.
- * Just return the result.
- */
- DEBUG(SSSDBG_CRIT_FAILURE, "Could not set up attrs\n");
- goto done;
- }
-
- tret = sysdb_set_user_attr(state->domain, state->username, attrs,
- SYSDB_MOD_REP);
+ tret = sdap_save_user_cache_bool(state->domain, state->username,
+ SYSDB_LDAP_ACCESS_FILTER, found);
if (tret != EOK) {
/* Failing to save to the cache is non-fatal.
* Just return the result.
@@ -1060,6 +1047,46 @@ static errno_t sdap_access_service(struct pam_data *pd,
return ret;
}
+static errno_t sdap_save_user_cache_bool(struct sss_domain_info *domain,
+ const char *username,
+ const char *attr_name,
+ bool value)
+{
+ errno_t ret;
+ struct sysdb_attrs *attrs;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ attrs = sysdb_new_attrs(tmp_ctx);
+ if (attrs == NULL) {
+ ret = ENOMEM;
+ DEBUG(SSSDBG_CRIT_FAILURE, "Could not set up attrs\n");
+ goto done;
+ }
+
+ ret = sysdb_attrs_add_bool(attrs, attr_name, value);
+
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Could not set up attrs\n");
+ goto done;
+ }
+
+ ret = sysdb_set_user_attr(domain, username, attrs, SYSDB_MOD_REP);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set user access attribute\n");
+ goto done;
+ }
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
static errno_t sdap_access_host(struct ldb_message *user_entry)
{
errno_t ret;
--
1.9.3
>From bce1150187d4526b2593167409852b4eee829b6e Mon Sep 17 00:00:00 2001
From: Pavel Reichl <[email protected]>
Date: Fri, 1 Aug 2014 11:00:48 +0100
Subject: [PATCH 2/8] SDAP: refactor sdap_access_filter_send
As preparation for ticket #2364 separate code for parsing user basedn
to a new function sdap_get_basedn_user_entry().
---
src/providers/ldap/sdap_access.c | 51 ++++++++++++++++++++++++++++------------
1 file changed, 36 insertions(+), 15 deletions(-)
diff --git a/src/providers/ldap/sdap_access.c b/src/providers/ldap/sdap_access.c
index 6e612950326c42914a98b1436a9b36936cce3133..894d105fadfb837482e8ef2734b5b1c227bad3fa 100644
--- a/src/providers/ldap/sdap_access.c
+++ b/src/providers/ldap/sdap_access.c
@@ -45,6 +45,11 @@ static errno_t sdap_save_user_cache_bool(struct sss_domain_info *domain,
const char *attr_name,
bool value);
+static errno_t sdap_get_basedn_user_entry(TALLOC_CTX *mem_ctx,
+ struct ldb_message *user_entry,
+ const char *username,
+ char **_basedn);
+
static struct tevent_req *sdap_access_filter_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct be_ctx *be_ctx,
@@ -666,7 +671,6 @@ static struct tevent_req *sdap_access_filter_send(TALLOC_CTX *mem_ctx,
{
struct sdap_access_filter_req_ctx *state;
struct tevent_req *req;
- const char *basedn;
char *clean_username;
errno_t ret = ERR_INTERNAL;
char *name;
@@ -704,20 +708,9 @@ static struct tevent_req *sdap_access_filter_send(TALLOC_CTX *mem_ctx,
goto done;
}
- /* Perform online operation */
- basedn = ldb_msg_find_attr_as_string(user_entry, SYSDB_ORIG_DN, NULL);
- if (basedn == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE,"Could not find originalDN for user [%s]\n",
- state->username);
- ret = EINVAL;
- goto done;
- }
-
- state->basedn = talloc_strdup(state, basedn);
- if (state->basedn == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Could not allocate memory for originalDN\n");
- ret = ENOMEM;
+ ret = sdap_get_basedn_user_entry(state, user_entry, state->username,
+ &state->basedn);
+ if (ret != EOK) {
goto done;
}
@@ -1149,3 +1142,31 @@ static errno_t sdap_access_host(struct ldb_message *user_entry)
return ret;
}
+
+static errno_t sdap_get_basedn_user_entry(TALLOC_CTX *mem_ctx,
+ struct ldb_message *user_entry,
+ const char *username,
+ char **_basedn)
+{
+ const char *basedn;
+ errno_t ret = EOK;
+
+ basedn = ldb_msg_find_attr_as_string(user_entry, SYSDB_ORIG_DN, NULL);
+ if (basedn == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE,"Could not find originalDN for user [%s]\n",
+ username);
+ ret = EINVAL;
+ goto done;
+ }
+
+ *_basedn = talloc_strdup(mem_ctx, basedn);
+ if (*_basedn == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Could not allocate memory for originalDN\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+done:
+ return ret;
+}
--
1.9.3
>From f038ef40859d7ec7a67c5d48e80eaf5729bf4fad Mon Sep 17 00:00:00 2001
From: Pavel Reichl <[email protected]>
Date: Fri, 1 Aug 2014 11:13:20 +0100
Subject: [PATCH 3/8] SDAP: nitpicks in sdap_access_filter_get_access_done
Fixed typo and replaced duplicated string by macro definition.
---
src/providers/ldap/sdap_access.c | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/src/providers/ldap/sdap_access.c b/src/providers/ldap/sdap_access.c
index 894d105fadfb837482e8ef2734b5b1c227bad3fa..c18f69d43dfa74c787fa91963ca26d97d17ad1d4 100644
--- a/src/providers/ldap/sdap_access.c
+++ b/src/providers/ldap/sdap_access.c
@@ -40,6 +40,8 @@
#include "providers/data_provider.h"
#include "providers/dp_backend.h"
+#define MALFORMED_FILTER "Malformed access control filter [%s]\n"
+
static errno_t sdap_save_user_cache_bool(struct sss_domain_info *domain,
const char *username,
const char *attr_name,
@@ -875,10 +877,8 @@ static void sdap_access_filter_get_access_done(struct tevent_req *subreq)
} else if (dp_error == DP_ERR_OFFLINE) {
ret = sdap_access_filter_decide_offline(req);
} else if (ret == ERR_INVALID_FILTER) {
- sss_log(SSS_LOG_ERR,
- "Malformed access control filter [%s]\n", state->filter);
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Malformed access control filter [%s]\n", state->filter);
+ sss_log(SSS_LOG_ERR, MALFORMED_FILTER, state->filter);
+ DEBUG(SSSDBG_CRIT_FAILURE, MALFORMED_FILTER, state->filter);
ret = ERR_ACCESS_DENIED;
} else {
DEBUG(SSSDBG_CRIT_FAILURE,
@@ -918,9 +918,7 @@ static void sdap_access_filter_get_access_done(struct tevent_req *subreq)
}
if (found) {
- /* Save "allow" to the cache for future offline
- :q* access checks.
- */
+ /* Save "allow" to the cache for future offline access checks. */
DEBUG(SSSDBG_TRACE_FUNC, "Access granted by online lookup\n");
ret = EOK;
}
--
1.9.3
>From 17a06664368ad8d3d8bda09426eb82c85e80ebd3 Mon Sep 17 00:00:00 2001
From: Pavel Reichl <[email protected]>
Date: Fri, 1 Aug 2014 12:22:21 +0100
Subject: [PATCH 4/8] SDAP: refactor sdap_access_filter_done
As preparation for ticket #2364 move code from sdap_access_filter_done()
into sdap_access_done() to make its reuse possible and thus avoid code
duplication.
Also remove sdap_access_filter_recv() as it is replaced by
sdap_access_filter_recv().
---
src/providers/ldap/sdap_access.c | 18 +++++++-----------
1 file changed, 7 insertions(+), 11 deletions(-)
diff --git a/src/providers/ldap/sdap_access.c b/src/providers/ldap/sdap_access.c
index c18f69d43dfa74c787fa91963ca26d97d17ad1d4..8c0abadae07b33fa7ff880304906b5923d79ad28 100644
--- a/src/providers/ldap/sdap_access.c
+++ b/src/providers/ldap/sdap_access.c
@@ -60,7 +60,6 @@ static struct tevent_req *sdap_access_filter_send(TALLOC_CTX *mem_ctx,
struct sdap_id_conn_ctx *conn,
const char *username,
struct ldb_message *user_entry);
-static errno_t sdap_access_filter_recv(struct tevent_req *req);
static errno_t sdap_account_expired(struct sdap_access_ctx *access_ctx,
struct pam_data *pd,
@@ -219,14 +218,14 @@ static errno_t check_next_rule(struct sdap_access_req_ctx *state,
return ret;
}
-static void sdap_access_filter_done(struct tevent_req *subreq)
+static void sdap_access_done(struct tevent_req *subreq)
{
errno_t ret;
struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
struct sdap_access_req_ctx *state =
tevent_req_data(req, struct sdap_access_req_ctx);
- ret = sdap_access_filter_recv(subreq);
+ ret = sdap_access_recv(subreq);
talloc_zfree(subreq);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "Error retrieving access check result.\n");
@@ -249,6 +248,11 @@ static void sdap_access_filter_done(struct tevent_req *subreq)
}
}
+static void sdap_access_filter_done(struct tevent_req *subreq)
+{
+ sdap_access_done(subreq);
+}
+
errno_t sdap_access_recv(struct tevent_req *req)
{
TEVENT_REQ_RETURN_ON_ERROR(req);
@@ -949,14 +953,6 @@ done:
}
}
-static errno_t sdap_access_filter_recv(struct tevent_req *req)
-{
- TEVENT_REQ_RETURN_ON_ERROR(req);
-
- return EOK;
-}
-
-
#define AUTHR_SRV_MISSING_MSG "Authorized service attribute missing, " \
"access denied"
#define AUTHR_SRV_DENY_MSG "Access denied by authorized service attribute"
--
1.9.3
>From c16de8e6810270035ce9ff6d2a0d0a90d9dc9cfe Mon Sep 17 00:00:00 2001
From: Pavel Reichl <[email protected]>
Date: Fri, 1 Aug 2014 16:05:13 +0100
Subject: [PATCH 5/8] SDAP: don't log error on access denied
Don't log error if access is denied in function sdap_access_done().
---
src/providers/ldap/sdap_access.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/providers/ldap/sdap_access.c b/src/providers/ldap/sdap_access.c
index 8c0abadae07b33fa7ff880304906b5923d79ad28..ecde3ecc8ddfa38aa9b2025e83e8ad94238d9bdc 100644
--- a/src/providers/ldap/sdap_access.c
+++ b/src/providers/ldap/sdap_access.c
@@ -228,7 +228,12 @@ static void sdap_access_done(struct tevent_req *subreq)
ret = sdap_access_recv(subreq);
talloc_zfree(subreq);
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Error retrieving access check result.\n");
+ if (ret == ERR_ACCESS_DENIED) {
+ DEBUG(SSSDBG_TRACE_FUNC, "Access was denied.\n");
+ } else {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Error retrieving access check result.\n");
+ }
tevent_req_error(req, ret);
return;
}
--
1.9.3
>From c98f84f6ddea58a7deb6f69b9b8a6cd5f7d14382 Mon Sep 17 00:00:00 2001
From: Pavel Reichl <[email protected]>
Date: Fri, 1 Aug 2014 16:13:08 +0100
Subject: [PATCH 6/8] SDAP: use versatile name for caching AC results
Use more versatile name for caching results of access control as this
may be used not just for filtering.
---
src/providers/ldap/sdap_access.c | 15 ++++++++-------
src/providers/ldap/sdap_access.h | 2 +-
2 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/src/providers/ldap/sdap_access.c b/src/providers/ldap/sdap_access.c
index ecde3ecc8ddfa38aa9b2025e83e8ad94238d9bdc..6eed59ab855693f2d5299ef14eb2f3fb743107b4 100644
--- a/src/providers/ldap/sdap_access.c
+++ b/src/providers/ldap/sdap_access.c
@@ -663,11 +663,12 @@ struct sdap_access_filter_req_ctx {
struct sdap_id_op *sdap_op;
struct sysdb_handle *handle;
struct sss_domain_info *domain;
+ /* Used for both filter and locked use-cases. */
bool cached_access;
char *basedn;
};
-static errno_t sdap_access_filter_decide_offline(struct tevent_req *req);
+static errno_t sdap_access_decide_offline(struct tevent_req *req);
static int sdap_access_filter_retry(struct tevent_req *req);
static void sdap_access_filter_connect_done(struct tevent_req *subreq);
static void sdap_access_filter_get_access_done(struct tevent_req *req);
@@ -710,12 +711,12 @@ static struct tevent_req *sdap_access_filter_send(TALLOC_CTX *mem_ctx,
"Performing access filter check for user [%s]\n", username);
state->cached_access = ldb_msg_find_attr_as_bool(user_entry,
- SYSDB_LDAP_ACCESS_FILTER,
+ SYSDB_LDAP_ACCESS_CACHED,
false);
/* Ok, we have one result, check if we are online or offline */
if (be_is_offline(be_ctx)) {
/* Ok, we're offline. Return from the cache */
- ret = sdap_access_filter_decide_offline(req);
+ ret = sdap_access_decide_offline(req);
goto done;
}
@@ -781,7 +782,7 @@ done:
return req;
}
-static errno_t sdap_access_filter_decide_offline(struct tevent_req *req)
+static errno_t sdap_access_decide_offline(struct tevent_req *req)
{
struct sdap_access_filter_req_ctx *state =
tevent_req_data(req, struct sdap_access_filter_req_ctx);
@@ -826,7 +827,7 @@ static void sdap_access_filter_connect_done(struct tevent_req *subreq)
if (ret != EOK) {
if (dp_error == DP_ERR_OFFLINE) {
- ret = sdap_access_filter_decide_offline(req);
+ ret = sdap_access_decide_offline(req);
if (ret == EOK) {
tevent_req_done(req);
return;
@@ -884,7 +885,7 @@ static void sdap_access_filter_get_access_done(struct tevent_req *subreq)
return;
}
} else if (dp_error == DP_ERR_OFFLINE) {
- ret = sdap_access_filter_decide_offline(req);
+ ret = sdap_access_decide_offline(req);
} else if (ret == ERR_INVALID_FILTER) {
sss_log(SSS_LOG_ERR, MALFORMED_FILTER, state->filter);
DEBUG(SSSDBG_CRIT_FAILURE, MALFORMED_FILTER, state->filter);
@@ -940,7 +941,7 @@ static void sdap_access_filter_get_access_done(struct tevent_req *subreq)
}
tret = sdap_save_user_cache_bool(state->domain, state->username,
- SYSDB_LDAP_ACCESS_FILTER, found);
+ SYSDB_LDAP_ACCESS_CACHED, found);
if (tret != EOK) {
/* Failing to save to the cache is non-fatal.
* Just return the result.
diff --git a/src/providers/ldap/sdap_access.h b/src/providers/ldap/sdap_access.h
index 30097e21f59abe19fc14d052edb0a6343c67f892..890ea48bd906bd2ab7efa4f0720c01058389226d 100644
--- a/src/providers/ldap/sdap_access.h
+++ b/src/providers/ldap/sdap_access.h
@@ -28,7 +28,7 @@
#include "providers/dp_backend.h"
#include "providers/ldap/ldap_common.h"
-#define SYSDB_LDAP_ACCESS_FILTER "ldap_access_filter_allow"
+#define SYSDB_LDAP_ACCESS_CACHED "ldap_access_cached"
#define LDAP_ACCESS_FILTER_NAME "filter"
#define LDAP_ACCESS_EXPIRE_NAME "expire"
--
1.9.3
>From 220e8ab33015acdbed04de306eb796ffd53ce2e0 Mon Sep 17 00:00:00 2001
From: Pavel Reichl <[email protected]>
Date: Fri, 1 Aug 2014 17:04:55 +0100
Subject: [PATCH 7/8] MAN: document new option 'lock' of ldap_access_order
Resolves:
https://fedorahosted.org/sssd/ticket/2364
---
src/man/sssd-ldap.5.xml | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
index e8bcfd0d13cb39b7e60fc8f3aa4338b53d2921e2..d9e8af544249f80a90c0ef779cca0e80bcf0aa35 100644
--- a/src/man/sssd-ldap.5.xml
+++ b/src/man/sssd-ldap.5.xml
@@ -1914,6 +1914,13 @@ ldap_access_filter = (employeeType=admin)
<emphasis>filter</emphasis>: use ldap_access_filter
</para>
<para>
+ <emphasis>lock</emphasis>: use account locking.
+ If set, this option denies access in case that ldap
+ attribute 'pwdAccountLockedTime' is present and has
+ value of '000001010000Z'.
+ </para>
+
+ <para>
<emphasis>expire</emphasis>: use
ldap_account_expire_policy
</para>
--
1.9.3
>From da565c407e616b2b5c43c301f8212bc8cdc736fd Mon Sep 17 00:00:00 2001
From: Pavel Reichl <[email protected]>
Date: Fri, 1 Aug 2014 17:44:24 +0100
Subject: [PATCH 8/8] SDAP: account lock to restrict access via ssh key
Be able to configure sssd to honor openldap account lock to restrict
access via ssh key. Introduce new ldap_access_order value ('lock')
for enabling/disabling this feature.
Resolves:
https://fedorahosted.org/sssd/ticket/2364
---
src/providers/ldap/ldap_init.c | 2 +
src/providers/ldap/sdap_access.c | 294 ++++++++++++++++++++++++++++++++++++++-
src/providers/ldap/sdap_access.h | 3 +
3 files changed, 298 insertions(+), 1 deletion(-)
diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c
index 9960fd3ab7a6e446e5cdc1e8fa4984aab812d980..85d9acef1d2dd55361cba2ae67376673fe67d021 100644
--- a/src/providers/ldap/ldap_init.c
+++ b/src/providers/ldap/ldap_init.c
@@ -421,6 +421,8 @@ int sssm_ldap_access_init(struct be_ctx *bectx,
access_ctx->access_rule[c] = LDAP_ACCESS_SERVICE;
} else if (strcasecmp(order_list[c], LDAP_ACCESS_HOST_NAME) == 0) {
access_ctx->access_rule[c] = LDAP_ACCESS_HOST;
+ } else if (strcasecmp(order_list[c], LDAP_ACCESS_LOCK_NAME) == 0) {
+ access_ctx->access_rule[c] = LDAP_ACCESS_LOCK;
} else {
DEBUG(SSSDBG_CRIT_FAILURE,
"Unexpected access rule name [%s].\n", order_list[c]);
diff --git a/src/providers/ldap/sdap_access.c b/src/providers/ldap/sdap_access.c
index 6eed59ab855693f2d5299ef14eb2f3fb743107b4..cb4b4dbd9508bc9d75d5d285009967d2bf5e3ecb 100644
--- a/src/providers/ldap/sdap_access.c
+++ b/src/providers/ldap/sdap_access.c
@@ -40,6 +40,7 @@
#include "providers/data_provider.h"
#include "providers/dp_backend.h"
+#define PERMANENTLY_LOCKED_ACCOUNT "000001010000Z"
#define MALFORMED_FILTER "Malformed access control filter [%s]\n"
static errno_t sdap_save_user_cache_bool(struct sss_domain_info *domain,
@@ -52,6 +53,18 @@ static errno_t sdap_get_basedn_user_entry(TALLOC_CTX *mem_ctx,
const char *username,
char **_basedn);
+static struct tevent_req *
+sdap_access_lock_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct be_ctx *be_ctx,
+ struct sss_domain_info *domain,
+ struct sdap_access_ctx *access_ctx,
+ struct sdap_id_conn_ctx *conn,
+ const char *username,
+ struct ldb_message *user_entry);
+
+static void sdap_access_lock_done(struct tevent_req *subreq);
+
static struct tevent_req *sdap_access_filter_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct be_ctx *be_ctx,
@@ -178,6 +191,24 @@ static errno_t check_next_rule(struct sdap_access_req_ctx *state,
/* we are done with no errors */
return EOK;
+ case LDAP_ACCESS_LOCK:
+ ret = EOK;
+
+ subreq = sdap_access_lock_send(state, state->ev, state->be_ctx,
+ state->domain,
+ state->access_ctx,
+ state->conn,
+ state->pd->user,
+ state->user_entry);
+ if (subreq == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "sdap_access_lock_send failed.\n");
+ return ENOMEM;
+ }
+
+ tevent_req_set_callback(subreq, sdap_access_lock_done, req);
+ return EAGAIN;
+ break;
+
case LDAP_ACCESS_FILTER:
subreq = sdap_access_filter_send(state, state->ev, state->be_ctx,
state->domain,
@@ -265,7 +296,6 @@ errno_t sdap_access_recv(struct tevent_req *req)
return EOK;
}
-
#define SHADOW_EXPIRE_MSG "Account expired according to shadow attributes"
static errno_t sdap_account_expired_shadow(struct pam_data *pd,
@@ -670,8 +700,10 @@ struct sdap_access_filter_req_ctx {
static errno_t sdap_access_decide_offline(struct tevent_req *req);
static int sdap_access_filter_retry(struct tevent_req *req);
+static void sdap_access_lock_connect_done(struct tevent_req *subreq);
static void sdap_access_filter_connect_done(struct tevent_req *subreq);
static void sdap_access_filter_get_access_done(struct tevent_req *req);
+
static struct tevent_req *sdap_access_filter_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct be_ctx *be_ctx,
@@ -1143,6 +1175,266 @@ static errno_t sdap_access_host(struct ldb_message *user_entry)
return ret;
}
+static void sdap_access_lock_get_access_done(struct tevent_req *subreq);
+static int sdap_access_lock_retry(struct tevent_req *req);
+static struct tevent_req *
+sdap_access_lock_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct be_ctx *be_ctx,
+ struct sss_domain_info *domain,
+ struct sdap_access_ctx *access_ctx,
+ struct sdap_id_conn_ctx *conn,
+ const char *username,
+ struct ldb_message *user_entry)
+{
+ struct sdap_access_filter_req_ctx *state;
+ struct tevent_req *req;
+ errno_t ret = ERR_INTERNAL;
+
+ req = tevent_req_create(mem_ctx,
+ &state, struct sdap_access_filter_req_ctx);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->filter = NULL;
+ state->username = username;
+ state->opts = access_ctx->id_ctx->opts;
+ state->conn = conn;
+ state->ev = ev;
+ state->access_ctx = access_ctx;
+ state->domain = domain;
+
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Performing access lock check for user [%s]\n", username);
+
+ state->cached_access = ldb_msg_find_attr_as_bool(user_entry,
+ SYSDB_LDAP_ACCESS_CACHED,
+ false);
+
+ /* Ok, we have one result, check if we are online or offline */
+ if (be_is_offline(be_ctx)) {
+ /* Ok, we're offline. Return from the cache */
+ ret = sdap_access_decide_offline(req);
+ goto done;
+ }
+
+ ret = sdap_get_basedn_user_entry(state, user_entry, state->username,
+ &state->basedn);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC, "Checking lock against LDAP\n");
+
+ state->sdap_op = sdap_id_op_create(state,
+ state->conn->conn_cache);
+ if (!state->sdap_op) {
+ DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sdap_access_lock_retry(req);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ return req;
+
+done:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static int sdap_access_lock_retry(struct tevent_req *req)
+{
+ struct sdap_access_filter_req_ctx *state;
+ struct tevent_req *subreq;
+ int ret;
+
+ state = tevent_req_data(req, struct sdap_access_filter_req_ctx);
+ subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
+ if (!subreq) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "sdap_id_op_connect_send failed: %d (%s)\n", ret, strerror(ret));
+ return ret;
+ }
+
+ tevent_req_set_callback(subreq, sdap_access_lock_connect_done, req);
+ return EOK;
+}
+
+static void sdap_access_lock_connect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req;
+ struct sdap_access_filter_req_ctx *state;
+ int ret, dp_error;
+ static const char *attrs[] = { SYSDB_LDAP_ACCESS_LOCKED_TIME, NULL };
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct sdap_access_filter_req_ctx);
+
+ ret = sdap_id_op_connect_recv(subreq, &dp_error);
+ talloc_zfree(subreq);
+
+ if (ret != EOK) {
+ if (dp_error == DP_ERR_OFFLINE) {
+ ret = sdap_access_decide_offline(req);
+ if (ret == EOK) {
+ tevent_req_done(req);
+ return;
+ }
+ }
+
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ /* Connection to LDAP succeeded
+ * Send filter request
+ */
+ subreq = sdap_get_generic_send(state,
+ state->ev,
+ state->opts,
+ sdap_id_op_handle(state->sdap_op),
+ state->basedn,
+ LDAP_SCOPE_BASE,
+ NULL, attrs,
+ NULL, 0,
+ dp_opt_get_int(state->opts->basic,
+ SDAP_SEARCH_TIMEOUT),
+ false);
+ if (subreq == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Could not start LDAP communication\n");
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ tevent_req_set_callback(subreq, sdap_access_lock_get_access_done, req);
+}
+
+static void sdap_access_lock_get_access_done(struct tevent_req *subreq)
+{
+ int ret, tret, dp_error;
+ size_t num_results;
+ bool locked = false;
+ const char *pwdAccountLockedTime;
+ struct sysdb_attrs **results;
+ struct tevent_req *req;
+ struct sdap_access_filter_req_ctx *state;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct sdap_access_filter_req_ctx);
+
+ ret = sdap_get_generic_recv(subreq, state, &num_results, &results);
+ talloc_zfree(subreq);
+
+ ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
+ if (ret != EOK) {
+ if (dp_error == DP_ERR_OK) {
+ /* retry */
+ tret = sdap_access_lock_retry(req);
+ if (tret == EOK) {
+ return;
+ }
+ } else if (dp_error == DP_ERR_OFFLINE) {
+ ret = sdap_access_decide_offline(req);
+ } else {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "sdap_get_generic_send() returned error [%d][%s]\n",
+ ret, sss_strerror(ret));
+ }
+
+ goto done;
+ }
+
+ /* Check the number of responses we got
+ * If it's exactly 1, we passed the check
+ * If it's < 1, we failed the check
+ * Anything else is an error
+ */
+ if (num_results < 1) {
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "User [%s] was not found with the specified filter. "
+ "Denying access.\n", state->username);
+ } else if (results == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "num_results > 0, but results is NULL\n");
+ ret = ERR_INTERNAL;
+ goto done;
+ } else if (num_results > 1) {
+ /* It should not be possible to get more than one reply
+ * here, since we're doing a base-scoped search
+ */
+ DEBUG(SSSDBG_CRIT_FAILURE, "Received multiple replies\n");
+ ret = ERR_INTERNAL;
+ goto done;
+ } else { /* Ok, we got a single reply */
+ ret = sysdb_attrs_get_string(results[0], SYSDB_LDAP_ACCESS_LOCKED_TIME,
+ &pwdAccountLockedTime);
+ if (ret == EOK) {
+ if (strcasecmp(pwdAccountLockedTime,
+ PERMANENTLY_LOCKED_ACCOUNT) == 0) {
+ locked = true;
+ } else {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Account of: %s is beeing blocked by password policy, "
+ "but value: [%s] value is ignored by SSSD.\n",
+ state->username, pwdAccountLockedTime);
+ }
+ } else {
+ /* Attribute SYSDB_LDAP_ACCESS_LOCKED_TIME in not be present unless
+ * user's account is blocked by password policy.
+ */
+ DEBUG(SSSDBG_TRACE_INTERNAL,
+ "Attribute %s failed to be obtained - [%d][%s].\n",
+ SYSDB_LDAP_ACCESS_LOCKED_TIME, ret, strerror(ret));
+ }
+ }
+
+ if (locked) {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Access denied by online lookup - account is locked.\n");
+ ret = ERR_ACCESS_DENIED;
+ } else {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Access granted by online lookup - account is not locked.\n");
+ ret = EOK;
+ }
+
+ /* Save '!locked' to the cache for future offline access checks.
+ * Locked == true => access denied,
+ * Locked == false => access granted
+ */
+ tret = sdap_save_user_cache_bool(state->domain, state->username,
+ SYSDB_LDAP_ACCESS_CACHED, !locked);
+
+ if (tret != EOK) {
+ /* Failing to save to the cache is non-fatal.
+ * Just return the result.
+ */
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set user locked attribute\n");
+ goto done;
+ }
+
+done:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+}
+
+static void sdap_access_lock_done(struct tevent_req *subreq)
+{
+ sdap_access_done(subreq);
+}
+
static errno_t sdap_get_basedn_user_entry(TALLOC_CTX *mem_ctx,
struct ldb_message *user_entry,
const char *username,
diff --git a/src/providers/ldap/sdap_access.h b/src/providers/ldap/sdap_access.h
index 890ea48bd906bd2ab7efa4f0720c01058389226d..9ffea9196974958ccb1be03a6f8346b6c0192436 100644
--- a/src/providers/ldap/sdap_access.h
+++ b/src/providers/ldap/sdap_access.h
@@ -29,11 +29,13 @@
#include "providers/ldap/ldap_common.h"
#define SYSDB_LDAP_ACCESS_CACHED "ldap_access_cached"
+#define SYSDB_LDAP_ACCESS_LOCKED_TIME "pwdAccountLockedTime"
#define LDAP_ACCESS_FILTER_NAME "filter"
#define LDAP_ACCESS_EXPIRE_NAME "expire"
#define LDAP_ACCESS_SERVICE_NAME "authorized_service"
#define LDAP_ACCESS_HOST_NAME "host"
+#define LDAP_ACCESS_LOCK_NAME "lock"
#define LDAP_ACCOUNT_EXPIRE_SHADOW "shadow"
#define LDAP_ACCOUNT_EXPIRE_AD "ad"
@@ -48,6 +50,7 @@ enum ldap_access_rule {
LDAP_ACCESS_EXPIRE,
LDAP_ACCESS_SERVICE,
LDAP_ACCESS_HOST,
+ LDAP_ACCESS_LOCK,
LDAP_ACCESS_LAST
};
--
1.9.3
_______________________________________________
sssd-devel mailing list
[email protected]
https://lists.fedorahosted.org/mailman/listinfo/sssd-devel