s3: Paranoia in smbsock_connect_state_destructor
[Samba.git] / source3 / libsmb / clilist.c
blob1017eb54bd81322c28ecba59fe2b3a4613d1d8c5
1 /*
2 Unix SMB/CIFS implementation.
3 client directory list routines
4 Copyright (C) Andrew Tridgell 1994-1998
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "../lib/util/tevent_ntstatus.h"
22 #include "async_smb.h"
23 #include "trans2.h"
25 /****************************************************************************
26 Calculate a safe next_entry_offset.
27 ****************************************************************************/
29 static size_t calc_next_entry_offset(const char *base, const char *pdata_end)
31 size_t next_entry_offset = (size_t)IVAL(base,0);
33 if (next_entry_offset == 0 ||
34 base + next_entry_offset < base ||
35 base + next_entry_offset > pdata_end) {
36 next_entry_offset = pdata_end - base;
38 return next_entry_offset;
41 /****************************************************************************
42 Interpret a long filename structure - this is mostly guesses at the moment.
43 The length of the structure is returned
44 The structure of a long filename depends on the info level.
45 SMB_FIND_FILE_BOTH_DIRECTORY_INFO is used
46 by NT and SMB_FIND_EA_SIZE is used by OS/2
47 ****************************************************************************/
49 static size_t interpret_long_filename(TALLOC_CTX *ctx,
50 struct cli_state *cli,
51 int level,
52 const char *base_ptr,
53 uint16_t recv_flags2,
54 const char *p,
55 const char *pdata_end,
56 struct file_info *finfo,
57 uint32 *p_resume_key,
58 DATA_BLOB *p_last_name_raw)
60 int len;
61 size_t ret;
62 const char *base = p;
64 data_blob_free(p_last_name_raw);
66 if (p_resume_key) {
67 *p_resume_key = 0;
69 ZERO_STRUCTP(finfo);
71 switch (level) {
72 case SMB_FIND_INFO_STANDARD: /* OS/2 understands this */
73 /* these dates are converted to GMT by
74 make_unix_date */
75 if (pdata_end - base < 27) {
76 return pdata_end - base;
78 finfo->ctime_ts = convert_time_t_to_timespec(
79 make_unix_date2(p+4, cli->serverzone));
80 finfo->atime_ts = convert_time_t_to_timespec(
81 make_unix_date2(p+8, cli->serverzone));
82 finfo->mtime_ts = convert_time_t_to_timespec(
83 make_unix_date2(p+12, cli->serverzone));
84 finfo->size = IVAL(p,16);
85 finfo->mode = CVAL(p,24);
86 len = CVAL(p, 26);
87 p += 27;
88 p += align_string(base_ptr, p, 0);
90 /* We can safely use len here (which is required by OS/2)
91 * and the NAS-BASIC server instead of +2 or +1 as the
92 * STR_TERMINATE flag below is
93 * actually used as the length calculation.
94 * The len is merely an upper bound.
95 * Due to the explicit 2 byte null termination
96 * in cli_receive_trans/cli_receive_nt_trans
97 * we know this is safe. JRA + kukks
100 if (p + len > pdata_end) {
101 return pdata_end - base;
104 /* the len+2 below looks strange but it is
105 important to cope with the differences
106 between win2000 and win9x for this call
107 (tridge) */
108 ret = clistr_pull_talloc(ctx,
109 base_ptr,
110 recv_flags2,
111 &finfo->name,
113 len+2,
114 STR_TERMINATE);
115 if (ret == (size_t)-1) {
116 return pdata_end - base;
118 p += ret;
119 return PTR_DIFF(p, base);
121 case SMB_FIND_EA_SIZE: /* this is what OS/2 uses mostly */
122 /* these dates are converted to GMT by
123 make_unix_date */
124 if (pdata_end - base < 31) {
125 return pdata_end - base;
127 finfo->ctime_ts = convert_time_t_to_timespec(
128 make_unix_date2(p+4, cli->serverzone));
129 finfo->atime_ts = convert_time_t_to_timespec(
130 make_unix_date2(p+8, cli->serverzone));
131 finfo->mtime_ts = convert_time_t_to_timespec(
132 make_unix_date2(p+12, cli->serverzone));
133 finfo->size = IVAL(p,16);
134 finfo->mode = CVAL(p,24);
135 len = CVAL(p, 30);
136 p += 31;
137 /* check for unisys! */
138 if (p + len + 1 > pdata_end) {
139 return pdata_end - base;
141 ret = clistr_pull_talloc(ctx,
142 base_ptr,
143 recv_flags2,
144 &finfo->name,
146 len,
147 STR_NOALIGN);
148 if (ret == (size_t)-1) {
149 return pdata_end - base;
151 p += ret;
152 return PTR_DIFF(p, base) + 1;
154 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: /* NT uses this, but also accepts 2 */
156 size_t namelen, slen;
158 if (pdata_end - base < 94) {
159 return pdata_end - base;
162 p += 4; /* next entry offset */
164 if (p_resume_key) {
165 *p_resume_key = IVAL(p,0);
167 p += 4; /* fileindex */
169 /* Offset zero is "create time", not "change time". */
170 p += 8;
171 finfo->atime_ts = interpret_long_date(p);
172 p += 8;
173 finfo->mtime_ts = interpret_long_date(p);
174 p += 8;
175 finfo->ctime_ts = interpret_long_date(p);
176 p += 8;
177 finfo->size = IVAL2_TO_SMB_BIG_UINT(p,0);
178 p += 8;
179 p += 8; /* alloc size */
180 finfo->mode = CVAL(p,0);
181 p += 4;
182 namelen = IVAL(p,0);
183 p += 4;
184 p += 4; /* EA size */
185 slen = SVAL(p, 0);
186 if (slen > 24) {
187 /* Bad short name length. */
188 return pdata_end - base;
190 p += 2;
192 /* stupid NT bugs. grr */
193 int flags = 0;
194 if (p[1] == 0 && namelen > 1) flags |= STR_UNICODE;
195 clistr_pull(base_ptr, finfo->short_name, p,
196 sizeof(finfo->short_name),
197 slen, flags);
199 p += 24; /* short name? */
200 if (p + namelen < p || p + namelen > pdata_end) {
201 return pdata_end - base;
203 ret = clistr_pull_talloc(ctx,
204 base_ptr,
205 recv_flags2,
206 &finfo->name,
208 namelen,
210 if (ret == (size_t)-1) {
211 return pdata_end - base;
214 /* To be robust in the face of unicode conversion failures
215 we need to copy the raw bytes of the last name seen here.
216 Namelen doesn't include the terminating unicode null, so
217 copy it here. */
219 if (p_last_name_raw) {
220 *p_last_name_raw = data_blob(NULL, namelen+2);
221 memcpy(p_last_name_raw->data, p, namelen);
222 SSVAL(p_last_name_raw->data, namelen, 0);
224 return calc_next_entry_offset(base, pdata_end);
228 DEBUG(1,("Unknown long filename format %d\n",level));
229 return calc_next_entry_offset(base, pdata_end);
232 /****************************************************************************
233 Interpret a short filename structure.
234 The length of the structure is returned.
235 ****************************************************************************/
237 static bool interpret_short_filename(TALLOC_CTX *ctx,
238 struct cli_state *cli,
239 char *p,
240 struct file_info *finfo)
242 size_t ret;
243 ZERO_STRUCTP(finfo);
245 finfo->mode = CVAL(p,21);
247 /* this date is converted to GMT by make_unix_date */
248 finfo->ctime_ts.tv_sec = make_unix_date(p+22, cli->serverzone);
249 finfo->ctime_ts.tv_nsec = 0;
250 finfo->mtime_ts.tv_sec = finfo->atime_ts.tv_sec = finfo->ctime_ts.tv_sec;
251 finfo->mtime_ts.tv_nsec = finfo->atime_ts.tv_nsec = 0;
252 finfo->size = IVAL(p,26);
253 ret = clistr_pull_talloc(ctx,
254 cli->inbuf,
255 SVAL(cli->inbuf, smb_flg2),
256 &finfo->name,
257 p+30,
259 STR_ASCII);
260 if (ret == (size_t)-1) {
261 return false;
264 if (finfo->name) {
265 strlcpy(finfo->short_name,
266 finfo->name,
267 sizeof(finfo->short_name));
269 return true;
272 struct cli_list_old_state {
273 struct tevent_context *ev;
274 struct cli_state *cli;
275 uint16_t vwv[2];
276 char *mask;
277 int num_asked;
278 uint16_t attribute;
279 uint8_t search_status[23];
280 bool first;
281 bool done;
282 uint8_t *dirlist;
285 static void cli_list_old_done(struct tevent_req *subreq);
287 static struct tevent_req *cli_list_old_send(TALLOC_CTX *mem_ctx,
288 struct tevent_context *ev,
289 struct cli_state *cli,
290 const char *mask,
291 uint16_t attribute)
293 struct tevent_req *req, *subreq;
294 struct cli_list_old_state *state;
295 uint8_t *bytes;
296 static const uint16_t zero = 0;
298 req = tevent_req_create(mem_ctx, &state, struct cli_list_old_state);
299 if (req == NULL) {
300 return NULL;
302 state->ev = ev;
303 state->cli = cli;
304 state->attribute = attribute;
305 state->first = true;
306 state->mask = talloc_strdup(state, mask);
307 if (tevent_req_nomem(state->mask, req)) {
308 return tevent_req_post(req, ev);
310 state->num_asked = (cli->max_xmit - 100) / DIR_STRUCT_SIZE;
312 SSVAL(state->vwv + 0, 0, state->num_asked);
313 SSVAL(state->vwv + 1, 0, state->attribute);
315 bytes = talloc_array(state, uint8_t, 1);
316 if (tevent_req_nomem(bytes, req)) {
317 return tevent_req_post(req, ev);
319 bytes[0] = 4;
320 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), mask,
321 strlen(mask)+1, NULL);
323 bytes = smb_bytes_push_bytes(bytes, 5, (uint8_t *)&zero, 2);
324 if (tevent_req_nomem(bytes, req)) {
325 return tevent_req_post(req, ev);
328 subreq = cli_smb_send(state, state->ev, state->cli, SMBsearch,
329 0, 2, state->vwv, talloc_get_size(bytes), bytes);
330 if (tevent_req_nomem(subreq, req)) {
331 return tevent_req_post(req, ev);
333 tevent_req_set_callback(subreq, cli_list_old_done, req);
334 return req;
337 static void cli_list_old_done(struct tevent_req *subreq)
339 struct tevent_req *req = tevent_req_callback_data(
340 subreq, struct tevent_req);
341 struct cli_list_old_state *state = tevent_req_data(
342 req, struct cli_list_old_state);
343 NTSTATUS status;
344 uint8_t cmd;
345 uint8_t wct;
346 uint16_t *vwv;
347 uint32_t num_bytes;
348 uint8_t *bytes;
349 uint16_t received;
350 size_t dirlist_len;
351 uint8_t *tmp;
353 status = cli_smb_recv(subreq, state, NULL, 0, &wct, &vwv, &num_bytes,
354 &bytes);
355 if (!NT_STATUS_IS_OK(status)
356 && !NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRnofiles))
357 && !NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
358 TALLOC_FREE(subreq);
359 tevent_req_nterror(req, status);
360 return;
362 if (NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRnofiles))
363 || NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
364 received = 0;
365 } else {
366 if (wct < 1) {
367 TALLOC_FREE(subreq);
368 tevent_req_nterror(
369 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
370 return;
372 received = SVAL(vwv + 0, 0);
375 if (received > 0) {
377 * I don't think this can wrap. received is
378 * initialized from a 16-bit value.
380 if (num_bytes < (received * DIR_STRUCT_SIZE + 3)) {
381 TALLOC_FREE(subreq);
382 tevent_req_nterror(
383 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
384 return;
387 dirlist_len = talloc_get_size(state->dirlist);
389 tmp = TALLOC_REALLOC_ARRAY(
390 state, state->dirlist, uint8_t,
391 dirlist_len + received * DIR_STRUCT_SIZE);
392 if (tevent_req_nomem(tmp, req)) {
393 return;
395 state->dirlist = tmp;
396 memcpy(state->dirlist + dirlist_len, bytes + 3,
397 received * DIR_STRUCT_SIZE);
399 SSVAL(state->search_status, 0, 21);
400 memcpy(state->search_status + 2,
401 bytes + 3 + (received-1)*DIR_STRUCT_SIZE, 21);
402 cmd = SMBsearch;
403 } else {
404 if (state->first || state->done) {
405 tevent_req_done(req);
406 return;
408 state->done = true;
409 state->num_asked = 0;
410 cmd = SMBfclose;
412 TALLOC_FREE(subreq);
414 state->first = false;
416 SSVAL(state->vwv + 0, 0, state->num_asked);
417 SSVAL(state->vwv + 1, 0, state->attribute);
419 bytes = talloc_array(state, uint8_t, 1);
420 if (tevent_req_nomem(bytes, req)) {
421 return;
423 bytes[0] = 4;
424 bytes = smb_bytes_push_str(bytes, cli_ucs2(state->cli), "",
425 1, NULL);
426 bytes = smb_bytes_push_bytes(bytes, 5, state->search_status,
427 sizeof(state->search_status));
428 if (tevent_req_nomem(bytes, req)) {
429 return;
431 subreq = cli_smb_send(state, state->ev, state->cli, cmd, 0,
432 2, state->vwv, talloc_get_size(bytes), bytes);
433 if (tevent_req_nomem(subreq, req)) {
434 return;
436 tevent_req_set_callback(subreq, cli_list_old_done, req);
439 static NTSTATUS cli_list_old_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
440 struct file_info **pfinfo)
442 struct cli_list_old_state *state = tevent_req_data(
443 req, struct cli_list_old_state);
444 NTSTATUS status;
445 size_t i, num_received;
446 struct file_info *finfo;
448 if (tevent_req_is_nterror(req, &status)) {
449 return status;
452 num_received = talloc_array_length(state->dirlist) / DIR_STRUCT_SIZE;
454 finfo = TALLOC_ARRAY(mem_ctx, struct file_info, num_received);
455 if (finfo == NULL) {
456 return NT_STATUS_NO_MEMORY;
459 for (i=0; i<num_received; i++) {
460 if (!interpret_short_filename(
461 finfo, state->cli,
462 (char *)state->dirlist + i * DIR_STRUCT_SIZE,
463 &finfo[i])) {
464 TALLOC_FREE(finfo);
465 return NT_STATUS_NO_MEMORY;
468 *pfinfo = finfo;
469 return NT_STATUS_OK;
472 NTSTATUS cli_list_old(struct cli_state *cli, const char *mask,
473 uint16 attribute,
474 NTSTATUS (*fn)(const char *, struct file_info *,
475 const char *, void *), void *state)
477 TALLOC_CTX *frame = talloc_stackframe();
478 struct event_context *ev;
479 struct tevent_req *req;
480 NTSTATUS status = NT_STATUS_NO_MEMORY;
481 struct file_info *finfo;
482 size_t i, num_finfo;
484 if (cli_has_async_calls(cli)) {
486 * Can't use sync call while an async call is in flight
488 status = NT_STATUS_INVALID_PARAMETER;
489 goto fail;
491 ev = event_context_init(frame);
492 if (ev == NULL) {
493 goto fail;
495 req = cli_list_old_send(frame, ev, cli, mask, attribute);
496 if (req == NULL) {
497 goto fail;
499 if (!tevent_req_poll(req, ev)) {
500 status = map_nt_error_from_unix(errno);
501 goto fail;
503 status = cli_list_old_recv(req, frame, &finfo);
504 if (!NT_STATUS_IS_OK(status)) {
505 goto fail;
507 num_finfo = talloc_array_length(finfo);
508 for (i=0; i<num_finfo; i++) {
509 status = fn(cli->dfs_mountpoint, &finfo[i], mask, state);
510 if (!NT_STATUS_IS_OK(status)) {
511 goto fail;
514 fail:
515 TALLOC_FREE(frame);
516 if (!NT_STATUS_IS_OK(status)) {
517 cli_set_error(cli, status);
519 return status;
522 struct cli_list_trans_state {
523 struct tevent_context *ev;
524 struct cli_state *cli;
525 char *mask;
526 uint16_t attribute;
527 uint16_t info_level;
529 int loop_count;
530 int total_received;
531 uint16_t max_matches;
532 bool first;
534 int ff_eos;
535 int ff_dir_handle;
537 uint16_t setup[1];
538 uint8_t *param;
540 struct file_info *finfo;
543 static void cli_list_trans_done(struct tevent_req *subreq);
545 static struct tevent_req *cli_list_trans_send(TALLOC_CTX *mem_ctx,
546 struct tevent_context *ev,
547 struct cli_state *cli,
548 const char *mask,
549 uint16_t attribute,
550 uint16_t info_level)
552 struct tevent_req *req, *subreq;
553 struct cli_list_trans_state *state;
554 size_t nlen, param_len;
555 char *p;
557 req = tevent_req_create(mem_ctx, &state,
558 struct cli_list_trans_state);
559 if (req == NULL) {
560 return NULL;
562 state->ev = ev;
563 state->cli = cli;
564 state->mask = talloc_strdup(state, mask);
565 if (tevent_req_nomem(state->mask, req)) {
566 return tevent_req_post(req, ev);
568 state->attribute = attribute;
569 state->info_level = info_level;
570 state->loop_count = 0;
571 state->first = true;
573 state->max_matches = 1366; /* Match W2k */
575 state->setup[0] = TRANSACT2_FINDFIRST;
577 nlen = 2*(strlen(mask)+1);
578 state->param = TALLOC_ARRAY(state, uint8_t, 12+nlen+2);
579 if (tevent_req_nomem(state->param, req)) {
580 return tevent_req_post(req, ev);
583 SSVAL(state->param, 0, state->attribute);
584 SSVAL(state->param, 2, state->max_matches);
585 SSVAL(state->param, 4,
586 FLAG_TRANS2_FIND_REQUIRE_RESUME
587 |FLAG_TRANS2_FIND_CLOSE_IF_END);
588 SSVAL(state->param, 6, state->info_level);
589 SIVAL(state->param, 8, 0);
591 p = ((char *)state->param)+12;
592 p += clistr_push(state->cli, p, state->mask, nlen,
593 STR_TERMINATE);
594 param_len = PTR_DIFF(p, state->param);
596 subreq = cli_trans_send(state, state->ev, state->cli,
597 SMBtrans2, NULL, -1, 0, 0,
598 state->setup, 1, 0,
599 state->param, param_len, 10,
600 NULL, 0, cli->max_xmit);
601 if (tevent_req_nomem(subreq, req)) {
602 return tevent_req_post(req, ev);
604 tevent_req_set_callback(subreq, cli_list_trans_done, req);
605 return req;
608 static void cli_list_trans_done(struct tevent_req *subreq)
610 struct tevent_req *req = tevent_req_callback_data(
611 subreq, struct tevent_req);
612 struct cli_list_trans_state *state = tevent_req_data(
613 req, struct cli_list_trans_state);
614 NTSTATUS status;
615 uint8_t *param;
616 uint32_t num_param;
617 uint8_t *data;
618 char *data_end;
619 uint32_t num_data;
620 uint32_t min_param;
621 struct file_info *tmp;
622 size_t old_num_finfo;
623 uint16_t recv_flags2;
624 int ff_searchcount;
625 bool ff_eos;
626 char *p, *p2;
627 uint32_t resume_key = 0;
628 int i;
629 DATA_BLOB last_name_raw;
630 struct file_info *finfo = NULL;
631 size_t nlen, param_len;
633 min_param = (state->first ? 6 : 4);
635 status = cli_trans_recv(subreq, talloc_tos(), &recv_flags2,
636 NULL, 0, NULL,
637 &param, min_param, &num_param,
638 &data, 0, &num_data);
639 TALLOC_FREE(subreq);
640 if (!NT_STATUS_IS_OK(status)) {
642 * TODO: retry, OS/2 nofiles
644 tevent_req_nterror(req, status);
645 return;
648 if (state->first) {
649 state->ff_dir_handle = SVAL(param, 0);
650 ff_searchcount = SVAL(param, 2);
651 ff_eos = SVAL(param, 4) != 0;
652 } else {
653 ff_searchcount = SVAL(param, 0);
654 ff_eos = SVAL(param, 2) != 0;
657 old_num_finfo = talloc_array_length(state->finfo);
659 tmp = TALLOC_REALLOC_ARRAY(state, state->finfo, struct file_info,
660 old_num_finfo + ff_searchcount);
661 if (tevent_req_nomem(tmp, req)) {
662 return;
664 state->finfo = tmp;
666 p2 = p = (char *)data;
667 data_end = (char *)data + num_data;
668 last_name_raw = data_blob_null;
670 for (i=0; i<ff_searchcount; i++) {
671 if (p2 >= data_end) {
672 ff_eos = true;
673 break;
675 if ((state->info_level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
676 && (i == ff_searchcount-1)) {
677 /* Last entry - fixup the last offset length. */
678 SIVAL(p2, 0, PTR_DIFF((data + num_data), p2));
681 data_blob_free(&last_name_raw);
683 finfo = &state->finfo[old_num_finfo + i];
685 p2 += interpret_long_filename(
686 state->finfo, /* Stick fname to the array as such */
687 state->cli, state->info_level,
688 (char *)data, recv_flags2, p2,
689 data_end, finfo, &resume_key, &last_name_raw);
691 if (finfo->name == NULL) {
692 DEBUG(1, ("cli_list: Error: unable to parse name from "
693 "info level %d\n", state->info_level));
694 ff_eos = true;
695 break;
697 if (!state->first && (state->mask[0] != '\0') &&
698 strcsequal(finfo->name, state->mask)) {
699 DEBUG(1, ("Error: Looping in FIND_NEXT as name %s has "
700 "already been seen?\n", finfo->name));
701 ff_eos = true;
702 break;
706 if (ff_searchcount == 0) {
707 ff_eos = true;
710 TALLOC_FREE(param);
711 TALLOC_FREE(data);
714 * Shrink state->finfo to the real length we received
716 tmp = TALLOC_REALLOC_ARRAY(state, state->finfo, struct file_info,
717 old_num_finfo + i);
718 if (tevent_req_nomem(tmp, req)) {
719 return;
721 state->finfo = tmp;
723 state->first = false;
725 if (ff_eos) {
726 data_blob_free(&last_name_raw);
727 tevent_req_done(req);
728 return;
731 TALLOC_FREE(state->mask);
732 state->mask = talloc_strdup(state, finfo->name);
733 if (tevent_req_nomem(state->mask, req)) {
734 return;
737 state->setup[0] = TRANSACT2_FINDNEXT;
739 nlen = 2*(strlen(state->mask) + 1);
741 param = TALLOC_REALLOC_ARRAY(state, state->param, uint8_t,
742 12 + nlen + last_name_raw.length + 2);
743 if (tevent_req_nomem(param, req)) {
744 return;
746 state->param = param;
748 SSVAL(param, 0, state->ff_dir_handle);
749 SSVAL(param, 2, state->max_matches); /* max count */
750 SSVAL(param, 4, state->info_level);
752 * For W2K servers serving out FAT filesystems we *must* set
753 * the resume key. If it's not FAT then it's returned as zero.
755 SIVAL(param, 6, resume_key); /* ff_resume_key */
757 * NB. *DON'T* use continue here. If you do it seems that W2K
758 * and bretheren can miss filenames. Use last filename
759 * continue instead. JRA
761 SSVAL(param, 10, (FLAG_TRANS2_FIND_REQUIRE_RESUME
762 |FLAG_TRANS2_FIND_CLOSE_IF_END));
763 p = ((char *)param)+12;
764 if (last_name_raw.length) {
765 memcpy(p, last_name_raw.data, last_name_raw.length);
766 p += last_name_raw.length;
767 data_blob_free(&last_name_raw);
768 } else {
769 p += clistr_push(state->cli, p, state->mask, nlen,
770 STR_TERMINATE);
773 param_len = PTR_DIFF(p, param);
775 subreq = cli_trans_send(state, state->ev, state->cli,
776 SMBtrans2, NULL, -1, 0, 0,
777 state->setup, 1, 0,
778 state->param, param_len, 10,
779 NULL, 0, state->cli->max_xmit);
780 if (tevent_req_nomem(subreq, req)) {
781 return;
783 tevent_req_set_callback(subreq, cli_list_trans_done, req);
786 static NTSTATUS cli_list_trans_recv(struct tevent_req *req,
787 TALLOC_CTX *mem_ctx,
788 struct file_info **finfo)
790 struct cli_list_trans_state *state = tevent_req_data(
791 req, struct cli_list_trans_state);
792 NTSTATUS status;
794 if (tevent_req_is_nterror(req, &status)) {
795 return status;
797 *finfo = talloc_move(mem_ctx, &state->finfo);
798 return NT_STATUS_OK;
801 NTSTATUS cli_list_trans(struct cli_state *cli, const char *mask,
802 uint16_t attribute, int info_level,
803 NTSTATUS (*fn)(const char *mnt, struct file_info *finfo,
804 const char *mask, void *private_data),
805 void *private_data)
807 TALLOC_CTX *frame = talloc_stackframe();
808 struct event_context *ev;
809 struct tevent_req *req;
810 int i, num_finfo;
811 struct file_info *finfo = NULL;
812 NTSTATUS status = NT_STATUS_NO_MEMORY;
814 if (cli_has_async_calls(cli)) {
816 * Can't use sync call while an async call is in flight
818 status = NT_STATUS_INVALID_PARAMETER;
819 goto fail;
821 ev = event_context_init(frame);
822 if (ev == NULL) {
823 goto fail;
825 req = cli_list_trans_send(frame, ev, cli, mask, attribute, info_level);
826 if (req == NULL) {
827 goto fail;
829 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
830 goto fail;
832 status = cli_list_trans_recv(req, frame, &finfo);
833 if (!NT_STATUS_IS_OK(status)) {
834 goto fail;
836 num_finfo = talloc_array_length(finfo);
837 for (i=0; i<num_finfo; i++) {
838 status = fn(cli->dfs_mountpoint, &finfo[i], mask, private_data);
839 if (!NT_STATUS_IS_OK(status)) {
840 goto fail;
843 fail:
844 TALLOC_FREE(frame);
845 if (!NT_STATUS_IS_OK(status)) {
846 cli_set_error(cli, status);
848 return status;
851 struct cli_list_state {
852 NTSTATUS (*recv_fn)(struct tevent_req *req, TALLOC_CTX *mem_ctx,
853 struct file_info **finfo);
854 struct file_info *finfo;
857 static void cli_list_done(struct tevent_req *subreq);
859 struct tevent_req *cli_list_send(TALLOC_CTX *mem_ctx,
860 struct tevent_context *ev,
861 struct cli_state *cli,
862 const char *mask,
863 uint16_t attribute,
864 uint16_t info_level)
866 struct tevent_req *req, *subreq;
867 struct cli_list_state *state;
869 req = tevent_req_create(mem_ctx, &state, struct cli_list_state);
870 if (req == NULL) {
871 return NULL;
874 if (cli->protocol <= PROTOCOL_LANMAN1) {
875 subreq = cli_list_old_send(state, ev, cli, mask, attribute);
876 state->recv_fn = cli_list_old_recv;
877 } else {
878 subreq = cli_list_trans_send(state, ev, cli, mask, attribute,
879 info_level);
880 state->recv_fn = cli_list_trans_recv;
882 if (tevent_req_nomem(subreq, req)) {
883 return tevent_req_post(req, ev);
885 tevent_req_set_callback(subreq, cli_list_done, req);
886 return req;
889 static void cli_list_done(struct tevent_req *subreq)
891 struct tevent_req *req = tevent_req_callback_data(
892 subreq, struct tevent_req);
893 struct cli_list_state *state = tevent_req_data(
894 req, struct cli_list_state);
895 NTSTATUS status;
897 status = state->recv_fn(subreq, state, &state->finfo);
898 TALLOC_FREE(subreq);
899 if (!NT_STATUS_IS_OK(status)) {
900 tevent_req_nterror(req, status);
901 return;
903 tevent_req_done(req);
906 NTSTATUS cli_list_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
907 struct file_info **finfo, size_t *num_finfo)
909 struct cli_list_state *state = tevent_req_data(
910 req, struct cli_list_state);
911 NTSTATUS status;
913 if (tevent_req_is_nterror(req, &status)) {
914 return status;
916 *num_finfo = talloc_array_length(state->finfo);
917 *finfo = talloc_move(mem_ctx, &state->finfo);
918 return NT_STATUS_OK;
921 NTSTATUS cli_list(struct cli_state *cli, const char *mask, uint16 attribute,
922 NTSTATUS (*fn)(const char *, struct file_info *, const char *,
923 void *), void *state)
925 TALLOC_CTX *frame = talloc_stackframe();
926 struct event_context *ev;
927 struct tevent_req *req;
928 NTSTATUS status = NT_STATUS_NO_MEMORY;
929 struct file_info *finfo;
930 size_t i, num_finfo;
931 uint16_t info_level;
933 if (cli_has_async_calls(cli)) {
935 * Can't use sync call while an async call is in flight
937 status = NT_STATUS_INVALID_PARAMETER;
938 goto fail;
940 ev = event_context_init(frame);
941 if (ev == NULL) {
942 goto fail;
945 info_level = (cli->capabilities & CAP_NT_SMBS)
946 ? SMB_FIND_FILE_BOTH_DIRECTORY_INFO : SMB_FIND_INFO_STANDARD;
948 req = cli_list_send(frame, ev, cli, mask, attribute, info_level);
949 if (req == NULL) {
950 goto fail;
952 if (!tevent_req_poll(req, ev)) {
953 status = map_nt_error_from_unix(errno);
954 goto fail;
957 status = cli_list_recv(req, frame, &finfo, &num_finfo);
958 if (!NT_STATUS_IS_OK(status)) {
959 goto fail;
962 for (i=0; i<num_finfo; i++) {
963 status = fn(cli->dfs_mountpoint, &finfo[i], mask, state);
964 if (!NT_STATUS_IS_OK(status)) {
965 goto fail;
968 fail:
969 TALLOC_FREE(frame);
970 if (!NT_STATUS_IS_OK(status)) {
971 cli_set_error(cli, status);
973 return status;