From c66139e7a676803898c36eef7280013c746bdcd6 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 20 Jun 2014 08:23:47 +0000 Subject: [PATCH 01/14] libsmb: Make cli_smb2_create_fnum async Signed-off-by: Volker Lendecke --- source3/libsmb/cli_smb2_fnum.c | 164 +++++++++++++++++++++++++++++++--------- source3/libsmb/cli_smb2_fnum.h | 12 +++ 2 files changed, 139 insertions(+), 37 deletions(-) diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c index 950398a..6c24038 100644 --- a/source3/libsmb/cli_smb2_fnum.c +++ b/source3/libsmb/cli_smb2_fnum.c @@ -151,32 +151,40 @@ static uint8_t flags_to_smb2_oplock(uint32_t create_flags) /*************************************************************** Small wrapper that allows SMB2 create to return a uint16_t fnum. - Synchronous only. ***************************************************************/ -NTSTATUS cli_smb2_create_fnum(struct cli_state *cli, - const char *fname, - uint32_t create_flags, - uint32_t desired_access, - uint32_t file_attributes, - uint32_t share_access, - uint32_t create_disposition, - uint32_t create_options, - uint16_t *pfid, - struct smb_create_returns *cr) +struct cli_smb2_create_fnum_state { + struct cli_state *cli; + struct smb_create_returns cr; + uint16_t fnum; +}; + +static void cli_smb2_create_fnum_done(struct tevent_req *subreq); + +struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + const char *fname, + uint32_t create_flags, + uint32_t desired_access, + uint32_t file_attributes, + uint32_t share_access, + uint32_t create_disposition, + uint32_t create_options) { - NTSTATUS status; - struct smb2_hnd h; + struct tevent_req *req, *subreq; + struct cli_smb2_create_fnum_state *state; - if (smbXcli_conn_has_async_calls(cli->conn)) { - /* - * Can't use sync call while an async call is in flight - */ - return NT_STATUS_INVALID_PARAMETER; + req = tevent_req_create(mem_ctx, &state, + struct cli_smb2_create_fnum_state); + if (req == NULL) { + return NULL; } + state->cli = cli; if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { - return NT_STATUS_INVALID_PARAMETER; + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); } if (cli->backup_intent) { @@ -189,27 +197,109 @@ NTSTATUS cli_smb2_create_fnum(struct cli_state *cli, fname++; } - status = smb2cli_create(cli->conn, - cli->timeout, - cli->smb2.session, - cli->smb2.tcon, - fname, - flags_to_smb2_oplock(create_flags), - SMB2_IMPERSONATION_IMPERSONATION, - desired_access, - file_attributes, - share_access, - create_disposition, - create_options, - NULL, - &h.fid_persistent, - &h.fid_volatile, - cr); + subreq = smb2cli_create_send(state, ev, + cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + fname, + flags_to_smb2_oplock(create_flags), + SMB2_IMPERSONATION_IMPERSONATION, + desired_access, + file_attributes, + share_access, + create_disposition, + create_options, + NULL); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req); + return req; +} - if (NT_STATUS_IS_OK(status)) { - status = map_smb2_handle_to_fnum(cli, &h, pfid); +static void cli_smb2_create_fnum_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_smb2_create_fnum_state *state = tevent_req_data( + req, struct cli_smb2_create_fnum_state); + struct smb2_hnd h; + NTSTATUS status; + + status = smb2cli_create_recv(subreq, &h.fid_persistent, + &h.fid_volatile, &state->cr); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + + status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum); + if (tevent_req_nterror(req, status)) { + return; + } + tevent_req_done(req); +} + +NTSTATUS cli_smb2_create_fnum_recv(struct tevent_req *req, uint16_t *pfnum, + struct smb_create_returns *cr) +{ + struct cli_smb2_create_fnum_state *state = tevent_req_data( + req, struct cli_smb2_create_fnum_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + if (pfnum != NULL) { + *pfnum = state->fnum; } + if (cr != NULL) { + *cr = state->cr; + } + return NT_STATUS_OK; +} +NTSTATUS cli_smb2_create_fnum(struct cli_state *cli, + const char *fname, + uint32_t create_flags, + uint32_t desired_access, + uint32_t file_attributes, + uint32_t share_access, + uint32_t create_disposition, + uint32_t create_options, + uint16_t *pfid, + struct smb_create_returns *cr) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct tevent_context *ev; + struct tevent_req *req; + NTSTATUS status = NT_STATUS_NO_MEMORY; + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + ev = samba_tevent_context_init(frame); + if (ev == NULL) { + goto fail; + } + req = cli_smb2_create_fnum_send(frame, ev, cli, fname, create_flags, + desired_access, file_attributes, + share_access, create_disposition, + create_options); + if (req == NULL) { + goto fail; + } + if (!tevent_req_poll_ntstatus(req, ev, &status)) { + goto fail; + } + status = cli_smb2_create_fnum_recv(req, pfid, cr); + fail: + TALLOC_FREE(frame); return status; } diff --git a/source3/libsmb/cli_smb2_fnum.h b/source3/libsmb/cli_smb2_fnum.h index a5ed5a0..9394918 100644 --- a/source3/libsmb/cli_smb2_fnum.h +++ b/source3/libsmb/cli_smb2_fnum.h @@ -25,6 +25,18 @@ struct smbXcli_session; struct cli_state; struct file_info; +struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + const char *fname, + uint32_t create_flags, + uint32_t desired_access, + uint32_t file_attributes, + uint32_t share_access, + uint32_t create_disposition, + uint32_t create_options); +NTSTATUS cli_smb2_create_fnum_recv(struct tevent_req *req, uint16_t *pfnum, + struct smb_create_returns *cr); NTSTATUS cli_smb2_create_fnum(struct cli_state *cli, const char *fname, uint32_t create_flags, -- 1.7.9.5 From 8aff09094488df7669779e903806343ce0e6c78b Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 20 Jun 2014 08:41:59 +0000 Subject: [PATCH 02/14] libsmb: Add cli_create_send/recv Async wrapper around smb1 and smb2 create Signed-off-by: Volker Lendecke --- source3/libsmb/clifile.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++ source3/libsmb/proto.h | 13 +++++++ 2 files changed, 97 insertions(+) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 1c52730..6fd4f39 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -1919,6 +1919,90 @@ NTSTATUS cli_ntcreate_recv(struct tevent_req *req, return NT_STATUS_OK; } +struct cli_create_state { + NTSTATUS (*recv)(struct tevent_req *req, uint16_t *fnum, + struct smb_create_returns *cr); + struct smb_create_returns cr; + uint16_t fnum; +}; + +static void cli_create_done(struct tevent_req *subreq); + +struct tevent_req *cli_create_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + const char *fname, + uint32_t create_flags, + uint32_t desired_access, + uint32_t file_attributes, + uint32_t share_access, + uint32_t create_disposition, + uint32_t create_options, + uint8_t security_flags) +{ + struct tevent_req *req, *subreq; + struct cli_create_state *state; + + req = tevent_req_create(mem_ctx, &state, struct cli_create_state); + if (req == NULL) { + return NULL; + } + + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + state->recv = cli_smb2_create_fnum_recv; + subreq = cli_smb2_create_fnum_send( + state, ev, cli, fname, create_flags, desired_access, + file_attributes, share_access, create_disposition, + create_options); + } else { + state->recv = cli_ntcreate_recv; + subreq = cli_ntcreate_send( + state, ev, cli, fname, create_flags, desired_access, + file_attributes, share_access, create_disposition, + create_options, security_flags); + } + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_create_done, req); + return req; +} + +static void cli_create_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_create_state *state = tevent_req_data( + req, struct cli_create_state); + NTSTATUS status; + + status = state->recv(subreq, &state->fnum, &state->cr); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + tevent_req_done(req); +} + +NTSTATUS cli_create_recv(struct tevent_req *req, uint16_t *fnum, + struct smb_create_returns *cr) +{ + struct cli_create_state *state = tevent_req_data( + req, struct cli_create_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + if (fnum != NULL) { + *fnum = state->fnum; + } + if (cr != NULL) { + *cr = state->cr; + } + return NT_STATUS_OK; +} + NTSTATUS cli_ntcreate(struct cli_state *cli, const char *fname, uint32_t CreatFlags, diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h index 63d2df4..7c09e588 100644 --- a/source3/libsmb/proto.h +++ b/source3/libsmb/proto.h @@ -359,6 +359,19 @@ struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx, NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *pfnum, struct smb_create_returns *cr); +struct tevent_req *cli_create_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + const char *fname, + uint32_t create_flags, + uint32_t desired_access, + uint32_t file_attributes, + uint32_t share_access, + uint32_t create_disposition, + uint32_t create_options, + uint8_t security_flags); +NTSTATUS cli_create_recv(struct tevent_req *req, uint16_t *fnum, + struct smb_create_returns *cr); NTSTATUS cli_ntcreate(struct cli_state *cli, const char *fname, uint32_t CreatFlags, -- 1.7.9.5 From 875b2f398e3a13ed87ea1b05e4a657ec7446d600 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 20 Jun 2014 08:50:17 +0000 Subject: [PATCH 03/14] libsmb: Replace async cli_ntcreate by cli_create Done by rename cli_ntcreate_send/recv to cli_ntcreate1_send/recv and cli_create_send/recv to cli_ntcreate_send/recv Possibly cli_create might be the better name, but I am sooo used to cli_ntcreate() that I don't really want to rename this ;-) Signed-off-by: Volker Lendecke --- source3/libsmb/clifile.c | 98 +++++++++++++++++++++++----------------------- source3/libsmb/proto.h | 13 ------ 2 files changed, 49 insertions(+), 62 deletions(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 6fd4f39..40c41d9 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -1792,33 +1792,33 @@ NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag) return status; } -struct cli_ntcreate_state { +struct cli_ntcreate1_state { uint16_t vwv[24]; uint16_t fnum; struct smb_create_returns cr; }; -static void cli_ntcreate_done(struct tevent_req *subreq); +static void cli_ntcreate1_done(struct tevent_req *subreq); -struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct cli_state *cli, - const char *fname, - uint32_t CreatFlags, - uint32_t DesiredAccess, - uint32_t FileAttributes, - uint32_t ShareAccess, - uint32_t CreateDisposition, - uint32_t CreateOptions, - uint8_t SecurityFlags) +static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + const char *fname, + uint32_t CreatFlags, + uint32_t DesiredAccess, + uint32_t FileAttributes, + uint32_t ShareAccess, + uint32_t CreateDisposition, + uint32_t CreateOptions, + uint8_t SecurityFlags) { struct tevent_req *req, *subreq; - struct cli_ntcreate_state *state; + struct cli_ntcreate1_state *state; uint16_t *vwv; uint8_t *bytes; size_t converted_len; - req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state); + req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate1_state); if (req == NULL) { return NULL; } @@ -1865,16 +1865,16 @@ struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx, if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } - tevent_req_set_callback(subreq, cli_ntcreate_done, req); + tevent_req_set_callback(subreq, cli_ntcreate1_done, req); return req; } -static void cli_ntcreate_done(struct tevent_req *subreq) +static void cli_ntcreate1_done(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data( subreq, struct tevent_req); - struct cli_ntcreate_state *state = tevent_req_data( - req, struct cli_ntcreate_state); + struct cli_ntcreate1_state *state = tevent_req_data( + req, struct cli_ntcreate1_state); uint8_t wct; uint16_t *vwv; uint32_t num_bytes; @@ -1901,12 +1901,12 @@ static void cli_ntcreate_done(struct tevent_req *subreq) tevent_req_done(req); } -NTSTATUS cli_ntcreate_recv(struct tevent_req *req, - uint16_t *pfnum, - struct smb_create_returns *cr) +static NTSTATUS cli_ntcreate1_recv(struct tevent_req *req, + uint16_t *pfnum, + struct smb_create_returns *cr) { - struct cli_ntcreate_state *state = tevent_req_data( - req, struct cli_ntcreate_state); + struct cli_ntcreate1_state *state = tevent_req_data( + req, struct cli_ntcreate1_state); NTSTATUS status; if (tevent_req_is_nterror(req, &status)) { @@ -1919,31 +1919,31 @@ NTSTATUS cli_ntcreate_recv(struct tevent_req *req, return NT_STATUS_OK; } -struct cli_create_state { +struct cli_ntcreate_state { NTSTATUS (*recv)(struct tevent_req *req, uint16_t *fnum, struct smb_create_returns *cr); struct smb_create_returns cr; uint16_t fnum; }; -static void cli_create_done(struct tevent_req *subreq); +static void cli_ntcreate_done(struct tevent_req *subreq); -struct tevent_req *cli_create_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct cli_state *cli, - const char *fname, - uint32_t create_flags, - uint32_t desired_access, - uint32_t file_attributes, - uint32_t share_access, - uint32_t create_disposition, - uint32_t create_options, - uint8_t security_flags) +struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + const char *fname, + uint32_t create_flags, + uint32_t desired_access, + uint32_t file_attributes, + uint32_t share_access, + uint32_t create_disposition, + uint32_t create_options, + uint8_t security_flags) { struct tevent_req *req, *subreq; - struct cli_create_state *state; + struct cli_ntcreate_state *state; - req = tevent_req_create(mem_ctx, &state, struct cli_create_state); + req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state); if (req == NULL) { return NULL; } @@ -1955,8 +1955,8 @@ struct tevent_req *cli_create_send(TALLOC_CTX *mem_ctx, file_attributes, share_access, create_disposition, create_options); } else { - state->recv = cli_ntcreate_recv; - subreq = cli_ntcreate_send( + state->recv = cli_ntcreate1_recv; + subreq = cli_ntcreate1_send( state, ev, cli, fname, create_flags, desired_access, file_attributes, share_access, create_disposition, create_options, security_flags); @@ -1964,16 +1964,16 @@ struct tevent_req *cli_create_send(TALLOC_CTX *mem_ctx, if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } - tevent_req_set_callback(subreq, cli_create_done, req); + tevent_req_set_callback(subreq, cli_ntcreate_done, req); return req; } -static void cli_create_done(struct tevent_req *subreq) +static void cli_ntcreate_done(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data( subreq, struct tevent_req); - struct cli_create_state *state = tevent_req_data( - req, struct cli_create_state); + struct cli_ntcreate_state *state = tevent_req_data( + req, struct cli_ntcreate_state); NTSTATUS status; status = state->recv(subreq, &state->fnum, &state->cr); @@ -1984,11 +1984,11 @@ static void cli_create_done(struct tevent_req *subreq) tevent_req_done(req); } -NTSTATUS cli_create_recv(struct tevent_req *req, uint16_t *fnum, - struct smb_create_returns *cr) +NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *fnum, + struct smb_create_returns *cr) { - struct cli_create_state *state = tevent_req_data( - req, struct cli_create_state); + struct cli_ntcreate_state *state = tevent_req_data( + req, struct cli_ntcreate_state); NTSTATUS status; if (tevent_req_is_nterror(req, &status)) { diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h index 7c09e588..63d2df4 100644 --- a/source3/libsmb/proto.h +++ b/source3/libsmb/proto.h @@ -359,19 +359,6 @@ struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx, NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *pfnum, struct smb_create_returns *cr); -struct tevent_req *cli_create_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct cli_state *cli, - const char *fname, - uint32_t create_flags, - uint32_t desired_access, - uint32_t file_attributes, - uint32_t share_access, - uint32_t create_disposition, - uint32_t create_options, - uint8_t security_flags); -NTSTATUS cli_create_recv(struct tevent_req *req, uint16_t *fnum, - struct smb_create_returns *cr); NTSTATUS cli_ntcreate(struct cli_state *cli, const char *fname, uint32_t CreatFlags, -- 1.7.9.5 From 1556224a31d1d3f39a482e002cc002a68b460409 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 20 Jun 2014 08:52:45 +0000 Subject: [PATCH 04/14] libsmb: remove smb2 switch from cli_ntcreate Signed-off-by: Volker Lendecke --- source3/libsmb/clifile.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 40c41d9..c8a3610 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -2020,19 +2020,6 @@ NTSTATUS cli_ntcreate(struct cli_state *cli, struct tevent_req *req; NTSTATUS status = NT_STATUS_OK; - if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { - return cli_smb2_create_fnum(cli, - fname, - CreatFlags, - DesiredAccess, - FileAttributes, - ShareAccess, - CreateDisposition, - CreateOptions, - pfid, - cr); - } - frame = talloc_stackframe(); if (smbXcli_conn_has_async_calls(cli->conn)) { -- 1.7.9.5 From 6afe723231806a8ab0422d7520692d0ff6224f16 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 20 Jun 2014 08:53:49 +0000 Subject: [PATCH 05/14] libsmb: Align cli_ntcreate with other sync wrappers ... saves 5 lines :-) Signed-off-by: Volker Lendecke --- source3/libsmb/clifile.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index c8a3610..aee1745 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -2015,12 +2015,10 @@ NTSTATUS cli_ntcreate(struct cli_state *cli, uint16_t *pfid, struct smb_create_returns *cr) { - TALLOC_CTX *frame = NULL; + TALLOC_CTX *frame = talloc_stackframe(); struct tevent_context *ev; struct tevent_req *req; - NTSTATUS status = NT_STATUS_OK; - - frame = talloc_stackframe(); + NTSTATUS status = NT_STATUS_NO_MEMORY; if (smbXcli_conn_has_async_calls(cli->conn)) { /* @@ -2032,7 +2030,6 @@ NTSTATUS cli_ntcreate(struct cli_state *cli, ev = samba_tevent_context_init(frame); if (ev == NULL) { - status = NT_STATUS_NO_MEMORY; goto fail; } @@ -2041,12 +2038,10 @@ NTSTATUS cli_ntcreate(struct cli_state *cli, CreateDisposition, CreateOptions, SecurityFlags); if (req == NULL) { - status = NT_STATUS_NO_MEMORY; goto fail; } - if (!tevent_req_poll(req, ev)) { - status = map_nt_error_from_unix(errno); + if (!tevent_req_poll_ntstatus(req, ev, &status)) { goto fail; } -- 1.7.9.5 From 53d86406b6434f03f057e31d439404aa566a9e24 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 20 Jun 2014 09:55:04 +0000 Subject: [PATCH 06/14] libsmb: Enable oplocks for smb2 cli_ntcreate Signed-off-by: Volker Lendecke --- source3/libsmb/clifile.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index aee1745..3ec5e9a 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -1950,6 +1950,11 @@ struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx, if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { state->recv = cli_smb2_create_fnum_recv; + + if (cli->use_oplocks) { + create_flags |= REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK; + } + subreq = cli_smb2_create_fnum_send( state, ev, cli, fname, create_flags, desired_access, file_attributes, share_access, create_disposition, -- 1.7.9.5 From df5fa4b14415f147a107f83df0bec70abe293936 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 20 Jun 2014 10:37:14 +0000 Subject: [PATCH 07/14] libsmb: Make smb2cli_create cancellable Signed-off-by: Volker Lendecke --- libcli/smb/smb2cli_create.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/libcli/smb/smb2cli_create.c b/libcli/smb/smb2cli_create.c index 834a881..bcd674e 100644 --- a/libcli/smb/smb2cli_create.c +++ b/libcli/smb/smb2cli_create.c @@ -31,9 +31,11 @@ struct smb2cli_create_state { uint64_t fid_volatile; struct smb_create_returns cr; struct smb2_create_blobs blobs; + struct tevent_req *subreq; }; static void smb2cli_create_done(struct tevent_req *subreq); +static bool smb2cli_create_cancel(struct tevent_req *req); struct tevent_req *smb2cli_create_send( TALLOC_CTX *mem_ctx, @@ -159,9 +161,20 @@ struct tevent_req *smb2cli_create_send( return tevent_req_post(req, ev); } tevent_req_set_callback(subreq, smb2cli_create_done, req); + + state->subreq = subreq; + tevent_req_set_cancel_fn(req, smb2cli_create_cancel); + return req; } +static bool smb2cli_create_cancel(struct tevent_req *req) +{ + struct smb2cli_create_state *state = tevent_req_data(req, + struct smb2cli_create_state); + return tevent_req_cancel(state->subreq); +} + static void smb2cli_create_done(struct tevent_req *subreq) { struct tevent_req *req = -- 1.7.9.5 From 98015b501ec6640b57fdc4a7e6dd0db79112f228 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 20 Jun 2014 10:37:46 +0000 Subject: [PATCH 08/14] libsmb: Make cli_smb2_create_fnum cancellable Signed-off-by: Volker Lendecke --- source3/libsmb/cli_smb2_fnum.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c index 6c24038..87edf4e 100644 --- a/source3/libsmb/cli_smb2_fnum.c +++ b/source3/libsmb/cli_smb2_fnum.c @@ -157,9 +157,11 @@ struct cli_smb2_create_fnum_state { struct cli_state *cli; struct smb_create_returns cr; uint16_t fnum; + struct tevent_req *subreq; }; static void cli_smb2_create_fnum_done(struct tevent_req *subreq); +static bool cli_smb2_create_fnum_cancel(struct tevent_req *req); struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, @@ -215,6 +217,10 @@ struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req); + + state->subreq = subreq; + tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel); + return req; } @@ -241,6 +247,13 @@ static void cli_smb2_create_fnum_done(struct tevent_req *subreq) tevent_req_done(req); } +static bool cli_smb2_create_fnum_cancel(struct tevent_req *req) +{ + struct cli_smb2_create_fnum_state *state = tevent_req_data( + req, struct cli_smb2_create_fnum_state); + return tevent_req_cancel(state->subreq); +} + NTSTATUS cli_smb2_create_fnum_recv(struct tevent_req *req, uint16_t *pfnum, struct smb_create_returns *cr) { -- 1.7.9.5 From 9bd3da33bac5c7a4629e18f9a78d8bf06cde1332 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 20 Jun 2014 10:38:10 +0000 Subject: [PATCH 09/14] libsmb: Make cli_ntcreate1 cancellable Signed-off-by: Volker Lendecke --- source3/libsmb/clifile.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 3ec5e9a..2ee6eda 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -1796,9 +1796,11 @@ struct cli_ntcreate1_state { uint16_t vwv[24]; uint16_t fnum; struct smb_create_returns cr; + struct tevent_req *subreq; }; static void cli_ntcreate1_done(struct tevent_req *subreq); +static bool cli_ntcreate1_cancel(struct tevent_req *req); static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, @@ -1866,6 +1868,10 @@ static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } tevent_req_set_callback(subreq, cli_ntcreate1_done, req); + + state->subreq = subreq; + tevent_req_set_cancel_fn(req, cli_ntcreate1_cancel); + return req; } @@ -1901,6 +1907,13 @@ static void cli_ntcreate1_done(struct tevent_req *subreq) tevent_req_done(req); } +static bool cli_ntcreate1_cancel(struct tevent_req *req) +{ + struct cli_ntcreate1_state *state = tevent_req_data( + req, struct cli_ntcreate1_state); + return tevent_req_cancel(state->subreq); +} + static NTSTATUS cli_ntcreate1_recv(struct tevent_req *req, uint16_t *pfnum, struct smb_create_returns *cr) -- 1.7.9.5 From 0f08d69cf8aacb533f532422c60a0c3bb38988a0 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 20 Jun 2014 10:38:36 +0000 Subject: [PATCH 10/14] libsmb: Make cli_ntcreate cancellable Signed-off-by: Volker Lendecke --- source3/libsmb/clifile.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 2ee6eda..61cb8b5 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -1937,9 +1937,11 @@ struct cli_ntcreate_state { struct smb_create_returns *cr); struct smb_create_returns cr; uint16_t fnum; + struct tevent_req *subreq; }; static void cli_ntcreate_done(struct tevent_req *subreq); +static bool cli_ntcreate_cancel(struct tevent_req *req); struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, @@ -1983,6 +1985,10 @@ struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } tevent_req_set_callback(subreq, cli_ntcreate_done, req); + + state->subreq = subreq; + tevent_req_set_cancel_fn(req, cli_ntcreate_cancel); + return req; } @@ -2002,6 +2008,13 @@ static void cli_ntcreate_done(struct tevent_req *subreq) tevent_req_done(req); } +static bool cli_ntcreate_cancel(struct tevent_req *req) +{ + struct cli_ntcreate_state *state = tevent_req_data( + req, struct cli_ntcreate_state); + return tevent_req_cancel(state->subreq); +} + NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *fnum, struct smb_create_returns *cr) { -- 1.7.9.5 From 8a7946418a636b451fecbb55c0929bd9b4774b86 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 20 Jun 2014 14:12:14 +0000 Subject: [PATCH 11/14] smbd: Store "struct deferred_open_record" instead of anonymous data on pml The main point is to get a talloc parent that will go away when the request is cancelled --- source3/smbd/globals.h | 13 +++++++------ source3/smbd/open.c | 24 ++++++++++++++++-------- source3/smbd/process.c | 30 +++++++++++------------------- source3/smbd/proto.h | 14 +++++++------- source3/smbd/smb2_create.c | 19 +++++++------------ 5 files changed, 48 insertions(+), 52 deletions(-) diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index cd99fe7..28e4f94 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -287,6 +287,8 @@ void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx, struct tevent_immediate *im, void *private_data); +struct deferred_open_record; + /* SMB1 -> SMB2 glue. */ void send_break_message_smb2(files_struct *fsp, int level); struct blocking_lock_record *get_pending_smb2req_blr(struct smbd_smb2_request *smb2req); @@ -310,7 +312,7 @@ void cancel_pending_lock_requests_by_fid_smb2(files_struct *fsp, int map_smb2_oplock_levels_to_samba(uint8_t in_oplock_level); bool get_deferred_open_message_state_smb2(struct smbd_smb2_request *smb2req, struct timeval *p_request_time, - void **pp_state); + struct deferred_open_record **open_rec); bool open_was_deferred_smb2(struct smbd_server_connection *sconn, uint64_t mid); void remove_deferred_open_message_smb2( @@ -318,11 +320,10 @@ void remove_deferred_open_message_smb2( bool schedule_deferred_open_message_smb2( struct smbd_server_connection *sconn, 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); + struct timeval request_time, + struct timeval timeout, + struct file_id id, + struct deferred_open_record *open_rec); struct smbXsrv_connection { struct smbd_server_connection *sconn; diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 237e90c..c0f4dea 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -1564,14 +1564,24 @@ static void defer_open(struct share_mode_lock *lck, struct smb_request *req, struct deferred_open_record *state) { + struct deferred_open_record *open_rec; + DEBUG(10,("defer_open_sharing_error: time [%u.%06u] adding deferred " "open entry for mid %llu\n", (unsigned int)request_time.tv_sec, (unsigned int)request_time.tv_usec, (unsigned long long)req->mid)); + open_rec = talloc(NULL, struct deferred_open_record); + if (open_rec == NULL) { + TALLOC_FREE(lck); + exit_server("talloc failed"); + } + + *open_rec = *state; + if (!push_deferred_open_message_smb(req, request_time, timeout, - state->id, (char *)state, sizeof(*state))) { + state->id, open_rec)) { TALLOC_FREE(lck); exit_server("push_deferred_open_message_smb failed"); } @@ -1930,11 +1940,9 @@ NTSTATUS smbd_calculate_access_mask(connection_struct *conn, Return true if this is a state pointer to an asynchronous create. ****************************************************************************/ -bool is_deferred_open_async(const void *ptr) +bool is_deferred_open_async(const struct deferred_open_record *rec) { - const struct deferred_open_record *state = (const struct deferred_open_record *)ptr; - - return state->async_open; + return rec->async_open; } static bool clear_ads(uint32_t create_disposition) @@ -2143,10 +2151,10 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, */ if (req) { - void *ptr; + struct deferred_open_record *open_rec; if (get_deferred_open_message_state(req, &request_time, - &ptr)) { + &open_rec)) { /* Remember the absolute time of the original request with this mid. We'll use it later to see if this has timed out. */ @@ -2154,7 +2162,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, /* If it was an async create retry, the file didn't exist. */ - if (is_deferred_open_async(ptr)) { + if (is_deferred_open_async(open_rec)) { SET_STAT_INVALID(smb_fname->st); file_existed = false; } diff --git a/source3/smbd/process.c b/source3/smbd/process.c index 8a1d1d6..b1d522d 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -52,7 +52,7 @@ struct pending_message_list { bool encrypted; bool processed; DATA_BLOB buf; - DATA_BLOB private_data; + struct deferred_open_record *open_rec; }; static void construct_reply_common(struct smb_request *req, const char *inbuf, @@ -635,7 +635,7 @@ static void smbd_deferred_open_timer(struct tevent_context *ev, static bool push_queued_message(struct smb_request *req, struct timeval request_time, struct timeval end_time, - char *private_data, size_t private_len) + struct deferred_open_record *open_rec) { int msg_len = smb_len(req->inbuf) + 4; struct pending_message_list *msg; @@ -661,14 +661,8 @@ static bool push_queued_message(struct smb_request *req, msg->processed = false; SMB_PERFCOUNT_DEFER_OP(&req->pcd, &msg->pcd); - if (private_data) { - msg->private_data = data_blob_talloc(msg, private_data, - private_len); - if (msg->private_data.data == NULL) { - DEBUG(0,("push_message: malloc fail (3)\n")); - TALLOC_FREE(msg); - return False; - } + if (open_rec) { + msg->open_rec = talloc_move(msg, &open_rec); } #if 0 @@ -828,14 +822,14 @@ static struct pending_message_list *get_deferred_open_message_smb( bool get_deferred_open_message_state(struct smb_request *smbreq, struct timeval *p_request_time, - void **pp_state) + struct deferred_open_record **open_rec) { struct pending_message_list *pml; if (smbreq->sconn->using_smb2) { return get_deferred_open_message_state_smb2(smbreq->smb2req, p_request_time, - pp_state); + open_rec); } pml = get_deferred_open_message_smb(smbreq->sconn, smbreq->mid); @@ -845,8 +839,8 @@ bool get_deferred_open_message_state(struct smb_request *smbreq, if (p_request_time) { *p_request_time = pml->request_time; } - if (pp_state) { - *pp_state = (void *)pml->private_data.data; + if (open_rec != NULL) { + *open_rec = pml->open_rec; } return true; } @@ -860,7 +854,7 @@ 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 deferred_open_record *open_rec) { struct timeval end_time; @@ -869,8 +863,7 @@ bool push_deferred_open_message_smb(struct smb_request *req, request_time, timeout, id, - private_data, - priv_len); + open_rec); } if (req->unread_bytes) { @@ -890,8 +883,7 @@ bool push_deferred_open_message_smb(struct smb_request *req, (unsigned int)end_time.tv_sec, (unsigned int)end_time.tv_usec)); - return push_queued_message(req, request_time, end_time, - private_data, priv_len); + return push_queued_message(req, request_time, end_time, open_rec); } static void smbd_sig_term_handler(struct tevent_context *ev, diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index 1e17f5b..b25ef7b 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -620,7 +620,8 @@ NTSTATUS change_dir_owner_to_parent(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf); bool is_stat_open(uint32 access_mask); -bool is_deferred_open_async(const void *ptr); +struct deferred_open_record; +bool is_deferred_open_async(const struct deferred_open_record *rec); NTSTATUS create_directory(connection_struct *conn, struct smb_request *req, struct smb_filename *smb_dname); void msg_file_was_renamed(struct messaging_context *msg, @@ -764,13 +765,12 @@ bool schedule_deferred_open_message_smb(struct smbd_server_connection *sconn, bool open_was_deferred(struct smbd_server_connection *sconn, uint64_t mid); bool get_deferred_open_message_state(struct smb_request *smbreq, struct timeval *p_request_time, - void **pp_state); + struct deferred_open_record **open_rec); 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 request_time, + struct timeval timeout, + struct file_id id, + struct deferred_open_record *open_rec); NTSTATUS allow_new_trans(struct trans_state *list, uint64_t mid); void reply_outbuf(struct smb_request *req, uint8 num_words, uint32 num_bytes); void smb_request_done(struct smb_request *req); diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c index 4e2e6bc..976e81a 100644 --- a/source3/smbd/smb2_create.c +++ b/source3/smbd/smb2_create.c @@ -382,7 +382,7 @@ struct smbd_smb2_create_state { struct tevent_immediate *im; struct timeval request_time; struct file_id id; - DATA_BLOB private_data; + struct deferred_open_record *open_rec; uint8_t out_oplock_level; uint32_t out_create_action; struct timespec out_creation_ts; @@ -1177,7 +1177,7 @@ static NTSTATUS smbd_smb2_create_recv(struct tevent_req *req, bool get_deferred_open_message_state_smb2(struct smbd_smb2_request *smb2req, struct timeval *p_request_time, - void **pp_state) + struct deferred_open_record **open_rec) { struct smbd_smb2_create_state *state = NULL; struct tevent_req *req = NULL; @@ -1199,8 +1199,8 @@ bool get_deferred_open_message_state_smb2(struct smbd_smb2_request *smb2req, if (p_request_time) { *p_request_time = state->request_time; } - if (pp_state) { - *pp_state = (void *)state->private_data.data; + if (open_rec != NULL) { + *open_rec = state->open_rec; } return true; } @@ -1409,7 +1409,7 @@ static bool smbd_smb2_create_cancel(struct tevent_req *req) smb2req = state->smb2req; mid = get_mid_from_smb2req(smb2req); - if (is_deferred_open_async(state->private_data.data)) { + if (is_deferred_open_async(state->open_rec)) { /* Can't cancel an async create. */ return false; } @@ -1425,8 +1425,7 @@ 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) + struct deferred_open_record *open_rec) { struct tevent_req *req = NULL; struct smbd_smb2_create_state *state = NULL; @@ -1445,11 +1444,7 @@ bool push_deferred_open_message_smb2(struct smbd_smb2_request *smb2req, } state->id = id; state->request_time = request_time; - state->private_data = data_blob_talloc(state, private_data, - priv_len); - if (!state->private_data.data) { - return false; - } + state->open_rec = talloc_move(state, &open_rec); /* Re-schedule us to retry on timer expiry. */ end_time = timeval_sum(&request_time, &timeout); -- 1.7.9.5 From f3b6f536f8b7e4c6b825cd9af843133470b227b0 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 20 Jun 2014 14:15:19 +0000 Subject: [PATCH 12/14] smbd: First watch, then defer --- source3/smbd/open.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/source3/smbd/open.c b/source3/smbd/open.c index c0f4dea..9cbc046 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -1580,11 +1580,6 @@ static void defer_open(struct share_mode_lock *lck, *open_rec = *state; - if (!push_deferred_open_message_smb(req, request_time, timeout, - state->id, open_rec)) { - TALLOC_FREE(lck); - exit_server("push_deferred_open_message_smb failed"); - } if (lck) { struct defer_open_state *watch_state; struct tevent_req *watch_req; @@ -1614,6 +1609,12 @@ static void defer_open(struct share_mode_lock *lck, timeval_sum(&request_time, &timeout)); SMB_ASSERT(ret); } + + if (!push_deferred_open_message_smb(req, request_time, timeout, + state->id, open_rec)) { + TALLOC_FREE(lck); + exit_server("push_deferred_open_message_smb failed"); + } } static void defer_open_done(struct tevent_req *req) -- 1.7.9.5 From 977862908a4a93280506d72ef2f1d85683d297b0 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 20 Jun 2014 14:15:54 +0000 Subject: [PATCH 13/14] smbd: Fix bug 10593 --- source3/smbd/open.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 9cbc046..b913c9c 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -1585,7 +1585,7 @@ static void defer_open(struct share_mode_lock *lck, struct tevent_req *watch_req; bool ret; - watch_state = talloc(req->sconn, struct defer_open_state); + watch_state = talloc(open_rec, struct defer_open_state); if (watch_state == NULL) { exit_server("talloc failed"); } -- 1.7.9.5 From 43489f04492811e4f484ebf55d244e34b2b1ee67 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 19 Jun 2014 14:37:40 +0000 Subject: [PATCH 14/14] torture3: Reproducer for bug 10593 We panic if we get an oplock break response for a cancelled create request --- source3/torture/proto.h | 1 + source3/torture/test_oplock_cancel.c | 159 ++++++++++++++++++++++++++++++++++ source3/torture/torture.c | 1 + source3/wscript_build | 1 + 4 files changed, 162 insertions(+) create mode 100644 source3/torture/test_oplock_cancel.c diff --git a/source3/torture/proto.h b/source3/torture/proto.h index 20c1110..08790c7 100644 --- a/source3/torture/proto.h +++ b/source3/torture/proto.h @@ -116,5 +116,6 @@ bool run_bench_pthreadpool(int dummy); bool run_messaging_read1(int dummy); bool run_messaging_read2(int dummy); bool run_messaging_read3(int dummy); +bool run_oplock_cancel(int dummy); #endif /* __TORTURE_H__ */ diff --git a/source3/torture/test_oplock_cancel.c b/source3/torture/test_oplock_cancel.c new file mode 100644 index 0000000..aa4218a --- /dev/null +++ b/source3/torture/test_oplock_cancel.c @@ -0,0 +1,159 @@ +/* + Unix SMB/CIFS implementation. + Test cleanup behaviour + Copyright (C) Volker Lendecke 2011 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "locking/proto.h" +#include "torture/proto.h" +#include "system/filesys.h" +#include "system/select.h" +#include "libsmb/libsmb.h" +#include "libcli/smb/smbXcli_base.h" +#include "libcli/security/security.h" +#include "lib/util/tevent_ntstatus.h" + +struct create_cancel_state { + uint8_t dummy; +}; + +static void create_cancel_done(struct tevent_req *subreq); + +static struct tevent_req *create_cancel_send( + TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct cli_state *cli, const char *fname) +{ + struct tevent_req *req, *subreq; + struct create_cancel_state *state; + + req = tevent_req_create(mem_ctx, &state, struct create_cancel_state); + if (req == NULL) { + return NULL; + } + + subreq = cli_ntcreate_send( + mem_ctx, ev, cli, fname, 0, FILE_GENERIC_READ, + FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN_IF, 0, 0); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + if (!tevent_req_cancel(subreq)) { + tevent_req_oom(req); + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, create_cancel_done, req); + return req; +} + +static void create_cancel_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + NTSTATUS status; + + status = cli_ntcreate_recv(subreq, NULL, NULL); + TALLOC_FREE(subreq); + if (!NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) { + if (NT_STATUS_IS_OK(status)) { + status = NT_STATUS_UNSUCCESSFUL; + } + tevent_req_nterror(req, status); + return; + } + tevent_req_done(req); +} + +static NTSTATUS create_cancel_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); +} + +static NTSTATUS create_cancel(struct cli_state *cli, const char *fname) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct tevent_context *ev; + struct tevent_req *req; + NTSTATUS status = NT_STATUS_NO_MEMORY; + + ev = samba_tevent_context_init(frame); + if (ev == NULL) { + goto fail; + } + req = create_cancel_send(frame, ev, cli, fname); + if (req == NULL) { + goto fail; + } + if (!tevent_req_poll_ntstatus(req, ev, &status)) { + goto fail; + } + status = create_cancel_recv(req); + fail: + TALLOC_FREE(frame); + return status; +} + +bool run_oplock_cancel(int dummy) +{ + struct cli_state *cli1, *cli2; + const char *fname = "oplock-cancel"; + uint16_t fnum1; + NTSTATUS status; + + lp_set_cmdline("client max protocol", "smb3"); + + if (!torture_open_connection(&cli1, 0)) { + return false; + } + cli1->use_oplocks = true; + + if (!torture_open_connection(&cli2, 0)) { + return false; + } + cli2->use_oplocks = true; + + status = cli_ntcreate( + cli1, fname, 0, FILE_GENERIC_READ, FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN_IF, 0, 0, + &fnum1, NULL); + if (!NT_STATUS_IS_OK(status)) { + d_printf("cli_ntcreate failed: %s\n", nt_errstr(status)); + return false; + } + + status = create_cancel(cli2, fname); + if (!NT_STATUS_IS_OK(status)) { + d_printf("create_cancel failed: %s\n", nt_errstr(status)); + return false; + } + + TALLOC_FREE(cli1); + + /* + * Give cli1's smbd time to inform cli2's smbd + */ + smb_msleep(5000); + + status = cli_unlink(cli2, fname, + FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN); + if (!NT_STATUS_IS_OK(status)) { + d_printf("cli_unlink failed: %s\n", nt_errstr(status)); + return false; + } + + return true; +} diff --git a/source3/torture/torture.c b/source3/torture/torture.c index cea9089..f5f8f86 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -9596,6 +9596,7 @@ static struct { { "CLEANUP2", run_cleanup2 }, { "CLEANUP3", run_cleanup3 }, { "CLEANUP4", run_cleanup4 }, + { "OPLOCK-CANCEL", run_oplock_cancel }, { "LOCAL-SUBSTITUTE", run_local_substitute, 0}, { "LOCAL-GENCACHE", run_local_gencache, 0}, { "LOCAL-TALLOC-DICT", run_local_talloc_dict, 0}, diff --git a/source3/wscript_build b/source3/wscript_build index 5002f93..6f668ba 100755 --- a/source3/wscript_build +++ b/source3/wscript_build @@ -1253,6 +1253,7 @@ bld.SAMBA3_BINARY('smbtorture' + bld.env.suffix3, torture/test_dbwrap_ctdb.c torture/test_buffersize.c torture/test_messaging_read.c + torture/test_oplock_cancel.c torture/t_strappend.c torture/bench_pthreadpool.c torture/wbc_async.c''', -- 1.7.9.5