[Fedora-directory-commits] ldapserver/ldap/servers/slapd extendop.c, 1.11, 1.12 modify.c, 1.20, 1.21 passwd_extop.c, 1.18, 1.19

Nathan Kinder nkinder at fedoraproject.org
Thu Jan 15 18:24:51 UTC 2009


Author: nkinder

Update of /cvs/dirsec/ldapserver/ldap/servers/slapd
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv21352/ldap/servers/slapd

Modified Files:
	extendop.c modify.c passwd_extop.c 
Log Message:
Resolves: 184141
Summary: Make password modify extop work properly with the password policy control.



Index: extendop.c
===================================================================
RCS file: /cvs/dirsec/ldapserver/ldap/servers/slapd/extendop.c,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -r1.11 -r1.12
--- extendop.c	11 Dec 2008 23:05:23 -0000	1.11
+++ extendop.c	15 Jan 2009 18:24:48 -0000	1.12
@@ -311,6 +311,19 @@
 		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 );


Index: modify.c
===================================================================
RCS file: /cvs/dirsec/ldapserver/ldap/servers/slapd/modify.c,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -r1.20 -r1.21
--- modify.c	5 Dec 2008 22:41:52 -0000	1.20
+++ modify.c	15 Jan 2009 18:24:48 -0000	1.21
@@ -437,21 +437,30 @@
 
 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;


Index: passwd_extop.c
===================================================================
RCS file: /cvs/dirsec/ldapserver/ldap/servers/slapd/passwd_extop.c,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -r1.18 -r1.19
--- passwd_extop.c	11 Dec 2008 23:05:23 -0000	1.18
+++ passwd_extop.c	15 Jan 2009 18:24:48 -0000	1.19
@@ -143,33 +143,48 @@
 /* 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 @@
 
 
 /* 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 @@
 	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 @@
 	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 @@
 	 }
 
 	 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 @@
 	 /* 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 @@
 		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 @@
  	 * 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 @@
 	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 @@
 	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); 




More information about the Fedora-directory-commits mailing list