Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Core SMB2 server
4 :
5 : Copyright (C) Stefan Metzmacher 2009
6 : Copyright (C) Jeremy Allison 2021
7 :
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.
12 :
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.
17 :
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/>.
20 : */
21 :
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"
30 :
31 : #undef DBGC_CLASS
32 : #define DBGC_CLASS DBGC_SMB2
33 :
34 : struct async_sleep_state {
35 : struct smbd_server_connection *sconn;
36 : files_struct *fsp;
37 : };
38 :
39 : static void smbd_fsctl_torture_async_sleep_done(struct tevent_req *subreq);
40 :
41 8 : 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)
46 : {
47 8 : struct async_sleep_state *state = NULL;
48 8 : struct tevent_req *subreq = NULL;
49 0 : bool ok;
50 :
51 8 : subreq = tevent_req_create(mem_ctx,
52 : &state,
53 : struct async_sleep_state);
54 8 : if (!subreq) {
55 0 : return NULL;
56 : }
57 :
58 : /*
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.
63 : */
64 8 : state->sconn = fsp->conn->sconn;
65 8 : state->fsp = fsp;
66 :
67 : /*
68 : * Just wait for the specified number of micro seconds,
69 : * to allow the client time to close fsp.
70 : */
71 8 : ok = tevent_req_set_endtime(subreq,
72 : ev,
73 : timeval_current_ofs(0, msecs));
74 8 : if (!ok) {
75 0 : tevent_req_nterror(subreq, NT_STATUS_NO_MEMORY);
76 0 : return tevent_req_post(subreq, ev);
77 : }
78 :
79 8 : return subreq;
80 : }
81 :
82 8 : static files_struct *find_my_fsp(struct files_struct *fsp,
83 : void *private_data)
84 : {
85 8 : struct files_struct *myfsp = (struct files_struct *)private_data;
86 :
87 8 : if (fsp == myfsp) {
88 8 : return myfsp;
89 : }
90 0 : return NULL;
91 : }
92 :
93 8 : static bool smbd_fsctl_torture_async_sleep_recv(struct tevent_req *subreq)
94 : {
95 8 : tevent_req_received(subreq);
96 8 : return true;
97 : }
98 :
99 8 : static void smbd_fsctl_torture_async_sleep_done(struct tevent_req *subreq)
100 : {
101 0 : struct files_struct *found_fsp;
102 8 : struct tevent_req *req = tevent_req_callback_data(
103 : subreq,
104 : struct tevent_req);
105 8 : struct async_sleep_state *state = tevent_req_data(
106 : subreq,
107 : struct async_sleep_state);
108 :
109 : /* Does state->fsp still exist on state->sconn ? */
110 8 : found_fsp = files_forall(state->sconn,
111 : find_my_fsp,
112 8 : state->fsp);
113 :
114 8 : smbd_fsctl_torture_async_sleep_recv(subreq);
115 8 : TALLOC_FREE(subreq);
116 :
117 8 : if (found_fsp == NULL) {
118 : /*
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
123 : *
124 : * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14769
125 : *
126 : * This request should block file closure until it
127 : * has completed.
128 : */
129 0 : tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
130 0 : return;
131 : }
132 8 : tevent_req_done(req);
133 : }
134 :
135 348 : 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)
139 : {
140 0 : NTSTATUS status;
141 0 : bool ok;
142 :
143 348 : ok = lp_parm_bool(-1, "smbd", "FSCTL_SMBTORTURE", false);
144 348 : if (!ok) {
145 0 : goto not_supported;
146 : }
147 :
148 348 : switch (ctl_code) {
149 328 : case FSCTL_SMBTORTURE_FORCE_UNACKED_TIMEOUT:
150 328 : if (state->in_input.length != 0) {
151 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
152 0 : return tevent_req_post(req, ev);
153 : }
154 :
155 328 : state->smb2req->xconn->ack.force_unacked_timeout = true;
156 328 : tevent_req_done(req);
157 328 : return tevent_req_post(req, ev);
158 :
159 8 : case FSCTL_SMBTORTURE_IOCTL_RESPONSE_BODY_PADDING8:
160 8 : if (state->in_input.length != 0) {
161 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
162 0 : return tevent_req_post(req, ev);
163 : }
164 :
165 8 : if (state->in_max_output > 0) {
166 8 : uint32_t size = state->in_max_output;
167 :
168 8 : state->out_output = data_blob_talloc(state, NULL, size);
169 8 : if (tevent_req_nomem(state->out_output.data, req)) {
170 0 : return tevent_req_post(req, ev);
171 : }
172 8 : memset(state->out_output.data, 8, size);
173 : }
174 :
175 8 : state->body_padding = 8;
176 8 : tevent_req_done(req);
177 8 : return tevent_req_post(req, ev);
178 :
179 4 : case FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8:
180 4 : if (state->in_input.length != 0) {
181 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
182 0 : return tevent_req_post(req, ev);
183 : }
184 :
185 4 : state->smb2req->xconn->smb2.smbtorture.read_body_padding = 8;
186 4 : tevent_req_done(req);
187 4 : return tevent_req_post(req, ev);
188 :
189 8 : case FSCTL_SMBTORTURE_FSP_ASYNC_SLEEP: {
190 8 : struct tevent_req *subreq = NULL;
191 :
192 : /* Data is 1 byte of CVAL stored seconds to delay for. */
193 8 : if (state->in_input.length != 1) {
194 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
195 0 : return tevent_req_post(req, ev);
196 : }
197 8 : if (state->fsp == NULL) {
198 0 : tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
199 0 : return tevent_req_post(req, ev);
200 : }
201 :
202 8 : subreq = smbd_fsctl_torture_async_sleep_send(
203 : req,
204 : ev,
205 : state->fsp,
206 8 : CVAL(state->in_input.data,0));
207 8 : if (subreq == NULL) {
208 0 : tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
209 0 : return tevent_req_post(req, ev);
210 : }
211 8 : tevent_req_set_callback(subreq,
212 : smbd_fsctl_torture_async_sleep_done,
213 : req);
214 8 : return req;
215 : }
216 :
217 0 : default:
218 0 : goto not_supported;
219 : }
220 :
221 0 : not_supported:
222 0 : if (IS_IPC(state->smbreq->conn)) {
223 0 : status = NT_STATUS_FS_DRIVER_REQUIRED;
224 : } else {
225 0 : status = NT_STATUS_INVALID_DEVICE_REQUEST;
226 : }
227 :
228 0 : tevent_req_nterror(req, status);
229 0 : return tevent_req_post(req, ev);
230 : }
|