1 /*
2 Unix SMB/CIFS implementation.
3 smb2 lib
4 Copyright (C) Jeremy Allison 2013
5 Copyright (C) Volker Lendecke 2013
6 Copyright (C) Stefan Metzmacher 2013
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 /*
23 This code is a thin wrapper around the existing
24 cli_smb2_XXXX() functions in libcli/smb/smb2cli_XXXXX.c,
25 but allows the handles to be mapped to uint16_t fnums,
26 which are easier for smbclient to use.
27 */
28
29 #include "includes.h"
30 #include "client.h"
31 #include "async_smb.h"
32 #include "../libcli/smb/smbXcli_base.h"
33 #include "cli_smb2_fnum.h"
34 #include "trans2.h"
35 #include "clirap.h"
36 #include "../libcli/smb/smb2_create_blob.h"
37 #include "libsmb/proto.h"
38 #include "lib/util/tevent_ntstatus.h"
39 #include "../libcli/security/security.h"
40 #include "../librpc/gen_ndr/ndr_security.h"
41 #include "lib/util_ea.h"
42 #include "librpc/gen_ndr/ndr_ioctl.h"
43 #include "ntioctl.h"
44 #include "librpc/gen_ndr/ndr_quota.h"
45
46 struct smb2_hnd {
47 uint64_t fid_persistent;
48 uint64_t fid_volatile;
49 };
50
51 /*
52 * Handle mapping code.
53 */
54
55 /***************************************************************
56 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
57 Ensures handle is owned by cli struct.
58 ***************************************************************/
59
map_smb2_handle_to_fnum(struct cli_state * cli,const struct smb2_hnd * ph,uint16_t * pfnum)60 static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli,
61 const struct smb2_hnd *ph, /* In */
62 uint16_t *pfnum) /* Out */
63 {
64 int ret;
65 struct idr_context *idp = cli->smb2.open_handles;
66 struct smb2_hnd *owned_h = talloc_memdup(cli,
67 ph,
68 sizeof(struct smb2_hnd));
69
70 if (owned_h == NULL) {
71 return NT_STATUS_NO_MEMORY;
72 }
73
74 if (idp == NULL) {
75 /* Lazy init */
76 cli->smb2.open_handles = idr_init(cli);
77 if (cli->smb2.open_handles == NULL) {
78 TALLOC_FREE(owned_h);
79 return NT_STATUS_NO_MEMORY;
80 }
81 idp = cli->smb2.open_handles;
82 }
83
84 ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE);
85 if (ret == -1) {
86 TALLOC_FREE(owned_h);
87 return NT_STATUS_NO_MEMORY;
88 }
89
90 *pfnum = (uint16_t)ret;
91 return NT_STATUS_OK;
92 }
93
94 /***************************************************************
95 Return the smb2_hnd pointer associated with the given fnum.
96 ***************************************************************/
97
map_fnum_to_smb2_handle(struct cli_state * cli,uint16_t fnum,struct smb2_hnd ** pph)98 static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli,
99 uint16_t fnum, /* In */
100 struct smb2_hnd **pph) /* Out */
101 {
102 struct idr_context *idp = cli->smb2.open_handles;
103
104 if (idp == NULL) {
105 return NT_STATUS_INVALID_PARAMETER;
106 }
107 *pph = (struct smb2_hnd *)idr_find(idp, fnum);
108 if (*pph == NULL) {
109 return NT_STATUS_INVALID_HANDLE;
110 }
111 return NT_STATUS_OK;
112 }
113
114 /***************************************************************
115 Delete the fnum to smb2_hnd mapping. Zeros out handle on
116 successful return.
117 ***************************************************************/
118
delete_smb2_handle_mapping(struct cli_state * cli,struct smb2_hnd ** pph,uint16_t fnum)119 static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli,
120 struct smb2_hnd **pph, /* In */
121 uint16_t fnum) /* In */
122 {
123 struct idr_context *idp = cli->smb2.open_handles;
124 struct smb2_hnd *ph;
125
126 if (idp == NULL) {
127 return NT_STATUS_INVALID_PARAMETER;
128 }
129
130 ph = (struct smb2_hnd *)idr_find(idp, fnum);
131 if (ph != *pph) {
132 return NT_STATUS_INVALID_PARAMETER;
133 }
134 idr_remove(idp, fnum);
135 TALLOC_FREE(*pph);
136 return NT_STATUS_OK;
137 }
138
139 /***************************************************************
140 Oplock mapping code.
141 ***************************************************************/
142
flags_to_smb2_oplock(uint32_t create_flags)143 static uint8_t flags_to_smb2_oplock(uint32_t create_flags)
144 {
145 if (create_flags & REQUEST_BATCH_OPLOCK) {
146 return SMB2_OPLOCK_LEVEL_BATCH;
147 } else if (create_flags & REQUEST_OPLOCK) {
148 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
149 }
150
151 /* create_flags doesn't do a level2 request. */
152 return SMB2_OPLOCK_LEVEL_NONE;
153 }
154
155 /***************************************************************
156 Small wrapper that allows SMB2 create to return a uint16_t fnum.
157 ***************************************************************/
158
159 struct cli_smb2_create_fnum_state {
160 struct cli_state *cli;
161 struct smb2_create_blobs in_cblobs;
162 struct smb2_create_blobs out_cblobs;
163 struct smb_create_returns cr;
164 uint16_t fnum;
165 struct tevent_req *subreq;
166 };
167
168 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
169 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
170
cli_smb2_create_fnum_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,const char * fname,uint32_t create_flags,uint32_t impersonation_level,uint32_t desired_access,uint32_t file_attributes,uint32_t share_access,uint32_t create_disposition,uint32_t create_options,const struct smb2_create_blobs * in_cblobs)171 struct tevent_req *cli_smb2_create_fnum_send(
172 TALLOC_CTX *mem_ctx,
173 struct tevent_context *ev,
174 struct cli_state *cli,
175 const char *fname,
176 uint32_t create_flags,
177 uint32_t impersonation_level,
178 uint32_t desired_access,
179 uint32_t file_attributes,
180 uint32_t share_access,
181 uint32_t create_disposition,
182 uint32_t create_options,
183 const struct smb2_create_blobs *in_cblobs)
184 {
185 struct tevent_req *req, *subreq;
186 struct cli_smb2_create_fnum_state *state;
187 size_t fname_len = 0;
188 const char *startp = NULL;
189 const char *endp = NULL;
190 time_t tstamp = (time_t)0;
191 NTSTATUS status;
192
193 req = tevent_req_create(mem_ctx, &state,
194 struct cli_smb2_create_fnum_state);
195 if (req == NULL) {
196 return NULL;
197 }
198 state->cli = cli;
199
200 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
201 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
202 return tevent_req_post(req, ev);
203 }
204
205 if (cli->backup_intent) {
206 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
207 }
208
209 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
210 fname_len = strlen(fname);
211 if (clistr_is_previous_version_path(fname, &startp, &endp, &tstamp)) {
212 size_t len_before_gmt = startp - fname;
213 size_t len_after_gmt = fname + fname_len - endp;
214 DATA_BLOB twrp_blob;
215 NTTIME ntt;
216
217 char *new_fname = talloc_array(state, char,
218 len_before_gmt + len_after_gmt + 1);
219
220 if (tevent_req_nomem(new_fname, req)) {
221 return tevent_req_post(req, ev);
222 }
223
224 memcpy(new_fname, fname, len_before_gmt);
225 memcpy(new_fname + len_before_gmt, endp, len_after_gmt + 1);
226 fname = new_fname;
227 fname_len = len_before_gmt + len_after_gmt;
228
229 unix_to_nt_time(&ntt, tstamp);
230 twrp_blob = data_blob_const((const void *)&ntt, 8);
231
232 status = smb2_create_blob_add(
233 state,
234 &state->in_cblobs,
235 SMB2_CREATE_TAG_TWRP,
236 twrp_blob);
237 if (!NT_STATUS_IS_OK(status)) {
238 tevent_req_nterror(req, status);
239 return tevent_req_post(req, ev);
240 }
241 }
242
243 if (in_cblobs != NULL) {
244 uint32_t i;
245 for (i=0; i<in_cblobs->num_blobs; i++) {
246 struct smb2_create_blob *b = &in_cblobs->blobs[i];
247 status = smb2_create_blob_add(
248 state, &state->in_cblobs, b->tag, b->data);
249 if (!NT_STATUS_IS_OK(status)) {
250 tevent_req_nterror(req, status);
251 return tevent_req_post(req, ev);
252 }
253 }
254 }
255
256 /* SMB2 is pickier about pathnames. Ensure it doesn't
257 start in a '\' */
258 if (*fname == '\\') {
259 fname++;
260 fname_len--;
261 }
262
263 /* Or end in a '\' */
264 if (fname_len > 0 && fname[fname_len-1] == '\\') {
265 char *new_fname = talloc_strdup(state, fname);
266 if (tevent_req_nomem(new_fname, req)) {
267 return tevent_req_post(req, ev);
268 }
269 new_fname[fname_len-1] = '\0';
270 fname = new_fname;
271 }
272
273 subreq = smb2cli_create_send(state, ev,
274 cli->conn,
275 cli->timeout,
276 cli->smb2.session,
277 cli->smb2.tcon,
278 fname,
279 flags_to_smb2_oplock(create_flags),
280 impersonation_level,
281 desired_access,
282 file_attributes,
283 share_access,
284 create_disposition,
285 create_options,
286 &state->in_cblobs);
287 if (tevent_req_nomem(subreq, req)) {
288 return tevent_req_post(req, ev);
289 }
290 tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
291
292 state->subreq = subreq;
293 tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
294
295 return req;
296 }
297
cli_smb2_create_fnum_done(struct tevent_req * subreq)298 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
299 {
300 struct tevent_req *req = tevent_req_callback_data(
301 subreq, struct tevent_req);
302 struct cli_smb2_create_fnum_state *state = tevent_req_data(
303 req, struct cli_smb2_create_fnum_state);
304 struct smb2_hnd h;
305 NTSTATUS status;
306
307 status = smb2cli_create_recv(
308 subreq,
309 &h.fid_persistent,
310 &h.fid_volatile, &state->cr,
311 state,
312 &state->out_cblobs);
313 TALLOC_FREE(subreq);
314 if (tevent_req_nterror(req, status)) {
315 return;
316 }
317
318 status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
319 if (tevent_req_nterror(req, status)) {
320 return;
321 }
322 tevent_req_done(req);
323 }
324
cli_smb2_create_fnum_cancel(struct tevent_req * req)325 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
326 {
327 struct cli_smb2_create_fnum_state *state = tevent_req_data(
328 req, struct cli_smb2_create_fnum_state);
329 return tevent_req_cancel(state->subreq);
330 }
331
cli_smb2_create_fnum_recv(struct tevent_req * req,uint16_t * pfnum,struct smb_create_returns * cr,TALLOC_CTX * mem_ctx,struct smb2_create_blobs * out_cblobs)332 NTSTATUS cli_smb2_create_fnum_recv(
333 struct tevent_req *req,
334 uint16_t *pfnum,
335 struct smb_create_returns *cr,
336 TALLOC_CTX *mem_ctx,
337 struct smb2_create_blobs *out_cblobs)
338 {
339 struct cli_smb2_create_fnum_state *state = tevent_req_data(
340 req, struct cli_smb2_create_fnum_state);
341 NTSTATUS status;
342
343 if (tevent_req_is_nterror(req, &status)) {
344 state->cli->raw_status = status;
345 return status;
346 }
347 if (pfnum != NULL) {
348 *pfnum = state->fnum;
349 }
350 if (cr != NULL) {
351 *cr = state->cr;
352 }
353 if (out_cblobs != NULL) {
354 *out_cblobs = (struct smb2_create_blobs) {
355 .num_blobs = state->out_cblobs.num_blobs,
356 .blobs = talloc_move(
357 mem_ctx, &state->out_cblobs.blobs),
358 };
359 }
360 state->cli->raw_status = NT_STATUS_OK;
361 return NT_STATUS_OK;
362 }
363
cli_smb2_create_fnum(struct cli_state * cli,const char * fname,uint32_t create_flags,uint32_t impersonation_level,uint32_t desired_access,uint32_t file_attributes,uint32_t share_access,uint32_t create_disposition,uint32_t create_options,const struct smb2_create_blobs * in_cblobs,uint16_t * pfid,struct smb_create_returns * cr,TALLOC_CTX * mem_ctx,struct smb2_create_blobs * out_cblobs)364 NTSTATUS cli_smb2_create_fnum(
365 struct cli_state *cli,
366 const char *fname,
367 uint32_t create_flags,
368 uint32_t impersonation_level,
369 uint32_t desired_access,
370 uint32_t file_attributes,
371 uint32_t share_access,
372 uint32_t create_disposition,
373 uint32_t create_options,
374 const struct smb2_create_blobs *in_cblobs,
375 uint16_t *pfid,
376 struct smb_create_returns *cr,
377 TALLOC_CTX *mem_ctx,
378 struct smb2_create_blobs *out_cblobs)
379 {
380 TALLOC_CTX *frame = talloc_stackframe();
381 struct tevent_context *ev;
382 struct tevent_req *req;
383 NTSTATUS status = NT_STATUS_NO_MEMORY;
384
385 if (smbXcli_conn_has_async_calls(cli->conn)) {
386 /*
387 * Can't use sync call while an async call is in flight
388 */
389 status = NT_STATUS_INVALID_PARAMETER;
390 goto fail;
391 }
392 ev = samba_tevent_context_init(frame);
393 if (ev == NULL) {
394 goto fail;
395 }
396 req = cli_smb2_create_fnum_send(
397 frame,
398 ev,
399 cli,
400 fname,
401 create_flags,
402 impersonation_level,
403 desired_access,
404 file_attributes,
405 share_access,
406 create_disposition,
407 create_options,
408 in_cblobs);
409 if (req == NULL) {
410 goto fail;
411 }
412 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
413 goto fail;
414 }
415 status = cli_smb2_create_fnum_recv(req, pfid, cr, mem_ctx, out_cblobs);
416 fail:
417 TALLOC_FREE(frame);
418 return status;
419 }
420
421 /***************************************************************
422 Small wrapper that allows SMB2 close to use a uint16_t fnum.
423 ***************************************************************/
424
425 struct cli_smb2_close_fnum_state {
426 struct cli_state *cli;
427 uint16_t fnum;
428 struct smb2_hnd *ph;
429 };
430
431 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
432
cli_smb2_close_fnum_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,uint16_t fnum)433 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
434 struct tevent_context *ev,
435 struct cli_state *cli,
436 uint16_t fnum)
437 {
438 struct tevent_req *req, *subreq;
439 struct cli_smb2_close_fnum_state *state;
440 NTSTATUS status;
441
442 req = tevent_req_create(mem_ctx, &state,
443 struct cli_smb2_close_fnum_state);
444 if (req == NULL) {
445 return NULL;
446 }
447 state->cli = cli;
448 state->fnum = fnum;
449
450 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
451 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
452 return tevent_req_post(req, ev);
453 }
454
455 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
456 if (tevent_req_nterror(req, status)) {
457 return tevent_req_post(req, ev);
458 }
459
460 subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
461 cli->smb2.session, cli->smb2.tcon,
462 0, state->ph->fid_persistent,
463 state->ph->fid_volatile);
464 if (tevent_req_nomem(subreq, req)) {
465 return tevent_req_post(req, ev);
466 }
467 tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
468 return req;
469 }
470
cli_smb2_close_fnum_done(struct tevent_req * subreq)471 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
472 {
473 struct tevent_req *req = tevent_req_callback_data(
474 subreq, struct tevent_req);
475 struct cli_smb2_close_fnum_state *state = tevent_req_data(
476 req, struct cli_smb2_close_fnum_state);
477 NTSTATUS status;
478
479 status = smb2cli_close_recv(subreq);
480 if (tevent_req_nterror(req, status)) {
481 return;
482 }
483
484 /* Delete the fnum -> handle mapping. */
485 status = delete_smb2_handle_mapping(state->cli, &state->ph,
486 state->fnum);
487 if (tevent_req_nterror(req, status)) {
488 return;
489 }
490 tevent_req_done(req);
491 }
492
cli_smb2_close_fnum_recv(struct tevent_req * req)493 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
494 {
495 struct cli_smb2_close_fnum_state *state = tevent_req_data(
496 req, struct cli_smb2_close_fnum_state);
497 NTSTATUS status = NT_STATUS_OK;
498
499 if (tevent_req_is_nterror(req, &status)) {
500 state->cli->raw_status = status;
501 }
502 tevent_req_received(req);
503 return status;
504 }
505
cli_smb2_close_fnum(struct cli_state * cli,uint16_t fnum)506 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
507 {
508 TALLOC_CTX *frame = talloc_stackframe();
509 struct tevent_context *ev;
510 struct tevent_req *req;
511 NTSTATUS status = NT_STATUS_NO_MEMORY;
512
513 if (smbXcli_conn_has_async_calls(cli->conn)) {
514 /*
515 * Can't use sync call while an async call is in flight
516 */
517 status = NT_STATUS_INVALID_PARAMETER;
518 goto fail;
519 }
520 ev = samba_tevent_context_init(frame);
521 if (ev == NULL) {
522 goto fail;
523 }
524 req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
525 if (req == NULL) {
526 goto fail;
527 }
528 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
529 goto fail;
530 }
531 status = cli_smb2_close_fnum_recv(req);
532 fail:
533 TALLOC_FREE(frame);
534 return status;
535 }
536
537 struct cli_smb2_set_info_fnum_state {
538 uint8_t dummy;
539 };
540
541 static void cli_smb2_set_info_fnum_done(struct tevent_req *subreq);
542
cli_smb2_set_info_fnum_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,uint16_t fnum,uint8_t in_info_type,uint8_t in_info_class,const DATA_BLOB * in_input_buffer,uint32_t in_additional_info)543 struct tevent_req *cli_smb2_set_info_fnum_send(
544 TALLOC_CTX *mem_ctx,
545 struct tevent_context *ev,
546 struct cli_state *cli,
547 uint16_t fnum,
548 uint8_t in_info_type,
549 uint8_t in_info_class,
550 const DATA_BLOB *in_input_buffer,
551 uint32_t in_additional_info)
552 {
553 struct tevent_req *req = NULL, *subreq = NULL;
554 struct cli_smb2_set_info_fnum_state *state = NULL;
555 struct smb2_hnd *ph = NULL;
556 NTSTATUS status;
557
558 req = tevent_req_create(
559 mem_ctx, &state, struct cli_smb2_set_info_fnum_state);
560 if (req == NULL) {
561 return NULL;
562 }
563
564 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
565 if (tevent_req_nterror(req, status)) {
566 return tevent_req_post(req, ev);
567 }
568
569 subreq = smb2cli_set_info_send(
570 state,
571 ev,
572 cli->conn,
573 cli->timeout,
574 cli->smb2.session,
575 cli->smb2.tcon,
576 in_info_type,
577 in_info_class,
578 in_input_buffer,
579 in_additional_info,
580 ph->fid_persistent,
581 ph->fid_volatile);
582 if (tevent_req_nomem(subreq, req)) {
583 return tevent_req_post(req, ev);
584 }
585 tevent_req_set_callback(subreq, cli_smb2_set_info_fnum_done, req);
586 return req;
587 }
588
cli_smb2_set_info_fnum_done(struct tevent_req * subreq)589 static void cli_smb2_set_info_fnum_done(struct tevent_req *subreq)
590 {
591 NTSTATUS status = smb2cli_set_info_recv(subreq);
592 tevent_req_simple_finish_ntstatus(subreq, status);
593 }
594
cli_smb2_set_info_fnum_recv(struct tevent_req * req)595 NTSTATUS cli_smb2_set_info_fnum_recv(struct tevent_req *req)
596 {
597 return tevent_req_simple_recv_ntstatus(req);
598 }
599
cli_smb2_set_info_fnum(struct cli_state * cli,uint16_t fnum,uint8_t in_info_type,uint8_t in_info_class,const DATA_BLOB * in_input_buffer,uint32_t in_additional_info)600 NTSTATUS cli_smb2_set_info_fnum(
601 struct cli_state *cli,
602 uint16_t fnum,
603 uint8_t in_info_type,
604 uint8_t in_info_class,
605 const DATA_BLOB *in_input_buffer,
606 uint32_t in_additional_info)
607 {
608 TALLOC_CTX *frame = talloc_stackframe();
609 struct tevent_context *ev = NULL;
610 struct tevent_req *req = NULL;
611 NTSTATUS status = NT_STATUS_NO_MEMORY;
612 bool ok;
613
614 if (smbXcli_conn_has_async_calls(cli->conn)) {
615 /*
616 * Can't use sync call while an async call is in flight
617 */
618 status = NT_STATUS_INVALID_PARAMETER;
619 goto fail;
620 }
621 ev = samba_tevent_context_init(frame);
622 if (ev == NULL) {
623 goto fail;
624 }
625 req = cli_smb2_set_info_fnum_send(
626 frame,
627 ev,
628 cli,
629 fnum,
630 in_info_type,
631 in_info_class,
632 in_input_buffer,
633 in_additional_info);
634 if (req == NULL) {
635 goto fail;
636 }
637 ok = tevent_req_poll_ntstatus(req, ev, &status);
638 if (!ok) {
639 goto fail;
640 }
641 status = cli_smb2_set_info_fnum_recv(req);
642 fail:
643 TALLOC_FREE(frame);
644 return status;
645 }
646
647 struct cli_smb2_delete_on_close_state {
648 struct cli_state *cli;
649 uint8_t data[1];
650 DATA_BLOB inbuf;
651 };
652
653 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
654
cli_smb2_delete_on_close_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,uint16_t fnum,bool flag)655 struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
656 struct tevent_context *ev,
657 struct cli_state *cli,
658 uint16_t fnum,
659 bool flag)
660 {
661 struct tevent_req *req = NULL;
662 struct cli_smb2_delete_on_close_state *state = NULL;
663 struct tevent_req *subreq = NULL;
664 uint8_t in_info_type;
665 uint8_t in_file_info_class;
666
667 req = tevent_req_create(mem_ctx, &state,
668 struct cli_smb2_delete_on_close_state);
669 if (req == NULL) {
670 return NULL;
671 }
672 state->cli = cli;
673
674 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
675 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
676 return tevent_req_post(req, ev);
677 }
678
679 /*
680 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
681 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
682 */
683 in_info_type = 1;
684 in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000;
685 /* Setup data array. */
686 SCVAL(&state->data[0], 0, flag ? 1 : 0);
687 state->inbuf.data = &state->data[0];
688 state->inbuf.length = 1;
689
690 subreq = cli_smb2_set_info_fnum_send(
691 state,
692 ev,
693 cli,
694 fnum,
695 in_info_type,
696 in_file_info_class,
697 &state->inbuf,
698 0);
699 if (tevent_req_nomem(subreq, req)) {
700 return tevent_req_post(req, ev);
701 }
702 tevent_req_set_callback(subreq,
703 cli_smb2_delete_on_close_done,
704 req);
705 return req;
706 }
707
cli_smb2_delete_on_close_done(struct tevent_req * subreq)708 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
709 {
710 NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
711 tevent_req_simple_finish_ntstatus(subreq, status);
712 }
713
cli_smb2_delete_on_close_recv(struct tevent_req * req)714 NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
715 {
716 struct cli_smb2_delete_on_close_state *state =
717 tevent_req_data(req,
718 struct cli_smb2_delete_on_close_state);
719 NTSTATUS status;
720
721 if (tevent_req_is_nterror(req, &status)) {
722 state->cli->raw_status = status;
723 tevent_req_received(req);
724 return status;
725 }
726
727 state->cli->raw_status = NT_STATUS_OK;
728 tevent_req_received(req);
729 return NT_STATUS_OK;
730 }
731
cli_smb2_delete_on_close(struct cli_state * cli,uint16_t fnum,bool flag)732 NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
733 {
734 TALLOC_CTX *frame = talloc_stackframe();
735 struct tevent_context *ev;
736 struct tevent_req *req;
737 NTSTATUS status = NT_STATUS_NO_MEMORY;
738
739 if (smbXcli_conn_has_async_calls(cli->conn)) {
740 /*
741 * Can't use sync call while an async call is in flight
742 */
743 status = NT_STATUS_INVALID_PARAMETER;
744 goto fail;
745 }
746 ev = samba_tevent_context_init(frame);
747 if (ev == NULL) {
748 goto fail;
749 }
750 req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
751 if (req == NULL) {
752 goto fail;
753 }
754 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
755 goto fail;
756 }
757 status = cli_smb2_delete_on_close_recv(req);
758 fail:
759 TALLOC_FREE(frame);
760 return status;
761 }
762
763 /***************************************************************
764 Small wrapper that allows SMB2 to create a directory
765 Synchronous only.
766 ***************************************************************/
767
cli_smb2_mkdir(struct cli_state * cli,const char * dname)768 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
769 {
770 NTSTATUS status;
771 uint16_t fnum;
772
773 if (smbXcli_conn_has_async_calls(cli->conn)) {
774 /*
775 * Can't use sync call while an async call is in flight
776 */
777 return NT_STATUS_INVALID_PARAMETER;
778 }
779
780 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
781 return NT_STATUS_INVALID_PARAMETER;
782 }
783
784 status = cli_smb2_create_fnum(cli,
785 dname,
786 0, /* create_flags */
787 SMB2_IMPERSONATION_IMPERSONATION,
788 FILE_READ_ATTRIBUTES, /* desired_access */
789 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
790 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
791 FILE_CREATE, /* create_disposition */
792 FILE_DIRECTORY_FILE, /* create_options */
793 NULL,
794 &fnum,
795 NULL,
796 NULL,
797 NULL);
798
799 if (!NT_STATUS_IS_OK(status)) {
800 return status;
801 }
802 return cli_smb2_close_fnum(cli, fnum);
803 }
804
805 struct cli_smb2_rmdir_state {
806 struct tevent_context *ev;
807 struct cli_state *cli;
808 const char *dname;
809 const struct smb2_create_blobs *in_cblobs;
810 uint16_t fnum;
811 NTSTATUS status;
812 };
813
814 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq);
815 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq);
816 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq);
817 static void cli_smb2_rmdir_closed(struct tevent_req *subreq);
818
cli_smb2_rmdir_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,const char * dname,const struct smb2_create_blobs * in_cblobs)819 struct tevent_req *cli_smb2_rmdir_send(
820 TALLOC_CTX *mem_ctx,
821 struct tevent_context *ev,
822 struct cli_state *cli,
823 const char *dname,
824 const struct smb2_create_blobs *in_cblobs)
825 {
826 struct tevent_req *req = NULL, *subreq = NULL;
827 struct cli_smb2_rmdir_state *state = NULL;
828
829 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_rmdir_state);
830 if (req == NULL) {
831 return NULL;
832 }
833 state->ev = ev;
834 state->cli = cli;
835 state->dname = dname;
836 state->in_cblobs = in_cblobs;
837
838 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
839 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
840 return tevent_req_post(req, ev);
841 }
842
843 subreq = cli_smb2_create_fnum_send(
844 state,
845 state->ev,
846 state->cli,
847 state->dname,
848 0, /* create_flags */
849 SMB2_IMPERSONATION_IMPERSONATION,
850 DELETE_ACCESS, /* desired_access */
851 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
852 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
853 FILE_OPEN, /* create_disposition */
854 FILE_DIRECTORY_FILE, /* create_options */
855 state->in_cblobs); /* in_cblobs */
856 if (tevent_req_nomem(subreq, req)) {
857 return tevent_req_post(req, ev);
858 }
859 tevent_req_set_callback(subreq, cli_smb2_rmdir_opened1, req);
860 return req;
861 }
862
cli_smb2_rmdir_opened1(struct tevent_req * subreq)863 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq)
864 {
865 struct tevent_req *req = tevent_req_callback_data(
866 subreq, struct tevent_req);
867 struct cli_smb2_rmdir_state *state = tevent_req_data(
868 req, struct cli_smb2_rmdir_state);
869 NTSTATUS status;
870
871 status = cli_smb2_create_fnum_recv(
872 subreq, &state->fnum, NULL, NULL, NULL);
873 TALLOC_FREE(subreq);
874
875 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
876 /*
877 * Naive option to match our SMB1 code. Assume the
878 * symlink path that tripped us up was the last
879 * component and try again. Eventually we will have to
880 * deal with the returned path unprocessed component. JRA.
881 */
882 subreq = cli_smb2_create_fnum_send(
883 state,
884 state->ev,
885 state->cli,
886 state->dname,
887 0, /* create_flags */
888 SMB2_IMPERSONATION_IMPERSONATION,
889 DELETE_ACCESS, /* desired_access */
890 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
891 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
892 FILE_OPEN, /* create_disposition */
893 FILE_DIRECTORY_FILE|
894 FILE_DELETE_ON_CLOSE|
895 FILE_OPEN_REPARSE_POINT, /* create_options */
896 state->in_cblobs); /* in_cblobs */
897 if (tevent_req_nomem(subreq, req)) {
898 return;
899 }
900 tevent_req_set_callback(subreq, cli_smb2_rmdir_opened2, req);
901 return;
902 }
903
904 if (tevent_req_nterror(req, status)) {
905 return;
906 }
907
908 subreq = cli_smb2_delete_on_close_send(
909 state, state->ev, state->cli, state->fnum, true);
910 if (tevent_req_nomem(subreq, req)) {
911 return;
912 }
913 tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
914 }
915
cli_smb2_rmdir_opened2(struct tevent_req * subreq)916 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq)
917 {
918 struct tevent_req *req = tevent_req_callback_data(
919 subreq, struct tevent_req);
920 struct cli_smb2_rmdir_state *state = tevent_req_data(
921 req, struct cli_smb2_rmdir_state);
922 NTSTATUS status;
923
924 status = cli_smb2_create_fnum_recv(
925 subreq, &state->fnum, NULL, NULL, NULL);
926 TALLOC_FREE(subreq);
927 if (tevent_req_nterror(req, status)) {
928 return;
929 }
930
931 subreq = cli_smb2_delete_on_close_send(
932 state, state->ev, state->cli, state->fnum, true);
933 if (tevent_req_nomem(subreq, req)) {
934 return;
935 }
936 tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
937 }
938
cli_smb2_rmdir_disp_set(struct tevent_req * subreq)939 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq)
940 {
941 struct tevent_req *req = tevent_req_callback_data(
942 subreq, struct tevent_req);
943 struct cli_smb2_rmdir_state *state = tevent_req_data(
944 req, struct cli_smb2_rmdir_state);
945
946 state->status = cli_smb2_delete_on_close_recv(subreq);
947 TALLOC_FREE(subreq);
948
949 /*
950 * Close the fd even if the set_disp failed
951 */
952
953 subreq = cli_smb2_close_fnum_send(
954 state, state->ev, state->cli, state->fnum);
955 if (tevent_req_nomem(subreq, req)) {
956 return;
957 }
958 tevent_req_set_callback(subreq, cli_smb2_rmdir_closed, req);
959 }
960
cli_smb2_rmdir_closed(struct tevent_req * subreq)961 static void cli_smb2_rmdir_closed(struct tevent_req *subreq)
962 {
963 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
964 tevent_req_simple_finish_ntstatus(subreq, status);
965 }
966
cli_smb2_rmdir_recv(struct tevent_req * req)967 NTSTATUS cli_smb2_rmdir_recv(struct tevent_req *req)
968 {
969 struct cli_smb2_rmdir_state *state = tevent_req_data(
970 req, struct cli_smb2_rmdir_state);
971 NTSTATUS status;
972
973 if (tevent_req_is_nterror(req, &status)) {
974 return status;
975 }
976 return state->status;
977 }
978
cli_smb2_rmdir(struct cli_state * cli,const char * dname,const struct smb2_create_blobs * in_cblobs)979 NTSTATUS cli_smb2_rmdir(
980 struct cli_state *cli,
981 const char *dname,
982 const struct smb2_create_blobs *in_cblobs)
983 {
984 TALLOC_CTX *frame = talloc_stackframe();
985 struct tevent_context *ev;
986 struct tevent_req *req;
987 NTSTATUS status = NT_STATUS_NO_MEMORY;
988 bool ok;
989
990 if (smbXcli_conn_has_async_calls(cli->conn)) {
991 /*
992 * Can't use sync call while an async call is in flight
993 */
994 status = NT_STATUS_INVALID_PARAMETER;
995 goto fail;
996 }
997 ev = samba_tevent_context_init(frame);
998 if (ev == NULL) {
999 goto fail;
1000 }
1001 req = cli_smb2_rmdir_send(frame, ev, cli, dname, in_cblobs);
1002 if (req == NULL) {
1003 goto fail;
1004 }
1005 ok = tevent_req_poll_ntstatus(req, ev, &status);
1006 if (!ok) {
1007 goto fail;
1008 }
1009 status = cli_smb2_rmdir_recv(req);
1010 fail:
1011 cli->raw_status = status;
1012 TALLOC_FREE(frame);
1013 return status;
1014 }
1015
1016 /***************************************************************
1017 Small wrapper that allows SMB2 to unlink a pathname.
1018 Synchronous only.
1019 ***************************************************************/
1020
1021 struct cli_smb2_unlink_state {
1022 struct tevent_context *ev;
1023 struct cli_state *cli;
1024 const char *fname;
1025 const struct smb2_create_blobs *in_cblobs;
1026 };
1027
1028 static void cli_smb2_unlink_opened1(struct tevent_req *subreq);
1029 static void cli_smb2_unlink_opened2(struct tevent_req *subreq);
1030 static void cli_smb2_unlink_closed(struct tevent_req *subreq);
1031
cli_smb2_unlink_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,const char * fname,const struct smb2_create_blobs * in_cblobs)1032 struct tevent_req *cli_smb2_unlink_send(
1033 TALLOC_CTX *mem_ctx,
1034 struct tevent_context *ev,
1035 struct cli_state *cli,
1036 const char *fname,
1037 const struct smb2_create_blobs *in_cblobs)
1038 {
1039 struct tevent_req *req = NULL, *subreq = NULL;
1040 struct cli_smb2_unlink_state *state = NULL;
1041
1042 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_unlink_state);
1043 if (req == NULL) {
1044 return NULL;
1045 }
1046 state->ev = ev;
1047 state->cli = cli;
1048 state->fname = fname;
1049 state->in_cblobs = in_cblobs;
1050
1051 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1052 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1053 return tevent_req_post(req, ev);
1054 }
1055
1056 subreq = cli_smb2_create_fnum_send(
1057 state, /* mem_ctx */
1058 state->ev, /* tevent_context */
1059 state->cli, /* cli_struct */
1060 state->fname, /* filename */
1061 0, /* create_flags */
1062 SMB2_IMPERSONATION_IMPERSONATION,
1063 DELETE_ACCESS, /* desired_access */
1064 FILE_ATTRIBUTE_NORMAL, /* file attributes */
1065 FILE_SHARE_READ|
1066 FILE_SHARE_WRITE|
1067 FILE_SHARE_DELETE, /* share_access */
1068 FILE_OPEN, /* create_disposition */
1069 FILE_DELETE_ON_CLOSE, /* create_options */
1070 state->in_cblobs); /* in_cblobs */
1071 if (tevent_req_nomem(subreq, req)) {
1072 return tevent_req_post(req, ev);
1073 }
1074 tevent_req_set_callback(subreq, cli_smb2_unlink_opened1, req);
1075 return req;
1076 }
1077
cli_smb2_unlink_opened1(struct tevent_req * subreq)1078 static void cli_smb2_unlink_opened1(struct tevent_req *subreq)
1079 {
1080 struct tevent_req *req = tevent_req_callback_data(
1081 subreq, struct tevent_req);
1082 struct cli_smb2_unlink_state *state = tevent_req_data(
1083 req, struct cli_smb2_unlink_state);
1084 uint16_t fnum;
1085 NTSTATUS status;
1086
1087 status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
1088 TALLOC_FREE(subreq);
1089
1090 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1091 /*
1092 * Naive option to match our SMB1 code. Assume the
1093 * symlink path that tripped us up was the last
1094 * component and try again. Eventually we will have to
1095 * deal with the returned path unprocessed component. JRA.
1096 */
1097 subreq = cli_smb2_create_fnum_send(
1098 state, /* mem_ctx */
1099 state->ev, /* tevent_context */
1100 state->cli, /* cli_struct */
1101 state->fname, /* filename */
1102 0, /* create_flags */
1103 SMB2_IMPERSONATION_IMPERSONATION,
1104 DELETE_ACCESS, /* desired_access */
1105 FILE_ATTRIBUTE_NORMAL, /* file attributes */
1106 FILE_SHARE_READ|
1107 FILE_SHARE_WRITE|
1108 FILE_SHARE_DELETE, /* share_access */
1109 FILE_OPEN, /* create_disposition */
1110 FILE_DELETE_ON_CLOSE|
1111 FILE_OPEN_REPARSE_POINT, /* create_options */
1112 state->in_cblobs); /* in_cblobs */
1113 if (tevent_req_nomem(subreq, req)) {
1114 return;
1115 }
1116 tevent_req_set_callback(subreq, cli_smb2_unlink_opened2, req);
1117 return;
1118 }
1119
1120 if (tevent_req_nterror(req, status)) {
1121 return;
1122 }
1123
1124 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1125 if (tevent_req_nomem(subreq, req)) {
1126 return;
1127 }
1128 tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1129 }
1130
cli_smb2_unlink_opened2(struct tevent_req * subreq)1131 static void cli_smb2_unlink_opened2(struct tevent_req *subreq)
1132 {
1133 struct tevent_req *req = tevent_req_callback_data(
1134 subreq, struct tevent_req);
1135 struct cli_smb2_unlink_state *state = tevent_req_data(
1136 req, struct cli_smb2_unlink_state);
1137 uint16_t fnum;
1138 NTSTATUS status;
1139
1140 status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
1141 TALLOC_FREE(subreq);
1142 if (tevent_req_nterror(req, status)) {
1143 return;
1144 }
1145
1146 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1147 if (tevent_req_nomem(subreq, req)) {
1148 return;
1149 }
1150 tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1151 }
1152
cli_smb2_unlink_closed(struct tevent_req * subreq)1153 static void cli_smb2_unlink_closed(struct tevent_req *subreq)
1154 {
1155 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1156 tevent_req_simple_finish_ntstatus(subreq, status);
1157 }
1158
cli_smb2_unlink_recv(struct tevent_req * req)1159 NTSTATUS cli_smb2_unlink_recv(struct tevent_req *req)
1160 {
1161 return tevent_req_simple_recv_ntstatus(req);
1162 }
1163
cli_smb2_unlink(struct cli_state * cli,const char * fname,const struct smb2_create_blobs * in_cblobs)1164 NTSTATUS cli_smb2_unlink(
1165 struct cli_state *cli,
1166 const char *fname,
1167 const struct smb2_create_blobs *in_cblobs)
1168 {
1169 TALLOC_CTX *frame = talloc_stackframe();
1170 struct tevent_context *ev;
1171 struct tevent_req *req;
1172 NTSTATUS status = NT_STATUS_NO_MEMORY;
1173 bool ok;
1174
1175 if (smbXcli_conn_has_async_calls(cli->conn)) {
1176 /*
1177 * Can't use sync call while an async call is in flight
1178 */
1179 status = NT_STATUS_INVALID_PARAMETER;
1180 goto fail;
1181 }
1182 ev = samba_tevent_context_init(frame);
1183 if (ev == NULL) {
1184 goto fail;
1185 }
1186 req = cli_smb2_unlink_send(frame, ev, cli, fname, in_cblobs);
1187 if (req == NULL) {
1188 goto fail;
1189 }
1190 ok = tevent_req_poll_ntstatus(req, ev, &status);
1191 if (!ok) {
1192 goto fail;
1193 }
1194 status = cli_smb2_unlink_recv(req);
1195 fail:
1196 cli->raw_status = status;
1197 TALLOC_FREE(frame);
1198 return status;
1199 }
1200
1201 /***************************************************************
1202 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
1203 ***************************************************************/
1204
parse_finfo_id_both_directory_info(uint8_t * dir_data,uint32_t dir_data_length,struct file_info * finfo,uint32_t * next_offset)1205 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
1206 uint32_t dir_data_length,
1207 struct file_info *finfo,
1208 uint32_t *next_offset)
1209 {
1210 size_t namelen = 0;
1211 size_t slen = 0;
1212 size_t ret = 0;
1213
1214 if (dir_data_length < 4) {
1215 return NT_STATUS_INFO_LENGTH_MISMATCH;
1216 }
1217
1218 *next_offset = IVAL(dir_data, 0);
1219
1220 if (*next_offset > dir_data_length) {
1221 return NT_STATUS_INFO_LENGTH_MISMATCH;
1222 }
1223
1224 if (*next_offset != 0) {
1225 /* Ensure we only read what in this record. */
1226 dir_data_length = *next_offset;
1227 }
1228
1229 if (dir_data_length < 105) {
1230 return NT_STATUS_INFO_LENGTH_MISMATCH;
1231 }
1232
1233 finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
1234 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
1235 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
1236 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
1237 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
1238 finfo->allocated_size = IVAL2_TO_SMB_BIG_UINT(dir_data + 48, 0);
1239 /* NB. We need to enlarge finfo->mode to be 32-bits. */
1240 finfo->mode = (uint16_t)IVAL(dir_data + 56, 0);
1241 finfo->ino = IVAL2_TO_SMB_BIG_UINT(dir_data + 96, 0);
1242 namelen = IVAL(dir_data + 60,0);
1243 if (namelen > (dir_data_length - 104)) {
1244 return NT_STATUS_INFO_LENGTH_MISMATCH;
1245 }
1246 slen = CVAL(dir_data + 68, 0);
1247 if (slen > 24) {
1248 return NT_STATUS_INFO_LENGTH_MISMATCH;
1249 }
1250 ret = pull_string_talloc(finfo,
1251 dir_data,
1252 FLAGS2_UNICODE_STRINGS,
1253 &finfo->short_name,
1254 dir_data + 70,
1255 slen,
1256 STR_UNICODE);
1257 if (ret == (size_t)-1) {
1258 /* Bad conversion. */
1259 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1260 }
1261
1262 ret = pull_string_talloc(finfo,
1263 dir_data,
1264 FLAGS2_UNICODE_STRINGS,
1265 &finfo->name,
1266 dir_data + 104,
1267 namelen,
1268 STR_UNICODE);
1269 if (ret == (size_t)-1) {
1270 /* Bad conversion. */
1271 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1272 }
1273
1274 if (finfo->name == NULL) {
1275 /* Bad conversion. */
1276 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1277 }
1278
1279 return NT_STATUS_OK;
1280 }
1281
1282 /*******************************************************************
1283 Given a filename - get its directory name
1284 ********************************************************************/
1285
windows_parent_dirname(TALLOC_CTX * mem_ctx,const char * dir,char ** parent,const char ** name)1286 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
1287 const char *dir,
1288 char **parent,
1289 const char **name)
1290 {
1291 char *p;
1292 ptrdiff_t len;
1293
1294 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
1295
1296 if (p == NULL) {
1297 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
1298 return false;
1299 }
1300 if (name) {
1301 *name = dir;
1302 }
1303 return true;
1304 }
1305
1306 len = p-dir;
1307
1308 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
1309 return false;
1310 }
1311 (*parent)[len] = '\0';
1312
1313 if (name) {
1314 *name = p+1;
1315 }
1316 return true;
1317 }
1318
1319 /***************************************************************
1320 Wrapper that allows SMB2 to list a directory.
1321 Synchronous only.
1322 ***************************************************************/
1323
cli_smb2_list(struct cli_state * cli,const char * pathname,uint16_t attribute,NTSTATUS (* fn)(const char *,struct file_info *,const char *,void *),void * state)1324 NTSTATUS cli_smb2_list(struct cli_state *cli,
1325 const char *pathname,
1326 uint16_t attribute,
1327 NTSTATUS (*fn)(const char *,
1328 struct file_info *,
1329 const char *,
1330 void *),
1331 void *state)
1332 {
1333 NTSTATUS status;
1334 uint16_t fnum = 0xffff;
1335 char *parent_dir = NULL;
1336 const char *mask = NULL;
1337 struct smb2_hnd *ph = NULL;
1338 bool processed_file = false;
1339 TALLOC_CTX *frame = talloc_stackframe();
1340 TALLOC_CTX *subframe = NULL;
1341 bool mask_has_wild;
1342 uint32_t max_trans;
1343 uint32_t max_avail_len;
1344 bool ok;
1345
1346 if (smbXcli_conn_has_async_calls(cli->conn)) {
1347 /*
1348 * Can't use sync call while an async call is in flight
1349 */
1350 status = NT_STATUS_INVALID_PARAMETER;
1351 goto fail;
1352 }
1353
1354 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1355 status = NT_STATUS_INVALID_PARAMETER;
1356 goto fail;
1357 }
1358
1359 /* Get the directory name. */
1360 if (!windows_parent_dirname(frame,
1361 pathname,
1362 &parent_dir,
1363 &mask)) {
1364 status = NT_STATUS_NO_MEMORY;
1365 goto fail;
1366 }
1367
1368 mask_has_wild = ms_has_wild(mask);
1369
1370 status = cli_smb2_create_fnum(cli,
1371 parent_dir,
1372 0, /* create_flags */
1373 SMB2_IMPERSONATION_IMPERSONATION,
1374 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
1375 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1376 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
1377 FILE_OPEN, /* create_disposition */
1378 FILE_DIRECTORY_FILE, /* create_options */
1379 NULL,
1380 &fnum,
1381 NULL,
1382 NULL,
1383 NULL);
1384
1385 if (!NT_STATUS_IS_OK(status)) {
1386 goto fail;
1387 }
1388
1389 status = map_fnum_to_smb2_handle(cli,
1390 fnum,
1391 &ph);
1392 if (!NT_STATUS_IS_OK(status)) {
1393 goto fail;
1394 }
1395
1396 /*
1397 * ideally, use the max transaction size, but don't send a request
1398 * bigger than we have credits available for
1399 */
1400 max_trans = smb2cli_conn_max_trans_size(cli->conn);
1401 ok = smb2cli_conn_req_possible(cli->conn, &max_avail_len);
1402 if (ok) {
1403 max_trans = MIN(max_trans, max_avail_len);
1404 }
1405
1406 do {
1407 uint8_t *dir_data = NULL;
1408 uint32_t dir_data_length = 0;
1409 uint32_t next_offset = 0;
1410 subframe = talloc_stackframe();
1411
1412 status = smb2cli_query_directory(cli->conn,
1413 cli->timeout,
1414 cli->smb2.session,
1415 cli->smb2.tcon,
1416 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
1417 0, /* flags */
1418 0, /* file_index */
1419 ph->fid_persistent,
1420 ph->fid_volatile,
1421 mask,
1422 max_trans,
1423 subframe,
1424 &dir_data,
1425 &dir_data_length);
1426
1427 if (!NT_STATUS_IS_OK(status)) {
1428 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1429 break;
1430 }
1431 goto fail;
1432 }
1433
1434 do {
1435 struct file_info *finfo = talloc_zero(subframe,
1436 struct file_info);
1437
1438 if (finfo == NULL) {
1439 status = NT_STATUS_NO_MEMORY;
1440 goto fail;
1441 }
1442
1443 status = parse_finfo_id_both_directory_info(dir_data,
1444 dir_data_length,
1445 finfo,
1446 &next_offset);
1447
1448 if (!NT_STATUS_IS_OK(status)) {
1449 goto fail;
1450 }
1451
1452 /* Protect against server attack. */
1453 status = is_bad_finfo_name(cli, finfo);
1454 if (!NT_STATUS_IS_OK(status)) {
1455 smbXcli_conn_disconnect(cli->conn, status);
1456 goto fail;
1457 }
1458
1459 if (dir_check_ftype((uint32_t)finfo->mode,
1460 (uint32_t)attribute)) {
1461 /*
1462 * Only process if attributes match.
1463 * On SMB1 server does this, so on
1464 * SMB2 we need to emulate in the
1465 * client.
1466 *
1467 * https://bugzilla.samba.org/show_bug.cgi?id=10260
1468 */
1469 processed_file = true;
1470
1471 status = fn(cli->dfs_mountpoint,
1472 finfo,
1473 pathname,
1474 state);
1475
1476 if (!NT_STATUS_IS_OK(status)) {
1477 break;
1478 }
1479 }
1480
1481 TALLOC_FREE(finfo);
1482
1483 /* Move to next entry. */
1484 if (next_offset) {
1485 dir_data += next_offset;
1486 dir_data_length -= next_offset;
1487 }
1488 } while (next_offset != 0);
1489
1490 TALLOC_FREE(subframe);
1491
1492 if (!mask_has_wild) {
1493 /*
1494 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
1495 * when handed a non-wildcard path. Do it
1496 * for the server (with a non-wildcard path
1497 * there should only ever be one file returned.
1498 */
1499 status = STATUS_NO_MORE_FILES;
1500 break;
1501 }
1502
1503 } while (NT_STATUS_IS_OK(status));
1504
1505 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1506 status = NT_STATUS_OK;
1507 }
1508
1509 if (NT_STATUS_IS_OK(status) && !processed_file) {
1510 /*
1511 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1512 * if no files match. Emulate this in the client.
1513 */
1514 status = NT_STATUS_NO_SUCH_FILE;
1515 }
1516
1517 fail:
1518
1519 if (fnum != 0xffff) {
1520 cli_smb2_close_fnum(cli, fnum);
1521 }
1522
1523 cli->raw_status = status;
1524
1525 TALLOC_FREE(subframe);
1526 TALLOC_FREE(frame);
1527 return status;
1528 }
1529
1530 /***************************************************************
1531 Wrapper that allows SMB2 to query a path info (basic level).
1532 Synchronous only.
1533 ***************************************************************/
1534
cli_smb2_qpathinfo_basic(struct cli_state * cli,const char * name,SMB_STRUCT_STAT * sbuf,uint32_t * attributes)1535 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1536 const char *name,
1537 SMB_STRUCT_STAT *sbuf,
1538 uint32_t *attributes)
1539 {
1540 NTSTATUS status;
1541 struct smb_create_returns cr;
1542 uint16_t fnum = 0xffff;
1543 size_t namelen = strlen(name);
1544
1545 if (smbXcli_conn_has_async_calls(cli->conn)) {
1546 /*
1547 * Can't use sync call while an async call is in flight
1548 */
1549 return NT_STATUS_INVALID_PARAMETER;
1550 }
1551
1552 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1553 return NT_STATUS_INVALID_PARAMETER;
1554 }
1555
1556 /* SMB2 is pickier about pathnames. Ensure it doesn't
1557 end in a '\' */
1558 if (namelen > 0 && name[namelen-1] == '\\') {
1559 char *modname = talloc_strdup(talloc_tos(), name);
1560 modname[namelen-1] = '\0';
1561 name = modname;
1562 }
1563
1564 /* This is commonly used as a 'cd'. Try qpathinfo on
1565 a directory handle first. */
1566
1567 status = cli_smb2_create_fnum(cli,
1568 name,
1569 0, /* create_flags */
1570 SMB2_IMPERSONATION_IMPERSONATION,
1571 FILE_READ_ATTRIBUTES, /* desired_access */
1572 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1573 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1574 FILE_OPEN, /* create_disposition */
1575 FILE_DIRECTORY_FILE, /* create_options */
1576 NULL,
1577 &fnum,
1578 &cr,
1579 NULL,
1580 NULL);
1581
1582 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1583 /* Maybe a file ? */
1584 status = cli_smb2_create_fnum(cli,
1585 name,
1586 0, /* create_flags */
1587 SMB2_IMPERSONATION_IMPERSONATION,
1588 FILE_READ_ATTRIBUTES, /* desired_access */
1589 0, /* file attributes */
1590 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1591 FILE_OPEN, /* create_disposition */
1592 0, /* create_options */
1593 NULL,
1594 &fnum,
1595 &cr,
1596 NULL,
1597 NULL);
1598 }
1599
1600 if (!NT_STATUS_IS_OK(status)) {
1601 return status;
1602 }
1603
1604 status = cli_smb2_close_fnum(cli, fnum);
1605
1606 ZERO_STRUCTP(sbuf);
1607
1608 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1609 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1610 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1611 sbuf->st_ex_size = cr.end_of_file;
1612 *attributes = cr.file_attributes;
1613
1614 return status;
1615 }
1616
1617 /***************************************************************
1618 Wrapper that allows SMB2 to check if a path is a directory.
1619 Synchronous only.
1620 ***************************************************************/
1621
cli_smb2_chkpath(struct cli_state * cli,const char * name)1622 NTSTATUS cli_smb2_chkpath(struct cli_state *cli,
1623 const char *name)
1624 {
1625 NTSTATUS status;
1626 uint16_t fnum = 0xffff;
1627
1628 if (smbXcli_conn_has_async_calls(cli->conn)) {
1629 /*
1630 * Can't use sync call while an async call is in flight
1631 */
1632 return NT_STATUS_INVALID_PARAMETER;
1633 }
1634
1635 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1636 return NT_STATUS_INVALID_PARAMETER;
1637 }
1638
1639 /* Ensure this is a directory. */
1640 status = cli_smb2_create_fnum(cli,
1641 name,
1642 0, /* create_flags */
1643 SMB2_IMPERSONATION_IMPERSONATION,
1644 FILE_READ_ATTRIBUTES, /* desired_access */
1645 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1646 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1647 FILE_OPEN, /* create_disposition */
1648 FILE_DIRECTORY_FILE, /* create_options */
1649 NULL,
1650 &fnum,
1651 NULL,
1652 NULL,
1653 NULL);
1654
1655 if (!NT_STATUS_IS_OK(status)) {
1656 return status;
1657 }
1658
1659 return cli_smb2_close_fnum(cli, fnum);
1660 }
1661
1662 struct cli_smb2_query_info_fnum_state {
1663 DATA_BLOB outbuf;
1664 };
1665
1666 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq);
1667
cli_smb2_query_info_fnum_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,uint16_t fnum,uint8_t in_info_type,uint8_t in_info_class,uint32_t in_max_output_length,const DATA_BLOB * in_input_buffer,uint32_t in_additional_info,uint32_t in_flags)1668 struct tevent_req *cli_smb2_query_info_fnum_send(
1669 TALLOC_CTX *mem_ctx,
1670 struct tevent_context *ev,
1671 struct cli_state *cli,
1672 uint16_t fnum,
1673 uint8_t in_info_type,
1674 uint8_t in_info_class,
1675 uint32_t in_max_output_length,
1676 const DATA_BLOB *in_input_buffer,
1677 uint32_t in_additional_info,
1678 uint32_t in_flags)
1679 {
1680 struct tevent_req *req = NULL, *subreq = NULL;
1681 struct cli_smb2_query_info_fnum_state *state = NULL;
1682 struct smb2_hnd *ph = NULL;
1683 NTSTATUS status;
1684
1685 req = tevent_req_create(
1686 mem_ctx, &state, struct cli_smb2_query_info_fnum_state);
1687 if (req == NULL) {
1688 return req;
1689 }
1690
1691 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
1692 if (tevent_req_nterror(req, status)) {
1693 return tevent_req_post(req, ev);
1694 }
1695
1696 subreq = smb2cli_query_info_send(
1697 state,
1698 ev,
1699 cli->conn,
1700 cli->timeout,
1701 cli->smb2.session,
1702 cli->smb2.tcon,
1703 in_info_type,
1704 in_info_class,
1705 in_max_output_length,
1706 in_input_buffer,
1707 in_additional_info,
1708 in_flags,
1709 ph->fid_persistent,
1710 ph->fid_volatile);
1711 if (tevent_req_nomem(subreq, req)) {
1712 return tevent_req_post(req, ev);
1713 }
1714 tevent_req_set_callback(subreq, cli_smb2_query_info_fnum_done, req);
1715 return req;
1716 }
1717
cli_smb2_query_info_fnum_done(struct tevent_req * subreq)1718 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq)
1719 {
1720 struct tevent_req *req = tevent_req_callback_data(
1721 subreq, struct tevent_req);
1722 struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1723 req, struct cli_smb2_query_info_fnum_state);
1724 DATA_BLOB outbuf;
1725 NTSTATUS status;
1726
1727 status = smb2cli_query_info_recv(subreq, state, &outbuf);
1728 TALLOC_FREE(subreq);
1729 if (tevent_req_nterror(req, status)) {
1730 return;
1731 }
1732
1733 /*
1734 * We have to dup the memory here because outbuf.data is not
1735 * returned as a talloc object by smb2cli_query_info_recv.
1736 * It's a pointer into the received buffer.
1737 */
1738 state->outbuf = data_blob_dup_talloc(state, outbuf);
1739
1740 if ((outbuf.length != 0) &&
1741 tevent_req_nomem(state->outbuf.data, req)) {
1742 return;
1743 }
1744 tevent_req_done(req);
1745 }
1746
cli_smb2_query_info_fnum_recv(struct tevent_req * req,TALLOC_CTX * mem_ctx,DATA_BLOB * outbuf)1747 NTSTATUS cli_smb2_query_info_fnum_recv(
1748 struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *outbuf)
1749 {
1750 struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1751 req, struct cli_smb2_query_info_fnum_state);
1752 NTSTATUS status;
1753
1754 if (tevent_req_is_nterror(req, &status)) {
1755 return status;
1756 }
1757 *outbuf = (DATA_BLOB) {
1758 .data = talloc_move(mem_ctx, &state->outbuf.data),
1759 .length = state->outbuf.length,
1760 };
1761 return NT_STATUS_OK;
1762 }
1763
cli_smb2_query_info_fnum(struct cli_state * cli,uint16_t fnum,uint8_t in_info_type,uint8_t in_info_class,uint32_t in_max_output_length,const DATA_BLOB * in_input_buffer,uint32_t in_additional_info,uint32_t in_flags,TALLOC_CTX * mem_ctx,DATA_BLOB * outbuf)1764 NTSTATUS cli_smb2_query_info_fnum(
1765 struct cli_state *cli,
1766 uint16_t fnum,
1767 uint8_t in_info_type,
1768 uint8_t in_info_class,
1769 uint32_t in_max_output_length,
1770 const DATA_BLOB *in_input_buffer,
1771 uint32_t in_additional_info,
1772 uint32_t in_flags,
1773 TALLOC_CTX *mem_ctx,
1774 DATA_BLOB *outbuf)
1775 {
1776 TALLOC_CTX *frame = talloc_stackframe();
1777 struct tevent_context *ev = NULL;
1778 struct tevent_req *req = NULL;
1779 NTSTATUS status = NT_STATUS_NO_MEMORY;
1780 bool ok;
1781
1782 if (smbXcli_conn_has_async_calls(cli->conn)) {
1783 /*
1784 * Can't use sync call while an async call is in flight
1785 */
1786 status = NT_STATUS_INVALID_PARAMETER;
1787 goto fail;
1788 }
1789 ev = samba_tevent_context_init(frame);
1790 if (ev == NULL) {
1791 goto fail;
1792 }
1793 req = cli_smb2_query_info_fnum_send(
1794 frame,
1795 ev,
1796 cli,
1797 fnum,
1798 in_info_type,
1799 in_info_class,
1800 in_max_output_length,
1801 in_input_buffer,
1802 in_additional_info,
1803 in_flags);
1804 if (req == NULL) {
1805 goto fail;
1806 }
1807 ok = tevent_req_poll_ntstatus(req, ev, &status);
1808 if (!ok) {
1809 goto fail;
1810 }
1811 status = cli_smb2_query_info_fnum_recv(req, mem_ctx, outbuf);
1812 fail:
1813 TALLOC_FREE(frame);
1814 return status;
1815 }
1816
1817 /***************************************************************
1818 Helper function for pathname operations.
1819 ***************************************************************/
1820
get_fnum_from_path(struct cli_state * cli,const char * name,uint32_t desired_access,uint16_t * pfnum)1821 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1822 const char *name,
1823 uint32_t desired_access,
1824 uint16_t *pfnum)
1825 {
1826 NTSTATUS status;
1827 size_t namelen = strlen(name);
1828 TALLOC_CTX *frame = talloc_stackframe();
1829 uint32_t create_options = 0;
1830
1831 /* SMB2 is pickier about pathnames. Ensure it doesn't
1832 end in a '\' */
1833 if (namelen > 0 && name[namelen-1] == '\\') {
1834 char *modname = talloc_strdup(frame, name);
1835 if (modname == NULL) {
1836 status = NT_STATUS_NO_MEMORY;
1837 goto fail;
1838 }
1839 modname[namelen-1] = '\0';
1840 name = modname;
1841 }
1842
1843 /* Try to open a file handle first. */
1844 status = cli_smb2_create_fnum(cli,
1845 name,
1846 0, /* create_flags */
1847 SMB2_IMPERSONATION_IMPERSONATION,
1848 desired_access,
1849 0, /* file attributes */
1850 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1851 FILE_OPEN, /* create_disposition */
1852 create_options,
1853 NULL,
1854 pfnum,
1855 NULL,
1856 NULL,
1857 NULL);
1858
1859 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1860 /*
1861 * Naive option to match our SMB1 code. Assume the
1862 * symlink path that tripped us up was the last
1863 * component and try again. Eventually we will have to
1864 * deal with the returned path unprocessed component. JRA.
1865 */
1866 create_options |= FILE_OPEN_REPARSE_POINT;
1867 status = cli_smb2_create_fnum(cli,
1868 name,
1869 0, /* create_flags */
1870 SMB2_IMPERSONATION_IMPERSONATION,
1871 desired_access,
1872 0, /* file attributes */
1873 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1874 FILE_OPEN, /* create_disposition */
1875 create_options,
1876 NULL,
1877 pfnum,
1878 NULL,
1879 NULL,
1880 NULL);
1881 }
1882
1883 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1884 create_options |= FILE_DIRECTORY_FILE;
1885 status = cli_smb2_create_fnum(cli,
1886 name,
1887 0, /* create_flags */
1888 SMB2_IMPERSONATION_IMPERSONATION,
1889 desired_access,
1890 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1891 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1892 FILE_OPEN, /* create_disposition */
1893 create_options, /* create_options */
1894 NULL,
1895 pfnum,
1896 NULL,
1897 NULL,
1898 NULL);
1899 }
1900
1901 fail:
1902
1903 TALLOC_FREE(frame);
1904 return status;
1905 }
1906
1907 /***************************************************************
1908 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1909 Synchronous only.
1910 ***************************************************************/
1911
cli_smb2_qpathinfo_alt_name(struct cli_state * cli,const char * name,fstring alt_name)1912 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1913 const char *name,
1914 fstring alt_name)
1915 {
1916 NTSTATUS status;
1917 DATA_BLOB outbuf = data_blob_null;
1918 uint16_t fnum = 0xffff;
1919 uint32_t altnamelen = 0;
1920 TALLOC_CTX *frame = talloc_stackframe();
1921
1922 if (smbXcli_conn_has_async_calls(cli->conn)) {
1923 /*
1924 * Can't use sync call while an async call is in flight
1925 */
1926 status = NT_STATUS_INVALID_PARAMETER;
1927 goto fail;
1928 }
1929
1930 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1931 status = NT_STATUS_INVALID_PARAMETER;
1932 goto fail;
1933 }
1934
1935 status = get_fnum_from_path(cli,
1936 name,
1937 FILE_READ_ATTRIBUTES,
1938 &fnum);
1939
1940 if (!NT_STATUS_IS_OK(status)) {
1941 goto fail;
1942 }
1943
1944 status = cli_smb2_query_info_fnum(
1945 cli,
1946 fnum,
1947 1, /* in_info_type */
1948 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1949 0xFFFF, /* in_max_output_length */
1950 NULL, /* in_input_buffer */
1951 0, /* in_additional_info */
1952 0, /* in_flags */
1953 frame,
1954 &outbuf);
1955
1956 if (!NT_STATUS_IS_OK(status)) {
1957 goto fail;
1958 }
1959
1960 /* Parse the reply. */
1961 if (outbuf.length < 4) {
1962 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1963 goto fail;
1964 }
1965
1966 altnamelen = IVAL(outbuf.data, 0);
1967 if (altnamelen > outbuf.length - 4) {
1968 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1969 goto fail;
1970 }
1971
1972 if (altnamelen > 0) {
1973 size_t ret = 0;
1974 char *short_name = NULL;
1975 ret = pull_string_talloc(frame,
1976 outbuf.data,
1977 FLAGS2_UNICODE_STRINGS,
1978 &short_name,
1979 outbuf.data + 4,
1980 altnamelen,
1981 STR_UNICODE);
1982 if (ret == (size_t)-1) {
1983 /* Bad conversion. */
1984 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1985 goto fail;
1986 }
1987
1988 fstrcpy(alt_name, short_name);
1989 } else {
1990 alt_name[0] = '\0';
1991 }
1992
1993 status = NT_STATUS_OK;
1994
1995 fail:
1996
1997 if (fnum != 0xffff) {
1998 cli_smb2_close_fnum(cli, fnum);
1999 }
2000
2001 cli->raw_status = status;
2002
2003 TALLOC_FREE(frame);
2004 return status;
2005 }
2006
2007
2008 /***************************************************************
2009 Wrapper that allows SMB2 to query a fnum info (basic level).
2010 Synchronous only.
2011 ***************************************************************/
2012
cli_smb2_qfileinfo_basic(struct cli_state * cli,uint16_t fnum,uint16_t * mode,off_t * size,struct timespec * create_time,struct timespec * access_time,struct timespec * write_time,struct timespec * change_time,SMB_INO_T * ino)2013 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
2014 uint16_t fnum,
2015 uint16_t *mode,
2016 off_t *size,
2017 struct timespec *create_time,
2018 struct timespec *access_time,
2019 struct timespec *write_time,
2020 struct timespec *change_time,
2021 SMB_INO_T *ino)
2022 {
2023 NTSTATUS status;
2024 DATA_BLOB outbuf = data_blob_null;
2025 TALLOC_CTX *frame = talloc_stackframe();
2026
2027 if (smbXcli_conn_has_async_calls(cli->conn)) {
2028 /*
2029 * Can't use sync call while an async call is in flight
2030 */
2031 status = NT_STATUS_INVALID_PARAMETER;
2032 goto fail;
2033 }
2034
2035 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2036 status = NT_STATUS_INVALID_PARAMETER;
2037 goto fail;
2038 }
2039
2040 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2041 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
2042
2043 status = cli_smb2_query_info_fnum(
2044 cli,
2045 fnum,
2046 1, /* in_info_type */
2047 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
2048 0xFFFF, /* in_max_output_length */
2049 NULL, /* in_input_buffer */
2050 0, /* in_additional_info */
2051 0, /* in_flags */
2052 frame,
2053 &outbuf);
2054 if (!NT_STATUS_IS_OK(status)) {
2055 goto fail;
2056 }
2057
2058 /* Parse the reply. */
2059 if (outbuf.length < 0x60) {
2060 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2061 goto fail;
2062 }
2063
2064 if (create_time) {
2065 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
2066 }
2067 if (access_time) {
2068 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
2069 }
2070 if (write_time) {
2071 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
2072 }
2073 if (change_time) {
2074 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
2075 }
2076 if (mode) {
2077 uint32_t attr = IVAL(outbuf.data, 0x20);
2078 *mode = (uint16_t)attr;
2079 }
2080 if (size) {
2081 uint64_t file_size = BVAL(outbuf.data, 0x30);
2082 *size = (off_t)file_size;
2083 }
2084 if (ino) {
2085 uint64_t file_index = BVAL(outbuf.data, 0x40);
2086 *ino = (SMB_INO_T)file_index;
2087 }
2088
2089 fail:
2090
2091 cli->raw_status = status;
2092
2093 TALLOC_FREE(frame);
2094 return status;
2095 }
2096
2097 /***************************************************************
2098 Wrapper that allows SMB2 to query an fnum.
2099 Implement on top of cli_smb2_qfileinfo_basic().
2100 Synchronous only.
2101 ***************************************************************/
2102
cli_smb2_getattrE(struct cli_state * cli,uint16_t fnum,uint16_t * attr,off_t * size,time_t * change_time,time_t * access_time,time_t * write_time)2103 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
2104 uint16_t fnum,
2105 uint16_t *attr,
2106 off_t *size,
2107 time_t *change_time,
2108 time_t *access_time,
2109 time_t *write_time)
2110 {
2111 struct timespec access_time_ts;
2112 struct timespec write_time_ts;
2113 struct timespec change_time_ts;
2114 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
2115 fnum,
2116 attr,
2117 size,
2118 NULL,
2119 &access_time_ts,
2120 &write_time_ts,
2121 &change_time_ts,
2122 NULL);
2123
2124 cli->raw_status = status;
2125
2126 if (!NT_STATUS_IS_OK(status)) {
2127 return status;
2128 }
2129
2130 if (change_time) {
2131 *change_time = change_time_ts.tv_sec;
2132 }
2133 if (access_time) {
2134 *access_time = access_time_ts.tv_sec;
2135 }
2136 if (write_time) {
2137 *write_time = write_time_ts.tv_sec;
2138 }
2139 return NT_STATUS_OK;
2140 }
2141
2142 /***************************************************************
2143 Wrapper that allows SMB2 to get pathname attributes.
2144 Synchronous only.
2145 ***************************************************************/
2146
cli_smb2_getatr(struct cli_state * cli,const char * name,uint16_t * attr,off_t * size,time_t * write_time)2147 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
2148 const char *name,
2149 uint16_t *attr,
2150 off_t *size,
2151 time_t *write_time)
2152 {
2153 NTSTATUS status;
2154 uint16_t fnum = 0xffff;
2155 struct smb2_hnd *ph = NULL;
2156 TALLOC_CTX *frame = talloc_stackframe();
2157
2158 if (smbXcli_conn_has_async_calls(cli->conn)) {
2159 /*
2160 * Can't use sync call while an async call is in flight
2161 */
2162 status = NT_STATUS_INVALID_PARAMETER;
2163 goto fail;
2164 }
2165
2166 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2167 status = NT_STATUS_INVALID_PARAMETER;
2168 goto fail;
2169 }
2170
2171 status = get_fnum_from_path(cli,
2172 name,
2173 FILE_READ_ATTRIBUTES,
2174 &fnum);
2175
2176 if (!NT_STATUS_IS_OK(status)) {
2177 goto fail;
2178 }
2179
2180 status = map_fnum_to_smb2_handle(cli,
2181 fnum,
2182 &ph);
2183 if (!NT_STATUS_IS_OK(status)) {
2184 goto fail;
2185 }
2186 status = cli_smb2_getattrE(cli,
2187 fnum,
2188 attr,
2189 size,
2190 NULL,
2191 NULL,
2192 write_time);
2193 if (!NT_STATUS_IS_OK(status)) {
2194 goto fail;
2195 }
2196
2197 fail:
2198
2199 if (fnum != 0xffff) {
2200 cli_smb2_close_fnum(cli, fnum);
2201 }
2202
2203 cli->raw_status = status;
2204
2205 TALLOC_FREE(frame);
2206 return status;
2207 }
2208
2209 /***************************************************************
2210 Wrapper that allows SMB2 to query a pathname info (basic level).
2211 Implement on top of cli_smb2_qfileinfo_basic().
2212 Synchronous only.
2213 ***************************************************************/
2214
cli_smb2_qpathinfo2(struct cli_state * cli,const char * name,struct timespec * create_time,struct timespec * access_time,struct timespec * write_time,struct timespec * change_time,off_t * size,uint16_t * mode,SMB_INO_T * ino)2215 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
2216 const char *name,
2217 struct timespec *create_time,
2218 struct timespec *access_time,
2219 struct timespec *write_time,
2220 struct timespec *change_time,
2221 off_t *size,
2222 uint16_t *mode,
2223 SMB_INO_T *ino)
2224 {
2225 NTSTATUS status;
2226 struct smb2_hnd *ph = NULL;
2227 uint16_t fnum = 0xffff;
2228 TALLOC_CTX *frame = talloc_stackframe();
2229
2230 if (smbXcli_conn_has_async_calls(cli->conn)) {
2231 /*
2232 * Can't use sync call while an async call is in flight
2233 */
2234 status = NT_STATUS_INVALID_PARAMETER;
2235 goto fail;
2236 }
2237
2238 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2239 status = NT_STATUS_INVALID_PARAMETER;
2240 goto fail;
2241 }
2242
2243 status = get_fnum_from_path(cli,
2244 name,
2245 FILE_READ_ATTRIBUTES,
2246 &fnum);
2247
2248 if (!NT_STATUS_IS_OK(status)) {
2249 goto fail;
2250 }
2251
2252 status = map_fnum_to_smb2_handle(cli,
2253 fnum,
2254 &ph);
2255 if (!NT_STATUS_IS_OK(status)) {
2256 goto fail;
2257 }
2258
2259 status = cli_smb2_qfileinfo_basic(cli,
2260 fnum,
2261 mode,
2262 size,
2263 create_time,
2264 access_time,
2265 write_time,
2266 change_time,
2267 ino);
2268
2269 fail:
2270
2271 if (fnum != 0xffff) {
2272 cli_smb2_close_fnum(cli, fnum);
2273 }
2274
2275 cli->raw_status = status;
2276
2277 TALLOC_FREE(frame);
2278 return status;
2279 }
2280
2281 /***************************************************************
2282 Wrapper that allows SMB2 to query pathname streams.
2283 Synchronous only.
2284 ***************************************************************/
2285
cli_smb2_qpathinfo_streams(struct cli_state * cli,const char * name,TALLOC_CTX * mem_ctx,unsigned int * pnum_streams,struct stream_struct ** pstreams)2286 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
2287 const char *name,
2288 TALLOC_CTX *mem_ctx,
2289 unsigned int *pnum_streams,
2290 struct stream_struct **pstreams)
2291 {
2292 NTSTATUS status;
2293 uint16_t fnum = 0xffff;
2294 DATA_BLOB outbuf = data_blob_null;
2295 TALLOC_CTX *frame = talloc_stackframe();
2296
2297 if (smbXcli_conn_has_async_calls(cli->conn)) {
2298 /*
2299 * Can't use sync call while an async call is in flight
2300 */
2301 status = NT_STATUS_INVALID_PARAMETER;
2302 goto fail;
2303 }
2304
2305 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2306 status = NT_STATUS_INVALID_PARAMETER;
2307 goto fail;
2308 }
2309
2310 status = get_fnum_from_path(cli,
2311 name,
2312 FILE_READ_ATTRIBUTES,
2313 &fnum);
2314
2315 if (!NT_STATUS_IS_OK(status)) {
2316 goto fail;
2317 }
2318
2319 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2320 level 22 (SMB2_FILE_STREAM_INFORMATION). */
2321
2322 status = cli_smb2_query_info_fnum(
2323 cli,
2324 fnum,
2325 1, /* in_info_type */
2326 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
2327 0xFFFF, /* in_max_output_length */
2328 NULL, /* in_input_buffer */
2329 0, /* in_additional_info */
2330 0, /* in_flags */
2331 frame,
2332 &outbuf);
2333
2334 if (!NT_STATUS_IS_OK(status)) {
2335 goto fail;
2336 }
2337
2338 /* Parse the reply. */
2339 if (!parse_streams_blob(mem_ctx,
2340 outbuf.data,
2341 outbuf.length,
2342 pnum_streams,
2343 pstreams)) {
2344 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2345 goto fail;
2346 }
2347
2348 fail:
2349
2350 if (fnum != 0xffff) {
2351 cli_smb2_close_fnum(cli, fnum);
2352 }
2353
2354 cli->raw_status = status;
2355
2356 TALLOC_FREE(frame);
2357 return status;
2358 }
2359
2360 /***************************************************************
2361 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
2362 a pathname.
2363 Synchronous only.
2364 ***************************************************************/
2365
cli_smb2_setpathinfo(struct cli_state * cli,const char * name,uint8_t in_info_type,uint8_t in_file_info_class,const DATA_BLOB * p_in_data)2366 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
2367 const char *name,
2368 uint8_t in_info_type,
2369 uint8_t in_file_info_class,
2370 const DATA_BLOB *p_in_data)
2371 {
2372 NTSTATUS status;
2373 uint16_t fnum = 0xffff;
2374 TALLOC_CTX *frame = talloc_stackframe();
2375
2376 if (smbXcli_conn_has_async_calls(cli->conn)) {
2377 /*
2378 * Can't use sync call while an async call is in flight
2379 */
2380 status = NT_STATUS_INVALID_PARAMETER;
2381 goto fail;
2382 }
2383
2384 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2385 status = NT_STATUS_INVALID_PARAMETER;
2386 goto fail;
2387 }
2388
2389 status = get_fnum_from_path(cli,
2390 name,
2391 FILE_WRITE_ATTRIBUTES,
2392 &fnum);
2393
2394 if (!NT_STATUS_IS_OK(status)) {
2395 goto fail;
2396 }
2397
2398 status = cli_smb2_set_info_fnum(
2399 cli,
2400 fnum,
2401 in_info_type,
2402 in_file_info_class,
2403 p_in_data, /* in_input_buffer */
2404 0); /* in_additional_info */
2405 fail:
2406
2407 if (fnum != 0xffff) {
2408 cli_smb2_close_fnum(cli, fnum);
2409 }
2410
2411 cli->raw_status = status;
2412
2413 TALLOC_FREE(frame);
2414 return status;
2415 }
2416
2417
2418 /***************************************************************
2419 Wrapper that allows SMB2 to set pathname attributes.
2420 Synchronous only.
2421 ***************************************************************/
2422
cli_smb2_setatr(struct cli_state * cli,const char * name,uint16_t attr,time_t mtime)2423 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
2424 const char *name,
2425 uint16_t attr,
2426 time_t mtime)
2427 {
2428 uint8_t inbuf_store[40];
2429 DATA_BLOB inbuf = data_blob_null;
2430
2431 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2432 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2433
2434 inbuf.data = inbuf_store;
2435 inbuf.length = sizeof(inbuf_store);
2436 data_blob_clear(&inbuf);
2437
2438 /*
2439 * SMB1 uses attr == 0 to clear all attributes
2440 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
2441 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
2442 * request attribute change.
2443 *
2444 * SMB2 uses exactly the reverse. Unfortunately as the
2445 * cli_setatr() ABI is exposed inside libsmbclient,
2446 * we must make the SMB2 cli_smb2_setatr() call
2447 * export the same ABI as the SMB1 cli_setatr()
2448 * which calls it. This means reversing the sense
2449 * of the requested attr argument if it's zero
2450 * or FILE_ATTRIBUTE_NORMAL.
2451 *
2452 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
2453 */
2454
2455 if (attr == 0) {
2456 attr = FILE_ATTRIBUTE_NORMAL;
2457 } else if (attr == FILE_ATTRIBUTE_NORMAL) {
2458 attr = 0;
2459 }
2460
2461 SSVAL(inbuf.data, 32, attr);
2462 if (mtime != 0) {
2463 put_long_date((char *)inbuf.data + 16,mtime);
2464 }
2465 /* Set all the other times to -1. */
2466 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2467 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
2468 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
2469
2470 return cli_smb2_setpathinfo(cli,
2471 name,
2472 1, /* in_info_type */
2473 /* in_file_info_class */
2474 SMB_FILE_BASIC_INFORMATION - 1000,
2475 &inbuf);
2476 }
2477
2478
2479 /***************************************************************
2480 Wrapper that allows SMB2 to set file handle times.
2481 Synchronous only.
2482 ***************************************************************/
2483
cli_smb2_setattrE(struct cli_state * cli,uint16_t fnum,time_t change_time,time_t access_time,time_t write_time)2484 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
2485 uint16_t fnum,
2486 time_t change_time,
2487 time_t access_time,
2488 time_t write_time)
2489 {
2490 uint8_t inbuf_store[40];
2491 DATA_BLOB inbuf = data_blob_null;
2492
2493 if (smbXcli_conn_has_async_calls(cli->conn)) {
2494 /*
2495 * Can't use sync call while an async call is in flight
2496 */
2497 return NT_STATUS_INVALID_PARAMETER;
2498 }
2499
2500 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2501 return NT_STATUS_INVALID_PARAMETER;
2502 }
2503
2504 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2505 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2506
2507 inbuf.data = inbuf_store;
2508 inbuf.length = sizeof(inbuf_store);
2509 data_blob_clear(&inbuf);
2510
2511 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2512 if (change_time != 0) {
2513 put_long_date((char *)inbuf.data + 24, change_time);
2514 }
2515 if (access_time != 0) {
2516 put_long_date((char *)inbuf.data + 8, access_time);
2517 }
2518 if (write_time != 0) {
2519 put_long_date((char *)inbuf.data + 16, write_time);
2520 }
2521
2522 cli->raw_status = cli_smb2_set_info_fnum(
2523 cli,
2524 fnum,
2525 1, /* in_info_type */
2526 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
2527 &inbuf, /* in_input_buffer */
2528 0); /* in_additional_info */
2529
2530 return cli->raw_status;
2531 }
2532
2533 /***************************************************************
2534 Wrapper that allows SMB2 to query disk attributes (size).
2535 Synchronous only.
2536 ***************************************************************/
2537
cli_smb2_dskattr(struct cli_state * cli,const char * path,uint64_t * bsize,uint64_t * total,uint64_t * avail)2538 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
2539 uint64_t *bsize, uint64_t *total, uint64_t *avail)
2540 {
2541 NTSTATUS status;
2542 uint16_t fnum = 0xffff;
2543 DATA_BLOB outbuf = data_blob_null;
2544 uint32_t sectors_per_unit = 0;
2545 uint32_t bytes_per_sector = 0;
2546 uint64_t total_size = 0;
2547 uint64_t size_free = 0;
2548 TALLOC_CTX *frame = talloc_stackframe();
2549
2550 if (smbXcli_conn_has_async_calls(cli->conn)) {
2551 /*
2552 * Can't use sync call while an async call is in flight
2553 */
2554 status = NT_STATUS_INVALID_PARAMETER;
2555 goto fail;
2556 }
2557
2558 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2559 status = NT_STATUS_INVALID_PARAMETER;
2560 goto fail;
2561 }
2562
2563 /* First open the top level directory. */
2564 status = cli_smb2_create_fnum(cli,
2565 path,
2566 0, /* create_flags */
2567 SMB2_IMPERSONATION_IMPERSONATION,
2568 FILE_READ_ATTRIBUTES, /* desired_access */
2569 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2570 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
2571 FILE_OPEN, /* create_disposition */
2572 FILE_DIRECTORY_FILE, /* create_options */
2573 NULL,
2574 &fnum,
2575 NULL,
2576 NULL,
2577 NULL);
2578
2579 if (!NT_STATUS_IS_OK(status)) {
2580 goto fail;
2581 }
2582
2583 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2584 level 3 (SMB_FS_SIZE_INFORMATION). */
2585
2586 status = cli_smb2_query_info_fnum(
2587 cli,
2588 fnum,
2589 2, /* in_info_type */
2590 3, /* in_file_info_class */
2591 0xFFFF, /* in_max_output_length */
2592 NULL, /* in_input_buffer */
2593 0, /* in_additional_info */
2594 0, /* in_flags */
2595 frame,
2596 &outbuf);
2597 if (!NT_STATUS_IS_OK(status)) {
2598 goto fail;
2599 }
2600
2601 /* Parse the reply. */
2602 if (outbuf.length != 24) {
2603 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2604 goto fail;
2605 }
2606
2607 total_size = BVAL(outbuf.data, 0);
2608 size_free = BVAL(outbuf.data, 8);
2609 sectors_per_unit = IVAL(outbuf.data, 16);
2610 bytes_per_sector = IVAL(outbuf.data, 20);
2611
2612 if (bsize) {
2613 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2614 }
2615 if (total) {
2616 *total = total_size;
2617 }
2618 if (avail) {
2619 *avail = size_free;
2620 }
2621
2622 status = NT_STATUS_OK;
2623
2624 fail:
2625
2626 if (fnum != 0xffff) {
2627 cli_smb2_close_fnum(cli, fnum);
2628 }
2629
2630 cli->raw_status = status;
2631
2632 TALLOC_FREE(frame);
2633 return status;
2634 }
2635
2636 /***************************************************************
2637 Wrapper that allows SMB2 to query file system sizes.
2638 Synchronous only.
2639 ***************************************************************/
2640
cli_smb2_get_fs_full_size_info(struct cli_state * cli,uint64_t * total_allocation_units,uint64_t * caller_allocation_units,uint64_t * actual_allocation_units,uint64_t * sectors_per_allocation_unit,uint64_t * bytes_per_sector)2641 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2642 uint64_t *total_allocation_units,
2643 uint64_t *caller_allocation_units,
2644 uint64_t *actual_allocation_units,
2645 uint64_t *sectors_per_allocation_unit,
2646 uint64_t *bytes_per_sector)
2647 {
2648 NTSTATUS status;
2649 uint16_t fnum = 0xffff;
2650 DATA_BLOB outbuf = data_blob_null;
2651 TALLOC_CTX *frame = talloc_stackframe();
2652
2653 if (smbXcli_conn_has_async_calls(cli->conn)) {
2654 /*
2655 * Can't use sync call while an async call is in flight
2656 */
2657 status = NT_STATUS_INVALID_PARAMETER;
2658 goto fail;
2659 }
2660
2661 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2662 status = NT_STATUS_INVALID_PARAMETER;
2663 goto fail;
2664 }
2665
2666 /* First open the top level directory. */
2667 status =
2668 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2669 SMB2_IMPERSONATION_IMPERSONATION,
2670 FILE_READ_ATTRIBUTES, /* desired_access */
2671 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2672 FILE_SHARE_READ | FILE_SHARE_WRITE |
2673 FILE_SHARE_DELETE, /* share_access */
2674 FILE_OPEN, /* create_disposition */
2675 FILE_DIRECTORY_FILE, /* create_options */
2676 NULL,
2677 &fnum,
2678 NULL,
2679 NULL,
2680 NULL);
2681
2682 if (!NT_STATUS_IS_OK(status)) {
2683 goto fail;
2684 }
2685
2686 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2687 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2688
2689 status = cli_smb2_query_info_fnum(
2690 cli,
2691 fnum,
2692 SMB2_0_INFO_FILESYSTEM, /* in_info_type */
2693 SMB_FS_FULL_SIZE_INFORMATION - 1000, /* in_file_info_class */
2694 0xFFFF, /* in_max_output_length */
2695 NULL, /* in_input_buffer */
2696 0, /* in_additional_info */
2697 0, /* in_flags */
2698 frame,
2699 &outbuf);
2700 if (!NT_STATUS_IS_OK(status)) {
2701 goto fail;
2702 }
2703
2704 if (outbuf.length < 32) {
2705 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2706 goto fail;
2707 }
2708
2709 *total_allocation_units = BIG_UINT(outbuf.data, 0);
2710 *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2711 *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2712 *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2713 *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2714
2715 fail:
2716
2717 if (fnum != 0xffff) {
2718 cli_smb2_close_fnum(cli, fnum);
2719 }
2720
2721 cli->raw_status = status;
2722
2723 TALLOC_FREE(frame);
2724 return status;
2725 }
2726
2727 /***************************************************************
2728 Wrapper that allows SMB2 to query file system attributes.
2729 Synchronous only.
2730 ***************************************************************/
2731
cli_smb2_get_fs_attr_info(struct cli_state * cli,uint32_t * fs_attr)2732 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2733 {
2734 NTSTATUS status;
2735 uint16_t fnum = 0xffff;
2736 DATA_BLOB outbuf = data_blob_null;
2737 TALLOC_CTX *frame = talloc_stackframe();
2738
2739 if (smbXcli_conn_has_async_calls(cli->conn)) {
2740 /*
2741 * Can't use sync call while an async call is in flight
2742 */
2743 status = NT_STATUS_INVALID_PARAMETER;
2744 goto fail;
2745 }
2746
2747 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2748 status = NT_STATUS_INVALID_PARAMETER;
2749 goto fail;
2750 }
2751
2752 /* First open the top level directory. */
2753 status =
2754 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2755 SMB2_IMPERSONATION_IMPERSONATION,
2756 FILE_READ_ATTRIBUTES, /* desired_access */
2757 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2758 FILE_SHARE_READ | FILE_SHARE_WRITE |
2759 FILE_SHARE_DELETE, /* share_access */
2760 FILE_OPEN, /* create_disposition */
2761 FILE_DIRECTORY_FILE, /* create_options */
2762 NULL,
2763 &fnum,
2764 NULL,
2765 NULL,
2766 NULL);
2767
2768 if (!NT_STATUS_IS_OK(status)) {
2769 goto fail;
2770 }
2771
2772 status = cli_smb2_query_info_fnum(
2773 cli,
2774 fnum,
2775 2, /* in_info_type */
2776 5, /* in_file_info_class */
2777 0xFFFF, /* in_max_output_length */
2778 NULL, /* in_input_buffer */
2779 0, /* in_additional_info */
2780 0, /* in_flags */
2781 frame,
2782 &outbuf);
2783 if (!NT_STATUS_IS_OK(status)) {
2784 goto fail;
2785 }
2786
2787 if (outbuf.length < 12) {
2788 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2789 goto fail;
2790 }
2791
2792 *fs_attr = IVAL(outbuf.data, 0);
2793
2794 fail:
2795
2796 if (fnum != 0xffff) {
2797 cli_smb2_close_fnum(cli, fnum);
2798 }
2799
2800 cli->raw_status = status;
2801
2802 TALLOC_FREE(frame);
2803 return status;
2804 }
2805
2806 /***************************************************************
2807 Wrapper that allows SMB2 to query file system volume info.
2808 Synchronous only.
2809 ***************************************************************/
2810
cli_smb2_get_fs_volume_info(struct cli_state * cli,TALLOC_CTX * mem_ctx,char ** _volume_name,uint32_t * pserial_number,time_t * pdate)2811 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2812 TALLOC_CTX *mem_ctx,
2813 char **_volume_name,
2814 uint32_t *pserial_number,
2815 time_t *pdate)
2816 {
2817 NTSTATUS status;
2818 uint16_t fnum = 0xffff;
2819 DATA_BLOB outbuf = data_blob_null;
2820 uint32_t nlen;
2821 char *volume_name = NULL;
2822 TALLOC_CTX *frame = talloc_stackframe();
2823
2824 if (smbXcli_conn_has_async_calls(cli->conn)) {
2825 /*
2826 * Can't use sync call while an async call is in flight
2827 */
2828 status = NT_STATUS_INVALID_PARAMETER;
2829 goto fail;
2830 }
2831
2832 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2833 status = NT_STATUS_INVALID_PARAMETER;
2834 goto fail;
2835 }
2836
2837 /* First open the top level directory. */
2838 status =
2839 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2840 SMB2_IMPERSONATION_IMPERSONATION,
2841 FILE_READ_ATTRIBUTES, /* desired_access */
2842 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2843 FILE_SHARE_READ | FILE_SHARE_WRITE |
2844 FILE_SHARE_DELETE, /* share_access */
2845 FILE_OPEN, /* create_disposition */
2846 FILE_DIRECTORY_FILE, /* create_options */
2847 NULL,
2848 &fnum,
2849 NULL,
2850 NULL,
2851 NULL);
2852
2853 if (!NT_STATUS_IS_OK(status)) {
2854 goto fail;
2855 }
2856
2857 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2858 level 1 (SMB_FS_VOLUME_INFORMATION). */
2859
2860 status = cli_smb2_query_info_fnum(
2861 cli,
2862 fnum,
2863 SMB2_0_INFO_FILESYSTEM, /* in_info_type */
2864 /* in_file_info_class */
2865 SMB_FS_VOLUME_INFORMATION - 1000,
2866 0xFFFF, /* in_max_output_length */
2867 NULL, /* in_input_buffer */
2868 0, /* in_additional_info */
2869 0, /* in_flags */
2870 frame,
2871 &outbuf);
2872 if (!NT_STATUS_IS_OK(status)) {
2873 goto fail;
2874 }
2875
2876 if (outbuf.length < 24) {
2877 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2878 goto fail;
2879 }
2880
2881 if (pdate) {
2882 struct timespec ts;
2883 ts = interpret_long_date((char *)outbuf.data);
2884 *pdate = ts.tv_sec;
2885 }
2886 if (pserial_number) {
2887 *pserial_number = IVAL(outbuf.data,8);
2888 }
2889 nlen = IVAL(outbuf.data,12);
2890 if (nlen + 18 < 18) {
2891 /* Integer wrap. */
2892 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2893 goto fail;
2894 }
2895 /*
2896 * The next check is safe as we know outbuf.length >= 24
2897 * from above.
2898 */
2899 if (nlen > (outbuf.length - 18)) {
2900 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2901 goto fail;
2902 }
2903
2904 clistr_pull_talloc(mem_ctx,
2905 (const char *)outbuf.data,
2906 0,
2907 &volume_name,
2908 outbuf.data + 18,
2909 nlen,
2910 STR_UNICODE);
2911 if (volume_name == NULL) {
2912 status = map_nt_error_from_unix(errno);
2913 goto fail;
2914 }
2915
2916 *_volume_name = volume_name;
2917
2918 fail:
2919
2920 if (fnum != 0xffff) {
2921 cli_smb2_close_fnum(cli, fnum);
2922 }
2923
2924 cli->raw_status = status;
2925
2926 TALLOC_FREE(frame);
2927 return status;
2928 }
2929
2930
2931 /***************************************************************
2932 Wrapper that allows SMB2 to query a security descriptor.
2933 Synchronous only.
2934 ***************************************************************/
2935
cli_smb2_query_security_descriptor(struct cli_state * cli,uint16_t fnum,uint32_t sec_info,TALLOC_CTX * mem_ctx,struct security_descriptor ** ppsd)2936 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2937 uint16_t fnum,
2938 uint32_t sec_info,
2939 TALLOC_CTX *mem_ctx,
2940 struct security_descriptor **ppsd)
2941 {
2942 NTSTATUS status;
2943 DATA_BLOB outbuf = data_blob_null;
2944 struct security_descriptor *lsd = NULL;
2945 TALLOC_CTX *frame = talloc_stackframe();
2946
2947 if (smbXcli_conn_has_async_calls(cli->conn)) {
2948 /*
2949 * Can't use sync call while an async call is in flight
2950 */
2951 status = NT_STATUS_INVALID_PARAMETER;
2952 goto fail;
2953 }
2954
2955 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2956 status = NT_STATUS_INVALID_PARAMETER;
2957 goto fail;
2958 }
2959
2960 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2961
2962 status = cli_smb2_query_info_fnum(
2963 cli,
2964 fnum,
2965 3, /* in_info_type */
2966 0, /* in_file_info_class */
2967 0xFFFF, /* in_max_output_length */
2968 NULL, /* in_input_buffer */
2969 sec_info, /* in_additional_info */
2970 0, /* in_flags */
2971 frame,
2972 &outbuf);
2973
2974 if (!NT_STATUS_IS_OK(status)) {
2975 goto fail;
2976 }
2977
2978 /* Parse the reply. */
2979 status = unmarshall_sec_desc(mem_ctx,
2980 outbuf.data,
2981 outbuf.length,
2982 &lsd);
2983
2984 if (!NT_STATUS_IS_OK(status)) {
2985 goto fail;
2986 }
2987
2988 if (ppsd != NULL) {
2989 *ppsd = lsd;
2990 } else {
2991 TALLOC_FREE(lsd);
2992 }
2993
2994 fail:
2995
2996 cli->raw_status = status;
2997
2998 TALLOC_FREE(frame);
2999 return status;
3000 }
3001
3002 /***************************************************************
3003 Wrapper that allows SMB2 to set a security descriptor.
3004 Synchronous only.
3005 ***************************************************************/
3006
cli_smb2_set_security_descriptor(struct cli_state * cli,uint16_t fnum,uint32_t sec_info,const struct security_descriptor * sd)3007 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
3008 uint16_t fnum,
3009 uint32_t sec_info,
3010 const struct security_descriptor *sd)
3011 {
3012 NTSTATUS status;
3013 DATA_BLOB inbuf = data_blob_null;
3014 TALLOC_CTX *frame = talloc_stackframe();
3015
3016 if (smbXcli_conn_has_async_calls(cli->conn)) {
3017 /*
3018 * Can't use sync call while an async call is in flight
3019 */
3020 status = NT_STATUS_INVALID_PARAMETER;
3021 goto fail;
3022 }
3023
3024 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3025 status = NT_STATUS_INVALID_PARAMETER;
3026 goto fail;
3027 }
3028
3029 status = marshall_sec_desc(frame,
3030 sd,
3031 &inbuf.data,
3032 &inbuf.length);
3033
3034 if (!NT_STATUS_IS_OK(status)) {
3035 goto fail;
3036 }
3037
3038 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
3039
3040 status = cli_smb2_set_info_fnum(
3041 cli,
3042 fnum,
3043 3, /* in_info_type */
3044 0, /* in_file_info_class */
3045 &inbuf, /* in_input_buffer */
3046 sec_info); /* in_additional_info */
3047
3048 fail:
3049
3050 cli->raw_status = status;
3051
3052 TALLOC_FREE(frame);
3053 return status;
3054 }
3055
3056 /***************************************************************
3057 Wrapper that allows SMB2 to query a security descriptor.
3058 Synchronous only.
3059
3060 ***************************************************************/
3061
3062 struct cli_smb2_mxac_state {
3063 struct tevent_context *ev;
3064 struct cli_state *cli;
3065 const char *fname;
3066 struct smb2_create_blobs in_cblobs;
3067 uint16_t fnum;
3068 NTSTATUS status;
3069 uint32_t mxac;
3070 };
3071
3072 static void cli_smb2_mxac_opened(struct tevent_req *subreq);
3073 static void cli_smb2_mxac_closed(struct tevent_req *subreq);
3074
cli_smb2_query_mxac_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,const char * fname)3075 struct tevent_req *cli_smb2_query_mxac_send(TALLOC_CTX *mem_ctx,
3076 struct tevent_context *ev,
3077 struct cli_state *cli,
3078 const char *fname)
3079 {
3080 struct tevent_req *req = NULL, *subreq = NULL;
3081 struct cli_smb2_mxac_state *state = NULL;
3082 NTSTATUS status;
3083
3084 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_mxac_state);
3085 if (req == NULL) {
3086 return NULL;
3087 }
3088 *state = (struct cli_smb2_mxac_state) {
3089 .ev = ev,
3090 .cli = cli,
3091 .fname = fname,
3092 };
3093
3094 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3095 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3096 return tevent_req_post(req, ev);
3097 }
3098
3099 status = smb2_create_blob_add(state,
3100 &state->in_cblobs,
3101 SMB2_CREATE_TAG_MXAC,
3102 data_blob(NULL, 0));
3103 if (tevent_req_nterror(req, status)) {
3104 return tevent_req_post(req, ev);
3105 }
3106
3107 subreq = cli_smb2_create_fnum_send(
3108 state,
3109 state->ev,
3110 state->cli,
3111 state->fname,
3112 0, /* create_flags */
3113 SMB2_IMPERSONATION_IMPERSONATION,
3114 FILE_READ_ATTRIBUTES,
3115 0, /* file attributes */
3116 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
3117 FILE_OPEN,
3118 0, /* create_options */
3119 &state->in_cblobs);
3120 if (tevent_req_nomem(subreq, req)) {
3121 return tevent_req_post(req, ev);
3122 }
3123 tevent_req_set_callback(subreq, cli_smb2_mxac_opened, req);
3124 return req;
3125 }
3126
cli_smb2_mxac_opened(struct tevent_req * subreq)3127 static void cli_smb2_mxac_opened(struct tevent_req *subreq)
3128 {
3129 struct tevent_req *req = tevent_req_callback_data(
3130 subreq, struct tevent_req);
3131 struct cli_smb2_mxac_state *state = tevent_req_data(
3132 req, struct cli_smb2_mxac_state);
3133 struct smb2_create_blobs out_cblobs = {0};
3134 struct smb2_create_blob *mxac_blob = NULL;
3135 NTSTATUS status;
3136
3137 status = cli_smb2_create_fnum_recv(
3138 subreq, &state->fnum, NULL, state, &out_cblobs);
3139 TALLOC_FREE(subreq);
3140
3141 if (tevent_req_nterror(req, status)) {
3142 return;
3143 }
3144
3145 mxac_blob = smb2_create_blob_find(&out_cblobs, SMB2_CREATE_TAG_MXAC);
3146 if (mxac_blob == NULL) {
3147 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3148 goto close;
3149 }
3150 if (mxac_blob->data.length != 8) {
3151 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3152 goto close;
3153 }
3154
3155 state->status = NT_STATUS(IVAL(mxac_blob->data.data, 0));
3156 state->mxac = IVAL(mxac_blob->data.data, 4);
3157
3158 close:
3159 subreq = cli_smb2_close_fnum_send(
3160 state, state->ev, state->cli, state->fnum);
3161 if (tevent_req_nomem(subreq, req)) {
3162 return;
3163 }
3164 tevent_req_set_callback(subreq, cli_smb2_mxac_closed, req);
3165
3166 return;
3167 }
3168
cli_smb2_mxac_closed(struct tevent_req * subreq)3169 static void cli_smb2_mxac_closed(struct tevent_req *subreq)
3170 {
3171 struct tevent_req *req = tevent_req_callback_data(
3172 subreq, struct tevent_req);
3173 NTSTATUS status;
3174
3175 status = cli_smb2_close_fnum_recv(subreq);
3176 if (tevent_req_nterror(req, status)) {
3177 return;
3178 }
3179
3180 tevent_req_done(req);
3181 }
3182
cli_smb2_query_mxac_recv(struct tevent_req * req,uint32_t * mxac)3183 NTSTATUS cli_smb2_query_mxac_recv(struct tevent_req *req, uint32_t *mxac)
3184 {
3185 struct cli_smb2_mxac_state *state = tevent_req_data(
3186 req, struct cli_smb2_mxac_state);
3187 NTSTATUS status;
3188
3189 if (tevent_req_is_nterror(req, &status)) {
3190 return status;
3191 }
3192
3193 if (!NT_STATUS_IS_OK(state->status)) {
3194 return state->status;
3195 }
3196
3197 *mxac = state->mxac;
3198 return NT_STATUS_OK;
3199 }
3200
cli_smb2_query_mxac(struct cli_state * cli,const char * fname,uint32_t * _mxac)3201 NTSTATUS cli_smb2_query_mxac(struct cli_state *cli,
3202 const char *fname,
3203 uint32_t *_mxac)
3204 {
3205 TALLOC_CTX *frame = talloc_stackframe();
3206 struct tevent_context *ev = NULL;
3207 struct tevent_req *req = NULL;
3208 NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
3209 bool ok;
3210
3211 if (smbXcli_conn_has_async_calls(cli->conn)) {
3212 /*
3213 * Can't use sync call while an async call is in flight
3214 */
3215 status = NT_STATUS_INVALID_PARAMETER;
3216 goto fail;
3217 }
3218
3219 ev = samba_tevent_context_init(frame);
3220 if (ev == NULL) {
3221 goto fail;
3222 }
3223 req = cli_smb2_query_mxac_send(frame, ev, cli, fname);
3224 if (req == NULL) {
3225 goto fail;
3226 }
3227 ok = tevent_req_poll_ntstatus(req, ev, &status);
3228 if (!ok) {
3229 goto fail;
3230 }
3231 status = cli_smb2_query_mxac_recv(req, _mxac);
3232
3233 fail:
3234 cli->raw_status = status;
3235 TALLOC_FREE(frame);
3236 return status;
3237 }
3238
3239 /***************************************************************
3240 Wrapper that allows SMB2 to rename a file.
3241 Synchronous only.
3242 ***************************************************************/
3243
cli_smb2_rename(struct cli_state * cli,const char * fname_src,const char * fname_dst,bool replace)3244 NTSTATUS cli_smb2_rename(struct cli_state *cli,
3245 const char *fname_src,
3246 const char *fname_dst,
3247 bool replace)
3248 {
3249 NTSTATUS status;
3250 DATA_BLOB inbuf = data_blob_null;
3251 uint16_t fnum = 0xffff;
3252 smb_ucs2_t *converted_str = NULL;
3253 size_t converted_size_bytes = 0;
3254 size_t namelen = 0;
3255 size_t inbuf_size;
3256 TALLOC_CTX *frame = talloc_stackframe();
3257
3258 if (smbXcli_conn_has_async_calls(cli->conn)) {
3259 /*
3260 * Can't use sync call while an async call is in flight
3261 */
3262 status = NT_STATUS_INVALID_PARAMETER;
3263 goto fail;
3264 }
3265
3266 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3267 status = NT_STATUS_INVALID_PARAMETER;
3268 goto fail;
3269 }
3270
3271 status = get_fnum_from_path(cli,
3272 fname_src,
3273 DELETE_ACCESS,
3274 &fnum);
3275
3276 if (!NT_STATUS_IS_OK(status)) {
3277 goto fail;
3278 }
3279
3280 /* SMB2 is pickier about pathnames. Ensure it doesn't
3281 start in a '\' */
3282 if (*fname_dst == '\\') {
3283 fname_dst++;
3284 }
3285
3286 /* SMB2 is pickier about pathnames. Ensure it doesn't
3287 end in a '\' */
3288 namelen = strlen(fname_dst);
3289 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
3290 char *modname = talloc_strdup(frame, fname_dst);
3291 modname[namelen-1] = '\0';
3292 fname_dst = modname;
3293 }
3294
3295 if (!push_ucs2_talloc(frame,
3296 &converted_str,
3297 fname_dst,
3298 &converted_size_bytes)) {
3299 status = NT_STATUS_INVALID_PARAMETER;
3300 goto fail;
3301 }
3302
3303 /* W2K8 insists the dest name is not null
3304 terminated. Remove the last 2 zero bytes
3305 and reduce the name length. */
3306
3307 if (converted_size_bytes < 2) {
3308 status = NT_STATUS_INVALID_PARAMETER;
3309 goto fail;
3310 }
3311 converted_size_bytes -= 2;
3312
3313 inbuf_size = 20 + converted_size_bytes;
3314 if (inbuf_size < 20) {
3315 /* Integer wrap check. */
3316 status = NT_STATUS_INVALID_PARAMETER;
3317 goto fail;
3318 }
3319
3320 /*
3321 * The Windows 10 SMB2 server has a minimum length
3322 * for a SMB2_FILE_RENAME_INFORMATION buffer of
3323 * 24 bytes. It returns NT_STATUS_INFO_LENGTH_MISMATCH
3324 * if the length is less. This isn't an alignment
3325 * issue as Windows client happily 2-byte align
3326 * for larget target name sizes. Also the Windows 10
3327 * SMB1 server doesn't have this restriction.
3328 *
3329 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14403
3330 */
3331 if (inbuf_size < 24) {
3332 inbuf_size = 24;
3333 }
3334
3335 inbuf = data_blob_talloc_zero(frame, inbuf_size);
3336 if (inbuf.data == NULL) {
3337 status = NT_STATUS_NO_MEMORY;
3338 goto fail;
3339 }
3340
3341 if (replace) {
3342 SCVAL(inbuf.data, 0, 1);
3343 }
3344
3345 SIVAL(inbuf.data, 16, converted_size_bytes);
3346 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
3347
3348 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
3349 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
3350
3351 status = cli_smb2_set_info_fnum(
3352 cli,
3353 fnum,
3354 1, /* in_info_type */
3355 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
3356 &inbuf, /* in_input_buffer */
3357 0); /* in_additional_info */
3358
3359 fail:
3360
3361 if (fnum != 0xffff) {
3362 cli_smb2_close_fnum(cli, fnum);
3363 }
3364
3365 cli->raw_status = status;
3366
3367 TALLOC_FREE(frame);
3368 return status;
3369 }
3370
3371 /***************************************************************
3372 Wrapper that allows SMB2 to set an EA on a fnum.
3373 Synchronous only.
3374 ***************************************************************/
3375
cli_smb2_set_ea_fnum(struct cli_state * cli,uint16_t fnum,const char * ea_name,const char * ea_val,size_t ea_len)3376 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
3377 uint16_t fnum,
3378 const char *ea_name,
3379 const char *ea_val,
3380 size_t ea_len)
3381 {
3382 NTSTATUS status;
3383 DATA_BLOB inbuf = data_blob_null;
3384 size_t bloblen = 0;
3385 char *ea_name_ascii = NULL;
3386 size_t namelen = 0;
3387 TALLOC_CTX *frame = talloc_stackframe();
3388
3389 if (smbXcli_conn_has_async_calls(cli->conn)) {
3390 /*
3391 * Can't use sync call while an async call is in flight
3392 */
3393 status = NT_STATUS_INVALID_PARAMETER;
3394 goto fail;
3395 }
3396
3397 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3398 status = NT_STATUS_INVALID_PARAMETER;
3399 goto fail;
3400 }
3401
3402 /* Marshall the SMB2 EA data. */
3403 if (ea_len > 0xFFFF) {
3404 status = NT_STATUS_INVALID_PARAMETER;
3405 goto fail;
3406 }
3407
3408 if (!push_ascii_talloc(frame,
3409 &ea_name_ascii,
3410 ea_name,
3411 &namelen)) {
3412 status = NT_STATUS_INVALID_PARAMETER;
3413 goto fail;
3414 }
3415
3416 if (namelen < 2 || namelen > 0xFF) {
3417 status = NT_STATUS_INVALID_PARAMETER;
3418 goto fail;
3419 }
3420
3421 bloblen = 8 + ea_len + namelen;
3422 /* Round up to a 4 byte boundary. */
3423 bloblen = ((bloblen + 3)&~3);
3424
3425 inbuf = data_blob_talloc_zero(frame, bloblen);
3426 if (inbuf.data == NULL) {
3427 status = NT_STATUS_NO_MEMORY;
3428 goto fail;
3429 }
3430 /* namelen doesn't include the NULL byte. */
3431 SCVAL(inbuf.data, 5, namelen - 1);
3432 SSVAL(inbuf.data, 6, ea_len);
3433 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
3434 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
3435
3436 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3437 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3438
3439 status = cli_smb2_set_info_fnum(
3440 cli,
3441 fnum,
3442 1, /* in_info_type */
3443 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3444 &inbuf, /* in_input_buffer */
3445 0); /* in_additional_info */
3446
3447 fail:
3448
3449 cli->raw_status = status;
3450
3451 TALLOC_FREE(frame);
3452 return status;
3453 }
3454
3455 /***************************************************************
3456 Wrapper that allows SMB2 to set an EA on a pathname.
3457 Synchronous only.
3458 ***************************************************************/
3459
cli_smb2_set_ea_path(struct cli_state * cli,const char * name,const char * ea_name,const char * ea_val,size_t ea_len)3460 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
3461 const char *name,
3462 const char *ea_name,
3463 const char *ea_val,
3464 size_t ea_len)
3465 {
3466 NTSTATUS status;
3467 uint16_t fnum = 0xffff;
3468
3469 if (smbXcli_conn_has_async_calls(cli->conn)) {
3470 /*
3471 * Can't use sync call while an async call is in flight
3472 */
3473 status = NT_STATUS_INVALID_PARAMETER;
3474 goto fail;
3475 }
3476
3477 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3478 status = NT_STATUS_INVALID_PARAMETER;
3479 goto fail;
3480 }
3481
3482 status = get_fnum_from_path(cli,
3483 name,
3484 FILE_WRITE_EA,
3485 &fnum);
3486
3487 if (!NT_STATUS_IS_OK(status)) {
3488 goto fail;
3489 }
3490
3491 status = cli_set_ea_fnum(cli,
3492 fnum,
3493 ea_name,
3494 ea_val,
3495 ea_len);
3496 if (!NT_STATUS_IS_OK(status)) {
3497 goto fail;
3498 }
3499
3500 fail:
3501
3502 if (fnum != 0xffff) {
3503 cli_smb2_close_fnum(cli, fnum);
3504 }
3505
3506 cli->raw_status = status;
3507
3508 return status;
3509 }
3510
3511 /***************************************************************
3512 Wrapper that allows SMB2 to get an EA list on a pathname.
3513 Synchronous only.
3514 ***************************************************************/
3515
cli_smb2_get_ea_list_path(struct cli_state * cli,const char * name,TALLOC_CTX * ctx,size_t * pnum_eas,struct ea_struct ** pea_array)3516 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
3517 const char *name,
3518 TALLOC_CTX *ctx,
3519 size_t *pnum_eas,
3520 struct ea_struct **pea_array)
3521 {
3522 NTSTATUS status;
3523 uint16_t fnum = 0xffff;
3524 DATA_BLOB outbuf = data_blob_null;
3525 struct ea_list *ea_list = NULL;
3526 struct ea_list *eal = NULL;
3527 size_t ea_count = 0;
3528 TALLOC_CTX *frame = talloc_stackframe();
3529
3530 *pnum_eas = 0;
3531 *pea_array = NULL;
3532
3533 if (smbXcli_conn_has_async_calls(cli->conn)) {
3534 /*
3535 * Can't use sync call while an async call is in flight
3536 */
3537 status = NT_STATUS_INVALID_PARAMETER;
3538 goto fail;
3539 }
3540
3541 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3542 status = NT_STATUS_INVALID_PARAMETER;
3543 goto fail;
3544 }
3545
3546 status = get_fnum_from_path(cli,
3547 name,
3548 FILE_READ_EA,
3549 &fnum);
3550
3551 if (!NT_STATUS_IS_OK(status)) {
3552 goto fail;
3553 }
3554
3555 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
3556 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3557
3558 status = cli_smb2_query_info_fnum(
3559 cli,
3560 fnum,
3561 1, /* in_info_type */
3562 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3563 0xFFFF, /* in_max_output_length */
3564 NULL, /* in_input_buffer */
3565 0, /* in_additional_info */
3566 0, /* in_flags */
3567 frame,
3568 &outbuf);
3569
3570 if (!NT_STATUS_IS_OK(status)) {
3571 goto fail;
3572 }
3573
3574 /* Parse the reply. */
3575 ea_list = read_nttrans_ea_list(ctx,
3576 (const char *)outbuf.data,
3577 outbuf.length);
3578 if (ea_list == NULL) {
3579 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3580 goto fail;
3581 }
3582
3583 /* Convert to an array. */
3584 for (eal = ea_list; eal; eal = eal->next) {
3585 ea_count++;
3586 }
3587
3588 if (ea_count) {
3589 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
3590 if (*pea_array == NULL) {
3591 status = NT_STATUS_NO_MEMORY;
3592 goto fail;
3593 }
3594 ea_count = 0;
3595 for (eal = ea_list; eal; eal = eal->next) {
3596 (*pea_array)[ea_count++] = eal->ea;
3597 }
3598 *pnum_eas = ea_count;
3599 }
3600
3601 fail:
3602
3603 if (fnum != 0xffff) {
3604 cli_smb2_close_fnum(cli, fnum);
3605 }
3606
3607 cli->raw_status = status;
3608
3609 TALLOC_FREE(frame);
3610 return status;
3611 }
3612
3613 /***************************************************************
3614 Wrapper that allows SMB2 to get user quota.
3615 Synchronous only.
3616 ***************************************************************/
3617
cli_smb2_get_user_quota(struct cli_state * cli,int quota_fnum,SMB_NTQUOTA_STRUCT * pqt)3618 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
3619 int quota_fnum,
3620 SMB_NTQUOTA_STRUCT *pqt)
3621 {
3622 NTSTATUS status;
3623 DATA_BLOB inbuf = data_blob_null;
3624 DATA_BLOB info_blob = data_blob_null;
3625 DATA_BLOB outbuf = data_blob_null;
3626 TALLOC_CTX *frame = talloc_stackframe();
3627 unsigned sid_len;
3628 unsigned int offset;
3629 struct smb2_query_quota_info query = {0};
3630 struct file_get_quota_info info = {0};
3631 enum ndr_err_code err;
3632 struct ndr_push *ndr_push = NULL;
3633
3634 if (smbXcli_conn_has_async_calls(cli->conn)) {
3635 /*
3636 * Can't use sync call while an async call is in flight
3637 */
3638 status = NT_STATUS_INVALID_PARAMETER;
3639 goto fail;
3640 }
3641
3642 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3643 status = NT_STATUS_INVALID_PARAMETER;
3644 goto fail;
3645 }
3646
3647 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
3648
3649 query.return_single = 1;
3650
3651 info.next_entry_offset = 0;
3652 info.sid_length = sid_len;
3653 info.sid = pqt->sid;
3654
3655 err = ndr_push_struct_blob(
3656 &info_blob,
3657 frame,
3658 &info,
3659 (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
3660
3661 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3662 status = NT_STATUS_INTERNAL_ERROR;
3663 goto fail;
3664 }
3665
3666 query.sid_list_length = info_blob.length;
3667 ndr_push = ndr_push_init_ctx(frame);
3668 if (!ndr_push) {
3669 status = NT_STATUS_NO_MEMORY;
3670 goto fail;
3671 }
3672
3673 err = ndr_push_smb2_query_quota_info(ndr_push,
3674 NDR_SCALARS | NDR_BUFFERS,
3675 &query);
3676
3677 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3678 status = NT_STATUS_INTERNAL_ERROR;
3679 goto fail;
3680 }
3681
3682 err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
3683 info_blob.length);
3684
3685 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3686 status = NT_STATUS_INTERNAL_ERROR;
3687 goto fail;
3688 }
3689 inbuf.data = ndr_push->data;
3690 inbuf.length = ndr_push->offset;
3691
3692 status = cli_smb2_query_info_fnum(
3693 cli,
3694 quota_fnum,
3695 4, /* in_info_type */
3696 0, /* in_file_info_class */
3697 0xFFFF, /* in_max_output_length */
3698 &inbuf, /* in_input_buffer */
3699 0, /* in_additional_info */
3700 0, /* in_flags */
3701 frame,
3702 &outbuf);
3703
3704 if (!NT_STATUS_IS_OK(status)) {
3705 goto fail;
3706 }
3707
3708 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
3709 pqt)) {
3710 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3711 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3712 }
3713
3714 fail:
3715 cli->raw_status = status;
3716
3717 TALLOC_FREE(frame);
3718 return status;
3719 }
3720
3721 /***************************************************************
3722 Wrapper that allows SMB2 to list user quota.
3723 Synchronous only.
3724 ***************************************************************/
3725
cli_smb2_list_user_quota_step(struct cli_state * cli,TALLOC_CTX * mem_ctx,int quota_fnum,SMB_NTQUOTA_LIST ** pqt_list,bool first)3726 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
3727 TALLOC_CTX *mem_ctx,
3728 int quota_fnum,
3729 SMB_NTQUOTA_LIST **pqt_list,
3730 bool first)
3731 {
3732 NTSTATUS status;
3733 DATA_BLOB inbuf = data_blob_null;
3734 DATA_BLOB outbuf = data_blob_null;
3735 TALLOC_CTX *frame = talloc_stackframe();
3736 struct smb2_query_quota_info info = {0};
3737 enum ndr_err_code err;
3738
3739 if (smbXcli_conn_has_async_calls(cli->conn)) {
3740 /*
3741 * Can't use sync call while an async call is in flight
3742 */
3743 status = NT_STATUS_INVALID_PARAMETER;
3744 goto cleanup;
3745 }
3746
3747 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3748 status = NT_STATUS_INVALID_PARAMETER;
3749 goto cleanup;
3750 }
3751
3752 info.restart_scan = first ? 1 : 0;
3753
3754 err = ndr_push_struct_blob(
3755 &inbuf,
3756 frame,
3757 &info,
3758 (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
3759
3760 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3761 status = NT_STATUS_INTERNAL_ERROR;
3762 goto cleanup;
3763 }
3764
3765 status = cli_smb2_query_info_fnum(
3766 cli,
3767 quota_fnum,
3768 4, /* in_info_type */
3769 0, /* in_file_info_class */
3770 0xFFFF, /* in_max_output_length */
3771 &inbuf, /* in_input_buffer */
3772 0, /* in_additional_info */
3773 0, /* in_flags */
3774 frame,
3775 &outbuf);
3776
3777 /*
3778 * safeguard against panic from calling parse_user_quota_list with
3779 * NULL buffer
3780 */
3781 if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
3782 status = NT_STATUS_NO_MORE_ENTRIES;
3783 }
3784
3785 if (!NT_STATUS_IS_OK(status)) {
3786 goto cleanup;
3787 }
3788
3789 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
3790 pqt_list);
3791
3792 cleanup:
3793 cli->raw_status = status;
3794
3795 TALLOC_FREE(frame);
3796 return status;
3797 }
3798
3799 /***************************************************************
3800 Wrapper that allows SMB2 to get file system quota.
3801 Synchronous only.
3802 ***************************************************************/
3803
cli_smb2_get_fs_quota_info(struct cli_state * cli,int quota_fnum,SMB_NTQUOTA_STRUCT * pqt)3804 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3805 int quota_fnum,
3806 SMB_NTQUOTA_STRUCT *pqt)
3807 {
3808 NTSTATUS status;
3809 DATA_BLOB outbuf = data_blob_null;
3810 TALLOC_CTX *frame = talloc_stackframe();
3811
3812 if (smbXcli_conn_has_async_calls(cli->conn)) {
3813 /*
3814 * Can't use sync call while an async call is in flight
3815 */
3816 status = NT_STATUS_INVALID_PARAMETER;
3817 goto cleanup;
3818 }
3819
3820 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3821 status = NT_STATUS_INVALID_PARAMETER;
3822 goto cleanup;
3823 }
3824
3825 status = cli_smb2_query_info_fnum(
3826 cli,
3827 quota_fnum,
3828 2, /* in_info_type */
3829 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3830 0xFFFF, /* in_max_output_length */
3831 NULL, /* in_input_buffer */
3832 0, /* in_additional_info */
3833 0, /* in_flags */
3834 frame,
3835 &outbuf);
3836
3837 if (!NT_STATUS_IS_OK(status)) {
3838 goto cleanup;
3839 }
3840
3841 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3842
3843 cleanup:
3844 cli->raw_status = status;
3845
3846 TALLOC_FREE(frame);
3847 return status;
3848 }
3849
3850 /***************************************************************
3851 Wrapper that allows SMB2 to set user quota.
3852 Synchronous only.
3853 ***************************************************************/
3854
cli_smb2_set_user_quota(struct cli_state * cli,int quota_fnum,SMB_NTQUOTA_LIST * qtl)3855 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3856 int quota_fnum,
3857 SMB_NTQUOTA_LIST *qtl)
3858 {
3859 NTSTATUS status;
3860 DATA_BLOB inbuf = data_blob_null;
3861 TALLOC_CTX *frame = talloc_stackframe();
3862
3863 if (smbXcli_conn_has_async_calls(cli->conn)) {
3864 /*
3865 * Can't use sync call while an async call is in flight
3866 */
3867 status = NT_STATUS_INVALID_PARAMETER;
3868 goto cleanup;
3869 }
3870
3871 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3872 status = NT_STATUS_INVALID_PARAMETER;
3873 goto cleanup;
3874 }
3875
3876 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3877 if (!NT_STATUS_IS_OK(status)) {
3878 goto cleanup;
3879 }
3880
3881 status = cli_smb2_set_info_fnum(
3882 cli,
3883 quota_fnum,
3884 4, /* in_info_type */
3885 0, /* in_file_info_class */
3886 &inbuf, /* in_input_buffer */
3887 0); /* in_additional_info */
3888 cleanup:
3889
3890 cli->raw_status = status;
3891
3892 TALLOC_FREE(frame);
3893
3894 return status;
3895 }
3896
cli_smb2_set_fs_quota_info(struct cli_state * cli,int quota_fnum,SMB_NTQUOTA_STRUCT * pqt)3897 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3898 int quota_fnum,
3899 SMB_NTQUOTA_STRUCT *pqt)
3900 {
3901 NTSTATUS status;
3902 DATA_BLOB inbuf = data_blob_null;
3903 TALLOC_CTX *frame = talloc_stackframe();
3904
3905 if (smbXcli_conn_has_async_calls(cli->conn)) {
3906 /*
3907 * Can't use sync call while an async call is in flight
3908 */
3909 status = NT_STATUS_INVALID_PARAMETER;
3910 goto cleanup;
3911 }
3912
3913 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3914 status = NT_STATUS_INVALID_PARAMETER;
3915 goto cleanup;
3916 }
3917
3918 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3919 if (!NT_STATUS_IS_OK(status)) {
3920 goto cleanup;
3921 }
3922
3923 status = cli_smb2_set_info_fnum(
3924 cli,
3925 quota_fnum,
3926 2, /* in_info_type */
3927 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3928 &inbuf, /* in_input_buffer */
3929 0); /* in_additional_info */
3930 cleanup:
3931 cli->raw_status = status;
3932
3933 TALLOC_FREE(frame);
3934 return status;
3935 }
3936
3937 struct cli_smb2_read_state {
3938 struct tevent_context *ev;
3939 struct cli_state *cli;
3940 struct smb2_hnd *ph;
3941 uint64_t start_offset;
3942 uint32_t size;
3943 uint32_t received;
3944 uint8_t *buf;
3945 };
3946
3947 static void cli_smb2_read_done(struct tevent_req *subreq);
3948
cli_smb2_read_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,uint16_t fnum,off_t offset,size_t size)3949 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3950 struct tevent_context *ev,
3951 struct cli_state *cli,
3952 uint16_t fnum,
3953 off_t offset,
3954 size_t size)
3955 {
3956 NTSTATUS status;
3957 struct tevent_req *req, *subreq;
3958 struct cli_smb2_read_state *state;
3959
3960 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
3961 if (req == NULL) {
3962 return NULL;
3963 }
3964 state->ev = ev;
3965 state->cli = cli;
3966 state->start_offset = (uint64_t)offset;
3967 state->size = (uint32_t)size;
3968 state->received = 0;
3969 state->buf = NULL;
3970
3971 status = map_fnum_to_smb2_handle(cli,
3972 fnum,
3973 &state->ph);
3974 if (tevent_req_nterror(req, status)) {
3975 return tevent_req_post(req, ev);
3976 }
3977
3978 subreq = smb2cli_read_send(state,
3979 state->ev,
3980 state->cli->conn,
3981 state->cli->timeout,
3982 state->cli->smb2.session,
3983 state->cli->smb2.tcon,
3984 state->size,
3985 state->start_offset,
3986 state->ph->fid_persistent,
3987 state->ph->fid_volatile,
3988 0, /* minimum_count */
3989 0); /* remaining_bytes */
3990
3991 if (tevent_req_nomem(subreq, req)) {
3992 return tevent_req_post(req, ev);
3993 }
3994 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
3995 return req;
3996 }
3997
cli_smb2_read_done(struct tevent_req * subreq)3998 static void cli_smb2_read_done(struct tevent_req *subreq)
3999 {
4000 struct tevent_req *req = tevent_req_callback_data(
4001 subreq, struct tevent_req);
4002 struct cli_smb2_read_state *state = tevent_req_data(
4003 req, struct cli_smb2_read_state);
4004 NTSTATUS status;
4005
4006 status = smb2cli_read_recv(subreq, state,
4007 &state->buf, &state->received);
4008 if (tevent_req_nterror(req, status)) {
4009 return;
4010 }
4011
4012 if (state->received > state->size) {
4013 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4014 return;
4015 }
4016
4017 tevent_req_done(req);
4018 }
4019
cli_smb2_read_recv(struct tevent_req * req,ssize_t * received,uint8_t ** rcvbuf)4020 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
4021 ssize_t *received,
4022 uint8_t **rcvbuf)
4023 {
4024 NTSTATUS status;
4025 struct cli_smb2_read_state *state = tevent_req_data(
4026 req, struct cli_smb2_read_state);
4027
4028 if (tevent_req_is_nterror(req, &status)) {
4029 state->cli->raw_status = status;
4030 return status;
4031 }
4032 /*
4033 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
4034 * better make sure that you copy it away before you talloc_free(req).
4035 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
4036 */
4037 *received = (ssize_t)state->received;
4038 *rcvbuf = state->buf;
4039 state->cli->raw_status = NT_STATUS_OK;
4040 return NT_STATUS_OK;
4041 }
4042
4043 struct cli_smb2_write_state {
4044 struct tevent_context *ev;
4045 struct cli_state *cli;
4046 struct smb2_hnd *ph;
4047 uint32_t flags;
4048 const uint8_t *buf;
4049 uint64_t offset;
4050 uint32_t size;
4051 uint32_t written;
4052 };
4053
4054 static void cli_smb2_write_written(struct tevent_req *req);
4055
cli_smb2_write_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,uint16_t fnum,uint16_t mode,const uint8_t * buf,off_t offset,size_t size)4056 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
4057 struct tevent_context *ev,
4058 struct cli_state *cli,
4059 uint16_t fnum,
4060 uint16_t mode,
4061 const uint8_t *buf,
4062 off_t offset,
4063 size_t size)
4064 {
4065 NTSTATUS status;
4066 struct tevent_req *req, *subreq = NULL;
4067 struct cli_smb2_write_state *state = NULL;
4068
4069 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
4070 if (req == NULL) {
4071 return NULL;
4072 }
4073 state->ev = ev;
4074 state->cli = cli;
4075 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4076 state->flags = (uint32_t)mode;
4077 state->buf = buf;
4078 state->offset = (uint64_t)offset;
4079 state->size = (uint32_t)size;
4080 state->written = 0;
4081
4082 status = map_fnum_to_smb2_handle(cli,
4083 fnum,
4084 &state->ph);
4085 if (tevent_req_nterror(req, status)) {
4086 return tevent_req_post(req, ev);
4087 }
4088
4089 subreq = smb2cli_write_send(state,
4090 state->ev,
4091 state->cli->conn,
4092 state->cli->timeout,
4093 state->cli->smb2.session,
4094 state->cli->smb2.tcon,
4095 state->size,
4096 state->offset,
4097 state->ph->fid_persistent,
4098 state->ph->fid_volatile,
4099 0, /* remaining_bytes */
4100 state->flags, /* flags */
4101 state->buf);
4102
4103 if (tevent_req_nomem(subreq, req)) {
4104 return tevent_req_post(req, ev);
4105 }
4106 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
4107 return req;
4108 }
4109
cli_smb2_write_written(struct tevent_req * subreq)4110 static void cli_smb2_write_written(struct tevent_req *subreq)
4111 {
4112 struct tevent_req *req = tevent_req_callback_data(
4113 subreq, struct tevent_req);
4114 struct cli_smb2_write_state *state = tevent_req_data(
4115 req, struct cli_smb2_write_state);
4116 NTSTATUS status;
4117 uint32_t written;
4118
4119 status = smb2cli_write_recv(subreq, &written);
4120 TALLOC_FREE(subreq);
4121 if (tevent_req_nterror(req, status)) {
4122 return;
4123 }
4124
4125 state->written = written;
4126
4127 tevent_req_done(req);
4128 }
4129
cli_smb2_write_recv(struct tevent_req * req,size_t * pwritten)4130 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
4131 size_t *pwritten)
4132 {
4133 struct cli_smb2_write_state *state = tevent_req_data(
4134 req, struct cli_smb2_write_state);
4135 NTSTATUS status;
4136
4137 if (tevent_req_is_nterror(req, &status)) {
4138 state->cli->raw_status = status;
4139 tevent_req_received(req);
4140 return status;
4141 }
4142
4143 if (pwritten != NULL) {
4144 *pwritten = (size_t)state->written;
4145 }
4146 state->cli->raw_status = NT_STATUS_OK;
4147 tevent_req_received(req);
4148 return NT_STATUS_OK;
4149 }
4150
4151 /***************************************************************
4152 Wrapper that allows SMB2 async write using an fnum.
4153 This is mostly cut-and-paste from Volker's code inside
4154 source3/libsmb/clireadwrite.c, adapted for SMB2.
4155
4156 Done this way so I can reuse all the logic inside cli_push()
4157 for free :-).
4158 ***************************************************************/
4159
4160 struct cli_smb2_writeall_state {
4161 struct tevent_context *ev;
4162 struct cli_state *cli;
4163 struct smb2_hnd *ph;
4164 uint32_t flags;
4165 const uint8_t *buf;
4166 uint64_t offset;
4167 uint32_t size;
4168 uint32_t written;
4169 };
4170
4171 static void cli_smb2_writeall_written(struct tevent_req *req);
4172
cli_smb2_writeall_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,uint16_t fnum,uint16_t mode,const uint8_t * buf,off_t offset,size_t size)4173 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
4174 struct tevent_context *ev,
4175 struct cli_state *cli,
4176 uint16_t fnum,
4177 uint16_t mode,
4178 const uint8_t *buf,
4179 off_t offset,
4180 size_t size)
4181 {
4182 NTSTATUS status;
4183 struct tevent_req *req, *subreq = NULL;
4184 struct cli_smb2_writeall_state *state = NULL;
4185 uint32_t to_write;
4186 uint32_t max_size;
4187 bool ok;
4188
4189 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
4190 if (req == NULL) {
4191 return NULL;
4192 }
4193 state->ev = ev;
4194 state->cli = cli;
4195 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4196 state->flags = (uint32_t)mode;
4197 state->buf = buf;
4198 state->offset = (uint64_t)offset;
4199 state->size = (uint32_t)size;
4200 state->written = 0;
4201
4202 status = map_fnum_to_smb2_handle(cli,
4203 fnum,
4204 &state->ph);
4205 if (tevent_req_nterror(req, status)) {
4206 return tevent_req_post(req, ev);
4207 }
4208
4209 to_write = state->size;
4210 max_size = smb2cli_conn_max_write_size(state->cli->conn);
4211 to_write = MIN(max_size, to_write);
4212 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4213 if (ok) {
4214 to_write = MIN(max_size, to_write);
4215 }
4216
4217 subreq = smb2cli_write_send(state,
4218 state->ev,
4219 state->cli->conn,
4220 state->cli->timeout,
4221 state->cli->smb2.session,
4222 state->cli->smb2.tcon,
4223 to_write,
4224 state->offset,
4225 state->ph->fid_persistent,
4226 state->ph->fid_volatile,
4227 0, /* remaining_bytes */
4228 state->flags, /* flags */
4229 state->buf + state->written);
4230
4231 if (tevent_req_nomem(subreq, req)) {
4232 return tevent_req_post(req, ev);
4233 }
4234 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4235 return req;
4236 }
4237
cli_smb2_writeall_written(struct tevent_req * subreq)4238 static void cli_smb2_writeall_written(struct tevent_req *subreq)
4239 {
4240 struct tevent_req *req = tevent_req_callback_data(
4241 subreq, struct tevent_req);
4242 struct cli_smb2_writeall_state *state = tevent_req_data(
4243 req, struct cli_smb2_writeall_state);
4244 NTSTATUS status;
4245 uint32_t written, to_write;
4246 uint32_t max_size;
4247 bool ok;
4248
4249 status = smb2cli_write_recv(subreq, &written);
4250 TALLOC_FREE(subreq);
4251 if (tevent_req_nterror(req, status)) {
4252 return;
4253 }
4254
4255 state->written += written;
4256
4257 if (state->written > state->size) {
4258 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4259 return;
4260 }
4261
4262 to_write = state->size - state->written;
4263
4264 if (to_write == 0) {
4265 tevent_req_done(req);
4266 return;
4267 }
4268
4269 max_size = smb2cli_conn_max_write_size(state->cli->conn);
4270 to_write = MIN(max_size, to_write);
4271 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4272 if (ok) {
4273 to_write = MIN(max_size, to_write);
4274 }
4275
4276 subreq = smb2cli_write_send(state,
4277 state->ev,
4278 state->cli->conn,
4279 state->cli->timeout,
4280 state->cli->smb2.session,
4281 state->cli->smb2.tcon,
4282 to_write,
4283 state->offset + state->written,
4284 state->ph->fid_persistent,
4285 state->ph->fid_volatile,
4286 0, /* remaining_bytes */
4287 state->flags, /* flags */
4288 state->buf + state->written);
4289
4290 if (tevent_req_nomem(subreq, req)) {
4291 return;
4292 }
4293 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4294 }
4295
cli_smb2_writeall_recv(struct tevent_req * req,size_t * pwritten)4296 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
4297 size_t *pwritten)
4298 {
4299 struct cli_smb2_writeall_state *state = tevent_req_data(
4300 req, struct cli_smb2_writeall_state);
4301 NTSTATUS status;
4302
4303 if (tevent_req_is_nterror(req, &status)) {
4304 state->cli->raw_status = status;
4305 return status;
4306 }
4307 if (pwritten != NULL) {
4308 *pwritten = (size_t)state->written;
4309 }
4310 state->cli->raw_status = NT_STATUS_OK;
4311 return NT_STATUS_OK;
4312 }
4313
4314 struct cli_smb2_splice_state {
4315 struct tevent_context *ev;
4316 struct cli_state *cli;
4317 struct smb2_hnd *src_ph;
4318 struct smb2_hnd *dst_ph;
4319 int (*splice_cb)(off_t n, void *priv);
4320 void *priv;
4321 off_t written;
4322 off_t size;
4323 off_t src_offset;
4324 off_t dst_offset;
4325 bool resized;
4326 struct req_resume_key_rsp resume_rsp;
4327 struct srv_copychunk_copy cc_copy;
4328 };
4329
4330 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4331 struct tevent_req *req);
4332
cli_splice_copychunk_done(struct tevent_req * subreq)4333 static void cli_splice_copychunk_done(struct tevent_req *subreq)
4334 {
4335 struct tevent_req *req = tevent_req_callback_data(
4336 subreq, struct tevent_req);
4337 struct cli_smb2_splice_state *state =
4338 tevent_req_data(req,
4339 struct cli_smb2_splice_state);
4340 struct smbXcli_conn *conn = state->cli->conn;
4341 DATA_BLOB out_input_buffer = data_blob_null;
4342 DATA_BLOB out_output_buffer = data_blob_null;
4343 struct srv_copychunk_rsp cc_copy_rsp;
4344 enum ndr_err_code ndr_ret;
4345 NTSTATUS status;
4346
4347 status = smb2cli_ioctl_recv(subreq, state,
4348 &out_input_buffer,
4349 &out_output_buffer);
4350 TALLOC_FREE(subreq);
4351 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
4352 state->resized) && tevent_req_nterror(req, status)) {
4353 return;
4354 }
4355
4356 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
4357 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
4358 if (ndr_ret != NDR_ERR_SUCCESS) {
4359 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
4360 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4361 return;
4362 }
4363
4364 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
4365 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
4366 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
4367 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
4368 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
4369 tevent_req_nterror(req, status)) {
4370 return;
4371 }
4372
4373 state->resized = true;
4374 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
4375 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
4376 } else {
4377 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4378 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4379 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
4380 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4381 return;
4382 }
4383 state->src_offset += cc_copy_rsp.total_bytes_written;
4384 state->dst_offset += cc_copy_rsp.total_bytes_written;
4385 state->written += cc_copy_rsp.total_bytes_written;
4386 if (!state->splice_cb(state->written, state->priv)) {
4387 tevent_req_nterror(req, NT_STATUS_CANCELLED);
4388 return;
4389 }
4390 }
4391
4392 cli_splice_copychunk_send(state, req);
4393 }
4394
cli_splice_copychunk_send(struct cli_smb2_splice_state * state,struct tevent_req * req)4395 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4396 struct tevent_req *req)
4397 {
4398 struct tevent_req *subreq;
4399 enum ndr_err_code ndr_ret;
4400 struct smbXcli_conn *conn = state->cli->conn;
4401 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
4402 off_t src_offset = state->src_offset;
4403 off_t dst_offset = state->dst_offset;
4404 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
4405 state->size - state->written);
4406 DATA_BLOB in_input_buffer = data_blob_null;
4407 DATA_BLOB in_output_buffer = data_blob_null;
4408
4409 if (state->size - state->written == 0) {
4410 tevent_req_done(req);
4411 return;
4412 }
4413
4414 cc_copy->chunk_count = 0;
4415 while (req_len) {
4416 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
4417 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
4418 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
4419 smb2cli_conn_cc_chunk_len(conn));
4420 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
4421 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4422 return;
4423 }
4424 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
4425 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
4426 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
4427 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4428 return;
4429 }
4430 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4431 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4432 cc_copy->chunk_count++;
4433 }
4434
4435 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
4436 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
4437 if (ndr_ret != NDR_ERR_SUCCESS) {
4438 DEBUG(0, ("failed to marshall copy chunk req\n"));
4439 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4440 return;
4441 }
4442
4443 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
4444 state->cli->timeout,
4445 state->cli->smb2.session,
4446 state->cli->smb2.tcon,
4447 state->dst_ph->fid_persistent, /* in_fid_persistent */
4448 state->dst_ph->fid_volatile, /* in_fid_volatile */
4449 FSCTL_SRV_COPYCHUNK_WRITE,
4450 0, /* in_max_input_length */
4451 &in_input_buffer,
4452 12, /* in_max_output_length */
4453 &in_output_buffer,
4454 SMB2_IOCTL_FLAG_IS_FSCTL);
4455 if (tevent_req_nomem(subreq, req)) {
4456 return;
4457 }
4458 tevent_req_set_callback(subreq,
4459 cli_splice_copychunk_done,
4460 req);
4461 }
4462
cli_splice_key_done(struct tevent_req * subreq)4463 static void cli_splice_key_done(struct tevent_req *subreq)
4464 {
4465 struct tevent_req *req = tevent_req_callback_data(
4466 subreq, struct tevent_req);
4467 struct cli_smb2_splice_state *state =
4468 tevent_req_data(req,
4469 struct cli_smb2_splice_state);
4470 enum ndr_err_code ndr_ret;
4471 NTSTATUS status;
4472
4473 DATA_BLOB out_input_buffer = data_blob_null;
4474 DATA_BLOB out_output_buffer = data_blob_null;
4475
4476 status = smb2cli_ioctl_recv(subreq, state,
4477 &out_input_buffer,
4478 &out_output_buffer);
4479 TALLOC_FREE(subreq);
4480 if (tevent_req_nterror(req, status)) {
4481 return;
4482 }
4483
4484 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
4485 state, &state->resume_rsp,
4486 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
4487 if (ndr_ret != NDR_ERR_SUCCESS) {
4488 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
4489 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4490 return;
4491 }
4492
4493 memcpy(&state->cc_copy.source_key,
4494 &state->resume_rsp.resume_key,
4495 sizeof state->resume_rsp.resume_key);
4496
4497 cli_splice_copychunk_send(state, req);
4498 }
4499
cli_smb2_splice_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,uint16_t src_fnum,uint16_t dst_fnum,off_t size,off_t src_offset,off_t dst_offset,int (* splice_cb)(off_t n,void * priv),void * priv)4500 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
4501 struct tevent_context *ev,
4502 struct cli_state *cli,
4503 uint16_t src_fnum, uint16_t dst_fnum,
4504 off_t size, off_t src_offset, off_t dst_offset,
4505 int (*splice_cb)(off_t n, void *priv),
4506 void *priv)
4507 {
4508 struct tevent_req *req;
4509 struct tevent_req *subreq;
4510 struct cli_smb2_splice_state *state;
4511 NTSTATUS status;
4512 DATA_BLOB in_input_buffer = data_blob_null;
4513 DATA_BLOB in_output_buffer = data_blob_null;
4514
4515 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
4516 if (req == NULL) {
4517 return NULL;
4518 }
4519 state->cli = cli;
4520 state->ev = ev;
4521 state->splice_cb = splice_cb;
4522 state->priv = priv;
4523 state->size = size;
4524 state->written = 0;
4525 state->src_offset = src_offset;
4526 state->dst_offset = dst_offset;
4527 state->cc_copy.chunks = talloc_array(state,
4528 struct srv_copychunk,
4529 smb2cli_conn_cc_max_chunks(cli->conn));
4530 if (state->cc_copy.chunks == NULL) {
4531 return NULL;
4532 }
4533
4534 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
4535 if (tevent_req_nterror(req, status))
4536 return tevent_req_post(req, ev);
4537
4538 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
4539 if (tevent_req_nterror(req, status))
4540 return tevent_req_post(req, ev);
4541
4542 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
4543 cli->timeout,
4544 cli->smb2.session,
4545 cli->smb2.tcon,
4546 state->src_ph->fid_persistent, /* in_fid_persistent */
4547 state->src_ph->fid_volatile, /* in_fid_volatile */
4548 FSCTL_SRV_REQUEST_RESUME_KEY,
4549 0, /* in_max_input_length */
4550 &in_input_buffer,
4551 32, /* in_max_output_length */
4552 &in_output_buffer,
4553 SMB2_IOCTL_FLAG_IS_FSCTL);
4554 if (tevent_req_nomem(subreq, req)) {
4555 return NULL;
4556 }
4557 tevent_req_set_callback(subreq,
4558 cli_splice_key_done,
4559 req);
4560
4561 return req;
4562 }
4563
cli_smb2_splice_recv(struct tevent_req * req,off_t * written)4564 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
4565 {
4566 struct cli_smb2_splice_state *state = tevent_req_data(
4567 req, struct cli_smb2_splice_state);
4568 NTSTATUS status;
4569
4570 if (tevent_req_is_nterror(req, &status)) {
4571 state->cli->raw_status = status;
4572 tevent_req_received(req);
4573 return status;
4574 }
4575 if (written != NULL) {
4576 *written = state->written;
4577 }
4578 state->cli->raw_status = NT_STATUS_OK;
4579 tevent_req_received(req);
4580 return NT_STATUS_OK;
4581 }
4582
4583 /***************************************************************
4584 SMB2 enum shadow copy data.
4585 ***************************************************************/
4586
4587 struct cli_smb2_shadow_copy_data_fnum_state {
4588 struct cli_state *cli;
4589 uint16_t fnum;
4590 struct smb2_hnd *ph;
4591 DATA_BLOB out_input_buffer;
4592 DATA_BLOB out_output_buffer;
4593 };
4594
4595 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
4596
cli_smb2_shadow_copy_data_fnum_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,uint16_t fnum,bool get_names)4597 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
4598 TALLOC_CTX *mem_ctx,
4599 struct tevent_context *ev,
4600 struct cli_state *cli,
4601 uint16_t fnum,
4602 bool get_names)
4603 {
4604 struct tevent_req *req, *subreq;
4605 struct cli_smb2_shadow_copy_data_fnum_state *state;
4606 NTSTATUS status;
4607
4608 req = tevent_req_create(mem_ctx, &state,
4609 struct cli_smb2_shadow_copy_data_fnum_state);
4610 if (req == NULL) {
4611 return NULL;
4612 }
4613
4614 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4615 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4616 return tevent_req_post(req, ev);
4617 }
4618
4619 state->cli = cli;
4620 state->fnum = fnum;
4621
4622 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4623 if (tevent_req_nterror(req, status)) {
4624 return tevent_req_post(req, ev);
4625 }
4626
4627 /*
4628 * TODO. Under SMB2 we should send a zero max_output_length
4629 * ioctl to get the required size, then send another ioctl
4630 * to get the data, but the current SMB1 implementation just
4631 * does one roundtrip with a 64K buffer size. Do the same
4632 * for now. JRA.
4633 */
4634
4635 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4636 state->cli->timeout,
4637 state->cli->smb2.session,
4638 state->cli->smb2.tcon,
4639 state->ph->fid_persistent, /* in_fid_persistent */
4640 state->ph->fid_volatile, /* in_fid_volatile */
4641 FSCTL_GET_SHADOW_COPY_DATA,
4642 0, /* in_max_input_length */
4643 NULL, /* in_input_buffer */
4644 get_names ?
4645 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
4646 NULL, /* in_output_buffer */
4647 SMB2_IOCTL_FLAG_IS_FSCTL);
4648
4649 if (tevent_req_nomem(subreq, req)) {
4650 return tevent_req_post(req, ev);
4651 }
4652 tevent_req_set_callback(subreq,
4653 cli_smb2_shadow_copy_data_fnum_done,
4654 req);
4655
4656 return req;
4657 }
4658
cli_smb2_shadow_copy_data_fnum_done(struct tevent_req * subreq)4659 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
4660 {
4661 struct tevent_req *req = tevent_req_callback_data(
4662 subreq, struct tevent_req);
4663 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4664 req, struct cli_smb2_shadow_copy_data_fnum_state);
4665 NTSTATUS status;
4666
4667 status = smb2cli_ioctl_recv(subreq, state,
4668 &state->out_input_buffer,
4669 &state->out_output_buffer);
4670 tevent_req_simple_finish_ntstatus(subreq, status);
4671 }
4672
cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req * req,TALLOC_CTX * mem_ctx,bool get_names,char *** pnames,int * pnum_names)4673 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
4674 TALLOC_CTX *mem_ctx,
4675 bool get_names,
4676 char ***pnames,
4677 int *pnum_names)
4678 {
4679 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4680 req, struct cli_smb2_shadow_copy_data_fnum_state);
4681 char **names = NULL;
4682 uint32_t num_names = 0;
4683 uint32_t num_names_returned = 0;
4684 uint32_t dlength = 0;
4685 uint32_t i;
4686 uint8_t *endp = NULL;
4687 NTSTATUS status;
4688
4689 if (tevent_req_is_nterror(req, &status)) {
4690 return status;
4691 }
4692
4693 if (state->out_output_buffer.length < 16) {
4694 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4695 }
4696
4697 num_names = IVAL(state->out_output_buffer.data, 0);
4698 num_names_returned = IVAL(state->out_output_buffer.data, 4);
4699 dlength = IVAL(state->out_output_buffer.data, 8);
4700
4701 if (num_names > 0x7FFFFFFF) {
4702 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4703 }
4704
4705 if (get_names == false) {
4706 *pnum_names = (int)num_names;
4707 return NT_STATUS_OK;
4708 }
4709 if (num_names != num_names_returned) {
4710 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4711 }
4712 if (dlength + 12 < 12) {
4713 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4714 }
4715 /*
4716 * NB. The below is an allowable return if there are
4717 * more snapshots than the buffer size we told the
4718 * server we can receive. We currently don't support
4719 * this.
4720 */
4721 if (dlength + 12 > state->out_output_buffer.length) {
4722 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4723 }
4724 if (state->out_output_buffer.length +
4725 (2 * sizeof(SHADOW_COPY_LABEL)) <
4726 state->out_output_buffer.length) {
4727 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4728 }
4729
4730 names = talloc_array(mem_ctx, char *, num_names_returned);
4731 if (names == NULL) {
4732 return NT_STATUS_NO_MEMORY;
4733 }
4734
4735 endp = state->out_output_buffer.data +
4736 state->out_output_buffer.length;
4737
4738 for (i=0; i<num_names_returned; i++) {
4739 bool ret;
4740 uint8_t *src;
4741 size_t converted_size;
4742
4743 src = state->out_output_buffer.data + 12 +
4744 (i * 2 * sizeof(SHADOW_COPY_LABEL));
4745
4746 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
4747 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4748 }
4749 ret = convert_string_talloc(
4750 names, CH_UTF16LE, CH_UNIX,
4751 src, 2 * sizeof(SHADOW_COPY_LABEL),
4752 &names[i], &converted_size);
4753 if (!ret) {
4754 TALLOC_FREE(names);
4755 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4756 }
4757 }
4758 *pnum_names = num_names;
4759 *pnames = names;
4760 return NT_STATUS_OK;
4761 }
4762
cli_smb2_shadow_copy_data(TALLOC_CTX * mem_ctx,struct cli_state * cli,uint16_t fnum,bool get_names,char *** pnames,int * pnum_names)4763 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
4764 struct cli_state *cli,
4765 uint16_t fnum,
4766 bool get_names,
4767 char ***pnames,
4768 int *pnum_names)
4769 {
4770 TALLOC_CTX *frame = talloc_stackframe();
4771 struct tevent_context *ev;
4772 struct tevent_req *req;
4773 NTSTATUS status = NT_STATUS_NO_MEMORY;
4774
4775 if (smbXcli_conn_has_async_calls(cli->conn)) {
4776 /*
4777 * Can't use sync call while an async call is in flight
4778 */
4779 status = NT_STATUS_INVALID_PARAMETER;
4780 goto fail;
4781 }
4782 ev = samba_tevent_context_init(frame);
4783 if (ev == NULL) {
4784 goto fail;
4785 }
4786 req = cli_smb2_shadow_copy_data_fnum_send(frame,
4787 ev,
4788 cli,
4789 fnum,
4790 get_names);
4791 if (req == NULL) {
4792 goto fail;
4793 }
4794 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4795 goto fail;
4796 }
4797 status = cli_smb2_shadow_copy_data_fnum_recv(req,
4798 mem_ctx,
4799 get_names,
4800 pnames,
4801 pnum_names);
4802 fail:
4803 cli->raw_status = status;
4804
4805 TALLOC_FREE(frame);
4806 return status;
4807 }
4808
4809 /***************************************************************
4810 Wrapper that allows SMB2 to truncate a file.
4811 Synchronous only.
4812 ***************************************************************/
4813
cli_smb2_ftruncate(struct cli_state * cli,uint16_t fnum,uint64_t newsize)4814 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4815 uint16_t fnum,
4816 uint64_t newsize)
4817 {
4818 NTSTATUS status;
4819 uint8_t buf[8] = {0};
4820 DATA_BLOB inbuf = { .data = buf, .length = sizeof(buf) };
4821 TALLOC_CTX *frame = talloc_stackframe();
4822
4823 if (smbXcli_conn_has_async_calls(cli->conn)) {
4824 /*
4825 * Can't use sync call while an async call is in flight
4826 */
4827 status = NT_STATUS_INVALID_PARAMETER;
4828 goto fail;
4829 }
4830
4831 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4832 status = NT_STATUS_INVALID_PARAMETER;
4833 goto fail;
4834 }
4835
4836 SBVAL(buf, 0, newsize);
4837
4838 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4839 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4840
4841 status = cli_smb2_set_info_fnum(
4842 cli,
4843 fnum,
4844 1, /* in_info_type */
4845 SMB_FILE_END_OF_FILE_INFORMATION-1000, /* in_file_info_class */
4846 &inbuf, /* in_input_buffer */
4847 0);
4848
4849 fail:
4850
4851 cli->raw_status = status;
4852
4853 TALLOC_FREE(frame);
4854 return status;
4855 }
4856
4857 struct cli_smb2_notify_state {
4858 struct tevent_req *subreq;
4859 struct notify_change *changes;
4860 size_t num_changes;
4861 };
4862
4863 static void cli_smb2_notify_done(struct tevent_req *subreq);
4864 static bool cli_smb2_notify_cancel(struct tevent_req *req);
4865
cli_smb2_notify_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,uint16_t fnum,uint32_t buffer_size,uint32_t completion_filter,bool recursive)4866 struct tevent_req *cli_smb2_notify_send(
4867 TALLOC_CTX *mem_ctx,
4868 struct tevent_context *ev,
4869 struct cli_state *cli,
4870 uint16_t fnum,
4871 uint32_t buffer_size,
4872 uint32_t completion_filter,
4873 bool recursive)
4874 {
4875 struct tevent_req *req = NULL;
4876 struct cli_smb2_notify_state *state = NULL;
4877 struct smb2_hnd *ph = NULL;
4878 NTSTATUS status;
4879
4880 req = tevent_req_create(mem_ctx, &state,
4881 struct cli_smb2_notify_state);
4882 if (req == NULL) {
4883 return NULL;
4884 }
4885
4886 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4887 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4888 return tevent_req_post(req, ev);
4889 }
4890
4891 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4892 if (tevent_req_nterror(req, status)) {
4893 return tevent_req_post(req, ev);
4894 }
4895
4896 state->subreq = smb2cli_notify_send(
4897 state,
4898 ev,
4899 cli->conn,
4900 cli->timeout,
4901 cli->smb2.session,
4902 cli->smb2.tcon,
4903 buffer_size,
4904 ph->fid_persistent,
4905 ph->fid_volatile,
4906 completion_filter,
4907 recursive);
4908 if (tevent_req_nomem(state->subreq, req)) {
4909 return tevent_req_post(req, ev);
4910 }
4911 tevent_req_set_callback(state->subreq, cli_smb2_notify_done, req);
4912 tevent_req_set_cancel_fn(req, cli_smb2_notify_cancel);
4913 return req;
4914 }
4915
cli_smb2_notify_cancel(struct tevent_req * req)4916 static bool cli_smb2_notify_cancel(struct tevent_req *req)
4917 {
4918 struct cli_smb2_notify_state *state = tevent_req_data(
4919 req, struct cli_smb2_notify_state);
4920 bool ok;
4921
4922 ok = tevent_req_cancel(state->subreq);
4923 return ok;
4924 }
4925
cli_smb2_notify_done(struct tevent_req * subreq)4926 static void cli_smb2_notify_done(struct tevent_req *subreq)
4927 {
4928 struct tevent_req *req = tevent_req_callback_data(
4929 subreq, struct tevent_req);
4930 struct cli_smb2_notify_state *state = tevent_req_data(
4931 req, struct cli_smb2_notify_state);
4932 uint8_t *base;
4933 uint32_t len;
4934 uint32_t ofs;
4935 NTSTATUS status;
4936
4937 status = smb2cli_notify_recv(subreq, state, &base, &len);
4938 TALLOC_FREE(subreq);
4939
4940 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
4941 tevent_req_done(req);
4942 return;
4943 }
4944 if (tevent_req_nterror(req, status)) {
4945 return;
4946 }
4947
4948 ofs = 0;
4949
4950 while (len - ofs >= 12) {
4951 struct notify_change *tmp;
4952 struct notify_change *c;
4953 uint32_t next_ofs = IVAL(base, ofs);
4954 uint32_t file_name_length = IVAL(base, ofs+8);
4955 size_t namelen;
4956 bool ok;
4957
4958 tmp = talloc_realloc(
4959 state,
4960 state->changes,
4961 struct notify_change,
4962 state->num_changes + 1);
4963 if (tevent_req_nomem(tmp, req)) {
4964 return;
4965 }
4966 state->changes = tmp;
4967 c = &state->changes[state->num_changes];
4968 state->num_changes += 1;
4969
4970 if (smb_buffer_oob(len, ofs, next_ofs) ||
4971 smb_buffer_oob(len, ofs+12, file_name_length)) {
4972 tevent_req_nterror(
4973 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4974 return;
4975 }
4976
4977 c->action = IVAL(base, ofs+4);
4978
4979 ok = convert_string_talloc(
4980 state->changes,
4981 CH_UTF16LE,
4982 CH_UNIX,
4983 base + ofs + 12,
4984 file_name_length,
4985 &c->name,
4986 &namelen);
4987 if (!ok) {
4988 tevent_req_nterror(
4989 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4990 return;
4991 }
4992
4993 if (next_ofs == 0) {
4994 break;
4995 }
4996 ofs += next_ofs;
4997 }
4998
4999 tevent_req_done(req);
5000 }
5001
cli_smb2_notify_recv(struct tevent_req * req,TALLOC_CTX * mem_ctx,struct notify_change ** pchanges,uint32_t * pnum_changes)5002 NTSTATUS cli_smb2_notify_recv(struct tevent_req *req,
5003 TALLOC_CTX *mem_ctx,
5004 struct notify_change **pchanges,
5005 uint32_t *pnum_changes)
5006 {
5007 struct cli_smb2_notify_state *state = tevent_req_data(
5008 req, struct cli_smb2_notify_state);
5009 NTSTATUS status;
5010
5011 if (tevent_req_is_nterror(req, &status)) {
5012 return status;
5013 }
5014 *pchanges = talloc_move(mem_ctx, &state->changes);
5015 *pnum_changes = state->num_changes;
5016 return NT_STATUS_OK;
5017 }
5018
cli_smb2_notify(struct cli_state * cli,uint16_t fnum,uint32_t buffer_size,uint32_t completion_filter,bool recursive,TALLOC_CTX * mem_ctx,struct notify_change ** pchanges,uint32_t * pnum_changes)5019 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
5020 uint32_t buffer_size, uint32_t completion_filter,
5021 bool recursive, TALLOC_CTX *mem_ctx,
5022 struct notify_change **pchanges,
5023 uint32_t *pnum_changes)
5024 {
5025 TALLOC_CTX *frame = talloc_stackframe();
5026 struct tevent_context *ev;
5027 struct tevent_req *req;
5028 NTSTATUS status = NT_STATUS_NO_MEMORY;
5029
5030 if (smbXcli_conn_has_async_calls(cli->conn)) {
5031 /*
5032 * Can't use sync call while an async call is in flight
5033 */
5034 status = NT_STATUS_INVALID_PARAMETER;
5035 goto fail;
5036 }
5037 ev = samba_tevent_context_init(frame);
5038 if (ev == NULL) {
5039 goto fail;
5040 }
5041 req = cli_smb2_notify_send(
5042 frame,
5043 ev,
5044 cli,
5045 fnum,
5046 buffer_size,
5047 completion_filter,
5048 recursive);
5049 if (req == NULL) {
5050 goto fail;
5051 }
5052 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5053 goto fail;
5054 }
5055 status = cli_smb2_notify_recv(req, mem_ctx, pchanges, pnum_changes);
5056 fail:
5057 TALLOC_FREE(frame);
5058 return status;
5059 }
5060
5061 struct cli_smb2_set_reparse_point_fnum_state {
5062 struct cli_state *cli;
5063 uint16_t fnum;
5064 struct smb2_hnd *ph;
5065 DATA_BLOB input_buffer;
5066 };
5067
5068 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq);
5069
cli_smb2_set_reparse_point_fnum_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,uint16_t fnum,DATA_BLOB in_buf)5070 struct tevent_req *cli_smb2_set_reparse_point_fnum_send(
5071 TALLOC_CTX *mem_ctx,
5072 struct tevent_context *ev,
5073 struct cli_state *cli,
5074 uint16_t fnum,
5075 DATA_BLOB in_buf)
5076 {
5077 struct tevent_req *req, *subreq;
5078 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
5079 NTSTATUS status;
5080
5081 req = tevent_req_create(mem_ctx, &state,
5082 struct cli_smb2_set_reparse_point_fnum_state);
5083 if (req == NULL) {
5084 return NULL;
5085 }
5086
5087 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5088 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
5089 return tevent_req_post(req, ev);
5090 }
5091
5092 state->cli = cli;
5093 state->fnum = fnum;
5094
5095 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
5096 if (tevent_req_nterror(req, status)) {
5097 return tevent_req_post(req, ev);
5098 }
5099
5100 state->input_buffer = data_blob_talloc(state,
5101 in_buf.data,
5102 in_buf.length);
5103 if (state->input_buffer.data == NULL) {
5104 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
5105 return tevent_req_post(req, ev);
5106 }
5107
5108 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
5109 state->cli->timeout,
5110 state->cli->smb2.session,
5111 state->cli->smb2.tcon,
5112 state->ph->fid_persistent, /* in_fid_persistent */
5113 state->ph->fid_volatile, /* in_fid_volatile */
5114 FSCTL_SET_REPARSE_POINT,
5115 0, /* in_max_input_length */
5116 &state->input_buffer ,
5117 0,
5118 NULL,
5119 SMB2_IOCTL_FLAG_IS_FSCTL);
5120
5121 if (tevent_req_nomem(subreq, req)) {
5122 return tevent_req_post(req, ev);
5123 }
5124 tevent_req_set_callback(subreq,
5125 cli_smb2_set_reparse_point_fnum_done,
5126 req);
5127
5128 return req;
5129 }
5130
cli_smb2_set_reparse_point_fnum_done(struct tevent_req * subreq)5131 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq)
5132 {
5133 struct tevent_req *req = tevent_req_callback_data(
5134 subreq, struct tevent_req);
5135 struct cli_smb2_set_reparse_point_fnum_state *state = tevent_req_data(
5136 req, struct cli_smb2_set_reparse_point_fnum_state);
5137 NTSTATUS status;
5138
5139 status = smb2cli_ioctl_recv(subreq, state,
5140 NULL,
5141 NULL);
5142 TALLOC_FREE(subreq);
5143 if (tevent_req_nterror(req, status)) {
5144 return;
5145 }
5146 tevent_req_done(req);
5147 }
5148
cli_smb2_set_reparse_point_fnum_recv(struct tevent_req * req)5149 NTSTATUS cli_smb2_set_reparse_point_fnum_recv(struct tevent_req *req)
5150 {
5151 return tevent_req_simple_recv_ntstatus(req);
5152 }
5153
5154 struct cli_smb2_get_reparse_point_fnum_state {
5155 struct cli_state *cli;
5156 uint16_t fnum;
5157 struct smb2_hnd *ph;
5158 DATA_BLOB output_buffer;
5159 };
5160
5161 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq);
5162
cli_smb2_get_reparse_point_fnum_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,uint16_t fnum)5163 struct tevent_req *cli_smb2_get_reparse_point_fnum_send(
5164 TALLOC_CTX *mem_ctx,
5165 struct tevent_context *ev,
5166 struct cli_state *cli,
5167 uint16_t fnum)
5168 {
5169 struct tevent_req *req, *subreq;
5170 struct cli_smb2_get_reparse_point_fnum_state *state = NULL;
5171 NTSTATUS status;
5172
5173 req = tevent_req_create(mem_ctx, &state,
5174 struct cli_smb2_get_reparse_point_fnum_state);
5175 if (req == NULL) {
5176 return NULL;
5177 }
5178
5179 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5180 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
5181 return tevent_req_post(req, ev);
5182 }
5183
5184 state->cli = cli;
5185 state->fnum = fnum;
5186
5187 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
5188 if (tevent_req_nterror(req, status)) {
5189 return tevent_req_post(req, ev);
5190 }
5191
5192 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
5193 state->cli->timeout,
5194 state->cli->smb2.session,
5195 state->cli->smb2.tcon,
5196 state->ph->fid_persistent, /* in_fid_persistent */
5197 state->ph->fid_volatile, /* in_fid_volatile */
5198 FSCTL_GET_REPARSE_POINT,
5199 0, /* in_max_input_length */
5200 NULL,
5201 64*1024,
5202 NULL,
5203 SMB2_IOCTL_FLAG_IS_FSCTL);
5204
5205 if (tevent_req_nomem(subreq, req)) {
5206 return tevent_req_post(req, ev);
5207 }
5208 tevent_req_set_callback(subreq,
5209 cli_smb2_get_reparse_point_fnum_done,
5210 req);
5211
5212 return req;
5213 }
5214
cli_smb2_get_reparse_point_fnum_done(struct tevent_req * subreq)5215 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq)
5216 {
5217 struct tevent_req *req = tevent_req_callback_data(
5218 subreq, struct tevent_req);
5219 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
5220 req, struct cli_smb2_get_reparse_point_fnum_state);
5221 struct cli_state *cli = state->cli;
5222 NTSTATUS status;
5223
5224 status = smb2cli_ioctl_recv(subreq, state,
5225 NULL,
5226 &state->output_buffer);
5227 TALLOC_FREE(subreq);
5228 if (tevent_req_nterror(req, status)) {
5229 cli->raw_status = status;
5230 return;
5231 }
5232 tevent_req_done(req);
5233 }
5234
cli_smb2_get_reparse_point_fnum_recv(struct tevent_req * req,TALLOC_CTX * mem_ctx,DATA_BLOB * output)5235 NTSTATUS cli_smb2_get_reparse_point_fnum_recv(struct tevent_req *req,
5236 TALLOC_CTX *mem_ctx,
5237 DATA_BLOB *output)
5238 {
5239 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
5240 req, struct cli_smb2_get_reparse_point_fnum_state);
5241
5242 if (tevent_req_is_nterror(req, &state->cli->raw_status)) {
5243 NTSTATUS status = state->cli->raw_status;
5244 tevent_req_received(req);
5245 return status;
5246 }
5247 *output = data_blob_dup_talloc(mem_ctx, state->output_buffer);
5248 if (output->data == NULL) {
5249 tevent_req_received(req);
5250 return NT_STATUS_NO_MEMORY;
5251 }
5252 tevent_req_received(req);
5253 return NT_STATUS_OK;
5254 }
5255