docs: fix a typo in history file
[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         state->mask = smb1_dfs_share_path(state, cli, state->mask);
398         if (tevent_req_nomem(state->mask, req)) {
399                 return tevent_req_post(req, ev);
400         }
401         usable_space = cli_state_available_size(cli, 100);
402         state->num_asked = usable_space / DIR_STRUCT_SIZE;
403
404         SSVAL(state->vwv + 0, 0, state->num_asked);
405         SSVAL(state->vwv + 1, 0, state->attribute);
406
407         bytes = talloc_array(state, uint8_t, 1);
408         if (tevent_req_nomem(bytes, req)) {
409                 return tevent_req_post(req, ev);
410         }
411         bytes[0] = 4;
412         bytes = smb_bytes_push_str(bytes,
413                                    smbXcli_conn_use_unicode(cli->conn),
414                                    state->mask,
415                                    strlen(state->mask)+1,
416                                    NULL);
417
418         bytes = smb_bytes_push_bytes(bytes, 5, (const uint8_t *)&zero, 2);
419         if (tevent_req_nomem(bytes, req)) {
420                 return tevent_req_post(req, ev);
421         }
422
423         subreq = cli_smb_send(state, state->ev, state->cli, SMBsearch, 0, 0,
424                         2, state->vwv, talloc_get_size(bytes), bytes);
425         if (tevent_req_nomem(subreq, req)) {
426                 return tevent_req_post(req, ev);
427         }
428         tevent_req_set_callback(subreq, cli_list_old_done, req);
429         return req;
430 }
431
432 static void cli_list_old_done(struct tevent_req *subreq)
433 {
434         struct tevent_req *req = tevent_req_callback_data(
435                 subreq, struct tevent_req);
436         struct cli_list_old_state *state = tevent_req_data(
437                 req, struct cli_list_old_state);
438         NTSTATUS status;
439         uint8_t cmd;
440         uint8_t wct;
441         uint16_t *vwv;
442         uint32_t num_bytes;
443         uint8_t *bytes;
444         uint16_t received;
445         size_t dirlist_len;
446         uint8_t *tmp;
447
448         status = cli_smb_recv(subreq, state, NULL, 0, &wct, &vwv, &num_bytes,
449                               &bytes);
450         if (!NT_STATUS_IS_OK(status)
451             && !NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRnofiles))
452             && !NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
453                 TALLOC_FREE(subreq);
454                 tevent_req_nterror(req, status);
455                 return;
456         }
457         if (NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRnofiles))
458             || NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
459                 received = 0;
460         } else {
461                 if (wct < 1) {
462                         TALLOC_FREE(subreq);
463                         tevent_req_nterror(
464                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
465                         return;
466                 }
467                 received = SVAL(vwv + 0, 0);
468         }
469
470         if (received > 0) {
471                 /*
472                  * I don't think this can wrap. received is
473                  * initialized from a 16-bit value.
474                  */
475                 if (num_bytes < ((uint32_t)received * DIR_STRUCT_SIZE + 3)) {
476                         TALLOC_FREE(subreq);
477                         tevent_req_nterror(
478                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
479                         return;
480                 }
481
482                 dirlist_len = talloc_get_size(state->dirlist);
483
484                 tmp = talloc_realloc(
485                         state, state->dirlist, uint8_t,
486                         dirlist_len + received * DIR_STRUCT_SIZE);
487                 if (tevent_req_nomem(tmp, req)) {
488                         return;
489                 }
490                 state->dirlist = tmp;
491                 memcpy(state->dirlist + dirlist_len, bytes + 3,
492                        received * DIR_STRUCT_SIZE);
493
494                 SSVAL(state->search_status, 0, 21);
495                 memcpy(state->search_status + 2,
496                        bytes + 3 + (received-1)*DIR_STRUCT_SIZE, 21);
497                 cmd = SMBsearch;
498         } else {
499                 if (state->first || state->done) {
500                         tevent_req_done(req);
501                         return;
502                 }
503                 state->done = true;
504                 state->num_asked = 0;
505                 cmd = SMBfclose;
506         }
507         TALLOC_FREE(subreq);
508
509         state->first = false;
510
511         SSVAL(state->vwv + 0, 0, state->num_asked);
512         SSVAL(state->vwv + 1, 0, state->attribute);
513
514         bytes = talloc_array(state, uint8_t, 1);
515         if (tevent_req_nomem(bytes, req)) {
516                 return;
517         }
518         bytes[0] = 4;
519         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(state->cli->conn), "",
520                                    1, NULL);
521         bytes = smb_bytes_push_bytes(bytes, 5, state->search_status,
522                                      sizeof(state->search_status));
523         if (tevent_req_nomem(bytes, req)) {
524                 return;
525         }
526         subreq = cli_smb_send(state, state->ev, state->cli, cmd, 0, 0,
527                               2, state->vwv, talloc_get_size(bytes), bytes);
528         if (tevent_req_nomem(subreq, req)) {
529                 return;
530         }
531         tevent_req_set_callback(subreq, cli_list_old_done, req);
532 }
533
534 static NTSTATUS cli_list_old_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
535                                   struct file_info **pfinfo)
536 {
537         struct cli_list_old_state *state = tevent_req_data(
538                 req, struct cli_list_old_state);
539         NTSTATUS status;
540         size_t i, num_received;
541         struct file_info *finfo;
542
543         if (tevent_req_is_nterror(req, &status)) {
544                 return status;
545         }
546
547         num_received = talloc_array_length(state->dirlist) / DIR_STRUCT_SIZE;
548
549         finfo = talloc_array(mem_ctx, struct file_info, num_received);
550         if (finfo == NULL) {
551                 return NT_STATUS_NO_MEMORY;
552         }
553
554         for (i=0; i<num_received; i++) {
555                 if (!interpret_short_filename(
556                             finfo, state->cli,
557                             (char *)state->dirlist + i * DIR_STRUCT_SIZE,
558                             &finfo[i])) {
559                         TALLOC_FREE(finfo);
560                         return NT_STATUS_NO_MEMORY;
561                 }
562                 if (finfo->name == NULL) {
563                         TALLOC_FREE(finfo);
564                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
565                 }
566                 status = is_bad_finfo_name(state->cli, finfo);
567                 if (!NT_STATUS_IS_OK(status)) {
568                         smbXcli_conn_disconnect(state->cli->conn, status);
569                         TALLOC_FREE(finfo);
570                         return status;
571                 }
572         }
573         *pfinfo = finfo;
574         return NT_STATUS_OK;
575 }
576
577 NTSTATUS cli_list_old(struct cli_state *cli, const char *mask,
578                       uint32_t attribute,
579                       NTSTATUS (*fn)(struct file_info *,
580                                  const char *, void *), void *state)
581 {
582         TALLOC_CTX *frame = talloc_stackframe();
583         struct tevent_context *ev;
584         struct tevent_req *req;
585         NTSTATUS status = NT_STATUS_NO_MEMORY;
586         struct file_info *finfo = NULL;
587         size_t i, num_finfo;
588
589         if (smbXcli_conn_has_async_calls(cli->conn)) {
590                 /*
591                  * Can't use sync call while an async call is in flight
592                  */
593                 status = NT_STATUS_INVALID_PARAMETER;
594                 goto fail;
595         }
596         ev = samba_tevent_context_init(frame);
597         if (ev == NULL) {
598                 goto fail;
599         }
600         req = cli_list_old_send(frame, ev, cli, mask, attribute);
601         if (req == NULL) {
602                 goto fail;
603         }
604         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
605                 goto fail;
606         }
607         status = cli_list_old_recv(req, frame, &finfo);
608         if (!NT_STATUS_IS_OK(status)) {
609                 goto fail;
610         }
611         num_finfo = talloc_array_length(finfo);
612         for (i=0; i<num_finfo; i++) {
613                 status = fn(&finfo[i], mask, state);
614                 if (!NT_STATUS_IS_OK(status)) {
615                         goto fail;
616                 }
617         }
618  fail:
619         TALLOC_FREE(frame);
620         return status;
621 }
622
623 struct cli_list_trans_state {
624         struct tevent_context *ev;
625         struct cli_state *cli;
626         char *mask;
627         uint32_t attribute;
628         uint16_t info_level;
629
630         int loop_count;
631         int total_received;
632         uint16_t max_matches;
633         bool first;
634
635         int ff_eos;
636         int ff_dir_handle;
637
638         uint16_t setup[1];
639         uint8_t *param;
640
641         struct file_info *finfo;
642 };
643
644 static void cli_list_trans_done(struct tevent_req *subreq);
645
646 static struct tevent_req *cli_list_trans_send(TALLOC_CTX *mem_ctx,
647                                               struct tevent_context *ev,
648                                               struct cli_state *cli,
649                                               const char *mask,
650                                               uint32_t attribute,
651                                               uint16_t info_level)
652 {
653         struct tevent_req *req, *subreq;
654         struct cli_list_trans_state *state;
655         size_t param_len;
656         uint16_t additional_flags2 = 0;
657
658         req = tevent_req_create(mem_ctx, &state,
659                                 struct cli_list_trans_state);
660         if (req == NULL) {
661                 return NULL;
662         }
663         state->ev = ev;
664         state->cli = cli;
665         state->mask = talloc_strdup(state, mask);
666         if (tevent_req_nomem(state->mask, req)) {
667                 return tevent_req_post(req, ev);
668         }
669         state->mask = smb1_dfs_share_path(state, cli, state->mask);
670         if (tevent_req_nomem(state->mask, req)) {
671                 return tevent_req_post(req, ev);
672         }
673         state->attribute = attribute;
674         state->info_level = info_level;
675         state->loop_count = 0;
676         state->first = true;
677
678         state->max_matches = 1366; /* Match W2k */
679
680         SSVAL(&state->setup[0], 0, TRANSACT2_FINDFIRST);
681
682         state->param = talloc_array(state, uint8_t, 12);
683         if (tevent_req_nomem(state->param, req)) {
684                 return tevent_req_post(req, ev);
685         }
686
687         SSVAL(state->param, 0, state->attribute);
688         SSVAL(state->param, 2, state->max_matches);
689         SSVAL(state->param, 4,
690               FLAG_TRANS2_FIND_REQUIRE_RESUME
691               |FLAG_TRANS2_FIND_CLOSE_IF_END
692               |(cli->backup_intent ? FLAG_TRANS2_FIND_BACKUP_INTENT : 0));
693         SSVAL(state->param, 6, state->info_level);
694         SIVAL(state->param, 8, 0);
695
696         state->param = trans2_bytes_push_str(state->param, smbXcli_conn_use_unicode(cli->conn),
697                                              state->mask, strlen(state->mask)+1,
698                                              NULL);
699         if (tevent_req_nomem(state->param, req)) {
700                 return tevent_req_post(req, ev);
701         }
702
703         if (clistr_is_previous_version_path(state->mask)) {
704                 additional_flags2 = FLAGS2_REPARSE_PATH;
705         }
706
707         param_len = talloc_get_size(state->param);
708
709         subreq = cli_trans_send(state, state->ev, state->cli, additional_flags2,
710                                 SMBtrans2, NULL, -1, 0, 0,
711                                 state->setup, 1, 0,
712                                 state->param, param_len, 10,
713                                 NULL, 0, CLI_BUFFER_SIZE);
714         if (tevent_req_nomem(subreq, req)) {
715                 return tevent_req_post(req, ev);
716         }
717         tevent_req_set_callback(subreq, cli_list_trans_done, req);
718         return req;
719 }
720
721 static void cli_list_trans_done(struct tevent_req *subreq)
722 {
723         struct tevent_req *req = tevent_req_callback_data(
724                 subreq, struct tevent_req);
725         struct cli_list_trans_state *state = tevent_req_data(
726                 req, struct cli_list_trans_state);
727         NTSTATUS status;
728         uint8_t *param;
729         uint32_t num_param;
730         uint8_t *data;
731         char *data_end;
732         uint32_t num_data;
733         uint32_t min_param;
734         struct file_info *tmp;
735         size_t old_num_finfo;
736         uint16_t recv_flags2;
737         int ff_searchcount;
738         bool ff_eos;
739         char *p, *p2;
740         uint32_t resume_key = 0;
741         int i;
742         DATA_BLOB last_name_raw;
743         struct file_info *finfo = NULL;
744         size_t param_len;
745         uint16_t additional_flags2 = 0;
746
747         min_param = (state->first ? 6 : 4);
748
749         status = cli_trans_recv(subreq, talloc_tos(), &recv_flags2,
750                                 NULL, 0, NULL,
751                                 &param, min_param, &num_param,
752                                 &data, 0, &num_data);
753         TALLOC_FREE(subreq);
754         if (!NT_STATUS_IS_OK(status)) {
755                 /*
756                  * TODO: retry, OS/2 nofiles
757                  */
758                 tevent_req_nterror(req, status);
759                 return;
760         }
761
762         if (state->first) {
763                 state->ff_dir_handle = SVAL(param, 0);
764                 ff_searchcount = SVAL(param, 2);
765                 ff_eos = SVAL(param, 4) != 0;
766         } else {
767                 ff_searchcount = SVAL(param, 0);
768                 ff_eos = SVAL(param, 2) != 0;
769         }
770
771         old_num_finfo = talloc_array_length(state->finfo);
772
773         tmp = talloc_realloc(state, state->finfo, struct file_info,
774                                    old_num_finfo + ff_searchcount);
775         if (tevent_req_nomem(tmp, req)) {
776                 return;
777         }
778         state->finfo = tmp;
779
780         p2 = p = (char *)data;
781         data_end = (char *)data + num_data;
782         last_name_raw = data_blob_null;
783
784         for (i=0; i<ff_searchcount; i++) {
785                 if (p2 >= data_end) {
786                         ff_eos = true;
787                         break;
788                 }
789                 if ((state->info_level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
790                     && (i == ff_searchcount-1)) {
791                         /* Last entry - fixup the last offset length. */
792                         SIVAL(p2, 0, PTR_DIFF((data + num_data), p2));
793                 }
794
795                 data_blob_free(&last_name_raw);
796
797                 finfo = &state->finfo[old_num_finfo + i];
798
799                 p2 += interpret_long_filename(
800                         state->finfo, /* Stick fname to the array as such */
801                         state->cli, state->info_level,
802                         (char *)data, recv_flags2, p2,
803                         data_end, finfo, &resume_key, &last_name_raw);
804
805                 if (finfo->name == NULL) {
806                         DEBUG(1, ("cli_list: Error: unable to parse name from "
807                                   "info level %d\n", state->info_level));
808                         tevent_req_nterror(req,
809                                 NT_STATUS_INVALID_NETWORK_RESPONSE);
810                         return;
811                 }
812
813                 status = is_bad_finfo_name(state->cli, finfo);
814                 if (!NT_STATUS_IS_OK(status)) {
815                         smbXcli_conn_disconnect(state->cli->conn, status);
816                         tevent_req_nterror(req, status);
817                         return;
818                 }
819
820                 if (!state->first && (state->mask[0] != '\0') &&
821                     strcsequal(finfo->name, state->mask)) {
822                         DEBUG(1, ("Error: Looping in FIND_NEXT as name %s has "
823                                   "already been seen?\n", finfo->name));
824                         ff_eos = true;
825                         break;
826                 }
827         }
828
829         if (ff_searchcount == 0) {
830                 ff_eos = true;
831         }
832
833         TALLOC_FREE(param);
834         TALLOC_FREE(data);
835
836         /*
837          * Shrink state->finfo to the real length we received
838          */
839         tmp = talloc_realloc(state, state->finfo, struct file_info,
840                                    old_num_finfo + i);
841         if (tevent_req_nomem(tmp, req)) {
842                 return;
843         }
844         state->finfo = tmp;
845
846         state->first = false;
847
848         if (ff_eos) {
849                 data_blob_free(&last_name_raw);
850                 tevent_req_done(req);
851                 return;
852         }
853
854         TALLOC_FREE(state->mask);
855         state->mask = talloc_strdup(state, finfo->name);
856         if (tevent_req_nomem(state->mask, req)) {
857                 return;
858         }
859
860         SSVAL(&state->setup[0], 0, TRANSACT2_FINDNEXT);
861
862         param = talloc_realloc(state, state->param, uint8_t, 12);
863         if (tevent_req_nomem(param, req)) {
864                 return;
865         }
866         state->param = param;
867
868         SSVAL(param, 0, state->ff_dir_handle);
869         SSVAL(param, 2, state->max_matches); /* max count */
870         SSVAL(param, 4, state->info_level);
871         /*
872          * For W2K servers serving out FAT filesystems we *must* set
873          * the resume key. If it's not FAT then it's returned as zero.
874          */
875         SIVAL(param, 6, resume_key); /* ff_resume_key */
876         /*
877          * NB. *DON'T* use continue here. If you do it seems that W2K
878          * and bretheren can miss filenames. Use last filename
879          * continue instead. JRA
880          */
881         SSVAL(param, 10, (FLAG_TRANS2_FIND_REQUIRE_RESUME
882                           |FLAG_TRANS2_FIND_CLOSE_IF_END
883                           |(state->cli->backup_intent ? FLAG_TRANS2_FIND_BACKUP_INTENT : 0)));
884         if (last_name_raw.length) {
885                 state->param = trans2_bytes_push_bytes(state->param,
886                                                        last_name_raw.data,
887                                                        last_name_raw.length);
888                 if (tevent_req_nomem(state->param, req)) {
889                         return;
890                 }
891                 data_blob_free(&last_name_raw);
892         } else {
893                 state->param = trans2_bytes_push_str(state->param,
894                                                      smbXcli_conn_use_unicode(state->cli->conn),
895                                                      state->mask,
896                                                      strlen(state->mask)+1,
897                                                      NULL);
898                 if (tevent_req_nomem(state->param, req)) {
899                         return;
900                 }
901         }
902         param_len = talloc_get_size(state->param);
903
904         if (clistr_is_previous_version_path(state->mask)) {
905                 additional_flags2 = FLAGS2_REPARSE_PATH;
906         }
907
908         subreq = cli_trans_send(state, state->ev, state->cli, additional_flags2,
909                                 SMBtrans2, NULL, -1, 0, 0,
910                                 state->setup, 1, 0,
911                                 state->param, param_len, 10,
912                                 NULL, 0, CLI_BUFFER_SIZE);
913         if (tevent_req_nomem(subreq, req)) {
914                 return;
915         }
916         tevent_req_set_callback(subreq, cli_list_trans_done, req);
917 }
918
919 static NTSTATUS cli_list_trans_recv(struct tevent_req *req,
920                                     TALLOC_CTX *mem_ctx,
921                                     struct file_info **finfo)
922 {
923         struct cli_list_trans_state *state = tevent_req_data(
924                 req, struct cli_list_trans_state);
925         NTSTATUS status;
926
927         if (tevent_req_is_nterror(req, &status)) {
928                 return status;
929         }
930         *finfo = talloc_move(mem_ctx, &state->finfo);
931         return NT_STATUS_OK;
932 }
933
934 NTSTATUS cli_list_trans(struct cli_state *cli, const char *mask,
935                         uint32_t attribute, int info_level,
936                         NTSTATUS (*fn)(
937                                 struct file_info *finfo,
938                                 const char *mask,
939                                 void *private_data),
940                         void *private_data)
941 {
942         TALLOC_CTX *frame = talloc_stackframe();
943         struct tevent_context *ev;
944         struct tevent_req *req;
945         int i, num_finfo;
946         struct file_info *finfo = NULL;
947         NTSTATUS status = NT_STATUS_NO_MEMORY;
948
949         if (smbXcli_conn_has_async_calls(cli->conn)) {
950                 /*
951                  * Can't use sync call while an async call is in flight
952                  */
953                 status = NT_STATUS_INVALID_PARAMETER;
954                 goto fail;
955         }
956         ev = samba_tevent_context_init(frame);
957         if (ev == NULL) {
958                 goto fail;
959         }
960         req = cli_list_trans_send(frame, ev, cli, mask, attribute, info_level);
961         if (req == NULL) {
962                 goto fail;
963         }
964         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
965                 goto fail;
966         }
967         status = cli_list_trans_recv(req, frame, &finfo);
968         if (!NT_STATUS_IS_OK(status)) {
969                 goto fail;
970         }
971         num_finfo = talloc_array_length(finfo);
972         for (i=0; i<num_finfo; i++) {
973                 status = fn(&finfo[i], mask, private_data);
974                 if (!NT_STATUS_IS_OK(status)) {
975                         goto fail;
976                 }
977         }
978  fail:
979         TALLOC_FREE(frame);
980         return status;
981 }
982
983 struct cli_list_state {
984         struct tevent_context *ev;
985         struct tevent_req *subreq;
986         NTSTATUS (*recv_fn)(struct tevent_req *req, TALLOC_CTX *mem_ctx,
987                             struct file_info **finfo);
988         struct file_info *finfo;
989         size_t num_received;
990 };
991
992 static void cli_list_done(struct tevent_req *subreq);
993
994 struct tevent_req *cli_list_send(TALLOC_CTX *mem_ctx,
995                                  struct tevent_context *ev,
996                                  struct cli_state *cli,
997                                  const char *mask,
998                                  uint32_t attribute,
999                                  uint16_t info_level,
1000                                  bool posix)
1001 {
1002         struct tevent_req *req = NULL;
1003         struct cli_list_state *state;
1004         enum protocol_types proto = smbXcli_conn_protocol(cli->conn);
1005
1006         req = tevent_req_create(mem_ctx, &state, struct cli_list_state);
1007         if (req == NULL) {
1008                 return NULL;
1009         }
1010         state->ev = ev;
1011
1012         if (proto >= PROTOCOL_SMB2_02) {
1013                 state->subreq = cli_smb2_list_send(state, ev, cli, mask,
1014                                                    info_level, posix);
1015                 state->recv_fn = cli_smb2_list_recv;
1016         } else if (proto >= PROTOCOL_LANMAN2) {
1017                 state->subreq = cli_list_trans_send(
1018                         state, ev, cli, mask, attribute, info_level);
1019                 state->recv_fn = cli_list_trans_recv;
1020         } else {
1021                 state->subreq = cli_list_old_send(
1022                         state, ev, cli, mask, attribute);
1023                 state->recv_fn = cli_list_old_recv;
1024         }
1025         if (tevent_req_nomem(state->subreq, req)) {
1026                 return tevent_req_post(req, ev);
1027         }
1028         tevent_req_set_callback(state->subreq, cli_list_done, req);
1029         return req;
1030 }
1031
1032 static void cli_list_done(struct tevent_req *subreq)
1033 {
1034         struct tevent_req *req = tevent_req_callback_data(
1035                 subreq, struct tevent_req);
1036         struct cli_list_state *state = tevent_req_data(
1037                 req, struct cli_list_state);
1038         NTSTATUS status;
1039
1040         SMB_ASSERT(subreq == state->subreq);
1041
1042         /*
1043          * We don't want to be called by the lowerlevel routines
1044          * from within state->recv_fn()
1045          */
1046         tevent_req_set_callback(subreq, NULL, NULL);
1047
1048         status = state->recv_fn(subreq, state, &state->finfo);
1049         if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
1050                 /* We'll get back here */
1051                 tevent_req_set_callback(subreq, cli_list_done, req);
1052                 return;
1053         }
1054
1055         if (tevent_req_nterror(req, status)) {
1056                 return;
1057         }
1058         tevent_req_notify_callback(req);
1059 }
1060
1061 NTSTATUS cli_list_recv(
1062         struct tevent_req *req,
1063         TALLOC_CTX *mem_ctx,
1064         struct file_info **pfinfo)
1065 {
1066         struct cli_list_state *state = tevent_req_data(
1067                 req, struct cli_list_state);
1068         size_t num_results;
1069         struct file_info *finfo = NULL;
1070         NTSTATUS status;
1071         bool in_progress;
1072
1073         in_progress = tevent_req_is_in_progress(req);
1074
1075         if (!in_progress) {
1076                 if (!tevent_req_is_nterror(req, &status)) {
1077                         status = NT_STATUS_NO_MORE_FILES;
1078                 }
1079                 return status;
1080         }
1081
1082         if (state->finfo == NULL) {
1083                 status = state->recv_fn(state->subreq, state, &state->finfo);
1084
1085                 if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
1086                         tevent_req_set_callback(
1087                                 state->subreq, cli_list_done, req);
1088                         return NT_STATUS_RETRY;
1089                 }
1090
1091                 if (NT_STATUS_IS_OK(status) && (state->finfo == NULL)) {
1092                         status = NT_STATUS_NO_MORE_FILES;
1093                 }
1094
1095                 if (tevent_req_nterror(req, status)) {
1096                         return status;
1097                 }
1098
1099                 state->num_received = 0;
1100         }
1101
1102         num_results = talloc_array_length(state->finfo);
1103
1104         if (num_results == 1) {
1105                 finfo = talloc_move(mem_ctx, &state->finfo);
1106         } else {
1107                 struct file_info *src_finfo =
1108                         &state->finfo[state->num_received];
1109
1110                 finfo = talloc(mem_ctx, struct file_info);
1111                 if (finfo == NULL) {
1112                         return NT_STATUS_NO_MEMORY;
1113                 }
1114                 *finfo = *src_finfo;
1115                 finfo->name = talloc_move(finfo, &src_finfo->name);
1116                 finfo->short_name = talloc_move(finfo, &src_finfo->short_name);
1117         }
1118
1119         state->num_received += 1;
1120
1121         if (state->num_received == num_results) {
1122                 TALLOC_FREE(state->finfo);
1123         }
1124
1125         tevent_req_defer_callback(req, state->ev);
1126         tevent_req_notify_callback(req);
1127
1128         *pfinfo = finfo;
1129         return NT_STATUS_OK;
1130 }
1131
1132 struct cli_list_sync_state {
1133         const char *mask;
1134         uint32_t attribute;
1135         NTSTATUS (*fn)(struct file_info *finfo,
1136                        const char *mask,
1137                        void *private_data);
1138         void *private_data;
1139         NTSTATUS status;
1140         bool processed_file;
1141 };
1142
1143 static void cli_list_sync_cb(struct tevent_req *subreq)
1144 {
1145         struct cli_list_sync_state *state =
1146                 tevent_req_callback_data_void(subreq);
1147         struct file_info *finfo;
1148         bool ok;
1149
1150         state->status = cli_list_recv(subreq, talloc_tos(), &finfo);
1151         /* No TALLOC_FREE(subreq), we get here more than once */
1152
1153         if (NT_STATUS_EQUAL(state->status, NT_STATUS_RETRY)) {
1154                 /*
1155                  * The lowlevel SMB call was rearmed, we'll get back
1156                  * here when it's done.
1157                  */
1158                 state->status = NT_STATUS_OK;
1159                 return;
1160         }
1161
1162         if (!NT_STATUS_IS_OK(state->status)) {
1163                 return;
1164         }
1165
1166         ok = dir_check_ftype(finfo->attr, state->attribute);
1167         if (!ok) {
1168                 /*
1169                  * Only process if attributes match.  On SMB1 server
1170                  * does this, so on SMB2 we need to emulate in the
1171                  * client.
1172                  *
1173                  * https://bugzilla.samba.org/show_bug.cgi?id=10260
1174                  */
1175                 return;
1176         }
1177
1178         state->status = state->fn(finfo, state->mask, state->private_data);
1179
1180         state->processed_file = true;
1181
1182         TALLOC_FREE(finfo);
1183 }
1184
1185 NTSTATUS cli_list(struct cli_state *cli,
1186                   const char *mask,
1187                   uint32_t attribute,
1188                   NTSTATUS (*fn)(struct file_info *finfo,
1189                                  const char *mask,
1190                                  void *private_data),
1191                   void *private_data)
1192 {
1193         TALLOC_CTX *frame = NULL;
1194         struct cli_list_sync_state state = {
1195                 .mask = mask,
1196                 .attribute = attribute,
1197                 .fn = fn,
1198                 .private_data = private_data,
1199         };
1200         struct tevent_context *ev;
1201         struct tevent_req *req;
1202         NTSTATUS status = NT_STATUS_NO_MEMORY;
1203         uint16_t info_level;
1204         enum protocol_types proto = smbXcli_conn_protocol(cli->conn);
1205
1206         frame = talloc_stackframe();
1207
1208         if (smbXcli_conn_has_async_calls(cli->conn)) {
1209                 /*
1210                  * Can't use sync call while an async call is in flight
1211                  */
1212                 status = NT_STATUS_INVALID_PARAMETER;
1213                 goto fail;
1214         }
1215         ev = samba_tevent_context_init(frame);
1216         if (ev == NULL) {
1217                 goto fail;
1218         }
1219
1220         if (proto >= PROTOCOL_SMB2_02) {
1221                 info_level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO;
1222         } else {
1223                 info_level = (smb1cli_conn_capabilities(cli->conn) & CAP_NT_SMBS)
1224                         ? SMB_FIND_FILE_BOTH_DIRECTORY_INFO : SMB_FIND_INFO_STANDARD;
1225         }
1226
1227         req = cli_list_send(frame, ev, cli, mask, attribute, info_level, false);
1228         if (req == NULL) {
1229                 goto fail;
1230         }
1231         tevent_req_set_callback(req, cli_list_sync_cb, &state);
1232
1233         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1234                 goto fail;
1235         }
1236
1237         status = state.status;
1238
1239         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_FILES)) {
1240                 status = NT_STATUS_OK;
1241         }
1242
1243         if (NT_STATUS_IS_OK(status) && !state.processed_file) {
1244                 status = NT_STATUS_NO_SUCH_FILE;
1245         }
1246
1247  fail:
1248         TALLOC_FREE(frame);
1249         return status;
1250 }