ipa/0005-Remove-unnecessary-prefixes-from-ipa-pwd-extop-files.patch
Rob Crittenden 12216fc83f Add OTP patches and patch to fix 389-ds ccache
The OTP patches add basic support for TOTP and Radius.

The 389-ds patch sets KRB5CCNAME in /etc/sysconfig/dirsrv so it can
get a usable ccache.
2013-05-14 16:28:58 -04:00

5604 lines
181 KiB
Diff

From fe0b5a2cf772c3f85ca2c030b5be2dd0cd9c041b Mon Sep 17 00:00:00 2001
From: Nathaniel McCallum <npmccallum@redhat.com>
Date: Thu, 9 May 2013 14:43:17 -0400
Subject: [PATCH 5/6] Remove unnecessary prefixes from ipa-pwd-extop files
---
.../ipa-slapi-plugins/ipa-pwd-extop/Makefile.am | 6 +-
daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c | 1107 ++++++++++++++++
daemons/ipa-slapi-plugins/ipa-pwd-extop/encoding.c | 291 +++++
daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h | 6 +-
.../ipa-pwd-extop/ipapwd_common.c | 1107 ----------------
.../ipa-pwd-extop/ipapwd_encoding.c | 291 -----
.../ipa-pwd-extop/ipapwd_prepost.c | 1349 --------------------
daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c | 1349 ++++++++++++++++++++
8 files changed, 2753 insertions(+), 2753 deletions(-)
create mode 100644 daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c
create mode 100644 daemons/ipa-slapi-plugins/ipa-pwd-extop/encoding.c
delete mode 100644 daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_common.c
delete mode 100644 daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_encoding.c
delete mode 100644 daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_prepost.c
create mode 100644 daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am b/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am
index ec98f95..90f940f 100644
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am
+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am
@@ -30,9 +30,9 @@ plugin_LTLIBRARIES = \
$(NULL)
libipa_pwd_extop_la_SOURCES = \
- ipapwd_common.c \
- ipapwd_encoding.c \
- ipapwd_prepost.c \
+ common.c \
+ encoding.c \
+ prepost.c \
ipa_pwd_extop.c \
$(KRB5_UTIL_SRCS) \
$(NULL)
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c
new file mode 100644
index 0000000..bb1d96a
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c
@@ -0,0 +1,1107 @@
+/** 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 **/
+
+#include "ipapwd.h"
+#include "util.h"
+
+/* Type of connection for this operation;*/
+#define LDAP_EXTOP_PASSMOD_CONN_SECURE
+
+/* Uncomment the following #undef FOR TESTING:
+ * allows non-SSL connections to use the password change extended op */
+/* #undef LDAP_EXTOP_PASSMOD_CONN_SECURE */
+
+extern void *ipapwd_plugin_id;
+extern const char *ipa_realm_dn;
+extern const char *ipa_etc_config_dn;
+extern const char *ipa_pwd_config_dn;
+
+/* These are the default enc:salt types if nothing is defined.
+ * TODO: retrieve the configure set of ecntypes either from the
+ * kfc.conf file or by synchronizing the file content into
+ * the directory */
+static const char *ipapwd_def_encsalts[] = {
+ "des3-hmac-sha1:normal",
+/* "arcfour-hmac:normal",
+ "des-hmac-sha1:normal",
+ "des-cbc-md5:normal", */
+ "des-cbc-crc:normal",
+/* "des-cbc-crc:v4",
+ "des-cbc-crc:afs3", */
+ NULL
+};
+
+static struct ipapwd_krbcfg *ipapwd_getConfig(void)
+{
+ krb5_error_code krberr;
+ struct ipapwd_krbcfg *config = NULL;
+ krb5_keyblock *kmkey = NULL;
+ Slapi_Entry *realm_entry = NULL;
+ Slapi_Entry *config_entry = NULL;
+ Slapi_Attr *a;
+ Slapi_Value *v;
+ BerElement *be = NULL;
+ ber_tag_t tag, tvno;
+ ber_int_t ttype;
+ const struct berval *bval;
+ struct berval *mkey = NULL;
+ char **encsalts;
+ char **tmparray;
+ char *tmpstr;
+ int i, ret;
+
+ config = calloc(1, sizeof(struct ipapwd_krbcfg));
+ if (!config) {
+ LOG_OOM();
+ goto free_and_error;
+ }
+ kmkey = calloc(1, sizeof(krb5_keyblock));
+ if (!kmkey) {
+ LOG_OOM();
+ goto free_and_error;
+ }
+ config->kmkey = kmkey;
+
+ krberr = krb5_init_context(&config->krbctx);
+ if (krberr) {
+ LOG_FATAL("krb5_init_context failed\n");
+ goto free_and_error;
+ }
+
+ ret = krb5_get_default_realm(config->krbctx, &config->realm);
+ if (ret) {
+ LOG_FATAL("Failed to get default realm?!\n");
+ goto free_and_error;
+ }
+
+ /* get the Realm Container entry */
+ ret = ipapwd_getEntry(ipa_realm_dn, &realm_entry, NULL);
+ if (ret != LDAP_SUCCESS) {
+ LOG_FATAL("No realm Entry?\n");
+ goto free_and_error;
+ }
+
+ /*** get the Kerberos Master Key ***/
+
+ ret = slapi_entry_attr_find(realm_entry, "krbMKey", &a);
+ if (ret == -1) {
+ LOG_FATAL("No master key??\n");
+ goto free_and_error;
+ }
+
+ /* there should be only one value here */
+ ret = slapi_attr_first_value(a, &v);
+ if (ret == -1) {
+ LOG_FATAL("No master key??\n");
+ goto free_and_error;
+ }
+
+ bval = slapi_value_get_berval(v);
+ if (!bval) {
+ LOG_FATAL("Error retrieving master key berval\n");
+ goto free_and_error;
+ }
+
+ be = ber_init(discard_const(bval));
+ if (!be) {
+ LOG_FATAL("ber_init() failed!\n");
+ goto free_and_error;
+ }
+
+ tag = ber_scanf(be, "{i{iO}}", &tvno, &ttype, &mkey);
+ if (tag == LBER_ERROR) {
+ LOG_FATAL("Bad Master key encoding ?!\n");
+ goto free_and_error;
+ }
+
+ config->mkvno = tvno;
+ kmkey->magic = KV5M_KEYBLOCK;
+ kmkey->enctype = ttype;
+ kmkey->length = mkey->bv_len;
+ kmkey->contents = malloc(mkey->bv_len);
+ if (!kmkey->contents) {
+ LOG_OOM();
+ goto free_and_error;
+ }
+ memcpy(kmkey->contents, mkey->bv_val, mkey->bv_len);
+ ber_bvfree(mkey);
+ ber_free(be, 1);
+ mkey = NULL;
+ be = NULL;
+
+ /*** get the Supported Enc/Salt types ***/
+
+ encsalts = slapi_entry_attr_get_charray(realm_entry,
+ "krbSupportedEncSaltTypes");
+ if (encsalts) {
+ for (i = 0; encsalts[i]; i++) /* count */ ;
+ ret = parse_bval_key_salt_tuples(config->krbctx,
+ (const char * const *)encsalts, i,
+ &config->supp_encsalts,
+ &config->num_supp_encsalts);
+ slapi_ch_array_free(encsalts);
+ } else {
+ LOG("No configured salt types use defaults\n");
+ for (i = 0; ipapwd_def_encsalts[i]; i++) /* count */ ;
+ ret = parse_bval_key_salt_tuples(config->krbctx,
+ ipapwd_def_encsalts, i,
+ &config->supp_encsalts,
+ &config->num_supp_encsalts);
+ }
+ if (ret) {
+ LOG_FATAL("Can't get Supported EncSalt Types\n");
+ goto free_and_error;
+ }
+
+ /*** get the Preferred Enc/Salt types ***/
+
+ encsalts = slapi_entry_attr_get_charray(realm_entry,
+ "krbDefaultEncSaltTypes");
+ if (encsalts) {
+ for (i = 0; encsalts[i]; i++) /* count */ ;
+ ret = parse_bval_key_salt_tuples(config->krbctx,
+ (const char * const *)encsalts, i,
+ &config->pref_encsalts,
+ &config->num_pref_encsalts);
+ slapi_ch_array_free(encsalts);
+ } else {
+ LOG("No configured salt types use defaults\n");
+ for (i = 0; ipapwd_def_encsalts[i]; i++) /* count */ ;
+ ret = parse_bval_key_salt_tuples(config->krbctx,
+ ipapwd_def_encsalts, i,
+ &config->pref_encsalts,
+ &config->num_pref_encsalts);
+ }
+ if (ret) {
+ LOG_FATAL("Can't get Preferred EncSalt Types\n");
+ goto free_and_error;
+ }
+
+ slapi_entry_free(realm_entry);
+
+ /* get the Realm Container entry */
+ ret = ipapwd_getEntry(ipa_pwd_config_dn, &config_entry, NULL);
+ if (ret != LDAP_SUCCESS) {
+ LOG_FATAL("No config Entry? Impossible!\n");
+ goto free_and_error;
+ }
+ config->passsync_mgrs =
+ slapi_entry_attr_get_charray(config_entry, "passSyncManagersDNs");
+ /* now add Directory Manager, it is always added by default */
+ tmpstr = slapi_ch_strdup("cn=Directory Manager");
+ slapi_ch_array_add(&config->passsync_mgrs, tmpstr);
+ if (config->passsync_mgrs == NULL) {
+ LOG_OOM();
+ goto free_and_error;
+ }
+ for (i = 0; config->passsync_mgrs[i]; i++) /* count */ ;
+ config->num_passsync_mgrs = i;
+
+ slapi_entry_free(config_entry);
+
+ /* get the ipa etc/ipaConfig entry */
+ config->allow_lm_hash = false;
+ config->allow_nt_hash = false;
+ ret = ipapwd_getEntry(ipa_etc_config_dn, &config_entry, NULL);
+ if (ret != LDAP_SUCCESS) {
+ LOG_FATAL("No config Entry?\n");
+ goto free_and_error;
+ } else {
+ tmparray = slapi_entry_attr_get_charray(config_entry,
+ "ipaConfigString");
+ for (i = 0; tmparray && tmparray[i]; i++) {
+ if (strcasecmp(tmparray[i], "AllowLMhash") == 0) {
+ config->allow_lm_hash = true;
+ continue;
+ }
+ if (strcasecmp(tmparray[i], "AllowNThash") == 0) {
+ config->allow_nt_hash = true;
+ continue;
+ }
+ }
+ if (tmparray) slapi_ch_array_free(tmparray);
+ }
+
+ slapi_entry_free(config_entry);
+
+ return config;
+
+free_and_error:
+ if (mkey) ber_bvfree(mkey);
+ if (be) ber_free(be, 1);
+ if (kmkey) {
+ free(kmkey->contents);
+ free(kmkey);
+ }
+ if (config) {
+ if (config->krbctx) {
+ if (config->realm)
+ krb5_free_default_realm(config->krbctx, config->realm);
+ krb5_free_context(config->krbctx);
+ }
+ free(config->pref_encsalts);
+ free(config->supp_encsalts);
+ slapi_ch_array_free(config->passsync_mgrs);
+ free(config);
+ }
+ slapi_entry_free(config_entry);
+ slapi_entry_free(realm_entry);
+ return NULL;
+}
+
+/* Easier handling for virtual attributes. You must call pwd_values_free()
+ * to free memory allocated here. It must be called before
+ * slapi_free_search_results_internal(entries) or
+ * slapi_pblock_destroy(pb)
+ */
+static int pwd_get_values(const Slapi_Entry *ent, const char *attrname,
+ Slapi_ValueSet** results, char** actual_type_name,
+ int *buffer_flags)
+{
+ int flags=0;
+ int type_name_disposition = 0;
+ int ret;
+
+ ret = slapi_vattr_values_get((Slapi_Entry *)ent, (char *)attrname,
+ results, &type_name_disposition,
+ actual_type_name, flags, buffer_flags);
+
+ return ret;
+}
+
+static void pwd_values_free(Slapi_ValueSet** results,
+ char** actual_type_name, int buffer_flags)
+{
+ slapi_vattr_values_free(results, actual_type_name, buffer_flags);
+}
+
+static int ipapwd_rdn_count(const char *dn)
+{
+ int rdnc = 0;
+ LDAPDN ldn;
+ int ret;
+
+ ret = ldap_str2dn(dn, &ldn, LDAP_DN_FORMAT_LDAPV3);
+ if (ret != LDAP_SUCCESS) {
+ LOG_TRACE("ldap_str2dn(dn) failed ?!");
+ return -1;
+ }
+
+ for (rdnc = 0; ldn != NULL && ldn[rdnc]; rdnc++) /* count */ ;
+ ldap_dnfree(ldn);
+
+ return rdnc;
+}
+
+int ipapwd_getPolicy(const char *dn,
+ Slapi_Entry *target,
+ struct ipapwd_policy *policy)
+{
+ const char *krbPwdPolicyReference;
+ const char *pdn;
+ const Slapi_DN *psdn;
+ Slapi_Backend *be;
+ Slapi_PBlock *pb = NULL;
+ char *attrs[] = { "krbMaxPwdLife", "krbMinPwdLife",
+ "krbPwdMinDiffChars", "krbPwdMinLength",
+ "krbPwdHistoryLength", NULL};
+ Slapi_Entry **es = NULL;
+ Slapi_Entry *pe = NULL;
+ int ret, res, dist, rdnc, scope, i;
+ Slapi_DN *sdn = NULL;
+ int buffer_flags=0;
+ Slapi_ValueSet* results = NULL;
+ char* actual_type_name = NULL;
+ int tmpint;
+
+ LOG_TRACE("Searching policy for [%s]\n", dn);
+
+ sdn = slapi_sdn_new_dn_byref(dn);
+ if (sdn == NULL) {
+ LOG_OOM();
+ ret = -1;
+ goto done;
+ }
+
+ pwd_get_values(target, "krbPwdPolicyReference",
+ &results, &actual_type_name, &buffer_flags);
+ if (results) {
+ Slapi_Value *sv;
+ slapi_valueset_first_value(results, &sv);
+ krbPwdPolicyReference = slapi_value_get_string(sv);
+ pdn = krbPwdPolicyReference;
+ scope = LDAP_SCOPE_BASE;
+ LOG_TRACE("using policy reference: %s\n", pdn);
+ } else {
+ /* Find ancestor base DN */
+ be = slapi_be_select(sdn);
+ psdn = slapi_be_getsuffix(be, 0);
+ if (psdn == NULL) {
+ LOG_FATAL("Invalid DN [%s]\n", dn);
+ ret = -1;
+ goto done;
+ }
+ pdn = slapi_sdn_get_dn(psdn);
+ scope = LDAP_SCOPE_SUBTREE;
+ }
+
+ pb = slapi_pblock_new();
+ slapi_search_internal_set_pb(pb,
+ pdn, scope,
+ "(objectClass=krbPwdPolicy)",
+ attrs, 0,
+ NULL, /* Controls */
+ NULL, /* UniqueID */
+ ipapwd_plugin_id,
+ 0); /* Flags */
+
+ /* do search the tree */
+ ret = slapi_search_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
+ if (ret == -1 || res != LDAP_SUCCESS) {
+ LOG_FATAL("Couldn't find policy, err (%d)\n", res ? res : ret);
+ ret = -1;
+ goto done;
+ }
+
+ /* get entries */
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &es);
+ if (!es) {
+ LOG_TRACE("No entries ?!");
+ ret = -1;
+ goto done;
+ }
+
+ /* count entries */
+ for (i = 0; es[i]; i++) /* count */ ;
+
+ /* if there is only one, return that */
+ if (i == 1) {
+ pe = es[0];
+ goto fill;
+ }
+
+ /* count number of RDNs in DN */
+ rdnc = ipapwd_rdn_count(dn);
+ if (rdnc == -1) {
+ LOG_TRACE("ipapwd_rdn_count(dn) failed");
+ ret = -1;
+ goto done;
+ }
+
+ pe = NULL;
+ dist = -1;
+
+ /* find closest entry */
+ for (i = 0; es[i]; i++) {
+ const Slapi_DN *esdn;
+
+ esdn = slapi_entry_get_sdn_const(es[i]);
+ if (esdn == NULL) continue;
+ if (0 == slapi_sdn_compare(esdn, sdn)) {
+ pe = es[i];
+ dist = 0;
+ break;
+ }
+ if (slapi_sdn_issuffix(sdn, esdn)) {
+ const char *dn1;
+ int c1;
+
+ dn1 = slapi_sdn_get_dn(esdn);
+ if (!dn1) continue;
+ c1 = ipapwd_rdn_count(dn1);
+ if (c1 == -1) continue;
+ if ((dist == -1) ||
+ ((rdnc - c1) < dist)) {
+ dist = rdnc - c1;
+ pe = es[i];
+ }
+ }
+ if (dist == 0) break; /* found closest */
+ }
+
+ if (pe == NULL) {
+ ret = -1;
+ goto done;
+ }
+
+fill:
+ policy->min_pwd_life = slapi_entry_attr_get_int(pe, "krbMinPwdLife");
+
+ tmpint = slapi_entry_attr_get_int(pe, "krbMaxPwdLife");
+ if (tmpint != 0) {
+ policy->max_pwd_life = tmpint;
+ }
+
+ tmpint = slapi_entry_attr_get_int(pe, "krbPwdMinLength");
+ if (tmpint != 0) {
+ policy->min_pwd_length = tmpint;
+ }
+
+ policy->history_length = slapi_entry_attr_get_int(pe,
+ "krbPwdHistoryLength");
+
+ policy->min_complexity = slapi_entry_attr_get_int(pe,
+ "krbPwdMinDiffChars");
+
+ ret = 0;
+
+done:
+ if (results) {
+ pwd_values_free(&results, &actual_type_name, buffer_flags);
+ }
+ if (pb) {
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+ }
+ if (sdn) slapi_sdn_free(&sdn);
+ return ret;
+}
+
+
+/*==Common-public-functions=============================================*/
+
+int ipapwd_entry_checks(Slapi_PBlock *pb, struct slapi_entry *e,
+ int *is_root, int *is_krb, int *is_smb, int *is_ipant,
+ char *attr, int acc)
+{
+ Slapi_Value *sval;
+ int rc;
+
+ /* Check ACIs */
+ slapi_pblock_get(pb, SLAPI_REQUESTOR_ISROOT, is_root);
+
+ if (!*is_root) {
+ /* verify this user is allowed to write a user password */
+ rc = slapi_access_allowed(pb, e, attr, NULL, acc);
+ if (rc != LDAP_SUCCESS) {
+ /* we have no business here, the operation will be denied anyway */
+ rc = LDAP_SUCCESS;
+ goto done;
+ }
+ }
+
+ /* Check if this is a krbPrincial and therefore needs us to generate other
+ * hashes */
+ sval = slapi_value_new_string("krbPrincipalAux");
+ if (!sval) {
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+ *is_krb = slapi_entry_attr_has_syntax_value(e, SLAPI_ATTR_OBJECTCLASS, sval);
+ slapi_value_free(&sval);
+
+ sval = slapi_value_new_string("sambaSamAccount");
+ if (!sval) {
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+ *is_smb = slapi_entry_attr_has_syntax_value(e, SLAPI_ATTR_OBJECTCLASS, sval);
+ slapi_value_free(&sval);
+
+ sval = slapi_value_new_string("ipaNTUserAttrs");
+ if (!sval) {
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+ *is_ipant = slapi_entry_attr_has_syntax_value(e, SLAPI_ATTR_OBJECTCLASS,
+ sval);
+ slapi_value_free(&sval);
+
+ rc = LDAP_SUCCESS;
+
+done:
+ return rc;
+}
+
+int ipapwd_gen_checks(Slapi_PBlock *pb, char **errMesg,
+ struct ipapwd_krbcfg **config, int check_flags)
+{
+ int ret, ssf;
+ int rc = LDAP_SUCCESS;
+ Slapi_Backend *be;
+ const Slapi_DN *psdn;
+ Slapi_DN *sdn;
+ char *dn = NULL;
+
+ LOG_TRACE("=>\n");
+
+#ifdef LDAP_EXTOP_PASSMOD_CONN_SECURE
+ if (check_flags & IPAPWD_CHECK_CONN_SECURE) {
+ /* Allow password modify on all connections with a Security Strength
+ * Factor (SSF) higher than 1 */
+ if (slapi_pblock_get(pb, SLAPI_OPERATION_SSF, &ssf) != 0) {
+ LOG("Could not get SSF from connection\n");
+ *errMesg = "Operation requires a secure connection.\n";
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ if (ssf <= 1) {
+ *errMesg = "Operation requires a secure connection.\n";
+ rc = LDAP_CONFIDENTIALITY_REQUIRED;
+ goto done;
+ }
+ }
+#endif
+
+ if (check_flags & IPAPWD_CHECK_DN) {
+ /* check we have a valid DN in the pblock or just abort */
+ ret = slapi_pblock_get(pb, SLAPI_TARGET_DN, &dn);
+ if (ret) {
+ LOG("Tried to change password for an invalid DN [%s]\n",
+ dn ? dn : "<NULL>");
+ *errMesg = "Invalid DN";
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+ sdn = slapi_sdn_new_dn_byref(dn);
+ if (!sdn) {
+ LOG_FATAL("Unable to convert dn to sdn %s", dn ? dn : "<NULL>");
+ *errMesg = "Internal Error";
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+ be = slapi_be_select(sdn);
+ slapi_sdn_free(&sdn);
+
+ psdn = slapi_be_getsuffix(be, 0);
+ if (!psdn) {
+ *errMesg = "Invalid DN";
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+ }
+
+ /* get the kerberos context and master key */
+ *config = ipapwd_getConfig();
+ if (NULL == *config) {
+ LOG_FATAL("Error Retrieving Master Key");
+ *errMesg = "Fatal Internal Error";
+ rc = LDAP_OPERATIONS_ERROR;
+ }
+
+done:
+ return rc;
+}
+
+/* check password strenght and history */
+int ipapwd_CheckPolicy(struct ipapwd_data *data)
+{
+ struct ipapwd_policy pol = {0};
+ time_t acct_expiration;
+ time_t pwd_expiration;
+ time_t last_pwd_change;
+ char **pwd_history;
+ char *tmpstr;
+ int ret;
+
+ pol.max_pwd_life = IPAPWD_DEFAULT_PWDLIFE;
+ pol.min_pwd_length = IPAPWD_DEFAULT_MINLEN;
+
+ if (data->changetype != IPA_CHANGETYPE_NORMAL) {
+ /* We must skip policy checks (Admin change) but
+ * force a password change on the next login.
+ * But not if Directory Manager */
+ if (data->changetype == IPA_CHANGETYPE_ADMIN) {
+ /* The expiration date needs to be older than the current time
+ * otherwise the KDC may not immediately register the password
+ * as expired. The last password change needs to match the
+ * password expiration otherwise minlife issues will arise.
+ */
+ data->timeNow -= 1;
+ data->expireTime = data->timeNow;
+ }
+
+ /* do not load policies */
+ } else {
+
+ /* find the entry with the password policy */
+ ret = ipapwd_getPolicy(data->dn, data->target, &pol);
+ if (ret) {
+ LOG_TRACE("No password policy, use defaults");
+ }
+ }
+
+ tmpstr = slapi_entry_attr_get_charptr(data->target,
+ "krbPrincipalExpiration");
+ acct_expiration = ipapwd_gentime_to_time_t(tmpstr);
+ slapi_ch_free_string(&tmpstr);
+
+ tmpstr = slapi_entry_attr_get_charptr(data->target,
+ "krbPasswordExpiration");
+ pwd_expiration = ipapwd_gentime_to_time_t(tmpstr);
+ slapi_ch_free_string(&tmpstr);
+
+ tmpstr = slapi_entry_attr_get_charptr(data->target,
+ "krbLastPwdChange");
+ last_pwd_change = ipapwd_gentime_to_time_t(tmpstr);
+ slapi_ch_free_string(&tmpstr);
+
+ pwd_history = slapi_entry_attr_get_charray(data->target,
+ "passwordHistory");
+
+ /* check policy */
+ ret = ipapwd_check_policy(&pol, data->password,
+ data->timeNow,
+ acct_expiration,
+ pwd_expiration,
+ last_pwd_change,
+ pwd_history);
+
+ slapi_ch_array_free(pwd_history);
+
+ if (data->expireTime == 0) {
+ data->expireTime = data->timeNow + pol.max_pwd_life;
+ }
+
+ data->policy = pol;
+
+ return ret;
+}
+
+/* Searches the dn in directory,
+ * If found : fills in slapi_entry structure and returns 0
+ * If NOT found : returns the search result as LDAP_NO_SUCH_OBJECT
+ */
+int ipapwd_getEntry(const char *dn, Slapi_Entry **e2, char **attrlist)
+{
+ Slapi_DN *sdn;
+ int search_result = 0;
+
+ LOG_TRACE("=>\n");
+
+ sdn = slapi_sdn_new_dn_byref(dn);
+ search_result = slapi_search_internal_get_entry(sdn, attrlist, e2,
+ ipapwd_plugin_id);
+ if (search_result != LDAP_SUCCESS) {
+ LOG_TRACE("No such entry-(%s), err (%d)\n", dn, search_result);
+ }
+
+ slapi_sdn_free(&sdn);
+ LOG_TRACE("<= result: %d\n", search_result);
+ return search_result;
+}
+
+int ipapwd_get_cur_kvno(Slapi_Entry *target)
+{
+ Slapi_Attr *krbPrincipalKey = NULL;
+ Slapi_ValueSet *svs;
+ Slapi_Value *sv;
+ BerElement *be = NULL;
+ const struct berval *cbval;
+ ber_tag_t tag, tmp;
+ ber_int_t tkvno;
+ int hint;
+ int kvno;
+ int ret;
+
+ /* retrieve current kvno and and keys */
+ ret = slapi_entry_attr_find(target, "krbPrincipalKey", &krbPrincipalKey);
+ if (ret != 0) {
+ return 0;
+ }
+
+ kvno = 0;
+
+ slapi_attr_get_valueset(krbPrincipalKey, &svs);
+ hint = slapi_valueset_first_value(svs, &sv);
+ while (hint != -1) {
+ cbval = slapi_value_get_berval(sv);
+ if (!cbval) {
+ LOG_TRACE("Error retrieving berval from Slapi_Value\n");
+ goto next;
+ }
+ be = ber_init(discard_const(cbval));
+ if (!be) {
+ LOG_TRACE("ber_init() failed!\n");
+ goto next;
+ }
+
+ tag = ber_scanf(be, "{xxt[i]", &tmp, &tkvno);
+ if (tag == LBER_ERROR) {
+ LOG_TRACE("Bad OLD key encoding ?!\n");
+ ber_free(be, 1);
+ goto next;
+ }
+
+ if (tkvno > kvno) {
+ kvno = tkvno;
+ }
+
+ ber_free(be, 1);
+next:
+ hint = slapi_valueset_next_value(svs, hint, &sv);
+ }
+
+ return kvno;
+}
+
+/* Modify the Password attributes of the entry */
+int ipapwd_SetPassword(struct ipapwd_krbcfg *krbcfg,
+ struct ipapwd_data *data, int is_krb)
+{
+ int ret = 0;
+ Slapi_Mods *smods = NULL;
+ Slapi_Value **svals = NULL;
+ Slapi_Value **ntvals = NULL;
+ Slapi_Value **pwvals = NULL;
+ struct tm utctime;
+ char timestr[GENERALIZED_TIME_LENGTH+1];
+ char *lm = NULL;
+ char *nt = NULL;
+ int is_smb = 0;
+ int is_ipant = 0;
+ int is_host = 0;
+ Slapi_Value *sambaSamAccount;
+ Slapi_Value *ipaNTUserAttrs;
+ Slapi_Value *ipaHost;
+ char *errMesg = NULL;
+ char *modtime = NULL;
+
+ LOG_TRACE("=>\n");
+
+ sambaSamAccount = slapi_value_new_string("sambaSamAccount");
+ if (slapi_entry_attr_has_syntax_value(data->target,
+ "objectClass", sambaSamAccount)) {
+ is_smb = 1;
+ }
+ slapi_value_free(&sambaSamAccount);
+
+ ipaNTUserAttrs = slapi_value_new_string("ipaNTUserAttrs");
+ if (slapi_entry_attr_has_syntax_value(data->target,
+ "objectClass", ipaNTUserAttrs)) {
+ is_ipant = 1;
+ }
+ slapi_value_free(&ipaNTUserAttrs);
+
+ ipaHost = slapi_value_new_string("ipaHost");
+ if (slapi_entry_attr_has_syntax_value(data->target,
+ "objectClass", ipaHost)) {
+ is_host = 1;
+ }
+ slapi_value_free(&ipaHost);
+
+ ret = ipapwd_gen_hashes(krbcfg, data,
+ data->password,
+ is_krb, is_smb, is_ipant,
+ &svals, &nt, &lm, &ntvals, &errMesg);
+ if (ret) {
+ goto free_and_return;
+ }
+
+ smods = slapi_mods_new();
+
+ if (svals) {
+ slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE,
+ "krbPrincipalKey", svals);
+
+ /* krbLastPwdChange is used to tell whether a host entry has a
+ * keytab so don't set it on hosts.
+ */
+ if (!is_host) {
+ /* change Last Password Change field with the current date */
+ if (!gmtime_r(&(data->timeNow), &utctime)) {
+ LOG_FATAL("failed to retrieve current date (buggy gmtime_r ?)\n");
+ ret = LDAP_OPERATIONS_ERROR;
+ goto free_and_return;
+ }
+ strftime(timestr, GENERALIZED_TIME_LENGTH + 1,
+ "%Y%m%d%H%M%SZ", &utctime);
+ slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
+ "krbLastPwdChange", timestr);
+
+ /* set Password Expiration date */
+ if (!gmtime_r(&(data->expireTime), &utctime)) {
+ LOG_FATAL("failed to convert expiration date\n");
+ ret = LDAP_OPERATIONS_ERROR;
+ goto free_and_return;
+ }
+ strftime(timestr, GENERALIZED_TIME_LENGTH + 1,
+ "%Y%m%d%H%M%SZ", &utctime);
+ slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
+ "krbPasswordExpiration", timestr);
+ }
+ }
+
+ if (lm && is_smb) {
+ slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
+ "sambaLMPassword", lm);
+ }
+
+ if (nt && is_smb) {
+ slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
+ "sambaNTPassword", nt);
+ }
+
+ if (ntvals && is_ipant) {
+ slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE,
+ "ipaNTHash", 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 (data->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 */
+ modtime = slapi_ch_smprintf("0");
+ } else {
+ modtime = slapi_ch_smprintf("%ld", (long)data->timeNow);
+ }
+ if (!modtime) {
+ LOG_FATAL("failed to smprintf string!\n");
+ ret = LDAP_OPERATIONS_ERROR;
+ goto free_and_return;
+ }
+ slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
+ "sambaPwdLastset", modtime);
+ }
+ if (is_krb) {
+ if (data->changetype == IPA_CHANGETYPE_ADMIN) {
+ slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
+ "krbLoginFailedCount", "0");
+ }
+ }
+ /* let DS encode the password itself, this allows also other plugins to
+ * intercept it to perform operations like synchronization with Active
+ * Directory domains through the replication plugin */
+ slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
+ "userPassword", data->password);
+
+ /* set password history */
+ if (data->policy.history_length > 0) {
+ pwvals = ipapwd_setPasswordHistory(smods, data);
+ if (pwvals) {
+ slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE,
+ "passwordHistory", pwvals);
+ }
+ }
+
+ /* FIXME:
+ * instead of replace we should use a delete/add so that we are
+ * completely sure nobody else modified the entry meanwhile and
+ * fail if that's the case */
+
+ /* commit changes */
+ ret = ipapwd_apply_mods(data->dn, smods);
+
+ LOG_TRACE("<= result: %d\n", ret);
+
+free_and_return:
+ if (lm) slapi_ch_free((void **)&lm);
+ if (nt) slapi_ch_free((void **)&nt);
+ if (modtime) slapi_ch_free((void **)&modtime);
+ slapi_mods_free(&smods);
+ ipapwd_free_slapi_value_array(&svals);
+ ipapwd_free_slapi_value_array(&ntvals);
+ ipapwd_free_slapi_value_array(&pwvals);
+
+ return ret;
+}
+
+
+Slapi_Value **ipapwd_setPasswordHistory(Slapi_Mods *smods,
+ struct ipapwd_data *data)
+{
+ Slapi_Value **pH = NULL;
+ char **pwd_history = NULL;
+ char **new_pwd_history = NULL;
+ int n = 0;
+ int ret;
+ int i;
+
+ pwd_history = slapi_entry_attr_get_charray(data->target,
+ "passwordHistory");
+
+ ret = ipapwd_generate_new_history(data->password, data->timeNow,
+ data->policy.history_length,
+ pwd_history, &new_pwd_history, &n);
+
+ if (ret && data->policy.history_length) {
+ LOG_FATAL("failed to generate new password history!\n");
+ goto done;
+ }
+
+ pH = (Slapi_Value **)slapi_ch_calloc(n + 1, sizeof(Slapi_Value *));
+ if (!pH) {
+ LOG_OOM();
+ goto done;
+ }
+
+ for (i = 0; i < n; i++) {
+ pH[i] = slapi_value_new_string(new_pwd_history[i]);
+ if (!pH[i]) {
+ ipapwd_free_slapi_value_array(&pH);
+ LOG_OOM();
+ goto done;
+ }
+ }
+
+done:
+ slapi_ch_array_free(pwd_history);
+ for (i = 0; i < n; i++) {
+ free(new_pwd_history[i]);
+ }
+ free(new_pwd_history);
+ return pH;
+}
+
+/* Construct Mods pblock and perform the modify operation
+ * Sets result of operation in SLAPI_PLUGIN_INTOP_RESULT
+ */
+int ipapwd_apply_mods(const char *dn, Slapi_Mods *mods)
+{
+ Slapi_PBlock *pb;
+ int ret;
+
+ LOG_TRACE("=>\n");
+
+ if (!mods || (slapi_mods_get_num_mods(mods) == 0)) {
+ return -1;
+ }
+
+ pb = slapi_pblock_new();
+ slapi_modify_internal_set_pb(pb, dn,
+ slapi_mods_get_ldapmods_byref(mods),
+ NULL, /* Controls */
+ NULL, /* UniqueID */
+ ipapwd_plugin_id, /* PluginID */
+ 0); /* Flags */
+
+ ret = slapi_modify_internal_pb(pb);
+ if (ret) {
+ LOG_TRACE("WARNING: modify error %d on entry '%s'\n", ret, dn);
+ } else {
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
+
+ if (ret != LDAP_SUCCESS){
+ LOG_TRACE("WARNING: modify error %d on entry '%s'\n", ret, dn);
+ } else {
+ LOG_TRACE("<= Successful\n");
+ }
+ }
+
+ slapi_pblock_destroy(pb);
+
+ return ret;
+}
+
+int ipapwd_set_extradata(const char *dn,
+ const char *principal,
+ time_t unixtime)
+{
+ Slapi_Mods *smods;
+ Slapi_Value *va[2] = { NULL };
+ struct berval bv;
+ char *xdata;
+ int xd_len;
+ int p_len;
+ int ret;
+
+ p_len = strlen(principal);
+ xd_len = 2 + 4 + p_len + 1;
+ xdata = malloc(xd_len);
+ if (!xdata) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ smods = slapi_mods_new();
+
+ /* data type id */
+ xdata[0] = 0x00;
+ xdata[1] = 0x02;
+
+ /* unix timestamp in Little Endian */
+ xdata[2] = unixtime & 0xff;
+ xdata[3] = (unixtime & 0xff00) >> 8;
+ xdata[4] = (unixtime & 0xff0000) >> 16;
+ xdata[5] = (unixtime & 0xff000000) >> 24;
+
+ /* append the principal name */
+ strncpy(&xdata[6], principal, p_len);
+
+ xdata[xd_len -1] = 0;
+
+ bv.bv_val = xdata;
+ bv.bv_len = xd_len;
+ va[0] = slapi_value_new_berval(&bv);
+
+ slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE, "krbExtraData", va);
+
+ ret = ipapwd_apply_mods(dn, smods);
+
+ slapi_value_free(&va[0]);
+ slapi_mods_free(&smods);
+
+ return ret;
+}
+
+void ipapwd_free_slapi_value_array(Slapi_Value ***svals)
+{
+ Slapi_Value **sv = *svals;
+ int i;
+
+ if (sv) {
+ for (i = 0; sv[i]; i++) {
+ slapi_value_free(&sv[i]);
+ }
+ }
+
+ slapi_ch_free((void **)sv);
+}
+
+void free_ipapwd_krbcfg(struct ipapwd_krbcfg **cfg)
+{
+ struct ipapwd_krbcfg *c = *cfg;
+
+ if (!c) return;
+
+ krb5_free_default_realm(c->krbctx, c->realm);
+ krb5_free_context(c->krbctx);
+ free(c->kmkey->contents);
+ free(c->kmkey);
+ free(c->supp_encsalts);
+ free(c->pref_encsalts);
+ slapi_ch_array_free(c->passsync_mgrs);
+ free(c);
+ *cfg = NULL;
+};
+
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/encoding.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/encoding.c
new file mode 100644
index 0000000..a92eaf0
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/encoding.c
@@ -0,0 +1,291 @@
+/** 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
+
+#include <stdio.h>
+#include <string.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"
+#include "ipa_krb5.h"
+
+/* krbTicketFlags */
+#define KTF_DISALLOW_POSTDATED 0x00000001
+#define KTF_DISALLOW_FORWARDABLE 0x00000002
+#define KTF_DISALLOW_TGT_BASED 0x00000004
+#define KTF_DISALLOW_RENEWABLE 0x00000008
+#define KTF_DISALLOW_PROXIABLE 0x00000010
+#define KTF_DISALLOW_DUP_SKEY 0x00000020
+#define KTF_DISALLOW_ALL_TIX 0x00000040
+#define KTF_REQUIRES_PRE_AUTH 0x00000080
+#define KTF_REQUIRES_HW_AUTH 0x00000100
+#define KTF_REQUIRES_PWCHANGE 0x00000200
+#define KTF_DISALLOW_SVR 0x00001000
+#define KTF_PWCHANGE_SERVICE 0x00002000
+
+/* ascii hex output of bytes in "in"
+ * out len is 32 (preallocated)
+ * in len is 16 */
+static const char hexchars[] = "0123456789ABCDEF";
+static void hexbuf(char *out, const uint8_t *in)
+{
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ out[i*2] = hexchars[in[i] >> 4];
+ out[i*2+1] = hexchars[in[i] & 0x0f];
+ }
+}
+
+void ipapwd_keyset_free(struct ipapwd_keyset **pkset)
+{
+ struct ipapwd_keyset *kset = *pkset;
+ int i;
+
+ if (!kset) return;
+
+ for (i = 0; i < kset->num_keys; i++) {
+ free(kset->keys[i].key_data_contents[0]);
+ free(kset->keys[i].key_data_contents[1]);
+ }
+ free(kset->keys);
+ free(kset);
+ *pkset = NULL;
+}
+
+static Slapi_Value **encrypt_encode_key(struct ipapwd_krbcfg *krbcfg,
+ struct ipapwd_data *data,
+ char **errMesg)
+{
+ krb5_context krbctx;
+ char *krbPrincipalName = NULL;
+ int kvno;
+ struct berval *bval = NULL;
+ Slapi_Value **svals = NULL;
+ krb5_principal princ = NULL;
+ krb5_error_code krberr;
+ krb5_data pwd;
+ struct ipapwd_keyset *kset = NULL;
+
+ krbctx = krbcfg->krbctx;
+
+ svals = (Slapi_Value **)calloc(2, sizeof(Slapi_Value *));
+ if (!svals) {
+ LOG_OOM();
+ return NULL;
+ }
+
+ kvno = ipapwd_get_cur_kvno(data->target);
+
+ krbPrincipalName = slapi_entry_attr_get_charptr(data->target,
+ "krbPrincipalName");
+ if (!krbPrincipalName) {
+ *errMesg = "no krbPrincipalName present in this entry\n";
+ LOG_FATAL("%s", *errMesg);
+ goto enc_error;
+ }
+
+ krberr = krb5_parse_name(krbctx, krbPrincipalName, &princ);
+ if (krberr) {
+ LOG_FATAL("krb5_parse_name failed [%s]\n",
+ krb5_get_error_message(krbctx, krberr));
+ goto enc_error;
+ }
+
+ pwd.data = (char *)data->password;
+ pwd.length = strlen(data->password);
+
+ kset = malloc(sizeof(struct ipapwd_keyset));
+ if (!kset) {
+ LOG_OOM();
+ goto enc_error;
+ }
+
+ /* this encoding assumes all keys have the same kvno */
+ /* major-vno = 1 and minor-vno = 1 */
+ kset->major_vno = 1;
+ kset->minor_vno = 1;
+ /* increment kvno (will be 1 if this is a new entry) */
+ kvno += 1;
+ kset->mkvno = krbcfg->mkvno;
+
+ krberr = ipa_krb5_generate_key_data(krbctx, princ,
+ pwd, kvno, krbcfg->kmkey,
+ krbcfg->num_pref_encsalts,
+ krbcfg->pref_encsalts,
+ &kset->num_keys, &kset->keys);
+ if (krberr != 0) {
+ LOG_FATAL("generating kerberos keys failed [%s]\n",
+ krb5_get_error_message(krbctx, krberr));
+ goto enc_error;
+ }
+
+ krberr = ber_encode_krb5_key_data(kset->keys, kset->num_keys,
+ kset->mkvno, &bval);
+ if (krberr != 0) {
+ LOG_FATAL("encoding krb5_key_data failed\n");
+ goto enc_error;
+ }
+
+ svals[0] = slapi_value_new_berval(bval);
+ if (!svals[0]) {
+ LOG_FATAL("Converting berval to Slapi_Value\n");
+ goto enc_error;
+ }
+
+ ipapwd_keyset_free(&kset);
+ krb5_free_principal(krbctx, princ);
+ slapi_ch_free_string(&krbPrincipalName);
+ ber_bvfree(bval);
+ return svals;
+
+enc_error:
+ *errMesg = "key encryption/encoding failed\n";
+ if (kset) ipapwd_keyset_free(&kset);
+ krb5_free_principal(krbctx, princ);
+ slapi_ch_free_string(&krbPrincipalName);
+ if (bval) ber_bvfree(bval);
+ free(svals);
+ return NULL;
+}
+
+int ipapwd_gen_hashes(struct ipapwd_krbcfg *krbcfg,
+ struct ipapwd_data *data, char *userpw,
+ int is_krb, int is_smb, int is_ipant, Slapi_Value ***svals,
+ char **nthash, char **lmhash, Slapi_Value ***ntvals,
+ char **errMesg)
+{
+ int rc;
+ char *userpw_uc = NULL;
+
+ *svals = NULL;
+ *nthash = NULL;
+ *lmhash = NULL;
+ *errMesg = NULL;
+
+ if (is_krb) {
+
+ *svals = encrypt_encode_key(krbcfg, data, errMesg);
+
+ if (!*svals) {
+ /* errMesg should have been set in encrypt_encode_key() */
+ LOG_FATAL("key encryption/encoding failed\n");
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+ }
+
+ if (is_smb || is_ipant) {
+ char lm[33], nt[33];
+ struct ntlm_keys ntlm;
+ int ret;
+
+ userpw_uc = (char *) slapi_utf8StrToUpper((unsigned char *) userpw);
+ if (!userpw_uc) {
+ *errMesg = "Failed to generate upper case password\n";
+ LOG_FATAL("%s", *errMesg);
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ ret = encode_ntlm_keys(userpw,
+ userpw_uc,
+ krbcfg->allow_lm_hash,
+ krbcfg->allow_nt_hash,
+ &ntlm);
+ memset(userpw_uc, 0, strlen(userpw_uc));
+ slapi_ch_free_string(&userpw_uc);
+ if (ret) {
+ *errMesg = "Failed to generate NT/LM hashes\n";
+ LOG_FATAL("%s", *errMesg);
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+ if (krbcfg->allow_lm_hash) {
+ hexbuf(lm, ntlm.lm);
+ lm[32] = '\0';
+ *lmhash = slapi_ch_strdup(lm);
+ }
+ if (krbcfg->allow_nt_hash) {
+ hexbuf(nt, ntlm.nt);
+ nt[32] = '\0';
+ *nthash = slapi_ch_strdup(nt);
+ }
+
+ if (is_ipant) {
+ *ntvals = (Slapi_Value **)calloc(2, sizeof(Slapi_Value *));
+ if (!*ntvals) {
+ LOG_OOM();
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+ (*ntvals)[0] = slapi_value_new();
+ if (slapi_value_set((*ntvals)[0], ntlm.nt, 16) == NULL) {
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+ }
+ }
+
+ rc = LDAP_SUCCESS;
+
+done:
+
+ /* when error, free possibly allocated output parameters */
+ if (rc) {
+ ipapwd_free_slapi_value_array(svals);
+ ipapwd_free_slapi_value_array(ntvals);
+ }
+
+ return rc;
+}
+
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h
index 3689783..372441d 100644
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h
+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h
@@ -96,7 +96,7 @@ struct ipapwd_operation {
#define GENERALIZED_TIME_LENGTH 15
-/* from ipapwd_common.c */
+/* from common.c */
struct ipapwd_krbcfg {
krb5_context krbctx;
char *realm;
@@ -131,7 +131,7 @@ int ipapwd_set_extradata(const char *dn,
void ipapwd_free_slapi_value_array(Slapi_Value ***svals);
void free_ipapwd_krbcfg(struct ipapwd_krbcfg **cfg);
-/* from ipapwd_encoding.c */
+/* from encoding.c */
struct ipapwd_keyset {
uint16_t major_vno;
uint16_t minor_vno;
@@ -148,7 +148,7 @@ int ipapwd_gen_hashes(struct ipapwd_krbcfg *krbcfg,
Slapi_Value ***svals, char **nthash, char **lmhash,
Slapi_Value ***ntvals, char **errMesg);
-/* from ipapwd_prepost.c */
+/* from prepost.c */
int ipapwd_ext_init(void);
int ipapwd_pre_init(Slapi_PBlock *pb);
int ipapwd_post_init(Slapi_PBlock *pb);
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_common.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_common.c
deleted file mode 100644
index bb1d96a..0000000
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_common.c
+++ /dev/null
@@ -1,1107 +0,0 @@
-/** 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 **/
-
-#include "ipapwd.h"
-#include "util.h"
-
-/* Type of connection for this operation;*/
-#define LDAP_EXTOP_PASSMOD_CONN_SECURE
-
-/* Uncomment the following #undef FOR TESTING:
- * allows non-SSL connections to use the password change extended op */
-/* #undef LDAP_EXTOP_PASSMOD_CONN_SECURE */
-
-extern void *ipapwd_plugin_id;
-extern const char *ipa_realm_dn;
-extern const char *ipa_etc_config_dn;
-extern const char *ipa_pwd_config_dn;
-
-/* These are the default enc:salt types if nothing is defined.
- * TODO: retrieve the configure set of ecntypes either from the
- * kfc.conf file or by synchronizing the file content into
- * the directory */
-static const char *ipapwd_def_encsalts[] = {
- "des3-hmac-sha1:normal",
-/* "arcfour-hmac:normal",
- "des-hmac-sha1:normal",
- "des-cbc-md5:normal", */
- "des-cbc-crc:normal",
-/* "des-cbc-crc:v4",
- "des-cbc-crc:afs3", */
- NULL
-};
-
-static struct ipapwd_krbcfg *ipapwd_getConfig(void)
-{
- krb5_error_code krberr;
- struct ipapwd_krbcfg *config = NULL;
- krb5_keyblock *kmkey = NULL;
- Slapi_Entry *realm_entry = NULL;
- Slapi_Entry *config_entry = NULL;
- Slapi_Attr *a;
- Slapi_Value *v;
- BerElement *be = NULL;
- ber_tag_t tag, tvno;
- ber_int_t ttype;
- const struct berval *bval;
- struct berval *mkey = NULL;
- char **encsalts;
- char **tmparray;
- char *tmpstr;
- int i, ret;
-
- config = calloc(1, sizeof(struct ipapwd_krbcfg));
- if (!config) {
- LOG_OOM();
- goto free_and_error;
- }
- kmkey = calloc(1, sizeof(krb5_keyblock));
- if (!kmkey) {
- LOG_OOM();
- goto free_and_error;
- }
- config->kmkey = kmkey;
-
- krberr = krb5_init_context(&config->krbctx);
- if (krberr) {
- LOG_FATAL("krb5_init_context failed\n");
- goto free_and_error;
- }
-
- ret = krb5_get_default_realm(config->krbctx, &config->realm);
- if (ret) {
- LOG_FATAL("Failed to get default realm?!\n");
- goto free_and_error;
- }
-
- /* get the Realm Container entry */
- ret = ipapwd_getEntry(ipa_realm_dn, &realm_entry, NULL);
- if (ret != LDAP_SUCCESS) {
- LOG_FATAL("No realm Entry?\n");
- goto free_and_error;
- }
-
- /*** get the Kerberos Master Key ***/
-
- ret = slapi_entry_attr_find(realm_entry, "krbMKey", &a);
- if (ret == -1) {
- LOG_FATAL("No master key??\n");
- goto free_and_error;
- }
-
- /* there should be only one value here */
- ret = slapi_attr_first_value(a, &v);
- if (ret == -1) {
- LOG_FATAL("No master key??\n");
- goto free_and_error;
- }
-
- bval = slapi_value_get_berval(v);
- if (!bval) {
- LOG_FATAL("Error retrieving master key berval\n");
- goto free_and_error;
- }
-
- be = ber_init(discard_const(bval));
- if (!be) {
- LOG_FATAL("ber_init() failed!\n");
- goto free_and_error;
- }
-
- tag = ber_scanf(be, "{i{iO}}", &tvno, &ttype, &mkey);
- if (tag == LBER_ERROR) {
- LOG_FATAL("Bad Master key encoding ?!\n");
- goto free_and_error;
- }
-
- config->mkvno = tvno;
- kmkey->magic = KV5M_KEYBLOCK;
- kmkey->enctype = ttype;
- kmkey->length = mkey->bv_len;
- kmkey->contents = malloc(mkey->bv_len);
- if (!kmkey->contents) {
- LOG_OOM();
- goto free_and_error;
- }
- memcpy(kmkey->contents, mkey->bv_val, mkey->bv_len);
- ber_bvfree(mkey);
- ber_free(be, 1);
- mkey = NULL;
- be = NULL;
-
- /*** get the Supported Enc/Salt types ***/
-
- encsalts = slapi_entry_attr_get_charray(realm_entry,
- "krbSupportedEncSaltTypes");
- if (encsalts) {
- for (i = 0; encsalts[i]; i++) /* count */ ;
- ret = parse_bval_key_salt_tuples(config->krbctx,
- (const char * const *)encsalts, i,
- &config->supp_encsalts,
- &config->num_supp_encsalts);
- slapi_ch_array_free(encsalts);
- } else {
- LOG("No configured salt types use defaults\n");
- for (i = 0; ipapwd_def_encsalts[i]; i++) /* count */ ;
- ret = parse_bval_key_salt_tuples(config->krbctx,
- ipapwd_def_encsalts, i,
- &config->supp_encsalts,
- &config->num_supp_encsalts);
- }
- if (ret) {
- LOG_FATAL("Can't get Supported EncSalt Types\n");
- goto free_and_error;
- }
-
- /*** get the Preferred Enc/Salt types ***/
-
- encsalts = slapi_entry_attr_get_charray(realm_entry,
- "krbDefaultEncSaltTypes");
- if (encsalts) {
- for (i = 0; encsalts[i]; i++) /* count */ ;
- ret = parse_bval_key_salt_tuples(config->krbctx,
- (const char * const *)encsalts, i,
- &config->pref_encsalts,
- &config->num_pref_encsalts);
- slapi_ch_array_free(encsalts);
- } else {
- LOG("No configured salt types use defaults\n");
- for (i = 0; ipapwd_def_encsalts[i]; i++) /* count */ ;
- ret = parse_bval_key_salt_tuples(config->krbctx,
- ipapwd_def_encsalts, i,
- &config->pref_encsalts,
- &config->num_pref_encsalts);
- }
- if (ret) {
- LOG_FATAL("Can't get Preferred EncSalt Types\n");
- goto free_and_error;
- }
-
- slapi_entry_free(realm_entry);
-
- /* get the Realm Container entry */
- ret = ipapwd_getEntry(ipa_pwd_config_dn, &config_entry, NULL);
- if (ret != LDAP_SUCCESS) {
- LOG_FATAL("No config Entry? Impossible!\n");
- goto free_and_error;
- }
- config->passsync_mgrs =
- slapi_entry_attr_get_charray(config_entry, "passSyncManagersDNs");
- /* now add Directory Manager, it is always added by default */
- tmpstr = slapi_ch_strdup("cn=Directory Manager");
- slapi_ch_array_add(&config->passsync_mgrs, tmpstr);
- if (config->passsync_mgrs == NULL) {
- LOG_OOM();
- goto free_and_error;
- }
- for (i = 0; config->passsync_mgrs[i]; i++) /* count */ ;
- config->num_passsync_mgrs = i;
-
- slapi_entry_free(config_entry);
-
- /* get the ipa etc/ipaConfig entry */
- config->allow_lm_hash = false;
- config->allow_nt_hash = false;
- ret = ipapwd_getEntry(ipa_etc_config_dn, &config_entry, NULL);
- if (ret != LDAP_SUCCESS) {
- LOG_FATAL("No config Entry?\n");
- goto free_and_error;
- } else {
- tmparray = slapi_entry_attr_get_charray(config_entry,
- "ipaConfigString");
- for (i = 0; tmparray && tmparray[i]; i++) {
- if (strcasecmp(tmparray[i], "AllowLMhash") == 0) {
- config->allow_lm_hash = true;
- continue;
- }
- if (strcasecmp(tmparray[i], "AllowNThash") == 0) {
- config->allow_nt_hash = true;
- continue;
- }
- }
- if (tmparray) slapi_ch_array_free(tmparray);
- }
-
- slapi_entry_free(config_entry);
-
- return config;
-
-free_and_error:
- if (mkey) ber_bvfree(mkey);
- if (be) ber_free(be, 1);
- if (kmkey) {
- free(kmkey->contents);
- free(kmkey);
- }
- if (config) {
- if (config->krbctx) {
- if (config->realm)
- krb5_free_default_realm(config->krbctx, config->realm);
- krb5_free_context(config->krbctx);
- }
- free(config->pref_encsalts);
- free(config->supp_encsalts);
- slapi_ch_array_free(config->passsync_mgrs);
- free(config);
- }
- slapi_entry_free(config_entry);
- slapi_entry_free(realm_entry);
- return NULL;
-}
-
-/* Easier handling for virtual attributes. You must call pwd_values_free()
- * to free memory allocated here. It must be called before
- * slapi_free_search_results_internal(entries) or
- * slapi_pblock_destroy(pb)
- */
-static int pwd_get_values(const Slapi_Entry *ent, const char *attrname,
- Slapi_ValueSet** results, char** actual_type_name,
- int *buffer_flags)
-{
- int flags=0;
- int type_name_disposition = 0;
- int ret;
-
- ret = slapi_vattr_values_get((Slapi_Entry *)ent, (char *)attrname,
- results, &type_name_disposition,
- actual_type_name, flags, buffer_flags);
-
- return ret;
-}
-
-static void pwd_values_free(Slapi_ValueSet** results,
- char** actual_type_name, int buffer_flags)
-{
- slapi_vattr_values_free(results, actual_type_name, buffer_flags);
-}
-
-static int ipapwd_rdn_count(const char *dn)
-{
- int rdnc = 0;
- LDAPDN ldn;
- int ret;
-
- ret = ldap_str2dn(dn, &ldn, LDAP_DN_FORMAT_LDAPV3);
- if (ret != LDAP_SUCCESS) {
- LOG_TRACE("ldap_str2dn(dn) failed ?!");
- return -1;
- }
-
- for (rdnc = 0; ldn != NULL && ldn[rdnc]; rdnc++) /* count */ ;
- ldap_dnfree(ldn);
-
- return rdnc;
-}
-
-int ipapwd_getPolicy(const char *dn,
- Slapi_Entry *target,
- struct ipapwd_policy *policy)
-{
- const char *krbPwdPolicyReference;
- const char *pdn;
- const Slapi_DN *psdn;
- Slapi_Backend *be;
- Slapi_PBlock *pb = NULL;
- char *attrs[] = { "krbMaxPwdLife", "krbMinPwdLife",
- "krbPwdMinDiffChars", "krbPwdMinLength",
- "krbPwdHistoryLength", NULL};
- Slapi_Entry **es = NULL;
- Slapi_Entry *pe = NULL;
- int ret, res, dist, rdnc, scope, i;
- Slapi_DN *sdn = NULL;
- int buffer_flags=0;
- Slapi_ValueSet* results = NULL;
- char* actual_type_name = NULL;
- int tmpint;
-
- LOG_TRACE("Searching policy for [%s]\n", dn);
-
- sdn = slapi_sdn_new_dn_byref(dn);
- if (sdn == NULL) {
- LOG_OOM();
- ret = -1;
- goto done;
- }
-
- pwd_get_values(target, "krbPwdPolicyReference",
- &results, &actual_type_name, &buffer_flags);
- if (results) {
- Slapi_Value *sv;
- slapi_valueset_first_value(results, &sv);
- krbPwdPolicyReference = slapi_value_get_string(sv);
- pdn = krbPwdPolicyReference;
- scope = LDAP_SCOPE_BASE;
- LOG_TRACE("using policy reference: %s\n", pdn);
- } else {
- /* Find ancestor base DN */
- be = slapi_be_select(sdn);
- psdn = slapi_be_getsuffix(be, 0);
- if (psdn == NULL) {
- LOG_FATAL("Invalid DN [%s]\n", dn);
- ret = -1;
- goto done;
- }
- pdn = slapi_sdn_get_dn(psdn);
- scope = LDAP_SCOPE_SUBTREE;
- }
-
- pb = slapi_pblock_new();
- slapi_search_internal_set_pb(pb,
- pdn, scope,
- "(objectClass=krbPwdPolicy)",
- attrs, 0,
- NULL, /* Controls */
- NULL, /* UniqueID */
- ipapwd_plugin_id,
- 0); /* Flags */
-
- /* do search the tree */
- ret = slapi_search_internal_pb(pb);
- slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
- if (ret == -1 || res != LDAP_SUCCESS) {
- LOG_FATAL("Couldn't find policy, err (%d)\n", res ? res : ret);
- ret = -1;
- goto done;
- }
-
- /* get entries */
- slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &es);
- if (!es) {
- LOG_TRACE("No entries ?!");
- ret = -1;
- goto done;
- }
-
- /* count entries */
- for (i = 0; es[i]; i++) /* count */ ;
-
- /* if there is only one, return that */
- if (i == 1) {
- pe = es[0];
- goto fill;
- }
-
- /* count number of RDNs in DN */
- rdnc = ipapwd_rdn_count(dn);
- if (rdnc == -1) {
- LOG_TRACE("ipapwd_rdn_count(dn) failed");
- ret = -1;
- goto done;
- }
-
- pe = NULL;
- dist = -1;
-
- /* find closest entry */
- for (i = 0; es[i]; i++) {
- const Slapi_DN *esdn;
-
- esdn = slapi_entry_get_sdn_const(es[i]);
- if (esdn == NULL) continue;
- if (0 == slapi_sdn_compare(esdn, sdn)) {
- pe = es[i];
- dist = 0;
- break;
- }
- if (slapi_sdn_issuffix(sdn, esdn)) {
- const char *dn1;
- int c1;
-
- dn1 = slapi_sdn_get_dn(esdn);
- if (!dn1) continue;
- c1 = ipapwd_rdn_count(dn1);
- if (c1 == -1) continue;
- if ((dist == -1) ||
- ((rdnc - c1) < dist)) {
- dist = rdnc - c1;
- pe = es[i];
- }
- }
- if (dist == 0) break; /* found closest */
- }
-
- if (pe == NULL) {
- ret = -1;
- goto done;
- }
-
-fill:
- policy->min_pwd_life = slapi_entry_attr_get_int(pe, "krbMinPwdLife");
-
- tmpint = slapi_entry_attr_get_int(pe, "krbMaxPwdLife");
- if (tmpint != 0) {
- policy->max_pwd_life = tmpint;
- }
-
- tmpint = slapi_entry_attr_get_int(pe, "krbPwdMinLength");
- if (tmpint != 0) {
- policy->min_pwd_length = tmpint;
- }
-
- policy->history_length = slapi_entry_attr_get_int(pe,
- "krbPwdHistoryLength");
-
- policy->min_complexity = slapi_entry_attr_get_int(pe,
- "krbPwdMinDiffChars");
-
- ret = 0;
-
-done:
- if (results) {
- pwd_values_free(&results, &actual_type_name, buffer_flags);
- }
- if (pb) {
- slapi_free_search_results_internal(pb);
- slapi_pblock_destroy(pb);
- }
- if (sdn) slapi_sdn_free(&sdn);
- return ret;
-}
-
-
-/*==Common-public-functions=============================================*/
-
-int ipapwd_entry_checks(Slapi_PBlock *pb, struct slapi_entry *e,
- int *is_root, int *is_krb, int *is_smb, int *is_ipant,
- char *attr, int acc)
-{
- Slapi_Value *sval;
- int rc;
-
- /* Check ACIs */
- slapi_pblock_get(pb, SLAPI_REQUESTOR_ISROOT, is_root);
-
- if (!*is_root) {
- /* verify this user is allowed to write a user password */
- rc = slapi_access_allowed(pb, e, attr, NULL, acc);
- if (rc != LDAP_SUCCESS) {
- /* we have no business here, the operation will be denied anyway */
- rc = LDAP_SUCCESS;
- goto done;
- }
- }
-
- /* Check if this is a krbPrincial and therefore needs us to generate other
- * hashes */
- sval = slapi_value_new_string("krbPrincipalAux");
- if (!sval) {
- rc = LDAP_OPERATIONS_ERROR;
- goto done;
- }
- *is_krb = slapi_entry_attr_has_syntax_value(e, SLAPI_ATTR_OBJECTCLASS, sval);
- slapi_value_free(&sval);
-
- sval = slapi_value_new_string("sambaSamAccount");
- if (!sval) {
- rc = LDAP_OPERATIONS_ERROR;
- goto done;
- }
- *is_smb = slapi_entry_attr_has_syntax_value(e, SLAPI_ATTR_OBJECTCLASS, sval);
- slapi_value_free(&sval);
-
- sval = slapi_value_new_string("ipaNTUserAttrs");
- if (!sval) {
- rc = LDAP_OPERATIONS_ERROR;
- goto done;
- }
- *is_ipant = slapi_entry_attr_has_syntax_value(e, SLAPI_ATTR_OBJECTCLASS,
- sval);
- slapi_value_free(&sval);
-
- rc = LDAP_SUCCESS;
-
-done:
- return rc;
-}
-
-int ipapwd_gen_checks(Slapi_PBlock *pb, char **errMesg,
- struct ipapwd_krbcfg **config, int check_flags)
-{
- int ret, ssf;
- int rc = LDAP_SUCCESS;
- Slapi_Backend *be;
- const Slapi_DN *psdn;
- Slapi_DN *sdn;
- char *dn = NULL;
-
- LOG_TRACE("=>\n");
-
-#ifdef LDAP_EXTOP_PASSMOD_CONN_SECURE
- if (check_flags & IPAPWD_CHECK_CONN_SECURE) {
- /* Allow password modify on all connections with a Security Strength
- * Factor (SSF) higher than 1 */
- if (slapi_pblock_get(pb, SLAPI_OPERATION_SSF, &ssf) != 0) {
- LOG("Could not get SSF from connection\n");
- *errMesg = "Operation requires a secure connection.\n";
- rc = LDAP_OPERATIONS_ERROR;
- goto done;
- }
-
- if (ssf <= 1) {
- *errMesg = "Operation requires a secure connection.\n";
- rc = LDAP_CONFIDENTIALITY_REQUIRED;
- goto done;
- }
- }
-#endif
-
- if (check_flags & IPAPWD_CHECK_DN) {
- /* check we have a valid DN in the pblock or just abort */
- ret = slapi_pblock_get(pb, SLAPI_TARGET_DN, &dn);
- if (ret) {
- LOG("Tried to change password for an invalid DN [%s]\n",
- dn ? dn : "<NULL>");
- *errMesg = "Invalid DN";
- rc = LDAP_OPERATIONS_ERROR;
- goto done;
- }
- sdn = slapi_sdn_new_dn_byref(dn);
- if (!sdn) {
- LOG_FATAL("Unable to convert dn to sdn %s", dn ? dn : "<NULL>");
- *errMesg = "Internal Error";
- rc = LDAP_OPERATIONS_ERROR;
- goto done;
- }
- be = slapi_be_select(sdn);
- slapi_sdn_free(&sdn);
-
- psdn = slapi_be_getsuffix(be, 0);
- if (!psdn) {
- *errMesg = "Invalid DN";
- rc = LDAP_OPERATIONS_ERROR;
- goto done;
- }
- }
-
- /* get the kerberos context and master key */
- *config = ipapwd_getConfig();
- if (NULL == *config) {
- LOG_FATAL("Error Retrieving Master Key");
- *errMesg = "Fatal Internal Error";
- rc = LDAP_OPERATIONS_ERROR;
- }
-
-done:
- return rc;
-}
-
-/* check password strenght and history */
-int ipapwd_CheckPolicy(struct ipapwd_data *data)
-{
- struct ipapwd_policy pol = {0};
- time_t acct_expiration;
- time_t pwd_expiration;
- time_t last_pwd_change;
- char **pwd_history;
- char *tmpstr;
- int ret;
-
- pol.max_pwd_life = IPAPWD_DEFAULT_PWDLIFE;
- pol.min_pwd_length = IPAPWD_DEFAULT_MINLEN;
-
- if (data->changetype != IPA_CHANGETYPE_NORMAL) {
- /* We must skip policy checks (Admin change) but
- * force a password change on the next login.
- * But not if Directory Manager */
- if (data->changetype == IPA_CHANGETYPE_ADMIN) {
- /* The expiration date needs to be older than the current time
- * otherwise the KDC may not immediately register the password
- * as expired. The last password change needs to match the
- * password expiration otherwise minlife issues will arise.
- */
- data->timeNow -= 1;
- data->expireTime = data->timeNow;
- }
-
- /* do not load policies */
- } else {
-
- /* find the entry with the password policy */
- ret = ipapwd_getPolicy(data->dn, data->target, &pol);
- if (ret) {
- LOG_TRACE("No password policy, use defaults");
- }
- }
-
- tmpstr = slapi_entry_attr_get_charptr(data->target,
- "krbPrincipalExpiration");
- acct_expiration = ipapwd_gentime_to_time_t(tmpstr);
- slapi_ch_free_string(&tmpstr);
-
- tmpstr = slapi_entry_attr_get_charptr(data->target,
- "krbPasswordExpiration");
- pwd_expiration = ipapwd_gentime_to_time_t(tmpstr);
- slapi_ch_free_string(&tmpstr);
-
- tmpstr = slapi_entry_attr_get_charptr(data->target,
- "krbLastPwdChange");
- last_pwd_change = ipapwd_gentime_to_time_t(tmpstr);
- slapi_ch_free_string(&tmpstr);
-
- pwd_history = slapi_entry_attr_get_charray(data->target,
- "passwordHistory");
-
- /* check policy */
- ret = ipapwd_check_policy(&pol, data->password,
- data->timeNow,
- acct_expiration,
- pwd_expiration,
- last_pwd_change,
- pwd_history);
-
- slapi_ch_array_free(pwd_history);
-
- if (data->expireTime == 0) {
- data->expireTime = data->timeNow + pol.max_pwd_life;
- }
-
- data->policy = pol;
-
- return ret;
-}
-
-/* Searches the dn in directory,
- * If found : fills in slapi_entry structure and returns 0
- * If NOT found : returns the search result as LDAP_NO_SUCH_OBJECT
- */
-int ipapwd_getEntry(const char *dn, Slapi_Entry **e2, char **attrlist)
-{
- Slapi_DN *sdn;
- int search_result = 0;
-
- LOG_TRACE("=>\n");
-
- sdn = slapi_sdn_new_dn_byref(dn);
- search_result = slapi_search_internal_get_entry(sdn, attrlist, e2,
- ipapwd_plugin_id);
- if (search_result != LDAP_SUCCESS) {
- LOG_TRACE("No such entry-(%s), err (%d)\n", dn, search_result);
- }
-
- slapi_sdn_free(&sdn);
- LOG_TRACE("<= result: %d\n", search_result);
- return search_result;
-}
-
-int ipapwd_get_cur_kvno(Slapi_Entry *target)
-{
- Slapi_Attr *krbPrincipalKey = NULL;
- Slapi_ValueSet *svs;
- Slapi_Value *sv;
- BerElement *be = NULL;
- const struct berval *cbval;
- ber_tag_t tag, tmp;
- ber_int_t tkvno;
- int hint;
- int kvno;
- int ret;
-
- /* retrieve current kvno and and keys */
- ret = slapi_entry_attr_find(target, "krbPrincipalKey", &krbPrincipalKey);
- if (ret != 0) {
- return 0;
- }
-
- kvno = 0;
-
- slapi_attr_get_valueset(krbPrincipalKey, &svs);
- hint = slapi_valueset_first_value(svs, &sv);
- while (hint != -1) {
- cbval = slapi_value_get_berval(sv);
- if (!cbval) {
- LOG_TRACE("Error retrieving berval from Slapi_Value\n");
- goto next;
- }
- be = ber_init(discard_const(cbval));
- if (!be) {
- LOG_TRACE("ber_init() failed!\n");
- goto next;
- }
-
- tag = ber_scanf(be, "{xxt[i]", &tmp, &tkvno);
- if (tag == LBER_ERROR) {
- LOG_TRACE("Bad OLD key encoding ?!\n");
- ber_free(be, 1);
- goto next;
- }
-
- if (tkvno > kvno) {
- kvno = tkvno;
- }
-
- ber_free(be, 1);
-next:
- hint = slapi_valueset_next_value(svs, hint, &sv);
- }
-
- return kvno;
-}
-
-/* Modify the Password attributes of the entry */
-int ipapwd_SetPassword(struct ipapwd_krbcfg *krbcfg,
- struct ipapwd_data *data, int is_krb)
-{
- int ret = 0;
- Slapi_Mods *smods = NULL;
- Slapi_Value **svals = NULL;
- Slapi_Value **ntvals = NULL;
- Slapi_Value **pwvals = NULL;
- struct tm utctime;
- char timestr[GENERALIZED_TIME_LENGTH+1];
- char *lm = NULL;
- char *nt = NULL;
- int is_smb = 0;
- int is_ipant = 0;
- int is_host = 0;
- Slapi_Value *sambaSamAccount;
- Slapi_Value *ipaNTUserAttrs;
- Slapi_Value *ipaHost;
- char *errMesg = NULL;
- char *modtime = NULL;
-
- LOG_TRACE("=>\n");
-
- sambaSamAccount = slapi_value_new_string("sambaSamAccount");
- if (slapi_entry_attr_has_syntax_value(data->target,
- "objectClass", sambaSamAccount)) {
- is_smb = 1;
- }
- slapi_value_free(&sambaSamAccount);
-
- ipaNTUserAttrs = slapi_value_new_string("ipaNTUserAttrs");
- if (slapi_entry_attr_has_syntax_value(data->target,
- "objectClass", ipaNTUserAttrs)) {
- is_ipant = 1;
- }
- slapi_value_free(&ipaNTUserAttrs);
-
- ipaHost = slapi_value_new_string("ipaHost");
- if (slapi_entry_attr_has_syntax_value(data->target,
- "objectClass", ipaHost)) {
- is_host = 1;
- }
- slapi_value_free(&ipaHost);
-
- ret = ipapwd_gen_hashes(krbcfg, data,
- data->password,
- is_krb, is_smb, is_ipant,
- &svals, &nt, &lm, &ntvals, &errMesg);
- if (ret) {
- goto free_and_return;
- }
-
- smods = slapi_mods_new();
-
- if (svals) {
- slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE,
- "krbPrincipalKey", svals);
-
- /* krbLastPwdChange is used to tell whether a host entry has a
- * keytab so don't set it on hosts.
- */
- if (!is_host) {
- /* change Last Password Change field with the current date */
- if (!gmtime_r(&(data->timeNow), &utctime)) {
- LOG_FATAL("failed to retrieve current date (buggy gmtime_r ?)\n");
- ret = LDAP_OPERATIONS_ERROR;
- goto free_and_return;
- }
- strftime(timestr, GENERALIZED_TIME_LENGTH + 1,
- "%Y%m%d%H%M%SZ", &utctime);
- slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
- "krbLastPwdChange", timestr);
-
- /* set Password Expiration date */
- if (!gmtime_r(&(data->expireTime), &utctime)) {
- LOG_FATAL("failed to convert expiration date\n");
- ret = LDAP_OPERATIONS_ERROR;
- goto free_and_return;
- }
- strftime(timestr, GENERALIZED_TIME_LENGTH + 1,
- "%Y%m%d%H%M%SZ", &utctime);
- slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
- "krbPasswordExpiration", timestr);
- }
- }
-
- if (lm && is_smb) {
- slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
- "sambaLMPassword", lm);
- }
-
- if (nt && is_smb) {
- slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
- "sambaNTPassword", nt);
- }
-
- if (ntvals && is_ipant) {
- slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE,
- "ipaNTHash", 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 (data->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 */
- modtime = slapi_ch_smprintf("0");
- } else {
- modtime = slapi_ch_smprintf("%ld", (long)data->timeNow);
- }
- if (!modtime) {
- LOG_FATAL("failed to smprintf string!\n");
- ret = LDAP_OPERATIONS_ERROR;
- goto free_and_return;
- }
- slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
- "sambaPwdLastset", modtime);
- }
- if (is_krb) {
- if (data->changetype == IPA_CHANGETYPE_ADMIN) {
- slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
- "krbLoginFailedCount", "0");
- }
- }
- /* let DS encode the password itself, this allows also other plugins to
- * intercept it to perform operations like synchronization with Active
- * Directory domains through the replication plugin */
- slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
- "userPassword", data->password);
-
- /* set password history */
- if (data->policy.history_length > 0) {
- pwvals = ipapwd_setPasswordHistory(smods, data);
- if (pwvals) {
- slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE,
- "passwordHistory", pwvals);
- }
- }
-
- /* FIXME:
- * instead of replace we should use a delete/add so that we are
- * completely sure nobody else modified the entry meanwhile and
- * fail if that's the case */
-
- /* commit changes */
- ret = ipapwd_apply_mods(data->dn, smods);
-
- LOG_TRACE("<= result: %d\n", ret);
-
-free_and_return:
- if (lm) slapi_ch_free((void **)&lm);
- if (nt) slapi_ch_free((void **)&nt);
- if (modtime) slapi_ch_free((void **)&modtime);
- slapi_mods_free(&smods);
- ipapwd_free_slapi_value_array(&svals);
- ipapwd_free_slapi_value_array(&ntvals);
- ipapwd_free_slapi_value_array(&pwvals);
-
- return ret;
-}
-
-
-Slapi_Value **ipapwd_setPasswordHistory(Slapi_Mods *smods,
- struct ipapwd_data *data)
-{
- Slapi_Value **pH = NULL;
- char **pwd_history = NULL;
- char **new_pwd_history = NULL;
- int n = 0;
- int ret;
- int i;
-
- pwd_history = slapi_entry_attr_get_charray(data->target,
- "passwordHistory");
-
- ret = ipapwd_generate_new_history(data->password, data->timeNow,
- data->policy.history_length,
- pwd_history, &new_pwd_history, &n);
-
- if (ret && data->policy.history_length) {
- LOG_FATAL("failed to generate new password history!\n");
- goto done;
- }
-
- pH = (Slapi_Value **)slapi_ch_calloc(n + 1, sizeof(Slapi_Value *));
- if (!pH) {
- LOG_OOM();
- goto done;
- }
-
- for (i = 0; i < n; i++) {
- pH[i] = slapi_value_new_string(new_pwd_history[i]);
- if (!pH[i]) {
- ipapwd_free_slapi_value_array(&pH);
- LOG_OOM();
- goto done;
- }
- }
-
-done:
- slapi_ch_array_free(pwd_history);
- for (i = 0; i < n; i++) {
- free(new_pwd_history[i]);
- }
- free(new_pwd_history);
- return pH;
-}
-
-/* Construct Mods pblock and perform the modify operation
- * Sets result of operation in SLAPI_PLUGIN_INTOP_RESULT
- */
-int ipapwd_apply_mods(const char *dn, Slapi_Mods *mods)
-{
- Slapi_PBlock *pb;
- int ret;
-
- LOG_TRACE("=>\n");
-
- if (!mods || (slapi_mods_get_num_mods(mods) == 0)) {
- return -1;
- }
-
- pb = slapi_pblock_new();
- slapi_modify_internal_set_pb(pb, dn,
- slapi_mods_get_ldapmods_byref(mods),
- NULL, /* Controls */
- NULL, /* UniqueID */
- ipapwd_plugin_id, /* PluginID */
- 0); /* Flags */
-
- ret = slapi_modify_internal_pb(pb);
- if (ret) {
- LOG_TRACE("WARNING: modify error %d on entry '%s'\n", ret, dn);
- } else {
-
- slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
-
- if (ret != LDAP_SUCCESS){
- LOG_TRACE("WARNING: modify error %d on entry '%s'\n", ret, dn);
- } else {
- LOG_TRACE("<= Successful\n");
- }
- }
-
- slapi_pblock_destroy(pb);
-
- return ret;
-}
-
-int ipapwd_set_extradata(const char *dn,
- const char *principal,
- time_t unixtime)
-{
- Slapi_Mods *smods;
- Slapi_Value *va[2] = { NULL };
- struct berval bv;
- char *xdata;
- int xd_len;
- int p_len;
- int ret;
-
- p_len = strlen(principal);
- xd_len = 2 + 4 + p_len + 1;
- xdata = malloc(xd_len);
- if (!xdata) {
- return LDAP_OPERATIONS_ERROR;
- }
-
- smods = slapi_mods_new();
-
- /* data type id */
- xdata[0] = 0x00;
- xdata[1] = 0x02;
-
- /* unix timestamp in Little Endian */
- xdata[2] = unixtime & 0xff;
- xdata[3] = (unixtime & 0xff00) >> 8;
- xdata[4] = (unixtime & 0xff0000) >> 16;
- xdata[5] = (unixtime & 0xff000000) >> 24;
-
- /* append the principal name */
- strncpy(&xdata[6], principal, p_len);
-
- xdata[xd_len -1] = 0;
-
- bv.bv_val = xdata;
- bv.bv_len = xd_len;
- va[0] = slapi_value_new_berval(&bv);
-
- slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE, "krbExtraData", va);
-
- ret = ipapwd_apply_mods(dn, smods);
-
- slapi_value_free(&va[0]);
- slapi_mods_free(&smods);
-
- return ret;
-}
-
-void ipapwd_free_slapi_value_array(Slapi_Value ***svals)
-{
- Slapi_Value **sv = *svals;
- int i;
-
- if (sv) {
- for (i = 0; sv[i]; i++) {
- slapi_value_free(&sv[i]);
- }
- }
-
- slapi_ch_free((void **)sv);
-}
-
-void free_ipapwd_krbcfg(struct ipapwd_krbcfg **cfg)
-{
- struct ipapwd_krbcfg *c = *cfg;
-
- if (!c) return;
-
- krb5_free_default_realm(c->krbctx, c->realm);
- krb5_free_context(c->krbctx);
- free(c->kmkey->contents);
- free(c->kmkey);
- free(c->supp_encsalts);
- free(c->pref_encsalts);
- slapi_ch_array_free(c->passsync_mgrs);
- free(c);
- *cfg = NULL;
-};
-
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_encoding.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_encoding.c
deleted file mode 100644
index a92eaf0..0000000
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_encoding.c
+++ /dev/null
@@ -1,291 +0,0 @@
-/** 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
-
-#include <stdio.h>
-#include <string.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"
-#include "ipa_krb5.h"
-
-/* krbTicketFlags */
-#define KTF_DISALLOW_POSTDATED 0x00000001
-#define KTF_DISALLOW_FORWARDABLE 0x00000002
-#define KTF_DISALLOW_TGT_BASED 0x00000004
-#define KTF_DISALLOW_RENEWABLE 0x00000008
-#define KTF_DISALLOW_PROXIABLE 0x00000010
-#define KTF_DISALLOW_DUP_SKEY 0x00000020
-#define KTF_DISALLOW_ALL_TIX 0x00000040
-#define KTF_REQUIRES_PRE_AUTH 0x00000080
-#define KTF_REQUIRES_HW_AUTH 0x00000100
-#define KTF_REQUIRES_PWCHANGE 0x00000200
-#define KTF_DISALLOW_SVR 0x00001000
-#define KTF_PWCHANGE_SERVICE 0x00002000
-
-/* ascii hex output of bytes in "in"
- * out len is 32 (preallocated)
- * in len is 16 */
-static const char hexchars[] = "0123456789ABCDEF";
-static void hexbuf(char *out, const uint8_t *in)
-{
- int i;
-
- for (i = 0; i < 16; i++) {
- out[i*2] = hexchars[in[i] >> 4];
- out[i*2+1] = hexchars[in[i] & 0x0f];
- }
-}
-
-void ipapwd_keyset_free(struct ipapwd_keyset **pkset)
-{
- struct ipapwd_keyset *kset = *pkset;
- int i;
-
- if (!kset) return;
-
- for (i = 0; i < kset->num_keys; i++) {
- free(kset->keys[i].key_data_contents[0]);
- free(kset->keys[i].key_data_contents[1]);
- }
- free(kset->keys);
- free(kset);
- *pkset = NULL;
-}
-
-static Slapi_Value **encrypt_encode_key(struct ipapwd_krbcfg *krbcfg,
- struct ipapwd_data *data,
- char **errMesg)
-{
- krb5_context krbctx;
- char *krbPrincipalName = NULL;
- int kvno;
- struct berval *bval = NULL;
- Slapi_Value **svals = NULL;
- krb5_principal princ = NULL;
- krb5_error_code krberr;
- krb5_data pwd;
- struct ipapwd_keyset *kset = NULL;
-
- krbctx = krbcfg->krbctx;
-
- svals = (Slapi_Value **)calloc(2, sizeof(Slapi_Value *));
- if (!svals) {
- LOG_OOM();
- return NULL;
- }
-
- kvno = ipapwd_get_cur_kvno(data->target);
-
- krbPrincipalName = slapi_entry_attr_get_charptr(data->target,
- "krbPrincipalName");
- if (!krbPrincipalName) {
- *errMesg = "no krbPrincipalName present in this entry\n";
- LOG_FATAL("%s", *errMesg);
- goto enc_error;
- }
-
- krberr = krb5_parse_name(krbctx, krbPrincipalName, &princ);
- if (krberr) {
- LOG_FATAL("krb5_parse_name failed [%s]\n",
- krb5_get_error_message(krbctx, krberr));
- goto enc_error;
- }
-
- pwd.data = (char *)data->password;
- pwd.length = strlen(data->password);
-
- kset = malloc(sizeof(struct ipapwd_keyset));
- if (!kset) {
- LOG_OOM();
- goto enc_error;
- }
-
- /* this encoding assumes all keys have the same kvno */
- /* major-vno = 1 and minor-vno = 1 */
- kset->major_vno = 1;
- kset->minor_vno = 1;
- /* increment kvno (will be 1 if this is a new entry) */
- kvno += 1;
- kset->mkvno = krbcfg->mkvno;
-
- krberr = ipa_krb5_generate_key_data(krbctx, princ,
- pwd, kvno, krbcfg->kmkey,
- krbcfg->num_pref_encsalts,
- krbcfg->pref_encsalts,
- &kset->num_keys, &kset->keys);
- if (krberr != 0) {
- LOG_FATAL("generating kerberos keys failed [%s]\n",
- krb5_get_error_message(krbctx, krberr));
- goto enc_error;
- }
-
- krberr = ber_encode_krb5_key_data(kset->keys, kset->num_keys,
- kset->mkvno, &bval);
- if (krberr != 0) {
- LOG_FATAL("encoding krb5_key_data failed\n");
- goto enc_error;
- }
-
- svals[0] = slapi_value_new_berval(bval);
- if (!svals[0]) {
- LOG_FATAL("Converting berval to Slapi_Value\n");
- goto enc_error;
- }
-
- ipapwd_keyset_free(&kset);
- krb5_free_principal(krbctx, princ);
- slapi_ch_free_string(&krbPrincipalName);
- ber_bvfree(bval);
- return svals;
-
-enc_error:
- *errMesg = "key encryption/encoding failed\n";
- if (kset) ipapwd_keyset_free(&kset);
- krb5_free_principal(krbctx, princ);
- slapi_ch_free_string(&krbPrincipalName);
- if (bval) ber_bvfree(bval);
- free(svals);
- return NULL;
-}
-
-int ipapwd_gen_hashes(struct ipapwd_krbcfg *krbcfg,
- struct ipapwd_data *data, char *userpw,
- int is_krb, int is_smb, int is_ipant, Slapi_Value ***svals,
- char **nthash, char **lmhash, Slapi_Value ***ntvals,
- char **errMesg)
-{
- int rc;
- char *userpw_uc = NULL;
-
- *svals = NULL;
- *nthash = NULL;
- *lmhash = NULL;
- *errMesg = NULL;
-
- if (is_krb) {
-
- *svals = encrypt_encode_key(krbcfg, data, errMesg);
-
- if (!*svals) {
- /* errMesg should have been set in encrypt_encode_key() */
- LOG_FATAL("key encryption/encoding failed\n");
- rc = LDAP_OPERATIONS_ERROR;
- goto done;
- }
- }
-
- if (is_smb || is_ipant) {
- char lm[33], nt[33];
- struct ntlm_keys ntlm;
- int ret;
-
- userpw_uc = (char *) slapi_utf8StrToUpper((unsigned char *) userpw);
- if (!userpw_uc) {
- *errMesg = "Failed to generate upper case password\n";
- LOG_FATAL("%s", *errMesg);
- rc = LDAP_OPERATIONS_ERROR;
- goto done;
- }
-
- ret = encode_ntlm_keys(userpw,
- userpw_uc,
- krbcfg->allow_lm_hash,
- krbcfg->allow_nt_hash,
- &ntlm);
- memset(userpw_uc, 0, strlen(userpw_uc));
- slapi_ch_free_string(&userpw_uc);
- if (ret) {
- *errMesg = "Failed to generate NT/LM hashes\n";
- LOG_FATAL("%s", *errMesg);
- rc = LDAP_OPERATIONS_ERROR;
- goto done;
- }
- if (krbcfg->allow_lm_hash) {
- hexbuf(lm, ntlm.lm);
- lm[32] = '\0';
- *lmhash = slapi_ch_strdup(lm);
- }
- if (krbcfg->allow_nt_hash) {
- hexbuf(nt, ntlm.nt);
- nt[32] = '\0';
- *nthash = slapi_ch_strdup(nt);
- }
-
- if (is_ipant) {
- *ntvals = (Slapi_Value **)calloc(2, sizeof(Slapi_Value *));
- if (!*ntvals) {
- LOG_OOM();
- rc = LDAP_OPERATIONS_ERROR;
- goto done;
- }
- (*ntvals)[0] = slapi_value_new();
- if (slapi_value_set((*ntvals)[0], ntlm.nt, 16) == NULL) {
- rc = LDAP_OPERATIONS_ERROR;
- goto done;
- }
- }
- }
-
- rc = LDAP_SUCCESS;
-
-done:
-
- /* when error, free possibly allocated output parameters */
- if (rc) {
- ipapwd_free_slapi_value_array(svals);
- ipapwd_free_slapi_value_array(ntvals);
- }
-
- return rc;
-}
-
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_prepost.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_prepost.c
deleted file mode 100644
index 0318cec..0000000
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_prepost.c
+++ /dev/null
@@ -1,1349 +0,0 @@
-/** 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;
-}
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 0000000..0318cec
--- /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;
+}
--
1.8.2.1