[Samba] Microsoft hotfix MS04-011, breaks Samba password change.

Jeremy Allison jra at samba.org
Tue May 4 20:06:45 GMT 2004


On Tue, May 04, 2004 at 09:31:07AM -0700, Jeremy Allison wrote:
> Hi all,
> 
> 	I wanted to give an update on this as I know this MS Hotfix
> is critical and must be applied to protect against the (latest) Microsoft
> worm.
> 
> I think I've found the problem in the code, and am currently testing
> a fix for this (not in the release to others to test stage yet). As
> soon as I'm reasonably confident I'll put a patch out there for others
> to test, and we'll probably do a new stable release to ensure this is
> fixed in the current codebase.

And here is a (preliminary working) patch against 3.0.3.

Please test this to see if it fixes the problem with password
changing. I am back-porting this to 2.2.8a and will issue another
patch shortly. We'll then do a 2.2.9 release which will consist
of 2.2.8a plus this patch.

Thanks for helping me test,

Jeremy.
-------------- next part --------------
Index: rpc_server/srv_pipe.c
===================================================================
--- rpc_server/srv_pipe.c	(revision 459)
+++ rpc_server/srv_pipe.c	(working copy)
@@ -87,6 +87,7 @@
 	RPC_HDR_RESP hdr_resp;
 	BOOL auth_verify = ((p->ntlmssp_chal_flags & NTLMSSP_NEGOTIATE_SIGN) != 0);
 	BOOL auth_seal   = ((p->ntlmssp_chal_flags & NTLMSSP_NEGOTIATE_SEAL) != 0);
+	uint32 ss_padding_len = 0;
 	uint32 data_len;
 	uint32 data_space_available;
 	uint32 data_len_left;
@@ -109,21 +110,22 @@
 	p->hdr.pkt_type = RPC_RESPONSE;
 
 	/* Set up rpc header flags. */
-	if (p->out_data.data_sent_length == 0)
+	if (p->out_data.data_sent_length == 0) {
 		p->hdr.flags = RPC_FLG_FIRST;
-	else
+	} else {
 		p->hdr.flags = 0;
+	}
 
 	/*
 	 * Work out how much we can fit in a single PDU.
 	 */
 
 	data_space_available = sizeof(p->out_data.current_pdu) - RPC_HEADER_LEN - RPC_HDR_RESP_LEN;
-	if(p->ntlmssp_auth_validated)
+	if(p->ntlmssp_auth_validated) {
 		data_space_available -= (RPC_HDR_AUTH_LEN + RPC_AUTH_NTLMSSP_CHK_LEN);
-
-	if(p->netsec_auth_validated)
+	} else if(p->netsec_auth_validated) {
 		data_space_available -= (RPC_HDR_AUTH_LEN + RPC_AUTH_NETSEC_CHK_LEN);
+	}
 
 	/*
 	 * The amount we send is the minimum of the available
@@ -151,15 +153,30 @@
 	hdr_resp.alloc_hint = data_len_left;
 
 	/*
+	 * Work out if this PDU will be the last.
+	 */
+
+	if(p->out_data.data_sent_length + data_len >= prs_offset(&p->out_data.rdata)) {
+		p->hdr.flags |= RPC_FLG_LAST;
+		if ((auth_seal || auth_verify) && (data_len_left % 8)) {
+			ss_padding_len = 8 - (data_len_left % 8);
+			DEBUG(10,("create_next_pdu: adding sign/seal padding of %u\n",
+				ss_padding_len ));
+		}
+	}
+
+	/*
 	 * Set up the header lengths.
 	 */
 
 	if (p->ntlmssp_auth_validated) {
-		p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len +
-					RPC_HDR_AUTH_LEN + RPC_AUTH_NTLMSSP_CHK_LEN;
+		p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN +
+			data_len + ss_padding_len +
+			RPC_HDR_AUTH_LEN + RPC_AUTH_NTLMSSP_CHK_LEN;
 		p->hdr.auth_len = RPC_AUTH_NTLMSSP_CHK_LEN;
 	} else if (p->netsec_auth_validated) {
-		p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len +
+		p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN +
+			data_len + ss_padding_len +
 			RPC_HDR_AUTH_LEN + RPC_AUTH_NETSEC_CHK_LEN;
 		p->hdr.auth_len = RPC_AUTH_NETSEC_CHK_LEN;
 	} else {
@@ -168,13 +185,6 @@
 	}
 
 	/*
-	 * Work out if this PDU will be the last.
-	 */
-
-	if(p->out_data.data_sent_length + data_len >= prs_offset(&p->out_data.rdata))
-		p->hdr.flags |= RPC_FLG_LAST;
-
-	/*
 	 * Init the parse struct to point at the outgoing
 	 * data.
 	 */
@@ -206,12 +216,26 @@
 		return False;
 	}
 
+	/* Copy the sign/seal padding data. */
+	if (ss_padding_len) {
+		char pad[8];
+		memset(pad, '\0', 8);
+		if (!prs_copy_data_in(&outgoing_pdu, pad, ss_padding_len)) {
+			DEBUG(0,("create_next_pdu: failed to add %u bytes of pad data.\n", (unsigned int)ss_padding_len));
+			prs_mem_free(&outgoing_pdu);
+			return False;
+		}
+	}
+
 	if (p->ntlmssp_auth_validated) {
+		/*
+		 * NTLMSSP processing. Mutually exclusive with Schannel.
+		 */
 		uint32 crc32 = 0;
 		char *data;
 
 		DEBUG(5,("create_next_pdu: sign: %s seal: %s data %d auth %d\n",
-			 BOOLSTR(auth_verify), BOOLSTR(auth_seal), data_len, p->hdr.auth_len));
+			 BOOLSTR(auth_verify), BOOLSTR(auth_seal), data_len + ss_padding_len, p->hdr.auth_len));
 
 		/*
 		 * Set data to point to where we copied the data into.
@@ -220,15 +244,16 @@
 		data = prs_data_p(&outgoing_pdu) + data_pos;
 
 		if (auth_seal) {
-			crc32 = crc32_calc_buffer(data, data_len);
-			NTLMSSPcalc_p(p, (uchar*)data, data_len);
+			crc32 = crc32_calc_buffer(data, data_len + ss_padding_len);
+			NTLMSSPcalc_p(p, (uchar*)data, data_len + ss_padding_len);
 		}
 
 		if (auth_seal || auth_verify) {
 			RPC_HDR_AUTH auth_info;
 
-			init_rpc_hdr_auth(&auth_info, NTLMSSP_AUTH_TYPE, auth_info.auth_level,
-					(auth_verify ? RPC_HDR_AUTH_LEN : 0), (auth_verify ? 1 : 0));
+			init_rpc_hdr_auth(&auth_info, NTLMSSP_AUTH_TYPE,
+					auth_seal ? RPC_PIPE_AUTH_SEAL_LEVEL : RPC_PIPE_AUTH_SIGN_LEVEL,
+					(auth_verify ? ss_padding_len : 0), (auth_verify ? 1 : 0));
 			if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, &outgoing_pdu, 0)) {
 				DEBUG(0,("create_next_pdu: failed to marshall RPC_HDR_AUTH.\n"));
 				prs_mem_free(&outgoing_pdu);
@@ -251,9 +276,10 @@
 			}
 			NTLMSSPcalc_p(p, (uchar*)auth_data, RPC_AUTH_NTLMSSP_CHK_LEN - 4);
 		}
-	}
-
-	if (p->netsec_auth_validated) {
+	} else if (p->netsec_auth_validated) {
+		/*
+		 * Schannel processing. Mutually exclusive with NTLMSSP.
+		 */
 		int auth_type, auth_level;
 		char *data;
 		RPC_HDR_AUTH auth_info;
@@ -267,7 +293,7 @@
 
 		get_auth_type_level(p->netsec_auth.auth_flags, &auth_type, &auth_level);
 		init_rpc_hdr_auth(&auth_info, auth_type, auth_level, 
-				  RPC_HDR_AUTH_LEN, 1);
+				  ss_padding_len, 1);
 
 		if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, &outgoing_pdu, 0)) {
 			DEBUG(0,("create_next_pdu: failed to marshall RPC_HDR_AUTH.\n"));
@@ -281,7 +307,7 @@
 		netsec_encode(&p->netsec_auth, 
 			      p->netsec_auth.auth_flags,
 			      SENDER_IS_ACCEPTOR,
-			      &verf, data, data_len);
+			      &verf, data, data_len + ss_padding_len);
 
 		smb_io_rpc_auth_netsec_chk("", &verf, &outgoing_pdu, 0);
 
@@ -292,7 +318,7 @@
 	 * Setup the counts for this PDU.
 	 */
 
-	p->out_data.data_sent_length += data_len;
+	p->out_data.data_sent_length += (data_len + ss_padding_len);
 	p->out_data.current_pdu_len = p->hdr.frag_len;
 	p->out_data.current_pdu_sent = 0;
 


More information about the samba-technical mailing list