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