smbtorture: add a test for recursive h-lease break when renaming
[samba4-gss.git] / source3 / smbd / smb2_ioctl_smbtorture.c
blob9a259fb0dbfa9d12d8c25e7adc7d04d182358fd2
1 /*
2 Unix SMB/CIFS implementation.
3 Core SMB2 server
5 Copyright (C) Stefan Metzmacher 2009
6 Copyright (C) Jeremy Allison 2021
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "smbd/smbd.h"
24 #include "smbd/globals.h"
25 #include "../libcli/smb/smb_common.h"
26 #include "../lib/util/tevent_ntstatus.h"
27 #include "include/ntioctl.h"
28 #include "smb2_ioctl_private.h"
29 #include "librpc/gen_ndr/ioctl.h"
31 #undef DBGC_CLASS
32 #define DBGC_CLASS DBGC_SMB2
34 struct async_sleep_state {
35 struct smbd_server_connection *sconn;
36 files_struct *fsp;
39 static void smbd_fsctl_torture_async_sleep_done(struct tevent_req *subreq);
41 static struct tevent_req *smbd_fsctl_torture_async_sleep_send(
42 TALLOC_CTX *mem_ctx,
43 struct tevent_context *ev,
44 files_struct *fsp,
45 uint8_t msecs)
47 struct async_sleep_state *state = NULL;
48 struct tevent_req *subreq = NULL;
49 bool ok;
51 subreq = tevent_req_create(mem_ctx,
52 &state,
53 struct async_sleep_state);
54 if (!subreq) {
55 return NULL;
59 * Store the conn separately, as the test is to
60 * see if fsp is still a valid pointer, so we can't
61 * do anything other than test it for entry in the
62 * open files on this server connection.
64 state->sconn = fsp->conn->sconn;
65 state->fsp = fsp;
68 * Just wait for the specified number of micro seconds,
69 * to allow the client time to close fsp.
71 ok = tevent_req_set_endtime(subreq,
72 ev,
73 timeval_current_ofs(0, msecs));
74 if (!ok) {
75 tevent_req_nterror(subreq, NT_STATUS_NO_MEMORY);
76 return tevent_req_post(subreq, ev);
79 return subreq;
82 static files_struct *find_my_fsp(struct files_struct *fsp,
83 void *private_data)
85 struct files_struct *myfsp = (struct files_struct *)private_data;
87 if (fsp == myfsp) {
88 return myfsp;
90 return NULL;
93 static bool smbd_fsctl_torture_async_sleep_recv(struct tevent_req *subreq)
95 tevent_req_received(subreq);
96 return true;
99 static void smbd_fsctl_torture_async_sleep_done(struct tevent_req *subreq)
101 struct files_struct *found_fsp;
102 struct tevent_req *req = tevent_req_callback_data(
103 subreq,
104 struct tevent_req);
105 struct async_sleep_state *state = tevent_req_data(
106 subreq,
107 struct async_sleep_state);
109 /* Does state->fsp still exist on state->sconn ? */
110 found_fsp = files_forall(state->sconn,
111 find_my_fsp,
112 state->fsp);
114 smbd_fsctl_torture_async_sleep_recv(subreq);
115 TALLOC_FREE(subreq);
117 if (found_fsp == NULL) {
119 * We didn't find it - return an error to the
120 * smb2 ioctl request. Use NT_STATUS_FILE_CLOSED so
121 * the client can tell the difference between
122 * a bad fsp handle and
124 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14769
126 * This request should block file closure until it
127 * has completed.
129 tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
130 return;
132 tevent_req_done(req);
135 struct tevent_req *smb2_ioctl_smbtorture(uint32_t ctl_code,
136 struct tevent_context *ev,
137 struct tevent_req *req,
138 struct smbd_smb2_ioctl_state *state)
140 NTSTATUS status;
141 bool ok;
143 ok = lp_parm_bool(-1, "smbd", "FSCTL_SMBTORTURE", false);
144 if (!ok) {
145 goto not_supported;
148 switch (ctl_code) {
149 case FSCTL_SMBTORTURE_FORCE_UNACKED_TIMEOUT:
150 if (state->in_input.length != 0) {
151 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
152 return tevent_req_post(req, ev);
155 state->smb2req->xconn->ack.force_unacked_timeout = true;
156 tevent_req_done(req);
157 return tevent_req_post(req, ev);
159 case FSCTL_SMBTORTURE_IOCTL_RESPONSE_BODY_PADDING8:
160 if (state->in_input.length != 0) {
161 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
162 return tevent_req_post(req, ev);
165 if (state->in_max_output > 0) {
166 uint32_t size = state->in_max_output;
168 state->out_output = data_blob_talloc(state, NULL, size);
169 if (tevent_req_nomem(state->out_output.data, req)) {
170 return tevent_req_post(req, ev);
172 memset(state->out_output.data, 8, size);
175 state->body_padding = 8;
176 tevent_req_done(req);
177 return tevent_req_post(req, ev);
179 case FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8:
180 if (state->in_input.length != 0) {
181 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
182 return tevent_req_post(req, ev);
185 state->smb2req->xconn->smb2.smbtorture.read_body_padding = 8;
186 tevent_req_done(req);
187 return tevent_req_post(req, ev);
189 case FSCTL_SMBTORTURE_FSP_ASYNC_SLEEP: {
190 struct tevent_req *subreq = NULL;
192 /* Data is 1 byte of CVAL stored seconds to delay for. */
193 if (state->in_input.length != 1) {
194 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
195 return tevent_req_post(req, ev);
197 if (state->fsp == NULL) {
198 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
199 return tevent_req_post(req, ev);
202 subreq = smbd_fsctl_torture_async_sleep_send(
203 req,
205 state->fsp,
206 CVAL(state->in_input.data,0));
207 if (subreq == NULL) {
208 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
209 return tevent_req_post(req, ev);
211 tevent_req_set_callback(subreq,
212 smbd_fsctl_torture_async_sleep_done,
213 req);
214 return req;
217 default:
218 goto not_supported;
221 not_supported:
222 if (IS_IPC(state->smbreq->conn)) {
223 status = NT_STATUS_FS_DRIVER_REQUIRED;
224 } else {
225 status = NT_STATUS_INVALID_DEVICE_REQUEST;
228 tevent_req_nterror(req, status);
229 return tevent_req_post(req, ev);