From 53b87f2fbabe3a2dcb5df6f6c494ef332bea81e7 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 1 Apr 2013 13:24:07 -0700 Subject: [PATCH] The guts of the receivefile code changes. If an incoming PDU might qualify, only read SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN = (SMB2_HEADER + SMB2_WRITE_BODY_LEN) bytes rather than the whole PDU. Next time we're called, use is_smb2_recvfile_write() to decide if this is an SMB2_WRITE that fit the receivefile criteria, otherwise just read the rest of the PDU. If we did do a short receivefile read, set up the smb2_req->smb1req->unread_bytes value to show what bytes remain in the TCP buffers. Signed-off-by: Jeremy Allison Reviewed-by: Stefan (metze) Metzmacher --- source3/smbd/smb2_server.c | 65 +++++++++++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 5 deletions(-) diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c index a983dcdfa532..226db15d732e 100644 --- a/source3/smbd/smb2_server.c +++ b/source3/smbd/smb2_server.c @@ -2906,12 +2906,38 @@ static int smbd_smb2_request_next_vector(struct tstream_context *stream, struct smbd_smb2_request_read_state *state = talloc_get_type_abort(private_data, struct smbd_smb2_request_read_state); - struct iovec *vector; + struct iovec *vector = NULL; + size_t min_recvfile_size = UINT32_MAX; if (state->pktlen > 0) { - /* if there're no remaining bytes, we're done */ - *_vector = NULL; - *_count = 0; + if (state->doing_receivefile && !is_smb2_recvfile_write(state)) { + /* + * Not a possible receivefile write. + * Read the rest of the data. + */ + state->doing_receivefile = false; + vector = talloc_array(mem_ctx, struct iovec, 1); + if (vector == NULL) { + return -1; + } + vector[0].iov_base = (void *)(state->pktbuf + + SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN); + vector[0].iov_len = (state->pktlen - + SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN); + *_vector = vector; + *_count = 1; + } else { + /* + * Either this is a receivefile write so we've + * done a short read, or if not we have all the data. + * Either way, we're done and + * smbd_smb2_request_read_done() will handle + * and short read case by looking at the + * state->doing_receivefile value. + */ + *_vector = NULL; + *_count = 0; + } return 0; } @@ -2957,7 +2983,26 @@ static int smbd_smb2_request_next_vector(struct tstream_context *stream, } vector[0].iov_base = (void *)state->pktbuf; - vector[0].iov_len = state->pktlen; + + if (state->min_recv_size != 0) { + min_recvfile_size = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN; + min_recvfile_size += state->min_recv_size; + } + + if (state->pktlen > min_recvfile_size) { + /* + * Might be a receivefile write. Read the SMB2 HEADER + + * SMB2_WRITE header first. Set 'doing_receivefile' + * as we're *attempting* receivefile write. If this + * turns out not to be a SMB2_WRITE request or otherwise + * not suitable then we'll just read the rest of the data + * the next time this function is called. + */ + vector[0].iov_len = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN; + state->doing_receivefile = true; + } else { + vector[0].iov_len = state->pktlen; + } *_vector = vector; *_count = 1; @@ -3020,6 +3065,16 @@ static void smbd_smb2_request_read_done(struct tevent_req *subreq) return; } + if (state->doing_receivefile) { + state->smb2_req->smb1req = talloc_zero(state->smb2_req, + struct smb_request); + if (tevent_req_nomem(state->smb2_req->smb1req, req)) { + return; + } + state->smb2_req->smb1req->unread_bytes = + state->pktlen - SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN; + } + state->smb2_req->current_idx = 1; tevent_req_done(req); -- 2.34.1