LCOV - code coverage report
Current view: top level - source3/smbd - dir.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 630 809 77.9 %
Date: 2021-09-23 10:06:22 Functions: 42 51 82.4 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Directory handling routines
       4             :    Copyright (C) Andrew Tridgell 1992-1998
       5             :    Copyright (C) Jeremy Allison 2007
       6             : 
       7             :    This program is free software; you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             : 
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include "includes.h"
      22             : #include "system/filesys.h"
      23             : #include "locking/share_mode_lock.h"
      24             : #include "smbd/smbd.h"
      25             : #include "smbd/globals.h"
      26             : #include "libcli/security/security.h"
      27             : #include "lib/util/bitmap.h"
      28             : #include "../lib/util/memcache.h"
      29             : #include "../librpc/gen_ndr/open_files.h"
      30             : #include "lib/util/string_wrappers.h"
      31             : 
      32             : /*
      33             :    This module implements directory related functions for Samba.
      34             : */
      35             : 
      36             : /* "Special" directory offsets. */
      37             : #define END_OF_DIRECTORY_OFFSET ((long)-1)
      38             : #define START_OF_DIRECTORY_OFFSET ((long)0)
      39             : #define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
      40             : 
      41             : /* "Special" directory offsets in 32-bit wire format. */
      42             : #define WIRE_END_OF_DIRECTORY_OFFSET ((uint32_t)0xFFFFFFFF)
      43             : #define WIRE_START_OF_DIRECTORY_OFFSET ((uint32_t)0)
      44             : #define WIRE_DOT_DOT_DIRECTORY_OFFSET ((uint32_t)0x80000000)
      45             : 
      46             : /* Make directory handle internals available. */
      47             : 
      48             : struct name_cache_entry {
      49             :         char *name;
      50             :         long offset;
      51             : };
      52             : 
      53             : struct smb_Dir {
      54             :         connection_struct *conn;
      55             :         DIR *dir;
      56             :         long offset;
      57             :         struct smb_filename *dir_smb_fname;
      58             :         size_t name_cache_size;
      59             :         struct name_cache_entry *name_cache;
      60             :         unsigned int name_cache_index;
      61             :         unsigned int file_number;
      62             :         files_struct *fsp; /* Back pointer to containing fsp, only
      63             :                               set from OpenDir_fsp(). */
      64             : };
      65             : 
      66             : struct dptr_struct {
      67             :         struct dptr_struct *next, *prev;
      68             :         int dnum;
      69             :         uint16_t spid;
      70             :         struct connection_struct *conn;
      71             :         struct smb_Dir *dir_hnd;
      72             :         bool expect_close;
      73             :         char *wcard;
      74             :         uint32_t attr;
      75             :         struct smb_filename *smb_dname;
      76             :         bool has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
      77             :         bool did_stat; /* Optimisation for non-wcard searches. */
      78             :         bool priv;     /* Directory handle opened with privilege. */
      79             :         uint32_t counter;
      80             :         struct memcache *dptr_cache;
      81             : };
      82             : 
      83             : static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
      84             :                         files_struct *fsp,
      85             :                         const char *mask,
      86             :                         uint32_t attr);
      87             : 
      88             : static void DirCacheAdd(struct smb_Dir *dir_hnd, const char *name, long offset);
      89             : 
      90             : static int smb_Dir_destructor(struct smb_Dir *dir_hnd);
      91             : 
      92             : static bool SearchDir(struct smb_Dir *dir_hnd, const char *name, long *poffset);
      93             : 
      94             : #define INVALID_DPTR_KEY (-3)
      95             : 
      96             : /****************************************************************************
      97             :  Initialise the dir bitmap.
      98             : ****************************************************************************/
      99             : 
     100       27261 : bool init_dptrs(struct smbd_server_connection *sconn)
     101             : {
     102       27261 :         if (sconn->searches.dptr_bmap) {
     103           0 :                 return true;
     104             :         }
     105             : 
     106       27261 :         sconn->searches.dptr_bmap = bitmap_talloc(
     107             :                 sconn, MAX_DIRECTORY_HANDLES);
     108             : 
     109       27261 :         if (sconn->searches.dptr_bmap == NULL) {
     110           0 :                 return false;
     111             :         }
     112             : 
     113       27261 :         return true;
     114             : }
     115             : 
     116             : /****************************************************************************
     117             :  Get the struct dptr_struct for a dir index.
     118             : ****************************************************************************/
     119             : 
     120       28720 : static struct dptr_struct *dptr_get(struct smbd_server_connection *sconn,
     121             :                                     int key)
     122             : {
     123             :         struct dptr_struct *dptr;
     124             : 
     125       59664 :         for (dptr = sconn->searches.dirptrs; dptr != NULL; dptr = dptr->next) {
     126       33274 :                 if(dptr->dnum != key) {
     127        4560 :                         continue;
     128             :                 }
     129       28714 :                 DLIST_PROMOTE(sconn->searches.dirptrs, dptr);
     130       28714 :                 return dptr;
     131             :         }
     132           6 :         return(NULL);
     133             : }
     134             : 
     135             : /****************************************************************************
     136             :  Get the dir path for a dir index.
     137             : ****************************************************************************/
     138             : 
     139        2030 : const char *dptr_path(struct smbd_server_connection *sconn, int key)
     140             : {
     141        2030 :         struct dptr_struct *dptr = dptr_get(sconn, key);
     142        2030 :         if (dptr)
     143        2030 :                 return(dptr->smb_dname->base_name);
     144           0 :         return(NULL);
     145             : }
     146             : 
     147             : /****************************************************************************
     148             :  Get the dir wcard for a dir index.
     149             : ****************************************************************************/
     150             : 
     151        2030 : const char *dptr_wcard(struct smbd_server_connection *sconn, int key)
     152             : {
     153        2030 :         struct dptr_struct *dptr = dptr_get(sconn, key);
     154        2030 :         if (dptr)
     155        2030 :                 return(dptr->wcard);
     156           0 :         return(NULL);
     157             : }
     158             : 
     159             : /****************************************************************************
     160             :  Get the dir attrib for a dir index.
     161             : ****************************************************************************/
     162             : 
     163        2030 : uint16_t dptr_attr(struct smbd_server_connection *sconn, int key)
     164             : {
     165        2030 :         struct dptr_struct *dptr = dptr_get(sconn, key);
     166        2030 :         if (dptr)
     167        2030 :                 return(dptr->attr);
     168           0 :         return(0);
     169             : }
     170             : 
     171             : /****************************************************************************
     172             :  Close all dptrs for a cnum.
     173             : ****************************************************************************/
     174             : 
     175           0 : void dptr_closecnum(connection_struct *conn)
     176             : {
     177             :         struct dptr_struct *dptr, *next;
     178           0 :         struct smbd_server_connection *sconn = conn->sconn;
     179             : 
     180           0 :         if (sconn == NULL) {
     181           0 :                 return;
     182             :         }
     183             : 
     184           0 :         for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
     185           0 :                 next = dptr->next;
     186           0 :                 if (dptr->conn == conn) {
     187           0 :                         files_struct *fsp = dptr->dir_hnd->fsp;
     188           0 :                         close_file(NULL, fsp, NORMAL_CLOSE);
     189           0 :                         fsp = NULL;
     190             :                 }
     191             :         }
     192             : }
     193             : 
     194             : /****************************************************************************
     195             :  Create a new dir ptr. If the flag old_handle is true then we must allocate
     196             :  from the bitmap range 0 - 255 as old SMBsearch directory handles are only
     197             :  one byte long. If old_handle is false we allocate from the range
     198             :  256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
     199             :  a directory handle is never zero.
     200             :  wcard must not be zero.
     201             : ****************************************************************************/
     202             : 
     203       14438 : NTSTATUS dptr_create(connection_struct *conn,
     204             :                 struct smb_request *req,
     205             :                 files_struct *fsp,
     206             :                 bool old_handle,
     207             :                 bool expect_close,
     208             :                 uint16_t spid,
     209             :                 const char *wcard,
     210             :                 uint32_t attr,
     211             :                 struct dptr_struct **dptr_ret)
     212             : {
     213       14438 :         struct smbd_server_connection *sconn = conn->sconn;
     214       14438 :         struct dptr_struct *dptr = NULL;
     215             :         struct smb_Dir *dir_hnd;
     216             : 
     217       14438 :         DBG_INFO("dir=%s\n", fsp_str_dbg(fsp));
     218             : 
     219       14438 :         if (sconn == NULL) {
     220           0 :                 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
     221           0 :                 return NT_STATUS_INTERNAL_ERROR;
     222             :         }
     223             : 
     224       14438 :         if (!wcard) {
     225           0 :                 return NT_STATUS_INVALID_PARAMETER;
     226             :         }
     227             : 
     228       14438 :         if (!(fsp->access_mask & SEC_DIR_LIST)) {
     229           0 :                 DBG_INFO("dptr_create: directory %s "
     230             :                         "not open for LIST access\n",
     231             :                         fsp_str_dbg(fsp));
     232           0 :                 return NT_STATUS_ACCESS_DENIED;
     233             :         }
     234       14438 :         dir_hnd = OpenDir_fsp(NULL, conn, fsp, wcard, attr);
     235       14438 :         if (!dir_hnd) {
     236           0 :                 return map_nt_error_from_unix(errno);
     237             :         }
     238             : 
     239       14438 :         dptr = talloc_zero(NULL, struct dptr_struct);
     240       14438 :         if(!dptr) {
     241           0 :                 DEBUG(0,("talloc fail in dptr_create.\n"));
     242           0 :                 TALLOC_FREE(dir_hnd);
     243           0 :                 return NT_STATUS_NO_MEMORY;
     244             :         }
     245             : 
     246       14438 :         dptr->smb_dname = cp_smb_filename(dptr, fsp->fsp_name);
     247       14438 :         if (dptr->smb_dname == NULL) {
     248           0 :                 TALLOC_FREE(dptr);
     249           0 :                 TALLOC_FREE(dir_hnd);
     250           0 :                 return NT_STATUS_NO_MEMORY;
     251             :         }
     252       14438 :         dptr->conn = conn;
     253       14438 :         dptr->dir_hnd = dir_hnd;
     254       14438 :         dptr->spid = spid;
     255       14438 :         dptr->expect_close = expect_close;
     256       14438 :         dptr->wcard = talloc_strdup(dptr, wcard);
     257       14438 :         if (!dptr->wcard) {
     258           0 :                 TALLOC_FREE(dptr);
     259           0 :                 TALLOC_FREE(dir_hnd);
     260           0 :                 return NT_STATUS_NO_MEMORY;
     261             :         }
     262       26592 :         if ((req != NULL && req->posix_pathnames) ||
     263       14400 :                         (wcard[0] == '.' && wcard[1] == 0)) {
     264          38 :                 dptr->has_wild = True;
     265             :         } else {
     266       14400 :                 dptr->has_wild = ms_has_wild(dptr->wcard);
     267             :         }
     268             : 
     269       14438 :         dptr->attr = attr;
     270             : 
     271       14438 :         if (sconn->using_smb2) {
     272        7180 :                 goto done;
     273             :         }
     274             : 
     275        7258 :         if(old_handle) {
     276             : 
     277             :                 /*
     278             :                  * This is an old-style SMBsearch request. Ensure the
     279             :                  * value we return will fit in the range 1-255.
     280             :                  */
     281             : 
     282         174 :                 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
     283             : 
     284         174 :                 if(dptr->dnum == -1 || dptr->dnum > 254) {
     285           0 :                         DBG_ERR("returned %d: Error - all old "
     286             :                                 "dirptrs in use ?\n",
     287             :                                 dptr->dnum);
     288           0 :                         TALLOC_FREE(dptr);
     289           0 :                         TALLOC_FREE(dir_hnd);
     290           0 :                         return NT_STATUS_TOO_MANY_OPENED_FILES;
     291             :                 }
     292             :         } else {
     293             : 
     294             :                 /*
     295             :                  * This is a new-style trans2 request. Allocate from
     296             :                  * a range that will return 256 - MAX_DIRECTORY_HANDLES.
     297             :                  */
     298             : 
     299        7084 :                 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
     300             : 
     301        7084 :                 if(dptr->dnum == -1 || dptr->dnum < 255) {
     302           0 :                         DBG_ERR("returned %d: Error - all new "
     303             :                                 "dirptrs in use ?\n",
     304             :                                 dptr->dnum);
     305           0 :                         TALLOC_FREE(dptr);
     306           0 :                         TALLOC_FREE(dir_hnd);
     307           0 :                         return NT_STATUS_TOO_MANY_OPENED_FILES;
     308             :                 }
     309             :         }
     310             : 
     311        7258 :         bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
     312             : 
     313        7258 :         dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
     314             : 
     315        7258 :         DLIST_ADD(sconn->searches.dirptrs, dptr);
     316             : 
     317       14438 : done:
     318       14438 :         DBG_INFO("creating new dirptr [%d] for path [%s], expect_close = %d\n",
     319             :                  dptr->dnum, fsp_str_dbg(fsp), expect_close);
     320             : 
     321       14438 :         *dptr_ret = dptr;
     322             : 
     323       14438 :         return NT_STATUS_OK;
     324             : }
     325             : 
     326             : 
     327             : /****************************************************************************
     328             :  Wrapper functions to access the lower level directory handles.
     329             : ****************************************************************************/
     330             : 
     331       14438 : void dptr_CloseDir(files_struct *fsp)
     332             : {
     333       14438 :         struct smbd_server_connection *sconn = NULL;
     334             : 
     335       14438 :         if (fsp->dptr == NULL) {
     336           0 :                 return;
     337             :         }
     338       14438 :         sconn = fsp->dptr->conn->sconn;
     339             : 
     340             :         /*
     341             :          * The destructor for the struct smb_Dir (fsp->dptr->dir_hnd)
     342             :          * now handles all resource deallocation.
     343             :          */
     344             : 
     345       14438 :         DBG_INFO("closing dptr key %d\n", fsp->dptr->dnum);
     346             : 
     347       14438 :         if (sconn != NULL && !sconn->using_smb2) {
     348        7258 :                 DLIST_REMOVE(sconn->searches.dirptrs, fsp->dptr);
     349             : 
     350             :                 /*
     351             :                  * Free the dnum in the bitmap. Remember the dnum value is
     352             :                  * always biased by one with respect to the bitmap.
     353             :                  */
     354             : 
     355        7258 :                 if (!bitmap_query(sconn->searches.dptr_bmap,
     356        7258 :                                   fsp->dptr->dnum - 1))
     357             :                 {
     358           0 :                         DBG_ERR("closing dnum = %d and bitmap not set !\n",
     359             :                                 fsp->dptr->dnum);
     360             :                 }
     361             : 
     362        7258 :                 bitmap_clear(sconn->searches.dptr_bmap, fsp->dptr->dnum - 1);
     363             :         }
     364             : 
     365       14438 :         TALLOC_FREE(fsp->dptr->dir_hnd);
     366       14438 :         TALLOC_FREE(fsp->dptr);
     367             : }
     368             : 
     369        1964 : void dptr_SeekDir(struct dptr_struct *dptr, long offset)
     370             : {
     371        1964 :         SeekDir(dptr->dir_hnd, offset);
     372        1964 : }
     373             : 
     374      559462 : long dptr_TellDir(struct dptr_struct *dptr)
     375             : {
     376      559462 :         return TellDir(dptr->dir_hnd);
     377             : }
     378             : 
     379      514826 : bool dptr_has_wild(struct dptr_struct *dptr)
     380             : {
     381      514826 :         return dptr->has_wild;
     382             : }
     383             : 
     384        7258 : int dptr_dnum(struct dptr_struct *dptr)
     385             : {
     386        7258 :         return dptr->dnum;
     387             : }
     388             : 
     389        1708 : bool dptr_get_priv(struct dptr_struct *dptr)
     390             : {
     391        1708 :         return dptr->priv;
     392             : }
     393             : 
     394           0 : void dptr_set_priv(struct dptr_struct *dptr)
     395             : {
     396           0 :         dptr->priv = true;
     397           0 : }
     398             : 
     399             : /****************************************************************************
     400             :  Return the next visible file name, skipping veto'd and invisible files.
     401             : ****************************************************************************/
     402             : 
     403      559462 : static char *dptr_ReadDirName(TALLOC_CTX *ctx,
     404             :                               struct dptr_struct *dptr,
     405             :                               long *poffset,
     406             :                               SMB_STRUCT_STAT *pst)
     407             : {
     408             :         struct smb_filename smb_fname_base;
     409      559462 :         char *name = NULL;
     410      559462 :         const char *name_temp = NULL;
     411      559462 :         char *talloced = NULL;
     412      559462 :         char *pathreal = NULL;
     413      559462 :         char *found_name = NULL;
     414             :         int ret;
     415             : 
     416      559462 :         SET_STAT_INVALID(*pst);
     417             : 
     418      559462 :         if (dptr->has_wild || dptr->did_stat) {
     419      557749 :                 name_temp = ReadDirName(dptr->dir_hnd, poffset, pst,
     420             :                                                     &talloced);
     421      557749 :                 if (name_temp == NULL) {
     422       19721 :                         return NULL;
     423             :                 }
     424      537983 :                 if (talloced != NULL) {
     425          26 :                         return talloc_move(ctx, &talloced);
     426             :                 }
     427      537957 :                 return talloc_strdup(ctx, name_temp);
     428             :         }
     429             : 
     430             :         /* If poffset is -1 then we know we returned this name before and we
     431             :          * have no wildcards. We're at the end of the directory. */
     432        1713 :         if (*poffset == END_OF_DIRECTORY_OFFSET) {
     433           0 :                 return NULL;
     434             :         }
     435             : 
     436             :         /* We know the stored wcard contains no wildcard characters.
     437             :          * See if we can match with a stat call. If we can't, then set
     438             :          * did_stat to true to ensure we only do this once and keep
     439             :          * searching. */
     440             : 
     441        1713 :         dptr->did_stat = true;
     442             : 
     443        1626 :         if (VALID_STAT(*pst)) {
     444           0 :                 name = talloc_strdup(ctx, dptr->wcard);
     445           0 :                 goto ret;
     446             :         }
     447             : 
     448        3247 :         pathreal = talloc_asprintf(ctx,
     449             :                                 "%s/%s",
     450        1713 :                                 dptr->smb_dname->base_name,
     451             :                                 dptr->wcard);
     452        1713 :         if (!pathreal)
     453           0 :                 return NULL;
     454             : 
     455             :         /* Create an smb_filename with stream_name == NULL. */
     456        1713 :         smb_fname_base = (struct smb_filename) {
     457             :                 .base_name = pathreal,
     458        1713 :                 .flags = dptr->dir_hnd->fsp->fsp_name->flags,
     459        1713 :                 .twrp = dptr->smb_dname->twrp,
     460             :         };
     461             : 
     462        1713 :         if (vfs_stat(dptr->conn, &smb_fname_base) == 0) {
     463        1451 :                 *pst = smb_fname_base.st;
     464        1451 :                 name = talloc_strdup(ctx, dptr->wcard);
     465        1451 :                 goto clean;
     466             :         } else {
     467             :                 /* If we get any other error than ENOENT or ENOTDIR
     468             :                    then the file exists we just can't stat it. */
     469         262 :                 if (errno != ENOENT && errno != ENOTDIR) {
     470           0 :                         name = talloc_strdup(ctx, dptr->wcard);
     471           0 :                         goto clean;
     472             :                 }
     473             :         }
     474             : 
     475             :         /* Stat failed. We know this is authoratiative if we are
     476             :          * providing case sensitive semantics or the underlying
     477             :          * filesystem is case sensitive.
     478             :          */
     479         497 :         if (dptr->conn->case_sensitive ||
     480         262 :             !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
     481             :         {
     482           0 :                 goto clean;
     483             :         }
     484             : 
     485             :         /*
     486             :          * Try case-insensitive stat if the fs has the ability. This avoids
     487             :          * scanning the whole directory.
     488             :          */
     489         262 :         ret = SMB_VFS_GET_REAL_FILENAME(dptr->conn,
     490             :                                         dptr->smb_dname,
     491             :                                         dptr->wcard,
     492             :                                         ctx,
     493             :                                         &found_name);
     494         262 :         if (ret == 0) {
     495           0 :                 name = found_name;
     496           0 :                 goto clean;
     497         262 :         } else if (errno == ENOENT) {
     498             :                 /* The case-insensitive lookup was authoritative. */
     499           0 :                 goto clean;
     500             :         }
     501             : 
     502         262 :         TALLOC_FREE(pathreal);
     503             : 
     504         262 :         name_temp = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced);
     505         262 :         if (name_temp == NULL) {
     506           0 :                 return NULL;
     507             :         }
     508         262 :         if (talloced != NULL) {
     509           0 :                 return talloc_move(ctx, &talloced);
     510             :         }
     511         262 :         return talloc_strdup(ctx, name_temp);
     512             : 
     513        1451 : clean:
     514        2663 :         TALLOC_FREE(pathreal);
     515        1299 : ret:
     516             :         /* We need to set the underlying dir_hnd offset to -1
     517             :          * also as this function is usually called with the
     518             :          * output from TellDir. */
     519        1451 :         dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
     520        1451 :         return name;
     521             : }
     522             : 
     523             : /****************************************************************************
     524             :  Search for a file by name.
     525             : ****************************************************************************/
     526             : 
     527        1408 : bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
     528             : {
     529        1408 :         SET_STAT_INVALID(*pst);
     530             : 
     531        1408 :         if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
     532             :                 /* This is a singleton directory and we're already at the end. */
     533           0 :                 *poffset = END_OF_DIRECTORY_OFFSET;
     534           0 :                 return False;
     535             :         }
     536             : 
     537        1408 :         return SearchDir(dptr->dir_hnd, name, poffset);
     538             : }
     539             : 
     540             : /****************************************************************************
     541             :  Map a native directory offset to a 32-bit cookie.
     542             : ****************************************************************************/
     543             : 
     544       20594 : static uint32_t map_dir_offset_to_wire(struct dptr_struct *dptr, long offset)
     545             : {
     546             :         DATA_BLOB key;
     547             :         DATA_BLOB val;
     548             : 
     549       20594 :         if (offset == END_OF_DIRECTORY_OFFSET) {
     550          18 :                 return WIRE_END_OF_DIRECTORY_OFFSET;
     551       20576 :         } else if(offset == START_OF_DIRECTORY_OFFSET) {
     552           8 :                 return WIRE_START_OF_DIRECTORY_OFFSET;
     553       20568 :         } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
     554           8 :                 return WIRE_DOT_DOT_DIRECTORY_OFFSET;
     555             :         }
     556             :         if (sizeof(long) == 4) {
     557             :                 /* 32-bit machine. We can cheat... */
     558             :                 return (uint32_t)offset;
     559             :         }
     560       20560 :         if (dptr->dptr_cache == NULL) {
     561             :                 /* Lazy initialize cache. */
     562         138 :                 dptr->dptr_cache = memcache_init(dptr, 0);
     563         138 :                 if (dptr->dptr_cache == NULL) {
     564           0 :                         return WIRE_END_OF_DIRECTORY_OFFSET;
     565             :                 }
     566             :         } else {
     567             :                 /* Have we seen this offset before ? */
     568       20422 :                 key.data = (void *)&offset;
     569       20422 :                 key.length = sizeof(offset);
     570       20422 :                 if (memcache_lookup(dptr->dptr_cache,
     571             :                                         SMB1_SEARCH_OFFSET_MAP,
     572             :                                         key,
     573             :                                         &val)) {
     574             :                         uint32_t wire_offset;
     575         120 :                         SMB_ASSERT(val.length == sizeof(wire_offset));
     576         120 :                         memcpy(&wire_offset, val.data, sizeof(wire_offset));
     577         120 :                         DEBUG(10,("found wire %u <-> offset %ld\n",
     578             :                                 (unsigned int)wire_offset,
     579             :                                 (long)offset));
     580         120 :                         return wire_offset;
     581             :                 }
     582             :         }
     583             :         /* Allocate a new wire cookie. */
     584             :         do {
     585       20440 :                 dptr->counter++;
     586       40880 :         } while (dptr->counter == WIRE_START_OF_DIRECTORY_OFFSET ||
     587       36140 :                  dptr->counter == WIRE_END_OF_DIRECTORY_OFFSET ||
     588       36140 :                  dptr->counter == WIRE_DOT_DOT_DIRECTORY_OFFSET);
     589             :         /* Store it in the cache. */
     590       20440 :         key.data = (void *)&offset;
     591       20440 :         key.length = sizeof(offset);
     592       20440 :         val.data = (void *)&dptr->counter;
     593       20440 :         val.length = sizeof(dptr->counter); /* MUST BE uint32_t ! */
     594       20440 :         memcache_add(dptr->dptr_cache,
     595             :                         SMB1_SEARCH_OFFSET_MAP,
     596             :                         key,
     597             :                         val);
     598             :         /* And the reverse mapping for lookup from
     599             :            map_wire_to_dir_offset(). */
     600       20440 :         memcache_add(dptr->dptr_cache,
     601             :                         SMB1_SEARCH_OFFSET_MAP,
     602             :                         val,
     603             :                         key);
     604       20440 :         DEBUG(10,("stored wire %u <-> offset %ld\n",
     605             :                 (unsigned int)dptr->counter,
     606             :                 (long)offset));
     607       20440 :         return dptr->counter;
     608             : }
     609             : 
     610             : /****************************************************************************
     611             :  Fill the 5 byte server reserved dptr field.
     612             : ****************************************************************************/
     613             : 
     614       20594 : bool dptr_fill(struct smbd_server_connection *sconn,
     615             :                char *buf1,unsigned int key)
     616             : {
     617       20594 :         unsigned char *buf = (unsigned char *)buf1;
     618       20594 :         struct dptr_struct *dptr = dptr_get(sconn, key);
     619             :         uint32_t wire_offset;
     620       20594 :         if (!dptr) {
     621           0 :                 DEBUG(1,("filling null dirptr %d\n",key));
     622           0 :                 return(False);
     623             :         }
     624       20594 :         wire_offset = map_dir_offset_to_wire(dptr,TellDir(dptr->dir_hnd));
     625       20594 :         DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
     626             :                 (long)dptr->dir_hnd,(int)wire_offset));
     627       20594 :         buf[0] = key;
     628       20594 :         SIVAL(buf,1,wire_offset);
     629       20594 :         return(True);
     630             : }
     631             : 
     632             : /****************************************************************************
     633             :  Map a 32-bit wire cookie to a native directory offset.
     634             : ****************************************************************************/
     635             : 
     636         322 : static long map_wire_to_dir_offset(struct dptr_struct *dptr, uint32_t wire_offset)
     637             : {
     638             :         DATA_BLOB key;
     639             :         DATA_BLOB val;
     640             : 
     641         322 :         if (wire_offset == WIRE_END_OF_DIRECTORY_OFFSET) {
     642           0 :                 return END_OF_DIRECTORY_OFFSET;
     643         322 :         } else if(wire_offset == WIRE_START_OF_DIRECTORY_OFFSET) {
     644           0 :                 return START_OF_DIRECTORY_OFFSET;
     645         322 :         } else if (wire_offset == WIRE_DOT_DOT_DIRECTORY_OFFSET) {
     646           0 :                 return DOT_DOT_DIRECTORY_OFFSET;
     647             :         }
     648             :         if (sizeof(long) == 4) {
     649             :                 /* 32-bit machine. We can cheat... */
     650             :                 return (long)wire_offset;
     651             :         }
     652         322 :         if (dptr->dptr_cache == NULL) {
     653             :                 /* Logic error, cache should be initialized. */
     654           0 :                 return END_OF_DIRECTORY_OFFSET;
     655             :         }
     656         322 :         key.data = (void *)&wire_offset;
     657         322 :         key.length = sizeof(wire_offset);
     658         322 :         if (memcache_lookup(dptr->dptr_cache,
     659             :                                 SMB1_SEARCH_OFFSET_MAP,
     660             :                                 key,
     661             :                                 &val)) {
     662             :                 /* Found mapping. */
     663             :                 long offset;
     664         322 :                 SMB_ASSERT(val.length == sizeof(offset));
     665         322 :                 memcpy(&offset, val.data, sizeof(offset));
     666         322 :                 DEBUG(10,("lookup wire %u <-> offset %ld\n",
     667             :                         (unsigned int)wire_offset,
     668             :                         (long)offset));
     669         322 :                 return offset;
     670             :         }
     671           0 :         return END_OF_DIRECTORY_OFFSET;
     672             : }
     673             : 
     674             : /****************************************************************************
     675             :  Return the associated fsp and seek the dir_hnd on it it given the 5 byte
     676             :  server field.
     677             : ****************************************************************************/
     678             : 
     679         328 : files_struct *dptr_fetch_fsp(struct smbd_server_connection *sconn,
     680             :                                char *buf, int *num)
     681             : {
     682         328 :         unsigned int key = *(unsigned char *)buf;
     683         328 :         struct dptr_struct *dptr = dptr_get(sconn, key);
     684             :         uint32_t wire_offset;
     685             :         long seekoff;
     686             : 
     687         328 :         if (dptr == NULL) {
     688           6 :                 DEBUG(3,("fetched null dirptr %d\n",key));
     689           6 :                 return(NULL);
     690             :         }
     691         322 :         *num = key;
     692         322 :         wire_offset = IVAL(buf,1);
     693         322 :         seekoff = map_wire_to_dir_offset(dptr, wire_offset);
     694         322 :         SeekDir(dptr->dir_hnd,seekoff);
     695         322 :         DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
     696             :                 key, dptr->smb_dname->base_name, (int)seekoff));
     697         322 :         return dptr->dir_hnd->fsp;
     698             : }
     699             : 
     700           0 : struct files_struct *dir_hnd_fetch_fsp(struct smb_Dir *dir_hnd)
     701             : {
     702           0 :         return dir_hnd->fsp;
     703             : }
     704             : 
     705             : /****************************************************************************
     706             :  Fetch the fsp associated with the dptr_num.
     707             : ****************************************************************************/
     708             : 
     709        1708 : files_struct *dptr_fetch_lanman2_fsp(struct smbd_server_connection *sconn,
     710             :                                        int dptr_num)
     711             : {
     712        1708 :         struct dptr_struct *dptr  = dptr_get(sconn, dptr_num);
     713        1708 :         if (dptr == NULL) {
     714           0 :                 return NULL;
     715             :         }
     716        1708 :         DBG_NOTICE("fetching dirptr %d for path %s\n",
     717             :                 dptr_num,
     718             :                 dptr->smb_dname->base_name);
     719        1708 :         return dptr->dir_hnd->fsp;
     720             : }
     721             : 
     722        1044 : static bool mangle_mask_match(connection_struct *conn,
     723             :                 const char *filename,
     724             :                 const char *mask)
     725             : {
     726             :         char mname[13];
     727             : 
     728        1044 :         if (!name_to_8_3(filename,mname,False,conn->params)) {
     729           0 :                 return False;
     730             :         }
     731        1044 :         return mask_match_search(mname,mask,False);
     732             : }
     733             : 
     734      534968 : bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
     735             :                            struct dptr_struct *dirptr,
     736             :                            const char *mask,
     737             :                            uint32_t dirtype,
     738             :                            bool dont_descend,
     739             :                            bool ask_sharemode,
     740             :                            bool get_dosmode_in,
     741             :                            bool (*match_fn)(TALLOC_CTX *ctx,
     742             :                                             void *private_data,
     743             :                                             const char *dname,
     744             :                                             const char *mask,
     745             :                                             char **_fname),
     746             :                            bool (*mode_fn)(TALLOC_CTX *ctx,
     747             :                                            void *private_data,
     748             :                                            struct files_struct *dirfsp,
     749             :                                            struct smb_filename *atname,
     750             :                                            struct smb_filename *smb_fname,
     751             :                                            bool get_dosmode,
     752             :                                            uint32_t *_mode),
     753             :                            void *private_data,
     754             :                            char **_fname,
     755             :                            struct smb_filename **_smb_fname,
     756             :                            uint32_t *_mode,
     757             :                            long *_prev_offset)
     758             : {
     759      534968 :         connection_struct *conn = dirptr->conn;
     760             :         size_t slashlen;
     761             :         size_t pathlen;
     762      534968 :         const char *dpath = dirptr->smb_dname->base_name;
     763      534968 :         bool dirptr_path_is_dot = ISDOT(dpath);
     764             :         NTSTATUS status;
     765             :         int ret;
     766             : 
     767      534968 :         *_smb_fname = NULL;
     768      534968 :         *_mode = 0;
     769             : 
     770      534968 :         pathlen = strlen(dpath);
     771      534968 :         slashlen = ( dpath[pathlen-1] != '/') ? 1 : 0;
     772             : 
     773       24494 :         while (true) {
     774             :                 long cur_offset;
     775             :                 long prev_offset;
     776      559462 :                 SMB_STRUCT_STAT sbuf = { 0 };
     777      559462 :                 char *dname = NULL;
     778             :                 bool isdots;
     779      559462 :                 char *fname = NULL;
     780      559462 :                 char *pathreal = NULL;
     781      559462 :                 struct smb_filename *atname = NULL;
     782      559462 :                 struct smb_filename *smb_fname = NULL;
     783      559462 :                 uint32_t mode = 0;
     784      559462 :                 bool check_dfs_symlink = false;
     785      559462 :                 bool get_dosmode = get_dosmode_in;
     786             :                 bool ok;
     787             : 
     788      559462 :                 cur_offset = dptr_TellDir(dirptr);
     789      559462 :                 prev_offset = cur_offset;
     790      559462 :                 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
     791             : 
     792      559462 :                 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
     793             :                         (long)dirptr, cur_offset));
     794             : 
     795      559462 :                 if (dname == NULL) {
     796      551682 :                         return false;
     797             :                 }
     798             : 
     799      539696 :                 isdots = (ISDOT(dname) || ISDOTDOT(dname));
     800      539696 :                 if (dont_descend && !isdots) {
     801           0 :                         TALLOC_FREE(dname);
     802       24494 :                         continue;
     803             :                 }
     804             : 
     805      539696 :                 if (IS_VETO_PATH(conn, dname)) {
     806           0 :                         TALLOC_FREE(dname);
     807           0 :                         continue;
     808             :                 }
     809             : 
     810             :                 /*
     811             :                  * fname may get mangled, dname is never mangled.
     812             :                  * Whenever we're accessing the filesystem we use
     813             :                  * pathreal which is composed from dname.
     814             :                  */
     815             : 
     816      539696 :                 ok = match_fn(ctx, private_data, dname, mask, &fname);
     817      539696 :                 if (!ok) {
     818       15576 :                         TALLOC_FREE(dname);
     819       15576 :                         continue;
     820             :                 }
     821             : 
     822             :                 /*
     823             :                  * This used to be
     824             :                  * pathreal = talloc_asprintf(ctx, "%s%s%s", dirptr->path,
     825             :                  *                            needslash?"/":"", dname);
     826             :                  * but this was measurably slower than doing the memcpy.
     827             :                  */
     828             : 
     829      524120 :                 pathreal = talloc_array(
     830             :                         ctx, char,
     831             :                         pathlen + slashlen + talloc_get_size(dname));
     832      524120 :                 if (!pathreal) {
     833           0 :                         TALLOC_FREE(dname);
     834           0 :                         TALLOC_FREE(fname);
     835           0 :                         return false;
     836             :                 }
     837             : 
     838             :                 /*
     839             :                  * We don't want to pass ./xxx to modules below us so don't
     840             :                  * add the path if it is just . by itself.
     841             :                  */
     842      524120 :                 if (dirptr_path_is_dot) {
     843       25578 :                         memcpy(pathreal, dname, talloc_get_size(dname));
     844             :                 } else {
     845      498542 :                         memcpy(pathreal, dpath, pathlen);
     846      498542 :                         pathreal[pathlen] = '/';
     847      498542 :                         memcpy(pathreal + slashlen + pathlen, dname,
     848             :                                talloc_get_size(dname));
     849             :                 }
     850             : 
     851             :                 /* Create smb_fname with NULL stream_name. */
     852      966502 :                 smb_fname = synthetic_smb_fname(talloc_tos(),
     853             :                                                 pathreal,
     854             :                                                 NULL,
     855             :                                                 &sbuf,
     856      523935 :                                                 dirptr->smb_dname->twrp,
     857      524120 :                                                 dirptr->smb_dname->flags);
     858      524120 :                 TALLOC_FREE(pathreal);
     859      524120 :                 if (smb_fname == NULL) {
     860           0 :                         TALLOC_FREE(dname);
     861           0 :                         TALLOC_FREE(fname);
     862           0 :                         return false;
     863             :                 }
     864             : 
     865      524120 :                 if (!VALID_STAT(smb_fname->st)) {
     866             :                         /*
     867             :                          * If stat() fails with ENOENT it might be a
     868             :                          * msdfs-symlink in Windows context, this is checked
     869             :                          * below, for now we just want to fill stat info as good
     870             :                          * as we can.
     871             :                          */
     872       82212 :                         ret = vfs_stat(conn, smb_fname);
     873       82212 :                         if (ret != 0 && errno != ENOENT) {
     874           0 :                                 TALLOC_FREE(smb_fname);
     875           0 :                                 TALLOC_FREE(dname);
     876           0 :                                 TALLOC_FREE(fname);
     877           0 :                                 continue;
     878             :                         }
     879             :                 }
     880             : 
     881             :                 /* Create smb_fname with NULL stream_name. */
     882     1409069 :                 atname = synthetic_smb_fname(talloc_tos(),
     883             :                                              dname,
     884             :                                              NULL,
     885      524120 :                                              &smb_fname->st,
     886      523935 :                                              dirptr->smb_dname->twrp,
     887      524120 :                                              dirptr->smb_dname->flags);
     888      524120 :                 if (atname == NULL) {
     889           0 :                         TALLOC_FREE(dname);
     890           0 :                         TALLOC_FREE(fname);
     891           0 :                         TALLOC_FREE(smb_fname);
     892           0 :                         return false;
     893             :                 }
     894             : 
     895             :                 /*
     896             :                  * openat_pathref_fsp() will return
     897             :                  * NT_STATUS_OBJECT_NAME_NOT_FOUND in non-POSIX context when
     898             :                  * hitting a dangling symlink. It may be a DFS symlink, this is
     899             :                  * checked below by the mode_fn() call, so we have to allow this
     900             :                  * here.
     901             :                  *
     902             :                  * NT_STATUS_STOPPED_ON_SYMLINK is returned in POSIX context
     903             :                  * when hitting a symlink and ensures we always return directory
     904             :                  * entries that are symlinks in POSIX context.
     905             :                  */
     906      524120 :                 status = openat_pathref_fsp(dirptr->dir_hnd->fsp, atname);
     907      524830 :                 if (!NT_STATUS_IS_OK(status) &&
     908         730 :                     !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND))
     909             :                 {
     910         162 :                         TALLOC_FREE(atname);
     911         162 :                         TALLOC_FREE(dname);
     912         162 :                         TALLOC_FREE(fname);
     913         162 :                         TALLOC_FREE(smb_fname);
     914         162 :                         continue;
     915      523958 :                 } else if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
     916         568 :                         if (!(atname->flags & SMB_FILENAME_POSIX_PATH)) {
     917         544 :                                 check_dfs_symlink = true;
     918             :                         }
     919             :                         /*
     920             :                          * Check if it's a symlink. We only want to return this
     921             :                          * if it's a DFS symlink or in POSIX mode. Disable
     922             :                          * getting dosmode in the mode_fn() and prime the mode
     923             :                          * as FILE_ATTRIBUTE_NORMAL.
     924             :                          */
     925         568 :                         mode = FILE_ATTRIBUTE_NORMAL;
     926         568 :                         get_dosmode = false;
     927             :                 }
     928             : 
     929      523958 :                 status = move_smb_fname_fsp_link(smb_fname, atname);
     930      523958 :                 if (!NT_STATUS_IS_OK(status)) {
     931           0 :                         DBG_WARNING("Failed to move pathref for [%s]: %s\n",
     932             :                                     smb_fname_str_dbg(smb_fname),
     933             :                                     nt_errstr(status));
     934           0 :                         TALLOC_FREE(atname);
     935           0 :                         TALLOC_FREE(smb_fname);
     936           0 :                         TALLOC_FREE(dname);
     937           0 :                         TALLOC_FREE(fname);
     938           0 :                         continue;
     939             :                 }
     940             : 
     941      523958 :                 if (!is_visible_fsp(smb_fname->fsp)) {
     942          38 :                         TALLOC_FREE(atname);
     943          38 :                         TALLOC_FREE(smb_fname);
     944          38 :                         TALLOC_FREE(dname);
     945          38 :                         TALLOC_FREE(fname);
     946          38 :                         continue;
     947             :                 }
     948             : 
     949             :                 /*
     950             :                  * Don't leak metadata about the containing
     951             :                  * directory of the share.
     952             :                  */
     953      523920 :                 if (dirptr_path_is_dot && ISDOTDOT(dname)) {
     954             :                         /*
     955             :                          * Making a copy here, then freeing
     956             :                          * the original will close the smb_fname->fsp.
     957             :                          */
     958        1076 :                         struct smb_filename *tmp_smb_fname =
     959        1276 :                                 cp_smb_filename(ctx, smb_fname);
     960             : 
     961        1276 :                         if (tmp_smb_fname == NULL) {
     962           0 :                                 TALLOC_FREE(atname);
     963           0 :                                 TALLOC_FREE(smb_fname);
     964           0 :                                 TALLOC_FREE(dname);
     965           0 :                                 TALLOC_FREE(fname);
     966           0 :                                 return false;
     967             :                         }
     968        1276 :                         TALLOC_FREE(smb_fname);
     969        1276 :                         smb_fname = tmp_smb_fname;
     970        1276 :                         mode = FILE_ATTRIBUTE_DIRECTORY;
     971        1276 :                         get_dosmode = false;
     972             :                 }
     973             : 
     974      966290 :                 ok = mode_fn(ctx,
     975             :                              private_data,
     976      523920 :                              dirptr->dir_hnd->fsp,
     977             :                              atname,
     978             :                              smb_fname,
     979             :                              get_dosmode,
     980             :                              &mode);
     981      523920 :                 if (!ok) {
     982          14 :                         TALLOC_FREE(atname);
     983          14 :                         TALLOC_FREE(smb_fname);
     984          14 :                         TALLOC_FREE(dname);
     985          14 :                         TALLOC_FREE(fname);
     986          14 :                         continue;
     987             :                 }
     988             : 
     989      523906 :                 TALLOC_FREE(atname);
     990             : 
     991             :                 /*
     992             :                  * The only valid cases where we return the directory entry if
     993             :                  * it's a symlink are:
     994             :                  *
     995             :                  * 1. POSIX context, always return it, or
     996             :                  *
     997             :                  * 2. a DFS symlink where the mode_fn() call above has verified
     998             :                  *    this and set mode to FILE_ATTRIBUTE_REPARSE_POINT.
     999             :                  */
    1000      524416 :                 if (check_dfs_symlink &&
    1001         530 :                     !(mode & FILE_ATTRIBUTE_REPARSE_POINT))
    1002             :                 {
    1003         268 :                         TALLOC_FREE(smb_fname);
    1004         268 :                         TALLOC_FREE(dname);
    1005         268 :                         TALLOC_FREE(fname);
    1006         268 :                         continue;
    1007             :                 }
    1008             : 
    1009      523638 :                 if (!dir_check_ftype(mode, dirtype)) {
    1010        8436 :                         DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
    1011             :                                 fname, (unsigned int)mode, (unsigned int)dirtype));
    1012        8436 :                         TALLOC_FREE(smb_fname);
    1013        8436 :                         TALLOC_FREE(dname);
    1014        8436 :                         TALLOC_FREE(fname);
    1015        8436 :                         continue;
    1016             :                 }
    1017             : 
    1018      515202 :                 if (ask_sharemode && !S_ISDIR(smb_fname->st.st_ex_mode)) {
    1019             :                         struct timespec write_time_ts;
    1020             :                         struct file_id fileid;
    1021             : 
    1022      317049 :                         fileid = vfs_file_id_from_sbuf(conn,
    1023      317049 :                                                        &smb_fname->st);
    1024      317049 :                         get_file_infos(fileid, 0, NULL, &write_time_ts);
    1025      317049 :                         if (!is_omit_timespec(&write_time_ts)) {
    1026         721 :                                 update_stat_ex_mtime(&smb_fname->st,
    1027             :                                                      write_time_ts);
    1028             :                         }
    1029             :                 }
    1030             : 
    1031      515202 :                 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
    1032             :                         "fname=%s (%s)\n",
    1033             :                         mask, smb_fname_str_dbg(smb_fname),
    1034             :                         dname, fname));
    1035             : 
    1036      515202 :                 if (!conn->sconn->using_smb2) {
    1037             :                         /*
    1038             :                          * The dircache is only needed for SMB1 because SMB1
    1039             :                          * uses a name for the resume wheras SMB2 always
    1040             :                          * continues from the next position (unless it's told to
    1041             :                          * restart or close-and-reopen the listing).
    1042             :                          */
    1043      205244 :                         DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
    1044             :                 }
    1045             : 
    1046      515202 :                 TALLOC_FREE(dname);
    1047             : 
    1048      515202 :                 *_smb_fname = talloc_move(ctx, &smb_fname);
    1049      515202 :                 if (*_smb_fname == NULL) {
    1050           0 :                         return false;
    1051             :                 }
    1052      515202 :                 *_fname = fname;
    1053      515202 :                 *_mode = mode;
    1054      515202 :                 *_prev_offset = prev_offset;
    1055             : 
    1056      515202 :                 return true;
    1057             :         }
    1058             : 
    1059             :         return false;
    1060             : }
    1061             : 
    1062             : /****************************************************************************
    1063             :  Get an 8.3 directory entry.
    1064             : ****************************************************************************/
    1065             : 
    1066       29658 : static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
    1067             :                                      void *private_data,
    1068             :                                      const char *dname,
    1069             :                                      const char *mask,
    1070             :                                      char **_fname)
    1071             : {
    1072       29658 :         connection_struct *conn = (connection_struct *)private_data;
    1073             : 
    1074       55104 :         if ((strcmp(mask,"*.*") == 0) ||
    1075       26490 :             mask_match_search(dname, mask, false) ||
    1076        1044 :             mangle_mask_match(conn, dname, mask)) {
    1077             :                 char mname[13];
    1078             :                 const char *fname;
    1079             :                 /*
    1080             :                  * Ensure we can push the original name as UCS2. If
    1081             :                  * not, then just don't return this name.
    1082             :                  */
    1083             :                 NTSTATUS status;
    1084       28614 :                 size_t ret_len = 0;
    1085       28614 :                 size_t len = (strlen(dname) + 2) * 4; /* Allow enough space. */
    1086       28614 :                 uint8_t *tmp = talloc_array(talloc_tos(),
    1087             :                                         uint8_t,
    1088             :                                         len);
    1089             : 
    1090       28614 :                 status = srvstr_push(NULL,
    1091             :                         FLAGS2_UNICODE_STRINGS,
    1092             :                         tmp,
    1093             :                         dname,
    1094             :                         len,
    1095             :                         STR_TERMINATE,
    1096             :                         &ret_len);
    1097             : 
    1098       28614 :                 TALLOC_FREE(tmp);
    1099             : 
    1100       28614 :                 if (!NT_STATUS_IS_OK(status)) {
    1101           0 :                         return false;
    1102             :                 }
    1103             : 
    1104       28614 :                 if (!mangle_is_8_3(dname, false, conn->params)) {
    1105          18 :                         bool ok = name_to_8_3(dname, mname, false,
    1106          18 :                                               conn->params);
    1107          18 :                         if (!ok) {
    1108           0 :                                 return false;
    1109             :                         }
    1110          18 :                         fname = mname;
    1111             :                 } else {
    1112       28596 :                         fname = dname;
    1113             :                 }
    1114             : 
    1115       28614 :                 *_fname = talloc_strdup(ctx, fname);
    1116       28614 :                 if (*_fname == NULL) {
    1117           0 :                         return false;
    1118             :                 }
    1119             : 
    1120       28614 :                 return true;
    1121             :         }
    1122             : 
    1123        1044 :         return false;
    1124             : }
    1125             : 
    1126       28614 : static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
    1127             :                                     void *private_data,
    1128             :                                     struct files_struct *dirfsp,
    1129             :                                     struct smb_filename *atname,
    1130             :                                     struct smb_filename *smb_fname,
    1131             :                                     bool get_dosmode,
    1132             :                                     uint32_t *_mode)
    1133             : {
    1134       28614 :         connection_struct *conn = (connection_struct *)private_data;
    1135             : 
    1136       28614 :         if (!VALID_STAT(smb_fname->st)) {
    1137           0 :                 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
    1138           0 :                         DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
    1139             :                                  "Couldn't stat [%s]. Error "
    1140             :                                  "= %s\n",
    1141             :                                  smb_fname_str_dbg(smb_fname),
    1142             :                                  strerror(errno)));
    1143           0 :                         return false;
    1144             :                 }
    1145             :         }
    1146             : 
    1147       28614 :         if (get_dosmode) {
    1148       28614 :                 *_mode = fdos_mode(smb_fname->fsp);
    1149       28614 :                 smb_fname->st = smb_fname->fsp->fsp_name->st;
    1150             :         }
    1151       28614 :         return true;
    1152             : }
    1153             : 
    1154       20638 : bool get_dir_entry(TALLOC_CTX *ctx,
    1155             :                 struct dptr_struct *dirptr,
    1156             :                 const char *mask,
    1157             :                 uint32_t dirtype,
    1158             :                 char **_fname,
    1159             :                 off_t *_size,
    1160             :                 uint32_t *_mode,
    1161             :                 struct timespec *_date,
    1162             :                 bool check_descend,
    1163             :                 bool ask_sharemode)
    1164             : {
    1165       20638 :         connection_struct *conn = dirptr->conn;
    1166       20638 :         char *fname = NULL;
    1167       20638 :         struct smb_filename *smb_fname = NULL;
    1168       20638 :         uint32_t mode = 0;
    1169             :         long prev_offset;
    1170             :         bool ok;
    1171             : 
    1172       20638 :         ok = smbd_dirptr_get_entry(ctx,
    1173             :                                    dirptr,
    1174             :                                    mask,
    1175             :                                    dirtype,
    1176             :                                    check_descend,
    1177             :                                    ask_sharemode,
    1178             :                                    true,
    1179             :                                    smbd_dirptr_8_3_match_fn,
    1180             :                                    smbd_dirptr_8_3_mode_fn,
    1181             :                                    conn,
    1182             :                                    &fname,
    1183             :                                    &smb_fname,
    1184             :                                    &mode,
    1185             :                                    &prev_offset);
    1186       20638 :         if (!ok) {
    1187          44 :                 return false;
    1188             :         }
    1189             : 
    1190       20594 :         *_fname = talloc_move(ctx, &fname);
    1191       20594 :         *_size = smb_fname->st.st_ex_size;
    1192       20594 :         *_mode = mode;
    1193       20594 :         *_date = smb_fname->st.st_ex_mtime;
    1194       20594 :         TALLOC_FREE(smb_fname);
    1195       20594 :         return true;
    1196             : }
    1197             : 
    1198             : /*******************************************************************
    1199             :  Check to see if a user can read an fsp . This is only approximate,
    1200             :  it is used as part of the "hide unreadable" option. Don't
    1201             :  use it for anything security sensitive.
    1202             : ********************************************************************/
    1203             : 
    1204         118 : static bool user_can_read_fsp(struct files_struct *fsp)
    1205             : {
    1206             :         NTSTATUS status;
    1207         118 :         uint32_t rejected_share_access = 0;
    1208         118 :         uint32_t rejected_mask = 0;
    1209         118 :         struct security_descriptor *sd = NULL;
    1210         118 :         uint32_t access_mask = FILE_READ_DATA|
    1211             :                                 FILE_READ_EA|
    1212             :                                 FILE_READ_ATTRIBUTES|
    1213             :                                 SEC_STD_READ_CONTROL;
    1214             : 
    1215             :         /*
    1216             :          * Never hide files from the root user.
    1217             :          * We use (uid_t)0 here not sec_initial_uid()
    1218             :          * as make test uses a single user context.
    1219             :          */
    1220             : 
    1221         118 :         if (get_current_uid(fsp->conn) == (uid_t)0) {
    1222           0 :                 return true;
    1223             :         }
    1224             : 
    1225             :         /*
    1226             :          * We can't directly use smbd_check_access_rights_fsp()
    1227             :          * here, as this implicitly grants FILE_READ_ATTRIBUTES
    1228             :          * which the Windows access-based-enumeration code
    1229             :          * explicitly checks for on the file security descriptor.
    1230             :          * See bug:
    1231             :          *
    1232             :          * https://bugzilla.samba.org/show_bug.cgi?id=10252
    1233             :          *
    1234             :          * and the smb2.acl2.ACCESSBASED test for details.
    1235             :          */
    1236             : 
    1237         118 :         rejected_share_access = access_mask & ~(fsp->conn->share_access);
    1238         118 :         if (rejected_share_access) {
    1239           0 :                 DBG_DEBUG("rejected share access 0x%x "
    1240             :                         "on %s (0x%x)\n",
    1241             :                         (unsigned int)access_mask,
    1242             :                         fsp_str_dbg(fsp),
    1243             :                         (unsigned int)rejected_share_access);
    1244           0 :                 return false;
    1245             :         }
    1246             : 
    1247         118 :         status = SMB_VFS_FGET_NT_ACL(fsp,
    1248             :                         (SECINFO_OWNER |
    1249             :                          SECINFO_GROUP |
    1250             :                          SECINFO_DACL),
    1251             :                         talloc_tos(),
    1252             :                         &sd);
    1253             : 
    1254         118 :         if (!NT_STATUS_IS_OK(status)) {
    1255           0 :                 DBG_DEBUG("Could not get acl "
    1256             :                         "on %s: %s\n",
    1257             :                         fsp_str_dbg(fsp),
    1258             :                         nt_errstr(status));
    1259           0 :                 return false;
    1260             :         }
    1261             : 
    1262         118 :         status = se_file_access_check(sd,
    1263         118 :                                 get_current_nttok(fsp->conn),
    1264             :                                 false,
    1265             :                                 access_mask,
    1266             :                                 &rejected_mask);
    1267             : 
    1268         118 :         TALLOC_FREE(sd);
    1269             : 
    1270         118 :         if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
    1271          14 :                 DBG_DEBUG("rejected bits 0x%x read access for %s\n",
    1272             :                         (unsigned int)rejected_mask,
    1273             :                         fsp_str_dbg(fsp));
    1274          14 :                 return false;
    1275             :         }
    1276         104 :         return true;
    1277             : }
    1278             : 
    1279             : /*******************************************************************
    1280             :  Check to see if a user can write to an fsp.
    1281             :  Always return true for directories.
    1282             :  This is only approximate,
    1283             :  it is used as part of the "hide unwriteable" option. Don't
    1284             :  use it for anything security sensitive.
    1285             : ********************************************************************/
    1286             : 
    1287         102 : static bool user_can_write_fsp(struct files_struct *fsp)
    1288             : {
    1289             :         /*
    1290             :          * Never hide files from the root user.
    1291             :          * We use (uid_t)0 here not sec_initial_uid()
    1292             :          * as make test uses a single user context.
    1293             :          */
    1294             : 
    1295         102 :         if (get_current_uid(fsp->conn) == (uid_t)0) {
    1296           0 :                 return true;
    1297             :         }
    1298             : 
    1299         102 :         if (fsp->fsp_flags.is_directory) {
    1300          18 :                 return true;
    1301             :         }
    1302             : 
    1303          84 :         return can_write_to_fsp(fsp);
    1304             : }
    1305             : 
    1306             : /*******************************************************************
    1307             :   Is a file a "special" type ?
    1308             : ********************************************************************/
    1309             : 
    1310           0 : static bool file_is_special(connection_struct *conn,
    1311             :                             const struct smb_filename *smb_fname)
    1312             : {
    1313             :         /*
    1314             :          * Never hide files from the root user.
    1315             :          * We use (uid_t)0 here not sec_initial_uid()
    1316             :          * as make test uses a single user context.
    1317             :          */
    1318             : 
    1319           0 :         if (get_current_uid(conn) == (uid_t)0) {
    1320           0 :                 return False;
    1321             :         }
    1322             : 
    1323           0 :         SMB_ASSERT(VALID_STAT(smb_fname->st));
    1324             : 
    1325           0 :         if (S_ISREG(smb_fname->st.st_ex_mode) ||
    1326           0 :             S_ISDIR(smb_fname->st.st_ex_mode) ||
    1327           0 :             S_ISLNK(smb_fname->st.st_ex_mode))
    1328           0 :                 return False;
    1329             : 
    1330           0 :         return True;
    1331             : }
    1332             : 
    1333             : /*******************************************************************
    1334             :  Should the file be seen by the client?
    1335             : ********************************************************************/
    1336             : 
    1337      536629 : bool is_visible_fsp(struct files_struct *fsp)
    1338             : {
    1339      536629 :         bool hide_unreadable = false;
    1340      536629 :         bool hide_unwriteable = false;
    1341      536629 :         bool hide_special = false;
    1342      536629 :         int hide_new_files_timeout = 0;
    1343      536629 :         const char *last_component = NULL;
    1344             : 
    1345             :         /*
    1346             :          * If the file does not exist, there's no point checking
    1347             :          * the configuration options. We succeed, on the basis that the
    1348             :          * checks *might* have passed if the file was present.
    1349             :          */
    1350      536629 :         if (fsp == NULL) {
    1351         568 :                 return true;
    1352             :         }
    1353             : 
    1354      536061 :         hide_unreadable = lp_hide_unreadable(SNUM(fsp->conn));
    1355      536061 :         hide_unwriteable = lp_hide_unwriteable_files(SNUM(fsp->conn));
    1356      536061 :         hide_special = lp_hide_special_files(SNUM(fsp->conn));
    1357      536061 :         hide_new_files_timeout = lp_hide_new_files_timeout(SNUM(fsp->conn));
    1358             : 
    1359      536061 :         if (fsp->base_fsp != NULL) {
    1360             :                 /* Only operate on non-stream files. */
    1361           0 :                 fsp = fsp->base_fsp;
    1362             :         }
    1363             : 
    1364             :         /* Get the last component of the base name. */
    1365      536061 :         last_component = strrchr_m(fsp->fsp_name->base_name, '/');
    1366      536061 :         if (!last_component) {
    1367       25220 :                 last_component = fsp->fsp_name->base_name;
    1368             :         } else {
    1369      510841 :                 last_component++; /* Go past '/' */
    1370             :         }
    1371             : 
    1372      536061 :         if (ISDOT(last_component) || ISDOTDOT(last_component)) {
    1373       24382 :                 return true; /* . and .. are always visible. */
    1374             :         }
    1375             : 
    1376      511589 :         if (fsp_get_pathref_fd(fsp) == -1) {
    1377             :                 /*
    1378             :                  * Symlink in POSIX mode or MS-DFS.
    1379             :                  * We've checked veto files so the
    1380             :                  * only thing we can check is the
    1381             :                  * hide_new_files_timeout.
    1382             :                  */
    1383           0 :                 if (hide_new_files_timeout != 0) {
    1384           0 :                         double age = timespec_elapsed(
    1385           0 :                                 &fsp->fsp_name->st.st_ex_mtime);
    1386             : 
    1387           0 :                         if (age < (double)hide_new_files_timeout) {
    1388           0 :                                 return false;
    1389             :                         }
    1390             :                 }
    1391           0 :                 return true;
    1392             :         }
    1393             : 
    1394      511589 :         if (hide_unreadable ||
    1395      511369 :             hide_unwriteable ||
    1396      511369 :             hide_special ||
    1397             :             (hide_new_files_timeout != 0))
    1398             :         {
    1399             :                 /* Honour _hide unreadable_ option */
    1400         496 :                 if (hide_unreadable &&
    1401         118 :                     !user_can_read_fsp(fsp))
    1402             :                 {
    1403          14 :                         DBG_DEBUG("file %s is unreadable.\n",
    1404             :                                  fsp_str_dbg(fsp));
    1405          14 :                         return false;
    1406             :                 }
    1407             :                 /* Honour _hide unwriteable_ option */
    1408         470 :                 if (hide_unwriteable &&
    1409         102 :                     !user_can_write_fsp(fsp))
    1410             :                 {
    1411           4 :                         DBG_DEBUG("file %s is unwritable.\n",
    1412             :                                  fsp_str_dbg(fsp));
    1413           4 :                         return false;
    1414             :                 }
    1415             :                 /* Honour _hide_special_ option */
    1416         364 :                 if (hide_special && file_is_special(fsp->conn, fsp->fsp_name)) {
    1417           0 :                         DBG_DEBUG("file %s is special.\n",
    1418             :                                  fsp_str_dbg(fsp));
    1419           0 :                         return false;
    1420             :                 }
    1421             : 
    1422         364 :                 if (hide_new_files_timeout != 0) {
    1423         162 :                         double age = timespec_elapsed(
    1424         162 :                                 &fsp->fsp_name->st.st_ex_mtime);
    1425             : 
    1426         162 :                         if (age < (double)hide_new_files_timeout) {
    1427          20 :                                 return false;
    1428             :                         }
    1429             :                 }
    1430             :         }
    1431             : 
    1432      511409 :         return true;
    1433             : }
    1434             : 
    1435      314088 : static int smb_Dir_destructor(struct smb_Dir *dir_hnd)
    1436             : {
    1437      314088 :         files_struct *fsp = dir_hnd->fsp;
    1438             : 
    1439      314088 :         SMB_VFS_CLOSEDIR(dir_hnd->conn, dir_hnd->dir);
    1440      314088 :         fsp_set_fd(fsp, -1);
    1441      314088 :         if (fsp->dptr != NULL) {
    1442       14438 :                 SMB_ASSERT(fsp->dptr->dir_hnd == dir_hnd);
    1443       14438 :                 fsp->dptr->dir_hnd = NULL;
    1444             :         }
    1445      314088 :         dir_hnd->fsp = NULL;
    1446      314088 :         return 0;
    1447             : }
    1448             : 
    1449             : /*******************************************************************
    1450             :  Open a directory.
    1451             : ********************************************************************/
    1452             : 
    1453      299650 : static int smb_Dir_OpenDir_destructor(struct smb_Dir *dir_hnd)
    1454             : {
    1455      299650 :         files_struct *fsp = dir_hnd->fsp;
    1456             : 
    1457      299650 :         smb_Dir_destructor(dir_hnd);
    1458      299650 :         file_free(NULL, fsp);
    1459      299650 :         return 0;
    1460             : }
    1461             : 
    1462      300061 : struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx,
    1463             :                         connection_struct *conn,
    1464             :                         const struct smb_filename *smb_dname,
    1465             :                         const char *mask,
    1466             :                         uint32_t attr)
    1467             : {
    1468      300061 :         struct files_struct *fsp = NULL;
    1469      300061 :         struct smb_Dir *dir_hnd = NULL;
    1470             :         NTSTATUS status;
    1471             : 
    1472      300061 :         status = open_internal_dirfsp(conn,
    1473             :                                       smb_dname,
    1474             :                                       O_RDONLY,
    1475             :                                       &fsp);
    1476      300061 :         if (!NT_STATUS_IS_OK(status)) {
    1477             :                 /* Ensure we return the actual error from status in errno. */
    1478         411 :                 errno = map_errno_from_nt_status(status);
    1479         411 :                 return NULL;
    1480             :         }
    1481             : 
    1482      299650 :         dir_hnd = OpenDir_fsp(mem_ctx, conn, fsp, mask, attr);
    1483      299650 :         if (dir_hnd == NULL) {
    1484           0 :                 return NULL;
    1485             :         }
    1486             : 
    1487             :         /*
    1488             :          * This overwrites the destructor set by smb_Dir_OpenDir_destructor(),
    1489             :          * but smb_Dir_OpenDir_destructor() calls the OpenDir_fsp() destructor.
    1490             :          */
    1491      299650 :         talloc_set_destructor(dir_hnd, smb_Dir_OpenDir_destructor);
    1492      299650 :         return dir_hnd;
    1493             : }
    1494             : 
    1495             : /*******************************************************************
    1496             :  Open a directory from an fsp.
    1497             : ********************************************************************/
    1498             : 
    1499      314088 : static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
    1500             :                         files_struct *fsp,
    1501             :                         const char *mask,
    1502             :                         uint32_t attr)
    1503             : {
    1504      314088 :         struct smb_Dir *dir_hnd = talloc_zero(mem_ctx, struct smb_Dir);
    1505             : 
    1506      314088 :         if (!dir_hnd) {
    1507           0 :                 goto fail;
    1508             :         }
    1509             : 
    1510      314088 :         if (!fsp->fsp_flags.is_directory) {
    1511           0 :                 errno = EBADF;
    1512           0 :                 goto fail;
    1513             :         }
    1514             : 
    1515      314088 :         if (fsp_get_io_fd(fsp) == -1) {
    1516           0 :                 errno = EBADF;
    1517           0 :                 goto fail;
    1518             :         }
    1519             : 
    1520      314088 :         dir_hnd->conn = conn;
    1521             : 
    1522      314088 :         if (!conn->sconn->using_smb2) {
    1523             :                 /*
    1524             :                  * The dircache is only needed for SMB1 because SMB1 uses a name
    1525             :                  * for the resume wheras SMB2 always continues from the next
    1526             :                  * position (unless it's told to restart or close-and-reopen the
    1527             :                  * listing).
    1528             :                  */
    1529       53688 :                 dir_hnd->name_cache_size =
    1530       53688 :                         lp_directory_name_cache_size(SNUM(conn));
    1531             :         }
    1532             : 
    1533      314088 :         dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, fsp->fsp_name);
    1534      314088 :         if (!dir_hnd->dir_smb_fname) {
    1535           0 :                 errno = ENOMEM;
    1536           0 :                 goto fail;
    1537             :         }
    1538             : 
    1539      314088 :         dir_hnd->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
    1540      314088 :         if (dir_hnd->dir == NULL) {
    1541           0 :                 goto fail;
    1542             :         }
    1543      314088 :         dir_hnd->fsp = fsp;
    1544             : 
    1545      314088 :         talloc_set_destructor(dir_hnd, smb_Dir_destructor);
    1546             : 
    1547      314088 :         return dir_hnd;
    1548             : 
    1549           0 :   fail:
    1550           0 :         TALLOC_FREE(dir_hnd);
    1551           0 :         return NULL;
    1552             : }
    1553             : 
    1554             : 
    1555             : /*******************************************************************
    1556             :  Read from a directory.
    1557             :  Return directory entry, current offset, and optional stat information.
    1558             :  Don't check for veto or invisible files.
    1559             : ********************************************************************/
    1560             : 
    1561   207765820 : const char *ReadDirName(struct smb_Dir *dir_hnd, long *poffset,
    1562             :                         SMB_STRUCT_STAT *sbuf, char **ptalloced)
    1563             : {
    1564             :         const char *n;
    1565   207765820 :         char *talloced = NULL;
    1566   207765820 :         connection_struct *conn = dir_hnd->conn;
    1567             : 
    1568             :         /* Cheat to allow . and .. to be the first entries returned. */
    1569   401162379 :         if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
    1570   208019969 :              (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dir_hnd->file_number < 2))
    1571             :         {
    1572      625472 :                 if (dir_hnd->file_number == 0) {
    1573      312739 :                         n = ".";
    1574      312739 :                         *poffset = dir_hnd->offset = START_OF_DIRECTORY_OFFSET;
    1575             :                 } else {
    1576      312733 :                         n = "..";
    1577      312733 :                         *poffset = dir_hnd->offset = DOT_DOT_DIRECTORY_OFFSET;
    1578             :                 }
    1579      625472 :                 dir_hnd->file_number++;
    1580      625472 :                 *ptalloced = NULL;
    1581      625472 :                 return n;
    1582             :         }
    1583             : 
    1584   207140348 :         if (*poffset == END_OF_DIRECTORY_OFFSET) {
    1585        6679 :                 *poffset = dir_hnd->offset = END_OF_DIRECTORY_OFFSET;
    1586        6679 :                 return NULL;
    1587             :         }
    1588             : 
    1589             :         /* A real offset, seek to it. */
    1590   207133669 :         SeekDir(dir_hnd, *poffset);
    1591             : 
    1592   207239811 :         while ((n = vfs_readdirname(conn, dir_hnd->fsp, dir_hnd->dir, sbuf, &talloced))) {
    1593             :                 /* Ignore . and .. - we've already returned them. */
    1594   207448030 :                 if (*n == '.') {
    1595      658178 :                         if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
    1596      625237 :                                 TALLOC_FREE(talloced);
    1597      625237 :                                 continue;
    1598             :                         }
    1599             :                 }
    1600   206822793 :                 *poffset = dir_hnd->offset = SMB_VFS_TELLDIR(conn, dir_hnd->dir);
    1601   206822793 :                 *ptalloced = talloced;
    1602   206822793 :                 dir_hnd->file_number++;
    1603   206822793 :                 return n;
    1604             :         }
    1605      310876 :         *poffset = dir_hnd->offset = END_OF_DIRECTORY_OFFSET;
    1606      310876 :         *ptalloced = NULL;
    1607      310876 :         return NULL;
    1608             : }
    1609             : 
    1610             : /*******************************************************************
    1611             :  Rewind to the start.
    1612             : ********************************************************************/
    1613             : 
    1614         100 : void RewindDir(struct smb_Dir *dir_hnd, long *poffset)
    1615             : {
    1616         100 :         SMB_VFS_REWINDDIR(dir_hnd->conn, dir_hnd->dir);
    1617         100 :         dir_hnd->file_number = 0;
    1618         100 :         dir_hnd->offset = START_OF_DIRECTORY_OFFSET;
    1619         100 :         *poffset = START_OF_DIRECTORY_OFFSET;
    1620         100 : }
    1621             : 
    1622             : /*******************************************************************
    1623             :  Seek a dir.
    1624             : ********************************************************************/
    1625             : 
    1626   207137357 : void SeekDir(struct smb_Dir *dirp, long offset)
    1627             : {
    1628   207137357 :         if (offset != dirp->offset) {
    1629        3126 :                 if (offset == START_OF_DIRECTORY_OFFSET) {
    1630          96 :                         RewindDir(dirp, &offset);
    1631             :                         /*
    1632             :                          * Ok we should really set the file number here
    1633             :                          * to 1 to enable ".." to be returned next. Trouble
    1634             :                          * is I'm worried about callers using SeekDir(dirp,0)
    1635             :                          * as equivalent to RewindDir(). So leave this alone
    1636             :                          * for now.
    1637             :                          */
    1638        3030 :                 } else if  (offset == DOT_DOT_DIRECTORY_OFFSET) {
    1639           4 :                         RewindDir(dirp, &offset);
    1640             :                         /*
    1641             :                          * Set the file number to 2 - we want to get the first
    1642             :                          * real file entry (the one we return after "..")
    1643             :                          * on the next ReadDir.
    1644             :                          */
    1645           4 :                         dirp->file_number = 2;
    1646        3026 :                 } else if (offset == END_OF_DIRECTORY_OFFSET) {
    1647             :                         ; /* Don't seek in this case. */
    1648             :                 } else {
    1649        3026 :                         SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
    1650             :                 }
    1651        3126 :                 dirp->offset = offset;
    1652             :         }
    1653   207137357 : }
    1654             : 
    1655             : /*******************************************************************
    1656             :  Tell a dir position.
    1657             : ********************************************************************/
    1658             : 
    1659      580056 : long TellDir(struct smb_Dir *dir_hnd)
    1660             : {
    1661      580056 :         return(dir_hnd->offset);
    1662             : }
    1663             : 
    1664             : /*******************************************************************
    1665             :  Add an entry into the dcache.
    1666             : ********************************************************************/
    1667             : 
    1668      205244 : static void DirCacheAdd(struct smb_Dir *dir_hnd, const char *name, long offset)
    1669             : {
    1670             :         struct name_cache_entry *e;
    1671             : 
    1672      205244 :         if (dir_hnd->name_cache_size == 0) {
    1673           0 :                 return;
    1674             :         }
    1675             : 
    1676      205244 :         if (dir_hnd->name_cache == NULL) {
    1677        7106 :                 dir_hnd->name_cache = talloc_zero_array(dir_hnd,
    1678             :                                                 struct name_cache_entry,
    1679             :                                                 dir_hnd->name_cache_size);
    1680             : 
    1681        7106 :                 if (dir_hnd->name_cache == NULL) {
    1682           0 :                         return;
    1683             :                 }
    1684             :         }
    1685             : 
    1686      375508 :         dir_hnd->name_cache_index = (dir_hnd->name_cache_index+1) %
    1687      205244 :                                         dir_hnd->name_cache_size;
    1688      205244 :         e = &dir_hnd->name_cache[dir_hnd->name_cache_index];
    1689      205244 :         TALLOC_FREE(e->name);
    1690      205244 :         e->name = talloc_strdup(dir_hnd, name);
    1691      205244 :         e->offset = offset;
    1692             : }
    1693             : 
    1694             : /*******************************************************************
    1695             :  Find an entry by name. Leave us at the offset after it.
    1696             :  Don't check for veto or invisible files.
    1697             : ********************************************************************/
    1698             : 
    1699        1408 : static bool SearchDir(struct smb_Dir *dir_hnd, const char *name, long *poffset)
    1700             : {
    1701             :         int i;
    1702        1408 :         const char *entry = NULL;
    1703        1408 :         char *talloced = NULL;
    1704        1408 :         connection_struct *conn = dir_hnd->conn;
    1705             : 
    1706             :         /* Search back in the name cache. */
    1707        1408 :         if (dir_hnd->name_cache_size && dir_hnd->name_cache) {
    1708        7720 :                 for (i = dir_hnd->name_cache_index; i >= 0; i--) {
    1709        6748 :                         struct name_cache_entry *e = &dir_hnd->name_cache[i];
    1710        6748 :                         if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
    1711         436 :                                 *poffset = e->offset;
    1712         436 :                                 SeekDir(dir_hnd, e->offset);
    1713         436 :                                 return True;
    1714             :                         }
    1715             :                 }
    1716       75022 :                 for (i = dir_hnd->name_cache_size - 1;
    1717       88050 :                                 i > dir_hnd->name_cache_index; i--) {
    1718       88854 :                         struct name_cache_entry *e = &dir_hnd->name_cache[i];
    1719       88854 :                         if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
    1720         966 :                                 *poffset = e->offset;
    1721         966 :                                 SeekDir(dir_hnd, e->offset);
    1722         966 :                                 return True;
    1723             :                         }
    1724             :                 }
    1725             :         }
    1726             : 
    1727             :         /* Not found in the name cache. Rewind directory and start from scratch. */
    1728           6 :         SMB_VFS_REWINDDIR(conn, dir_hnd->dir);
    1729           6 :         dir_hnd->file_number = 0;
    1730           6 :         *poffset = START_OF_DIRECTORY_OFFSET;
    1731          11 :         while ((entry = ReadDirName(dir_hnd, poffset, NULL, &talloced))) {
    1732           6 :                 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
    1733           6 :                         TALLOC_FREE(talloced);
    1734           6 :                         return True;
    1735             :                 }
    1736           0 :                 TALLOC_FREE(talloced);
    1737             :         }
    1738           0 :         return False;
    1739             : }
    1740             : 
    1741             : struct files_below_forall_state {
    1742             :         char *dirpath;
    1743             :         ssize_t dirpath_len;
    1744             :         int (*fn)(struct file_id fid, const struct share_mode_data *data,
    1745             :                   void *private_data);
    1746             :         void *private_data;
    1747             : };
    1748             : 
    1749       16532 : static int files_below_forall_fn(struct file_id fid,
    1750             :                                  const struct share_mode_data *data,
    1751             :                                  void *private_data)
    1752             : {
    1753       16532 :         struct files_below_forall_state *state = private_data;
    1754             :         char tmpbuf[PATH_MAX];
    1755             :         char *fullpath, *to_free;
    1756             :         ssize_t len;
    1757             : 
    1758       16532 :         len = full_path_tos(data->servicepath, data->base_name,
    1759             :                             tmpbuf, sizeof(tmpbuf),
    1760             :                             &fullpath, &to_free);
    1761       16532 :         if (len == -1) {
    1762           0 :                 return 0;
    1763             :         }
    1764       16532 :         if (state->dirpath_len >= len) {
    1765             :                 /*
    1766             :                  * Filter files above dirpath
    1767             :                  */
    1768       14478 :                 goto out;
    1769             :         }
    1770        2054 :         if (fullpath[state->dirpath_len] != '/') {
    1771             :                 /*
    1772             :                  * Filter file that don't have a path separator at the end of
    1773             :                  * dirpath's length
    1774             :                  */
    1775        2000 :                 goto out;
    1776             :         }
    1777             : 
    1778          54 :         if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
    1779             :                 /*
    1780             :                  * Not a parent
    1781             :                  */
    1782          42 :                 goto out;
    1783             :         }
    1784             : 
    1785          12 :         TALLOC_FREE(to_free);
    1786          12 :         return state->fn(fid, data, state->private_data);
    1787             : 
    1788       16520 : out:
    1789       16520 :         TALLOC_FREE(to_free);
    1790       16520 :         return 0;
    1791             : }
    1792             : 
    1793        5916 : static int files_below_forall(connection_struct *conn,
    1794             :                               const struct smb_filename *dir_name,
    1795             :                               int (*fn)(struct file_id fid,
    1796             :                                         const struct share_mode_data *data,
    1797             :                                         void *private_data),
    1798             :                               void *private_data)
    1799             : {
    1800        5916 :         struct files_below_forall_state state = {
    1801             :                         .fn = fn,
    1802             :                         .private_data = private_data,
    1803             :         };
    1804             :         int ret;
    1805             :         char tmpbuf[PATH_MAX];
    1806             :         char *to_free;
    1807             : 
    1808        5961 :         state.dirpath_len = full_path_tos(conn->connectpath,
    1809        5916 :                                           dir_name->base_name,
    1810             :                                           tmpbuf, sizeof(tmpbuf),
    1811             :                                           &state.dirpath, &to_free);
    1812        5916 :         if (state.dirpath_len == -1) {
    1813           0 :                 return -1;
    1814             :         }
    1815             : 
    1816        5916 :         ret = share_mode_forall(files_below_forall_fn, &state);
    1817        5916 :         TALLOC_FREE(to_free);
    1818        5916 :         return ret;
    1819             : }
    1820             : 
    1821             : struct have_file_open_below_state {
    1822             :         bool found_one;
    1823             : };
    1824             : 
    1825          12 : static int have_file_open_below_fn(struct file_id fid,
    1826             :                                    const struct share_mode_data *data,
    1827             :                                    void *private_data)
    1828             : {
    1829          12 :         struct have_file_open_below_state *state = private_data;
    1830          12 :         state->found_one = true;
    1831          12 :         return 1;
    1832             : }
    1833             : 
    1834        5916 : bool have_file_open_below(connection_struct *conn,
    1835             :                                  const struct smb_filename *name)
    1836             : {
    1837        5916 :         struct have_file_open_below_state state = {
    1838             :                 .found_one = false,
    1839             :         };
    1840             :         int ret;
    1841             : 
    1842        5916 :         if (!VALID_STAT(name->st)) {
    1843           0 :                 return false;
    1844             :         }
    1845        5916 :         if (!S_ISDIR(name->st.st_ex_mode)) {
    1846           0 :                 return false;
    1847             :         }
    1848             : 
    1849        5916 :         ret = files_below_forall(conn, name, have_file_open_below_fn, &state);
    1850        5916 :         if (ret == -1) {
    1851           0 :                 return false;
    1852             :         }
    1853             : 
    1854        5916 :         return state.found_one;
    1855             : }
    1856             : 
    1857             : /*****************************************************************
    1858             :  Is this directory empty ?
    1859             : *****************************************************************/
    1860             : 
    1861       10372 : NTSTATUS can_delete_directory_fsp(files_struct *fsp)
    1862             : {
    1863       10372 :         NTSTATUS status = NT_STATUS_OK;
    1864       10372 :         long dirpos = 0;
    1865       10372 :         const char *dname = NULL;
    1866       10372 :         char *talloced = NULL;
    1867             :         SMB_STRUCT_STAT st;
    1868       10372 :         struct connection_struct *conn = fsp->conn;
    1869       10372 :         struct smb_Dir *dir_hnd = OpenDir(talloc_tos(),
    1870             :                                         conn,
    1871       10372 :                                         fsp->fsp_name,
    1872             :                                         NULL,
    1873             :                                         0);
    1874             : 
    1875       10372 :         if (!dir_hnd) {
    1876           0 :                 return map_nt_error_from_unix(errno);
    1877             :         }
    1878             : 
    1879       39540 :         while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) {
    1880       20928 :                 struct smb_filename *smb_dname_full = NULL;
    1881       20928 :                 struct smb_filename *direntry_fname = NULL;
    1882       20928 :                 char *fullname = NULL;
    1883             :                 int ret;
    1884             : 
    1885       20928 :                 if (ISDOT(dname) || (ISDOTDOT(dname))) {
    1886       20744 :                         TALLOC_FREE(talloced);
    1887       37728 :                         continue;
    1888             :                 }
    1889         184 :                 if (IS_VETO_PATH(conn, dname)) {
    1890           0 :                         TALLOC_FREE(talloced);
    1891           0 :                         continue;
    1892             :                 }
    1893             : 
    1894         184 :                 fullname = talloc_asprintf(talloc_tos(),
    1895             :                                            "%s/%s",
    1896         184 :                                            fsp->fsp_name->base_name,
    1897             :                                            dname);
    1898         184 :                 if (fullname == NULL) {
    1899           0 :                         status = NT_STATUS_NO_MEMORY;
    1900         163 :                         break;
    1901             :                 }
    1902             : 
    1903         343 :                 smb_dname_full = synthetic_smb_fname(talloc_tos(),
    1904             :                                                      fullname,
    1905             :                                                      NULL,
    1906             :                                                      NULL,
    1907         180 :                                                      fsp->fsp_name->twrp,
    1908         184 :                                                      fsp->fsp_name->flags);
    1909         184 :                 if (smb_dname_full == NULL) {
    1910           0 :                         TALLOC_FREE(talloced);
    1911           0 :                         TALLOC_FREE(fullname);
    1912           0 :                         status = NT_STATUS_NO_MEMORY;
    1913           0 :                         break;
    1914             :                 }
    1915             : 
    1916         184 :                 ret = SMB_VFS_LSTAT(conn, smb_dname_full);
    1917         184 :                 if (ret != 0) {
    1918           0 :                         status = map_nt_error_from_unix(errno);
    1919           0 :                         TALLOC_FREE(talloced);
    1920           0 :                         TALLOC_FREE(fullname);
    1921           0 :                         TALLOC_FREE(smb_dname_full);
    1922           0 :                         break;
    1923             :                 }
    1924             : 
    1925             :                 /*
    1926             :                  * is_visible_fsp() always returns true
    1927             :                  * for the symlink/MSDFS case.
    1928             :                  */
    1929             : 
    1930         184 :                 if (S_ISLNK(smb_dname_full->st.st_ex_mode)) {
    1931           0 :                         TALLOC_FREE(talloced);
    1932           0 :                         TALLOC_FREE(fullname);
    1933           0 :                         TALLOC_FREE(smb_dname_full);
    1934           0 :                         DBG_DEBUG("got name %s - can't delete\n", dname);
    1935           0 :                         status = NT_STATUS_DIRECTORY_NOT_EMPTY;
    1936           0 :                         break;
    1937             :                 }
    1938             : 
    1939             :                 /* Not a symlink, get a pathref. */
    1940         506 :                 status = synthetic_pathref(talloc_tos(),
    1941             :                                            fsp,
    1942             :                                            dname,
    1943             :                                            NULL,
    1944         184 :                                            &smb_dname_full->st,
    1945         180 :                                            fsp->fsp_name->twrp,
    1946         184 :                                            fsp->fsp_name->flags,
    1947             :                                            &direntry_fname);
    1948         184 :                 if (!NT_STATUS_IS_OK(status)) {
    1949           0 :                         status = map_nt_error_from_unix(errno);
    1950           0 :                         TALLOC_FREE(talloced);
    1951           0 :                         TALLOC_FREE(fullname);
    1952           0 :                         TALLOC_FREE(smb_dname_full);
    1953           0 :                         break;
    1954             :                 }
    1955             : 
    1956         184 :                 if (!is_visible_fsp(direntry_fname->fsp)) {
    1957           0 :                         TALLOC_FREE(talloced);
    1958           0 :                         TALLOC_FREE(fullname);
    1959           0 :                         TALLOC_FREE(smb_dname_full);
    1960           0 :                         TALLOC_FREE(direntry_fname);
    1961           0 :                         continue;
    1962             :                 }
    1963             : 
    1964         184 :                 TALLOC_FREE(talloced);
    1965         184 :                 TALLOC_FREE(fullname);
    1966         184 :                 TALLOC_FREE(smb_dname_full);
    1967         184 :                 TALLOC_FREE(direntry_fname);
    1968             : 
    1969         184 :                 DBG_DEBUG("got name %s - can't delete\n", dname);
    1970         180 :                 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
    1971         180 :                 break;
    1972             :         }
    1973       10372 :         TALLOC_FREE(talloced);
    1974       10372 :         TALLOC_FREE(dir_hnd);
    1975             : 
    1976       10372 :         if (!NT_STATUS_IS_OK(status)) {
    1977         184 :                 return status;
    1978             :         }
    1979             : 
    1980       20328 :         if (!(fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) &&
    1981       15876 :             lp_strict_rename(SNUM(conn)) &&
    1982        5736 :             have_file_open_below(fsp->conn, fsp->fsp_name))
    1983             :         {
    1984           0 :                 return NT_STATUS_ACCESS_DENIED;
    1985             :         }
    1986             : 
    1987       10188 :         return NT_STATUS_OK;
    1988             : }

Generated by: LCOV version 1.13