summaryrefslogtreecommitdiffstats
path: root/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c
diff options
context:
space:
mode:
authorNathaniel McCallum <npmccallum@redhat.com>2013-05-09 14:43:17 -0400
committerMartin Kosek <mkosek@redhat.com>2013-05-17 09:30:51 +0200
commit1e1bab4edc0ce4b70a370deac8109092b53b97a2 (patch)
treec6fbd938cf3f4a71b268b16f74bab07013a02e8d /daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c
parent203754691c28243dd3cf378e98390fc0a455b485 (diff)
downloadfreeipa.git-1e1bab4edc0ce4b70a370deac8109092b53b97a2.tar.gz
freeipa.git-1e1bab4edc0ce4b70a370deac8109092b53b97a2.tar.xz
freeipa.git-1e1bab4edc0ce4b70a370deac8109092b53b97a2.zip
Remove unnecessary prefixes from ipa-pwd-extop files
Diffstat (limited to 'daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c')
-rw-r--r--daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c1349
1 files changed, 1349 insertions, 0 deletions
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c
new file mode 100644
index 00000000..0318cecd
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c
@@ -0,0 +1,1349 @@
+/** 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 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.
+ *
+ * Authors:
+ * Simo Sorce <ssorce@redhat.com>
+ *
+ * Copyright (C) 2007-2010 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* strptime needs _XOPEN_SOURCE and endian.h needs __USE_BSD
+ * _GNU_SOURCE imply both, and we use it elsewhere, so use this */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <dirsrv/slapi-plugin.h>
+#include <lber.h>
+#include <time.h>
+#include <endian.h>
+
+#include "ipapwd.h"
+#include "util.h"
+
+#define IPAPWD_OP_NULL 0
+#define IPAPWD_OP_ADD 1
+#define IPAPWD_OP_MOD 2
+
+extern Slapi_PluginDesc ipapwd_plugin_desc;
+extern void *ipapwd_plugin_id;
+extern const char *ipa_realm_tree;
+
+/* structure with information for each extension */
+struct ipapwd_op_ext {
+ char *object_name; /* name of the object extended */
+ int object_type; /* handle to the extended object */
+ int handle; /* extension handle */
+};
+/*****************************************************************************
+ * pre/post operations to intercept writes to userPassword
+ ****************************************************************************/
+static struct ipapwd_op_ext ipapwd_op_ext_list;
+
+static void *ipapwd_op_ext_constructor(void *object, void *parent)
+{
+ struct ipapwd_operation *ext;
+
+ ext = (struct ipapwd_operation *)slapi_ch_calloc(1, sizeof(struct ipapwd_operation));
+ return ext;
+}
+
+static void ipapwd_op_ext_destructor(void *ext, void *object, void *parent)
+{
+ struct ipapwd_operation *pwdop = (struct ipapwd_operation *)ext;
+ if (!pwdop)
+ return;
+ if (pwdop->pwd_op != IPAPWD_OP_NULL) {
+ slapi_ch_free_string(&(pwdop->pwdata.dn));
+ slapi_ch_free_string(&(pwdop->pwdata.password));
+ }
+ slapi_ch_free((void **)&pwdop);
+}
+
+int ipapwd_ext_init(void)
+{
+ int ret;
+
+ ipapwd_op_ext_list.object_name = SLAPI_EXT_OPERATION;
+
+ ret = slapi_register_object_extension(IPAPWD_PLUGIN_NAME,
+ SLAPI_EXT_OPERATION,
+ ipapwd_op_ext_constructor,
+ ipapwd_op_ext_destructor,
+ &ipapwd_op_ext_list.object_type,
+ &ipapwd_op_ext_list.handle);
+
+ return ret;
+}
+
+
+static char *ipapwd_getIpaConfigAttr(const char *attr)
+{
+ /* check if migrtion is enabled */
+ Slapi_Entry *entry = NULL;
+ const char *attrs_list[] = {attr, 0};
+ char *value = NULL;
+ char *dn = NULL;
+ int ret;
+
+ dn = slapi_ch_smprintf("cn=ipaconfig,cn=etc,%s", ipa_realm_tree);
+ if (!dn) {
+ LOG_OOM();
+ goto done;
+ }
+
+ ret = ipapwd_getEntry(dn, &entry, (char **) attrs_list);
+ if (ret) {
+ LOG("failed to retrieve config entry: %s\n", dn);
+ goto done;
+ }
+
+ value = slapi_entry_attr_get_charptr(entry, attr);
+
+done:
+ slapi_entry_free(entry);
+ slapi_ch_free_string(&dn);
+ return value;
+}
+
+
+/* PRE ADD Operation:
+ * Gets the clean text password (fail the operation if the password came
+ * pre-hashed, unless this is a replicated operation or migration mode is
+ * enabled).
+ * Check user is authorized to add it otherwise just returns, operation will
+ * fail later anyway.
+ * Run a password policy check.
+ * Check if krb or smb hashes are required by testing if the krb or smb
+ * objectclasses are present.
+ * store information for the post operation
+ */
+static int ipapwd_pre_add(Slapi_PBlock *pb)
+{
+ struct ipapwd_krbcfg *krbcfg = NULL;
+ char *errMesg = "Internal operations error\n";
+ struct slapi_entry *e = NULL;
+ char *userpw = NULL;
+ char *dn = NULL;
+ struct ipapwd_operation *pwdop = NULL;
+ void *op;
+ int is_repl_op, is_root, is_krb, is_smb, is_ipant;
+ int ret;
+ int rc = LDAP_SUCCESS;
+
+ LOG_TRACE("=>\n");
+
+ ret = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &is_repl_op);
+ if (ret != 0) {
+ LOG_FATAL("slapi_pblock_get failed!?\n");
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ /* pass through if this is a replicated operation */
+ if (is_repl_op)
+ return 0;
+
+ /* retrieve the entry */
+ slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &e);
+ if (NULL == e)
+ return 0;
+
+ /* check this is something interesting for us first */
+ userpw = slapi_entry_attr_get_charptr(e, SLAPI_USERPWD_ATTR);
+ if (!userpw) {
+ /* nothing interesting here */
+ return 0;
+ }
+
+ /* Ok this is interesting,
+ * Check this is a clear text password, or refuse operation */
+ if ('{' == userpw[0]) {
+ if (0 == strncasecmp(userpw, "{CLEAR}", strlen("{CLEAR}"))) {
+ char *tmp = slapi_ch_strdup(&userpw[strlen("{CLEAR}")]);
+ if (NULL == tmp) {
+ LOG_OOM();
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+ slapi_ch_free_string(&userpw);
+ userpw = tmp;
+ } else if (slapi_is_encoded(userpw)) {
+ const char *userpw_clear = NULL;
+ Slapi_Value **pwvals = NULL;
+
+ /* Try to get clear password from an entry extension.
+ * This function does not return a copy of the values,
+ * no need to free them. */
+ rc = slapi_pw_get_entry_ext(e, &pwvals);
+ if (LDAP_SUCCESS == rc) {
+ userpw_clear = slapi_value_get_string(pwvals[0]);
+ }
+
+ /* Fail if we did not get a real clear text password from
+ * the extension. This will happen if the password is hashed. */
+ if (!userpw_clear || (0 == strcmp(userpw, userpw_clear))) {
+ rc = LDAP_CONSTRAINT_VIOLATION;
+ slapi_ch_free_string(&userpw);
+ } else {
+ userpw = slapi_ch_strdup(userpw_clear);
+ }
+
+ if (rc != LDAP_SUCCESS) {
+ /* we don't have access to the clear text password;
+ * let it slide if migration is enabled, but don't
+ * generate kerberos keys */
+ char *enabled = ipapwd_getIpaConfigAttr("ipamigrationenabled");
+ if (NULL == enabled) {
+ LOG("no ipaMigrationEnabled in config, assuming FALSE\n");
+ } else if (0 == strcmp(enabled, "TRUE")) {
+ return 0;
+ }
+
+ LOG("pre-hashed passwords are not valid\n");
+ errMesg = "pre-hashed passwords are not valid\n";
+ goto done;
+ }
+ }
+ }
+
+ rc = ipapwd_entry_checks(pb, e,
+ &is_root, &is_krb, &is_smb, &is_ipant,
+ NULL, SLAPI_ACL_ADD);
+ if (rc != LDAP_SUCCESS) {
+ goto done;
+ }
+
+ rc = ipapwd_gen_checks(pb, &errMesg, &krbcfg, IPAPWD_CHECK_DN);
+ if (rc != LDAP_SUCCESS) {
+ goto done;
+ }
+
+ /* Get target DN */
+ ret = slapi_pblock_get(pb, SLAPI_TARGET_DN, &dn);
+ if (ret) {
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ /* time to get the operation handler */
+ ret = slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ if (ret != 0) {
+ LOG_FATAL("slapi_pblock_get failed!?\n");
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ pwdop = slapi_get_object_extension(ipapwd_op_ext_list.object_type,
+ op, ipapwd_op_ext_list.handle);
+ if (NULL == pwdop) {
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ pwdop->pwd_op = IPAPWD_OP_ADD;
+ pwdop->pwdata.password = slapi_ch_strdup(userpw);
+
+ if (is_root) {
+ pwdop->pwdata.changetype = IPA_CHANGETYPE_DSMGR;
+ } else {
+ char *binddn;
+ int i;
+
+ pwdop->pwdata.changetype = IPA_CHANGETYPE_ADMIN;
+
+ /* Check Bind DN */
+ slapi_pblock_get(pb, SLAPI_CONN_DN, &binddn);
+
+ /* if it is a passsync manager we also need to skip resets */
+ for (i = 0; i < krbcfg->num_passsync_mgrs; i++) {
+ if (strcasecmp(krbcfg->passsync_mgrs[i], binddn) == 0) {
+ pwdop->pwdata.changetype = IPA_CHANGETYPE_DSMGR;
+ break;
+ }
+ }
+ }
+
+ pwdop->pwdata.dn = slapi_ch_strdup(dn);
+ pwdop->pwdata.timeNow = time(NULL);
+ pwdop->pwdata.target = e;
+
+ ret = ipapwd_CheckPolicy(&pwdop->pwdata);
+ if (ret) {
+ errMesg = ipapwd_error2string(ret);
+ rc = LDAP_CONSTRAINT_VIOLATION;
+ goto done;
+ }
+
+ if (is_krb || is_smb || is_ipant) {
+
+ Slapi_Value **svals = NULL;
+ Slapi_Value **ntvals = NULL;
+ char *nt = NULL;
+ char *lm = NULL;
+
+ pwdop->is_krb = is_krb;
+
+ rc = ipapwd_gen_hashes(krbcfg, &pwdop->pwdata,
+ userpw, is_krb, is_smb, is_ipant,
+ &svals, &nt, &lm, &ntvals, &errMesg);
+ if (rc != LDAP_SUCCESS) {
+ goto done;
+ }
+
+ if (svals) {
+ /* add/replace values in existing entry */
+ ret = slapi_entry_attr_replace_sv(e, "krbPrincipalKey", svals);
+ if (ret) {
+ LOG_FATAL("failed to set encoded values in entry\n");
+ rc = LDAP_OPERATIONS_ERROR;
+ ipapwd_free_slapi_value_array(&svals);
+ goto done;
+ }
+
+ ipapwd_free_slapi_value_array(&svals);
+ }
+
+ if (lm && is_smb) {
+ /* set value */
+ slapi_entry_attr_set_charptr(e, "sambaLMPassword", lm);
+ slapi_ch_free_string(&lm);
+ }
+ if (nt && is_smb) {
+ /* set value */
+ slapi_entry_attr_set_charptr(e, "sambaNTPassword", nt);
+ slapi_ch_free_string(&nt);
+ }
+
+ if (ntvals && is_ipant) {
+ slapi_entry_attr_replace_sv(e, "ipaNTHash", ntvals);
+ ipapwd_free_slapi_value_array(&ntvals);
+ }
+
+ if (is_smb) {
+ /* with samba integration we need to also set sambaPwdLastSet or
+ * samba will decide the user has to change the password again */
+ if (pwdop->pwdata.changetype == IPA_CHANGETYPE_ADMIN) {
+ /* if it is an admin change instead we need to let know to
+ * samba as well that the use rmust change its password */
+ slapi_entry_attr_set_long(e, "sambaPwdLastset", 0L);
+ } else {
+ slapi_entry_attr_set_long(e, "sambaPwdLastset",
+ (long)pwdop->pwdata.timeNow);
+ }
+ }
+ }
+
+ rc = LDAP_SUCCESS;
+
+done:
+ if (pwdop) pwdop->pwdata.target = NULL;
+ free_ipapwd_krbcfg(&krbcfg);
+ slapi_ch_free_string(&userpw);
+ if (rc != LDAP_SUCCESS) {
+ slapi_send_ldap_result(pb, rc, NULL, errMesg, 0, NULL);
+ return -1;
+ }
+ return 0;
+}
+
+#define NTHASH_REGEN_VAL "MagicRegen"
+#define NTHASH_REGEN_LEN sizeof(NTHASH_REGEN_VAL)
+static int ipapwd_regen_nthash(Slapi_PBlock *pb, Slapi_Mods *smods,
+ char *dn, struct slapi_entry *entry,
+ struct ipapwd_krbcfg *krbcfg);
+
+/* PRE MOD Operation:
+ * Gets the clean text password (fail the operation if the password came
+ * pre-hashed, unless this is a replicated operation).
+ * Check user is authorized to add it otherwise just returns, operation will
+ * fail later anyway.
+ * Check if krb or smb hashes are required by testing if the krb or smb
+ * objectclasses are present.
+ * Run a password policy check.
+ * store information for the post operation
+ */
+static int ipapwd_pre_mod(Slapi_PBlock *pb)
+{
+ struct ipapwd_krbcfg *krbcfg = NULL;
+ char *errMesg = NULL;
+ LDAPMod **mods;
+ LDAPMod *lmod;
+ Slapi_Mods *smods = NULL;
+ char *userpw = NULL;
+ char *unhashedpw = NULL;
+ char *dn = NULL;
+ Slapi_DN *tmp_dn;
+ struct slapi_entry *e = NULL;
+ struct ipapwd_operation *pwdop = NULL;
+ void *op;
+ int is_repl_op, is_pwd_op, is_root, is_krb, is_smb, is_ipant;
+ int has_krb_keys = 0;
+ int has_history = 0;
+ int gen_krb_keys = 0;
+ int is_magic_regen = 0;
+ int ret, rc;
+
+ LOG_TRACE( "=>\n");
+
+ ret = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &is_repl_op);
+ if (ret != 0) {
+ LOG_FATAL("slapi_pblock_get failed!?\n");
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ /* pass through if this is a replicated operation */
+ if (is_repl_op) {
+ rc = LDAP_SUCCESS;
+ goto done;
+ }
+
+ /* grab the mods - we'll put them back later with
+ * our modifications appended
+ */
+ slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
+ smods = slapi_mods_new();
+ slapi_mods_init_passin(smods, mods);
+
+ /* In the first pass,
+ * only check there is anything we are interested in */
+ is_pwd_op = 0;
+ lmod = slapi_mods_get_first_mod(smods);
+ while (lmod) {
+ struct berval *bv;
+
+ if (slapi_attr_types_equivalent(lmod->mod_type, SLAPI_USERPWD_ATTR)) {
+ /* check op filtering out LDAP_MOD_BVALUES */
+ switch (lmod->mod_op & 0x0f) {
+ case LDAP_MOD_ADD:
+ case LDAP_MOD_REPLACE:
+ is_pwd_op = 1;
+ default:
+ break;
+ }
+ } else if (slapi_attr_types_equivalent(lmod->mod_type, "ipaNTHash")) {
+ /* check op filtering out LDAP_MOD_BVALUES */
+ switch (lmod->mod_op & 0x0f) {
+ case LDAP_MOD_ADD:
+ if (!lmod->mod_bvalues ||
+ !lmod->mod_bvalues[0]) {
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+ bv = lmod->mod_bvalues[0];
+ if ((bv->bv_len >= NTHASH_REGEN_LEN -1) &&
+ (bv->bv_len <= NTHASH_REGEN_LEN) &&
+ (strncmp(NTHASH_REGEN_VAL,
+ bv->bv_val, bv->bv_len) == 0)) {
+ is_magic_regen = 1;
+ /* make sure the database will later ignore this mod */
+ slapi_mods_remove(smods);
+ }
+ default:
+ break;
+ }
+ } else if (slapi_attr_types_equivalent(lmod->mod_type,
+ "unhashed#user#password")) {
+ /* we check for unahsehd password here so that we are sure to
+ * catch them early, before further checks go on, this helps
+ * checking LDAP_MOD_DELETE operations in some corner cases later.
+ * We keep only the last one if multiple are provided for any
+ * reason */
+ if (!lmod->mod_bvalues ||
+ !lmod->mod_bvalues[0]) {
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+ bv = lmod->mod_bvalues[0];
+ slapi_ch_free_string(&unhashedpw);
+ unhashedpw = slapi_ch_malloc(bv->bv_len+1);
+ if (!unhashedpw) {
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+ memcpy(unhashedpw, bv->bv_val, bv->bv_len);
+ unhashedpw[bv->bv_len] = '\0';
+ }
+ lmod = slapi_mods_get_next_mod(smods);
+ }
+
+ /* If userPassword is not modified check if this is a request to generate
+ * NT hashes otherwise we are done here */
+ if (!is_pwd_op && !is_magic_regen) {
+ rc = LDAP_SUCCESS;
+ goto done;
+ }
+
+ /* OK we have something interesting here, start checking for
+ * pre-requisites */
+
+ /* Get target DN */
+ ret = slapi_pblock_get(pb, SLAPI_TARGET_DN, &dn);
+ if (ret) {
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ tmp_dn = slapi_sdn_new_dn_byref(dn);
+ if (tmp_dn) {
+ /* xxxPAR: Ideally SLAPI_MODIFY_EXISTING_ENTRY should be
+ * available but it turns out that is only true if you are
+ * a dbm backend pre-op plugin - lucky dbm backend pre-op
+ * plugins.
+ * I think that is wrong since the entry is useful for filter
+ * tests and schema checks and this plugin shouldn't be limited
+ * to a single backend type, but I don't want that fight right
+ * now so we go get the entry here
+ *
+ slapi_pblock_get( pb, SLAPI_MODIFY_EXISTING_ENTRY, &e);
+ */
+ ret = slapi_search_internal_get_entry(tmp_dn, 0, &e, ipapwd_plugin_id);
+ slapi_sdn_free(&tmp_dn);
+ if (ret != LDAP_SUCCESS) {
+ LOG("Failed to retrieve entry?!\n");
+ rc = LDAP_NO_SUCH_OBJECT;
+ goto done;
+ }
+ }
+
+ rc = ipapwd_entry_checks(pb, e,
+ &is_root, &is_krb, &is_smb, &is_ipant,
+ SLAPI_USERPWD_ATTR, SLAPI_ACL_WRITE);
+ if (rc) {
+ goto done;
+ }
+
+ rc = ipapwd_gen_checks(pb, &errMesg, &krbcfg, IPAPWD_CHECK_DN);
+ if (rc) {
+ goto done;
+ }
+
+ if (!is_pwd_op) {
+ /* This may be a magic op to ask us to generate the NT hashes */
+ if (is_magic_regen) {
+ /* Make sense to call only if this entry has krb keys to source
+ * the nthash from */
+ if (is_krb) {
+ rc = ipapwd_regen_nthash(pb, smods, dn, e, krbcfg);
+ } else {
+ rc = LDAP_UNWILLING_TO_PERFORM;
+ }
+ } else {
+ rc = LDAP_OPERATIONS_ERROR;
+ }
+ goto done;
+ }
+
+ /* run through the mods again and adjust flags if operations affect them */
+ lmod = slapi_mods_get_first_mod(smods);
+ while (lmod) {
+ struct berval *bv;
+
+ if (slapi_attr_types_equivalent(lmod->mod_type, SLAPI_USERPWD_ATTR)) {
+ /* check op filtering out LDAP_MOD_BVALUES */
+ switch (lmod->mod_op & 0x0f) {
+ case LDAP_MOD_ADD:
+ /* FIXME: should we try to track cases where we would end up
+ * with multiple userPassword entries ?? */
+ case LDAP_MOD_REPLACE:
+ is_pwd_op = 1;
+ if (!lmod->mod_bvalues ||
+ !lmod->mod_bvalues[0]) {
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+ bv = lmod->mod_bvalues[0];
+ slapi_ch_free_string(&userpw);
+ userpw = slapi_ch_malloc(bv->bv_len+1);
+ if (!userpw) {
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+ memcpy(userpw, bv->bv_val, bv->bv_len);
+ userpw[bv->bv_len] = '\0';
+ break;
+ case LDAP_MOD_DELETE:
+ /* reset only if we are deleting all values, or the exact
+ * same value previously set, otherwise we are just trying to
+ * add a new value and delete an existing one */
+ if (!lmod->mod_bvalues ||
+ !lmod->mod_bvalues[0]) {
+ is_pwd_op = 0;
+ } else {
+ bv = lmod->mod_bvalues[0];
+ if ((userpw &&
+ strncmp(userpw, bv->bv_val, bv->bv_len) == 0) ||
+ (unhashedpw &&
+ strncmp(unhashedpw, bv->bv_val, bv->bv_len) == 0)) {
+ is_pwd_op = 0;
+ }
+ }
+ default:
+ break;
+ }
+
+ } else if (slapi_attr_types_equivalent(lmod->mod_type,
+ SLAPI_ATTR_OBJECTCLASS)) {
+ int i;
+ /* check op filtering out LDAP_MOD_BVALUES */
+ switch (lmod->mod_op & 0x0f) {
+ case LDAP_MOD_REPLACE:
+ /* if objectclasses are replaced we need to start clean with
+ * flags, so we sero them out and see if they get set again */
+ is_krb = 0;
+ is_smb = 0;
+ is_ipant = 0;
+
+ case LDAP_MOD_ADD:
+ if (!lmod->mod_bvalues ||
+ !lmod->mod_bvalues[0]) {
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+ for (i = 0; (bv = lmod->mod_bvalues[i]) != NULL; i++) {
+ if (strncasecmp("krbPrincipalAux",
+ bv->bv_val, bv->bv_len) == 0) {
+ is_krb = 1;
+ } else if (strncasecmp("sambaSamAccount",
+ bv->bv_val, bv->bv_len) == 0) {
+ is_smb = 1;
+ } else if (strncasecmp("ipaNTUserAttrs",
+ bv->bv_val, bv->bv_len) == 0) {
+ is_ipant = 1;
+ }
+ }
+
+ break;
+
+ case LDAP_MOD_DELETE:
+ /* can this happen for objectclasses ? */
+ is_krb = 0;
+ is_smb = 0;
+ is_ipant = 0;
+
+ default:
+ break;
+ }
+
+ } else if (slapi_attr_types_equivalent(lmod->mod_type,
+ "krbPrincipalKey")) {
+
+ /* if we are getting a krbPrincipalKey, also avoid regenerating
+ * the keys, it means kadmin has alredy done the job and is simply
+ * keeping userPassword and sambaXXPAssword in sync */
+
+ /* we also check we have enough authority */
+ if (is_root) {
+ has_krb_keys = 1;
+ }
+
+ } else if (slapi_attr_types_equivalent(lmod->mod_type,
+ "passwordHistory")) {
+
+ /* if we are getting a passwordHistory, also avoid regenerating
+ * the hashes, it means kadmin has alredy done the job and is
+ * simply keeping userPassword and sambaXXPAssword in sync */
+
+ /* we also check we have enough authority */
+ if (is_root) {
+ has_history = 1;
+ }
+ }
+
+ lmod = slapi_mods_get_next_mod(smods);
+ }
+
+ if (is_krb) {
+ if (has_krb_keys) {
+ gen_krb_keys = 0;
+ } else {
+ gen_krb_keys = 1;
+ }
+ }
+
+ /* It seem like we have determined that the end result will be deletion of
+ * the userPassword attribute, so we have no more business here */
+ if (! is_pwd_op) {
+ rc = LDAP_SUCCESS;
+ goto done;
+ }
+
+ /* Check this is a clear text password, or refuse operation (only if we need
+ * to comput other hashes */
+ if (! unhashedpw && (gen_krb_keys || is_smb || is_ipant)) {
+ if ('{' == userpw[0]) {
+ if (0 == strncasecmp(userpw, "{CLEAR}", strlen("{CLEAR}"))) {
+ unhashedpw = slapi_ch_strdup(&userpw[strlen("{CLEAR}")]);
+ if (NULL == unhashedpw) {
+ LOG_OOM();
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+ slapi_ch_free_string(&userpw);
+
+ } else if (slapi_is_encoded(userpw)) {
+
+ LOG("Pre-Encoded passwords are not valid\n");
+ errMesg = "Pre-Encoded passwords are not valid\n";
+ rc = LDAP_CONSTRAINT_VIOLATION;
+ goto done;
+ }
+ }
+ }
+
+ /* time to get the operation handler */
+ ret = slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ if (ret != 0) {
+ LOG_FATAL("slapi_pblock_get failed!?\n");
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ pwdop = slapi_get_object_extension(ipapwd_op_ext_list.object_type,
+ op, ipapwd_op_ext_list.handle);
+ if (NULL == pwdop) {
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ pwdop->is_krb = is_krb;
+ pwdop->pwd_op = IPAPWD_OP_MOD;
+ pwdop->pwdata.password = slapi_ch_strdup(unhashedpw);
+ pwdop->pwdata.changetype = IPA_CHANGETYPE_NORMAL;
+ pwdop->skip_history = has_history;
+ pwdop->skip_keys = has_krb_keys;
+
+ if (is_root) {
+ pwdop->pwdata.changetype = IPA_CHANGETYPE_DSMGR;
+ } else {
+ char *binddn;
+ Slapi_DN *bdn, *tdn;
+ int i;
+
+ /* Check Bind DN */
+ slapi_pblock_get(pb, SLAPI_CONN_DN, &binddn);
+ bdn = slapi_sdn_new_dn_byref(binddn);
+ tdn = slapi_sdn_new_dn_byref(dn);
+
+ /* if the change is performed by someone else,
+ * it is an admin change that will require a new
+ * password change immediately as per our IPA policy */
+ if (slapi_sdn_compare(bdn, tdn)) {
+ pwdop->pwdata.changetype = IPA_CHANGETYPE_ADMIN;
+
+ /* if it is a passsync manager we also need to skip resets */
+ for (i = 0; i < krbcfg->num_passsync_mgrs; i++) {
+ if (strcasecmp(krbcfg->passsync_mgrs[i], binddn) == 0) {
+ pwdop->pwdata.changetype = IPA_CHANGETYPE_DSMGR;
+ break;
+ }
+ }
+
+ }
+
+ slapi_sdn_free(&bdn);
+ slapi_sdn_free(&tdn);
+
+ }
+
+ pwdop->pwdata.dn = slapi_ch_strdup(dn);
+ pwdop->pwdata.timeNow = time(NULL);
+ pwdop->pwdata.target = e;
+
+ /* if krb keys are being set by an external agent we assume password
+ * policies have been properly checked already, so we check them only
+ * if no krb keys are available */
+ if (has_krb_keys == 0) {
+ ret = ipapwd_CheckPolicy(&pwdop->pwdata);
+ if (ret) {
+ errMesg = ipapwd_error2string(ret);
+ rc = LDAP_CONSTRAINT_VIOLATION;
+ goto done;
+ }
+ }
+
+ if (gen_krb_keys || is_smb || is_ipant) {
+
+ Slapi_Value **svals = NULL;
+ Slapi_Value **ntvals = NULL;
+ char *nt = NULL;
+ char *lm = NULL;
+
+ rc = ipapwd_gen_hashes(krbcfg, &pwdop->pwdata, unhashedpw,
+ gen_krb_keys, is_smb, is_ipant,
+ &svals, &nt, &lm, &ntvals, &errMesg);
+ if (rc) {
+ goto done;
+ }
+
+ if (svals) {
+ /* replace values */
+ slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE,
+ "krbPrincipalKey", svals);
+ ipapwd_free_slapi_value_array(&svals);
+ }
+
+ if (lm && is_smb) {
+ /* replace value */
+ slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
+ "sambaLMPassword", lm);
+ slapi_ch_free_string(&lm);
+ }
+ if (nt && is_smb) {
+ /* replace value */
+ slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
+ "sambaNTPassword", nt);
+ slapi_ch_free_string(&nt);
+ }
+
+ if (ntvals && is_ipant) {
+ slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE,
+ "ipaNTHash", ntvals);
+ ipapwd_free_slapi_value_array(&ntvals);
+ }
+
+ if (is_smb) {
+ /* with samba integration we need to also set sambaPwdLastSet or
+ * samba will decide the user has to change the password again */
+ if (pwdop->pwdata.changetype == IPA_CHANGETYPE_ADMIN) {
+ /* if it is an admin change instead we need to let know to
+ * samba as well that the use rmust change its password */
+ slapi_entry_attr_set_long(e, "sambaPwdLastset", 0L);
+ } else {
+ slapi_entry_attr_set_long(e, "sambaPwdLastset",
+ (long)pwdop->pwdata.timeNow);
+ }
+ }
+ }
+
+ rc = LDAP_SUCCESS;
+
+done:
+ free_ipapwd_krbcfg(&krbcfg);
+ slapi_ch_free_string(&userpw); /* just to be sure */
+ slapi_ch_free_string(&unhashedpw); /* we copied it to pwdop */
+ if (e) slapi_entry_free(e); /* this is a copy in this function */
+ if (pwdop) pwdop->pwdata.target = NULL;
+
+ /* put back a, possibly modified, set of mods */
+ if (smods) {
+ mods = slapi_mods_get_ldapmods_passout(smods);
+ if (slapi_pblock_set(pb, SLAPI_MODIFY_MODS, mods)) {
+ LOG_FATAL("slapi_pblock_set failed!\n");
+ rc = LDAP_OPERATIONS_ERROR;
+ }
+ slapi_mods_free(&smods);
+ }
+
+ if (rc != LDAP_SUCCESS) {
+ slapi_send_ldap_result(pb, rc, NULL, errMesg, 0, NULL);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int ipapwd_regen_nthash(Slapi_PBlock *pb, Slapi_Mods *smods,
+ char *dn, struct slapi_entry *entry,
+ struct ipapwd_krbcfg *krbcfg)
+{
+ Slapi_Attr *attr;
+ Slapi_Value *value;
+ const struct berval *val;
+ struct berval *ntvals[2] = { NULL, NULL };
+ struct berval bval;
+ krb5_key_data *keys;
+ int num_keys;
+ int mkvno;
+ int ret;
+ int i;
+
+ ret = slapi_entry_attr_find(entry, "ipaNTHash", &attr);
+ if (ret == 0) {
+ /* We refuse to regen if there is already a value */
+ return LDAP_CONSTRAINT_VIOLATION;
+ }
+
+ /* ok let's see if we can find the RC4 hash in the keys */
+ ret = slapi_entry_attr_find(entry, "krbPrincipalKey", &attr);
+ if (ret) {
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+
+ ret = slapi_attr_first_value(attr, &value);
+ if (ret) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ val = slapi_value_get_berval(value);
+ if (!val) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ ret = ber_decode_krb5_key_data((struct berval *)val,
+ &mkvno, &num_keys, &keys);
+ if (ret) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ ret = LDAP_UNWILLING_TO_PERFORM;
+
+ for (i = 0; i < num_keys; i++) {
+ char nthash[16];
+ krb5_enc_data cipher;
+ krb5_data plain;
+ krb5_int16 t;
+
+ if (keys[i].key_data_type[0] != ENCTYPE_ARCFOUR_HMAC) {
+ continue;
+ }
+
+ memcpy(&t, keys[i].key_data_contents[0], 2);
+ plain.length = le16toh(t);
+ if (plain.length != 16) {
+ continue;
+ }
+ plain.data = nthash;
+
+ memset(&cipher, 0, sizeof(krb5_enc_data));
+ cipher.enctype = krbcfg->kmkey->enctype;
+ cipher.ciphertext.length = keys[i].key_data_length[0] - 2;
+ cipher.ciphertext.data = ((char *)keys[i].key_data_contents[0]) + 2;
+
+ ret = krb5_c_decrypt(krbcfg->krbctx, krbcfg->kmkey,
+ 0, NULL, &cipher, &plain);
+ if (ret) {
+ ret = LDAP_OPERATIONS_ERROR;
+ break;
+ }
+
+ bval.bv_val = nthash;
+ bval.bv_len = 16;
+ ntvals[0] = &bval;
+
+ slapi_mods_add_modbvps(smods, LDAP_MOD_ADD, "ipaNTHash", ntvals);
+
+ ret = LDAP_SUCCESS;
+ break;
+ }
+
+ ipa_krb5_free_key_data(keys, num_keys);
+
+ return ret;
+}
+
+static int ipapwd_post_op(Slapi_PBlock *pb)
+{
+ void *op;
+ struct ipapwd_operation *pwdop = NULL;
+ Slapi_Mods *smods;
+ Slapi_Value **pwvals;
+ struct tm utctime;
+ char timestr[GENERALIZED_TIME_LENGTH+1];
+ int ret;
+ char *errMsg = "Internal operations error\n";
+ struct ipapwd_krbcfg *krbcfg = NULL;
+ char *principal = NULL;
+ Slapi_Value *ipahost;
+
+ LOG_TRACE("=>\n");
+
+ /* time to get the operation handler */
+ ret = slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ if (ret != 0) {
+ LOG_FATAL("slapi_pblock_get failed!?\n");
+ return 0;
+ }
+
+ pwdop = slapi_get_object_extension(ipapwd_op_ext_list.object_type,
+ op, ipapwd_op_ext_list.handle);
+ if (NULL == pwdop) {
+ LOG_FATAL("Internal error, couldn't find pluginextension ?!\n");
+ return 0;
+ }
+
+ /* not interesting */
+ if (IPAPWD_OP_NULL == pwdop->pwd_op)
+ return 0;
+
+ if ( ! (pwdop->is_krb)) {
+ LOG("Not a kerberos user, ignore krb attributes\n");
+ return 0;
+ }
+
+ if (pwdop->skip_keys && pwdop->skip_history) {
+ /* nothing to do, caller already set all interesting attributes */
+ return 0;
+ }
+
+ ret = ipapwd_gen_checks(pb, &errMsg, &krbcfg, 0);
+ if (ret != 0) {
+ LOG_FATAL("ipapwd_gen_checks failed!?\n");
+ return 0;
+ }
+
+ /* prepare changes that can be made only as root */
+ smods = slapi_mods_new();
+
+ /* This was a mod operation on an existing entry, make sure we also update
+ * the password history based on the entry we saved from the pre-op */
+ if (IPAPWD_OP_MOD == pwdop->pwd_op && !pwdop->skip_history) {
+ Slapi_DN *tmp_dn = slapi_sdn_new_dn_byref(pwdop->pwdata.dn);
+ if (tmp_dn) {
+ ret = slapi_search_internal_get_entry(tmp_dn, 0,
+ &pwdop->pwdata.target,
+ ipapwd_plugin_id);
+ slapi_sdn_free(&tmp_dn);
+ if (ret != LDAP_SUCCESS) {
+ LOG("Failed to retrieve entry?!\n");
+ goto done;
+ }
+ }
+ pwvals = ipapwd_setPasswordHistory(smods, &pwdop->pwdata);
+ if (pwvals) {
+ slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE,
+ "passwordHistory", pwvals);
+ }
+ }
+
+ /* we assume that krb attributes are properly updated too if keys were
+ * passed in */
+ if (!pwdop->skip_keys) {
+ /* Don't set a last password change or expiration on host passwords.
+ * krbLastPwdChange is used to tell whether we have a valid keytab.
+ * If we set it on userPassword it confuses enrollment.
+ * If krbPasswordExpiration is set on a host entry then the keytab
+ * will appear to be expired.
+ *
+ * When a host is issued a keytab these attributes get set properly by
+ * ipapwd_setkeytab().
+ */
+ ipahost = slapi_value_new_string("ipaHost");
+ if (!pwdop->pwdata.target ||
+ (slapi_entry_attr_has_syntax_value(pwdop->pwdata.target,
+ SLAPI_ATTR_OBJECTCLASS, ipahost)) == 0) {
+ /* set Password Expiration date */
+ if (!gmtime_r(&(pwdop->pwdata.expireTime), &utctime)) {
+ LOG_FATAL("failed to parse expiration date (buggy gmtime_r ?)\n");
+ goto done;
+ }
+ strftime(timestr, GENERALIZED_TIME_LENGTH+1,
+ "%Y%m%d%H%M%SZ", &utctime);
+ slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
+ "krbPasswordExpiration", timestr);
+
+ /* change Last Password Change field with the current date */
+ if (!gmtime_r(&(pwdop->pwdata.timeNow), &utctime)) {
+ LOG_FATAL("failed to parse current date (buggy gmtime_r ?)\n");
+ slapi_value_free(&ipahost);
+ goto done;
+ }
+ strftime(timestr, GENERALIZED_TIME_LENGTH+1,
+ "%Y%m%d%H%M%SZ", &utctime);
+ slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
+ "krbLastPwdChange", timestr);
+ }
+ slapi_value_free(&ipahost);
+ }
+
+ ret = ipapwd_apply_mods(pwdop->pwdata.dn, smods);
+ if (ret)
+ LOG("Failed to set additional password attributes in the post-op!\n");
+
+ if (!pwdop->skip_keys) {
+ if (pwdop->pwdata.changetype == IPA_CHANGETYPE_NORMAL) {
+ principal = slapi_entry_attr_get_charptr(pwdop->pwdata.target,
+ "krbPrincipalName");
+ } else {
+ principal = slapi_ch_smprintf("root/admin@%s", krbcfg->realm);
+ }
+ ipapwd_set_extradata(pwdop->pwdata.dn, principal, pwdop->pwdata.timeNow);
+ }
+
+done:
+ if (pwdop && pwdop->pwdata.target) slapi_entry_free(pwdop->pwdata.target);
+ slapi_mods_free(&smods);
+ slapi_ch_free_string(&principal);
+ free_ipapwd_krbcfg(&krbcfg);
+ return 0;
+}
+
+/* PRE BIND Operation:
+ * Used for password migration from DS to IPA.
+ * Gets the clean text password, authenticates the user and generates
+ * a kerberos key if missing.
+ * Person to blame if anything blows up: Pavel Zuna <pzuna@redhat.com>
+ */
+static int ipapwd_pre_bind(Slapi_PBlock *pb)
+{
+ struct ipapwd_krbcfg *krbcfg = NULL;
+ struct ipapwd_data pwdata;
+ struct berval *credentials; /* bind credentials */
+ Slapi_Entry *entry = NULL;
+ Slapi_Value **pwd_values = NULL; /* values of userPassword attribute */
+ Slapi_Value *value = NULL;
+ Slapi_Attr *attr = NULL;
+ struct tm expire_tm;
+ char *errMesg = "Internal operations error\n"; /* error message */
+ char *expire = NULL; /* passwordExpirationTime attribute value */
+ char *dn = NULL; /* bind DN */
+ Slapi_Value *objectclass;
+ int method; /* authentication method */
+ int ret = 0;
+ char *principal = NULL;
+
+ LOG_TRACE("=>\n");
+
+ /* get BIND parameters */
+ ret |= slapi_pblock_get(pb, SLAPI_BIND_TARGET, &dn);
+ ret |= slapi_pblock_get(pb, SLAPI_BIND_METHOD, &method);
+ ret |= slapi_pblock_get(pb, SLAPI_BIND_CREDENTIALS, &credentials);
+ if (ret) {
+ LOG_FATAL("slapi_pblock_get failed!?\n");
+ goto done;
+ }
+
+ /* we're only interested in simple authentication */
+ if (method != LDAP_AUTH_SIMPLE)
+ goto done;
+
+ /* list of attributes to retrieve */
+ const char *attrs_list[] = {SLAPI_USERPWD_ATTR, "krbprincipalkey", "uid",
+ "krbprincipalname", "objectclass",
+ "passwordexpirationtime", "passwordhistory",
+ NULL};
+
+ /* retrieve user entry */
+ ret = ipapwd_getEntry(dn, &entry, (char **) attrs_list);
+ if (ret) {
+ LOG("failed to retrieve user entry: %s\n", dn);
+ goto done;
+ }
+
+ /* check the krbPrincipalName attribute is present */
+ ret = slapi_entry_attr_find(entry, "krbprincipalname", &attr);
+ if (ret) {
+ LOG("no krbPrincipalName in user entry: %s\n", dn);
+ goto done;
+ }
+
+ /* we aren't interested in host principals */
+ objectclass = slapi_value_new_string("ipaHost");
+ if ((slapi_entry_attr_has_syntax_value(entry, SLAPI_ATTR_OBJECTCLASS, objectclass)) == 1) {
+ slapi_value_free(&objectclass);
+ goto done;
+ }
+ slapi_value_free(&objectclass);
+
+ /* check the krbPrincipalKey attribute is NOT present */
+ ret = slapi_entry_attr_find(entry, "krbprincipalkey", &attr);
+ if (!ret) {
+ LOG("kerberos key already present in user entry: %s\n", dn);
+ goto done;
+ }
+
+ /* retrieve userPassword attribute */
+ ret = slapi_entry_attr_find(entry, SLAPI_USERPWD_ATTR, &attr);
+ if (ret) {
+ LOG("no " SLAPI_USERPWD_ATTR " in user entry: %s\n", dn);
+ goto done;
+ }
+
+ /* get the number of userPassword values and allocate enough memory */
+ slapi_attr_get_numvalues(attr, &ret);
+ ret = (ret + 1) * sizeof (Slapi_Value *);
+ pwd_values = (Slapi_Value **) slapi_ch_malloc(ret);
+ if (!pwd_values) {
+ /* probably not required: should terminate the server anyway */
+ LOG_OOM();
+ goto done;
+ }
+ /* zero-fill the allocated memory; we need the array ending with NULL */
+ memset(pwd_values, 0, ret);
+
+ /* retrieve userPassword values */
+ ret = slapi_attr_first_value(attr, &value);
+ while (ret != -1) {
+ pwd_values[ret] = value;
+ ret = slapi_attr_next_value(attr, ret, &value);
+ }
+
+ /* check if BIND password and userPassword match */
+ value = slapi_value_new_berval(credentials);
+ ret = slapi_pw_find_sv(pwd_values, value);
+
+ /* free before checking ret; we might not get a chance later */
+ slapi_ch_free((void **) &pwd_values);
+ slapi_value_free(&value);
+
+ if (ret) {
+ LOG("invalid BIND password for user entry: %s\n", dn);
+ goto done;
+ }
+
+ /* general checks */
+ ret = ipapwd_gen_checks(pb, &errMesg, &krbcfg, IPAPWD_CHECK_DN);
+ if (ret) {
+ LOG_FATAL("Generic checks failed: %s", errMesg);
+ goto done;
+ }
+
+ /* delete userPassword - a new one will be generated later */
+ /* this is needed, otherwise ipapwd_CheckPolicy will think
+ * we're changing the password to its previous value
+ * and force a password change on next login */
+ ret = slapi_entry_attr_delete(entry, SLAPI_USERPWD_ATTR);
+ if (ret) {
+ LOG_FATAL("failed to delete " SLAPI_USERPWD_ATTR "\n");
+ goto done;
+ }
+
+ /* prepare data for kerberos key generation */
+ memset(&pwdata, 0, sizeof (pwdata));
+ pwdata.dn = dn;
+ pwdata.target = entry;
+ pwdata.password = credentials->bv_val;
+ pwdata.timeNow = time(NULL);
+ pwdata.changetype = IPA_CHANGETYPE_NORMAL;
+
+ /* keep password expiration time from DS, if possible */
+ expire = slapi_entry_attr_get_charptr(entry, "passwordexpirationtime");
+ if (expire) {
+ memset(&expire_tm, 0, sizeof (expire_tm));
+ if (strptime(expire, "%Y%m%d%H%M%SZ", &expire_tm))
+ pwdata.expireTime = mktime(&expire_tm);
+ }
+
+ /* check password policy */
+ ret = ipapwd_CheckPolicy(&pwdata);
+ if (ret) {
+ /* Password fails to meet IPA password policy,
+ * force user to change his password next time he logs in. */
+ LOG("password policy check failed on user entry: %s"
+ " (force password change on next login)\n", dn);
+ pwdata.expireTime = time(NULL);
+ }
+
+ /* generate kerberos keys */
+ ret = ipapwd_SetPassword(krbcfg, &pwdata, 1);
+ if (ret) {
+ LOG("failed to set kerberos key for user entry: %s\n", dn);
+ goto done;
+ }
+
+ /* we need to make sure the ExtraData is set, otherwise kadmin
+ * will not like the object */
+ principal = slapi_entry_attr_get_charptr(entry, "krbPrincipalName");
+ if (!principal) {
+ LOG_OOM();
+ goto done;
+ }
+ ipapwd_set_extradata(pwdata.dn, principal, pwdata.timeNow);
+
+ LOG("kerberos key generated for user entry: %s\n", dn);
+
+done:
+ slapi_ch_free_string(&principal);
+ slapi_ch_free_string(&expire);
+ if (entry)
+ slapi_entry_free(entry);
+ free_ipapwd_krbcfg(&krbcfg);
+
+ return 0;
+}
+
+
+
+/* Init pre ops */
+int ipapwd_pre_init(Slapi_PBlock *pb)
+{
+ int ret;
+
+ ret = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01);
+ if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&ipapwd_plugin_desc);
+ if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_BIND_FN, (void *)ipapwd_pre_bind);
+ if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_ADD_FN, (void *)ipapwd_pre_add);
+ if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_MODIFY_FN, (void *)ipapwd_pre_mod);
+
+ return ret;
+}
+
+int ipapwd_pre_init_betxn(Slapi_PBlock *pb)
+{
+ int ret;
+
+ ret = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01);
+ if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&ipapwd_plugin_desc);
+ if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_BE_TXN_PRE_ADD_FN, (void *)ipapwd_pre_add);
+ if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_BE_TXN_PRE_MODIFY_FN, (void *)ipapwd_pre_mod);
+
+ return ret;
+}
+
+/* Init post ops */
+int ipapwd_post_init(Slapi_PBlock *pb)
+{
+ int ret;
+
+ ret = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01);
+ if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&ipapwd_plugin_desc);
+ if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_ADD_FN, (void *)ipapwd_post_op);
+ if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODIFY_FN, (void *)ipapwd_post_op);
+
+ return ret;
+}
+
+int ipapwd_post_init_betxn(Slapi_PBlock *pb)
+{
+ int ret;
+
+ ret = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01);
+ if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&ipapwd_plugin_desc);
+ if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_BE_TXN_POST_ADD_FN, (void *)ipapwd_post_op);
+ if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN, (void *)ipapwd_post_op);
+
+ return ret;
+}