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