2 Unix SMB/CIFS implementation.
5 Copyright (C) Stefan Metzmacher 2009
6 Copyright (C) Jeremy Allison 2010
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
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 "../librpc/gen_ndr/ndr_smb3posix.h"
31 #include "../lib/util/tevent_ntstatus.h"
33 #include "lib/util_ea.h"
34 #include "source3/passdb/lookup_sid.h"
35 #include "source3/modules/util_reparse.h"
36 #include "libcli/smb/reparse.h"
39 #define DBGC_CLASS DBGC_SMB2
41 int map_smb2_oplock_levels_to_samba(uint8_t in_oplock_level
)
43 switch(in_oplock_level
) {
44 case SMB2_OPLOCK_LEVEL_NONE
:
46 case SMB2_OPLOCK_LEVEL_II
:
47 return LEVEL_II_OPLOCK
;
48 case SMB2_OPLOCK_LEVEL_EXCLUSIVE
:
49 return EXCLUSIVE_OPLOCK
;
50 case SMB2_OPLOCK_LEVEL_BATCH
:
52 case SMB2_OPLOCK_LEVEL_LEASE
:
55 DEBUG(2,("map_smb2_oplock_levels_to_samba: "
57 (unsigned int)in_oplock_level
));
62 static uint8_t map_samba_oplock_levels_to_smb2(int oplock_type
)
64 if (BATCH_OPLOCK_TYPE(oplock_type
)) {
65 return SMB2_OPLOCK_LEVEL_BATCH
;
66 } else if (EXCLUSIVE_OPLOCK_TYPE(oplock_type
)) {
67 return SMB2_OPLOCK_LEVEL_EXCLUSIVE
;
68 } else if (oplock_type
== LEVEL_II_OPLOCK
) {
69 return SMB2_OPLOCK_LEVEL_II
;
70 } else if (oplock_type
== LEASE_OPLOCK
) {
71 return SMB2_OPLOCK_LEVEL_LEASE
;
73 return SMB2_OPLOCK_LEVEL_NONE
;
78 MS-FSA 2.1.5.1 Server Requests an Open of a File
79 Trailing '/' or '\\' checker.
80 Must be done before the filename parser removes any
81 trailing characters. If we decide to add this to SMB1
82 NTCreate processing we can make this public.
84 Note this is Windows pathname processing only. When
85 POSIX pathnames are added to SMB2 this will not apply.
88 static NTSTATUS
windows_name_trailing_check(const char *name
,
89 uint32_t create_options
)
91 size_t name_len
= strlen(name
);
98 trail_c
= name
[name_len
-1];
101 * Trailing '/' is always invalid.
103 if (trail_c
== '/') {
104 return NT_STATUS_OBJECT_NAME_INVALID
;
107 if (create_options
& FILE_NON_DIRECTORY_FILE
) {
108 if (trail_c
== '\\') {
109 return NT_STATUS_OBJECT_NAME_INVALID
;
115 static struct tevent_req
*smbd_smb2_create_send(TALLOC_CTX
*mem_ctx
,
116 struct tevent_context
*ev
,
117 struct smbd_smb2_request
*smb2req
,
118 uint8_t in_oplock_level
,
119 uint32_t in_impersonation_level
,
120 uint32_t in_desired_access
,
121 uint32_t in_file_attributes
,
122 uint32_t in_share_access
,
123 uint32_t in_create_disposition
,
124 uint32_t _in_create_options
,
126 struct smb2_create_blobs in_context_blobs
);
127 static NTSTATUS
smbd_smb2_create_recv(struct tevent_req
*req
,
129 uint8_t *out_oplock_level
,
130 uint32_t *out_create_action
,
131 struct timespec
*out_creation_ts
,
132 struct timespec
*out_last_access_ts
,
133 struct timespec
*out_last_write_ts
,
134 struct timespec
*out_change_ts
,
135 uint64_t *out_allocation_size
,
136 uint64_t *out_end_of_file
,
137 uint32_t *out_file_attributes
,
138 uint64_t *out_file_id_persistent
,
139 uint64_t *out_file_id_volatile
,
140 struct smb2_create_blobs
*out_context_blobs
,
141 struct reparse_data_buffer
**symlink_reparse
);
143 static void smbd_smb2_request_create_done(struct tevent_req
*tsubreq
);
144 NTSTATUS
smbd_smb2_request_process_create(struct smbd_smb2_request
*smb2req
)
146 const uint8_t *inbody
;
147 const struct iovec
*indyniov
;
148 uint8_t in_oplock_level
;
149 uint32_t in_impersonation_level
;
150 uint32_t in_desired_access
;
151 uint32_t in_file_attributes
;
152 uint32_t in_share_access
;
153 uint32_t in_create_disposition
;
154 uint32_t in_create_options
;
155 uint16_t in_name_offset
;
156 uint16_t in_name_length
;
157 DATA_BLOB in_name_buffer
;
158 char *in_name_string
;
159 size_t in_name_string_size
;
160 uint32_t name_offset
= 0;
161 uint32_t name_available_length
= 0;
162 uint32_t in_context_offset
;
163 uint32_t in_context_length
;
164 DATA_BLOB in_context_buffer
;
165 struct smb2_create_blobs in_context_blobs
;
166 uint32_t context_offset
= 0;
167 uint32_t context_available_length
= 0;
171 struct tevent_req
*tsubreq
;
173 status
= smbd_smb2_request_verify_sizes(smb2req
, 0x39);
174 if (!NT_STATUS_IS_OK(status
)) {
175 return smbd_smb2_request_error(smb2req
, status
);
177 inbody
= SMBD_SMB2_IN_BODY_PTR(smb2req
);
179 in_oplock_level
= CVAL(inbody
, 0x03);
180 in_impersonation_level
= IVAL(inbody
, 0x04);
181 in_desired_access
= IVAL(inbody
, 0x18);
182 in_file_attributes
= IVAL(inbody
, 0x1C);
183 in_share_access
= IVAL(inbody
, 0x20);
184 in_create_disposition
= IVAL(inbody
, 0x24);
185 in_create_options
= IVAL(inbody
, 0x28);
186 in_name_offset
= SVAL(inbody
, 0x2C);
187 in_name_length
= SVAL(inbody
, 0x2E);
188 in_context_offset
= IVAL(inbody
, 0x30);
189 in_context_length
= IVAL(inbody
, 0x34);
192 * First check if the dynamic name and context buffers
193 * are correctly specified.
195 * Note: That we don't check if the name and context buffers
199 dyn_offset
= SMB2_HDR_BODY
+ SMBD_SMB2_IN_BODY_LEN(smb2req
);
201 if (in_name_offset
== 0 && in_name_length
== 0) {
204 } else if (in_name_offset
< dyn_offset
) {
205 return smbd_smb2_request_error(smb2req
, NT_STATUS_INVALID_PARAMETER
);
207 name_offset
= in_name_offset
- dyn_offset
;
210 indyniov
= SMBD_SMB2_IN_DYN_IOV(smb2req
);
212 if (name_offset
> indyniov
->iov_len
) {
213 return smbd_smb2_request_error(smb2req
, NT_STATUS_INVALID_PARAMETER
);
216 name_available_length
= indyniov
->iov_len
- name_offset
;
218 if (in_name_length
> name_available_length
) {
219 return smbd_smb2_request_error(smb2req
, NT_STATUS_INVALID_PARAMETER
);
222 in_name_buffer
.data
= (uint8_t *)indyniov
->iov_base
+ name_offset
;
223 in_name_buffer
.length
= in_name_length
;
225 if (in_context_offset
== 0 && in_context_length
== 0) {
228 } else if (in_context_offset
< dyn_offset
) {
229 return smbd_smb2_request_error(smb2req
, NT_STATUS_INVALID_PARAMETER
);
231 context_offset
= in_context_offset
- dyn_offset
;
234 if (context_offset
> indyniov
->iov_len
) {
235 return smbd_smb2_request_error(smb2req
, NT_STATUS_INVALID_PARAMETER
);
238 context_available_length
= indyniov
->iov_len
- context_offset
;
240 if (in_context_length
> context_available_length
) {
241 return smbd_smb2_request_error(smb2req
, NT_STATUS_INVALID_PARAMETER
);
244 in_context_buffer
.data
= (uint8_t *)indyniov
->iov_base
+
246 in_context_buffer
.length
= in_context_length
;
249 * Now interpret the name and context buffers
252 ok
= convert_string_talloc(smb2req
, CH_UTF16
, CH_UNIX
,
254 in_name_buffer
.length
,
256 &in_name_string_size
);
258 return smbd_smb2_request_error(smb2req
, NT_STATUS_ILLEGAL_CHARACTER
);
261 if (in_name_buffer
.length
== 0) {
262 in_name_string_size
= 0;
265 if (strlen(in_name_string
) != in_name_string_size
) {
266 return smbd_smb2_request_error(smb2req
, NT_STATUS_OBJECT_NAME_INVALID
);
269 ZERO_STRUCT(in_context_blobs
);
270 status
= smb2_create_blob_parse(smb2req
, in_context_buffer
, &in_context_blobs
);
271 if (!NT_STATUS_IS_OK(status
)) {
272 return smbd_smb2_request_error(smb2req
, status
);
275 if (CHECK_DEBUGLVL(DBGLVL_DEBUG
)) {
276 char *str
= talloc_asprintf(
278 "\nGot %"PRIu32
" create blobs\n",
279 in_context_blobs
.num_blobs
);
282 for (i
=0; i
<in_context_blobs
.num_blobs
; i
++) {
283 struct smb2_create_blob
*b
=
284 &in_context_blobs
.blobs
[i
];
285 talloc_asprintf_addbuf(&str
, "[%"PRIu32
"]\n", i
);
287 (uint8_t *)b
->tag
, strlen(b
->tag
), &str
);
289 b
->data
.data
, b
->data
.length
, &str
);
291 DBG_DEBUG("%s", str
);
295 tsubreq
= smbd_smb2_create_send(smb2req
,
296 smb2req
->sconn
->ev_ctx
,
299 in_impersonation_level
,
303 in_create_disposition
,
307 if (tsubreq
== NULL
) {
308 smb2req
->subreq
= NULL
;
309 return smbd_smb2_request_error(smb2req
, NT_STATUS_NO_MEMORY
);
311 tevent_req_set_callback(tsubreq
, smbd_smb2_request_create_done
, smb2req
);
313 return smbd_smb2_request_pending_queue(smb2req
, tsubreq
, 500);
316 static uint64_t get_mid_from_smb2req(struct smbd_smb2_request
*smb2req
)
318 uint8_t *reqhdr
= SMBD_SMB2_OUT_HDR_PTR(smb2req
);
319 return BVAL(reqhdr
, SMB2_HDR_MESSAGE_ID
);
323 * [MS-SMB2] 2.2.2.1 SMB2 ERROR Context Response
325 static bool smbd_smb2_create_symlink_error_context_response(
327 struct reparse_data_buffer
*symlink_reparse
,
331 ssize_t symlink_buffer_len
;
332 size_t symlink_error_response_len
, error_context_response_len
;
333 uint8_t *resp
= NULL
;
335 SMB_ASSERT(symlink_reparse
->tag
== IO_REPARSE_TAG_SYMLINK
);
337 symlink_buffer_len
= reparse_data_buffer_marshall(symlink_reparse
,
340 if (symlink_buffer_len
< 0) {
341 DBG_DEBUG("reparse_data_buffer_marshall() failed\n");
345 /* 2.2.2.2.1 Symbolic Link Error Response */
346 symlink_error_response_len
= symlink_buffer_len
+ 8;
347 if (symlink_error_response_len
< (size_t)symlink_buffer_len
) {
351 /* 2.2.2.1 SMB2 ERROR Context Response */
352 error_context_response_len
= symlink_error_response_len
+ 8;
353 if (error_context_response_len
< symlink_error_response_len
) {
357 resp
= talloc_array(mem_ctx
, uint8_t, error_context_response_len
);
361 PUSH_LE_U32(resp
, 0, symlink_error_response_len
); /* ErrorDataLength */
362 PUSH_LE_U32(resp
, 4, 0); /* ErrorId */
365 symlink_error_response_len
- 4); /* SymLinkLength */
366 PUSH_LE_U32(resp
, 12, 0x4C4D5953);
368 reparse_data_buffer_marshall(symlink_reparse
,
373 *_resplen
= error_context_response_len
;
380 static NTSTATUS
smbd_smb2_create_error(
381 struct smbd_smb2_request
*smb2req
,
383 struct reparse_data_buffer
*symlink_reparse
)
385 struct smbXsrv_connection
*xconn
= smb2req
->xconn
;
392 if (!NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
393 error
= smbd_smb2_request_error(smb2req
, status
);
397 ok
= smbd_smb2_create_symlink_error_context_response(smb2req
,
402 error
= smbd_smb2_request_error(smb2req
, NT_STATUS_NO_MEMORY
);
406 if (xconn
->protocol
< PROTOCOL_SMB3_11
) {
408 * smbd_smb2_create_symlink_error_context_response()
409 * has created a smb3.11 SMB2 ERROR Context from
410 * [MS-SMB2] 2.2.2.1. This has an 8-byte header before
411 * the symlink response.
413 DATA_BLOB symlink_error
= {
414 .data
= resp
.data
+ 8,
415 .length
= resp
.length
- 8,
418 SMB_ASSERT(resp
.length
>= 8);
420 error
= smbd_smb2_request_error_ex(
422 NT_STATUS_STOPPED_ON_SYMLINK
,
427 error
= smbd_smb2_request_error_ex(
429 NT_STATUS_STOPPED_ON_SYMLINK
,
438 static void smbd_smb2_request_create_done(struct tevent_req
*tsubreq
)
440 struct smbd_smb2_request
*smb2req
= tevent_req_callback_data(tsubreq
,
441 struct smbd_smb2_request
);
444 uint8_t out_oplock_level
= 0;
445 uint32_t out_create_action
= 0;
446 connection_struct
*conn
= smb2req
->tcon
->compat
;
447 struct timespec out_creation_ts
= { 0, };
448 struct timespec out_last_access_ts
= { 0, };
449 struct timespec out_last_write_ts
= { 0, };
450 struct timespec out_change_ts
= { 0, };
451 uint64_t out_allocation_size
= 0;
452 uint64_t out_end_of_file
= 0;
453 uint32_t out_file_attributes
= 0;
454 uint64_t out_file_id_persistent
= 0;
455 uint64_t out_file_id_volatile
= 0;
456 struct smb2_create_blobs out_context_blobs
;
457 DATA_BLOB out_context_buffer
;
458 uint16_t out_context_buffer_offset
= 0;
459 struct reparse_data_buffer
*symlink_reparse
= NULL
;
461 NTSTATUS error
; /* transport error */
463 status
= smbd_smb2_create_recv(tsubreq
,
471 &out_allocation_size
,
473 &out_file_attributes
,
474 &out_file_id_persistent
,
475 &out_file_id_volatile
,
478 if (!NT_STATUS_IS_OK(status
)) {
479 if (smbd_smb2_is_compound(smb2req
)) {
480 smb2req
->compound_create_err
= status
;
482 error
= smbd_smb2_create_error(smb2req
,
485 if (!NT_STATUS_IS_OK(error
)) {
486 smbd_server_connection_terminate(smb2req
->xconn
,
493 status
= smb2_create_blob_push(smb2req
, &out_context_buffer
, out_context_blobs
);
494 if (!NT_STATUS_IS_OK(status
)) {
495 error
= smbd_smb2_request_error(smb2req
, status
);
496 if (!NT_STATUS_IS_OK(error
)) {
497 smbd_server_connection_terminate(smb2req
->xconn
,
504 if (out_context_buffer
.length
> 0) {
505 out_context_buffer_offset
= SMB2_HDR_BODY
+ 0x58;
508 outbody
= smbd_smb2_generate_outbody(smb2req
, 0x58);
509 if (outbody
.data
== NULL
) {
510 error
= smbd_smb2_request_error(smb2req
, NT_STATUS_NO_MEMORY
);
511 if (!NT_STATUS_IS_OK(error
)) {
512 smbd_server_connection_terminate(smb2req
->xconn
,
519 SSVAL(outbody
.data
, 0x00, 0x58 + 1); /* struct size */
520 SCVAL(outbody
.data
, 0x02,
521 out_oplock_level
); /* oplock level */
522 SCVAL(outbody
.data
, 0x03, 0); /* reserved */
523 SIVAL(outbody
.data
, 0x04,
524 out_create_action
); /* create action */
525 put_long_date_full_timespec(conn
->ts_res
,
526 (char *)outbody
.data
+ 0x08,
527 &out_creation_ts
); /* creation time */
528 put_long_date_full_timespec(conn
->ts_res
,
529 (char *)outbody
.data
+ 0x10,
530 &out_last_access_ts
); /* last access time */
531 put_long_date_full_timespec(conn
->ts_res
,
532 (char *)outbody
.data
+ 0x18,
533 &out_last_write_ts
); /* last write time */
534 put_long_date_full_timespec(conn
->ts_res
,
535 (char *)outbody
.data
+ 0x20,
536 &out_change_ts
); /* change time */
537 SBVAL(outbody
.data
, 0x28,
538 out_allocation_size
); /* allocation size */
539 SBVAL(outbody
.data
, 0x30,
540 out_end_of_file
); /* end of file */
541 SIVAL(outbody
.data
, 0x38,
542 out_file_attributes
); /* file attributes */
543 SIVAL(outbody
.data
, 0x3C, 0); /* reserved */
544 SBVAL(outbody
.data
, 0x40,
545 out_file_id_persistent
); /* file id (persistent) */
546 SBVAL(outbody
.data
, 0x48,
547 out_file_id_volatile
); /* file id (volatile) */
548 SIVAL(outbody
.data
, 0x50,
549 out_context_buffer_offset
); /* create contexts offset */
550 SIVAL(outbody
.data
, 0x54,
551 out_context_buffer
.length
); /* create contexts length */
553 outdyn
= out_context_buffer
;
555 error
= smbd_smb2_request_done(smb2req
, outbody
, &outdyn
);
556 if (!NT_STATUS_IS_OK(error
)) {
557 smbd_server_connection_terminate(smb2req
->xconn
,
563 static bool smb2_lease_key_valid(const struct smb2_lease_key
*key
)
565 return ((key
->data
[0] != 0) || (key
->data
[1] != 0));
568 static NTSTATUS
smbd_smb2_create_durable_lease_check(struct smb_request
*smb1req
,
569 const char *requested_filename
, const struct files_struct
*fsp
,
570 const struct smb2_lease
*lease_ptr
)
572 struct files_struct
*dirfsp
= NULL
;
573 char *filename
= NULL
;
574 struct smb_filename
*smb_fname
= NULL
;
576 NTTIME twrp
= fsp
->fsp_name
->twrp
;
578 bool is_dfs
= (smb1req
->flags2
& FLAGS2_DFS_PATHNAMES
);
579 bool is_posix
= (fsp
->fsp_name
->flags
& SMB_FILENAME_POSIX_PATH
);
581 if (lease_ptr
== NULL
) {
582 if (fsp
->oplock_type
!= LEASE_OPLOCK
) {
585 DEBUG(10, ("Reopened file has lease, but no lease "
587 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
590 if (fsp
->oplock_type
!= LEASE_OPLOCK
) {
591 DEBUG(10, ("Lease requested, but reopened file has no "
593 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
596 if (!smb2_lease_key_equal(&lease_ptr
->lease_key
,
597 &fsp
->lease
->lease
.lease_key
)) {
598 DEBUG(10, ("Different lease key requested than found "
599 "in reopened file\n"));
600 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
604 const char *non_dfs_requested_filename
= NULL
;
606 * With a DFS flag set, remove any DFS prefix
607 * before further processing.
609 status
= smb2_strip_dfs_path(requested_filename
,
610 &non_dfs_requested_filename
);
611 if (!NT_STATUS_IS_OK(status
)) {
615 * TODO: Note for dealing with reparse point errors.
616 * We will need to remember and store the number of characters
617 * we have removed here, which is
618 * (requested_filename - non_dfs_requested_filename)
619 * in order to correctly report how many characters we
620 * have removed before hitting the reparse point.
621 * This will be a patch needed once we properly
622 * deal with reparse points later.
624 requested_filename
= non_dfs_requested_filename
;
626 * Now we're no longer dealing with a DFS path, so
629 smb1req
->flags2
&= ~FLAGS2_DFS_PATHNAMES
;
633 filename
= talloc_strdup(talloc_tos(), requested_filename
);
634 if (filename
== NULL
) {
635 return NT_STATUS_NO_MEMORY
;
638 /* This also converts '\' to '/' */
639 status
= check_path_syntax(filename
, is_posix
);
640 if (!NT_STATUS_IS_OK(status
)) {
641 TALLOC_FREE(filename
);
645 ucf_flags
= filename_create_ucf_flags(smb1req
, FILE_OPEN
, 0);
646 status
= filename_convert_dirfsp(talloc_tos(),
653 TALLOC_FREE(filename
);
654 if (!NT_STATUS_IS_OK(status
)) {
655 DEBUG(10, ("filename_convert returned %s\n",
660 if (!strequal(fsp
->fsp_name
->base_name
, smb_fname
->base_name
)) {
661 DEBUG(10, ("Lease requested for file %s, reopened file "
662 "is named %s\n", smb_fname
->base_name
,
663 fsp
->fsp_name
->base_name
));
664 TALLOC_FREE(smb_fname
);
665 return NT_STATUS_INVALID_PARAMETER
;
668 TALLOC_FREE(smb_fname
);
673 struct smbd_smb2_create_state
{
674 struct tevent_context
*ev
;
675 struct smbd_smb2_request
*smb2req
;
676 struct GUID req_guid
;
677 struct smb_request
*smb1req
;
678 bool open_was_deferred
;
679 struct tevent_immediate
*im
;
680 struct timeval request_time
;
682 struct deferred_open_record
*open_rec
;
683 files_struct
*result
;
684 bool replay_operation
;
685 uint8_t in_oplock_level
;
686 uint32_t in_create_disposition
;
687 uint32_t in_create_options
;
688 int requested_oplock_level
;
691 struct ea_list
*ea_list
;
692 NTTIME max_access_time
;
693 struct security_descriptor
*sec_desc
;
694 uint64_t allocation_size
;
695 struct GUID _create_guid
;
696 struct GUID
*create_guid
;
697 struct GUID _purge_create_guid
;
698 struct GUID
*purge_create_guid
;
700 bool durable_requested
;
701 uint32_t durable_timeout_msec
;
702 bool do_durable_reconnect
;
703 uint64_t persistent_id
;
704 struct smb2_lease lease
;
705 struct smb2_lease
*lease_ptr
;
707 bool need_replay_cache
;
708 struct smbXsrv_open
*op
;
711 struct smb2_create_blob
*dhnc
;
712 struct smb2_create_blob
*dh2c
;
713 struct smb2_create_blob
*dhnq
;
714 struct smb2_create_blob
*dh2q
;
715 struct smb2_create_blob
*rqls
;
716 struct smb2_create_blob
*exta
;
717 struct smb2_create_blob
*mxac
;
718 struct smb2_create_blob
*secd
;
719 struct smb2_create_blob
*alsi
;
720 struct smb2_create_blob
*twrp
;
721 struct smb2_create_blob
*qfid
;
722 struct smb2_create_blob
*posx
;
723 struct smb2_create_blob
*svhdx
;
725 uint8_t out_oplock_level
;
726 uint32_t out_create_action
;
727 struct timespec out_creation_ts
;
728 struct timespec out_last_access_ts
;
729 struct timespec out_last_write_ts
;
730 struct timespec out_change_ts
;
731 uint64_t out_allocation_size
;
732 uint64_t out_end_of_file
;
733 uint32_t out_file_attributes
;
734 uint64_t out_file_id_persistent
;
735 uint64_t out_file_id_volatile
;
736 struct smb2_create_blobs
*out_context_blobs
;
738 /* symlink error data */
739 struct reparse_data_buffer
*symlink_err
;
742 static void smbd_smb2_create_purge_replay_cache(struct tevent_req
*req
,
743 const char *caller_func
);
745 static void smbd_smb2_create_cleanup(struct tevent_req
*req
,
746 enum tevent_req_state req_state
)
748 smbd_smb2_create_purge_replay_cache(req
, __func__
);
751 static NTSTATUS
smbd_smb2_create_fetch_create_ctx(
752 struct tevent_req
*req
,
753 struct smb2_create_blobs
*in_context_blobs
)
755 struct smbd_smb2_create_state
*state
= tevent_req_data(
756 req
, struct smbd_smb2_create_state
);
757 struct smbd_smb2_request
*smb2req
= state
->smb2req
;
758 struct smbXsrv_connection
*xconn
= smb2req
->xconn
;
760 state
->dhnq
= smb2_create_blob_find(in_context_blobs
,
761 SMB2_CREATE_TAG_DHNQ
);
762 state
->dhnc
= smb2_create_blob_find(in_context_blobs
,
763 SMB2_CREATE_TAG_DHNC
);
764 state
->dh2q
= smb2_create_blob_find(in_context_blobs
,
765 SMB2_CREATE_TAG_DH2Q
);
766 state
->dh2c
= smb2_create_blob_find(in_context_blobs
,
767 SMB2_CREATE_TAG_DH2C
);
768 if (xconn
->smb2
.server
.capabilities
& SMB2_CAP_LEASING
) {
769 state
->rqls
= smb2_create_blob_find(in_context_blobs
,
770 SMB2_CREATE_TAG_RQLS
);
773 if (((state
->dhnc
!= NULL
) && (state
->dh2c
!= NULL
)) ||
774 ((state
->dhnc
!= NULL
) && (state
->dh2q
!= NULL
)) ||
775 ((state
->dh2c
!= NULL
) && (state
->dhnq
!= NULL
)) ||
776 ((state
->dh2q
!= NULL
) && (state
->dh2c
!= NULL
)))
778 /* not both are allowed at the same time */
779 return NT_STATUS_INVALID_PARAMETER
;
782 if (state
->dhnc
!= NULL
) {
783 uint32_t num_blobs_allowed
;
785 if (state
->dhnc
->data
.length
!= 16) {
786 return NT_STATUS_INVALID_PARAMETER
;
790 * According to MS-SMB2: 3.3.5.9.7, "Handling the
791 * SMB2_CREATE_DURABLE_HANDLE_RECONNECT Create Context",
792 * we should ignore an additional dhnq blob, but fail
793 * the request (with status OBJECT_NAME_NOT_FOUND) if
794 * any other extra create blob has been provided.
796 * (Note that the cases of an additional dh2q or dh2c blob
797 * which require a different error code, have been treated
801 if (state
->dhnq
!= NULL
) {
802 num_blobs_allowed
= 2;
804 num_blobs_allowed
= 1;
807 if (state
->rqls
!= NULL
) {
808 num_blobs_allowed
+= 1;
811 if (in_context_blobs
->num_blobs
!= num_blobs_allowed
) {
812 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
816 if (state
->dh2c
!= NULL
) {
817 uint32_t num_blobs_allowed
;
819 if (state
->dh2c
->data
.length
!= 36) {
820 return NT_STATUS_INVALID_PARAMETER
;
824 * According to MS-SMB2: 3.3.5.9.12, "Handling the
825 * SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 Create Context",
826 * we should fail the request with status
827 * OBJECT_NAME_NOT_FOUND if any other create blob has been
830 * (Note that the cases of an additional dhnq, dhnc or dh2q
831 * blob which require a different error code, have been
835 num_blobs_allowed
= 1;
837 if (state
->rqls
!= NULL
) {
838 num_blobs_allowed
+= 1;
841 if (in_context_blobs
->num_blobs
!= num_blobs_allowed
) {
842 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
846 state
->exta
= smb2_create_blob_find(in_context_blobs
,
847 SMB2_CREATE_TAG_EXTA
);
848 state
->mxac
= smb2_create_blob_find(in_context_blobs
,
849 SMB2_CREATE_TAG_MXAC
);
850 state
->secd
= smb2_create_blob_find(in_context_blobs
,
851 SMB2_CREATE_TAG_SECD
);
852 state
->alsi
= smb2_create_blob_find(in_context_blobs
,
853 SMB2_CREATE_TAG_ALSI
);
854 state
->twrp
= smb2_create_blob_find(in_context_blobs
,
855 SMB2_CREATE_TAG_TWRP
);
856 state
->qfid
= smb2_create_blob_find(in_context_blobs
,
857 SMB2_CREATE_TAG_QFID
);
858 if (xconn
->protocol
>= PROTOCOL_SMB3_02
) {
860 * This was introduced with SMB3_02
862 state
->svhdx
= smb2_create_blob_find(
863 in_context_blobs
, SVHDX_OPEN_DEVICE_CONTEXT
);
865 if (xconn
->smb2
.server
.posix_extensions_negotiated
&&
866 lp_smb3_unix_extensions(SNUM(state
->smb1req
->conn
)))
869 * Negprot only allowed this for proto>=3.11
871 SMB_ASSERT(xconn
->protocol
>= PROTOCOL_SMB3_11
);
873 state
->posx
= smb2_create_blob_find(
874 in_context_blobs
, SMB2_CREATE_TAG_POSIX
);
876 * Setting the bool below will cause
877 * ucf_flags_from_smb_request() to
878 * return UCF_POSIX_PATHNAMES in ucf_flags.
880 state
->smb1req
->posix_pathnames
= (state
->posx
!= NULL
);
886 static void smbd_smb2_create_before_exec(struct tevent_req
*req
);
887 static void smbd_smb2_create_after_exec(struct tevent_req
*req
);
888 static void smbd_smb2_create_finish(struct tevent_req
*req
);
890 static struct tevent_req
*smbd_smb2_create_send(TALLOC_CTX
*mem_ctx
,
891 struct tevent_context
*ev
,
892 struct smbd_smb2_request
*smb2req
,
893 uint8_t in_oplock_level
,
894 uint32_t in_impersonation_level
,
895 uint32_t in_desired_access
,
896 uint32_t in_file_attributes
,
897 uint32_t in_share_access
,
898 uint32_t in_create_disposition
,
899 uint32_t _in_create_options
,
901 struct smb2_create_blobs in_context_blobs
)
903 struct tevent_req
*req
= NULL
;
904 struct smbd_smb2_create_state
*state
= NULL
;
906 struct smb_request
*smb1req
= NULL
;
907 struct files_struct
*dirfsp
= NULL
;
908 struct smb_filename
*smb_fname
= NULL
;
911 bool is_posix
= false;
913 req
= tevent_req_create(mem_ctx
, &state
,
914 struct smbd_smb2_create_state
);
918 *state
= (struct smbd_smb2_create_state
) {
921 .in_oplock_level
= in_oplock_level
,
922 .in_create_disposition
= in_create_disposition
,
923 .in_create_options
= _in_create_options
,
926 smb1req
= smbd_smb2_fake_smb_request(smb2req
, NULL
);
927 if (tevent_req_nomem(smb1req
, req
)) {
928 return tevent_req_post(req
, state
->ev
);
930 state
->smb1req
= smb1req
;
932 state
->req_guid
= smbd_request_guid(smb1req
, 0);
934 tevent_req_set_cleanup_fn(req
, smbd_smb2_create_cleanup
);
936 if (smb2req
->subreq
== NULL
) {
937 DBG_DEBUG("name [%s]\n", in_name
);
939 struct smbd_smb2_create_state
*old_state
= tevent_req_data(
940 smb2req
->subreq
, struct smbd_smb2_create_state
);
942 DBG_DEBUG("reentrant for file %s\n", in_name
);
944 state
->id
= old_state
->id
;
945 state
->request_time
= old_state
->request_time
;
946 state
->open_rec
= talloc_move(state
, &old_state
->open_rec
);
947 state
->open_was_deferred
= old_state
->open_was_deferred
;
948 state
->_purge_create_guid
= old_state
->_purge_create_guid
;
949 state
->purge_create_guid
= old_state
->purge_create_guid
;
950 old_state
->purge_create_guid
= NULL
;
953 TALLOC_FREE(smb2req
->subreq
);
954 smb2req
->subreq
= req
;
956 if (lp_fake_oplocks(SNUM(smb2req
->tcon
->compat
))) {
957 state
->requested_oplock_level
= SMB2_OPLOCK_LEVEL_NONE
;
959 state
->requested_oplock_level
= state
->in_oplock_level
;
962 /* these are ignored for SMB2 */
963 state
->in_create_options
&= ~(0x10); /* NTCREATEX_OPTIONS_SYNC_ALERT */
964 state
->in_create_options
&= ~(0x20); /* NTCREATEX_OPTIONS_ASYNC_ALERT */
966 in_file_attributes
&= ~FILE_FLAG_POSIX_SEMANTICS
;
968 is_dfs
= (smb1req
->flags2
& FLAGS2_DFS_PATHNAMES
);
970 const char *non_dfs_in_name
= NULL
;
972 * With a DFS flag set, remove any DFS prefix
973 * before further processing.
975 status
= smb2_strip_dfs_path(in_name
, &non_dfs_in_name
);
976 if (!NT_STATUS_IS_OK(status
)) {
977 tevent_req_nterror(req
, status
);
978 return tevent_req_post(req
, state
->ev
);
981 * TODO: Note for dealing with reparse point errors.
982 * We will need to remember and store the number of characters
983 * we have removed here, which is (non_dfs_in_name - in_name)
984 * in order to correctly report how many characters we
985 * have removed before hitting the reparse point.
986 * This will be a patch needed once we properly
987 * deal with reparse points later.
989 in_name
= non_dfs_in_name
;
991 * Now we're no longer dealing with a DFS path, so
994 smb1req
->flags2
&= ~FLAGS2_DFS_PATHNAMES
;
998 state
->fname
= talloc_strdup(state
, in_name
);
999 if (tevent_req_nomem(state
->fname
, req
)) {
1000 return tevent_req_post(req
, state
->ev
);
1003 state
->out_context_blobs
= talloc_zero(state
, struct smb2_create_blobs
);
1004 if (tevent_req_nomem(state
->out_context_blobs
, req
)) {
1005 return tevent_req_post(req
, state
->ev
);
1008 status
= smbd_smb2_create_fetch_create_ctx(req
, &in_context_blobs
);
1009 if (tevent_req_nterror(req
, status
)) {
1010 return tevent_req_post(req
, state
->ev
);
1013 if (IS_IPC(smb1req
->conn
)) {
1014 const char *pipe_name
= in_name
;
1016 if (state
->dhnc
!= NULL
|| state
->dh2c
!= NULL
) {
1017 /* durable handles are not supported on IPC$ */
1018 tevent_req_nterror(req
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
1019 return tevent_req_post(req
, state
->ev
);
1022 if (!lp_nt_pipe_support()) {
1023 tevent_req_nterror(req
, NT_STATUS_ACCESS_DENIED
);
1024 return tevent_req_post(req
, state
->ev
);
1027 status
= open_np_file(smb1req
, pipe_name
, &state
->result
);
1028 if (tevent_req_nterror(req
, status
)) {
1029 return tevent_req_post(req
, state
->ev
);
1031 state
->info
= FILE_WAS_OPENED
;
1033 smbd_smb2_create_finish(req
);
1037 if (CAN_PRINT(smb1req
->conn
)) {
1038 if (state
->dhnc
!= NULL
|| state
->dh2c
!= NULL
) {
1039 /* durable handles are not supported on printers */
1040 tevent_req_nterror(req
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
1041 return tevent_req_post(req
, state
->ev
);
1044 status
= file_new(smb1req
, smb1req
->conn
, &state
->result
);
1045 if (tevent_req_nterror(req
, status
)) {
1046 return tevent_req_post(req
, state
->ev
);
1049 status
= print_spool_open(state
->result
, in_name
,
1051 if (tevent_req_nterror(req
, status
)) {
1052 file_free(smb1req
, state
->result
);
1053 return tevent_req_post(req
, state
->ev
);
1055 state
->info
= FILE_WAS_CREATED
;
1057 smbd_smb2_create_finish(req
);
1061 /* Check for trailing slash specific directory handling. */
1062 status
= windows_name_trailing_check(state
->fname
,
1063 state
->in_create_options
);
1064 if (tevent_req_nterror(req
, status
)) {
1065 return tevent_req_post(req
, state
->ev
);
1068 smbd_smb2_create_before_exec(req
);
1069 if (!tevent_req_is_in_progress(req
)) {
1070 return tevent_req_post(req
, state
->ev
);
1073 DBG_DEBUG("open execution phase\n");
1076 * For the backend file open procedure, there are
1077 * three possible modes: replay operation (in which case
1078 * there is nothing else to do), durable_reconnect or
1081 if (state
->replay_operation
) {
1082 state
->result
= state
->op
->compat
;
1083 state
->result
->op
= state
->op
;
1084 state
->update_open
= false;
1085 state
->info
= state
->op
->create_action
;
1087 smbd_smb2_create_after_exec(req
);
1088 if (!tevent_req_is_in_progress(req
)) {
1089 return tevent_req_post(req
, state
->ev
);
1092 smbd_smb2_create_finish(req
);
1096 if (state
->do_durable_reconnect
) {
1097 DATA_BLOB new_cookie
= data_blob_null
;
1098 NTTIME now
= timeval_to_nttime(&smb2req
->request_time
);
1100 status
= smb2srv_open_recreate(smb2req
->xconn
,
1101 smb1req
->conn
->session_info
,
1102 state
->persistent_id
,
1106 if (tevent_req_nterror(req
, status
)) {
1107 DBG_NOTICE("smb2srv_open_recreate failed: %s\n",
1109 return tevent_req_post(req
, state
->ev
);
1112 DBG_DEBUG("%s to recreate durable handle\n",
1113 state
->op
->global
->durable
? "succeeded" : "failed");
1115 if (!state
->op
->global
->durable
) {
1116 talloc_free(state
->op
);
1117 tevent_req_nterror(req
,
1118 NT_STATUS_OBJECT_NAME_NOT_FOUND
);
1119 return tevent_req_post(req
, state
->ev
);
1122 status
= SMB_VFS_DURABLE_RECONNECT(smb1req
->conn
,
1124 state
->op
, /* smbXsrv_open input */
1125 state
->op
->global
->backend_cookie
,
1126 state
->op
, /* TALLOC_CTX */
1129 if (!NT_STATUS_IS_OK(status
)) {
1130 NTSTATUS return_status
;
1132 return_status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1134 DBG_NOTICE("durable_reconnect failed: %s => %s\n",
1136 nt_errstr(return_status
));
1138 tevent_req_nterror(req
, return_status
);
1139 return tevent_req_post(req
, state
->ev
);
1142 DBG_DEBUG("oplock_type=%u, lease_ptr==%p\n",
1143 (unsigned)state
->result
->oplock_type
, state
->lease_ptr
);
1145 status
= smbd_smb2_create_durable_lease_check(
1146 smb1req
, state
->fname
, state
->result
, state
->lease_ptr
);
1147 if (tevent_req_nterror(req
, status
)) {
1149 smb1req
, &state
->result
, SHUTDOWN_CLOSE
);
1150 return tevent_req_post(req
, state
->ev
);
1153 data_blob_free(&state
->op
->global
->backend_cookie
);
1154 state
->op
->global
->backend_cookie
= new_cookie
;
1156 state
->op
->status
= NT_STATUS_OK
;
1157 state
->op
->global
->disconnect_time
= 0;
1159 /* save the timeout for later update */
1160 state
->durable_timeout_msec
= state
->op
->global
->durable_timeout_msec
;
1162 state
->update_open
= true;
1164 state
->info
= FILE_WAS_OPENED
;
1166 smbd_smb2_create_after_exec(req
);
1167 if (!tevent_req_is_in_progress(req
)) {
1168 return tevent_req_post(req
, state
->ev
);
1171 smbd_smb2_create_finish(req
);
1175 if (state
->requested_oplock_level
== SMB2_OPLOCK_LEVEL_LEASE
) {
1176 if (state
->lease_ptr
== NULL
) {
1177 state
->requested_oplock_level
= SMB2_OPLOCK_LEVEL_NONE
;
1180 state
->lease_ptr
= NULL
;
1183 is_posix
= (state
->posx
!= NULL
);
1185 /* convert '\\' into '/' */
1186 status
= check_path_syntax(state
->fname
, is_posix
);
1187 if (tevent_req_nterror(req
, status
)) {
1188 return tevent_req_post(req
, state
->ev
);
1191 ucf_flags
= filename_create_ucf_flags(smb1req
,
1192 state
->in_create_disposition
,
1193 state
->in_create_options
);
1195 if (lp_follow_symlinks(SNUM(smb1req
->conn
)) &&
1196 (state
->posx
== NULL
)) {
1197 status
= filename_convert_dirfsp(mem_ctx
,
1205 struct smb_filename
*smb_fname_rel
= NULL
;
1207 status
= filename_convert_dirfsp_nosymlink(
1210 smb1req
->conn
->cwd_fsp
,
1217 &state
->symlink_err
);
1218 TALLOC_FREE(smb_fname_rel
);
1220 if ((state
->symlink_err
!= NULL
) &&
1221 !(state
->in_create_options
& FILE_OPEN_REPARSE_POINT
))
1223 if (dirfsp
!= NULL
) {
1224 close_file_free(NULL
, &dirfsp
, ERROR_CLOSE
);
1226 TALLOC_FREE(smb_fname
);
1227 TALLOC_FREE(smb_fname_rel
);
1228 status
= NT_STATUS_STOPPED_ON_SYMLINK
;
1231 if (tevent_req_nterror(req
, status
)) {
1232 return tevent_req_post(req
, state
->ev
);
1236 * MS-SMB2: 2.2.13 SMB2 CREATE Request
1237 * ImpersonationLevel ... MUST contain one of the
1238 * following values. The server MUST validate this
1239 * field, but otherwise ignore it.
1241 * NB. The source4/torture/smb2/durable_open.c test
1242 * shows this check is only done on real opens, not
1243 * on durable handle-reopens.
1246 if (in_impersonation_level
>
1247 SMB2_IMPERSONATION_DELEGATE
) {
1248 tevent_req_nterror(req
,
1249 NT_STATUS_BAD_IMPERSONATION_LEVEL
);
1250 return tevent_req_post(req
, state
->ev
);
1254 * We know we're going to do a local open, so now
1255 * we must be protocol strict. JRA.
1257 * MS-SMB2: 3.3.5.9 - Receiving an SMB2 CREATE Request
1258 * If the file name length is greater than zero and the
1259 * first character is a path separator character, the
1260 * server MUST fail the request with
1261 * STATUS_INVALID_PARAMETER.
1263 if (in_name
[0] == '/') {
1264 /* Names starting with '/' are never allowed. */
1265 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
1266 return tevent_req_post(req
, ev
);
1268 if (!is_posix
&& (in_name
[0] == '\\')) {
1270 * Windows names starting with '\' are not allowed.
1272 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
1273 return tevent_req_post(req
, ev
);
1276 status
= SMB_VFS_CREATE_FILE(smb1req
->conn
,
1282 state
->in_create_disposition
,
1283 state
->in_create_options
,
1285 map_smb2_oplock_levels_to_samba(
1286 state
->requested_oplock_level
),
1288 state
->allocation_size
,
1289 0, /* private_flags */
1295 state
->out_context_blobs
);
1296 if (NT_STATUS_IS_OK(status
) &&
1297 !(state
->in_create_options
& FILE_OPEN_REPARSE_POINT
))
1300 mode_t mode
= state
->result
->fsp_name
->st
.st_ex_mode
;
1302 if (!(S_ISREG(mode
) || S_ISDIR(mode
))) {
1304 * Only open files and dirs without
1305 * FILE_OPEN_REPARSE_POINT
1307 close_file_free(smb1req
, &state
->result
, ERROR_CLOSE
);
1308 status
= NT_STATUS_IO_REPARSE_TAG_NOT_HANDLED
;
1311 if (!NT_STATUS_IS_OK(status
)) {
1312 if (open_was_deferred(smb1req
->xconn
, smb1req
->mid
)) {
1313 SMBPROFILE_IOBYTES_ASYNC_SET_IDLE(smb2req
->profile
);
1316 tevent_req_nterror(req
, status
);
1317 return tevent_req_post(req
, state
->ev
);
1319 state
->op
= state
->result
->op
;
1321 smbd_smb2_create_after_exec(req
);
1322 if (!tevent_req_is_in_progress(req
)) {
1323 return tevent_req_post(req
, state
->ev
);
1326 smbd_smb2_create_finish(req
);
1330 static void smbd_smb2_create_purge_replay_cache(struct tevent_req
*req
,
1331 const char *caller_func
)
1333 struct smbd_smb2_create_state
*state
= tevent_req_data(
1334 req
, struct smbd_smb2_create_state
);
1337 if (state
->purge_create_guid
== NULL
) {
1341 status
= smbXsrv_open_purge_replay_cache(state
->smb2req
->xconn
->client
,
1342 state
->purge_create_guid
);
1343 if (!NT_STATUS_IS_OK(status
)) {
1344 struct GUID_txt_buf buf
;
1346 D_ERR("%s: smbXsrv_open_purge_replay_cache(%s) %s\n",
1348 GUID_buf_string(state
->purge_create_guid
, &buf
),
1352 state
->purge_create_guid
= NULL
;
1355 static void smbd_smb2_create_before_exec(struct tevent_req
*req
)
1357 struct smbd_smb2_create_state
*state
= tevent_req_data(
1358 req
, struct smbd_smb2_create_state
);
1359 struct smbd_smb2_request
*smb2req
= state
->smb2req
;
1362 if (state
->exta
!= NULL
) {
1363 if (!lp_ea_support(SNUM(smb2req
->tcon
->compat
))) {
1364 tevent_req_nterror(req
, NT_STATUS_EAS_NOT_SUPPORTED
);
1368 state
->ea_list
= read_nttrans_ea_list(
1370 (const char *)state
->exta
->data
.data
,
1371 state
->exta
->data
.length
);
1372 if (state
->ea_list
== NULL
) {
1373 DEBUG(10,("smbd_smb2_create_send: read_ea_name_list failed.\n"));
1374 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
1378 if ((state
->posx
== NULL
) &&
1379 ea_list_has_invalid_name(state
->ea_list
)) {
1380 tevent_req_nterror(req
, STATUS_INVALID_EA_NAME
);
1385 if (state
->mxac
!= NULL
) {
1386 if (state
->mxac
->data
.length
== 0) {
1387 state
->max_access_time
= 0;
1388 } else if (state
->mxac
->data
.length
== 8) {
1389 state
->max_access_time
= BVAL(state
->mxac
->data
.data
, 0);
1391 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
1396 if (state
->secd
!= NULL
) {
1397 enum ndr_err_code ndr_err
;
1399 state
->sec_desc
= talloc_zero(state
, struct security_descriptor
);
1400 if (tevent_req_nomem(state
->sec_desc
, req
)) {
1404 ndr_err
= ndr_pull_struct_blob(&state
->secd
->data
,
1405 state
->sec_desc
, state
->sec_desc
,
1406 (ndr_pull_flags_fn_t
)ndr_pull_security_descriptor
);
1407 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1408 DEBUG(2,("ndr_pull_security_descriptor failed: %s\n",
1409 ndr_errstr(ndr_err
)));
1410 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
1415 if (state
->dhnq
!= NULL
) {
1416 if (state
->dhnq
->data
.length
!= 16) {
1417 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
1421 if (state
->dh2q
!= NULL
) {
1422 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
1427 * durable handle request is processed below.
1429 state
->durable_requested
= true;
1431 * Set the timeout to 16 mins.
1433 * TODO: test this against Windows 2012
1434 * as the default for durable v2 is 1 min.
1436 state
->durable_timeout_msec
= (16*60*1000);
1439 if (state
->dh2q
!= NULL
) {
1440 const uint8_t *p
= state
->dh2q
->data
.data
;
1441 NTTIME now
= timeval_to_nttime(&smb2req
->request_time
);
1442 uint32_t durable_v2_timeout
= 0;
1443 DATA_BLOB create_guid_blob
;
1447 if (state
->dh2q
->data
.length
!= 32) {
1448 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
1452 if (state
->dhnq
!= NULL
) {
1453 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
1457 durable_v2_timeout
= IVAL(p
, 0);
1458 create_guid_blob
= data_blob_const(p
+ 16, 16);
1460 status
= GUID_from_ndr_blob(&create_guid_blob
,
1461 &state
->_create_guid
);
1462 if (tevent_req_nterror(req
, status
)) {
1465 state
->create_guid
= &state
->_create_guid
;
1468 * we need to store the create_guid later
1470 state
->update_open
= true;
1473 * And we need to create a cache for replaying the
1476 state
->need_replay_cache
= true;
1479 * durable handle v2 request processed below
1481 state
->durable_requested
= true;
1482 state
->durable_timeout_msec
= MIN(durable_v2_timeout
, 300*1000);
1483 if (state
->durable_timeout_msec
== 0) {
1485 * Set the timeout to 1 min as default.
1487 * This matches Windows 2012.
1489 state
->durable_timeout_msec
= (60*1000);
1493 * Check for replay operation.
1494 * Only consider it when we have dh2q.
1495 * If we do not have a replay operation, verify that
1496 * the create_guid is not cached for replay.
1498 hdr
= SMBD_SMB2_IN_HDR_PTR(smb2req
);
1499 flags
= IVAL(hdr
, SMB2_HDR_FLAGS
);
1500 state
->replay_operation
=
1501 flags
& SMB2_HDR_FLAG_REPLAY_OPERATION
;
1503 status
= smb2srv_open_lookup_replay_cache(smb2req
->xconn
,
1505 *state
->create_guid
,
1509 if (NT_STATUS_EQUAL(status
, NT_STATUS_FWP_RESERVED
)) {
1511 * We've reserved the replay_cache record
1512 * for ourself, indicating we're still
1515 * It means the smbd_smb2_create_cleanup()
1516 * may need to call smbXsrv_open_purge_replay_cache()
1517 * in order to cleanup.
1519 SMB_ASSERT(state
->op
== NULL
);
1520 state
->_purge_create_guid
= state
->_create_guid
;
1521 state
->purge_create_guid
= &state
->_purge_create_guid
;
1522 status
= NT_STATUS_OK
;
1523 state
->replay_operation
= false;
1524 } else if (NT_STATUS_EQUAL(status
, NT_STATUS_FILE_NOT_AVAILABLE
)) {
1525 tevent_req_nterror(req
, status
);
1527 } else if (tevent_req_nterror(req
, status
)) {
1528 DBG_WARNING("smb2srv_open_lookup_replay_cache "
1529 "failed: %s\n", nt_errstr(status
));
1531 } else if (!state
->replay_operation
) {
1533 * If a create without replay operation flag
1534 * is sent but with a create_guid that is
1535 * currently in the replay cache -- fail.
1537 status
= NT_STATUS_DUPLICATE_OBJECTID
;
1538 (void)tevent_req_nterror(req
, status
);
1543 if (state
->dhnc
!= NULL
) {
1544 state
->persistent_id
= BVAL(state
->dhnc
->data
.data
, 0);
1545 state
->do_durable_reconnect
= true;
1548 if (state
->dh2c
!= NULL
) {
1549 const uint8_t *p
= state
->dh2c
->data
.data
;
1550 DATA_BLOB create_guid_blob
;
1552 state
->persistent_id
= BVAL(p
, 0);
1553 create_guid_blob
= data_blob_const(p
+ 16, 16);
1555 status
= GUID_from_ndr_blob(&create_guid_blob
,
1556 &state
->_create_guid
);
1557 if (tevent_req_nterror(req
, status
)) {
1561 state
->create_guid
= &state
->_create_guid
;
1562 state
->do_durable_reconnect
= true;
1565 if (state
->alsi
!= NULL
) {
1566 if (state
->alsi
->data
.length
!= 8) {
1567 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
1570 state
->allocation_size
= BVAL(state
->alsi
->data
.data
, 0);
1573 if (state
->twrp
!= NULL
) {
1574 if (state
->twrp
->data
.length
!= 8) {
1575 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
1579 state
->twrp_time
= BVAL(state
->twrp
->data
.data
, 0);
1582 if (state
->qfid
!= NULL
) {
1583 if (state
->qfid
->data
.length
!= 0) {
1584 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
1589 if (state
->rqls
!= NULL
) {
1590 ssize_t lease_len
= -1;
1592 lease_len
= smb2_lease_pull(state
->rqls
->data
.data
,
1593 state
->rqls
->data
.length
,
1595 if (lease_len
== -1) {
1597 req
, NT_STATUS_INVALID_PARAMETER
);
1600 state
->lease_ptr
= &state
->lease
;
1602 if (DEBUGLEVEL
>= 10) {
1603 DEBUG(10, ("Got lease request size %d\n",
1605 NDR_PRINT_DEBUG(smb2_lease
, state
->lease_ptr
);
1608 if (!smb2_lease_key_valid(&state
->lease
.lease_key
)) {
1609 state
->lease_ptr
= NULL
;
1610 state
->requested_oplock_level
= SMB2_OPLOCK_LEVEL_NONE
;
1613 if ((smb2req
->xconn
->protocol
< PROTOCOL_SMB3_00
) &&
1614 (state
->lease
.lease_version
!= 1))
1616 DEBUG(10, ("v2 lease key only for SMB3\n"));
1617 state
->lease_ptr
= NULL
;
1621 * Replay with a lease is only allowed if the
1622 * established open carries a lease with the
1625 if (state
->replay_operation
) {
1626 struct smb2_lease
*op_ls
=
1627 &state
->op
->compat
->lease
->lease
;
1628 int op_oplock
= state
->op
->compat
->oplock_type
;
1630 if (map_samba_oplock_levels_to_smb2(op_oplock
)
1631 != SMB2_OPLOCK_LEVEL_LEASE
)
1633 status
= NT_STATUS_ACCESS_DENIED
;
1634 (void)tevent_req_nterror(req
, status
);
1637 if (!smb2_lease_key_equal(&state
->lease
.lease_key
,
1640 status
= NT_STATUS_ACCESS_DENIED
;
1641 (void)tevent_req_nterror(req
, status
);
1647 if (state
->posx
!= NULL
) {
1648 if (state
->posx
->data
.length
!= 4) {
1649 DBG_DEBUG("Got %zu bytes POSX cctx, expected 4\n",
1650 state
->posx
->data
.length
);
1651 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
1657 static void smbd_smb2_create_after_exec(struct tevent_req
*req
)
1659 struct smbd_smb2_create_state
*state
= tevent_req_data(
1660 req
, struct smbd_smb2_create_state
);
1661 connection_struct
*conn
= state
->result
->conn
;
1665 * here we have op == result->op
1668 DBG_DEBUG("response construction phase\n");
1670 state
->out_file_attributes
= fdos_mode(state
->result
);
1672 if ((state
->out_file_attributes
& FILE_ATTRIBUTE_REPARSE_POINT
) &&
1673 (!(state
->in_create_options
& FILE_OPEN_REPARSE_POINT
)))
1677 uint8_t *data
= NULL
;
1680 status
= fsctl_get_reparse_point(
1681 state
->result
, talloc_tos(), &tag
, &data
, 65536, &len
);
1682 if (!NT_STATUS_IS_OK(status
)) {
1686 if (tag
!= IO_REPARSE_TAG_SYMLINK
) {
1687 status
= NT_STATUS_IO_REPARSE_TAG_NOT_HANDLED
;
1691 state
->symlink_err
= talloc_zero(state
,
1692 struct reparse_data_buffer
);
1693 if (state
->symlink_err
== NULL
) {
1695 status
= NT_STATUS_NO_MEMORY
;
1699 status
= reparse_data_buffer_parse(state
->symlink_err
,
1704 if (!NT_STATUS_IS_OK(status
)) {
1705 DBG_DEBUG("reparse_data_buffer_parse failed: %s\n",
1711 * Checked above, just to make sure
1713 SMB_ASSERT(state
->symlink_err
->tag
== IO_REPARSE_TAG_SYMLINK
);
1715 DBG_DEBUG("Redirecting to %s\n",
1716 state
->symlink_err
->parsed
.lnk
.substitute_name
);
1718 status
= NT_STATUS_STOPPED_ON_SYMLINK
;
1722 if (state
->mxac
!= NULL
) {
1723 NTTIME last_write_time
;
1725 last_write_time
= full_timespec_to_nt_time(
1726 &state
->result
->fsp_name
->st
.st_ex_mtime
);
1727 if (last_write_time
!= state
->max_access_time
) {
1729 uint32_t max_access_granted
;
1730 DATA_BLOB blob
= data_blob_const(p
, sizeof(p
));
1732 status
= smbd_calculate_access_mask_fsp(
1736 SEC_FLAG_MAXIMUM_ALLOWED
,
1737 &max_access_granted
);
1739 SIVAL(p
, 0, NT_STATUS_V(status
));
1740 SIVAL(p
, 4, max_access_granted
);
1742 status
= smb2_create_blob_add(
1743 state
->out_context_blobs
,
1744 state
->out_context_blobs
,
1745 SMB2_CREATE_TAG_MXAC
,
1747 if (!NT_STATUS_IS_OK(status
)) {
1753 if (!state
->replay_operation
&& state
->durable_requested
&&
1754 (fsp_lease_type(state
->result
) & SMB2_LEASE_HANDLE
))
1756 status
= SMB_VFS_DURABLE_COOKIE(
1759 &state
->op
->global
->backend_cookie
);
1760 if (!NT_STATUS_IS_OK(status
)) {
1761 state
->op
->global
->backend_cookie
= data_blob_null
;
1764 if (!state
->replay_operation
&& state
->op
->global
->backend_cookie
.length
> 0)
1766 state
->update_open
= true;
1768 state
->op
->global
->durable
= true;
1769 state
->op
->global
->durable_timeout_msec
= state
->durable_timeout_msec
;
1772 if (state
->update_open
) {
1773 state
->op
->global
->create_guid
= state
->_create_guid
;
1774 if (state
->need_replay_cache
) {
1775 state
->op
->flags
|= SMBXSRV_OPEN_NEED_REPLAY_CACHE
;
1778 status
= smbXsrv_open_update(state
->op
);
1779 DEBUG(10, ("smb2_create_send: smbXsrv_open_update "
1781 nt_errstr(status
)));
1782 if (!NT_STATUS_IS_OK(status
)) {
1787 * We should not purge the replay cache anymore
1788 * as it's attached to the smbXsrv_open record now.
1790 state
->purge_create_guid
= NULL
;
1793 if (state
->dhnq
!= NULL
&& state
->op
->global
->durable
) {
1794 uint8_t p
[8] = { 0, };
1795 DATA_BLOB blob
= data_blob_const(p
, sizeof(p
));
1797 status
= smb2_create_blob_add(state
->out_context_blobs
,
1798 state
->out_context_blobs
,
1799 SMB2_CREATE_TAG_DHNQ
,
1801 if (!NT_STATUS_IS_OK(status
)) {
1806 if (state
->dh2q
!= NULL
&& state
->op
->global
->durable
&&
1808 * For replay operations, we return the dh2q blob
1809 * in the case of oplocks not based on the state of
1810 * the open, but on whether it could have been granted
1811 * for the request data. In the case of leases instead,
1812 * the state of the open is used...
1814 (!state
->replay_operation
||
1815 state
->in_oplock_level
== SMB2_OPLOCK_LEVEL_BATCH
||
1816 state
->in_oplock_level
== SMB2_OPLOCK_LEVEL_LEASE
))
1818 uint8_t p
[8] = { 0, };
1819 DATA_BLOB blob
= data_blob_const(p
, sizeof(p
));
1820 uint32_t durable_v2_response_flags
= 0;
1822 SIVAL(p
, 0, state
->op
->global
->durable_timeout_msec
);
1823 SIVAL(p
, 4, durable_v2_response_flags
);
1825 status
= smb2_create_blob_add(state
->out_context_blobs
,
1826 state
->out_context_blobs
,
1827 SMB2_CREATE_TAG_DH2Q
,
1829 if (!NT_STATUS_IS_OK(status
)) {
1834 if (state
->qfid
!= NULL
) {
1836 SMB_STRUCT_STAT
*base_sp
= state
->result
->base_fsp
?
1837 &state
->result
->base_fsp
->fsp_name
->st
:
1838 &state
->result
->fsp_name
->st
;
1839 uint64_t file_id
= SMB_VFS_FS_FILE_ID(conn
, base_sp
);
1840 DATA_BLOB blob
= data_blob_const(p
, sizeof(p
));
1844 /* From conversations with Microsoft engineers at
1845 the MS plugfest. The first 8 bytes are the "volume index"
1846 == inode, the second 8 bytes are the "volume id",
1847 == dev. This will be updated in the SMB2 doc. */
1848 SBVAL(p
, 0, file_id
);
1849 SIVAL(p
, 8, base_sp
->st_ex_dev
);/* FileIndexHigh */
1851 status
= smb2_create_blob_add(state
->out_context_blobs
,
1852 state
->out_context_blobs
,
1853 SMB2_CREATE_TAG_QFID
,
1855 if (!NT_STATUS_IS_OK(status
)) {
1860 if ((state
->rqls
!= NULL
) && (state
->result
->oplock_type
== LEASE_OPLOCK
)) {
1862 struct smb2_lease lease
;
1865 lease
= state
->result
->lease
->lease
;
1867 lease_len
= sizeof(buf
);
1868 if (lease
.lease_version
== 1) {
1872 if (!smb2_lease_push(&lease
, buf
, lease_len
)) {
1873 status
= NT_STATUS_INTERNAL_ERROR
;
1877 status
= smb2_create_blob_add(
1878 state
, state
->out_context_blobs
,
1879 SMB2_CREATE_TAG_RQLS
,
1880 data_blob_const(buf
, lease_len
));
1881 if (!NT_STATUS_IS_OK(status
)) {
1886 if (state
->posx
!= NULL
) {
1887 struct stat_ex
*psbuf
= &state
->result
->fsp_name
->st
;
1888 struct smb3_posix_cc_info cc
= {
1889 .nlinks
= psbuf
->st_ex_nlink
,
1890 .posix_mode
= unix_mode_to_wire(psbuf
->st_ex_mode
),
1892 uint8_t buf
[sizeof(struct smb3_posix_cc_info
)];
1893 struct ndr_push ndr
= {
1895 .alloc_size
= sizeof(buf
),
1896 .fixed_buf_size
= true,
1898 enum ndr_err_code ndr_err
;
1900 uid_to_sid(&cc
.owner
, psbuf
->st_ex_uid
);
1901 gid_to_sid(&cc
.group
, psbuf
->st_ex_gid
);
1903 (void)fsctl_get_reparse_tag(state
->result
, &cc
.reparse_tag
);
1906 ndr_push_smb3_posix_cc_info(&ndr
,
1907 NDR_SCALARS
| NDR_BUFFERS
,
1909 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1910 status
= NT_STATUS_INSUFFICIENT_RESOURCES
;
1914 status
= smb2_create_blob_add(state
->out_context_blobs
,
1915 state
->out_context_blobs
,
1916 SMB2_CREATE_TAG_POSIX
,
1919 .length
= ndr
.offset
,
1921 if (!NT_STATUS_IS_OK(status
)) {
1929 close_file_free(state
->smb1req
, &state
->result
, ERROR_CLOSE
);
1930 tevent_req_nterror(req
, status
);
1933 static void smbd_smb2_create_finish(struct tevent_req
*req
)
1935 struct smbd_smb2_create_state
*state
= tevent_req_data(
1936 req
, struct smbd_smb2_create_state
);
1937 struct smbd_smb2_request
*smb2req
= state
->smb2req
;
1938 struct smb_request
*smb1req
= state
->smb1req
;
1939 files_struct
*result
= state
->result
;
1941 smb2req
->compat_chain_fsp
= smb1req
->chain_fsp
;
1943 if (state
->replay_operation
) {
1944 state
->out_oplock_level
= state
->in_oplock_level
;
1945 } else if (lp_fake_oplocks(SNUM(smb2req
->tcon
->compat
))) {
1946 state
->out_oplock_level
= state
->in_oplock_level
;
1948 state
->out_oplock_level
= map_samba_oplock_levels_to_smb2(result
->oplock_type
);
1951 if ((state
->in_create_disposition
== FILE_SUPERSEDE
)
1952 && (state
->info
== FILE_WAS_OVERWRITTEN
)) {
1953 state
->out_create_action
= FILE_WAS_SUPERSEDED
;
1955 state
->out_create_action
= state
->info
;
1957 result
->op
->create_action
= state
->out_create_action
;
1959 state
->out_creation_ts
= get_create_timespec(smb1req
->conn
,
1960 result
, result
->fsp_name
);
1961 state
->out_last_access_ts
= result
->fsp_name
->st
.st_ex_atime
;
1962 state
->out_last_write_ts
= result
->fsp_name
->st
.st_ex_mtime
;
1963 state
->out_change_ts
= get_change_timespec(smb1req
->conn
,
1964 result
, result
->fsp_name
);
1966 if (lp_dos_filetime_resolution(SNUM(smb2req
->tcon
->compat
))) {
1967 dos_filetime_timespec(&state
->out_creation_ts
);
1968 dos_filetime_timespec(&state
->out_last_access_ts
);
1969 dos_filetime_timespec(&state
->out_last_write_ts
);
1970 dos_filetime_timespec(&state
->out_change_ts
);
1973 state
->out_allocation_size
=
1974 SMB_VFS_GET_ALLOC_SIZE(smb1req
->conn
, result
,
1975 &(result
->fsp_name
->st
));
1976 state
->out_end_of_file
= result
->fsp_name
->st
.st_ex_size
;
1977 if (state
->out_file_attributes
== 0) {
1978 state
->out_file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1980 state
->out_file_id_persistent
= result
->op
->global
->open_persistent_id
;
1981 state
->out_file_id_volatile
= result
->op
->global
->open_volatile_id
;
1983 DBG_DEBUG("%s - %s\n", fsp_str_dbg(result
), fsp_fnum_dbg(result
));
1985 tevent_req_done(req
);
1986 tevent_req_post(req
, state
->ev
);
1989 static NTSTATUS
smbd_smb2_create_recv(struct tevent_req
*req
,
1990 TALLOC_CTX
*mem_ctx
,
1991 uint8_t *out_oplock_level
,
1992 uint32_t *out_create_action
,
1993 struct timespec
*out_creation_ts
,
1994 struct timespec
*out_last_access_ts
,
1995 struct timespec
*out_last_write_ts
,
1996 struct timespec
*out_change_ts
,
1997 uint64_t *out_allocation_size
,
1998 uint64_t *out_end_of_file
,
1999 uint32_t *out_file_attributes
,
2000 uint64_t *out_file_id_persistent
,
2001 uint64_t *out_file_id_volatile
,
2002 struct smb2_create_blobs
*out_context_blobs
,
2003 struct reparse_data_buffer
**symlink_reparse
)
2005 NTSTATUS status
= NT_STATUS_OK
;
2006 struct smbd_smb2_create_state
*state
= tevent_req_data(req
,
2007 struct smbd_smb2_create_state
);
2010 error
= tevent_req_is_nterror(req
, &status
);
2012 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
2013 struct symlink_reparse_struct
*lnk
= &state
->symlink_err
2015 size_t fname_len
= strlen(state
->fname
);
2018 * filename_convert_dirfsp_nosymlink() calculates
2019 * unparsed_path_length. Just assert it did not mess up big
2022 SMB_ASSERT(lnk
->unparsed_path_length
<= fname_len
);
2024 if (lnk
->unparsed_path_length
!= 0) {
2026 char *unparsed_unix
= NULL
;
2027 char *utf_16
= NULL
;
2030 unparsed_unix
= state
->fname
+ fname_len
-
2031 lnk
->unparsed_path_length
;
2033 ok
= convert_string_talloc(talloc_tos(),
2037 lnk
->unparsed_path_length
,
2041 tevent_req_received(req
);
2042 return NT_STATUS_INTERNAL_ERROR
;
2044 TALLOC_FREE(utf_16
);
2046 if (utf_16_len
> UINT16_MAX
) {
2047 tevent_req_received(req
);
2048 return NT_STATUS_BUFFER_OVERFLOW
;
2050 lnk
->unparsed_path_length
= utf_16_len
;
2052 *symlink_reparse
= talloc_move(mem_ctx
, &state
->symlink_err
);
2056 tevent_req_received(req
);
2060 *out_oplock_level
= state
->out_oplock_level
;
2061 *out_create_action
= state
->out_create_action
;
2062 *out_creation_ts
= state
->out_creation_ts
;
2063 *out_last_access_ts
= state
->out_last_access_ts
;
2064 *out_last_write_ts
= state
->out_last_write_ts
;
2065 *out_change_ts
= state
->out_change_ts
;
2066 *out_allocation_size
= state
->out_allocation_size
;
2067 *out_end_of_file
= state
->out_end_of_file
;
2068 *out_file_attributes
= state
->out_file_attributes
;
2069 *out_file_id_persistent
= state
->out_file_id_persistent
;
2070 *out_file_id_volatile
= state
->out_file_id_volatile
;
2071 *out_context_blobs
= *(state
->out_context_blobs
);
2072 *symlink_reparse
= NULL
;
2074 talloc_steal(mem_ctx
, state
->out_context_blobs
->blobs
);
2076 tevent_req_received(req
);
2077 return NT_STATUS_OK
;
2080 /*********************************************************
2081 Code for dealing with deferred opens.
2082 *********************************************************/
2084 bool get_deferred_open_message_state_smb2(struct smbd_smb2_request
*smb2req
,
2085 struct timeval
*p_request_time
,
2086 struct deferred_open_record
**open_rec
)
2088 struct smbd_smb2_create_state
*state
= NULL
;
2089 struct tevent_req
*req
= NULL
;
2094 req
= smb2req
->subreq
;
2098 state
= tevent_req_data(req
, struct smbd_smb2_create_state
);
2102 if (!state
->open_was_deferred
) {
2105 if (p_request_time
) {
2106 *p_request_time
= state
->request_time
;
2108 if (open_rec
!= NULL
) {
2109 *open_rec
= state
->open_rec
;
2114 /*********************************************************
2115 Re-process this call early - requested by message or
2117 *********************************************************/
2119 static struct smbd_smb2_request
*find_open_smb2req(
2120 struct smbXsrv_connection
*xconn
, uint64_t mid
)
2122 struct smbd_smb2_request
*smb2req
;
2124 for (smb2req
= xconn
->smb2
.requests
; smb2req
; smb2req
= smb2req
->next
) {
2125 uint64_t message_id
;
2126 if (smb2req
->subreq
== NULL
) {
2127 /* This message has been processed. */
2130 if (!tevent_req_is_in_progress(smb2req
->subreq
)) {
2131 /* This message has been processed. */
2134 message_id
= get_mid_from_smb2req(smb2req
);
2135 if (message_id
== mid
) {
2142 bool open_was_deferred_smb2(struct smbXsrv_connection
*xconn
, uint64_t mid
)
2144 struct smbd_smb2_create_state
*state
= NULL
;
2145 struct smbd_smb2_request
*smb2req
;
2147 smb2req
= find_open_smb2req(xconn
, mid
);
2150 DEBUG(10,("open_was_deferred_smb2: mid %llu smb2req == NULL\n",
2151 (unsigned long long)mid
));
2154 if (!smb2req
->subreq
) {
2157 if (!tevent_req_is_in_progress(smb2req
->subreq
)) {
2160 state
= tevent_req_data(smb2req
->subreq
,
2161 struct smbd_smb2_create_state
);
2165 /* It's not in progress if there's no timeout event. */
2166 if (!state
->open_was_deferred
) {
2170 DEBUG(10,("open_was_deferred_smb2: mid = %llu\n",
2171 (unsigned long long)mid
));
2176 static void remove_deferred_open_message_smb2_internal(struct smbd_smb2_request
*smb2req
,
2179 struct smbd_smb2_create_state
*state
= NULL
;
2181 if (!smb2req
->subreq
) {
2184 if (!tevent_req_is_in_progress(smb2req
->subreq
)) {
2187 state
= tevent_req_data(smb2req
->subreq
,
2188 struct smbd_smb2_create_state
);
2193 DEBUG(10,("remove_deferred_open_message_smb2_internal: "
2195 (unsigned long long)mid
));
2197 state
->open_was_deferred
= false;
2198 /* Ensure we don't have any outstanding immediate event. */
2199 TALLOC_FREE(state
->im
);
2200 TALLOC_FREE(state
->open_rec
);
2203 void remove_deferred_open_message_smb2(
2204 struct smbXsrv_connection
*xconn
, uint64_t mid
)
2206 struct smbd_smb2_request
*smb2req
;
2208 smb2req
= find_open_smb2req(xconn
, mid
);
2211 DEBUG(10,("remove_deferred_open_message_smb2: "
2212 "can't find mid %llu\n",
2213 (unsigned long long)mid
));
2216 remove_deferred_open_message_smb2_internal(smb2req
, mid
);
2219 static void smbd_smb2_create_request_dispatch_immediate(struct tevent_context
*ctx
,
2220 struct tevent_immediate
*im
,
2223 struct smbd_smb2_request
*smb2req
= talloc_get_type_abort(private_data
,
2224 struct smbd_smb2_request
);
2225 uint64_t mid
= get_mid_from_smb2req(smb2req
);
2228 DEBUG(10,("smbd_smb2_create_request_dispatch_immediate: "
2229 "re-dispatching mid %llu\n",
2230 (unsigned long long)mid
));
2232 status
= smbd_smb2_request_dispatch(smb2req
);
2233 if (!NT_STATUS_IS_OK(status
)) {
2234 smbd_server_connection_terminate(smb2req
->xconn
,
2240 bool schedule_deferred_open_message_smb2(
2241 struct smbXsrv_connection
*xconn
, uint64_t mid
)
2243 struct smbd_smb2_create_state
*state
= NULL
;
2244 struct smbd_smb2_request
*smb2req
;
2246 smb2req
= find_open_smb2req(xconn
, mid
);
2249 DEBUG(10,("schedule_deferred_open_message_smb2: "
2250 "can't find mid %llu\n",
2251 (unsigned long long)mid
));
2254 if (!smb2req
->subreq
) {
2257 if (!tevent_req_is_in_progress(smb2req
->subreq
)) {
2260 state
= tevent_req_data(smb2req
->subreq
,
2261 struct smbd_smb2_create_state
);
2266 /* Ensure we don't have any outstanding immediate event. */
2267 TALLOC_FREE(state
->im
);
2270 * This is subtle. We must null out the callback
2271 * before rescheduling, else the first call to
2272 * tevent_req_nterror() causes the _receive()
2273 * function to be called, this causing tevent_req_post()
2276 tevent_req_set_callback(smb2req
->subreq
, NULL
, NULL
);
2278 state
->im
= tevent_create_immediate(smb2req
);
2280 smbd_server_connection_terminate(smb2req
->xconn
,
2281 nt_errstr(NT_STATUS_NO_MEMORY
));
2285 DEBUG(10,("schedule_deferred_open_message_smb2: "
2286 "re-processing mid %llu\n",
2287 (unsigned long long)mid
));
2289 tevent_schedule_immediate(state
->im
,
2290 smb2req
->sconn
->ev_ctx
,
2291 smbd_smb2_create_request_dispatch_immediate
,
2297 static bool smbd_smb2_create_cancel(struct tevent_req
*req
)
2299 struct smbd_smb2_request
*smb2req
= NULL
;
2300 struct smbd_smb2_create_state
*state
= tevent_req_data(req
,
2301 struct smbd_smb2_create_state
);
2308 if (!state
->smb2req
) {
2312 smb2req
= state
->smb2req
;
2313 mid
= get_mid_from_smb2req(smb2req
);
2315 if (is_deferred_open_async(state
->open_rec
)) {
2316 /* Can't cancel an async create. */
2320 remove_deferred_open_message_smb2_internal(smb2req
, mid
);
2322 tevent_req_defer_callback(req
, smb2req
->sconn
->ev_ctx
);
2323 tevent_req_nterror(req
, NT_STATUS_CANCELLED
);
2327 bool push_deferred_open_message_smb2(struct smbd_smb2_request
*smb2req
,
2328 struct timeval request_time
,
2329 struct timeval timeout
,
2331 struct deferred_open_record
*open_rec
)
2333 struct tevent_req
*req
= NULL
;
2334 struct smbd_smb2_create_state
*state
= NULL
;
2335 struct timeval end_time
;
2340 req
= smb2req
->subreq
;
2344 state
= tevent_req_data(req
, struct smbd_smb2_create_state
);
2349 state
->request_time
= request_time
;
2350 state
->open_rec
= talloc_move(state
, &open_rec
);
2352 /* Re-schedule us to retry on timer expiry. */
2353 end_time
= timeval_sum(&request_time
, &timeout
);
2355 DEBUG(10,("push_deferred_open_message_smb2: "
2357 timeval_string(talloc_tos(),
2361 state
->open_was_deferred
= true;
2363 /* allow this request to be canceled */
2364 tevent_req_set_cancel_fn(req
, smbd_smb2_create_cancel
);