f868e72a239e4b2aa2ba230fa08b80c834899d37
[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->mode = CVAL(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 = clistr_pull_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->mode = CVAL(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 = clistr_pull_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->mode = CVAL(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 = clistr_pull_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 = clistr_pull_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->mode = 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 = clistr_pull_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         uint16_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                                             uint16_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
556                 status = is_bad_finfo_name(state->cli, finfo);
557                 if (!NT_STATUS_IS_OK(status)) {
558                         smbXcli_conn_disconnect(state->cli->conn, status);
559                         TALLOC_FREE(finfo);
560                         return status;
561                 }
562         }
563         *pfinfo = finfo;
564         return NT_STATUS_OK;
565 }
566
567 NTSTATUS cli_list_old(struct cli_state *cli, const char *mask,
568                       uint16_t attribute,
569                       NTSTATUS (*fn)(const char *, struct file_info *,
570                                  const char *, void *), void *state)
571 {
572         TALLOC_CTX *frame = talloc_stackframe();
573         struct tevent_context *ev;
574         struct tevent_req *req;
575         NTSTATUS status = NT_STATUS_NO_MEMORY;
576         struct file_info *finfo = NULL;
577         size_t i, num_finfo;
578
579         if (smbXcli_conn_has_async_calls(cli->conn)) {
580                 /*
581                  * Can't use sync call while an async call is in flight
582                  */
583                 status = NT_STATUS_INVALID_PARAMETER;
584                 goto fail;
585         }
586         ev = samba_tevent_context_init(frame);
587         if (ev == NULL) {
588                 goto fail;
589         }
590         req = cli_list_old_send(frame, ev, cli, mask, attribute);
591         if (req == NULL) {
592                 goto fail;
593         }
594         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
595                 goto fail;
596         }
597         status = cli_list_old_recv(req, frame, &finfo);
598         if (!NT_STATUS_IS_OK(status)) {
599                 goto fail;
600         }
601         num_finfo = talloc_array_length(finfo);
602         for (i=0; i<num_finfo; i++) {
603                 status = fn(cli->dfs_mountpoint, &finfo[i], mask, state);
604                 if (!NT_STATUS_IS_OK(status)) {
605                         goto fail;
606                 }
607         }
608  fail:
609         TALLOC_FREE(frame);
610         return status;
611 }
612
613 struct cli_list_trans_state {
614         struct tevent_context *ev;
615         struct cli_state *cli;
616         char *mask;
617         uint16_t attribute;
618         uint16_t info_level;
619
620         int loop_count;
621         int total_received;
622         uint16_t max_matches;
623         bool first;
624
625         int ff_eos;
626         int ff_dir_handle;
627
628         uint16_t setup[1];
629         uint8_t *param;
630
631         struct file_info *finfo;
632 };
633
634 static void cli_list_trans_done(struct tevent_req *subreq);
635
636 static struct tevent_req *cli_list_trans_send(TALLOC_CTX *mem_ctx,
637                                               struct tevent_context *ev,
638                                               struct cli_state *cli,
639                                               const char *mask,
640                                               uint16_t attribute,
641                                               uint16_t info_level)
642 {
643         struct tevent_req *req, *subreq;
644         struct cli_list_trans_state *state;
645         size_t param_len;
646         uint16_t additional_flags2 = 0;
647
648         req = tevent_req_create(mem_ctx, &state,
649                                 struct cli_list_trans_state);
650         if (req == NULL) {
651                 return NULL;
652         }
653         state->ev = ev;
654         state->cli = cli;
655         state->mask = talloc_strdup(state, mask);
656         if (tevent_req_nomem(state->mask, req)) {
657                 return tevent_req_post(req, ev);
658         }
659         state->attribute = attribute;
660         state->info_level = info_level;
661         state->loop_count = 0;
662         state->first = true;
663
664         state->max_matches = 1366; /* Match W2k */
665
666         SSVAL(&state->setup[0], 0, TRANSACT2_FINDFIRST);
667
668         state->param = talloc_array(state, uint8_t, 12);
669         if (tevent_req_nomem(state->param, req)) {
670                 return tevent_req_post(req, ev);
671         }
672
673         SSVAL(state->param, 0, state->attribute);
674         SSVAL(state->param, 2, state->max_matches);
675         SSVAL(state->param, 4,
676               FLAG_TRANS2_FIND_REQUIRE_RESUME
677               |FLAG_TRANS2_FIND_CLOSE_IF_END
678               |(cli->backup_intent ? FLAG_TRANS2_FIND_BACKUP_INTENT : 0));
679         SSVAL(state->param, 6, state->info_level);
680         SIVAL(state->param, 8, 0);
681
682         state->param = trans2_bytes_push_str(state->param, smbXcli_conn_use_unicode(cli->conn),
683                                              state->mask, strlen(state->mask)+1,
684                                              NULL);
685         if (tevent_req_nomem(state->param, req)) {
686                 return tevent_req_post(req, ev);
687         }
688
689         if (clistr_is_previous_version_path(state->mask, NULL, NULL, NULL)) {
690                 additional_flags2 = FLAGS2_REPARSE_PATH;
691         }
692
693         param_len = talloc_get_size(state->param);
694
695         subreq = cli_trans_send(state, state->ev, state->cli, additional_flags2,
696                                 SMBtrans2, NULL, -1, 0, 0,
697                                 state->setup, 1, 0,
698                                 state->param, param_len, 10,
699                                 NULL, 0, CLI_BUFFER_SIZE);
700         if (tevent_req_nomem(subreq, req)) {
701                 return tevent_req_post(req, ev);
702         }
703         tevent_req_set_callback(subreq, cli_list_trans_done, req);
704         return req;
705 }
706
707 static void cli_list_trans_done(struct tevent_req *subreq)
708 {
709         struct tevent_req *req = tevent_req_callback_data(
710                 subreq, struct tevent_req);
711         struct cli_list_trans_state *state = tevent_req_data(
712                 req, struct cli_list_trans_state);
713         NTSTATUS status;
714         uint8_t *param;
715         uint32_t num_param;
716         uint8_t *data;
717         char *data_end;
718         uint32_t num_data;
719         uint32_t min_param;
720         struct file_info *tmp;
721         size_t old_num_finfo;
722         uint16_t recv_flags2;
723         int ff_searchcount;
724         bool ff_eos;
725         char *p, *p2;
726         uint32_t resume_key = 0;
727         int i;
728         DATA_BLOB last_name_raw;
729         struct file_info *finfo = NULL;
730         size_t param_len;
731         uint16_t additional_flags2 = 0;
732
733         min_param = (state->first ? 6 : 4);
734
735         status = cli_trans_recv(subreq, talloc_tos(), &recv_flags2,
736                                 NULL, 0, NULL,
737                                 &param, min_param, &num_param,
738                                 &data, 0, &num_data);
739         TALLOC_FREE(subreq);
740         if (!NT_STATUS_IS_OK(status)) {
741                 /*
742                  * TODO: retry, OS/2 nofiles
743                  */
744                 tevent_req_nterror(req, status);
745                 return;
746         }
747
748         if (state->first) {
749                 state->ff_dir_handle = SVAL(param, 0);
750                 ff_searchcount = SVAL(param, 2);
751                 ff_eos = SVAL(param, 4) != 0;
752         } else {
753                 ff_searchcount = SVAL(param, 0);
754                 ff_eos = SVAL(param, 2) != 0;
755         }
756
757         old_num_finfo = talloc_array_length(state->finfo);
758
759         tmp = talloc_realloc(state, state->finfo, struct file_info,
760                                    old_num_finfo + ff_searchcount);
761         if (tevent_req_nomem(tmp, req)) {
762                 return;
763         }
764         state->finfo = tmp;
765
766         p2 = p = (char *)data;
767         data_end = (char *)data + num_data;
768         last_name_raw = data_blob_null;
769
770         for (i=0; i<ff_searchcount; i++) {
771                 if (p2 >= data_end) {
772                         ff_eos = true;
773                         break;
774                 }
775                 if ((state->info_level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
776                     && (i == ff_searchcount-1)) {
777                         /* Last entry - fixup the last offset length. */
778                         SIVAL(p2, 0, PTR_DIFF((data + num_data), p2));
779                 }
780
781                 data_blob_free(&last_name_raw);
782
783                 finfo = &state->finfo[old_num_finfo + i];
784
785                 p2 += interpret_long_filename(
786                         state->finfo, /* Stick fname to the array as such */
787                         state->cli, state->info_level,
788                         (char *)data, recv_flags2, p2,
789                         data_end, finfo, &resume_key, &last_name_raw);
790
791                 if (finfo->name == NULL) {
792                         DEBUG(1, ("cli_list: Error: unable to parse name from "
793                                   "info level %d\n", state->info_level));
794                         ff_eos = true;
795                         break;
796                 }
797
798                 status = is_bad_finfo_name(state->cli, finfo);
799                 if (!NT_STATUS_IS_OK(status)) {
800                         smbXcli_conn_disconnect(state->cli->conn, status);
801                         tevent_req_nterror(req, status);
802                         return;
803                 }
804
805                 if (!state->first && (state->mask[0] != '\0') &&
806                     strcsequal(finfo->name, state->mask)) {
807                         DEBUG(1, ("Error: Looping in FIND_NEXT as name %s has "
808                                   "already been seen?\n", finfo->name));
809                         ff_eos = true;
810                         break;
811                 }
812         }
813
814         if (ff_searchcount == 0) {
815                 ff_eos = true;
816         }
817
818         TALLOC_FREE(param);
819         TALLOC_FREE(data);
820
821         /*
822          * Shrink state->finfo to the real length we received
823          */
824         tmp = talloc_realloc(state, state->finfo, struct file_info,
825                                    old_num_finfo + i);
826         if (tevent_req_nomem(tmp, req)) {
827                 return;
828         }
829         state->finfo = tmp;
830
831         state->first = false;
832
833         if (ff_eos) {
834                 data_blob_free(&last_name_raw);
835                 tevent_req_done(req);
836                 return;
837         }
838
839         TALLOC_FREE(state->mask);
840         state->mask = talloc_strdup(state, finfo->name);
841         if (tevent_req_nomem(state->mask, req)) {
842                 return;
843         }
844
845         SSVAL(&state->setup[0], 0, TRANSACT2_FINDNEXT);
846
847         param = talloc_realloc(state, state->param, uint8_t, 12);
848         if (tevent_req_nomem(param, req)) {
849                 return;
850         }
851         state->param = param;
852
853         SSVAL(param, 0, state->ff_dir_handle);
854         SSVAL(param, 2, state->max_matches); /* max count */
855         SSVAL(param, 4, state->info_level);
856         /*
857          * For W2K servers serving out FAT filesystems we *must* set
858          * the resume key. If it's not FAT then it's returned as zero.
859          */
860         SIVAL(param, 6, resume_key); /* ff_resume_key */
861         /*
862          * NB. *DON'T* use continue here. If you do it seems that W2K
863          * and bretheren can miss filenames. Use last filename
864          * continue instead. JRA
865          */
866         SSVAL(param, 10, (FLAG_TRANS2_FIND_REQUIRE_RESUME
867                           |FLAG_TRANS2_FIND_CLOSE_IF_END
868                           |(state->cli->backup_intent ? FLAG_TRANS2_FIND_BACKUP_INTENT : 0)));
869         if (last_name_raw.length) {
870                 state->param = trans2_bytes_push_bytes(state->param,
871                                                        last_name_raw.data,
872                                                        last_name_raw.length);
873                 if (tevent_req_nomem(state->param, req)) {
874                         return;
875                 }
876                 data_blob_free(&last_name_raw);
877         } else {
878                 state->param = trans2_bytes_push_str(state->param,
879                                                      smbXcli_conn_use_unicode(state->cli->conn),
880                                                      state->mask,
881                                                      strlen(state->mask)+1,
882                                                      NULL);
883                 if (tevent_req_nomem(state->param, req)) {
884                         return;
885                 }
886         }
887         param_len = talloc_get_size(state->param);
888
889         if (clistr_is_previous_version_path(state->mask, NULL, NULL, NULL)) {
890                 additional_flags2 = FLAGS2_REPARSE_PATH;
891         }
892
893         subreq = cli_trans_send(state, state->ev, state->cli, additional_flags2,
894                                 SMBtrans2, NULL, -1, 0, 0,
895                                 state->setup, 1, 0,
896                                 state->param, param_len, 10,
897                                 NULL, 0, CLI_BUFFER_SIZE);
898         if (tevent_req_nomem(subreq, req)) {
899                 return;
900         }
901         tevent_req_set_callback(subreq, cli_list_trans_done, req);
902 }
903
904 static NTSTATUS cli_list_trans_recv(struct tevent_req *req,
905                                     TALLOC_CTX *mem_ctx,
906                                     struct file_info **finfo)
907 {
908         struct cli_list_trans_state *state = tevent_req_data(
909                 req, struct cli_list_trans_state);
910         NTSTATUS status;
911
912         if (tevent_req_is_nterror(req, &status)) {
913                 return status;
914         }
915         *finfo = talloc_move(mem_ctx, &state->finfo);
916         return NT_STATUS_OK;
917 }
918
919 NTSTATUS cli_list_trans(struct cli_state *cli, const char *mask,
920                         uint16_t attribute, int info_level,
921                         NTSTATUS (*fn)(const char *mnt, struct file_info *finfo,
922                                    const char *mask, void *private_data),
923                         void *private_data)
924 {
925         TALLOC_CTX *frame = talloc_stackframe();
926         struct tevent_context *ev;
927         struct tevent_req *req;
928         int i, num_finfo;
929         struct file_info *finfo = NULL;
930         NTSTATUS status = NT_STATUS_NO_MEMORY;
931
932         if (smbXcli_conn_has_async_calls(cli->conn)) {
933                 /*
934                  * Can't use sync call while an async call is in flight
935                  */
936                 status = NT_STATUS_INVALID_PARAMETER;
937                 goto fail;
938         }
939         ev = samba_tevent_context_init(frame);
940         if (ev == NULL) {
941                 goto fail;
942         }
943         req = cli_list_trans_send(frame, ev, cli, mask, attribute, info_level);
944         if (req == NULL) {
945                 goto fail;
946         }
947         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
948                 goto fail;
949         }
950         status = cli_list_trans_recv(req, frame, &finfo);
951         if (!NT_STATUS_IS_OK(status)) {
952                 goto fail;
953         }
954         num_finfo = talloc_array_length(finfo);
955         for (i=0; i<num_finfo; i++) {
956                 status = fn(cli->dfs_mountpoint, &finfo[i], mask, private_data);
957                 if (!NT_STATUS_IS_OK(status)) {
958                         goto fail;
959                 }
960         }
961  fail:
962         TALLOC_FREE(frame);
963         return status;
964 }
965
966 struct cli_list_state {
967         NTSTATUS (*recv_fn)(struct tevent_req *req, TALLOC_CTX *mem_ctx,
968                             struct file_info **finfo);
969         struct file_info *finfo;
970 };
971
972 static void cli_list_done(struct tevent_req *subreq);
973
974 struct tevent_req *cli_list_send(TALLOC_CTX *mem_ctx,
975                                  struct tevent_context *ev,
976                                  struct cli_state *cli,
977                                  const char *mask,
978                                  uint16_t attribute,
979                                  uint16_t info_level)
980 {
981         struct tevent_req *req, *subreq;
982         struct cli_list_state *state;
983
984         req = tevent_req_create(mem_ctx, &state, struct cli_list_state);
985         if (req == NULL) {
986                 return NULL;
987         }
988
989         if (smbXcli_conn_protocol(cli->conn) <= PROTOCOL_LANMAN1) {
990                 subreq = cli_list_old_send(state, ev, cli, mask, attribute);
991                 state->recv_fn = cli_list_old_recv;
992         } else {
993                 subreq = cli_list_trans_send(state, ev, cli, mask, attribute,
994                                              info_level);
995                 state->recv_fn = cli_list_trans_recv;
996         }
997         if (tevent_req_nomem(subreq, req)) {
998                 return tevent_req_post(req, ev);
999         }
1000         tevent_req_set_callback(subreq, cli_list_done, req);
1001         return req;
1002 }
1003
1004 static void cli_list_done(struct tevent_req *subreq)
1005 {
1006         struct tevent_req *req = tevent_req_callback_data(
1007                 subreq, struct tevent_req);
1008         struct cli_list_state *state = tevent_req_data(
1009                 req, struct cli_list_state);
1010         NTSTATUS status;
1011
1012         status = state->recv_fn(subreq, state, &state->finfo);
1013         TALLOC_FREE(subreq);
1014         if (!NT_STATUS_IS_OK(status)) {
1015                 tevent_req_nterror(req, status);
1016                 return;
1017         }
1018         tevent_req_done(req);
1019 }
1020
1021 NTSTATUS cli_list_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
1022                        struct file_info **finfo, size_t *num_finfo)
1023 {
1024         struct cli_list_state *state = tevent_req_data(
1025                 req, struct cli_list_state);
1026         NTSTATUS status;
1027
1028         if (tevent_req_is_nterror(req, &status)) {
1029                 return status;
1030         }
1031         *num_finfo = talloc_array_length(state->finfo);
1032         *finfo = talloc_move(mem_ctx, &state->finfo);
1033         return NT_STATUS_OK;
1034 }
1035
1036 NTSTATUS cli_list(struct cli_state *cli, const char *mask, uint16_t attribute,
1037                   NTSTATUS (*fn)(const char *, struct file_info *, const char *,
1038                              void *), void *state)
1039 {
1040         TALLOC_CTX *frame = NULL;
1041         struct tevent_context *ev;
1042         struct tevent_req *req;
1043         NTSTATUS status = NT_STATUS_NO_MEMORY;
1044         struct file_info *finfo;
1045         size_t i, num_finfo = 0;
1046         uint16_t info_level;
1047
1048         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1049                 return cli_smb2_list(cli, mask, attribute, fn, state);
1050         }
1051
1052         frame = talloc_stackframe();
1053
1054         if (smbXcli_conn_has_async_calls(cli->conn)) {
1055                 /*
1056                  * Can't use sync call while an async call is in flight
1057                  */
1058                 status = NT_STATUS_INVALID_PARAMETER;
1059                 goto fail;
1060         }
1061         ev = samba_tevent_context_init(frame);
1062         if (ev == NULL) {
1063                 goto fail;
1064         }
1065
1066         info_level = (smb1cli_conn_capabilities(cli->conn) & CAP_NT_SMBS)
1067                 ? SMB_FIND_FILE_BOTH_DIRECTORY_INFO : SMB_FIND_INFO_STANDARD;
1068
1069         req = cli_list_send(frame, ev, cli, mask, attribute, info_level);
1070         if (req == NULL) {
1071                 goto fail;
1072         }
1073         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1074                 goto fail;
1075         }
1076
1077         status = cli_list_recv(req, frame, &finfo, &num_finfo);
1078         if (!NT_STATUS_IS_OK(status)) {
1079                 goto fail;
1080         }
1081
1082         for (i=0; i<num_finfo; i++) {
1083                 status = fn(cli->dfs_mountpoint, &finfo[i], mask, state);
1084                 if (!NT_STATUS_IS_OK(status)) {
1085                         goto fail;
1086                 }
1087         }
1088  fail:
1089         TALLOC_FREE(frame);
1090         return status;
1091 }