Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : smb2 lib
4 : Copyright (C) Volker Lendecke 2011
5 :
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.
10 :
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.
15 :
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/>.
18 : */
19 :
20 : #include "includes.h"
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"
26 : #include "reparse.h"
27 :
28 : struct smb2cli_create_state {
29 : enum protocol_types protocol; /* for symlink error response parser */
30 : uint8_t *name_utf16;
31 : size_t name_utf16_len;
32 : uint8_t fixed[56];
33 :
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;
40 : };
41 :
42 : static void smb2cli_create_done(struct tevent_req *subreq);
43 : static bool smb2cli_create_cancel(struct tevent_req *req);
44 :
45 74355 : struct tevent_req *smb2cli_create_send(
46 : TALLOC_CTX *mem_ctx,
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,
52 : const char *filename,
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)
61 : {
62 620 : struct tevent_req *req, *subreq;
63 620 : struct smb2cli_create_state *state;
64 620 : uint8_t *fixed;
65 620 : DATA_BLOB blob;
66 620 : NTSTATUS status;
67 620 : size_t blobs_offset;
68 620 : uint8_t *dyn;
69 620 : size_t dyn_len;
70 620 : size_t max_dyn_len;
71 74355 : uint32_t additional_flags = 0;
72 74355 : uint32_t clear_flags = 0;
73 620 : bool ok;
74 :
75 74355 : req = tevent_req_create(mem_ctx, &state,
76 : struct smb2cli_create_state);
77 74355 : if (req == NULL) {
78 0 : return NULL;
79 : }
80 74355 : state->protocol = smbXcli_conn_protocol(conn);
81 :
82 74975 : ok = convert_string_talloc(
83 : state,
84 : CH_UNIX,
85 : CH_UTF16,
86 : filename,
87 : strlen(filename),
88 74355 : &state->name_utf16,
89 74355 : &state->name_utf16_len);
90 74355 : if (!ok) {
91 0 : tevent_req_oom(req);
92 0 : return tevent_req_post(req, ev);
93 : }
94 :
95 74355 : if (strlen(filename) == 0) {
96 4715 : TALLOC_FREE(state->name_utf16);
97 4715 : state->name_utf16_len = 0;
98 : }
99 :
100 74355 : fixed = state->fixed;
101 :
102 74355 : SSVAL(fixed, 0, 57);
103 74355 : SCVAL(fixed, 3, oplock_level);
104 74355 : SIVAL(fixed, 4, impersonation_level);
105 74355 : SIVAL(fixed, 24, desired_access);
106 74355 : SIVAL(fixed, 28, file_attributes);
107 74355 : SIVAL(fixed, 32, share_access);
108 74355 : SIVAL(fixed, 36, create_disposition);
109 74355 : SIVAL(fixed, 40, create_options);
110 :
111 74355 : SSVAL(fixed, 44, SMB2_HDR_BODY + 56);
112 74355 : SSVAL(fixed, 46, state->name_utf16_len);
113 :
114 74355 : blob = data_blob_null;
115 :
116 74355 : if (blobs != NULL) {
117 56321 : status = smb2_create_blob_push(state, &blob, *blobs);
118 56321 : if (tevent_req_nterror(req, status)) {
119 0 : return tevent_req_post(req, ev);
120 : }
121 : }
122 :
123 74355 : blobs_offset = state->name_utf16_len;
124 74355 : blobs_offset = ((blobs_offset + 3) & ~3);
125 :
126 74355 : if (blob.length > 0) {
127 4807 : blobs_offset = ((blobs_offset + 7) & ~7);
128 4807 : SIVAL(fixed, 48, blobs_offset + SMB2_HDR_BODY + 56);
129 4807 : SIVAL(fixed, 52, blob.length);
130 : }
131 :
132 74355 : dyn_len = MAX(1, blobs_offset + blob.length);
133 74355 : dyn = talloc_zero_array(state, uint8_t, dyn_len);
134 74355 : if (tevent_req_nomem(dyn, req)) {
135 0 : return tevent_req_post(req, ev);
136 : }
137 :
138 74355 : if (state->name_utf16 != NULL) {
139 69640 : memcpy(dyn, state->name_utf16, state->name_utf16_len);
140 : }
141 :
142 74355 : if (blob.data != NULL) {
143 4807 : memcpy(dyn + blobs_offset,
144 4807 : blob.data, blob.length);
145 4807 : data_blob_free(&blob);
146 : }
147 :
148 145142 : if (smbXcli_conn_dfs_supported(conn) &&
149 70787 : smbXcli_tcon_is_dfs_share(tcon))
150 : {
151 12676 : additional_flags |= SMB2_HDR_FLAG_DFS;
152 : }
153 :
154 : /*
155 : * We use max_dyn_len = 0
156 : * as we don't explicitly ask for any output length.
157 : *
158 : * But it's still possible for the server to return
159 : * large create blobs.
160 : */
161 74355 : max_dyn_len = 0;
162 :
163 74975 : subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_CREATE,
164 : additional_flags, clear_flags,
165 : timeout_msec,
166 : tcon,
167 : session,
168 74355 : state->fixed, sizeof(state->fixed),
169 : dyn, dyn_len,
170 : max_dyn_len);
171 74355 : if (tevent_req_nomem(subreq, req)) {
172 0 : return tevent_req_post(req, ev);
173 : }
174 74355 : tevent_req_set_callback(subreq, smb2cli_create_done, req);
175 :
176 74355 : state->subreq = subreq;
177 74355 : tevent_req_set_cancel_fn(req, smb2cli_create_cancel);
178 :
179 74355 : return req;
180 : }
181 :
182 2 : static bool smb2cli_create_cancel(struct tevent_req *req)
183 : {
184 2 : struct smb2cli_create_state *state = tevent_req_data(req,
185 : struct smb2cli_create_state);
186 2 : return tevent_req_cancel(state->subreq);
187 : }
188 :
189 : /*
190 : * [MS-SMB2] 2.2.2.2.1 Symbolic Link Error Response
191 : */
192 :
193 0 : static NTSTATUS smb2cli_parse_symlink_error_response(
194 : TALLOC_CTX *mem_ctx,
195 : const uint8_t *buf,
196 : size_t buflen,
197 : struct symlink_reparse_struct **psymlink)
198 : {
199 0 : struct symlink_reparse_struct *symlink = NULL;
200 0 : struct reparse_data_buffer reparse_buf = {
201 : .tag = 0,
202 : };
203 0 : uint32_t symlink_length, error_tag;
204 0 : NTSTATUS status;
205 :
206 0 : if (buflen < 8) {
207 0 : DBG_DEBUG("buffer too short: %zu bytes\n", buflen);
208 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
209 : }
210 :
211 0 : symlink_length = IVAL(buf, 0);
212 0 : if (symlink_length != (buflen-4)) {
213 0 : DBG_DEBUG("symlink_length=%"PRIu32", (buflen-4)=%zu\n",
214 : symlink_length, buflen-4);
215 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
216 : }
217 :
218 0 : error_tag = IVAL(buf, 4);
219 0 : if (error_tag != SYMLINK_ERROR_TAG) {
220 0 : DBG_DEBUG("error_tag=%"PRIu32", expected 0x%x\n",
221 : error_tag,
222 : SYMLINK_ERROR_TAG);
223 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
224 : }
225 :
226 0 : symlink = talloc(mem_ctx, struct symlink_reparse_struct);
227 0 : if (symlink == NULL) {
228 0 : return NT_STATUS_NO_MEMORY;
229 : }
230 :
231 0 : status = reparse_data_buffer_parse(symlink,
232 : &reparse_buf,
233 : buf + 8,
234 : buflen - 8);
235 0 : if (!NT_STATUS_IS_OK(status)) {
236 0 : DBG_DEBUG("reparse_data_buffer_parse() failed: %s\n",
237 : nt_errstr(status));
238 0 : TALLOC_FREE(symlink);
239 0 : return status;
240 : }
241 :
242 0 : if (reparse_buf.tag != IO_REPARSE_TAG_SYMLINK) {
243 0 : DBG_DEBUG("Got tag 0x%" PRIx32 ", "
244 : "expected IO_REPARSE_TAG_SYMLINK\n",
245 : reparse_buf.tag);
246 0 : TALLOC_FREE(symlink);
247 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
248 : }
249 :
250 0 : *symlink = reparse_buf.parsed.lnk;
251 0 : *psymlink = symlink;
252 0 : return NT_STATUS_OK;
253 : }
254 :
255 : /*
256 : * [MS-SMB2] 2.2.2 ErrorData
257 : *
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
260 : * just this.
261 : */
262 0 : static NTSTATUS smb2cli_create_error_data_parse(
263 : enum protocol_types protocol,
264 : uint8_t error_context_count,
265 : uint32_t byte_count,
266 : const uint8_t *buf,
267 : size_t buflen,
268 : TALLOC_CTX *mem_ctx,
269 : struct symlink_reparse_struct **_symlink)
270 : {
271 0 : struct symlink_reparse_struct *symlink = NULL;
272 0 : uint32_t error_data_length, error_id;
273 0 : NTSTATUS status;
274 :
275 0 : if (protocol != PROTOCOL_SMB3_11) {
276 0 : if (error_context_count != 0) {
277 0 : DBG_DEBUG("Got error_context_count=%"PRIu8"\n",
278 : error_context_count);
279 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
280 : }
281 :
282 0 : status = smb2cli_parse_symlink_error_response(
283 : mem_ctx, buf, buflen, &symlink);
284 0 : if (!NT_STATUS_IS_OK(status)) {
285 0 : return status;
286 : }
287 0 : *_symlink = symlink;
288 0 : return NT_STATUS_OK;
289 : }
290 :
291 : /*
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.
296 : */
297 :
298 0 : if (error_context_count != 1) {
299 0 : DBG_DEBUG("Got error_context_count=%"PRIu8"\n",
300 : error_context_count);
301 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
302 : }
303 :
304 0 : if (byte_count != buflen) {
305 0 : DBG_DEBUG("bytecount=%"PRIu32", "
306 : "buflen=%zu\n",
307 : byte_count,
308 : buflen);
309 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
310 : }
311 :
312 0 : if (buflen < 8) {
313 0 : DBG_DEBUG("buflen=%zu\n", buflen);
314 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
315 : }
316 :
317 0 : error_data_length = IVAL(buf, 0);
318 0 : if (error_data_length != (buflen - 8)) {
319 0 : DBG_DEBUG("error_data_length=%"PRIu32", expected %zu\n",
320 : error_data_length,
321 : buflen - 8);
322 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
323 : }
324 :
325 0 : error_id = IVAL(buf, 4);
326 0 : if (error_id != 0) {
327 0 : DBG_DEBUG("error_id=%"PRIu32", expected 0\n", error_id);
328 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
329 : }
330 :
331 0 : status = smb2cli_parse_symlink_error_response(
332 : mem_ctx, buf + 8, buflen - 8, &symlink);
333 0 : if (!NT_STATUS_IS_OK(status)) {
334 0 : DBG_DEBUG("smb2cli_parse_symlink_error_response failed: %s\n",
335 : nt_errstr(status));
336 0 : return status;
337 : }
338 :
339 0 : *_symlink = symlink;
340 0 : return NT_STATUS_OK;
341 : }
342 :
343 0 : static NTSTATUS smb2cli_create_unparsed_unix_len(
344 : size_t unparsed_utf16_len,
345 : uint8_t *name_utf16,
346 : size_t name_utf16_len,
347 : size_t *_unparsed_unix_len)
348 : {
349 0 : uint8_t *unparsed_utf16 = NULL;
350 0 : uint8_t *unparsed_unix = NULL;
351 0 : size_t unparsed_unix_len = 0;
352 0 : bool ok;
353 :
354 0 : if (unparsed_utf16_len > name_utf16_len) {
355 0 : DBG_DEBUG("unparsed_utf16_len=%zu, name_utf16_len=%zu\n",
356 : unparsed_utf16_len,
357 : name_utf16_len);
358 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
359 : }
360 :
361 0 : if (unparsed_utf16_len == 0) {
362 0 : *_unparsed_unix_len = 0;
363 0 : return NT_STATUS_OK;
364 : }
365 :
366 0 : unparsed_utf16 = name_utf16 + name_utf16_len - unparsed_utf16_len;
367 :
368 0 : ok = convert_string_talloc(
369 : talloc_tos(),
370 : CH_UTF16,
371 : CH_UNIX,
372 : unparsed_utf16,
373 : unparsed_utf16_len,
374 : &unparsed_unix,
375 : &unparsed_unix_len);
376 0 : if (!ok) {
377 0 : NTSTATUS status = map_nt_error_from_unix_common(errno);
378 0 : DBG_DEBUG("convert_string_talloc failed: %s\n",
379 : strerror(errno));
380 0 : return status;
381 : }
382 0 : *_unparsed_unix_len = unparsed_unix_len;
383 0 : return NT_STATUS_OK;
384 : }
385 :
386 74355 : static void smb2cli_create_done(struct tevent_req *subreq)
387 : {
388 620 : struct tevent_req *req =
389 74355 : tevent_req_callback_data(subreq,
390 : struct tevent_req);
391 620 : struct smb2cli_create_state *state =
392 74355 : tevent_req_data(req,
393 : struct smb2cli_create_state);
394 620 : NTSTATUS status;
395 620 : struct iovec *iov;
396 620 : uint8_t *body;
397 620 : uint32_t offset, length;
398 620 : static const struct smb2cli_req_expected_response expected[] = {
399 : {
400 : .status = NT_STATUS_OK,
401 : .body_size = 0x59
402 : },
403 : {
404 : .status = NT_STATUS_STOPPED_ON_SYMLINK,
405 : .body_size = 0x9,
406 : }
407 : };
408 :
409 74355 : status = smb2cli_req_recv(subreq, state, &iov,
410 : expected, ARRAY_SIZE(expected));
411 74355 : TALLOC_FREE(subreq);
412 :
413 74355 : if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
414 0 : uint16_t error_context_count = CVAL(iov[1].iov_base, 2);
415 0 : uint32_t byte_count = IVAL(iov[1].iov_base, 4);
416 0 : size_t unparsed_unix_len = 0;
417 :
418 0 : NTSTATUS symlink_status;
419 :
420 0 : symlink_status = smb2cli_create_error_data_parse(
421 : state->protocol,
422 : error_context_count,
423 : byte_count,
424 0 : iov[2].iov_base,
425 0 : iov[2].iov_len,
426 : state,
427 : &state->symlink);
428 0 : if (tevent_req_nterror(req, symlink_status)) {
429 0 : return;
430 : }
431 :
432 : /*
433 : * Our callers want to know the unparsed length in
434 : * unix encoding.
435 : */
436 0 : symlink_status = smb2cli_create_unparsed_unix_len(
437 0 : state->symlink->unparsed_path_length,
438 : state->name_utf16,
439 : state->name_utf16_len,
440 : &unparsed_unix_len);
441 0 : if (tevent_req_nterror(req, symlink_status)) {
442 0 : return;
443 : }
444 0 : state->symlink->unparsed_path_length = unparsed_unix_len;
445 : }
446 :
447 74355 : if (tevent_req_nterror(req, status)) {
448 10115 : return;
449 : }
450 :
451 64240 : body = (uint8_t *)iov[1].iov_base;
452 :
453 64240 : state->cr.oplock_level = CVAL(body, 2);
454 64240 : state->cr.flags = CVAL(body, 3);
455 64240 : state->cr.create_action = IVAL(body, 4);
456 64240 : state->cr.creation_time = BVAL(body, 8);
457 64240 : state->cr.last_access_time = BVAL(body, 16);
458 64240 : state->cr.last_write_time = BVAL(body, 24);
459 64240 : state->cr.change_time = BVAL(body, 32);
460 64240 : state->cr.allocation_size = BVAL(body, 40);
461 64240 : state->cr.end_of_file = BVAL(body, 48);
462 64240 : state->cr.file_attributes = IVAL(body, 56);
463 64240 : state->fid_persistent = BVAL(body, 64);
464 64240 : state->fid_volatile = BVAL(body, 72);
465 :
466 64240 : offset = IVAL(body, 80);
467 64240 : length = IVAL(body, 84);
468 :
469 64240 : if ((offset != 0) && (length != 0)) {
470 2146 : if ((offset != SMB2_HDR_BODY + 88) ||
471 2146 : (length > iov[2].iov_len)) {
472 0 : tevent_req_nterror(
473 : req, NT_STATUS_INVALID_NETWORK_RESPONSE);
474 0 : return;
475 : }
476 2146 : status = smb2_create_blob_parse(
477 2146 : state, data_blob_const(iov[2].iov_base, length),
478 : &state->blobs);
479 2146 : if (tevent_req_nterror(req, status)) {
480 0 : return;
481 : }
482 : }
483 64240 : tevent_req_done(req);
484 : }
485 :
486 74355 : NTSTATUS smb2cli_create_recv(struct tevent_req *req,
487 : uint64_t *fid_persistent,
488 : uint64_t *fid_volatile,
489 : struct smb_create_returns *cr,
490 : TALLOC_CTX *mem_ctx,
491 : struct smb2_create_blobs *blobs,
492 : struct symlink_reparse_struct **psymlink)
493 : {
494 620 : struct smb2cli_create_state *state =
495 74355 : tevent_req_data(req,
496 : struct smb2cli_create_state);
497 620 : NTSTATUS status;
498 :
499 74355 : if (tevent_req_is_nterror(req, &status)) {
500 10115 : if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK) &&
501 : (psymlink != NULL)) {
502 0 : *psymlink = talloc_move(mem_ctx, &state->symlink);
503 : }
504 10115 : tevent_req_received(req);
505 10115 : return status;
506 : }
507 64240 : *fid_persistent = state->fid_persistent;
508 64240 : *fid_volatile = state->fid_volatile;
509 64240 : if (cr) {
510 46448 : *cr = state->cr;
511 : }
512 64240 : if (blobs) {
513 46448 : blobs->num_blobs = state->blobs.num_blobs;
514 46448 : blobs->blobs = talloc_move(mem_ctx, &state->blobs.blobs);
515 : }
516 64240 : tevent_req_received(req);
517 64240 : return NT_STATUS_OK;
518 : }
519 :
520 270 : 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,
536 : TALLOC_CTX *mem_ctx,
537 : struct smb2_create_blobs *ret_blobs,
538 : struct symlink_reparse_struct **psymlink)
539 : {
540 270 : TALLOC_CTX *frame = talloc_stackframe();
541 0 : struct tevent_context *ev;
542 0 : struct tevent_req *req;
543 270 : NTSTATUS status = NT_STATUS_NO_MEMORY;
544 :
545 270 : if (smbXcli_conn_has_async_calls(conn)) {
546 : /*
547 : * Can't use sync call while an async call is in flight
548 : */
549 0 : status = NT_STATUS_INVALID_PARAMETER;
550 0 : goto fail;
551 : }
552 270 : ev = samba_tevent_context_init(frame);
553 270 : if (ev == NULL) {
554 0 : goto fail;
555 : }
556 270 : req = smb2cli_create_send(frame, ev, conn, timeout_msec,
557 : session, tcon,
558 : filename, oplock_level,
559 : impersonation_level, desired_access,
560 : file_attributes, share_access,
561 : create_disposition, create_options,
562 : blobs);
563 270 : if (req == NULL) {
564 0 : goto fail;
565 : }
566 270 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
567 0 : goto fail;
568 : }
569 270 : status = smb2cli_create_recv(
570 : req,
571 : fid_persistent,
572 : fid_volatile,
573 : cr,
574 : mem_ctx,
575 : ret_blobs,
576 : psymlink);
577 270 : fail:
578 270 : TALLOC_FREE(frame);
579 270 : return status;
580 : }
|