summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2007-05-14 18:02:49 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 14:52:26 -0500
commitbf62b6642c77e14142cdb724dc99dd3f8bfd89ac (patch)
tree2b17ad07f9b77bb5ec7d4397b8306e02938095ba
parent37f8c04d900df00dd984dfd6be33b367b145a3ac (diff)
downloadsamba-bf62b6642c77e14142cdb724dc99dd3f8bfd89ac.tar.gz
samba-bf62b6642c77e14142cdb724dc99dd3f8bfd89ac.tar.bz2
samba-bf62b6642c77e14142cdb724dc99dd3f8bfd89ac.zip
r22866: handle incoming chained smb2 requests in our server code to let
the windows explorer in longhorn beta3 work. metze (This used to be commit 2390c9f24daccec917608cac0870890cdc73cb1c)
-rw-r--r--source4/libcli/smb2/request.c24
-rw-r--r--source4/libcli/smb2/smb2.h2
-rw-r--r--source4/smb_server/smb2/fileio.c6
-rw-r--r--source4/smb_server/smb2/negprot.c24
-rw-r--r--source4/smb_server/smb2/receive.c117
-rw-r--r--source4/smb_server/smb2/smb2_server.h7
-rw-r--r--source4/smb_server/smb2/tcon.c11
7 files changed, 148 insertions, 43 deletions
diff --git a/source4/libcli/smb2/request.c b/source4/libcli/smb2/request.c
index 87c4dd78e1..ef024d53f8 100644
--- a/source4/libcli/smb2/request.c
+++ b/source4/libcli/smb2/request.c
@@ -80,18 +80,18 @@ struct smb2_request *smb2_request_init(struct smb2_transport *transport, uint16_
req->out.body_size = body_fixed_size;
req->out.dynamic = (body_dynamic_size ? req->out.body + body_fixed_size : NULL);
- SIVAL(req->out.hdr, 0, SMB2_MAGIC);
- SSVAL(req->out.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
- SSVAL(req->out.hdr, SMB2_HDR_PAD1, 0);
- SIVAL(req->out.hdr, SMB2_HDR_STATUS, 0);
- SSVAL(req->out.hdr, SMB2_HDR_OPCODE, opcode);
- SSVAL(req->out.hdr, SMB2_HDR_UNKNOWN1,0);
- SIVAL(req->out.hdr, SMB2_HDR_FLAGS, 0);
- SIVAL(req->out.hdr, SMB2_HDR_UNKNOWN2,0);
- SBVAL(req->out.hdr, SMB2_HDR_SEQNUM, req->seqnum);
- SIVAL(req->out.hdr, SMB2_HDR_PID, 0);
- SIVAL(req->out.hdr, SMB2_HDR_TID, 0);
- SBVAL(req->out.hdr, SMB2_HDR_UID, 0);
+ SIVAL(req->out.hdr, 0, SMB2_MAGIC);
+ SSVAL(req->out.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
+ SSVAL(req->out.hdr, SMB2_HDR_PAD1, 0);
+ SIVAL(req->out.hdr, SMB2_HDR_STATUS, 0);
+ SSVAL(req->out.hdr, SMB2_HDR_OPCODE, opcode);
+ SSVAL(req->out.hdr, SMB2_HDR_UNKNOWN1, 0);
+ SIVAL(req->out.hdr, SMB2_HDR_FLAGS, 0);
+ SIVAL(req->out.hdr, SMB2_HDR_CHAIN_OFFSET, 0);
+ SBVAL(req->out.hdr, SMB2_HDR_SEQNUM, req->seqnum);
+ SIVAL(req->out.hdr, SMB2_HDR_PID, 0);
+ SIVAL(req->out.hdr, SMB2_HDR_TID, 0);
+ SBVAL(req->out.hdr, SMB2_HDR_UID, 0);
memset(req->out.hdr+SMB2_HDR_SIG, 0, 16);
/* set the length of the fixed body part and +1 if there's a dynamic part also */
diff --git a/source4/libcli/smb2/smb2.h b/source4/libcli/smb2/smb2.h
index 586acaccf6..4db7c126d8 100644
--- a/source4/libcli/smb2/smb2.h
+++ b/source4/libcli/smb2/smb2.h
@@ -164,7 +164,7 @@ struct smb2_request {
#define SMB2_HDR_OPCODE 0x0c
#define SMB2_HDR_UNKNOWN1 0x0e
#define SMB2_HDR_FLAGS 0x10
-#define SMB2_HDR_UNKNOWN2 0x14
+#define SMB2_HDR_CHAIN_OFFSET 0x14
#define SMB2_HDR_SEQNUM 0x18
#define SMB2_HDR_PID 0x20
#define SMB2_HDR_TID 0x24
diff --git a/source4/smb_server/smb2/fileio.c b/source4/smb_server/smb2/fileio.c
index 8e420458be..e399bfb901 100644
--- a/source4/smb_server/smb2/fileio.c
+++ b/source4/smb_server/smb2/fileio.c
@@ -44,9 +44,13 @@ static void smb2srv_create_send(struct ntvfs_request *ntvfs)
SBVAL(req->out.body, 0x30, io->smb2.out.size);
SIVAL(req->out.body, 0x38, io->smb2.out.file_attr);
SIVAL(req->out.body, 0x3C, io->smb2.out._pad);
- smb2srv_push_handle(req->out.body, 0x40,io->smb2.out.file.ntvfs);
+ smb2srv_push_handle(req->out.body, 0x40, io->smb2.out.file.ntvfs);
SMB2SRV_CHECK(smb2_push_o32s32_blob(&req->out, 0x50, io->smb2.out.blob));
+ /* also setup the chained file handle */
+ req->chained_file_handle = req->_chained_file_handle;
+ smb2srv_push_handle(req->chained_file_handle, 0, io->smb2.out.file.ntvfs);
+
smb2srv_send_reply(req);
}
diff --git a/source4/smb_server/smb2/negprot.c b/source4/smb_server/smb2/negprot.c
index fe65917275..c666b3d761 100644
--- a/source4/smb_server/smb2/negprot.c
+++ b/source4/smb_server/smb2/negprot.c
@@ -204,18 +204,18 @@ void smb2srv_reply_smb_negprot(struct smbsrv_request *smb_req)
req->in.body_size = body_fixed_size;
req->in.dynamic = NULL;
- SIVAL(req->in.hdr, 0, SMB2_MAGIC);
- SSVAL(req->in.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
- SSVAL(req->in.hdr, SMB2_HDR_PAD1, 0);
- SIVAL(req->in.hdr, SMB2_HDR_STATUS, 0);
- SSVAL(req->in.hdr, SMB2_HDR_OPCODE, SMB2_OP_NEGPROT);
- SSVAL(req->in.hdr, SMB2_HDR_UNKNOWN1,0);
- SIVAL(req->in.hdr, SMB2_HDR_FLAGS, 0);
- SIVAL(req->in.hdr, SMB2_HDR_UNKNOWN2,0);
- SBVAL(req->in.hdr, SMB2_HDR_SEQNUM, 0);
- SIVAL(req->in.hdr, SMB2_HDR_PID, 0);
- SIVAL(req->in.hdr, SMB2_HDR_TID, 0);
- SBVAL(req->in.hdr, SMB2_HDR_UID, 0);
+ SIVAL(req->in.hdr, 0, SMB2_MAGIC);
+ SSVAL(req->in.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
+ SSVAL(req->in.hdr, SMB2_HDR_PAD1, 0);
+ SIVAL(req->in.hdr, SMB2_HDR_STATUS, 0);
+ SSVAL(req->in.hdr, SMB2_HDR_OPCODE, SMB2_OP_NEGPROT);
+ SSVAL(req->in.hdr, SMB2_HDR_UNKNOWN1, 0);
+ SIVAL(req->in.hdr, SMB2_HDR_FLAGS, 0);
+ SIVAL(req->in.hdr, SMB2_HDR_CHAIN_OFFSET, 0);
+ SBVAL(req->in.hdr, SMB2_HDR_SEQNUM, 0);
+ SIVAL(req->in.hdr, SMB2_HDR_PID, 0);
+ SIVAL(req->in.hdr, SMB2_HDR_TID, 0);
+ SBVAL(req->in.hdr, SMB2_HDR_UID, 0);
memset(req->in.hdr+SMB2_HDR_SIG, 0, 16);
/* this seems to be a bug, they use 0x24 but the length is 0x26 */
diff --git a/source4/smb_server/smb2/receive.c b/source4/smb_server/smb2/receive.c
index f2a34bdcbf..bae3486014 100644
--- a/source4/smb_server/smb2/receive.c
+++ b/source4/smb_server/smb2/receive.c
@@ -91,18 +91,18 @@ NTSTATUS smb2srv_setup_reply(struct smb2srv_request *req, uint16_t body_fixed_si
req->out.body_size = body_fixed_size;
req->out.dynamic = (body_dynamic_size ? req->out.body + body_fixed_size : NULL);
- SIVAL(req->out.hdr, 0, SMB2_MAGIC);
- SSVAL(req->out.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
- SSVAL(req->out.hdr, SMB2_HDR_PAD1, 0);
- SIVAL(req->out.hdr, SMB2_HDR_STATUS, NT_STATUS_V(req->status));
- SSVAL(req->out.hdr, SMB2_HDR_OPCODE, SVAL(req->in.hdr, SMB2_HDR_OPCODE));
- SSVAL(req->out.hdr, SMB2_HDR_UNKNOWN1,0x0001);
- SIVAL(req->out.hdr, SMB2_HDR_FLAGS, flags);
- SIVAL(req->out.hdr, SMB2_HDR_UNKNOWN2,0);
- SBVAL(req->out.hdr, SMB2_HDR_SEQNUM, req->seqnum);
- SIVAL(req->out.hdr, SMB2_HDR_PID, pid);
- SIVAL(req->out.hdr, SMB2_HDR_TID, tid);
- SBVAL(req->out.hdr, SMB2_HDR_UID, BVAL(req->in.hdr, SMB2_HDR_UID));
+ SIVAL(req->out.hdr, 0, SMB2_MAGIC);
+ SSVAL(req->out.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
+ SSVAL(req->out.hdr, SMB2_HDR_PAD1, 0);
+ SIVAL(req->out.hdr, SMB2_HDR_STATUS, NT_STATUS_V(req->status));
+ SSVAL(req->out.hdr, SMB2_HDR_OPCODE, SVAL(req->in.hdr, SMB2_HDR_OPCODE));
+ SSVAL(req->out.hdr, SMB2_HDR_UNKNOWN1, 0x0001);
+ SIVAL(req->out.hdr, SMB2_HDR_FLAGS, flags);
+ SIVAL(req->out.hdr, SMB2_HDR_CHAIN_OFFSET, 0);
+ SBVAL(req->out.hdr, SMB2_HDR_SEQNUM, req->seqnum);
+ SIVAL(req->out.hdr, SMB2_HDR_PID, pid);
+ SIVAL(req->out.hdr, SMB2_HDR_TID, tid);
+ SBVAL(req->out.hdr, SMB2_HDR_UID, BVAL(req->in.hdr, SMB2_HDR_UID));
memset(req->out.hdr+SMB2_HDR_SIG, 0, 16);
/* set the length of the fixed body part and +1 if there's a dynamic part also */
@@ -120,6 +120,85 @@ NTSTATUS smb2srv_setup_reply(struct smb2srv_request *req, uint16_t body_fixed_si
return NT_STATUS_OK;
}
+static NTSTATUS smb2srv_reply(struct smb2srv_request *req);
+
+static void smb2srv_chain_reply(struct smb2srv_request *p_req)
+{
+ NTSTATUS status;
+ struct smb2srv_request *req;
+ uint32_t chain_offset;
+ uint32_t protocol_version;
+ uint16_t buffer_code;
+ uint32_t dynamic_size;
+
+ chain_offset = p_req->chain_offset;
+ p_req->chain_offset = 0;
+
+ if (p_req->in.size < (NBT_HDR_SIZE + chain_offset + SMB2_MIN_SIZE)) {
+ DEBUG(2,("Invalid SMB2 chained packet at offset 0x%X\n",
+ chain_offset));
+ smbsrv_terminate_connection(p_req->smb_conn, "Invalid SMB2 chained packet");
+ return;
+ }
+
+ protocol_version = IVAL(p_req->in.buffer, NBT_HDR_SIZE + chain_offset);
+ if (protocol_version != SMB2_MAGIC) {
+ DEBUG(2,("Invalid SMB chained packet: protocol prefix: 0x%08X\n",
+ protocol_version));
+ smbsrv_terminate_connection(p_req->smb_conn, "NON-SMB2 chained packet");
+ return;
+ }
+
+ req = smb2srv_init_request(p_req->smb_conn);
+ if (!req) {
+ smbsrv_terminate_connection(p_req->smb_conn, "SMB2 chained packet - no memory");
+ return;
+ }
+
+ req->in.buffer = talloc_steal(req, p_req->in.buffer);
+ req->in.size = p_req->in.size;
+ req->request_time = p_req->request_time;
+ req->in.allocated = req->in.size;
+
+ req->in.hdr = req->in.buffer+ NBT_HDR_SIZE + chain_offset;
+ req->in.body = req->in.hdr + SMB2_HDR_BODY;
+ req->in.body_size = req->in.size - (NBT_HDR_SIZE+ chain_offset + SMB2_HDR_BODY);
+ req->in.dynamic = NULL;
+
+ buffer_code = SVAL(req->in.body, 0);
+ req->in.body_fixed = (buffer_code & ~1);
+ dynamic_size = req->in.body_size - req->in.body_fixed;
+
+ if (dynamic_size != 0 && (buffer_code & 1)) {
+ req->in.dynamic = req->in.body + req->in.body_fixed;
+ if (smb2_oob(&req->in, req->in.dynamic, dynamic_size)) {
+ DEBUG(1,("SMB2 chained request invalid dynamic size 0x%x\n",
+ dynamic_size));
+ smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+ }
+
+ if (p_req->chained_file_handle) {
+ memcpy(req->_chained_file_handle,
+ p_req->_chained_file_handle,
+ sizeof(req->_chained_file_handle));
+ req->chained_file_handle = req->_chained_file_handle;
+ }
+
+ /*
+ * TODO: - make sure the length field is 64
+ * - make sure it's a request
+ */
+
+ status = smb2srv_reply(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
+ talloc_free(req);
+ return;
+ }
+}
+
void smb2srv_send_reply(struct smb2srv_request *req)
{
DATA_BLOB blob;
@@ -140,6 +219,10 @@ void smb2srv_send_reply(struct smb2srv_request *req)
if (!NT_STATUS_IS_OK(status)) {
smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
}
+ if (req->chain_offset) {
+ smb2srv_chain_reply(req);
+ return;
+ }
talloc_free(req);
}
@@ -174,10 +257,11 @@ static NTSTATUS smb2srv_reply(struct smb2srv_request *req)
uint32_t tid;
uint64_t uid;
- opcode = SVAL(req->in.hdr, SMB2_HDR_OPCODE);
- req->seqnum = BVAL(req->in.hdr, SMB2_HDR_SEQNUM);
- tid = IVAL(req->in.hdr, SMB2_HDR_TID);
- uid = BVAL(req->in.hdr, SMB2_HDR_UID);
+ opcode = SVAL(req->in.hdr, SMB2_HDR_OPCODE);
+ req->chain_offset = IVAL(req->in.hdr, SMB2_HDR_CHAIN_OFFSET);
+ req->seqnum = BVAL(req->in.hdr, SMB2_HDR_SEQNUM);
+ tid = IVAL(req->in.hdr, SMB2_HDR_TID);
+ uid = BVAL(req->in.hdr, SMB2_HDR_UID);
req->session = smbsrv_session_find(req->smb_conn, uid, req->request_time);
req->tcon = smbsrv_smb2_tcon_find(req->session, tid, req->request_time);
@@ -311,7 +395,6 @@ NTSTATUS smbsrv_recv_smb2_request(void *private, DATA_BLOB blob)
}
protocol_version = IVAL(blob.data, NBT_HDR_SIZE);
-
if (protocol_version != SMB2_MAGIC) {
DEBUG(2,("Invalid SMB packet: protocol prefix: 0x%08X\n",
protocol_version));
diff --git a/source4/smb_server/smb2/smb2_server.h b/source4/smb_server/smb2/smb2_server.h
index 353300681f..909a4228df 100644
--- a/source4/smb_server/smb2/smb2_server.h
+++ b/source4/smb_server/smb2/smb2_server.h
@@ -56,6 +56,13 @@ struct smb2srv_request {
/* the id that can be used to cancel the request */
uint32_t pending_id;
+ /* the offset to the next SMB2 Header for chained requests */
+ uint32_t chain_offset;
+
+ /* chained file handle */
+ uint8_t _chained_file_handle[16];
+ uint8_t *chained_file_handle;
+
struct smb2_request_buffer in;
struct smb2_request_buffer out;
};
diff --git a/source4/smb_server/smb2/tcon.c b/source4/smb_server/smb2/tcon.c
index a98110ab85..023ca9b0a4 100644
--- a/source4/smb_server/smb2/tcon.c
+++ b/source4/smb_server/smb2/tcon.c
@@ -45,6 +45,17 @@ struct ntvfs_handle *smb2srv_pull_handle(struct smb2srv_request *req, const uint
uint32_t tid;
uint32_t pad;
+ /*
+ * if there're chained requests used the cached handle
+ *
+ * TODO: check if this also correct when the given handle
+ * isn't all 0xFF.
+ */
+ if (req->chained_file_handle) {
+ base = req->chained_file_handle;
+ offset = 0;
+ }
+
hid = BVAL(base, offset);
tid = IVAL(base, offset + 8);
pad = IVAL(base, offset + 12);