mirror of
https://github.com/samba-team/samba.git
synced 2025-01-22 22:04:08 +03:00
smbd: rework async rename check for handle lease breaks
Add a version of delay_rename_for_lease_break() that is usable in other places where we have to check for handle lease breaks. No change in behaviour. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15608 Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Stefan Metzmacher <metze@samba.org>
This commit is contained in:
parent
00754add3c
commit
f9c9593225
@ -1204,4 +1204,15 @@ void smb3_file_posix_information_init(
|
||||
uint32_t dos_attributes,
|
||||
struct smb3_file_posix_information *dst);
|
||||
|
||||
struct tevent_req *delay_for_handle_lease_break_send(
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct tevent_context *ev,
|
||||
struct timeval timeout,
|
||||
struct files_struct *fsp,
|
||||
struct share_mode_lock **lck);
|
||||
|
||||
NTSTATUS delay_for_handle_lease_break_recv(struct tevent_req *req,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct share_mode_lock **lck);
|
||||
|
||||
#endif /* _SMBD_PROTO_H_ */
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "messages.h"
|
||||
#include "locking/leases_db.h"
|
||||
#include "../librpc/gen_ndr/ndr_open_files.h"
|
||||
#include "lib/util/tevent_ntstatus.h"
|
||||
|
||||
/*
|
||||
* helper function used by the kernel oplock backends to post the break message
|
||||
@ -1368,3 +1369,232 @@ void init_kernel_oplocks(struct smbd_server_connection *sconn)
|
||||
sconn->oplocks.kernel_ops = koplocks;
|
||||
}
|
||||
}
|
||||
|
||||
struct delay_for_handle_lease_break_state {
|
||||
TALLOC_CTX *mem_ctx;
|
||||
struct tevent_context *ev;
|
||||
struct timeval timeout;
|
||||
struct files_struct *fsp;
|
||||
struct share_mode_lock *lck;
|
||||
bool delay;
|
||||
};
|
||||
|
||||
static void delay_for_handle_lease_break_cleanup(struct tevent_req *req,
|
||||
enum tevent_req_state req_state)
|
||||
{
|
||||
struct delay_for_handle_lease_break_state *state =
|
||||
tevent_req_data(req, struct delay_for_handle_lease_break_state);
|
||||
|
||||
if (req_state == TEVENT_REQ_DONE) {
|
||||
return;
|
||||
}
|
||||
TALLOC_FREE(state->lck);
|
||||
}
|
||||
|
||||
static void delay_for_handle_lease_break_check(struct tevent_req *req);
|
||||
|
||||
struct tevent_req *delay_for_handle_lease_break_send(
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct tevent_context *ev,
|
||||
struct timeval timeout,
|
||||
struct files_struct *fsp,
|
||||
struct share_mode_lock **lck)
|
||||
{
|
||||
struct tevent_req *req = NULL;
|
||||
struct delay_for_handle_lease_break_state *state = NULL;
|
||||
|
||||
req = tevent_req_create(
|
||||
mem_ctx, &state, struct delay_for_handle_lease_break_state);
|
||||
if (req == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tevent_req_set_cleanup_fn(req, delay_for_handle_lease_break_cleanup);
|
||||
|
||||
*state = (struct delay_for_handle_lease_break_state) {
|
||||
.mem_ctx = mem_ctx,
|
||||
.ev = ev,
|
||||
.timeout = timeout,
|
||||
.fsp = fsp,
|
||||
.lck = talloc_move(state, lck),
|
||||
};
|
||||
|
||||
delay_for_handle_lease_break_check(req);
|
||||
if (!tevent_req_is_in_progress(req)) {
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
/* Ensure we can't be closed in flight. */
|
||||
if (!aio_add_req_to_fsp(fsp, req)) {
|
||||
tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
static bool delay_for_handle_lease_break_fn(struct share_mode_entry *e,
|
||||
void *private_data)
|
||||
{
|
||||
struct delay_for_handle_lease_break_state *state = talloc_get_type_abort(
|
||||
private_data, struct delay_for_handle_lease_break_state);
|
||||
struct files_struct *fsp = state->fsp;
|
||||
struct server_id_buf buf;
|
||||
uint32_t lease_type;
|
||||
bool ours, stale;
|
||||
|
||||
if (fsp->lease != NULL) {
|
||||
ours = smb2_lease_equal(fsp_client_guid(fsp),
|
||||
&fsp->lease->lease.lease_key,
|
||||
&e->client_guid,
|
||||
&e->lease_key);
|
||||
if (ours) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
lease_type = get_lease_type(e, fsp->file_id);
|
||||
if ((lease_type & SMB2_LEASE_HANDLE) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
stale = share_entry_stale_pid(e);
|
||||
if (stale) {
|
||||
return false;
|
||||
}
|
||||
|
||||
state->delay = true;
|
||||
|
||||
DBG_DEBUG("Breaking h-lease on [%s] pid [%s]\n",
|
||||
fsp_str_dbg(fsp),
|
||||
server_id_str_buf(e->pid, &buf));
|
||||
|
||||
send_break_message(fsp->conn->sconn->msg_ctx,
|
||||
&fsp->file_id,
|
||||
e,
|
||||
lease_type & ~SMB2_LEASE_HANDLE);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void delay_for_handle_lease_break_fsp_done(struct tevent_req *subreq);
|
||||
|
||||
static void delay_for_handle_lease_break_fsp_check(struct tevent_req *req)
|
||||
{
|
||||
struct delay_for_handle_lease_break_state *state = tevent_req_data(
|
||||
req, struct delay_for_handle_lease_break_state);
|
||||
struct tevent_req *subreq = NULL;
|
||||
bool ok;
|
||||
|
||||
DBG_DEBUG("fsp [%s]\n", fsp_str_dbg(state->fsp));
|
||||
|
||||
ok = share_mode_forall_leases(state->lck,
|
||||
delay_for_handle_lease_break_fn,
|
||||
state);
|
||||
if (!ok) {
|
||||
tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
if (state->delay) {
|
||||
DBG_DEBUG("Delaying fsp [%s]\n", fsp_str_dbg(state->fsp));
|
||||
|
||||
subreq = share_mode_watch_send(state,
|
||||
state->ev,
|
||||
state->lck,
|
||||
(struct server_id){0});
|
||||
if (tevent_req_nomem(subreq, req)) {
|
||||
return;
|
||||
}
|
||||
|
||||
tevent_req_set_callback(subreq,
|
||||
delay_for_handle_lease_break_fsp_done,
|
||||
req);
|
||||
|
||||
if (!tevent_req_set_endtime(subreq, state->ev, state->timeout)) {
|
||||
tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void delay_for_handle_lease_break_fsp_done(struct tevent_req *subreq)
|
||||
{
|
||||
struct tevent_req *req = tevent_req_callback_data(
|
||||
subreq, struct tevent_req);
|
||||
struct delay_for_handle_lease_break_state *state = tevent_req_data(
|
||||
req, struct delay_for_handle_lease_break_state);
|
||||
NTSTATUS status;
|
||||
|
||||
DBG_DEBUG("Watch returned for fsp [%s]\n", fsp_str_dbg(state->fsp));
|
||||
|
||||
status = share_mode_watch_recv(subreq, NULL, NULL);
|
||||
TALLOC_FREE(subreq);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DBG_ERR("share_mode_watch_recv returned %s\n",
|
||||
nt_errstr(status));
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
|
||||
/*
|
||||
* The sharemode-watch timer fired because a client
|
||||
* didn't respond to the lease break.
|
||||
*/
|
||||
status = NT_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
tevent_req_nterror(req, status);
|
||||
return;
|
||||
}
|
||||
|
||||
state->lck = get_existing_share_mode_lock(state, state->fsp->file_id);
|
||||
if (state->lck == NULL) {
|
||||
tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* This could potentially end up looping for some if a client
|
||||
* aggressively reaquires H-leases on the file, but we have a
|
||||
* timeout on the tevent req as upper bound.
|
||||
*/
|
||||
delay_for_handle_lease_break_check(req);
|
||||
}
|
||||
|
||||
static void delay_for_handle_lease_break_check(struct tevent_req *req)
|
||||
{
|
||||
struct delay_for_handle_lease_break_state *state = tevent_req_data(
|
||||
req, struct delay_for_handle_lease_break_state);
|
||||
|
||||
state->delay = false;
|
||||
|
||||
DBG_DEBUG("fsp [%s]\n", fsp_str_dbg(state->fsp));
|
||||
|
||||
delay_for_handle_lease_break_fsp_check(req);
|
||||
if (!tevent_req_is_in_progress(req)) {
|
||||
return;
|
||||
}
|
||||
if (state->delay) {
|
||||
DBG_DEBUG("Delaying fsp [%s]\n", fsp_str_dbg(state->fsp));
|
||||
TALLOC_FREE(state->lck);
|
||||
return;
|
||||
}
|
||||
|
||||
tevent_req_done(req);
|
||||
}
|
||||
|
||||
NTSTATUS delay_for_handle_lease_break_recv(struct tevent_req *req,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct share_mode_lock **lck)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
struct delay_for_handle_lease_break_state *state =
|
||||
tevent_req_data(req, struct delay_for_handle_lease_break_state);
|
||||
|
||||
if (tevent_req_is_nterror(req, &status)) {
|
||||
tevent_req_received(req);
|
||||
return status;
|
||||
}
|
||||
|
||||
*lck = talloc_move(mem_ctx, &state->lck);
|
||||
tevent_req_received(req);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
@ -168,188 +168,30 @@ static void smbd_smb2_request_setinfo_done(struct tevent_req *subreq)
|
||||
}
|
||||
}
|
||||
|
||||
struct defer_rename_state {
|
||||
struct tevent_req *req;
|
||||
struct smbd_smb2_request *smb2req;
|
||||
struct smbd_smb2_setinfo_state {
|
||||
struct tevent_context *ev;
|
||||
struct smbd_smb2_request *smb2req;
|
||||
struct files_struct *fsp;
|
||||
struct share_mode_lock *lck;
|
||||
uint16_t file_info_level;
|
||||
DATA_BLOB data;
|
||||
};
|
||||
|
||||
static void defer_rename_done(struct tevent_req *subreq);
|
||||
|
||||
struct delay_rename_lease_break_state {
|
||||
struct files_struct *fsp;
|
||||
bool delay;
|
||||
};
|
||||
|
||||
static bool delay_rename_lease_break_fn(
|
||||
struct share_mode_entry *e,
|
||||
void *private_data)
|
||||
static void smbd_smb2_setinfo_lease_break_check(struct tevent_req *req);
|
||||
|
||||
static void smbd_smb2_setinfo_cleanup(struct tevent_req *req,
|
||||
enum tevent_req_state req_state)
|
||||
{
|
||||
struct delay_rename_lease_break_state *state = private_data;
|
||||
struct files_struct *fsp = state->fsp;
|
||||
uint32_t e_lease_type, break_to;
|
||||
bool ours, stale;
|
||||
struct smbd_smb2_setinfo_state *state = tevent_req_data(
|
||||
req, struct smbd_smb2_setinfo_state);
|
||||
|
||||
ours = smb2_lease_equal(fsp_client_guid(fsp),
|
||||
&fsp->lease->lease.lease_key,
|
||||
&e->client_guid,
|
||||
&e->lease_key);
|
||||
if (ours) {
|
||||
return false;
|
||||
if (req_state == TEVENT_REQ_DONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
e_lease_type = get_lease_type(e, fsp->file_id);
|
||||
|
||||
if ((e_lease_type & SMB2_LEASE_HANDLE) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
stale = share_entry_stale_pid(e);
|
||||
if (stale) {
|
||||
return false;
|
||||
}
|
||||
|
||||
state->delay = true;
|
||||
break_to = (e_lease_type & ~SMB2_LEASE_HANDLE);
|
||||
|
||||
send_break_message(
|
||||
fsp->conn->sconn->msg_ctx, &fsp->file_id, e, break_to);
|
||||
|
||||
return false;
|
||||
TALLOC_FREE(state->lck);
|
||||
}
|
||||
|
||||
static struct tevent_req *delay_rename_for_lease_break(struct tevent_req *req,
|
||||
struct smbd_smb2_request *smb2req,
|
||||
struct tevent_context *ev,
|
||||
struct files_struct *fsp,
|
||||
struct share_mode_lock *lck,
|
||||
DATA_BLOB *data)
|
||||
{
|
||||
struct tevent_req *subreq;
|
||||
struct defer_rename_state *rename_state;
|
||||
struct delay_rename_lease_break_state state = { .fsp = fsp };
|
||||
struct timeval timeout;
|
||||
bool ok;
|
||||
|
||||
ok = share_mode_forall_leases(
|
||||
lck, delay_rename_lease_break_fn, &state);
|
||||
if (!ok) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!state.delay) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Setup a watch on this record. */
|
||||
rename_state = talloc_zero(req, struct defer_rename_state);
|
||||
if (rename_state == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rename_state->req = req;
|
||||
rename_state->smb2req = smb2req;
|
||||
rename_state->ev = ev;
|
||||
rename_state->fsp = fsp;
|
||||
rename_state->data = *data;
|
||||
|
||||
subreq = share_mode_watch_send(
|
||||
rename_state,
|
||||
ev,
|
||||
lck,
|
||||
(struct server_id){0});
|
||||
|
||||
if (subreq == NULL) {
|
||||
exit_server("Could not watch share mode record for rename\n");
|
||||
}
|
||||
|
||||
tevent_req_set_callback(subreq, defer_rename_done, rename_state);
|
||||
|
||||
timeout = tevent_timeval_set(OPLOCK_BREAK_TIMEOUT * 2, 0);
|
||||
if (!tevent_req_set_endtime(subreq,
|
||||
ev,
|
||||
timeval_sum(&smb2req->request_time, &timeout))) {
|
||||
exit_server("Could not set rename timeout\n");
|
||||
}
|
||||
|
||||
return subreq;
|
||||
}
|
||||
|
||||
static void defer_rename_done(struct tevent_req *subreq)
|
||||
{
|
||||
struct defer_rename_state *state = tevent_req_callback_data(
|
||||
subreq, struct defer_rename_state);
|
||||
NTSTATUS status;
|
||||
struct share_mode_lock *lck;
|
||||
int ret_size = 0;
|
||||
bool ok;
|
||||
|
||||
status = share_mode_watch_recv(subreq, NULL, NULL);
|
||||
TALLOC_FREE(subreq);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(5, ("dbwrap_record_watch_recv returned %s\n",
|
||||
nt_errstr(status)));
|
||||
tevent_req_nterror(state->req, status);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure we run as the user again
|
||||
*/
|
||||
ok = change_to_user_and_service(
|
||||
state->smb2req->tcon->compat,
|
||||
state->smb2req->session->global->session_wire_id);
|
||||
if (!ok) {
|
||||
tevent_req_nterror(state->req, NT_STATUS_ACCESS_DENIED);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Do we still need to wait ? */
|
||||
lck = get_existing_share_mode_lock(state->req, state->fsp->file_id);
|
||||
if (lck == NULL) {
|
||||
tevent_req_nterror(state->req, NT_STATUS_UNSUCCESSFUL);
|
||||
return;
|
||||
}
|
||||
subreq = delay_rename_for_lease_break(state->req,
|
||||
state->smb2req,
|
||||
state->ev,
|
||||
state->fsp,
|
||||
lck,
|
||||
&state->data);
|
||||
if (subreq) {
|
||||
/* Yep - keep waiting. */
|
||||
TALLOC_FREE(state);
|
||||
TALLOC_FREE(lck);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Do the rename under the lock. */
|
||||
status = smbd_do_setfilepathinfo(state->fsp->conn,
|
||||
state->smb2req->smb1req,
|
||||
state,
|
||||
SMB2_FILE_RENAME_INFORMATION_INTERNAL,
|
||||
state->fsp,
|
||||
state->fsp->fsp_name,
|
||||
(char *)state->data.data,
|
||||
state->data.length,
|
||||
&ret_size);
|
||||
|
||||
TALLOC_FREE(lck);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
tevent_req_nterror(state->req, status);
|
||||
return;
|
||||
}
|
||||
|
||||
tevent_req_done(state->req);
|
||||
}
|
||||
|
||||
struct smbd_smb2_setinfo_state {
|
||||
struct smbd_smb2_request *smb2req;
|
||||
};
|
||||
|
||||
static struct tevent_req *smbd_smb2_setinfo_send(TALLOC_CTX *mem_ctx,
|
||||
struct tevent_context *ev,
|
||||
struct smbd_smb2_request *smb2req,
|
||||
@ -363,7 +205,6 @@ static struct tevent_req *smbd_smb2_setinfo_send(TALLOC_CTX *mem_ctx,
|
||||
struct smbd_smb2_setinfo_state *state = NULL;
|
||||
struct smb_request *smbreq = NULL;
|
||||
connection_struct *conn = smb2req->tcon->compat;
|
||||
struct share_mode_lock *lck = NULL;
|
||||
NTSTATUS status;
|
||||
int ret;
|
||||
|
||||
@ -372,7 +213,12 @@ static struct tevent_req *smbd_smb2_setinfo_send(TALLOC_CTX *mem_ctx,
|
||||
if (req == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
state->ev = ev;
|
||||
state->smb2req = smb2req;
|
||||
state->fsp = fsp;
|
||||
state->data = in_input_buffer;
|
||||
|
||||
tevent_req_set_cleanup_fn(req, smbd_smb2_setinfo_cleanup);
|
||||
|
||||
DEBUG(10,("smbd_smb2_setinfo_send: %s - %s\n",
|
||||
fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
|
||||
@ -391,13 +237,13 @@ static struct tevent_req *smbd_smb2_setinfo_send(TALLOC_CTX *mem_ctx,
|
||||
case SMB2_0_INFO_FILE:
|
||||
{
|
||||
uint16_t file_info_level;
|
||||
int ret_size = 0;
|
||||
|
||||
file_info_level = in_file_info_class + 1000;
|
||||
if (file_info_level == SMB_FILE_RENAME_INFORMATION) {
|
||||
/* SMB2_FILE_RENAME_INFORMATION_INTERNAL == 0xFF00 + in_file_info_class */
|
||||
file_info_level = SMB2_FILE_RENAME_INFORMATION_INTERNAL;
|
||||
}
|
||||
state->file_info_level = file_info_level;
|
||||
|
||||
if (fsp_get_pathref_fd(fsp) == -1) {
|
||||
/*
|
||||
@ -448,54 +294,12 @@ static struct tevent_req *smbd_smb2_setinfo_send(TALLOC_CTX *mem_ctx,
|
||||
}
|
||||
}
|
||||
|
||||
if (file_info_level == SMB2_FILE_RENAME_INFORMATION_INTERNAL) {
|
||||
struct tevent_req *subreq;
|
||||
|
||||
lck = get_existing_share_mode_lock(mem_ctx,
|
||||
fsp->file_id);
|
||||
if (lck == NULL) {
|
||||
tevent_req_nterror(req,
|
||||
NT_STATUS_UNSUCCESSFUL);
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
subreq = delay_rename_for_lease_break(req,
|
||||
smb2req,
|
||||
ev,
|
||||
fsp,
|
||||
lck,
|
||||
&in_input_buffer);
|
||||
if (subreq) {
|
||||
/* Wait for lease break response. */
|
||||
|
||||
/* Ensure we can't be closed in flight. */
|
||||
if (!aio_add_req_to_fsp(fsp, req)) {
|
||||
TALLOC_FREE(lck);
|
||||
tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
TALLOC_FREE(lck);
|
||||
return req;
|
||||
}
|
||||
}
|
||||
|
||||
status = smbd_do_setfilepathinfo(conn, smbreq, state,
|
||||
file_info_level,
|
||||
fsp,
|
||||
fsp->fsp_name,
|
||||
(char *)in_input_buffer.data,
|
||||
in_input_buffer.length,
|
||||
&ret_size);
|
||||
TALLOC_FREE(lck);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL)) {
|
||||
status = NT_STATUS_INVALID_INFO_CLASS;
|
||||
}
|
||||
tevent_req_nterror(req, status);
|
||||
smbd_smb2_setinfo_lease_break_check(req);
|
||||
if (!tevent_req_is_in_progress(req)) {
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
break;
|
||||
SMB_ASSERT(state->delay);
|
||||
return req;
|
||||
}
|
||||
|
||||
case SMB2_0_INFO_FILESYSTEM:
|
||||
@ -583,6 +387,144 @@ static struct tevent_req *smbd_smb2_setinfo_send(TALLOC_CTX *mem_ctx,
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
static void smbd_smb2_setinfo_lease_break_fsp_check(struct tevent_req *req);
|
||||
static void smbd_smb2_setinfo_lease_break_fsp_done(struct tevent_req *subreq);
|
||||
|
||||
static void smbd_smb2_setinfo_lease_break_check(struct tevent_req *req)
|
||||
{
|
||||
struct smbd_smb2_setinfo_state *state = tevent_req_data(
|
||||
req, struct smbd_smb2_setinfo_state);
|
||||
int ret_size;
|
||||
NTSTATUS status;
|
||||
|
||||
state->delay = false;
|
||||
|
||||
smbd_smb2_setinfo_lease_break_fsp_check(req);
|
||||
if (!tevent_req_is_in_progress(req)) {
|
||||
return;
|
||||
}
|
||||
if (state->delay) {
|
||||
TALLOC_FREE(state->lck);
|
||||
DBG_DEBUG("Waiting for h-lease breaks on fsp [%s]\n",
|
||||
fsp_str_dbg(state->fsp));
|
||||
return;
|
||||
}
|
||||
|
||||
status = smbd_do_setfilepathinfo(state->fsp->conn,
|
||||
state->smb2req->smb1req,
|
||||
state,
|
||||
state->file_info_level,
|
||||
state->fsp,
|
||||
state->fsp->fsp_name,
|
||||
(char *)state->data.data,
|
||||
state->data.length,
|
||||
&ret_size);
|
||||
TALLOC_FREE(state->lck);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL)) {
|
||||
status = NT_STATUS_INVALID_INFO_CLASS;
|
||||
}
|
||||
tevent_req_nterror(req, status);
|
||||
return;
|
||||
}
|
||||
|
||||
tevent_req_done(req);
|
||||
}
|
||||
|
||||
static void smbd_smb2_setinfo_lease_break_fsp_check(struct tevent_req *req)
|
||||
{
|
||||
struct smbd_smb2_setinfo_state *state = tevent_req_data(
|
||||
req, struct smbd_smb2_setinfo_state);
|
||||
struct smbd_smb2_request *smb2req = state->smb2req;
|
||||
struct files_struct *fsp = state->fsp;
|
||||
uint16_t file_info_level = state->file_info_level;
|
||||
struct tevent_req *subreq = NULL;
|
||||
struct timeval timeout;
|
||||
bool rename;
|
||||
NTSTATUS status;
|
||||
|
||||
rename = (file_info_level == SMB2_FILE_RENAME_INFORMATION_INTERNAL);
|
||||
if (!rename) {
|
||||
return;
|
||||
}
|
||||
|
||||
state->lck = get_existing_share_mode_lock(state, fsp->file_id);
|
||||
if (state->lck == NULL) {
|
||||
tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
|
||||
return;
|
||||
}
|
||||
|
||||
timeout = tevent_timeval_set(OPLOCK_BREAK_TIMEOUT, 0);
|
||||
timeout = timeval_sum(&smb2req->request_time, &timeout);
|
||||
|
||||
subreq = delay_for_handle_lease_break_send(state,
|
||||
state->ev,
|
||||
timeout,
|
||||
fsp,
|
||||
&state->lck);
|
||||
if (tevent_req_nomem(subreq, req)) {
|
||||
return;
|
||||
}
|
||||
if (tevent_req_is_in_progress(subreq)) {
|
||||
state->delay = true;
|
||||
tevent_req_set_callback(subreq,
|
||||
smbd_smb2_setinfo_lease_break_fsp_done,
|
||||
req);
|
||||
return;
|
||||
}
|
||||
|
||||
status = delay_for_handle_lease_break_recv(subreq, state, &state->lck);
|
||||
TALLOC_FREE(subreq);
|
||||
if (tevent_req_nterror(req, status)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void smbd_smb2_setinfo_lease_break_fsp_done(struct tevent_req *subreq)
|
||||
{
|
||||
struct tevent_req *req = tevent_req_callback_data(
|
||||
subreq, struct tevent_req);
|
||||
struct smbd_smb2_setinfo_state *state = tevent_req_data(
|
||||
req, struct smbd_smb2_setinfo_state);
|
||||
int ret_size;
|
||||
NTSTATUS status;
|
||||
bool ok;
|
||||
|
||||
status = delay_for_handle_lease_break_recv(subreq, state, &state->lck);
|
||||
TALLOC_FREE(subreq);
|
||||
if (tevent_req_nterror(req, status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure we run as the user again
|
||||
*/
|
||||
ok = change_to_user_and_service(
|
||||
state->smb2req->tcon->compat,
|
||||
state->smb2req->session->global->session_wire_id);
|
||||
if (!ok) {
|
||||
tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Do the rename under the lock. */
|
||||
status = smbd_do_setfilepathinfo(state->fsp->conn,
|
||||
state->smb2req->smb1req,
|
||||
state,
|
||||
state->file_info_level,
|
||||
state->fsp,
|
||||
state->fsp->fsp_name,
|
||||
(char *)state->data.data,
|
||||
state->data.length,
|
||||
&ret_size);
|
||||
TALLOC_FREE(state->lck);
|
||||
if (tevent_req_nterror(req, status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
tevent_req_done(req);
|
||||
}
|
||||
|
||||
static NTSTATUS smbd_smb2_setinfo_recv(struct tevent_req *req)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
Loading…
x
Reference in New Issue
Block a user