[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