]> git.samba.org - samba.git/blob - source3/smbd/smb2_ioctl_smbtorture.c
s3:utils: let smbstatus report anonymous signing/encryption explicitly
[samba.git] / source3 / smbd / smb2_ioctl_smbtorture.c
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 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         struct async_sleep_state *state = NULL;
48         struct tevent_req *subreq = NULL;
49         bool ok;
50
51         subreq = tevent_req_create(mem_ctx,
52                                 &state,
53                                 struct async_sleep_state);
54         if (!subreq) {
55                 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         state->sconn = fsp->conn->sconn;
65         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         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);
77         }
78
79         return subreq;
80 }
81
82 static files_struct *find_my_fsp(struct files_struct *fsp,
83                                  void *private_data)
84 {
85         struct files_struct *myfsp = (struct files_struct *)private_data;
86
87         if (fsp == myfsp) {
88                 return myfsp;
89         }
90         return NULL;
91 }
92
93 static bool smbd_fsctl_torture_async_sleep_recv(struct tevent_req *subreq)
94 {
95         tevent_req_received(subreq);
96         return true;
97 }
98
99 static void smbd_fsctl_torture_async_sleep_done(struct tevent_req *subreq)
100 {
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);
108
109         /* Does state->fsp still exist on state->sconn ? */
110         found_fsp = files_forall(state->sconn,
111                                  find_my_fsp,
112                                  state->fsp);
113
114         smbd_fsctl_torture_async_sleep_recv(subreq);
115         TALLOC_FREE(subreq);
116
117         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                 tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
130                 return;
131         }
132         tevent_req_done(req);
133 }
134
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)
139 {
140         NTSTATUS status;
141         bool ok;
142
143         ok = lp_parm_bool(-1, "smbd", "FSCTL_SMBTORTURE", false);
144         if (!ok) {
145                 goto not_supported;
146         }
147
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);
153                 }
154
155                 state->smb2req->xconn->ack.force_unacked_timeout = true;
156                 tevent_req_done(req);
157                 return tevent_req_post(req, ev);
158
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);
163                 }
164
165                 if (state->in_max_output > 0) {
166                         uint32_t size = state->in_max_output;
167
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);
171                         }
172                         memset(state->out_output.data, 8, size);
173                 }
174
175                 state->body_padding = 8;
176                 tevent_req_done(req);
177                 return tevent_req_post(req, ev);
178
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);
183                 }
184
185                 state->smb2req->xconn->smb2.smbtorture.read_body_padding = 8;
186                 tevent_req_done(req);
187                 return tevent_req_post(req, ev);
188
189         case FSCTL_SMBTORTURE_FSP_ASYNC_SLEEP: {
190                 struct tevent_req *subreq = NULL;
191
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);
196                 }
197                 if (state->fsp == NULL) {
198                         tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
199                         return tevent_req_post(req, ev);
200                 }
201
202                 subreq = smbd_fsctl_torture_async_sleep_send(
203                                                 req,
204                                                 ev,
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);
210                 }
211                 tevent_req_set_callback(subreq,
212                                         smbd_fsctl_torture_async_sleep_done,
213                                         req);
214                 return req;
215         }
216
217         default:
218                 goto not_supported;
219         }
220
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;
226         }
227
228         tevent_req_nterror(req, status);
229         return tevent_req_post(req, ev);
230 }