summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/providers/ldap/ldap_init.c2
-rw-r--r--src/providers/ldap/sdap_access.c557
-rw-r--r--src/providers/ldap/sdap_access.h9
3 files changed, 568 insertions, 0 deletions
diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c
index 9960fd3ab..44333a9a3 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_LOCKOUT;
} 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 fa05a452d..3b2d3970c 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,
@@ -51,6 +52,16 @@ static errno_t sdap_get_basedn_user_entry(struct ldb_message *user_entry,
const char *username,
const 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 struct tevent_req *sdap_access_filter_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct be_ctx *be_ctx,
@@ -62,6 +73,8 @@ static struct tevent_req *sdap_access_filter_send(TALLOC_CTX *mem_ctx,
static errno_t sdap_access_filter_recv(struct tevent_req *req);
+static errno_t sdap_access_lock_recv(struct tevent_req *req);
+
static errno_t sdap_account_expired(struct sdap_access_ctx *access_ctx,
struct pam_data *pd,
struct ldb_message *user_entry);
@@ -73,6 +86,7 @@ static errno_t sdap_access_host(struct ldb_message *user_entry);
enum sdap_access_control_type {
SDAP_ACCESS_CONTROL_FILTER,
+ SDAP_ACCESS_CONTROL_PPOLICY_LOCK,
};
struct sdap_access_req_ctx {
@@ -184,6 +198,23 @@ static errno_t sdap_access_check_next_rule(struct sdap_access_req_ctx *state,
/* we are done with no errors */
return EOK;
+ case LDAP_ACCESS_LOCKOUT:
+ 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;
+ }
+
+ state->ac_type = SDAP_ACCESS_CONTROL_PPOLICY_LOCK;
+
+ tevent_req_set_callback(subreq, sdap_access_done, req);
+ return EAGAIN;
+
case LDAP_ACCESS_FILTER:
subreq = sdap_access_filter_send(state, state->ev, state->be_ctx,
state->domain,
@@ -240,6 +271,9 @@ static void sdap_access_done(struct tevent_req *subreq)
case SDAP_ACCESS_CONTROL_FILTER:
ret = sdap_access_filter_recv(subreq);
break;
+ case SDAP_ACCESS_CONTROL_PPOLICY_LOCK:
+ ret = sdap_access_lock_recv(subreq);
+ break;
default:
ret = EINVAL;
DEBUG(SSSDBG_MINOR_FAILURE, "Unknown access control type: %d.",
@@ -685,6 +719,8 @@ struct sdap_access_filter_req_ctx {
static errno_t sdap_access_decide_offline(bool cached_ac);
static int sdap_access_filter_retry(struct tevent_req *req);
+static void sdap_access_lock_connect_done(struct tevent_req *subreq);
+static errno_t sdap_access_lock_get_lockout_step(struct tevent_req *req);
static void sdap_access_filter_connect_done(struct tevent_req *subreq);
static void sdap_access_filter_done(struct tevent_req *req);
static struct tevent_req *sdap_access_filter_send(TALLOC_CTX *mem_ctx,
@@ -1159,6 +1195,527 @@ static errno_t sdap_access_host(struct ldb_message *user_entry)
return ret;
}
+static void sdap_access_lock_get_lockout_done(struct tevent_req *subreq);
+static int sdap_access_lock_retry(struct tevent_req *req);
+static errno_t sdap_access_lock_step(struct tevent_req *req);
+static void sdap_access_lock_step_done(struct tevent_req *subreq);
+
+struct sdap_access_lock_req_ctx {
+ const char *username;
+ const char *filter;
+ struct tevent_context *ev;
+ struct sdap_access_ctx *access_ctx;
+ struct sdap_options *opts;
+ struct sdap_id_conn_ctx *conn;
+ struct sdap_id_op *sdap_op;
+ struct sysdb_handle *handle;
+ struct sss_domain_info *domain;
+ /* cached results of access control checks */
+ bool cached_access;
+ const char *basedn;
+ /* default DNs to ppolicy */
+ const char **ppolicy_dns;
+ unsigned int ppolicy_dns_index;
+};
+
+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_lock_req_ctx *state;
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx,
+ &state, struct sdap_access_lock_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;
+ state->ppolicy_dns_index = 0;
+
+ 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_LOCKOUT, 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(state->cached_access);
+ goto done;
+ }
+
+ ret = sdap_get_basedn_user_entry(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_lock_req_ctx *state;
+ struct tevent_req *subreq;
+ int ret;
+
+ state = tevent_req_data(req, struct sdap_access_lock_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 const char**
+get_default_ppolicy_dns(TALLOC_CTX *mem_ctx, struct sdap_domain *sdom)
+{
+ const char **ppolicy_dns;
+ int count = 0;
+ int i;
+
+ while(sdom->search_bases[count] != NULL) {
+ count++;
+ }
+
+ /* +1 to have space for final NULL */
+ ppolicy_dns = talloc_array(mem_ctx, const char*, count + 1);
+
+ for(i = 0; i < count; i++) {
+ ppolicy_dns[i] = talloc_asprintf(mem_ctx, "cn=ppolicy,ou=policies,%s",
+ sdom->search_bases[i]->basedn);
+ }
+
+ ppolicy_dns[count] = NULL;
+ return ppolicy_dns;
+}
+
+static void sdap_access_lock_connect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req;
+ struct sdap_access_lock_req_ctx *state;
+ int ret, dp_error;
+ const char *ppolicy_dn;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct sdap_access_lock_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(state->cached_access);
+ if (ret == EOK) {
+ tevent_req_done(req);
+ return;
+ }
+ }
+
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ ppolicy_dn = dp_opt_get_string(state->opts->basic,
+ SDAP_PWDLOCKOUT_DN);
+
+ /* option was configured */
+ if (ppolicy_dn != NULL) {
+ state->ppolicy_dns = talloc_array(state, const char*, 2);
+ if (state->ppolicy_dns == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Could not allocate ppolicy_dns.\n");
+ tevent_req_error(req, ERR_ACCESS_DENIED);
+ return;
+ }
+
+ state->ppolicy_dns[0] = ppolicy_dn;
+ state->ppolicy_dns[1] = NULL;
+
+ } else {
+ /* try to determine default value */
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "ldap_pwdlockout_dn was not defined in configuration file.\n");
+
+ state->ppolicy_dns = get_default_ppolicy_dns(state, state->opts->sdom);
+ if (state->ppolicy_dns == NULL) {
+ tevent_req_error(req, ERR_ACCESS_DENIED);
+ return;
+ }
+ }
+
+ /* Connection to LDAP succeeded
+ * Send 'pwdLockout' request
+ */
+ ret = sdap_access_lock_get_lockout_step(req);
+ if (ret != EOK && ret != EAGAIN) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "sdap_access_lock_get_lockout_step failed: [%d][%s]\n",
+ ret, strerror(ret));
+ tevent_req_error(req, ERR_ACCESS_DENIED);
+ return;
+ }
+}
+
+static errno_t
+sdap_access_lock_get_lockout_step(struct tevent_req *req)
+{
+ const char *attrs[] = { SYSDB_LDAP_ACCESS_LOCKOUT, NULL };
+ struct sdap_access_lock_req_ctx *state;
+ struct tevent_req *subreq;
+ errno_t ret;
+
+ state = tevent_req_data(req, struct sdap_access_lock_req_ctx);
+
+ /* no more DNs to try */
+ if (state->ppolicy_dns[state->ppolicy_dns_index] == NULL) {
+ ret = EOK;
+ goto done;
+ }
+
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "Trying to find out if ppolicy is enabled using the DN: %s\n",
+ state->ppolicy_dns[state->ppolicy_dns_index]);
+
+ subreq = sdap_get_generic_send(state,
+ state->ev,
+ state->opts,
+ sdap_id_op_handle(state->sdap_op),
+ state->ppolicy_dns[state->ppolicy_dns_index],
+ 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);
+ ret = EIO;
+ goto done;
+ }
+
+ /* try next basedn */
+ state->ppolicy_dns_index++;
+ tevent_req_set_callback(subreq, sdap_access_lock_get_lockout_done, req);
+
+ ret = EAGAIN;
+
+done:
+ return ret;
+}
+
+static void sdap_access_lock_get_lockout_done(struct tevent_req *subreq)
+{
+ int ret, tret, dp_error;
+ size_t num_results;
+ bool pwdLockout = false;
+ struct sysdb_attrs **results;
+ struct tevent_req *req;
+ struct sdap_access_lock_req_ctx *state;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct sdap_access_lock_req_ctx);
+
+ ret = sdap_get_generic_recv(subreq, state, &num_results, &results);
+ talloc_zfree(subreq);
+
+ /* 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
+ */
+ /* Didn't find ppolicy attribute */
+ if (num_results < 1) {
+ /* Try using next $search_base */
+ ret = sdap_access_lock_get_lockout_step(req);
+ if (ret == EOK) {
+ /* No more search bases to try */
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "[%s] was not found. Granting access.\n",
+ SYSDB_LDAP_ACCESS_LOCKOUT);
+ } else {
+ if (ret != EAGAIN) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "sdap_access_lock_get_lockout_step failed: [%d][%s]\n",
+ ret, strerror(ret));
+ }
+ goto done;
+ }
+ } 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_bool(results[0], SYSDB_LDAP_ACCESS_LOCKOUT,
+ &pwdLockout);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Error reading %s: [%s]\n", SYSDB_LDAP_ACCESS_LOCKOUT,
+ strerror(ret));
+ ret = ERR_INTERNAL;
+ goto done;
+ }
+ }
+
+ if (pwdLockout) {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Password policy is enabled on LDAP server.\n");
+
+ /* ppolicy is enabled => find out if account is locked */
+ ret = sdap_access_lock_step(req);
+ if (ret != EOK && ret != EAGAIN) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "sdap_access_lock_step failed: [%d][%s].\n",
+ ret, strerror(ret));
+ }
+ goto done;
+ } else {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Password policy is disabled on LDAP server "
+ "- storing 'access granted' in sysdb.\n");
+ tret = sdap_save_user_cache_bool(state->domain, state->username,
+ SYSDB_LDAP_ACCESS_CACHED_LOCKOUT,
+ true);
+ 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;
+ }
+
+ ret = EOK;
+ goto done;
+ }
+
+done:
+ if (ret != EAGAIN) {
+ /* release connection */
+ tret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
+ if (tret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "sdap_get_generic_send() returned error [%d][%s]\n",
+ ret, sss_strerror(ret));
+ }
+
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+ }
+}
+
+errno_t sdap_access_lock_step(struct tevent_req *req)
+{
+ errno_t ret;
+ struct tevent_req *subreq;
+ struct sdap_access_lock_req_ctx *state;
+ const char *attrs[] = { SYSDB_LDAP_ACCESS_LOCKED_TIME, NULL };
+
+ state = tevent_req_data(req, struct sdap_access_lock_req_ctx);
+
+ 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, "sdap_access_lock_send failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ tevent_req_set_callback(subreq, sdap_access_lock_step_done, req);
+ ret = EAGAIN;
+
+done:
+ return ret;
+}
+
+static void sdap_access_lock_step_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_lock_req_ctx *state;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct sdap_access_lock_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(state->cached_access);
+ } 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) {
+ /* We do *not* care about exact value of account locked time, we
+ * only *do* care if the value is equal to
+ * PERMANENTLY_LOCKED_ACCOUNT, which means that account is locked
+ * permanently.
+ */
+ 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_LOCKOUT,
+ !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 errno_t sdap_access_lock_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ return EOK;
+}
+
static errno_t sdap_get_basedn_user_entry(struct ldb_message *user_entry,
const char *username,
const char **_basedn)
diff --git a/src/providers/ldap/sdap_access.h b/src/providers/ldap/sdap_access.h
index 30097e21f..f085e6199 100644
--- a/src/providers/ldap/sdap_access.h
+++ b/src/providers/ldap/sdap_access.h
@@ -28,12 +28,20 @@
#include "providers/dp_backend.h"
#include "providers/ldap/ldap_common.h"
+/* Attributes in sysdb, used for caching last values of lockout or filter
+ * access control checks.
+ */
#define SYSDB_LDAP_ACCESS_FILTER "ldap_access_filter_allow"
+#define SYSDB_LDAP_ACCESS_CACHED_LOCKOUT "ldap_access_lockout_allow"
+/* names of ppolicy attributes */
+#define SYSDB_LDAP_ACCESS_LOCKED_TIME "pwdAccountLockedTime"
+#define SYSDB_LDAP_ACCESS_LOCKOUT "pwdLockout"
#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 "lockout"
#define LDAP_ACCOUNT_EXPIRE_SHADOW "shadow"
#define LDAP_ACCOUNT_EXPIRE_AD "ad"
@@ -48,6 +56,7 @@ enum ldap_access_rule {
LDAP_ACCESS_EXPIRE,
LDAP_ACCESS_SERVICE,
LDAP_ACCESS_HOST,
+ LDAP_ACCESS_LOCKOUT,
LDAP_ACCESS_LAST
};