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_symlink.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 16269 : 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 : struct tevent_req *req, *subreq;
63 : struct smb2cli_create_state *state;
64 : uint8_t *fixed;
65 : DATA_BLOB blob;
66 : NTSTATUS status;
67 : size_t blobs_offset;
68 : uint8_t *dyn;
69 : size_t dyn_len;
70 : size_t max_dyn_len;
71 16269 : uint32_t additional_flags = 0;
72 16269 : uint32_t clear_flags = 0;
73 : bool ok;
74 :
75 16269 : req = tevent_req_create(mem_ctx, &state,
76 : struct smb2cli_create_state);
77 16269 : if (req == NULL) {
78 0 : return NULL;
79 : }
80 16269 : state->protocol = smbXcli_conn_protocol(conn);
81 :
82 16269 : ok = convert_string_talloc(
83 : state,
84 : CH_UNIX,
85 : CH_UTF16,
86 : filename,
87 : strlen(filename),
88 16269 : &state->name_utf16,
89 16269 : &state->name_utf16_len);
90 16269 : if (!ok) {
91 0 : tevent_req_oom(req);
92 0 : return tevent_req_post(req, ev);
93 : }
94 :
95 16269 : if (strlen(filename) == 0) {
96 999 : TALLOC_FREE(state->name_utf16);
97 999 : state->name_utf16_len = 0;
98 : }
99 :
100 16269 : fixed = state->fixed;
101 :
102 16269 : SSVAL(fixed, 0, 57);
103 16269 : SCVAL(fixed, 3, oplock_level);
104 16269 : SIVAL(fixed, 4, impersonation_level);
105 16269 : SIVAL(fixed, 24, desired_access);
106 16269 : SIVAL(fixed, 28, file_attributes);
107 16269 : SIVAL(fixed, 32, share_access);
108 16269 : SIVAL(fixed, 36, create_disposition);
109 16269 : SIVAL(fixed, 40, create_options);
110 :
111 16269 : SSVAL(fixed, 44, SMB2_HDR_BODY + 56);
112 16269 : SSVAL(fixed, 46, state->name_utf16_len);
113 :
114 16269 : blob = data_blob_null;
115 :
116 16269 : if (blobs != NULL) {
117 11537 : status = smb2_create_blob_push(state, &blob, *blobs);
118 11537 : if (tevent_req_nterror(req, status)) {
119 0 : return tevent_req_post(req, ev);
120 : }
121 : }
122 :
123 16269 : blobs_offset = state->name_utf16_len;
124 16269 : blobs_offset = ((blobs_offset + 3) & ~3);
125 :
126 16269 : if (blob.length > 0) {
127 0 : blobs_offset = ((blobs_offset + 7) & ~7);
128 0 : SIVAL(fixed, 48, blobs_offset + SMB2_HDR_BODY + 56);
129 0 : SIVAL(fixed, 52, blob.length);
130 : }
131 :
132 16269 : dyn_len = MAX(1, blobs_offset + blob.length);
133 16269 : dyn = talloc_zero_array(state, uint8_t, dyn_len);
134 16269 : if (tevent_req_nomem(dyn, req)) {
135 0 : return tevent_req_post(req, ev);
136 : }
137 :
138 16269 : if (state->name_utf16 != NULL) {
139 15270 : memcpy(dyn, state->name_utf16, state->name_utf16_len);
140 : }
141 :
142 16269 : if (blob.data != NULL) {
143 0 : memcpy(dyn + blobs_offset,
144 0 : blob.data, blob.length);
145 0 : data_blob_free(&blob);
146 : }
147 :
148 29165 : if (smbXcli_conn_dfs_supported(conn) &&
149 12896 : smbXcli_tcon_is_dfs_share(tcon))
150 : {
151 1048 : 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 16269 : max_dyn_len = 0;
162 :
163 16269 : subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_CREATE,
164 : additional_flags, clear_flags,
165 : timeout_msec,
166 : tcon,
167 : session,
168 16269 : state->fixed, sizeof(state->fixed),
169 : dyn, dyn_len,
170 : max_dyn_len);
171 16269 : if (tevent_req_nomem(subreq, req)) {
172 0 : return tevent_req_post(req, ev);
173 : }
174 16269 : tevent_req_set_callback(subreq, smb2cli_create_done, req);
175 :
176 16269 : state->subreq = subreq;
177 16269 : tevent_req_set_cancel_fn(req, smb2cli_create_cancel);
178 :
179 16269 : return req;
180 : }
181 :
182 0 : static bool smb2cli_create_cancel(struct tevent_req *req)
183 : {
184 0 : struct smb2cli_create_state *state = tevent_req_data(req,
185 : struct smb2cli_create_state);
186 0 : 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 : uint32_t symlink_length, error_tag;
201 :
202 0 : if (buflen < 8) {
203 0 : DBG_DEBUG("buffer too short: %zu bytes\n", buflen);
204 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
205 : }
206 :
207 0 : symlink_length = IVAL(buf, 0);
208 0 : if (symlink_length != (buflen-4)) {
209 0 : DBG_DEBUG("symlink_length=%"PRIu32", (buflen-4)=%zu",
210 : symlink_length, buflen-4);
211 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
212 : }
213 :
214 0 : error_tag = IVAL(buf, 4);
215 0 : if (error_tag != SYMLINK_ERROR_TAG) {
216 0 : DBG_DEBUG("error_tag=%"PRIu32", expected 0x%x\n",
217 : error_tag,
218 : SYMLINK_ERROR_TAG);
219 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
220 : }
221 :
222 0 : symlink = symlink_reparse_buffer_parse(
223 : mem_ctx, buf+8, buflen-8);
224 0 : if (symlink == NULL) {
225 0 : DBG_DEBUG("symlink_reparse_buffer_parse failed\n");
226 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
227 : }
228 :
229 0 : *psymlink = symlink;
230 0 : return NT_STATUS_OK;
231 : }
232 :
233 : /*
234 : * [MS-SMB2] 2.2.2 ErrorData
235 : *
236 : * This is in theory a broad API, but as right now we only have a
237 : * single [MS-SMB2] 2.2.2.2.1 symlink error response we can return
238 : * just this.
239 : */
240 0 : static NTSTATUS smb2cli_create_error_data_parse(
241 : enum protocol_types protocol,
242 : uint8_t error_context_count,
243 : uint32_t byte_count,
244 : const uint8_t *buf,
245 : size_t buflen,
246 : TALLOC_CTX *mem_ctx,
247 : struct symlink_reparse_struct **_symlink)
248 : {
249 0 : struct symlink_reparse_struct *symlink = NULL;
250 : uint32_t error_data_length, error_id;
251 : NTSTATUS status;
252 :
253 0 : if (protocol != PROTOCOL_SMB3_11) {
254 0 : if (error_context_count != 0) {
255 0 : DBG_DEBUG("Got error_context_count=%"PRIu8"\n",
256 : error_context_count);
257 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
258 : }
259 :
260 0 : status = smb2cli_parse_symlink_error_response(
261 : mem_ctx, buf, buflen, &symlink);
262 0 : if (!NT_STATUS_IS_OK(status)) {
263 0 : return status;
264 : }
265 0 : *_symlink = symlink;
266 0 : return NT_STATUS_OK;
267 : }
268 :
269 : /*
270 : * The STOPPED_ON_SYMLINK that I've seen coming from W2k16 has
271 : * just a single array element in the [MS-SMB2] 2.2.2
272 : * ErrorData array. We'll need to adapt this if there actually
273 : * comes an array of multiple ErrorData elements.
274 : */
275 :
276 0 : if (error_context_count != 1) {
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 : if (byte_count != buflen) {
283 0 : DBG_DEBUG("bytecount=%"PRIu32", "
284 : "buflen=%zu\n",
285 : byte_count,
286 : buflen);
287 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
288 : }
289 :
290 0 : if (buflen < 8) {
291 0 : DBG_DEBUG("buflen=%zu\n", buflen);
292 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
293 : }
294 :
295 0 : error_data_length = IVAL(buf, 0);
296 0 : if (error_data_length != (buflen - 8)) {
297 0 : DBG_DEBUG("error_data_length=%"PRIu32", expected %zu\n",
298 : error_data_length,
299 : buflen - 8);
300 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
301 : }
302 :
303 0 : error_id = IVAL(buf, 4);
304 0 : if (error_id != 0) {
305 0 : DBG_DEBUG("error_id=%"PRIu32", expected 0\n", error_id);
306 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
307 : }
308 :
309 0 : status = smb2cli_parse_symlink_error_response(
310 : mem_ctx, buf + 8, buflen - 8, &symlink);
311 0 : if (!NT_STATUS_IS_OK(status)) {
312 0 : DBG_DEBUG("smb2cli_parse_symlink_error_response failed: %s\n",
313 : nt_errstr(status));
314 0 : return status;
315 : }
316 :
317 0 : *_symlink = symlink;
318 0 : return NT_STATUS_OK;
319 : }
320 :
321 0 : static NTSTATUS smb2cli_create_unparsed_unix_len(
322 : size_t unparsed_utf16_len,
323 : uint8_t *name_utf16,
324 : size_t name_utf16_len,
325 : size_t *_unparsed_unix_len)
326 : {
327 0 : uint8_t *unparsed_utf16 = NULL;
328 0 : uint8_t *unparsed_unix = NULL;
329 0 : size_t unparsed_unix_len = 0;
330 : bool ok;
331 :
332 0 : if (unparsed_utf16_len > name_utf16_len) {
333 0 : DBG_DEBUG("unparsed_utf16_len=%zu, name_utf16_len=%zu\n",
334 : unparsed_utf16_len,
335 : name_utf16_len);
336 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
337 : }
338 :
339 0 : if (unparsed_utf16_len == 0) {
340 0 : *_unparsed_unix_len = 0;
341 0 : return NT_STATUS_OK;
342 : }
343 :
344 0 : unparsed_utf16 = name_utf16 + name_utf16_len - unparsed_utf16_len;
345 :
346 0 : ok = convert_string_talloc(
347 : talloc_tos(),
348 : CH_UTF16,
349 : CH_UNIX,
350 : unparsed_utf16,
351 : unparsed_utf16_len,
352 : &unparsed_unix,
353 : &unparsed_unix_len);
354 0 : if (!ok) {
355 0 : NTSTATUS status = map_nt_error_from_unix_common(errno);
356 0 : DBG_DEBUG("convert_string_talloc failed: %s\n",
357 : strerror(errno));
358 0 : return status;
359 : }
360 0 : *_unparsed_unix_len = unparsed_unix_len;
361 0 : return NT_STATUS_OK;
362 : }
363 :
364 16269 : static void smb2cli_create_done(struct tevent_req *subreq)
365 : {
366 : struct tevent_req *req =
367 16269 : tevent_req_callback_data(subreq,
368 : struct tevent_req);
369 : struct smb2cli_create_state *state =
370 16269 : tevent_req_data(req,
371 : struct smb2cli_create_state);
372 : NTSTATUS status;
373 : struct iovec *iov;
374 : uint8_t *body;
375 : uint32_t offset, length;
376 : static const struct smb2cli_req_expected_response expected[] = {
377 : {
378 : .status = NT_STATUS_OK,
379 : .body_size = 0x59
380 : },
381 : {
382 : .status = NT_STATUS_STOPPED_ON_SYMLINK,
383 : .body_size = 0x9,
384 : }
385 : };
386 :
387 16269 : status = smb2cli_req_recv(subreq, state, &iov,
388 : expected, ARRAY_SIZE(expected));
389 16269 : TALLOC_FREE(subreq);
390 :
391 16269 : if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
392 0 : uint16_t error_context_count = CVAL(iov[1].iov_base, 2);
393 0 : uint32_t byte_count = IVAL(iov[1].iov_base, 4);
394 0 : size_t unparsed_unix_len = 0;
395 :
396 : NTSTATUS symlink_status;
397 :
398 0 : symlink_status = smb2cli_create_error_data_parse(
399 : state->protocol,
400 : error_context_count,
401 : byte_count,
402 0 : iov[2].iov_base,
403 0 : iov[2].iov_len,
404 : state,
405 : &state->symlink);
406 0 : if (tevent_req_nterror(req, symlink_status)) {
407 0 : return;
408 : }
409 :
410 : /*
411 : * Our callers want to know the unparsed length in
412 : * unix encoding.
413 : */
414 0 : symlink_status = smb2cli_create_unparsed_unix_len(
415 0 : state->symlink->unparsed_path_length,
416 : state->name_utf16,
417 : state->name_utf16_len,
418 : &unparsed_unix_len);
419 0 : if (tevent_req_nterror(req, symlink_status)) {
420 0 : return;
421 : }
422 0 : state->symlink->unparsed_path_length = unparsed_unix_len;
423 : }
424 :
425 16269 : if (tevent_req_nterror(req, status)) {
426 2020 : return;
427 : }
428 :
429 14249 : body = (uint8_t *)iov[1].iov_base;
430 :
431 14249 : state->cr.oplock_level = CVAL(body, 2);
432 14249 : state->cr.create_action = IVAL(body, 4);
433 14249 : state->cr.creation_time = BVAL(body, 8);
434 14249 : state->cr.last_access_time = BVAL(body, 16);
435 14249 : state->cr.last_write_time = BVAL(body, 24);
436 14249 : state->cr.change_time = BVAL(body, 32);
437 14249 : state->cr.allocation_size = BVAL(body, 40);
438 14249 : state->cr.end_of_file = BVAL(body, 48);
439 14249 : state->cr.file_attributes = IVAL(body, 56);
440 14249 : state->fid_persistent = BVAL(body, 64);
441 14249 : state->fid_volatile = BVAL(body, 72);
442 :
443 14249 : offset = IVAL(body, 80);
444 14249 : length = IVAL(body, 84);
445 :
446 14249 : if ((offset != 0) && (length != 0)) {
447 0 : if ((offset != SMB2_HDR_BODY + 88) ||
448 0 : (length > iov[2].iov_len)) {
449 0 : tevent_req_nterror(
450 : req, NT_STATUS_INVALID_NETWORK_RESPONSE);
451 0 : return;
452 : }
453 0 : status = smb2_create_blob_parse(
454 0 : state, data_blob_const(iov[2].iov_base, length),
455 : &state->blobs);
456 0 : if (tevent_req_nterror(req, status)) {
457 0 : return;
458 : }
459 : }
460 14249 : tevent_req_done(req);
461 : }
462 :
463 16269 : NTSTATUS smb2cli_create_recv(struct tevent_req *req,
464 : uint64_t *fid_persistent,
465 : uint64_t *fid_volatile,
466 : struct smb_create_returns *cr,
467 : TALLOC_CTX *mem_ctx,
468 : struct smb2_create_blobs *blobs,
469 : struct symlink_reparse_struct **psymlink)
470 : {
471 : struct smb2cli_create_state *state =
472 16269 : tevent_req_data(req,
473 : struct smb2cli_create_state);
474 : NTSTATUS status;
475 :
476 16269 : if (tevent_req_is_nterror(req, &status)) {
477 2020 : if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK) &&
478 : (psymlink != NULL)) {
479 0 : *psymlink = talloc_move(mem_ctx, &state->symlink);
480 : }
481 2020 : tevent_req_received(req);
482 2020 : return status;
483 : }
484 14249 : *fid_persistent = state->fid_persistent;
485 14249 : *fid_volatile = state->fid_volatile;
486 14249 : if (cr) {
487 9676 : *cr = state->cr;
488 : }
489 14249 : if (blobs) {
490 9676 : blobs->num_blobs = state->blobs.num_blobs;
491 9676 : blobs->blobs = talloc_move(mem_ctx, &state->blobs.blobs);
492 : }
493 14249 : tevent_req_received(req);
494 14249 : return NT_STATUS_OK;
495 : }
496 :
497 6 : NTSTATUS smb2cli_create(struct smbXcli_conn *conn,
498 : uint32_t timeout_msec,
499 : struct smbXcli_session *session,
500 : struct smbXcli_tcon *tcon,
501 : const char *filename,
502 : uint8_t oplock_level, /* SMB2_OPLOCK_LEVEL_* */
503 : uint32_t impersonation_level, /* SMB2_IMPERSONATION_* */
504 : uint32_t desired_access,
505 : uint32_t file_attributes,
506 : uint32_t share_access,
507 : uint32_t create_disposition,
508 : uint32_t create_options,
509 : struct smb2_create_blobs *blobs,
510 : uint64_t *fid_persistent,
511 : uint64_t *fid_volatile,
512 : struct smb_create_returns *cr,
513 : TALLOC_CTX *mem_ctx,
514 : struct smb2_create_blobs *ret_blobs,
515 : struct symlink_reparse_struct **psymlink)
516 : {
517 6 : TALLOC_CTX *frame = talloc_stackframe();
518 : struct tevent_context *ev;
519 : struct tevent_req *req;
520 6 : NTSTATUS status = NT_STATUS_NO_MEMORY;
521 :
522 6 : if (smbXcli_conn_has_async_calls(conn)) {
523 : /*
524 : * Can't use sync call while an async call is in flight
525 : */
526 0 : status = NT_STATUS_INVALID_PARAMETER;
527 0 : goto fail;
528 : }
529 6 : ev = samba_tevent_context_init(frame);
530 6 : if (ev == NULL) {
531 0 : goto fail;
532 : }
533 6 : req = smb2cli_create_send(frame, ev, conn, timeout_msec,
534 : session, tcon,
535 : filename, oplock_level,
536 : impersonation_level, desired_access,
537 : file_attributes, share_access,
538 : create_disposition, create_options,
539 : blobs);
540 6 : if (req == NULL) {
541 0 : goto fail;
542 : }
543 6 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
544 0 : goto fail;
545 : }
546 6 : status = smb2cli_create_recv(
547 : req,
548 : fid_persistent,
549 : fid_volatile,
550 : cr,
551 : mem_ctx,
552 : ret_blobs,
553 : psymlink);
554 6 : fail:
555 6 : TALLOC_FREE(frame);
556 6 : return status;
557 : }
|