LCOV - code coverage report
Current view: top level - source3/smbd - dir.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 371 861 43.1 %
Date: 2024-06-13 04:01:37 Functions: 21 48 43.8 %

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

Generated by: LCOV version 1.13