LCOV - code coverage report
Current view: top level - source3/libsmb - clilist.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 366 634 57.7 %
Date: 2024-04-21 15:09:00 Functions: 16 18 88.9 %

          Line data    Source code
       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       90997 : static NTSTATUS is_bad_name(bool windows_names, const char *name)
      32             : {
      33       90997 :         const char *bad_name_p = NULL;
      34             : 
      35       90997 :         bad_name_p = strchr(name, '/');
      36       90997 :         if (bad_name_p != NULL) {
      37             :                 /*
      38             :                  * Windows and POSIX names can't have '/'.
      39             :                  * Server is attacking us.
      40             :                  */
      41           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
      42             :         }
      43       90997 :         if (windows_names) {
      44       90861 :                 bad_name_p = strchr(name, '\\');
      45       90861 :                 if (bad_name_p != NULL) {
      46             :                         /*
      47             :                          * Windows names can't have '\\'.
      48             :                          * Server is attacking us.
      49             :                          */
      50           0 :                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
      51             :                 }
      52             :         }
      53       90997 :         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       64794 : NTSTATUS is_bad_finfo_name(const struct cli_state *cli,
      62             :                         const struct file_info *finfo)
      63             : {
      64       64794 :         NTSTATUS status = NT_STATUS_OK;
      65       64794 :         bool windows_names = true;
      66             : 
      67       64794 :         if (cli->requested_posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
      68         136 :                 windows_names = false;
      69             :         }
      70       64794 :         if (finfo->name != NULL) {
      71       64794 :                 status = is_bad_name(windows_names, finfo->name);
      72       64794 :                 if (!NT_STATUS_IS_OK(status)) {
      73           0 :                         DBG_ERR("bad finfo->name\n");
      74           0 :                         return status;
      75             :                 }
      76             :         }
      77       64794 :         if (finfo->short_name != NULL) {
      78       26203 :                 status = is_bad_name(windows_names, finfo->short_name);
      79       26203 :                 if (!NT_STATUS_IS_OK(status)) {
      80           0 :                         DBG_ERR("bad finfo->short_name\n");
      81           0 :                         return status;
      82             :                 }
      83             :         }
      84       64794 :         return NT_STATUS_OK;
      85             : }
      86             : 
      87             : /****************************************************************************
      88             :  Calculate a safe next_entry_offset.
      89             : ****************************************************************************/
      90             : 
      91        9245 : static size_t calc_next_entry_offset(const char *base, const char *pdata_end)
      92             : {
      93        9245 :         size_t next_entry_offset = (size_t)IVAL(base,0);
      94             : 
      95        9245 :         if (next_entry_offset == 0 ||
      96        9245 :                         base + next_entry_offset < base ||
      97        9245 :                         base + next_entry_offset > pdata_end) {
      98           0 :                 next_entry_offset = pdata_end - base;
      99             :         }
     100        9245 :         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        9245 : 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           0 :         int len;
     123           0 :         size_t ret;
     124        9245 :         const char *base = p;
     125             : 
     126        9245 :         data_blob_free(p_last_name_raw);
     127             : 
     128        9245 :         if (p_resume_key) {
     129        9245 :                 *p_resume_key = 0;
     130             :         }
     131        9245 :         ZERO_STRUCTP(finfo);
     132             : 
     133        9245 :         switch (level) {
     134           0 :                 case SMB_FIND_INFO_STANDARD: /* OS/2 understands this */
     135             :                         /* these dates are converted to GMT by
     136             :                            make_unix_date */
     137           0 :                         if (pdata_end - base < 27) {
     138           0 :                                 return pdata_end - base;
     139             :                         }
     140             :                         /*
     141             :                          * What we're returning here as ctime_ts is
     142             :                          * actually the server create time.
     143             :                          */
     144           0 :                         finfo->btime_ts = convert_time_t_to_timespec(
     145           0 :                                 make_unix_date2(p+4,
     146             :                                         smb1cli_conn_server_time_zone(
     147             :                                                 cli->conn)));
     148           0 :                         finfo->ctime_ts = convert_time_t_to_timespec(
     149           0 :                                 make_unix_date2(p+4, smb1cli_conn_server_time_zone(cli->conn)));
     150           0 :                         finfo->atime_ts = convert_time_t_to_timespec(
     151           0 :                                 make_unix_date2(p+8, smb1cli_conn_server_time_zone(cli->conn)));
     152           0 :                         finfo->mtime_ts = convert_time_t_to_timespec(
     153           0 :                                 make_unix_date2(p+12, smb1cli_conn_server_time_zone(cli->conn)));
     154           0 :                         finfo->size = IVAL(p,16);
     155           0 :                         finfo->attr = SVAL(p,24);
     156           0 :                         len = CVAL(p, 26);
     157           0 :                         p += 27;
     158           0 :                         if (recv_flags2 & FLAGS2_UNICODE_STRINGS) {
     159           0 :                                 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           0 :                         if (p + len > pdata_end) {
     173           0 :                                 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           0 :                         ret = pull_string_talloc(ctx,
     181             :                                                  base_ptr,
     182             :                                                  recv_flags2,
     183             :                                                  &finfo->name,
     184             :                                                  p,
     185           0 :                                                  len+2,
     186             :                                                  STR_TERMINATE);
     187           0 :                         if (ret == (size_t)-1) {
     188           0 :                                 return pdata_end - base;
     189             :                         }
     190           0 :                         p += ret;
     191           0 :                         return PTR_DIFF(p, base);
     192             : 
     193           0 :                 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           0 :                         if (pdata_end - base < 31) {
     197           0 :                                 return pdata_end - base;
     198             :                         }
     199             :                         /*
     200             :                          * What we're returning here as ctime_ts is
     201             :                          * actually the server create time.
     202             :                          */
     203           0 :                         finfo->btime_ts = convert_time_t_to_timespec(
     204           0 :                                 make_unix_date2(p+4,
     205             :                                         smb1cli_conn_server_time_zone(
     206             :                                                 cli->conn)));
     207           0 :                         finfo->ctime_ts = convert_time_t_to_timespec(
     208           0 :                                 make_unix_date2(p+4, smb1cli_conn_server_time_zone(cli->conn)));
     209           0 :                         finfo->atime_ts = convert_time_t_to_timespec(
     210           0 :                                 make_unix_date2(p+8, smb1cli_conn_server_time_zone(cli->conn)));
     211           0 :                         finfo->mtime_ts = convert_time_t_to_timespec(
     212           0 :                                 make_unix_date2(p+12, smb1cli_conn_server_time_zone(cli->conn)));
     213           0 :                         finfo->size = IVAL(p,16);
     214           0 :                         finfo->attr = SVAL(p,24);
     215           0 :                         len = CVAL(p, 30);
     216           0 :                         p += 31;
     217             :                         /* check for unisys! */
     218           0 :                         if (p + len + 1 > pdata_end) {
     219           0 :                                 return pdata_end - base;
     220             :                         }
     221           0 :                         ret = pull_string_talloc(ctx,
     222             :                                                  base_ptr,
     223             :                                                  recv_flags2,
     224             :                                                  &finfo->name,
     225             :                                                  p,
     226             :                                                  len,
     227             :                                                  STR_NOALIGN);
     228           0 :                         if (ret == (size_t)-1) {
     229           0 :                                 return pdata_end - base;
     230             :                         }
     231           0 :                         p += ret;
     232           0 :                         return PTR_DIFF(p, base) + 1;
     233             : 
     234        9245 :                 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: /* NT uses this, but also accepts 2 */
     235             :                 {
     236           0 :                         size_t namelen, slen;
     237             : 
     238        9245 :                         if (pdata_end - base < 94) {
     239           0 :                                 return pdata_end - base;
     240             :                         }
     241             : 
     242        9245 :                         p += 4; /* next entry offset */
     243             : 
     244        9245 :                         if (p_resume_key) {
     245        9245 :                                 *p_resume_key = IVAL(p,0);
     246             :                         }
     247        9245 :                         p += 4; /* fileindex */
     248             : 
     249             :                         /* Offset zero is "create time", not "change time". */
     250        9245 :                         p += 8;
     251        9245 :                         finfo->atime_ts = interpret_long_date(BVAL(p, 0));
     252        9245 :                         p += 8;
     253        9245 :                         finfo->mtime_ts = interpret_long_date(BVAL(p, 0));
     254        9245 :                         p += 8;
     255        9245 :                         finfo->ctime_ts = interpret_long_date(BVAL(p, 0));
     256        9245 :                         p += 8;
     257        9245 :                         finfo->size = IVAL2_TO_SMB_BIG_UINT(p,0);
     258        9245 :                         p += 8;
     259        9245 :                         p += 8; /* alloc size */
     260        9245 :                         finfo->attr = IVAL(p,0);
     261        9245 :                         p += 4;
     262        9245 :                         namelen = IVAL(p,0);
     263        9245 :                         p += 4;
     264        9245 :                         p += 4; /* EA size */
     265        9245 :                         slen = CVAL(p, 0);
     266        9245 :                         if (slen > 24) {
     267             :                                 /* Bad short name length. */
     268           0 :                                 return pdata_end - base;
     269             :                         }
     270        9245 :                         p += 2;
     271        9245 :                         ret = pull_string_talloc(ctx,
     272             :                                                  base_ptr,
     273             :                                                  recv_flags2,
     274             :                                                  &finfo->short_name,
     275             :                                                  p,
     276             :                                                  slen,
     277             :                                                  STR_UNICODE);
     278        9245 :                         if (ret == (size_t)-1) {
     279           0 :                                 return pdata_end - base;
     280             :                         }
     281        9245 :                         p += 24; /* short name? */
     282        9245 :                         if (p + namelen < p || p + namelen > pdata_end) {
     283           0 :                                 return pdata_end - base;
     284             :                         }
     285        9245 :                         ret = pull_string_talloc(ctx,
     286             :                                                  base_ptr,
     287             :                                                  recv_flags2,
     288             :                                                  &finfo->name,
     289             :                                                  p,
     290             :                                                  namelen,
     291             :                                                  0);
     292        9245 :                         if (ret == (size_t)-1) {
     293           0 :                                 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        9245 :                         if (p_last_name_raw) {
     302        9245 :                                 *p_last_name_raw = data_blob(NULL, namelen+2);
     303        9245 :                                 memcpy(p_last_name_raw->data, p, namelen);
     304        9245 :                                 SSVAL(p_last_name_raw->data, namelen, 0);
     305             :                         }
     306        9245 :                         return calc_next_entry_offset(base, pdata_end);
     307             :                 }
     308             :         }
     309             : 
     310           0 :         DEBUG(1,("Unknown long filename format %d\n",level));
     311           0 :         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         131 : static bool interpret_short_filename(TALLOC_CTX *ctx,
     320             :                                 struct cli_state *cli,
     321             :                                 char *p,
     322             :                                 struct file_info *finfo)
     323             : {
     324           0 :         size_t ret;
     325         131 :         ZERO_STRUCTP(finfo);
     326             : 
     327         131 :         finfo->attr = CVAL(p,21);
     328             : 
     329             :         /* We don't get birth time. */
     330         131 :         finfo->btime_ts.tv_sec = 0;
     331         131 :         finfo->btime_ts.tv_nsec = 0;
     332             :         /* this date is converted to GMT by make_unix_date */
     333         131 :         finfo->ctime_ts.tv_sec = make_unix_date(p+22, smb1cli_conn_server_time_zone(cli->conn));
     334         131 :         finfo->ctime_ts.tv_nsec = 0;
     335         131 :         finfo->mtime_ts.tv_sec = finfo->atime_ts.tv_sec = finfo->ctime_ts.tv_sec;
     336         131 :         finfo->mtime_ts.tv_nsec = finfo->atime_ts.tv_nsec = 0;
     337         131 :         finfo->size = IVAL(p,26);
     338         131 :         ret = pull_string_talloc(ctx,
     339             :                                  NULL,
     340             :                                  0,
     341             :                                  &finfo->name,
     342         131 :                                  p+30,
     343             :                                  12,
     344             :                                  STR_ASCII);
     345         131 :         if (ret == (size_t)-1) {
     346           0 :                 return false;
     347             :         }
     348             : 
     349         131 :         if (finfo->name) {
     350         131 :                 finfo->short_name = talloc_strdup(ctx, finfo->name);
     351         131 :                 if (finfo->short_name == NULL) {
     352           0 :                         return false;
     353             :                 }
     354             :         }
     355         131 :         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           2 : 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           0 :         struct tevent_req *req, *subreq;
     380           0 :         struct cli_list_old_state *state;
     381           0 :         uint8_t *bytes;
     382           0 :         static const uint16_t zero = 0;
     383           0 :         uint32_t usable_space;
     384             : 
     385           2 :         req = tevent_req_create(mem_ctx, &state, struct cli_list_old_state);
     386           2 :         if (req == NULL) {
     387           0 :                 return NULL;
     388             :         }
     389           2 :         state->ev = ev;
     390           2 :         state->cli = cli;
     391           2 :         state->attribute = attribute;
     392           2 :         state->first = true;
     393           2 :         state->mask = talloc_strdup(state, mask);
     394           2 :         if (tevent_req_nomem(state->mask, req)) {
     395           0 :                 return tevent_req_post(req, ev);
     396             :         }
     397           2 :         state->mask = smb1_dfs_share_path(state, cli, state->mask);
     398           2 :         if (tevent_req_nomem(state->mask, req)) {
     399           0 :                 return tevent_req_post(req, ev);
     400             :         }
     401           2 :         usable_space = cli_state_available_size(cli, 100);
     402           2 :         state->num_asked = usable_space / DIR_STRUCT_SIZE;
     403             : 
     404           2 :         SSVAL(state->vwv + 0, 0, state->num_asked);
     405           2 :         SSVAL(state->vwv + 1, 0, state->attribute);
     406             : 
     407           2 :         bytes = talloc_array(state, uint8_t, 1);
     408           2 :         if (tevent_req_nomem(bytes, req)) {
     409           0 :                 return tevent_req_post(req, ev);
     410             :         }
     411           2 :         bytes[0] = 4;
     412           2 :         bytes = smb_bytes_push_str(bytes,
     413           2 :                                    smbXcli_conn_use_unicode(cli->conn),
     414           2 :                                    state->mask,
     415           2 :                                    strlen(state->mask)+1,
     416             :                                    NULL);
     417             : 
     418           2 :         bytes = smb_bytes_push_bytes(bytes, 5, (const uint8_t *)&zero, 2);
     419           2 :         if (tevent_req_nomem(bytes, req)) {
     420           0 :                 return tevent_req_post(req, ev);
     421             :         }
     422             : 
     423           2 :         subreq = cli_smb_send(state, state->ev, state->cli, SMBsearch, 0, 0,
     424           2 :                         2, state->vwv, talloc_get_size(bytes), bytes);
     425           2 :         if (tevent_req_nomem(subreq, req)) {
     426           0 :                 return tevent_req_post(req, ev);
     427             :         }
     428           2 :         tevent_req_set_callback(subreq, cli_list_old_done, req);
     429           2 :         return req;
     430             : }
     431             : 
     432           6 : static void cli_list_old_done(struct tevent_req *subreq)
     433             : {
     434           6 :         struct tevent_req *req = tevent_req_callback_data(
     435             :                 subreq, struct tevent_req);
     436           6 :         struct cli_list_old_state *state = tevent_req_data(
     437             :                 req, struct cli_list_old_state);
     438           0 :         NTSTATUS status;
     439           0 :         uint8_t cmd;
     440           0 :         uint8_t wct;
     441           0 :         uint16_t *vwv;
     442           0 :         uint32_t num_bytes;
     443           0 :         uint8_t *bytes;
     444           0 :         uint16_t received;
     445           0 :         size_t dirlist_len;
     446           0 :         uint8_t *tmp;
     447             : 
     448           6 :         status = cli_smb_recv(subreq, state, NULL, 0, &wct, &vwv, &num_bytes,
     449             :                               &bytes);
     450           6 :         if (!NT_STATUS_IS_OK(status)
     451           0 :             && !NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRnofiles))
     452           0 :             && !NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
     453           0 :                 TALLOC_FREE(subreq);
     454           0 :                 tevent_req_nterror(req, status);
     455           0 :                 return;
     456             :         }
     457           6 :         if (NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRnofiles))
     458           6 :             || NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
     459           0 :                 received = 0;
     460             :         } else {
     461           6 :                 if (wct < 1) {
     462           0 :                         TALLOC_FREE(subreq);
     463           0 :                         tevent_req_nterror(
     464             :                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
     465           0 :                         return;
     466             :                 }
     467           6 :                 received = SVAL(vwv + 0, 0);
     468             :         }
     469             : 
     470           6 :         if (received > 0) {
     471             :                 /*
     472             :                  * I don't think this can wrap. received is
     473             :                  * initialized from a 16-bit value.
     474             :                  */
     475           2 :                 if (num_bytes < ((uint32_t)received * DIR_STRUCT_SIZE + 3)) {
     476           0 :                         TALLOC_FREE(subreq);
     477           0 :                         tevent_req_nterror(
     478             :                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
     479           0 :                         return;
     480             :                 }
     481             : 
     482           2 :                 dirlist_len = talloc_get_size(state->dirlist);
     483             : 
     484           2 :                 tmp = talloc_realloc(
     485             :                         state, state->dirlist, uint8_t,
     486             :                         dirlist_len + received * DIR_STRUCT_SIZE);
     487           2 :                 if (tevent_req_nomem(tmp, req)) {
     488           0 :                         return;
     489             :                 }
     490           2 :                 state->dirlist = tmp;
     491           2 :                 memcpy(state->dirlist + dirlist_len, bytes + 3,
     492           2 :                        received * DIR_STRUCT_SIZE);
     493             : 
     494           2 :                 SSVAL(state->search_status, 0, 21);
     495           2 :                 memcpy(state->search_status + 2,
     496           2 :                        bytes + 3 + (received-1)*DIR_STRUCT_SIZE, 21);
     497           2 :                 cmd = SMBsearch;
     498             :         } else {
     499           4 :                 if (state->first || state->done) {
     500           2 :                         tevent_req_done(req);
     501           2 :                         return;
     502             :                 }
     503           2 :                 state->done = true;
     504           2 :                 state->num_asked = 0;
     505           2 :                 cmd = SMBfclose;
     506             :         }
     507           4 :         TALLOC_FREE(subreq);
     508             : 
     509           4 :         state->first = false;
     510             : 
     511           4 :         SSVAL(state->vwv + 0, 0, state->num_asked);
     512           4 :         SSVAL(state->vwv + 1, 0, state->attribute);
     513             : 
     514           4 :         bytes = talloc_array(state, uint8_t, 1);
     515           4 :         if (tevent_req_nomem(bytes, req)) {
     516           0 :                 return;
     517             :         }
     518           4 :         bytes[0] = 4;
     519           4 :         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(state->cli->conn), "",
     520             :                                    1, NULL);
     521           4 :         bytes = smb_bytes_push_bytes(bytes, 5, state->search_status,
     522             :                                      sizeof(state->search_status));
     523           4 :         if (tevent_req_nomem(bytes, req)) {
     524           0 :                 return;
     525             :         }
     526           8 :         subreq = cli_smb_send(state, state->ev, state->cli, cmd, 0, 0,
     527           4 :                               2, state->vwv, talloc_get_size(bytes), bytes);
     528           4 :         if (tevent_req_nomem(subreq, req)) {
     529           0 :                 return;
     530             :         }
     531           4 :         tevent_req_set_callback(subreq, cli_list_old_done, req);
     532             : }
     533             : 
     534           4 : static NTSTATUS cli_list_old_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     535             :                                   struct file_info **pfinfo)
     536             : {
     537           4 :         struct cli_list_old_state *state = tevent_req_data(
     538             :                 req, struct cli_list_old_state);
     539           0 :         NTSTATUS status;
     540           0 :         size_t i, num_received;
     541           0 :         struct file_info *finfo;
     542             : 
     543           4 :         if (tevent_req_is_nterror(req, &status)) {
     544           0 :                 return status;
     545             :         }
     546             : 
     547           4 :         if (state->dirlist == NULL) {
     548           2 :                 *pfinfo = NULL;
     549           2 :                 return NT_STATUS_OK;
     550             :         }
     551             : 
     552           2 :         num_received = talloc_array_length(state->dirlist) / DIR_STRUCT_SIZE;
     553             : 
     554           2 :         finfo = talloc_array(mem_ctx, struct file_info, num_received);
     555           2 :         if (finfo == NULL) {
     556           0 :                 return NT_STATUS_NO_MEMORY;
     557             :         }
     558             : 
     559         133 :         for (i=0; i<num_received; i++) {
     560         131 :                 if (!interpret_short_filename(
     561             :                             finfo, state->cli,
     562         131 :                             (char *)state->dirlist + i * DIR_STRUCT_SIZE,
     563         131 :                             &finfo[i])) {
     564           0 :                         TALLOC_FREE(finfo);
     565           0 :                         return NT_STATUS_NO_MEMORY;
     566             :                 }
     567         131 :                 if (finfo->name == NULL) {
     568           0 :                         TALLOC_FREE(finfo);
     569           0 :                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
     570             :                 }
     571         131 :                 status = is_bad_finfo_name(state->cli, finfo);
     572         131 :                 if (!NT_STATUS_IS_OK(status)) {
     573           0 :                         smbXcli_conn_disconnect(state->cli->conn, status);
     574           0 :                         TALLOC_FREE(finfo);
     575           0 :                         return status;
     576             :                 }
     577             :         }
     578           2 :         TALLOC_FREE(state->dirlist);
     579           2 :         *pfinfo = finfo;
     580           2 :         return NT_STATUS_OK;
     581             : }
     582             : 
     583           0 : 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           0 :         TALLOC_CTX *frame = talloc_stackframe();
     589           0 :         struct tevent_context *ev;
     590           0 :         struct tevent_req *req;
     591           0 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     592           0 :         struct file_info *finfo = NULL;
     593           0 :         size_t i, num_finfo;
     594             : 
     595           0 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
     596             :                 /*
     597             :                  * Can't use sync call while an async call is in flight
     598             :                  */
     599           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     600           0 :                 goto fail;
     601             :         }
     602           0 :         ev = samba_tevent_context_init(frame);
     603           0 :         if (ev == NULL) {
     604           0 :                 goto fail;
     605             :         }
     606           0 :         req = cli_list_old_send(frame, ev, cli, mask, attribute);
     607           0 :         if (req == NULL) {
     608           0 :                 goto fail;
     609             :         }
     610           0 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     611           0 :                 goto fail;
     612             :         }
     613           0 :         status = cli_list_old_recv(req, frame, &finfo);
     614           0 :         if (!NT_STATUS_IS_OK(status)) {
     615           0 :                 goto fail;
     616             :         }
     617           0 :         num_finfo = talloc_array_length(finfo);
     618           0 :         for (i=0; i<num_finfo; i++) {
     619           0 :                 status = fn(&finfo[i], mask, state);
     620           0 :                 if (!NT_STATUS_IS_OK(status)) {
     621           0 :                         goto fail;
     622             :                 }
     623             :         }
     624           0 :  fail:
     625           0 :         TALLOC_FREE(frame);
     626           0 :         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        2225 : 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           0 :         struct tevent_req *req, *subreq;
     660           0 :         struct cli_list_trans_state *state;
     661           0 :         size_t param_len;
     662        2225 :         uint16_t additional_flags2 = 0;
     663             : 
     664        2225 :         req = tevent_req_create(mem_ctx, &state,
     665             :                                 struct cli_list_trans_state);
     666        2225 :         if (req == NULL) {
     667           0 :                 return NULL;
     668             :         }
     669        2225 :         state->ev = ev;
     670        2225 :         state->cli = cli;
     671        2225 :         state->mask = talloc_strdup(state, mask);
     672        2225 :         if (tevent_req_nomem(state->mask, req)) {
     673           0 :                 return tevent_req_post(req, ev);
     674             :         }
     675        2225 :         state->mask = smb1_dfs_share_path(state, cli, state->mask);
     676        2225 :         if (tevent_req_nomem(state->mask, req)) {
     677           0 :                 return tevent_req_post(req, ev);
     678             :         }
     679        2225 :         state->attribute = attribute;
     680        2225 :         state->info_level = info_level;
     681        2225 :         state->loop_count = 0;
     682        2225 :         state->first = true;
     683             : 
     684        2225 :         state->max_matches = 1366; /* Match W2k */
     685             : 
     686        2225 :         SSVAL(&state->setup[0], 0, TRANSACT2_FINDFIRST);
     687             : 
     688        2225 :         state->param = talloc_array(state, uint8_t, 12);
     689        2225 :         if (tevent_req_nomem(state->param, req)) {
     690           0 :                 return tevent_req_post(req, ev);
     691             :         }
     692             : 
     693        2225 :         SSVAL(state->param, 0, state->attribute);
     694        2225 :         SSVAL(state->param, 2, state->max_matches);
     695        2225 :         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        2225 :         SSVAL(state->param, 6, state->info_level);
     700        2225 :         SIVAL(state->param, 8, 0);
     701             : 
     702        2225 :         state->param = trans2_bytes_push_str(state->param, smbXcli_conn_use_unicode(cli->conn),
     703        2225 :                                              state->mask, strlen(state->mask)+1,
     704             :                                              NULL);
     705        2225 :         if (tevent_req_nomem(state->param, req)) {
     706           0 :                 return tevent_req_post(req, ev);
     707             :         }
     708             : 
     709        2225 :         if (clistr_is_previous_version_path(state->mask)) {
     710          68 :                 additional_flags2 = FLAGS2_REPARSE_PATH;
     711             :         }
     712             : 
     713        2225 :         param_len = talloc_get_size(state->param);
     714             : 
     715        2225 :         subreq = cli_trans_send(state, state->ev, state->cli, additional_flags2,
     716             :                                 SMBtrans2, NULL, -1, 0, 0,
     717        2225 :                                 state->setup, 1, 0,
     718        2225 :                                 state->param, param_len, 10,
     719             :                                 NULL, 0, CLI_BUFFER_SIZE);
     720        2225 :         if (tevent_req_nomem(subreq, req)) {
     721           0 :                 return tevent_req_post(req, ev);
     722             :         }
     723        2225 :         tevent_req_set_callback(subreq, cli_list_trans_done, req);
     724        2225 :         return req;
     725             : }
     726             : 
     727        2225 : static void cli_list_trans_done(struct tevent_req *subreq)
     728             : {
     729        2225 :         struct tevent_req *req = tevent_req_callback_data(
     730             :                 subreq, struct tevent_req);
     731        2225 :         struct cli_list_trans_state *state = tevent_req_data(
     732             :                 req, struct cli_list_trans_state);
     733           0 :         NTSTATUS status;
     734           0 :         uint8_t *param;
     735           0 :         uint32_t num_param;
     736           0 :         uint8_t *data;
     737           0 :         char *data_end;
     738           0 :         uint32_t num_data;
     739           0 :         uint32_t min_param;
     740           0 :         struct file_info *tmp;
     741           0 :         size_t old_num_finfo;
     742           0 :         uint16_t recv_flags2;
     743           0 :         int ff_searchcount;
     744           0 :         bool ff_eos;
     745           0 :         char *p, *p2;
     746        2225 :         uint32_t resume_key = 0;
     747           0 :         int i;
     748           0 :         DATA_BLOB last_name_raw;
     749        2225 :         struct file_info *finfo = NULL;
     750           0 :         size_t param_len;
     751        2225 :         uint16_t additional_flags2 = 0;
     752             : 
     753        2225 :         min_param = (state->first ? 6 : 4);
     754             : 
     755        2225 :         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        2225 :         TALLOC_FREE(subreq);
     760        2225 :         if (!NT_STATUS_IS_OK(status)) {
     761             :                 /*
     762             :                  * TODO: retry, OS/2 nofiles
     763             :                  */
     764         350 :                 tevent_req_nterror(req, status);
     765        2225 :                 return;
     766             :         }
     767             : 
     768        1875 :         if (state->first) {
     769        1875 :                 state->ff_dir_handle = SVAL(param, 0);
     770        1875 :                 ff_searchcount = SVAL(param, 2);
     771        1875 :                 ff_eos = SVAL(param, 4) != 0;
     772             :         } else {
     773           0 :                 ff_searchcount = SVAL(param, 0);
     774           0 :                 ff_eos = SVAL(param, 2) != 0;
     775             :         }
     776             : 
     777        1875 :         old_num_finfo = talloc_array_length(state->finfo);
     778             : 
     779        1875 :         tmp = talloc_realloc(state, state->finfo, struct file_info,
     780             :                                    old_num_finfo + ff_searchcount);
     781        1875 :         if (tevent_req_nomem(tmp, req)) {
     782           0 :                 return;
     783             :         }
     784        1875 :         state->finfo = tmp;
     785             : 
     786        1875 :         p2 = p = (char *)data;
     787        1875 :         data_end = (char *)data + num_data;
     788        1875 :         last_name_raw = data_blob_null;
     789             : 
     790       11118 :         for (i=0; i<ff_searchcount; i++) {
     791        9245 :                 if (p2 >= data_end) {
     792           0 :                         ff_eos = true;
     793           0 :                         break;
     794             :                 }
     795        9245 :                 if ((state->info_level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
     796        9245 :                     && (i == ff_searchcount-1)) {
     797             :                         /* Last entry - fixup the last offset length. */
     798        1875 :                         SIVAL(p2, 0, PTR_DIFF((data + num_data), p2));
     799             :                 }
     800             : 
     801        9245 :                 data_blob_free(&last_name_raw);
     802             : 
     803        9245 :                 finfo = &state->finfo[old_num_finfo + i];
     804             : 
     805       18490 :                 p2 += interpret_long_filename(
     806        9245 :                         state->finfo, /* Stick fname to the array as such */
     807        9245 :                         state->cli, state->info_level,
     808             :                         (char *)data, recv_flags2, p2,
     809             :                         data_end, finfo, &resume_key, &last_name_raw);
     810             : 
     811        9245 :                 if (finfo->name == NULL) {
     812           2 :                         DEBUG(1, ("cli_list: Error: unable to parse name from "
     813             :                                   "info level %d\n", state->info_level));
     814           2 :                         tevent_req_nterror(req,
     815             :                                 NT_STATUS_INVALID_NETWORK_RESPONSE);
     816           2 :                         return;
     817             :                 }
     818             : 
     819        9243 :                 status = is_bad_finfo_name(state->cli, finfo);
     820        9243 :                 if (!NT_STATUS_IS_OK(status)) {
     821           0 :                         smbXcli_conn_disconnect(state->cli->conn, status);
     822           0 :                         tevent_req_nterror(req, status);
     823           0 :                         return;
     824             :                 }
     825             : 
     826        9243 :                 if (!state->first && (state->mask[0] != '\0') &&
     827           0 :                     strcsequal(finfo->name, state->mask)) {
     828           0 :                         DEBUG(1, ("Error: Looping in FIND_NEXT as name %s has "
     829             :                                   "already been seen?\n", finfo->name));
     830           0 :                         ff_eos = true;
     831           0 :                         break;
     832             :                 }
     833             :         }
     834             : 
     835        1873 :         if (ff_searchcount == 0) {
     836           0 :                 ff_eos = true;
     837             :         }
     838             : 
     839        1873 :         TALLOC_FREE(param);
     840        1873 :         TALLOC_FREE(data);
     841             : 
     842             :         /*
     843             :          * Shrink state->finfo to the real length we received
     844             :          */
     845        1873 :         tmp = talloc_realloc(state, state->finfo, struct file_info,
     846             :                                    old_num_finfo + i);
     847        1873 :         if (tevent_req_nomem(tmp, req)) {
     848           0 :                 return;
     849             :         }
     850        1873 :         state->finfo = tmp;
     851             : 
     852        1873 :         state->first = false;
     853             : 
     854        1873 :         if (ff_eos) {
     855        1873 :                 data_blob_free(&last_name_raw);
     856        1873 :                 tevent_req_done(req);
     857        1873 :                 return;
     858             :         }
     859             : 
     860           0 :         TALLOC_FREE(state->mask);
     861           0 :         state->mask = talloc_strdup(state, finfo->name);
     862           0 :         if (tevent_req_nomem(state->mask, req)) {
     863           0 :                 return;
     864             :         }
     865             : 
     866           0 :         SSVAL(&state->setup[0], 0, TRANSACT2_FINDNEXT);
     867             : 
     868           0 :         param = talloc_realloc(state, state->param, uint8_t, 12);
     869           0 :         if (tevent_req_nomem(param, req)) {
     870           0 :                 return;
     871             :         }
     872           0 :         state->param = param;
     873             : 
     874           0 :         SSVAL(param, 0, state->ff_dir_handle);
     875           0 :         SSVAL(param, 2, state->max_matches); /* max count */
     876           0 :         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           0 :         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           0 :         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           0 :         if (last_name_raw.length) {
     891           0 :                 state->param = trans2_bytes_push_bytes(state->param,
     892           0 :                                                        last_name_raw.data,
     893             :                                                        last_name_raw.length);
     894           0 :                 if (tevent_req_nomem(state->param, req)) {
     895           0 :                         return;
     896             :                 }
     897           0 :                 data_blob_free(&last_name_raw);
     898             :         } else {
     899           0 :                 state->param = trans2_bytes_push_str(state->param,
     900           0 :                                                      smbXcli_conn_use_unicode(state->cli->conn),
     901           0 :                                                      state->mask,
     902           0 :                                                      strlen(state->mask)+1,
     903             :                                                      NULL);
     904           0 :                 if (tevent_req_nomem(state->param, req)) {
     905           0 :                         return;
     906             :                 }
     907             :         }
     908           0 :         param_len = talloc_get_size(state->param);
     909             : 
     910           0 :         if (clistr_is_previous_version_path(state->mask)) {
     911           0 :                 additional_flags2 = FLAGS2_REPARSE_PATH;
     912             :         }
     913             : 
     914           0 :         subreq = cli_trans_send(state, state->ev, state->cli, additional_flags2,
     915             :                                 SMBtrans2, NULL, -1, 0, 0,
     916           0 :                                 state->setup, 1, 0,
     917             :                                 state->param, param_len, 10,
     918             :                                 NULL, 0, CLI_BUFFER_SIZE);
     919           0 :         if (tevent_req_nomem(subreq, req)) {
     920           0 :                 return;
     921             :         }
     922           0 :         tevent_req_set_callback(subreq, cli_list_trans_done, req);
     923             : }
     924             : 
     925        4098 : static NTSTATUS cli_list_trans_recv(struct tevent_req *req,
     926             :                                     TALLOC_CTX *mem_ctx,
     927             :                                     struct file_info **finfo)
     928             : {
     929        4098 :         struct cli_list_trans_state *state = tevent_req_data(
     930             :                 req, struct cli_list_trans_state);
     931           0 :         NTSTATUS status;
     932             : 
     933        4098 :         if (tevent_req_is_nterror(req, &status)) {
     934         352 :                 return status;
     935             :         }
     936        3746 :         *finfo = talloc_move(mem_ctx, &state->finfo);
     937        3746 :         return NT_STATUS_OK;
     938             : }
     939             : 
     940           0 : 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           0 :         TALLOC_CTX *frame = talloc_stackframe();
     949           0 :         struct tevent_context *ev;
     950           0 :         struct tevent_req *req;
     951           0 :         int i, num_finfo;
     952           0 :         struct file_info *finfo = NULL;
     953           0 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     954             : 
     955           0 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
     956             :                 /*
     957             :                  * Can't use sync call while an async call is in flight
     958             :                  */
     959           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     960           0 :                 goto fail;
     961             :         }
     962           0 :         ev = samba_tevent_context_init(frame);
     963           0 :         if (ev == NULL) {
     964           0 :                 goto fail;
     965             :         }
     966           0 :         req = cli_list_trans_send(frame, ev, cli, mask, attribute, info_level);
     967           0 :         if (req == NULL) {
     968           0 :                 goto fail;
     969             :         }
     970           0 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     971           0 :                 goto fail;
     972             :         }
     973           0 :         status = cli_list_trans_recv(req, frame, &finfo);
     974           0 :         if (!NT_STATUS_IS_OK(status)) {
     975           0 :                 goto fail;
     976             :         }
     977           0 :         num_finfo = talloc_array_length(finfo);
     978           0 :         for (i=0; i<num_finfo; i++) {
     979           0 :                 status = fn(&finfo[i], mask, private_data);
     980           0 :                 if (!NT_STATUS_IS_OK(status)) {
     981           0 :                         goto fail;
     982             :                 }
     983             :         }
     984           0 :  fail:
     985           0 :         TALLOC_FREE(frame);
     986           0 :         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       10933 : 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       10933 :         struct tevent_req *req = NULL;
    1008           0 :         struct cli_list_state *state;
    1009       10933 :         enum protocol_types proto = smbXcli_conn_protocol(cli->conn);
    1010             : 
    1011       10933 :         req = tevent_req_create(mem_ctx, &state, struct cli_list_state);
    1012       10933 :         if (req == NULL) {
    1013           0 :                 return NULL;
    1014             :         }
    1015       10933 :         state->ev = ev;
    1016             : 
    1017       10933 :         if (proto >= PROTOCOL_SMB2_02) {
    1018        8706 :                 state->subreq = cli_smb2_list_send(state, ev, cli, mask,
    1019             :                                                    info_level);
    1020        8706 :                 state->recv_fn = cli_smb2_list_recv;
    1021        2227 :         } else if (proto >= PROTOCOL_LANMAN2) {
    1022        2225 :                 state->subreq = cli_list_trans_send(
    1023             :                         state, ev, cli, mask, attribute, info_level);
    1024        2225 :                 state->recv_fn = cli_list_trans_recv;
    1025             :         } else {
    1026           2 :                 state->subreq = cli_list_old_send(
    1027             :                         state, ev, cli, mask, attribute);
    1028           2 :                 state->recv_fn = cli_list_old_recv;
    1029             :         }
    1030       10933 :         if (tevent_req_nomem(state->subreq, req)) {
    1031           0 :                 return tevent_req_post(req, ev);
    1032             :         }
    1033       10933 :         tevent_req_set_callback(state->subreq, cli_list_done, req);
    1034       10933 :         return req;
    1035             : }
    1036             : 
    1037       27556 : static void cli_list_done(struct tevent_req *subreq)
    1038             : {
    1039       27556 :         struct tevent_req *req = tevent_req_callback_data(
    1040             :                 subreq, struct tevent_req);
    1041       27556 :         struct cli_list_state *state = tevent_req_data(
    1042             :                 req, struct cli_list_state);
    1043           0 :         NTSTATUS status;
    1044             : 
    1045       27556 :         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       27556 :         tevent_req_set_callback(subreq, NULL, NULL);
    1052             : 
    1053       27556 :         status = state->recv_fn(subreq, state, &state->finfo);
    1054       27556 :         if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
    1055             :                 /* We'll get back here */
    1056        8426 :                 tevent_req_set_callback(subreq, cli_list_done, req);
    1057        8426 :                 return;
    1058             :         }
    1059             : 
    1060       19130 :         if (tevent_req_nterror(req, status)) {
    1061        9056 :                 return;
    1062             :         }
    1063       10074 :         tevent_req_notify_callback(req);
    1064             : }
    1065             : 
    1066       85797 : NTSTATUS cli_list_recv(
    1067             :         struct tevent_req *req,
    1068             :         TALLOC_CTX *mem_ctx,
    1069             :         struct file_info **pfinfo)
    1070             : {
    1071       85797 :         struct cli_list_state *state = tevent_req_data(
    1072             :                 req, struct cli_list_state);
    1073           0 :         size_t num_results;
    1074       85797 :         struct file_info *finfo = NULL;
    1075           0 :         NTSTATUS status;
    1076           0 :         bool in_progress;
    1077             : 
    1078       85797 :         in_progress = tevent_req_is_in_progress(req);
    1079             : 
    1080       85797 :         if (!in_progress) {
    1081       10933 :                 if (!tevent_req_is_nterror(req, &status)) {
    1082           0 :                         status = NT_STATUS_NO_MORE_FILES;
    1083             :                 }
    1084       10933 :                 return status;
    1085             :         }
    1086             : 
    1087       74864 :         if (state->finfo == NULL) {
    1088       57295 :                 status = state->recv_fn(state->subreq, state, &state->finfo);
    1089             : 
    1090       57295 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
    1091        8197 :                         tevent_req_set_callback(
    1092             :                                 state->subreq, cli_list_done, req);
    1093        8197 :                         return NT_STATUS_RETRY;
    1094             :                 }
    1095             : 
    1096       49098 :                 if (NT_STATUS_IS_OK(status) && (state->finfo == NULL)) {
    1097        1875 :                         status = NT_STATUS_NO_MORE_FILES;
    1098             :                 }
    1099             : 
    1100       49098 :                 if (tevent_req_nterror(req, status)) {
    1101        1877 :                         return status;
    1102             :                 }
    1103             : 
    1104       47221 :                 state->num_received = 0;
    1105             :         }
    1106             : 
    1107       64790 :         num_results = talloc_array_length(state->finfo);
    1108             : 
    1109       64790 :         if (num_results == 1) {
    1110       56110 :                 finfo = talloc_move(mem_ctx, &state->finfo);
    1111             :         } else {
    1112        8680 :                 struct file_info *src_finfo =
    1113        8680 :                         &state->finfo[state->num_received];
    1114             : 
    1115        8680 :                 finfo = talloc(mem_ctx, struct file_info);
    1116        8680 :                 if (finfo == NULL) {
    1117           0 :                         return NT_STATUS_NO_MEMORY;
    1118             :                 }
    1119        8680 :                 *finfo = *src_finfo;
    1120        8680 :                 finfo->name = talloc_move(finfo, &src_finfo->name);
    1121        8680 :                 finfo->short_name = talloc_move(finfo, &src_finfo->short_name);
    1122             :         }
    1123             : 
    1124       64790 :         state->num_received += 1;
    1125             : 
    1126       64790 :         if (state->num_received == num_results) {
    1127       57295 :                 TALLOC_FREE(state->finfo);
    1128             :         }
    1129             : 
    1130       64790 :         tevent_req_defer_callback(req, state->ev);
    1131       64790 :         tevent_req_notify_callback(req);
    1132             : 
    1133       64790 :         *pfinfo = finfo;
    1134       64790 :         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       66002 : static void cli_list_sync_cb(struct tevent_req *subreq)
    1149             : {
    1150           0 :         struct cli_list_sync_state *state =
    1151       66002 :                 tevent_req_callback_data_void(subreq);
    1152           0 :         struct file_info *finfo;
    1153           0 :         bool ok;
    1154             : 
    1155       66002 :         state->status = cli_list_recv(subreq, talloc_tos(), &finfo);
    1156             :         /* No TALLOC_FREE(subreq), we get here more than once */
    1157             : 
    1158       66002 :         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        4734 :                 state->status = NT_STATUS_OK;
    1164        4734 :                 return;
    1165             :         }
    1166             : 
    1167       61268 :         if (!NT_STATUS_IS_OK(state->status)) {
    1168        9345 :                 return;
    1169             :         }
    1170             : 
    1171       51923 :         ok = dir_check_ftype(finfo->attr, state->attribute);
    1172       51923 :         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           0 :                 return;
    1181             :         }
    1182             : 
    1183       51923 :         state->status = state->fn(finfo, state->mask, state->private_data);
    1184             : 
    1185       51923 :         state->processed_file = true;
    1186             : 
    1187       51923 :         TALLOC_FREE(finfo);
    1188             : }
    1189             : 
    1190        7468 : 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        7468 :         TALLOC_CTX *frame = NULL;
    1199        7468 :         struct cli_list_sync_state state = {
    1200             :                 .mask = mask,
    1201             :                 .attribute = attribute,
    1202             :                 .fn = fn,
    1203             :                 .private_data = private_data,
    1204             :         };
    1205           0 :         struct tevent_context *ev;
    1206           0 :         struct tevent_req *req;
    1207        7468 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    1208           0 :         uint16_t info_level;
    1209        7468 :         enum protocol_types proto = smbXcli_conn_protocol(cli->conn);
    1210             : 
    1211        7468 :         frame = talloc_stackframe();
    1212             : 
    1213        7468 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    1214             :                 /*
    1215             :                  * Can't use sync call while an async call is in flight
    1216             :                  */
    1217           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    1218           0 :                 goto fail;
    1219             :         }
    1220        7468 :         ev = samba_tevent_context_init(frame);
    1221        7468 :         if (ev == NULL) {
    1222           0 :                 goto fail;
    1223             :         }
    1224             : 
    1225        7468 :         if (proto >= PROTOCOL_SMB2_02) {
    1226        5241 :                 info_level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO;
    1227             :         } else {
    1228        2227 :                 info_level = (smb1cli_conn_capabilities(cli->conn) & CAP_NT_SMBS)
    1229             :                         ? SMB_FIND_FILE_BOTH_DIRECTORY_INFO : SMB_FIND_INFO_STANDARD;
    1230             :         }
    1231             : 
    1232        7468 :         req = cli_list_send(frame, ev, cli, mask, attribute, info_level);
    1233        7468 :         if (req == NULL) {
    1234           0 :                 goto fail;
    1235             :         }
    1236        7468 :         tevent_req_set_callback(req, cli_list_sync_cb, &state);
    1237             : 
    1238        7468 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    1239           0 :                 goto fail;
    1240             :         }
    1241             : 
    1242        7468 :         status = state.status;
    1243             : 
    1244        7468 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_FILES)) {
    1245        6834 :                 status = NT_STATUS_OK;
    1246             :         }
    1247             : 
    1248        7468 :         if (NT_STATUS_IS_OK(status) && !state.processed_file) {
    1249         225 :                 status = NT_STATUS_NO_SUCH_FILE;
    1250             :         }
    1251             : 
    1252        7243 :  fail:
    1253        7468 :         TALLOC_FREE(frame);
    1254        7468 :         return status;
    1255             : }

Generated by: LCOV version 1.14