Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : client file operations
4 : Copyright (C) Andrew Tridgell 1994-1998
5 : Copyright (C) Jeremy Allison 2001-2009
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "includes.h"
22 : #include "system/filesys.h"
23 : #include "libsmb/libsmb.h"
24 : #include "../lib/util/tevent_ntstatus.h"
25 : #include "async_smb.h"
26 : #include "libsmb/clirap.h"
27 : #include "trans2.h"
28 : #include "ntioctl.h"
29 : #include "libcli/security/security.h"
30 : #include "../libcli/smb/smbXcli_base.h"
31 :
32 : struct cli_setpathinfo_state {
33 : uint16_t setup;
34 : uint8_t *param;
35 : };
36 :
37 : static void cli_setpathinfo_done(struct tevent_req *subreq);
38 :
39 4 : struct tevent_req *cli_setpathinfo_send(TALLOC_CTX *mem_ctx,
40 : struct tevent_context *ev,
41 : struct cli_state *cli,
42 : uint16_t level,
43 : const char *path,
44 : uint8_t *data,
45 : size_t data_len)
46 : {
47 : struct tevent_req *req, *subreq;
48 : struct cli_setpathinfo_state *state;
49 4 : uint16_t additional_flags2 = 0;
50 4 : char *path_cp = NULL;
51 :
52 4 : req = tevent_req_create(mem_ctx, &state,
53 : struct cli_setpathinfo_state);
54 4 : if (req == NULL) {
55 0 : return NULL;
56 : }
57 :
58 : /* Setup setup word. */
59 4 : SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
60 :
61 : /* Setup param array. */
62 4 : state->param = talloc_zero_array(state, uint8_t, 6);
63 4 : if (tevent_req_nomem(state->param, req)) {
64 0 : return tevent_req_post(req, ev);
65 : }
66 4 : SSVAL(state->param, 0, level);
67 :
68 : /* Check for DFS. */
69 4 : path_cp = smb1_dfs_share_path(state, cli, path);
70 4 : if (tevent_req_nomem(path_cp, req)) {
71 0 : return tevent_req_post(req, ev);
72 : }
73 4 : state->param = trans2_bytes_push_str(state->param,
74 4 : smbXcli_conn_use_unicode(cli->conn),
75 : path_cp,
76 4 : strlen(path_cp)+1,
77 : NULL);
78 4 : if (tevent_req_nomem(state->param, req)) {
79 0 : return tevent_req_post(req, ev);
80 : }
81 :
82 4 : if (clistr_is_previous_version_path(path) &&
83 0 : !INFO_LEVEL_IS_UNIX(level)) {
84 0 : additional_flags2 = FLAGS2_REPARSE_PATH;
85 : }
86 :
87 8 : subreq = cli_trans_send(
88 : state, /* mem ctx. */
89 : ev, /* event ctx. */
90 : cli, /* cli_state. */
91 : additional_flags2, /* additional_flags2 */
92 : SMBtrans2, /* cmd. */
93 : NULL, /* pipe name. */
94 : -1, /* fid. */
95 : 0, /* function. */
96 : 0, /* flags. */
97 4 : &state->setup, /* setup. */
98 : 1, /* num setup uint16_t words. */
99 : 0, /* max returned setup. */
100 4 : state->param, /* param. */
101 4 : talloc_get_size(state->param), /* num param. */
102 : 2, /* max returned param. */
103 : data, /* data. */
104 : data_len, /* num data. */
105 : 0); /* max returned data. */
106 :
107 4 : if (tevent_req_nomem(subreq, req)) {
108 0 : return tevent_req_post(req, ev);
109 : }
110 4 : tevent_req_set_callback(subreq, cli_setpathinfo_done, req);
111 4 : return req;
112 : }
113 :
114 4 : static void cli_setpathinfo_done(struct tevent_req *subreq)
115 : {
116 4 : NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
117 : NULL, 0, NULL, NULL, 0, NULL);
118 4 : tevent_req_simple_finish_ntstatus(subreq, status);
119 4 : }
120 :
121 4 : NTSTATUS cli_setpathinfo_recv(struct tevent_req *req)
122 : {
123 4 : return tevent_req_simple_recv_ntstatus(req);
124 : }
125 :
126 4 : NTSTATUS cli_setpathinfo(struct cli_state *cli,
127 : uint16_t level,
128 : const char *path,
129 : uint8_t *data,
130 : size_t data_len)
131 : {
132 4 : TALLOC_CTX *frame = talloc_stackframe();
133 : struct tevent_context *ev;
134 : struct tevent_req *req;
135 4 : NTSTATUS status = NT_STATUS_NO_MEMORY;
136 :
137 4 : if (smbXcli_conn_has_async_calls(cli->conn)) {
138 : /*
139 : * Can't use sync call while an async call is in flight
140 : */
141 0 : status = NT_STATUS_INVALID_PARAMETER;
142 0 : goto fail;
143 : }
144 4 : ev = samba_tevent_context_init(frame);
145 4 : if (ev == NULL) {
146 0 : goto fail;
147 : }
148 4 : req = cli_setpathinfo_send(ev, ev, cli, level, path, data, data_len);
149 4 : if (req == NULL) {
150 0 : goto fail;
151 : }
152 4 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
153 0 : goto fail;
154 : }
155 4 : status = cli_setpathinfo_recv(req);
156 4 : fail:
157 4 : TALLOC_FREE(frame);
158 4 : return status;
159 : }
160 :
161 : struct cli_setfileinfo_state {
162 : uint16_t setup;
163 : uint8_t param[6];
164 : };
165 :
166 : static void cli_setfileinfo_done(struct tevent_req *subreq);
167 :
168 10 : struct tevent_req *cli_setfileinfo_send(
169 : TALLOC_CTX *mem_ctx,
170 : struct tevent_context *ev,
171 : struct cli_state *cli,
172 : uint16_t fnum,
173 : uint16_t level,
174 : uint8_t *data,
175 : size_t data_len)
176 : {
177 10 : struct tevent_req *req = NULL, *subreq = NULL;
178 10 : struct cli_setfileinfo_state *state = NULL;
179 :
180 10 : req = tevent_req_create(mem_ctx, &state, struct cli_setfileinfo_state);
181 10 : if (req == NULL) {
182 0 : return NULL;
183 : }
184 10 : PUSH_LE_U16(&state->setup, 0, TRANSACT2_SETFILEINFO);
185 :
186 10 : PUSH_LE_U16(state->param, 0, fnum);
187 10 : PUSH_LE_U16(state->param, 2, level);
188 :
189 10 : subreq = cli_trans_send(state, /* mem ctx. */
190 : ev, /* event ctx. */
191 : cli, /* cli_state. */
192 : 0, /* additional_flags2 */
193 : SMBtrans2, /* cmd. */
194 : NULL, /* pipe name. */
195 : -1, /* fid. */
196 : 0, /* function. */
197 : 0, /* flags. */
198 10 : &state->setup, /* setup. */
199 : 1, /* num setup uint16_t words. */
200 : 0, /* max returned setup. */
201 10 : state->param, /* param. */
202 : 6, /* num param. */
203 : 2, /* max returned param. */
204 : data, /* data. */
205 : data_len, /* num data. */
206 : 0); /* max returned data. */
207 :
208 10 : if (tevent_req_nomem(subreq, req)) {
209 0 : return tevent_req_post(req, ev);
210 : }
211 10 : tevent_req_set_callback(subreq, cli_setfileinfo_done, req);
212 10 : return req;
213 : }
214 :
215 10 : static void cli_setfileinfo_done(struct tevent_req *subreq)
216 : {
217 10 : NTSTATUS status = cli_trans_recv(
218 : subreq, /* req */
219 : NULL, /* mem_ctx */
220 : NULL, /* recv_flags2 */
221 : NULL, /* setup */
222 : 0, /* min_setup */
223 : NULL, /* num_setup */
224 : NULL, /* param */
225 : 0, /* min_param */
226 : NULL, /* num_param */
227 : NULL, /* data */
228 : 0, /* min_data */
229 : NULL); /* num_data */
230 10 : tevent_req_simple_finish_ntstatus(subreq, status);
231 10 : }
232 :
233 10 : NTSTATUS cli_setfileinfo_recv(struct tevent_req *req)
234 : {
235 10 : return tevent_req_simple_recv_ntstatus(req);
236 : }
237 :
238 : /****************************************************************************
239 : Hard/Symlink a file (UNIX extensions).
240 : Creates new name (sym)linked to link_target.
241 : ****************************************************************************/
242 :
243 : struct cli_posix_link_internal_state {
244 : uint8_t *data;
245 : };
246 :
247 : static void cli_posix_link_internal_done(struct tevent_req *subreq);
248 :
249 0 : static struct tevent_req *cli_posix_link_internal_send(TALLOC_CTX *mem_ctx,
250 : struct tevent_context *ev,
251 : struct cli_state *cli,
252 : uint16_t level,
253 : const char *link_target,
254 : const char *newname)
255 : {
256 0 : struct tevent_req *req = NULL, *subreq = NULL;
257 0 : struct cli_posix_link_internal_state *state = NULL;
258 :
259 0 : req = tevent_req_create(mem_ctx, &state,
260 : struct cli_posix_link_internal_state);
261 0 : if (req == NULL) {
262 0 : return NULL;
263 : }
264 :
265 : /* Setup data array. */
266 0 : state->data = talloc_array(state, uint8_t, 0);
267 0 : if (tevent_req_nomem(state->data, req)) {
268 0 : return tevent_req_post(req, ev);
269 : }
270 0 : state->data = trans2_bytes_push_str(
271 0 : state->data, smbXcli_conn_use_unicode(cli->conn),
272 0 : link_target, strlen(link_target)+1, NULL);
273 :
274 0 : subreq = cli_setpathinfo_send(
275 : state, ev, cli, level, newname,
276 0 : state->data, talloc_get_size(state->data));
277 0 : if (tevent_req_nomem(subreq, req)) {
278 0 : return tevent_req_post(req, ev);
279 : }
280 0 : tevent_req_set_callback(subreq, cli_posix_link_internal_done, req);
281 0 : return req;
282 : }
283 :
284 0 : static void cli_posix_link_internal_done(struct tevent_req *subreq)
285 : {
286 0 : NTSTATUS status = cli_setpathinfo_recv(subreq);
287 0 : tevent_req_simple_finish_ntstatus(subreq, status);
288 0 : }
289 :
290 0 : static NTSTATUS cli_posix_link_internal_recv(struct tevent_req *req)
291 : {
292 0 : return tevent_req_simple_recv_ntstatus(req);
293 : }
294 :
295 : /****************************************************************************
296 : Symlink a file (UNIX extensions).
297 : ****************************************************************************/
298 :
299 : struct cli_posix_symlink_state {
300 : uint8_t dummy;
301 : };
302 :
303 : static void cli_posix_symlink_done(struct tevent_req *subreq);
304 :
305 0 : struct tevent_req *cli_posix_symlink_send(TALLOC_CTX *mem_ctx,
306 : struct tevent_context *ev,
307 : struct cli_state *cli,
308 : const char *link_target,
309 : const char *newname)
310 : {
311 0 : struct tevent_req *req = NULL, *subreq = NULL;
312 0 : struct cli_posix_symlink_state *state = NULL;
313 :
314 0 : req = tevent_req_create(
315 : mem_ctx, &state, struct cli_posix_symlink_state);
316 0 : if (req == NULL) {
317 0 : return NULL;
318 : }
319 :
320 0 : subreq = cli_posix_link_internal_send(
321 : mem_ctx, ev, cli, SMB_SET_FILE_UNIX_LINK, link_target, newname);
322 0 : if (tevent_req_nomem(subreq, req)) {
323 0 : return tevent_req_post(req, ev);
324 : }
325 0 : tevent_req_set_callback(subreq, cli_posix_symlink_done, req);
326 0 : return req;
327 : }
328 :
329 0 : static void cli_posix_symlink_done(struct tevent_req *subreq)
330 : {
331 0 : NTSTATUS status = cli_posix_link_internal_recv(subreq);
332 0 : tevent_req_simple_finish_ntstatus(subreq, status);
333 0 : }
334 :
335 0 : NTSTATUS cli_posix_symlink_recv(struct tevent_req *req)
336 : {
337 0 : return tevent_req_simple_recv_ntstatus(req);
338 : }
339 :
340 0 : NTSTATUS cli_posix_symlink(struct cli_state *cli,
341 : const char *link_target,
342 : const char *newname)
343 : {
344 0 : TALLOC_CTX *frame = talloc_stackframe();
345 0 : struct tevent_context *ev = NULL;
346 0 : struct tevent_req *req = NULL;
347 0 : NTSTATUS status = NT_STATUS_OK;
348 :
349 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
350 : /*
351 : * Can't use sync call while an async call is in flight
352 : */
353 0 : status = NT_STATUS_INVALID_PARAMETER;
354 0 : goto fail;
355 : }
356 :
357 0 : ev = samba_tevent_context_init(frame);
358 0 : if (ev == NULL) {
359 0 : status = NT_STATUS_NO_MEMORY;
360 0 : goto fail;
361 : }
362 :
363 0 : req = cli_posix_symlink_send(frame,
364 : ev,
365 : cli,
366 : link_target,
367 : newname);
368 0 : if (req == NULL) {
369 0 : status = NT_STATUS_NO_MEMORY;
370 0 : goto fail;
371 : }
372 :
373 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
374 0 : goto fail;
375 : }
376 :
377 0 : status = cli_posix_symlink_recv(req);
378 :
379 0 : fail:
380 0 : TALLOC_FREE(frame);
381 0 : return status;
382 : }
383 :
384 : /****************************************************************************
385 : Read a POSIX symlink.
386 : ****************************************************************************/
387 :
388 : struct cli_posix_readlink_state {
389 : struct cli_state *cli;
390 : char *converted;
391 : };
392 :
393 : static void cli_posix_readlink_done(struct tevent_req *subreq);
394 :
395 0 : struct tevent_req *cli_posix_readlink_send(TALLOC_CTX *mem_ctx,
396 : struct tevent_context *ev,
397 : struct cli_state *cli,
398 : const char *fname)
399 : {
400 0 : struct tevent_req *req = NULL, *subreq = NULL;
401 0 : struct cli_posix_readlink_state *state = NULL;
402 :
403 0 : req = tevent_req_create(
404 : mem_ctx, &state, struct cli_posix_readlink_state);
405 0 : if (req == NULL) {
406 0 : return NULL;
407 : }
408 0 : state->cli = cli;
409 :
410 0 : subreq = cli_qpathinfo_send(
411 : state,
412 : ev,
413 : cli,
414 : fname,
415 : SMB_QUERY_FILE_UNIX_LINK,
416 : 1,
417 : UINT16_MAX);
418 0 : if (tevent_req_nomem(subreq, req)) {
419 0 : return tevent_req_post(req, ev);
420 : }
421 0 : tevent_req_set_callback(subreq, cli_posix_readlink_done, req);
422 0 : return req;
423 : }
424 :
425 0 : static void cli_posix_readlink_done(struct tevent_req *subreq)
426 : {
427 0 : struct tevent_req *req = tevent_req_callback_data(
428 : subreq, struct tevent_req);
429 0 : struct cli_posix_readlink_state *state = tevent_req_data(
430 : req, struct cli_posix_readlink_state);
431 : NTSTATUS status;
432 0 : uint8_t *data = NULL;
433 0 : uint32_t num_data = 0;
434 : charset_t charset;
435 : size_t converted_size;
436 : bool ok;
437 :
438 0 : status = cli_qpathinfo_recv(subreq, state, &data, &num_data);
439 0 : TALLOC_FREE(subreq);
440 0 : if (tevent_req_nterror(req, status)) {
441 0 : return;
442 : }
443 : /*
444 : * num_data is > 1, we've given 1 as minimum to cli_qpathinfo_send
445 : */
446 0 : if (data == NULL || data[num_data-1] != '\0') {
447 0 : tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
448 0 : return;
449 : }
450 :
451 0 : charset = smbXcli_conn_use_unicode(state->cli->conn) ?
452 0 : CH_UTF16LE : CH_DOS;
453 :
454 : /* The returned data is a pushed string, not raw data. */
455 0 : ok = convert_string_talloc(
456 : state,
457 : charset,
458 : CH_UNIX,
459 : data,
460 : num_data,
461 0 : &state->converted,
462 : &converted_size);
463 0 : if (!ok) {
464 0 : tevent_req_oom(req);
465 0 : return;
466 : }
467 0 : tevent_req_done(req);
468 : }
469 :
470 0 : NTSTATUS cli_posix_readlink_recv(
471 : struct tevent_req *req, TALLOC_CTX *mem_ctx, char **target)
472 : {
473 0 : struct cli_posix_readlink_state *state = tevent_req_data(
474 : req, struct cli_posix_readlink_state);
475 : NTSTATUS status;
476 :
477 0 : if (tevent_req_is_nterror(req, &status)) {
478 0 : return status;
479 : }
480 0 : *target = talloc_move(mem_ctx, &state->converted);
481 0 : tevent_req_received(req);
482 0 : return NT_STATUS_OK;
483 : }
484 :
485 : /****************************************************************************
486 : Hard link a file (UNIX extensions).
487 : ****************************************************************************/
488 :
489 : struct cli_posix_hardlink_state {
490 : uint8_t dummy;
491 : };
492 :
493 : static void cli_posix_hardlink_done(struct tevent_req *subreq);
494 :
495 0 : struct tevent_req *cli_posix_hardlink_send(TALLOC_CTX *mem_ctx,
496 : struct tevent_context *ev,
497 : struct cli_state *cli,
498 : const char *oldname,
499 : const char *newname)
500 : {
501 0 : struct tevent_req *req = NULL, *subreq = NULL;
502 0 : struct cli_posix_hardlink_state *state = NULL;
503 :
504 0 : req = tevent_req_create(
505 : mem_ctx, &state, struct cli_posix_hardlink_state);
506 0 : if (req == NULL) {
507 0 : return NULL;
508 : }
509 :
510 0 : subreq = cli_posix_link_internal_send(
511 : state, ev, cli, SMB_SET_FILE_UNIX_HLINK, oldname, newname);
512 0 : if (tevent_req_nomem(subreq, req)) {
513 0 : return tevent_req_post(req, ev);
514 : }
515 0 : tevent_req_set_callback(subreq, cli_posix_hardlink_done, req);
516 0 : return req;
517 : }
518 :
519 0 : static void cli_posix_hardlink_done(struct tevent_req *subreq)
520 : {
521 0 : NTSTATUS status = cli_posix_link_internal_recv(subreq);
522 0 : tevent_req_simple_finish_ntstatus(subreq, status);
523 0 : }
524 :
525 0 : NTSTATUS cli_posix_hardlink_recv(struct tevent_req *req)
526 : {
527 0 : return tevent_req_simple_recv_ntstatus(req);
528 : }
529 :
530 0 : NTSTATUS cli_posix_hardlink(struct cli_state *cli,
531 : const char *oldname,
532 : const char *newname)
533 : {
534 0 : TALLOC_CTX *frame = talloc_stackframe();
535 0 : struct tevent_context *ev = NULL;
536 0 : struct tevent_req *req = NULL;
537 0 : NTSTATUS status = NT_STATUS_OK;
538 :
539 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
540 : /*
541 : * Can't use sync call while an async call is in flight
542 : */
543 0 : status = NT_STATUS_INVALID_PARAMETER;
544 0 : goto fail;
545 : }
546 :
547 0 : ev = samba_tevent_context_init(frame);
548 0 : if (ev == NULL) {
549 0 : status = NT_STATUS_NO_MEMORY;
550 0 : goto fail;
551 : }
552 :
553 0 : req = cli_posix_hardlink_send(frame,
554 : ev,
555 : cli,
556 : oldname,
557 : newname);
558 0 : if (req == NULL) {
559 0 : status = NT_STATUS_NO_MEMORY;
560 0 : goto fail;
561 : }
562 :
563 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
564 0 : goto fail;
565 : }
566 :
567 0 : status = cli_posix_hardlink_recv(req);
568 :
569 0 : fail:
570 0 : TALLOC_FREE(frame);
571 0 : return status;
572 : }
573 :
574 : /****************************************************************************
575 : Do a POSIX getacl - pathname based ACL get (UNIX extensions).
576 : ****************************************************************************/
577 :
578 : struct getacl_state {
579 : uint32_t num_data;
580 : uint8_t *data;
581 : };
582 :
583 : static void cli_posix_getacl_done(struct tevent_req *subreq);
584 :
585 0 : struct tevent_req *cli_posix_getacl_send(TALLOC_CTX *mem_ctx,
586 : struct tevent_context *ev,
587 : struct cli_state *cli,
588 : const char *fname)
589 : {
590 0 : struct tevent_req *req = NULL, *subreq = NULL;
591 0 : struct getacl_state *state = NULL;
592 :
593 0 : req = tevent_req_create(mem_ctx, &state, struct getacl_state);
594 0 : if (req == NULL) {
595 0 : return NULL;
596 : }
597 0 : subreq = cli_qpathinfo_send(state, ev, cli, fname, SMB_QUERY_POSIX_ACL,
598 : 0, CLI_BUFFER_SIZE);
599 0 : if (tevent_req_nomem(subreq, req)) {
600 0 : return tevent_req_post(req, ev);
601 : }
602 0 : tevent_req_set_callback(subreq, cli_posix_getacl_done, req);
603 0 : return req;
604 : }
605 :
606 0 : static void cli_posix_getacl_done(struct tevent_req *subreq)
607 : {
608 0 : struct tevent_req *req = tevent_req_callback_data(
609 : subreq, struct tevent_req);
610 0 : struct getacl_state *state = tevent_req_data(
611 : req, struct getacl_state);
612 : NTSTATUS status;
613 :
614 0 : status = cli_qpathinfo_recv(subreq, state, &state->data,
615 : &state->num_data);
616 0 : TALLOC_FREE(subreq);
617 0 : if (tevent_req_nterror(req, status)) {
618 0 : return;
619 : }
620 0 : tevent_req_done(req);
621 : }
622 :
623 0 : NTSTATUS cli_posix_getacl_recv(struct tevent_req *req,
624 : TALLOC_CTX *mem_ctx,
625 : size_t *prb_size,
626 : char **retbuf)
627 : {
628 0 : struct getacl_state *state = tevent_req_data(req, struct getacl_state);
629 : NTSTATUS status;
630 :
631 0 : if (tevent_req_is_nterror(req, &status)) {
632 0 : return status;
633 : }
634 0 : *prb_size = (size_t)state->num_data;
635 0 : *retbuf = (char *)talloc_move(mem_ctx, &state->data);
636 0 : return NT_STATUS_OK;
637 : }
638 :
639 0 : NTSTATUS cli_posix_getacl(struct cli_state *cli,
640 : const char *fname,
641 : TALLOC_CTX *mem_ctx,
642 : size_t *prb_size,
643 : char **retbuf)
644 : {
645 0 : TALLOC_CTX *frame = talloc_stackframe();
646 0 : struct tevent_context *ev = NULL;
647 0 : struct tevent_req *req = NULL;
648 0 : NTSTATUS status = NT_STATUS_OK;
649 :
650 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
651 : /*
652 : * Can't use sync call while an async call is in flight
653 : */
654 0 : status = NT_STATUS_INVALID_PARAMETER;
655 0 : goto fail;
656 : }
657 :
658 0 : ev = samba_tevent_context_init(frame);
659 0 : if (ev == NULL) {
660 0 : status = NT_STATUS_NO_MEMORY;
661 0 : goto fail;
662 : }
663 :
664 0 : req = cli_posix_getacl_send(frame,
665 : ev,
666 : cli,
667 : fname);
668 0 : if (req == NULL) {
669 0 : status = NT_STATUS_NO_MEMORY;
670 0 : goto fail;
671 : }
672 :
673 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
674 0 : goto fail;
675 : }
676 :
677 0 : status = cli_posix_getacl_recv(req, mem_ctx, prb_size, retbuf);
678 :
679 0 : fail:
680 0 : TALLOC_FREE(frame);
681 0 : return status;
682 : }
683 :
684 : /****************************************************************************
685 : Do a POSIX setacl - pathname based ACL set (UNIX extensions).
686 : ****************************************************************************/
687 :
688 : struct setacl_state {
689 : uint8_t *data;
690 : };
691 :
692 : static void cli_posix_setacl_done(struct tevent_req *subreq);
693 :
694 0 : struct tevent_req *cli_posix_setacl_send(TALLOC_CTX *mem_ctx,
695 : struct tevent_context *ev,
696 : struct cli_state *cli,
697 : const char *fname,
698 : const void *data,
699 : size_t num_data)
700 : {
701 0 : struct tevent_req *req = NULL, *subreq = NULL;
702 0 : struct setacl_state *state = NULL;
703 :
704 0 : req = tevent_req_create(mem_ctx, &state, struct setacl_state);
705 0 : if (req == NULL) {
706 0 : return NULL;
707 : }
708 0 : state->data = talloc_memdup(state, data, num_data);
709 0 : if (tevent_req_nomem(state->data, req)) {
710 0 : return tevent_req_post(req, ev);
711 : }
712 :
713 0 : subreq = cli_setpathinfo_send(state,
714 : ev,
715 : cli,
716 : SMB_SET_POSIX_ACL,
717 : fname,
718 0 : state->data,
719 : num_data);
720 0 : if (tevent_req_nomem(subreq, req)) {
721 0 : return tevent_req_post(req, ev);
722 : }
723 0 : tevent_req_set_callback(subreq, cli_posix_setacl_done, req);
724 0 : return req;
725 : }
726 :
727 0 : static void cli_posix_setacl_done(struct tevent_req *subreq)
728 : {
729 0 : NTSTATUS status = cli_setpathinfo_recv(subreq);
730 0 : tevent_req_simple_finish_ntstatus(subreq, status);
731 0 : }
732 :
733 0 : NTSTATUS cli_posix_setacl_recv(struct tevent_req *req)
734 : {
735 0 : return tevent_req_simple_recv_ntstatus(req);
736 : }
737 :
738 0 : NTSTATUS cli_posix_setacl(struct cli_state *cli,
739 : const char *fname,
740 : const void *acl_buf,
741 : size_t acl_buf_size)
742 : {
743 0 : TALLOC_CTX *frame = talloc_stackframe();
744 0 : struct tevent_context *ev = NULL;
745 0 : struct tevent_req *req = NULL;
746 0 : NTSTATUS status = NT_STATUS_OK;
747 :
748 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
749 : /*
750 : * Can't use sync call while an async call is in flight
751 : */
752 0 : status = NT_STATUS_INVALID_PARAMETER;
753 0 : goto fail;
754 : }
755 :
756 0 : ev = samba_tevent_context_init(frame);
757 0 : if (ev == NULL) {
758 0 : status = NT_STATUS_NO_MEMORY;
759 0 : goto fail;
760 : }
761 :
762 0 : req = cli_posix_setacl_send(frame,
763 : ev,
764 : cli,
765 : fname,
766 : acl_buf,
767 : acl_buf_size);
768 0 : if (req == NULL) {
769 0 : status = NT_STATUS_NO_MEMORY;
770 0 : goto fail;
771 : }
772 :
773 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
774 0 : goto fail;
775 : }
776 :
777 0 : status = cli_posix_setacl_recv(req);
778 :
779 0 : fail:
780 0 : TALLOC_FREE(frame);
781 0 : return status;
782 : }
783 :
784 : /****************************************************************************
785 : Stat a file (UNIX extensions).
786 : ****************************************************************************/
787 :
788 : struct stat_state {
789 : SMB_STRUCT_STAT *sbuf;
790 : };
791 :
792 : static void cli_posix_stat_done(struct tevent_req *subreq);
793 :
794 0 : struct tevent_req *cli_posix_stat_send(TALLOC_CTX *mem_ctx,
795 : struct tevent_context *ev,
796 : struct cli_state *cli,
797 : const char *fname,
798 : SMB_STRUCT_STAT *sbuf)
799 : {
800 0 : struct tevent_req *req = NULL, *subreq = NULL;
801 0 : struct stat_state *state = NULL;
802 :
803 0 : req = tevent_req_create(mem_ctx, &state, struct stat_state);
804 0 : if (req == NULL) {
805 0 : return NULL;
806 : }
807 0 : state->sbuf = sbuf;
808 :
809 0 : subreq = cli_qpathinfo_send(state, ev, cli, fname,
810 : SMB_QUERY_FILE_UNIX_BASIC, 100, 100);
811 0 : if (tevent_req_nomem(subreq, req)) {
812 0 : return tevent_req_post(req, ev);
813 : }
814 0 : tevent_req_set_callback(subreq, cli_posix_stat_done, req);
815 0 : return req;
816 : }
817 :
818 0 : static void cli_posix_stat_done(struct tevent_req *subreq)
819 : {
820 0 : struct tevent_req *req = tevent_req_callback_data(
821 : subreq, struct tevent_req);
822 0 : struct stat_state *state = tevent_req_data(req, struct stat_state);
823 0 : SMB_STRUCT_STAT *sbuf = state->sbuf;
824 : uint8_t *data;
825 0 : uint32_t num_data = 0;
826 : NTSTATUS status;
827 :
828 0 : status = cli_qpathinfo_recv(subreq, state, &data, &num_data);
829 0 : TALLOC_FREE(subreq);
830 0 : if (tevent_req_nterror(req, status)) {
831 0 : return;
832 : }
833 :
834 0 : if (num_data != 100) {
835 : /*
836 : * Paranoia, cli_qpathinfo should have guaranteed
837 : * this, but you never know...
838 : */
839 0 : tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
840 0 : return;
841 : }
842 :
843 0 : *sbuf = (SMB_STRUCT_STAT) { 0 };
844 :
845 : /* total size, in bytes */
846 0 : sbuf->st_ex_size = IVAL2_TO_SMB_BIG_UINT(data, 0);
847 :
848 : /* number of blocks allocated */
849 0 : sbuf->st_ex_blocks = IVAL2_TO_SMB_BIG_UINT(data,8);
850 : #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
851 0 : sbuf->st_ex_blocks /= STAT_ST_BLOCKSIZE;
852 : #else
853 : /* assume 512 byte blocks */
854 : sbuf->st_ex_blocks /= 512;
855 : #endif
856 : /* time of last change */
857 0 : sbuf->st_ex_ctime = interpret_long_date((char *)(data + 16));
858 :
859 : /* time of last access */
860 0 : sbuf->st_ex_atime = interpret_long_date((char *)(data + 24));
861 :
862 : /* time of last modification */
863 0 : sbuf->st_ex_mtime = interpret_long_date((char *)(data + 32));
864 :
865 0 : sbuf->st_ex_uid = (uid_t) IVAL(data, 40); /* user ID of owner */
866 0 : sbuf->st_ex_gid = (gid_t) IVAL(data, 48); /* group ID of owner */
867 0 : sbuf->st_ex_mode = unix_filetype_from_wire(IVAL(data, 56));
868 :
869 : #if defined(HAVE_MAKEDEV)
870 : {
871 0 : uint32_t dev_major = IVAL(data,60);
872 0 : uint32_t dev_minor = IVAL(data,68);
873 0 : sbuf->st_ex_rdev = makedev(dev_major, dev_minor);
874 : }
875 : #endif
876 : /* inode */
877 0 : sbuf->st_ex_ino = (SMB_INO_T)IVAL2_TO_SMB_BIG_UINT(data, 76);
878 :
879 : /* protection */
880 0 : sbuf->st_ex_mode |= wire_perms_to_unix(IVAL(data, 84));
881 :
882 : /* number of hard links */
883 0 : sbuf->st_ex_nlink = BIG_UINT(data, 92);
884 :
885 0 : tevent_req_done(req);
886 : }
887 :
888 0 : NTSTATUS cli_posix_stat_recv(struct tevent_req *req)
889 : {
890 0 : return tevent_req_simple_recv_ntstatus(req);
891 : }
892 :
893 0 : NTSTATUS cli_posix_stat(struct cli_state *cli,
894 : const char *fname,
895 : SMB_STRUCT_STAT *sbuf)
896 : {
897 0 : TALLOC_CTX *frame = talloc_stackframe();
898 0 : struct tevent_context *ev = NULL;
899 0 : struct tevent_req *req = NULL;
900 0 : NTSTATUS status = NT_STATUS_OK;
901 :
902 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
903 : /*
904 : * Can't use sync call while an async call is in flight
905 : */
906 0 : status = NT_STATUS_INVALID_PARAMETER;
907 0 : goto fail;
908 : }
909 :
910 0 : ev = samba_tevent_context_init(frame);
911 0 : if (ev == NULL) {
912 0 : status = NT_STATUS_NO_MEMORY;
913 0 : goto fail;
914 : }
915 :
916 0 : req = cli_posix_stat_send(frame, ev, cli, fname, sbuf);
917 0 : if (req == NULL) {
918 0 : status = NT_STATUS_NO_MEMORY;
919 0 : goto fail;
920 : }
921 :
922 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
923 0 : goto fail;
924 : }
925 :
926 0 : status = cli_posix_stat_recv(req);
927 :
928 0 : fail:
929 0 : TALLOC_FREE(frame);
930 0 : return status;
931 : }
932 :
933 : /****************************************************************************
934 : Chmod or chown a file internal (UNIX extensions).
935 : ****************************************************************************/
936 :
937 : struct cli_posix_chown_chmod_internal_state {
938 : uint8_t data[100];
939 : };
940 :
941 : static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq);
942 :
943 0 : static struct tevent_req *cli_posix_chown_chmod_internal_send(TALLOC_CTX *mem_ctx,
944 : struct tevent_context *ev,
945 : struct cli_state *cli,
946 : const char *fname,
947 : uint32_t mode,
948 : uint32_t uid,
949 : uint32_t gid)
950 : {
951 0 : struct tevent_req *req = NULL, *subreq = NULL;
952 0 : struct cli_posix_chown_chmod_internal_state *state = NULL;
953 :
954 0 : req = tevent_req_create(mem_ctx, &state,
955 : struct cli_posix_chown_chmod_internal_state);
956 0 : if (req == NULL) {
957 0 : return NULL;
958 : }
959 :
960 0 : memset(state->data, 0xff, 40); /* Set all sizes/times to no change. */
961 0 : memset(&state->data[40], '\0', 60);
962 0 : SIVAL(state->data,40,uid);
963 0 : SIVAL(state->data,48,gid);
964 0 : SIVAL(state->data,84,mode);
965 :
966 0 : subreq = cli_setpathinfo_send(state, ev, cli, SMB_SET_FILE_UNIX_BASIC,
967 0 : fname, state->data, sizeof(state->data));
968 0 : if (tevent_req_nomem(subreq, req)) {
969 0 : return tevent_req_post(req, ev);
970 : }
971 0 : tevent_req_set_callback(subreq, cli_posix_chown_chmod_internal_done,
972 : req);
973 0 : return req;
974 : }
975 :
976 0 : static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq)
977 : {
978 0 : NTSTATUS status = cli_setpathinfo_recv(subreq);
979 0 : tevent_req_simple_finish_ntstatus(subreq, status);
980 0 : }
981 :
982 0 : static NTSTATUS cli_posix_chown_chmod_internal_recv(struct tevent_req *req)
983 : {
984 0 : return tevent_req_simple_recv_ntstatus(req);
985 : }
986 :
987 : /****************************************************************************
988 : chmod a file (UNIX extensions).
989 : ****************************************************************************/
990 :
991 : struct cli_posix_chmod_state {
992 : uint8_t dummy;
993 : };
994 :
995 : static void cli_posix_chmod_done(struct tevent_req *subreq);
996 :
997 0 : struct tevent_req *cli_posix_chmod_send(TALLOC_CTX *mem_ctx,
998 : struct tevent_context *ev,
999 : struct cli_state *cli,
1000 : const char *fname,
1001 : mode_t mode)
1002 : {
1003 0 : struct tevent_req *req = NULL, *subreq = NULL;
1004 0 : struct cli_posix_chmod_state *state = NULL;
1005 :
1006 0 : req = tevent_req_create(mem_ctx, &state, struct cli_posix_chmod_state);
1007 0 : if (req == NULL) {
1008 0 : return NULL;
1009 : }
1010 :
1011 0 : subreq = cli_posix_chown_chmod_internal_send(
1012 : state,
1013 : ev,
1014 : cli,
1015 : fname,
1016 : unix_perms_to_wire(mode),
1017 : SMB_UID_NO_CHANGE,
1018 : SMB_GID_NO_CHANGE);
1019 0 : if (tevent_req_nomem(subreq, req)) {
1020 0 : return tevent_req_post(req, ev);
1021 : }
1022 0 : tevent_req_set_callback(subreq, cli_posix_chmod_done, req);
1023 0 : return req;
1024 : }
1025 :
1026 0 : static void cli_posix_chmod_done(struct tevent_req *subreq)
1027 : {
1028 0 : NTSTATUS status = cli_posix_chown_chmod_internal_recv(subreq);
1029 0 : tevent_req_simple_finish_ntstatus(subreq, status);
1030 0 : }
1031 :
1032 0 : NTSTATUS cli_posix_chmod_recv(struct tevent_req *req)
1033 : {
1034 0 : return tevent_req_simple_recv_ntstatus(req);
1035 : }
1036 :
1037 0 : NTSTATUS cli_posix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
1038 : {
1039 0 : TALLOC_CTX *frame = talloc_stackframe();
1040 0 : struct tevent_context *ev = NULL;
1041 0 : struct tevent_req *req = NULL;
1042 0 : NTSTATUS status = NT_STATUS_OK;
1043 :
1044 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
1045 : /*
1046 : * Can't use sync call while an async call is in flight
1047 : */
1048 0 : status = NT_STATUS_INVALID_PARAMETER;
1049 0 : goto fail;
1050 : }
1051 :
1052 0 : ev = samba_tevent_context_init(frame);
1053 0 : if (ev == NULL) {
1054 0 : status = NT_STATUS_NO_MEMORY;
1055 0 : goto fail;
1056 : }
1057 :
1058 0 : req = cli_posix_chmod_send(frame,
1059 : ev,
1060 : cli,
1061 : fname,
1062 : mode);
1063 0 : if (req == NULL) {
1064 0 : status = NT_STATUS_NO_MEMORY;
1065 0 : goto fail;
1066 : }
1067 :
1068 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1069 0 : goto fail;
1070 : }
1071 :
1072 0 : status = cli_posix_chmod_recv(req);
1073 :
1074 0 : fail:
1075 0 : TALLOC_FREE(frame);
1076 0 : return status;
1077 : }
1078 :
1079 : /****************************************************************************
1080 : chown a file (UNIX extensions).
1081 : ****************************************************************************/
1082 :
1083 : struct cli_posix_chown_state {
1084 : uint8_t dummy;
1085 : };
1086 :
1087 : static void cli_posix_chown_done(struct tevent_req *subreq);
1088 :
1089 0 : struct tevent_req *cli_posix_chown_send(TALLOC_CTX *mem_ctx,
1090 : struct tevent_context *ev,
1091 : struct cli_state *cli,
1092 : const char *fname,
1093 : uid_t uid,
1094 : gid_t gid)
1095 : {
1096 0 : struct tevent_req *req = NULL, *subreq = NULL;
1097 0 : struct cli_posix_chown_state *state = NULL;
1098 :
1099 0 : req = tevent_req_create(
1100 : mem_ctx, &state, struct cli_posix_chown_state);
1101 0 : if (req == NULL) {
1102 0 : return NULL;
1103 : }
1104 :
1105 0 : subreq = cli_posix_chown_chmod_internal_send(
1106 : state,
1107 : ev,
1108 : cli,
1109 : fname,
1110 : SMB_MODE_NO_CHANGE,
1111 : (uint32_t)uid,
1112 : (uint32_t)gid);
1113 0 : if (tevent_req_nomem(subreq, req)) {
1114 0 : return tevent_req_post(req, ev);
1115 : }
1116 0 : tevent_req_set_callback(subreq, cli_posix_chown_done, req);
1117 0 : return req;
1118 : }
1119 :
1120 0 : static void cli_posix_chown_done(struct tevent_req *subreq)
1121 : {
1122 0 : NTSTATUS status = cli_posix_chown_chmod_internal_recv(subreq);
1123 0 : tevent_req_simple_finish_ntstatus(subreq, status);
1124 0 : }
1125 :
1126 0 : NTSTATUS cli_posix_chown_recv(struct tevent_req *req)
1127 : {
1128 0 : return tevent_req_simple_recv_ntstatus(req);
1129 : }
1130 :
1131 0 : NTSTATUS cli_posix_chown(struct cli_state *cli,
1132 : const char *fname,
1133 : uid_t uid,
1134 : gid_t gid)
1135 : {
1136 0 : TALLOC_CTX *frame = talloc_stackframe();
1137 0 : struct tevent_context *ev = NULL;
1138 0 : struct tevent_req *req = NULL;
1139 0 : NTSTATUS status = NT_STATUS_OK;
1140 :
1141 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
1142 : /*
1143 : * Can't use sync call while an async call is in flight
1144 : */
1145 0 : status = NT_STATUS_INVALID_PARAMETER;
1146 0 : goto fail;
1147 : }
1148 :
1149 0 : ev = samba_tevent_context_init(frame);
1150 0 : if (ev == NULL) {
1151 0 : status = NT_STATUS_NO_MEMORY;
1152 0 : goto fail;
1153 : }
1154 :
1155 0 : req = cli_posix_chown_send(frame,
1156 : ev,
1157 : cli,
1158 : fname,
1159 : uid,
1160 : gid);
1161 0 : if (req == NULL) {
1162 0 : status = NT_STATUS_NO_MEMORY;
1163 0 : goto fail;
1164 : }
1165 :
1166 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1167 0 : goto fail;
1168 : }
1169 :
1170 0 : status = cli_posix_chown_recv(req);
1171 :
1172 0 : fail:
1173 0 : TALLOC_FREE(frame);
1174 0 : return status;
1175 : }
1176 :
1177 : /****************************************************************************
1178 : Rename a file.
1179 : ****************************************************************************/
1180 :
1181 : struct cli_smb1_rename_state {
1182 : uint8_t *data;
1183 : };
1184 :
1185 : static void cli_smb1_rename_done(struct tevent_req *subreq);
1186 :
1187 0 : static struct tevent_req *cli_smb1_rename_send(TALLOC_CTX *mem_ctx,
1188 : struct tevent_context *ev,
1189 : struct cli_state *cli,
1190 : const char *fname_src,
1191 : const char *fname_dst,
1192 : bool replace)
1193 : {
1194 : NTSTATUS status;
1195 0 : struct tevent_req *req = NULL, *subreq = NULL;
1196 0 : struct cli_smb1_rename_state *state = NULL;
1197 0 : smb_ucs2_t *converted_str = NULL;
1198 0 : size_t converted_size_bytes = 0;
1199 :
1200 0 : req = tevent_req_create(mem_ctx, &state, struct cli_smb1_rename_state);
1201 0 : if (req == NULL) {
1202 0 : return NULL;
1203 : }
1204 :
1205 : /*
1206 : * Strip a MSDFS path from fname_dst if we were given one.
1207 : */
1208 0 : status = cli_dfs_target_check(state,
1209 : cli,
1210 : fname_dst,
1211 : &fname_dst);
1212 0 : if (!NT_STATUS_IS_OK(status)) {
1213 0 : goto fail;
1214 : }
1215 :
1216 0 : if (!push_ucs2_talloc(talloc_tos(), &converted_str, fname_dst,
1217 : &converted_size_bytes)) {
1218 0 : status = NT_STATUS_INVALID_PARAMETER;
1219 0 : goto fail;
1220 : }
1221 :
1222 : /* W2K8 insists the dest name is not null
1223 : terminated. Remove the last 2 zero bytes
1224 : and reduce the name length. */
1225 :
1226 0 : if (converted_size_bytes < 2) {
1227 0 : status = NT_STATUS_INVALID_PARAMETER;
1228 0 : goto fail;
1229 : }
1230 0 : converted_size_bytes -= 2;
1231 :
1232 0 : state->data =
1233 0 : talloc_zero_array(state, uint8_t, 12 + converted_size_bytes);
1234 0 : if (state->data == NULL) {
1235 0 : status = NT_STATUS_NO_MEMORY;
1236 0 : goto fail;
1237 : }
1238 :
1239 0 : if (replace) {
1240 0 : SCVAL(state->data, 0, 1);
1241 : }
1242 :
1243 0 : SIVAL(state->data, 8, converted_size_bytes);
1244 0 : memcpy(state->data + 12, converted_str, converted_size_bytes);
1245 :
1246 0 : TALLOC_FREE(converted_str);
1247 :
1248 0 : subreq = cli_setpathinfo_send(
1249 0 : state, ev, cli, SMB_FILE_RENAME_INFORMATION, fname_src, state->data,
1250 0 : talloc_get_size(state->data));
1251 0 : if (tevent_req_nomem(subreq, req)) {
1252 0 : status = NT_STATUS_NO_MEMORY;
1253 0 : goto fail;
1254 : }
1255 0 : tevent_req_set_callback(subreq, cli_smb1_rename_done, req);
1256 0 : return req;
1257 :
1258 0 : fail:
1259 0 : TALLOC_FREE(converted_str);
1260 0 : tevent_req_nterror(req, status);
1261 0 : return tevent_req_post(req, ev);
1262 : }
1263 :
1264 0 : static void cli_smb1_rename_done(struct tevent_req *subreq)
1265 : {
1266 0 : NTSTATUS status = cli_setpathinfo_recv(subreq);
1267 0 : tevent_req_simple_finish_ntstatus(subreq, status);
1268 0 : }
1269 :
1270 0 : static NTSTATUS cli_smb1_rename_recv(struct tevent_req *req)
1271 : {
1272 0 : return tevent_req_simple_recv_ntstatus(req);
1273 : }
1274 :
1275 : static void cli_cifs_rename_done(struct tevent_req *subreq);
1276 :
1277 : struct cli_cifs_rename_state {
1278 : uint16_t vwv[1];
1279 : };
1280 :
1281 5 : static struct tevent_req *cli_cifs_rename_send(TALLOC_CTX *mem_ctx,
1282 : struct tevent_context *ev,
1283 : struct cli_state *cli,
1284 : const char *fname_src,
1285 : const char *fname_dst,
1286 : bool replace)
1287 : {
1288 5 : struct tevent_req *req = NULL, *subreq = NULL;
1289 5 : struct cli_cifs_rename_state *state = NULL;
1290 5 : uint8_t additional_flags = 0;
1291 5 : uint16_t additional_flags2 = 0;
1292 5 : uint8_t *bytes = NULL;
1293 5 : char *fname_src_cp = NULL;
1294 5 : char *fname_dst_cp = NULL;
1295 :
1296 5 : req = tevent_req_create(mem_ctx, &state, struct cli_cifs_rename_state);
1297 5 : if (req == NULL) {
1298 0 : return NULL;
1299 : }
1300 :
1301 5 : if (replace) {
1302 : /*
1303 : * CIFS doesn't support replace
1304 : */
1305 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1306 0 : return tevent_req_post(req, ev);
1307 : }
1308 :
1309 5 : SSVAL(state->vwv+0, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1310 :
1311 5 : bytes = talloc_array(state, uint8_t, 1);
1312 5 : if (tevent_req_nomem(bytes, req)) {
1313 0 : return tevent_req_post(req, ev);
1314 : }
1315 :
1316 : /*
1317 : * SMBmv on a DFS share uses DFS names for src and dst.
1318 : * See smbtorture3: SMB1-DFS-PATHS: test_smb1_mv().
1319 : */
1320 :
1321 5 : fname_src_cp = smb1_dfs_share_path(state, cli, fname_src);
1322 5 : if (tevent_req_nomem(fname_src_cp, req)) {
1323 0 : return tevent_req_post(req, ev);
1324 : }
1325 5 : bytes[0] = 4;
1326 5 : bytes = smb_bytes_push_str(bytes,
1327 5 : smbXcli_conn_use_unicode(cli->conn),
1328 : fname_src_cp,
1329 5 : strlen(fname_src_cp)+1,
1330 : NULL);
1331 5 : if (tevent_req_nomem(bytes, req)) {
1332 0 : return tevent_req_post(req, ev);
1333 : }
1334 :
1335 5 : if (clistr_is_previous_version_path(fname_src)) {
1336 0 : additional_flags2 = FLAGS2_REPARSE_PATH;
1337 : }
1338 :
1339 5 : bytes = talloc_realloc(state, bytes, uint8_t,
1340 : talloc_get_size(bytes)+1);
1341 5 : if (tevent_req_nomem(bytes, req)) {
1342 0 : return tevent_req_post(req, ev);
1343 : }
1344 :
1345 : /*
1346 : * SMBmv on a DFS share uses DFS names for src and dst.
1347 : * See smbtorture3: SMB1-DFS-PATHS: test_smb1_mv().
1348 : */
1349 :
1350 5 : fname_dst_cp = smb1_dfs_share_path(state, cli, fname_dst);
1351 5 : if (tevent_req_nomem(fname_dst_cp, req)) {
1352 0 : return tevent_req_post(req, ev);
1353 : }
1354 5 : bytes[talloc_get_size(bytes)-1] = 4;
1355 5 : bytes = smb_bytes_push_str(bytes,
1356 5 : smbXcli_conn_use_unicode(cli->conn),
1357 : fname_dst_cp,
1358 5 : strlen(fname_dst_cp)+1,
1359 : NULL);
1360 5 : if (tevent_req_nomem(bytes, req)) {
1361 0 : return tevent_req_post(req, ev);
1362 : }
1363 :
1364 5 : subreq = cli_smb_send(state, ev, cli, SMBmv, additional_flags,
1365 : additional_flags2,
1366 5 : 1, state->vwv, talloc_get_size(bytes), bytes);
1367 5 : if (tevent_req_nomem(subreq, req)) {
1368 0 : return tevent_req_post(req, ev);
1369 : }
1370 5 : tevent_req_set_callback(subreq, cli_cifs_rename_done, req);
1371 5 : return req;
1372 : }
1373 :
1374 5 : static void cli_cifs_rename_done(struct tevent_req *subreq)
1375 : {
1376 5 : NTSTATUS status = cli_smb_recv(
1377 : subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1378 5 : tevent_req_simple_finish_ntstatus(subreq, status);
1379 5 : }
1380 :
1381 5 : static NTSTATUS cli_cifs_rename_recv(struct tevent_req *req)
1382 : {
1383 5 : return tevent_req_simple_recv_ntstatus(req);
1384 : }
1385 :
1386 : struct cli_rename_state {
1387 : uint8_t dummy;
1388 : };
1389 :
1390 : static void cli_rename_done1(struct tevent_req *subreq);
1391 : static void cli_rename_done_cifs(struct tevent_req *subreq);
1392 : static void cli_rename_done2(struct tevent_req *subreq);
1393 :
1394 26 : struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
1395 : struct tevent_context *ev,
1396 : struct cli_state *cli,
1397 : const char *fname_src,
1398 : const char *fname_dst,
1399 : bool replace)
1400 : {
1401 26 : struct tevent_req *req = NULL, *subreq = NULL;
1402 26 : struct cli_rename_state *state = NULL;
1403 :
1404 26 : req = tevent_req_create(mem_ctx, &state, struct cli_rename_state);
1405 26 : if (req == NULL) {
1406 0 : return NULL;
1407 : }
1408 :
1409 26 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1410 21 : subreq = cli_smb2_rename_send(
1411 : state, ev, cli, fname_src, fname_dst, replace);
1412 21 : if (tevent_req_nomem(subreq, req)) {
1413 0 : return tevent_req_post(req, ev);
1414 : }
1415 21 : tevent_req_set_callback(subreq, cli_rename_done2, req);
1416 21 : return req;
1417 : }
1418 :
1419 5 : if (replace && smbXcli_conn_support_passthrough(cli->conn)) {
1420 0 : subreq = cli_smb1_rename_send(
1421 : state, ev, cli, fname_src, fname_dst, replace);
1422 0 : if (tevent_req_nomem(subreq, req)) {
1423 0 : return tevent_req_post(req, ev);
1424 : }
1425 0 : tevent_req_set_callback(subreq, cli_rename_done1, req);
1426 0 : return req;
1427 : }
1428 :
1429 5 : subreq = cli_cifs_rename_send(
1430 : state, ev, cli, fname_src,fname_dst, replace);
1431 5 : if (tevent_req_nomem(subreq, req)) {
1432 0 : return tevent_req_post(req, ev);
1433 : }
1434 5 : tevent_req_set_callback(subreq, cli_rename_done_cifs, req);
1435 5 : return req;
1436 : }
1437 :
1438 0 : static void cli_rename_done1(struct tevent_req *subreq)
1439 : {
1440 0 : NTSTATUS status = cli_smb1_rename_recv(subreq);
1441 0 : tevent_req_simple_finish_ntstatus(subreq, status);
1442 0 : }
1443 :
1444 5 : static void cli_rename_done_cifs(struct tevent_req *subreq)
1445 : {
1446 5 : NTSTATUS status = cli_cifs_rename_recv(subreq);
1447 5 : tevent_req_simple_finish_ntstatus(subreq, status);
1448 5 : }
1449 :
1450 21 : static void cli_rename_done2(struct tevent_req *subreq)
1451 : {
1452 21 : NTSTATUS status = cli_smb2_rename_recv(subreq);
1453 21 : tevent_req_simple_finish_ntstatus(subreq, status);
1454 21 : }
1455 :
1456 26 : NTSTATUS cli_rename_recv(struct tevent_req *req)
1457 : {
1458 26 : return tevent_req_simple_recv_ntstatus(req);
1459 : }
1460 :
1461 26 : NTSTATUS cli_rename(struct cli_state *cli,
1462 : const char *fname_src,
1463 : const char *fname_dst,
1464 : bool replace)
1465 : {
1466 26 : TALLOC_CTX *frame = NULL;
1467 : struct tevent_context *ev;
1468 : struct tevent_req *req;
1469 26 : NTSTATUS status = NT_STATUS_OK;
1470 :
1471 26 : frame = talloc_stackframe();
1472 :
1473 26 : if (smbXcli_conn_has_async_calls(cli->conn)) {
1474 : /*
1475 : * Can't use sync call while an async call is in flight
1476 : */
1477 0 : status = NT_STATUS_INVALID_PARAMETER;
1478 0 : goto fail;
1479 : }
1480 :
1481 26 : ev = samba_tevent_context_init(frame);
1482 26 : if (ev == NULL) {
1483 0 : status = NT_STATUS_NO_MEMORY;
1484 0 : goto fail;
1485 : }
1486 :
1487 26 : req = cli_rename_send(frame, ev, cli, fname_src, fname_dst, replace);
1488 26 : if (req == NULL) {
1489 0 : status = NT_STATUS_NO_MEMORY;
1490 0 : goto fail;
1491 : }
1492 :
1493 26 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1494 0 : goto fail;
1495 : }
1496 :
1497 26 : status = cli_rename_recv(req);
1498 26 : cli->raw_status = status; /* cli_smb2_rename_recv doesn't set this */
1499 :
1500 26 : fail:
1501 26 : TALLOC_FREE(frame);
1502 26 : return status;
1503 : }
1504 :
1505 : /****************************************************************************
1506 : NT Rename a file.
1507 : ****************************************************************************/
1508 :
1509 : static void cli_ntrename_internal_done(struct tevent_req *subreq);
1510 :
1511 : struct cli_ntrename_internal_state {
1512 : uint16_t vwv[4];
1513 : };
1514 :
1515 1 : static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
1516 : struct tevent_context *ev,
1517 : struct cli_state *cli,
1518 : const char *fname_src,
1519 : const char *fname_dst,
1520 : uint16_t rename_flag)
1521 : {
1522 1 : struct tevent_req *req = NULL, *subreq = NULL;
1523 1 : struct cli_ntrename_internal_state *state = NULL;
1524 1 : uint8_t additional_flags = 0;
1525 1 : uint16_t additional_flags2 = 0;
1526 1 : uint8_t *bytes = NULL;
1527 1 : char *fname_src_cp = NULL;
1528 1 : char *fname_dst_cp = NULL;
1529 :
1530 1 : req = tevent_req_create(mem_ctx, &state,
1531 : struct cli_ntrename_internal_state);
1532 1 : if (req == NULL) {
1533 0 : return NULL;
1534 : }
1535 :
1536 1 : SSVAL(state->vwv+0, 0 ,FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1537 1 : SSVAL(state->vwv+1, 0, rename_flag);
1538 :
1539 1 : bytes = talloc_array(state, uint8_t, 1);
1540 1 : if (tevent_req_nomem(bytes, req)) {
1541 0 : return tevent_req_post(req, ev);
1542 : }
1543 : /*
1544 : * SMBntrename on a DFS share uses DFS names for src and dst.
1545 : * See smbtorture3: SMB1-DFS-PATHS: test_smb1_ntrename_rename().
1546 : */
1547 1 : fname_src_cp = smb1_dfs_share_path(state, cli, fname_src);
1548 1 : if (tevent_req_nomem(fname_src_cp, req)) {
1549 0 : return tevent_req_post(req, ev);
1550 : }
1551 1 : bytes[0] = 4;
1552 1 : bytes = smb_bytes_push_str(bytes,
1553 1 : smbXcli_conn_use_unicode(cli->conn),
1554 : fname_src_cp,
1555 1 : strlen(fname_src_cp)+1,
1556 : NULL);
1557 1 : if (tevent_req_nomem(bytes, req)) {
1558 0 : return tevent_req_post(req, ev);
1559 : }
1560 :
1561 1 : if (clistr_is_previous_version_path(fname_src)) {
1562 0 : additional_flags2 = FLAGS2_REPARSE_PATH;
1563 : }
1564 :
1565 1 : bytes = talloc_realloc(state, bytes, uint8_t,
1566 : talloc_get_size(bytes)+1);
1567 1 : if (tevent_req_nomem(bytes, req)) {
1568 0 : return tevent_req_post(req, ev);
1569 : }
1570 :
1571 : /*
1572 : * SMBntrename on a DFS share uses DFS names for src and dst.
1573 : * See smbtorture3: SMB1-DFS-PATHS: test_smb1_ntrename_rename().
1574 : * and smbtorture3: SMB1-DFS-PATHS: test_smb1_ntrename_hardlink()
1575 : */
1576 1 : fname_dst_cp = smb1_dfs_share_path(state, cli, fname_dst);
1577 1 : if (tevent_req_nomem(fname_dst_cp, req)) {
1578 0 : return tevent_req_post(req, ev);
1579 : }
1580 1 : bytes[talloc_get_size(bytes)-1] = 4;
1581 1 : bytes = smb_bytes_push_str(bytes,
1582 1 : smbXcli_conn_use_unicode(cli->conn),
1583 : fname_dst_cp,
1584 1 : strlen(fname_dst_cp)+1,
1585 : NULL);
1586 1 : if (tevent_req_nomem(bytes, req)) {
1587 0 : return tevent_req_post(req, ev);
1588 : }
1589 :
1590 1 : subreq = cli_smb_send(state, ev, cli, SMBntrename, additional_flags,
1591 : additional_flags2,
1592 1 : 4, state->vwv, talloc_get_size(bytes), bytes);
1593 1 : if (tevent_req_nomem(subreq, req)) {
1594 0 : return tevent_req_post(req, ev);
1595 : }
1596 1 : tevent_req_set_callback(subreq, cli_ntrename_internal_done, req);
1597 1 : return req;
1598 : }
1599 :
1600 1 : static void cli_ntrename_internal_done(struct tevent_req *subreq)
1601 : {
1602 1 : NTSTATUS status = cli_smb_recv(
1603 : subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1604 1 : tevent_req_simple_finish_ntstatus(subreq, status);
1605 1 : }
1606 :
1607 1 : static NTSTATUS cli_ntrename_internal_recv(struct tevent_req *req)
1608 : {
1609 1 : return tevent_req_simple_recv_ntstatus(req);
1610 : }
1611 :
1612 0 : struct tevent_req *cli_ntrename_send(TALLOC_CTX *mem_ctx,
1613 : struct tevent_context *ev,
1614 : struct cli_state *cli,
1615 : const char *fname_src,
1616 : const char *fname_dst)
1617 : {
1618 0 : return cli_ntrename_internal_send(mem_ctx,
1619 : ev,
1620 : cli,
1621 : fname_src,
1622 : fname_dst,
1623 : RENAME_FLAG_RENAME);
1624 : }
1625 :
1626 0 : NTSTATUS cli_ntrename_recv(struct tevent_req *req)
1627 : {
1628 0 : return cli_ntrename_internal_recv(req);
1629 : }
1630 :
1631 0 : NTSTATUS cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1632 : {
1633 0 : TALLOC_CTX *frame = talloc_stackframe();
1634 : struct tevent_context *ev;
1635 : struct tevent_req *req;
1636 0 : NTSTATUS status = NT_STATUS_OK;
1637 :
1638 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
1639 : /*
1640 : * Can't use sync call while an async call is in flight
1641 : */
1642 0 : status = NT_STATUS_INVALID_PARAMETER;
1643 0 : goto fail;
1644 : }
1645 :
1646 0 : ev = samba_tevent_context_init(frame);
1647 0 : if (ev == NULL) {
1648 0 : status = NT_STATUS_NO_MEMORY;
1649 0 : goto fail;
1650 : }
1651 :
1652 0 : req = cli_ntrename_send(frame, ev, cli, fname_src, fname_dst);
1653 0 : if (req == NULL) {
1654 0 : status = NT_STATUS_NO_MEMORY;
1655 0 : goto fail;
1656 : }
1657 :
1658 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1659 0 : goto fail;
1660 : }
1661 :
1662 0 : status = cli_ntrename_recv(req);
1663 :
1664 0 : fail:
1665 0 : TALLOC_FREE(frame);
1666 0 : return status;
1667 : }
1668 :
1669 : /****************************************************************************
1670 : NT hardlink a file.
1671 : ****************************************************************************/
1672 :
1673 1 : static struct tevent_req *cli_nt_hardlink_send(TALLOC_CTX *mem_ctx,
1674 : struct tevent_context *ev,
1675 : struct cli_state *cli,
1676 : const char *fname_src,
1677 : const char *fname_dst)
1678 : {
1679 1 : return cli_ntrename_internal_send(mem_ctx,
1680 : ev,
1681 : cli,
1682 : fname_src,
1683 : fname_dst,
1684 : RENAME_FLAG_HARD_LINK);
1685 : }
1686 :
1687 1 : static NTSTATUS cli_nt_hardlink_recv(struct tevent_req *req)
1688 : {
1689 1 : return cli_ntrename_internal_recv(req);
1690 : }
1691 :
1692 : struct cli_smb2_hardlink_state {
1693 : struct tevent_context *ev;
1694 : struct cli_state *cli;
1695 : uint16_t fnum_src;
1696 : const char *fname_dst;
1697 : bool overwrite;
1698 : NTSTATUS status;
1699 : };
1700 :
1701 : static void cli_smb2_hardlink_opened(struct tevent_req *subreq);
1702 : static void cli_smb2_hardlink_info_set(struct tevent_req *subreq);
1703 : static void cli_smb2_hardlink_closed(struct tevent_req *subreq);
1704 :
1705 4 : static struct tevent_req *cli_smb2_hardlink_send(
1706 : TALLOC_CTX *mem_ctx,
1707 : struct tevent_context *ev,
1708 : struct cli_state *cli,
1709 : const char *fname_src,
1710 : const char *fname_dst,
1711 : bool overwrite,
1712 : struct smb2_create_blobs *in_cblobs)
1713 : {
1714 4 : struct tevent_req *req = NULL, *subreq = NULL;
1715 4 : struct cli_smb2_hardlink_state *state = NULL;
1716 : NTSTATUS status;
1717 :
1718 4 : req = tevent_req_create(
1719 : mem_ctx, &state, struct cli_smb2_hardlink_state);
1720 4 : if (req == NULL) {
1721 0 : return NULL;
1722 : }
1723 :
1724 : /*
1725 : * Strip a MSDFS path from fname_dst if we were given one.
1726 : */
1727 4 : status = cli_dfs_target_check(state,
1728 : cli,
1729 : fname_dst,
1730 : &fname_dst);
1731 4 : if (tevent_req_nterror(req, status)) {
1732 0 : return tevent_req_post(req, ev);
1733 : }
1734 :
1735 4 : state->ev = ev;
1736 4 : state->cli = cli;
1737 4 : state->fname_dst = fname_dst;
1738 4 : state->overwrite = overwrite;
1739 :
1740 4 : subreq = cli_smb2_create_fnum_send(
1741 : state,
1742 : ev,
1743 : cli,
1744 : fname_src,
1745 : 0, /* create_flags */
1746 : SMB2_IMPERSONATION_IMPERSONATION,
1747 : FILE_WRITE_ATTRIBUTES,
1748 : 0, /* file attributes */
1749 : FILE_SHARE_READ|
1750 : FILE_SHARE_WRITE|
1751 : FILE_SHARE_DELETE, /* share_access */
1752 : FILE_OPEN, /* create_disposition */
1753 : FILE_NON_DIRECTORY_FILE, /* no hardlinks on directories */
1754 : in_cblobs);
1755 4 : if (tevent_req_nomem(subreq, req)) {
1756 0 : return tevent_req_post(req, ev);
1757 : }
1758 4 : tevent_req_set_callback(subreq, cli_smb2_hardlink_opened, req);
1759 4 : return req;
1760 : }
1761 :
1762 4 : static void cli_smb2_hardlink_opened(struct tevent_req *subreq)
1763 : {
1764 4 : struct tevent_req *req = tevent_req_callback_data(
1765 : subreq, struct tevent_req);
1766 4 : struct cli_smb2_hardlink_state *state = tevent_req_data(
1767 : req, struct cli_smb2_hardlink_state);
1768 : NTSTATUS status;
1769 : smb_ucs2_t *ucs2_dst;
1770 : size_t ucs2_len;
1771 : DATA_BLOB inbuf;
1772 : bool ok;
1773 :
1774 4 : status = cli_smb2_create_fnum_recv(
1775 : subreq, &state->fnum_src, NULL, NULL, NULL, NULL);
1776 4 : TALLOC_FREE(subreq);
1777 4 : if (tevent_req_nterror(req, status)) {
1778 0 : return;
1779 : }
1780 :
1781 4 : ok = push_ucs2_talloc(state, &ucs2_dst, state->fname_dst, &ucs2_len);
1782 4 : if (!ok || (ucs2_len < 2)) {
1783 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1784 0 : return;
1785 : }
1786 : /* Don't 0-terminate the name */
1787 4 : ucs2_len -= 2;
1788 :
1789 4 : inbuf = data_blob_talloc_zero(state, ucs2_len + 20);
1790 4 : if (tevent_req_nomem(inbuf.data, req)) {
1791 0 : return;
1792 : }
1793 :
1794 4 : if (state->overwrite) {
1795 0 : SCVAL(inbuf.data, 0, 1);
1796 : }
1797 4 : SIVAL(inbuf.data, 16, ucs2_len);
1798 4 : memcpy(inbuf.data + 20, ucs2_dst, ucs2_len);
1799 4 : TALLOC_FREE(ucs2_dst);
1800 :
1801 4 : subreq = cli_smb2_set_info_fnum_send(
1802 : state,
1803 : state->ev,
1804 : state->cli,
1805 4 : state->fnum_src,
1806 : 1, /* in_info_type */
1807 : SMB_FILE_LINK_INFORMATION - 1000, /* in_file_info_class */
1808 : &inbuf,
1809 : 0); /* in_additional_info */
1810 4 : if (tevent_req_nomem(subreq, req)) {
1811 0 : return;
1812 : }
1813 4 : tevent_req_set_callback(subreq, cli_smb2_hardlink_info_set, req);
1814 : }
1815 :
1816 4 : static void cli_smb2_hardlink_info_set(struct tevent_req *subreq)
1817 : {
1818 4 : struct tevent_req *req = tevent_req_callback_data(
1819 : subreq, struct tevent_req);
1820 4 : struct cli_smb2_hardlink_state *state = tevent_req_data(
1821 : req, struct cli_smb2_hardlink_state);
1822 :
1823 4 : state->status = cli_smb2_set_info_fnum_recv(subreq);
1824 4 : TALLOC_FREE(subreq);
1825 :
1826 : /* ignore error here, we need to close the file */
1827 :
1828 4 : subreq = cli_smb2_close_fnum_send(
1829 4 : state, state->ev, state->cli, state->fnum_src);
1830 4 : if (tevent_req_nomem(subreq, req)) {
1831 0 : return;
1832 : }
1833 4 : tevent_req_set_callback(subreq, cli_smb2_hardlink_closed, req);
1834 : }
1835 :
1836 4 : static void cli_smb2_hardlink_closed(struct tevent_req *subreq)
1837 : {
1838 4 : NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1839 4 : tevent_req_simple_finish_ntstatus(subreq, status);
1840 4 : }
1841 :
1842 4 : static NTSTATUS cli_smb2_hardlink_recv(struct tevent_req *req)
1843 : {
1844 4 : struct cli_smb2_hardlink_state *state = tevent_req_data(
1845 : req, struct cli_smb2_hardlink_state);
1846 : NTSTATUS status;
1847 :
1848 4 : if (tevent_req_is_nterror(req, &status)) {
1849 0 : return status;
1850 : }
1851 4 : return state->status;
1852 : }
1853 :
1854 : struct cli_hardlink_state {
1855 : uint8_t dummy;
1856 : };
1857 :
1858 : static void cli_hardlink_done(struct tevent_req *subreq);
1859 : static void cli_hardlink_done2(struct tevent_req *subreq);
1860 :
1861 5 : struct tevent_req *cli_hardlink_send(
1862 : TALLOC_CTX *mem_ctx,
1863 : struct tevent_context *ev,
1864 : struct cli_state *cli,
1865 : const char *fname_src,
1866 : const char *fname_dst)
1867 : {
1868 5 : struct tevent_req *req = NULL, *subreq = NULL;
1869 : struct cli_hardlink_state *state;
1870 :
1871 5 : req = tevent_req_create(mem_ctx, &state, struct cli_hardlink_state);
1872 5 : if (req == NULL) {
1873 0 : return NULL;
1874 : }
1875 :
1876 5 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1877 4 : subreq = cli_smb2_hardlink_send(
1878 : state, ev, cli, fname_src, fname_dst, false, NULL);
1879 4 : if (tevent_req_nomem(subreq, req)) {
1880 0 : return tevent_req_post(req, ev);
1881 : }
1882 4 : tevent_req_set_callback(subreq, cli_hardlink_done2, req);
1883 4 : return req;
1884 : }
1885 :
1886 1 : subreq = cli_nt_hardlink_send(state, ev, cli, fname_src, fname_dst);
1887 1 : if (tevent_req_nomem(subreq, req)) {
1888 0 : return tevent_req_post(req, ev);
1889 : }
1890 1 : tevent_req_set_callback(subreq, cli_hardlink_done, req);
1891 1 : return req;
1892 : }
1893 :
1894 1 : static void cli_hardlink_done(struct tevent_req *subreq)
1895 : {
1896 1 : NTSTATUS status = cli_nt_hardlink_recv(subreq);
1897 1 : tevent_req_simple_finish_ntstatus(subreq, status);
1898 1 : }
1899 :
1900 4 : static void cli_hardlink_done2(struct tevent_req *subreq)
1901 : {
1902 4 : NTSTATUS status = cli_smb2_hardlink_recv(subreq);
1903 4 : tevent_req_simple_finish_ntstatus(subreq, status);
1904 4 : }
1905 :
1906 5 : NTSTATUS cli_hardlink_recv(struct tevent_req *req)
1907 : {
1908 5 : return tevent_req_simple_recv_ntstatus(req);
1909 : }
1910 :
1911 5 : NTSTATUS cli_hardlink(
1912 : struct cli_state *cli, const char *fname_src, const char *fname_dst)
1913 : {
1914 5 : TALLOC_CTX *frame = talloc_stackframe();
1915 5 : struct tevent_context *ev = NULL;
1916 5 : struct tevent_req *req = NULL;
1917 5 : NTSTATUS status = NT_STATUS_NO_MEMORY;
1918 :
1919 5 : if (smbXcli_conn_has_async_calls(cli->conn)) {
1920 0 : status = NT_STATUS_INVALID_PARAMETER;
1921 0 : goto fail;
1922 : }
1923 5 : ev = samba_tevent_context_init(frame);
1924 5 : if (ev == NULL) {
1925 0 : goto fail;
1926 : }
1927 5 : req = cli_hardlink_send(frame, ev, cli, fname_src, fname_dst);
1928 5 : if (req == NULL) {
1929 0 : goto fail;
1930 : }
1931 5 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1932 0 : goto fail;
1933 : }
1934 5 : status = cli_hardlink_recv(req);
1935 5 : fail:
1936 5 : TALLOC_FREE(frame);
1937 5 : return status;
1938 : }
1939 :
1940 : /****************************************************************************
1941 : Delete a file.
1942 : ****************************************************************************/
1943 :
1944 : static void cli_unlink_done(struct tevent_req *subreq);
1945 : static void cli_unlink_done2(struct tevent_req *subreq);
1946 :
1947 : struct cli_unlink_state {
1948 : uint16_t vwv[1];
1949 : };
1950 :
1951 729 : struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
1952 : struct tevent_context *ev,
1953 : struct cli_state *cli,
1954 : const char *fname,
1955 : uint32_t mayhave_attrs)
1956 : {
1957 729 : struct tevent_req *req = NULL, *subreq = NULL;
1958 729 : struct cli_unlink_state *state = NULL;
1959 729 : uint8_t additional_flags = 0;
1960 729 : uint16_t additional_flags2 = 0;
1961 729 : uint8_t *bytes = NULL;
1962 729 : char *fname_cp = NULL;
1963 :
1964 729 : req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state);
1965 729 : if (req == NULL) {
1966 0 : return NULL;
1967 : }
1968 :
1969 729 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1970 530 : subreq = cli_smb2_unlink_send(state, ev, cli, fname, NULL);
1971 530 : if (tevent_req_nomem(subreq, req)) {
1972 0 : return tevent_req_post(req, ev);
1973 : }
1974 530 : tevent_req_set_callback(subreq, cli_unlink_done2, req);
1975 530 : return req;
1976 : }
1977 :
1978 199 : if (mayhave_attrs & 0xFFFF0000) {
1979 : /*
1980 : * Don't allow attributes greater than
1981 : * 16-bits for a 16-bit protocol value.
1982 : */
1983 1 : if (tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER)) {
1984 1 : return tevent_req_post(req, ev);
1985 : }
1986 : }
1987 :
1988 198 : SSVAL(state->vwv+0, 0, mayhave_attrs);
1989 :
1990 198 : bytes = talloc_array(state, uint8_t, 1);
1991 198 : if (tevent_req_nomem(bytes, req)) {
1992 0 : return tevent_req_post(req, ev);
1993 : }
1994 : /*
1995 : * SMBunlink on a DFS share must use DFS names.
1996 : */
1997 198 : fname_cp = smb1_dfs_share_path(state, cli, fname);
1998 198 : if (tevent_req_nomem(fname_cp, req)) {
1999 0 : return tevent_req_post(req, ev);
2000 : }
2001 198 : bytes[0] = 4;
2002 198 : bytes = smb_bytes_push_str(bytes,
2003 198 : smbXcli_conn_use_unicode(cli->conn),
2004 : fname_cp,
2005 198 : strlen(fname_cp)+1,
2006 : NULL);
2007 :
2008 198 : if (tevent_req_nomem(bytes, req)) {
2009 0 : return tevent_req_post(req, ev);
2010 : }
2011 :
2012 198 : if (clistr_is_previous_version_path(fname)) {
2013 0 : additional_flags2 = FLAGS2_REPARSE_PATH;
2014 : }
2015 :
2016 198 : subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags,
2017 : additional_flags2,
2018 198 : 1, state->vwv, talloc_get_size(bytes), bytes);
2019 198 : if (tevent_req_nomem(subreq, req)) {
2020 0 : return tevent_req_post(req, ev);
2021 : }
2022 198 : tevent_req_set_callback(subreq, cli_unlink_done, req);
2023 198 : return req;
2024 : }
2025 :
2026 198 : static void cli_unlink_done(struct tevent_req *subreq)
2027 : {
2028 198 : NTSTATUS status = cli_smb_recv(
2029 : subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2030 198 : tevent_req_simple_finish_ntstatus(subreq, status);
2031 198 : }
2032 :
2033 530 : static void cli_unlink_done2(struct tevent_req *subreq)
2034 : {
2035 530 : NTSTATUS status = cli_smb2_unlink_recv(subreq);
2036 530 : tevent_req_simple_finish_ntstatus(subreq, status);
2037 530 : }
2038 :
2039 729 : NTSTATUS cli_unlink_recv(struct tevent_req *req)
2040 : {
2041 729 : return tevent_req_simple_recv_ntstatus(req);
2042 : }
2043 :
2044 264 : NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint32_t mayhave_attrs)
2045 : {
2046 264 : TALLOC_CTX *frame = NULL;
2047 : struct tevent_context *ev;
2048 : struct tevent_req *req;
2049 264 : NTSTATUS status = NT_STATUS_OK;
2050 :
2051 264 : frame = talloc_stackframe();
2052 :
2053 264 : if (smbXcli_conn_has_async_calls(cli->conn)) {
2054 : /*
2055 : * Can't use sync call while an async call is in flight
2056 : */
2057 0 : status = NT_STATUS_INVALID_PARAMETER;
2058 0 : goto fail;
2059 : }
2060 :
2061 264 : ev = samba_tevent_context_init(frame);
2062 264 : if (ev == NULL) {
2063 0 : status = NT_STATUS_NO_MEMORY;
2064 0 : goto fail;
2065 : }
2066 :
2067 264 : req = cli_unlink_send(frame, ev, cli, fname, mayhave_attrs);
2068 264 : if (req == NULL) {
2069 0 : status = NT_STATUS_NO_MEMORY;
2070 0 : goto fail;
2071 : }
2072 :
2073 264 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2074 0 : goto fail;
2075 : }
2076 :
2077 264 : status = cli_unlink_recv(req);
2078 264 : cli->raw_status = status; /* cli_smb2_unlink_recv doesn't set this */
2079 :
2080 264 : fail:
2081 264 : TALLOC_FREE(frame);
2082 264 : return status;
2083 : }
2084 :
2085 : /****************************************************************************
2086 : Create a directory.
2087 : ****************************************************************************/
2088 :
2089 : static void cli_mkdir_done(struct tevent_req *subreq);
2090 : static void cli_mkdir_done2(struct tevent_req *subreq);
2091 :
2092 : struct cli_mkdir_state {
2093 : int dummy;
2094 : };
2095 :
2096 1009 : struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
2097 : struct tevent_context *ev,
2098 : struct cli_state *cli,
2099 : const char *dname)
2100 : {
2101 1009 : struct tevent_req *req = NULL, *subreq = NULL;
2102 1009 : struct cli_mkdir_state *state = NULL;
2103 1009 : uint8_t additional_flags = 0;
2104 1009 : uint16_t additional_flags2 = 0;
2105 1009 : uint8_t *bytes = NULL;
2106 1009 : char *dname_cp = NULL;
2107 :
2108 1009 : req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
2109 1009 : if (req == NULL) {
2110 0 : return NULL;
2111 : }
2112 :
2113 1009 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2114 1005 : subreq = cli_smb2_mkdir_send(state, ev, cli, dname);
2115 1005 : if (tevent_req_nomem(subreq, req)) {
2116 0 : return tevent_req_post(req, ev);
2117 : }
2118 1005 : tevent_req_set_callback(subreq, cli_mkdir_done2, req);
2119 1005 : return req;
2120 : }
2121 :
2122 4 : bytes = talloc_array(state, uint8_t, 1);
2123 4 : if (tevent_req_nomem(bytes, req)) {
2124 0 : return tevent_req_post(req, ev);
2125 : }
2126 : /*
2127 : * SMBmkdir on a DFS share must use DFS names.
2128 : */
2129 4 : dname_cp = smb1_dfs_share_path(state, cli, dname);
2130 4 : if (tevent_req_nomem(dname_cp, req)) {
2131 0 : return tevent_req_post(req, ev);
2132 : }
2133 4 : bytes[0] = 4;
2134 4 : bytes = smb_bytes_push_str(bytes,
2135 4 : smbXcli_conn_use_unicode(cli->conn),
2136 : dname_cp,
2137 4 : strlen(dname_cp)+1,
2138 : NULL);
2139 :
2140 4 : if (tevent_req_nomem(bytes, req)) {
2141 0 : return tevent_req_post(req, ev);
2142 : }
2143 :
2144 4 : if (clistr_is_previous_version_path(dname)) {
2145 0 : additional_flags2 = FLAGS2_REPARSE_PATH;
2146 : }
2147 :
2148 4 : subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags,
2149 : additional_flags2,
2150 4 : 0, NULL, talloc_get_size(bytes), bytes);
2151 4 : if (tevent_req_nomem(subreq, req)) {
2152 0 : return tevent_req_post(req, ev);
2153 : }
2154 4 : tevent_req_set_callback(subreq, cli_mkdir_done, req);
2155 4 : return req;
2156 : }
2157 :
2158 4 : static void cli_mkdir_done(struct tevent_req *subreq)
2159 : {
2160 4 : struct tevent_req *req = tevent_req_callback_data(
2161 : subreq, struct tevent_req);
2162 : NTSTATUS status;
2163 :
2164 4 : status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2165 4 : TALLOC_FREE(subreq);
2166 4 : if (tevent_req_nterror(req, status)) {
2167 0 : return;
2168 : }
2169 4 : tevent_req_done(req);
2170 : }
2171 :
2172 1005 : static void cli_mkdir_done2(struct tevent_req *subreq)
2173 : {
2174 1005 : NTSTATUS status = cli_smb2_mkdir_recv(subreq);
2175 1005 : tevent_req_simple_finish_ntstatus(subreq, status);
2176 1005 : }
2177 :
2178 1009 : NTSTATUS cli_mkdir_recv(struct tevent_req *req)
2179 : {
2180 1009 : return tevent_req_simple_recv_ntstatus(req);
2181 : }
2182 :
2183 97 : NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
2184 : {
2185 97 : TALLOC_CTX *frame = NULL;
2186 : struct tevent_context *ev;
2187 : struct tevent_req *req;
2188 97 : NTSTATUS status = NT_STATUS_OK;
2189 :
2190 97 : frame = talloc_stackframe();
2191 :
2192 97 : if (smbXcli_conn_has_async_calls(cli->conn)) {
2193 : /*
2194 : * Can't use sync call while an async call is in flight
2195 : */
2196 0 : status = NT_STATUS_INVALID_PARAMETER;
2197 0 : goto fail;
2198 : }
2199 :
2200 97 : ev = samba_tevent_context_init(frame);
2201 97 : if (ev == NULL) {
2202 0 : status = NT_STATUS_NO_MEMORY;
2203 0 : goto fail;
2204 : }
2205 :
2206 97 : req = cli_mkdir_send(frame, ev, cli, dname);
2207 97 : if (req == NULL) {
2208 0 : status = NT_STATUS_NO_MEMORY;
2209 0 : goto fail;
2210 : }
2211 :
2212 97 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2213 0 : goto fail;
2214 : }
2215 :
2216 97 : status = cli_mkdir_recv(req);
2217 97 : cli->raw_status = status; /* cli_smb2_mkdir_recv doesn't set this */
2218 :
2219 97 : fail:
2220 97 : TALLOC_FREE(frame);
2221 97 : return status;
2222 : }
2223 :
2224 : /****************************************************************************
2225 : Remove a directory.
2226 : ****************************************************************************/
2227 :
2228 : static void cli_rmdir_done(struct tevent_req *subreq);
2229 : static void cli_rmdir_done2(struct tevent_req *subreq);
2230 :
2231 : struct cli_rmdir_state {
2232 : int dummy;
2233 : };
2234 :
2235 1056 : struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
2236 : struct tevent_context *ev,
2237 : struct cli_state *cli,
2238 : const char *dname)
2239 : {
2240 1056 : struct tevent_req *req = NULL, *subreq = NULL;
2241 1056 : struct cli_rmdir_state *state = NULL;
2242 1056 : uint8_t additional_flags = 0;
2243 1056 : uint16_t additional_flags2 = 0;
2244 1056 : uint8_t *bytes = NULL;
2245 1056 : char *dname_cp = NULL;
2246 :
2247 1056 : req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
2248 1056 : if (req == NULL) {
2249 0 : return NULL;
2250 : }
2251 :
2252 1056 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2253 1051 : subreq = cli_smb2_rmdir_send(state, ev, cli, dname, NULL);
2254 1051 : if (tevent_req_nomem(subreq, req)) {
2255 0 : return tevent_req_post(req, ev);
2256 : }
2257 1051 : tevent_req_set_callback(subreq, cli_rmdir_done2, req);
2258 1051 : return req;
2259 : }
2260 :
2261 5 : bytes = talloc_array(state, uint8_t, 1);
2262 5 : if (tevent_req_nomem(bytes, req)) {
2263 0 : return tevent_req_post(req, ev);
2264 : }
2265 : /*
2266 : * SMBrmdir on a DFS share must use DFS names.
2267 : */
2268 5 : dname_cp = smb1_dfs_share_path(state, cli, dname);
2269 5 : if (tevent_req_nomem(dname_cp, req)) {
2270 0 : return tevent_req_post(req, ev);
2271 : }
2272 5 : bytes[0] = 4;
2273 5 : bytes = smb_bytes_push_str(bytes,
2274 5 : smbXcli_conn_use_unicode(cli->conn),
2275 : dname_cp,
2276 5 : strlen(dname_cp)+1,
2277 : NULL);
2278 :
2279 5 : if (tevent_req_nomem(bytes, req)) {
2280 0 : return tevent_req_post(req, ev);
2281 : }
2282 :
2283 5 : if (clistr_is_previous_version_path(dname)) {
2284 0 : additional_flags2 = FLAGS2_REPARSE_PATH;
2285 : }
2286 :
2287 5 : subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags,
2288 : additional_flags2,
2289 5 : 0, NULL, talloc_get_size(bytes), bytes);
2290 5 : if (tevent_req_nomem(subreq, req)) {
2291 0 : return tevent_req_post(req, ev);
2292 : }
2293 5 : tevent_req_set_callback(subreq, cli_rmdir_done, req);
2294 5 : return req;
2295 : }
2296 :
2297 5 : static void cli_rmdir_done(struct tevent_req *subreq)
2298 : {
2299 5 : NTSTATUS status = cli_smb_recv(
2300 : subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2301 5 : tevent_req_simple_finish_ntstatus(subreq, status);
2302 5 : }
2303 :
2304 1051 : static void cli_rmdir_done2(struct tevent_req *subreq)
2305 : {
2306 1051 : NTSTATUS status = cli_smb2_rmdir_recv(subreq);
2307 1051 : tevent_req_simple_finish_ntstatus(subreq, status);
2308 1051 : }
2309 :
2310 1056 : NTSTATUS cli_rmdir_recv(struct tevent_req *req)
2311 : {
2312 1056 : return tevent_req_simple_recv_ntstatus(req);
2313 : }
2314 :
2315 87 : NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
2316 : {
2317 87 : TALLOC_CTX *frame = NULL;
2318 : struct tevent_context *ev;
2319 : struct tevent_req *req;
2320 87 : NTSTATUS status = NT_STATUS_OK;
2321 :
2322 87 : frame = talloc_stackframe();
2323 :
2324 87 : if (smbXcli_conn_has_async_calls(cli->conn)) {
2325 : /*
2326 : * Can't use sync call while an async call is in flight
2327 : */
2328 0 : status = NT_STATUS_INVALID_PARAMETER;
2329 0 : goto fail;
2330 : }
2331 :
2332 87 : ev = samba_tevent_context_init(frame);
2333 87 : if (ev == NULL) {
2334 0 : status = NT_STATUS_NO_MEMORY;
2335 0 : goto fail;
2336 : }
2337 :
2338 87 : req = cli_rmdir_send(frame, ev, cli, dname);
2339 87 : if (req == NULL) {
2340 0 : status = NT_STATUS_NO_MEMORY;
2341 0 : goto fail;
2342 : }
2343 :
2344 87 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2345 0 : goto fail;
2346 : }
2347 :
2348 87 : status = cli_rmdir_recv(req);
2349 87 : cli->raw_status = status; /* cli_smb2_rmdir_recv doesn't set this */
2350 :
2351 87 : fail:
2352 87 : TALLOC_FREE(frame);
2353 87 : return status;
2354 : }
2355 :
2356 : /****************************************************************************
2357 : Set or clear the delete on close flag.
2358 : ****************************************************************************/
2359 :
2360 : struct doc_state {
2361 : uint8_t data[1];
2362 : };
2363 :
2364 : static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq);
2365 : static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq);
2366 :
2367 14 : struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
2368 : struct tevent_context *ev,
2369 : struct cli_state *cli,
2370 : uint16_t fnum,
2371 : bool flag)
2372 : {
2373 14 : struct tevent_req *req = NULL, *subreq = NULL;
2374 14 : struct doc_state *state = NULL;
2375 :
2376 14 : req = tevent_req_create(mem_ctx, &state, struct doc_state);
2377 14 : if (req == NULL) {
2378 0 : return NULL;
2379 : }
2380 :
2381 14 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2382 4 : subreq = cli_smb2_delete_on_close_send(state, ev, cli,
2383 : fnum, flag);
2384 4 : if (tevent_req_nomem(subreq, req)) {
2385 0 : return tevent_req_post(req, ev);
2386 : }
2387 4 : tevent_req_set_callback(subreq,
2388 : cli_nt_delete_on_close_smb2_done,
2389 : req);
2390 4 : return req;
2391 : }
2392 :
2393 : /* Setup data array. */
2394 10 : SCVAL(&state->data[0], 0, flag ? 1 : 0);
2395 :
2396 10 : subreq = cli_setfileinfo_send(
2397 : state,
2398 : ev,
2399 : cli,
2400 : fnum,
2401 : SMB_SET_FILE_DISPOSITION_INFO,
2402 10 : state->data,
2403 : sizeof(state->data));
2404 :
2405 10 : if (tevent_req_nomem(subreq, req)) {
2406 0 : return tevent_req_post(req, ev);
2407 : }
2408 10 : tevent_req_set_callback(subreq,
2409 : cli_nt_delete_on_close_smb1_done,
2410 : req);
2411 10 : return req;
2412 : }
2413 :
2414 10 : static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq)
2415 : {
2416 10 : NTSTATUS status = cli_setfileinfo_recv(subreq);
2417 10 : tevent_req_simple_finish_ntstatus(subreq, status);
2418 10 : }
2419 :
2420 4 : static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq)
2421 : {
2422 4 : NTSTATUS status = cli_smb2_delete_on_close_recv(subreq);
2423 4 : tevent_req_simple_finish_ntstatus(subreq, status);
2424 4 : }
2425 :
2426 14 : NTSTATUS cli_nt_delete_on_close_recv(struct tevent_req *req)
2427 : {
2428 14 : return tevent_req_simple_recv_ntstatus(req);
2429 : }
2430 :
2431 10 : NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
2432 : {
2433 10 : TALLOC_CTX *frame = talloc_stackframe();
2434 10 : struct tevent_context *ev = NULL;
2435 10 : struct tevent_req *req = NULL;
2436 10 : NTSTATUS status = NT_STATUS_OK;
2437 :
2438 10 : if (smbXcli_conn_has_async_calls(cli->conn)) {
2439 : /*
2440 : * Can't use sync call while an async call is in flight
2441 : */
2442 0 : status = NT_STATUS_INVALID_PARAMETER;
2443 0 : goto fail;
2444 : }
2445 :
2446 10 : ev = samba_tevent_context_init(frame);
2447 10 : if (ev == NULL) {
2448 0 : status = NT_STATUS_NO_MEMORY;
2449 0 : goto fail;
2450 : }
2451 :
2452 10 : req = cli_nt_delete_on_close_send(frame,
2453 : ev,
2454 : cli,
2455 : fnum,
2456 : flag);
2457 10 : if (req == NULL) {
2458 0 : status = NT_STATUS_NO_MEMORY;
2459 0 : goto fail;
2460 : }
2461 :
2462 10 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2463 0 : goto fail;
2464 : }
2465 :
2466 10 : status = cli_nt_delete_on_close_recv(req);
2467 :
2468 10 : fail:
2469 10 : TALLOC_FREE(frame);
2470 10 : return status;
2471 : }
2472 :
2473 : struct cli_ntcreate1_state {
2474 : uint16_t vwv[24];
2475 : uint16_t fnum;
2476 : struct smb_create_returns cr;
2477 : struct tevent_req *subreq;
2478 : };
2479 :
2480 : static void cli_ntcreate1_done(struct tevent_req *subreq);
2481 : static bool cli_ntcreate1_cancel(struct tevent_req *req);
2482 :
2483 65 : static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx,
2484 : struct tevent_context *ev,
2485 : struct cli_state *cli,
2486 : const char *fname,
2487 : uint32_t CreatFlags,
2488 : uint32_t DesiredAccess,
2489 : uint32_t FileAttributes,
2490 : uint32_t ShareAccess,
2491 : uint32_t CreateDisposition,
2492 : uint32_t CreateOptions,
2493 : uint32_t ImpersonationLevel,
2494 : uint8_t SecurityFlags)
2495 : {
2496 : struct tevent_req *req, *subreq;
2497 : struct cli_ntcreate1_state *state;
2498 : uint16_t *vwv;
2499 : uint8_t *bytes;
2500 : size_t converted_len;
2501 65 : uint16_t additional_flags2 = 0;
2502 65 : char *fname_cp = NULL;
2503 :
2504 65 : req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate1_state);
2505 65 : if (req == NULL) {
2506 0 : return NULL;
2507 : }
2508 :
2509 65 : vwv = state->vwv;
2510 :
2511 65 : SCVAL(vwv+0, 0, 0xFF);
2512 65 : SCVAL(vwv+0, 1, 0);
2513 65 : SSVAL(vwv+1, 0, 0);
2514 65 : SCVAL(vwv+2, 0, 0);
2515 :
2516 65 : if (cli->use_oplocks) {
2517 0 : CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
2518 : }
2519 65 : SIVAL(vwv+3, 1, CreatFlags);
2520 65 : SIVAL(vwv+5, 1, 0x0); /* RootDirectoryFid */
2521 65 : SIVAL(vwv+7, 1, DesiredAccess);
2522 65 : SIVAL(vwv+9, 1, 0x0); /* AllocationSize */
2523 65 : SIVAL(vwv+11, 1, 0x0); /* AllocationSize */
2524 65 : SIVAL(vwv+13, 1, FileAttributes);
2525 65 : SIVAL(vwv+15, 1, ShareAccess);
2526 65 : SIVAL(vwv+17, 1, CreateDisposition);
2527 65 : SIVAL(vwv+19, 1, CreateOptions |
2528 : (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
2529 65 : SIVAL(vwv+21, 1, ImpersonationLevel);
2530 65 : SCVAL(vwv+23, 1, SecurityFlags);
2531 :
2532 65 : bytes = talloc_array(state, uint8_t, 0);
2533 65 : if (tevent_req_nomem(bytes, req)) {
2534 0 : return tevent_req_post(req, ev);
2535 : }
2536 : /*
2537 : * SMBntcreateX on a DFS share must use DFS names.
2538 : */
2539 65 : fname_cp = smb1_dfs_share_path(state, cli, fname);
2540 65 : if (tevent_req_nomem(fname_cp, req)) {
2541 0 : return tevent_req_post(req, ev);
2542 : }
2543 65 : bytes = smb_bytes_push_str(bytes,
2544 65 : smbXcli_conn_use_unicode(cli->conn),
2545 : fname_cp,
2546 65 : strlen(fname_cp)+1,
2547 : &converted_len);
2548 65 : if (tevent_req_nomem(bytes, req)) {
2549 0 : return tevent_req_post(req, ev);
2550 : }
2551 :
2552 65 : if (clistr_is_previous_version_path(fname)) {
2553 0 : additional_flags2 = FLAGS2_REPARSE_PATH;
2554 : }
2555 :
2556 : /* sigh. this copes with broken netapp filer behaviour */
2557 65 : bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 1, NULL);
2558 :
2559 65 : if (tevent_req_nomem(bytes, req)) {
2560 0 : return tevent_req_post(req, ev);
2561 : }
2562 :
2563 65 : SSVAL(vwv+2, 1, converted_len);
2564 :
2565 65 : subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0,
2566 : additional_flags2, 24, vwv,
2567 65 : talloc_get_size(bytes), bytes);
2568 65 : if (tevent_req_nomem(subreq, req)) {
2569 0 : return tevent_req_post(req, ev);
2570 : }
2571 65 : tevent_req_set_callback(subreq, cli_ntcreate1_done, req);
2572 :
2573 65 : state->subreq = subreq;
2574 65 : tevent_req_set_cancel_fn(req, cli_ntcreate1_cancel);
2575 :
2576 65 : return req;
2577 : }
2578 :
2579 65 : static void cli_ntcreate1_done(struct tevent_req *subreq)
2580 : {
2581 65 : struct tevent_req *req = tevent_req_callback_data(
2582 : subreq, struct tevent_req);
2583 65 : struct cli_ntcreate1_state *state = tevent_req_data(
2584 : req, struct cli_ntcreate1_state);
2585 : uint8_t wct;
2586 : uint16_t *vwv;
2587 : uint32_t num_bytes;
2588 : uint8_t *bytes;
2589 : NTSTATUS status;
2590 :
2591 65 : status = cli_smb_recv(subreq, state, NULL, 34, &wct, &vwv,
2592 : &num_bytes, &bytes);
2593 65 : TALLOC_FREE(subreq);
2594 65 : if (tevent_req_nterror(req, status)) {
2595 11 : return;
2596 : }
2597 54 : state->cr.oplock_level = CVAL(vwv+2, 0);
2598 54 : state->fnum = SVAL(vwv+2, 1);
2599 54 : state->cr.create_action = IVAL(vwv+3, 1);
2600 54 : state->cr.creation_time = BVAL(vwv+5, 1);
2601 54 : state->cr.last_access_time = BVAL(vwv+9, 1);
2602 54 : state->cr.last_write_time = BVAL(vwv+13, 1);
2603 54 : state->cr.change_time = BVAL(vwv+17, 1);
2604 54 : state->cr.file_attributes = IVAL(vwv+21, 1);
2605 54 : state->cr.allocation_size = BVAL(vwv+23, 1);
2606 54 : state->cr.end_of_file = BVAL(vwv+27, 1);
2607 :
2608 54 : tevent_req_done(req);
2609 : }
2610 :
2611 0 : static bool cli_ntcreate1_cancel(struct tevent_req *req)
2612 : {
2613 0 : struct cli_ntcreate1_state *state = tevent_req_data(
2614 : req, struct cli_ntcreate1_state);
2615 0 : return tevent_req_cancel(state->subreq);
2616 : }
2617 :
2618 65 : static NTSTATUS cli_ntcreate1_recv(struct tevent_req *req,
2619 : uint16_t *pfnum,
2620 : struct smb_create_returns *cr)
2621 : {
2622 65 : struct cli_ntcreate1_state *state = tevent_req_data(
2623 : req, struct cli_ntcreate1_state);
2624 : NTSTATUS status;
2625 :
2626 65 : if (tevent_req_is_nterror(req, &status)) {
2627 11 : return status;
2628 : }
2629 54 : *pfnum = state->fnum;
2630 54 : if (cr != NULL) {
2631 54 : *cr = state->cr;
2632 : }
2633 54 : return NT_STATUS_OK;
2634 : }
2635 :
2636 : struct cli_ntcreate_state {
2637 : struct smb_create_returns cr;
2638 : uint16_t fnum;
2639 : struct tevent_req *subreq;
2640 : };
2641 :
2642 : static void cli_ntcreate_done_nt1(struct tevent_req *subreq);
2643 : static void cli_ntcreate_done_smb2(struct tevent_req *subreq);
2644 : static bool cli_ntcreate_cancel(struct tevent_req *req);
2645 :
2646 4852 : struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
2647 : struct tevent_context *ev,
2648 : struct cli_state *cli,
2649 : const char *fname,
2650 : uint32_t create_flags,
2651 : uint32_t desired_access,
2652 : uint32_t file_attributes,
2653 : uint32_t share_access,
2654 : uint32_t create_disposition,
2655 : uint32_t create_options,
2656 : uint32_t impersonation_level,
2657 : uint8_t security_flags)
2658 : {
2659 : struct tevent_req *req, *subreq;
2660 : struct cli_ntcreate_state *state;
2661 :
2662 4852 : req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
2663 4852 : if (req == NULL) {
2664 0 : return NULL;
2665 : }
2666 :
2667 4852 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2668 4787 : if (cli->use_oplocks) {
2669 0 : create_flags |= REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK;
2670 : }
2671 :
2672 4787 : subreq = cli_smb2_create_fnum_send(
2673 : state,
2674 : ev,
2675 : cli,
2676 : fname,
2677 : create_flags,
2678 : impersonation_level,
2679 : desired_access,
2680 : file_attributes,
2681 : share_access,
2682 : create_disposition,
2683 : create_options,
2684 : NULL);
2685 4787 : if (tevent_req_nomem(subreq, req)) {
2686 0 : return tevent_req_post(req, ev);
2687 : }
2688 4787 : tevent_req_set_callback(subreq, cli_ntcreate_done_smb2, req);
2689 : } else {
2690 65 : subreq = cli_ntcreate1_send(
2691 : state, ev, cli, fname, create_flags, desired_access,
2692 : file_attributes, share_access, create_disposition,
2693 : create_options, impersonation_level, security_flags);
2694 65 : if (tevent_req_nomem(subreq, req)) {
2695 0 : return tevent_req_post(req, ev);
2696 : }
2697 65 : tevent_req_set_callback(subreq, cli_ntcreate_done_nt1, req);
2698 : }
2699 :
2700 4852 : state->subreq = subreq;
2701 4852 : tevent_req_set_cancel_fn(req, cli_ntcreate_cancel);
2702 :
2703 4852 : return req;
2704 : }
2705 :
2706 65 : static void cli_ntcreate_done_nt1(struct tevent_req *subreq)
2707 : {
2708 65 : struct tevent_req *req = tevent_req_callback_data(
2709 : subreq, struct tevent_req);
2710 65 : struct cli_ntcreate_state *state = tevent_req_data(
2711 : req, struct cli_ntcreate_state);
2712 : NTSTATUS status;
2713 :
2714 65 : status = cli_ntcreate1_recv(subreq, &state->fnum, &state->cr);
2715 65 : TALLOC_FREE(subreq);
2716 65 : if (tevent_req_nterror(req, status)) {
2717 11 : return;
2718 : }
2719 54 : tevent_req_done(req);
2720 : }
2721 :
2722 4787 : static void cli_ntcreate_done_smb2(struct tevent_req *subreq)
2723 : {
2724 4787 : struct tevent_req *req = tevent_req_callback_data(
2725 : subreq, struct tevent_req);
2726 4787 : struct cli_ntcreate_state *state = tevent_req_data(
2727 : req, struct cli_ntcreate_state);
2728 : NTSTATUS status;
2729 :
2730 4787 : status = cli_smb2_create_fnum_recv(
2731 : subreq,
2732 : &state->fnum,
2733 : &state->cr,
2734 : NULL,
2735 : NULL,
2736 : NULL);
2737 4787 : TALLOC_FREE(subreq);
2738 4787 : if (tevent_req_nterror(req, status)) {
2739 874 : return;
2740 : }
2741 3913 : tevent_req_done(req);
2742 : }
2743 :
2744 0 : static bool cli_ntcreate_cancel(struct tevent_req *req)
2745 : {
2746 0 : struct cli_ntcreate_state *state = tevent_req_data(
2747 : req, struct cli_ntcreate_state);
2748 0 : return tevent_req_cancel(state->subreq);
2749 : }
2750 :
2751 4852 : NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *fnum,
2752 : struct smb_create_returns *cr)
2753 : {
2754 4852 : struct cli_ntcreate_state *state = tevent_req_data(
2755 : req, struct cli_ntcreate_state);
2756 : NTSTATUS status;
2757 :
2758 4852 : if (tevent_req_is_nterror(req, &status)) {
2759 885 : return status;
2760 : }
2761 3967 : if (fnum != NULL) {
2762 3967 : *fnum = state->fnum;
2763 : }
2764 3967 : if (cr != NULL) {
2765 94 : *cr = state->cr;
2766 : }
2767 3967 : return NT_STATUS_OK;
2768 : }
2769 :
2770 217 : NTSTATUS cli_ntcreate(struct cli_state *cli,
2771 : const char *fname,
2772 : uint32_t CreatFlags,
2773 : uint32_t DesiredAccess,
2774 : uint32_t FileAttributes,
2775 : uint32_t ShareAccess,
2776 : uint32_t CreateDisposition,
2777 : uint32_t CreateOptions,
2778 : uint8_t SecurityFlags,
2779 : uint16_t *pfid,
2780 : struct smb_create_returns *cr)
2781 : {
2782 217 : TALLOC_CTX *frame = talloc_stackframe();
2783 : struct tevent_context *ev;
2784 : struct tevent_req *req;
2785 217 : uint32_t ImpersonationLevel = SMB2_IMPERSONATION_IMPERSONATION;
2786 217 : NTSTATUS status = NT_STATUS_NO_MEMORY;
2787 :
2788 217 : if (smbXcli_conn_has_async_calls(cli->conn)) {
2789 : /*
2790 : * Can't use sync call while an async call is in flight
2791 : */
2792 0 : status = NT_STATUS_INVALID_PARAMETER;
2793 0 : goto fail;
2794 : }
2795 :
2796 217 : ev = samba_tevent_context_init(frame);
2797 217 : if (ev == NULL) {
2798 0 : goto fail;
2799 : }
2800 :
2801 217 : req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
2802 : DesiredAccess, FileAttributes, ShareAccess,
2803 : CreateDisposition, CreateOptions,
2804 : ImpersonationLevel, SecurityFlags);
2805 217 : if (req == NULL) {
2806 0 : goto fail;
2807 : }
2808 :
2809 217 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2810 0 : goto fail;
2811 : }
2812 :
2813 217 : status = cli_ntcreate_recv(req, pfid, cr);
2814 217 : fail:
2815 217 : TALLOC_FREE(frame);
2816 217 : return status;
2817 : }
2818 :
2819 : struct cli_nttrans_create_state {
2820 : uint16_t fnum;
2821 : struct smb_create_returns cr;
2822 : };
2823 :
2824 : static void cli_nttrans_create_done(struct tevent_req *subreq);
2825 :
2826 0 : struct tevent_req *cli_nttrans_create_send(TALLOC_CTX *mem_ctx,
2827 : struct tevent_context *ev,
2828 : struct cli_state *cli,
2829 : const char *fname,
2830 : uint32_t CreatFlags,
2831 : uint32_t DesiredAccess,
2832 : uint32_t FileAttributes,
2833 : uint32_t ShareAccess,
2834 : uint32_t CreateDisposition,
2835 : uint32_t CreateOptions,
2836 : uint8_t SecurityFlags,
2837 : struct security_descriptor *secdesc,
2838 : struct ea_struct *eas,
2839 : int num_eas)
2840 : {
2841 : struct tevent_req *req, *subreq;
2842 : struct cli_nttrans_create_state *state;
2843 : uint8_t *param;
2844 : uint8_t *secdesc_buf;
2845 : size_t secdesc_len;
2846 : NTSTATUS status;
2847 : size_t converted_len;
2848 0 : uint16_t additional_flags2 = 0;
2849 0 : char *fname_cp = NULL;
2850 :
2851 0 : req = tevent_req_create(mem_ctx,
2852 : &state, struct cli_nttrans_create_state);
2853 0 : if (req == NULL) {
2854 0 : return NULL;
2855 : }
2856 :
2857 0 : if (secdesc != NULL) {
2858 0 : status = marshall_sec_desc(talloc_tos(), secdesc,
2859 : &secdesc_buf, &secdesc_len);
2860 0 : if (tevent_req_nterror(req, status)) {
2861 0 : DEBUG(10, ("marshall_sec_desc failed: %s\n",
2862 : nt_errstr(status)));
2863 0 : return tevent_req_post(req, ev);
2864 : }
2865 : } else {
2866 0 : secdesc_buf = NULL;
2867 0 : secdesc_len = 0;
2868 : }
2869 :
2870 0 : if (num_eas != 0) {
2871 : /*
2872 : * TODO ;-)
2873 : */
2874 0 : tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2875 0 : return tevent_req_post(req, ev);
2876 : }
2877 :
2878 0 : param = talloc_array(state, uint8_t, 53);
2879 0 : if (tevent_req_nomem(param, req)) {
2880 0 : return tevent_req_post(req, ev);
2881 : }
2882 :
2883 : /*
2884 : * SMBntcreateX on a DFS share must use DFS names.
2885 : */
2886 0 : fname_cp = smb1_dfs_share_path(state, cli, fname);
2887 0 : if (tevent_req_nomem(fname_cp, req)) {
2888 0 : return tevent_req_post(req, ev);
2889 : }
2890 0 : param = trans2_bytes_push_str(param,
2891 0 : smbXcli_conn_use_unicode(cli->conn),
2892 : fname_cp,
2893 : strlen(fname_cp),
2894 : &converted_len);
2895 0 : if (tevent_req_nomem(param, req)) {
2896 0 : return tevent_req_post(req, ev);
2897 : }
2898 :
2899 0 : if (clistr_is_previous_version_path(fname)) {
2900 0 : additional_flags2 = FLAGS2_REPARSE_PATH;
2901 : }
2902 :
2903 0 : SIVAL(param, 0, CreatFlags);
2904 0 : SIVAL(param, 4, 0x0); /* RootDirectoryFid */
2905 0 : SIVAL(param, 8, DesiredAccess);
2906 0 : SIVAL(param, 12, 0x0); /* AllocationSize */
2907 0 : SIVAL(param, 16, 0x0); /* AllocationSize */
2908 0 : SIVAL(param, 20, FileAttributes);
2909 0 : SIVAL(param, 24, ShareAccess);
2910 0 : SIVAL(param, 28, CreateDisposition);
2911 0 : SIVAL(param, 32, CreateOptions |
2912 : (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
2913 0 : SIVAL(param, 36, secdesc_len);
2914 0 : SIVAL(param, 40, 0); /* EA length*/
2915 0 : SIVAL(param, 44, converted_len);
2916 0 : SIVAL(param, 48, 0x02); /* ImpersonationLevel */
2917 0 : SCVAL(param, 52, SecurityFlags);
2918 :
2919 0 : subreq = cli_trans_send(state, ev, cli,
2920 : additional_flags2, /* additional_flags2 */
2921 : SMBnttrans,
2922 : NULL, -1, /* name, fid */
2923 : NT_TRANSACT_CREATE, 0,
2924 : NULL, 0, 0, /* setup */
2925 0 : param, talloc_get_size(param), 128, /* param */
2926 : secdesc_buf, secdesc_len, 0); /* data */
2927 0 : if (tevent_req_nomem(subreq, req)) {
2928 0 : return tevent_req_post(req, ev);
2929 : }
2930 0 : tevent_req_set_callback(subreq, cli_nttrans_create_done, req);
2931 0 : return req;
2932 : }
2933 :
2934 0 : static void cli_nttrans_create_done(struct tevent_req *subreq)
2935 : {
2936 0 : struct tevent_req *req = tevent_req_callback_data(
2937 : subreq, struct tevent_req);
2938 0 : struct cli_nttrans_create_state *state = tevent_req_data(
2939 : req, struct cli_nttrans_create_state);
2940 : uint8_t *param;
2941 : uint32_t num_param;
2942 : NTSTATUS status;
2943 :
2944 0 : status = cli_trans_recv(subreq, talloc_tos(), NULL,
2945 : NULL, 0, NULL, /* rsetup */
2946 : ¶m, 69, &num_param,
2947 : NULL, 0, NULL);
2948 0 : if (tevent_req_nterror(req, status)) {
2949 0 : return;
2950 : }
2951 0 : state->cr.oplock_level = CVAL(param, 0);
2952 0 : state->fnum = SVAL(param, 2);
2953 0 : state->cr.create_action = IVAL(param, 4);
2954 0 : state->cr.creation_time = BVAL(param, 12);
2955 0 : state->cr.last_access_time = BVAL(param, 20);
2956 0 : state->cr.last_write_time = BVAL(param, 28);
2957 0 : state->cr.change_time = BVAL(param, 36);
2958 0 : state->cr.file_attributes = IVAL(param, 44);
2959 0 : state->cr.allocation_size = BVAL(param, 48);
2960 0 : state->cr.end_of_file = BVAL(param, 56);
2961 :
2962 0 : TALLOC_FREE(param);
2963 0 : tevent_req_done(req);
2964 : }
2965 :
2966 0 : NTSTATUS cli_nttrans_create_recv(struct tevent_req *req,
2967 : uint16_t *fnum,
2968 : struct smb_create_returns *cr)
2969 : {
2970 0 : struct cli_nttrans_create_state *state = tevent_req_data(
2971 : req, struct cli_nttrans_create_state);
2972 : NTSTATUS status;
2973 :
2974 0 : if (tevent_req_is_nterror(req, &status)) {
2975 0 : return status;
2976 : }
2977 0 : *fnum = state->fnum;
2978 0 : if (cr != NULL) {
2979 0 : *cr = state->cr;
2980 : }
2981 0 : return NT_STATUS_OK;
2982 : }
2983 :
2984 0 : NTSTATUS cli_nttrans_create(struct cli_state *cli,
2985 : const char *fname,
2986 : uint32_t CreatFlags,
2987 : uint32_t DesiredAccess,
2988 : uint32_t FileAttributes,
2989 : uint32_t ShareAccess,
2990 : uint32_t CreateDisposition,
2991 : uint32_t CreateOptions,
2992 : uint8_t SecurityFlags,
2993 : struct security_descriptor *secdesc,
2994 : struct ea_struct *eas,
2995 : int num_eas,
2996 : uint16_t *pfid,
2997 : struct smb_create_returns *cr)
2998 : {
2999 0 : TALLOC_CTX *frame = talloc_stackframe();
3000 : struct tevent_context *ev;
3001 : struct tevent_req *req;
3002 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
3003 :
3004 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
3005 : /*
3006 : * Can't use sync call while an async call is in flight
3007 : */
3008 0 : status = NT_STATUS_INVALID_PARAMETER;
3009 0 : goto fail;
3010 : }
3011 0 : ev = samba_tevent_context_init(frame);
3012 0 : if (ev == NULL) {
3013 0 : goto fail;
3014 : }
3015 0 : req = cli_nttrans_create_send(frame, ev, cli, fname, CreatFlags,
3016 : DesiredAccess, FileAttributes,
3017 : ShareAccess, CreateDisposition,
3018 : CreateOptions, SecurityFlags,
3019 : secdesc, eas, num_eas);
3020 0 : if (req == NULL) {
3021 0 : goto fail;
3022 : }
3023 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3024 0 : goto fail;
3025 : }
3026 0 : status = cli_nttrans_create_recv(req, pfid, cr);
3027 0 : fail:
3028 0 : TALLOC_FREE(frame);
3029 0 : return status;
3030 : }
3031 :
3032 : /****************************************************************************
3033 : Open a file
3034 : WARNING: if you open with O_WRONLY then getattrE won't work!
3035 : ****************************************************************************/
3036 :
3037 : struct cli_openx_state {
3038 : const char *fname;
3039 : uint16_t vwv[15];
3040 : uint16_t fnum;
3041 : struct iovec bytes;
3042 : };
3043 :
3044 : static void cli_openx_done(struct tevent_req *subreq);
3045 :
3046 174 : struct tevent_req *cli_openx_create(TALLOC_CTX *mem_ctx,
3047 : struct tevent_context *ev,
3048 : struct cli_state *cli, const char *fname,
3049 : int flags, int share_mode,
3050 : struct tevent_req **psmbreq)
3051 : {
3052 : struct tevent_req *req, *subreq;
3053 : struct cli_openx_state *state;
3054 : unsigned openfn;
3055 : unsigned accessmode;
3056 : uint8_t additional_flags;
3057 174 : uint16_t additional_flags2 = 0;
3058 : uint8_t *bytes;
3059 174 : char *fname_cp = NULL;
3060 :
3061 174 : req = tevent_req_create(mem_ctx, &state, struct cli_openx_state);
3062 174 : if (req == NULL) {
3063 0 : return NULL;
3064 : }
3065 :
3066 174 : openfn = 0;
3067 174 : if (flags & O_CREAT) {
3068 143 : openfn |= (1<<4);
3069 : }
3070 174 : if (!(flags & O_EXCL)) {
3071 150 : if (flags & O_TRUNC)
3072 7 : openfn |= (1<<1);
3073 : else
3074 143 : openfn |= (1<<0);
3075 : }
3076 :
3077 174 : accessmode = (share_mode<<4);
3078 :
3079 174 : if ((flags & O_ACCMODE) == O_RDWR) {
3080 164 : accessmode |= 2;
3081 10 : } else if ((flags & O_ACCMODE) == O_WRONLY) {
3082 0 : accessmode |= 1;
3083 : }
3084 :
3085 : #if defined(O_SYNC)
3086 174 : if ((flags & O_SYNC) == O_SYNC) {
3087 0 : accessmode |= (1<<14);
3088 : }
3089 : #endif /* O_SYNC */
3090 :
3091 174 : if (share_mode == DENY_FCB) {
3092 0 : accessmode = 0xFF;
3093 : }
3094 :
3095 174 : SCVAL(state->vwv + 0, 0, 0xFF);
3096 174 : SCVAL(state->vwv + 0, 1, 0);
3097 174 : SSVAL(state->vwv + 1, 0, 0);
3098 174 : SSVAL(state->vwv + 2, 0, 0); /* no additional info */
3099 174 : SSVAL(state->vwv + 3, 0, accessmode);
3100 174 : SSVAL(state->vwv + 4, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
3101 174 : SSVAL(state->vwv + 5, 0, 0);
3102 174 : SIVAL(state->vwv + 6, 0, 0);
3103 174 : SSVAL(state->vwv + 8, 0, openfn);
3104 174 : SIVAL(state->vwv + 9, 0, 0);
3105 174 : SIVAL(state->vwv + 11, 0, 0);
3106 174 : SIVAL(state->vwv + 13, 0, 0);
3107 :
3108 174 : additional_flags = 0;
3109 :
3110 174 : if (cli->use_oplocks) {
3111 : /* if using oplocks then ask for a batch oplock via
3112 : core and extended methods */
3113 3 : additional_flags =
3114 : FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
3115 3 : SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
3116 : }
3117 :
3118 174 : bytes = talloc_array(state, uint8_t, 0);
3119 174 : if (tevent_req_nomem(bytes, req)) {
3120 0 : return tevent_req_post(req, ev);
3121 : }
3122 : /*
3123 : * SMBopenX on a DFS share must use DFS names.
3124 : */
3125 174 : fname_cp = smb1_dfs_share_path(state, cli, fname);
3126 174 : if (tevent_req_nomem(fname_cp, req)) {
3127 0 : return tevent_req_post(req, ev);
3128 : }
3129 174 : bytes = smb_bytes_push_str(bytes,
3130 174 : smbXcli_conn_use_unicode(cli->conn),
3131 : fname_cp,
3132 174 : strlen(fname_cp)+1,
3133 : NULL);
3134 :
3135 174 : if (tevent_req_nomem(bytes, req)) {
3136 0 : return tevent_req_post(req, ev);
3137 : }
3138 :
3139 174 : if (clistr_is_previous_version_path(fname)) {
3140 0 : additional_flags2 = FLAGS2_REPARSE_PATH;
3141 : }
3142 :
3143 174 : state->bytes.iov_base = (void *)bytes;
3144 174 : state->bytes.iov_len = talloc_get_size(bytes);
3145 :
3146 174 : subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
3147 174 : additional_flags2, 15, state->vwv, 1, &state->bytes);
3148 174 : if (subreq == NULL) {
3149 0 : TALLOC_FREE(req);
3150 0 : return NULL;
3151 : }
3152 174 : tevent_req_set_callback(subreq, cli_openx_done, req);
3153 174 : *psmbreq = subreq;
3154 174 : return req;
3155 : }
3156 :
3157 172 : struct tevent_req *cli_openx_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
3158 : struct cli_state *cli, const char *fname,
3159 : int flags, int share_mode)
3160 : {
3161 : struct tevent_req *req, *subreq;
3162 : NTSTATUS status;
3163 :
3164 172 : req = cli_openx_create(mem_ctx, ev, cli, fname, flags, share_mode,
3165 : &subreq);
3166 172 : if (req == NULL) {
3167 0 : return NULL;
3168 : }
3169 :
3170 172 : status = smb1cli_req_chain_submit(&subreq, 1);
3171 172 : if (tevent_req_nterror(req, status)) {
3172 0 : return tevent_req_post(req, ev);
3173 : }
3174 172 : return req;
3175 : }
3176 :
3177 174 : static void cli_openx_done(struct tevent_req *subreq)
3178 : {
3179 174 : struct tevent_req *req = tevent_req_callback_data(
3180 : subreq, struct tevent_req);
3181 174 : struct cli_openx_state *state = tevent_req_data(
3182 : req, struct cli_openx_state);
3183 : uint8_t wct;
3184 : uint16_t *vwv;
3185 : NTSTATUS status;
3186 :
3187 174 : status = cli_smb_recv(subreq, state, NULL, 3, &wct, &vwv, NULL,
3188 : NULL);
3189 174 : TALLOC_FREE(subreq);
3190 174 : if (tevent_req_nterror(req, status)) {
3191 9 : return;
3192 : }
3193 165 : state->fnum = SVAL(vwv+2, 0);
3194 165 : tevent_req_done(req);
3195 : }
3196 :
3197 174 : NTSTATUS cli_openx_recv(struct tevent_req *req, uint16_t *pfnum)
3198 : {
3199 174 : struct cli_openx_state *state = tevent_req_data(
3200 : req, struct cli_openx_state);
3201 : NTSTATUS status;
3202 :
3203 174 : if (tevent_req_is_nterror(req, &status)) {
3204 9 : return status;
3205 : }
3206 165 : *pfnum = state->fnum;
3207 165 : return NT_STATUS_OK;
3208 : }
3209 :
3210 171 : NTSTATUS cli_openx(struct cli_state *cli, const char *fname, int flags,
3211 : int share_mode, uint16_t *pfnum)
3212 : {
3213 171 : TALLOC_CTX *frame = talloc_stackframe();
3214 : struct tevent_context *ev;
3215 : struct tevent_req *req;
3216 171 : NTSTATUS status = NT_STATUS_NO_MEMORY;
3217 :
3218 171 : if (smbXcli_conn_has_async_calls(cli->conn)) {
3219 : /*
3220 : * Can't use sync call while an async call is in flight
3221 : */
3222 0 : status = NT_STATUS_INVALID_PARAMETER;
3223 0 : goto fail;
3224 : }
3225 :
3226 171 : ev = samba_tevent_context_init(frame);
3227 171 : if (ev == NULL) {
3228 0 : goto fail;
3229 : }
3230 :
3231 171 : req = cli_openx_send(frame, ev, cli, fname, flags, share_mode);
3232 171 : if (req == NULL) {
3233 0 : goto fail;
3234 : }
3235 :
3236 171 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3237 0 : goto fail;
3238 : }
3239 :
3240 171 : status = cli_openx_recv(req, pfnum);
3241 171 : fail:
3242 171 : TALLOC_FREE(frame);
3243 171 : return status;
3244 : }
3245 : /****************************************************************************
3246 : Synchronous wrapper function that does an NtCreateX open by preference
3247 : and falls back to openX if this fails.
3248 : ****************************************************************************/
3249 :
3250 110 : NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
3251 : int share_mode_in, uint16_t *pfnum)
3252 : {
3253 : NTSTATUS status;
3254 110 : unsigned int openfn = 0;
3255 110 : unsigned int dos_deny = 0;
3256 : uint32_t access_mask, share_mode, create_disposition, create_options;
3257 110 : struct smb_create_returns cr = {0};
3258 :
3259 : /* Do the initial mapping into OpenX parameters. */
3260 110 : if (flags & O_CREAT) {
3261 89 : openfn |= (1<<4);
3262 : }
3263 110 : if (!(flags & O_EXCL)) {
3264 110 : if (flags & O_TRUNC)
3265 89 : openfn |= (1<<1);
3266 : else
3267 21 : openfn |= (1<<0);
3268 : }
3269 :
3270 110 : dos_deny = (share_mode_in<<4);
3271 :
3272 110 : if ((flags & O_ACCMODE) == O_RDWR) {
3273 89 : dos_deny |= 2;
3274 21 : } else if ((flags & O_ACCMODE) == O_WRONLY) {
3275 0 : dos_deny |= 1;
3276 : }
3277 :
3278 : #if defined(O_SYNC)
3279 110 : if ((flags & O_SYNC) == O_SYNC) {
3280 0 : dos_deny |= (1<<14);
3281 : }
3282 : #endif /* O_SYNC */
3283 :
3284 110 : if (share_mode_in == DENY_FCB) {
3285 0 : dos_deny = 0xFF;
3286 : }
3287 :
3288 110 : if (!map_open_params_to_ntcreate(fname, dos_deny,
3289 : openfn, &access_mask,
3290 : &share_mode, &create_disposition,
3291 : &create_options, NULL)) {
3292 0 : goto try_openx;
3293 : }
3294 :
3295 110 : status = cli_ntcreate(cli,
3296 : fname,
3297 : 0,
3298 : access_mask,
3299 : 0,
3300 : share_mode,
3301 : create_disposition,
3302 : create_options,
3303 : 0,
3304 : pfnum,
3305 : &cr);
3306 :
3307 : /* Try and cope will all varients of "we don't do this call"
3308 : and fall back to openX. */
3309 :
3310 110 : if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
3311 110 : NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
3312 110 : NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
3313 110 : NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
3314 110 : NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
3315 110 : NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
3316 110 : NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
3317 110 : NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
3318 110 : NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
3319 0 : goto try_openx;
3320 : }
3321 :
3322 110 : if (NT_STATUS_IS_OK(status) &&
3323 94 : (create_options & FILE_NON_DIRECTORY_FILE) &&
3324 94 : (cr.file_attributes & FILE_ATTRIBUTE_DIRECTORY))
3325 : {
3326 : /*
3327 : * Some (broken) servers return a valid handle
3328 : * for directories even if FILE_NON_DIRECTORY_FILE
3329 : * is set. Just close the handle and set the
3330 : * error explicitly to NT_STATUS_FILE_IS_A_DIRECTORY.
3331 : */
3332 0 : status = cli_close(cli, *pfnum);
3333 0 : if (!NT_STATUS_IS_OK(status)) {
3334 0 : return status;
3335 : }
3336 0 : status = NT_STATUS_FILE_IS_A_DIRECTORY;
3337 : /* Set this so libsmbclient can retrieve it. */
3338 0 : cli->raw_status = status;
3339 : }
3340 :
3341 110 : return status;
3342 :
3343 0 : try_openx:
3344 :
3345 0 : return cli_openx(cli, fname, flags, share_mode_in, pfnum);
3346 : }
3347 :
3348 : /****************************************************************************
3349 : Close a file.
3350 : ****************************************************************************/
3351 :
3352 : struct cli_smb1_close_state {
3353 : uint16_t vwv[3];
3354 : };
3355 :
3356 : static void cli_smb1_close_done(struct tevent_req *subreq);
3357 :
3358 210 : struct tevent_req *cli_smb1_close_create(TALLOC_CTX *mem_ctx,
3359 : struct tevent_context *ev,
3360 : struct cli_state *cli,
3361 : uint16_t fnum,
3362 : struct tevent_req **psubreq)
3363 : {
3364 : struct tevent_req *req, *subreq;
3365 : struct cli_smb1_close_state *state;
3366 :
3367 210 : req = tevent_req_create(mem_ctx, &state, struct cli_smb1_close_state);
3368 210 : if (req == NULL) {
3369 0 : return NULL;
3370 : }
3371 :
3372 210 : SSVAL(state->vwv+0, 0, fnum);
3373 210 : SIVALS(state->vwv+1, 0, -1);
3374 :
3375 210 : subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 0,
3376 210 : 3, state->vwv, 0, NULL);
3377 210 : if (subreq == NULL) {
3378 0 : TALLOC_FREE(req);
3379 0 : return NULL;
3380 : }
3381 210 : tevent_req_set_callback(subreq, cli_smb1_close_done, req);
3382 210 : *psubreq = subreq;
3383 210 : return req;
3384 : }
3385 :
3386 210 : static void cli_smb1_close_done(struct tevent_req *subreq)
3387 : {
3388 210 : struct tevent_req *req = tevent_req_callback_data(
3389 : subreq, struct tevent_req);
3390 : NTSTATUS status;
3391 :
3392 210 : status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3393 210 : TALLOC_FREE(subreq);
3394 210 : if (tevent_req_nterror(req, status)) {
3395 5 : return;
3396 : }
3397 205 : tevent_req_done(req);
3398 : }
3399 :
3400 : struct cli_close_state {
3401 : int dummy;
3402 : };
3403 :
3404 : static void cli_close_done(struct tevent_req *subreq);
3405 :
3406 4121 : struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
3407 : struct tevent_context *ev,
3408 : struct cli_state *cli,
3409 : uint16_t fnum)
3410 : {
3411 : struct tevent_req *req, *subreq;
3412 : struct cli_close_state *state;
3413 : NTSTATUS status;
3414 :
3415 4121 : req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
3416 4121 : if (req == NULL) {
3417 0 : return NULL;
3418 : }
3419 :
3420 4121 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3421 3913 : subreq = cli_smb2_close_fnum_send(state,
3422 : ev,
3423 : cli,
3424 : fnum);
3425 3913 : if (tevent_req_nomem(subreq, req)) {
3426 0 : return tevent_req_post(req, ev);
3427 : }
3428 : } else {
3429 208 : struct tevent_req *ch_req = NULL;
3430 208 : subreq = cli_smb1_close_create(state, ev, cli, fnum, &ch_req);
3431 208 : if (tevent_req_nomem(subreq, req)) {
3432 0 : return tevent_req_post(req, ev);
3433 : }
3434 208 : status = smb1cli_req_chain_submit(&ch_req, 1);
3435 208 : if (tevent_req_nterror(req, status)) {
3436 0 : return tevent_req_post(req, ev);
3437 : }
3438 : }
3439 :
3440 4121 : tevent_req_set_callback(subreq, cli_close_done, req);
3441 4121 : return req;
3442 : }
3443 :
3444 4121 : static void cli_close_done(struct tevent_req *subreq)
3445 : {
3446 4121 : struct tevent_req *req = tevent_req_callback_data(
3447 : subreq, struct tevent_req);
3448 4121 : NTSTATUS status = NT_STATUS_OK;
3449 4121 : bool err = tevent_req_is_nterror(subreq, &status);
3450 :
3451 4121 : TALLOC_FREE(subreq);
3452 4121 : if (err) {
3453 5 : tevent_req_nterror(req, status);
3454 5 : return;
3455 : }
3456 4116 : tevent_req_done(req);
3457 : }
3458 :
3459 4123 : NTSTATUS cli_close_recv(struct tevent_req *req)
3460 : {
3461 4123 : return tevent_req_simple_recv_ntstatus(req);
3462 : }
3463 :
3464 341 : NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
3465 : {
3466 341 : TALLOC_CTX *frame = NULL;
3467 : struct tevent_context *ev;
3468 : struct tevent_req *req;
3469 341 : NTSTATUS status = NT_STATUS_OK;
3470 :
3471 341 : frame = talloc_stackframe();
3472 :
3473 341 : if (smbXcli_conn_has_async_calls(cli->conn)) {
3474 : /*
3475 : * Can't use sync call while an async call is in flight
3476 : */
3477 0 : status = NT_STATUS_INVALID_PARAMETER;
3478 0 : goto fail;
3479 : }
3480 :
3481 341 : ev = samba_tevent_context_init(frame);
3482 341 : if (ev == NULL) {
3483 0 : status = NT_STATUS_NO_MEMORY;
3484 0 : goto fail;
3485 : }
3486 :
3487 341 : req = cli_close_send(frame, ev, cli, fnum);
3488 341 : if (req == NULL) {
3489 0 : status = NT_STATUS_NO_MEMORY;
3490 0 : goto fail;
3491 : }
3492 :
3493 341 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3494 0 : goto fail;
3495 : }
3496 :
3497 341 : status = cli_close_recv(req);
3498 341 : fail:
3499 341 : TALLOC_FREE(frame);
3500 341 : return status;
3501 : }
3502 :
3503 : /****************************************************************************
3504 : Truncate a file to a specified size
3505 : ****************************************************************************/
3506 :
3507 : struct ftrunc_state {
3508 : uint8_t data[8];
3509 : };
3510 :
3511 0 : static void cli_ftruncate_done(struct tevent_req *subreq)
3512 : {
3513 0 : NTSTATUS status = cli_setfileinfo_recv(subreq);
3514 0 : tevent_req_simple_finish_ntstatus(subreq, status);
3515 0 : }
3516 :
3517 0 : struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
3518 : struct tevent_context *ev,
3519 : struct cli_state *cli,
3520 : uint16_t fnum,
3521 : uint64_t size)
3522 : {
3523 0 : struct tevent_req *req = NULL, *subreq = NULL;
3524 0 : struct ftrunc_state *state = NULL;
3525 :
3526 0 : req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
3527 0 : if (req == NULL) {
3528 0 : return NULL;
3529 : }
3530 :
3531 : /* Setup data array. */
3532 0 : SBVAL(state->data, 0, size);
3533 :
3534 0 : subreq = cli_setfileinfo_send(
3535 : state,
3536 : ev,
3537 : cli,
3538 : fnum,
3539 : SMB_SET_FILE_END_OF_FILE_INFO,
3540 0 : state->data,
3541 : sizeof(state->data));
3542 :
3543 0 : if (tevent_req_nomem(subreq, req)) {
3544 0 : return tevent_req_post(req, ev);
3545 : }
3546 0 : tevent_req_set_callback(subreq, cli_ftruncate_done, req);
3547 0 : return req;
3548 : }
3549 :
3550 0 : NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
3551 : {
3552 0 : return tevent_req_simple_recv_ntstatus(req);
3553 : }
3554 :
3555 10 : NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
3556 : {
3557 10 : TALLOC_CTX *frame = NULL;
3558 10 : struct tevent_context *ev = NULL;
3559 10 : struct tevent_req *req = NULL;
3560 10 : NTSTATUS status = NT_STATUS_OK;
3561 :
3562 10 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3563 10 : return cli_smb2_ftruncate(cli, fnum, size);
3564 : }
3565 :
3566 0 : frame = talloc_stackframe();
3567 :
3568 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
3569 : /*
3570 : * Can't use sync call while an async call is in flight
3571 : */
3572 0 : status = NT_STATUS_INVALID_PARAMETER;
3573 0 : goto fail;
3574 : }
3575 :
3576 0 : ev = samba_tevent_context_init(frame);
3577 0 : if (ev == NULL) {
3578 0 : status = NT_STATUS_NO_MEMORY;
3579 0 : goto fail;
3580 : }
3581 :
3582 0 : req = cli_ftruncate_send(frame,
3583 : ev,
3584 : cli,
3585 : fnum,
3586 : size);
3587 0 : if (req == NULL) {
3588 0 : status = NT_STATUS_NO_MEMORY;
3589 0 : goto fail;
3590 : }
3591 :
3592 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3593 0 : goto fail;
3594 : }
3595 :
3596 0 : status = cli_ftruncate_recv(req);
3597 :
3598 0 : fail:
3599 0 : TALLOC_FREE(frame);
3600 0 : return status;
3601 : }
3602 :
3603 1790 : static uint8_t *cli_lockingx_put_locks(
3604 : uint8_t *buf,
3605 : bool large,
3606 : uint16_t num_locks,
3607 : const struct smb1_lock_element *locks)
3608 : {
3609 : uint16_t i;
3610 :
3611 2683 : for (i=0; i<num_locks; i++) {
3612 893 : const struct smb1_lock_element *e = &locks[i];
3613 893 : if (large) {
3614 0 : SSVAL(buf, 0, e->pid);
3615 0 : SSVAL(buf, 2, 0);
3616 0 : SOFF_T_R(buf, 4, e->offset);
3617 0 : SOFF_T_R(buf, 12, e->length);
3618 0 : buf += 20;
3619 : } else {
3620 893 : SSVAL(buf, 0, e->pid);
3621 893 : SIVAL(buf, 2, e->offset);
3622 893 : SIVAL(buf, 6, e->length);
3623 893 : buf += 10;
3624 : }
3625 : }
3626 1790 : return buf;
3627 : }
3628 :
3629 : struct cli_lockingx_state {
3630 : uint16_t vwv[8];
3631 : struct iovec bytes;
3632 : struct tevent_req *subreq;
3633 : };
3634 :
3635 : static void cli_lockingx_done(struct tevent_req *subreq);
3636 : static bool cli_lockingx_cancel(struct tevent_req *req);
3637 :
3638 895 : struct tevent_req *cli_lockingx_create(
3639 : TALLOC_CTX *mem_ctx,
3640 : struct tevent_context *ev,
3641 : struct cli_state *cli,
3642 : uint16_t fnum,
3643 : uint8_t typeoflock,
3644 : uint8_t newoplocklevel,
3645 : int32_t timeout,
3646 : uint16_t num_unlocks,
3647 : const struct smb1_lock_element *unlocks,
3648 : uint16_t num_locks,
3649 : const struct smb1_lock_element *locks,
3650 : struct tevent_req **psmbreq)
3651 : {
3652 895 : struct tevent_req *req = NULL, *subreq = NULL;
3653 895 : struct cli_lockingx_state *state = NULL;
3654 : uint16_t *vwv;
3655 : uint8_t *p;
3656 895 : const bool large = (typeoflock & LOCKING_ANDX_LARGE_FILES);
3657 895 : const size_t element_len = large ? 20 : 10;
3658 :
3659 : /* uint16->size_t, no overflow */
3660 895 : const size_t num_elements = (size_t)num_locks + (size_t)num_unlocks;
3661 :
3662 : /* at most 20*2*65535 = 2621400, no overflow */
3663 895 : const size_t num_bytes = num_elements * element_len;
3664 :
3665 895 : req = tevent_req_create(mem_ctx, &state, struct cli_lockingx_state);
3666 895 : if (req == NULL) {
3667 0 : return NULL;
3668 : }
3669 895 : vwv = state->vwv;
3670 :
3671 895 : SCVAL(vwv + 0, 0, 0xFF);
3672 895 : SCVAL(vwv + 0, 1, 0);
3673 895 : SSVAL(vwv + 1, 0, 0);
3674 895 : SSVAL(vwv + 2, 0, fnum);
3675 895 : SCVAL(vwv + 3, 0, typeoflock);
3676 895 : SCVAL(vwv + 3, 1, newoplocklevel);
3677 895 : SIVALS(vwv + 4, 0, timeout);
3678 895 : SSVAL(vwv + 6, 0, num_unlocks);
3679 895 : SSVAL(vwv + 7, 0, num_locks);
3680 :
3681 895 : state->bytes.iov_len = num_bytes;
3682 895 : state->bytes.iov_base = talloc_array(state, uint8_t, num_bytes);
3683 895 : if (tevent_req_nomem(state->bytes.iov_base, req)) {
3684 0 : return tevent_req_post(req, ev);
3685 : }
3686 :
3687 895 : p = cli_lockingx_put_locks(
3688 895 : state->bytes.iov_base, large, num_unlocks, unlocks);
3689 895 : cli_lockingx_put_locks(p, large, num_locks, locks);
3690 :
3691 895 : subreq = cli_smb_req_create(
3692 895 : state, ev, cli, SMBlockingX, 0, 0, 8, vwv, 1, &state->bytes);
3693 895 : if (tevent_req_nomem(subreq, req)) {
3694 0 : return tevent_req_post(req, ev);
3695 : }
3696 895 : tevent_req_set_callback(subreq, cli_lockingx_done, req);
3697 895 : *psmbreq = subreq;
3698 895 : return req;
3699 : }
3700 :
3701 893 : struct tevent_req *cli_lockingx_send(
3702 : TALLOC_CTX *mem_ctx,
3703 : struct tevent_context *ev,
3704 : struct cli_state *cli,
3705 : uint16_t fnum,
3706 : uint8_t typeoflock,
3707 : uint8_t newoplocklevel,
3708 : int32_t timeout,
3709 : uint16_t num_unlocks,
3710 : const struct smb1_lock_element *unlocks,
3711 : uint16_t num_locks,
3712 : const struct smb1_lock_element *locks)
3713 : {
3714 893 : struct tevent_req *req = NULL, *subreq = NULL;
3715 893 : struct cli_lockingx_state *state = NULL;
3716 : NTSTATUS status;
3717 :
3718 893 : req = cli_lockingx_create(
3719 : mem_ctx,
3720 : ev,
3721 : cli,
3722 : fnum,
3723 : typeoflock,
3724 : newoplocklevel,
3725 : timeout,
3726 : num_unlocks,
3727 : unlocks,
3728 : num_locks,
3729 : locks,
3730 : &subreq);
3731 893 : if (req == NULL) {
3732 0 : return NULL;
3733 : }
3734 893 : state = tevent_req_data(req, struct cli_lockingx_state);
3735 893 : state->subreq = subreq;
3736 :
3737 893 : status = smb1cli_req_chain_submit(&subreq, 1);
3738 893 : if (tevent_req_nterror(req, status)) {
3739 0 : return tevent_req_post(req, ev);
3740 : }
3741 893 : tevent_req_set_cancel_fn(req, cli_lockingx_cancel);
3742 893 : return req;
3743 : }
3744 :
3745 895 : static void cli_lockingx_done(struct tevent_req *subreq)
3746 : {
3747 895 : NTSTATUS status = cli_smb_recv(
3748 : subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3749 895 : tevent_req_simple_finish_ntstatus(subreq, status);
3750 895 : }
3751 :
3752 1 : static bool cli_lockingx_cancel(struct tevent_req *req)
3753 : {
3754 1 : struct cli_lockingx_state *state = tevent_req_data(
3755 : req, struct cli_lockingx_state);
3756 1 : if (state->subreq == NULL) {
3757 0 : return false;
3758 : }
3759 1 : return tevent_req_cancel(state->subreq);
3760 : }
3761 :
3762 895 : NTSTATUS cli_lockingx_recv(struct tevent_req *req)
3763 : {
3764 895 : return tevent_req_simple_recv_ntstatus(req);
3765 : }
3766 :
3767 669 : NTSTATUS cli_lockingx(
3768 : struct cli_state *cli,
3769 : uint16_t fnum,
3770 : uint8_t typeoflock,
3771 : uint8_t newoplocklevel,
3772 : int32_t timeout,
3773 : uint16_t num_unlocks,
3774 : const struct smb1_lock_element *unlocks,
3775 : uint16_t num_locks,
3776 : const struct smb1_lock_element *locks)
3777 : {
3778 669 : TALLOC_CTX *frame = talloc_stackframe();
3779 669 : struct tevent_context *ev = NULL;
3780 669 : struct tevent_req *req = NULL;
3781 669 : NTSTATUS status = NT_STATUS_NO_MEMORY;
3782 669 : unsigned int set_timeout = 0;
3783 669 : unsigned int saved_timeout = 0;
3784 :
3785 669 : if (smbXcli_conn_has_async_calls(cli->conn)) {
3786 0 : return NT_STATUS_INVALID_PARAMETER;
3787 : }
3788 669 : ev = samba_tevent_context_init(frame);
3789 669 : if (ev == NULL) {
3790 0 : goto fail;
3791 : }
3792 :
3793 669 : if (timeout != 0) {
3794 1 : if (timeout == -1) {
3795 0 : set_timeout = 0x7FFFFFFF;
3796 : } else {
3797 1 : set_timeout = timeout + 2*1000;
3798 : }
3799 1 : saved_timeout = cli_set_timeout(cli, set_timeout);
3800 : }
3801 :
3802 669 : req = cli_lockingx_send(
3803 : frame,
3804 : ev,
3805 : cli,
3806 : fnum,
3807 : typeoflock,
3808 : newoplocklevel,
3809 : timeout,
3810 : num_unlocks,
3811 : unlocks,
3812 : num_locks,
3813 : locks);
3814 669 : if (req == NULL) {
3815 0 : goto fail;
3816 : }
3817 669 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3818 0 : goto fail;
3819 : }
3820 669 : status = cli_lockingx_recv(req);
3821 :
3822 669 : if (saved_timeout != 0) {
3823 1 : cli_set_timeout(cli, saved_timeout);
3824 : }
3825 668 : fail:
3826 669 : TALLOC_FREE(frame);
3827 669 : return status;
3828 : }
3829 :
3830 : /****************************************************************************
3831 : send a lock with a specified locktype
3832 : this is used for testing LOCKING_ANDX_CANCEL_LOCK
3833 : ****************************************************************************/
3834 :
3835 668 : NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
3836 : uint32_t offset, uint32_t len,
3837 : int timeout, unsigned char locktype)
3838 : {
3839 668 : struct smb1_lock_element lck = {
3840 668 : .pid = cli_getpid(cli),
3841 : .offset = offset,
3842 : .length = len,
3843 : };
3844 : NTSTATUS status;
3845 :
3846 668 : status = cli_lockingx(
3847 : cli, /* cli */
3848 : fnum, /* fnum */
3849 : locktype, /* typeoflock */
3850 : 0, /* newoplocklevel */
3851 : timeout, /* timeout */
3852 : 0, /* num_unlocks */
3853 : NULL, /* unlocks */
3854 : 1, /* num_locks */
3855 : &lck); /* locks */
3856 668 : return status;
3857 : }
3858 :
3859 : /****************************************************************************
3860 : Lock a file.
3861 : note that timeout is in units of 2 milliseconds
3862 : ****************************************************************************/
3863 :
3864 663 : NTSTATUS cli_lock32(struct cli_state *cli, uint16_t fnum,
3865 : uint32_t offset, uint32_t len, int timeout,
3866 : enum brl_type lock_type)
3867 : {
3868 : NTSTATUS status;
3869 :
3870 663 : status = cli_locktype(cli, fnum, offset, len, timeout,
3871 : (lock_type == READ_LOCK? 1 : 0));
3872 663 : return status;
3873 : }
3874 :
3875 : /****************************************************************************
3876 : Unlock a file.
3877 : ****************************************************************************/
3878 :
3879 : struct cli_unlock_state {
3880 : struct smb1_lock_element lck;
3881 : };
3882 :
3883 : static void cli_unlock_done(struct tevent_req *subreq);
3884 :
3885 222 : struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
3886 : struct tevent_context *ev,
3887 : struct cli_state *cli,
3888 : uint16_t fnum,
3889 : uint64_t offset,
3890 : uint64_t len)
3891 :
3892 : {
3893 222 : struct tevent_req *req = NULL, *subreq = NULL;
3894 222 : struct cli_unlock_state *state = NULL;
3895 :
3896 222 : req = tevent_req_create(mem_ctx, &state, struct cli_unlock_state);
3897 222 : if (req == NULL) {
3898 0 : return NULL;
3899 : }
3900 444 : state->lck = (struct smb1_lock_element) {
3901 222 : .pid = cli_getpid(cli),
3902 : .offset = offset,
3903 : .length = len,
3904 : };
3905 :
3906 222 : subreq = cli_lockingx_send(
3907 : state, /* mem_ctx */
3908 : ev, /* tevent_context */
3909 : cli, /* cli */
3910 : fnum, /* fnum */
3911 : 0, /* typeoflock */
3912 : 0, /* newoplocklevel */
3913 : 0, /* timeout */
3914 : 1, /* num_unlocks */
3915 222 : &state->lck, /* unlocks */
3916 : 0, /* num_locks */
3917 : NULL); /* locks */
3918 222 : if (tevent_req_nomem(subreq, req)) {
3919 0 : return tevent_req_post(req, ev);
3920 : }
3921 222 : tevent_req_set_callback(subreq, cli_unlock_done, req);
3922 222 : return req;
3923 : }
3924 :
3925 222 : static void cli_unlock_done(struct tevent_req *subreq)
3926 : {
3927 222 : NTSTATUS status = cli_lockingx_recv(subreq);
3928 222 : tevent_req_simple_finish_ntstatus(subreq, status);
3929 222 : }
3930 :
3931 222 : NTSTATUS cli_unlock_recv(struct tevent_req *req)
3932 : {
3933 222 : return tevent_req_simple_recv_ntstatus(req);
3934 : }
3935 :
3936 222 : NTSTATUS cli_unlock(struct cli_state *cli,
3937 : uint16_t fnum,
3938 : uint32_t offset,
3939 : uint32_t len)
3940 : {
3941 222 : TALLOC_CTX *frame = talloc_stackframe();
3942 : struct tevent_context *ev;
3943 : struct tevent_req *req;
3944 222 : NTSTATUS status = NT_STATUS_OK;
3945 :
3946 222 : if (smbXcli_conn_has_async_calls(cli->conn)) {
3947 : /*
3948 : * Can't use sync call while an async call is in flight
3949 : */
3950 0 : status = NT_STATUS_INVALID_PARAMETER;
3951 0 : goto fail;
3952 : }
3953 :
3954 222 : ev = samba_tevent_context_init(frame);
3955 222 : if (ev == NULL) {
3956 0 : status = NT_STATUS_NO_MEMORY;
3957 0 : goto fail;
3958 : }
3959 :
3960 222 : req = cli_unlock_send(frame, ev, cli,
3961 : fnum, offset, len);
3962 222 : if (req == NULL) {
3963 0 : status = NT_STATUS_NO_MEMORY;
3964 0 : goto fail;
3965 : }
3966 :
3967 222 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3968 0 : goto fail;
3969 : }
3970 :
3971 222 : status = cli_unlock_recv(req);
3972 :
3973 222 : fail:
3974 222 : TALLOC_FREE(frame);
3975 222 : return status;
3976 : }
3977 :
3978 : /****************************************************************************
3979 : Get/unlock a POSIX lock on a file - internal function.
3980 : ****************************************************************************/
3981 :
3982 : struct posix_lock_state {
3983 : uint16_t setup;
3984 : uint8_t param[4];
3985 : uint8_t data[POSIX_LOCK_DATA_SIZE];
3986 : };
3987 :
3988 0 : static void cli_posix_unlock_internal_done(struct tevent_req *subreq)
3989 : {
3990 0 : NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
3991 : NULL, 0, NULL, NULL, 0, NULL);
3992 0 : tevent_req_simple_finish_ntstatus(subreq, status);
3993 0 : }
3994 :
3995 0 : static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
3996 : struct tevent_context *ev,
3997 : struct cli_state *cli,
3998 : uint16_t fnum,
3999 : uint64_t offset,
4000 : uint64_t len,
4001 : bool wait_lock,
4002 : enum brl_type lock_type)
4003 : {
4004 0 : struct tevent_req *req = NULL, *subreq = NULL;
4005 0 : struct posix_lock_state *state = NULL;
4006 :
4007 0 : req = tevent_req_create(mem_ctx, &state, struct posix_lock_state);
4008 0 : if (req == NULL) {
4009 0 : return NULL;
4010 : }
4011 :
4012 : /* Setup setup word. */
4013 0 : SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
4014 :
4015 : /* Setup param array. */
4016 0 : SSVAL(&state->param, 0, fnum);
4017 0 : SSVAL(&state->param, 2, SMB_SET_POSIX_LOCK);
4018 :
4019 : /* Setup data array. */
4020 0 : switch (lock_type) {
4021 0 : case READ_LOCK:
4022 0 : SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
4023 : POSIX_LOCK_TYPE_READ);
4024 0 : break;
4025 0 : case WRITE_LOCK:
4026 0 : SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
4027 : POSIX_LOCK_TYPE_WRITE);
4028 0 : break;
4029 0 : case UNLOCK_LOCK:
4030 0 : SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
4031 : POSIX_LOCK_TYPE_UNLOCK);
4032 0 : break;
4033 0 : default:
4034 0 : return NULL;
4035 : }
4036 :
4037 0 : if (wait_lock) {
4038 0 : SSVAL(&state->data, POSIX_LOCK_FLAGS_OFFSET,
4039 : POSIX_LOCK_FLAG_WAIT);
4040 : } else {
4041 0 : SSVAL(state->data, POSIX_LOCK_FLAGS_OFFSET,
4042 : POSIX_LOCK_FLAG_NOWAIT);
4043 : }
4044 :
4045 0 : SIVAL(&state->data, POSIX_LOCK_PID_OFFSET, cli_getpid(cli));
4046 0 : SOFF_T(&state->data, POSIX_LOCK_START_OFFSET, offset);
4047 0 : SOFF_T(&state->data, POSIX_LOCK_LEN_OFFSET, len);
4048 :
4049 0 : subreq = cli_trans_send(state, /* mem ctx. */
4050 : ev, /* event ctx. */
4051 : cli, /* cli_state. */
4052 : 0, /* additional_flags2 */
4053 : SMBtrans2, /* cmd. */
4054 : NULL, /* pipe name. */
4055 : -1, /* fid. */
4056 : 0, /* function. */
4057 : 0, /* flags. */
4058 0 : &state->setup, /* setup. */
4059 : 1, /* num setup uint16_t words. */
4060 : 0, /* max returned setup. */
4061 0 : state->param, /* param. */
4062 : 4, /* num param. */
4063 : 2, /* max returned param. */
4064 0 : state->data, /* data. */
4065 : POSIX_LOCK_DATA_SIZE, /* num data. */
4066 : 0); /* max returned data. */
4067 :
4068 0 : if (tevent_req_nomem(subreq, req)) {
4069 0 : return tevent_req_post(req, ev);
4070 : }
4071 0 : tevent_req_set_callback(subreq, cli_posix_unlock_internal_done, req);
4072 0 : return req;
4073 : }
4074 :
4075 : /****************************************************************************
4076 : POSIX Lock a file.
4077 : ****************************************************************************/
4078 :
4079 0 : struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx,
4080 : struct tevent_context *ev,
4081 : struct cli_state *cli,
4082 : uint16_t fnum,
4083 : uint64_t offset,
4084 : uint64_t len,
4085 : bool wait_lock,
4086 : enum brl_type lock_type)
4087 : {
4088 0 : return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
4089 : wait_lock, lock_type);
4090 : }
4091 :
4092 0 : NTSTATUS cli_posix_lock_recv(struct tevent_req *req)
4093 : {
4094 0 : return tevent_req_simple_recv_ntstatus(req);
4095 : }
4096 :
4097 0 : NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
4098 : uint64_t offset, uint64_t len,
4099 : bool wait_lock, enum brl_type lock_type)
4100 : {
4101 0 : TALLOC_CTX *frame = talloc_stackframe();
4102 0 : struct tevent_context *ev = NULL;
4103 0 : struct tevent_req *req = NULL;
4104 0 : NTSTATUS status = NT_STATUS_OK;
4105 :
4106 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
4107 : /*
4108 : * Can't use sync call while an async call is in flight
4109 : */
4110 0 : status = NT_STATUS_INVALID_PARAMETER;
4111 0 : goto fail;
4112 : }
4113 :
4114 0 : if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
4115 0 : status = NT_STATUS_INVALID_PARAMETER;
4116 0 : goto fail;
4117 : }
4118 :
4119 0 : ev = samba_tevent_context_init(frame);
4120 0 : if (ev == NULL) {
4121 0 : status = NT_STATUS_NO_MEMORY;
4122 0 : goto fail;
4123 : }
4124 :
4125 0 : req = cli_posix_lock_send(frame,
4126 : ev,
4127 : cli,
4128 : fnum,
4129 : offset,
4130 : len,
4131 : wait_lock,
4132 : lock_type);
4133 0 : if (req == NULL) {
4134 0 : status = NT_STATUS_NO_MEMORY;
4135 0 : goto fail;
4136 : }
4137 :
4138 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4139 0 : goto fail;
4140 : }
4141 :
4142 0 : status = cli_posix_lock_recv(req);
4143 :
4144 0 : fail:
4145 0 : TALLOC_FREE(frame);
4146 0 : return status;
4147 : }
4148 :
4149 : /****************************************************************************
4150 : POSIX Unlock a file.
4151 : ****************************************************************************/
4152 :
4153 0 : struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx,
4154 : struct tevent_context *ev,
4155 : struct cli_state *cli,
4156 : uint16_t fnum,
4157 : uint64_t offset,
4158 : uint64_t len)
4159 : {
4160 0 : return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
4161 : false, UNLOCK_LOCK);
4162 : }
4163 :
4164 0 : NTSTATUS cli_posix_unlock_recv(struct tevent_req *req)
4165 : {
4166 0 : return tevent_req_simple_recv_ntstatus(req);
4167 : }
4168 :
4169 0 : NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
4170 : {
4171 0 : TALLOC_CTX *frame = talloc_stackframe();
4172 0 : struct tevent_context *ev = NULL;
4173 0 : struct tevent_req *req = NULL;
4174 0 : NTSTATUS status = NT_STATUS_OK;
4175 :
4176 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
4177 : /*
4178 : * Can't use sync call while an async call is in flight
4179 : */
4180 0 : status = NT_STATUS_INVALID_PARAMETER;
4181 0 : goto fail;
4182 : }
4183 :
4184 0 : ev = samba_tevent_context_init(frame);
4185 0 : if (ev == NULL) {
4186 0 : status = NT_STATUS_NO_MEMORY;
4187 0 : goto fail;
4188 : }
4189 :
4190 0 : req = cli_posix_unlock_send(frame,
4191 : ev,
4192 : cli,
4193 : fnum,
4194 : offset,
4195 : len);
4196 0 : if (req == NULL) {
4197 0 : status = NT_STATUS_NO_MEMORY;
4198 0 : goto fail;
4199 : }
4200 :
4201 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4202 0 : goto fail;
4203 : }
4204 :
4205 0 : status = cli_posix_unlock_recv(req);
4206 :
4207 0 : fail:
4208 0 : TALLOC_FREE(frame);
4209 0 : return status;
4210 : }
4211 :
4212 : /****************************************************************************
4213 : Do a SMBgetattrE call.
4214 : ****************************************************************************/
4215 :
4216 : static void cli_getattrE_done(struct tevent_req *subreq);
4217 :
4218 : struct cli_getattrE_state {
4219 : uint16_t vwv[1];
4220 : int zone_offset;
4221 : uint32_t attr;
4222 : off_t size;
4223 : time_t change_time;
4224 : time_t access_time;
4225 : time_t write_time;
4226 : };
4227 :
4228 0 : struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
4229 : struct tevent_context *ev,
4230 : struct cli_state *cli,
4231 : uint16_t fnum)
4232 : {
4233 0 : struct tevent_req *req = NULL, *subreq = NULL;
4234 0 : struct cli_getattrE_state *state = NULL;
4235 0 : uint8_t additional_flags = 0;
4236 :
4237 0 : req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
4238 0 : if (req == NULL) {
4239 0 : return NULL;
4240 : }
4241 :
4242 0 : state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
4243 0 : SSVAL(state->vwv+0,0,fnum);
4244 :
4245 0 : subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags, 0,
4246 0 : 1, state->vwv, 0, NULL);
4247 0 : if (tevent_req_nomem(subreq, req)) {
4248 0 : return tevent_req_post(req, ev);
4249 : }
4250 0 : tevent_req_set_callback(subreq, cli_getattrE_done, req);
4251 0 : return req;
4252 : }
4253 :
4254 0 : static void cli_getattrE_done(struct tevent_req *subreq)
4255 : {
4256 0 : struct tevent_req *req = tevent_req_callback_data(
4257 : subreq, struct tevent_req);
4258 0 : struct cli_getattrE_state *state = tevent_req_data(
4259 : req, struct cli_getattrE_state);
4260 : uint8_t wct;
4261 0 : uint16_t *vwv = NULL;
4262 : NTSTATUS status;
4263 :
4264 0 : status = cli_smb_recv(subreq, state, NULL, 11, &wct, &vwv,
4265 : NULL, NULL);
4266 0 : TALLOC_FREE(subreq);
4267 0 : if (tevent_req_nterror(req, status)) {
4268 0 : return;
4269 : }
4270 :
4271 0 : state->size = (off_t)IVAL(vwv+6,0);
4272 0 : state->attr = SVAL(vwv+10,0);
4273 0 : state->change_time = make_unix_date2(vwv+0, state->zone_offset);
4274 0 : state->access_time = make_unix_date2(vwv+2, state->zone_offset);
4275 0 : state->write_time = make_unix_date2(vwv+4, state->zone_offset);
4276 :
4277 0 : tevent_req_done(req);
4278 : }
4279 :
4280 0 : NTSTATUS cli_getattrE_recv(struct tevent_req *req,
4281 : uint32_t *pattr,
4282 : off_t *size,
4283 : time_t *change_time,
4284 : time_t *access_time,
4285 : time_t *write_time)
4286 : {
4287 0 : struct cli_getattrE_state *state = tevent_req_data(
4288 : req, struct cli_getattrE_state);
4289 : NTSTATUS status;
4290 :
4291 0 : if (tevent_req_is_nterror(req, &status)) {
4292 0 : return status;
4293 : }
4294 0 : if (pattr) {
4295 0 : *pattr = state->attr;
4296 : }
4297 0 : if (size) {
4298 0 : *size = state->size;
4299 : }
4300 0 : if (change_time) {
4301 0 : *change_time = state->change_time;
4302 : }
4303 0 : if (access_time) {
4304 0 : *access_time = state->access_time;
4305 : }
4306 0 : if (write_time) {
4307 0 : *write_time = state->write_time;
4308 : }
4309 0 : return NT_STATUS_OK;
4310 : }
4311 :
4312 : /****************************************************************************
4313 : Do a SMBgetatr call
4314 : ****************************************************************************/
4315 :
4316 : static void cli_getatr_done(struct tevent_req *subreq);
4317 :
4318 : struct cli_getatr_state {
4319 : int zone_offset;
4320 : uint32_t attr;
4321 : off_t size;
4322 : time_t write_time;
4323 : };
4324 :
4325 9 : struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
4326 : struct tevent_context *ev,
4327 : struct cli_state *cli,
4328 : const char *fname)
4329 : {
4330 9 : struct tevent_req *req = NULL, *subreq = NULL;
4331 9 : struct cli_getatr_state *state = NULL;
4332 9 : uint8_t additional_flags = 0;
4333 9 : uint16_t additional_flags2 = 0;
4334 9 : uint8_t *bytes = NULL;
4335 9 : char *fname_cp = NULL;
4336 :
4337 9 : req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
4338 9 : if (req == NULL) {
4339 0 : return NULL;
4340 : }
4341 :
4342 9 : state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
4343 :
4344 9 : bytes = talloc_array(state, uint8_t, 1);
4345 9 : if (tevent_req_nomem(bytes, req)) {
4346 0 : return tevent_req_post(req, ev);
4347 : }
4348 : /*
4349 : * SMBgetatr on a DFS share must use DFS names.
4350 : */
4351 9 : fname_cp = smb1_dfs_share_path(state, cli, fname);
4352 9 : if (tevent_req_nomem(fname_cp, req)) {
4353 0 : return tevent_req_post(req, ev);
4354 : }
4355 9 : bytes[0] = 4;
4356 9 : bytes = smb_bytes_push_str(bytes,
4357 9 : smbXcli_conn_use_unicode(cli->conn),
4358 : fname_cp,
4359 9 : strlen(fname_cp)+1,
4360 : NULL);
4361 :
4362 9 : if (tevent_req_nomem(bytes, req)) {
4363 0 : return tevent_req_post(req, ev);
4364 : }
4365 :
4366 9 : if (clistr_is_previous_version_path(fname)) {
4367 0 : additional_flags2 = FLAGS2_REPARSE_PATH;
4368 : }
4369 :
4370 9 : subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
4371 : additional_flags2,
4372 9 : 0, NULL, talloc_get_size(bytes), bytes);
4373 9 : if (tevent_req_nomem(subreq, req)) {
4374 0 : return tevent_req_post(req, ev);
4375 : }
4376 9 : tevent_req_set_callback(subreq, cli_getatr_done, req);
4377 9 : return req;
4378 : }
4379 :
4380 9 : static void cli_getatr_done(struct tevent_req *subreq)
4381 : {
4382 9 : struct tevent_req *req = tevent_req_callback_data(
4383 : subreq, struct tevent_req);
4384 9 : struct cli_getatr_state *state = tevent_req_data(
4385 : req, struct cli_getatr_state);
4386 : uint8_t wct;
4387 9 : uint16_t *vwv = NULL;
4388 : NTSTATUS status;
4389 :
4390 9 : status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
4391 : NULL);
4392 9 : TALLOC_FREE(subreq);
4393 9 : if (tevent_req_nterror(req, status)) {
4394 0 : return;
4395 : }
4396 :
4397 9 : state->attr = SVAL(vwv+0,0);
4398 9 : state->size = (off_t)IVAL(vwv+3,0);
4399 9 : state->write_time = make_unix_date3(vwv+1, state->zone_offset);
4400 :
4401 9 : tevent_req_done(req);
4402 : }
4403 :
4404 9 : NTSTATUS cli_getatr_recv(struct tevent_req *req,
4405 : uint32_t *pattr,
4406 : off_t *size,
4407 : time_t *write_time)
4408 : {
4409 9 : struct cli_getatr_state *state = tevent_req_data(
4410 : req, struct cli_getatr_state);
4411 : NTSTATUS status;
4412 :
4413 9 : if (tevent_req_is_nterror(req, &status)) {
4414 0 : return status;
4415 : }
4416 9 : if (pattr) {
4417 5 : *pattr = state->attr;
4418 : }
4419 9 : if (size) {
4420 2 : *size = state->size;
4421 : }
4422 9 : if (write_time) {
4423 2 : *write_time = state->write_time;
4424 : }
4425 9 : return NT_STATUS_OK;
4426 : }
4427 :
4428 65 : NTSTATUS cli_getatr(struct cli_state *cli,
4429 : const char *fname,
4430 : uint32_t *pattr,
4431 : off_t *size,
4432 : time_t *write_time)
4433 : {
4434 65 : TALLOC_CTX *frame = NULL;
4435 65 : struct tevent_context *ev = NULL;
4436 65 : struct tevent_req *req = NULL;
4437 65 : NTSTATUS status = NT_STATUS_OK;
4438 :
4439 65 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4440 56 : return cli_smb2_getatr(cli,
4441 : fname,
4442 : pattr,
4443 : size,
4444 : write_time);
4445 : }
4446 :
4447 9 : frame = talloc_stackframe();
4448 :
4449 9 : if (smbXcli_conn_has_async_calls(cli->conn)) {
4450 : /*
4451 : * Can't use sync call while an async call is in flight
4452 : */
4453 0 : status = NT_STATUS_INVALID_PARAMETER;
4454 0 : goto fail;
4455 : }
4456 :
4457 9 : ev = samba_tevent_context_init(frame);
4458 9 : if (ev == NULL) {
4459 0 : status = NT_STATUS_NO_MEMORY;
4460 0 : goto fail;
4461 : }
4462 :
4463 9 : req = cli_getatr_send(frame, ev, cli, fname);
4464 9 : if (req == NULL) {
4465 0 : status = NT_STATUS_NO_MEMORY;
4466 0 : goto fail;
4467 : }
4468 :
4469 9 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4470 0 : goto fail;
4471 : }
4472 :
4473 9 : status = cli_getatr_recv(req,
4474 : pattr,
4475 : size,
4476 : write_time);
4477 :
4478 9 : fail:
4479 9 : TALLOC_FREE(frame);
4480 9 : return status;
4481 : }
4482 :
4483 : /****************************************************************************
4484 : Do a SMBsetattrE call.
4485 : ****************************************************************************/
4486 :
4487 : static void cli_setattrE_done(struct tevent_req *subreq);
4488 :
4489 : struct cli_setattrE_state {
4490 : uint16_t vwv[7];
4491 : };
4492 :
4493 0 : struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
4494 : struct tevent_context *ev,
4495 : struct cli_state *cli,
4496 : uint16_t fnum,
4497 : time_t change_time,
4498 : time_t access_time,
4499 : time_t write_time)
4500 : {
4501 0 : struct tevent_req *req = NULL, *subreq = NULL;
4502 0 : struct cli_setattrE_state *state = NULL;
4503 0 : uint8_t additional_flags = 0;
4504 :
4505 0 : req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
4506 0 : if (req == NULL) {
4507 0 : return NULL;
4508 : }
4509 :
4510 0 : SSVAL(state->vwv+0, 0, fnum);
4511 0 : push_dos_date2((uint8_t *)&state->vwv[1], 0, change_time,
4512 : smb1cli_conn_server_time_zone(cli->conn));
4513 0 : push_dos_date2((uint8_t *)&state->vwv[3], 0, access_time,
4514 : smb1cli_conn_server_time_zone(cli->conn));
4515 0 : push_dos_date2((uint8_t *)&state->vwv[5], 0, write_time,
4516 : smb1cli_conn_server_time_zone(cli->conn));
4517 :
4518 0 : subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags, 0,
4519 0 : 7, state->vwv, 0, NULL);
4520 0 : if (tevent_req_nomem(subreq, req)) {
4521 0 : return tevent_req_post(req, ev);
4522 : }
4523 0 : tevent_req_set_callback(subreq, cli_setattrE_done, req);
4524 0 : return req;
4525 : }
4526 :
4527 0 : static void cli_setattrE_done(struct tevent_req *subreq)
4528 : {
4529 0 : struct tevent_req *req = tevent_req_callback_data(
4530 : subreq, struct tevent_req);
4531 : NTSTATUS status;
4532 :
4533 0 : status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4534 0 : TALLOC_FREE(subreq);
4535 0 : if (tevent_req_nterror(req, status)) {
4536 0 : return;
4537 : }
4538 0 : tevent_req_done(req);
4539 : }
4540 :
4541 0 : NTSTATUS cli_setattrE_recv(struct tevent_req *req)
4542 : {
4543 0 : return tevent_req_simple_recv_ntstatus(req);
4544 : }
4545 :
4546 0 : NTSTATUS cli_setattrE(struct cli_state *cli,
4547 : uint16_t fnum,
4548 : time_t change_time,
4549 : time_t access_time,
4550 : time_t write_time)
4551 : {
4552 0 : TALLOC_CTX *frame = NULL;
4553 0 : struct tevent_context *ev = NULL;
4554 0 : struct tevent_req *req = NULL;
4555 0 : NTSTATUS status = NT_STATUS_OK;
4556 :
4557 0 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4558 0 : return cli_smb2_setattrE(cli,
4559 : fnum,
4560 : change_time,
4561 : access_time,
4562 : write_time);
4563 : }
4564 :
4565 0 : frame = talloc_stackframe();
4566 :
4567 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
4568 : /*
4569 : * Can't use sync call while an async call is in flight
4570 : */
4571 0 : status = NT_STATUS_INVALID_PARAMETER;
4572 0 : goto fail;
4573 : }
4574 :
4575 0 : ev = samba_tevent_context_init(frame);
4576 0 : if (ev == NULL) {
4577 0 : status = NT_STATUS_NO_MEMORY;
4578 0 : goto fail;
4579 : }
4580 :
4581 0 : req = cli_setattrE_send(frame, ev,
4582 : cli,
4583 : fnum,
4584 : change_time,
4585 : access_time,
4586 : write_time);
4587 :
4588 0 : if (req == NULL) {
4589 0 : status = NT_STATUS_NO_MEMORY;
4590 0 : goto fail;
4591 : }
4592 :
4593 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4594 0 : goto fail;
4595 : }
4596 :
4597 0 : status = cli_setattrE_recv(req);
4598 :
4599 0 : fail:
4600 0 : TALLOC_FREE(frame);
4601 0 : return status;
4602 : }
4603 :
4604 : /****************************************************************************
4605 : Do a SMBsetatr call.
4606 : ****************************************************************************/
4607 :
4608 : static void cli_setatr_done(struct tevent_req *subreq);
4609 :
4610 : struct cli_setatr_state {
4611 : uint16_t vwv[8];
4612 : };
4613 :
4614 18 : struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
4615 : struct tevent_context *ev,
4616 : struct cli_state *cli,
4617 : const char *fname,
4618 : uint32_t attr,
4619 : time_t mtime)
4620 : {
4621 18 : struct tevent_req *req = NULL, *subreq = NULL;
4622 18 : struct cli_setatr_state *state = NULL;
4623 18 : uint8_t additional_flags = 0;
4624 18 : uint16_t additional_flags2 = 0;
4625 18 : uint8_t *bytes = NULL;
4626 18 : char *fname_cp = NULL;
4627 :
4628 18 : req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
4629 18 : if (req == NULL) {
4630 0 : return NULL;
4631 : }
4632 :
4633 18 : if (attr & 0xFFFF0000) {
4634 : /*
4635 : * Don't allow attributes greater than
4636 : * 16-bits for a 16-bit protocol value.
4637 : */
4638 1 : if (tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER)) {
4639 1 : return tevent_req_post(req, ev);
4640 : }
4641 : }
4642 :
4643 17 : SSVAL(state->vwv+0, 0, attr);
4644 17 : push_dos_date3((uint8_t *)&state->vwv[1], 0, mtime, smb1cli_conn_server_time_zone(cli->conn));
4645 :
4646 17 : bytes = talloc_array(state, uint8_t, 1);
4647 17 : if (tevent_req_nomem(bytes, req)) {
4648 0 : return tevent_req_post(req, ev);
4649 : }
4650 : /*
4651 : * SMBsetatr on a DFS share must use DFS names.
4652 : */
4653 17 : fname_cp = smb1_dfs_share_path(state, cli, fname);
4654 17 : if (tevent_req_nomem(fname_cp, req)) {
4655 0 : return tevent_req_post(req, ev);
4656 : }
4657 17 : bytes[0] = 4;
4658 17 : bytes = smb_bytes_push_str(bytes,
4659 17 : smbXcli_conn_use_unicode(cli->conn),
4660 : fname_cp,
4661 17 : strlen(fname_cp)+1,
4662 : NULL);
4663 17 : if (tevent_req_nomem(bytes, req)) {
4664 0 : return tevent_req_post(req, ev);
4665 : }
4666 17 : bytes = talloc_realloc(state, bytes, uint8_t,
4667 : talloc_get_size(bytes)+1);
4668 17 : if (tevent_req_nomem(bytes, req)) {
4669 0 : return tevent_req_post(req, ev);
4670 : }
4671 :
4672 17 : bytes[talloc_get_size(bytes)-1] = 4;
4673 17 : bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "",
4674 : 1, NULL);
4675 17 : if (tevent_req_nomem(bytes, req)) {
4676 0 : return tevent_req_post(req, ev);
4677 : }
4678 :
4679 17 : if (clistr_is_previous_version_path(fname)) {
4680 0 : additional_flags2 = FLAGS2_REPARSE_PATH;
4681 : }
4682 :
4683 17 : subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
4684 : additional_flags2,
4685 17 : 8, state->vwv, talloc_get_size(bytes), bytes);
4686 17 : if (tevent_req_nomem(subreq, req)) {
4687 0 : return tevent_req_post(req, ev);
4688 : }
4689 17 : tevent_req_set_callback(subreq, cli_setatr_done, req);
4690 17 : return req;
4691 : }
4692 :
4693 17 : static void cli_setatr_done(struct tevent_req *subreq)
4694 : {
4695 17 : struct tevent_req *req = tevent_req_callback_data(
4696 : subreq, struct tevent_req);
4697 : NTSTATUS status;
4698 :
4699 17 : status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4700 17 : TALLOC_FREE(subreq);
4701 17 : if (tevent_req_nterror(req, status)) {
4702 10 : return;
4703 : }
4704 7 : tevent_req_done(req);
4705 : }
4706 :
4707 18 : NTSTATUS cli_setatr_recv(struct tevent_req *req)
4708 : {
4709 18 : return tevent_req_simple_recv_ntstatus(req);
4710 : }
4711 :
4712 76 : NTSTATUS cli_setatr(struct cli_state *cli,
4713 : const char *fname,
4714 : uint32_t attr,
4715 : time_t mtime)
4716 : {
4717 76 : TALLOC_CTX *frame = NULL;
4718 76 : struct tevent_context *ev = NULL;
4719 76 : struct tevent_req *req = NULL;
4720 76 : NTSTATUS status = NT_STATUS_OK;
4721 :
4722 76 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4723 58 : return cli_smb2_setatr(cli,
4724 : fname,
4725 : attr,
4726 : mtime);
4727 : }
4728 :
4729 18 : frame = talloc_stackframe();
4730 :
4731 18 : if (smbXcli_conn_has_async_calls(cli->conn)) {
4732 : /*
4733 : * Can't use sync call while an async call is in flight
4734 : */
4735 0 : status = NT_STATUS_INVALID_PARAMETER;
4736 0 : goto fail;
4737 : }
4738 :
4739 18 : ev = samba_tevent_context_init(frame);
4740 18 : if (ev == NULL) {
4741 0 : status = NT_STATUS_NO_MEMORY;
4742 0 : goto fail;
4743 : }
4744 :
4745 18 : req = cli_setatr_send(frame, ev, cli, fname, attr, mtime);
4746 18 : if (req == NULL) {
4747 0 : status = NT_STATUS_NO_MEMORY;
4748 0 : goto fail;
4749 : }
4750 :
4751 18 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4752 0 : goto fail;
4753 : }
4754 :
4755 18 : status = cli_setatr_recv(req);
4756 :
4757 18 : fail:
4758 18 : TALLOC_FREE(frame);
4759 18 : return status;
4760 : }
4761 :
4762 : /****************************************************************************
4763 : Check for existence of a dir.
4764 : ****************************************************************************/
4765 :
4766 : static void cli_chkpath_done(struct tevent_req *subreq);
4767 : static void cli_chkpath_opened(struct tevent_req *subreq);
4768 : static void cli_chkpath_closed(struct tevent_req *subreq);
4769 :
4770 : struct cli_chkpath_state {
4771 : struct tevent_context *ev;
4772 : struct cli_state *cli;
4773 : };
4774 :
4775 2977 : struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
4776 : struct tevent_context *ev,
4777 : struct cli_state *cli,
4778 : const char *fname)
4779 : {
4780 2977 : struct tevent_req *req = NULL, *subreq = NULL;
4781 2977 : struct cli_chkpath_state *state = NULL;
4782 2977 : uint8_t additional_flags = 0;
4783 2977 : uint16_t additional_flags2 = 0;
4784 2977 : uint8_t *bytes = NULL;
4785 2977 : char *fname_cp = NULL;
4786 :
4787 2977 : req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
4788 2977 : if (req == NULL) {
4789 0 : return NULL;
4790 : }
4791 2977 : state->ev = ev;
4792 2977 : state->cli = cli;
4793 :
4794 2977 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_NT1) {
4795 2977 : subreq = cli_ntcreate_send(
4796 : state, /* mem_ctx */
4797 2977 : state->ev, /* ev */
4798 2977 : state->cli, /* cli */
4799 : fname, /* fname */
4800 : 0, /* create_flags */
4801 : FILE_READ_ATTRIBUTES, /* desired_access */
4802 : FILE_ATTRIBUTE_DIRECTORY, /* FileAttributes */
4803 : FILE_SHARE_READ|
4804 : FILE_SHARE_WRITE|
4805 : FILE_SHARE_DELETE, /* share_access */
4806 : FILE_OPEN, /* CreateDisposition */
4807 : FILE_DIRECTORY_FILE, /* CreateOptions */
4808 : SMB2_IMPERSONATION_IMPERSONATION,
4809 : 0); /* SecurityFlags */
4810 2977 : if (tevent_req_nomem(subreq, req)) {
4811 0 : return tevent_req_post(req, ev);
4812 : }
4813 2977 : tevent_req_set_callback(subreq, cli_chkpath_opened, req);
4814 2977 : return req;
4815 : }
4816 :
4817 0 : bytes = talloc_array(state, uint8_t, 1);
4818 0 : if (tevent_req_nomem(bytes, req)) {
4819 0 : return tevent_req_post(req, ev);
4820 : }
4821 : /*
4822 : * SMBcheckpath on a DFS share must use DFS names.
4823 : */
4824 0 : fname_cp = smb1_dfs_share_path(state, cli, fname);
4825 0 : if (tevent_req_nomem(fname_cp, req)) {
4826 0 : return tevent_req_post(req, ev);
4827 : }
4828 0 : bytes[0] = 4;
4829 0 : bytes = smb_bytes_push_str(bytes,
4830 0 : smbXcli_conn_use_unicode(cli->conn),
4831 : fname_cp,
4832 0 : strlen(fname_cp)+1,
4833 : NULL);
4834 :
4835 0 : if (tevent_req_nomem(bytes, req)) {
4836 0 : return tevent_req_post(req, ev);
4837 : }
4838 :
4839 0 : if (clistr_is_previous_version_path(fname)) {
4840 0 : additional_flags2 = FLAGS2_REPARSE_PATH;
4841 : }
4842 :
4843 0 : subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
4844 : additional_flags2,
4845 0 : 0, NULL, talloc_get_size(bytes), bytes);
4846 0 : if (tevent_req_nomem(subreq, req)) {
4847 0 : return tevent_req_post(req, ev);
4848 : }
4849 0 : tevent_req_set_callback(subreq, cli_chkpath_done, req);
4850 0 : return req;
4851 : }
4852 :
4853 0 : static void cli_chkpath_done(struct tevent_req *subreq)
4854 : {
4855 0 : NTSTATUS status = cli_smb_recv(
4856 : subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4857 0 : tevent_req_simple_finish_ntstatus(subreq, status);
4858 0 : }
4859 :
4860 2977 : static void cli_chkpath_opened(struct tevent_req *subreq)
4861 : {
4862 2977 : struct tevent_req *req = tevent_req_callback_data(
4863 : subreq, struct tevent_req);
4864 2977 : struct cli_chkpath_state *state = tevent_req_data(
4865 : req, struct cli_chkpath_state);
4866 : NTSTATUS status;
4867 : uint16_t fnum;
4868 :
4869 2977 : status = cli_ntcreate_recv(subreq, &fnum, NULL);
4870 2977 : TALLOC_FREE(subreq);
4871 2977 : if (tevent_req_nterror(req, status)) {
4872 791 : return;
4873 : }
4874 :
4875 2186 : subreq = cli_close_send(state, state->ev, state->cli, fnum);
4876 2186 : if (tevent_req_nomem(subreq, req)) {
4877 0 : return;
4878 : }
4879 2186 : tevent_req_set_callback(subreq, cli_chkpath_closed, req);
4880 : }
4881 :
4882 2186 : static void cli_chkpath_closed(struct tevent_req *subreq)
4883 : {
4884 2186 : NTSTATUS status = cli_close_recv(subreq);
4885 2186 : tevent_req_simple_finish_ntstatus(subreq, status);
4886 2186 : }
4887 :
4888 2977 : NTSTATUS cli_chkpath_recv(struct tevent_req *req)
4889 : {
4890 2977 : return tevent_req_simple_recv_ntstatus(req);
4891 : }
4892 :
4893 70 : NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
4894 : {
4895 70 : TALLOC_CTX *frame = NULL;
4896 70 : struct tevent_context *ev = NULL;
4897 70 : struct tevent_req *req = NULL;
4898 70 : char *path2 = NULL;
4899 70 : NTSTATUS status = NT_STATUS_OK;
4900 :
4901 70 : frame = talloc_stackframe();
4902 :
4903 70 : if (smbXcli_conn_has_async_calls(cli->conn)) {
4904 : /*
4905 : * Can't use sync call while an async call is in flight
4906 : */
4907 0 : status = NT_STATUS_INVALID_PARAMETER;
4908 0 : goto fail;
4909 : }
4910 :
4911 70 : path2 = talloc_strdup(frame, path);
4912 70 : if (!path2) {
4913 0 : status = NT_STATUS_NO_MEMORY;
4914 0 : goto fail;
4915 : }
4916 70 : trim_char(path2,'\0','\\');
4917 70 : if (!*path2) {
4918 0 : path2 = talloc_strdup(frame, "\\");
4919 0 : if (!path2) {
4920 0 : status = NT_STATUS_NO_MEMORY;
4921 0 : goto fail;
4922 : }
4923 : }
4924 :
4925 70 : ev = samba_tevent_context_init(frame);
4926 70 : if (ev == NULL) {
4927 0 : status = NT_STATUS_NO_MEMORY;
4928 0 : goto fail;
4929 : }
4930 :
4931 70 : req = cli_chkpath_send(frame, ev, cli, path2);
4932 70 : if (req == NULL) {
4933 0 : status = NT_STATUS_NO_MEMORY;
4934 0 : goto fail;
4935 : }
4936 :
4937 70 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4938 0 : goto fail;
4939 : }
4940 :
4941 70 : status = cli_chkpath_recv(req);
4942 70 : cli->raw_status = status; /* cli_smb2_chkpath_recv doesn't set this */
4943 :
4944 70 : fail:
4945 70 : TALLOC_FREE(frame);
4946 70 : return status;
4947 : }
4948 :
4949 : /****************************************************************************
4950 : Query disk space.
4951 : ****************************************************************************/
4952 :
4953 : static void cli_dskattr_done(struct tevent_req *subreq);
4954 :
4955 : struct cli_dskattr_state {
4956 : int bsize;
4957 : int total;
4958 : int avail;
4959 : };
4960 :
4961 0 : struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx,
4962 : struct tevent_context *ev,
4963 : struct cli_state *cli)
4964 : {
4965 0 : struct tevent_req *req = NULL, *subreq = NULL;
4966 0 : struct cli_dskattr_state *state = NULL;
4967 0 : uint8_t additional_flags = 0;
4968 :
4969 0 : req = tevent_req_create(mem_ctx, &state, struct cli_dskattr_state);
4970 0 : if (req == NULL) {
4971 0 : return NULL;
4972 : }
4973 :
4974 0 : subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags, 0,
4975 : 0, NULL, 0, NULL);
4976 0 : if (tevent_req_nomem(subreq, req)) {
4977 0 : return tevent_req_post(req, ev);
4978 : }
4979 0 : tevent_req_set_callback(subreq, cli_dskattr_done, req);
4980 0 : return req;
4981 : }
4982 :
4983 0 : static void cli_dskattr_done(struct tevent_req *subreq)
4984 : {
4985 0 : struct tevent_req *req = tevent_req_callback_data(
4986 : subreq, struct tevent_req);
4987 0 : struct cli_dskattr_state *state = tevent_req_data(
4988 : req, struct cli_dskattr_state);
4989 : uint8_t wct;
4990 0 : uint16_t *vwv = NULL;
4991 : NTSTATUS status;
4992 :
4993 0 : status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
4994 : NULL);
4995 0 : TALLOC_FREE(subreq);
4996 0 : if (tevent_req_nterror(req, status)) {
4997 0 : return;
4998 : }
4999 0 : state->bsize = SVAL(vwv+1, 0)*SVAL(vwv+2,0);
5000 0 : state->total = SVAL(vwv+0, 0);
5001 0 : state->avail = SVAL(vwv+3, 0);
5002 0 : tevent_req_done(req);
5003 : }
5004 :
5005 0 : NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *avail)
5006 : {
5007 0 : struct cli_dskattr_state *state = tevent_req_data(
5008 : req, struct cli_dskattr_state);
5009 : NTSTATUS status;
5010 :
5011 0 : if (tevent_req_is_nterror(req, &status)) {
5012 0 : return status;
5013 : }
5014 0 : *bsize = state->bsize;
5015 0 : *total = state->total;
5016 0 : *avail = state->avail;
5017 0 : return NT_STATUS_OK;
5018 : }
5019 :
5020 0 : NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
5021 : {
5022 0 : TALLOC_CTX *frame = NULL;
5023 0 : struct tevent_context *ev = NULL;
5024 0 : struct tevent_req *req = NULL;
5025 0 : NTSTATUS status = NT_STATUS_OK;
5026 :
5027 0 : frame = talloc_stackframe();
5028 :
5029 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
5030 : /*
5031 : * Can't use sync call while an async call is in flight
5032 : */
5033 0 : status = NT_STATUS_INVALID_PARAMETER;
5034 0 : goto fail;
5035 : }
5036 :
5037 0 : ev = samba_tevent_context_init(frame);
5038 0 : if (ev == NULL) {
5039 0 : status = NT_STATUS_NO_MEMORY;
5040 0 : goto fail;
5041 : }
5042 :
5043 0 : req = cli_dskattr_send(frame, ev, cli);
5044 0 : if (req == NULL) {
5045 0 : status = NT_STATUS_NO_MEMORY;
5046 0 : goto fail;
5047 : }
5048 :
5049 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5050 0 : goto fail;
5051 : }
5052 :
5053 0 : status = cli_dskattr_recv(req, bsize, total, avail);
5054 :
5055 0 : fail:
5056 0 : TALLOC_FREE(frame);
5057 0 : return status;
5058 : }
5059 :
5060 387 : NTSTATUS cli_disk_size(struct cli_state *cli, const char *path, uint64_t *bsize,
5061 : uint64_t *total, uint64_t *avail)
5062 : {
5063 : uint64_t sectors_per_block;
5064 : uint64_t bytes_per_sector;
5065 387 : int old_bsize = 0, old_total = 0, old_avail = 0;
5066 : NTSTATUS status;
5067 :
5068 387 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5069 387 : return cli_smb2_dskattr(cli, path, bsize, total, avail);
5070 : }
5071 :
5072 : /*
5073 : * Try the trans2 disk full size info call first.
5074 : * We already use this in SMBC_fstatvfs_ctx().
5075 : * Ignore 'actual_available_units' as we only
5076 : * care about the quota for the caller.
5077 : */
5078 :
5079 0 : status = cli_get_fs_full_size_info(cli,
5080 : total,
5081 : avail,
5082 : NULL,
5083 : §ors_per_block,
5084 : &bytes_per_sector);
5085 :
5086 : /* Try and cope will all varients of "we don't do this call"
5087 : and fall back to cli_dskattr. */
5088 :
5089 0 : if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
5090 0 : NT_STATUS_EQUAL(status,NT_STATUS_NOT_SUPPORTED) ||
5091 0 : NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
5092 0 : NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
5093 0 : NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
5094 0 : NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
5095 0 : NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
5096 0 : NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
5097 0 : NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
5098 0 : NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
5099 0 : goto try_dskattr;
5100 : }
5101 :
5102 0 : if (!NT_STATUS_IS_OK(status)) {
5103 0 : return status;
5104 : }
5105 :
5106 0 : if (bsize) {
5107 0 : *bsize = sectors_per_block *
5108 : bytes_per_sector;
5109 : }
5110 :
5111 0 : return NT_STATUS_OK;
5112 :
5113 0 : try_dskattr:
5114 :
5115 : /* Old SMB1 core protocol fallback. */
5116 0 : status = cli_dskattr(cli, &old_bsize, &old_total, &old_avail);
5117 0 : if (!NT_STATUS_IS_OK(status)) {
5118 0 : return status;
5119 : }
5120 0 : if (bsize) {
5121 0 : *bsize = (uint64_t)old_bsize;
5122 : }
5123 0 : if (total) {
5124 0 : *total = (uint64_t)old_total;
5125 : }
5126 0 : if (avail) {
5127 0 : *avail = (uint64_t)old_avail;
5128 : }
5129 0 : return NT_STATUS_OK;
5130 : }
5131 :
5132 : /****************************************************************************
5133 : Create and open a temporary file.
5134 : ****************************************************************************/
5135 :
5136 : static void cli_ctemp_done(struct tevent_req *subreq);
5137 :
5138 : struct ctemp_state {
5139 : uint16_t vwv[3];
5140 : char *ret_path;
5141 : uint16_t fnum;
5142 : };
5143 :
5144 1 : struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx,
5145 : struct tevent_context *ev,
5146 : struct cli_state *cli,
5147 : const char *path)
5148 : {
5149 1 : struct tevent_req *req = NULL, *subreq = NULL;
5150 1 : struct ctemp_state *state = NULL;
5151 1 : uint8_t additional_flags = 0;
5152 1 : uint16_t additional_flags2 = 0;
5153 1 : uint8_t *bytes = NULL;
5154 1 : char *path_cp = NULL;
5155 :
5156 1 : req = tevent_req_create(mem_ctx, &state, struct ctemp_state);
5157 1 : if (req == NULL) {
5158 0 : return NULL;
5159 : }
5160 :
5161 1 : SSVAL(state->vwv,0,0);
5162 1 : SIVALS(state->vwv+1,0,-1);
5163 :
5164 1 : bytes = talloc_array(state, uint8_t, 1);
5165 1 : if (tevent_req_nomem(bytes, req)) {
5166 0 : return tevent_req_post(req, ev);
5167 : }
5168 : /*
5169 : * SMBctemp on a DFS share must use DFS names.
5170 : */
5171 1 : path_cp = smb1_dfs_share_path(state, cli, path);
5172 1 : if (tevent_req_nomem(path_cp, req)) {
5173 0 : return tevent_req_post(req, ev);
5174 : }
5175 1 : bytes[0] = 4;
5176 1 : bytes = smb_bytes_push_str(bytes,
5177 1 : smbXcli_conn_use_unicode(cli->conn),
5178 : path_cp,
5179 1 : strlen(path_cp)+1,
5180 : NULL);
5181 1 : if (tevent_req_nomem(bytes, req)) {
5182 0 : return tevent_req_post(req, ev);
5183 : }
5184 :
5185 1 : if (clistr_is_previous_version_path(path)) {
5186 0 : additional_flags2 = FLAGS2_REPARSE_PATH;
5187 : }
5188 :
5189 1 : subreq = cli_smb_send(state, ev, cli, SMBctemp, additional_flags,
5190 : additional_flags2,
5191 1 : 3, state->vwv, talloc_get_size(bytes), bytes);
5192 1 : if (tevent_req_nomem(subreq, req)) {
5193 0 : return tevent_req_post(req, ev);
5194 : }
5195 1 : tevent_req_set_callback(subreq, cli_ctemp_done, req);
5196 1 : return req;
5197 : }
5198 :
5199 1 : static void cli_ctemp_done(struct tevent_req *subreq)
5200 : {
5201 1 : struct tevent_req *req = tevent_req_callback_data(
5202 : subreq, struct tevent_req);
5203 1 : struct ctemp_state *state = tevent_req_data(
5204 : req, struct ctemp_state);
5205 : NTSTATUS status;
5206 : uint8_t wcnt;
5207 : uint16_t *vwv;
5208 1 : uint32_t num_bytes = 0;
5209 1 : uint8_t *bytes = NULL;
5210 :
5211 1 : status = cli_smb_recv(subreq, state, NULL, 1, &wcnt, &vwv,
5212 : &num_bytes, &bytes);
5213 1 : TALLOC_FREE(subreq);
5214 1 : if (tevent_req_nterror(req, status)) {
5215 0 : return;
5216 : }
5217 :
5218 1 : state->fnum = SVAL(vwv+0, 0);
5219 :
5220 : /* From W2K3, the result is just the ASCII name */
5221 1 : if (num_bytes < 2) {
5222 0 : tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
5223 0 : return;
5224 : }
5225 :
5226 1 : if (pull_string_talloc(state,
5227 : NULL,
5228 : 0,
5229 : &state->ret_path,
5230 : bytes,
5231 : num_bytes,
5232 : STR_ASCII) == 0) {
5233 0 : tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
5234 0 : return;
5235 : }
5236 1 : tevent_req_done(req);
5237 : }
5238 :
5239 1 : NTSTATUS cli_ctemp_recv(struct tevent_req *req,
5240 : TALLOC_CTX *ctx,
5241 : uint16_t *pfnum,
5242 : char **outfile)
5243 : {
5244 1 : struct ctemp_state *state = tevent_req_data(req,
5245 : struct ctemp_state);
5246 : NTSTATUS status;
5247 :
5248 1 : if (tevent_req_is_nterror(req, &status)) {
5249 0 : return status;
5250 : }
5251 1 : *pfnum = state->fnum;
5252 1 : *outfile = talloc_strdup(ctx, state->ret_path);
5253 1 : if (!*outfile) {
5254 0 : return NT_STATUS_NO_MEMORY;
5255 : }
5256 1 : return NT_STATUS_OK;
5257 : }
5258 :
5259 1 : NTSTATUS cli_ctemp(struct cli_state *cli,
5260 : TALLOC_CTX *ctx,
5261 : const char *path,
5262 : uint16_t *pfnum,
5263 : char **out_path)
5264 : {
5265 1 : TALLOC_CTX *frame = talloc_stackframe();
5266 : struct tevent_context *ev;
5267 : struct tevent_req *req;
5268 1 : NTSTATUS status = NT_STATUS_OK;
5269 :
5270 1 : if (smbXcli_conn_has_async_calls(cli->conn)) {
5271 : /*
5272 : * Can't use sync call while an async call is in flight
5273 : */
5274 0 : status = NT_STATUS_INVALID_PARAMETER;
5275 0 : goto fail;
5276 : }
5277 :
5278 1 : ev = samba_tevent_context_init(frame);
5279 1 : if (ev == NULL) {
5280 0 : status = NT_STATUS_NO_MEMORY;
5281 0 : goto fail;
5282 : }
5283 :
5284 1 : req = cli_ctemp_send(frame, ev, cli, path);
5285 1 : if (req == NULL) {
5286 0 : status = NT_STATUS_NO_MEMORY;
5287 0 : goto fail;
5288 : }
5289 :
5290 1 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5291 0 : goto fail;
5292 : }
5293 :
5294 1 : status = cli_ctemp_recv(req, ctx, pfnum, out_path);
5295 :
5296 1 : fail:
5297 1 : TALLOC_FREE(frame);
5298 1 : return status;
5299 : }
5300 :
5301 : /*
5302 : send a raw ioctl - used by the torture code
5303 : */
5304 65538 : NTSTATUS cli_raw_ioctl(struct cli_state *cli, uint16_t fnum, uint32_t code, DATA_BLOB *blob)
5305 : {
5306 : uint16_t vwv[3];
5307 : NTSTATUS status;
5308 :
5309 65538 : SSVAL(vwv+0, 0, fnum);
5310 65538 : SSVAL(vwv+1, 0, code>>16);
5311 65538 : SSVAL(vwv+2, 0, (code&0xFFFF));
5312 :
5313 65538 : status = cli_smb(talloc_tos(), cli, SMBioctl, 0, 3, vwv, 0, NULL,
5314 : NULL, 0, NULL, NULL, NULL, NULL);
5315 65538 : if (!NT_STATUS_IS_OK(status)) {
5316 65538 : return status;
5317 : }
5318 0 : *blob = data_blob_null;
5319 0 : return NT_STATUS_OK;
5320 : }
5321 :
5322 : /*********************************************************
5323 : Set an extended attribute utility fn.
5324 : *********************************************************/
5325 :
5326 0 : static NTSTATUS cli_set_ea(struct cli_state *cli, uint16_t setup_val,
5327 : uint8_t *param, unsigned int param_len,
5328 : const char *ea_name,
5329 : const char *ea_val, size_t ea_len)
5330 : {
5331 : uint16_t setup[1];
5332 0 : unsigned int data_len = 0;
5333 0 : uint8_t *data = NULL;
5334 : char *p;
5335 0 : size_t ea_namelen = strlen(ea_name);
5336 : NTSTATUS status;
5337 :
5338 0 : SSVAL(setup, 0, setup_val);
5339 :
5340 0 : if (ea_namelen == 0 && ea_len == 0) {
5341 0 : data_len = 4;
5342 0 : data = talloc_array(talloc_tos(),
5343 : uint8_t,
5344 : data_len);
5345 0 : if (!data) {
5346 0 : return NT_STATUS_NO_MEMORY;
5347 : }
5348 0 : p = (char *)data;
5349 0 : SIVAL(p,0,data_len);
5350 : } else {
5351 0 : data_len = 4 + 4 + ea_namelen + 1 + ea_len;
5352 0 : data = talloc_array(talloc_tos(),
5353 : uint8_t,
5354 : data_len);
5355 0 : if (!data) {
5356 0 : return NT_STATUS_NO_MEMORY;
5357 : }
5358 0 : p = (char *)data;
5359 0 : SIVAL(p,0,data_len);
5360 0 : p += 4;
5361 0 : SCVAL(p, 0, 0); /* EA flags. */
5362 0 : SCVAL(p, 1, ea_namelen);
5363 0 : SSVAL(p, 2, ea_len);
5364 0 : memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
5365 0 : memcpy(p+4+ea_namelen+1, ea_val, ea_len);
5366 : }
5367 :
5368 : /*
5369 : * FIXME - if we want to do previous version path
5370 : * processing on an EA set call we need to turn this
5371 : * into calls to cli_trans_send()/cli_trans_recv()
5372 : * with a temporary event context, as cli_trans_send()
5373 : * have access to the additional_flags2 needed to
5374 : * send @GMT- paths. JRA.
5375 : */
5376 :
5377 0 : status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, -1, 0, 0,
5378 : setup, 1, 0,
5379 : param, param_len, 2,
5380 : data, data_len, 0,
5381 : NULL,
5382 : NULL, 0, NULL, /* rsetup */
5383 : NULL, 0, NULL, /* rparam */
5384 : NULL, 0, NULL); /* rdata */
5385 0 : talloc_free(data);
5386 0 : return status;
5387 : }
5388 :
5389 : /*********************************************************
5390 : Set an extended attribute on a pathname.
5391 : *********************************************************/
5392 :
5393 0 : NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path,
5394 : const char *ea_name, const char *ea_val,
5395 : size_t ea_len)
5396 : {
5397 0 : unsigned int param_len = 0;
5398 : uint8_t *param;
5399 : NTSTATUS status;
5400 0 : TALLOC_CTX *frame = NULL;
5401 0 : char *path_cp = NULL;
5402 :
5403 0 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5404 0 : return cli_smb2_set_ea_path(cli,
5405 : path,
5406 : ea_name,
5407 : ea_val,
5408 : ea_len);
5409 : }
5410 :
5411 0 : frame = talloc_stackframe();
5412 :
5413 0 : param = talloc_array(frame, uint8_t, 6);
5414 0 : if (!param) {
5415 0 : status = NT_STATUS_NO_MEMORY;
5416 0 : goto fail;
5417 : }
5418 0 : SSVAL(param,0,SMB_INFO_SET_EA);
5419 0 : SSVAL(param,2,0);
5420 0 : SSVAL(param,4,0);
5421 :
5422 : /*
5423 : * TRANSACT2_SETPATHINFO on a DFS share must use DFS names.
5424 : */
5425 0 : path_cp = smb1_dfs_share_path(frame, cli, path);
5426 0 : if (path_cp == NULL) {
5427 0 : status = NT_STATUS_NO_MEMORY;
5428 0 : goto fail;
5429 : }
5430 0 : param = trans2_bytes_push_str(param,
5431 0 : smbXcli_conn_use_unicode(cli->conn),
5432 : path_cp,
5433 0 : strlen(path_cp)+1,
5434 : NULL);
5435 0 : param_len = talloc_get_size(param);
5436 :
5437 0 : status = cli_set_ea(cli, TRANSACT2_SETPATHINFO, param, param_len,
5438 : ea_name, ea_val, ea_len);
5439 :
5440 0 : fail:
5441 :
5442 0 : TALLOC_FREE(frame);
5443 0 : return status;
5444 : }
5445 :
5446 : /*********************************************************
5447 : Set an extended attribute on an fnum.
5448 : *********************************************************/
5449 :
5450 0 : NTSTATUS cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum,
5451 : const char *ea_name, const char *ea_val,
5452 : size_t ea_len)
5453 : {
5454 0 : uint8_t param[6] = { 0, };
5455 :
5456 0 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5457 0 : return cli_smb2_set_ea_fnum(cli,
5458 : fnum,
5459 : ea_name,
5460 : ea_val,
5461 : ea_len);
5462 : }
5463 :
5464 0 : SSVAL(param,0,fnum);
5465 0 : SSVAL(param,2,SMB_INFO_SET_EA);
5466 :
5467 0 : return cli_set_ea(cli, TRANSACT2_SETFILEINFO, param, 6,
5468 : ea_name, ea_val, ea_len);
5469 : }
5470 :
5471 : /*********************************************************
5472 : Get an extended attribute list utility fn.
5473 : *********************************************************/
5474 :
5475 0 : static bool parse_ea_blob(TALLOC_CTX *ctx, const uint8_t *rdata,
5476 : size_t rdata_len,
5477 : size_t *pnum_eas, struct ea_struct **pea_list)
5478 : {
5479 0 : struct ea_struct *ea_list = NULL;
5480 : size_t num_eas;
5481 : size_t ea_size;
5482 : const uint8_t *p;
5483 :
5484 0 : if (rdata_len < 4) {
5485 0 : return false;
5486 : }
5487 :
5488 0 : ea_size = (size_t)IVAL(rdata,0);
5489 0 : if (ea_size > rdata_len) {
5490 0 : return false;
5491 : }
5492 :
5493 0 : if (ea_size == 0) {
5494 : /* No EA's present. */
5495 0 : *pnum_eas = 0;
5496 0 : *pea_list = NULL;
5497 0 : return true;
5498 : }
5499 :
5500 0 : p = rdata + 4;
5501 0 : ea_size -= 4;
5502 :
5503 : /* Validate the EA list and count it. */
5504 0 : for (num_eas = 0; ea_size >= 4; num_eas++) {
5505 0 : unsigned int ea_namelen = CVAL(p,1);
5506 0 : unsigned int ea_valuelen = SVAL(p,2);
5507 0 : if (ea_namelen == 0) {
5508 0 : return false;
5509 : }
5510 0 : if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
5511 0 : return false;
5512 : }
5513 0 : ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
5514 0 : p += 4 + ea_namelen + 1 + ea_valuelen;
5515 : }
5516 :
5517 0 : if (num_eas == 0) {
5518 0 : *pnum_eas = 0;
5519 0 : *pea_list = NULL;
5520 0 : return true;
5521 : }
5522 :
5523 0 : *pnum_eas = num_eas;
5524 0 : if (!pea_list) {
5525 : /* Caller only wants number of EA's. */
5526 0 : return true;
5527 : }
5528 :
5529 0 : ea_list = talloc_array(ctx, struct ea_struct, num_eas);
5530 0 : if (!ea_list) {
5531 0 : return false;
5532 : }
5533 :
5534 0 : p = rdata + 4;
5535 :
5536 0 : for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
5537 0 : struct ea_struct *ea = &ea_list[num_eas];
5538 : fstring unix_ea_name;
5539 0 : unsigned int ea_namelen = CVAL(p,1);
5540 0 : unsigned int ea_valuelen = SVAL(p,2);
5541 :
5542 0 : ea->flags = CVAL(p,0);
5543 0 : unix_ea_name[0] = '\0';
5544 0 : pull_ascii(unix_ea_name, p + 4, sizeof(unix_ea_name), rdata_len - PTR_DIFF(p+4, rdata), STR_TERMINATE);
5545 0 : ea->name = talloc_strdup(ea_list, unix_ea_name);
5546 0 : if (!ea->name) {
5547 0 : goto fail;
5548 : }
5549 : /* Ensure the value is null terminated (in case it's a string). */
5550 0 : ea->value = data_blob_talloc(ea_list, NULL, ea_valuelen + 1);
5551 0 : if (!ea->value.data) {
5552 0 : goto fail;
5553 : }
5554 0 : if (ea_valuelen) {
5555 0 : memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
5556 : }
5557 0 : ea->value.data[ea_valuelen] = 0;
5558 0 : ea->value.length--;
5559 0 : p += 4 + ea_namelen + 1 + ea_valuelen;
5560 : }
5561 :
5562 0 : *pea_list = ea_list;
5563 0 : return true;
5564 :
5565 0 : fail:
5566 0 : TALLOC_FREE(ea_list);
5567 0 : return false;
5568 : }
5569 :
5570 : /*********************************************************
5571 : Get an extended attribute list from a pathname.
5572 : *********************************************************/
5573 :
5574 : struct cli_get_ea_list_path_state {
5575 : uint32_t num_data;
5576 : uint8_t *data;
5577 : };
5578 :
5579 : static void cli_get_ea_list_path_done(struct tevent_req *subreq);
5580 :
5581 0 : struct tevent_req *cli_get_ea_list_path_send(TALLOC_CTX *mem_ctx,
5582 : struct tevent_context *ev,
5583 : struct cli_state *cli,
5584 : const char *fname)
5585 : {
5586 : struct tevent_req *req, *subreq;
5587 : struct cli_get_ea_list_path_state *state;
5588 :
5589 0 : req = tevent_req_create(mem_ctx, &state,
5590 : struct cli_get_ea_list_path_state);
5591 0 : if (req == NULL) {
5592 0 : return NULL;
5593 : }
5594 0 : subreq = cli_qpathinfo_send(state, ev, cli, fname,
5595 : SMB_INFO_QUERY_ALL_EAS, 4,
5596 : CLI_BUFFER_SIZE);
5597 0 : if (tevent_req_nomem(subreq, req)) {
5598 0 : return tevent_req_post(req, ev);
5599 : }
5600 0 : tevent_req_set_callback(subreq, cli_get_ea_list_path_done, req);
5601 0 : return req;
5602 : }
5603 :
5604 0 : static void cli_get_ea_list_path_done(struct tevent_req *subreq)
5605 : {
5606 0 : struct tevent_req *req = tevent_req_callback_data(
5607 : subreq, struct tevent_req);
5608 0 : struct cli_get_ea_list_path_state *state = tevent_req_data(
5609 : req, struct cli_get_ea_list_path_state);
5610 : NTSTATUS status;
5611 :
5612 0 : status = cli_qpathinfo_recv(subreq, state, &state->data,
5613 : &state->num_data);
5614 0 : TALLOC_FREE(subreq);
5615 0 : if (tevent_req_nterror(req, status)) {
5616 0 : return;
5617 : }
5618 0 : tevent_req_done(req);
5619 : }
5620 :
5621 0 : NTSTATUS cli_get_ea_list_path_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5622 : size_t *pnum_eas, struct ea_struct **peas)
5623 : {
5624 0 : struct cli_get_ea_list_path_state *state = tevent_req_data(
5625 : req, struct cli_get_ea_list_path_state);
5626 : NTSTATUS status;
5627 :
5628 0 : if (tevent_req_is_nterror(req, &status)) {
5629 0 : return status;
5630 : }
5631 0 : if (!parse_ea_blob(mem_ctx, state->data, state->num_data,
5632 : pnum_eas, peas)) {
5633 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
5634 : }
5635 0 : return NT_STATUS_OK;
5636 : }
5637 :
5638 0 : NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path,
5639 : TALLOC_CTX *ctx,
5640 : size_t *pnum_eas,
5641 : struct ea_struct **pea_list)
5642 : {
5643 0 : TALLOC_CTX *frame = NULL;
5644 0 : struct tevent_context *ev = NULL;
5645 0 : struct tevent_req *req = NULL;
5646 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
5647 :
5648 0 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5649 0 : return cli_smb2_get_ea_list_path(cli,
5650 : path,
5651 : ctx,
5652 : pnum_eas,
5653 : pea_list);
5654 : }
5655 :
5656 0 : frame = talloc_stackframe();
5657 :
5658 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
5659 : /*
5660 : * Can't use sync call while an async call is in flight
5661 : */
5662 0 : status = NT_STATUS_INVALID_PARAMETER;
5663 0 : goto fail;
5664 : }
5665 0 : ev = samba_tevent_context_init(frame);
5666 0 : if (ev == NULL) {
5667 0 : goto fail;
5668 : }
5669 0 : req = cli_get_ea_list_path_send(frame, ev, cli, path);
5670 0 : if (req == NULL) {
5671 0 : goto fail;
5672 : }
5673 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5674 0 : goto fail;
5675 : }
5676 0 : status = cli_get_ea_list_path_recv(req, ctx, pnum_eas, pea_list);
5677 0 : fail:
5678 0 : TALLOC_FREE(frame);
5679 0 : return status;
5680 : }
5681 :
5682 : /****************************************************************************
5683 : Convert open "flags" arg to uint32_t on wire.
5684 : ****************************************************************************/
5685 :
5686 0 : static uint32_t open_flags_to_wire(int flags)
5687 : {
5688 0 : int open_mode = flags & O_ACCMODE;
5689 0 : uint32_t ret = 0;
5690 :
5691 0 : switch (open_mode) {
5692 0 : case O_WRONLY:
5693 0 : ret |= SMB_O_WRONLY;
5694 0 : break;
5695 0 : case O_RDWR:
5696 0 : ret |= SMB_O_RDWR;
5697 0 : break;
5698 0 : default:
5699 : case O_RDONLY:
5700 0 : ret |= SMB_O_RDONLY;
5701 0 : break;
5702 : }
5703 :
5704 0 : if (flags & O_CREAT) {
5705 0 : ret |= SMB_O_CREAT;
5706 : }
5707 0 : if (flags & O_EXCL) {
5708 0 : ret |= SMB_O_EXCL;
5709 : }
5710 0 : if (flags & O_TRUNC) {
5711 0 : ret |= SMB_O_TRUNC;
5712 : }
5713 : #if defined(O_SYNC)
5714 0 : if (flags & O_SYNC) {
5715 0 : ret |= SMB_O_SYNC;
5716 : }
5717 : #endif /* O_SYNC */
5718 0 : if (flags & O_APPEND) {
5719 0 : ret |= SMB_O_APPEND;
5720 : }
5721 : #if defined(O_DIRECT)
5722 0 : if (flags & O_DIRECT) {
5723 0 : ret |= SMB_O_DIRECT;
5724 : }
5725 : #endif
5726 : #if defined(O_DIRECTORY)
5727 0 : if (flags & O_DIRECTORY) {
5728 0 : ret |= SMB_O_DIRECTORY;
5729 : }
5730 : #endif
5731 0 : return ret;
5732 : }
5733 :
5734 : /****************************************************************************
5735 : Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
5736 : ****************************************************************************/
5737 :
5738 : struct cli_posix_open_internal_state {
5739 : uint16_t setup;
5740 : uint8_t *param;
5741 : uint8_t data[18];
5742 : uint16_t fnum; /* Out */
5743 : };
5744 :
5745 : static void cli_posix_open_internal_done(struct tevent_req *subreq);
5746 :
5747 0 : static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
5748 : struct tevent_context *ev,
5749 : struct cli_state *cli,
5750 : const char *fname,
5751 : uint32_t wire_flags,
5752 : mode_t mode)
5753 : {
5754 0 : struct tevent_req *req = NULL, *subreq = NULL;
5755 0 : struct cli_posix_open_internal_state *state = NULL;
5756 0 : char *fname_cp = NULL;
5757 :
5758 0 : req = tevent_req_create(
5759 : mem_ctx, &state, struct cli_posix_open_internal_state);
5760 0 : if (req == NULL) {
5761 0 : return NULL;
5762 : }
5763 :
5764 : /* Setup setup word. */
5765 0 : SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
5766 :
5767 : /* Setup param array. */
5768 0 : state->param = talloc_zero_array(state, uint8_t, 6);
5769 0 : if (tevent_req_nomem(state->param, req)) {
5770 0 : return tevent_req_post(req, ev);
5771 : }
5772 0 : SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
5773 :
5774 : /*
5775 : * TRANSACT2_SETPATHINFO on a DFS share must use DFS names.
5776 : */
5777 0 : fname_cp = smb1_dfs_share_path(state, cli, fname);
5778 0 : if (tevent_req_nomem(fname_cp, req)) {
5779 0 : return tevent_req_post(req, ev);
5780 : }
5781 0 : state->param = trans2_bytes_push_str(
5782 0 : state->param,
5783 0 : smbXcli_conn_use_unicode(cli->conn),
5784 : fname_cp,
5785 0 : strlen(fname_cp)+1,
5786 : NULL);
5787 :
5788 0 : if (tevent_req_nomem(state->param, req)) {
5789 0 : return tevent_req_post(req, ev);
5790 : }
5791 :
5792 0 : SIVAL(state->data,0,0); /* No oplock. */
5793 0 : SIVAL(state->data,4,wire_flags);
5794 0 : SIVAL(state->data,8,unix_perms_to_wire(mode));
5795 0 : SIVAL(state->data,12,0); /* Top bits of perms currently undefined. */
5796 0 : SSVAL(state->data,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
5797 :
5798 0 : subreq = cli_trans_send(state, /* mem ctx. */
5799 : ev, /* event ctx. */
5800 : cli, /* cli_state. */
5801 : 0, /* additional_flags2 */
5802 : SMBtrans2, /* cmd. */
5803 : NULL, /* pipe name. */
5804 : -1, /* fid. */
5805 : 0, /* function. */
5806 : 0, /* flags. */
5807 0 : &state->setup, /* setup. */
5808 : 1, /* num setup uint16_t words. */
5809 : 0, /* max returned setup. */
5810 0 : state->param, /* param. */
5811 0 : talloc_get_size(state->param),/* num param. */
5812 : 2, /* max returned param. */
5813 0 : state->data, /* data. */
5814 : 18, /* num data. */
5815 : 12); /* max returned data. */
5816 :
5817 0 : if (tevent_req_nomem(subreq, req)) {
5818 0 : return tevent_req_post(req, ev);
5819 : }
5820 0 : tevent_req_set_callback(subreq, cli_posix_open_internal_done, req);
5821 0 : return req;
5822 : }
5823 :
5824 0 : static void cli_posix_open_internal_done(struct tevent_req *subreq)
5825 : {
5826 0 : struct tevent_req *req = tevent_req_callback_data(
5827 : subreq, struct tevent_req);
5828 0 : struct cli_posix_open_internal_state *state = tevent_req_data(
5829 : req, struct cli_posix_open_internal_state);
5830 : NTSTATUS status;
5831 : uint8_t *data;
5832 : uint32_t num_data;
5833 :
5834 0 : status = cli_trans_recv(
5835 : subreq,
5836 : state,
5837 : NULL,
5838 : NULL,
5839 : 0,
5840 : NULL,
5841 : NULL,
5842 : 0,
5843 : NULL,
5844 : &data,
5845 : 12,
5846 : &num_data);
5847 0 : TALLOC_FREE(subreq);
5848 0 : if (tevent_req_nterror(req, status)) {
5849 0 : return;
5850 : }
5851 0 : state->fnum = SVAL(data,2);
5852 0 : tevent_req_done(req);
5853 : }
5854 :
5855 0 : static NTSTATUS cli_posix_open_internal_recv(struct tevent_req *req,
5856 : uint16_t *pfnum)
5857 : {
5858 0 : struct cli_posix_open_internal_state *state = tevent_req_data(
5859 : req, struct cli_posix_open_internal_state);
5860 : NTSTATUS status;
5861 :
5862 0 : if (tevent_req_is_nterror(req, &status)) {
5863 0 : return status;
5864 : }
5865 0 : *pfnum = state->fnum;
5866 0 : return NT_STATUS_OK;
5867 : }
5868 :
5869 : struct cli_posix_open_state {
5870 : uint16_t fnum;
5871 : };
5872 :
5873 : static void cli_posix_open_done(struct tevent_req *subreq);
5874 :
5875 0 : struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
5876 : struct tevent_context *ev,
5877 : struct cli_state *cli,
5878 : const char *fname,
5879 : int flags,
5880 : mode_t mode)
5881 : {
5882 0 : struct tevent_req *req = NULL, *subreq = NULL;
5883 0 : struct cli_posix_open_state *state = NULL;
5884 : uint32_t wire_flags;
5885 :
5886 0 : req = tevent_req_create(mem_ctx, &state,
5887 : struct cli_posix_open_state);
5888 0 : if (req == NULL) {
5889 0 : return NULL;
5890 : }
5891 :
5892 0 : wire_flags = open_flags_to_wire(flags);
5893 :
5894 0 : subreq = cli_posix_open_internal_send(
5895 : mem_ctx, ev, cli, fname, wire_flags, mode);
5896 0 : if (tevent_req_nomem(subreq, req)) {
5897 0 : return tevent_req_post(req, ev);
5898 : }
5899 0 : tevent_req_set_callback(subreq, cli_posix_open_done, req);
5900 0 : return req;
5901 : }
5902 :
5903 0 : static void cli_posix_open_done(struct tevent_req *subreq)
5904 : {
5905 0 : struct tevent_req *req = tevent_req_callback_data(
5906 : subreq, struct tevent_req);
5907 0 : struct cli_posix_open_state *state = tevent_req_data(
5908 : req, struct cli_posix_open_state);
5909 : NTSTATUS status;
5910 :
5911 0 : status = cli_posix_open_internal_recv(subreq, &state->fnum);
5912 0 : tevent_req_simple_finish_ntstatus(subreq, status);
5913 0 : }
5914 :
5915 0 : NTSTATUS cli_posix_open_recv(struct tevent_req *req, uint16_t *pfnum)
5916 : {
5917 0 : struct cli_posix_open_state *state = tevent_req_data(
5918 : req, struct cli_posix_open_state);
5919 : NTSTATUS status;
5920 :
5921 0 : if (tevent_req_is_nterror(req, &status)) {
5922 0 : return status;
5923 : }
5924 0 : *pfnum = state->fnum;
5925 0 : return NT_STATUS_OK;
5926 : }
5927 :
5928 : /****************************************************************************
5929 : Open - POSIX semantics. Doesn't request oplock.
5930 : ****************************************************************************/
5931 :
5932 0 : NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
5933 : int flags, mode_t mode, uint16_t *pfnum)
5934 : {
5935 :
5936 0 : TALLOC_CTX *frame = talloc_stackframe();
5937 0 : struct tevent_context *ev = NULL;
5938 0 : struct tevent_req *req = NULL;
5939 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
5940 :
5941 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
5942 : /*
5943 : * Can't use sync call while an async call is in flight
5944 : */
5945 0 : status = NT_STATUS_INVALID_PARAMETER;
5946 0 : goto fail;
5947 : }
5948 0 : ev = samba_tevent_context_init(frame);
5949 0 : if (ev == NULL) {
5950 0 : goto fail;
5951 : }
5952 0 : req = cli_posix_open_send(
5953 : frame, ev, cli, fname, flags, mode);
5954 0 : if (req == NULL) {
5955 0 : goto fail;
5956 : }
5957 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5958 0 : goto fail;
5959 : }
5960 0 : status = cli_posix_open_recv(req, pfnum);
5961 0 : fail:
5962 0 : TALLOC_FREE(frame);
5963 0 : return status;
5964 : }
5965 :
5966 : struct cli_posix_mkdir_state {
5967 : struct tevent_context *ev;
5968 : struct cli_state *cli;
5969 : };
5970 :
5971 : static void cli_posix_mkdir_done(struct tevent_req *subreq);
5972 :
5973 0 : struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
5974 : struct tevent_context *ev,
5975 : struct cli_state *cli,
5976 : const char *fname,
5977 : mode_t mode)
5978 : {
5979 0 : struct tevent_req *req = NULL, *subreq = NULL;
5980 0 : struct cli_posix_mkdir_state *state = NULL;
5981 : uint32_t wire_flags;
5982 :
5983 0 : req = tevent_req_create(
5984 : mem_ctx, &state, struct cli_posix_mkdir_state);
5985 0 : if (req == NULL) {
5986 0 : return NULL;
5987 : }
5988 0 : state->ev = ev;
5989 0 : state->cli = cli;
5990 :
5991 0 : wire_flags = SMB_O_CREAT | SMB_O_DIRECTORY;
5992 :
5993 0 : subreq = cli_posix_open_internal_send(
5994 : mem_ctx, ev, cli, fname, wire_flags, mode);
5995 0 : if (tevent_req_nomem(subreq, req)) {
5996 0 : return tevent_req_post(req, ev);
5997 : }
5998 0 : tevent_req_set_callback(subreq, cli_posix_mkdir_done, req);
5999 0 : return req;
6000 : }
6001 :
6002 0 : static void cli_posix_mkdir_done(struct tevent_req *subreq)
6003 : {
6004 0 : struct tevent_req *req = tevent_req_callback_data(
6005 : subreq, struct tevent_req);
6006 : NTSTATUS status;
6007 : uint16_t fnum;
6008 :
6009 0 : status = cli_posix_open_internal_recv(subreq, &fnum);
6010 0 : TALLOC_FREE(subreq);
6011 0 : if (tevent_req_nterror(req, status)) {
6012 0 : return;
6013 : }
6014 0 : tevent_req_done(req);
6015 : }
6016 :
6017 0 : NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
6018 : {
6019 0 : return tevent_req_simple_recv_ntstatus(req);
6020 : }
6021 :
6022 0 : NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
6023 : {
6024 0 : TALLOC_CTX *frame = talloc_stackframe();
6025 0 : struct tevent_context *ev = NULL;
6026 0 : struct tevent_req *req = NULL;
6027 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
6028 :
6029 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
6030 : /*
6031 : * Can't use sync call while an async call is in flight
6032 : */
6033 0 : status = NT_STATUS_INVALID_PARAMETER;
6034 0 : goto fail;
6035 : }
6036 :
6037 0 : ev = samba_tevent_context_init(frame);
6038 0 : if (ev == NULL) {
6039 0 : goto fail;
6040 : }
6041 0 : req = cli_posix_mkdir_send(
6042 : frame, ev, cli, fname, mode);
6043 0 : if (req == NULL) {
6044 0 : goto fail;
6045 : }
6046 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6047 0 : goto fail;
6048 : }
6049 0 : status = cli_posix_mkdir_recv(req);
6050 0 : fail:
6051 0 : TALLOC_FREE(frame);
6052 0 : return status;
6053 : }
6054 :
6055 : /****************************************************************************
6056 : unlink or rmdir - POSIX semantics.
6057 : ****************************************************************************/
6058 :
6059 : struct cli_posix_unlink_internal_state {
6060 : uint8_t data[2];
6061 : };
6062 :
6063 : static void cli_posix_unlink_internal_done(struct tevent_req *subreq);
6064 :
6065 0 : static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
6066 : struct tevent_context *ev,
6067 : struct cli_state *cli,
6068 : const char *fname,
6069 : uint16_t level)
6070 : {
6071 0 : struct tevent_req *req = NULL, *subreq = NULL;
6072 0 : struct cli_posix_unlink_internal_state *state = NULL;
6073 :
6074 0 : req = tevent_req_create(mem_ctx, &state,
6075 : struct cli_posix_unlink_internal_state);
6076 0 : if (req == NULL) {
6077 0 : return NULL;
6078 : }
6079 :
6080 : /* Setup data word. */
6081 0 : SSVAL(state->data, 0, level);
6082 :
6083 0 : subreq = cli_setpathinfo_send(state, ev, cli,
6084 : SMB_POSIX_PATH_UNLINK,
6085 : fname,
6086 0 : state->data, sizeof(state->data));
6087 0 : if (tevent_req_nomem(subreq, req)) {
6088 0 : return tevent_req_post(req, ev);
6089 : }
6090 0 : tevent_req_set_callback(subreq, cli_posix_unlink_internal_done, req);
6091 0 : return req;
6092 : }
6093 :
6094 0 : static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
6095 : {
6096 0 : NTSTATUS status = cli_setpathinfo_recv(subreq);
6097 0 : tevent_req_simple_finish_ntstatus(subreq, status);
6098 0 : }
6099 :
6100 0 : static NTSTATUS cli_posix_unlink_internal_recv(struct tevent_req *req)
6101 : {
6102 0 : return tevent_req_simple_recv_ntstatus(req);
6103 : }
6104 :
6105 : struct cli_posix_unlink_state {
6106 : uint8_t dummy;
6107 : };
6108 :
6109 : static void cli_posix_unlink_done(struct tevent_req *subreq);
6110 :
6111 0 : struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx,
6112 : struct tevent_context *ev,
6113 : struct cli_state *cli,
6114 : const char *fname)
6115 : {
6116 0 : struct tevent_req *req = NULL, *subreq = NULL;
6117 : struct cli_posix_unlink_state *state;
6118 :
6119 0 : req = tevent_req_create(
6120 : mem_ctx, &state, struct cli_posix_unlink_state);
6121 0 : if (req == NULL) {
6122 0 : return NULL;
6123 : }
6124 0 : subreq = cli_posix_unlink_internal_send(
6125 : mem_ctx, ev, cli, fname, SMB_POSIX_UNLINK_FILE_TARGET);
6126 0 : if (tevent_req_nomem(subreq, req)) {
6127 0 : return tevent_req_post(req, ev);
6128 : }
6129 0 : tevent_req_set_callback(subreq, cli_posix_unlink_done, req);
6130 0 : return req;
6131 : }
6132 :
6133 0 : static void cli_posix_unlink_done(struct tevent_req *subreq)
6134 : {
6135 0 : NTSTATUS status = cli_posix_unlink_internal_recv(subreq);
6136 0 : tevent_req_simple_finish_ntstatus(subreq, status);
6137 0 : }
6138 :
6139 0 : NTSTATUS cli_posix_unlink_recv(struct tevent_req *req)
6140 : {
6141 0 : return tevent_req_simple_recv_ntstatus(req);
6142 : }
6143 :
6144 : /****************************************************************************
6145 : unlink - POSIX semantics.
6146 : ****************************************************************************/
6147 :
6148 0 : NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
6149 : {
6150 0 : TALLOC_CTX *frame = talloc_stackframe();
6151 0 : struct tevent_context *ev = NULL;
6152 0 : struct tevent_req *req = NULL;
6153 0 : NTSTATUS status = NT_STATUS_OK;
6154 :
6155 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
6156 : /*
6157 : * Can't use sync call while an async call is in flight
6158 : */
6159 0 : status = NT_STATUS_INVALID_PARAMETER;
6160 0 : goto fail;
6161 : }
6162 :
6163 0 : ev = samba_tevent_context_init(frame);
6164 0 : if (ev == NULL) {
6165 0 : status = NT_STATUS_NO_MEMORY;
6166 0 : goto fail;
6167 : }
6168 :
6169 0 : req = cli_posix_unlink_send(frame,
6170 : ev,
6171 : cli,
6172 : fname);
6173 0 : if (req == NULL) {
6174 0 : status = NT_STATUS_NO_MEMORY;
6175 0 : goto fail;
6176 : }
6177 :
6178 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6179 0 : goto fail;
6180 : }
6181 :
6182 0 : status = cli_posix_unlink_recv(req);
6183 :
6184 0 : fail:
6185 0 : TALLOC_FREE(frame);
6186 0 : return status;
6187 : }
6188 :
6189 : /****************************************************************************
6190 : rmdir - POSIX semantics.
6191 : ****************************************************************************/
6192 :
6193 : struct cli_posix_rmdir_state {
6194 : uint8_t dummy;
6195 : };
6196 :
6197 : static void cli_posix_rmdir_done(struct tevent_req *subreq);
6198 :
6199 0 : struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx,
6200 : struct tevent_context *ev,
6201 : struct cli_state *cli,
6202 : const char *fname)
6203 : {
6204 0 : struct tevent_req *req = NULL, *subreq = NULL;
6205 : struct cli_posix_rmdir_state *state;
6206 :
6207 0 : req = tevent_req_create(mem_ctx, &state, struct cli_posix_rmdir_state);
6208 0 : if (req == NULL) {
6209 0 : return NULL;
6210 : }
6211 0 : subreq = cli_posix_unlink_internal_send(
6212 : mem_ctx, ev, cli, fname, SMB_POSIX_UNLINK_DIRECTORY_TARGET);
6213 0 : if (tevent_req_nomem(subreq, req)) {
6214 0 : return tevent_req_post(req, ev);
6215 : }
6216 0 : tevent_req_set_callback(subreq, cli_posix_rmdir_done, req);
6217 0 : return req;
6218 : }
6219 :
6220 0 : static void cli_posix_rmdir_done(struct tevent_req *subreq)
6221 : {
6222 0 : NTSTATUS status = cli_posix_unlink_internal_recv(subreq);
6223 0 : tevent_req_simple_finish_ntstatus(subreq, status);
6224 0 : }
6225 :
6226 0 : NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
6227 : {
6228 0 : return tevent_req_simple_recv_ntstatus(req);
6229 : }
6230 :
6231 0 : NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
6232 : {
6233 0 : TALLOC_CTX *frame = talloc_stackframe();
6234 0 : struct tevent_context *ev = NULL;
6235 0 : struct tevent_req *req = NULL;
6236 0 : NTSTATUS status = NT_STATUS_OK;
6237 :
6238 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
6239 : /*
6240 : * Can't use sync call while an async call is in flight
6241 : */
6242 0 : status = NT_STATUS_INVALID_PARAMETER;
6243 0 : goto fail;
6244 : }
6245 :
6246 0 : ev = samba_tevent_context_init(frame);
6247 0 : if (ev == NULL) {
6248 0 : status = NT_STATUS_NO_MEMORY;
6249 0 : goto fail;
6250 : }
6251 :
6252 0 : req = cli_posix_rmdir_send(frame,
6253 : ev,
6254 : cli,
6255 : fname);
6256 0 : if (req == NULL) {
6257 0 : status = NT_STATUS_NO_MEMORY;
6258 0 : goto fail;
6259 : }
6260 :
6261 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6262 0 : goto fail;
6263 : }
6264 :
6265 0 : status = cli_posix_rmdir_recv(req, frame);
6266 :
6267 0 : fail:
6268 0 : TALLOC_FREE(frame);
6269 0 : return status;
6270 : }
6271 :
6272 : /****************************************************************************
6273 : filechangenotify
6274 : ****************************************************************************/
6275 :
6276 : struct cli_notify_state {
6277 : struct tevent_req *subreq;
6278 : uint8_t setup[8];
6279 : uint32_t num_changes;
6280 : struct notify_change *changes;
6281 : };
6282 :
6283 : static void cli_notify_done(struct tevent_req *subreq);
6284 : static void cli_notify_done_smb2(struct tevent_req *subreq);
6285 : static bool cli_notify_cancel(struct tevent_req *req);
6286 :
6287 42 : struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
6288 : struct tevent_context *ev,
6289 : struct cli_state *cli, uint16_t fnum,
6290 : uint32_t buffer_size,
6291 : uint32_t completion_filter, bool recursive)
6292 : {
6293 : struct tevent_req *req;
6294 : struct cli_notify_state *state;
6295 : unsigned old_timeout;
6296 :
6297 42 : req = tevent_req_create(mem_ctx, &state, struct cli_notify_state);
6298 42 : if (req == NULL) {
6299 0 : return NULL;
6300 : }
6301 :
6302 42 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
6303 : /*
6304 : * Notifies should not time out
6305 : */
6306 42 : old_timeout = cli_set_timeout(cli, 0);
6307 :
6308 42 : state->subreq = cli_smb2_notify_send(
6309 : state,
6310 : ev,
6311 : cli,
6312 : fnum,
6313 : buffer_size,
6314 : completion_filter,
6315 : recursive);
6316 :
6317 42 : cli_set_timeout(cli, old_timeout);
6318 :
6319 42 : if (tevent_req_nomem(state->subreq, req)) {
6320 0 : return tevent_req_post(req, ev);
6321 : }
6322 42 : tevent_req_set_callback(
6323 42 : state->subreq, cli_notify_done_smb2, req);
6324 42 : goto done;
6325 : }
6326 :
6327 0 : SIVAL(state->setup, 0, completion_filter);
6328 0 : SSVAL(state->setup, 4, fnum);
6329 0 : SSVAL(state->setup, 6, recursive);
6330 :
6331 : /*
6332 : * Notifies should not time out
6333 : */
6334 0 : old_timeout = cli_set_timeout(cli, 0);
6335 :
6336 0 : state->subreq = cli_trans_send(
6337 : state, /* mem ctx. */
6338 : ev, /* event ctx. */
6339 : cli, /* cli_state. */
6340 : 0, /* additional_flags2 */
6341 : SMBnttrans, /* cmd. */
6342 : NULL, /* pipe name. */
6343 : -1, /* fid. */
6344 : NT_TRANSACT_NOTIFY_CHANGE, /* function. */
6345 : 0, /* flags. */
6346 0 : (uint16_t *)state->setup, /* setup. */
6347 : 4, /* num setup uint16_t words. */
6348 : 0, /* max returned setup. */
6349 : NULL, /* param. */
6350 : 0, /* num param. */
6351 : buffer_size, /* max returned param. */
6352 : NULL, /* data. */
6353 : 0, /* num data. */
6354 : 0); /* max returned data. */
6355 :
6356 0 : cli_set_timeout(cli, old_timeout);
6357 :
6358 0 : if (tevent_req_nomem(state->subreq, req)) {
6359 0 : return tevent_req_post(req, ev);
6360 : }
6361 0 : tevent_req_set_callback(state->subreq, cli_notify_done, req);
6362 42 : done:
6363 42 : tevent_req_set_cancel_fn(req, cli_notify_cancel);
6364 42 : return req;
6365 : }
6366 :
6367 0 : static bool cli_notify_cancel(struct tevent_req *req)
6368 : {
6369 0 : struct cli_notify_state *state = tevent_req_data(
6370 : req, struct cli_notify_state);
6371 : bool ok;
6372 :
6373 0 : ok = tevent_req_cancel(state->subreq);
6374 0 : return ok;
6375 : }
6376 :
6377 0 : static void cli_notify_done(struct tevent_req *subreq)
6378 : {
6379 0 : struct tevent_req *req = tevent_req_callback_data(
6380 : subreq, struct tevent_req);
6381 0 : struct cli_notify_state *state = tevent_req_data(
6382 : req, struct cli_notify_state);
6383 : NTSTATUS status;
6384 : uint8_t *params;
6385 : uint32_t i, ofs, num_params;
6386 : uint16_t flags2;
6387 :
6388 0 : status = cli_trans_recv(subreq, talloc_tos(), &flags2, NULL, 0, NULL,
6389 : ¶ms, 0, &num_params, NULL, 0, NULL);
6390 0 : TALLOC_FREE(subreq);
6391 0 : state->subreq = NULL;
6392 0 : if (tevent_req_nterror(req, status)) {
6393 0 : DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status)));
6394 0 : return;
6395 : }
6396 :
6397 0 : state->num_changes = 0;
6398 0 : ofs = 0;
6399 :
6400 0 : while (num_params - ofs > 12) {
6401 0 : uint32_t next = IVAL(params, ofs);
6402 0 : state->num_changes += 1;
6403 :
6404 0 : if ((next == 0) || (ofs+next >= num_params)) {
6405 : break;
6406 : }
6407 0 : ofs += next;
6408 : }
6409 :
6410 0 : state->changes = talloc_array(state, struct notify_change,
6411 : state->num_changes);
6412 0 : if (tevent_req_nomem(state->changes, req)) {
6413 0 : TALLOC_FREE(params);
6414 0 : return;
6415 : }
6416 :
6417 0 : ofs = 0;
6418 :
6419 0 : for (i=0; i<state->num_changes; i++) {
6420 0 : uint32_t next = IVAL(params, ofs);
6421 0 : uint32_t len = IVAL(params, ofs+8);
6422 : ssize_t ret;
6423 : char *name;
6424 :
6425 0 : if (smb_buffer_oob(num_params, ofs + 12, len)) {
6426 0 : TALLOC_FREE(params);
6427 0 : tevent_req_nterror(
6428 : req, NT_STATUS_INVALID_NETWORK_RESPONSE);
6429 0 : return;
6430 : }
6431 :
6432 0 : state->changes[i].action = IVAL(params, ofs+4);
6433 0 : ret = pull_string_talloc(state->changes,
6434 : (char *)params,
6435 : flags2,
6436 : &name,
6437 0 : params+ofs+12,
6438 : len,
6439 : STR_TERMINATE|STR_UNICODE);
6440 0 : if (ret == -1) {
6441 0 : TALLOC_FREE(params);
6442 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
6443 0 : return;
6444 : }
6445 0 : state->changes[i].name = name;
6446 0 : ofs += next;
6447 : }
6448 :
6449 0 : TALLOC_FREE(params);
6450 0 : tevent_req_done(req);
6451 : }
6452 :
6453 42 : static void cli_notify_done_smb2(struct tevent_req *subreq)
6454 : {
6455 42 : struct tevent_req *req = tevent_req_callback_data(
6456 : subreq, struct tevent_req);
6457 42 : struct cli_notify_state *state = tevent_req_data(
6458 : req, struct cli_notify_state);
6459 : NTSTATUS status;
6460 :
6461 42 : status = cli_smb2_notify_recv(
6462 : subreq,
6463 : state,
6464 : &state->changes,
6465 : &state->num_changes);
6466 42 : TALLOC_FREE(subreq);
6467 42 : if (tevent_req_nterror(req, status)) {
6468 12 : return;
6469 : }
6470 30 : tevent_req_done(req);
6471 : }
6472 :
6473 42 : NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6474 : uint32_t *pnum_changes,
6475 : struct notify_change **pchanges)
6476 : {
6477 42 : struct cli_notify_state *state = tevent_req_data(
6478 : req, struct cli_notify_state);
6479 : NTSTATUS status;
6480 :
6481 42 : if (tevent_req_is_nterror(req, &status)) {
6482 12 : return status;
6483 : }
6484 :
6485 30 : *pnum_changes = state->num_changes;
6486 30 : *pchanges = talloc_move(mem_ctx, &state->changes);
6487 30 : return NT_STATUS_OK;
6488 : }
6489 :
6490 0 : NTSTATUS cli_notify(struct cli_state *cli, uint16_t fnum, uint32_t buffer_size,
6491 : uint32_t completion_filter, bool recursive,
6492 : TALLOC_CTX *mem_ctx, uint32_t *pnum_changes,
6493 : struct notify_change **pchanges)
6494 : {
6495 : TALLOC_CTX *frame;
6496 : struct tevent_context *ev;
6497 : struct tevent_req *req;
6498 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
6499 :
6500 0 : frame = talloc_stackframe();
6501 :
6502 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
6503 : /*
6504 : * Can't use sync call while an async call is in flight
6505 : */
6506 0 : status = NT_STATUS_INVALID_PARAMETER;
6507 0 : goto fail;
6508 : }
6509 0 : ev = samba_tevent_context_init(frame);
6510 0 : if (ev == NULL) {
6511 0 : goto fail;
6512 : }
6513 0 : req = cli_notify_send(ev, ev, cli, fnum, buffer_size,
6514 : completion_filter, recursive);
6515 0 : if (req == NULL) {
6516 0 : goto fail;
6517 : }
6518 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6519 0 : goto fail;
6520 : }
6521 0 : status = cli_notify_recv(req, mem_ctx, pnum_changes, pchanges);
6522 0 : fail:
6523 0 : TALLOC_FREE(frame);
6524 0 : return status;
6525 : }
6526 :
6527 : struct cli_qpathinfo_state {
6528 : uint8_t *param;
6529 : uint8_t *data;
6530 : uint16_t setup[1];
6531 : uint32_t min_rdata;
6532 : uint8_t *rdata;
6533 : uint32_t num_rdata;
6534 : };
6535 :
6536 : static void cli_qpathinfo_done(struct tevent_req *subreq);
6537 :
6538 4 : struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx,
6539 : struct tevent_context *ev,
6540 : struct cli_state *cli, const char *fname,
6541 : uint16_t level, uint32_t min_rdata,
6542 : uint32_t max_rdata)
6543 : {
6544 : struct tevent_req *req, *subreq;
6545 : struct cli_qpathinfo_state *state;
6546 4 : uint16_t additional_flags2 = 0;
6547 4 : char *fname_cp = NULL;
6548 :
6549 4 : req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo_state);
6550 4 : if (req == NULL) {
6551 0 : return NULL;
6552 : }
6553 4 : state->min_rdata = min_rdata;
6554 4 : SSVAL(state->setup, 0, TRANSACT2_QPATHINFO);
6555 :
6556 4 : state->param = talloc_zero_array(state, uint8_t, 6);
6557 4 : if (tevent_req_nomem(state->param, req)) {
6558 0 : return tevent_req_post(req, ev);
6559 : }
6560 4 : SSVAL(state->param, 0, level);
6561 : /*
6562 : * qpathinfo on a DFS share must use DFS names.
6563 : */
6564 4 : fname_cp = smb1_dfs_share_path(state, cli, fname);
6565 4 : if (tevent_req_nomem(fname_cp, req)) {
6566 0 : return tevent_req_post(req, ev);
6567 : }
6568 4 : state->param = trans2_bytes_push_str(state->param,
6569 4 : smbXcli_conn_use_unicode(cli->conn),
6570 : fname_cp,
6571 4 : strlen(fname_cp)+1,
6572 : NULL);
6573 4 : if (tevent_req_nomem(state->param, req)) {
6574 0 : return tevent_req_post(req, ev);
6575 : }
6576 :
6577 4 : if (clistr_is_previous_version_path(fname) &&
6578 0 : !INFO_LEVEL_IS_UNIX(level)) {
6579 0 : additional_flags2 = FLAGS2_REPARSE_PATH;
6580 : }
6581 :
6582 4 : subreq = cli_trans_send(
6583 : state, /* mem ctx. */
6584 : ev, /* event ctx. */
6585 : cli, /* cli_state. */
6586 : additional_flags2, /* additional_flags2 */
6587 : SMBtrans2, /* cmd. */
6588 : NULL, /* pipe name. */
6589 : -1, /* fid. */
6590 : 0, /* function. */
6591 : 0, /* flags. */
6592 4 : state->setup, /* setup. */
6593 : 1, /* num setup uint16_t words. */
6594 : 0, /* max returned setup. */
6595 4 : state->param, /* param. */
6596 4 : talloc_get_size(state->param), /* num param. */
6597 : 2, /* max returned param. */
6598 : NULL, /* data. */
6599 : 0, /* num data. */
6600 : max_rdata); /* max returned data. */
6601 :
6602 4 : if (tevent_req_nomem(subreq, req)) {
6603 0 : return tevent_req_post(req, ev);
6604 : }
6605 4 : tevent_req_set_callback(subreq, cli_qpathinfo_done, req);
6606 4 : return req;
6607 : }
6608 :
6609 4 : static void cli_qpathinfo_done(struct tevent_req *subreq)
6610 : {
6611 4 : struct tevent_req *req = tevent_req_callback_data(
6612 : subreq, struct tevent_req);
6613 4 : struct cli_qpathinfo_state *state = tevent_req_data(
6614 : req, struct cli_qpathinfo_state);
6615 : NTSTATUS status;
6616 :
6617 4 : status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
6618 : NULL, 0, NULL,
6619 : &state->rdata, state->min_rdata,
6620 : &state->num_rdata);
6621 4 : if (tevent_req_nterror(req, status)) {
6622 0 : return;
6623 : }
6624 4 : tevent_req_done(req);
6625 : }
6626 :
6627 4 : NTSTATUS cli_qpathinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6628 : uint8_t **rdata, uint32_t *num_rdata)
6629 : {
6630 4 : struct cli_qpathinfo_state *state = tevent_req_data(
6631 : req, struct cli_qpathinfo_state);
6632 : NTSTATUS status;
6633 :
6634 4 : if (tevent_req_is_nterror(req, &status)) {
6635 0 : return status;
6636 : }
6637 4 : if (rdata != NULL) {
6638 4 : *rdata = talloc_move(mem_ctx, &state->rdata);
6639 : } else {
6640 0 : TALLOC_FREE(state->rdata);
6641 : }
6642 4 : if (num_rdata != NULL) {
6643 4 : *num_rdata = state->num_rdata;
6644 : }
6645 4 : return NT_STATUS_OK;
6646 : }
6647 :
6648 0 : NTSTATUS cli_qpathinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
6649 : const char *fname, uint16_t level, uint32_t min_rdata,
6650 : uint32_t max_rdata,
6651 : uint8_t **rdata, uint32_t *num_rdata)
6652 : {
6653 0 : TALLOC_CTX *frame = talloc_stackframe();
6654 : struct tevent_context *ev;
6655 : struct tevent_req *req;
6656 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
6657 :
6658 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
6659 : /*
6660 : * Can't use sync call while an async call is in flight
6661 : */
6662 0 : status = NT_STATUS_INVALID_PARAMETER;
6663 0 : goto fail;
6664 : }
6665 0 : ev = samba_tevent_context_init(frame);
6666 0 : if (ev == NULL) {
6667 0 : goto fail;
6668 : }
6669 0 : req = cli_qpathinfo_send(frame, ev, cli, fname, level, min_rdata,
6670 : max_rdata);
6671 0 : if (req == NULL) {
6672 0 : goto fail;
6673 : }
6674 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6675 0 : goto fail;
6676 : }
6677 0 : status = cli_qpathinfo_recv(req, mem_ctx, rdata, num_rdata);
6678 0 : fail:
6679 0 : TALLOC_FREE(frame);
6680 0 : return status;
6681 : }
6682 :
6683 : struct cli_qfileinfo_state {
6684 : uint16_t setup[1];
6685 : uint8_t param[4];
6686 : uint8_t *data;
6687 : uint16_t recv_flags2;
6688 : uint32_t min_rdata;
6689 : uint8_t *rdata;
6690 : uint32_t num_rdata;
6691 : };
6692 :
6693 : static void cli_qfileinfo_done(struct tevent_req *subreq);
6694 :
6695 42 : struct tevent_req *cli_qfileinfo_send(TALLOC_CTX *mem_ctx,
6696 : struct tevent_context *ev,
6697 : struct cli_state *cli, uint16_t fnum,
6698 : uint16_t level, uint32_t min_rdata,
6699 : uint32_t max_rdata)
6700 : {
6701 : struct tevent_req *req, *subreq;
6702 : struct cli_qfileinfo_state *state;
6703 :
6704 42 : req = tevent_req_create(mem_ctx, &state, struct cli_qfileinfo_state);
6705 42 : if (req == NULL) {
6706 0 : return NULL;
6707 : }
6708 42 : state->min_rdata = min_rdata;
6709 42 : SSVAL(state->param, 0, fnum);
6710 42 : SSVAL(state->param, 2, level);
6711 42 : SSVAL(state->setup, 0, TRANSACT2_QFILEINFO);
6712 :
6713 42 : subreq = cli_trans_send(
6714 : state, /* mem ctx. */
6715 : ev, /* event ctx. */
6716 : cli, /* cli_state. */
6717 : 0, /* additional_flags2 */
6718 : SMBtrans2, /* cmd. */
6719 : NULL, /* pipe name. */
6720 : -1, /* fid. */
6721 : 0, /* function. */
6722 : 0, /* flags. */
6723 42 : state->setup, /* setup. */
6724 : 1, /* num setup uint16_t words. */
6725 : 0, /* max returned setup. */
6726 42 : state->param, /* param. */
6727 : sizeof(state->param), /* num param. */
6728 : 2, /* max returned param. */
6729 : NULL, /* data. */
6730 : 0, /* num data. */
6731 : max_rdata); /* max returned data. */
6732 :
6733 42 : if (tevent_req_nomem(subreq, req)) {
6734 0 : return tevent_req_post(req, ev);
6735 : }
6736 42 : tevent_req_set_callback(subreq, cli_qfileinfo_done, req);
6737 42 : return req;
6738 : }
6739 :
6740 42 : static void cli_qfileinfo_done(struct tevent_req *subreq)
6741 : {
6742 42 : struct tevent_req *req = tevent_req_callback_data(
6743 : subreq, struct tevent_req);
6744 42 : struct cli_qfileinfo_state *state = tevent_req_data(
6745 : req, struct cli_qfileinfo_state);
6746 : NTSTATUS status;
6747 :
6748 42 : status = cli_trans_recv(subreq, state,
6749 : &state->recv_flags2,
6750 : NULL, 0, NULL,
6751 : NULL, 0, NULL,
6752 : &state->rdata, state->min_rdata,
6753 : &state->num_rdata);
6754 42 : if (tevent_req_nterror(req, status)) {
6755 36 : return;
6756 : }
6757 6 : tevent_req_done(req);
6758 : }
6759 :
6760 42 : NTSTATUS cli_qfileinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6761 : uint16_t *recv_flags2,
6762 : uint8_t **rdata, uint32_t *num_rdata)
6763 : {
6764 42 : struct cli_qfileinfo_state *state = tevent_req_data(
6765 : req, struct cli_qfileinfo_state);
6766 : NTSTATUS status;
6767 :
6768 42 : if (tevent_req_is_nterror(req, &status)) {
6769 36 : return status;
6770 : }
6771 :
6772 6 : if (recv_flags2 != NULL) {
6773 1 : *recv_flags2 = state->recv_flags2;
6774 : }
6775 6 : if (rdata != NULL) {
6776 6 : *rdata = talloc_move(mem_ctx, &state->rdata);
6777 : }
6778 6 : if (num_rdata != NULL) {
6779 6 : *num_rdata = state->num_rdata;
6780 : }
6781 :
6782 6 : tevent_req_received(req);
6783 6 : return NT_STATUS_OK;
6784 : }
6785 :
6786 37 : NTSTATUS cli_qfileinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
6787 : uint16_t fnum, uint16_t level, uint32_t min_rdata,
6788 : uint32_t max_rdata, uint16_t *recv_flags2,
6789 : uint8_t **rdata, uint32_t *num_rdata)
6790 : {
6791 37 : TALLOC_CTX *frame = talloc_stackframe();
6792 : struct tevent_context *ev;
6793 : struct tevent_req *req;
6794 37 : NTSTATUS status = NT_STATUS_NO_MEMORY;
6795 :
6796 37 : if (smbXcli_conn_has_async_calls(cli->conn)) {
6797 : /*
6798 : * Can't use sync call while an async call is in flight
6799 : */
6800 0 : status = NT_STATUS_INVALID_PARAMETER;
6801 0 : goto fail;
6802 : }
6803 37 : ev = samba_tevent_context_init(frame);
6804 37 : if (ev == NULL) {
6805 0 : goto fail;
6806 : }
6807 37 : req = cli_qfileinfo_send(frame, ev, cli, fnum, level, min_rdata,
6808 : max_rdata);
6809 37 : if (req == NULL) {
6810 0 : goto fail;
6811 : }
6812 37 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6813 0 : goto fail;
6814 : }
6815 37 : status = cli_qfileinfo_recv(req, mem_ctx, recv_flags2, rdata, num_rdata);
6816 37 : fail:
6817 37 : TALLOC_FREE(frame);
6818 37 : return status;
6819 : }
6820 :
6821 : struct cli_flush_state {
6822 : uint16_t vwv[1];
6823 : };
6824 :
6825 : static void cli_flush_done(struct tevent_req *subreq);
6826 :
6827 0 : struct tevent_req *cli_flush_send(TALLOC_CTX *mem_ctx,
6828 : struct tevent_context *ev,
6829 : struct cli_state *cli,
6830 : uint16_t fnum)
6831 : {
6832 : struct tevent_req *req, *subreq;
6833 : struct cli_flush_state *state;
6834 :
6835 0 : req = tevent_req_create(mem_ctx, &state, struct cli_flush_state);
6836 0 : if (req == NULL) {
6837 0 : return NULL;
6838 : }
6839 0 : SSVAL(state->vwv + 0, 0, fnum);
6840 :
6841 0 : subreq = cli_smb_send(state, ev, cli, SMBflush, 0, 0, 1, state->vwv,
6842 : 0, NULL);
6843 0 : if (tevent_req_nomem(subreq, req)) {
6844 0 : return tevent_req_post(req, ev);
6845 : }
6846 0 : tevent_req_set_callback(subreq, cli_flush_done, req);
6847 0 : return req;
6848 : }
6849 :
6850 0 : static void cli_flush_done(struct tevent_req *subreq)
6851 : {
6852 0 : struct tevent_req *req = tevent_req_callback_data(
6853 : subreq, struct tevent_req);
6854 : NTSTATUS status;
6855 :
6856 0 : status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
6857 0 : TALLOC_FREE(subreq);
6858 0 : if (tevent_req_nterror(req, status)) {
6859 0 : return;
6860 : }
6861 0 : tevent_req_done(req);
6862 : }
6863 :
6864 0 : NTSTATUS cli_flush_recv(struct tevent_req *req)
6865 : {
6866 0 : return tevent_req_simple_recv_ntstatus(req);
6867 : }
6868 :
6869 0 : NTSTATUS cli_flush(TALLOC_CTX *mem_ctx, struct cli_state *cli, uint16_t fnum)
6870 : {
6871 0 : TALLOC_CTX *frame = talloc_stackframe();
6872 : struct tevent_context *ev;
6873 : struct tevent_req *req;
6874 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
6875 :
6876 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
6877 : /*
6878 : * Can't use sync call while an async call is in flight
6879 : */
6880 0 : status = NT_STATUS_INVALID_PARAMETER;
6881 0 : goto fail;
6882 : }
6883 0 : ev = samba_tevent_context_init(frame);
6884 0 : if (ev == NULL) {
6885 0 : goto fail;
6886 : }
6887 0 : req = cli_flush_send(frame, ev, cli, fnum);
6888 0 : if (req == NULL) {
6889 0 : goto fail;
6890 : }
6891 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6892 0 : goto fail;
6893 : }
6894 0 : status = cli_flush_recv(req);
6895 0 : fail:
6896 0 : TALLOC_FREE(frame);
6897 0 : return status;
6898 : }
6899 :
6900 : struct cli_shadow_copy_data_state {
6901 : uint16_t setup[4];
6902 : uint8_t *data;
6903 : uint32_t num_data;
6904 : bool get_names;
6905 : };
6906 :
6907 : static void cli_shadow_copy_data_done(struct tevent_req *subreq);
6908 :
6909 0 : struct tevent_req *cli_shadow_copy_data_send(TALLOC_CTX *mem_ctx,
6910 : struct tevent_context *ev,
6911 : struct cli_state *cli,
6912 : uint16_t fnum,
6913 : bool get_names)
6914 : {
6915 : struct tevent_req *req, *subreq;
6916 : struct cli_shadow_copy_data_state *state;
6917 : uint32_t ret_size;
6918 :
6919 0 : req = tevent_req_create(mem_ctx, &state,
6920 : struct cli_shadow_copy_data_state);
6921 0 : if (req == NULL) {
6922 0 : return NULL;
6923 : }
6924 0 : state->get_names = get_names;
6925 0 : ret_size = get_names ? CLI_BUFFER_SIZE : 16;
6926 :
6927 0 : SIVAL(state->setup + 0, 0, FSCTL_GET_SHADOW_COPY_DATA);
6928 0 : SSVAL(state->setup + 2, 0, fnum);
6929 0 : SCVAL(state->setup + 3, 0, 1); /* isFsctl */
6930 0 : SCVAL(state->setup + 3, 1, 0); /* compfilter, isFlags (WSSP) */
6931 :
6932 0 : subreq = cli_trans_send(
6933 : state, ev, cli, 0, SMBnttrans, NULL, 0, NT_TRANSACT_IOCTL, 0,
6934 0 : state->setup, ARRAY_SIZE(state->setup),
6935 : ARRAY_SIZE(state->setup),
6936 : NULL, 0, 0,
6937 : NULL, 0, ret_size);
6938 0 : if (tevent_req_nomem(subreq, req)) {
6939 0 : return tevent_req_post(req, ev);
6940 : }
6941 0 : tevent_req_set_callback(subreq, cli_shadow_copy_data_done, req);
6942 0 : return req;
6943 : }
6944 :
6945 0 : static void cli_shadow_copy_data_done(struct tevent_req *subreq)
6946 : {
6947 0 : struct tevent_req *req = tevent_req_callback_data(
6948 : subreq, struct tevent_req);
6949 0 : struct cli_shadow_copy_data_state *state = tevent_req_data(
6950 : req, struct cli_shadow_copy_data_state);
6951 : NTSTATUS status;
6952 :
6953 0 : status = cli_trans_recv(subreq, state, NULL,
6954 : NULL, 0, NULL, /* setup */
6955 : NULL, 0, NULL, /* param */
6956 : &state->data, 12, &state->num_data);
6957 0 : TALLOC_FREE(subreq);
6958 0 : if (tevent_req_nterror(req, status)) {
6959 0 : return;
6960 : }
6961 0 : tevent_req_done(req);
6962 : }
6963 :
6964 0 : NTSTATUS cli_shadow_copy_data_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6965 : char ***pnames, int *pnum_names)
6966 : {
6967 0 : struct cli_shadow_copy_data_state *state = tevent_req_data(
6968 : req, struct cli_shadow_copy_data_state);
6969 0 : char **names = NULL;
6970 : uint32_t i, num_names;
6971 : uint32_t dlength;
6972 0 : uint8_t *endp = NULL;
6973 : NTSTATUS status;
6974 :
6975 0 : if (tevent_req_is_nterror(req, &status)) {
6976 0 : return status;
6977 : }
6978 :
6979 0 : if (state->num_data < 16) {
6980 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
6981 : }
6982 :
6983 0 : num_names = IVAL(state->data, 4);
6984 0 : dlength = IVAL(state->data, 8);
6985 :
6986 0 : if (num_names > 0x7FFFFFFF) {
6987 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
6988 : }
6989 :
6990 0 : if (!state->get_names) {
6991 0 : *pnum_names = (int)num_names;
6992 0 : return NT_STATUS_OK;
6993 : }
6994 :
6995 0 : if (dlength + 12 < 12) {
6996 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
6997 : }
6998 0 : if (dlength + 12 > state->num_data) {
6999 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
7000 : }
7001 : if (state->num_data + (2 * sizeof(SHADOW_COPY_LABEL)) <
7002 : state->num_data) {
7003 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
7004 : }
7005 :
7006 0 : names = talloc_array(mem_ctx, char *, num_names);
7007 0 : if (names == NULL) {
7008 0 : return NT_STATUS_NO_MEMORY;
7009 : }
7010 :
7011 0 : endp = state->data + state->num_data;
7012 :
7013 0 : for (i=0; i<num_names; i++) {
7014 : bool ret;
7015 : uint8_t *src;
7016 : size_t converted_size;
7017 :
7018 0 : src = state->data + 12 + i * 2 * sizeof(SHADOW_COPY_LABEL);
7019 :
7020 0 : if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
7021 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
7022 : }
7023 :
7024 0 : ret = convert_string_talloc(
7025 : names, CH_UTF16LE, CH_UNIX,
7026 : src, 2 * sizeof(SHADOW_COPY_LABEL),
7027 0 : &names[i], &converted_size);
7028 0 : if (!ret) {
7029 0 : TALLOC_FREE(names);
7030 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
7031 : }
7032 : }
7033 0 : *pnum_names = (int)num_names;
7034 0 : *pnames = names;
7035 0 : return NT_STATUS_OK;
7036 : }
7037 :
7038 44 : NTSTATUS cli_shadow_copy_data(TALLOC_CTX *mem_ctx, struct cli_state *cli,
7039 : uint16_t fnum, bool get_names,
7040 : char ***pnames, int *pnum_names)
7041 : {
7042 44 : TALLOC_CTX *frame = NULL;
7043 : struct tevent_context *ev;
7044 : struct tevent_req *req;
7045 44 : NTSTATUS status = NT_STATUS_NO_MEMORY;
7046 :
7047 44 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
7048 44 : return cli_smb2_shadow_copy_data(mem_ctx,
7049 : cli,
7050 : fnum,
7051 : get_names,
7052 : pnames,
7053 : pnum_names);
7054 : }
7055 :
7056 0 : frame = talloc_stackframe();
7057 :
7058 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
7059 : /*
7060 : * Can't use sync call while an async call is in flight
7061 : */
7062 0 : status = NT_STATUS_INVALID_PARAMETER;
7063 0 : goto fail;
7064 : }
7065 0 : ev = samba_tevent_context_init(frame);
7066 0 : if (ev == NULL) {
7067 0 : goto fail;
7068 : }
7069 0 : req = cli_shadow_copy_data_send(frame, ev, cli, fnum, get_names);
7070 0 : if (req == NULL) {
7071 0 : goto fail;
7072 : }
7073 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
7074 0 : goto fail;
7075 : }
7076 0 : status = cli_shadow_copy_data_recv(req, mem_ctx, pnames, pnum_names);
7077 0 : fail:
7078 0 : TALLOC_FREE(frame);
7079 0 : return status;
7080 : }
7081 :
7082 : struct cli_fsctl_state {
7083 : DATA_BLOB out;
7084 : };
7085 :
7086 : static void cli_fsctl_smb1_done(struct tevent_req *subreq);
7087 : static void cli_fsctl_smb2_done(struct tevent_req *subreq);
7088 :
7089 4 : struct tevent_req *cli_fsctl_send(
7090 : TALLOC_CTX *mem_ctx,
7091 : struct tevent_context *ev,
7092 : struct cli_state *cli,
7093 : uint16_t fnum,
7094 : uint32_t ctl_code,
7095 : const DATA_BLOB *in,
7096 : uint32_t max_out)
7097 : {
7098 4 : struct tevent_req *req = NULL, *subreq = NULL;
7099 4 : struct cli_fsctl_state *state = NULL;
7100 4 : uint16_t *setup = NULL;
7101 :
7102 4 : req = tevent_req_create(mem_ctx, &state, struct cli_fsctl_state);
7103 4 : if (req == NULL) {
7104 0 : return NULL;
7105 : }
7106 :
7107 4 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
7108 4 : subreq = cli_smb2_fsctl_send(
7109 : state, ev, cli, fnum, ctl_code, in, max_out);
7110 4 : if (tevent_req_nomem(subreq, req)) {
7111 0 : return tevent_req_post(req, ev);
7112 : }
7113 4 : tevent_req_set_callback(subreq, cli_fsctl_smb2_done, req);
7114 4 : return req;
7115 : }
7116 :
7117 0 : setup = talloc_array(state, uint16_t, 4);
7118 0 : if (tevent_req_nomem(setup, req)) {
7119 0 : return tevent_req_post(req, ev);
7120 : }
7121 0 : SIVAL(setup, 0, ctl_code);
7122 0 : SSVAL(setup, 4, fnum);
7123 0 : SCVAL(setup, 6, 1); /* IsFcntl */
7124 0 : SCVAL(setup, 7, 0); /* IsFlags */
7125 :
7126 0 : subreq = cli_trans_send(
7127 : state, ev, cli,
7128 : 0, /* additional_flags2 */
7129 : SMBnttrans, /* cmd */
7130 : NULL, /* name */
7131 : -1, /* fid */
7132 : NT_TRANSACT_IOCTL, /* function */
7133 : 0, /* flags */
7134 : setup, 4, 0, /* setup */
7135 : NULL, 0, 0, /* param */
7136 0 : in->data, in->length, max_out); /* data */
7137 :
7138 0 : if (tevent_req_nomem(subreq, req)) {
7139 0 : return tevent_req_post(req, ev);
7140 : }
7141 0 : tevent_req_set_callback(subreq, cli_fsctl_smb1_done, req);
7142 0 : return req;
7143 : }
7144 :
7145 4 : static void cli_fsctl_smb2_done(struct tevent_req *subreq)
7146 : {
7147 4 : struct tevent_req *req = tevent_req_callback_data(
7148 : subreq, struct tevent_req);
7149 4 : struct cli_fsctl_state *state = tevent_req_data(
7150 : req, struct cli_fsctl_state);
7151 : NTSTATUS status;
7152 :
7153 4 : status = cli_smb2_fsctl_recv(subreq, state, &state->out);
7154 4 : tevent_req_simple_finish_ntstatus(subreq, status);
7155 4 : }
7156 :
7157 0 : static void cli_fsctl_smb1_done(struct tevent_req *subreq)
7158 : {
7159 0 : struct tevent_req *req = tevent_req_callback_data(
7160 : subreq, struct tevent_req);
7161 0 : struct cli_fsctl_state *state = tevent_req_data(
7162 : req, struct cli_fsctl_state);
7163 0 : uint8_t *out = NULL;
7164 : uint32_t out_len;
7165 : NTSTATUS status;
7166 :
7167 0 : status = cli_trans_recv(
7168 : subreq, state, NULL,
7169 : NULL, 0, NULL, /* rsetup */
7170 : NULL, 0, NULL, /* rparam */
7171 : &out, 0, &out_len);
7172 0 : TALLOC_FREE(subreq);
7173 0 : if (tevent_req_nterror(req, status)) {
7174 0 : return;
7175 : }
7176 0 : state->out = (DATA_BLOB) {
7177 : .data = out, .length = out_len,
7178 : };
7179 0 : tevent_req_done(req);
7180 : }
7181 :
7182 4 : NTSTATUS cli_fsctl_recv(
7183 : struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *out)
7184 : {
7185 4 : struct cli_fsctl_state *state = tevent_req_data(
7186 : req, struct cli_fsctl_state);
7187 : NTSTATUS status;
7188 :
7189 4 : if (tevent_req_is_nterror(req, &status)) {
7190 4 : return status;
7191 : }
7192 :
7193 0 : if (out != NULL) {
7194 0 : *out = (DATA_BLOB) {
7195 0 : .data = talloc_move(mem_ctx, &state->out.data),
7196 0 : .length = state->out.length,
7197 : };
7198 : }
7199 :
7200 0 : return NT_STATUS_OK;
7201 : }
|