The branch, master has been updated via e49bae7 s3:smb2_server: remove unused get_min_receive_file_size() wrapper function via 535103e s3:smb2_server: only allocate the required buffer in the smb2 recvfile() code path via 80de72b s3:smb2_server: prepare smbd_smb2_request_verify_sizes() for the optimized recvfile() case via 1f767b2 s3:smb2_write: allow SMBD_SMB2_IN_DYN_LEN() to be 0 for the recvfile case. via 95df39b s3:smb2_server: make sure we don't try recvfile for special NBT messages via 7968749 s3:smb2_server: use the same logic to avoid recvfile() for IPC/PRINT shares via 77b6860 s3:smbd: use smb1srv_open_lookup() in is_valid_writeX_buffer() via 8d45b75 s3:smbXsrv_open: allow now==0 to skip the idle_time update. via f717802 s3:lib: use stack buffers in drain_socket() and default_sys_recvfile() from 4daf7d4 libs: s3 and s4: make our dns lookup code signal-safe.
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit e49bae7ac9fb0be4cbb4530d75a4431cbbb495c8 Author: Stefan Metzmacher <me...@samba.org> Date: Fri Apr 11 01:37:42 2014 +0200 s3:smb2_server: remove unused get_min_receive_file_size() wrapper function smb2req always comes from talloc_zero(). Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> Autobuild-User(master): Jeremy Allison <j...@samba.org> Autobuild-Date(master): Fri Apr 11 23:55:17 CEST 2014 on sn-devel-104 commit 535103e7a38e175fec082a658c2b70dbdd9af33e Author: Stefan Metzmacher <me...@samba.org> Date: Fri Nov 15 09:12:40 2013 +0100 s3:smb2_server: only allocate the required buffer in the smb2 recvfile() code path This way the buffer will likely be allocated within the existing talloc_pool, which avoids one malloc() per request. Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 80de72bb57520a1a14c3d3db3f31dc588d0afd64 Author: Stefan Metzmacher <me...@samba.org> Date: Mon Nov 18 13:46:10 2013 +0100 s3:smb2_server: prepare smbd_smb2_request_verify_sizes() for the optimized recvfile() case For recvfile we haven't read and may not allocated the dyn buffer. Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 1f767b29a89e15c4d7187cd0bc9b0c2e3152edd7 Author: Stefan Metzmacher <me...@samba.org> Date: Mon Nov 18 13:45:37 2013 +0100 s3:smb2_write: allow SMBD_SMB2_IN_DYN_LEN() to be 0 for the recvfile case. For recvfile we haven't read and may not allocated the dyn buffer. Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 95df39b99f17810cb230c4a6a0d0952919cd0b81 Author: Stefan Metzmacher <me...@samba.org> Date: Fri Apr 11 01:05:21 2014 +0200 s3:smb2_server: make sure we don't try recvfile for special NBT messages Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 796874912d9935e202b8c767ca33d557dce9c43e Author: Stefan Metzmacher <me...@samba.org> Date: Fri Apr 11 00:43:46 2014 +0200 s3:smb2_server: use the same logic to avoid recvfile() for IPC/PRINT shares Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 77b6860668437bbb3bb66f57f75ea4fc378de49b Author: Stefan Metzmacher <me...@samba.org> Date: Fri Apr 11 00:51:32 2014 +0200 s3:smbd: use smb1srv_open_lookup() in is_valid_writeX_buffer() It's more logical to check the fnum instead of tid here. This will make it easier to reuse the logic for SMB2 and allows per fsp recvfile detection. Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 8d45b75df31d5c382345186791a375e2b800066e Author: Stefan Metzmacher <me...@samba.org> Date: Fri Apr 11 00:29:48 2014 +0200 s3:smbXsrv_open: allow now==0 to skip the idle_time update. Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit f71780202a3e736432020cf894b138a06e4bb869 Author: Stefan Metzmacher <me...@samba.org> Date: Thu Dec 5 11:20:49 2013 +0100 s3:lib: use stack buffers in drain_socket() and default_sys_recvfile() Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> ----------------------------------------------------------------------- Summary of changes: source3/lib/recvfile.c | 18 +------ source3/smbd/globals.h | 1 + source3/smbd/reply.c | 29 +++++++--- source3/smbd/smb2_server.c | 116 +++++++++++++++++++++++++++++++------------ source3/smbd/smb2_write.c | 20 +++++++- source3/smbd/smbXsrv_open.c | 4 +- 6 files changed, 128 insertions(+), 60 deletions(-) Changeset truncated at 500 lines: diff --git a/source3/lib/recvfile.c b/source3/lib/recvfile.c index 72f4257..500a7e4 100644 --- a/source3/lib/recvfile.c +++ b/source3/lib/recvfile.c @@ -51,7 +51,7 @@ static ssize_t default_sys_recvfile(int fromfd, size_t total = 0; size_t bufsize = MIN(TRANSFER_BUF_SIZE,count); size_t total_written = 0; - char *buffer = NULL; + char buffer[bufsize]; DEBUG(10,("default_sys_recvfile: from = %d, to = %d, " "offset=%.0f, count = %lu\n", @@ -70,11 +70,6 @@ static ssize_t default_sys_recvfile(int fromfd, } } - buffer = SMB_MALLOC_ARRAY(char, bufsize); - if (buffer == NULL) { - return -1; - } - while (total < count) { size_t num_written = 0; ssize_t read_ret; @@ -84,7 +79,6 @@ static ssize_t default_sys_recvfile(int fromfd, read_ret = sys_read(fromfd, buffer, toread); if (read_ret <= 0) { /* EOF or socket error. */ - free(buffer); return -1; } @@ -119,7 +113,6 @@ static ssize_t default_sys_recvfile(int fromfd, total += read_ret; } - free(buffer); if (saved_errno) { /* Return the correct write error. */ errno = saved_errno; @@ -247,21 +240,15 @@ ssize_t drain_socket(int sockfd, size_t count) { size_t total = 0; size_t bufsize = MIN(TRANSFER_BUF_SIZE,count); - char *buffer = NULL; + char buffer[bufsize]; int old_flags = 0; if (count == 0) { return 0; } - buffer = SMB_MALLOC_ARRAY(char, bufsize); - if (buffer == NULL) { - return -1; - } - old_flags = fcntl(sockfd, F_GETFL, 0); if (set_blocking(sockfd, true) == -1) { - free(buffer); return -1; } @@ -281,7 +268,6 @@ ssize_t drain_socket(int sockfd, size_t count) out: - free(buffer); if (fcntl(sockfd, F_SETFL, old_flags) == -1) { return -1; } diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index 3baa048..cd99fe7 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -768,6 +768,7 @@ struct smbd_server_connection { struct iovec vector; bool doing_receivefile; size_t min_recv_size; + size_t pktfull; size_t pktlen; uint8_t *pktbuf; } request_read_state; diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index e58735e..da59ca7 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -4598,12 +4598,12 @@ bool is_valid_writeX_buffer(struct smbd_server_connection *sconn, const uint8_t *inbuf) { size_t numtowrite; - connection_struct *conn = NULL; unsigned int doff = 0; size_t len = smb_len_large(inbuf); - struct smbXsrv_tcon *tcon; + uint16_t fnum; + struct smbXsrv_open *op = NULL; + struct files_struct *fsp = NULL; NTSTATUS status; - NTTIME now = 0; if (is_encrypted_packet(sconn, inbuf)) { /* Can't do this on encrypted @@ -4622,19 +4622,30 @@ bool is_valid_writeX_buffer(struct smbd_server_connection *sconn, return false; } - status = smb1srv_tcon_lookup(sconn->conn, SVAL(inbuf, smb_tid), - now, &tcon); + fnum = SVAL(inbuf, smb_vwv2); + status = smb1srv_open_lookup(sconn->conn, + fnum, + 0, /* now */ + &op); if (!NT_STATUS_IS_OK(status)) { - DEBUG(10,("is_valid_writeX_buffer: bad tid\n")); + DEBUG(10,("is_valid_writeX_buffer: bad fnum\n")); + return false; + } + fsp = op->compat; + if (fsp == NULL) { + DEBUG(10,("is_valid_writeX_buffer: bad fsp\n")); + return false; + } + if (fsp->conn == NULL) { + DEBUG(10,("is_valid_writeX_buffer: bad fsp->conn\n")); return false; } - conn = tcon->compat; - if (IS_IPC(conn)) { + if (IS_IPC(fsp->conn)) { DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n")); return false; } - if (IS_PRINT(conn)) { + if (IS_PRINT(fsp->conn)) { DEBUG(10,("is_valid_writeX_buffer: printing tid\n")); return false; } diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c index 3c46efd..4a7abcb 100644 --- a/source3/smbd/smb2_server.c +++ b/source3/smbd/smb2_server.c @@ -1870,6 +1870,15 @@ NTSTATUS smbd_smb2_request_verify_sizes(struct smbd_smb2_request *req, case SMB2_OP_GETINFO: min_dyn_size = 0; break; + case SMB2_OP_WRITE: + if (req->smb1req != NULL && req->smb1req->unread_bytes > 0) { + if (req->smb1req->unread_bytes < min_dyn_size) { + return NT_STATUS_INVALID_PARAMETER; + } + + min_dyn_size = 0; + } + break; } /* @@ -2828,20 +2837,21 @@ NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn, return NT_STATUS_OK; } -static size_t get_min_receive_file_size(struct smbd_smb2_request *smb2_req) -{ - if (smb2_req->do_signing) { - return 0; - } - if (smb2_req->do_encryption) { - return 0; - } - return (size_t)lp_min_receive_file_size(); -} - static bool is_smb2_recvfile_write(struct smbd_smb2_request_read_state *state) { + NTSTATUS status; uint32_t flags; + uint64_t file_id_persistent; + uint64_t file_id_volatile; + struct smbXsrv_open *op = NULL; + struct files_struct *fsp = NULL; + const uint8_t *body = NULL; + + /* + * This is only called with a pktbuf + * of at least SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN + * bytes + */ if (IVAL(state->pktbuf, 0) == SMB2_TF_MAGIC) { /* Transform header. Cannot recvfile. */ @@ -2873,9 +2883,37 @@ static bool is_smb2_recvfile_write(struct smbd_smb2_request_read_state *state) return false; } + body = &state->pktbuf[SMB2_HDR_BODY]; + + file_id_persistent = BVAL(body, 0x10); + file_id_volatile = BVAL(body, 0x18); + + status = smb2srv_open_lookup(state->req->sconn->conn, + file_id_persistent, + file_id_volatile, + 0, /* now */ + &op); + if (!NT_STATUS_IS_OK(status)) { + return false; + } + + fsp = op->compat; + if (fsp == NULL) { + return false; + } + if (fsp->conn == NULL) { + return false; + } + + if (IS_IPC(fsp->conn)) { + return false; + } + if (IS_PRINT(fsp->conn)) { + return false; + } + DEBUG(10,("Doing recvfile write len = %u\n", - (unsigned int)(state->pktlen - - SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN))); + (unsigned int)(state->pktfull - state->pktlen))); return true; } @@ -2920,7 +2958,7 @@ static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *s return NT_STATUS_NO_MEMORY; } state->req->sconn = sconn; - state->min_recv_size = get_min_receive_file_size(state->req); + state->min_recv_size = lp_min_receive_file_size(); TEVENT_FD_READABLE(sconn->smb2.fde); @@ -3213,10 +3251,21 @@ again: * Read the rest of the data. */ state->doing_receivefile = false; + + state->pktbuf = talloc_realloc(state->req, + state->pktbuf, + uint8_t, + state->pktfull); + if (state->pktbuf == NULL) { + return NT_STATUS_NO_MEMORY; + } + state->vector.iov_base = (void *)(state->pktbuf + - SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN); - state->vector.iov_len = (state->pktlen - - SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN); + state->pktlen); + state->vector.iov_len = (state->pktfull - + state->pktlen); + + state->pktlen = state->pktfull; goto again; } @@ -3230,24 +3279,20 @@ again: /* * Now we analyze the NBT header */ - state->pktlen = smb2_len(state->hdr.nbt); - if (state->pktlen == 0) { - goto got_full; + if (state->hdr.nbt[0] != 0x00) { + state->min_recv_size = 0; } - - state->pktbuf = talloc_array(state->req, uint8_t, state->pktlen); - if (state->pktbuf == NULL) { - return NT_STATUS_NO_MEMORY; + state->pktfull = smb2_len(state->hdr.nbt); + if (state->pktfull == 0) { + goto got_full; } - state->vector.iov_base = (void *)state->pktbuf; - 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) { + if (state->pktfull > min_recvfile_size) { /* * Might be a receivefile write. Read the SMB2 HEADER + * SMB2_WRITE header first. Set 'doing_receivefile' @@ -3256,12 +3301,20 @@ again: * not suitable then we'll just read the rest of the data * the next time this function is called. */ - state->vector.iov_len = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN; + state->pktlen = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN; state->doing_receivefile = true; } else { - state->vector.iov_len = state->pktlen; + state->pktlen = state->pktfull; } + state->pktbuf = talloc_array(state->req, uint8_t, state->pktlen); + if (state->pktbuf == NULL) { + return NT_STATUS_NO_MEMORY; + } + + state->vector.iov_base = (void *)state->pktbuf; + state->vector.iov_len = state->pktlen; + goto again; got_full: @@ -3273,7 +3326,7 @@ got_full: req = state->req; ZERO_STRUCTP(state); state->req = req; - state->min_recv_size = get_min_receive_file_size(state->req); + state->min_recv_size = lp_min_receive_file_size(); req = NULL; goto again; } @@ -3300,8 +3353,7 @@ got_full: if (req->smb1req == NULL) { return NT_STATUS_NO_MEMORY; } - req->smb1req->unread_bytes = - state->pktlen - SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN; + req->smb1req->unread_bytes = state->pktfull - state->pktlen; } ZERO_STRUCTP(state); diff --git a/source3/smbd/smb2_write.c b/source3/smbd/smb2_write.c index 4e138fe..c61254f 100644 --- a/source3/smbd/smb2_write.c +++ b/source3/smbd/smb2_write.c @@ -48,6 +48,8 @@ NTSTATUS smbd_smb2_request_process_write(struct smbd_smb2_request *req) uint64_t in_file_id_volatile; struct files_struct *in_fsp; uint32_t in_flags; + size_t in_dyn_len = 0; + uint8_t *in_dyn_ptr = NULL; struct tevent_req *subreq; status = smbd_smb2_request_verify_sizes(req, 0x31); @@ -67,7 +69,15 @@ NTSTATUS smbd_smb2_request_process_write(struct smbd_smb2_request *req) return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } - if (in_data_length > SMBD_SMB2_IN_DYN_LEN(req)) { + if (req->smb1req != NULL && req->smb1req->unread_bytes > 0) { + in_dyn_ptr = NULL; + in_dyn_len = req->smb1req->unread_bytes; + } else { + in_dyn_ptr = SMBD_SMB2_IN_DYN_PTR(req); + in_dyn_len = SMBD_SMB2_IN_DYN_LEN(req); + } + + if (in_data_length > in_dyn_len) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } @@ -79,7 +89,10 @@ NTSTATUS smbd_smb2_request_process_write(struct smbd_smb2_request *req) return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } - in_data_buffer.data = SMBD_SMB2_IN_DYN_PTR(req); + /* + * Note: that in_dyn_ptr is NULL for the recvfile case. + */ + in_data_buffer.data = in_dyn_ptr; in_data_buffer.length = in_data_length; status = smbd_smb2_request_verify_creditcharge(req, in_data_length); @@ -340,6 +353,9 @@ static struct tevent_req *smbd_smb2_write_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } + /* + * Note: in_data.data is NULL for the recvfile case. + */ nwritten = write_file(smbreq, fsp, (const char *)in_data.data, in_offset, diff --git a/source3/smbd/smbXsrv_open.c b/source3/smbd/smbXsrv_open.c index b15be28..c3ff3bb 100644 --- a/source3/smbd/smbXsrv_open.c +++ b/source3/smbd/smbXsrv_open.c @@ -444,7 +444,9 @@ static NTSTATUS smbXsrv_open_local_lookup(struct smbXsrv_open_table *table, return NT_STATUS_FILE_CLOSED; } - state.op->idle_time = now; + if (now != 0) { + state.op->idle_time = now; + } *_open = state.op; return state.op->status; -- Samba Shared Repository