diff --git a/contrib/slapd-modules/unicodepw/Makefile b/contrib/slapd-modules/unicodepw/Makefile
new file mode 100644
index 0000000000..baf1c9fa44
--- /dev/null
+++ b/contrib/slapd-modules/unicodepw/Makefile
@@ -0,0 +1,57 @@
+# $OpenLDAP$
+# This work is part of OpenLDAP Software .
+#
+# Copyright 2021 The OpenLDAP Foundation.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted only as authorized by the OpenLDAP
+# Public License.
+#
+# A copy of this license is available in the file LICENSE in the
+# top-level directory of the distribution or, alternatively, at
+# .
+
+LDAP_SRC = ../../..
+LDAP_BUILD = $(LDAP_SRC)
+LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd
+LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \
+ $(LDAP_BUILD)/libraries/liblber/liblber.la
+
+LIBTOOL = $(LDAP_BUILD)/libtool
+CC = gcc
+OPT = -g -O2 -Wall -Wextra
+DEFS = -DSLAPD_OVER_UNICODEPW=SLAPD_MOD_DYNAMIC
+INCS = $(LDAP_INC)
+LIBS = $(LDAP_LIB)
+
+PROGRAMS = unicodepw.la
+LTVER = 0:0:0
+
+prefix=/usr/local
+exec_prefix=$(prefix)
+ldap_subdir=/openldap
+
+libdir=$(exec_prefix)/lib
+libexecdir=$(exec_prefix)/libexec
+moduledir = $(libexecdir)$(ldap_subdir)
+
+.SUFFIXES: .c .o .lo
+
+.c.lo:
+ $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $<
+
+all: $(PROGRAMS)
+
+unicodepw.la: unicodepw.lo
+ $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \
+ -rpath $(moduledir) -module -o $@ $? $(LIBS)
+
+clean:
+ rm -rf *.o *.lo *.la .libs
+
+install: $(PROGRAMS)
+ mkdir -p $(DESTDIR)$(moduledir)
+ for p in $(PROGRAMS) ; do \
+ $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \
+ done
+
diff --git a/contrib/slapd-modules/unicodepw/README b/contrib/slapd-modules/unicodepw/README
new file mode 100644
index 0000000000..aa048d8e46
--- /dev/null
+++ b/contrib/slapd-modules/unicodepw/README
@@ -0,0 +1,34 @@
+This directory contains a slapd overlay, "unicodepw".
+
+ The overlay unicodepw restricts all LDAP modification requests, so that
+ only password changes for MS unicodePwd are possible. All other LDAP
+ requests will not be observed.
+
+Usage:
+ man slapo-unicodepw (see slapo-unicodepw.5)
+
+Build:
+ Use the Makefile to compile this plugin.
+
+---
+
+This work is part of OpenLDAP Software .
+
+Copyright 2021 The OpenLDAP Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted only as authorized by the OpenLDAP
+Public License.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted only as authorized by the OpenLDAP
+Public License.
+
+A copy of this license is available in the file LICENSE in the
+top-level directory of the distribution or, alternatively, at
+.
+
+The attached patch file is derived from OpenLDAP Software.
+All of the modifications to OpenLDAP Software represented in
+the following patch(es) were developed by Ingo Voss ingo.voss@gmail.com.
+I have not assigned rights and/or interest in this work to any party.
diff --git a/contrib/slapd-modules/unicodepw/slapo-unicodepw.5 b/contrib/slapd-modules/unicodepw/slapo-unicodepw.5
new file mode 100644
index 0000000000..d1d5bc7494
--- /dev/null
+++ b/contrib/slapd-modules/unicodepw/slapo-unicodepw.5
@@ -0,0 +1,292 @@
+.TH UNICODEPW 5 "RELEASEDATE" "OpenLDAP LDVERSION"
+.\" Copyright 2021 The OpenLDAP Foundation, All Rights Reserved.
+.\" Copying restrictions apply. See the COPYRIGHT file.
+.\" $OpenLDAP$
+.SH NAME
+unicodepw \- Overlay for openlap
+.SH SYNOPSIS
+The overlay
+.B unicodepw
+restricts all LDAP modification requests, so that only
+password changes for MS unicodePwd are possible.
+All other LDAP requests will not be observed.
+.SH DESCRIPTION
+Some remote access technologies for company networks (e.g. VPN gateways)
+require a MS Active Directory Service (ADS) in the backend to log in with the
+personal ADS account. In some cases (e.g. home office workers/max. password age),
+it must be possible to allow password changes from remote.
+But this requires "write access" (modify) from the gateway to the ADS.
+
+A direct access from the gateway to the ADS is a bad idea, so using
+OpenLDAP as proxy
+.B (slapd-ldap)
+in the DMZ can mitigate the security risks.
+All LDAP search results, initiated by the gateway can be restricted by ACLs.
+That will happen in the response from ADS. LDAP requests that only modify
+(write, modify, ..) cannot be protecte with ACLs, because slapd-ldap does not
+support restricting incoming request.
+
+The backend slapd-ldap itself cannot be set to read-only, because changing the password requires "write" access.
+The overlay
+.B denyop
+can only restrict LDAP requests, but it does not look
+inside the request. Using overlay denyop would only restrict the access by
+allowing ALL modifications to ADS, so that other manipulation are possible too.
+That was the reason to write the extra overlay
+.B unicodepw.
+
+The
+.B unicodepw
+overlay to
+.BR slapd (8)
+services is checking the modification requests, if the modification request
+is a password change for MS ADS. All other modifications are denied.
+.LP
+The conditions for changing the password in MS ADS are described in
+https://msdn.microsoft.com/en-us/library/cc223248 and KB269190.
+Microsoft stores the password in the attribute unicodePwd. It is not readable,
+but writeable. The sequence requires ONE LDAP modification with TWO operations to
+change the password:
+
+.RS
+.nf
+dn:
+changetype: modify
+delete: UnicodePwd
+UnicodePwd::
+-
+add: UnicodePwd
+UnicodePwd::
+.fi
+.RE
+
+The old password is required, no matter what rights the changing context
+(bind dn) in the ADS has.
+
+The
+.B unicodepw
+checks
+.RS
+.nf
+- The number of the operations: only TWO are allowed
+- The type of operations: only DELETE and ADD are allowed
+- The order of the operations: first DELETE, second ADD
+- The attribute which is modified (configurable)
+- The parent dn of the user who is changed (configurable)
+.fi
+.RE
+If one of these checks fails, the overlay will deny the request BEFORE sending
+the request to the ADS!
+.SH CONFIGURATION
+.LP
+The
+.B unicodepw
+is configured in the ETCDIR/slapd.conf.
+At the moment NO dynamic config support is available for the overlay unicodepw.
+.TP
+.B moduleload unicodepw
+Load the module in the slapd context. Don't forget to set the
+.B modulepath
+option.
+.TP
+.B overlay unicodepw
+This directive adds the unicodepw overlay to the current backend.
+.TP
+.B unicodepw pwattr
+This directive configures the attribute which is checked in the modification. Usually "unicodePwd" should be
+used here.
+.TP
+.B unicodepw userbase
+This directive configures the distinguished name of the user base.
+With the userbase directive you can restrict password changes to a dedicated location in the
+ADS. This location then should contain only users who use remote access.
+For all other users in the ADS a password change is NOT possible from the VPN gateway (outside).
+.TP
+.B unicodepw subtree
+If this directive is set to yes, password changes are allowed for all users under "userbase" and
+all DNs below (subtree)
+.TP
+.B unicodepw logactivity
+Enable the additional logging for all operations, checks and results from the unicodepw module.
+The global parameter "log level" MUST be set to stats)!
+This Parameter was intoduced to prevent the noise from the module during normal operation
+of slapd (the default log level is already stats).
+Since the module implements a security function, the admin likes to know and log, who is changing the password
+and with witch result. Then set logactivity to "yes"!
+
+.SH CONFIGURATION HINTS
+
+Since the unicodepw only restricts the modify request, the module
+.B denyop
+must used too, to restrict all other unwanted LDAP requests.
+
+Additionally, to configure slapd-ldap to proxy unicodePwd changes, at least the
+unicodePwd must be defined in a private schema (see EXAMPLES).
+
+All other LDAP operations comming from the access gateway should restict with ACLs!
+
+For your own security, the connection between LDAP client (e.g. VPN gateway)
+and OpenLDAP should be protected by SSL/TLS.
+
+The connection between OpenLDAP and Microsoft ADS MUST be encrypted via SSL/TLS.
+Microsoft does not allow password changes on a unencrypted session!
+
+.SH EXAMPLES
+
+Only the important parts for the slapd configuration:
+
+.RS
+.nf
+#################################
+# including private schema
+#################################
+include /etc/openldap/schema/myADschema.schema
+
+#################################
+# overlay configuration
+#################################
+modulepath /usr/lib/openldap/modules
+moduleload back_ldap
+moduleload denyop
+moduleload unicodepw
+
+overlay denyop
+# possible denyops add,bind,compare,delete,
+# extended,modify,modrdn,search,unbind
+denyop add,compare,delete,modrdn
+
+overlay unicodepw
+unicodepw pwattr "UnicodePwd"
+unicodepw userbase "ou=remoteUsers,dc=company,dc=com"
+unicodepw logactivity "yes"
+
+#################################
+# proxy configuration
+#################################
+database ldap
+rebind-as-user yes
+suffix "dc=company,dc=com"
+uri "ldap://ads1.company.com/ ldap://ads2.company.com"
+chase-referrals no
+protocol-version 3
+.fi
+.RE
+
+Please don't forget to configure the ACLs in the proxy backend and the TLS configuration for slapd!
+Parameters like:
+.B TLSCACertificateFile, TLSCertificateFile, TLSCertificateKeyFile, TLSVerifyClient, TLSCipherSuite
+should configured globally and
+.B security, tls, access
+in the database section!
+
+For testing purposes, it can be useful to create the encoded MS unicode password.
+The following commands should do it:
+.TP
+.nf
+.B echo | perl -ne 'chomp;print pack \*(lqv*\*(rq, unpack \*(lqC*\*(rq,\*(lq\e\*(rq$_\e\*(rq\*(rq' | base64
+.fi
+The output can be included in the modify request in the attribute unicodePwd.
+Example:
+.TP
+.nf
+.B echo password123_ | perl -ne 'chomp;print pack \*(lqv*\*(rq, unpack \*(lqC*\*(rq,\*(lq\e\*(rq$_\e\*(rq\*(rq' | base64
+the resulting attribute is:
+unicodePwd::IgBwAGEAcwBzAHcAbwByAGQAMQAyADMAXwAiAA==
+.fi
+.RE
+
+
+In the section CONFIGURATION HINTS, we talked about a private schema. Here is an example for it:
+.RS
+.nf
+
+attributetype ( 1.2.840.113556.1.4.750 NAME 'groupType'
+ SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )
+
+attributetype ( 1.3.114.7.4.2.0.33 NAME 'memberOf'
+ SYNTAX '1.3.6.1.4.1.1466.115.121.1.26' )
+
+attributetype ( 1.2.840.113556.1.4.656 NAME 'userPrincipalName'
+ SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' )
+
+attributetype ( 1.2.840.113556.1.4.52 NAME 'lastLogon'
+ SYNTAX '1.3.6.1.4.1.1466.115.121.1.38' )
+
+attributetype ( 1.2.840.113556.1.4.159 NAME 'accountExpires'
+ SYNTAX '1.3.6.1.4.1.1466.115.121.1.38' )
+
+attributetype ( 1.2.840.113556.1.4.96 NAME 'pwdLastSet'
+ SYNTAX '1.3.6.1.4.1.1466.115.121.1.38' )
+
+attributetype ( 1.2.840.113556.1.4.221 NAME 'sAMAccountName'
+ SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' )
+
+attributetype ( 1.2.840.113556.1.4.8 NAME 'userAccountControl'
+ SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' )
+
+attributetype ( 1.2.840.113556.1.4.90 NAME 'unicodePwd'
+ SYNTAX '1.3.6.1.4.1.1466.115.121.1.40' )
+
+objectclass ( 1.2.840.113556.1.5.9 NAME 'user'
+ DESC 'a user'
+ SUP inetOrgPerson STRUCTURAL
+ MUST ( cn )
+ MAY ( userPassword $ memberOf $ userPrincipalName $
+ distinguishedName $ lastLogon $ accountExpires $
+ pwdLastSet $ sAMAccountName $ userAccountControl $
+ unicodePwd ) )
+
+objectclass ( 1.2.840.113556.1.5.8 NAME 'group'
+ DESC 'a group of users'
+ SUP top STRUCTURAL
+ MUST ( groupType $ cn )
+ MAY ( member ) )
+.fi
+.RE
+
+.SH LOGGING/DEBUG
+If "stats" is enabled, each password change request and all checks are logged and if they fail, the reasons are logged too!
+For informations about the values during modification, please refer to the log before unicodepw. Grep for the same
+connection id and operation number (conn= and op=)!
+
+.B Example for a logging output, every thing is ok:
+.nf
+conn=1005 op=2 unicodepw: INFO => configured UsersBase nDN =>
+conn=1005 op=2 unicodepw: INFO => configured pwattr =>
+conn=1005 op=2 unicodepw: INFO => configured logactivity => <1>
+conn=1005 op=2 unicodepw: INFO => Parent DN from user, who is changed =>
+conn=1005 op=2 unicodepw: INFO => User, who is changed
+conn=1005 op=2 unicodepw: OK => Attribute in Modification (DEL) is the configured pwattr!
+conn=1005 op=2 unicodepw: OK => Attribute in Modification (ADD) is the configured pwattr!
+conn=1005 op=2 unicodepw: ACCEPT => UnicodePwd changing is permitted!
+.fi
+
+
+.B Example for a logging output, user DN is wrong:
+.nf
+conn=1006 op=2 unicodepw: INFO => configured UsersBase nDN =>
+conn=1006 op=2 unicodepw: INFO => configured pwattr =>
+conn=1006 op=2 unicodepw: INFO => configured logactivity => <1>
+conn=1006 op=2 unicodepw: INFO => Parent DN from user, who is changed =>
+conn=1006 op=2 unicodepw: INFO => User, who is changed
+conn=1006 op=2 unicodepw: DENY => UserBase from is not in configured UserBase!
+conn=1006 op=2 unicodepw: OK => Attribute in Modification (DEL) is the configured pwattr!
+conn=1006 op=2 unicodepw: OK => Attribute in Modification (ADD) is the configured pwattr!
+.fi
+
+
+
+.SH FILES
+.TP
+ETCDIR/slapd.conf
+default slapd configuration file
+.SH SEE ALSO
+.BR slapd.conf (5),
+.BR slapd\-config (5),
+.BR slapd\-ldap (5),
+.BR slapd (8),
+overlay
+.BR denyop
+and https://msdn.microsoft.com/en-us/library/cc223248 and KB269190 for description of password change.
+.SH AUTHOR
+This module is written in 2016-2020 by Ingo Voss (ingo.voss@gmail.com)
diff --git a/contrib/slapd-modules/unicodepw/unicodepw.c b/contrib/slapd-modules/unicodepw/unicodepw.c
new file mode 100644
index 0000000000..ee22b727ff
--- /dev/null
+++ b/contrib/slapd-modules/unicodepw/unicodepw.c
@@ -0,0 +1,317 @@
+/* unicodepw.c - acceppt only password change for MS Active Directory */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software .
+ *
+ * Copyright 2021 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * .
+ */
+ /* ACKNOLEDGEDMENTS:
+ * This work was initially developed by Ingo Voss (ingo.voss@gmail.com)
+ * for inclusion in OpenLDAP Software.
+ */
+
+#include "portable.h"
+
+#ifdef SLAPD_OVER_UNICODEPW
+
+#include
+
+#include
+#include
+
+#include "slap.h"
+#include "lber.h"
+
+
+typedef struct unicodepw_conf {
+ struct berval attr;
+ struct berval userbase;
+ int log_activity;
+ int subtree_search;
+} unicodepw_conf;
+
+
+static int
+unicodepw_mod( Operation *op, SlapReply *rs ) {
+
+ slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
+ unicodepw_conf *u_conf = (unicodepw_conf *) on->on_bi.bi_private;
+ int deny = 0;
+ int i = 1;
+ Modifications *m;
+
+ /* from Config for container, where users are located */
+ struct berval user_base_ndn;
+ dnNormalize( 0, NULL, NULL, &u_conf->userbase, &user_base_ndn, op->o_tmpmemctx );
+
+ /* get parent DN from user, who is changed */
+ struct berval user_parent_ndn;
+ dnParent( &op->o_req_ndn, &user_parent_ndn );
+
+ if ( u_conf->log_activity == 1 ) {
+ /* logging config */
+ Debug( LDAP_DEBUG_STATS,
+ "conn=%lu op=%lu unicodepw: INFO => configured UsersBase nDN => <%s>\n",
+ op->o_connid, op->o_opid, user_base_ndn.bv_val );
+ Debug( LDAP_DEBUG_STATS,
+ "conn=%lu op=%lu unicodepw: INFO => configured pwattr => <%s>\n",
+ op->o_connid, op->o_opid, u_conf->attr.bv_val );
+ Debug( LDAP_DEBUG_STATS,
+ "conn=%lu op=%lu unicodepw: INFO => configured logactivity => <%d>\n",
+ op->o_connid, op->o_opid, u_conf->log_activity );
+ Debug( LDAP_DEBUG_STATS,
+ "conn=%lu op=%lu unicodepw: INFO => configured subtree => <%d>\n",
+ op->o_connid, op->o_opid, u_conf->subtree_search );
+ Debug( LDAP_DEBUG_STATS,
+ "conn=%lu op=%lu unicodepw: INFO => User, who is changed <%s>\n",
+ op->o_connid, op->o_opid, op->o_req_ndn.bv_val );
+ /* logging User and parent DN */
+ Debug( LDAP_DEBUG_STATS,
+ "conn=%lu op=%lu unicodepw: INFO => Parent DN from user, who is changed => <%s>\n",
+ op->o_connid, op->o_opid, user_parent_ndn.bv_val );
+ }
+
+ /* check if user is in configured UserBase */
+ if ( u_conf->subtree_search == 1 ) {
+ int found = 0;
+ while (!BER_BVISEMPTY( &user_parent_ndn )) {
+ if ( u_conf->log_activity == 1 ) {
+ Debug( LDAP_DEBUG_STATS,
+ "conn=%lu op=%lu unicodepw: DEBUG => <%s>\n",
+ op->o_connid, op->o_opid, user_parent_ndn.bv_val );
+ }
+ if ( strcmp( user_parent_ndn.bv_val, user_base_ndn.bv_val ) == 0 ) {
+ found = 1;
+ if ( u_conf->log_activity == 1 ) {
+ Debug( LDAP_DEBUG_STATS,
+ "conn=%lu op=%lu unicodepw: INFO: Found User under => <%s>\n",
+ op->o_connid, op->o_opid, user_parent_ndn.bv_val );
+ }
+ break;
+ }
+ dnParent( &user_parent_ndn , &user_parent_ndn );
+ }
+ if ( found == 0 ) {
+ if ( u_conf->log_activity == 1 ) {
+ Debug( LDAP_DEBUG_STATS,
+ "conn=%lu op=%lu unicodepw: DENY => UserBase from <%s> is not in configured UserBase\n",
+ op->o_connid, op->o_opid, op->o_req_dn.bv_val );
+ }
+ deny = 1;
+ }
+ } else {
+ if ( strcmp( user_parent_ndn.bv_val, user_base_ndn.bv_val ) != 0 ) {
+ if ( u_conf->log_activity == 1 ) {
+ Debug( LDAP_DEBUG_STATS,
+ "conn=%lu op=%lu unicodepw: DENY => UserBase from <%s> is not in configured UserBase\n",
+ op->o_connid, op->o_opid, op->o_req_dn.bv_val );
+ }
+ deny = 1;
+ }
+ }
+
+
+ /* load Modifications and process */
+ if ( !(m = op->orm_modlist) ) {
+ op->o_bd->bd_info = (BackendInfo *) on->on_info;
+ send_ldap_error( op, rs, LDAP_INVALID_SYNTAX, "unique_modify() got null op.orm_modlist" );
+ return rs->sr_err;
+ }
+
+ /* successful load */
+ for ( ; m; m = m->sml_next ) {
+ /* only attribute UnicodePwd allowed! */
+ if ( strcasecmp( m->sml_type.bv_val, u_conf->attr.bv_val ) != 0 ) {
+ if ( u_conf->log_activity == 1 ) {
+ Debug( LDAP_DEBUG_STATS,
+ "conn=%lu op=%lu unicodepw: DENY => Attribute in Modification (%s) is not the configured pwattr!\n",
+ op->o_connid, op->o_opid,
+ m->sml_op == LDAP_MOD_ADD ? "ADD" : (m->sml_op == LDAP_MOD_DELETE ? "DEL" : "other") );
+ }
+ deny = 1;
+ } else {
+ if ( u_conf->log_activity == 1 ) {
+ Debug( LDAP_DEBUG_STATS,
+ "conn=%lu op=%lu unicodepw: OK => Attribute in Modification (%s) is the configured pwattr!\n",
+ op->o_connid, op->o_opid,
+ m->sml_op == LDAP_MOD_ADD ? "ADD" : (m->sml_op == LDAP_MOD_DELETE ? "DEL" : "other") );
+ }
+ }
+
+ /* only DEL and ADD allowed */
+ if ( m->sml_op == LDAP_MOD_DELETE || m->sml_op == LDAP_MOD_ADD ) {
+ if ( m->sml_op == LDAP_MOD_DELETE && i != 1 ) {
+ if ( u_conf->log_activity == 1 ) {
+ Debug( LDAP_DEBUG_STATS,
+ "conn=%lu op=%lu unicodepw: DENY => Modification DEL not in first place!%s\n",
+ op->o_connid, op->o_opid, "" );
+ }
+ deny = 1;
+ } else if ( m->sml_op == LDAP_MOD_ADD && i != 2 ) {
+ if ( u_conf->log_activity == 1 ) {
+ Debug( LDAP_DEBUG_STATS,
+ "conn=%lu op=%lu unicodepw: DENY => Modification ADD not in second place!%s\n",
+ op->o_connid, op->o_opid, "" );
+ }
+ deny = 1;
+ }
+ } else {
+ if ( u_conf->log_activity == 1 ) {
+ Debug( LDAP_DEBUG_STATS,
+ "conn=%lu op=%lu unicodepw: DENY => Modification not in ADD or DEL!%s\n",
+ op->o_connid, op->o_opid, "" );
+ }
+ deny = 1;
+ }
+ i++;
+ }
+
+ if ( i != 3 ) {
+ if ( u_conf->log_activity == 1 ) {
+ Debug( LDAP_DEBUG_STATS,
+ "conn=%lu op=%lu unicodepw: DENY => More or less than TWO modifications!%s\n",
+ op->o_connid, op->o_opid, "" );
+ }
+ deny = 1;
+ }
+
+ if ( !deny ) {
+ if ( u_conf->log_activity == 1 ) {
+ Debug( LDAP_DEBUG_STATS,
+ "conn=%lu op=%lu unicodepw: ACCEPT => UnicodePwd changing is permitted!%s\n",
+ op->o_connid, op->o_opid, "" );
+ }
+ return SLAP_CB_CONTINUE;
+ }
+
+ op->o_bd->bd_info = (BackendInfo *)on->on_info;
+ send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "operation not allowed by unicodepw!" );
+ return 0;
+}
+
+
+static int
+unicodepw_config(
+ BackendDB *be,
+ const char *fname,
+ int lineno,
+ int argc,
+ char **argv )
+{
+ slap_overinst *on = (slap_overinst *) be->bd_info;
+ unicodepw_conf *u_conf = (unicodepw_conf *) on->on_bi.bi_private;
+
+ Debug( LDAP_DEBUG_CONFIG,
+ "\tlline: %d,\t argv[1]: %s,\t argv[2]: %s\n",
+ lineno, argv[1], argv[2] );
+
+ if ( strcasecmp( argv[0], "unicodepw" ) == 0 ) {
+ if ( argc != 3 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: " "wrong configuration line, use: " "\"unicodepw \" line.%s\n",
+ fname, lineno, "" );
+ return 1;
+ }
+ Debug( LDAP_DEBUG_CONFIG,
+ "unicodepw: config => param: %s, value: %s%s\n",
+ argv[1] ,argv[2], "" );
+ if ( strcasecmp(argv[1], "pwattr" ) == 0 ) {
+ if ( u_conf->attr.bv_val ) {
+ /* if already defined! */
+ ch_free( u_conf->attr.bv_val );
+ }
+ ber_str2bv( argv[ 2 ], 0, 1, &u_conf->attr );
+ } else if ( strcasecmp(argv[1], "userbase" ) == 0 ) {
+ if ( u_conf->userbase.bv_val ) {
+ /* if already defined! */
+ ch_free( u_conf->userbase.bv_val );
+ }
+ ber_str2bv( argv[ 2 ], 0, 1, &u_conf->userbase );
+ } else if ( strcasecmp(argv[1], "logactivity" ) == 0 ) {
+ if ( strcasecmp( argv[ 2 ], "yes" ) == 0 ) {
+ u_conf->log_activity = 1;
+ } else if ( strcasecmp( argv[ 2 ], "no" ) == 0 ) {
+ u_conf->log_activity = 0;
+ } else {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: " "wrong configuration line, use: " "\"unicodepw logactivity \" line.%s\n",
+ fname, lineno, "" );
+ return SLAP_CONF_UNKNOWN;
+ }
+ } else if ( strcasecmp(argv[1], "subtree" ) == 0 ) {
+ if ( strcasecmp( argv[ 2 ], "yes" ) == 0 ) {
+ u_conf->subtree_search = 1;
+ } else if ( strcasecmp( argv[ 2 ], "no" ) == 0 ) {
+ u_conf->subtree_search = 0;
+ } else {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: " "wrong configuration line, use: " "\"unicodepw subtree \" line.%s\n",
+ fname, lineno, "" );
+ return SLAP_CONF_UNKNOWN;
+ }
+ } else {
+ return SLAP_CONF_UNKNOWN;
+ }
+ } else {
+ return SLAP_CONF_UNKNOWN;
+ }
+ return 0;
+}
+
+static int
+unicodepw_over_init( BackendDB *be )
+{
+ slap_overinst *on = (slap_overinst *) be->bd_info;
+ unicodepw_conf *u_conf;
+
+ u_conf = (unicodepw_conf *)ch_malloc( sizeof(unicodepw_conf) );
+ memset( u_conf, 0, sizeof(unicodepw_conf) );
+ on->on_bi.bi_private = u_conf;
+ return 0;
+}
+
+static int
+unicodepw_destroy( BackendDB *be )
+{
+ slap_overinst *on = (slap_overinst *) be->bd_info;
+ unicodepw_conf *u_conf = (unicodepw_conf *) on->on_bi.bi_private;
+
+ if ( u_conf ) {
+ ch_free ( u_conf );
+ }
+ return 0;
+}
+
+static slap_overinst unicodepw;
+
+int
+unicodepw_initialize( void ) {
+ memset( &unicodepw, 0, sizeof( slap_overinst ) );
+
+ unicodepw.on_bi.bi_type = "unicodepw";
+ unicodepw.on_bi.bi_db_init = unicodepw_over_init;
+ unicodepw.on_bi.bi_db_config = unicodepw_config;
+ unicodepw.on_bi.bi_db_destroy = unicodepw_destroy;
+
+ unicodepw.on_bi.bi_op_modify = unicodepw_mod;
+ unicodepw.on_response = NULL /* unicodepw_response */;
+
+ return overlay_register( &unicodepw );
+}
+
+#if SLAPD_OVER_UNICODEPW == SLAPD_MOD_DYNAMIC
+int
+init_module( int argc, char *argv[] ) {
+ return unicodepw_initialize();
+}
+#endif /* SLAPD_OVER_UNICODEPW == SLAPD_MOD_DYNAMIC */
+
+#endif /* defined(SLAPD_OVER_UNICODEPW) */