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