2 Unix SMB/CIFS implementation.
4 Copyright (C) Volker Lendecke 2011
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "system/network.h"
22 #include "lib/util/tevent_ntstatus.h"
23 #include "smb_common.h"
24 #include "smbXcli_base.h"
25 #include "smb2_create_blob.h"
28 struct smb2cli_create_state
{
29 enum protocol_types protocol
; /* for symlink error response parser */
31 size_t name_utf16_len
;
34 uint64_t fid_persistent
;
35 uint64_t fid_volatile
;
36 struct smb_create_returns cr
;
37 struct smb2_create_blobs blobs
;
38 struct symlink_reparse_struct
*symlink
;
39 struct tevent_req
*subreq
;
42 static void smb2cli_create_done(struct tevent_req
*subreq
);
43 static bool smb2cli_create_cancel(struct tevent_req
*req
);
45 struct tevent_req
*smb2cli_create_send(
47 struct tevent_context
*ev
,
48 struct smbXcli_conn
*conn
,
49 uint32_t timeout_msec
,
50 struct smbXcli_session
*session
,
51 struct smbXcli_tcon
*tcon
,
53 uint8_t oplock_level
, /* SMB2_OPLOCK_LEVEL_* */
54 uint32_t impersonation_level
, /* SMB2_IMPERSONATION_* */
55 uint32_t desired_access
,
56 uint32_t file_attributes
,
57 uint32_t share_access
,
58 uint32_t create_disposition
,
59 uint32_t create_options
,
60 struct smb2_create_blobs
*blobs
)
62 struct tevent_req
*req
, *subreq
;
63 struct smb2cli_create_state
*state
;
71 uint32_t additional_flags
= 0;
72 uint32_t clear_flags
= 0;
75 req
= tevent_req_create(mem_ctx
, &state
,
76 struct smb2cli_create_state
);
80 state
->protocol
= smbXcli_conn_protocol(conn
);
82 ok
= convert_string_talloc(
89 &state
->name_utf16_len
);
92 return tevent_req_post(req
, ev
);
95 if (strlen(filename
) == 0) {
96 TALLOC_FREE(state
->name_utf16
);
97 state
->name_utf16_len
= 0;
100 fixed
= state
->fixed
;
103 SCVAL(fixed
, 3, oplock_level
);
104 SIVAL(fixed
, 4, impersonation_level
);
105 SIVAL(fixed
, 24, desired_access
);
106 SIVAL(fixed
, 28, file_attributes
);
107 SIVAL(fixed
, 32, share_access
);
108 SIVAL(fixed
, 36, create_disposition
);
109 SIVAL(fixed
, 40, create_options
);
111 SSVAL(fixed
, 44, SMB2_HDR_BODY
+ 56);
112 SSVAL(fixed
, 46, state
->name_utf16_len
);
114 blob
= data_blob_null
;
117 status
= smb2_create_blob_push(state
, &blob
, *blobs
);
118 if (tevent_req_nterror(req
, status
)) {
119 return tevent_req_post(req
, ev
);
123 blobs_offset
= state
->name_utf16_len
;
124 blobs_offset
= ((blobs_offset
+ 3) & ~3);
126 if (blob
.length
> 0) {
127 blobs_offset
= ((blobs_offset
+ 7) & ~7);
128 SIVAL(fixed
, 48, blobs_offset
+ SMB2_HDR_BODY
+ 56);
129 SIVAL(fixed
, 52, blob
.length
);
132 dyn_len
= MAX(1, blobs_offset
+ blob
.length
);
133 dyn
= talloc_zero_array(state
, uint8_t, dyn_len
);
134 if (tevent_req_nomem(dyn
, req
)) {
135 return tevent_req_post(req
, ev
);
138 if (state
->name_utf16
!= NULL
) {
139 memcpy(dyn
, state
->name_utf16
, state
->name_utf16_len
);
142 if (blob
.data
!= NULL
) {
143 memcpy(dyn
+ blobs_offset
,
144 blob
.data
, blob
.length
);
145 data_blob_free(&blob
);
148 if (smbXcli_conn_dfs_supported(conn
) &&
149 smbXcli_tcon_is_dfs_share(tcon
))
151 additional_flags
|= SMB2_HDR_FLAG_DFS
;
155 * We use max_dyn_len = 0
156 * as we don't explicitly ask for any output length.
158 * But it's still possible for the server to return
159 * large create blobs.
163 subreq
= smb2cli_req_send(state
, ev
, conn
, SMB2_OP_CREATE
,
164 additional_flags
, clear_flags
,
168 state
->fixed
, sizeof(state
->fixed
),
171 if (tevent_req_nomem(subreq
, req
)) {
172 return tevent_req_post(req
, ev
);
174 tevent_req_set_callback(subreq
, smb2cli_create_done
, req
);
176 state
->subreq
= subreq
;
177 tevent_req_set_cancel_fn(req
, smb2cli_create_cancel
);
182 static bool smb2cli_create_cancel(struct tevent_req
*req
)
184 struct smb2cli_create_state
*state
= tevent_req_data(req
,
185 struct smb2cli_create_state
);
186 return tevent_req_cancel(state
->subreq
);
190 * [MS-SMB2] 2.2.2.2.1 Symbolic Link Error Response
193 static NTSTATUS
smb2cli_parse_symlink_error_response(
197 struct symlink_reparse_struct
**psymlink
)
199 struct symlink_reparse_struct
*symlink
= NULL
;
200 struct reparse_data_buffer reparse_buf
= {
203 uint32_t symlink_length
, error_tag
;
207 DBG_DEBUG("buffer too short: %zu bytes\n", buflen
);
208 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
211 symlink_length
= IVAL(buf
, 0);
212 if (symlink_length
!= (buflen
-4)) {
213 DBG_DEBUG("symlink_length=%"PRIu32
", (buflen-4)=%zu\n",
214 symlink_length
, buflen
-4);
215 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
218 error_tag
= IVAL(buf
, 4);
219 if (error_tag
!= SYMLINK_ERROR_TAG
) {
220 DBG_DEBUG("error_tag=%"PRIu32
", expected 0x%x\n",
223 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
226 symlink
= talloc(mem_ctx
, struct symlink_reparse_struct
);
227 if (symlink
== NULL
) {
228 return NT_STATUS_NO_MEMORY
;
231 status
= reparse_data_buffer_parse(symlink
,
235 if (!NT_STATUS_IS_OK(status
)) {
236 DBG_DEBUG("reparse_data_buffer_parse() failed: %s\n",
238 TALLOC_FREE(symlink
);
242 if (reparse_buf
.tag
!= IO_REPARSE_TAG_SYMLINK
) {
243 DBG_DEBUG("Got tag 0x%" PRIx32
", "
244 "expected IO_REPARSE_TAG_SYMLINK\n",
246 TALLOC_FREE(symlink
);
247 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
250 *symlink
= reparse_buf
.parsed
.lnk
;
256 * [MS-SMB2] 2.2.2 ErrorData
258 * This is in theory a broad API, but as right now we only have a
259 * single [MS-SMB2] 2.2.2.2.1 symlink error response we can return
262 static NTSTATUS
smb2cli_create_error_data_parse(
263 enum protocol_types protocol
,
264 uint8_t error_context_count
,
269 struct symlink_reparse_struct
**_symlink
)
271 struct symlink_reparse_struct
*symlink
= NULL
;
272 uint32_t error_data_length
, error_id
;
275 if (protocol
!= PROTOCOL_SMB3_11
) {
276 if (error_context_count
!= 0) {
277 DBG_DEBUG("Got error_context_count=%"PRIu8
"\n",
278 error_context_count
);
279 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
282 status
= smb2cli_parse_symlink_error_response(
283 mem_ctx
, buf
, buflen
, &symlink
);
284 if (!NT_STATUS_IS_OK(status
)) {
292 * The STOPPED_ON_SYMLINK that I've seen coming from W2k16 has
293 * just a single array element in the [MS-SMB2] 2.2.2
294 * ErrorData array. We'll need to adapt this if there actually
295 * comes an array of multiple ErrorData elements.
298 if (error_context_count
!= 1) {
299 DBG_DEBUG("Got error_context_count=%"PRIu8
"\n",
300 error_context_count
);
301 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
304 if (byte_count
!= buflen
) {
305 DBG_DEBUG("bytecount=%"PRIu32
", "
309 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
313 DBG_DEBUG("buflen=%zu\n", buflen
);
314 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
317 error_data_length
= IVAL(buf
, 0);
318 if (error_data_length
!= (buflen
- 8)) {
319 DBG_DEBUG("error_data_length=%"PRIu32
", expected %zu\n",
322 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
325 error_id
= IVAL(buf
, 4);
327 DBG_DEBUG("error_id=%"PRIu32
", expected 0\n", error_id
);
328 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
331 status
= smb2cli_parse_symlink_error_response(
332 mem_ctx
, buf
+ 8, buflen
- 8, &symlink
);
333 if (!NT_STATUS_IS_OK(status
)) {
334 DBG_DEBUG("smb2cli_parse_symlink_error_response failed: %s\n",
343 static NTSTATUS
smb2cli_create_unparsed_unix_len(
344 size_t unparsed_utf16_len
,
346 size_t name_utf16_len
,
347 size_t *_unparsed_unix_len
)
349 uint8_t *unparsed_utf16
= NULL
;
350 uint8_t *unparsed_unix
= NULL
;
351 size_t unparsed_unix_len
= 0;
354 if (unparsed_utf16_len
> name_utf16_len
) {
355 DBG_DEBUG("unparsed_utf16_len=%zu, name_utf16_len=%zu\n",
358 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
361 if (unparsed_utf16_len
== 0) {
362 *_unparsed_unix_len
= 0;
366 unparsed_utf16
= name_utf16
+ name_utf16_len
- unparsed_utf16_len
;
368 ok
= convert_string_talloc(
377 NTSTATUS status
= map_nt_error_from_unix_common(errno
);
378 DBG_DEBUG("convert_string_talloc failed: %s\n",
382 *_unparsed_unix_len
= unparsed_unix_len
;
386 static void smb2cli_create_done(struct tevent_req
*subreq
)
388 struct tevent_req
*req
=
389 tevent_req_callback_data(subreq
,
391 struct smb2cli_create_state
*state
=
393 struct smb2cli_create_state
);
397 uint32_t offset
, length
;
398 static const struct smb2cli_req_expected_response expected
[] = {
400 .status
= NT_STATUS_OK
,
404 .status
= NT_STATUS_STOPPED_ON_SYMLINK
,
409 status
= smb2cli_req_recv(subreq
, state
, &iov
,
410 expected
, ARRAY_SIZE(expected
));
413 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
414 uint16_t error_context_count
= CVAL(iov
[1].iov_base
, 2);
415 uint32_t byte_count
= IVAL(iov
[1].iov_base
, 4);
416 size_t unparsed_unix_len
= 0;
418 NTSTATUS symlink_status
;
420 symlink_status
= smb2cli_create_error_data_parse(
428 if (tevent_req_nterror(req
, symlink_status
)) {
433 * Our callers want to know the unparsed length in
436 symlink_status
= smb2cli_create_unparsed_unix_len(
437 state
->symlink
->unparsed_path_length
,
439 state
->name_utf16_len
,
441 if (tevent_req_nterror(req
, symlink_status
)) {
444 state
->symlink
->unparsed_path_length
= unparsed_unix_len
;
447 if (tevent_req_nterror(req
, status
)) {
451 body
= (uint8_t *)iov
[1].iov_base
;
453 state
->cr
.oplock_level
= CVAL(body
, 2);
454 state
->cr
.flags
= CVAL(body
, 3);
455 state
->cr
.create_action
= IVAL(body
, 4);
456 state
->cr
.creation_time
= BVAL(body
, 8);
457 state
->cr
.last_access_time
= BVAL(body
, 16);
458 state
->cr
.last_write_time
= BVAL(body
, 24);
459 state
->cr
.change_time
= BVAL(body
, 32);
460 state
->cr
.allocation_size
= BVAL(body
, 40);
461 state
->cr
.end_of_file
= BVAL(body
, 48);
462 state
->cr
.file_attributes
= IVAL(body
, 56);
463 state
->fid_persistent
= BVAL(body
, 64);
464 state
->fid_volatile
= BVAL(body
, 72);
466 offset
= IVAL(body
, 80);
467 length
= IVAL(body
, 84);
469 if ((offset
!= 0) && (length
!= 0)) {
470 if ((offset
!= SMB2_HDR_BODY
+ 88) ||
471 (length
> iov
[2].iov_len
)) {
473 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
476 status
= smb2_create_blob_parse(
477 state
, data_blob_const(iov
[2].iov_base
, length
),
479 if (tevent_req_nterror(req
, status
)) {
483 tevent_req_done(req
);
486 NTSTATUS
smb2cli_create_recv(struct tevent_req
*req
,
487 uint64_t *fid_persistent
,
488 uint64_t *fid_volatile
,
489 struct smb_create_returns
*cr
,
491 struct smb2_create_blobs
*blobs
,
492 struct symlink_reparse_struct
**psymlink
)
494 struct smb2cli_create_state
*state
=
496 struct smb2cli_create_state
);
499 if (tevent_req_is_nterror(req
, &status
)) {
500 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
) &&
501 (psymlink
!= NULL
)) {
502 *psymlink
= talloc_move(mem_ctx
, &state
->symlink
);
504 tevent_req_received(req
);
507 *fid_persistent
= state
->fid_persistent
;
508 *fid_volatile
= state
->fid_volatile
;
513 blobs
->num_blobs
= state
->blobs
.num_blobs
;
514 blobs
->blobs
= talloc_move(mem_ctx
, &state
->blobs
.blobs
);
516 tevent_req_received(req
);
520 NTSTATUS
smb2cli_create(struct smbXcli_conn
*conn
,
521 uint32_t timeout_msec
,
522 struct smbXcli_session
*session
,
523 struct smbXcli_tcon
*tcon
,
524 const char *filename
,
525 uint8_t oplock_level
, /* SMB2_OPLOCK_LEVEL_* */
526 uint32_t impersonation_level
, /* SMB2_IMPERSONATION_* */
527 uint32_t desired_access
,
528 uint32_t file_attributes
,
529 uint32_t share_access
,
530 uint32_t create_disposition
,
531 uint32_t create_options
,
532 struct smb2_create_blobs
*blobs
,
533 uint64_t *fid_persistent
,
534 uint64_t *fid_volatile
,
535 struct smb_create_returns
*cr
,
537 struct smb2_create_blobs
*ret_blobs
,
538 struct symlink_reparse_struct
**psymlink
)
540 TALLOC_CTX
*frame
= talloc_stackframe();
541 struct tevent_context
*ev
;
542 struct tevent_req
*req
;
543 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
545 if (smbXcli_conn_has_async_calls(conn
)) {
547 * Can't use sync call while an async call is in flight
549 status
= NT_STATUS_INVALID_PARAMETER
;
552 ev
= samba_tevent_context_init(frame
);
556 req
= smb2cli_create_send(frame
, ev
, conn
, timeout_msec
,
558 filename
, oplock_level
,
559 impersonation_level
, desired_access
,
560 file_attributes
, share_access
,
561 create_disposition
, create_options
,
566 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
569 status
= smb2cli_create_recv(