diff options
author | Jeremy Allison <jra@samba.org> | 2010-06-08 17:44:05 -0700 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2010-06-08 17:44:05 -0700 |
commit | 0c5d0e1c37daf5b802e990bde8469934ae33f6cc (patch) | |
tree | cdddb5290bb8cded19424fbf677f506a1af3a898 /source3/smbd | |
parent | fd9e02d5f3a2d98fe14b10b52c4ca3e654a6bd3e (diff) | |
download | samba-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
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/smb2_server.c | 134 |
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); |