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 2010
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 "printing.h"
24 : #include "smbd/smbd.h"
25 : #include "smbd/globals.h"
26 : #include "smbd/smbXsrv_open.h"
27 : #include "../libcli/smb/smb_common.h"
28 : #include "../librpc/gen_ndr/ndr_security.h"
29 : #include "../librpc/gen_ndr/ndr_smb2_lease_struct.h"
30 : #include "../lib/util/tevent_ntstatus.h"
31 : #include "messages.h"
32 : #include "lib/util_ea.h"
33 : #include "source3/passdb/lookup_sid.h"
34 :
35 : #undef DBGC_CLASS
36 : #define DBGC_CLASS DBGC_SMB2
37 :
38 14149 : int map_smb2_oplock_levels_to_samba(uint8_t in_oplock_level)
39 : {
40 14149 : switch(in_oplock_level) {
41 14025 : case SMB2_OPLOCK_LEVEL_NONE:
42 14025 : return NO_OPLOCK;
43 0 : case SMB2_OPLOCK_LEVEL_II:
44 0 : return LEVEL_II_OPLOCK;
45 0 : case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
46 0 : return EXCLUSIVE_OPLOCK;
47 124 : case SMB2_OPLOCK_LEVEL_BATCH:
48 124 : return BATCH_OPLOCK;
49 0 : case SMB2_OPLOCK_LEVEL_LEASE:
50 0 : return LEASE_OPLOCK;
51 0 : default:
52 0 : DEBUG(2,("map_smb2_oplock_levels_to_samba: "
53 : "unknown level %u\n",
54 : (unsigned int)in_oplock_level));
55 0 : return NO_OPLOCK;
56 : }
57 : }
58 :
59 16658 : static uint8_t map_samba_oplock_levels_to_smb2(int oplock_type)
60 : {
61 16658 : if (BATCH_OPLOCK_TYPE(oplock_type)) {
62 124 : return SMB2_OPLOCK_LEVEL_BATCH;
63 16534 : } else if (EXCLUSIVE_OPLOCK_TYPE(oplock_type)) {
64 0 : return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
65 16534 : } else if (oplock_type == LEVEL_II_OPLOCK) {
66 0 : return SMB2_OPLOCK_LEVEL_II;
67 16534 : } else if (oplock_type == LEASE_OPLOCK) {
68 0 : return SMB2_OPLOCK_LEVEL_LEASE;
69 : } else {
70 16534 : return SMB2_OPLOCK_LEVEL_NONE;
71 : }
72 : }
73 :
74 : /*
75 : MS-FSA 2.1.5.1 Server Requests an Open of a File
76 : Trailing '/' or '\\' checker.
77 : Must be done before the filename parser removes any
78 : trailing characters. If we decide to add this to SMB1
79 : NTCreate processing we can make this public.
80 :
81 : Note this is Windows pathname processing only. When
82 : POSIX pathnames are added to SMB2 this will not apply.
83 : */
84 :
85 15050 : static NTSTATUS windows_name_trailing_check(const char *name,
86 : uint32_t create_options)
87 : {
88 15050 : size_t name_len = strlen(name);
89 : char trail_c;
90 :
91 15050 : if (name_len <= 1) {
92 6063 : return NT_STATUS_OK;
93 : }
94 :
95 8987 : trail_c = name[name_len-1];
96 :
97 : /*
98 : * Trailing '/' is always invalid.
99 : */
100 8987 : if (trail_c == '/') {
101 0 : return NT_STATUS_OBJECT_NAME_INVALID;
102 : }
103 :
104 8987 : if (create_options & FILE_NON_DIRECTORY_FILE) {
105 917 : if (trail_c == '\\') {
106 0 : return NT_STATUS_OBJECT_NAME_INVALID;
107 : }
108 : }
109 8987 : return NT_STATUS_OK;
110 : }
111 :
112 : static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
113 : struct tevent_context *ev,
114 : struct smbd_smb2_request *smb2req,
115 : uint8_t in_oplock_level,
116 : uint32_t in_impersonation_level,
117 : uint32_t in_desired_access,
118 : uint32_t in_file_attributes,
119 : uint32_t in_share_access,
120 : uint32_t in_create_disposition,
121 : uint32_t in_create_options,
122 : const char *in_name,
123 : struct smb2_create_blobs in_context_blobs);
124 : static NTSTATUS smbd_smb2_create_recv(struct tevent_req *req,
125 : TALLOC_CTX *mem_ctx,
126 : uint8_t *out_oplock_level,
127 : uint32_t *out_create_action,
128 : struct timespec *out_creation_ts,
129 : struct timespec *out_last_access_ts,
130 : struct timespec *out_last_write_ts,
131 : struct timespec *out_change_ts,
132 : uint64_t *out_allocation_size,
133 : uint64_t *out_end_of_file,
134 : uint32_t *out_file_attributes,
135 : uint64_t *out_file_id_persistent,
136 : uint64_t *out_file_id_volatile,
137 : struct smb2_create_blobs *out_context_blobs);
138 :
139 : static void smbd_smb2_request_create_done(struct tevent_req *tsubreq);
140 18476 : NTSTATUS smbd_smb2_request_process_create(struct smbd_smb2_request *smb2req)
141 : {
142 : const uint8_t *inbody;
143 : const struct iovec *indyniov;
144 : uint8_t in_oplock_level;
145 : uint32_t in_impersonation_level;
146 : uint32_t in_desired_access;
147 : uint32_t in_file_attributes;
148 : uint32_t in_share_access;
149 : uint32_t in_create_disposition;
150 : uint32_t in_create_options;
151 : uint16_t in_name_offset;
152 : uint16_t in_name_length;
153 : DATA_BLOB in_name_buffer;
154 : char *in_name_string;
155 : size_t in_name_string_size;
156 18476 : uint32_t name_offset = 0;
157 18476 : uint32_t name_available_length = 0;
158 : uint32_t in_context_offset;
159 : uint32_t in_context_length;
160 : DATA_BLOB in_context_buffer;
161 : struct smb2_create_blobs in_context_blobs;
162 18476 : uint32_t context_offset = 0;
163 18476 : uint32_t context_available_length = 0;
164 : uint32_t dyn_offset;
165 : NTSTATUS status;
166 : bool ok;
167 : struct tevent_req *tsubreq;
168 :
169 18476 : status = smbd_smb2_request_verify_sizes(smb2req, 0x39);
170 18476 : if (!NT_STATUS_IS_OK(status)) {
171 0 : return smbd_smb2_request_error(smb2req, status);
172 : }
173 18476 : inbody = SMBD_SMB2_IN_BODY_PTR(smb2req);
174 :
175 18476 : in_oplock_level = CVAL(inbody, 0x03);
176 18476 : in_impersonation_level = IVAL(inbody, 0x04);
177 18476 : in_desired_access = IVAL(inbody, 0x18);
178 18476 : in_file_attributes = IVAL(inbody, 0x1C);
179 18476 : in_share_access = IVAL(inbody, 0x20);
180 18476 : in_create_disposition = IVAL(inbody, 0x24);
181 18476 : in_create_options = IVAL(inbody, 0x28);
182 18476 : in_name_offset = SVAL(inbody, 0x2C);
183 18476 : in_name_length = SVAL(inbody, 0x2E);
184 18476 : in_context_offset = IVAL(inbody, 0x30);
185 18476 : in_context_length = IVAL(inbody, 0x34);
186 :
187 : /*
188 : * First check if the dynamic name and context buffers
189 : * are correctly specified.
190 : *
191 : * Note: That we don't check if the name and context buffers
192 : * overlap
193 : */
194 :
195 18476 : dyn_offset = SMB2_HDR_BODY + SMBD_SMB2_IN_BODY_LEN(smb2req);
196 :
197 18476 : if (in_name_offset == 0 && in_name_length == 0) {
198 : /* This is ok */
199 0 : name_offset = 0;
200 18476 : } else if (in_name_offset < dyn_offset) {
201 0 : return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
202 : } else {
203 18476 : name_offset = in_name_offset - dyn_offset;
204 : }
205 :
206 18476 : indyniov = SMBD_SMB2_IN_DYN_IOV(smb2req);
207 :
208 18476 : if (name_offset > indyniov->iov_len) {
209 0 : return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
210 : }
211 :
212 18476 : name_available_length = indyniov->iov_len - name_offset;
213 :
214 18476 : if (in_name_length > name_available_length) {
215 0 : return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
216 : }
217 :
218 18476 : in_name_buffer.data = (uint8_t *)indyniov->iov_base + name_offset;
219 18476 : in_name_buffer.length = in_name_length;
220 :
221 18476 : if (in_context_offset == 0 && in_context_length == 0) {
222 : /* This is ok */
223 18431 : context_offset = 0;
224 45 : } else if (in_context_offset < dyn_offset) {
225 0 : return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
226 : } else {
227 45 : context_offset = in_context_offset - dyn_offset;
228 : }
229 :
230 18476 : if (context_offset > indyniov->iov_len) {
231 0 : return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
232 : }
233 :
234 18476 : context_available_length = indyniov->iov_len - context_offset;
235 :
236 18476 : if (in_context_length > context_available_length) {
237 0 : return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
238 : }
239 :
240 18476 : in_context_buffer.data = (uint8_t *)indyniov->iov_base +
241 : context_offset;
242 18476 : in_context_buffer.length = in_context_length;
243 :
244 : /*
245 : * Now interpret the name and context buffers
246 : */
247 :
248 18476 : ok = convert_string_talloc(smb2req, CH_UTF16, CH_UNIX,
249 18476 : in_name_buffer.data,
250 : in_name_buffer.length,
251 : &in_name_string,
252 : &in_name_string_size);
253 18476 : if (!ok) {
254 0 : return smbd_smb2_request_error(smb2req, NT_STATUS_ILLEGAL_CHARACTER);
255 : }
256 :
257 18476 : if (in_name_buffer.length == 0) {
258 6063 : in_name_string_size = 0;
259 : }
260 :
261 18476 : if (strlen(in_name_string) != in_name_string_size) {
262 0 : return smbd_smb2_request_error(smb2req, NT_STATUS_OBJECT_NAME_INVALID);
263 : }
264 :
265 18476 : ZERO_STRUCT(in_context_blobs);
266 18476 : status = smb2_create_blob_parse(smb2req, in_context_buffer, &in_context_blobs);
267 18476 : if (!NT_STATUS_IS_OK(status)) {
268 0 : return smbd_smb2_request_error(smb2req, status);
269 : }
270 :
271 18476 : tsubreq = smbd_smb2_create_send(smb2req,
272 18476 : smb2req->sconn->ev_ctx,
273 : smb2req,
274 : in_oplock_level,
275 : in_impersonation_level,
276 : in_desired_access,
277 : in_file_attributes,
278 : in_share_access,
279 : in_create_disposition,
280 : in_create_options,
281 : in_name_string,
282 : in_context_blobs);
283 18476 : if (tsubreq == NULL) {
284 0 : smb2req->subreq = NULL;
285 0 : return smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY);
286 : }
287 18476 : tevent_req_set_callback(tsubreq, smbd_smb2_request_create_done, smb2req);
288 :
289 18476 : return smbd_smb2_request_pending_queue(smb2req, tsubreq, 500);
290 : }
291 :
292 912 : static uint64_t get_mid_from_smb2req(struct smbd_smb2_request *smb2req)
293 : {
294 912 : uint8_t *reqhdr = SMBD_SMB2_OUT_HDR_PTR(smb2req);
295 912 : return BVAL(reqhdr, SMB2_HDR_MESSAGE_ID);
296 : }
297 :
298 18476 : static void smbd_smb2_request_create_done(struct tevent_req *tsubreq)
299 : {
300 18476 : struct smbd_smb2_request *smb2req = tevent_req_callback_data(tsubreq,
301 : struct smbd_smb2_request);
302 : DATA_BLOB outbody;
303 : DATA_BLOB outdyn;
304 18476 : uint8_t out_oplock_level = 0;
305 18476 : uint32_t out_create_action = 0;
306 18476 : connection_struct *conn = smb2req->tcon->compat;
307 18476 : struct timespec out_creation_ts = { 0, };
308 18476 : struct timespec out_last_access_ts = { 0, };
309 18476 : struct timespec out_last_write_ts = { 0, };
310 18476 : struct timespec out_change_ts = { 0, };
311 18476 : uint64_t out_allocation_size = 0;
312 18476 : uint64_t out_end_of_file = 0;
313 18476 : uint32_t out_file_attributes = 0;
314 18476 : uint64_t out_file_id_persistent = 0;
315 18476 : uint64_t out_file_id_volatile = 0;
316 : struct smb2_create_blobs out_context_blobs;
317 : DATA_BLOB out_context_buffer;
318 18476 : uint16_t out_context_buffer_offset = 0;
319 : NTSTATUS status;
320 : NTSTATUS error; /* transport error */
321 :
322 18476 : status = smbd_smb2_create_recv(tsubreq,
323 : smb2req,
324 : &out_oplock_level,
325 : &out_create_action,
326 : &out_creation_ts,
327 : &out_last_access_ts,
328 : &out_last_write_ts,
329 : &out_change_ts,
330 : &out_allocation_size,
331 : &out_end_of_file,
332 : &out_file_attributes,
333 : &out_file_id_persistent,
334 : &out_file_id_volatile,
335 : &out_context_blobs);
336 18476 : if (!NT_STATUS_IS_OK(status)) {
337 1818 : if (smbd_smb2_is_compound(smb2req)) {
338 0 : smb2req->compound_create_err = status;
339 : }
340 1818 : error = smbd_smb2_request_error(smb2req, status);
341 1818 : if (!NT_STATUS_IS_OK(error)) {
342 0 : smbd_server_connection_terminate(smb2req->xconn,
343 : nt_errstr(error));
344 1818 : return;
345 : }
346 1818 : return;
347 : }
348 :
349 16658 : status = smb2_create_blob_push(smb2req, &out_context_buffer, out_context_blobs);
350 16658 : if (!NT_STATUS_IS_OK(status)) {
351 0 : error = smbd_smb2_request_error(smb2req, status);
352 0 : if (!NT_STATUS_IS_OK(error)) {
353 0 : smbd_server_connection_terminate(smb2req->xconn,
354 : nt_errstr(error));
355 0 : return;
356 : }
357 0 : return;
358 : }
359 :
360 16658 : if (out_context_buffer.length > 0) {
361 1 : out_context_buffer_offset = SMB2_HDR_BODY + 0x58;
362 : }
363 :
364 16658 : outbody = smbd_smb2_generate_outbody(smb2req, 0x58);
365 16658 : if (outbody.data == NULL) {
366 0 : error = smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY);
367 0 : if (!NT_STATUS_IS_OK(error)) {
368 0 : smbd_server_connection_terminate(smb2req->xconn,
369 : nt_errstr(error));
370 0 : return;
371 : }
372 0 : return;
373 : }
374 :
375 16658 : SSVAL(outbody.data, 0x00, 0x58 + 1); /* struct size */
376 16658 : SCVAL(outbody.data, 0x02,
377 : out_oplock_level); /* oplock level */
378 16658 : SCVAL(outbody.data, 0x03, 0); /* reserved */
379 16658 : SIVAL(outbody.data, 0x04,
380 : out_create_action); /* create action */
381 16658 : put_long_date_full_timespec(conn->ts_res,
382 16658 : (char *)outbody.data + 0x08,
383 : &out_creation_ts); /* creation time */
384 16658 : put_long_date_full_timespec(conn->ts_res,
385 16658 : (char *)outbody.data + 0x10,
386 : &out_last_access_ts); /* last access time */
387 16658 : put_long_date_full_timespec(conn->ts_res,
388 16658 : (char *)outbody.data + 0x18,
389 : &out_last_write_ts); /* last write time */
390 16658 : put_long_date_full_timespec(conn->ts_res,
391 16658 : (char *)outbody.data + 0x20,
392 : &out_change_ts); /* change time */
393 16658 : SBVAL(outbody.data, 0x28,
394 : out_allocation_size); /* allocation size */
395 16658 : SBVAL(outbody.data, 0x30,
396 : out_end_of_file); /* end of file */
397 16658 : SIVAL(outbody.data, 0x38,
398 : out_file_attributes); /* file attributes */
399 16658 : SIVAL(outbody.data, 0x3C, 0); /* reserved */
400 16658 : SBVAL(outbody.data, 0x40,
401 : out_file_id_persistent); /* file id (persistent) */
402 16658 : SBVAL(outbody.data, 0x48,
403 : out_file_id_volatile); /* file id (volatile) */
404 16658 : SIVAL(outbody.data, 0x50,
405 : out_context_buffer_offset); /* create contexts offset */
406 16658 : SIVAL(outbody.data, 0x54,
407 : out_context_buffer.length); /* create contexts length */
408 :
409 16658 : outdyn = out_context_buffer;
410 :
411 16658 : error = smbd_smb2_request_done(smb2req, outbody, &outdyn);
412 16658 : if (!NT_STATUS_IS_OK(error)) {
413 0 : smbd_server_connection_terminate(smb2req->xconn,
414 : nt_errstr(error));
415 0 : return;
416 : }
417 : }
418 :
419 0 : static bool smb2_lease_key_valid(const struct smb2_lease_key *key)
420 : {
421 0 : return ((key->data[0] != 0) || (key->data[1] != 0));
422 : }
423 :
424 0 : static NTSTATUS smbd_smb2_create_durable_lease_check(struct smb_request *smb1req,
425 : const char *requested_filename, const struct files_struct *fsp,
426 : const struct smb2_lease *lease_ptr)
427 : {
428 0 : struct files_struct *dirfsp = NULL;
429 0 : char *filename = NULL;
430 0 : struct smb_filename *smb_fname = NULL;
431 : uint32_t ucf_flags;
432 0 : NTTIME twrp = fsp->fsp_name->twrp;
433 : NTSTATUS status;
434 0 : bool is_dfs = (smb1req->flags2 & FLAGS2_DFS_PATHNAMES);
435 :
436 0 : if (lease_ptr == NULL) {
437 0 : if (fsp->oplock_type != LEASE_OPLOCK) {
438 0 : return NT_STATUS_OK;
439 : }
440 0 : DEBUG(10, ("Reopened file has lease, but no lease "
441 : "requested\n"));
442 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
443 : }
444 :
445 0 : if (fsp->oplock_type != LEASE_OPLOCK) {
446 0 : DEBUG(10, ("Lease requested, but reopened file has no "
447 : "lease\n"));
448 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
449 : }
450 :
451 0 : if (!smb2_lease_key_equal(&lease_ptr->lease_key,
452 0 : &fsp->lease->lease.lease_key)) {
453 0 : DEBUG(10, ("Different lease key requested than found "
454 : "in reopened file\n"));
455 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
456 : }
457 :
458 0 : filename = talloc_strdup(talloc_tos(), requested_filename);
459 0 : if (filename == NULL) {
460 0 : return NT_STATUS_NO_MEMORY;
461 : }
462 :
463 : /* This also converts '\' to '/' */
464 0 : status = check_path_syntax_smb2(filename, is_dfs);
465 0 : if (!NT_STATUS_IS_OK(status)) {
466 0 : TALLOC_FREE(filename);
467 0 : return status;
468 : }
469 :
470 0 : ucf_flags = filename_create_ucf_flags(smb1req, FILE_OPEN);
471 0 : status = filename_convert_dirfsp(talloc_tos(),
472 0 : fsp->conn,
473 : filename,
474 : ucf_flags,
475 : twrp,
476 : &dirfsp,
477 : &smb_fname);
478 0 : TALLOC_FREE(filename);
479 0 : if (!NT_STATUS_IS_OK(status)) {
480 0 : DEBUG(10, ("filename_convert returned %s\n",
481 : nt_errstr(status)));
482 0 : return status;
483 : }
484 :
485 0 : if (!strequal(fsp->fsp_name->base_name, smb_fname->base_name)) {
486 0 : DEBUG(10, ("Lease requested for file %s, reopened file "
487 : "is named %s\n", smb_fname->base_name,
488 : fsp->fsp_name->base_name));
489 0 : TALLOC_FREE(smb_fname);
490 0 : return NT_STATUS_INVALID_PARAMETER;
491 : }
492 :
493 0 : TALLOC_FREE(smb_fname);
494 :
495 0 : return NT_STATUS_OK;
496 : }
497 :
498 : struct smbd_smb2_create_state {
499 : struct tevent_context *ev;
500 : struct smbd_smb2_request *smb2req;
501 : struct GUID req_guid;
502 : struct smb_request *smb1req;
503 : bool open_was_deferred;
504 : struct tevent_immediate *im;
505 : struct timeval request_time;
506 : struct file_id id;
507 : struct deferred_open_record *open_rec;
508 : files_struct *result;
509 : bool replay_operation;
510 : uint8_t in_oplock_level;
511 : uint32_t in_create_disposition;
512 : int requested_oplock_level;
513 : int info;
514 : char *fname;
515 : struct ea_list *ea_list;
516 : NTTIME max_access_time;
517 : struct security_descriptor *sec_desc;
518 : uint64_t allocation_size;
519 : struct GUID _create_guid;
520 : struct GUID *create_guid;
521 : struct GUID _purge_create_guid;
522 : struct GUID *purge_create_guid;
523 : bool update_open;
524 : bool durable_requested;
525 : uint32_t durable_timeout_msec;
526 : bool do_durable_reconnect;
527 : uint64_t persistent_id;
528 : struct smb2_lease lease;
529 : struct smb2_lease *lease_ptr;
530 : ssize_t lease_len;
531 : bool need_replay_cache;
532 : struct smbXsrv_open *op;
533 : NTTIME twrp_time;
534 :
535 : struct smb2_create_blob *dhnc;
536 : struct smb2_create_blob *dh2c;
537 : struct smb2_create_blob *dhnq;
538 : struct smb2_create_blob *dh2q;
539 : struct smb2_create_blob *rqls;
540 : struct smb2_create_blob *exta;
541 : struct smb2_create_blob *mxac;
542 : struct smb2_create_blob *secd;
543 : struct smb2_create_blob *alsi;
544 : struct smb2_create_blob *twrp;
545 : struct smb2_create_blob *qfid;
546 : struct smb2_create_blob *posx;
547 : struct smb2_create_blob *svhdx;
548 :
549 : uint8_t out_oplock_level;
550 : uint32_t out_create_action;
551 : struct timespec out_creation_ts;
552 : struct timespec out_last_access_ts;
553 : struct timespec out_last_write_ts;
554 : struct timespec out_change_ts;
555 : uint64_t out_allocation_size;
556 : uint64_t out_end_of_file;
557 : uint32_t out_file_attributes;
558 : uint64_t out_file_id_persistent;
559 : uint64_t out_file_id_volatile;
560 : struct smb2_create_blobs *out_context_blobs;
561 : };
562 :
563 : static void smbd_smb2_create_purge_replay_cache(struct tevent_req *req,
564 : const char *caller_func);
565 :
566 36952 : static void smbd_smb2_create_cleanup(struct tevent_req *req,
567 : enum tevent_req_state req_state)
568 : {
569 36952 : smbd_smb2_create_purge_replay_cache(req, __func__);
570 36952 : }
571 :
572 18476 : static NTSTATUS smbd_smb2_create_fetch_create_ctx(
573 : struct tevent_req *req,
574 : struct smb2_create_blobs *in_context_blobs)
575 : {
576 18476 : struct smbd_smb2_create_state *state = tevent_req_data(
577 : req, struct smbd_smb2_create_state);
578 18476 : struct smbd_smb2_request *smb2req = state->smb2req;
579 18476 : struct smbXsrv_connection *xconn = smb2req->xconn;
580 :
581 18476 : state->dhnq = smb2_create_blob_find(in_context_blobs,
582 : SMB2_CREATE_TAG_DHNQ);
583 18476 : state->dhnc = smb2_create_blob_find(in_context_blobs,
584 : SMB2_CREATE_TAG_DHNC);
585 18476 : state->dh2q = smb2_create_blob_find(in_context_blobs,
586 : SMB2_CREATE_TAG_DH2Q);
587 18476 : state->dh2c = smb2_create_blob_find(in_context_blobs,
588 : SMB2_CREATE_TAG_DH2C);
589 18476 : if (xconn->smb2.server.capabilities & SMB2_CAP_LEASING) {
590 16434 : state->rqls = smb2_create_blob_find(in_context_blobs,
591 : SMB2_CREATE_TAG_RQLS);
592 : }
593 :
594 18476 : if (((state->dhnc != NULL) && (state->dh2c != NULL)) ||
595 18476 : ((state->dhnc != NULL) && (state->dh2q != NULL)) ||
596 18476 : ((state->dh2c != NULL) && (state->dhnq != NULL)) ||
597 18476 : ((state->dh2q != NULL) && (state->dh2c != NULL)))
598 : {
599 : /* not both are allowed at the same time */
600 0 : return NT_STATUS_INVALID_PARAMETER;
601 : }
602 :
603 18476 : if (state->dhnc != NULL) {
604 : uint32_t num_blobs_allowed;
605 :
606 0 : if (state->dhnc->data.length != 16) {
607 0 : return NT_STATUS_INVALID_PARAMETER;
608 : }
609 :
610 : /*
611 : * According to MS-SMB2: 3.3.5.9.7, "Handling the
612 : * SMB2_CREATE_DURABLE_HANDLE_RECONNECT Create Context",
613 : * we should ignore an additional dhnq blob, but fail
614 : * the request (with status OBJECT_NAME_NOT_FOUND) if
615 : * any other extra create blob has been provided.
616 : *
617 : * (Note that the cases of an additional dh2q or dh2c blob
618 : * which require a different error code, have been treated
619 : * above.)
620 : */
621 :
622 0 : if (state->dhnq != NULL) {
623 0 : num_blobs_allowed = 2;
624 : } else {
625 0 : num_blobs_allowed = 1;
626 : }
627 :
628 0 : if (state->rqls != NULL) {
629 0 : num_blobs_allowed += 1;
630 : }
631 :
632 0 : if (in_context_blobs->num_blobs != num_blobs_allowed) {
633 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
634 : }
635 : }
636 :
637 18476 : if (state->dh2c!= NULL) {
638 : uint32_t num_blobs_allowed;
639 :
640 0 : if (state->dh2c->data.length != 36) {
641 0 : return NT_STATUS_INVALID_PARAMETER;
642 : }
643 :
644 : /*
645 : * According to MS-SMB2: 3.3.5.9.12, "Handling the
646 : * SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 Create Context",
647 : * we should fail the request with status
648 : * OBJECT_NAME_NOT_FOUND if any other create blob has been
649 : * provided.
650 : *
651 : * (Note that the cases of an additional dhnq, dhnc or dh2q
652 : * blob which require a different error code, have been
653 : * treated above.)
654 : */
655 :
656 0 : num_blobs_allowed = 1;
657 :
658 0 : if (state->rqls != NULL) {
659 0 : num_blobs_allowed += 1;
660 : }
661 :
662 0 : if (in_context_blobs->num_blobs != num_blobs_allowed) {
663 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
664 : }
665 : }
666 :
667 18476 : state->exta = smb2_create_blob_find(in_context_blobs,
668 : SMB2_CREATE_TAG_EXTA);
669 18476 : state->mxac = smb2_create_blob_find(in_context_blobs,
670 : SMB2_CREATE_TAG_MXAC);
671 18476 : state->secd = smb2_create_blob_find(in_context_blobs,
672 : SMB2_CREATE_TAG_SECD);
673 18476 : state->alsi = smb2_create_blob_find(in_context_blobs,
674 : SMB2_CREATE_TAG_ALSI);
675 18476 : state->twrp = smb2_create_blob_find(in_context_blobs,
676 : SMB2_CREATE_TAG_TWRP);
677 18476 : state->qfid = smb2_create_blob_find(in_context_blobs,
678 : SMB2_CREATE_TAG_QFID);
679 18476 : if (xconn->protocol >= PROTOCOL_SMB3_02) {
680 : /*
681 : * This was introduced with SMB3_02
682 : */
683 10494 : state->svhdx = smb2_create_blob_find(
684 : in_context_blobs, SVHDX_OPEN_DEVICE_CONTEXT);
685 : }
686 18476 : if (xconn->smb2.server.posix_extensions_negotiated) {
687 : /*
688 : * Negprot only allowed this for proto>=3.11
689 : */
690 0 : SMB_ASSERT(xconn->protocol >= PROTOCOL_SMB3_11);
691 :
692 0 : state->posx = smb2_create_blob_find(
693 : in_context_blobs, SMB2_CREATE_TAG_POSIX);
694 : }
695 :
696 18476 : return NT_STATUS_OK;
697 : }
698 :
699 : static void smbd_smb2_create_before_exec(struct tevent_req *req);
700 : static void smbd_smb2_create_after_exec(struct tevent_req *req);
701 : static void smbd_smb2_create_finish(struct tevent_req *req);
702 :
703 18476 : static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
704 : struct tevent_context *ev,
705 : struct smbd_smb2_request *smb2req,
706 : uint8_t in_oplock_level,
707 : uint32_t in_impersonation_level,
708 : uint32_t in_desired_access,
709 : uint32_t in_file_attributes,
710 : uint32_t in_share_access,
711 : uint32_t in_create_disposition,
712 : uint32_t in_create_options,
713 : const char *in_name,
714 : struct smb2_create_blobs in_context_blobs)
715 : {
716 18476 : struct tevent_req *req = NULL;
717 18476 : struct smbd_smb2_create_state *state = NULL;
718 : NTSTATUS status;
719 18476 : struct smb_request *smb1req = NULL;
720 18476 : struct files_struct *dirfsp = NULL;
721 18476 : struct smb_filename *smb_fname = NULL;
722 : uint32_t ucf_flags;
723 18476 : bool is_dfs = false;
724 :
725 18476 : req = tevent_req_create(mem_ctx, &state,
726 : struct smbd_smb2_create_state);
727 18476 : if (req == NULL) {
728 0 : return NULL;
729 : }
730 18476 : *state = (struct smbd_smb2_create_state) {
731 : .ev = ev,
732 : .smb2req = smb2req,
733 : .in_oplock_level = in_oplock_level,
734 : .in_create_disposition = in_create_disposition,
735 : };
736 :
737 18476 : smb1req = smbd_smb2_fake_smb_request(smb2req);
738 18476 : if (tevent_req_nomem(smb1req, req)) {
739 0 : return tevent_req_post(req, state->ev);
740 : }
741 18476 : state->smb1req = smb1req;
742 :
743 18476 : state->req_guid = smbd_request_guid(smb1req, 0);
744 :
745 18476 : tevent_req_set_cleanup_fn(req, smbd_smb2_create_cleanup);
746 :
747 18476 : if (smb2req->subreq == NULL) {
748 18476 : DBG_DEBUG("name [%s]\n", in_name);
749 : } else {
750 0 : struct smbd_smb2_create_state *old_state = tevent_req_data(
751 : smb2req->subreq, struct smbd_smb2_create_state);
752 :
753 0 : DBG_DEBUG("reentrant for file %s\n", in_name);
754 :
755 0 : state->id = old_state->id;
756 0 : state->request_time = old_state->request_time;
757 0 : state->open_rec = talloc_move(state, &old_state->open_rec);
758 0 : state->open_was_deferred = old_state->open_was_deferred;
759 0 : state->_purge_create_guid = old_state->_purge_create_guid;
760 0 : state->purge_create_guid = old_state->purge_create_guid;
761 0 : old_state->purge_create_guid = NULL;
762 : }
763 :
764 18476 : TALLOC_FREE(smb2req->subreq);
765 18476 : smb2req->subreq = req;
766 :
767 18476 : if (lp_fake_oplocks(SNUM(smb2req->tcon->compat))) {
768 0 : state->requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
769 : } else {
770 18476 : state->requested_oplock_level = state->in_oplock_level;
771 : }
772 :
773 : /* these are ignored for SMB2 */
774 18476 : in_create_options &= ~(0x10);/* NTCREATEX_OPTIONS_SYNC_ALERT */
775 18476 : in_create_options &= ~(0x20);/* NTCREATEX_OPTIONS_ASYNC_ALERT */
776 :
777 18476 : in_file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS;
778 :
779 18476 : is_dfs = (smb1req->flags2 & FLAGS2_DFS_PATHNAMES);
780 18476 : if (is_dfs) {
781 : /*
782 : * With a DFS flag set, remove any leading '\\'
783 : * characters from in_name before further processing.
784 : */
785 1048 : while (in_name[0] == '\\') {
786 0 : in_name++;
787 : }
788 : }
789 :
790 18476 : state->fname = talloc_strdup(state, in_name);
791 18476 : if (tevent_req_nomem(state->fname, req)) {
792 0 : return tevent_req_post(req, state->ev);
793 : }
794 :
795 18476 : state->out_context_blobs = talloc_zero(state, struct smb2_create_blobs);
796 18476 : if (tevent_req_nomem(state->out_context_blobs, req)) {
797 0 : return tevent_req_post(req, state->ev);
798 : }
799 :
800 18476 : status = smbd_smb2_create_fetch_create_ctx(req, &in_context_blobs);
801 18476 : if (tevent_req_nterror(req, status)) {
802 0 : return tevent_req_post(req, state->ev);
803 : }
804 :
805 18476 : if (IS_IPC(smb1req->conn)) {
806 3426 : const char *pipe_name = in_name;
807 :
808 3426 : if (state->dhnc != NULL || state->dh2c != NULL) {
809 : /* durable handles are not supported on IPC$ */
810 0 : tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
811 0 : return tevent_req_post(req, state->ev);
812 : }
813 :
814 3426 : if (!lp_nt_pipe_support()) {
815 0 : tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
816 0 : return tevent_req_post(req, state->ev);
817 : }
818 :
819 3426 : status = open_np_file(smb1req, pipe_name, &state->result);
820 3426 : if (tevent_req_nterror(req, status)) {
821 5 : return tevent_req_post(req, state->ev);
822 : }
823 3421 : state->info = FILE_WAS_OPENED;
824 :
825 3421 : smbd_smb2_create_finish(req);
826 3421 : return req;
827 : }
828 :
829 15050 : if (CAN_PRINT(smb1req->conn)) {
830 0 : if (state->dhnc != NULL || state->dh2c != NULL) {
831 : /* durable handles are not supported on printers */
832 0 : tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
833 0 : return tevent_req_post(req, state->ev);
834 : }
835 :
836 0 : status = file_new(smb1req, smb1req->conn, &state->result);
837 0 : if (tevent_req_nterror(req, status)) {
838 0 : return tevent_req_post(req, state->ev);
839 : }
840 :
841 0 : status = print_spool_open(state->result, in_name,
842 : smb1req->vuid);
843 0 : if (tevent_req_nterror(req, status)) {
844 0 : file_free(smb1req, state->result);
845 0 : return tevent_req_post(req, state->ev);
846 : }
847 0 : state->info = FILE_WAS_CREATED;
848 :
849 0 : smbd_smb2_create_finish(req);
850 0 : return req;
851 : }
852 :
853 : /* Check for trailing slash specific directory handling. */
854 15050 : status = windows_name_trailing_check(state->fname, in_create_options);
855 15050 : if (tevent_req_nterror(req, status)) {
856 0 : return tevent_req_post(req, state->ev);
857 : }
858 :
859 15050 : smbd_smb2_create_before_exec(req);
860 15050 : if (!tevent_req_is_in_progress(req)) {
861 0 : return tevent_req_post(req, state->ev);
862 : }
863 :
864 15050 : DBG_DEBUG("open execution phase\n");
865 :
866 : /*
867 : * For the backend file open procedure, there are
868 : * three possible modes: replay operation (in which case
869 : * there is nothing else to do), durable_reconnect or
870 : * new open.
871 : */
872 15050 : if (state->replay_operation) {
873 0 : state->result = state->op->compat;
874 0 : state->result->op = state->op;
875 0 : state->update_open = false;
876 0 : state->info = state->op->create_action;
877 :
878 0 : smbd_smb2_create_after_exec(req);
879 0 : if (!tevent_req_is_in_progress(req)) {
880 0 : return req;
881 : }
882 :
883 0 : smbd_smb2_create_finish(req);
884 0 : return req;
885 : }
886 :
887 15050 : if (state->do_durable_reconnect) {
888 0 : DATA_BLOB new_cookie = data_blob_null;
889 0 : NTTIME now = timeval_to_nttime(&smb2req->request_time);
890 :
891 0 : status = smb2srv_open_recreate(smb2req->xconn,
892 0 : smb1req->conn->session_info,
893 0 : state->persistent_id,
894 0 : state->create_guid,
895 : now,
896 0 : &state->op);
897 0 : if (tevent_req_nterror(req, status)) {
898 0 : DBG_NOTICE("smb2srv_open_recreate failed: %s\n",
899 : nt_errstr(status));
900 0 : return tevent_req_post(req, state->ev);
901 : }
902 :
903 0 : DBG_DEBUG("%s to recreate durable handle\n",
904 : state->op->global->durable ? "succeeded" : "failed");
905 :
906 0 : if (!state->op->global->durable) {
907 0 : talloc_free(state->op);
908 0 : tevent_req_nterror(req,
909 : NT_STATUS_OBJECT_NAME_NOT_FOUND);
910 0 : return tevent_req_post(req, state->ev);
911 : }
912 :
913 0 : status = SMB_VFS_DURABLE_RECONNECT(smb1req->conn,
914 : smb1req,
915 : state->op, /* smbXsrv_open input */
916 : state->op->global->backend_cookie,
917 : state->op, /* TALLOC_CTX */
918 : &state->result,
919 : &new_cookie);
920 0 : if (!NT_STATUS_IS_OK(status)) {
921 : NTSTATUS return_status;
922 :
923 0 : return_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
924 :
925 0 : DBG_NOTICE("durable_reconnect failed: %s => %s\n",
926 : nt_errstr(status),
927 : nt_errstr(return_status));
928 :
929 0 : tevent_req_nterror(req, return_status);
930 0 : return tevent_req_post(req, state->ev);
931 : }
932 :
933 0 : DBG_DEBUG("oplock_type=%u, lease_ptr==%p\n",
934 : (unsigned)state->result->oplock_type, state->lease_ptr);
935 :
936 0 : status = smbd_smb2_create_durable_lease_check(
937 0 : smb1req, state->fname, state->result, state->lease_ptr);
938 0 : if (tevent_req_nterror(req, status)) {
939 0 : close_file_free(
940 0 : smb1req, &state->result, SHUTDOWN_CLOSE);
941 0 : return tevent_req_post(req, state->ev);
942 : }
943 :
944 0 : data_blob_free(&state->op->global->backend_cookie);
945 0 : state->op->global->backend_cookie = new_cookie;
946 :
947 0 : state->op->status = NT_STATUS_OK;
948 0 : state->op->global->disconnect_time = 0;
949 :
950 : /* save the timout for later update */
951 0 : state->durable_timeout_msec = state->op->global->durable_timeout_msec;
952 :
953 0 : state->update_open = true;
954 :
955 0 : state->info = FILE_WAS_OPENED;
956 :
957 0 : smbd_smb2_create_after_exec(req);
958 0 : if (!tevent_req_is_in_progress(req)) {
959 0 : return req;
960 : }
961 :
962 0 : smbd_smb2_create_finish(req);
963 0 : return req;
964 : }
965 :
966 15050 : if (state->requested_oplock_level == SMB2_OPLOCK_LEVEL_LEASE) {
967 0 : if (state->lease_ptr == NULL) {
968 0 : state->requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
969 : }
970 : } else {
971 15050 : state->lease_ptr = NULL;
972 : }
973 :
974 : /* convert '\\' into '/' */
975 15050 : status = check_path_syntax_smb2(state->fname, is_dfs);
976 15050 : if (tevent_req_nterror(req, status)) {
977 0 : return tevent_req_post(req, state->ev);
978 : }
979 :
980 15050 : ucf_flags = filename_create_ucf_flags(
981 15050 : smb1req, state->in_create_disposition);
982 :
983 15050 : status = filename_convert_dirfsp(
984 : req,
985 : smb1req->conn,
986 15050 : state->fname,
987 : ucf_flags,
988 15050 : state->twrp_time,
989 : &dirfsp,
990 : &smb_fname);
991 15050 : if (tevent_req_nterror(req, status)) {
992 899 : return tevent_req_post(req, state->ev);
993 : }
994 :
995 : /*
996 : * MS-SMB2: 2.2.13 SMB2 CREATE Request
997 : * ImpersonationLevel ... MUST contain one of the
998 : * following values. The server MUST validate this
999 : * field, but otherwise ignore it.
1000 : *
1001 : * NB. The source4/torture/smb2/durable_open.c test
1002 : * shows this check is only done on real opens, not
1003 : * on durable handle-reopens.
1004 : */
1005 :
1006 14151 : if (in_impersonation_level >
1007 : SMB2_IMPERSONATION_DELEGATE) {
1008 1 : tevent_req_nterror(req,
1009 : NT_STATUS_BAD_IMPERSONATION_LEVEL);
1010 1 : return tevent_req_post(req, state->ev);
1011 : }
1012 :
1013 : /*
1014 : * We know we're going to do a local open, so now
1015 : * we must be protocol strict. JRA.
1016 : *
1017 : * MS-SMB2: 3.3.5.9 - Receiving an SMB2 CREATE Request
1018 : * If the file name length is greater than zero and the
1019 : * first character is a path separator character, the
1020 : * server MUST fail the request with
1021 : * STATUS_INVALID_PARAMETER.
1022 : */
1023 14150 : if (in_name[0] == '\\' || in_name[0] == '/') {
1024 1 : tevent_req_nterror(req,
1025 : NT_STATUS_INVALID_PARAMETER);
1026 1 : return tevent_req_post(req, state->ev);
1027 : }
1028 :
1029 14149 : status = SMB_VFS_CREATE_FILE(smb1req->conn,
1030 : smb1req,
1031 : dirfsp,
1032 : smb_fname,
1033 : in_desired_access,
1034 : in_share_access,
1035 : state->in_create_disposition,
1036 : in_create_options,
1037 : in_file_attributes,
1038 : map_smb2_oplock_levels_to_samba(
1039 : state->requested_oplock_level),
1040 : state->lease_ptr,
1041 : state->allocation_size,
1042 : 0, /* private_flags */
1043 : state->sec_desc,
1044 : state->ea_list,
1045 : &state->result,
1046 : &state->info,
1047 : &in_context_blobs,
1048 : state->out_context_blobs);
1049 14149 : if (!NT_STATUS_IS_OK(status)) {
1050 912 : if (open_was_deferred(smb1req->xconn, smb1req->mid)) {
1051 0 : SMBPROFILE_IOBYTES_ASYNC_SET_IDLE(smb2req->profile);
1052 0 : return req;
1053 : }
1054 912 : tevent_req_nterror(req, status);
1055 912 : return tevent_req_post(req, state->ev);
1056 : }
1057 13237 : state->op = state->result->op;
1058 :
1059 13237 : smbd_smb2_create_after_exec(req);
1060 13237 : if (!tevent_req_is_in_progress(req)) {
1061 0 : return req;
1062 : }
1063 :
1064 13237 : smbd_smb2_create_finish(req);
1065 13237 : return req;
1066 : }
1067 :
1068 36952 : static void smbd_smb2_create_purge_replay_cache(struct tevent_req *req,
1069 : const char *caller_func)
1070 : {
1071 36952 : struct smbd_smb2_create_state *state = tevent_req_data(
1072 : req, struct smbd_smb2_create_state);
1073 : NTSTATUS status;
1074 :
1075 36952 : if (state->purge_create_guid == NULL) {
1076 36952 : return;
1077 : }
1078 :
1079 0 : status = smbXsrv_open_purge_replay_cache(state->smb2req->xconn->client,
1080 0 : state->purge_create_guid);
1081 0 : if (!NT_STATUS_IS_OK(status)) {
1082 : struct GUID_txt_buf buf;
1083 :
1084 0 : D_ERR("%s: smbXsrv_open_purge_replay_cache(%s) %s\n",
1085 : caller_func,
1086 : GUID_buf_string(state->purge_create_guid, &buf),
1087 : nt_errstr(status));
1088 : }
1089 :
1090 0 : state->purge_create_guid = NULL;
1091 : }
1092 :
1093 15050 : static void smbd_smb2_create_before_exec(struct tevent_req *req)
1094 : {
1095 15050 : struct smbd_smb2_create_state *state = tevent_req_data(
1096 : req, struct smbd_smb2_create_state);
1097 15050 : struct smbd_smb2_request *smb2req = state->smb2req;
1098 : NTSTATUS status;
1099 :
1100 15050 : if (state->exta != NULL) {
1101 1 : if (!lp_ea_support(SNUM(smb2req->tcon->compat))) {
1102 0 : tevent_req_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
1103 0 : return;
1104 : }
1105 :
1106 2 : state->ea_list = read_nttrans_ea_list(
1107 : state,
1108 1 : (const char *)state->exta->data.data,
1109 1 : state->exta->data.length);
1110 1 : if (state->ea_list == NULL) {
1111 0 : DEBUG(10,("smbd_smb2_create_send: read_ea_name_list failed.\n"));
1112 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1113 0 : return;
1114 : }
1115 :
1116 : /*
1117 : * NB. When SMB2+ unix extensions are added,
1118 : * we need to relax this check in invalid
1119 : * names - we used to not do this if
1120 : * lp_posix_pathnames() was false.
1121 : */
1122 1 : if (ea_list_has_invalid_name(state->ea_list)) {
1123 0 : tevent_req_nterror(req, STATUS_INVALID_EA_NAME);
1124 0 : return;
1125 : }
1126 : }
1127 :
1128 15050 : if (state->mxac != NULL) {
1129 2 : if (state->mxac->data.length == 0) {
1130 2 : state->max_access_time = 0;
1131 0 : } else if (state->mxac->data.length == 8) {
1132 0 : state->max_access_time = BVAL(state->mxac->data.data, 0);
1133 : } else {
1134 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1135 0 : return;
1136 : }
1137 : }
1138 :
1139 15050 : if (state->secd != NULL) {
1140 : enum ndr_err_code ndr_err;
1141 :
1142 17 : state->sec_desc = talloc_zero(state, struct security_descriptor);
1143 17 : if (tevent_req_nomem(state->sec_desc, req)) {
1144 0 : return;
1145 : }
1146 :
1147 17 : ndr_err = ndr_pull_struct_blob(&state->secd->data,
1148 17 : state->sec_desc, state->sec_desc,
1149 : (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
1150 17 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1151 0 : DEBUG(2,("ndr_pull_security_descriptor failed: %s\n",
1152 : ndr_errstr(ndr_err)));
1153 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1154 0 : return;
1155 : }
1156 : }
1157 :
1158 15050 : if (state->dhnq != NULL) {
1159 3 : if (state->dhnq->data.length != 16) {
1160 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1161 0 : return;
1162 : }
1163 :
1164 3 : if (state->dh2q != NULL) {
1165 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1166 0 : return;
1167 : }
1168 :
1169 : /*
1170 : * durable handle request is processed below.
1171 : */
1172 3 : state->durable_requested = true;
1173 : /*
1174 : * Set the timeout to 16 mins.
1175 : *
1176 : * TODO: test this against Windows 2012
1177 : * as the default for durable v2 is 1 min.
1178 : */
1179 3 : state->durable_timeout_msec = (16*60*1000);
1180 : }
1181 :
1182 15050 : if (state->dh2q != NULL) {
1183 0 : const uint8_t *p = state->dh2q->data.data;
1184 0 : NTTIME now = timeval_to_nttime(&smb2req->request_time);
1185 0 : uint32_t durable_v2_timeout = 0;
1186 : DATA_BLOB create_guid_blob;
1187 : const uint8_t *hdr;
1188 : uint32_t flags;
1189 :
1190 0 : if (state->dh2q->data.length != 32) {
1191 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1192 0 : return;
1193 : }
1194 :
1195 0 : if (state->dhnq != NULL) {
1196 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1197 0 : return;
1198 : }
1199 :
1200 0 : durable_v2_timeout = IVAL(p, 0);
1201 0 : create_guid_blob = data_blob_const(p + 16, 16);
1202 :
1203 0 : status = GUID_from_ndr_blob(&create_guid_blob,
1204 : &state->_create_guid);
1205 0 : if (tevent_req_nterror(req, status)) {
1206 0 : return;
1207 : }
1208 0 : state->create_guid = &state->_create_guid;
1209 :
1210 : /*
1211 : * we need to store the create_guid later
1212 : */
1213 0 : state->update_open = true;
1214 :
1215 : /*
1216 : * And we need to create a cache for replaying the
1217 : * create.
1218 : */
1219 0 : state->need_replay_cache = true;
1220 :
1221 : /*
1222 : * durable handle v2 request processed below
1223 : */
1224 0 : state->durable_requested = true;
1225 0 : state->durable_timeout_msec = MIN(durable_v2_timeout, 300*1000);
1226 0 : if (state->durable_timeout_msec == 0) {
1227 : /*
1228 : * Set the timeout to 1 min as default.
1229 : *
1230 : * This matches Windows 2012.
1231 : */
1232 0 : state->durable_timeout_msec = (60*1000);
1233 : }
1234 :
1235 : /*
1236 : * Check for replay operation.
1237 : * Only consider it when we have dh2q.
1238 : * If we do not have a replay operation, verify that
1239 : * the create_guid is not cached for replay.
1240 : */
1241 0 : hdr = SMBD_SMB2_IN_HDR_PTR(smb2req);
1242 0 : flags = IVAL(hdr, SMB2_HDR_FLAGS);
1243 0 : state->replay_operation =
1244 0 : flags & SMB2_HDR_FLAG_REPLAY_OPERATION;
1245 :
1246 0 : status = smb2srv_open_lookup_replay_cache(smb2req->xconn,
1247 : state->req_guid,
1248 0 : *state->create_guid,
1249 0 : state->fname,
1250 : now,
1251 : &state->op);
1252 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_FWP_RESERVED)) {
1253 : /*
1254 : * We've reserved the replay_cache record
1255 : * for ourself, indicating we're still
1256 : * in progress.
1257 : *
1258 : * It means the smbd_smb2_create_cleanup()
1259 : * may need to call smbXsrv_open_purge_replay_cache()
1260 : * in order to cleanup.
1261 : */
1262 0 : SMB_ASSERT(state->op == NULL);
1263 0 : state->_purge_create_guid = state->_create_guid;
1264 0 : state->purge_create_guid = &state->_purge_create_guid;
1265 0 : status = NT_STATUS_OK;
1266 0 : state->replay_operation = false;
1267 0 : } else if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_NOT_AVAILABLE)) {
1268 0 : tevent_req_nterror(req, status);
1269 0 : return;
1270 0 : } else if (tevent_req_nterror(req, status)) {
1271 0 : DBG_WARNING("smb2srv_open_lookup_replay_cache "
1272 : "failed: %s\n", nt_errstr(status));
1273 0 : return;
1274 0 : } else if (!state->replay_operation) {
1275 : /*
1276 : * If a create without replay operation flag
1277 : * is sent but with a create_guid that is
1278 : * currently in the replay cache -- fail.
1279 : */
1280 0 : status = NT_STATUS_DUPLICATE_OBJECTID;
1281 0 : (void)tevent_req_nterror(req, status);
1282 0 : return;
1283 : }
1284 : }
1285 :
1286 15050 : if (state->dhnc != NULL) {
1287 0 : state->persistent_id = BVAL(state->dhnc->data.data, 0);
1288 0 : state->do_durable_reconnect = true;
1289 : }
1290 :
1291 15050 : if (state->dh2c != NULL) {
1292 0 : const uint8_t *p = state->dh2c->data.data;
1293 : DATA_BLOB create_guid_blob;
1294 :
1295 0 : state->persistent_id = BVAL(p, 0);
1296 0 : create_guid_blob = data_blob_const(p + 16, 16);
1297 :
1298 0 : status = GUID_from_ndr_blob(&create_guid_blob,
1299 : &state->_create_guid);
1300 0 : if (tevent_req_nterror(req, status)) {
1301 0 : return;
1302 : }
1303 :
1304 0 : state->create_guid = &state->_create_guid;
1305 0 : state->do_durable_reconnect = true;
1306 : }
1307 :
1308 15050 : if (state->alsi != NULL) {
1309 27 : if (state->alsi->data.length != 8) {
1310 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1311 0 : return;
1312 : }
1313 27 : state->allocation_size = BVAL(state->alsi->data.data, 0);
1314 : }
1315 :
1316 15050 : if (state->twrp != NULL) {
1317 1 : if (state->twrp->data.length != 8) {
1318 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1319 0 : return;
1320 : }
1321 :
1322 1 : state->twrp_time = BVAL(state->twrp->data.data, 0);
1323 : }
1324 :
1325 15050 : if (state->qfid != NULL) {
1326 0 : if (state->qfid->data.length != 0) {
1327 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1328 0 : return;
1329 : }
1330 : }
1331 :
1332 15050 : if (state->rqls != NULL) {
1333 0 : ssize_t lease_len = -1;
1334 :
1335 0 : lease_len = smb2_lease_pull(state->rqls->data.data,
1336 0 : state->rqls->data.length,
1337 : &state->lease);
1338 0 : if (lease_len == -1) {
1339 0 : tevent_req_nterror(
1340 : req, NT_STATUS_INVALID_PARAMETER);
1341 0 : return;
1342 : }
1343 0 : state->lease_ptr = &state->lease;
1344 :
1345 0 : if (DEBUGLEVEL >= 10) {
1346 0 : DEBUG(10, ("Got lease request size %d\n",
1347 : (int)lease_len));
1348 0 : NDR_PRINT_DEBUG(smb2_lease, state->lease_ptr);
1349 : }
1350 :
1351 0 : if (!smb2_lease_key_valid(&state->lease.lease_key)) {
1352 0 : state->lease_ptr = NULL;
1353 0 : state->requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
1354 : }
1355 :
1356 0 : if ((smb2req->xconn->protocol < PROTOCOL_SMB3_00) &&
1357 0 : (state->lease.lease_version != 1))
1358 : {
1359 0 : DEBUG(10, ("v2 lease key only for SMB3\n"));
1360 0 : state->lease_ptr = NULL;
1361 : }
1362 :
1363 : /*
1364 : * Replay with a lease is only allowed if the
1365 : * established open carries a lease with the
1366 : * same lease key.
1367 : */
1368 0 : if (state->replay_operation) {
1369 0 : struct smb2_lease *op_ls =
1370 0 : &state->op->compat->lease->lease;
1371 0 : int op_oplock = state->op->compat->oplock_type;
1372 :
1373 0 : if (map_samba_oplock_levels_to_smb2(op_oplock)
1374 : != SMB2_OPLOCK_LEVEL_LEASE)
1375 : {
1376 0 : status = NT_STATUS_ACCESS_DENIED;
1377 0 : (void)tevent_req_nterror(req, status);
1378 0 : return;
1379 : }
1380 0 : if (!smb2_lease_key_equal(&state->lease.lease_key,
1381 0 : &op_ls->lease_key))
1382 : {
1383 0 : status = NT_STATUS_ACCESS_DENIED;
1384 0 : (void)tevent_req_nterror(req, status);
1385 0 : return;
1386 : }
1387 : }
1388 : }
1389 :
1390 15050 : if (state->posx != NULL) {
1391 0 : if (state->posx->data.length != 4) {
1392 0 : DBG_DEBUG("Got %zu bytes POSX cctx, expected 4\n",
1393 : state->posx->data.length);
1394 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1395 0 : return;
1396 : }
1397 : }
1398 : }
1399 :
1400 13237 : static void smbd_smb2_create_after_exec(struct tevent_req *req)
1401 : {
1402 13237 : struct smbd_smb2_create_state *state = tevent_req_data(
1403 : req, struct smbd_smb2_create_state);
1404 13237 : connection_struct *conn = state->result->conn;
1405 : NTSTATUS status;
1406 :
1407 : /*
1408 : * here we have op == result->op
1409 : */
1410 :
1411 13237 : DEBUG(10, ("smbd_smb2_create_send: "
1412 : "response construction phase\n"));
1413 :
1414 13237 : state->out_file_attributes = fdos_mode(state->result);
1415 :
1416 13237 : if (state->mxac != NULL) {
1417 : NTTIME last_write_time;
1418 :
1419 1 : last_write_time = full_timespec_to_nt_time(
1420 1 : &state->result->fsp_name->st.st_ex_mtime);
1421 1 : if (last_write_time != state->max_access_time) {
1422 : uint8_t p[8];
1423 : uint32_t max_access_granted;
1424 1 : DATA_BLOB blob = data_blob_const(p, sizeof(p));
1425 :
1426 1 : status = smbd_calculate_access_mask_fsp(
1427 : conn->cwd_fsp,
1428 1 : state->result,
1429 : false,
1430 : SEC_FLAG_MAXIMUM_ALLOWED,
1431 : &max_access_granted);
1432 :
1433 1 : SIVAL(p, 0, NT_STATUS_V(status));
1434 1 : SIVAL(p, 4, max_access_granted);
1435 :
1436 1 : status = smb2_create_blob_add(
1437 1 : state->out_context_blobs,
1438 : state->out_context_blobs,
1439 : SMB2_CREATE_TAG_MXAC,
1440 : blob);
1441 1 : if (!NT_STATUS_IS_OK(status)) {
1442 0 : goto fail;
1443 : }
1444 : }
1445 : }
1446 :
1447 13237 : if (!state->replay_operation && state->durable_requested &&
1448 2 : (fsp_lease_type(state->result) & SMB2_LEASE_HANDLE))
1449 : {
1450 0 : status = SMB_VFS_DURABLE_COOKIE(
1451 : state->result,
1452 : state->op,
1453 : &state->op->global->backend_cookie);
1454 0 : if (!NT_STATUS_IS_OK(status)) {
1455 0 : state->op->global->backend_cookie = data_blob_null;
1456 : }
1457 : }
1458 13237 : if (!state->replay_operation && state->op->global->backend_cookie.length > 0)
1459 : {
1460 0 : state->update_open = true;
1461 :
1462 0 : state->op->global->durable = true;
1463 0 : state->op->global->durable_timeout_msec = state->durable_timeout_msec;
1464 : }
1465 :
1466 13237 : if (state->update_open) {
1467 0 : state->op->global->create_guid = state->_create_guid;
1468 0 : if (state->need_replay_cache) {
1469 0 : state->op->flags |= SMBXSRV_OPEN_NEED_REPLAY_CACHE;
1470 : }
1471 :
1472 0 : status = smbXsrv_open_update(state->op);
1473 0 : DEBUG(10, ("smb2_create_send: smbXsrv_open_update "
1474 : "returned %s\n",
1475 : nt_errstr(status)));
1476 0 : if (!NT_STATUS_IS_OK(status)) {
1477 0 : goto fail;
1478 : }
1479 :
1480 : /*
1481 : * We should not purge the replay cache anymore
1482 : * as it's attached to the smbXsrv_open record now.
1483 : */
1484 0 : state->purge_create_guid = NULL;
1485 : }
1486 :
1487 13237 : if (state->dhnq != NULL && state->op->global->durable) {
1488 0 : uint8_t p[8] = { 0, };
1489 0 : DATA_BLOB blob = data_blob_const(p, sizeof(p));
1490 :
1491 0 : status = smb2_create_blob_add(state->out_context_blobs,
1492 : state->out_context_blobs,
1493 : SMB2_CREATE_TAG_DHNQ,
1494 : blob);
1495 0 : if (!NT_STATUS_IS_OK(status)) {
1496 0 : goto fail;
1497 : }
1498 : }
1499 :
1500 13237 : if (state->dh2q != NULL && state->op->global->durable &&
1501 : /*
1502 : * For replay operations, we return the dh2q blob
1503 : * in the case of oplocks not based on the state of
1504 : * the open, but on whether it could have been granted
1505 : * for the request data. In the case of leases instead,
1506 : * the state of the open is used...
1507 : */
1508 0 : (!state->replay_operation ||
1509 0 : state->in_oplock_level == SMB2_OPLOCK_LEVEL_BATCH ||
1510 0 : state->in_oplock_level == SMB2_OPLOCK_LEVEL_LEASE))
1511 : {
1512 0 : uint8_t p[8] = { 0, };
1513 0 : DATA_BLOB blob = data_blob_const(p, sizeof(p));
1514 0 : uint32_t durable_v2_response_flags = 0;
1515 :
1516 0 : SIVAL(p, 0, state->op->global->durable_timeout_msec);
1517 0 : SIVAL(p, 4, durable_v2_response_flags);
1518 :
1519 0 : status = smb2_create_blob_add(state->out_context_blobs,
1520 : state->out_context_blobs,
1521 : SMB2_CREATE_TAG_DH2Q,
1522 : blob);
1523 0 : if (!NT_STATUS_IS_OK(status)) {
1524 0 : goto fail;
1525 : }
1526 : }
1527 :
1528 13237 : if (state->qfid != NULL) {
1529 : uint8_t p[32];
1530 0 : SMB_STRUCT_STAT *base_sp = state->result->base_fsp ?
1531 0 : &state->result->base_fsp->fsp_name->st :
1532 0 : &state->result->fsp_name->st;
1533 0 : uint64_t file_id = SMB_VFS_FS_FILE_ID(conn, base_sp);
1534 0 : DATA_BLOB blob = data_blob_const(p, sizeof(p));
1535 :
1536 0 : ZERO_STRUCT(p);
1537 :
1538 : /* From conversations with Microsoft engineers at
1539 : the MS plugfest. The first 8 bytes are the "volume index"
1540 : == inode, the second 8 bytes are the "volume id",
1541 : == dev. This will be updated in the SMB2 doc. */
1542 0 : SBVAL(p, 0, file_id);
1543 0 : SIVAL(p, 8, base_sp->st_ex_dev);/* FileIndexHigh */
1544 :
1545 0 : status = smb2_create_blob_add(state->out_context_blobs,
1546 : state->out_context_blobs,
1547 : SMB2_CREATE_TAG_QFID,
1548 : blob);
1549 0 : if (!NT_STATUS_IS_OK(status)) {
1550 0 : goto fail;
1551 : }
1552 : }
1553 :
1554 13237 : if ((state->rqls != NULL) && (state->result->oplock_type == LEASE_OPLOCK)) {
1555 : uint8_t buf[52];
1556 : struct smb2_lease lease;
1557 : size_t lease_len;
1558 :
1559 0 : lease = state->result->lease->lease;
1560 :
1561 0 : lease_len = sizeof(buf);
1562 0 : if (lease.lease_version == 1) {
1563 0 : lease_len = 32;
1564 : }
1565 :
1566 0 : if (!smb2_lease_push(&lease, buf, lease_len)) {
1567 0 : status = NT_STATUS_INTERNAL_ERROR;
1568 0 : goto fail;
1569 : }
1570 :
1571 0 : status = smb2_create_blob_add(
1572 : state, state->out_context_blobs,
1573 : SMB2_CREATE_TAG_RQLS,
1574 : data_blob_const(buf, lease_len));
1575 0 : if (!NT_STATUS_IS_OK(status)) {
1576 0 : goto fail;
1577 : }
1578 : }
1579 :
1580 13237 : if (state->posx != NULL) {
1581 0 : struct dom_sid owner = { .sid_rev_num = 0, };
1582 0 : struct dom_sid group = { .sid_rev_num = 0, };
1583 0 : struct stat_ex *psbuf = &state->result->fsp_name->st;
1584 : ssize_t cc_len;
1585 :
1586 0 : uid_to_sid(&owner, psbuf->st_ex_uid);
1587 0 : gid_to_sid(&group, psbuf->st_ex_gid);
1588 :
1589 0 : cc_len = smb2_posix_cc_info(
1590 : conn, 0, psbuf, &owner, &group, NULL, 0);
1591 :
1592 0 : if (cc_len == -1) {
1593 0 : status = NT_STATUS_INSUFFICIENT_RESOURCES;
1594 0 : goto fail;
1595 : }
1596 :
1597 0 : {
1598 : /*
1599 : * cc_len is 68 + 2 SIDs, allocate on the stack
1600 : */
1601 0 : uint8_t buf[cc_len];
1602 0 : DATA_BLOB blob = { .data = buf, .length = cc_len, };
1603 :
1604 0 : smb2_posix_cc_info(
1605 : conn,
1606 : 0,
1607 : psbuf,
1608 : &owner,
1609 : &group,
1610 : buf,
1611 0 : sizeof(buf));
1612 :
1613 0 : status = smb2_create_blob_add(
1614 0 : state->out_context_blobs,
1615 : state->out_context_blobs,
1616 : SMB2_CREATE_TAG_POSIX,
1617 : blob);
1618 0 : if (!NT_STATUS_IS_OK(status)) {
1619 0 : goto fail;
1620 : }
1621 : }
1622 : }
1623 :
1624 13237 : return;
1625 :
1626 0 : fail:
1627 0 : close_file_free(state->smb1req, &state->result, ERROR_CLOSE);
1628 0 : tevent_req_nterror(req, status);
1629 0 : tevent_req_post(req, state->ev);
1630 : }
1631 :
1632 16658 : static void smbd_smb2_create_finish(struct tevent_req *req)
1633 : {
1634 16658 : struct smbd_smb2_create_state *state = tevent_req_data(
1635 : req, struct smbd_smb2_create_state);
1636 16658 : struct smbd_smb2_request *smb2req = state->smb2req;
1637 16658 : struct smb_request *smb1req = state->smb1req;
1638 16658 : files_struct *result = state->result;
1639 :
1640 16658 : smb2req->compat_chain_fsp = smb1req->chain_fsp;
1641 :
1642 16658 : if (state->replay_operation) {
1643 0 : state->out_oplock_level = state->in_oplock_level;
1644 16658 : } else if (lp_fake_oplocks(SNUM(smb2req->tcon->compat))) {
1645 0 : state->out_oplock_level = state->in_oplock_level;
1646 : } else {
1647 16658 : state->out_oplock_level = map_samba_oplock_levels_to_smb2(result->oplock_type);
1648 : }
1649 :
1650 16658 : if ((state->in_create_disposition == FILE_SUPERSEDE)
1651 2 : && (state->info == FILE_WAS_OVERWRITTEN)) {
1652 1 : state->out_create_action = FILE_WAS_SUPERSEDED;
1653 : } else {
1654 16657 : state->out_create_action = state->info;
1655 : }
1656 16658 : result->op->create_action = state->out_create_action;
1657 :
1658 16658 : state->out_creation_ts = get_create_timespec(smb1req->conn,
1659 16658 : result, result->fsp_name);
1660 16658 : state->out_last_access_ts = result->fsp_name->st.st_ex_atime;
1661 16658 : state->out_last_write_ts = result->fsp_name->st.st_ex_mtime;
1662 16658 : state->out_change_ts = get_change_timespec(smb1req->conn,
1663 16658 : result, result->fsp_name);
1664 :
1665 16658 : if (lp_dos_filetime_resolution(SNUM(smb2req->tcon->compat))) {
1666 0 : dos_filetime_timespec(&state->out_creation_ts);
1667 0 : dos_filetime_timespec(&state->out_last_access_ts);
1668 0 : dos_filetime_timespec(&state->out_last_write_ts);
1669 0 : dos_filetime_timespec(&state->out_change_ts);
1670 : }
1671 :
1672 16658 : state->out_allocation_size =
1673 16658 : SMB_VFS_GET_ALLOC_SIZE(smb1req->conn, result,
1674 : &(result->fsp_name->st));
1675 16658 : state->out_end_of_file = result->fsp_name->st.st_ex_size;
1676 16658 : if (state->out_file_attributes == 0) {
1677 3421 : state->out_file_attributes = FILE_ATTRIBUTE_NORMAL;
1678 : }
1679 16658 : state->out_file_id_persistent = result->op->global->open_persistent_id;
1680 16658 : state->out_file_id_volatile = result->op->global->open_volatile_id;
1681 :
1682 16658 : DBG_DEBUG("%s - %s\n", fsp_str_dbg(result), fsp_fnum_dbg(result));
1683 :
1684 16658 : tevent_req_done(req);
1685 16658 : tevent_req_post(req, state->ev);
1686 16658 : }
1687 :
1688 18476 : static NTSTATUS smbd_smb2_create_recv(struct tevent_req *req,
1689 : TALLOC_CTX *mem_ctx,
1690 : uint8_t *out_oplock_level,
1691 : uint32_t *out_create_action,
1692 : struct timespec *out_creation_ts,
1693 : struct timespec *out_last_access_ts,
1694 : struct timespec *out_last_write_ts,
1695 : struct timespec *out_change_ts,
1696 : uint64_t *out_allocation_size,
1697 : uint64_t *out_end_of_file,
1698 : uint32_t *out_file_attributes,
1699 : uint64_t *out_file_id_persistent,
1700 : uint64_t *out_file_id_volatile,
1701 : struct smb2_create_blobs *out_context_blobs)
1702 : {
1703 : NTSTATUS status;
1704 18476 : struct smbd_smb2_create_state *state = tevent_req_data(req,
1705 : struct smbd_smb2_create_state);
1706 :
1707 18476 : if (tevent_req_is_nterror(req, &status)) {
1708 1818 : tevent_req_received(req);
1709 1818 : return status;
1710 : }
1711 :
1712 16658 : *out_oplock_level = state->out_oplock_level;
1713 16658 : *out_create_action = state->out_create_action;
1714 16658 : *out_creation_ts = state->out_creation_ts;
1715 16658 : *out_last_access_ts = state->out_last_access_ts;
1716 16658 : *out_last_write_ts = state->out_last_write_ts;
1717 16658 : *out_change_ts = state->out_change_ts;
1718 16658 : *out_allocation_size = state->out_allocation_size;
1719 16658 : *out_end_of_file = state->out_end_of_file;
1720 16658 : *out_file_attributes = state->out_file_attributes;
1721 16658 : *out_file_id_persistent = state->out_file_id_persistent;
1722 16658 : *out_file_id_volatile = state->out_file_id_volatile;
1723 16658 : *out_context_blobs = *(state->out_context_blobs);
1724 :
1725 16658 : talloc_steal(mem_ctx, state->out_context_blobs->blobs);
1726 :
1727 16658 : tevent_req_received(req);
1728 16658 : return NT_STATUS_OK;
1729 : }
1730 :
1731 : /*********************************************************
1732 : Code for dealing with deferred opens.
1733 : *********************************************************/
1734 :
1735 21826 : bool get_deferred_open_message_state_smb2(struct smbd_smb2_request *smb2req,
1736 : struct timeval *p_request_time,
1737 : struct deferred_open_record **open_rec)
1738 : {
1739 21826 : struct smbd_smb2_create_state *state = NULL;
1740 21826 : struct tevent_req *req = NULL;
1741 :
1742 21826 : if (!smb2req) {
1743 0 : return false;
1744 : }
1745 21826 : req = smb2req->subreq;
1746 21826 : if (!req) {
1747 0 : return false;
1748 : }
1749 21826 : state = tevent_req_data(req, struct smbd_smb2_create_state);
1750 21826 : if (!state) {
1751 0 : return false;
1752 : }
1753 21826 : if (!state->open_was_deferred) {
1754 21826 : return false;
1755 : }
1756 0 : if (p_request_time) {
1757 0 : *p_request_time = state->request_time;
1758 : }
1759 0 : if (open_rec != NULL) {
1760 0 : *open_rec = state->open_rec;
1761 : }
1762 0 : return true;
1763 : }
1764 :
1765 : /*********************************************************
1766 : Re-process this call early - requested by message or
1767 : close.
1768 : *********************************************************/
1769 :
1770 912 : static struct smbd_smb2_request *find_open_smb2req(
1771 : struct smbXsrv_connection *xconn, uint64_t mid)
1772 : {
1773 : struct smbd_smb2_request *smb2req;
1774 :
1775 912 : for (smb2req = xconn->smb2.requests; smb2req; smb2req = smb2req->next) {
1776 : uint64_t message_id;
1777 912 : if (smb2req->subreq == NULL) {
1778 : /* This message has been processed. */
1779 0 : continue;
1780 : }
1781 912 : if (!tevent_req_is_in_progress(smb2req->subreq)) {
1782 : /* This message has been processed. */
1783 0 : continue;
1784 : }
1785 912 : message_id = get_mid_from_smb2req(smb2req);
1786 912 : if (message_id == mid) {
1787 912 : return smb2req;
1788 : }
1789 : }
1790 0 : return NULL;
1791 : }
1792 :
1793 912 : bool open_was_deferred_smb2(struct smbXsrv_connection *xconn, uint64_t mid)
1794 : {
1795 912 : struct smbd_smb2_create_state *state = NULL;
1796 : struct smbd_smb2_request *smb2req;
1797 :
1798 912 : smb2req = find_open_smb2req(xconn, mid);
1799 :
1800 912 : if (!smb2req) {
1801 0 : DEBUG(10,("open_was_deferred_smb2: mid %llu smb2req == NULL\n",
1802 : (unsigned long long)mid));
1803 0 : return false;
1804 : }
1805 912 : if (!smb2req->subreq) {
1806 0 : return false;
1807 : }
1808 912 : if (!tevent_req_is_in_progress(smb2req->subreq)) {
1809 0 : return false;
1810 : }
1811 912 : state = tevent_req_data(smb2req->subreq,
1812 : struct smbd_smb2_create_state);
1813 912 : if (!state) {
1814 0 : return false;
1815 : }
1816 : /* It's not in progress if there's no timeout event. */
1817 912 : if (!state->open_was_deferred) {
1818 912 : return false;
1819 : }
1820 :
1821 0 : DEBUG(10,("open_was_deferred_smb2: mid = %llu\n",
1822 : (unsigned long long)mid));
1823 :
1824 0 : return true;
1825 : }
1826 :
1827 0 : static void remove_deferred_open_message_smb2_internal(struct smbd_smb2_request *smb2req,
1828 : uint64_t mid)
1829 : {
1830 0 : struct smbd_smb2_create_state *state = NULL;
1831 :
1832 0 : if (!smb2req->subreq) {
1833 0 : return;
1834 : }
1835 0 : if (!tevent_req_is_in_progress(smb2req->subreq)) {
1836 0 : return;
1837 : }
1838 0 : state = tevent_req_data(smb2req->subreq,
1839 : struct smbd_smb2_create_state);
1840 0 : if (!state) {
1841 0 : return;
1842 : }
1843 :
1844 0 : DEBUG(10,("remove_deferred_open_message_smb2_internal: "
1845 : "mid %llu\n",
1846 : (unsigned long long)mid ));
1847 :
1848 0 : state->open_was_deferred = false;
1849 : /* Ensure we don't have any outstanding immediate event. */
1850 0 : TALLOC_FREE(state->im);
1851 0 : TALLOC_FREE(state->open_rec);
1852 : }
1853 :
1854 0 : void remove_deferred_open_message_smb2(
1855 : struct smbXsrv_connection *xconn, uint64_t mid)
1856 : {
1857 : struct smbd_smb2_request *smb2req;
1858 :
1859 0 : smb2req = find_open_smb2req(xconn, mid);
1860 :
1861 0 : if (!smb2req) {
1862 0 : DEBUG(10,("remove_deferred_open_message_smb2: "
1863 : "can't find mid %llu\n",
1864 : (unsigned long long)mid ));
1865 0 : return;
1866 : }
1867 0 : remove_deferred_open_message_smb2_internal(smb2req, mid);
1868 : }
1869 :
1870 0 : static void smbd_smb2_create_request_dispatch_immediate(struct tevent_context *ctx,
1871 : struct tevent_immediate *im,
1872 : void *private_data)
1873 : {
1874 0 : struct smbd_smb2_request *smb2req = talloc_get_type_abort(private_data,
1875 : struct smbd_smb2_request);
1876 0 : uint64_t mid = get_mid_from_smb2req(smb2req);
1877 : NTSTATUS status;
1878 :
1879 0 : DEBUG(10,("smbd_smb2_create_request_dispatch_immediate: "
1880 : "re-dispatching mid %llu\n",
1881 : (unsigned long long)mid ));
1882 :
1883 0 : status = smbd_smb2_request_dispatch(smb2req);
1884 0 : if (!NT_STATUS_IS_OK(status)) {
1885 0 : smbd_server_connection_terminate(smb2req->xconn,
1886 : nt_errstr(status));
1887 0 : return;
1888 : }
1889 : }
1890 :
1891 0 : bool schedule_deferred_open_message_smb2(
1892 : struct smbXsrv_connection *xconn, uint64_t mid)
1893 : {
1894 0 : struct smbd_smb2_create_state *state = NULL;
1895 : struct smbd_smb2_request *smb2req;
1896 :
1897 0 : smb2req = find_open_smb2req(xconn, mid);
1898 :
1899 0 : if (!smb2req) {
1900 0 : DEBUG(10,("schedule_deferred_open_message_smb2: "
1901 : "can't find mid %llu\n",
1902 : (unsigned long long)mid ));
1903 0 : return false;
1904 : }
1905 0 : if (!smb2req->subreq) {
1906 0 : return false;
1907 : }
1908 0 : if (!tevent_req_is_in_progress(smb2req->subreq)) {
1909 0 : return false;
1910 : }
1911 0 : state = tevent_req_data(smb2req->subreq,
1912 : struct smbd_smb2_create_state);
1913 0 : if (!state) {
1914 0 : return false;
1915 : }
1916 :
1917 : /* Ensure we don't have any outstanding immediate event. */
1918 0 : TALLOC_FREE(state->im);
1919 :
1920 : /*
1921 : * This is subtle. We must null out the callback
1922 : * before rescheduling, else the first call to
1923 : * tevent_req_nterror() causes the _receive()
1924 : * function to be called, this causing tevent_req_post()
1925 : * to crash.
1926 : */
1927 0 : tevent_req_set_callback(smb2req->subreq, NULL, NULL);
1928 :
1929 0 : state->im = tevent_create_immediate(smb2req);
1930 0 : if (!state->im) {
1931 0 : smbd_server_connection_terminate(smb2req->xconn,
1932 : nt_errstr(NT_STATUS_NO_MEMORY));
1933 0 : return false;
1934 : }
1935 :
1936 0 : DEBUG(10,("schedule_deferred_open_message_smb2: "
1937 : "re-processing mid %llu\n",
1938 : (unsigned long long)mid ));
1939 :
1940 0 : tevent_schedule_immediate(state->im,
1941 : smb2req->sconn->ev_ctx,
1942 : smbd_smb2_create_request_dispatch_immediate,
1943 : smb2req);
1944 :
1945 0 : return true;
1946 : }
1947 :
1948 0 : static bool smbd_smb2_create_cancel(struct tevent_req *req)
1949 : {
1950 0 : struct smbd_smb2_request *smb2req = NULL;
1951 0 : struct smbd_smb2_create_state *state = tevent_req_data(req,
1952 : struct smbd_smb2_create_state);
1953 : uint64_t mid;
1954 :
1955 0 : if (!state) {
1956 0 : return false;
1957 : }
1958 :
1959 0 : if (!state->smb2req) {
1960 0 : return false;
1961 : }
1962 :
1963 0 : smb2req = state->smb2req;
1964 0 : mid = get_mid_from_smb2req(smb2req);
1965 :
1966 0 : if (is_deferred_open_async(state->open_rec)) {
1967 : /* Can't cancel an async create. */
1968 0 : return false;
1969 : }
1970 :
1971 0 : remove_deferred_open_message_smb2_internal(smb2req, mid);
1972 :
1973 0 : tevent_req_defer_callback(req, smb2req->sconn->ev_ctx);
1974 0 : tevent_req_nterror(req, NT_STATUS_CANCELLED);
1975 0 : return true;
1976 : }
1977 :
1978 0 : bool push_deferred_open_message_smb2(struct smbd_smb2_request *smb2req,
1979 : struct timeval request_time,
1980 : struct timeval timeout,
1981 : struct file_id id,
1982 : struct deferred_open_record *open_rec)
1983 : {
1984 0 : struct tevent_req *req = NULL;
1985 0 : struct smbd_smb2_create_state *state = NULL;
1986 : struct timeval end_time;
1987 :
1988 0 : if (!smb2req) {
1989 0 : return false;
1990 : }
1991 0 : req = smb2req->subreq;
1992 0 : if (!req) {
1993 0 : return false;
1994 : }
1995 0 : state = tevent_req_data(req, struct smbd_smb2_create_state);
1996 0 : if (!state) {
1997 0 : return false;
1998 : }
1999 0 : state->id = id;
2000 0 : state->request_time = request_time;
2001 0 : state->open_rec = talloc_move(state, &open_rec);
2002 :
2003 : /* Re-schedule us to retry on timer expiry. */
2004 0 : end_time = timeval_sum(&request_time, &timeout);
2005 :
2006 0 : DEBUG(10,("push_deferred_open_message_smb2: "
2007 : "timeout at %s\n",
2008 : timeval_string(talloc_tos(),
2009 : &end_time,
2010 : true) ));
2011 :
2012 0 : state->open_was_deferred = true;
2013 :
2014 : /* allow this request to be canceled */
2015 0 : tevent_req_set_cancel_fn(req, smbd_smb2_create_cancel);
2016 :
2017 0 : return true;
2018 : }
|