2 Unix SMB/CIFS implementation.
5 Copyright (C) Stefan Metzmacher 2009
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "smbd/globals.h"
23 #include "../libcli/smb/smb_common.h"
25 static struct tevent_req
*smbd_smb2_create_send(TALLOC_CTX
*mem_ctx
,
26 struct tevent_context
*ev
,
27 struct smbd_smb2_request
*smb2req
,
28 uint8_t in_oplock_level
,
29 uint32_t in_impersonation_level
,
30 uint32_t in_desired_access
,
31 uint32_t in_file_attributes
,
32 uint32_t in_share_access
,
33 uint32_t in_create_disposition
,
34 uint32_t in_create_options
,
36 struct smb2_create_blobs in_context_blobs
);
37 static NTSTATUS
smbd_smb2_create_recv(struct tevent_req
*treq
,
39 uint8_t *out_oplock_level
,
40 uint32_t *out_create_action
,
41 NTTIME
*out_creation_time
,
42 NTTIME
*out_last_access_time
,
43 NTTIME
*out_last_write_time
,
44 NTTIME
*out_change_time
,
45 uint64_t *out_allocation_size
,
46 uint64_t *out_end_of_file
,
47 uint32_t *out_file_attributes
,
48 uint64_t *out_file_id_volatile
,
49 struct smb2_create_blobs
*out_context_blobs
);
51 static void smbd_smb2_request_create_done(struct tevent_req
*tsubreq
);
52 NTSTATUS
smbd_smb2_request_process_create(struct smbd_smb2_request
*smb2req
)
54 const uint8_t *inbody
;
55 int i
= smb2req
->current_idx
;
56 size_t expected_body_size
= 0x39;
58 uint8_t in_oplock_level
;
59 uint32_t in_impersonation_level
;
60 uint32_t in_desired_access
;
61 uint32_t in_file_attributes
;
62 uint32_t in_share_access
;
63 uint32_t in_create_disposition
;
64 uint32_t in_create_options
;
65 uint16_t in_name_offset
;
66 uint16_t in_name_length
;
67 DATA_BLOB in_name_buffer
;
69 size_t in_name_string_size
;
70 uint32_t name_offset
= 0;
71 uint32_t name_available_length
= 0;
72 uint32_t in_context_offset
;
73 uint32_t in_context_length
;
74 DATA_BLOB in_context_buffer
;
75 struct smb2_create_blobs in_context_blobs
;
76 uint32_t context_offset
= 0;
77 uint32_t context_available_length
= 0;
81 struct tevent_req
*tsubreq
;
83 if (smb2req
->in
.vector
[i
+1].iov_len
!= (expected_body_size
& 0xFFFFFFFE)) {
84 return smbd_smb2_request_error(smb2req
, NT_STATUS_INVALID_PARAMETER
);
87 inbody
= (const uint8_t *)smb2req
->in
.vector
[i
+1].iov_base
;
89 body_size
= SVAL(inbody
, 0x00);
90 if (body_size
!= expected_body_size
) {
91 return smbd_smb2_request_error(smb2req
, NT_STATUS_INVALID_PARAMETER
);
94 in_oplock_level
= CVAL(inbody
, 0x03);
95 in_impersonation_level
= IVAL(inbody
, 0x04);
96 in_desired_access
= IVAL(inbody
, 0x18);
97 in_file_attributes
= IVAL(inbody
, 0x1C);
98 in_share_access
= IVAL(inbody
, 0x20);
99 in_create_disposition
= IVAL(inbody
, 0x24);
100 in_create_options
= IVAL(inbody
, 0x28);
101 in_name_offset
= SVAL(inbody
, 0x2C);
102 in_name_length
= SVAL(inbody
, 0x2E);
103 in_context_offset
= IVAL(inbody
, 0x30);
104 in_context_length
= IVAL(inbody
, 0x34);
107 * First check if the dynamic name and context buffers
108 * are correctly specified.
110 * Note: That we don't check if the name and context buffers
114 dyn_offset
= SMB2_HDR_BODY
+ (body_size
& 0xFFFFFFFE);
116 if (in_name_offset
== 0 && in_name_length
== 0) {
119 } else if (in_name_offset
< dyn_offset
) {
120 return smbd_smb2_request_error(smb2req
, NT_STATUS_INVALID_PARAMETER
);
122 name_offset
= in_name_offset
- dyn_offset
;
125 if (name_offset
> smb2req
->in
.vector
[i
+2].iov_len
) {
126 return smbd_smb2_request_error(smb2req
, NT_STATUS_INVALID_PARAMETER
);
129 name_available_length
= smb2req
->in
.vector
[i
+2].iov_len
- name_offset
;
131 if (in_name_length
> name_available_length
) {
132 return smbd_smb2_request_error(smb2req
, NT_STATUS_INVALID_PARAMETER
);
135 in_name_buffer
.data
= (uint8_t *)smb2req
->in
.vector
[i
+2].iov_base
+
137 in_name_buffer
.length
= in_name_length
;
139 if (in_context_offset
== 0 && in_context_length
== 0) {
142 } else if (in_context_offset
< dyn_offset
) {
143 return smbd_smb2_request_error(smb2req
, NT_STATUS_INVALID_PARAMETER
);
145 context_offset
= in_context_offset
- dyn_offset
;
148 if (context_offset
> smb2req
->in
.vector
[i
+2].iov_len
) {
149 return smbd_smb2_request_error(smb2req
, NT_STATUS_INVALID_PARAMETER
);
152 context_available_length
= smb2req
->in
.vector
[i
+2].iov_len
- context_offset
;
154 if (in_context_length
> context_available_length
) {
155 return smbd_smb2_request_error(smb2req
, NT_STATUS_INVALID_PARAMETER
);
158 in_context_buffer
.data
= (uint8_t *)smb2req
->in
.vector
[i
+2].iov_base
+
160 in_context_buffer
.length
= in_context_length
;
163 * Now interpret the name and context buffers
166 ok
= convert_string_talloc(smb2req
, CH_UTF16
, CH_UNIX
,
168 in_name_buffer
.length
,
170 &in_name_string_size
, false);
172 return smbd_smb2_request_error(smb2req
, NT_STATUS_ILLEGAL_CHARACTER
);
175 ZERO_STRUCT(in_context_blobs
);
176 status
= smb2_create_blob_parse(smb2req
, in_context_buffer
, &in_context_blobs
);
177 if (!NT_STATUS_IS_OK(status
)) {
178 return smbd_smb2_request_error(smb2req
, status
);
181 tsubreq
= smbd_smb2_create_send(smb2req
,
182 smb2req
->sconn
->smb2
.event_ctx
,
185 in_impersonation_level
,
189 in_create_disposition
,
193 if (tsubreq
== NULL
) {
194 smb2req
->subreq
= NULL
;
195 return smbd_smb2_request_error(smb2req
, NT_STATUS_NO_MEMORY
);
197 tevent_req_set_callback(tsubreq
, smbd_smb2_request_create_done
, smb2req
);
199 return smbd_smb2_request_pending_queue(smb2req
, tsubreq
);
202 static void smbd_smb2_request_create_done(struct tevent_req
*tsubreq
)
204 struct smbd_smb2_request
*smb2req
= tevent_req_callback_data(tsubreq
,
205 struct smbd_smb2_request
);
206 int i
= smb2req
->current_idx
;
210 uint8_t out_oplock_level
= 0;
211 uint32_t out_create_action
= 0;
212 NTTIME out_creation_time
= 0;
213 NTTIME out_last_access_time
= 0;
214 NTTIME out_last_write_time
= 0;
215 NTTIME out_change_time
= 0;
216 uint64_t out_allocation_size
= 0;
217 uint64_t out_end_of_file
= 0;
218 uint32_t out_file_attributes
= 0;
219 uint64_t out_file_id_volatile
= 0;
220 struct smb2_create_blobs out_context_blobs
;
221 DATA_BLOB out_context_buffer
;
222 uint16_t out_context_buffer_offset
= 0;
224 NTSTATUS error
; /* transport error */
226 status
= smbd_smb2_create_recv(tsubreq
,
231 &out_last_access_time
,
232 &out_last_write_time
,
234 &out_allocation_size
,
236 &out_file_attributes
,
237 &out_file_id_volatile
,
239 if (!NT_STATUS_IS_OK(status
)) {
240 error
= smbd_smb2_request_error(smb2req
, status
);
241 if (!NT_STATUS_IS_OK(error
)) {
242 smbd_server_connection_terminate(smb2req
->sconn
,
249 status
= smb2_create_blob_push(smb2req
, &out_context_buffer
, out_context_blobs
);
250 if (!NT_STATUS_IS_OK(status
)) {
251 error
= smbd_smb2_request_error(smb2req
, status
);
252 if (!NT_STATUS_IS_OK(error
)) {
253 smbd_server_connection_terminate(smb2req
->sconn
,
260 if (out_context_buffer
.length
> 0) {
261 out_context_buffer_offset
= SMB2_HDR_BODY
+ 0x58;
264 outhdr
= (uint8_t *)smb2req
->out
.vector
[i
].iov_base
;
266 outbody
= data_blob_talloc(smb2req
->out
.vector
, NULL
, 0x58);
267 if (outbody
.data
== NULL
) {
268 error
= smbd_smb2_request_error(smb2req
, NT_STATUS_NO_MEMORY
);
269 if (!NT_STATUS_IS_OK(error
)) {
270 smbd_server_connection_terminate(smb2req
->sconn
,
277 SSVAL(outbody
.data
, 0x00, 0x58 + 1); /* struct size */
278 SCVAL(outbody
.data
, 0x02,
279 out_oplock_level
); /* oplock level */
280 SCVAL(outbody
.data
, 0x03, 0); /* reserved */
281 SIVAL(outbody
.data
, 0x04,
282 out_create_action
); /* create action */
283 SBVAL(outbody
.data
, 0x08,
284 out_creation_time
); /* creation time */
285 SBVAL(outbody
.data
, 0x10,
286 out_last_access_time
); /* last access time */
287 SBVAL(outbody
.data
, 0x18,
288 out_last_write_time
); /* last write time */
289 SBVAL(outbody
.data
, 0x20,
290 out_change_time
); /* change time */
291 SBVAL(outbody
.data
, 0x28,
292 out_allocation_size
); /* allocation size */
293 SBVAL(outbody
.data
, 0x30,
294 out_end_of_file
); /* end of file */
295 SIVAL(outbody
.data
, 0x38,
296 out_file_attributes
); /* file attributes */
297 SIVAL(outbody
.data
, 0x3C, 0); /* reserved */
298 SBVAL(outbody
.data
, 0x40, 0); /* file id (persistent) */
299 SBVAL(outbody
.data
, 0x48,
300 out_file_id_volatile
); /* file id (volatile) */
301 SIVAL(outbody
.data
, 0x50,
302 out_context_buffer_offset
); /* create contexts offset */
303 SIVAL(outbody
.data
, 0x54,
304 out_context_buffer
.length
); /* create contexts length */
306 outdyn
= out_context_buffer
;
308 error
= smbd_smb2_request_done(smb2req
, outbody
, &outdyn
);
309 if (!NT_STATUS_IS_OK(error
)) {
310 smbd_server_connection_terminate(smb2req
->sconn
,
316 struct smbd_smb2_create_state
{
317 struct smbd_smb2_request
*smb2req
;
318 struct smb_request
*smb1req
;
319 struct timed_event
*te
;
320 struct timeval request_time
;
321 DATA_BLOB private_data
;
322 uint8_t out_oplock_level
;
323 uint32_t out_create_action
;
324 NTTIME out_creation_time
;
325 NTTIME out_last_access_time
;
326 NTTIME out_last_write_time
;
327 NTTIME out_change_time
;
328 uint64_t out_allocation_size
;
329 uint64_t out_end_of_file
;
330 uint32_t out_file_attributes
;
331 uint64_t out_file_id_volatile
;
332 struct smb2_create_blobs out_context_blobs
;
335 static struct tevent_req
*smbd_smb2_create_send(TALLOC_CTX
*mem_ctx
,
336 struct tevent_context
*ev
,
337 struct smbd_smb2_request
*smb2req
,
338 uint8_t in_oplock_level
,
339 uint32_t in_impersonation_level
,
340 uint32_t in_desired_access
,
341 uint32_t in_file_attributes
,
342 uint32_t in_share_access
,
343 uint32_t in_create_disposition
,
344 uint32_t in_create_options
,
346 struct smb2_create_blobs in_context_blobs
)
348 struct tevent_req
*treq
= NULL
;
349 struct smbd_smb2_create_state
*state
= NULL
;
351 struct smb_request
*smb1req
= NULL
;
352 files_struct
*result
= NULL
;
354 struct timespec write_time_ts
;
355 struct smb2_create_blobs out_context_blobs
;
357 ZERO_STRUCT(out_context_blobs
);
359 if (!smb2req
->async
) {
360 /* New create call. */
361 treq
= tevent_req_create(mem_ctx
, &state
,
362 struct smbd_smb2_create_state
);
366 state
->smb2req
= smb2req
;
367 smb2req
->subreq
= treq
; /* So we can find this when going async. */
369 smb1req
= smbd_smb2_fake_smb_request(smb2req
);
370 if (tevent_req_nomem(smb1req
, treq
)) {
371 return tevent_req_post(treq
, ev
);
373 state
->smb1req
= smb1req
;
374 DEBUG(10,("smbd_smb2_create: name[%s]\n",
377 /* Re-entrant create call. */
378 treq
= smb2req
->subreq
;
379 state
= tevent_req_data(treq
,
380 struct smbd_smb2_create_state
);
381 smb1req
= state
->smb1req
;
382 DEBUG(10,("smbd_smb2_create_send: reentrant for file %s\n",
386 if (IS_IPC(smb1req
->conn
)) {
387 const char *pipe_name
= in_name
;
389 if (!lp_nt_pipe_support()) {
390 tevent_req_nterror(treq
, NT_STATUS_ACCESS_DENIED
);
391 return tevent_req_post(treq
, ev
);
394 /* Strip \\ off the name. */
395 if (pipe_name
[0] == '\\') {
399 status
= open_np_file(smb1req
, pipe_name
, &result
);
400 if (!NT_STATUS_IS_OK(status
)) {
401 tevent_req_nterror(treq
, status
);
402 return tevent_req_post(treq
, ev
);
404 info
= FILE_WAS_OPENED
;
405 } else if (CAN_PRINT(smb1req
->conn
)) {
406 status
= file_new(smb1req
, smb1req
->conn
, &result
);
407 if(!NT_STATUS_IS_OK(status
)) {
408 tevent_req_nterror(treq
, status
);
409 return tevent_req_post(treq
, ev
);
412 status
= print_fsp_open(smb1req
,
417 if (!NT_STATUS_IS_OK(status
)) {
418 file_free(smb1req
, result
);
419 tevent_req_nterror(treq
, status
);
420 return tevent_req_post(treq
, ev
);
422 info
= FILE_WAS_CREATED
;
425 struct smb_filename
*smb_fname
= NULL
;
426 struct smb2_create_blob
*exta
= NULL
;
427 struct ea_list
*ea_list
= NULL
;
428 struct smb2_create_blob
*mxac
= NULL
;
429 NTTIME max_access_time
= 0;
430 struct smb2_create_blob
*secd
= NULL
;
431 struct security_descriptor
*sec_desc
= NULL
;
432 struct smb2_create_blob
*dhnq
= NULL
;
433 struct smb2_create_blob
*dhnc
= NULL
;
434 struct smb2_create_blob
*alsi
= NULL
;
435 uint64_t allocation_size
= 0;
436 struct smb2_create_blob
*twrp
= NULL
;
437 struct smb2_create_blob
*qfid
= NULL
;
439 exta
= smb2_create_blob_find(&in_context_blobs
,
440 SMB2_CREATE_TAG_EXTA
);
441 mxac
= smb2_create_blob_find(&in_context_blobs
,
442 SMB2_CREATE_TAG_MXAC
);
443 secd
= smb2_create_blob_find(&in_context_blobs
,
444 SMB2_CREATE_TAG_SECD
);
445 dhnq
= smb2_create_blob_find(&in_context_blobs
,
446 SMB2_CREATE_TAG_DHNQ
);
447 dhnc
= smb2_create_blob_find(&in_context_blobs
,
448 SMB2_CREATE_TAG_DHNC
);
449 alsi
= smb2_create_blob_find(&in_context_blobs
,
450 SMB2_CREATE_TAG_ALSI
);
451 twrp
= smb2_create_blob_find(&in_context_blobs
,
452 SMB2_CREATE_TAG_TWRP
);
453 qfid
= smb2_create_blob_find(&in_context_blobs
,
454 SMB2_CREATE_TAG_QFID
);
456 fname
= talloc_strdup(state
, in_name
);
457 if (tevent_req_nomem(fname
, treq
)) {
458 return tevent_req_post(treq
, ev
);
463 tevent_req_nterror(treq
, NT_STATUS_INVALID_PARAMETER
);
464 return tevent_req_post(treq
, ev
);
467 ea_list
= read_nttrans_ea_list(mem_ctx
,
468 (const char *)exta
->data
.data
, exta
->data
.length
);
470 DEBUG(10,("smbd_smb2_create_send: read_ea_name_list failed.\n"));
471 tevent_req_nterror(treq
, NT_STATUS_INVALID_PARAMETER
);
472 return tevent_req_post(treq
, ev
);
478 tevent_req_nterror(treq
, NT_STATUS_INVALID_PARAMETER
);
479 return tevent_req_post(treq
, ev
);
482 if (mxac
->data
.length
== 0) {
484 } else if (mxac
->data
.length
== 8) {
485 max_access_time
= BVAL(mxac
->data
.data
, 0);
487 tevent_req_nterror(treq
, NT_STATUS_INVALID_PARAMETER
);
488 return tevent_req_post(treq
, ev
);
493 enum ndr_err_code ndr_err
;
496 tevent_req_nterror(treq
, NT_STATUS_INVALID_PARAMETER
);
497 return tevent_req_post(treq
, ev
);
500 sec_desc
= talloc_zero(state
, struct security_descriptor
);
501 if (tevent_req_nomem(sec_desc
, treq
)) {
502 return tevent_req_post(treq
, ev
);
505 ndr_err
= ndr_pull_struct_blob(&secd
->data
,
506 sec_desc
, NULL
, sec_desc
,
507 (ndr_pull_flags_fn_t
)ndr_pull_security_descriptor
);
508 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
509 DEBUG(2,("ndr_pull_security_descriptor failed: %s\n",
510 ndr_errstr(ndr_err
)));
511 tevent_req_nterror(treq
, NT_STATUS_INVALID_PARAMETER
);
512 return tevent_req_post(treq
, ev
);
518 tevent_req_nterror(treq
, NT_STATUS_INVALID_PARAMETER
);
519 return tevent_req_post(treq
, ev
);
522 if (dhnq
->data
.length
!= 16) {
523 tevent_req_nterror(treq
, NT_STATUS_INVALID_PARAMETER
);
524 return tevent_req_post(treq
, ev
);
527 * we don't support durable handles yet
528 * and have to ignore this
533 if (dhnc
->data
.length
!= 16) {
534 tevent_req_nterror(treq
, NT_STATUS_INVALID_PARAMETER
);
535 return tevent_req_post(treq
, ev
);
537 /* we don't support durable handles yet */
538 tevent_req_nterror(treq
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
539 return tevent_req_post(treq
, ev
);
544 tevent_req_nterror(treq
, NT_STATUS_INVALID_PARAMETER
);
545 return tevent_req_post(treq
, ev
);
548 if (alsi
->data
.length
!= 8) {
549 tevent_req_nterror(treq
, NT_STATUS_INVALID_PARAMETER
);
550 return tevent_req_post(treq
, ev
);
552 allocation_size
= BVAL(alsi
->data
.data
, 0);
561 tevent_req_nterror(treq
, NT_STATUS_INVALID_PARAMETER
);
562 return tevent_req_post(treq
, ev
);
565 if (twrp
->data
.length
!= 8) {
566 tevent_req_nterror(treq
, NT_STATUS_INVALID_PARAMETER
);
567 return tevent_req_post(treq
, ev
);
570 nttime
= BVAL(twrp
->data
.data
, 0);
571 t
= nt_time_to_unix(nttime
);
575 fname
= talloc_asprintf(state
,
576 "@GMT-%04u.%02u.%02u-%02u.%02u.%02u\\%s",
584 if (tevent_req_nomem(fname
, treq
)) {
585 return tevent_req_post(treq
, ev
);
590 if (qfid
->data
.length
!= 0) {
591 tevent_req_nterror(treq
, NT_STATUS_INVALID_PARAMETER
);
592 return tevent_req_post(treq
, ev
);
596 /* these are ignored for SMB2 */
597 in_create_options
&= ~(0x10);/* NTCREATEX_OPTIONS_SYNC_ALERT */
598 in_create_options
&= ~(0x20);/* NTCREATEX_OPTIONS_ASYNC_ALERT */
600 /* convert '\\' into '/' */
601 status
= check_path_syntax(fname
);
602 if (!NT_STATUS_IS_OK(status
)) {
603 tevent_req_nterror(treq
, status
);
604 return tevent_req_post(treq
, ev
);
607 status
= filename_convert(treq
,
609 smb1req
->flags2
& FLAGS2_DFS_PATHNAMES
,
614 if (!NT_STATUS_IS_OK(status
)) {
615 tevent_req_nterror(treq
, status
);
616 return tevent_req_post(treq
, ev
);
619 status
= SMB_VFS_CREATE_FILE(smb1req
->conn
,
621 0, /* root_dir_fid */
625 in_create_disposition
,
628 0, /* oplock_request */
630 0, /* private_flags */
635 if (!NT_STATUS_IS_OK(status
)) {
636 if (open_was_deferred(smb1req
->mid
)) {
639 tevent_req_nterror(treq
, status
);
640 return tevent_req_post(treq
, ev
);
644 NTTIME last_write_time
;
646 unix_timespec_to_nt_time(&last_write_time
,
647 result
->fsp_name
->st
.st_ex_mtime
);
648 if (last_write_time
!= max_access_time
) {
650 uint32_t max_access_granted
;
651 DATA_BLOB blob
= data_blob_const(p
, sizeof(p
));
653 status
= smbd_check_open_rights(smb1req
->conn
,
655 SEC_FLAG_MAXIMUM_ALLOWED
,
656 &max_access_granted
);
658 SIVAL(p
, 0, NT_STATUS_V(status
));
659 SIVAL(p
, 4, max_access_granted
);
661 status
= smb2_create_blob_add(state
,
663 SMB2_CREATE_TAG_MXAC
,
665 if (!NT_STATUS_IS_OK(status
)) {
666 tevent_req_nterror(treq
, status
);
667 return tevent_req_post(treq
, ev
);
674 DATA_BLOB blob
= data_blob_const(p
, sizeof(p
));
678 /* TODO: maybe use result->file_id */
679 SIVAL(p
, 0, result
->fsp_name
->st
.st_ex_ino
);/* FileIndexLow */
680 SIVAL(p
, 4, result
->fsp_name
->st
.st_ex_dev
);/* FileIndexHigh */
682 status
= smb2_create_blob_add(state
, &out_context_blobs
,
683 SMB2_CREATE_TAG_QFID
,
685 if (!NT_STATUS_IS_OK(status
)) {
686 tevent_req_nterror(treq
, status
);
687 return tevent_req_post(treq
, ev
);
692 smb2req
->compat_chain_fsp
= smb1req
->chain_fsp
;
694 state
->out_oplock_level
= 0;
695 if ((in_create_disposition
== FILE_SUPERSEDE
)
696 && (info
== FILE_WAS_OVERWRITTEN
)) {
697 state
->out_create_action
= FILE_WAS_SUPERSEDED
;
699 state
->out_create_action
= info
;
701 state
->out_file_attributes
= dos_mode(result
->conn
,
703 /* Deal with other possible opens having a modified
705 ZERO_STRUCT(write_time_ts
);
706 get_file_infos(result
->file_id
, NULL
, &write_time_ts
);
707 if (!null_timespec(write_time_ts
)) {
708 update_stat_ex_mtime(&result
->fsp_name
->st
, write_time_ts
);
711 unix_timespec_to_nt_time(&state
->out_creation_time
,
712 get_create_timespec(smb1req
->conn
, result
,
714 unix_timespec_to_nt_time(&state
->out_last_access_time
,
715 result
->fsp_name
->st
.st_ex_atime
);
716 unix_timespec_to_nt_time(&state
->out_last_write_time
,
717 result
->fsp_name
->st
.st_ex_mtime
);
718 unix_timespec_to_nt_time(&state
->out_change_time
,
719 get_change_timespec(smb1req
->conn
, result
,
721 state
->out_allocation_size
=
722 result
->fsp_name
->st
.st_ex_blksize
*
723 result
->fsp_name
->st
.st_ex_blocks
;
724 state
->out_end_of_file
= result
->fsp_name
->st
.st_ex_size
;
725 if (state
->out_file_attributes
== 0) {
726 state
->out_file_attributes
= FILE_ATTRIBUTE_NORMAL
;
728 state
->out_file_id_volatile
= result
->fnum
;
729 state
->out_context_blobs
= out_context_blobs
;
731 tevent_req_done(treq
);
732 return tevent_req_post(treq
, ev
);
735 static NTSTATUS
smbd_smb2_create_recv(struct tevent_req
*treq
,
737 uint8_t *out_oplock_level
,
738 uint32_t *out_create_action
,
739 NTTIME
*out_creation_time
,
740 NTTIME
*out_last_access_time
,
741 NTTIME
*out_last_write_time
,
742 NTTIME
*out_change_time
,
743 uint64_t *out_allocation_size
,
744 uint64_t *out_end_of_file
,
745 uint32_t *out_file_attributes
,
746 uint64_t *out_file_id_volatile
,
747 struct smb2_create_blobs
*out_context_blobs
)
750 struct smbd_smb2_create_state
*state
= tevent_req_data(treq
,
751 struct smbd_smb2_create_state
);
753 if (tevent_req_is_nterror(treq
, &status
)) {
754 tevent_req_received(treq
);
758 *out_oplock_level
= state
->out_oplock_level
;
759 *out_create_action
= state
->out_create_action
;
760 *out_creation_time
= state
->out_creation_time
;
761 *out_last_access_time
= state
->out_last_access_time
;
762 *out_last_write_time
= state
->out_last_write_time
;
763 *out_change_time
= state
->out_change_time
;
764 *out_allocation_size
= state
->out_allocation_size
;
765 *out_end_of_file
= state
->out_end_of_file
;
766 *out_file_attributes
= state
->out_file_attributes
;
767 *out_file_id_volatile
= state
->out_file_id_volatile
;
768 *out_context_blobs
= state
->out_context_blobs
;
770 talloc_steal(mem_ctx
, state
->out_context_blobs
.blobs
);
772 tevent_req_received(treq
);
776 /*********************************************************
777 Code for dealing with deferred opens.
778 *********************************************************/
780 bool get_deferred_open_message_state_smb2(struct smbd_smb2_request
*smb2req
,
781 struct timeval
*p_request_time
,
784 struct smbd_smb2_create_state
*state
= NULL
;
785 struct tevent_req
*treq
= NULL
;
790 if (!smb2req
->async
) {
793 treq
= smb2req
->subreq
;
797 state
= tevent_req_data(treq
, struct smbd_smb2_create_state
);
801 if (p_request_time
) {
802 *p_request_time
= state
->request_time
;
805 *pp_state
= (void *)state
->private_data
.data
;
810 /*********************************************************
811 Re-process this call early - requested by message or
813 *********************************************************/
815 static struct smbd_smb2_request
*find_open_smb2req(uint64_t mid
)
817 struct smbd_server_connection
*sconn
= smbd_server_conn
;
818 struct smbd_smb2_request
*smb2req
;
820 for (smb2req
= sconn
->smb2
.requests
; smb2req
; smb2req
= smb2req
->next
) {
821 uint8_t *reqhdr
= (uint8_t *)smb2req
->out
.vector
[smb2req
->current_idx
].iov_base
;
822 uint64_t message_id
= BVAL(reqhdr
, SMB2_HDR_MESSAGE_ID
);
823 if (message_id
== mid
) {
830 bool open_was_deferred_smb2(uint64_t mid
)
832 struct smbd_smb2_create_state
*state
= NULL
;
833 struct smbd_smb2_request
*smb2req
= find_open_smb2req(mid
);
836 DEBUG(10,("open_was_deferred_smb2: mid %llu smb2req == NULL\n",
837 (unsigned long long)mid
));
840 if (!smb2req
->subreq
) {
843 if (!tevent_req_is_in_progress(smb2req
->subreq
)) {
846 state
= tevent_req_data(smb2req
->subreq
,
847 struct smbd_smb2_create_state
);
851 /* It's not in progress if there's no timeout event. */
856 DEBUG(10,("open_was_deferred_smb2: mid = %llu\n",
857 (unsigned long long)mid
));
862 void remove_deferred_open_message_smb2(uint64_t mid
)
864 struct smbd_smb2_create_state
*state
= NULL
;
865 struct smbd_smb2_request
*smb2req
= find_open_smb2req(mid
);
868 DEBUG(10,("remove_deferred_open_message_smb2: "
869 "can't find mid %llu\n",
870 (unsigned long long)mid
));
873 if (!smb2req
->subreq
) {
876 if (!tevent_req_is_in_progress(smb2req
->subreq
)) {
879 state
= tevent_req_data(smb2req
->subreq
,
880 struct smbd_smb2_create_state
);
885 DEBUG(10,("remove_deferred_open_message_smb2: "
887 (unsigned long long)mid
));
889 /* Ensure we don't have any outstanding timer event. */
890 TALLOC_FREE(state
->te
);
893 void schedule_deferred_open_message_smb2(uint64_t mid
)
895 struct tevent_immediate
*im
= NULL
;
896 struct smbd_smb2_create_state
*state
= NULL
;
897 struct smbd_smb2_request
*smb2req
= find_open_smb2req(mid
);
900 DEBUG(10,("schedule_deferred_open_message_smb2: "
901 "can't find mid %llu\n",
902 (unsigned long long)mid
));
905 if (!smb2req
->subreq
) {
908 if (!tevent_req_is_in_progress(smb2req
->subreq
)) {
911 state
= tevent_req_data(smb2req
->subreq
,
912 struct smbd_smb2_create_state
);
916 /* Ensure we don't have any outstanding timer event. */
917 TALLOC_FREE(state
->te
);
919 im
= tevent_create_immediate(smb2req
);
921 smbd_server_connection_terminate(smb2req
->sconn
,
922 nt_errstr(NT_STATUS_NO_MEMORY
));
925 DEBUG(10,("schedule_deferred_open_message_smb2: "
926 "re-processing mid %llu\n",
927 (unsigned long long)mid
));
929 tevent_schedule_immediate(im
,
930 smb2req
->sconn
->smb2
.event_ctx
,
931 smbd_smb2_request_dispatch_immediate
,
935 /*********************************************************
936 Re-process this call.
937 *********************************************************/
939 static void smb2_deferred_open_timer(struct event_context
*ev
,
940 struct timed_event
*te
,
941 struct timeval _tval
,
945 struct smbd_smb2_create_state
*state
= NULL
;
946 struct smbd_smb2_request
*smb2req
= talloc_get_type(private_data
,
947 struct smbd_smb2_request
);
949 DEBUG(10,("smb2_deferred_open_timer: [idx=%d], %s\n",
950 smb2req
->current_idx
,
951 tevent_req_default_print(smb2req
->subreq
, talloc_tos()) ));
953 state
= tevent_req_data(smb2req
->subreq
,
954 struct smbd_smb2_create_state
);
959 * Null this out, don't talloc_free. It will
960 * be talloc_free'd by the tevent library when
966 * This is subtle. We must null out the callback
967 * before resheduling, else the first call to
968 * tevent_req_nterror() causes the _receive()
969 * function to be called, this causing tevent_req_post()
972 tevent_req_set_callback(smb2req
->subreq
, NULL
, NULL
);
974 status
= smbd_smb2_request_dispatch(smb2req
);
976 if (!NT_STATUS_IS_OK(status
)) {
977 smbd_server_connection_terminate(smb2req
->sconn
,
982 bool push_deferred_open_message_smb2(struct smbd_smb2_request
*smb2req
,
983 struct timeval request_time
,
984 struct timeval timeout
,
988 struct tevent_req
*treq
= NULL
;
989 struct smbd_smb2_create_state
*state
= NULL
;
990 struct timeval end_time
;
995 treq
= smb2req
->subreq
;
999 state
= tevent_req_data(treq
, struct smbd_smb2_create_state
);
1003 state
->request_time
= request_time
;
1004 state
->private_data
= data_blob_talloc(state
, private_data
,
1006 if (!state
->private_data
.data
) {
1010 /* Boo - turns out this isn't what W2K8R2
1011 does. It actually sends the STATUS_PENDING
1012 message followed by the STATUS_SHARING_VIOLATION
1013 message. Surely this means that all open
1014 calls (even on directories) will potentially
1015 fail in a chain.... ? And I've seen directory
1016 opens as the start of a chain. JRA.
1019 * More subtlety. To match W2K8R2 don't
1020 * send a "gone async" message if it's simply
1021 * a STATUS_SHARING_VIOLATION (short) wait, not
1022 * an oplock break wait. We do this by prematurely
1023 * setting smb2req->async flag.
1025 if (timeout
.tv_sec
< 2) {
1026 DEBUG(10,("push_deferred_open_message_smb2: "
1027 "short timer wait (usec = %u). "
1028 "Don't send async message.\n",
1029 (unsigned int)timeout
.tv_usec
));
1030 smb2req
->async
= true;
1034 /* Re-schedule us to retry on timer expiry. */
1035 end_time
= timeval_sum(&request_time
, &timeout
);
1037 DEBUG(10,("push_deferred_open_message_smb2: "
1039 timeval_string(talloc_tos(),
1043 state
->te
= event_add_timed(smb2req
->sconn
->smb2
.event_ctx
,
1046 smb2_deferred_open_timer
,