summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2010-06-08 17:44:05 -0700
committerJeremy Allison <jra@samba.org>2010-06-08 17:44:05 -0700
commit0c5d0e1c37daf5b802e990bde8469934ae33f6cc (patch)
treecdddb5290bb8cded19424fbf677f506a1af3a898
parentfd9e02d5f3a2d98fe14b10b52c4ca3e654a6bd3e (diff)
downloadsamba-0c5d0e1c37daf5b802e990bde8469934ae33f6cc.tar.gz
samba-0c5d0e1c37daf5b802e990bde8469934ae33f6cc.tar.bz2
samba-0c5d0e1c37daf5b802e990bde8469934ae33f6cc.zip
Second part of fix for 7501 - SMB2: CREATE request replies getting mangled.
Based on code from Ira Cooper <samba@ira.wakeful.net>, and also advice on refactoring the patch into a function call. outbuf vectors can be reallocated by smb2 processing code, so when returning interim responses we must not make assumptions about vector size. Jeremy
-rw-r--r--source3/smbd/smb2_server.c134
1 files changed, 67 insertions, 67 deletions
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index 009cc77e9f..d7be0deb09 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -476,23 +476,71 @@ void smbd_server_connection_terminate_ex(struct smbd_server_connection *sconn,
exit_server_cleanly(reason);
}
-static bool dup_smb2_vec(struct iovec *dstvec,
- const struct iovec *srcvec,
- int offset)
+static bool dup_smb2_vec3(TALLOC_CTX *ctx,
+ struct iovec *outvec,
+ const struct iovec *srcvec)
{
+ /* vec[0] is always boilerplate and must
+ * be allocated with size OUTVEC_ALLOC_SIZE. */
- if (srcvec[offset].iov_len &&
- srcvec[offset].iov_base) {
- dstvec[offset].iov_base = talloc_memdup(dstvec,
- srcvec[offset].iov_base,
- srcvec[offset].iov_len);
- if (!dstvec[offset].iov_base) {
+ outvec[0].iov_base = talloc_memdup(ctx,
+ srcvec[0].iov_base,
+ OUTVEC_ALLOC_SIZE);
+ if (!outvec[0].iov_base) {
+ return false;
+ }
+ outvec[0].iov_len = SMB2_HDR_BODY;
+
+ /*
+ * If this is a "standard" vec[1] of length 8,
+ * pointing to srcvec[0].iov_base + SMB2_HDR_BODY,
+ * then duplicate this. Else use talloc_memdup().
+ */
+
+ if (srcvec[1].iov_len == 8 &&
+ srcvec[1].iov_base ==
+ ((uint8_t *)srcvec[0].iov_base) +
+ SMB2_HDR_BODY) {
+ outvec[1].iov_base = ((uint8_t *)outvec[1].iov_base) +
+ SMB2_HDR_BODY;
+ outvec[1].iov_len = 8;
+ } else {
+ outvec[1].iov_base = talloc_memdup(ctx,
+ srcvec[1].iov_base,
+ srcvec[1].iov_len);
+ if (!outvec[1].iov_base) {
return false;
}
- dstvec[offset].iov_len = srcvec[offset].iov_len;
+ outvec[1].iov_len = srcvec[1].iov_len;
+ }
+
+ /*
+ * If this is a "standard" vec[2] of length 1,
+ * pointing to srcvec[0].iov_base + (OUTVEC_ALLOC_SIZE - 1)
+ * then duplicate this. Else use talloc_memdup().
+ */
+
+ if (srcvec[2].iov_base &&
+ srcvec[2].iov_len) {
+ if (srcvec[2].iov_base ==
+ ((uint8_t *)srcvec[0].iov_base) +
+ (OUTVEC_ALLOC_SIZE - 1) &&
+ srcvec[2].iov_len == 1) {
+ /* Common SMB2 error packet case. */
+ outvec[2].iov_base = ((uint8_t *)outvec[0].iov_base) +
+ (OUTVEC_ALLOC_SIZE - 1);
+ } else {
+ outvec[2].iov_base = talloc_memdup(ctx,
+ srcvec[2].iov_base,
+ srcvec[2].iov_len);
+ if (!outvec[2].iov_base) {
+ return false;
+ }
+ }
+ outvec[2].iov_len = srcvec[2].iov_len;
} else {
- dstvec[offset].iov_base = NULL;
- dstvec[offset].iov_len = 0;
+ outvec[2].iov_base = NULL;
+ outvec[2].iov_len = 0;
}
return true;
}
@@ -528,30 +576,9 @@ static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *re
outvec[0].iov_len = 4;
memcpy(newreq->out.nbt_hdr, req->out.nbt_hdr, 4);
+ /* Setup the vectors identically to the ones in req. */
for (i = 1; i < count; i += 3) {
- /* i + 0 and i + 1 are always
- * boilerplate. */
- outvec[i].iov_base = talloc_memdup(outvec,
- req->out.vector[i].iov_base,
- OUTVEC_ALLOC_SIZE);
- if (!outvec[i].iov_base) {
- break;
- }
- outvec[i].iov_len = SMB2_HDR_BODY;
-
- outvec[i+1].iov_base = ((uint8_t *)outvec[i].iov_base) +
- SMB2_HDR_BODY;
- outvec[i+1].iov_len = 8;
-
- if (req->out.vector[i+2].iov_base ==
- ((uint8_t *)req->out.vector[i].iov_base) +
- (OUTVEC_ALLOC_SIZE - 1) &&
- req->out.vector[i+2].iov_len == 1) {
- /* Common SMB2 error packet case. */
- outvec[i+2].iov_base = ((uint8_t *)outvec[i].iov_base) +
- (OUTVEC_ALLOC_SIZE - 1);
- outvec[i+2].iov_len = 1;
- } else if (!dup_smb2_vec(outvec, req->out.vector, i+2)) {
+ if (!dup_smb2_vec3(outvec, &outvec[i], &req->out.vector[i])) {
break;
}
}
@@ -821,44 +848,17 @@ NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
if (!outvec) {
return NT_STATUS_NO_MEMORY;
}
+
+ /* 0 is always boilerplate and must
+ * be of size 4 for the length field. */
+
outvec[0].iov_base = req->out.nbt_hdr;
outvec[0].iov_len = 4;
SIVAL(req->out.nbt_hdr, 0, 0);
- outvec[1].iov_base = talloc_memdup(outvec,
- req->out.vector[i].iov_base,
- OUTVEC_ALLOC_SIZE);
- if (!outvec[1].iov_base) {
+ if (!dup_smb2_vec3(outvec, &outvec[1], &req->out.vector[i])) {
return NT_STATUS_NO_MEMORY;
}
- outvec[1].iov_len = SMB2_HDR_BODY;
-
- outvec[2].iov_base = ((uint8_t *)outvec[1].iov_base) +
- SMB2_HDR_BODY;
- outvec[2].iov_len = 8;
-
- if (req->out.vector[i+2].iov_base &&
- req->out.vector[i+2].iov_len) {
- if (req->out.vector[i+2].iov_base ==
- ((uint8_t *)req->out.vector[i].iov_base) +
- (OUTVEC_ALLOC_SIZE - 1) &&
- req->out.vector[i].iov_len == 1) {
- /* Common SMB2 error packet case. */
- outvec[3].iov_base = ((uint8_t *)outvec[1].iov_base) +
- (OUTVEC_ALLOC_SIZE - 1);
- } else {
- outvec[3].iov_base = talloc_memdup(outvec,
- req->out.vector[i+2].iov_base,
- req->out.vector[i+2].iov_len);
- if (!outvec[3].iov_base) {
- return NT_STATUS_NO_MEMORY;
- }
- }
- outvec[3].iov_len = req->out.vector[i+2].iov_len;
- } else {
- outvec[3].iov_base = NULL;
- outvec[3].iov_len = 0;
- }
TALLOC_FREE(req->out.vector);