Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : SMB2 client tree handling
5 :
6 : Copyright (C) Andrew Tridgell 2005
7 :
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.
12 :
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.
17 :
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/>.
20 : */
21 :
22 : #include "includes.h"
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"
28 :
29 : /*
30 : send a create request
31 : */
32 618063 : struct smb2_request *smb2_create_send(struct smb2_tree *tree, struct smb2_create *io)
33 : {
34 363 : struct smb2_request *req;
35 363 : NTSTATUS status;
36 363 : DATA_BLOB blob;
37 363 : struct smb2_create_blobs blobs;
38 363 : int i;
39 :
40 618063 : ZERO_STRUCT(blobs);
41 :
42 618063 : req = smb2_request_init_tree(tree, SMB2_OP_CREATE, 0x38, true, 0);
43 618063 : if (req == NULL) return NULL;
44 :
45 618063 : SCVAL(req->out.body, 0x02, io->in.security_flags);
46 618063 : SCVAL(req->out.body, 0x03, io->in.oplock_level);
47 618063 : SIVAL(req->out.body, 0x04, io->in.impersonation_level);
48 618063 : SBVAL(req->out.body, 0x08, io->in.create_flags);
49 618063 : SBVAL(req->out.body, 0x10, io->in.reserved);
50 618063 : SIVAL(req->out.body, 0x18, io->in.desired_access);
51 618063 : SIVAL(req->out.body, 0x1C, io->in.file_attributes);
52 618063 : SIVAL(req->out.body, 0x20, io->in.share_access);
53 618063 : SIVAL(req->out.body, 0x24, io->in.create_disposition);
54 618063 : SIVAL(req->out.body, 0x28, io->in.create_options);
55 :
56 618063 : status = smb2_push_o16s16_string(&req->out, 0x2C, io->in.fname);
57 618063 : if (!NT_STATUS_IS_OK(status)) {
58 0 : talloc_free(req);
59 0 : return NULL;
60 : }
61 :
62 : /* now add all the optional blobs */
63 618063 : if (io->in.eas.num_eas != 0) {
64 231 : DATA_BLOB b = data_blob_talloc(req, NULL,
65 : ea_list_size_chained(io->in.eas.num_eas, io->in.eas.eas, 4));
66 231 : ea_put_list_chained(b.data, io->in.eas.num_eas, io->in.eas.eas, 4);
67 231 : status = smb2_create_blob_add(req, &blobs,
68 : SMB2_CREATE_TAG_EXTA, b);
69 231 : if (!NT_STATUS_IS_OK(status)) {
70 0 : talloc_free(req);
71 0 : return NULL;
72 : }
73 231 : data_blob_free(&b);
74 : }
75 :
76 : /* an empty MxAc tag seems to be used to ask the server to
77 : return the maximum access mask allowed on the file */
78 618063 : if (io->in.query_maximal_access) {
79 : /* TODO: MS-SMB2 2.2.13.2.5 says this can contain a timestamp? What to do
80 : with that if it doesn't match? */
81 44 : status = smb2_create_blob_add(req, &blobs,
82 : SMB2_CREATE_TAG_MXAC, data_blob(NULL, 0));
83 44 : if (!NT_STATUS_IS_OK(status)) {
84 0 : talloc_free(req);
85 0 : return NULL;
86 : }
87 : }
88 :
89 618063 : if (io->in.alloc_size != 0) {
90 0 : uint8_t data[8];
91 181 : SBVAL(data, 0, io->in.alloc_size);
92 181 : status = smb2_create_blob_add(req, &blobs,
93 : SMB2_CREATE_TAG_ALSI, data_blob_const(data, 8));
94 181 : if (!NT_STATUS_IS_OK(status)) {
95 0 : talloc_free(req);
96 0 : return NULL;
97 : }
98 : }
99 :
100 618063 : if (io->in.durable_open) {
101 338 : status = smb2_create_blob_add(req, &blobs,
102 : SMB2_CREATE_TAG_DHNQ, data_blob_talloc_zero(req, 16));
103 338 : if (!NT_STATUS_IS_OK(status)) {
104 0 : talloc_free(req);
105 0 : return NULL;
106 : }
107 : }
108 :
109 618063 : if (io->in.durable_open_v2) {
110 0 : uint8_t data[32];
111 1050 : uint32_t flags = 0;
112 1050 : struct GUID_ndr_buf guid_buf = { .buf = {0}, };
113 :
114 1050 : SIVAL(data, 0, io->in.timeout);
115 1050 : if (io->in.persistent_open) {
116 208 : flags = SMB2_DHANDLE_FLAG_PERSISTENT;
117 : }
118 1050 : SIVAL(data, 4, flags);
119 1050 : SBVAL(data, 8, 0x0); /* reserved */
120 1050 : GUID_to_ndr_buf(&io->in.create_guid, &guid_buf);
121 1050 : memcpy(data+16, guid_buf.buf, sizeof(guid_buf.buf));
122 :
123 1050 : status = smb2_create_blob_add(req, &blobs,
124 : SMB2_CREATE_TAG_DH2Q,
125 : data_blob_const(data, 32));
126 1050 : if (!NT_STATUS_IS_OK(status)) {
127 0 : talloc_free(req);
128 0 : return NULL;
129 : }
130 : }
131 :
132 618063 : if (io->in.durable_handle) {
133 0 : uint8_t data[16];
134 138 : smb2_push_handle(data, io->in.durable_handle);
135 138 : status = smb2_create_blob_add(req, &blobs,
136 : SMB2_CREATE_TAG_DHNC, data_blob_const(data, 16));
137 138 : if (!NT_STATUS_IS_OK(status)) {
138 0 : talloc_free(req);
139 0 : return NULL;
140 : }
141 : }
142 :
143 618063 : if (io->in.durable_handle_v2) {
144 0 : uint8_t data[36];
145 126 : struct GUID_ndr_buf guid_buf = { .buf = {0}, };
146 126 : uint32_t flags = 0;
147 :
148 126 : smb2_push_handle(data, io->in.durable_handle_v2);
149 126 : GUID_to_ndr_buf(&io->in.create_guid, &guid_buf);
150 126 : memcpy(data+16, guid_buf.buf, sizeof(guid_buf.buf));
151 126 : if (io->in.persistent_open) {
152 0 : flags = SMB2_DHANDLE_FLAG_PERSISTENT;
153 : }
154 126 : SIVAL(data, 32, flags);
155 :
156 126 : status = smb2_create_blob_add(req, &blobs,
157 : SMB2_CREATE_TAG_DH2C,
158 : data_blob_const(data, 36));
159 126 : if (!NT_STATUS_IS_OK(status)) {
160 0 : talloc_free(req);
161 0 : return NULL;
162 : }
163 : }
164 :
165 618063 : if (io->in.timewarp) {
166 0 : uint8_t data[8];
167 23 : SBVAL(data, 0, io->in.timewarp);
168 23 : status = smb2_create_blob_add(req, &blobs,
169 : SMB2_CREATE_TAG_TWRP, data_blob_const(data, 8));
170 23 : if (!NT_STATUS_IS_OK(status)) {
171 0 : talloc_free(req);
172 0 : return NULL;
173 : }
174 : }
175 :
176 618063 : if (io->in.sec_desc) {
177 0 : enum ndr_err_code ndr_err;
178 0 : DATA_BLOB sd_blob;
179 105 : ndr_err = ndr_push_struct_blob(&sd_blob, req, io->in.sec_desc,
180 : (ndr_push_flags_fn_t)ndr_push_security_descriptor);
181 105 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
182 0 : talloc_free(req);
183 0 : return NULL;
184 : }
185 105 : status = smb2_create_blob_add(req, &blobs,
186 : SMB2_CREATE_TAG_SECD, sd_blob);
187 105 : if (!NT_STATUS_IS_OK(status)) {
188 0 : talloc_free(req);
189 0 : return NULL;
190 : }
191 : }
192 :
193 618063 : if (io->in.query_on_disk_id) {
194 52 : status = smb2_create_blob_add(req, &blobs,
195 : SMB2_CREATE_TAG_QFID, data_blob(NULL, 0));
196 52 : if (!NT_STATUS_IS_OK(status)) {
197 0 : talloc_free(req);
198 0 : return NULL;
199 : }
200 : }
201 :
202 618063 : if (io->in.lease_request) {
203 0 : uint8_t data[32];
204 :
205 952 : if (!smb2_lease_push(io->in.lease_request, data,
206 : sizeof(data))) {
207 0 : TALLOC_FREE(req);
208 0 : return NULL;
209 : }
210 :
211 952 : status = smb2_create_blob_add(
212 : req, &blobs, SMB2_CREATE_TAG_RQLS,
213 : data_blob_const(data, sizeof(data)));
214 952 : if (!NT_STATUS_IS_OK(status)) {
215 0 : talloc_free(req);
216 0 : return NULL;
217 : }
218 : }
219 :
220 618063 : if (io->in.lease_request_v2) {
221 0 : uint8_t data[52];
222 :
223 196 : if (!smb2_lease_push(io->in.lease_request_v2, data,
224 : sizeof(data))) {
225 0 : TALLOC_FREE(req);
226 0 : return NULL;
227 : }
228 :
229 196 : status = smb2_create_blob_add(
230 : req, &blobs, SMB2_CREATE_TAG_RQLS,
231 : data_blob_const(data, sizeof(data)));
232 196 : if (!NT_STATUS_IS_OK(status)) {
233 0 : talloc_free(req);
234 0 : return NULL;
235 : }
236 : }
237 :
238 618063 : if (io->in.app_instance_id) {
239 0 : uint8_t data[20];
240 8 : struct GUID_ndr_buf guid_buf = { .buf = {0}, };
241 :
242 8 : SSVAL(data, 0, 20); /* structure size */
243 8 : SSVAL(data, 2, 0); /* reserved */
244 :
245 8 : GUID_to_ndr_buf(io->in.app_instance_id, &guid_buf);
246 8 : memcpy(data+4, guid_buf.buf, sizeof(guid_buf.buf));
247 :
248 8 : status = smb2_create_blob_add(req, &blobs,
249 : SMB2_CREATE_TAG_APP_INSTANCE_ID,
250 : data_blob_const(data, 20));
251 8 : if (!NT_STATUS_IS_OK(status)) {
252 0 : talloc_free(req);
253 0 : return NULL;
254 : }
255 : }
256 :
257 : /* and any custom blobs */
258 618204 : for (i=0;i<io->in.blobs.num_blobs;i++) {
259 141 : status = smb2_create_blob_add(req, &blobs,
260 141 : io->in.blobs.blobs[i].tag,
261 141 : io->in.blobs.blobs[i].data);
262 141 : if (!NT_STATUS_IS_OK(status)) {
263 0 : talloc_free(req);
264 0 : return NULL;
265 : }
266 : }
267 :
268 :
269 618063 : status = smb2_create_blob_push(req, &blob, blobs);
270 618063 : if (!NT_STATUS_IS_OK(status)) {
271 0 : talloc_free(req);
272 0 : return NULL;
273 : }
274 :
275 618063 : status = smb2_push_o32s32_blob(&req->out, 0x30, blob);
276 618063 : if (!NT_STATUS_IS_OK(status)) {
277 0 : talloc_free(req);
278 0 : return NULL;
279 : }
280 :
281 618063 : if (((io->in.fname == NULL) || (strlen(io->in.fname) == 0)) &&
282 31583 : (blob.length == 0)) {
283 31438 : struct smb2_request_buffer *buf = &req->out;
284 :
285 31438 : status = smb2_grow_buffer(buf, 1);
286 31438 : if (!NT_STATUS_IS_OK(status)) {
287 0 : talloc_free(req);
288 0 : return NULL;
289 : }
290 31438 : buf->dynamic[0] = 0;
291 31438 : buf->dynamic += 1;
292 31438 : buf->body_size += 1;
293 31438 : buf->size += 1;
294 : }
295 :
296 618063 : data_blob_free(&blob);
297 :
298 618063 : smb2_transport_send(req);
299 :
300 618063 : return req;
301 : }
302 :
303 :
304 : /*
305 : recv a create reply
306 : */
307 617993 : NTSTATUS smb2_create_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, struct smb2_create *io)
308 : {
309 363 : NTSTATUS status;
310 363 : DATA_BLOB blob;
311 363 : int i;
312 :
313 618356 : if (!smb2_request_receive(req) ||
314 617969 : !smb2_request_is_ok(req)) {
315 167670 : return smb2_request_destroy(req);
316 : }
317 :
318 450323 : SMB2_CHECK_PACKET_RECV(req, 0x58, true);
319 450323 : ZERO_STRUCT(io->out);
320 450323 : io->out.oplock_level = CVAL(req->in.body, 0x02);
321 450323 : io->out.reserved = CVAL(req->in.body, 0x03);
322 450323 : io->out.create_action = IVAL(req->in.body, 0x04);
323 450323 : io->out.create_time = smbcli_pull_nttime(req->in.body, 0x08);
324 450323 : io->out.access_time = smbcli_pull_nttime(req->in.body, 0x10);
325 450323 : io->out.write_time = smbcli_pull_nttime(req->in.body, 0x18);
326 450323 : io->out.change_time = smbcli_pull_nttime(req->in.body, 0x20);
327 450323 : io->out.alloc_size = BVAL(req->in.body, 0x28);
328 450323 : io->out.size = BVAL(req->in.body, 0x30);
329 450323 : io->out.file_attr = IVAL(req->in.body, 0x38);
330 450323 : io->out.reserved2 = IVAL(req->in.body, 0x3C);
331 450323 : smb2_pull_handle(req->in.body+0x40, &io->out.file.handle);
332 450323 : status = smb2_pull_o32s32_blob(&req->in, mem_ctx, req->in.body+0x50, &blob);
333 450323 : if (!NT_STATUS_IS_OK(status)) {
334 0 : smb2_request_destroy(req);
335 0 : return status;
336 : }
337 :
338 450323 : status = smb2_create_blob_parse(mem_ctx, blob, &io->out.blobs);
339 450323 : if (!NT_STATUS_IS_OK(status)) {
340 0 : smb2_request_destroy(req);
341 0 : return status;
342 : }
343 :
344 : /* pull out the parsed blobs */
345 452135 : for (i=0;i<io->out.blobs.num_blobs;i++) {
346 1812 : if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_MXAC) == 0) {
347 34 : if (io->out.blobs.blobs[i].data.length != 8) {
348 0 : smb2_request_destroy(req);
349 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
350 : }
351 34 : io->out.maximal_access_status =
352 34 : IVAL(io->out.blobs.blobs[i].data.data, 0);
353 34 : io->out.maximal_access = IVAL(io->out.blobs.blobs[i].data.data, 4);
354 : }
355 1812 : if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_QFID) == 0) {
356 48 : if (io->out.blobs.blobs[i].data.length != 32) {
357 0 : smb2_request_destroy(req);
358 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
359 : }
360 48 : memcpy(io->out.on_disk_id, io->out.blobs.blobs[i].data.data, 32);
361 : }
362 1812 : if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_RQLS) == 0) {
363 1010 : struct smb2_lease *ls = NULL;
364 0 : uint8_t *data;
365 :
366 1010 : ZERO_STRUCT(io->out.lease_response);
367 1010 : ZERO_STRUCT(io->out.lease_response_v2);
368 :
369 1010 : switch (io->out.blobs.blobs[i].data.length) {
370 878 : case 32:
371 878 : ls = &io->out.lease_response;
372 878 : ls->lease_version = 1;
373 878 : break;
374 132 : case 52:
375 132 : ls = &io->out.lease_response_v2;
376 132 : ls->lease_version = 2;
377 132 : break;
378 0 : default:
379 0 : smb2_request_destroy(req);
380 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
381 : }
382 :
383 1010 : data = io->out.blobs.blobs[i].data.data;
384 1010 : memcpy(&ls->lease_key, data, 16);
385 1010 : ls->lease_state = IVAL(data, 16);
386 1010 : ls->lease_flags = IVAL(data, 20);
387 1010 : ls->lease_duration = BVAL(data, 24);
388 :
389 1010 : if (io->out.blobs.blobs[i].data.length == 52) {
390 132 : memcpy(&ls->parent_lease_key, data+32, 16);
391 132 : ls->lease_epoch = SVAL(data, 48);
392 : }
393 : }
394 1812 : if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_DHNQ) == 0) {
395 154 : if (io->out.blobs.blobs[i].data.length != 8) {
396 0 : smb2_request_destroy(req);
397 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
398 : }
399 154 : io->out.durable_open = true;
400 : }
401 1812 : if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_DH2Q) == 0) {
402 0 : uint32_t flags;
403 0 : uint8_t *data;
404 :
405 438 : if (io->out.blobs.blobs[i].data.length != 8) {
406 0 : smb2_request_destroy(req);
407 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
408 : }
409 :
410 438 : io->out.durable_open = false;
411 438 : io->out.durable_open_v2 = true;
412 :
413 438 : data = io->out.blobs.blobs[i].data.data;
414 438 : io->out.timeout = IVAL(data, 0);
415 438 : flags = IVAL(data, 4);
416 438 : if ((flags & SMB2_DHANDLE_FLAG_PERSISTENT) != 0) {
417 0 : io->out.persistent_open = true;
418 : }
419 : }
420 : }
421 :
422 450323 : data_blob_free(&blob);
423 :
424 450323 : return smb2_request_destroy(req);
425 : }
426 :
427 : /*
428 : sync create request
429 : */
430 224797 : NTSTATUS smb2_create(struct smb2_tree *tree, TALLOC_CTX *mem_ctx, struct smb2_create *io)
431 : {
432 224797 : struct smb2_request *req = smb2_create_send(tree, io);
433 224797 : return smb2_create_recv(req, mem_ctx, io);
434 : }
|