diff options
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/smb2_flush.c | 122 |
1 files changed, 97 insertions, 25 deletions
diff --git a/source3/smbd/smb2_flush.c b/source3/smbd/smb2_flush.c index 5164d1b4a4..37a8309b33 100644 --- a/source3/smbd/smb2_flush.c +++ b/source3/smbd/smb2_flush.c @@ -22,20 +22,23 @@ #include "smbd/globals.h" #include "../source4/libcli/smb2/smb2_constants.h" -static NTSTATUS smbd_smb2_flush(struct smbd_smb2_request *req, - uint64_t in_file_id_volatile); +static struct tevent_req *smbd_smb2_flush_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct smbd_smb2_request *smb2req, + uint64_t in_file_id_volatile); +static NTSTATUS smbd_smb2_flush_recv(struct tevent_req *req); +static void smbd_smb2_request_flush_done(struct tevent_req *subreq); NTSTATUS smbd_smb2_request_process_flush(struct smbd_smb2_request *req) { const uint8_t *inhdr; const uint8_t *inbody; int i = req->current_idx; - DATA_BLOB outbody; size_t expected_body_size = 0x18; size_t body_size; uint64_t in_file_id_persistent; uint64_t in_file_id_volatile; - NTSTATUS status; + struct tevent_req *subreq; inhdr = (const uint8_t *)req->in.vector[i+0].iov_base; if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { @@ -56,65 +59,134 @@ NTSTATUS smbd_smb2_request_process_flush(struct smbd_smb2_request *req) return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED); } - status = smbd_smb2_flush(req, - in_file_id_volatile); + subreq = smbd_smb2_flush_send(req, + req->conn->smb2.event_ctx, + req, + in_file_id_volatile); + if (subreq == NULL) { + return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); + } + tevent_req_set_callback(subreq, smbd_smb2_request_flush_done, req); + return NT_STATUS_OK; +} + +static void smbd_smb2_request_flush_done(struct tevent_req *subreq) +{ + struct smbd_smb2_request *req = tevent_req_callback_data(subreq, + struct smbd_smb2_request); + DATA_BLOB outbody; + NTSTATUS status; + NTSTATUS error; /* transport error */ + + status = smbd_smb2_flush_recv(subreq); + TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { - return smbd_smb2_request_error(req, status); + error = smbd_smb2_request_error(req, status); + if (!NT_STATUS_IS_OK(error)) { + smbd_server_connection_terminate(req->conn, + nt_errstr(error)); + return; + } + return; } outbody = data_blob_talloc(req->out.vector, NULL, 0x10); if (outbody.data == NULL) { - return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); + error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); + if (!NT_STATUS_IS_OK(error)) { + smbd_server_connection_terminate(req->conn, + nt_errstr(error)); + return; + } + return; } SSVAL(outbody.data, 0x00, 0x04); /* struct size */ SSVAL(outbody.data, 0x02, 0); /* reserved */ - return smbd_smb2_request_done(req, outbody, NULL); + error = smbd_smb2_request_done(req, outbody, NULL); + if (!NT_STATUS_IS_OK(error)) { + smbd_server_connection_terminate(req->conn, + nt_errstr(error)); + return; + } } -static NTSTATUS smbd_smb2_flush(struct smbd_smb2_request *req, - uint64_t in_file_id_volatile) +struct smbd_smb2_flush_state { + struct smbd_smb2_request *smb2req; +}; + +static struct tevent_req *smbd_smb2_flush_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct smbd_smb2_request *smb2req, + uint64_t in_file_id_volatile) { + struct tevent_req *req; + struct smbd_smb2_flush_state *state; NTSTATUS status; struct smb_request *smbreq; - connection_struct *conn = req->tcon->compat_conn; files_struct *fsp; + req = tevent_req_create(mem_ctx, &state, + struct smbd_smb2_flush_state); + if (req == NULL) { + return NULL; + } + state->smb2req = smb2req; + DEBUG(10,("smbd_smb2_flush: file_id[0x%016llX]\n", (unsigned long long)in_file_id_volatile)); - smbreq = smbd_smb2_fake_smb_request(req); - if (smbreq == NULL) { - return NT_STATUS_NO_MEMORY; + smbreq = smbd_smb2_fake_smb_request(smb2req); + if (tevent_req_nomem(smbreq, req)) { + return tevent_req_post(req, ev); } - /* If it's an IPC, pass off the pipe handler. */ - if (IS_IPC(conn)) { - return NT_STATUS_NOT_IMPLEMENTED; + if (IS_IPC(smbreq->conn)) { + tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED); + return tevent_req_post(req, ev); } fsp = file_fsp(smbreq, (uint16_t)in_file_id_volatile); if (fsp == NULL) { - return NT_STATUS_FILE_CLOSED; + tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); + return tevent_req_post(req, ev); } - if (conn != fsp->conn) { - return NT_STATUS_FILE_CLOSED; + if (smbreq->conn != fsp->conn) { + tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); + return tevent_req_post(req, ev); } - if (req->session->vuid != fsp->vuid) { - return NT_STATUS_FILE_CLOSED; + if (smb2req->session->vuid != fsp->vuid) { + tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); + return tevent_req_post(req, ev); } if (!CHECK_WRITE(fsp)) { - return NT_STATUS_ACCESS_DENIED; + tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); + return tevent_req_post(req, ev); } - status = sync_file(conn, fsp, true); + status = sync_file(smbreq->conn, fsp, true); if (!NT_STATUS_IS_OK(status)) { DEBUG(5,("smbd_smb2_flush: sync_file for %s returned %s\n", fsp->fsp_name, nt_errstr(status))); + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + + tevent_req_done(req); + return tevent_req_post(req, ev); +} + +static NTSTATUS smbd_smb2_flush_recv(struct tevent_req *req) +{ + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); return status; } + tevent_req_received(req); return NT_STATUS_OK; } |