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