LCOV - code coverage report
Current view: top level - source3/libsmb - clilist.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 363 601 60.4 %
Date: 2024-05-31 13:13:24 Functions: 16 17 94.1 %

          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       91643 : static NTSTATUS is_bad_name(bool windows_names, const char *name)
      32             : {
      33       91643 :         const char *bad_name_p = NULL;
      34             : 
      35       91643 :         bad_name_p = strchr(name, '/');
      36       91643 :         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       91643 :         if (windows_names) {
      44       91507 :                 bad_name_p = strchr(name, '\\');
      45       91507 :                 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       91643 :         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       65392 : NTSTATUS is_bad_finfo_name(const struct cli_state *cli,
      62             :                         const struct file_info *finfo)
      63             : {
      64       65392 :         NTSTATUS status = NT_STATUS_OK;
      65       65392 :         bool windows_names = true;
      66             : 
      67       65392 :         if (cli->requested_posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
      68         136 :                 windows_names = false;
      69             :         }
      70       65392 :         if (finfo->name != NULL) {
      71       65392 :                 status = is_bad_name(windows_names, finfo->name);
      72       65392 :                 if (!NT_STATUS_IS_OK(status)) {
      73           0 :                         DBG_ERR("bad finfo->name\n");
      74           0 :                         return status;
      75             :                 }
      76             :         }
      77       65392 :         if (finfo->short_name != NULL) {
      78       26251 :                 status = is_bad_name(windows_names, finfo->short_name);
      79       26251 :                 if (!NT_STATUS_IS_OK(status)) {
      80           0 :                         DBG_ERR("bad finfo->short_name\n");
      81           0 :                         return status;
      82             :                 }
      83             :         }
      84       65392 :         return NT_STATUS_OK;
      85             : }
      86             : 
      87             : /****************************************************************************
      88             :  Calculate a safe next_entry_offset.
      89             : ****************************************************************************/
      90             : 
      91        9257 : static size_t calc_next_entry_offset(const char *base, const char *pdata_end)
      92             : {
      93        9257 :         size_t next_entry_offset = (size_t)IVAL(base,0);
      94             : 
      95        9257 :         if (next_entry_offset == 0 ||
      96        9257 :                         base + next_entry_offset < base ||
      97        9257 :                         base + next_entry_offset > pdata_end) {
      98           0 :                 next_entry_offset = pdata_end - base;
      99             :         }
     100        9257 :         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        9257 : 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        9257 :         const char *base = p;
     125             : 
     126        9257 :         data_blob_free(p_last_name_raw);
     127             : 
     128        9257 :         if (p_resume_key) {
     129        9257 :                 *p_resume_key = 0;
     130             :         }
     131        9257 :         ZERO_STRUCTP(finfo);
     132             : 
     133        9257 :         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        9257 :                 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: /* NT uses this, but also accepts 2 */
     235             :                 {
     236           0 :                         size_t namelen, slen;
     237             : 
     238        9257 :                         if (pdata_end - base < 94) {
     239           0 :                                 return pdata_end - base;
     240             :                         }
     241             : 
     242        9257 :                         p += 4; /* next entry offset */
     243             : 
     244        9257 :                         if (p_resume_key) {
     245        9257 :                                 *p_resume_key = IVAL(p,0);
     246             :                         }
     247        9257 :                         p += 4; /* fileindex */
     248             : 
     249             :                         /* Offset zero is "create time", not "change time". */
     250        9257 :                         p += 8;
     251        9257 :                         finfo->atime_ts = interpret_long_date(BVAL(p, 0));
     252        9257 :                         p += 8;
     253        9257 :                         finfo->mtime_ts = interpret_long_date(BVAL(p, 0));
     254        9257 :                         p += 8;
     255        9257 :                         finfo->ctime_ts = interpret_long_date(BVAL(p, 0));
     256        9257 :                         p += 8;
     257        9257 :                         finfo->size = BVAL(p,0);
     258        9257 :                         p += 8;
     259        9257 :                         p += 8; /* alloc size */
     260        9257 :                         finfo->attr = IVAL(p,0);
     261        9257 :                         p += 4;
     262        9257 :                         namelen = IVAL(p,0);
     263        9257 :                         p += 4;
     264        9257 :                         p += 4; /* EA size */
     265        9257 :                         slen = CVAL(p, 0);
     266        9257 :                         if (slen > 24) {
     267             :                                 /* Bad short name length. */
     268           0 :                                 return pdata_end - base;
     269             :                         }
     270        9257 :                         p += 2;
     271        9257 :                         ret = pull_string_talloc(ctx,
     272             :                                                  base_ptr,
     273             :                                                  recv_flags2,
     274             :                                                  &finfo->short_name,
     275             :                                                  p,
     276             :                                                  slen,
     277             :                                                  STR_UNICODE);
     278        9257 :                         if (ret == (size_t)-1) {
     279           0 :                                 return pdata_end - base;
     280             :                         }
     281        9257 :                         p += 24; /* short name? */
     282        9257 :                         if (p + namelen < p || p + namelen > pdata_end) {
     283           0 :                                 return pdata_end - base;
     284             :                         }
     285        9257 :                         ret = pull_string_talloc(ctx,
     286             :                                                  base_ptr,
     287             :                                                  recv_flags2,
     288             :                                                  &finfo->name,
     289             :                                                  p,
     290             :                                                  namelen,
     291             :                                                  0);
     292        9257 :                         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        9257 :                         *p_last_name_raw = data_blob(NULL, namelen + 2);
     302        9257 :                         memcpy(p_last_name_raw->data, p, namelen);
     303        9257 :                         SSVAL(p_last_name_raw->data, namelen, 0);
     304             : 
     305        9257 :                         return calc_next_entry_offset(base, pdata_end);
     306             :                 }
     307             :         }
     308             : 
     309           0 :         DEBUG(1,("Unknown long filename format %d\n",level));
     310           0 :         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         131 : static bool interpret_short_filename(TALLOC_CTX *ctx,
     319             :                                 struct cli_state *cli,
     320             :                                 char *p,
     321             :                                 struct file_info *finfo)
     322             : {
     323           0 :         size_t ret;
     324         131 :         ZERO_STRUCTP(finfo);
     325             : 
     326         131 :         finfo->attr = CVAL(p,21);
     327             : 
     328             :         /* We don't get birth time. */
     329         131 :         finfo->btime_ts.tv_sec = 0;
     330         131 :         finfo->btime_ts.tv_nsec = 0;
     331             :         /* this date is converted to GMT by make_unix_date */
     332         131 :         finfo->ctime_ts.tv_sec = make_unix_date(p+22, smb1cli_conn_server_time_zone(cli->conn));
     333         131 :         finfo->ctime_ts.tv_nsec = 0;
     334         131 :         finfo->mtime_ts.tv_sec = finfo->atime_ts.tv_sec = finfo->ctime_ts.tv_sec;
     335         131 :         finfo->mtime_ts.tv_nsec = finfo->atime_ts.tv_nsec = 0;
     336         131 :         finfo->size = IVAL(p,26);
     337         131 :         ret = pull_string_talloc(ctx,
     338             :                                  NULL,
     339             :                                  0,
     340             :                                  &finfo->name,
     341         131 :                                  p+30,
     342             :                                  12,
     343             :                                  STR_ASCII);
     344         131 :         if (ret == (size_t)-1) {
     345           0 :                 return false;
     346             :         }
     347             : 
     348         131 :         if (finfo->name) {
     349         131 :                 finfo->short_name = talloc_strdup(ctx, finfo->name);
     350         131 :                 if (finfo->short_name == NULL) {
     351           0 :                         return false;
     352             :                 }
     353             :         }
     354         131 :         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           2 : 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           0 :         struct tevent_req *req, *subreq;
     379           0 :         struct cli_list_old_state *state;
     380           0 :         uint8_t *bytes;
     381           0 :         static const uint16_t zero = 0;
     382           0 :         uint32_t usable_space;
     383             : 
     384           2 :         req = tevent_req_create(mem_ctx, &state, struct cli_list_old_state);
     385           2 :         if (req == NULL) {
     386           0 :                 return NULL;
     387             :         }
     388           2 :         state->ev = ev;
     389           2 :         state->cli = cli;
     390           2 :         state->attribute = attribute;
     391           2 :         state->first = true;
     392           2 :         state->mask = talloc_strdup(state, mask);
     393           2 :         if (tevent_req_nomem(state->mask, req)) {
     394           0 :                 return tevent_req_post(req, ev);
     395             :         }
     396           2 :         state->mask = smb1_dfs_share_path(state, cli, state->mask);
     397           2 :         if (tevent_req_nomem(state->mask, req)) {
     398           0 :                 return tevent_req_post(req, ev);
     399             :         }
     400           2 :         usable_space = cli_state_available_size(cli, 100);
     401           2 :         state->num_asked = usable_space / DIR_STRUCT_SIZE;
     402             : 
     403           2 :         SSVAL(state->vwv + 0, 0, state->num_asked);
     404           2 :         SSVAL(state->vwv + 1, 0, state->attribute);
     405             : 
     406           2 :         bytes = talloc_array(state, uint8_t, 1);
     407           2 :         if (tevent_req_nomem(bytes, req)) {
     408           0 :                 return tevent_req_post(req, ev);
     409             :         }
     410           2 :         bytes[0] = 4;
     411           2 :         bytes = smb_bytes_push_str(bytes,
     412           2 :                                    smbXcli_conn_use_unicode(cli->conn),
     413           2 :                                    state->mask,
     414           2 :                                    strlen(state->mask)+1,
     415             :                                    NULL);
     416             : 
     417           2 :         bytes = smb_bytes_push_bytes(bytes, 5, (const uint8_t *)&zero, 2);
     418           2 :         if (tevent_req_nomem(bytes, req)) {
     419           0 :                 return tevent_req_post(req, ev);
     420             :         }
     421             : 
     422           2 :         subreq = cli_smb_send(state, state->ev, state->cli, SMBsearch, 0, 0,
     423           2 :                         2, state->vwv, talloc_get_size(bytes), bytes);
     424           2 :         if (tevent_req_nomem(subreq, req)) {
     425           0 :                 return tevent_req_post(req, ev);
     426             :         }
     427           2 :         tevent_req_set_callback(subreq, cli_list_old_done, req);
     428           2 :         return req;
     429             : }
     430             : 
     431           6 : static void cli_list_old_done(struct tevent_req *subreq)
     432             : {
     433           6 :         struct tevent_req *req = tevent_req_callback_data(
     434             :                 subreq, struct tevent_req);
     435           6 :         struct cli_list_old_state *state = tevent_req_data(
     436             :                 req, struct cli_list_old_state);
     437           0 :         NTSTATUS status;
     438           0 :         uint8_t cmd;
     439           0 :         uint8_t wct;
     440           0 :         uint16_t *vwv;
     441           0 :         uint32_t num_bytes;
     442           0 :         uint8_t *bytes;
     443           0 :         uint16_t received;
     444           0 :         size_t dirlist_len;
     445           0 :         uint8_t *tmp;
     446             : 
     447           6 :         status = cli_smb_recv(subreq, state, NULL, 0, &wct, &vwv, &num_bytes,
     448             :                               &bytes);
     449           6 :         if (!NT_STATUS_IS_OK(status)
     450           0 :             && !NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRnofiles))
     451           0 :             && !NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
     452           0 :                 TALLOC_FREE(subreq);
     453           0 :                 tevent_req_nterror(req, status);
     454           0 :                 return;
     455             :         }
     456           6 :         if (NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRnofiles))
     457           6 :             || NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
     458           0 :                 received = 0;
     459             :         } else {
     460           6 :                 if (wct < 1) {
     461           0 :                         TALLOC_FREE(subreq);
     462           0 :                         tevent_req_nterror(
     463             :                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
     464           0 :                         return;
     465             :                 }
     466           6 :                 received = SVAL(vwv + 0, 0);
     467             :         }
     468             : 
     469           6 :         if (received > 0) {
     470             :                 /*
     471             :                  * I don't think this can wrap. received is
     472             :                  * initialized from a 16-bit value.
     473             :                  */
     474           2 :                 if (num_bytes < ((uint32_t)received * DIR_STRUCT_SIZE + 3)) {
     475           0 :                         TALLOC_FREE(subreq);
     476           0 :                         tevent_req_nterror(
     477             :                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
     478           0 :                         return;
     479             :                 }
     480             : 
     481           2 :                 dirlist_len = talloc_get_size(state->dirlist);
     482             : 
     483           2 :                 tmp = talloc_realloc(
     484             :                         state, state->dirlist, uint8_t,
     485             :                         dirlist_len + received * DIR_STRUCT_SIZE);
     486           2 :                 if (tevent_req_nomem(tmp, req)) {
     487           0 :                         return;
     488             :                 }
     489           2 :                 state->dirlist = tmp;
     490           2 :                 memcpy(state->dirlist + dirlist_len, bytes + 3,
     491           2 :                        received * DIR_STRUCT_SIZE);
     492             : 
     493           2 :                 SSVAL(state->search_status, 0, 21);
     494           2 :                 memcpy(state->search_status + 2,
     495           2 :                        bytes + 3 + (received-1)*DIR_STRUCT_SIZE, 21);
     496           2 :                 cmd = SMBsearch;
     497             :         } else {
     498           4 :                 if (state->first || state->done) {
     499           2 :                         tevent_req_done(req);
     500           2 :                         return;
     501             :                 }
     502           2 :                 state->done = true;
     503           2 :                 state->num_asked = 0;
     504           2 :                 cmd = SMBfclose;
     505             :         }
     506           4 :         TALLOC_FREE(subreq);
     507             : 
     508           4 :         state->first = false;
     509             : 
     510           4 :         SSVAL(state->vwv + 0, 0, state->num_asked);
     511           4 :         SSVAL(state->vwv + 1, 0, state->attribute);
     512             : 
     513           4 :         bytes = talloc_array(state, uint8_t, 1);
     514           4 :         if (tevent_req_nomem(bytes, req)) {
     515           0 :                 return;
     516             :         }
     517           4 :         bytes[0] = 4;
     518           4 :         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(state->cli->conn), "",
     519             :                                    1, NULL);
     520           4 :         bytes = smb_bytes_push_bytes(bytes, 5, state->search_status,
     521             :                                      sizeof(state->search_status));
     522           4 :         if (tevent_req_nomem(bytes, req)) {
     523           0 :                 return;
     524             :         }
     525           8 :         subreq = cli_smb_send(state, state->ev, state->cli, cmd, 0, 0,
     526           4 :                               2, state->vwv, talloc_get_size(bytes), bytes);
     527           4 :         if (tevent_req_nomem(subreq, req)) {
     528           0 :                 return;
     529             :         }
     530           4 :         tevent_req_set_callback(subreq, cli_list_old_done, req);
     531             : }
     532             : 
     533           4 : static NTSTATUS cli_list_old_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     534             :                                   struct file_info **pfinfo)
     535             : {
     536           4 :         struct cli_list_old_state *state = tevent_req_data(
     537             :                 req, struct cli_list_old_state);
     538           0 :         NTSTATUS status;
     539           0 :         size_t i, num_received;
     540           0 :         struct file_info *finfo;
     541             : 
     542           4 :         if (tevent_req_is_nterror(req, &status)) {
     543           0 :                 return status;
     544             :         }
     545             : 
     546           4 :         if (state->dirlist == NULL) {
     547           2 :                 *pfinfo = NULL;
     548           2 :                 return NT_STATUS_OK;
     549             :         }
     550             : 
     551           2 :         num_received = talloc_array_length(state->dirlist) / DIR_STRUCT_SIZE;
     552             : 
     553           2 :         finfo = talloc_array(mem_ctx, struct file_info, num_received);
     554           2 :         if (finfo == NULL) {
     555           0 :                 return NT_STATUS_NO_MEMORY;
     556             :         }
     557             : 
     558         133 :         for (i=0; i<num_received; i++) {
     559         131 :                 if (!interpret_short_filename(
     560             :                             finfo, state->cli,
     561         131 :                             (char *)state->dirlist + i * DIR_STRUCT_SIZE,
     562         131 :                             &finfo[i])) {
     563           0 :                         TALLOC_FREE(finfo);
     564           0 :                         return NT_STATUS_NO_MEMORY;
     565             :                 }
     566         131 :                 if (finfo->name == NULL) {
     567           0 :                         TALLOC_FREE(finfo);
     568           0 :                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
     569             :                 }
     570         131 :                 status = is_bad_finfo_name(state->cli, finfo);
     571         131 :                 if (!NT_STATUS_IS_OK(status)) {
     572           0 :                         smbXcli_conn_disconnect(state->cli->conn, status);
     573           0 :                         TALLOC_FREE(finfo);
     574           0 :                         return status;
     575             :                 }
     576             :         }
     577           2 :         TALLOC_FREE(state->dirlist);
     578           2 :         *pfinfo = finfo;
     579           2 :         return NT_STATUS_OK;
     580             : }
     581             : 
     582           0 : 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           0 :         TALLOC_CTX *frame = talloc_stackframe();
     588           0 :         struct tevent_context *ev;
     589           0 :         struct tevent_req *req;
     590           0 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     591           0 :         struct file_info *finfo = NULL;
     592           0 :         size_t i, num_finfo;
     593             : 
     594           0 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
     595             :                 /*
     596             :                  * Can't use sync call while an async call is in flight
     597             :                  */
     598           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     599           0 :                 goto fail;
     600             :         }
     601           0 :         ev = samba_tevent_context_init(frame);
     602           0 :         if (ev == NULL) {
     603           0 :                 goto fail;
     604             :         }
     605           0 :         req = cli_list_old_send(frame, ev, cli, mask, attribute);
     606           0 :         if (req == NULL) {
     607           0 :                 goto fail;
     608             :         }
     609           0 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     610           0 :                 goto fail;
     611             :         }
     612           0 :         status = cli_list_old_recv(req, frame, &finfo);
     613           0 :         if (!NT_STATUS_IS_OK(status)) {
     614           0 :                 goto fail;
     615             :         }
     616           0 :         num_finfo = talloc_array_length(finfo);
     617           0 :         for (i=0; i<num_finfo; i++) {
     618           0 :                 status = fn(&finfo[i], mask, state);
     619           0 :                 if (!NT_STATUS_IS_OK(status)) {
     620           0 :                         goto fail;
     621             :                 }
     622             :         }
     623           0 :  fail:
     624           0 :         TALLOC_FREE(frame);
     625           0 :         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        2229 : 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           0 :         struct tevent_req *req, *subreq;
     659           0 :         struct cli_list_trans_state *state;
     660           0 :         size_t param_len;
     661        2229 :         uint16_t additional_flags2 = 0;
     662             : 
     663        2229 :         req = tevent_req_create(mem_ctx, &state,
     664             :                                 struct cli_list_trans_state);
     665        2229 :         if (req == NULL) {
     666           0 :                 return NULL;
     667             :         }
     668        2229 :         state->ev = ev;
     669        2229 :         state->cli = cli;
     670        2229 :         state->mask = smb1_dfs_share_path(state, cli, mask);
     671        2229 :         if (tevent_req_nomem(state->mask, req)) {
     672           0 :                 return tevent_req_post(req, ev);
     673             :         }
     674        2229 :         state->attribute = attribute;
     675        2229 :         state->info_level = info_level;
     676        2229 :         state->loop_count = 0;
     677        2229 :         state->first = true;
     678             : 
     679        2229 :         state->max_matches = 1366; /* Match W2k */
     680             : 
     681        2229 :         SSVAL(&state->setup[0], 0, TRANSACT2_FINDFIRST);
     682             : 
     683        2229 :         state->param = talloc_array(state, uint8_t, 12);
     684        2229 :         if (tevent_req_nomem(state->param, req)) {
     685           0 :                 return tevent_req_post(req, ev);
     686             :         }
     687             : 
     688        2229 :         SSVAL(state->param, 0, state->attribute);
     689        2229 :         SSVAL(state->param, 2, state->max_matches);
     690        2229 :         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        2229 :         SSVAL(state->param, 6, state->info_level);
     695        2229 :         SIVAL(state->param, 8, 0);
     696             : 
     697        2229 :         state->param = trans2_bytes_push_str(state->param, smbXcli_conn_use_unicode(cli->conn),
     698        2229 :                                              state->mask, strlen(state->mask)+1,
     699             :                                              NULL);
     700        2229 :         if (tevent_req_nomem(state->param, req)) {
     701           0 :                 return tevent_req_post(req, ev);
     702             :         }
     703             : 
     704        2229 :         if (clistr_is_previous_version_path(state->mask)) {
     705          68 :                 additional_flags2 = FLAGS2_REPARSE_PATH;
     706             :         }
     707             : 
     708        2229 :         param_len = talloc_get_size(state->param);
     709             : 
     710        2229 :         subreq = cli_trans_send(state, state->ev, state->cli, additional_flags2,
     711             :                                 SMBtrans2, NULL, -1, 0, 0,
     712        2229 :                                 state->setup, 1, 0,
     713        2229 :                                 state->param, param_len, 10,
     714             :                                 NULL, 0, CLI_BUFFER_SIZE);
     715        2229 :         if (tevent_req_nomem(subreq, req)) {
     716           0 :                 return tevent_req_post(req, ev);
     717             :         }
     718        2229 :         tevent_req_set_callback(subreq, cli_list_trans_done, req);
     719        2229 :         return req;
     720             : }
     721             : 
     722        2229 : static void cli_list_trans_done(struct tevent_req *subreq)
     723             : {
     724        2229 :         struct tevent_req *req = tevent_req_callback_data(
     725             :                 subreq, struct tevent_req);
     726        2229 :         struct cli_list_trans_state *state = tevent_req_data(
     727             :                 req, struct cli_list_trans_state);
     728           0 :         NTSTATUS status;
     729           0 :         uint8_t *param;
     730           0 :         uint32_t num_param;
     731           0 :         uint8_t *data;
     732           0 :         char *data_end;
     733           0 :         uint32_t num_data;
     734           0 :         uint32_t min_param;
     735           0 :         struct file_info *tmp;
     736           0 :         size_t old_num_finfo;
     737           0 :         uint16_t recv_flags2;
     738           0 :         int ff_searchcount;
     739           0 :         bool ff_eos;
     740           0 :         char *p, *p2;
     741        2229 :         uint32_t resume_key = 0;
     742           0 :         int i;
     743           0 :         DATA_BLOB last_name_raw;
     744        2229 :         struct file_info *finfo = NULL;
     745           0 :         size_t param_len;
     746        2229 :         uint16_t additional_flags2 = 0;
     747             : 
     748        2229 :         min_param = (state->first ? 6 : 4);
     749             : 
     750        2229 :         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        2229 :         TALLOC_FREE(subreq);
     755        2229 :         if (!NT_STATUS_IS_OK(status)) {
     756             :                 /*
     757             :                  * TODO: retry, OS/2 nofiles
     758             :                  */
     759         350 :                 tevent_req_nterror(req, status);
     760        2229 :                 return;
     761             :         }
     762             : 
     763        1879 :         if (state->first) {
     764        1879 :                 state->ff_dir_handle = SVAL(param, 0);
     765        1879 :                 ff_searchcount = SVAL(param, 2);
     766        1879 :                 ff_eos = SVAL(param, 4) != 0;
     767             :         } else {
     768           0 :                 ff_searchcount = SVAL(param, 0);
     769           0 :                 ff_eos = SVAL(param, 2) != 0;
     770             :         }
     771             : 
     772        1879 :         old_num_finfo = talloc_array_length(state->finfo);
     773             : 
     774        1879 :         tmp = talloc_realloc(state, state->finfo, struct file_info,
     775             :                                    old_num_finfo + ff_searchcount);
     776        1879 :         if (tevent_req_nomem(tmp, req)) {
     777           0 :                 return;
     778             :         }
     779        1879 :         state->finfo = tmp;
     780             : 
     781        1879 :         p2 = p = (char *)data;
     782        1879 :         data_end = (char *)data + num_data;
     783        1879 :         last_name_raw = data_blob_null;
     784             : 
     785       11134 :         for (i=0; i<ff_searchcount; i++) {
     786        9257 :                 if (p2 >= data_end) {
     787           0 :                         ff_eos = true;
     788           0 :                         break;
     789             :                 }
     790        9257 :                 if ((state->info_level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
     791        9257 :                     && (i == ff_searchcount-1)) {
     792             :                         /* Last entry - fixup the last offset length. */
     793        1879 :                         SIVAL(p2, 0, PTR_DIFF((data + num_data), p2));
     794             :                 }
     795             : 
     796        9257 :                 data_blob_free(&last_name_raw);
     797             : 
     798        9257 :                 finfo = &state->finfo[old_num_finfo + i];
     799             : 
     800       18514 :                 p2 += interpret_long_filename(
     801        9257 :                         state->finfo, /* Stick fname to the array as such */
     802        9257 :                         state->cli, state->info_level,
     803             :                         (char *)data, recv_flags2, p2,
     804             :                         data_end, finfo, &resume_key, &last_name_raw);
     805             : 
     806        9257 :                 if (finfo->name == NULL) {
     807           2 :                         DEBUG(1, ("cli_list: Error: unable to parse name from "
     808             :                                   "info level %d\n", state->info_level));
     809           2 :                         tevent_req_nterror(req,
     810             :                                 NT_STATUS_INVALID_NETWORK_RESPONSE);
     811           2 :                         return;
     812             :                 }
     813             : 
     814        9255 :                 status = is_bad_finfo_name(state->cli, finfo);
     815        9255 :                 if (!NT_STATUS_IS_OK(status)) {
     816           0 :                         smbXcli_conn_disconnect(state->cli->conn, status);
     817           0 :                         tevent_req_nterror(req, status);
     818           0 :                         return;
     819             :                 }
     820             : 
     821        9255 :                 if (!state->first && (state->mask[0] != '\0') &&
     822           0 :                     strcsequal(finfo->name, state->mask)) {
     823           0 :                         DEBUG(1, ("Error: Looping in FIND_NEXT as name %s has "
     824             :                                   "already been seen?\n", finfo->name));
     825           0 :                         ff_eos = true;
     826           0 :                         break;
     827             :                 }
     828             :         }
     829             : 
     830        1877 :         if (ff_searchcount == 0) {
     831           0 :                 ff_eos = true;
     832             :         }
     833             : 
     834        1877 :         TALLOC_FREE(param);
     835        1877 :         TALLOC_FREE(data);
     836             : 
     837             :         /*
     838             :          * Shrink state->finfo to the real length we received
     839             :          */
     840        1877 :         tmp = talloc_realloc(state, state->finfo, struct file_info,
     841             :                                    old_num_finfo + i);
     842        1877 :         if (tevent_req_nomem(tmp, req)) {
     843           0 :                 return;
     844             :         }
     845        1877 :         state->finfo = tmp;
     846             : 
     847        1877 :         state->first = false;
     848             : 
     849        1877 :         if (ff_eos) {
     850        1877 :                 data_blob_free(&last_name_raw);
     851        1877 :                 tevent_req_done(req);
     852        1877 :                 return;
     853             :         }
     854             : 
     855           0 :         TALLOC_FREE(state->mask);
     856           0 :         state->mask = talloc_strdup(state, finfo->name);
     857           0 :         if (tevent_req_nomem(state->mask, req)) {
     858           0 :                 return;
     859             :         }
     860             : 
     861           0 :         SSVAL(&state->setup[0], 0, TRANSACT2_FINDNEXT);
     862             : 
     863           0 :         param = talloc_realloc(state, state->param, uint8_t, 12);
     864           0 :         if (tevent_req_nomem(param, req)) {
     865           0 :                 return;
     866             :         }
     867           0 :         state->param = param;
     868             : 
     869           0 :         SSVAL(param, 0, state->ff_dir_handle);
     870           0 :         SSVAL(param, 2, state->max_matches); /* max count */
     871           0 :         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           0 :         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           0 :         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           0 :         if (last_name_raw.length) {
     886           0 :                 state->param = trans2_bytes_push_bytes(state->param,
     887           0 :                                                        last_name_raw.data,
     888             :                                                        last_name_raw.length);
     889           0 :                 if (tevent_req_nomem(state->param, req)) {
     890           0 :                         return;
     891             :                 }
     892           0 :                 data_blob_free(&last_name_raw);
     893             :         } else {
     894           0 :                 state->param = trans2_bytes_push_str(state->param,
     895           0 :                                                      smbXcli_conn_use_unicode(state->cli->conn),
     896           0 :                                                      state->mask,
     897           0 :                                                      strlen(state->mask)+1,
     898             :                                                      NULL);
     899           0 :                 if (tevent_req_nomem(state->param, req)) {
     900           0 :                         return;
     901             :                 }
     902             :         }
     903           0 :         param_len = talloc_get_size(state->param);
     904             : 
     905           0 :         if (clistr_is_previous_version_path(state->mask)) {
     906           0 :                 additional_flags2 = FLAGS2_REPARSE_PATH;
     907             :         }
     908             : 
     909           0 :         subreq = cli_trans_send(state, state->ev, state->cli, additional_flags2,
     910             :                                 SMBtrans2, NULL, -1, 0, 0,
     911           0 :                                 state->setup, 1, 0,
     912             :                                 state->param, param_len, 10,
     913             :                                 NULL, 0, CLI_BUFFER_SIZE);
     914           0 :         if (tevent_req_nomem(subreq, req)) {
     915           0 :                 return;
     916             :         }
     917           0 :         tevent_req_set_callback(subreq, cli_list_trans_done, req);
     918             : }
     919             : 
     920        4106 : static NTSTATUS cli_list_trans_recv(struct tevent_req *req,
     921             :                                     TALLOC_CTX *mem_ctx,
     922             :                                     struct file_info **finfo)
     923             : {
     924        4106 :         struct cli_list_trans_state *state = tevent_req_data(
     925             :                 req, struct cli_list_trans_state);
     926           0 :         NTSTATUS status;
     927             : 
     928        4106 :         if (tevent_req_is_nterror(req, &status)) {
     929         352 :                 return status;
     930             :         }
     931        3754 :         *finfo = talloc_move(mem_ctx, &state->finfo);
     932        3754 :         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       11057 : 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       11057 :         struct tevent_req *req = NULL;
     954           0 :         struct cli_list_state *state;
     955       11057 :         enum protocol_types proto = smbXcli_conn_protocol(cli->conn);
     956             : 
     957       11057 :         req = tevent_req_create(mem_ctx, &state, struct cli_list_state);
     958       11057 :         if (req == NULL) {
     959           0 :                 return NULL;
     960             :         }
     961       11057 :         state->ev = ev;
     962             : 
     963       11057 :         if (proto >= PROTOCOL_SMB2_02) {
     964        8826 :                 state->subreq = cli_smb2_list_send(state, ev, cli, mask,
     965             :                                                    info_level);
     966        8826 :                 state->recv_fn = cli_smb2_list_recv;
     967        2231 :         } else if (proto >= PROTOCOL_LANMAN2) {
     968        2229 :                 state->subreq = cli_list_trans_send(
     969             :                         state, ev, cli, mask, attribute, info_level);
     970        2229 :                 state->recv_fn = cli_list_trans_recv;
     971             :         } else {
     972           2 :                 state->subreq = cli_list_old_send(
     973             :                         state, ev, cli, mask, attribute);
     974           2 :                 state->recv_fn = cli_list_old_recv;
     975             :         }
     976       11057 :         if (tevent_req_nomem(state->subreq, req)) {
     977           0 :                 return tevent_req_post(req, ev);
     978             :         }
     979       11057 :         tevent_req_set_callback(state->subreq, cli_list_done, req);
     980       11057 :         return req;
     981             : }
     982             : 
     983       27920 : static void cli_list_done(struct tevent_req *subreq)
     984             : {
     985       27920 :         struct tevent_req *req = tevent_req_callback_data(
     986             :                 subreq, struct tevent_req);
     987       27920 :         struct cli_list_state *state = tevent_req_data(
     988             :                 req, struct cli_list_state);
     989           0 :         NTSTATUS status;
     990             : 
     991       27920 :         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       27920 :         tevent_req_set_callback(subreq, NULL, NULL);
     998             : 
     999       27920 :         status = state->recv_fn(subreq, state, &state->finfo);
    1000       27920 :         if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
    1001             :                 /* We'll get back here */
    1002        8546 :                 tevent_req_set_callback(subreq, cli_list_done, req);
    1003        8546 :                 return;
    1004             :         }
    1005             : 
    1006       19374 :         if (tevent_req_nterror(req, status)) {
    1007        9176 :                 return;
    1008             :         }
    1009       10198 :         tevent_req_notify_callback(req);
    1010             : }
    1011             : 
    1012       86643 : NTSTATUS cli_list_recv(
    1013             :         struct tevent_req *req,
    1014             :         TALLOC_CTX *mem_ctx,
    1015             :         struct file_info **pfinfo)
    1016             : {
    1017       86643 :         struct cli_list_state *state = tevent_req_data(
    1018             :                 req, struct cli_list_state);
    1019           0 :         size_t num_results;
    1020       86643 :         struct file_info *finfo = NULL;
    1021           0 :         NTSTATUS status;
    1022           0 :         bool in_progress;
    1023             : 
    1024       86643 :         in_progress = tevent_req_is_in_progress(req);
    1025             : 
    1026       86643 :         if (!in_progress) {
    1027       11057 :                 if (!tevent_req_is_nterror(req, &status)) {
    1028           0 :                         status = NT_STATUS_NO_MORE_FILES;
    1029             :                 }
    1030       11057 :                 return status;
    1031             :         }
    1032             : 
    1033       75586 :         if (state->finfo == NULL) {
    1034       57885 :                 status = state->recv_fn(state->subreq, state, &state->finfo);
    1035             : 
    1036       57885 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
    1037        8317 :                         tevent_req_set_callback(
    1038             :                                 state->subreq, cli_list_done, req);
    1039        8317 :                         return NT_STATUS_RETRY;
    1040             :                 }
    1041             : 
    1042       49568 :                 if (NT_STATUS_IS_OK(status) && (state->finfo == NULL)) {
    1043        1879 :                         status = NT_STATUS_NO_MORE_FILES;
    1044             :                 }
    1045             : 
    1046       49568 :                 if (tevent_req_nterror(req, status)) {
    1047        1881 :                         return status;
    1048             :                 }
    1049             : 
    1050       47687 :                 state->num_received = 0;
    1051             :         }
    1052             : 
    1053       65388 :         num_results = talloc_array_length(state->finfo);
    1054             : 
    1055       65388 :         if (num_results == 1) {
    1056       56696 :                 finfo = talloc_move(mem_ctx, &state->finfo);
    1057             :         } else {
    1058        8692 :                 struct file_info *src_finfo =
    1059        8692 :                         &state->finfo[state->num_received];
    1060             : 
    1061        8692 :                 finfo = talloc(mem_ctx, struct file_info);
    1062        8692 :                 if (finfo == NULL) {
    1063           0 :                         return NT_STATUS_NO_MEMORY;
    1064             :                 }
    1065        8692 :                 *finfo = *src_finfo;
    1066        8692 :                 finfo->name = talloc_move(finfo, &src_finfo->name);
    1067        8692 :                 finfo->short_name = talloc_move(finfo, &src_finfo->short_name);
    1068             :         }
    1069             : 
    1070       65388 :         state->num_received += 1;
    1071             : 
    1072       65388 :         if (state->num_received == num_results) {
    1073       57885 :                 TALLOC_FREE(state->finfo);
    1074             :         }
    1075             : 
    1076       65388 :         tevent_req_defer_callback(req, state->ev);
    1077       65388 :         tevent_req_notify_callback(req);
    1078             : 
    1079       65388 :         *pfinfo = finfo;
    1080       65388 :         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       66848 : static void cli_list_sync_cb(struct tevent_req *subreq)
    1095             : {
    1096           0 :         struct cli_list_sync_state *state =
    1097       66848 :                 tevent_req_callback_data_void(subreq);
    1098           0 :         struct file_info *finfo;
    1099           0 :         bool ok;
    1100             : 
    1101       66848 :         state->status = cli_list_recv(subreq, talloc_tos(), &finfo);
    1102             :         /* No TALLOC_FREE(subreq), we get here more than once */
    1103             : 
    1104       66848 :         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        4854 :                 state->status = NT_STATUS_OK;
    1110        4854 :                 return;
    1111             :         }
    1112             : 
    1113       61994 :         if (!NT_STATUS_IS_OK(state->status)) {
    1114        9473 :                 return;
    1115             :         }
    1116             : 
    1117       52521 :         ok = dir_check_ftype(finfo->attr, state->attribute);
    1118       52521 :         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           0 :                 return;
    1127             :         }
    1128             : 
    1129       52521 :         state->status = state->fn(finfo, state->mask, state->private_data);
    1130             : 
    1131       52521 :         state->processed_file = true;
    1132             : 
    1133       52521 :         TALLOC_FREE(finfo);
    1134             : }
    1135             : 
    1136        7592 : 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        7592 :         TALLOC_CTX *frame = NULL;
    1145        7592 :         struct cli_list_sync_state state = {
    1146             :                 .mask = mask,
    1147             :                 .attribute = attribute,
    1148             :                 .fn = fn,
    1149             :                 .private_data = private_data,
    1150             :         };
    1151           0 :         struct tevent_context *ev;
    1152           0 :         struct tevent_req *req;
    1153        7592 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    1154           0 :         uint16_t info_level;
    1155        7592 :         enum protocol_types proto = smbXcli_conn_protocol(cli->conn);
    1156             : 
    1157        7592 :         frame = talloc_stackframe();
    1158             : 
    1159        7592 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    1160             :                 /*
    1161             :                  * Can't use sync call while an async call is in flight
    1162             :                  */
    1163           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    1164           0 :                 goto fail;
    1165             :         }
    1166        7592 :         ev = samba_tevent_context_init(frame);
    1167        7592 :         if (ev == NULL) {
    1168           0 :                 goto fail;
    1169             :         }
    1170             : 
    1171        7592 :         if (proto >= PROTOCOL_SMB2_02) {
    1172        5361 :                 info_level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO;
    1173             :         } else {
    1174        2231 :                 info_level = (smb1cli_conn_capabilities(cli->conn) & CAP_NT_SMBS)
    1175             :                         ? SMB_FIND_FILE_BOTH_DIRECTORY_INFO : SMB_FIND_INFO_STANDARD;
    1176             :         }
    1177             : 
    1178        7592 :         req = cli_list_send(frame, ev, cli, mask, attribute, info_level);
    1179        7592 :         if (req == NULL) {
    1180           0 :                 goto fail;
    1181             :         }
    1182        7592 :         tevent_req_set_callback(req, cli_list_sync_cb, &state);
    1183             : 
    1184        7592 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    1185           0 :                 goto fail;
    1186             :         }
    1187             : 
    1188        7592 :         status = state.status;
    1189             : 
    1190        7592 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_FILES)) {
    1191        6958 :                 status = NT_STATUS_OK;
    1192             :         }
    1193             : 
    1194        7592 :         if (NT_STATUS_IS_OK(status) && !state.processed_file) {
    1195         225 :                 status = NT_STATUS_NO_SUCH_FILE;
    1196             :         }
    1197             : 
    1198        7367 :  fail:
    1199        7592 :         TALLOC_FREE(frame);
    1200        7592 :         return status;
    1201             : }

Generated by: LCOV version 1.14