[PATCH] Support Setup[SetupCount] values in nttrans response packets

David Disseldorp ddiss at sgi.com
Fri Jun 13 08:19:09 GMT 2008


send_nt_replies currently sets SetupCount to zero, however some packets
require different values. When testing FSCTL_RECALL_FILE, Windows XPsp2
was observed dropping connections where SetupCount was not one in the server
response.

The SNIA CIFS documentation also describes NT_TRANSACT_IOCTL server response
packets as having a SetupCount of 1.
---
 source/include/smb.h  |    2 +
 source/smbd/notify.c  |    4 +-
 source/smbd/nttrans.c |  172 +++++++++++++++++++++++++++++--------------------
 3 files changed, 105 insertions(+), 73 deletions(-)

diff --git a/source/include/smb.h b/source/include/smb.h
index 76cc389..be32ea9 100644
--- a/source/include/smb.h
+++ b/source/include/smb.h
@@ -1203,6 +1203,8 @@ struct bitmap {
 #define smb_ntr_DataCount (smb_vwv0 + 23)
 #define smb_ntr_DataOffset (smb_vwv0 + 27)
 #define smb_ntr_DataDisplacement (smb_vwv0 + 31)
+#define smb_ntr_SetupCount (smb_vwv0 + 35)
+#define smb_ntr_SetupStart (smb_vwv0 + 36)
 
 /* these are for the NT create_and_X */
 #define smb_ntcreate_NameLength (smb_vwv0 + 5)
diff --git a/source/smbd/notify.c b/source/smbd/notify.c
index eb3384d..e1157b8 100644
--- a/source/smbd/notify.c
+++ b/source/smbd/notify.c
@@ -196,8 +196,8 @@ void change_notify_reply(connection_struct *conn,
 
 	init_smb_request(req, tmp_request,0, conn->encrypted_tid);
 
-	send_nt_replies(conn, req, NT_STATUS_OK, prs_data_p(&ps),
-			prs_offset(&ps), NULL, 0);
+	send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0,
+			prs_data_p(&ps), prs_offset(&ps), NULL, 0);
 
  done:
 	TALLOC_FREE(req);
diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c
index cbe1299..270f382 100644
--- a/source/smbd/nttrans.c
+++ b/source/smbd/nttrans.c
@@ -63,11 +63,11 @@ static char *nttrans_realloc(char **ptr, size_t size)
  Send the required number of replies back.
  We assume all fields other than the data fields are
  set correctly for the type of call.
- HACK ! Always assumes smb_setup field is zero.
 ****************************************************************************/
 
 void send_nt_replies(connection_struct *conn,
-			struct smb_request *req, NTSTATUS nt_error,
+		     struct smb_request *req, NTSTATUS nt_error,
+		     uint16 *setup, uint8 setup_count,
 		     char *params, int paramsize,
 		     char *pdata, int datasize)
 {
@@ -76,30 +76,28 @@ void send_nt_replies(connection_struct *conn,
 	int useable_space;
 	char *pp = params;
 	char *pd = pdata;
-	int params_sent_thistime, data_sent_thistime, total_sent_thistime;
-	int alignment_offset = 3;
-	int data_alignment_offset = 0;
+	int params_sent_thistime, data_sent_thistime;
+	int i;
+	int pad1 = 0;
+	int pad2 = 0;
 
 	/*
-	 * If there genuinely are no parameters or data to send just send
+	 * If there genuinely are no parameters, data or setup to send just send
 	 * the empty packet.
 	 */
 
-	if(params_to_send == 0 && data_to_send == 0) {
+	if(params_to_send == 0 && data_to_send == 0 && setup_count == 0) {
 		reply_outbuf(req, 18, 0);
 		show_msg((char *)req->outbuf);
 		return;
 	}
 
 	/*
-	 * When sending params and data ensure that both are nicely aligned.
-	 * Only do this alignment when there is also data to send - else
-	 * can cause NT redirector problems.
+	 * pad1 pushes out to a four byte boundary after:
+	 * UCHAR SetupCount + USHORT Setup[SetupCount] + USHORT ByteCount
 	 */
-
-	if (((params_to_send % 4) != 0) && (data_to_send != 0)) {
-		data_alignment_offset = 4 - (params_to_send % 4);
-	}
+	pad1 = (((1 + 2 * setup_count + 2) + 3) & ~3)
+	       - (1 + 2 * setup_count + 2);
 
 	/*
 	 * Space is bufsize minus Netbios over TCP header minus SMB header.
@@ -109,35 +107,60 @@ void send_nt_replies(connection_struct *conn,
 	 */
 
 	useable_space = max_send - (smb_size
-				    + 2 * 18 /* wct */
-				    + alignment_offset
-				    + data_alignment_offset);
+				    + 2 * 18 /* wct no setup */
+				    + 1 /* UCHAR SetupCount */
+				    + 2 * setup_count /* USHORT Setup[SetupCount] */
+				    + 2 /* USHORT ByteCount */
+				    + pad1);
 
 	/*
-	 * useable_space can never be more than max_send minus the
-	 * alignment offset.
+	 * if Setup[] is to big, there will be no room for data or
+	 * parameters.
 	 */
+	if (useable_space <= 0) {
+		exit_server_cleanly(
+			"send_nt_replies: no usable space in nt reply packet");
+		return;
+	}
 
-	useable_space = MIN(useable_space,
-				max_send - (alignment_offset+data_alignment_offset));
-
-
-	while (params_to_send || data_to_send) {
+	do {
 
 		/*
-		 * Calculate whether we will totally or partially fill this packet.
+		 * Calculate how many parameters and data we can fit into
+		 * this packet. Parameters get precedence.
 		 */
 
-		total_sent_thistime = params_to_send + data_to_send +
-					alignment_offset + data_alignment_offset;
+		params_sent_thistime = MIN(params_to_send,useable_space);
+		/*
+		 * When sending params and data ensure that both are nicely aligned.
+		 * Only do this alignment when there is also data to send - else
+		 * can cause NT redirector problems.
+		 *
+		 * pad2 pushes out to a four byte boundary after parameters
+		 */
+		if ((data_to_send) && (params_sent_thistime)) {
+			pad2 = ((params_sent_thistime + 3) & ~3)
+			       - params_sent_thistime;
+		}
+		else {
+			pad2 = 0;
+		}
+		data_sent_thistime = useable_space - params_sent_thistime - pad2;
+		/*
+		 * check if pad2 pushed past packet end
+		 */
+		if (data_sent_thistime <= 0) {
+			pad2 = 0;
+			data_sent_thistime = 0;
+		}
+		data_sent_thistime = MIN(data_sent_thistime,data_to_send);
 
 		/*
 		 * We can never send more than useable_space.
 		 */
 
-		total_sent_thistime = MIN(total_sent_thistime, useable_space);
-
-		reply_outbuf(req, 18, total_sent_thistime);
+		reply_outbuf(req, 18 + setup_count,
+			pad1 + params_sent_thistime + pad2 + data_sent_thistime);
 
 		/*
 		 * Set total params and data to be sent.
@@ -145,16 +168,6 @@ void send_nt_replies(connection_struct *conn,
 
 		SIVAL(req->outbuf,smb_ntr_TotalParameterCount,paramsize);
 		SIVAL(req->outbuf,smb_ntr_TotalDataCount,datasize);
-
-		/*
-		 * Calculate how many parameters and data we can fit into
-		 * this packet. Parameters get precedence.
-		 */
-
-		params_sent_thistime = MIN(params_to_send,useable_space);
-		data_sent_thistime = useable_space - params_sent_thistime;
-		data_sent_thistime = MIN(data_sent_thistime,data_to_send);
-
 		SIVAL(req->outbuf, smb_ntr_ParameterCount,
 		      params_sent_thistime);
 
@@ -163,14 +176,14 @@ void send_nt_replies(connection_struct *conn,
 			SIVAL(req->outbuf,smb_ntr_ParameterDisplacement,0);
 		} else {
 			/*
-			 * smb_ntr_ParameterOffset is the offset from the start of the SMB header to the
-			 * parameter bytes, however the first 4 bytes of outbuf are
-			 * the Netbios over TCP header. Thus use smb_base() to subtract
-			 * them from the calculation.
+			 * smb_ntr_ParameterOffset is the offset from the start of the
+			 * SMB header to the parameter bytes, however the first 4 bytes of
+			 * outbuf are the Netbios over TCP header. Thus use smb_base() to
+			 * subtract them from the calculation.
 			 */
 
 			SIVAL(req->outbuf,smb_ntr_ParameterOffset,
-			      ((smb_buf(req->outbuf)+alignment_offset)
+			      ((smb_buf(req->outbuf) + pad1)
 			       - smb_base(req->outbuf)));
 			/*
 			 * Absolute displacement of param bytes sent in this packet.
@@ -196,22 +209,35 @@ void send_nt_replies(connection_struct *conn,
 			 */
 
 			SIVAL(req->outbuf, smb_ntr_DataOffset,
-			      ((smb_buf(req->outbuf)+alignment_offset) -
+			      ((smb_buf(req->outbuf) + pad1) -
 			       smb_base(req->outbuf))
-			      + params_sent_thistime + data_alignment_offset);
+			      + params_sent_thistime + pad2);
 			SIVAL(req->outbuf,smb_ntr_DataDisplacement, pd - pdata);
 		}
 
 		/*
+		 * Deal with the setup portion.
+		 */
+
+		SCVAL(req->outbuf,smb_ntr_SetupCount,setup_count);
+		for (i=0;i<setup_count;i++) {
+			SSVAL(req->outbuf,smb_ntr_SetupStart+i*2,setup[i]);
+		}
+
+		/*
+		 * zero pading
+		 */
+		if (pad1 != 0) {
+			memset(smb_buf(req->outbuf), 0,
+			       pad1);
+		}
+
+		/*
 		 * Copy the param bytes into the packet.
 		 */
 
 		if(params_sent_thistime) {
-			if (alignment_offset != 0) {
-				memset(smb_buf(req->outbuf), 0,
-				       alignment_offset);
-			}
-			memcpy((smb_buf(req->outbuf)+alignment_offset), pp,
+			memcpy((smb_buf(req->outbuf) + pad1), pp,
 			       params_sent_thistime);
 		}
 
@@ -220,13 +246,13 @@ void send_nt_replies(connection_struct *conn,
 		 */
 
 		if(data_sent_thistime) {
-			if (data_alignment_offset != 0) {
-				memset((smb_buf(req->outbuf)+alignment_offset+
-					params_sent_thistime), 0,
-				       data_alignment_offset);
+			if (pad2 != 0) {
+				memset((smb_buf(req->outbuf) + pad1
+				       +params_sent_thistime), 0,
+				       pad2);
 			}
-			memcpy(smb_buf(req->outbuf)+alignment_offset
-			       +params_sent_thistime+data_alignment_offset,
+			memcpy(smb_buf(req->outbuf) + pad1
+			       +params_sent_thistime+pad2,
 			       pd,data_sent_thistime);
 		}
 
@@ -266,7 +292,7 @@ void send_nt_replies(connection_struct *conn,
 				params_to_send, data_to_send));
 			return;
 		}
-	}
+	} while (params_to_send || data_to_send);
 }
 
 /****************************************************************************
@@ -732,7 +758,8 @@ static void do_nt_transact_create_pipe(connection_struct *conn,
 	DEBUG(5,("do_nt_transact_create_pipe: open name = %s\n", fname));
 
 	/* Send the required number of replies */
-	send_nt_replies(conn, req, NT_STATUS_OK, params, param_len, *ppdata, 0);
+	send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0,
+			params, param_len, *ppdata, 0);
 
 	return;
 }
@@ -1078,7 +1105,8 @@ static void call_nt_transact_create(connection_struct *conn,
 	DEBUG(5,("call_nt_transact_create: open name = %s\n", fsp->fsp_name));
 
 	/* Send the required number of replies */
-	send_nt_replies(conn, req, NT_STATUS_OK, params, param_len, *ppdata, 0);
+	send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0,
+			params, param_len, *ppdata, 0);
 
 	return;
 }
@@ -1535,7 +1563,7 @@ static void call_nt_transact_rename(connection_struct *conn,
 	 * W2K3 ignores this request as the RAW-RENAME test
 	 * demonstrates, so we do.
 	 */
-	send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0);
+	send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0, NULL, 0);
 
 	DEBUG(3,("nt transact rename from = %s, to = %s ignored!\n",
 		 fsp->fsp_name, new_name));
@@ -1629,7 +1657,7 @@ static void call_nt_transact_query_security_desc(connection_struct *conn,
 
 	if (max_data_count < sd_size) {
 		send_nt_replies(conn, req, NT_STATUS_BUFFER_TOO_SMALL,
-				params, 4, *ppdata, 0);
+				NULL, 0, params, 4, *ppdata, 0);
 		return;
 	}
 
@@ -1654,7 +1682,8 @@ static void call_nt_transact_query_security_desc(connection_struct *conn,
 	SMB_ASSERT(sd_size == blob.length);
 	memcpy(data, blob.data, sd_size);
 
-	send_nt_replies(conn, req, NT_STATUS_OK, params, 4, data, (int)sd_size);
+	send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, params, 4,
+			data, (int)sd_size);
 
 	return;
 }
@@ -1711,7 +1740,7 @@ static void call_nt_transact_set_security_desc(connection_struct *conn,
 	}
 
   done:
-	send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0);
+	send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0, NULL, 0);
 	return;
 }
 
@@ -1760,7 +1789,7 @@ static void call_nt_transact_ioctl(connection_struct *conn,
 		   so we can know if we need to pre-allocate or not */
 
 		DEBUG(10,("FSCTL_SET_SPARSE: called on FID[0x%04X](but not implemented)\n", fidnum));
-		send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0);
+		send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0, NULL, 0);
 		return;
 
 	case FSCTL_CREATE_OR_GET_OBJECT_ID:
@@ -1786,7 +1815,7 @@ static void call_nt_transact_ioctl(connection_struct *conn,
 		push_file_id_16(pdata, &fsp->file_id);
 		memcpy(pdata+16,create_volume_objectid(conn,objid),16);
 		push_file_id_16(pdata+32, &fsp->file_id);
-		send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0,
+		send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0,
 				pdata, data_count);
 		return;
 	}
@@ -1931,7 +1960,7 @@ static void call_nt_transact_ioctl(connection_struct *conn,
 
 		talloc_destroy(shadow_data->mem_ctx);
 
-		send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0,
+		send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0,
 				pdata, data_count);
 
 		return;
@@ -1987,9 +2016,10 @@ static void call_nt_transact_ioctl(connection_struct *conn,
 		 */
 
 		/* this works for now... */
-		send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0);
+		send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0, NULL, 0);
 		return;
 	}
+
 	default:
 		if (!logged_message) {
 			logged_message = True; /* Only print this once... */
@@ -2274,7 +2304,7 @@ static void call_nt_transact_get_user_quota(connection_struct *conn,
 			break;
 	}
 
-	send_nt_replies(conn, req, nt_status, params, param_len,
+	send_nt_replies(conn, req, nt_status, NULL, 0, params, param_len,
 			pdata, data_len);
 }
 
@@ -2405,7 +2435,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn,
 		return;
 	}
 
-	send_nt_replies(conn, req, NT_STATUS_OK, params, param_len,
+	send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, params, param_len,
 			pdata, data_len);
 }
 #endif /* HAVE_SYS_QUOTAS */
-- 
1.5.4.rc0



More information about the samba-technical mailing list