summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ldap/servers/slapd/Makefile2
-rw-r--r--ldap/servers/slapd/main.c13
-rw-r--r--ldap/servers/slapd/modify.c81
-rw-r--r--ldap/servers/slapd/passwd_extop.c516
4 files changed, 567 insertions, 45 deletions
diff --git a/ldap/servers/slapd/Makefile b/ldap/servers/slapd/Makefile
index 6935ac30..dc342de7 100644
--- a/ldap/servers/slapd/Makefile
+++ b/ldap/servers/slapd/Makefile
@@ -88,7 +88,7 @@ REGULAR_SLAPD_OBJS= abandon.o bind.o \
configdse.o pw_mgmt.o auth.o \
psearch.o conntable.o \
stubs.o protect_db.o fileio.o lite_entries.o \
- getopt_ext.o start_tls_extop.o
+ getopt_ext.o start_tls_extop.o passwd_extop.o
FEDSE_OBJ= fedse.o
FEDSE_SRC= fedse.c
SLAPD_OBJS= $(REGULAR_SLAPD_OBJS) $(FEDSE_OBJ)
diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c
index b52df26d..346444da 100644
--- a/ldap/servers/slapd/main.c
+++ b/ldap/servers/slapd/main.c
@@ -1015,12 +1015,17 @@ main( int argc, char **argv)
/* --ugaston: register the start-tls plugin */
#ifndef _WIN32
if ( slapd_security_library_is_initialized() != 0 ) {
+
+
start_tls_register_plugin();
LDAPDebug( LDAP_DEBUG_PLUGIN,
"Start TLS plugin registered.\n",
0, 0, 0 );
}
#endif
+ passwd_modify_register_plugin();
+ LDAPDebug( LDAP_DEBUG_PLUGIN,
+ "Password Modify plugin registered.\n", 0, 0, 0 );
plugin_startall(argc, argv, 1 /* Start Backends */, 1 /* Start Globals */);
if (housekeeping_start((time_t)0, NULL) == NULL) {
@@ -1246,12 +1251,13 @@ process_command_line(int argc, char **argv, char *myname,
{"encrypt",ArgOptional,'E'},
{0,0,0}};
- char *opts_archive2db = "vd:i:a:SD:";
+ char *opts_archive2db = "vd:i:a:n:SD:";
struct opt_ext long_options_archive2db[] = {
{"version",ArgNone,'v'},
{"debug",ArgRequired,'d'},
{"pidfile",ArgRequired,'i'},
{"archive",ArgRequired,'a'},
+ {"backEndInstName",ArgRequired,'n'},
{"allowMultipleProcesses",ArgNone,'S'},
{"instanceDir",ArgRequired,'D'},
{0,0,0}};
@@ -1486,10 +1492,11 @@ process_command_line(int argc, char **argv, char *myname,
case 'w': /* set startup pid file */
start_pid_file = rel2abspath( optarg_ext );
break;
- case 'n': /* which backend to do ldif2db for */
+ case 'n': /* which backend to do ldif2db/bak2db for */
if (slapd_exemode == SLAPD_EXEMODE_LDIF2DB ||
slapd_exemode == SLAPD_EXEMODE_DBTEST ||
- slapd_exemode == SLAPD_EXEMODE_DB2INDEX) {
+ slapd_exemode == SLAPD_EXEMODE_DB2INDEX ||
+ slapd_exemode == SLAPD_EXEMODE_ARCHIVE2DB) {
/* The -n argument will give the name of a backend instance. */
cmd_line_instance_name = optarg_ext;
} else if (slapd_exemode == SLAPD_EXEMODE_DB2LDIF) {
diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c
index 56c4de7c..86237758 100644
--- a/ldap/servers/slapd/modify.c
+++ b/ldap/servers/slapd/modify.c
@@ -90,17 +90,15 @@ do_modify( Slapi_PBlock *pb )
int err;
int pw_change = 0; /* 0= no password change */
int ignored_some_mods = 0;
+ int has_password_mod = 0; /* number of password mods */
char *old_pw = NULL; /* remember the old password */
char *dn;
- LDAPControl **ctrlp = NULL;
LDAPDebug( LDAP_DEBUG_TRACE, "do_modify\n", 0, 0, 0 );
slapi_pblock_get( pb, SLAPI_OPERATION, &operation);
ber = operation->o_ber;
- slapi_pblock_get(pb, SLAPI_REQCONTROLS, &ctrlp);
-
/* count the modify request */
PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsModifyEntryOps);
@@ -217,47 +215,45 @@ do_modify( Slapi_PBlock *pb )
/* check for password change */
if ( mod->mod_bvalues != NULL &&
strcasecmp( mod->mod_type, SLAPI_USERPWD_ATTR ) == 0 ){
- if ( (err = get_ldapmessage_controls( pb, ber, NULL )) != 0 ) {
- op_shared_log_error_access (pb, "MOD", dn, "failed to decode LDAP controls");
- send_ldap_result( pb, err, NULL, NULL, 0, NULL );
- goto free_and_return;
- }
- pw_change = op_shared_allow_pw_change (pb, mod, &old_pw);
- if (pw_change == -1)
- {
- ber_bvecfree(mod->mod_bvalues);
- slapi_ch_free((void **)&(mod->mod_type));
- slapi_ch_free((void **)&mod);
- goto free_and_return;
- }
+ has_password_mod++;
}
mod->mod_op |= LDAP_MOD_BVALUES;
slapi_mods_add_ldapmod (&smods, mod);
}
- if ( tag == LBER_ERROR && !ctrlp )
+ /* check for decoding error */
+ if ( tag == LBER_ERROR )
{
op_shared_log_error_access (pb, "MOD", dn, "decoding error");
send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "decoding error", 0, NULL );
goto free_and_return;
}
- if ( slapi_mods_get_num_mods (&smods) == 0 )
+ /* decode the optional controls - put them in the pblock */
+ if ( (err = get_ldapmessage_controls( pb, ber, NULL )) != 0 )
{
- int lderr;
- char *emsg;
+ op_shared_log_error_access (pb, "MOD", dn, "failed to decode LDAP controls");
+ send_ldap_result( pb, err, NULL, NULL, 0, NULL );
+ goto free_and_return;
+ }
- if ( ignored_some_mods ) {
- lderr = LDAP_UNWILLING_TO_PERFORM;
- emsg = "no modifiable attributes specified";
- } else {
- lderr = LDAP_PROTOCOL_ERROR;
- emsg = "no modifications specified";
+ /* if there are any password mods, see if they are allowed */
+ if (has_password_mod) {
+ /* iterate through the mods looking for password mods */
+ for (mod = slapi_mods_get_first_mod(&smods);
+ mod;
+ mod = slapi_mods_get_next_mod(&smods)) {
+ if ( mod->mod_bvalues != NULL &&
+ strcasecmp( mod->mod_type, SLAPI_USERPWD_ATTR ) == 0 ) {
+ /* assumes controls have already been decoded and placed
+ in the pblock */
+ pw_change = op_shared_allow_pw_change (pb, mod, &old_pw);
+ if (pw_change == -1) {
+ goto free_and_return;
+ }
+ }
}
- op_shared_log_error_access (pb, "MOD", dn, emsg);
- send_ldap_result( pb, lderr, NULL, emsg, 0, NULL );
- goto free_and_return;
}
if (!pb->pb_conn->c_isreplication_session &&
@@ -269,19 +265,23 @@ do_modify( Slapi_PBlock *pb )
goto free_and_return;
}
- /*
- * in LDAPv3 there can be optional control extensions on
- * the end of an LDAPMessage. we need to read them in and
- * pass them to the backend.
- */
- if ( !ctrlp ) {
- if ( (err = get_ldapmessage_controls( pb, ber, NULL )) != 0 )
+ /* see if there were actually any mods to perform */
+ if ( slapi_mods_get_num_mods (&smods) == 0 )
{
- op_shared_log_error_access (pb, "MOD", dn, "failed to decode LDAP controls");
- send_ldap_result( pb, err, NULL, NULL, 0, NULL );
+ int lderr;
+ char *emsg;
+
+ if ( ignored_some_mods ) {
+ lderr = LDAP_UNWILLING_TO_PERFORM;
+ emsg = "no modifiable attributes specified";
+ } else {
+ lderr = LDAP_PROTOCOL_ERROR;
+ emsg = "no modifications specified";
+ }
+ op_shared_log_error_access (pb, "MOD", dn, emsg);
+ send_ldap_result( pb, lderr, NULL, emsg, 0, NULL );
goto free_and_return;
}
- }
#ifdef LDAP_DEBUG
LDAPDebug( LDAP_DEBUG_ARGS, "modifications:\n", 0, 0, 0 );
@@ -441,8 +441,7 @@ static int modify_internal_pb (Slapi_PBlock *pb)
pw_change = op_shared_allow_pw_change (pb, *mod, &old_pw);
if (pw_change == -1)
{
- opresult = LDAP_PARAM_ERROR;
- slapi_pblock_set(pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+ /* The internal result code will already have been set by op_shared_allow_pw_change() */
return 0;
}
}
diff --git a/ldap/servers/slapd/passwd_extop.c b/ldap/servers/slapd/passwd_extop.c
new file mode 100644
index 00000000..c4412746
--- /dev/null
+++ b/ldap/servers/slapd/passwd_extop.c
@@ -0,0 +1,516 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Password Modify - LDAP Extended Operation.
+ * RFC 3062
+ *
+ *
+ * This plugin implements the "Password Modify - LDAP3"
+ * extended operation for LDAP. The plugin function is called by
+ * the server if an LDAP client request contains the OID:
+ * "1.3.6.1.4.1.4203.1.11.1".
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <private/pprio.h>
+
+
+#include <prio.h>
+#include <ssl.h>
+#include "slap.h"
+#include "slapi-plugin.h"
+#include "fe.h"
+
+/* Type of connection for this operation;*/
+#define LDAP_EXTOP_PASSMOD_CONN_SECURE
+
+/* Uncomment the following line FOR TESTING: allows non-SSL connections to use the password change extended op */
+/* #undef LDAP_EXTOP_PASSMOD_CONN_SECURE */
+
+/* ber tags for the PasswdModifyRequestValue sequence */
+#define LDAP_EXTOP_PASSMOD_TAG_USERID 0x80U
+#define LDAP_EXTOP_PASSMOD_TAG_OLDPWD 0x81U
+#define LDAP_EXTOP_PASSMOD_TAG_NEWPWD 0x82U
+
+/* OID of the extended operation handled by this plug-in */
+#define EXOP_PASSWD_OID "1.3.6.1.4.1.4203.1.11.1"
+
+
+Slapi_PluginDesc passwdopdesc = { "passwd_modify_plugin", "Netscape", "0.1",
+ "Password Modify extended operation plugin" };
+
+/* Check SLAPI_USERPWD_ATTR attribute of the directory entry
+ * return 0, if the userpassword attribute contains the given pwd value
+ * return -1, if userPassword attribute is absent for given Entry
+ * return LDAP_INVALID_CREDENTIALS,if userPassword attribute and given pwd don't match
+ */
+static int passwd_check_pwd(Slapi_Entry *targetEntry, const char *pwd){
+ int rc = LDAP_SUCCESS;
+ Slapi_Attr *attr = NULL;
+ Slapi_Value cv;
+ Slapi_Value **bvals;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> passwd_check_pwd\n", 0, 0, 0 );
+
+ slapi_value_init_string(&cv,pwd);
+
+ if ( (rc = slapi_entry_attr_find( targetEntry, SLAPI_USERPWD_ATTR, &attr )) == 0 )
+ { /* we have found the userPassword attribute and it has some value */
+ bvals = attr_get_present_values( attr );
+ if ( slapi_pw_find_sv( bvals, &cv ) != 0 )
+ {
+ rc = LDAP_INVALID_CREDENTIALS;
+ }
+ }
+
+ value_done(&cv);
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= passwd_check_pwd: %d\n", rc, 0, 0 );
+
+ /* if the userPassword attribute is absent then rc is -1 */
+ return rc;
+}
+
+
+/* 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
+ */
+static int
+passwd_modify_getEntry( const char *dn, Slapi_Entry **e2 ) {
+ int search_result = 0;
+ Slapi_DN sdn;
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> passwd_modify_getEntry\n", 0, 0, 0 );
+ slapi_sdn_init_dn_byref( &sdn, dn );
+ if ((search_result = slapi_search_internal_get_entry( &sdn, NULL, e2,
+ plugin_get_default_component_id())) != LDAP_SUCCESS ){
+ LDAPDebug (LDAP_DEBUG_TRACE, "passwd_modify_getEntry: No such entry-(%s), err (%d)\n",
+ dn, search_result, 0);
+ }
+
+ slapi_sdn_done( &sdn );
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= passwd_modify_getEntry: %d\n", search_result, 0, 0 );
+ return search_result;
+}
+
+
+/* Construct Mods pblock and perform the modify operation
+ * Sets result of operation in SLAPI_PLUGIN_INTOP_RESULT
+ */
+static int passwd_apply_mods(const char *dn, Slapi_Mods *mods)
+{
+ Slapi_PBlock pb;
+ Slapi_Operation *operation= NULL;
+ int ret=0;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> passwd_apply_mods\n", 0, 0, 0 );
+
+ if (mods && (slapi_mods_get_num_mods(mods) > 0))
+ {
+ pblock_init(&pb);
+ slapi_modify_internal_set_pb (&pb, dn,
+ slapi_mods_get_ldapmods_byref(mods),
+ NULL, /* Controls */
+ NULL, /* UniqueID */
+ pw_get_componentID(), /* PluginID */
+ 0); /* Flags */
+
+ /* Plugin operations are INTERNAL by default, bypass it to enforce ACL checks */
+ slapi_pblock_get (&pb, SLAPI_OPERATION, &operation);
+
+ ret =slapi_modify_internal_pb (&pb);
+
+ slapi_pblock_get(&pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
+
+ if (ret != LDAP_SUCCESS){
+ LDAPDebug(LDAP_DEBUG_TRACE, "WARNING: passwordPolicy modify error %d on entry '%s'\n",
+ ret, dn, 0);
+ }
+
+ pblock_done(&pb);
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= passwd_apply_mods: %d\n", ret, 0, 0 );
+
+ return ret;
+}
+
+
+
+/* Modify the userPassword attribute field of the entry */
+static int passwd_modify_userpassword(Slapi_Entry *targetEntry, const char *newPasswd)
+{
+ char *dn = NULL;
+ int ret = 0;
+ Slapi_Mods smods;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> passwd_modify_userpassword\n", 0, 0, 0 );
+
+ slapi_mods_init (&smods, 0);
+ dn = slapi_entry_get_ndn( targetEntry );
+ slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, SLAPI_USERPWD_ATTR, newPasswd);
+
+
+ ret = passwd_apply_mods(dn, &smods);
+
+ slapi_mods_done(&smods);
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= passwd_modify_userpassword: %d\n", ret, 0, 0 );
+
+ return ret;
+}
+
+/* Password Modify Extended operation plugin function */
+int
+passwd_modify_extop( Slapi_PBlock *pb )
+{
+ char *oid = NULL;
+ char *bindDN = NULL;
+ char *dn = NULL;
+ char *oldPasswd = NULL;
+ char *newPasswd = NULL;
+ char *errMesg = NULL;
+ char **reqvals = NULL;
+ int ret=0, rc=0;
+ unsigned long tag=0, len=-1;
+ LDAPControl **ctrlp = NULL; /* unused */
+ Slapi_Operation *operation = NULL; /* unused */
+ struct berval *extop_value = NULL;
+ BerElement *ber = NULL;
+ Slapi_Entry *targetEntry=NULL;
+ Connection *conn = NULL;
+ /* Slapi_DN sdn; */
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> passwd_modify_extop\n", 0, 0, 0 );
+ /* Get the pb ready for sending Password Modify Extended Responses back to the client.
+ * The only requirement is to set the LDAP OID of the extended response to the EXOP_PASSWD_OID. */
+
+ if ( slapi_pblock_set( pb, SLAPI_EXT_OP_RET_OID, EXOP_PASSWD_OID ) != 0 ) {
+ errMesg = "Could not set extended response oid.\n";
+ rc = LDAP_OPERATIONS_ERROR;
+ slapi_log_error( SLAPI_LOG_PLUGIN, "passwd_modify_extop",
+ errMesg );
+ goto free_and_return;
+ }
+
+ /* Before going any further, we'll make sure that the right extended operation plugin
+ * has been called: i.e., the OID shipped whithin the extended operation request must
+ * match this very plugin's OID: EXOP_PASSWD_OID. */
+ if ( slapi_pblock_get( pb, SLAPI_EXT_OP_REQ_OID, &oid ) != 0 ) {
+ errMesg = "Could not get OID value from request.\n";
+ rc = LDAP_OPERATIONS_ERROR;
+ slapi_log_error( SLAPI_LOG_PLUGIN, "passwd_modify_extop",
+ errMesg );
+ goto free_and_return;
+ } else {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "passwd_modify_extop",
+ "Received extended operation request with OID %s\n", oid );
+ }
+
+ if ( strcasecmp( oid, EXOP_PASSWD_OID ) != 0) {
+ errMesg = "Request OID does not match Passwd OID.\n";
+ rc = LDAP_OPERATIONS_ERROR;
+ goto free_and_return;
+ } else {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "passwd_modify_extop",
+ "Password Modify extended operation request confirmed.\n" );
+ }
+
+ /* Now , at least we know that the request was indeed a Password Modify one. */
+
+#ifdef LDAP_EXTOP_PASSMOD_CONN_SECURE
+ /* Allow password modify only for SSL/TLS established connections */
+ conn = pb->pb_conn;
+ if ( (conn->c_flags & CONN_FLAG_SSL) != CONN_FLAG_SSL) {
+ errMesg = "Operation requires a secure connection.\n";
+ rc = LDAP_CONFIDENTIALITY_REQUIRED;
+ goto free_and_return;
+ }
+#endif
+
+ /* Get the ber value of the extended operation */
+ slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_value);
+
+ if ((ber = ber_init(extop_value)) == NULL)
+ {
+ errMesg = "PasswdModify Request decode failed.\n";
+ rc = LDAP_PROTOCOL_ERROR;
+ goto free_and_return;
+ }
+
+ /* Format of request to parse
+ *
+ * PasswdModifyRequestValue ::= SEQUENCE {
+ * userIdentity [0] OCTET STRING OPTIONAL
+ * oldPasswd [1] OCTET STRING OPTIONAL
+ * newPasswd [2] OCTET STRING OPTIONAL }
+ */
+ slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_value);
+
+ /* ber parse code */
+ if ( ber_scanf( ber, "{") == LBER_ERROR )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ber_scanf failed :{\n", 0, 0, 0 );
+ errMesg = "ber_scanf failed\n";
+ rc = LDAP_PROTOCOL_ERROR;
+ goto free_and_return;
+ } else {
+ tag = ber_peek_tag( ber, &len);
+ }
+
+
+ /* identify userID field by tags */
+ if (tag == LDAP_EXTOP_PASSMOD_TAG_USERID )
+ {
+ if ( ber_scanf( ber, "a", &dn) == LBER_ERROR )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ber_scanf failed :{\n", 0, 0, 0 );
+ errMesg = "ber_scanf failed at userID parse.\n";
+ rc = LDAP_PROTOCOL_ERROR;
+ goto free_and_return;
+ }
+
+ tag = ber_peek_tag( ber, &len);
+ }
+
+
+ /* identify oldPasswd field by tags */
+ if (tag == LDAP_EXTOP_PASSMOD_TAG_OLDPWD )
+ {
+ if ( ber_scanf( ber, "a", &oldPasswd ) == LBER_ERROR )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ber_scanf failed :{\n", 0, 0, 0 );
+ errMesg = "ber_scanf failed at oldPasswd parse.\n";
+ rc = LDAP_PROTOCOL_ERROR;
+ goto free_and_return;
+ }
+ tag = ber_peek_tag( ber, &len);
+ } else {
+ errMesg = "Current passwd must be supplied by the user.\n";
+ rc = LDAP_PARAM_ERROR;
+ goto free_and_return;
+ }
+
+ /* identify newPasswd field by tags */
+ if (tag == LDAP_EXTOP_PASSMOD_TAG_NEWPWD )
+ {
+ if ( ber_scanf( ber, "a", &newPasswd ) == LBER_ERROR )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ber_scanf failed :{\n", 0, 0, 0 );
+ errMesg = "ber_scanf failed at newPasswd parse.\n";
+ rc = LDAP_PROTOCOL_ERROR;
+ goto free_and_return;
+ }
+ } else {
+ errMesg = "New passwd must be supplied by the user.\n";
+ rc = LDAP_PARAM_ERROR;
+ goto free_and_return;
+ }
+
+ /* Uncomment for debugging, otherwise we don't want to leak the password values into the log... */
+ /* LDAPDebug( LDAP_DEBUG_ARGS, "passwd: dn (%s), oldPasswd (%s) ,newPasswd (%s)\n",
+ dn, oldPasswd, newPasswd); */
+
+
+ if (oldPasswd == NULL || *oldPasswd == '\0') {
+ /* Refuse to handle this operation because current password is not provided */
+ errMesg = "Current passwd must be supplied by the user.\n";
+ rc = LDAP_PARAM_ERROR;
+ goto free_and_return;
+ }
+
+ /* We don't implement password generation, so if the request implies
+ * that they asked us to do that, we must refuse to process it */
+ if (newPasswd == NULL || *newPasswd == '\0') {
+ /* Refuse to handle this operation because we don't allow password generation */
+ errMesg = "New passwd must be supplied by the user.\n";
+ rc = LDAP_PARAM_ERROR;
+ goto free_and_return;
+ }
+
+ /* Get Bind DN */
+ slapi_pblock_get( pb, SLAPI_CONN_DN, &bindDN );
+
+ /* If the connection is bound anonymously, we must refuse to process this operation. */
+ if (bindDN == NULL || *bindDN == '\0') {
+ /* Refuse the operation because they're bound anonymously */
+ errMesg = "Anonymous Binds are not allowed.\n";
+ rc = LDAP_INSUFFICIENT_ACCESS;
+ goto free_and_return;
+ }
+
+ /* Determine the target DN for this operation */
+ /* Did they give us a DN ? */
+ if (dn == NULL || *dn == '\0') {
+ /* Get the DN from the bind identity on this connection */
+ dn = bindDN;
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Missing userIdentity in request, using the bind DN instead.\n",
+ 0, 0, 0 );
+ }
+
+ slapi_pblock_set( pb, SLAPI_ORIGINAL_TARGET, dn );
+
+ /* Now we have the DN, look for the entry */
+ ret = passwd_modify_getEntry(dn, &targetEntry);
+ /* If we can't find the entry, then that's an error */
+ if (ret) {
+ /* Couldn't find the entry, fail */
+ errMesg = "No such Entry exists.\n" ;
+ rc = LDAP_NO_SUCH_OBJECT ;
+ goto free_and_return;
+ }
+
+ /* First thing to do is to ask access control if the bound identity has
+ rights to modify the userpassword attribute on this entry. If not, then
+ we fail immediately with insufficient access. This means that we don't
+ leak any useful information to the client such as current password
+ wrong, etc.
+ */
+
+ operation_set_target_spec (pb->pb_op, slapi_entry_get_sdn(targetEntry));
+ slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &pb->pb_op->o_isroot );
+
+ /* In order to perform the access control check , we need to select a backend (even though
+ * we don't actually need it otherwise).
+ */
+ {
+ Slapi_Backend *be = NULL;
+
+ be = slapi_mapping_tree_find_backend_for_sdn(slapi_entry_get_sdn(targetEntry));
+ if (NULL == be) {
+ errMesg = "Failed to find backend for target entry";
+ rc = LDAP_OPERATIONS_ERROR;
+ goto free_and_return;
+ }
+ slapi_pblock_set(pb, SLAPI_BACKEND, be);
+ }
+
+ ret = slapi_access_allowed ( pb, targetEntry, SLAPI_USERPWD_ATTR, NULL, SLAPI_ACL_WRITE );
+ if ( ret != LDAP_SUCCESS ) {
+ errMesg = "Insufficient access rights\n";
+ rc = LDAP_INSUFFICIENT_ACCESS;
+ goto free_and_return;
+ }
+
+ /* Now we have the entry which we want to modify
+ * They gave us a password (old), check it against the target entry
+ * Is the old password valid ?
+ */
+ ret = passwd_check_pwd(targetEntry, oldPasswd);
+ if (ret) {
+ /* No, then we fail this operation */
+ errMesg = "Invalid oldPasswd value.\n";
+ rc = ret;
+ goto free_and_return;
+ }
+
+
+ /* Now we're ready to make actual password change */
+ ret = passwd_modify_userpassword(targetEntry, newPasswd);
+ if (ret != LDAP_SUCCESS) {
+ /* Failed to modify the password, e.g. because insufficient access allowed */
+ errMesg = "Failed to update password\n";
+ rc = ret;
+ goto free_and_return;
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= passwd_modify_extop: %d\n", rc, 0, 0 );
+
+ /* Free anything that we allocated above */
+ free_and_return:
+
+ if ( targetEntry != NULL ){
+ slapi_entry_free (targetEntry);
+ }
+
+ if ( ber != NULL ){
+ ber_free(ber, 1);
+ ber = NULL;
+ }
+
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, "passwd_modify_extop",
+ errMesg );
+ send_ldap_result( pb, rc, NULL, errMesg, 0, NULL );
+
+
+ return( SLAPI_PLUGIN_EXTENDED_SENT_RESULT );
+
+}/* passwd_modify_extop */
+
+
+static char *passwd_oid_list[] = {
+ EXOP_PASSWD_OID,
+ NULL
+};
+
+
+static char *passwd_name_list[] = {
+ "passwd_modify_extop",
+ NULL
+};
+
+
+/* Initialization function */
+int passwd_modify_init( Slapi_PBlock *pb )
+{
+ char **argv;
+ char *oid;
+
+ /* Get the arguments appended to the plugin extendedop directive. The first argument
+ * (after the standard arguments for the directive) should contain the OID of the
+ * extended operation.
+ */
+
+ if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGV, &argv ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "passwd_modify_init", "Could not get argv\n" );
+ return( -1 );
+ }
+
+ /* Compare the OID specified in the configuration file against the Passwd OID. */
+
+ if ( argv == NULL || strcmp( argv[0], EXOP_PASSWD_OID ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "passwd_modify_init",
+ "OID is missing or is not %s\n", EXOP_PASSWD_OID );
+ return( -1 );
+ } else {
+ oid = slapi_ch_strdup( argv[0] );
+ slapi_log_error( SLAPI_LOG_PLUGIN, "passwd_modify_init",
+ "Registering plug-in for Password Modify extended op %s.\n", oid );
+ }
+
+ /* Register the plug-in function as an extended operation
+ * plug-in function that handles the operation identified by
+ * OID 1.3.6.1.4.1.4203.1.11.1 . Also specify the version of the server
+ * plug-in */
+ if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&passwdopdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_FN, (void *) passwd_modify_extop ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_OIDLIST, passwd_oid_list ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_NAMELIST, passwd_name_list ) != 0 ) {
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, "passwd_modify_init",
+ "Failed to set plug-in version, function, and OID.\n" );
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+int passwd_modify_register_plugin()
+{
+ slapi_register_plugin( "extendedop", 1 /* Enabled */, "passwd_modify_init",
+ passwd_modify_init, "Password Modify extended operation",
+ passwd_oid_list, NULL );
+
+ return 0;
+}
+