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