diff options
Diffstat (limited to 'source4')
-rw-r--r-- | source4/smb_server/smb_server.c | 125 | ||||
-rw-r--r-- | source4/smb_server/smb_server.h | 3 |
2 files changed, 81 insertions, 47 deletions
diff --git a/source4/smb_server/smb_server.c b/source4/smb_server/smb_server.c index d6022ef63e..91de20bb31 100644 --- a/source4/smb_server/smb_server.c +++ b/source4/smb_server/smb_server.c @@ -55,54 +55,87 @@ BOOL req_send_oplock_break(struct smbsrv_tcon *tcon, uint16_t fnum, uint8_t leve return True; } + +static void construct_reply(struct smbsrv_request *req); + /**************************************************************************** -receive a SMB request from the wire, forming a request_context from the result +receive a SMB request header from the wire, forming a request_context +from the result ****************************************************************************/ -static struct smbsrv_request *receive_smb_request(struct smbsrv_connection *smb_conn) +static NTSTATUS receive_smb_request(struct smbsrv_connection *smb_conn) { NTSTATUS status; - ssize_t len, len2; - DATA_BLOB tmp_blob; + ssize_t len; struct smbsrv_request *req; - char hdr[4]; size_t nread; - status = socket_recv(smb_conn->connection->socket, hdr, - 4, &nread, SOCKET_FLAG_BLOCK|SOCKET_FLAG_PEEK); - if (!NT_STATUS_IS_OK(status)) { - return NULL; - } - if (nread != 4) { - return NULL; - } - - len = smb_len(hdr); - - req = init_smb_request(smb_conn); + /* allocate the request if needed */ + if (smb_conn->partial_req == NULL) { + req = init_smb_request(smb_conn); + if (req == NULL) { + return NT_STATUS_NO_MEMORY; + } - GetTimeOfDay(&req->request_time); - req->chained_fnum = -1; + req->in.buffer = talloc_array_p(req, char, NBT_HDR_SIZE); + if (req->in.buffer == NULL) { + talloc_free(req); + return NT_STATUS_NO_MEMORY; + } + req->in.size = 0; + smb_conn->partial_req = req; + } - len2 = len + NBT_HDR_SIZE; + req = smb_conn->partial_req; - tmp_blob = data_blob_talloc(req, NULL, len2); - if (tmp_blob.data == NULL) { - return NULL; + /* read in the header */ + if (req->in.size < NBT_HDR_SIZE) { + status = socket_recv(smb_conn->connection->socket, + req->in.buffer + req->in.size, + NBT_HDR_SIZE - req->in.size, + &nread, 0); + if (NT_STATUS_IS_ERR(status)) { + return status; + } + if (nread == 0) { + return NT_STATUS_OK; + } + req->in.size += nread; + + /* when we have a full NBT header, then allocate the packet */ + if (req->in.size == NBT_HDR_SIZE) { + len = smb_len(req->in.buffer) + NBT_HDR_SIZE; + req->in.buffer = talloc_realloc(req, req->in.buffer, len); + if (req->in.buffer == NULL) { + return NT_STATUS_NO_MEMORY; + } + } else { + return NT_STATUS_OK; + } } + /* read in the main packet */ + len = smb_len(req->in.buffer) + NBT_HDR_SIZE; + status = socket_recv(smb_conn->connection->socket, - tmp_blob.data, len2, - &nread, SOCKET_FLAG_BLOCK); - if (!NT_STATUS_IS_OK(status)) { - return NULL; + req->in.buffer + req->in.size, + len - req->in.size, + &nread, 0); + if (NT_STATUS_IS_ERR(status)) { + return status; } - if (nread != len2) { - return NULL; + if (nread == 0) { + return NT_STATUS_OK; } - /* fill in the rest of the req->in structure */ - req->in.buffer = tmp_blob.data; - req->in.size = len2; + req->in.size += nread; + + if (req->in.size != len) { + return NT_STATUS_OK; + } + + /* we have a full packet */ + GetTimeOfDay(&req->request_time); + req->chained_fnum = -1; req->in.allocated = req->in.size; req->in.hdr = req->in.buffer + NBT_HDR_SIZE; req->in.vwv = req->in.hdr + HDR_VWV; @@ -125,7 +158,11 @@ static struct smbsrv_request *receive_smb_request(struct smbsrv_connection *smb_ } } - return req; + smb_conn->partial_req = NULL; + + construct_reply(req); + + return NT_STATUS_OK; } /* @@ -746,23 +783,20 @@ static void smbsrv_init(struct server_service *service, const struct model_ops * */ static void smbsrv_recv(struct server_connection *conn, time_t t, uint16_t flags) { - struct smbsrv_request *req; struct smbsrv_connection *smb_conn = conn->private_data; + NTSTATUS status; DEBUG(10,("smbsrv_recv\n")); - req = receive_smb_request(smb_conn); - if (!req) { + status = receive_smb_request(smb_conn); + if (NT_STATUS_IS_ERR(status)) { conn->event.fde->flags = 0; - smbsrv_terminate_connection(smb_conn, "receive error"); + smbsrv_terminate_connection(smb_conn, nt_errstr(status)); return; } - construct_reply(req); - /* free up temporary memory */ lp_talloc_free(); - return; } /* @@ -806,15 +840,12 @@ static void smbsrv_close(struct server_connection *conn, const char *reason) */ void smbd_process_async(struct smbsrv_connection *smb_conn) { - struct smbsrv_request *req; + NTSTATUS status; - req = receive_smb_request(smb_conn); - if (!req) { - smbsrv_terminate_connection(smb_conn, "receive error"); - return; + status = receive_smb_request(smb_conn); + if (NT_STATUS_IS_ERR(status)) { + smbsrv_terminate_connection(smb_conn, nt_errstr(status)); } - - construct_reply(req); } diff --git a/source4/smb_server/smb_server.h b/source4/smb_server/smb_server.h index 29dc93acd2..4fdbdfe671 100644 --- a/source4/smb_server/smb_server.h +++ b/source4/smb_server/smb_server.h @@ -286,4 +286,7 @@ struct smbsrv_connection { pid_t pid; struct server_connection *connection; + + /* this holds a partially received request */ + struct smbsrv_request *partial_req; }; |