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