nbt: fix WinXP S3 domain join: alignment of nbt_netlogon_response_from_pdc
[Samba.git] / source3 / libsmb / clilist.c
blob59d01b7fc19e82c4ac9d37af354e47c63eee7264
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 "libsmb/libsmb.h"
22 #include "../lib/util/tevent_ntstatus.h"
23 #include "async_smb.h"
24 #include "trans2.h"
26 /****************************************************************************
27 Calculate a safe next_entry_offset.
28 ****************************************************************************/
30 static size_t calc_next_entry_offset(const char *base, const char *pdata_end)
32 size_t next_entry_offset = (size_t)IVAL(base,0);
34 if (next_entry_offset == 0 ||
35 base + next_entry_offset < base ||
36 base + next_entry_offset > pdata_end) {
37 next_entry_offset = pdata_end - base;
39 return next_entry_offset;
42 /****************************************************************************
43 Interpret a long filename structure - this is mostly guesses at the moment.
44 The length of the structure is returned
45 The structure of a long filename depends on the info level.
46 SMB_FIND_FILE_BOTH_DIRECTORY_INFO is used
47 by NT and SMB_FIND_EA_SIZE is used by OS/2
48 ****************************************************************************/
50 static size_t interpret_long_filename(TALLOC_CTX *ctx,
51 struct cli_state *cli,
52 int level,
53 const char *base_ptr,
54 uint16_t recv_flags2,
55 const char *p,
56 const char *pdata_end,
57 struct file_info *finfo,
58 uint32 *p_resume_key,
59 DATA_BLOB *p_last_name_raw)
61 int len;
62 size_t ret;
63 const char *base = p;
65 data_blob_free(p_last_name_raw);
67 if (p_resume_key) {
68 *p_resume_key = 0;
70 ZERO_STRUCTP(finfo);
72 switch (level) {
73 case SMB_FIND_INFO_STANDARD: /* OS/2 understands this */
74 /* these dates are converted to GMT by
75 make_unix_date */
76 if (pdata_end - base < 27) {
77 return pdata_end - base;
79 finfo->ctime_ts = convert_time_t_to_timespec(
80 make_unix_date2(p+4, cli->serverzone));
81 finfo->atime_ts = convert_time_t_to_timespec(
82 make_unix_date2(p+8, cli->serverzone));
83 finfo->mtime_ts = convert_time_t_to_timespec(
84 make_unix_date2(p+12, cli->serverzone));
85 finfo->size = IVAL(p,16);
86 finfo->mode = CVAL(p,24);
87 len = CVAL(p, 26);
88 p += 27;
89 p += align_string(base_ptr, p, 0);
91 /* We can safely use len here (which is required by OS/2)
92 * and the NAS-BASIC server instead of +2 or +1 as the
93 * STR_TERMINATE flag below is
94 * actually used as the length calculation.
95 * The len is merely an upper bound.
96 * Due to the explicit 2 byte null termination
97 * in cli_receive_trans/cli_receive_nt_trans
98 * we know this is safe. JRA + kukks
101 if (p + len > pdata_end) {
102 return pdata_end - base;
105 /* the len+2 below looks strange but it is
106 important to cope with the differences
107 between win2000 and win9x for this call
108 (tridge) */
109 ret = clistr_pull_talloc(ctx,
110 base_ptr,
111 recv_flags2,
112 &finfo->name,
114 len+2,
115 STR_TERMINATE);
116 if (ret == (size_t)-1) {
117 return pdata_end - base;
119 p += ret;
120 return PTR_DIFF(p, base);
122 case SMB_FIND_EA_SIZE: /* this is what OS/2 uses mostly */
123 /* these dates are converted to GMT by
124 make_unix_date */
125 if (pdata_end - base < 31) {
126 return pdata_end - base;
128 finfo->ctime_ts = convert_time_t_to_timespec(
129 make_unix_date2(p+4, cli->serverzone));
130 finfo->atime_ts = convert_time_t_to_timespec(
131 make_unix_date2(p+8, cli->serverzone));
132 finfo->mtime_ts = convert_time_t_to_timespec(
133 make_unix_date2(p+12, cli->serverzone));
134 finfo->size = IVAL(p,16);
135 finfo->mode = CVAL(p,24);
136 len = CVAL(p, 30);
137 p += 31;
138 /* check for unisys! */
139 if (p + len + 1 > pdata_end) {
140 return pdata_end - base;
142 ret = clistr_pull_talloc(ctx,
143 base_ptr,
144 recv_flags2,
145 &finfo->name,
147 len,
148 STR_NOALIGN);
149 if (ret == (size_t)-1) {
150 return pdata_end - base;
152 p += ret;
153 return PTR_DIFF(p, base) + 1;
155 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: /* NT uses this, but also accepts 2 */
157 size_t namelen, slen;
159 if (pdata_end - base < 94) {
160 return pdata_end - base;
163 p += 4; /* next entry offset */
165 if (p_resume_key) {
166 *p_resume_key = IVAL(p,0);
168 p += 4; /* fileindex */
170 /* Offset zero is "create time", not "change time". */
171 p += 8;
172 finfo->atime_ts = interpret_long_date(p);
173 p += 8;
174 finfo->mtime_ts = interpret_long_date(p);
175 p += 8;
176 finfo->ctime_ts = interpret_long_date(p);
177 p += 8;
178 finfo->size = IVAL2_TO_SMB_BIG_UINT(p,0);
179 p += 8;
180 p += 8; /* alloc size */
181 finfo->mode = CVAL(p,0);
182 p += 4;
183 namelen = IVAL(p,0);
184 p += 4;
185 p += 4; /* EA size */
186 slen = SVAL(p, 0);
187 if (slen > 24) {
188 /* Bad short name length. */
189 return pdata_end - base;
191 p += 2;
193 /* stupid NT bugs. grr */
194 int flags = 0;
195 if (p[1] == 0 && namelen > 1) flags |= STR_UNICODE;
196 clistr_pull(base_ptr, finfo->short_name, p,
197 sizeof(finfo->short_name),
198 slen, flags);
200 p += 24; /* short name? */
201 if (p + namelen < p || p + namelen > pdata_end) {
202 return pdata_end - base;
204 ret = clistr_pull_talloc(ctx,
205 base_ptr,
206 recv_flags2,
207 &finfo->name,
209 namelen,
211 if (ret == (size_t)-1) {
212 return pdata_end - base;
215 /* To be robust in the face of unicode conversion failures
216 we need to copy the raw bytes of the last name seen here.
217 Namelen doesn't include the terminating unicode null, so
218 copy it here. */
220 if (p_last_name_raw) {
221 *p_last_name_raw = data_blob(NULL, namelen+2);
222 memcpy(p_last_name_raw->data, p, namelen);
223 SSVAL(p_last_name_raw->data, namelen, 0);
225 return calc_next_entry_offset(base, pdata_end);
229 DEBUG(1,("Unknown long filename format %d\n",level));
230 return calc_next_entry_offset(base, pdata_end);
233 /****************************************************************************
234 Interpret a short filename structure.
235 The length of the structure is returned.
236 ****************************************************************************/
238 static bool interpret_short_filename(TALLOC_CTX *ctx,
239 struct cli_state *cli,
240 char *p,
241 struct file_info *finfo)
243 size_t ret;
244 ZERO_STRUCTP(finfo);
246 finfo->mode = CVAL(p,21);
248 /* this date is converted to GMT by make_unix_date */
249 finfo->ctime_ts.tv_sec = make_unix_date(p+22, cli->serverzone);
250 finfo->ctime_ts.tv_nsec = 0;
251 finfo->mtime_ts.tv_sec = finfo->atime_ts.tv_sec = finfo->ctime_ts.tv_sec;
252 finfo->mtime_ts.tv_nsec = finfo->atime_ts.tv_nsec = 0;
253 finfo->size = IVAL(p,26);
254 ret = clistr_pull_talloc(ctx,
255 cli->inbuf,
256 SVAL(cli->inbuf, smb_flg2),
257 &finfo->name,
258 p+30,
260 STR_ASCII);
261 if (ret == (size_t)-1) {
262 return false;
265 if (finfo->name) {
266 strlcpy(finfo->short_name,
267 finfo->name,
268 sizeof(finfo->short_name));
270 return true;
273 struct cli_list_old_state {
274 struct tevent_context *ev;
275 struct cli_state *cli;
276 uint16_t vwv[2];
277 char *mask;
278 int num_asked;
279 uint16_t attribute;
280 uint8_t search_status[23];
281 bool first;
282 bool done;
283 uint8_t *dirlist;
286 static void cli_list_old_done(struct tevent_req *subreq);
288 static struct tevent_req *cli_list_old_send(TALLOC_CTX *mem_ctx,
289 struct tevent_context *ev,
290 struct cli_state *cli,
291 const char *mask,
292 uint16_t attribute)
294 struct tevent_req *req, *subreq;
295 struct cli_list_old_state *state;
296 uint8_t *bytes;
297 static const uint16_t zero = 0;
299 req = tevent_req_create(mem_ctx, &state, struct cli_list_old_state);
300 if (req == NULL) {
301 return NULL;
303 state->ev = ev;
304 state->cli = cli;
305 state->attribute = attribute;
306 state->first = true;
307 state->mask = talloc_strdup(state, mask);
308 if (tevent_req_nomem(state->mask, req)) {
309 return tevent_req_post(req, ev);
311 state->num_asked = (cli->max_xmit - 100) / DIR_STRUCT_SIZE;
313 SSVAL(state->vwv + 0, 0, state->num_asked);
314 SSVAL(state->vwv + 1, 0, state->attribute);
316 bytes = talloc_array(state, uint8_t, 1);
317 if (tevent_req_nomem(bytes, req)) {
318 return tevent_req_post(req, ev);
320 bytes[0] = 4;
321 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), mask,
322 strlen(mask)+1, NULL);
324 bytes = smb_bytes_push_bytes(bytes, 5, (uint8_t *)&zero, 2);
325 if (tevent_req_nomem(bytes, req)) {
326 return tevent_req_post(req, ev);
329 subreq = cli_smb_send(state, state->ev, state->cli, SMBsearch,
330 0, 2, state->vwv, talloc_get_size(bytes), bytes);
331 if (tevent_req_nomem(subreq, req)) {
332 return tevent_req_post(req, ev);
334 tevent_req_set_callback(subreq, cli_list_old_done, req);
335 return req;
338 static void cli_list_old_done(struct tevent_req *subreq)
340 struct tevent_req *req = tevent_req_callback_data(
341 subreq, struct tevent_req);
342 struct cli_list_old_state *state = tevent_req_data(
343 req, struct cli_list_old_state);
344 NTSTATUS status;
345 uint8_t cmd;
346 uint8_t wct;
347 uint16_t *vwv;
348 uint32_t num_bytes;
349 uint8_t *bytes;
350 uint16_t received;
351 size_t dirlist_len;
352 uint8_t *tmp;
354 status = cli_smb_recv(subreq, state, NULL, 0, &wct, &vwv, &num_bytes,
355 &bytes);
356 if (!NT_STATUS_IS_OK(status)
357 && !NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRnofiles))
358 && !NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
359 TALLOC_FREE(subreq);
360 tevent_req_nterror(req, status);
361 return;
363 if (NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRnofiles))
364 || NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
365 received = 0;
366 } else {
367 if (wct < 1) {
368 TALLOC_FREE(subreq);
369 tevent_req_nterror(
370 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
371 return;
373 received = SVAL(vwv + 0, 0);
376 if (received > 0) {
378 * I don't think this can wrap. received is
379 * initialized from a 16-bit value.
381 if (num_bytes < (received * DIR_STRUCT_SIZE + 3)) {
382 TALLOC_FREE(subreq);
383 tevent_req_nterror(
384 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
385 return;
388 dirlist_len = talloc_get_size(state->dirlist);
390 tmp = TALLOC_REALLOC_ARRAY(
391 state, state->dirlist, uint8_t,
392 dirlist_len + received * DIR_STRUCT_SIZE);
393 if (tevent_req_nomem(tmp, req)) {
394 return;
396 state->dirlist = tmp;
397 memcpy(state->dirlist + dirlist_len, bytes + 3,
398 received * DIR_STRUCT_SIZE);
400 SSVAL(state->search_status, 0, 21);
401 memcpy(state->search_status + 2,
402 bytes + 3 + (received-1)*DIR_STRUCT_SIZE, 21);
403 cmd = SMBsearch;
404 } else {
405 if (state->first || state->done) {
406 tevent_req_done(req);
407 return;
409 state->done = true;
410 state->num_asked = 0;
411 cmd = SMBfclose;
413 TALLOC_FREE(subreq);
415 state->first = false;
417 SSVAL(state->vwv + 0, 0, state->num_asked);
418 SSVAL(state->vwv + 1, 0, state->attribute);
420 bytes = talloc_array(state, uint8_t, 1);
421 if (tevent_req_nomem(bytes, req)) {
422 return;
424 bytes[0] = 4;
425 bytes = smb_bytes_push_str(bytes, cli_ucs2(state->cli), "",
426 1, NULL);
427 bytes = smb_bytes_push_bytes(bytes, 5, state->search_status,
428 sizeof(state->search_status));
429 if (tevent_req_nomem(bytes, req)) {
430 return;
432 subreq = cli_smb_send(state, state->ev, state->cli, cmd, 0,
433 2, state->vwv, talloc_get_size(bytes), bytes);
434 if (tevent_req_nomem(subreq, req)) {
435 return;
437 tevent_req_set_callback(subreq, cli_list_old_done, req);
440 static NTSTATUS cli_list_old_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
441 struct file_info **pfinfo)
443 struct cli_list_old_state *state = tevent_req_data(
444 req, struct cli_list_old_state);
445 NTSTATUS status;
446 size_t i, num_received;
447 struct file_info *finfo;
449 if (tevent_req_is_nterror(req, &status)) {
450 return status;
453 num_received = talloc_array_length(state->dirlist) / DIR_STRUCT_SIZE;
455 finfo = TALLOC_ARRAY(mem_ctx, struct file_info, num_received);
456 if (finfo == NULL) {
457 return NT_STATUS_NO_MEMORY;
460 for (i=0; i<num_received; i++) {
461 if (!interpret_short_filename(
462 finfo, state->cli,
463 (char *)state->dirlist + i * DIR_STRUCT_SIZE,
464 &finfo[i])) {
465 TALLOC_FREE(finfo);
466 return NT_STATUS_NO_MEMORY;
469 *pfinfo = finfo;
470 return NT_STATUS_OK;
473 NTSTATUS cli_list_old(struct cli_state *cli, const char *mask,
474 uint16 attribute,
475 NTSTATUS (*fn)(const char *, struct file_info *,
476 const char *, void *), void *state)
478 TALLOC_CTX *frame = talloc_stackframe();
479 struct event_context *ev;
480 struct tevent_req *req;
481 NTSTATUS status = NT_STATUS_NO_MEMORY;
482 struct file_info *finfo;
483 size_t i, num_finfo;
485 if (cli_has_async_calls(cli)) {
487 * Can't use sync call while an async call is in flight
489 status = NT_STATUS_INVALID_PARAMETER;
490 goto fail;
492 ev = event_context_init(frame);
493 if (ev == NULL) {
494 goto fail;
496 req = cli_list_old_send(frame, ev, cli, mask, attribute);
497 if (req == NULL) {
498 goto fail;
500 if (!tevent_req_poll(req, ev)) {
501 status = map_nt_error_from_unix(errno);
502 goto fail;
504 status = cli_list_old_recv(req, frame, &finfo);
505 if (!NT_STATUS_IS_OK(status)) {
506 goto fail;
508 num_finfo = talloc_array_length(finfo);
509 for (i=0; i<num_finfo; i++) {
510 status = fn(cli->dfs_mountpoint, &finfo[i], mask, state);
511 if (!NT_STATUS_IS_OK(status)) {
512 goto fail;
515 fail:
516 TALLOC_FREE(frame);
517 if (!NT_STATUS_IS_OK(status)) {
518 cli_set_error(cli, status);
520 return status;
523 struct cli_list_trans_state {
524 struct tevent_context *ev;
525 struct cli_state *cli;
526 char *mask;
527 uint16_t attribute;
528 uint16_t info_level;
530 int loop_count;
531 int total_received;
532 uint16_t max_matches;
533 bool first;
535 int ff_eos;
536 int ff_dir_handle;
538 uint16_t setup[1];
539 uint8_t *param;
541 struct file_info *finfo;
544 static void cli_list_trans_done(struct tevent_req *subreq);
546 static struct tevent_req *cli_list_trans_send(TALLOC_CTX *mem_ctx,
547 struct tevent_context *ev,
548 struct cli_state *cli,
549 const char *mask,
550 uint16_t attribute,
551 uint16_t info_level)
553 struct tevent_req *req, *subreq;
554 struct cli_list_trans_state *state;
555 size_t nlen, param_len;
556 char *p;
558 req = tevent_req_create(mem_ctx, &state,
559 struct cli_list_trans_state);
560 if (req == NULL) {
561 return NULL;
563 state->ev = ev;
564 state->cli = cli;
565 state->mask = talloc_strdup(state, mask);
566 if (tevent_req_nomem(state->mask, req)) {
567 return tevent_req_post(req, ev);
569 state->attribute = attribute;
570 state->info_level = info_level;
571 state->loop_count = 0;
572 state->first = true;
574 state->max_matches = 1366; /* Match W2k */
576 SSVAL(&state->setup[0], 0, TRANSACT2_FINDFIRST);
578 nlen = 2*(strlen(mask)+1);
579 state->param = TALLOC_ARRAY(state, uint8_t, 12+nlen+2);
580 if (tevent_req_nomem(state->param, req)) {
581 return tevent_req_post(req, ev);
584 SSVAL(state->param, 0, state->attribute);
585 SSVAL(state->param, 2, state->max_matches);
586 SSVAL(state->param, 4,
587 FLAG_TRANS2_FIND_REQUIRE_RESUME
588 |FLAG_TRANS2_FIND_CLOSE_IF_END);
589 SSVAL(state->param, 6, state->info_level);
590 SIVAL(state->param, 8, 0);
592 p = ((char *)state->param)+12;
593 p += clistr_push(state->cli, p, state->mask, nlen,
594 STR_TERMINATE);
595 param_len = PTR_DIFF(p, state->param);
597 subreq = cli_trans_send(state, state->ev, state->cli,
598 SMBtrans2, NULL, -1, 0, 0,
599 state->setup, 1, 0,
600 state->param, param_len, 10,
601 NULL, 0, cli->max_xmit);
602 if (tevent_req_nomem(subreq, req)) {
603 return tevent_req_post(req, ev);
605 tevent_req_set_callback(subreq, cli_list_trans_done, req);
606 return req;
609 static void cli_list_trans_done(struct tevent_req *subreq)
611 struct tevent_req *req = tevent_req_callback_data(
612 subreq, struct tevent_req);
613 struct cli_list_trans_state *state = tevent_req_data(
614 req, struct cli_list_trans_state);
615 NTSTATUS status;
616 uint8_t *param;
617 uint32_t num_param;
618 uint8_t *data;
619 char *data_end;
620 uint32_t num_data;
621 uint32_t min_param;
622 struct file_info *tmp;
623 size_t old_num_finfo;
624 uint16_t recv_flags2;
625 int ff_searchcount;
626 bool ff_eos;
627 char *p, *p2;
628 uint32_t resume_key = 0;
629 int i;
630 DATA_BLOB last_name_raw;
631 struct file_info *finfo = NULL;
632 size_t nlen, param_len;
634 min_param = (state->first ? 6 : 4);
636 status = cli_trans_recv(subreq, talloc_tos(), &recv_flags2,
637 NULL, 0, NULL,
638 &param, min_param, &num_param,
639 &data, 0, &num_data);
640 TALLOC_FREE(subreq);
641 if (!NT_STATUS_IS_OK(status)) {
643 * TODO: retry, OS/2 nofiles
645 tevent_req_nterror(req, status);
646 return;
649 if (state->first) {
650 state->ff_dir_handle = SVAL(param, 0);
651 ff_searchcount = SVAL(param, 2);
652 ff_eos = SVAL(param, 4) != 0;
653 } else {
654 ff_searchcount = SVAL(param, 0);
655 ff_eos = SVAL(param, 2) != 0;
658 old_num_finfo = talloc_array_length(state->finfo);
660 tmp = TALLOC_REALLOC_ARRAY(state, state->finfo, struct file_info,
661 old_num_finfo + ff_searchcount);
662 if (tevent_req_nomem(tmp, req)) {
663 return;
665 state->finfo = tmp;
667 p2 = p = (char *)data;
668 data_end = (char *)data + num_data;
669 last_name_raw = data_blob_null;
671 for (i=0; i<ff_searchcount; i++) {
672 if (p2 >= data_end) {
673 ff_eos = true;
674 break;
676 if ((state->info_level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
677 && (i == ff_searchcount-1)) {
678 /* Last entry - fixup the last offset length. */
679 SIVAL(p2, 0, PTR_DIFF((data + num_data), p2));
682 data_blob_free(&last_name_raw);
684 finfo = &state->finfo[old_num_finfo + i];
686 p2 += interpret_long_filename(
687 state->finfo, /* Stick fname to the array as such */
688 state->cli, state->info_level,
689 (char *)data, recv_flags2, p2,
690 data_end, finfo, &resume_key, &last_name_raw);
692 if (finfo->name == NULL) {
693 DEBUG(1, ("cli_list: Error: unable to parse name from "
694 "info level %d\n", state->info_level));
695 ff_eos = true;
696 break;
698 if (!state->first && (state->mask[0] != '\0') &&
699 strcsequal(finfo->name, state->mask)) {
700 DEBUG(1, ("Error: Looping in FIND_NEXT as name %s has "
701 "already been seen?\n", finfo->name));
702 ff_eos = true;
703 break;
707 if (ff_searchcount == 0) {
708 ff_eos = true;
711 TALLOC_FREE(param);
712 TALLOC_FREE(data);
715 * Shrink state->finfo to the real length we received
717 tmp = TALLOC_REALLOC_ARRAY(state, state->finfo, struct file_info,
718 old_num_finfo + i);
719 if (tevent_req_nomem(tmp, req)) {
720 return;
722 state->finfo = tmp;
724 state->first = false;
726 if (ff_eos) {
727 data_blob_free(&last_name_raw);
728 tevent_req_done(req);
729 return;
732 TALLOC_FREE(state->mask);
733 state->mask = talloc_strdup(state, finfo->name);
734 if (tevent_req_nomem(state->mask, req)) {
735 return;
738 SSVAL(&state->setup[0], 0, TRANSACT2_FINDNEXT);
740 nlen = 2*(strlen(state->mask) + 1);
742 param = TALLOC_REALLOC_ARRAY(state, state->param, uint8_t,
743 12 + nlen + last_name_raw.length + 2);
744 if (tevent_req_nomem(param, req)) {
745 return;
747 state->param = param;
749 SSVAL(param, 0, state->ff_dir_handle);
750 SSVAL(param, 2, state->max_matches); /* max count */
751 SSVAL(param, 4, state->info_level);
753 * For W2K servers serving out FAT filesystems we *must* set
754 * the resume key. If it's not FAT then it's returned as zero.
756 SIVAL(param, 6, resume_key); /* ff_resume_key */
758 * NB. *DON'T* use continue here. If you do it seems that W2K
759 * and bretheren can miss filenames. Use last filename
760 * continue instead. JRA
762 SSVAL(param, 10, (FLAG_TRANS2_FIND_REQUIRE_RESUME
763 |FLAG_TRANS2_FIND_CLOSE_IF_END));
764 p = ((char *)param)+12;
765 if (last_name_raw.length) {
766 memcpy(p, last_name_raw.data, last_name_raw.length);
767 p += last_name_raw.length;
768 data_blob_free(&last_name_raw);
769 } else {
770 p += clistr_push(state->cli, p, state->mask, nlen,
771 STR_TERMINATE);
774 param_len = PTR_DIFF(p, param);
776 subreq = cli_trans_send(state, state->ev, state->cli,
777 SMBtrans2, NULL, -1, 0, 0,
778 state->setup, 1, 0,
779 state->param, param_len, 10,
780 NULL, 0, state->cli->max_xmit);
781 if (tevent_req_nomem(subreq, req)) {
782 return;
784 tevent_req_set_callback(subreq, cli_list_trans_done, req);
787 static NTSTATUS cli_list_trans_recv(struct tevent_req *req,
788 TALLOC_CTX *mem_ctx,
789 struct file_info **finfo)
791 struct cli_list_trans_state *state = tevent_req_data(
792 req, struct cli_list_trans_state);
793 NTSTATUS status;
795 if (tevent_req_is_nterror(req, &status)) {
796 return status;
798 *finfo = talloc_move(mem_ctx, &state->finfo);
799 return NT_STATUS_OK;
802 NTSTATUS cli_list_trans(struct cli_state *cli, const char *mask,
803 uint16_t attribute, int info_level,
804 NTSTATUS (*fn)(const char *mnt, struct file_info *finfo,
805 const char *mask, void *private_data),
806 void *private_data)
808 TALLOC_CTX *frame = talloc_stackframe();
809 struct event_context *ev;
810 struct tevent_req *req;
811 int i, num_finfo;
812 struct file_info *finfo = NULL;
813 NTSTATUS status = NT_STATUS_NO_MEMORY;
815 if (cli_has_async_calls(cli)) {
817 * Can't use sync call while an async call is in flight
819 status = NT_STATUS_INVALID_PARAMETER;
820 goto fail;
822 ev = event_context_init(frame);
823 if (ev == NULL) {
824 goto fail;
826 req = cli_list_trans_send(frame, ev, cli, mask, attribute, info_level);
827 if (req == NULL) {
828 goto fail;
830 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
831 goto fail;
833 status = cli_list_trans_recv(req, frame, &finfo);
834 if (!NT_STATUS_IS_OK(status)) {
835 goto fail;
837 num_finfo = talloc_array_length(finfo);
838 for (i=0; i<num_finfo; i++) {
839 status = fn(cli->dfs_mountpoint, &finfo[i], mask, private_data);
840 if (!NT_STATUS_IS_OK(status)) {
841 goto fail;
844 fail:
845 TALLOC_FREE(frame);
846 if (!NT_STATUS_IS_OK(status)) {
847 cli_set_error(cli, status);
849 return status;
852 struct cli_list_state {
853 NTSTATUS (*recv_fn)(struct tevent_req *req, TALLOC_CTX *mem_ctx,
854 struct file_info **finfo);
855 struct file_info *finfo;
858 static void cli_list_done(struct tevent_req *subreq);
860 struct tevent_req *cli_list_send(TALLOC_CTX *mem_ctx,
861 struct tevent_context *ev,
862 struct cli_state *cli,
863 const char *mask,
864 uint16_t attribute,
865 uint16_t info_level)
867 struct tevent_req *req, *subreq;
868 struct cli_list_state *state;
870 req = tevent_req_create(mem_ctx, &state, struct cli_list_state);
871 if (req == NULL) {
872 return NULL;
875 if (cli->protocol <= PROTOCOL_LANMAN1) {
876 subreq = cli_list_old_send(state, ev, cli, mask, attribute);
877 state->recv_fn = cli_list_old_recv;
878 } else {
879 subreq = cli_list_trans_send(state, ev, cli, mask, attribute,
880 info_level);
881 state->recv_fn = cli_list_trans_recv;
883 if (tevent_req_nomem(subreq, req)) {
884 return tevent_req_post(req, ev);
886 tevent_req_set_callback(subreq, cli_list_done, req);
887 return req;
890 static void cli_list_done(struct tevent_req *subreq)
892 struct tevent_req *req = tevent_req_callback_data(
893 subreq, struct tevent_req);
894 struct cli_list_state *state = tevent_req_data(
895 req, struct cli_list_state);
896 NTSTATUS status;
898 status = state->recv_fn(subreq, state, &state->finfo);
899 TALLOC_FREE(subreq);
900 if (!NT_STATUS_IS_OK(status)) {
901 tevent_req_nterror(req, status);
902 return;
904 tevent_req_done(req);
907 NTSTATUS cli_list_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
908 struct file_info **finfo, size_t *num_finfo)
910 struct cli_list_state *state = tevent_req_data(
911 req, struct cli_list_state);
912 NTSTATUS status;
914 if (tevent_req_is_nterror(req, &status)) {
915 return status;
917 *num_finfo = talloc_array_length(state->finfo);
918 *finfo = talloc_move(mem_ctx, &state->finfo);
919 return NT_STATUS_OK;
922 NTSTATUS cli_list(struct cli_state *cli, const char *mask, uint16 attribute,
923 NTSTATUS (*fn)(const char *, struct file_info *, const char *,
924 void *), void *state)
926 TALLOC_CTX *frame = talloc_stackframe();
927 struct event_context *ev;
928 struct tevent_req *req;
929 NTSTATUS status = NT_STATUS_NO_MEMORY;
930 struct file_info *finfo;
931 size_t i, num_finfo;
932 uint16_t info_level;
934 if (cli_has_async_calls(cli)) {
936 * Can't use sync call while an async call is in flight
938 status = NT_STATUS_INVALID_PARAMETER;
939 goto fail;
941 ev = event_context_init(frame);
942 if (ev == NULL) {
943 goto fail;
946 info_level = (cli->capabilities & CAP_NT_SMBS)
947 ? SMB_FIND_FILE_BOTH_DIRECTORY_INFO : SMB_FIND_INFO_STANDARD;
949 req = cli_list_send(frame, ev, cli, mask, attribute, info_level);
950 if (req == NULL) {
951 goto fail;
953 if (!tevent_req_poll(req, ev)) {
954 status = map_nt_error_from_unix(errno);
955 goto fail;
958 status = cli_list_recv(req, frame, &finfo, &num_finfo);
959 if (!NT_STATUS_IS_OK(status)) {
960 goto fail;
963 for (i=0; i<num_finfo; i++) {
964 status = fn(cli->dfs_mountpoint, &finfo[i], mask, state);
965 if (!NT_STATUS_IS_OK(status)) {
966 goto fail;
969 fail:
970 TALLOC_FREE(frame);
971 if (!NT_STATUS_IS_OK(status)) {
972 cli_set_error(cli, status);
974 return status;