diff options
-rw-r--r-- | daemons/configure.ac | 1 | ||||
-rw-r--r-- | daemons/ipa-slapi-plugins/Makefile.am | 1 | ||||
-rw-r--r-- | daemons/ipa-slapi-plugins/ipa-lockout/Makefile.am | 46 | ||||
-rw-r--r-- | daemons/ipa-slapi-plugins/ipa-lockout/ipa_lockout.c | 643 | ||||
-rw-r--r-- | daemons/ipa-slapi-plugins/ipa-lockout/lockout-conf.ldif | 15 | ||||
-rw-r--r-- | ipa.spec.in | 2 | ||||
-rw-r--r-- | ipaserver/install/dsinstance.py | 4 |
7 files changed, 712 insertions, 0 deletions
diff --git a/daemons/configure.ac b/daemons/configure.ac index c024c12cf..d15a5c70c 100644 --- a/daemons/configure.ac +++ b/daemons/configure.ac @@ -291,6 +291,7 @@ AC_CONFIG_FILES([ ipa-kpasswd/Makefile ipa-slapi-plugins/Makefile ipa-slapi-plugins/ipa-enrollment/Makefile + ipa-slapi-plugins/ipa-lockout/Makefile ipa-slapi-plugins/ipa-pwd-extop/Makefile ipa-slapi-plugins/ipa-winsync/Makefile ipa-slapi-plugins/ipa-version/Makefile diff --git a/daemons/ipa-slapi-plugins/Makefile.am b/daemons/ipa-slapi-plugins/Makefile.am index 1ae2351dd..25f50d5f7 100644 --- a/daemons/ipa-slapi-plugins/Makefile.am +++ b/daemons/ipa-slapi-plugins/Makefile.am @@ -2,6 +2,7 @@ NULL = SUBDIRS = \ ipa-enrollment \ + ipa-lockout \ ipa-modrdn \ ipa-pwd-extop \ ipa-uuid \ diff --git a/daemons/ipa-slapi-plugins/ipa-lockout/Makefile.am b/daemons/ipa-slapi-plugins/ipa-lockout/Makefile.am new file mode 100644 index 000000000..fea3fe67d --- /dev/null +++ b/daemons/ipa-slapi-plugins/ipa-lockout/Makefile.am @@ -0,0 +1,46 @@ +NULL = + +PLUGIN_COMMON_DIR=../common + +INCLUDES = \ + -I. \ + -I$(srcdir) \ + -I$(PLUGIN_COMMON_DIR) \ + -I/usr/include/dirsrv \ + -DPREFIX=\""$(prefix)"\" \ + -DBINDIR=\""$(bindir)"\" \ + -DLIBDIR=\""$(libdir)"\" \ + -DLIBEXECDIR=\""$(libexecdir)"\" \ + -DDATADIR=\""$(datadir)"\" \ + $(AM_CFLAGS) \ + $(LDAP_CFLAGS) \ + $(WARN_CFLAGS) \ + $(NULL) + +plugindir = $(libdir)/dirsrv/plugins +plugin_LTLIBRARIES = \ + libipa_lockout.la \ + $(NULL) + +libipa_lockout_la_SOURCES = \ + ipa_lockout.c \ + $(NULL) + +libipa_lockout_la_LDFLAGS = -avoid-version + +libipa_lockout_la_LIBADD = \ + $(LDAP_LIBS) \ + $(NULL) + +appdir = $(IPA_DATA_DIR) +app_DATA = \ + lockout-conf.ldif \ + $(NULL) + +EXTRA_DIST = \ + $(app_DATA) \ + $(NULL) + +MAINTAINERCLEANFILES = \ + *~ \ + Makefile.in diff --git a/daemons/ipa-slapi-plugins/ipa-lockout/ipa_lockout.c b/daemons/ipa-slapi-plugins/ipa-lockout/ipa_lockout.c new file mode 100644 index 000000000..0284872b8 --- /dev/null +++ b/daemons/ipa-slapi-plugins/ipa-lockout/ipa_lockout.c @@ -0,0 +1,643 @@ +/** BEGIN COPYRIGHT BLOCK + * 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/>. + * + * Additional permission under GPLv3 section 7: + * + * In the following paragraph, "GPL" means the GNU General Public + * License, version 3 or any later version, and "Non-GPL Code" means + * code that is governed neither by the the GPL nor a license + * compatible with the GPL. + * + * You may link the code of this Program with Non-GPL Code and convey + * linked combinations including the two, provided that such Non-GPL + * Code only links to the code of this Program through those well + * defined interfaces identified in the file named EXCEPTION found in + * the source code files (the "Approved Interfaces"). The files of + * Non-GPL Code may instantiate templates or use macros or inline + * functions from the Approved Interfaces without causing the resulting + * work to be covered by the GPL. Only the copyright holders of this + * Program may make changes or additions to the list of Approved + * Interfaces. + * + * Copyright (C) 2010 Red Hat, Inc. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +/** + * IPA Lockout plug-in + * + * Update the Kerberos lockout variables on LDAP binds. + * + */ +#include <string.h> +#include <stdbool.h> +#include <time.h> +#include "slapi-plugin.h" +#include "nspr.h" + +#include "util.h" + +#define IPALOCKOUT_PLUGIN_NAME "ipa-lockout-plugin" +#define IPALOCKOUT_PLUGIN_VERSION 0x00010000 + +#define IPA_PLUGIN_NAME IPALOCKOUT_PLUGIN_NAME + +#define IPALOCKOUT_FEATURE_DESC "IPA Lockout" +#define IPALOCKOUT_PLUGIN_DESC "IPA Lockout plugin" +#define IPALOCKOUT_POSTOP_DESC "IPA Lockout postop plugin" +#define IPALOCKOUT_PREOP_DESC "IPA Lockout preop plugin" + +static Slapi_PluginDesc pdesc = { + IPALOCKOUT_FEATURE_DESC, + "Red Hat, Inc.", + "1.0", + IPALOCKOUT_PLUGIN_DESC +}; + +static void *_PluginID = NULL; +static char *_PluginDN = NULL; + +static int g_plugin_started = 0; + +#define GENERALIZED_TIME_LENGTH 15 + +/** + * + * management functions + * + */ +int ipalockout_init(Slapi_PBlock * pb); +static int ipalockout_start(Slapi_PBlock * pb); +static int ipalockout_close(Slapi_PBlock * pb); +static int ipalockout_postop_init(Slapi_PBlock * pb); +static int ipalockout_preop_init(Slapi_PBlock * pb); + +/** + * + * the ops (where the real work is done) + * + */ +static int ipalockout_postop(Slapi_PBlock *pb); +static int ipalockout_preop(Slapi_PBlock *pb); + +/** + * + * Get the plug-in version + * + */ +int ipalockout_version(void) +{ + return IPALOCKOUT_PLUGIN_VERSION; +} + +/** + * Plugin identity mgmt + */ +void setPluginID(void *pluginID) +{ + _PluginID = pluginID; +} + +void *getPluginID(void) +{ + return _PluginID; +} + +void setPluginDN(char *pluginDN) +{ + _PluginDN = pluginDN; +} + +char *getPluginDN(void) +{ + return _PluginDN; +} + +int +ipalockout_init(Slapi_PBlock *pb) +{ + int status = EOK; + char *plugin_identity = NULL; + + LOG_TRACE("--in-->\n"); + + slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &plugin_identity); + PR_ASSERT(plugin_identity); + setPluginID(plugin_identity); + + if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, + SLAPI_PLUGIN_VERSION_01) != 0 || + slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN, + (void *) ipalockout_start) != 0 || + slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN, + (void *) ipalockout_close) != 0 || + slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, + (void *) &pdesc) != 0 || + slapi_register_plugin("postoperation", + 1, + "ipalockout_init", + ipalockout_postop_init, + IPALOCKOUT_POSTOP_DESC, + NULL, + plugin_identity + ) || + slapi_register_plugin("preoperation", + 1, + "ipalockout_init", + ipalockout_preop_init, + IPALOCKOUT_PREOP_DESC, + NULL, + plugin_identity + ) + ) { + LOG_FATAL("failed to register plugin\n"); + status = EFAIL; + } + + LOG_TRACE("<--out--\n"); + return status; +} + +static int +ipalockout_postop_init(Slapi_PBlock *pb) +{ + int status = EOK; + + if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, + SLAPI_PLUGIN_VERSION_01) != 0 || + slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, + (void *) &pdesc) != 0 || + slapi_pblock_set(pb, SLAPI_PLUGIN_POST_BIND_FN, + (void *) ipalockout_postop) != 0) { + status = EFAIL; + } + + return status; +} + +static int +ipalockout_preop_init(Slapi_PBlock *pb) +{ + int status = EOK; + + if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, + SLAPI_PLUGIN_VERSION_01) != 0 || + slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, + (void *) &pdesc) != 0 || + slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_BIND_FN, + (void *) ipalockout_preop) != 0) { + status = EFAIL; + } + + return status; +} + +static int +ipalockout_start(Slapi_PBlock * pb) +{ + LOG_TRACE("--in-->\n"); + + /* Check if we're already started */ + if (g_plugin_started) { + goto done; + } + + g_plugin_started = 1; + LOG("ready for service\n"); + LOG_TRACE("<--out--\n"); + +done: + return EOK; +} + +static int +ipalockout_close(Slapi_PBlock * pb) +{ + LOG_TRACE( "--in-->\n"); + + LOG_TRACE("<--out--\n"); + + return EOK; +} + +/* + * In the post-operation we know whether the bind was successful or not + * so here we handle updating the Kerberos lockout policy attributes. + */ +static int ipalockout_postop(Slapi_PBlock *pb) +{ + char *dn = NULL; + char *policy_dn = NULL; + Slapi_Entry *target_entry = NULL; + Slapi_Entry *policy_entry = NULL; + Slapi_DN *sdn = NULL; + Slapi_DN *pdn = NULL; + Slapi_PBlock *pbtm = NULL; + Slapi_Mods *smods = NULL; + Slapi_Value *objectclass = NULL; + char *errstr = NULL; + int ldrc, rc = 0; + int ret = LDAP_SUCCESS; + unsigned long failedcount = 0; + char failedcountstr[32]; + int failed_bind = 0; + struct tm utctime; + time_t time_now; + char timestr[GENERALIZED_TIME_LENGTH+1]; + unsigned int failcnt_interval = 0; + char *lastfail = NULL; + int tries = 0; + int failure = 1; + + LOG_TRACE("--in-->\n"); + + /* Just bail if we aren't ready to service requests yet. */ + if (!g_plugin_started) { + goto done; + } + + slapi_pblock_get(pb, SLAPI_RESULT_CODE, &rc); + + /* free the dn here */ + if (slapi_pblock_get(pb, SLAPI_CONN_DN, &dn) != 0) { + LOG_FATAL("Error retrieving bind DN\n"); + ret = LDAP_OPERATIONS_ERROR; + goto done; + } + + /* dn will be NULL on failed auth, get the target instead */ + /* don't free this dn */ + if (dn == NULL && rc != LDAP_SUCCESS) { + failed_bind = 1; + if (slapi_pblock_get(pb, SLAPI_BIND_TARGET, &dn) != 0) { + LOG_FATAL("Error retrieving target DN\n"); + ret = LDAP_OPERATIONS_ERROR; + goto done; + } + } + + /* Client is anonymously bound */ + if (dn == NULL) { + LOG_TRACE("anonymous bind\n"); + goto done; + } + + /* Get the entry */ + sdn = slapi_sdn_new_dn_byref(dn); + if (sdn == NULL) { + LOG_OOM(); + errstr = "Out of memory.\n"; + ret = LDAP_OPERATIONS_ERROR; + goto done; + } + + ldrc = slapi_search_internal_get_entry(sdn, NULL, &target_entry, + getPluginID()); + + if (ldrc != LDAP_SUCCESS) { + LOG_FATAL("Failed to retrieve entry \"%s\": %d\n", dn, ldrc); + goto done; + } + + /* Only update kerberos principal entries */ + objectclass = slapi_value_new_string("krbPrincipalAux"); + if ((slapi_entry_attr_has_syntax_value(target_entry, SLAPI_ATTR_OBJECTCLASS, objectclass)) != 1) { + LOG_TRACE("Not a kerberos user\n"); + slapi_value_free(&objectclass); + goto done; + } + slapi_value_free(&objectclass); + + /* Only update if there is a password policy */ + policy_dn = slapi_entry_attr_get_charptr(target_entry, "krbPwdPolicyReference"); + if (policy_dn == NULL) { + LOG_TRACE("No kerberos password policy\n"); + goto done; + } else { + pdn = slapi_sdn_new_dn_byref(policy_dn); + ldrc = slapi_search_internal_get_entry(pdn, NULL, &policy_entry, + getPluginID()); + slapi_sdn_free(&pdn); + if (ldrc != LDAP_SUCCESS) { + LOG_FATAL("Failed to retrieve entry \"%s\": %d\n", policy_dn, ldrc); + errstr = "Failed to retrieve account policy."; + ret = LDAP_OPERATIONS_ERROR; + goto done; + } + } + + failedcount = slapi_entry_attr_get_ulong(target_entry, "krbLoginFailedCount"); + failcnt_interval = slapi_entry_attr_get_uint(policy_entry, "krbPwdFailureCountInterval"); + lastfail = slapi_entry_attr_get_charptr(target_entry, "krbLastFailedAuth"); + time_now = time(NULL); + if (lastfail != NULL) { + struct tm tm; + int ret = 0; + + memset(&tm, 0, sizeof(struct tm)); + ret = sscanf(lastfail, + "%04u%02u%02u%02u%02u%02u", + &tm.tm_year, &tm.tm_mon, &tm.tm_mday, + &tm.tm_hour, &tm.tm_min, &tm.tm_sec); + + if (ret == 6) { + tm.tm_year -= 1900; + tm.tm_mon -= 1; + + if (time_now > timegm(&tm) + failcnt_interval) { + failedcount = 0; + } + } + } + + while (tries < 5) { + smods = slapi_mods_new(); + + /* On failures try very hard to update the entry so that failures + * are counted properly. This involves doing a DELETE of the value + * we expect and an ADD of the new one in the same update. If the + * record has changed while we were handling the request our + * update will fail and we will try again. + * + * On a successful bind just do a replace and set failurecount to 0. + */ + if (failed_bind) { + PR_snprintf(failedcountstr, sizeof(failedcountstr), "%lu", failedcount); + if (!gmtime_r(&(time_now), &utctime)) { + errstr = "failed to parse current date (buggy gmtime_r ?)\n"; + LOG_FATAL("%s", errstr); + ret = LDAP_OPERATIONS_ERROR; + goto done; + } + strftime(timestr, GENERALIZED_TIME_LENGTH+1, + "%Y%m%d%H%M%SZ", &utctime); + slapi_mods_add_string(smods, LDAP_MOD_DELETE, "krbLoginFailedCount", failedcountstr); + failedcount += 1; + PR_snprintf(failedcountstr, sizeof(failedcountstr), "%lu", failedcount); + slapi_mods_add_string(smods, LDAP_MOD_ADD, "krbLoginFailedCount", failedcountstr); + if (lastfail) + slapi_mods_add_string(smods, LDAP_MOD_DELETE, "krbLastFailedAuth", lastfail); + slapi_mods_add_string(smods, LDAP_MOD_ADD, "krbLastFailedAuth", timestr); + } else { + PR_snprintf(failedcountstr, sizeof(failedcountstr), "%lu", 0L); + time_now = time(NULL); + if (!gmtime_r(&(time_now), &utctime)) { + errstr = "failed to parse current date (buggy gmtime_r ?)\n"; + LOG_FATAL("%s", errstr); + ret = LDAP_OPERATIONS_ERROR; + goto done; + } + strftime(timestr, GENERALIZED_TIME_LENGTH+1, + "%Y%m%d%H%M%SZ", &utctime); + slapi_mods_add_string(smods, LDAP_MOD_REPLACE, "krbLoginFailedCount", failedcountstr); + slapi_mods_add_string(smods, LDAP_MOD_REPLACE, "krbLastSuccessfulAuth", timestr); + } + + pbtm = slapi_pblock_new(); + slapi_modify_internal_set_pb (pbtm, slapi_entry_get_dn_const(target_entry), + slapi_mods_get_ldapmods_byref(smods), + NULL, /* Controls */ + NULL, /* UniqueID */ + getPluginID(), /* PluginID */ + 0); /* Flags */ + + slapi_modify_internal_pb (pbtm); + slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc); + + if (rc != LDAP_SUCCESS) { + LOG_TRACE("WARNING: modify error %d on entry '%s'\n", + rc, slapi_entry_get_dn_const(target_entry)); + + ldrc = slapi_search_internal_get_entry(sdn, NULL, &target_entry, + getPluginID()); + + if (ldrc != LDAP_SUCCESS) { + LOG_FATAL("Failed to retrieve entry \"%s\": %d\n", dn, ldrc); + goto done; + } + slapi_mods_free(&smods); + slapi_pblock_destroy(pbtm); + if (lastfail) slapi_ch_free_string(&lastfail); + smods = NULL; + pbtm = NULL; + lastfail = NULL; + tries += 1; + } else { + LOG_TRACE("<= apply mods: Successful\n"); + failure = 0; + break; + } + } /* while */ + + if (failure) { + ret = LDAP_OPERATIONS_ERROR; + } + +done: + if (!failed_bind && dn != NULL) slapi_ch_free_string(&dn); + slapi_entry_free(target_entry); + if (policy_dn) { + slapi_ch_free_string(&policy_dn); + slapi_entry_free(policy_entry); + } + if (sdn) slapi_sdn_free(&sdn); + if (lastfail) slapi_ch_free_string(&lastfail); + if (pbtm) slapi_pblock_destroy(pbtm); + if (smods) slapi_mods_free(&smods); + + LOG("postop returning %d: %s\n", ret, errstr ? errstr : "success\n"); + + if (ret) { + slapi_send_ldap_result(pb, ret, NULL, errstr, 0, NULL); + } + + LOG_TRACE("<--out--\n"); + + return (ret == 0 ? EOK : EFAIL); +} + +/* + * In the pre-op stage the bind hasn't occurred yet. It is here that + * we do the lockout enforcement. + */ +static int ipalockout_preop(Slapi_PBlock *pb) +{ + char *dn = NULL; + char *policy_dn = NULL; + Slapi_Entry *target_entry = NULL; + Slapi_Entry *policy_entry = NULL; + Slapi_DN *sdn = NULL; + Slapi_DN *pdn = NULL; + Slapi_Value *objectclass = NULL; + char *errstr = NULL; + int ldrc = 0; + int ret = LDAP_SUCCESS; + unsigned long failedcount = 0; + time_t time_now; + unsigned int failcnt_interval = 0; + unsigned int max_fail = 0; + unsigned int lockout_duration = 0; + time_t last_failed = 0; + char *lastfail = NULL; + char *unlock_time = NULL; + + LOG_TRACE("--in-->\n"); + + /* Just bail if we aren't ready to service requests yet. */ + if (!g_plugin_started) { + goto done; + } + + if (slapi_pblock_get(pb, SLAPI_BIND_TARGET, &dn) != 0) { + LOG_FATAL("Error retrieving target DN\n"); + ret = LDAP_OPERATIONS_ERROR; + goto done; + } + + /* Client is anonymously bound */ + if (dn == NULL) { + LOG_TRACE("anonymous bind\n"); + goto done; + } + + /* Get the entry */ + sdn = slapi_sdn_new_dn_byref(dn); + if (sdn == NULL) { + LOG_OOM(); + errstr = "Out of memory.\n"; + ret = LDAP_OPERATIONS_ERROR; + goto done; + } + + ldrc = slapi_search_internal_get_entry(sdn, NULL, &target_entry, + getPluginID()); + + if (ldrc != LDAP_SUCCESS) { + LOG_FATAL("Failed to retrieve entry \"%s\": %d\n", dn, ldrc); + goto done; + } + + /* Only handle kerberos principal entries */ + objectclass = slapi_value_new_string("krbPrincipalAux"); + if ((slapi_entry_attr_has_syntax_value(target_entry, SLAPI_ATTR_OBJECTCLASS, objectclass)) != 1) { + LOG_TRACE("Not a kerberos user\n"); + slapi_value_free(&objectclass); + goto done; + } + slapi_value_free(&objectclass); + + /* Only continue if there is a password policy */ + policy_dn = slapi_entry_attr_get_charptr(target_entry, "krbPwdPolicyReference"); + if (policy_dn == NULL) { + LOG_TRACE("No kerberos password policy\n"); + goto done; + } else { + pdn = slapi_sdn_new_dn_byref(policy_dn); + ldrc = slapi_search_internal_get_entry(pdn, NULL, &policy_entry, + getPluginID()); + slapi_sdn_free(&pdn); + if (ldrc != LDAP_SUCCESS) { + LOG_FATAL("Failed to retrieve entry \"%s\": %d\n", policy_dn, ldrc); + errstr = "Failed to retrieve account policy."; + ret = LDAP_OPERATIONS_ERROR; + goto done; + } + } + + failedcount = slapi_entry_attr_get_ulong(target_entry, "krbLoginFailedCount"); + time_now = time(NULL); + failcnt_interval = slapi_entry_attr_get_uint(policy_entry, "krbPwdFailureCountInterval"); + lastfail = slapi_entry_attr_get_charptr(target_entry, "krbLastFailedAuth"); + unlock_time = slapi_entry_attr_get_charptr(target_entry, "krbLastAdminUnlock"); + if (lastfail != NULL) { + struct tm tm; + int ret = 0; + + memset(&tm, 0, sizeof(struct tm)); + ret = sscanf(lastfail, + "%04u%02u%02u%02u%02u%02u", + &tm.tm_year, &tm.tm_mon, &tm.tm_mday, + &tm.tm_hour, &tm.tm_min, &tm.tm_sec); + + if (ret == 6) { + tm.tm_year -= 1900; + tm.tm_mon -= 1; + + last_failed = timegm(&tm); + LOG("%d > %d ?\n", time_now, last_failed + failcnt_interval); + LOG("diff %d\n", (last_failed + failcnt_interval) - time_now); + if (time_now > last_failed + failcnt_interval) { + failedcount = 0; + } + } + if (unlock_time) { + time_t unlock; + + memset(&tm, 0, sizeof(struct tm)); + ret = sscanf(lastfail, + "%04u%02u%02u%02u%02u%02u", + &tm.tm_year, &tm.tm_mon, &tm.tm_mday, + &tm.tm_hour, &tm.tm_min, &tm.tm_sec); + + if (ret == 6) { + tm.tm_year -= 1900; + tm.tm_mon -= 1; + + unlock = timegm(&tm); + if (last_failed <= unlock) { + goto done; + } + } + slapi_ch_free_string(&unlock_time); + } + slapi_ch_free_string(&lastfail); + } + + max_fail = slapi_entry_attr_get_uint(policy_entry, "krbPwdMaxFailure"); + if (max_fail == 0) { + goto done; + } + + lockout_duration = slapi_entry_attr_get_uint(policy_entry, "krbPwdLockoutDuration"); + if (lockout_duration == 0) { + errstr = "Entry permanently locked.\n"; + ret = LDAP_UNWILLING_TO_PERFORM; + goto done; + } + + if (failedcount > max_fail) { + if (time_now < last_failed + lockout_duration) { + /* Too many failures */ + LOG_TRACE("Too many failed logins. %lu out of %d\n", failedcount, max_fail); + errstr = "Too many failed logins.\n"; + ret = LDAP_UNWILLING_TO_PERFORM; + } + } + +done: + slapi_entry_free(target_entry); + slapi_entry_free(policy_entry); + if (policy_dn) slapi_ch_free_string(&policy_dn); + if (sdn) slapi_sdn_free(&sdn); + + LOG("preop returning %d: %s\n", ret, errstr ? errstr : "success\n"); + + if (ret) { + slapi_send_ldap_result(pb, ret, NULL, errstr, 0, NULL); + } + + LOG_TRACE("<--out--\n"); + + return (ret == 0 ? EOK : EFAIL); +} diff --git a/daemons/ipa-slapi-plugins/ipa-lockout/lockout-conf.ldif b/daemons/ipa-slapi-plugins/ipa-lockout/lockout-conf.ldif new file mode 100644 index 000000000..8a13fc94b --- /dev/null +++ b/daemons/ipa-slapi-plugins/ipa-lockout/lockout-conf.ldif @@ -0,0 +1,15 @@ +dn: cn=IPA Lockout,cn=plugins,cn=config +changetype: add +objectclass: top +objectclass: nsSlapdPlugin +objectclass: extensibleObject +cn: IPA Lockout +nsslapd-pluginpath: libipa_lockout +nsslapd-plugininitfunc: ipalockout_init +nsslapd-plugintype: object +nsslapd-pluginenabled: on +nsslapd-pluginid: ipalockout_version +nsslapd-pluginversion: 1.0 +nsslapd-pluginvendor: Red Hat, Inc. +nsslapd-plugindescription: IPA Lockout plugin +nsslapd-plugin-depends-on-type: database diff --git a/ipa.spec.in b/ipa.spec.in index d43a029c4..7d7ce7787 100644 --- a/ipa.spec.in +++ b/ipa.spec.in @@ -235,6 +235,7 @@ rm %{buildroot}/%{plugin_dir}/libipa_winsync.la rm %{buildroot}/%{plugin_dir}/libipa_repl_version.la rm %{buildroot}/%{plugin_dir}/libipa_uuid.la rm %{buildroot}/%{plugin_dir}/libipa_modrdn.la +rm %{buildroot}/%{plugin_dir}/libipa_lockout.la # Some user-modifiable HTML files are provided. Move these to /etc # and link back. @@ -392,6 +393,7 @@ fi %attr(755,root,root) %{plugin_dir}/libipa_repl_version.so %attr(755,root,root) %{plugin_dir}/libipa_uuid.so %attr(755,root,root) %{plugin_dir}/libipa_modrdn.so +%attr(755,root,root) %{plugin_dir}/libipa_lockout.so %dir %{_localstatedir}/lib/ipa %attr(700,root,root) %dir %{_localstatedir}/lib/ipa/sysrestore %dir %{_localstatedir}/cache/ipa diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py index 378e01234..9a121ea62 100644 --- a/ipaserver/install/dsinstance.py +++ b/ipaserver/install/dsinstance.py @@ -204,6 +204,7 @@ class DsInstance(service.Service): self.step("configuring uuid plugin", self.__config_uuid_module) self.step("configuring modrdn plugin", self.__config_modrdn_module) self.step("enabling entryUSN plugin", self.__enable_entryusn) + self.step("configuring lockout plugin", self.__config_lockout_module) self.step("creating indices", self.__create_indices) self.step("configuring ssl for ds instance", self.__enable_ssl) self.step("configuring certmap.conf", self.__certmap_conf) @@ -459,6 +460,9 @@ class DsInstance(service.Service): self._ldap_mod("modrdn-conf.ldif") self._ldap_mod("modrdn-krbprinc.ldif", self.sub_dict) + def __config_lockout_module(self): + self._ldap_mod("lockout-conf.ldif") + def __user_private_groups(self): if not has_managed_entries(self.fqdn, self.dm_password): raise errors.NotFound(reason='Missing Managed Entries Plugin') |