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