libsmb: Remove unused sync version of cli_getattrE()
[bbaumbach/samba-autobuild/.git] / source3 / libsmb / clilist.c
1 /*
2    Unix SMB/CIFS implementation.
3    client directory list routines
4    Copyright (C) Andrew Tridgell 1994-1998
5
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.
10
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.
15
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/>.
18 */
19
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"
25 #include "../libcli/smb/smbXcli_base.h"
26
27 /****************************************************************************
28  Check if a returned directory name is safe.
29 ****************************************************************************/
30
31 static NTSTATUS is_bad_name(bool windows_names, const char *name)
32 {
33         const char *bad_name_p = NULL;
34
35         bad_name_p = strchr(name, '/');
36         if (bad_name_p != NULL) {
37                 /*
38                  * Windows and POSIX names can't have '/'.
39                  * Server is attacking us.
40                  */
41                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
42         }
43         if (windows_names) {
44                 bad_name_p = strchr(name, '\\');
45                 if (bad_name_p != NULL) {
46                         /*
47                          * Windows names can't have '\\'.
48                          * Server is attacking us.
49                          */
50                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
51                 }
52         }
53         return NT_STATUS_OK;
54 }
55
56 /****************************************************************************
57  Check if a returned directory name is safe. Disconnect if server is
58  sending bad names.
59 ****************************************************************************/
60
61 NTSTATUS is_bad_finfo_name(const struct cli_state *cli,
62                         const struct file_info *finfo)
63 {
64         NTSTATUS status = NT_STATUS_OK;
65         bool windows_names = true;
66
67         if (cli->requested_posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
68                 windows_names = false;
69         }
70         if (finfo->name != NULL) {
71                 status = is_bad_name(windows_names, finfo->name);
72                 if (!NT_STATUS_IS_OK(status)) {
73                         DBG_ERR("bad finfo->name\n");
74                         return status;
75                 }
76         }
77         if (finfo->short_name != NULL) {
78                 status = is_bad_name(windows_names, finfo->short_name);
79                 if (!NT_STATUS_IS_OK(status)) {
80                         DBG_ERR("bad finfo->short_name\n");
81                         return status;
82                 }
83         }
84         return NT_STATUS_OK;
85 }
86
87 /****************************************************************************
88  Calculate a safe next_entry_offset.
89 ****************************************************************************/
90
91 static size_t calc_next_entry_offset(const char *base, const char *pdata_end)
92 {
93         size_t next_entry_offset = (size_t)IVAL(base,0);
94
95         if (next_entry_offset == 0 ||
96                         base + next_entry_offset < base ||
97                         base + next_entry_offset > pdata_end) {
98                 next_entry_offset = pdata_end - base;
99         }
100         return next_entry_offset;
101 }
102
103 /****************************************************************************
104  Interpret a long filename structure - this is mostly guesses at the moment.
105  The length of the structure is returned
106  The structure of a long filename depends on the info level.
107  SMB_FIND_FILE_BOTH_DIRECTORY_INFO is used
108  by NT and SMB_FIND_EA_SIZE is used by OS/2
109 ****************************************************************************/
110
111 static size_t interpret_long_filename(TALLOC_CTX *ctx,
112                                         struct cli_state *cli,
113                                         int level,
114                                         const char *base_ptr,
115                                         uint16_t recv_flags2,
116                                         const char *p,
117                                         const char *pdata_end,
118                                         struct file_info *finfo,
119                                         uint32_t *p_resume_key,
120                                         DATA_BLOB *p_last_name_raw)
121 {
122         int len;
123         size_t ret;
124         const char *base = p;
125
126         data_blob_free(p_last_name_raw);
127
128         if (p_resume_key) {
129                 *p_resume_key = 0;
130         }
131         ZERO_STRUCTP(finfo);
132
133         switch (level) {
134                 case SMB_FIND_INFO_STANDARD: /* OS/2 understands this */
135                         /* these dates are converted to GMT by
136                            make_unix_date */
137                         if (pdata_end - base < 27) {
138                                 return pdata_end - base;
139                         }
140                         /*
141                          * What we're returning here as ctime_ts is
142                          * actually the server create time.
143                          */
144                         finfo->btime_ts = convert_time_t_to_timespec(
145                                 make_unix_date2(p+4,
146                                         smb1cli_conn_server_time_zone(
147                                                 cli->conn)));
148                         finfo->ctime_ts = convert_time_t_to_timespec(
149                                 make_unix_date2(p+4, smb1cli_conn_server_time_zone(cli->conn)));
150                         finfo->atime_ts = convert_time_t_to_timespec(
151                                 make_unix_date2(p+8, smb1cli_conn_server_time_zone(cli->conn)));
152                         finfo->mtime_ts = convert_time_t_to_timespec(
153                                 make_unix_date2(p+12, smb1cli_conn_server_time_zone(cli->conn)));
154                         finfo->size = IVAL(p,16);
155                         finfo->attr = SVAL(p,24);
156                         len = CVAL(p, 26);
157                         p += 27;
158                         if (recv_flags2 & FLAGS2_UNICODE_STRINGS) {
159                                 p += ucs2_align(base_ptr, p, STR_UNICODE);
160                         }
161
162                         /* We can safely use len here (which is required by OS/2)
163                          * and the NAS-BASIC server instead of +2 or +1 as the
164                          * STR_TERMINATE flag below is
165                          * actually used as the length calculation.
166                          * The len is merely an upper bound.
167                          * Due to the explicit 2 byte null termination
168                          * in cli_receive_trans/cli_receive_nt_trans
169                          * we know this is safe. JRA + kukks
170                          */
171
172                         if (p + len > pdata_end) {
173                                 return pdata_end - base;
174                         }
175
176                         /* the len+2 below looks strange but it is
177                            important to cope with the differences
178                            between win2000 and win9x for this call
179                            (tridge) */
180                         ret = pull_string_talloc(ctx,
181                                                  base_ptr,
182                                                  recv_flags2,
183                                                  &finfo->name,
184                                                  p,
185                                                  len+2,
186                                                  STR_TERMINATE);
187                         if (ret == (size_t)-1) {
188                                 return pdata_end - base;
189                         }
190                         p += ret;
191                         return PTR_DIFF(p, base);
192
193                 case SMB_FIND_EA_SIZE: /* this is what OS/2 uses mostly */
194                         /* these dates are converted to GMT by
195                            make_unix_date */
196                         if (pdata_end - base < 31) {
197                                 return pdata_end - base;
198                         }
199                         /*
200                          * What we're returning here as ctime_ts is
201                          * actually the server create time.
202                          */
203                         finfo->btime_ts = convert_time_t_to_timespec(
204                                 make_unix_date2(p+4,
205                                         smb1cli_conn_server_time_zone(
206                                                 cli->conn)));
207                         finfo->ctime_ts = convert_time_t_to_timespec(
208                                 make_unix_date2(p+4, smb1cli_conn_server_time_zone(cli->conn)));
209                         finfo->atime_ts = convert_time_t_to_timespec(
210                                 make_unix_date2(p+8, smb1cli_conn_server_time_zone(cli->conn)));
211                         finfo->mtime_ts = convert_time_t_to_timespec(
212                                 make_unix_date2(p+12, smb1cli_conn_server_time_zone(cli->conn)));
213                         finfo->size = IVAL(p,16);
214                         finfo->attr = SVAL(p,24);
215                         len = CVAL(p, 30);
216                         p += 31;
217                         /* check for unisys! */
218                         if (p + len + 1 > pdata_end) {
219                                 return pdata_end - base;
220                         }
221                         ret = pull_string_talloc(ctx,
222                                                  base_ptr,
223                                                  recv_flags2,
224                                                  &finfo->name,
225                                                  p,
226                                                  len,
227                                                  STR_NOALIGN);
228                         if (ret == (size_t)-1) {
229                                 return pdata_end - base;
230                         }
231                         p += ret;
232                         return PTR_DIFF(p, base) + 1;
233
234                 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: /* NT uses this, but also accepts 2 */
235                 {
236                         size_t namelen, slen;
237
238                         if (pdata_end - base < 94) {
239                                 return pdata_end - base;
240                         }
241
242                         p += 4; /* next entry offset */
243
244                         if (p_resume_key) {
245                                 *p_resume_key = IVAL(p,0);
246                         }
247                         p += 4; /* fileindex */
248
249                         /* Offset zero is "create time", not "change time". */
250                         p += 8;
251                         finfo->atime_ts = interpret_long_date(p);
252                         p += 8;
253                         finfo->mtime_ts = interpret_long_date(p);
254                         p += 8;
255                         finfo->ctime_ts = interpret_long_date(p);
256                         p += 8;
257                         finfo->size = IVAL2_TO_SMB_BIG_UINT(p,0);
258                         p += 8;
259                         p += 8; /* alloc size */
260                         finfo->attr = IVAL(p,0);
261                         p += 4;
262                         namelen = IVAL(p,0);
263                         p += 4;
264                         p += 4; /* EA size */
265                         slen = CVAL(p, 0);
266                         if (slen > 24) {
267                                 /* Bad short name length. */
268                                 return pdata_end - base;
269                         }
270                         p += 2;
271                         ret = pull_string_talloc(ctx,
272                                                  base_ptr,
273                                                  recv_flags2,
274                                                  &finfo->short_name,
275                                                  p,
276                                                  slen,
277                                                  STR_UNICODE);
278                         if (ret == (size_t)-1) {
279                                 return pdata_end - base;
280                         }
281                         p += 24; /* short name? */
282                         if (p + namelen < p || p + namelen > pdata_end) {
283                                 return pdata_end - base;
284                         }
285                         ret = pull_string_talloc(ctx,
286                                                  base_ptr,
287                                                  recv_flags2,
288                                                  &finfo->name,
289                                                  p,
290                                                  namelen,
291                                                  0);
292                         if (ret == (size_t)-1) {
293                                 return pdata_end - base;
294                         }
295
296                         /* To be robust in the face of unicode conversion failures
297                            we need to copy the raw bytes of the last name seen here.
298                            Namelen doesn't include the terminating unicode null, so
299                            copy it here. */
300
301                         if (p_last_name_raw) {
302                                 *p_last_name_raw = data_blob(NULL, namelen+2);
303                                 memcpy(p_last_name_raw->data, p, namelen);
304                                 SSVAL(p_last_name_raw->data, namelen, 0);
305                         }
306                         return calc_next_entry_offset(base, pdata_end);
307                 }
308         }
309
310         DEBUG(1,("Unknown long filename format %d\n",level));
311         return calc_next_entry_offset(base, pdata_end);
312 }
313
314 /****************************************************************************
315  Interpret a short filename structure.
316  The length of the structure is returned.
317 ****************************************************************************/
318
319 static bool interpret_short_filename(TALLOC_CTX *ctx,
320                                 struct cli_state *cli,
321                                 char *p,
322                                 struct file_info *finfo)
323 {
324         size_t ret;
325         ZERO_STRUCTP(finfo);
326
327         finfo->attr = CVAL(p,21);
328
329         /* We don't get birth time. */
330         finfo->btime_ts.tv_sec = 0;
331         finfo->btime_ts.tv_nsec = 0;
332         /* this date is converted to GMT by make_unix_date */
333         finfo->ctime_ts.tv_sec = make_unix_date(p+22, smb1cli_conn_server_time_zone(cli->conn));
334         finfo->ctime_ts.tv_nsec = 0;
335         finfo->mtime_ts.tv_sec = finfo->atime_ts.tv_sec = finfo->ctime_ts.tv_sec;
336         finfo->mtime_ts.tv_nsec = finfo->atime_ts.tv_nsec = 0;
337         finfo->size = IVAL(p,26);
338         ret = pull_string_talloc(ctx,
339                                  NULL,
340                                  0,
341                                  &finfo->name,
342                                  p+30,
343                                  12,
344                                  STR_ASCII);
345         if (ret == (size_t)-1) {
346                 return false;
347         }
348
349         if (finfo->name) {
350                 finfo->short_name = talloc_strdup(ctx, finfo->name);
351                 if (finfo->short_name == NULL) {
352                         return false;
353                 }
354         }
355         return true;
356 }
357
358 struct cli_list_old_state {
359         struct tevent_context *ev;
360         struct cli_state *cli;
361         uint16_t vwv[2];
362         char *mask;
363         int num_asked;
364         uint32_t attribute;
365         uint8_t search_status[23];
366         bool first;
367         bool done;
368         uint8_t *dirlist;
369 };
370
371 static void cli_list_old_done(struct tevent_req *subreq);
372
373 static struct tevent_req *cli_list_old_send(TALLOC_CTX *mem_ctx,
374                                             struct tevent_context *ev,
375                                             struct cli_state *cli,
376                                             const char *mask,
377                                             uint32_t attribute)
378 {
379         struct tevent_req *req, *subreq;
380         struct cli_list_old_state *state;
381         uint8_t *bytes;
382         static const uint16_t zero = 0;
383         uint32_t usable_space;
384
385         req = tevent_req_create(mem_ctx, &state, struct cli_list_old_state);
386         if (req == NULL) {
387                 return NULL;
388         }
389         state->ev = ev;
390         state->cli = cli;
391         state->attribute = attribute;
392         state->first = true;
393         state->mask = talloc_strdup(state, mask);
394         if (tevent_req_nomem(state->mask, req)) {
395                 return tevent_req_post(req, ev);
396         }
397         usable_space = cli_state_available_size(cli, 100);
398         state->num_asked = usable_space / DIR_STRUCT_SIZE;
399
400         SSVAL(state->vwv + 0, 0, state->num_asked);
401         SSVAL(state->vwv + 1, 0, state->attribute);
402
403         bytes = talloc_array(state, uint8_t, 1);
404         if (tevent_req_nomem(bytes, req)) {
405                 return tevent_req_post(req, ev);
406         }
407         bytes[0] = 4;
408         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), mask,
409                                    strlen(mask)+1, NULL);
410
411         bytes = smb_bytes_push_bytes(bytes, 5, (const uint8_t *)&zero, 2);
412         if (tevent_req_nomem(bytes, req)) {
413                 return tevent_req_post(req, ev);
414         }
415
416         subreq = cli_smb_send(state, state->ev, state->cli, SMBsearch, 0, 0,
417                         2, state->vwv, talloc_get_size(bytes), bytes);
418         if (tevent_req_nomem(subreq, req)) {
419                 return tevent_req_post(req, ev);
420         }
421         tevent_req_set_callback(subreq, cli_list_old_done, req);
422         return req;
423 }
424
425 static void cli_list_old_done(struct tevent_req *subreq)
426 {
427         struct tevent_req *req = tevent_req_callback_data(
428                 subreq, struct tevent_req);
429         struct cli_list_old_state *state = tevent_req_data(
430                 req, struct cli_list_old_state);
431         NTSTATUS status;
432         uint8_t cmd;
433         uint8_t wct;
434         uint16_t *vwv;
435         uint32_t num_bytes;
436         uint8_t *bytes;
437         uint16_t received;
438         size_t dirlist_len;
439         uint8_t *tmp;
440
441         status = cli_smb_recv(subreq, state, NULL, 0, &wct, &vwv, &num_bytes,
442                               &bytes);
443         if (!NT_STATUS_IS_OK(status)
444             && !NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRnofiles))
445             && !NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
446                 TALLOC_FREE(subreq);
447                 tevent_req_nterror(req, status);
448                 return;
449         }
450         if (NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRnofiles))
451             || NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
452                 received = 0;
453         } else {
454                 if (wct < 1) {
455                         TALLOC_FREE(subreq);
456                         tevent_req_nterror(
457                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
458                         return;
459                 }
460                 received = SVAL(vwv + 0, 0);
461         }
462
463         if (received > 0) {
464                 /*
465                  * I don't think this can wrap. received is
466                  * initialized from a 16-bit value.
467                  */
468                 if (num_bytes < (received * DIR_STRUCT_SIZE + 3)) {
469                         TALLOC_FREE(subreq);
470                         tevent_req_nterror(
471                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
472                         return;
473                 }
474
475                 dirlist_len = talloc_get_size(state->dirlist);
476
477                 tmp = talloc_realloc(
478                         state, state->dirlist, uint8_t,
479                         dirlist_len + received * DIR_STRUCT_SIZE);
480                 if (tevent_req_nomem(tmp, req)) {
481                         return;
482                 }
483                 state->dirlist = tmp;
484                 memcpy(state->dirlist + dirlist_len, bytes + 3,
485                        received * DIR_STRUCT_SIZE);
486
487                 SSVAL(state->search_status, 0, 21);
488                 memcpy(state->search_status + 2,
489                        bytes + 3 + (received-1)*DIR_STRUCT_SIZE, 21);
490                 cmd = SMBsearch;
491         } else {
492                 if (state->first || state->done) {
493                         tevent_req_done(req);
494                         return;
495                 }
496                 state->done = true;
497                 state->num_asked = 0;
498                 cmd = SMBfclose;
499         }
500         TALLOC_FREE(subreq);
501
502         state->first = false;
503
504         SSVAL(state->vwv + 0, 0, state->num_asked);
505         SSVAL(state->vwv + 1, 0, state->attribute);
506
507         bytes = talloc_array(state, uint8_t, 1);
508         if (tevent_req_nomem(bytes, req)) {
509                 return;
510         }
511         bytes[0] = 4;
512         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(state->cli->conn), "",
513                                    1, NULL);
514         bytes = smb_bytes_push_bytes(bytes, 5, state->search_status,
515                                      sizeof(state->search_status));
516         if (tevent_req_nomem(bytes, req)) {
517                 return;
518         }
519         subreq = cli_smb_send(state, state->ev, state->cli, cmd, 0, 0,
520                               2, state->vwv, talloc_get_size(bytes), bytes);
521         if (tevent_req_nomem(subreq, req)) {
522                 return;
523         }
524         tevent_req_set_callback(subreq, cli_list_old_done, req);
525 }
526
527 static NTSTATUS cli_list_old_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
528                                   struct file_info **pfinfo)
529 {
530         struct cli_list_old_state *state = tevent_req_data(
531                 req, struct cli_list_old_state);
532         NTSTATUS status;
533         size_t i, num_received;
534         struct file_info *finfo;
535
536         if (tevent_req_is_nterror(req, &status)) {
537                 return status;
538         }
539
540         num_received = talloc_array_length(state->dirlist) / DIR_STRUCT_SIZE;
541
542         finfo = talloc_array(mem_ctx, struct file_info, num_received);
543         if (finfo == NULL) {
544                 return NT_STATUS_NO_MEMORY;
545         }
546
547         for (i=0; i<num_received; i++) {
548                 if (!interpret_short_filename(
549                             finfo, state->cli,
550                             (char *)state->dirlist + i * DIR_STRUCT_SIZE,
551                             &finfo[i])) {
552                         TALLOC_FREE(finfo);
553                         return NT_STATUS_NO_MEMORY;
554                 }
555                 if (finfo->name == NULL) {
556                         TALLOC_FREE(finfo);
557                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
558                 }
559                 status = is_bad_finfo_name(state->cli, finfo);
560                 if (!NT_STATUS_IS_OK(status)) {
561                         smbXcli_conn_disconnect(state->cli->conn, status);
562                         TALLOC_FREE(finfo);
563                         return status;
564                 }
565         }
566         *pfinfo = finfo;
567         return NT_STATUS_OK;
568 }
569
570 NTSTATUS cli_list_old(struct cli_state *cli, const char *mask,
571                       uint32_t attribute,
572                       NTSTATUS (*fn)(const char *, struct file_info *,
573                                  const char *, void *), void *state)
574 {
575         TALLOC_CTX *frame = talloc_stackframe();
576         struct tevent_context *ev;
577         struct tevent_req *req;
578         NTSTATUS status = NT_STATUS_NO_MEMORY;
579         struct file_info *finfo = NULL;
580         size_t i, num_finfo;
581
582         if (smbXcli_conn_has_async_calls(cli->conn)) {
583                 /*
584                  * Can't use sync call while an async call is in flight
585                  */
586                 status = NT_STATUS_INVALID_PARAMETER;
587                 goto fail;
588         }
589         ev = samba_tevent_context_init(frame);
590         if (ev == NULL) {
591                 goto fail;
592         }
593         req = cli_list_old_send(frame, ev, cli, mask, attribute);
594         if (req == NULL) {
595                 goto fail;
596         }
597         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
598                 goto fail;
599         }
600         status = cli_list_old_recv(req, frame, &finfo);
601         if (!NT_STATUS_IS_OK(status)) {
602                 goto fail;
603         }
604         num_finfo = talloc_array_length(finfo);
605         for (i=0; i<num_finfo; i++) {
606                 status = fn(cli->dfs_mountpoint, &finfo[i], mask, state);
607                 if (!NT_STATUS_IS_OK(status)) {
608                         goto fail;
609                 }
610         }
611  fail:
612         TALLOC_FREE(frame);
613         return status;
614 }
615
616 struct cli_list_trans_state {
617         struct tevent_context *ev;
618         struct cli_state *cli;
619         char *mask;
620         uint32_t attribute;
621         uint16_t info_level;
622
623         int loop_count;
624         int total_received;
625         uint16_t max_matches;
626         bool first;
627
628         int ff_eos;
629         int ff_dir_handle;
630
631         uint16_t setup[1];
632         uint8_t *param;
633
634         struct file_info *finfo;
635 };
636
637 static void cli_list_trans_done(struct tevent_req *subreq);
638
639 static struct tevent_req *cli_list_trans_send(TALLOC_CTX *mem_ctx,
640                                               struct tevent_context *ev,
641                                               struct cli_state *cli,
642                                               const char *mask,
643                                               uint32_t attribute,
644                                               uint16_t info_level)
645 {
646         struct tevent_req *req, *subreq;
647         struct cli_list_trans_state *state;
648         size_t param_len;
649         uint16_t additional_flags2 = 0;
650
651         req = tevent_req_create(mem_ctx, &state,
652                                 struct cli_list_trans_state);
653         if (req == NULL) {
654                 return NULL;
655         }
656         state->ev = ev;
657         state->cli = cli;
658         state->mask = talloc_strdup(state, mask);
659         if (tevent_req_nomem(state->mask, req)) {
660                 return tevent_req_post(req, ev);
661         }
662         state->attribute = attribute;
663         state->info_level = info_level;
664         state->loop_count = 0;
665         state->first = true;
666
667         state->max_matches = 1366; /* Match W2k */
668
669         SSVAL(&state->setup[0], 0, TRANSACT2_FINDFIRST);
670
671         state->param = talloc_array(state, uint8_t, 12);
672         if (tevent_req_nomem(state->param, req)) {
673                 return tevent_req_post(req, ev);
674         }
675
676         SSVAL(state->param, 0, state->attribute);
677         SSVAL(state->param, 2, state->max_matches);
678         SSVAL(state->param, 4,
679               FLAG_TRANS2_FIND_REQUIRE_RESUME
680               |FLAG_TRANS2_FIND_CLOSE_IF_END
681               |(cli->backup_intent ? FLAG_TRANS2_FIND_BACKUP_INTENT : 0));
682         SSVAL(state->param, 6, state->info_level);
683         SIVAL(state->param, 8, 0);
684
685         state->param = trans2_bytes_push_str(state->param, smbXcli_conn_use_unicode(cli->conn),
686                                              state->mask, strlen(state->mask)+1,
687                                              NULL);
688         if (tevent_req_nomem(state->param, req)) {
689                 return tevent_req_post(req, ev);
690         }
691
692         if (clistr_is_previous_version_path(state->mask, NULL, NULL, NULL)) {
693                 additional_flags2 = FLAGS2_REPARSE_PATH;
694         }
695
696         param_len = talloc_get_size(state->param);
697
698         subreq = cli_trans_send(state, state->ev, state->cli, additional_flags2,
699                                 SMBtrans2, NULL, -1, 0, 0,
700                                 state->setup, 1, 0,
701                                 state->param, param_len, 10,
702                                 NULL, 0, CLI_BUFFER_SIZE);
703         if (tevent_req_nomem(subreq, req)) {
704                 return tevent_req_post(req, ev);
705         }
706         tevent_req_set_callback(subreq, cli_list_trans_done, req);
707         return req;
708 }
709
710 static void cli_list_trans_done(struct tevent_req *subreq)
711 {
712         struct tevent_req *req = tevent_req_callback_data(
713                 subreq, struct tevent_req);
714         struct cli_list_trans_state *state = tevent_req_data(
715                 req, struct cli_list_trans_state);
716         NTSTATUS status;
717         uint8_t *param;
718         uint32_t num_param;
719         uint8_t *data;
720         char *data_end;
721         uint32_t num_data;
722         uint32_t min_param;
723         struct file_info *tmp;
724         size_t old_num_finfo;
725         uint16_t recv_flags2;
726         int ff_searchcount;
727         bool ff_eos;
728         char *p, *p2;
729         uint32_t resume_key = 0;
730         int i;
731         DATA_BLOB last_name_raw;
732         struct file_info *finfo = NULL;
733         size_t param_len;
734         uint16_t additional_flags2 = 0;
735
736         min_param = (state->first ? 6 : 4);
737
738         status = cli_trans_recv(subreq, talloc_tos(), &recv_flags2,
739                                 NULL, 0, NULL,
740                                 &param, min_param, &num_param,
741                                 &data, 0, &num_data);
742         TALLOC_FREE(subreq);
743         if (!NT_STATUS_IS_OK(status)) {
744                 /*
745                  * TODO: retry, OS/2 nofiles
746                  */
747                 tevent_req_nterror(req, status);
748                 return;
749         }
750
751         if (state->first) {
752                 state->ff_dir_handle = SVAL(param, 0);
753                 ff_searchcount = SVAL(param, 2);
754                 ff_eos = SVAL(param, 4) != 0;
755         } else {
756                 ff_searchcount = SVAL(param, 0);
757                 ff_eos = SVAL(param, 2) != 0;
758         }
759
760         old_num_finfo = talloc_array_length(state->finfo);
761
762         tmp = talloc_realloc(state, state->finfo, struct file_info,
763                                    old_num_finfo + ff_searchcount);
764         if (tevent_req_nomem(tmp, req)) {
765                 return;
766         }
767         state->finfo = tmp;
768
769         p2 = p = (char *)data;
770         data_end = (char *)data + num_data;
771         last_name_raw = data_blob_null;
772
773         for (i=0; i<ff_searchcount; i++) {
774                 if (p2 >= data_end) {
775                         ff_eos = true;
776                         break;
777                 }
778                 if ((state->info_level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
779                     && (i == ff_searchcount-1)) {
780                         /* Last entry - fixup the last offset length. */
781                         SIVAL(p2, 0, PTR_DIFF((data + num_data), p2));
782                 }
783
784                 data_blob_free(&last_name_raw);
785
786                 finfo = &state->finfo[old_num_finfo + i];
787
788                 p2 += interpret_long_filename(
789                         state->finfo, /* Stick fname to the array as such */
790                         state->cli, state->info_level,
791                         (char *)data, recv_flags2, p2,
792                         data_end, finfo, &resume_key, &last_name_raw);
793
794                 if (finfo->name == NULL) {
795                         DEBUG(1, ("cli_list: Error: unable to parse name from "
796                                   "info level %d\n", state->info_level));
797                         tevent_req_nterror(req,
798                                 NT_STATUS_INVALID_NETWORK_RESPONSE);
799                         return;
800                 }
801
802                 status = is_bad_finfo_name(state->cli, finfo);
803                 if (!NT_STATUS_IS_OK(status)) {
804                         smbXcli_conn_disconnect(state->cli->conn, status);
805                         tevent_req_nterror(req, status);
806                         return;
807                 }
808
809                 if (!state->first && (state->mask[0] != '\0') &&
810                     strcsequal(finfo->name, state->mask)) {
811                         DEBUG(1, ("Error: Looping in FIND_NEXT as name %s has "
812                                   "already been seen?\n", finfo->name));
813                         ff_eos = true;
814                         break;
815                 }
816         }
817
818         if (ff_searchcount == 0) {
819                 ff_eos = true;
820         }
821
822         TALLOC_FREE(param);
823         TALLOC_FREE(data);
824
825         /*
826          * Shrink state->finfo to the real length we received
827          */
828         tmp = talloc_realloc(state, state->finfo, struct file_info,
829                                    old_num_finfo + i);
830         if (tevent_req_nomem(tmp, req)) {
831                 return;
832         }
833         state->finfo = tmp;
834
835         state->first = false;
836
837         if (ff_eos) {
838                 data_blob_free(&last_name_raw);
839                 tevent_req_done(req);
840                 return;
841         }
842
843         TALLOC_FREE(state->mask);
844         state->mask = talloc_strdup(state, finfo->name);
845         if (tevent_req_nomem(state->mask, req)) {
846                 return;
847         }
848
849         SSVAL(&state->setup[0], 0, TRANSACT2_FINDNEXT);
850
851         param = talloc_realloc(state, state->param, uint8_t, 12);
852         if (tevent_req_nomem(param, req)) {
853                 return;
854         }
855         state->param = param;
856
857         SSVAL(param, 0, state->ff_dir_handle);
858         SSVAL(param, 2, state->max_matches); /* max count */
859         SSVAL(param, 4, state->info_level);
860         /*
861          * For W2K servers serving out FAT filesystems we *must* set
862          * the resume key. If it's not FAT then it's returned as zero.
863          */
864         SIVAL(param, 6, resume_key); /* ff_resume_key */
865         /*
866          * NB. *DON'T* use continue here. If you do it seems that W2K
867          * and bretheren can miss filenames. Use last filename
868          * continue instead. JRA
869          */
870         SSVAL(param, 10, (FLAG_TRANS2_FIND_REQUIRE_RESUME
871                           |FLAG_TRANS2_FIND_CLOSE_IF_END
872                           |(state->cli->backup_intent ? FLAG_TRANS2_FIND_BACKUP_INTENT : 0)));
873         if (last_name_raw.length) {
874                 state->param = trans2_bytes_push_bytes(state->param,
875                                                        last_name_raw.data,
876                                                        last_name_raw.length);
877                 if (tevent_req_nomem(state->param, req)) {
878                         return;
879                 }
880                 data_blob_free(&last_name_raw);
881         } else {
882                 state->param = trans2_bytes_push_str(state->param,
883                                                      smbXcli_conn_use_unicode(state->cli->conn),
884                                                      state->mask,
885                                                      strlen(state->mask)+1,
886                                                      NULL);
887                 if (tevent_req_nomem(state->param, req)) {
888                         return;
889                 }
890         }
891         param_len = talloc_get_size(state->param);
892
893         if (clistr_is_previous_version_path(state->mask, NULL, NULL, NULL)) {
894                 additional_flags2 = FLAGS2_REPARSE_PATH;
895         }
896
897         subreq = cli_trans_send(state, state->ev, state->cli, additional_flags2,
898                                 SMBtrans2, NULL, -1, 0, 0,
899                                 state->setup, 1, 0,
900                                 state->param, param_len, 10,
901                                 NULL, 0, CLI_BUFFER_SIZE);
902         if (tevent_req_nomem(subreq, req)) {
903                 return;
904         }
905         tevent_req_set_callback(subreq, cli_list_trans_done, req);
906 }
907
908 static NTSTATUS cli_list_trans_recv(struct tevent_req *req,
909                                     TALLOC_CTX *mem_ctx,
910                                     struct file_info **finfo)
911 {
912         struct cli_list_trans_state *state = tevent_req_data(
913                 req, struct cli_list_trans_state);
914         NTSTATUS status;
915
916         if (tevent_req_is_nterror(req, &status)) {
917                 return status;
918         }
919         *finfo = talloc_move(mem_ctx, &state->finfo);
920         return NT_STATUS_OK;
921 }
922
923 NTSTATUS cli_list_trans(struct cli_state *cli, const char *mask,
924                         uint32_t attribute, int info_level,
925                         NTSTATUS (*fn)(const char *mnt, struct file_info *finfo,
926                                    const char *mask, void *private_data),
927                         void *private_data)
928 {
929         TALLOC_CTX *frame = talloc_stackframe();
930         struct tevent_context *ev;
931         struct tevent_req *req;
932         int i, num_finfo;
933         struct file_info *finfo = NULL;
934         NTSTATUS status = NT_STATUS_NO_MEMORY;
935
936         if (smbXcli_conn_has_async_calls(cli->conn)) {
937                 /*
938                  * Can't use sync call while an async call is in flight
939                  */
940                 status = NT_STATUS_INVALID_PARAMETER;
941                 goto fail;
942         }
943         ev = samba_tevent_context_init(frame);
944         if (ev == NULL) {
945                 goto fail;
946         }
947         req = cli_list_trans_send(frame, ev, cli, mask, attribute, info_level);
948         if (req == NULL) {
949                 goto fail;
950         }
951         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
952                 goto fail;
953         }
954         status = cli_list_trans_recv(req, frame, &finfo);
955         if (!NT_STATUS_IS_OK(status)) {
956                 goto fail;
957         }
958         num_finfo = talloc_array_length(finfo);
959         for (i=0; i<num_finfo; i++) {
960                 status = fn(cli->dfs_mountpoint, &finfo[i], mask, private_data);
961                 if (!NT_STATUS_IS_OK(status)) {
962                         goto fail;
963                 }
964         }
965  fail:
966         TALLOC_FREE(frame);
967         return status;
968 }
969
970 struct cli_list_state {
971         NTSTATUS (*recv_fn)(struct tevent_req *req, TALLOC_CTX *mem_ctx,
972                             struct file_info **finfo);
973         struct file_info *finfo;
974 };
975
976 static void cli_list_done(struct tevent_req *subreq);
977
978 struct tevent_req *cli_list_send(TALLOC_CTX *mem_ctx,
979                                  struct tevent_context *ev,
980                                  struct cli_state *cli,
981                                  const char *mask,
982                                  uint32_t attribute,
983                                  uint16_t info_level)
984 {
985         struct tevent_req *req, *subreq;
986         struct cli_list_state *state;
987
988         req = tevent_req_create(mem_ctx, &state, struct cli_list_state);
989         if (req == NULL) {
990                 return NULL;
991         }
992
993         if (smbXcli_conn_protocol(cli->conn) <= PROTOCOL_LANMAN1) {
994                 subreq = cli_list_old_send(state, ev, cli, mask, attribute);
995                 state->recv_fn = cli_list_old_recv;
996         } else {
997                 subreq = cli_list_trans_send(state, ev, cli, mask, attribute,
998                                              info_level);
999                 state->recv_fn = cli_list_trans_recv;
1000         }
1001         if (tevent_req_nomem(subreq, req)) {
1002                 return tevent_req_post(req, ev);
1003         }
1004         tevent_req_set_callback(subreq, cli_list_done, req);
1005         return req;
1006 }
1007
1008 static void cli_list_done(struct tevent_req *subreq)
1009 {
1010         struct tevent_req *req = tevent_req_callback_data(
1011                 subreq, struct tevent_req);
1012         struct cli_list_state *state = tevent_req_data(
1013                 req, struct cli_list_state);
1014         NTSTATUS status;
1015
1016         status = state->recv_fn(subreq, state, &state->finfo);
1017         TALLOC_FREE(subreq);
1018         if (!NT_STATUS_IS_OK(status)) {
1019                 tevent_req_nterror(req, status);
1020                 return;
1021         }
1022         tevent_req_done(req);
1023 }
1024
1025 NTSTATUS cli_list_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
1026                        struct file_info **finfo, size_t *num_finfo)
1027 {
1028         struct cli_list_state *state = tevent_req_data(
1029                 req, struct cli_list_state);
1030         NTSTATUS status;
1031
1032         if (tevent_req_is_nterror(req, &status)) {
1033                 return status;
1034         }
1035         *num_finfo = talloc_array_length(state->finfo);
1036         *finfo = talloc_move(mem_ctx, &state->finfo);
1037         return NT_STATUS_OK;
1038 }
1039
1040 NTSTATUS cli_list(struct cli_state *cli, const char *mask, uint32_t attribute,
1041                   NTSTATUS (*fn)(const char *, struct file_info *, const char *,
1042                              void *), void *state)
1043 {
1044         TALLOC_CTX *frame = NULL;
1045         struct tevent_context *ev;
1046         struct tevent_req *req;
1047         NTSTATUS status = NT_STATUS_NO_MEMORY;
1048         struct file_info *finfo;
1049         size_t i, num_finfo = 0;
1050         uint16_t info_level;
1051
1052         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1053                 return cli_smb2_list(cli, mask, attribute, fn, state);
1054         }
1055
1056         frame = talloc_stackframe();
1057
1058         if (smbXcli_conn_has_async_calls(cli->conn)) {
1059                 /*
1060                  * Can't use sync call while an async call is in flight
1061                  */
1062                 status = NT_STATUS_INVALID_PARAMETER;
1063                 goto fail;
1064         }
1065         ev = samba_tevent_context_init(frame);
1066         if (ev == NULL) {
1067                 goto fail;
1068         }
1069
1070         info_level = (smb1cli_conn_capabilities(cli->conn) & CAP_NT_SMBS)
1071                 ? SMB_FIND_FILE_BOTH_DIRECTORY_INFO : SMB_FIND_INFO_STANDARD;
1072
1073         req = cli_list_send(frame, ev, cli, mask, attribute, info_level);
1074         if (req == NULL) {
1075                 goto fail;
1076         }
1077         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1078                 goto fail;
1079         }
1080
1081         status = cli_list_recv(req, frame, &finfo, &num_finfo);
1082         if (!NT_STATUS_IS_OK(status)) {
1083                 goto fail;
1084         }
1085
1086         for (i=0; i<num_finfo; i++) {
1087                 status = fn(cli->dfs_mountpoint, &finfo[i], mask, state);
1088                 if (!NT_STATUS_IS_OK(status)) {
1089                         goto fail;
1090                 }
1091         }
1092  fail:
1093         TALLOC_FREE(frame);
1094         return status;
1095 }