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
*req
,
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
*subreq
);
52 NTSTATUS
smbd_smb2_request_process_create(struct smbd_smb2_request
*req
)
54 const uint8_t *inbody
;
55 int i
= req
->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
*subreq
;
83 if (req
->in
.vector
[i
+1].iov_len
!= (expected_body_size
& 0xFFFFFFFE)) {
84 return smbd_smb2_request_error(req
, NT_STATUS_INVALID_PARAMETER
);
87 inbody
= (const uint8_t *)req
->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(req
, 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(req
, NT_STATUS_INVALID_PARAMETER
);
122 name_offset
= in_name_offset
- dyn_offset
;
125 if (name_offset
> req
->in
.vector
[i
+2].iov_len
) {
126 return smbd_smb2_request_error(req
, NT_STATUS_INVALID_PARAMETER
);
129 name_available_length
= req
->in
.vector
[i
+2].iov_len
- name_offset
;
131 if (in_name_length
> name_available_length
) {
132 return smbd_smb2_request_error(req
, NT_STATUS_INVALID_PARAMETER
);
135 in_name_buffer
.data
= (uint8_t *)req
->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(req
, NT_STATUS_INVALID_PARAMETER
);
145 context_offset
= in_context_offset
- dyn_offset
;
148 if (context_offset
> req
->in
.vector
[i
+2].iov_len
) {
149 return smbd_smb2_request_error(req
, NT_STATUS_INVALID_PARAMETER
);
152 context_available_length
= req
->in
.vector
[i
+2].iov_len
- context_offset
;
154 if (in_context_length
> context_available_length
) {
155 return smbd_smb2_request_error(req
, NT_STATUS_INVALID_PARAMETER
);
158 in_context_buffer
.data
= (uint8_t *)req
->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(req
, CH_UTF16
, CH_UNIX
,
168 in_name_buffer
.length
,
170 &in_name_string_size
, false);
172 return smbd_smb2_request_error(req
, NT_STATUS_ILLEGAL_CHARACTER
);
175 ZERO_STRUCT(in_context_blobs
);
176 status
= smb2_create_blob_parse(req
, in_context_buffer
, &in_context_blobs
);
177 if (!NT_STATUS_IS_OK(status
)) {
178 return smbd_smb2_request_error(req
, status
);
181 subreq
= smbd_smb2_create_send(req
,
182 req
->sconn
->smb2
.event_ctx
,
185 in_impersonation_level
,
189 in_create_disposition
,
193 if (subreq
== NULL
) {
194 return smbd_smb2_request_error(req
, NT_STATUS_NO_MEMORY
);
196 tevent_req_set_callback(subreq
, smbd_smb2_request_create_done
, req
);
198 return smbd_smb2_request_pending_queue(req
, subreq
);
201 static void smbd_smb2_request_create_done(struct tevent_req
*subreq
)
203 struct smbd_smb2_request
*req
= tevent_req_callback_data(subreq
,
204 struct smbd_smb2_request
);
205 int i
= req
->current_idx
;
209 uint8_t out_oplock_level
= 0;
210 uint32_t out_create_action
= 0;
211 NTTIME out_creation_time
= 0;
212 NTTIME out_last_access_time
= 0;
213 NTTIME out_last_write_time
= 0;
214 NTTIME out_change_time
= 0;
215 uint64_t out_allocation_size
= 0;
216 uint64_t out_end_of_file
= 0;
217 uint32_t out_file_attributes
= 0;
218 uint64_t out_file_id_volatile
= 0;
219 struct smb2_create_blobs out_context_blobs
;
220 DATA_BLOB out_context_buffer
;
221 uint16_t out_context_buffer_offset
= 0;
223 NTSTATUS error
; /* transport error */
225 status
= smbd_smb2_create_recv(subreq
,
230 &out_last_access_time
,
231 &out_last_write_time
,
233 &out_allocation_size
,
235 &out_file_attributes
,
236 &out_file_id_volatile
,
239 if (!NT_STATUS_IS_OK(status
)) {
240 error
= smbd_smb2_request_error(req
, status
);
241 if (!NT_STATUS_IS_OK(error
)) {
242 smbd_server_connection_terminate(req
->sconn
,
249 status
= smb2_create_blob_push(req
, &out_context_buffer
, out_context_blobs
);
250 if (!NT_STATUS_IS_OK(status
)) {
251 error
= smbd_smb2_request_error(req
, status
);
252 if (!NT_STATUS_IS_OK(error
)) {
253 smbd_server_connection_terminate(req
->sconn
,
260 if (out_context_buffer
.length
> 0) {
261 out_context_buffer_offset
= SMB2_HDR_BODY
+ 0x58;
264 outhdr
= (uint8_t *)req
->out
.vector
[i
].iov_base
;
266 outbody
= data_blob_talloc(req
->out
.vector
, NULL
, 0x58);
267 if (outbody
.data
== NULL
) {
268 error
= smbd_smb2_request_error(req
, NT_STATUS_NO_MEMORY
);
269 if (!NT_STATUS_IS_OK(error
)) {
270 smbd_server_connection_terminate(req
->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(req
, outbody
, &outdyn
);
309 if (!NT_STATUS_IS_OK(error
)) {
310 smbd_server_connection_terminate(req
->sconn
,
316 struct smbd_smb2_create_state
{
317 struct smbd_smb2_request
*smb2req
;
318 uint8_t out_oplock_level
;
319 uint32_t out_create_action
;
320 NTTIME out_creation_time
;
321 NTTIME out_last_access_time
;
322 NTTIME out_last_write_time
;
323 NTTIME out_change_time
;
324 uint64_t out_allocation_size
;
325 uint64_t out_end_of_file
;
326 uint32_t out_file_attributes
;
327 uint64_t out_file_id_volatile
;
328 struct smb2_create_blobs out_context_blobs
;
331 static struct tevent_req
*smbd_smb2_create_send(TALLOC_CTX
*mem_ctx
,
332 struct tevent_context
*ev
,
333 struct smbd_smb2_request
*smb2req
,
334 uint8_t in_oplock_level
,
335 uint32_t in_impersonation_level
,
336 uint32_t in_desired_access
,
337 uint32_t in_file_attributes
,
338 uint32_t in_share_access
,
339 uint32_t in_create_disposition
,
340 uint32_t in_create_options
,
342 struct smb2_create_blobs in_context_blobs
)
344 struct tevent_req
*req
;
345 struct smbd_smb2_create_state
*state
;
347 struct smb_request
*smbreq
;
348 files_struct
*result
;
350 struct timespec write_time_ts
;
351 struct smb2_create_blobs out_context_blobs
;
353 ZERO_STRUCT(out_context_blobs
);
355 req
= tevent_req_create(mem_ctx
, &state
,
356 struct smbd_smb2_create_state
);
360 state
->smb2req
= smb2req
;
362 DEBUG(10,("smbd_smb2_create: name[%s]\n",
365 smbreq
= smbd_smb2_fake_smb_request(smb2req
);
366 if (tevent_req_nomem(smbreq
, req
)) {
367 return tevent_req_post(req
, ev
);
370 if (IS_IPC(smbreq
->conn
)) {
371 const char *pipe_name
= in_name
;
373 if (!lp_nt_pipe_support()) {
374 tevent_req_nterror(req
, NT_STATUS_ACCESS_DENIED
);
375 return tevent_req_post(req
, ev
);
378 /* Strip \\ off the name. */
379 if (pipe_name
[0] == '\\') {
383 status
= open_np_file(smbreq
, pipe_name
, &result
);
384 if (!NT_STATUS_IS_OK(status
)) {
385 tevent_req_nterror(req
, status
);
386 return tevent_req_post(req
, ev
);
388 info
= FILE_WAS_OPENED
;
389 } else if (CAN_PRINT(smbreq
->conn
)) {
390 status
= file_new(smbreq
, smbreq
->conn
, &result
);
391 if(!NT_STATUS_IS_OK(status
)) {
392 tevent_req_nterror(req
, status
);
393 return tevent_req_post(req
, ev
);
396 status
= print_fsp_open(smbreq
,
401 if (!NT_STATUS_IS_OK(status
)) {
402 file_free(smbreq
, result
);
403 tevent_req_nterror(req
, status
);
404 return tevent_req_post(req
, ev
);
406 info
= FILE_WAS_CREATED
;
409 struct smb_filename
*smb_fname
= NULL
;
410 struct smb2_create_blob
*exta
= NULL
;
411 struct ea_list
*ea_list
= NULL
;
412 struct smb2_create_blob
*mxac
= NULL
;
413 NTTIME max_access_time
= 0;
414 struct smb2_create_blob
*secd
= NULL
;
415 struct security_descriptor
*sec_desc
= NULL
;
416 struct smb2_create_blob
*dhnq
= NULL
;
417 struct smb2_create_blob
*dhnc
= NULL
;
418 struct smb2_create_blob
*alsi
= NULL
;
419 uint64_t allocation_size
= 0;
420 struct smb2_create_blob
*twrp
= NULL
;
421 struct smb2_create_blob
*qfid
= NULL
;
423 exta
= smb2_create_blob_find(&in_context_blobs
,
424 SMB2_CREATE_TAG_EXTA
);
425 mxac
= smb2_create_blob_find(&in_context_blobs
,
426 SMB2_CREATE_TAG_MXAC
);
427 secd
= smb2_create_blob_find(&in_context_blobs
,
428 SMB2_CREATE_TAG_SECD
);
429 dhnq
= smb2_create_blob_find(&in_context_blobs
,
430 SMB2_CREATE_TAG_DHNQ
);
431 dhnc
= smb2_create_blob_find(&in_context_blobs
,
432 SMB2_CREATE_TAG_DHNC
);
433 alsi
= smb2_create_blob_find(&in_context_blobs
,
434 SMB2_CREATE_TAG_ALSI
);
435 twrp
= smb2_create_blob_find(&in_context_blobs
,
436 SMB2_CREATE_TAG_TWRP
);
437 qfid
= smb2_create_blob_find(&in_context_blobs
,
438 SMB2_CREATE_TAG_QFID
);
440 fname
= talloc_strdup(state
, in_name
);
441 if (tevent_req_nomem(fname
, req
)) {
442 return tevent_req_post(req
, ev
);
447 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
448 return tevent_req_post(req
, ev
);
451 ea_list
= read_nttrans_ea_list(mem_ctx
,
452 (const char *)exta
->data
.data
, exta
->data
.length
);
454 DEBUG(10,("smbd_smb2_create_send: read_ea_name_list failed.\n"));
455 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
456 return tevent_req_post(req
, ev
);
462 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
463 return tevent_req_post(req
, ev
);
466 if (mxac
->data
.length
== 0) {
468 } else if (mxac
->data
.length
== 8) {
469 max_access_time
= BVAL(mxac
->data
.data
, 0);
471 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
472 return tevent_req_post(req
, ev
);
477 enum ndr_err_code ndr_err
;
480 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
481 return tevent_req_post(req
, ev
);
484 sec_desc
= talloc_zero(state
, struct security_descriptor
);
485 if (tevent_req_nomem(sec_desc
, req
)) {
486 return tevent_req_post(req
, ev
);
489 ndr_err
= ndr_pull_struct_blob(&secd
->data
,
490 sec_desc
, NULL
, sec_desc
,
491 (ndr_pull_flags_fn_t
)ndr_pull_security_descriptor
);
492 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
493 DEBUG(2,("ndr_pull_security_descriptor failed: %s\n",
494 ndr_errstr(ndr_err
)));
495 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
496 return tevent_req_post(req
, ev
);
502 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
503 return tevent_req_post(req
, ev
);
506 if (dhnq
->data
.length
!= 16) {
507 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
508 return tevent_req_post(req
, ev
);
511 * we don't support durable handles yet
512 * and have to ignore this
517 if (dhnc
->data
.length
!= 16) {
518 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
519 return tevent_req_post(req
, ev
);
521 /* we don't support durable handles yet */
522 tevent_req_nterror(req
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
523 return tevent_req_post(req
, ev
);
528 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
529 return tevent_req_post(req
, ev
);
532 if (alsi
->data
.length
!= 8) {
533 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
534 return tevent_req_post(req
, ev
);
536 allocation_size
= BVAL(alsi
->data
.data
, 0);
545 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
546 return tevent_req_post(req
, ev
);
549 if (twrp
->data
.length
!= 8) {
550 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
551 return tevent_req_post(req
, ev
);
554 nttime
= BVAL(twrp
->data
.data
, 0);
555 t
= nt_time_to_unix(nttime
);
559 fname
= talloc_asprintf(state
,
560 "@GMT-%04u.%02u.%02u-%02u.%02u.%02u\\%s",
568 if (tevent_req_nomem(fname
, req
)) {
569 return tevent_req_post(req
, ev
);
574 if (qfid
->data
.length
!= 0) {
575 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
576 return tevent_req_post(req
, ev
);
580 /* these are ignored for SMB2 */
581 in_create_options
&= ~(0x10);/* NTCREATEX_OPTIONS_SYNC_ALERT */
582 in_create_options
&= ~(0x20);/* NTCREATEX_OPTIONS_ASYNC_ALERT */
584 /* convert '\\' into '/' */
585 status
= check_path_syntax(fname
);
586 if (!NT_STATUS_IS_OK(status
)) {
587 tevent_req_nterror(req
, status
);
588 return tevent_req_post(req
, ev
);
591 status
= filename_convert(req
,
593 smbreq
->flags2
& FLAGS2_DFS_PATHNAMES
,
598 if (!NT_STATUS_IS_OK(status
)) {
599 tevent_req_nterror(req
, status
);
600 return tevent_req_post(req
, ev
);
603 status
= SMB_VFS_CREATE_FILE(smbreq
->conn
,
605 0, /* root_dir_fid */
609 in_create_disposition
,
612 0, /* oplock_request */
618 if (!NT_STATUS_IS_OK(status
)) {
619 tevent_req_nterror(req
, status
);
620 return tevent_req_post(req
, ev
);
624 NTTIME last_write_time
;
626 unix_timespec_to_nt_time(&last_write_time
,
627 result
->fsp_name
->st
.st_ex_mtime
);
628 if (last_write_time
!= max_access_time
) {
630 uint32_t max_access_granted
;
631 DATA_BLOB blob
= data_blob_const(p
, sizeof(p
));
633 status
= smbd_check_open_rights(smbreq
->conn
,
635 SEC_FLAG_MAXIMUM_ALLOWED
,
636 &max_access_granted
);
638 SIVAL(p
, 0, NT_STATUS_V(status
));
639 SIVAL(p
, 4, max_access_granted
);
641 status
= smb2_create_blob_add(state
,
643 SMB2_CREATE_TAG_MXAC
,
645 if (!NT_STATUS_IS_OK(status
)) {
646 tevent_req_nterror(req
, status
);
647 return tevent_req_post(req
, ev
);
654 uint64_t file_index
= get_FileIndex(result
->conn
,
655 &result
->fsp_name
->st
);
656 DATA_BLOB blob
= data_blob_const(p
, sizeof(p
));
660 /* From conversations with Microsoft engineers at
661 the MS plugfest. The first 8 bytes are the "volume index"
662 == inode, the second 8 bytes are the "volume id",
663 == dev. This will be updated in the SMB2 doc. */
664 SBVAL(p
, 0, file_index
);
665 SIVAL(p
, 8, result
->fsp_name
->st
.st_ex_dev
);/* FileIndexHigh */
667 status
= smb2_create_blob_add(state
, &out_context_blobs
,
668 SMB2_CREATE_TAG_QFID
,
670 if (!NT_STATUS_IS_OK(status
)) {
671 tevent_req_nterror(req
, status
);
672 return tevent_req_post(req
, ev
);
677 smb2req
->compat_chain_fsp
= smbreq
->chain_fsp
;
679 state
->out_oplock_level
= 0;
680 if ((in_create_disposition
== FILE_SUPERSEDE
)
681 && (info
== FILE_WAS_OVERWRITTEN
)) {
682 state
->out_create_action
= FILE_WAS_SUPERSEDED
;
684 state
->out_create_action
= info
;
686 state
->out_file_attributes
= dos_mode(result
->conn
,
688 /* Deal with other possible opens having a modified
690 ZERO_STRUCT(write_time_ts
);
691 get_file_infos(result
->file_id
, NULL
, &write_time_ts
);
692 if (!null_timespec(write_time_ts
)) {
693 update_stat_ex_mtime(&result
->fsp_name
->st
, write_time_ts
);
696 unix_timespec_to_nt_time(&state
->out_creation_time
,
697 get_create_timespec(smbreq
->conn
, result
,
699 unix_timespec_to_nt_time(&state
->out_last_access_time
,
700 result
->fsp_name
->st
.st_ex_atime
);
701 unix_timespec_to_nt_time(&state
->out_last_write_time
,
702 result
->fsp_name
->st
.st_ex_mtime
);
703 unix_timespec_to_nt_time(&state
->out_change_time
,
704 get_change_timespec(smbreq
->conn
, result
,
706 state
->out_allocation_size
=
707 result
->fsp_name
->st
.st_ex_blksize
*
708 result
->fsp_name
->st
.st_ex_blocks
;
709 state
->out_end_of_file
= result
->fsp_name
->st
.st_ex_size
;
710 if (state
->out_file_attributes
== 0) {
711 state
->out_file_attributes
= FILE_ATTRIBUTE_NORMAL
;
713 state
->out_file_id_volatile
= result
->fnum
;
714 state
->out_context_blobs
= out_context_blobs
;
716 tevent_req_done(req
);
717 return tevent_req_post(req
, ev
);
720 static NTSTATUS
smbd_smb2_create_recv(struct tevent_req
*req
,
722 uint8_t *out_oplock_level
,
723 uint32_t *out_create_action
,
724 NTTIME
*out_creation_time
,
725 NTTIME
*out_last_access_time
,
726 NTTIME
*out_last_write_time
,
727 NTTIME
*out_change_time
,
728 uint64_t *out_allocation_size
,
729 uint64_t *out_end_of_file
,
730 uint32_t *out_file_attributes
,
731 uint64_t *out_file_id_volatile
,
732 struct smb2_create_blobs
*out_context_blobs
)
735 struct smbd_smb2_create_state
*state
= tevent_req_data(req
,
736 struct smbd_smb2_create_state
);
738 if (tevent_req_is_nterror(req
, &status
)) {
739 tevent_req_received(req
);
743 *out_oplock_level
= state
->out_oplock_level
;
744 *out_create_action
= state
->out_create_action
;
745 *out_creation_time
= state
->out_creation_time
;
746 *out_last_access_time
= state
->out_last_access_time
;
747 *out_last_write_time
= state
->out_last_write_time
;
748 *out_change_time
= state
->out_change_time
;
749 *out_allocation_size
= state
->out_allocation_size
;
750 *out_end_of_file
= state
->out_end_of_file
;
751 *out_file_attributes
= state
->out_file_attributes
;
752 *out_file_id_volatile
= state
->out_file_id_volatile
;
753 *out_context_blobs
= state
->out_context_blobs
;
755 talloc_steal(mem_ctx
, state
->out_context_blobs
.blobs
);
757 tevent_req_received(req
);