summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathan Kinder <nkinder@redhat.com>2009-01-15 18:24:48 +0000
committerNathan Kinder <nkinder@redhat.com>2009-01-15 18:24:48 +0000
commitbf00ddf580bfd3f9340ab7703c23d867ad5524af (patch)
treeacc9a2fb22abd377bf4dba5732031fabd653b8b9
parent03ab7a78d9396e4583aa5fdcb70515c57512e96a (diff)
downloadds-bf00ddf580bfd3f9340ab7703c23d867ad5524af.tar.gz
ds-bf00ddf580bfd3f9340ab7703c23d867ad5524af.tar.xz
ds-bf00ddf580bfd3f9340ab7703c23d867ad5524af.zip
Resolves: 184141
Summary: Make password modify extop work properly with the password policy control.
-rw-r--r--ldap/servers/slapd/extendop.c13
-rw-r--r--ldap/servers/slapd/modify.c17
-rw-r--r--ldap/servers/slapd/passwd_extop.c147
3 files changed, 126 insertions, 51 deletions
diff --git a/ldap/servers/slapd/extendop.c b/ldap/servers/slapd/extendop.c
index 53947c6e..ced66c34 100644
--- a/ldap/servers/slapd/extendop.c
+++ b/ldap/servers/slapd/extendop.c
@@ -311,6 +311,19 @@ do_extended( Slapi_PBlock *pb )
goto free_and_return;
}
+ /* decode the optional controls - put them in the pblock */
+ if ( (lderr = get_ldapmessage_controls( pb, pb->pb_op->o_ber, NULL )) != 0 )
+ {
+ char *dn = NULL;
+ slapi_pblock_get(pb, SLAPI_CONN_DN, &dn);
+
+ op_shared_log_error_access (pb, "EXT", dn ? dn : "", "failed to decode LDAP controls");
+ send_ldap_result( pb, lderr, NULL, NULL, 0, NULL );
+
+ slapi_ch_free_string(&dn);
+ goto free_and_return;
+ }
+
slapi_pblock_set( pb, SLAPI_EXT_OP_REQ_OID, extoid );
slapi_pblock_set( pb, SLAPI_EXT_OP_REQ_VALUE, &extval );
rc = plugin_call_exop_plugins( pb, extoid );
diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c
index 4fd2a8b2..09ccd424 100644
--- a/ldap/servers/slapd/modify.c
+++ b/ldap/servers/slapd/modify.c
@@ -437,21 +437,30 @@ void slapi_modify_internal_set_pb (Slapi_PBlock *pb, const char *dn, LDAPMod **m
static int modify_internal_pb (Slapi_PBlock *pb)
{
- LDAPControl **controls;
+ LDAPControl **controls;
+ LDAPControl *pwpolicy_ctrl;
Operation *op;
- int opresult = 0;
+ int opresult = 0;
LDAPMod **normalized_mods = NULL;
LDAPMod **mods;
LDAPMod **mod;
Slapi_Mods smods;
- int pw_change = 0;
- char *old_pw = NULL;
+ int pw_change = 0;
+ char *old_pw = NULL;
PR_ASSERT (pb != NULL);
slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
slapi_pblock_get(pb, SLAPI_CONTROLS_ARG, &controls);
+ /* See if pwpolicy control is present. We need to do
+ * this before we call op_shared_allow_pw_change() since
+ * it looks for SLAPI_PWPOLICY in the pblock to determine
+ * if the response contorl is needed. */
+ pwpolicy_ctrl = slapi_control_present( controls,
+ LDAP_X_CONTROL_PWPOLICY_REQUEST, NULL, NULL );
+ slapi_pblock_set( pb, SLAPI_PWPOLICY, &pwpolicy_ctrl );
+
if(mods == NULL)
{
opresult = LDAP_PARAM_ERROR;
diff --git a/ldap/servers/slapd/passwd_extop.c b/ldap/servers/slapd/passwd_extop.c
index 8b1185a5..5958171b 100644
--- a/ldap/servers/slapd/passwd_extop.c
+++ b/ldap/servers/slapd/passwd_extop.c
@@ -143,33 +143,48 @@ passwd_modify_getEntry( const char *dn, Slapi_Entry **e2 ) {
/* 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)
+static int passwd_apply_mods(const char *dn, Slapi_Mods *mods, LDAPControl **req_controls,
+ LDAPControl ***resp_controls)
{
Slapi_PBlock pb;
+ LDAPControl **req_controls_copy = NULL;
+ LDAPControl **pb_resp_controls = NULL;
int ret=0;
LDAPDebug( LDAP_DEBUG_TRACE, "=> passwd_apply_mods\n", 0, 0, 0 );
if (mods && (slapi_mods_get_num_mods(mods) > 0))
{
+ /* We need to dup the request controls since the original
+ * pblock owns the ones that have been passed in. */
+ if (req_controls) {
+ slapi_add_controls(&req_controls_copy, req_controls, 1);
+ }
+
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 */
+ slapi_mods_get_ldapmods_byref(mods),
+ req_controls_copy, NULL, /* UniqueID */
+ pw_get_componentID(), /* PluginID */
+ 0); /* Flags */
- ret =slapi_modify_internal_pb (&pb);
+ ret =slapi_modify_internal_pb (&pb);
- slapi_pblock_get(&pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
+ 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);
- }
+ /* Retreive and duplicate the response controls since they will be
+ * destroyed along with the pblock used for the internal operation. */
+ slapi_pblock_get(&pb, SLAPI_RESCONTROLS, &pb_resp_controls);
+ if (pb_resp_controls) {
+ slapi_add_controls(resp_controls, pb_resp_controls, 1);
+ }
- pblock_done(&pb);
+ 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 );
@@ -180,7 +195,8 @@ static int passwd_apply_mods(const char *dn, Slapi_Mods *mods)
/* Modify the userPassword attribute field of the entry */
-static int passwd_modify_userpassword(Slapi_Entry *targetEntry, const char *newPasswd)
+static int passwd_modify_userpassword(Slapi_Entry *targetEntry, const char *newPasswd,
+ LDAPControl **req_controls, LDAPControl ***resp_controls)
{
char *dn = NULL;
int ret = 0;
@@ -193,7 +209,7 @@ static int passwd_modify_userpassword(Slapi_Entry *targetEntry, const char *newP
slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, SLAPI_USERPWD_ATTR, newPasswd);
- ret = passwd_apply_mods(dn, &smods);
+ ret = passwd_apply_mods(dn, &smods, req_controls, resp_controls);
slapi_mods_done(&smods);
@@ -432,15 +448,18 @@ passwd_modify_extop( Slapi_PBlock *pb )
char *oldPasswd = NULL;
char *newPasswd = NULL;
char *errMesg = NULL;
- int ret=0, rc=0, sasl_ssf=0;
+ int ret=0, rc=0, sasl_ssf=0, need_pwpolicy_ctrl=0;
ber_tag_t tag=0;
ber_len_t len=(ber_len_t)-1;
struct berval *extop_value = NULL;
struct berval *gen_passwd = NULL;
BerElement *ber = NULL;
BerElement *response_ber = NULL;
- Slapi_Entry *targetEntry=NULL;
+ Slapi_Entry *targetEntry=NULL;
Connection *conn = NULL;
+ LDAPControl **req_controls = NULL;
+ LDAPControl **resp_controls = NULL;
+ passwdPolicy *pwpolicy = NULL;
/* Slapi_DN sdn; */
LDAPDebug( LDAP_DEBUG_TRACE, "=> passwd_modify_extop\n", 0, 0, 0 );
@@ -589,33 +608,31 @@ parse_req_done:
}
if (oldPasswd == NULL || *oldPasswd == '\0') {
- /* If user is authenticated, they already gave their password during
- the bind operation (or used sasl or client cert auth or OS creds) */
- slapi_pblock_get(pb, SLAPI_CONN_AUTHMETHOD, &authmethod);
- if (!authmethod || !strcmp(authmethod, SLAPD_AUTH_NONE)) {
- errMesg = "User must be authenticated to the directory server.\n";
- rc = LDAP_INSUFFICIENT_ACCESS;
- goto free_and_return;
- }
+ /* If user is authenticated, they already gave their password during
+ * the bind operation (or used sasl or client cert auth or OS creds) */
+ slapi_pblock_get(pb, SLAPI_CONN_AUTHMETHOD, &authmethod);
+ if (!authmethod || !strcmp(authmethod, SLAPD_AUTH_NONE)) {
+ errMesg = "User must be authenticated to the directory server.\n";
+ rc = LDAP_INSUFFICIENT_ACCESS;
+ goto free_and_return;
+ }
}
+
+ /* Fetch the password policy. We need this in case we need to
+ * generate a password as well as for some policy checks. */
+ pwpolicy = new_passwdPolicy( pb, dn );
/* A new password was not supplied in the request, so we need to generate
* a random one and return it to the user in a response.
*/
if (newPasswd == NULL || *newPasswd == '\0') {
- passwdPolicy *pwpolicy;
int rval;
/* Do a free of newPasswd here to be safe, otherwise we may leak 1 byte */
slapi_ch_free_string( &newPasswd );
-
- pwpolicy = new_passwdPolicy( pb, dn );
-
/* Generate a new password */
rval = passwd_modify_generate_passwd( pwpolicy, &newPasswd, &errMesg );
- delete_passwdPolicy(&pwpolicy);
-
if (rval != LDAP_SUCCESS) {
if (!errMesg)
errMesg = "Error generating new password.\n";
@@ -659,8 +676,8 @@ parse_req_done:
/* Did they give us a DN ? */
if (dn == NULL || *dn == '\0') {
/* Get the DN from the bind identity on this connection */
- slapi_ch_free_string(&dn);
- dn = slapi_ch_strdup(bindDN);
+ slapi_ch_free_string(&dn);
+ dn = slapi_ch_strdup(bindDN);
LDAPDebug( LDAP_DEBUG_ANY,
"Missing userIdentity in request, using the bind DN instead.\n",
0, 0, 0 );
@@ -703,8 +720,14 @@ parse_req_done:
slapi_pblock_set(pb, SLAPI_BACKEND, be);
}
+ /* Check if the pwpolicy control is present */
+ slapi_pblock_get( pb, SLAPI_PWPOLICY, &need_pwpolicy_ctrl );
+
ret = slapi_access_allowed ( pb, targetEntry, SLAPI_USERPWD_ATTR, NULL, SLAPI_ACL_WRITE );
- if ( ret != LDAP_SUCCESS ) {
+ if ( ret != LDAP_SUCCESS ) {
+ if (need_pwpolicy_ctrl) {
+ slapi_pwpolicy_make_response_control ( pb, -1, -1, LDAP_PWPOLICY_PWDMODNOTALLOWED );
+ }
errMesg = "Insufficient access rights\n";
rc = LDAP_INSUFFICIENT_ACCESS;
goto free_and_return;
@@ -714,21 +737,50 @@ parse_req_done:
* They gave us a password (old), check it against the target entry
* Is the old password valid ?
*/
- if (oldPasswd && *oldPasswd) {
- 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;
- }
- }
-
+ if (oldPasswd && *oldPasswd) {
+ 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;
+ }
+ }
+
+ /* Check if password policy allows users to change their passwords. We need to do
+ * this here since the normal modify code doesn't perform this check for
+ * internal operations. */
+ if (!pb->pb_op->o_isroot && !pb->pb_conn->c_needpw && !pwpolicy->pw_change) {
+ Slapi_DN *bindSDN = slapi_sdn_new_dn_byref(bindDN);
+ /* Is this a user modifying their own password? */
+ if (slapi_sdn_compare(bindSDN, slapi_entry_get_sdn(targetEntry))==0) {
+ if (need_pwpolicy_ctrl) {
+ slapi_pwpolicy_make_response_control ( pb, -1, -1, LDAP_PWPOLICY_PWDMODNOTALLOWED );
+ }
+ errMesg = "User is not allowed to change password\n";
+ rc = LDAP_UNWILLING_TO_PERFORM;
+ slapi_sdn_free(&bindSDN);
+ goto free_and_return;
+ }
+ slapi_sdn_free(&bindSDN);
+ }
+ /* Fetch any present request controls so we can use them when
+ * performing the modify operation. */
+ slapi_pblock_get(pb, SLAPI_REQCONTROLS, &req_controls);
+
/* Now we're ready to make actual password change */
- ret = passwd_modify_userpassword(targetEntry, newPasswd);
+ ret = passwd_modify_userpassword(targetEntry, newPasswd, req_controls, &resp_controls);
+
+ /* Set the response controls if necessary. We want to do this now
+ * so it is set for both the success and failure cases. The pblock
+ * will now own the controls. */
+ if (resp_controls) {
+ slapi_pblock_set(pb, SLAPI_RESCONTROLS, resp_controls);
+ }
+
if (ret != LDAP_SUCCESS) {
- /* Failed to modify the password, e.g. because insufficient access allowed */
+ /* Failed to modify the password, e.g. because password policy, etc. */
errMesg = "Failed to update password\n";
rc = ret;
goto free_and_return;
@@ -742,7 +794,7 @@ parse_req_done:
LDAPDebug( LDAP_DEBUG_TRACE, "<= passwd_modify_extop: %d\n", rc, 0, 0 );
/* Free anything that we allocated above */
- free_and_return:
+free_and_return:
slapi_ch_free_string(&bindDN); /* slapi_pblock_get SLAPI_CONN_DN does strdup */
slapi_ch_free_string(&oldPasswd);
slapi_ch_free_string(&newPasswd);
@@ -756,6 +808,7 @@ parse_req_done:
slapi_ch_free_string(&otdn);
slapi_pblock_set( pb, SLAPI_ORIGINAL_TARGET, NULL );
slapi_ch_free_string(&authmethod);
+ delete_passwdPolicy(&pwpolicy);
if ( targetEntry != NULL ){
slapi_entry_free (targetEntry);