2 Unix SMB/CIFS implementation.
4 SMB2 client tree handling
6 Copyright (C) Andrew Tridgell 2005
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/>.
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/raw/raw_proto.h"
25 #include "libcli/smb2/smb2.h"
26 #include "libcli/smb2/smb2_calls.h"
27 #include "librpc/gen_ndr/ndr_security.h"
31 parse a set of SMB2 create blobs
33 NTSTATUS
smb2_create_blob_parse(TALLOC_CTX
*mem_ctx
, const DATA_BLOB buffer
,
34 struct smb2_create_blobs
*blobs
)
36 const uint8_t *data
= buffer
.data
;
37 uint32_t remaining
= buffer
.length
;
39 while (remaining
> 0) {
41 uint32_t name_offset
, name_length
;
42 uint32_t reserved
, data_offset
;
49 return NT_STATUS_INVALID_PARAMETER
;
52 name_offset
= SVAL(data
, 4);
53 name_length
= SVAL(data
, 6);
54 reserved
= SVAL(data
, 8);
55 data_offset
= SVAL(data
, 10);
56 data_length
= IVAL(data
, 12);
58 if ((next
& 0x7) != 0 ||
61 name_offset
> remaining
||
62 name_length
!= 4 || /* windows enforces this */
63 name_offset
+ name_length
> remaining
||
64 data_offset
< name_offset
+ name_length
||
65 data_offset
> remaining
||
66 data_offset
+ (uint64_t)data_length
> remaining
) {
67 return NT_STATUS_INVALID_PARAMETER
;
70 tag
= talloc_strndup(mem_ctx
, (const char *)data
+ name_offset
, name_length
);
72 return NT_STATUS_NO_MEMORY
;
75 b
= data_blob_const(data
+data_offset
, data_length
);
76 status
= smb2_create_blob_add(mem_ctx
, blobs
, tag
, b
);
77 if (!NT_STATUS_IS_OK(status
)) {
89 return NT_STATUS_INVALID_PARAMETER
;
98 add a blob to a smb2_create attribute blob
100 static NTSTATUS
smb2_create_blob_push_one(TALLOC_CTX
*mem_ctx
, DATA_BLOB
*buffer
,
101 const struct smb2_create_blob
*blob
,
104 uint32_t ofs
= buffer
->length
;
105 size_t tag_length
= strlen(blob
->tag
);
106 uint8_t pad
= smb2_padding_size(blob
->data
.length
+tag_length
, 4);
108 if (!data_blob_realloc(mem_ctx
, buffer
,
109 buffer
->length
+ 0x14 + tag_length
+ blob
->data
.length
+ pad
))
110 return NT_STATUS_NO_MEMORY
;
113 SIVAL(buffer
->data
, ofs
+0x00, 0);
115 SIVAL(buffer
->data
, ofs
+0x00, 0x14 + tag_length
+ blob
->data
.length
+ pad
);
117 SSVAL(buffer
->data
, ofs
+0x04, 0x10); /* offset of tag */
118 SIVAL(buffer
->data
, ofs
+0x06, tag_length
); /* tag length */
119 SSVAL(buffer
->data
, ofs
+0x0A, 0x14 + tag_length
); /* offset of data */
120 SIVAL(buffer
->data
, ofs
+0x0C, blob
->data
.length
);
121 memcpy(buffer
->data
+ofs
+0x10, blob
->tag
, tag_length
);
122 SIVAL(buffer
->data
, ofs
+0x10+tag_length
, 0); /* pad? */
123 memcpy(buffer
->data
+ofs
+0x14+tag_length
, blob
->data
.data
, blob
->data
.length
);
124 memset(buffer
->data
+ofs
+0x14+tag_length
+blob
->data
.length
, 0, pad
);
131 create a buffer of a set of create blobs
133 NTSTATUS
smb2_create_blob_push(TALLOC_CTX
*mem_ctx
, DATA_BLOB
*buffer
,
134 const struct smb2_create_blobs blobs
)
139 *buffer
= data_blob(NULL
, 0);
140 for (i
=0; i
< blobs
.num_blobs
; i
++) {
142 const struct smb2_create_blob
*c
;
144 if ((i
+ 1) == blobs
.num_blobs
) {
149 status
= smb2_create_blob_push_one(mem_ctx
, buffer
, c
, last
);
150 if (!NT_STATUS_IS_OK(status
)) {
158 NTSTATUS
smb2_create_blob_add(TALLOC_CTX
*mem_ctx
, struct smb2_create_blobs
*b
,
159 const char *tag
, DATA_BLOB data
)
161 struct smb2_create_blob
*array
;
163 array
= talloc_realloc(mem_ctx
, b
->blobs
,
164 struct smb2_create_blob
,
166 NT_STATUS_HAVE_NO_MEMORY(array
);
169 b
->blobs
[b
->num_blobs
].tag
= talloc_strdup(b
->blobs
, tag
);
170 NT_STATUS_HAVE_NO_MEMORY(b
->blobs
[b
->num_blobs
].tag
);
173 b
->blobs
[b
->num_blobs
].data
= data_blob_talloc(b
->blobs
,
176 NT_STATUS_HAVE_NO_MEMORY(b
->blobs
[b
->num_blobs
].data
.data
);
178 b
->blobs
[b
->num_blobs
].data
= data_blob(NULL
, 0);
187 send a create request
189 struct smb2_request
*smb2_create_send(struct smb2_tree
*tree
, struct smb2_create
*io
)
191 struct smb2_request
*req
;
194 struct smb2_create_blobs blobs
;
199 req
= smb2_request_init_tree(tree
, SMB2_OP_CREATE
, 0x38, true, 0);
200 if (req
== NULL
) return NULL
;
202 SCVAL(req
->out
.body
, 0x02, io
->in
.security_flags
);
203 SCVAL(req
->out
.body
, 0x03, io
->in
.oplock_level
);
204 SIVAL(req
->out
.body
, 0x04, io
->in
.impersonation_level
);
205 SBVAL(req
->out
.body
, 0x08, io
->in
.create_flags
);
206 SBVAL(req
->out
.body
, 0x10, io
->in
.reserved
);
207 SIVAL(req
->out
.body
, 0x18, io
->in
.desired_access
);
208 SIVAL(req
->out
.body
, 0x1C, io
->in
.file_attributes
);
209 SIVAL(req
->out
.body
, 0x20, io
->in
.share_access
);
210 SIVAL(req
->out
.body
, 0x24, io
->in
.create_disposition
);
211 SIVAL(req
->out
.body
, 0x28, io
->in
.create_options
);
213 status
= smb2_push_o16s16_string(&req
->out
, 0x2C, io
->in
.fname
);
214 if (!NT_STATUS_IS_OK(status
)) {
219 /* now add all the optional blobs */
220 if (io
->in
.eas
.num_eas
!= 0) {
221 DATA_BLOB b
= data_blob_talloc(req
, NULL
,
222 ea_list_size_chained(io
->in
.eas
.num_eas
, io
->in
.eas
.eas
, 4));
223 ea_put_list_chained(b
.data
, io
->in
.eas
.num_eas
, io
->in
.eas
.eas
, 4);
224 status
= smb2_create_blob_add(req
, &blobs
,
225 SMB2_CREATE_TAG_EXTA
, b
);
226 if (!NT_STATUS_IS_OK(status
)) {
233 /* an empty MxAc tag seems to be used to ask the server to
234 return the maximum access mask allowed on the file */
235 if (io
->in
.query_maximal_access
) {
236 /* TODO: MS-SMB2 2.2.13.2.5 says this can contain a timestamp? What to do
237 with that if it doesn't match? */
238 status
= smb2_create_blob_add(req
, &blobs
,
239 SMB2_CREATE_TAG_MXAC
, data_blob(NULL
, 0));
240 if (!NT_STATUS_IS_OK(status
)) {
246 if (io
->in
.alloc_size
!= 0) {
248 SBVAL(data
, 0, io
->in
.alloc_size
);
249 status
= smb2_create_blob_add(req
, &blobs
,
250 SMB2_CREATE_TAG_ALSI
, data_blob_const(data
, 8));
251 if (!NT_STATUS_IS_OK(status
)) {
257 if (io
->in
.durable_open
) {
258 status
= smb2_create_blob_add(req
, &blobs
,
259 SMB2_CREATE_TAG_DHNQ
, data_blob_talloc_zero(req
, 16));
260 if (!NT_STATUS_IS_OK(status
)) {
266 if (io
->in
.durable_handle
) {
268 smb2_push_handle(data
, io
->in
.durable_handle
);
269 status
= smb2_create_blob_add(req
, &blobs
,
270 SMB2_CREATE_TAG_DHNC
, data_blob_const(data
, 16));
271 if (!NT_STATUS_IS_OK(status
)) {
277 if (io
->in
.timewarp
) {
279 SBVAL(data
, 0, io
->in
.timewarp
);
280 status
= smb2_create_blob_add(req
, &blobs
,
281 SMB2_CREATE_TAG_TWRP
, data_blob_const(data
, 8));
282 if (!NT_STATUS_IS_OK(status
)) {
288 if (io
->in
.sec_desc
) {
289 enum ndr_err_code ndr_err
;
291 ndr_err
= ndr_push_struct_blob(&sd_blob
, req
, NULL
,
293 (ndr_push_flags_fn_t
)ndr_push_security_descriptor
);
294 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
298 status
= smb2_create_blob_add(req
, &blobs
,
299 SMB2_CREATE_TAG_SECD
, sd_blob
);
300 if (!NT_STATUS_IS_OK(status
)) {
306 if (io
->in
.query_on_disk_id
) {
307 status
= smb2_create_blob_add(req
, &blobs
,
308 SMB2_CREATE_TAG_QFID
, data_blob(NULL
, 0));
309 if (!NT_STATUS_IS_OK(status
)) {
315 /* and any custom blobs */
316 for (i
=0;i
<io
->in
.blobs
.num_blobs
;i
++) {
317 status
= smb2_create_blob_add(req
, &blobs
,
318 io
->in
.blobs
.blobs
[i
].tag
,
319 io
->in
.blobs
.blobs
[i
].data
);
320 if (!NT_STATUS_IS_OK(status
)) {
327 status
= smb2_create_blob_push(req
, &blob
, blobs
);
328 if (!NT_STATUS_IS_OK(status
)) {
333 status
= smb2_push_o32s32_blob(&req
->out
, 0x30, blob
);
334 if (!NT_STATUS_IS_OK(status
)) {
339 data_blob_free(&blob
);
341 smb2_transport_send(req
);
350 NTSTATUS
smb2_create_recv(struct smb2_request
*req
, TALLOC_CTX
*mem_ctx
, struct smb2_create
*io
)
356 if (!smb2_request_receive(req
) ||
357 !smb2_request_is_ok(req
)) {
358 return smb2_request_destroy(req
);
361 SMB2_CHECK_PACKET_RECV(req
, 0x58, true);
362 ZERO_STRUCT(io
->out
);
363 io
->out
.oplock_level
= CVAL(req
->in
.body
, 0x02);
364 io
->out
.reserved
= CVAL(req
->in
.body
, 0x03);
365 io
->out
.create_action
= IVAL(req
->in
.body
, 0x04);
366 io
->out
.create_time
= smbcli_pull_nttime(req
->in
.body
, 0x08);
367 io
->out
.access_time
= smbcli_pull_nttime(req
->in
.body
, 0x10);
368 io
->out
.write_time
= smbcli_pull_nttime(req
->in
.body
, 0x18);
369 io
->out
.change_time
= smbcli_pull_nttime(req
->in
.body
, 0x20);
370 io
->out
.alloc_size
= BVAL(req
->in
.body
, 0x28);
371 io
->out
.size
= BVAL(req
->in
.body
, 0x30);
372 io
->out
.file_attr
= IVAL(req
->in
.body
, 0x38);
373 io
->out
.reserved2
= IVAL(req
->in
.body
, 0x3C);
374 smb2_pull_handle(req
->in
.body
+0x40, &io
->out
.file
.handle
);
375 status
= smb2_pull_o32s32_blob(&req
->in
, mem_ctx
, req
->in
.body
+0x50, &blob
);
376 if (!NT_STATUS_IS_OK(status
)) {
377 smb2_request_destroy(req
);
381 status
= smb2_create_blob_parse(mem_ctx
, blob
, &io
->out
.blobs
);
382 if (!NT_STATUS_IS_OK(status
)) {
383 smb2_request_destroy(req
);
387 /* pull out the parsed blobs */
388 for (i
=0;i
<io
->out
.blobs
.num_blobs
;i
++) {
389 if (strcmp(io
->out
.blobs
.blobs
[i
].tag
, SMB2_CREATE_TAG_MXAC
) == 0) {
390 /* TODO: this also contains a status field in
392 if (io
->out
.blobs
.blobs
[i
].data
.length
!= 8) {
393 smb2_request_destroy(req
);
394 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
396 io
->out
.maximal_access
= IVAL(io
->out
.blobs
.blobs
[i
].data
.data
, 4);
398 if (strcmp(io
->out
.blobs
.blobs
[i
].tag
, SMB2_CREATE_TAG_QFID
) == 0) {
399 if (io
->out
.blobs
.blobs
[i
].data
.length
!= 32) {
400 smb2_request_destroy(req
);
401 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
403 memcpy(io
->out
.on_disk_id
, io
->out
.blobs
.blobs
[i
].data
.data
, 32);
407 data_blob_free(&blob
);
409 return smb2_request_destroy(req
);
415 NTSTATUS
smb2_create(struct smb2_tree
*tree
, TALLOC_CTX
*mem_ctx
, struct smb2_create
*io
)
417 struct smb2_request
*req
= smb2_create_send(tree
, io
);
418 return smb2_create_recv(req
, mem_ctx
, io
);