[Fedora-directory-commits] ldapserver/ldap/servers/plugins/replication windows_connection.c, 1.16, 1.17 windows_protocol_util.c, 1.34, 1.35 windowsrepl.h, 1.13, 1.14

Nathan Kinder (nkinder) fedora-directory-commits at redhat.com
Thu Sep 27 18:33:33 UTC 2007


Author: nkinder

Update of /cvs/dirsec/ldapserver/ldap/servers/plugins/replication
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv15634

Modified Files:
	windows_connection.c windows_protocol_util.c windowsrepl.h 
Log Message:
Resolves: 238504
Summary: Don't replay AD originated password changes back to AD.



Index: windows_connection.c
===================================================================
RCS file: /cvs/dirsec/ldapserver/ldap/servers/plugins/replication/windows_connection.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -r1.16 -r1.17
--- windows_connection.c	12 Sep 2007 23:05:24 -0000	1.16
+++ windows_connection.c	27 Sep 2007 18:33:30 -0000	1.17
@@ -1796,6 +1796,34 @@
 	}
 }
 
+/* Attempt to bind as a user to AD in order to see if we posess the
+ * most current password. Returns the LDAP return code of the bind. */
+int
+windows_check_user_password(Repl_Connection *conn, Slapi_DN *sdn, char *password)
+{
+	const char *binddn = NULL;
+	LDAPMessage *res = NULL;
+	int rc = 0;
+	int msgid = 0;
+
+	/* If we're already connected, this will just return success */
+	windows_conn_connect(conn);
+
+	/* Get binddn from sdn */
+	binddn =  slapi_sdn_get_dn(sdn);
+
+	/* Attempt to do a bind on the existing connection 
+	 * using the dn and password that were passed in. */
+	msgid = do_simple_bind(conn, conn->ld, (char *) binddn, password);
+	ldap_result(conn->ld, msgid, LDAP_MSG_ALL, NULL, &res);
+	ldap_parse_result( conn->ld, res, &rc, NULL, NULL, NULL, NULL, 1 /* Free res */);
+
+	/* rebind as the DN specified in the sync agreement */
+	do_simple_bind(conn, conn->ld, conn->binddn, conn->plain);
+
+	return rc;
+}
+
 static int
 do_simple_bind (Repl_Connection *conn, LDAP *ld, char * binddn, char *password)
 {


Index: windows_protocol_util.c
===================================================================
RCS file: /cvs/dirsec/ldapserver/ldap/servers/plugins/replication/windows_protocol_util.c,v
retrieving revision 1.34
retrieving revision 1.35
diff -u -r1.34 -r1.35
--- windows_protocol_util.c	20 Sep 2007 23:32:17 -0000	1.34
+++ windows_protocol_util.c	27 Sep 2007 18:33:30 -0000	1.35
@@ -741,49 +741,62 @@
 
 		} else
 		{
-			char *quoted_password = NULL;
-			/* AD wants the password in quotes ! */
-			quoted_password = PR_smprintf("\"%s\"",password);
-			if (quoted_password)
-			{
-				LDAPMod *pw_mods[2];
-				LDAPMod pw_mod;
-				struct berval bv = {0};
-				UChar *unicode_password = NULL;
-				int32_t unicode_password_length = 0; /* Length in _characters_ */
-				int32_t buffer_size = 0; /* Size in _characters_ */
-				UErrorCode error = U_ZERO_ERROR;
-				struct berval *bvals[2];
-				/* Need to UNICODE encode the password here */
-				/* It's one of those 'ask me first and I will tell you the buffer size' functions */
-				u_strFromUTF8(NULL, 0, &unicode_password_length, quoted_password, strlen(quoted_password), &error);
-				buffer_size = unicode_password_length;
-				unicode_password = (UChar *)slapi_ch_malloc(unicode_password_length * sizeof(UChar));
-				if (unicode_password) {
-					error = U_ZERO_ERROR;
-					u_strFromUTF8(unicode_password, buffer_size, &unicode_password_length, quoted_password, strlen(quoted_password), &error);
-
-					/* As an extra special twist, we need to send the unicode in little-endian order for AD to be happy */
-					to_little_endian_double_bytes(unicode_password, unicode_password_length);
-
-					bv.bv_len = unicode_password_length * sizeof(UChar);
-					bv.bv_val = (char*)unicode_password;
+			/* We will attempt to bind to AD with the new password first. We do
+			 * this to avoid playing a password change that originated from AD
+			 * back to AD.  If we just played the password change back, then
+			 * both sides would be in sync, but AD would contain the new password
+			 * twice in it's password history, which undermines the password
+			 * history policies in AD. */
+			if (windows_check_user_password(prp->conn, sdn, password)) {
+				char *quoted_password = NULL;
+				/* AD wants the password in quotes ! */
+				quoted_password = PR_smprintf("\"%s\"",password);
+				if (quoted_password)
+				{
+					LDAPMod *pw_mods[2];
+					LDAPMod pw_mod;
+					struct berval bv = {0};
+					UChar *unicode_password = NULL;
+					int32_t unicode_password_length = 0; /* Length in _characters_ */
+					int32_t buffer_size = 0; /* Size in _characters_ */
+					UErrorCode error = U_ZERO_ERROR;
+					struct berval *bvals[2];
+					/* Need to UNICODE encode the password here */
+					/* It's one of those 'ask me first and I will tell you the buffer size' functions */
+					u_strFromUTF8(NULL, 0, &unicode_password_length, quoted_password, strlen(quoted_password), &error);
+					buffer_size = unicode_password_length;
+					unicode_password = (UChar *)slapi_ch_malloc(unicode_password_length * sizeof(UChar));
+					if (unicode_password) {
+						error = U_ZERO_ERROR;
+						u_strFromUTF8(unicode_password, buffer_size, &unicode_password_length, quoted_password, strlen(quoted_password), &error);
+	
+						/* As an extra special twist, we need to send the unicode in little-endian order for AD to be happy */
+						to_little_endian_double_bytes(unicode_password, unicode_password_length);
+	
+						bv.bv_len = unicode_password_length * sizeof(UChar);
+						bv.bv_val = (char*)unicode_password;
 				
-					bvals[0] = &bv; 
-					bvals[1] = NULL;
+						bvals[0] = &bv; 
+						bvals[1] = NULL;
 						
-					pw_mod.mod_type = "UnicodePwd";
-					pw_mod.mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
-					pw_mod.mod_bvalues = bvals;
+						pw_mod.mod_type = "UnicodePwd";
+						pw_mod.mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
+						pw_mod.mod_bvalues = bvals;
 					
-					pw_mods[0] = &pw_mod;
-					pw_mods[1] = NULL;
+						pw_mods[0] = &pw_mod;
+						pw_mods[1] = NULL;
 
-					pw_return = windows_conn_send_modify(prp->conn, slapi_sdn_get_dn(sdn), pw_mods, NULL, NULL );
+						pw_return = windows_conn_send_modify(prp->conn, slapi_sdn_get_dn(sdn), pw_mods, NULL, NULL );
 
-					slapi_ch_free((void**)&unicode_password);
+						slapi_ch_free((void**)&unicode_password);
+					}
+					PR_smprintf_free(quoted_password);
 				}
-				PR_smprintf_free(quoted_password);
+			} else {
+				slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
+					"%s: AD already has the current password for %s. "
+					"Not sending password modify to AD.\n",
+					agmt_get_long_name(prp->agmt), slapi_sdn_get_dn(sdn));
 			}
 		}
 
@@ -1230,15 +1243,32 @@
 		}
 		if (password) 
 		{
-			return_value = send_password_modify(remote_dn, password, prp);
+			/* We need to have a non-GUID dn in send_password_modify in order to
+			 * bind as the user to check if we need to send the password change.
+			 * You are supposed to be able to bind using a GUID dn, but it doesn't
+			 * seem to work over plain LDAP. */
+			if (is_guid_dn(remote_dn)) {
+				Slapi_DN *remote_dn_norm = NULL;
+				int norm_missing = 0;
+
+				map_entry_dn_outbound(local_entry,&remote_dn_norm,prp,&norm_missing, 0);
+				return_value = send_password_modify(remote_dn_norm, password, prp);
+				slapi_sdn_free(&remote_dn_norm);
+			} else {
+				return_value = send_password_modify(remote_dn, password, prp);
+			}
+
 			if (return_value)
 			{
-				slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, "%s: windows_replay_update: update password returned %d\n",
+				slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
+					"%s: windows_replay_update: update password returned %d\n",
 					agmt_get_long_name(prp->agmt), return_value );
 			} else {
-				/* If we successfully added an entry, and then subsequently changed its password, THEN we need to change its status in AD 
-				 * in order that it can be used (otherwise the user is marked as disabled). To do this we set this attribute and value:
-				 * userAccountControl: 512 */
+				/* If we successfully added an entry, and then subsequently changed
+				 * its password, THEN we need to change its status in AD in order
+				 * that it can be used (otherwise the user is marked as disabled).
+				 * To do this we set this attribute and value:
+				 *   userAccountControl: 512 */
 				if (op->operation_type == SLAPI_OPERATION_ADD && missing_entry)
 				{
 					return_value = send_accountcontrol_modify(remote_dn, prp);


Index: windowsrepl.h
===================================================================
RCS file: /cvs/dirsec/ldapserver/ldap/servers/plugins/replication/windowsrepl.h,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- windowsrepl.h	17 Sep 2007 19:18:30 -0000	1.13
+++ windowsrepl.h	27 Sep 2007 18:33:30 -0000	1.14
@@ -100,6 +100,7 @@
 ConnResult windows_conn_push_schema(Repl_Connection *conn, CSN **remotecsn);
 void windows_conn_set_timeout(Repl_Connection *conn, long timeout);
 void windows_conn_set_agmt_changed(Repl_Connection *conn);
+int windows_check_user_password(Repl_Connection *conn, Slapi_DN *sdn, char *password);
 
 /* Used to work around a schema incompatibility between Microsoft and the IETF */
 #define FAKE_STREET_ATTR_NAME "in#place#of#streetaddress"




More information about the Fedora-directory-commits mailing list