From 2bbb8c917e372ceeb1e144259d9d2b0eab7cc212 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 23 Apr 2010 13:10:15 -0700 Subject: Allow smb2 create requests to be cancelled. Jeremy. --- source3/smbd/globals.h | 1 + source3/smbd/open.c | 27 ++++++++++------ source3/smbd/process.c | 2 ++ source3/smbd/smb2_create.c | 80 +++++++++++++++++++++++++++++++++++++++------- 4 files changed, 90 insertions(+), 20 deletions(-) (limited to 'source3/smbd') diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index a86f0e9bc2..4d1a13d3b1 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -346,6 +346,7 @@ void schedule_deferred_open_message_smb2(uint64_t mid); bool push_deferred_open_message_smb2(struct smbd_smb2_request *smb2req, struct timeval request_time, struct timeval timeout, + struct file_id id, char *private_data, size_t priv_len); diff --git a/source3/smbd/open.c b/source3/smbd/open.c index e0c24dab8d..f49aca8429 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -1085,7 +1085,7 @@ static void defer_open(struct share_mode_lock *lck, (unsigned long long)req->mid)); if (!push_deferred_open_message_smb(req, request_time, timeout, - (char *)state, sizeof(*state))) { + state->id, (char *)state, sizeof(*state))) { exit_server("push_deferred_open_message_smb failed"); } add_deferred_open(lck, req->mid, request_time, state->id); @@ -1448,6 +1448,22 @@ static NTSTATUS calculate_access_mask(connection_struct *conn, return NT_STATUS_OK; } +/**************************************************************************** + Remove the deferred open entry under lock. +****************************************************************************/ + +void remove_deferred_open_entry(struct file_id id, uint64_t mid) +{ + struct share_mode_lock *lck = get_share_mode_lock(talloc_tos(), id, + NULL, NULL, NULL); + if (lck == NULL) { + DEBUG(0, ("could not get share mode lock\n")); + } else { + del_deferred_open_entry(lck, mid); + TALLOC_FREE(lck); + } +} + /**************************************************************************** Open a file with a share mode. Passed in an already created files_struct *. ****************************************************************************/ @@ -1556,14 +1572,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, see if this has timed out. */ /* Remove the deferred open entry under lock. */ - lck = get_share_mode_lock(talloc_tos(), state->id, - NULL, NULL, NULL); - if (lck == NULL) { - DEBUG(0, ("could not get share mode lock\n")); - } else { - del_deferred_open_entry(lck, req->mid); - TALLOC_FREE(lck); - } + remove_deferred_open_entry(state->id, req->mid); /* Ensure we don't reprocess this message. */ remove_deferred_open_message_smb(req->mid); diff --git a/source3/smbd/process.c b/source3/smbd/process.c index a4838987a3..bbfa052de4 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -759,6 +759,7 @@ bool get_deferred_open_message_state(struct smb_request *smbreq, bool push_deferred_open_message_smb(struct smb_request *req, struct timeval request_time, struct timeval timeout, + struct file_id id, char *private_data, size_t priv_len) { struct timeval end_time; @@ -767,6 +768,7 @@ bool push_deferred_open_message_smb(struct smb_request *req, return push_deferred_open_message_smb2(req->smb2req, request_time, timeout, + id, private_data, priv_len); } diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c index ec20b7c365..d97d4af63a 100644 --- a/source3/smbd/smb2_create.c +++ b/source3/smbd/smb2_create.c @@ -199,6 +199,12 @@ NTSTATUS smbd_smb2_request_process_create(struct smbd_smb2_request *smb2req) return smbd_smb2_request_pending_queue(smb2req, tsubreq); } +static uint64_t get_mid_from_smb2req(struct smbd_smb2_request *smb2req) +{ + uint8_t *reqhdr = (uint8_t *)smb2req->out.vector[smb2req->current_idx].iov_base; + return BVAL(reqhdr, SMB2_HDR_MESSAGE_ID); +} + static void smbd_smb2_request_create_done(struct tevent_req *tsubreq) { struct smbd_smb2_request *smb2req = tevent_req_callback_data(tsubreq, @@ -223,6 +229,19 @@ static void smbd_smb2_request_create_done(struct tevent_req *tsubreq) NTSTATUS status; NTSTATUS error; /* transport error */ + if (smb2req->cancelled) { + uint64_t mid = get_mid_from_smb2req(smb2req); + DEBUG(10,("smbd_smb2_request_create_done: cancelled mid %llu\n", + (unsigned long long)mid )); + error = smbd_smb2_request_error(smb2req, NT_STATUS_CANCELLED); + if (!NT_STATUS_IS_OK(error)) { + smbd_server_connection_terminate(smb2req->sconn, + nt_errstr(error)); + return; + } + return; + } + status = smbd_smb2_create_recv(tsubreq, smb2req, &out_oplock_level, @@ -318,6 +337,7 @@ struct smbd_smb2_create_state { struct smb_request *smb1req; struct timed_event *te; struct timeval request_time; + struct file_id id; DATA_BLOB private_data; uint8_t out_oplock_level; uint32_t out_create_action; @@ -818,8 +838,7 @@ static struct smbd_smb2_request *find_open_smb2req(uint64_t mid) struct smbd_smb2_request *smb2req; for (smb2req = sconn->smb2.requests; smb2req; smb2req = smb2req->next) { - uint8_t *reqhdr = (uint8_t *)smb2req->out.vector[smb2req->current_idx].iov_base; - uint64_t message_id = BVAL(reqhdr, SMB2_HDR_MESSAGE_ID); + uint64_t message_id = get_mid_from_smb2req(smb2req); if (message_id == mid) { return smb2req; } @@ -859,17 +878,11 @@ bool open_was_deferred_smb2(uint64_t mid) return true; } -void remove_deferred_open_message_smb2(uint64_t mid) +static void remove_deferred_open_message_smb2_internal(struct smbd_smb2_request *smb2req, + uint64_t mid) { struct smbd_smb2_create_state *state = NULL; - struct smbd_smb2_request *smb2req = find_open_smb2req(mid); - if (!smb2req) { - DEBUG(10,("remove_deferred_open_message_smb2: " - "can't find mid %llu\n", - (unsigned long long)mid )); - return; - } if (!smb2req->subreq) { return; } @@ -882,7 +895,7 @@ void remove_deferred_open_message_smb2(uint64_t mid) return; } - DEBUG(10,("remove_deferred_open_message_smb2: " + DEBUG(10,("remove_deferred_open_message_smb2_internal: " "mid %llu\n", (unsigned long long)mid )); @@ -890,6 +903,19 @@ void remove_deferred_open_message_smb2(uint64_t mid) TALLOC_FREE(state->te); } +void remove_deferred_open_message_smb2(uint64_t mid) +{ + struct smbd_smb2_request *smb2req = find_open_smb2req(mid); + + if (!smb2req) { + DEBUG(10,("remove_deferred_open_message_smb2: " + "can't find mid %llu\n", + (unsigned long long)mid )); + return; + } + remove_deferred_open_message_smb2_internal(smb2req, mid); +} + void schedule_deferred_open_message_smb2(uint64_t mid) { struct tevent_immediate *im = NULL; @@ -979,9 +1005,36 @@ static void smb2_deferred_open_timer(struct event_context *ev, } } +static bool smbd_smb2_create_cancel(struct tevent_req *req) +{ + struct smbd_smb2_request *smb2req = NULL; + struct smbd_smb2_create_state *state = tevent_req_data(req, + struct smbd_smb2_create_state); + uint64_t mid; + + if (!state) { + return false; + } + + if (!state->smb2req) { + return false; + } + + smb2req = state->smb2req; + mid = get_mid_from_smb2req(smb2req); + + remove_deferred_open_entry(state->id, mid); + remove_deferred_open_message_smb2_internal(smb2req, mid); + smb2req->cancelled = true; + + tevent_req_done(req); + return true; +} + bool push_deferred_open_message_smb2(struct smbd_smb2_request *smb2req, struct timeval request_time, struct timeval timeout, + struct file_id id, char *private_data, size_t priv_len) { @@ -1000,6 +1053,7 @@ bool push_deferred_open_message_smb2(struct smbd_smb2_request *smb2req, if (!state) { return false; } + state->id = id; state->request_time = request_time; state->private_data = data_blob_talloc(state, private_data, priv_len); @@ -1048,5 +1102,9 @@ bool push_deferred_open_message_smb2(struct smbd_smb2_request *smb2req, if (!state->te) { return false; } + + /* allow this request to be canceled */ + tevent_req_set_cancel_fn(req, smbd_smb2_create_cancel); + return true; } -- cgit