LCOV - code coverage report
Current view: top level - source3/smbd - dir.c (source / functions) Hit Total Coverage
Test: coverage report for fix-15632 9995c5c2 Lines: 510 641 79.6 %
Date: 2024-04-13 12:30:31 Functions: 35 38 92.1 %

          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             : #include "libcli/smb/reparse.h"
      32             : #include "source3/smbd/dir.h"
      33             : 
      34             : /*
      35             :    This module implements directory related functions for Samba.
      36             : */
      37             : 
      38             : /* "Special" directory offsets. */
      39             : #define END_OF_DIRECTORY_OFFSET ((long)-1)
      40             : #define START_OF_DIRECTORY_OFFSET ((long)0)
      41             : #define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
      42             : 
      43             : /* Make directory handle internals available. */
      44             : 
      45             : struct smb_Dir {
      46             :         connection_struct *conn;
      47             :         DIR *dir;
      48             :         struct smb_filename *dir_smb_fname;
      49             :         unsigned int file_number;
      50             :         bool case_sensitive;
      51             :         files_struct *fsp; /* Back pointer to containing fsp, only
      52             :                               set from OpenDir_fsp(). */
      53             : };
      54             : 
      55             : struct dptr_struct {
      56             :         struct dptr_struct *next, *prev;
      57             :         int dnum;
      58             :         struct smb_Dir *dir_hnd;
      59             :         char *wcard;
      60             :         uint32_t attr;
      61             :         bool has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
      62             :         bool did_stat; /* Optimisation for non-wcard searches. */
      63             :         bool priv;     /* Directory handle opened with privilege. */
      64             :         uint32_t counter;
      65             : 
      66             :         char *last_name_sent;   /* for name-based trans2 resume */
      67             : 
      68             :         struct {
      69             :                 char *fname;
      70             :                 struct smb_filename *smb_fname;
      71             :                 uint32_t mode;
      72             :         } overflow;
      73             : };
      74             : 
      75             : static NTSTATUS OpenDir_fsp(
      76             :         TALLOC_CTX *mem_ctx,
      77             :         connection_struct *conn,
      78             :         files_struct *fsp,
      79             :         const char *mask,
      80             :         uint32_t attr,
      81             :         struct smb_Dir **_dir_hnd);
      82             : 
      83             : static int smb_Dir_destructor(struct smb_Dir *dir_hnd);
      84             : 
      85             : #define INVALID_DPTR_KEY (-3)
      86             : 
      87             : /****************************************************************************
      88             :  Initialise the dir bitmap.
      89             : ****************************************************************************/
      90             : 
      91       31066 : bool init_dptrs(struct smbd_server_connection *sconn)
      92             : {
      93       31066 :         if (sconn->searches.dptr_bmap) {
      94           0 :                 return true;
      95             :         }
      96             : 
      97       31066 :         sconn->searches.dptr_bmap = bitmap_talloc(
      98             :                 sconn, MAX_DIRECTORY_HANDLES);
      99             : 
     100       31066 :         if (sconn->searches.dptr_bmap == NULL) {
     101           0 :                 return false;
     102             :         }
     103             : 
     104       30224 :         return true;
     105             : }
     106             : 
     107             : /****************************************************************************
     108             :  Get the struct dptr_struct for a dir index.
     109             : ****************************************************************************/
     110             : 
     111        8496 : static struct dptr_struct *dptr_get(struct smbd_server_connection *sconn,
     112             :                                     int key)
     113             : {
     114           0 :         struct dptr_struct *dptr;
     115             : 
     116       13056 :         for (dptr = sconn->searches.dirptrs; dptr != NULL; dptr = dptr->next) {
     117       13048 :                 if(dptr->dnum != key) {
     118        4560 :                         continue;
     119             :                 }
     120        8488 :                 DLIST_PROMOTE(sconn->searches.dirptrs, dptr);
     121        8488 :                 return dptr;
     122             :         }
     123           8 :         return(NULL);
     124             : }
     125             : 
     126             : /****************************************************************************
     127             :  Get the dir path for a dir index.
     128             : ****************************************************************************/
     129             : 
     130        2224 : const char *dptr_path(struct smbd_server_connection *sconn, int key)
     131             : {
     132        2224 :         struct dptr_struct *dptr = dptr_get(sconn, key);
     133        2224 :         if (dptr)
     134        2224 :                 return(dptr->dir_hnd->dir_smb_fname->base_name);
     135           0 :         return(NULL);
     136             : }
     137             : 
     138             : /****************************************************************************
     139             :  Get the dir wcard for a dir index.
     140             : ****************************************************************************/
     141             : 
     142        2168 : const char *dptr_wcard(struct smbd_server_connection *sconn, int key)
     143             : {
     144        2168 :         struct dptr_struct *dptr = dptr_get(sconn, key);
     145        2168 :         if (dptr)
     146        2168 :                 return(dptr->wcard);
     147           0 :         return(NULL);
     148             : }
     149             : 
     150             : /****************************************************************************
     151             :  Get the dir attrib for a dir index.
     152             : ****************************************************************************/
     153             : 
     154        2048 : uint16_t dptr_attr(struct smbd_server_connection *sconn, int key)
     155             : {
     156        2048 :         struct dptr_struct *dptr = dptr_get(sconn, key);
     157        2048 :         if (dptr)
     158        2048 :                 return(dptr->attr);
     159           0 :         return(0);
     160             : }
     161             : 
     162             : /****************************************************************************
     163             :  Close all dptrs for a cnum.
     164             : ****************************************************************************/
     165             : 
     166           0 : void dptr_closecnum(connection_struct *conn)
     167             : {
     168           0 :         struct dptr_struct *dptr, *next;
     169           0 :         struct smbd_server_connection *sconn = conn->sconn;
     170             : 
     171           0 :         if (sconn == NULL) {
     172           0 :                 return;
     173             :         }
     174             : 
     175           0 :         for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
     176           0 :                 next = dptr->next;
     177           0 :                 if (dptr->dir_hnd->conn == conn) {
     178             :                         /*
     179             :                          * Need to make a copy, "dptr" will be gone
     180             :                          * after close_file_free() returns
     181             :                          */
     182           0 :                         struct files_struct *fsp = dptr->dir_hnd->fsp;
     183           0 :                         close_file_free(NULL, &fsp, NORMAL_CLOSE);
     184             :                 }
     185             :         }
     186             : }
     187             : 
     188             : /****************************************************************************
     189             :  Create a new dir ptr. If the flag old_handle is true then we must allocate
     190             :  from the bitmap range 0 - 255 as old SMBsearch directory handles are only
     191             :  one byte long. If old_handle is false we allocate from the range
     192             :  256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
     193             :  a directory handle is never zero.
     194             :  wcard must not be zero.
     195             : ****************************************************************************/
     196             : 
     197       18692 : NTSTATUS dptr_create(connection_struct *conn,
     198             :                 struct smb_request *req,
     199             :                 files_struct *fsp,
     200             :                 bool old_handle,
     201             :                 const char *wcard,
     202             :                 uint32_t attr,
     203             :                 struct dptr_struct **dptr_ret)
     204             : {
     205       18692 :         struct smbd_server_connection *sconn = conn->sconn;
     206       18692 :         struct dptr_struct *dptr = NULL;
     207       18692 :         struct smb_Dir *dir_hnd = NULL;
     208         176 :         NTSTATUS status;
     209             : 
     210       18692 :         DBG_INFO("dir=%s\n", fsp_str_dbg(fsp));
     211             : 
     212       18692 :         if (sconn == NULL) {
     213           0 :                 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
     214           0 :                 return NT_STATUS_INTERNAL_ERROR;
     215             :         }
     216             : 
     217       18692 :         if (!wcard) {
     218           0 :                 return NT_STATUS_INVALID_PARAMETER;
     219             :         }
     220             : 
     221       18692 :         status = check_any_access_fsp(fsp, SEC_DIR_LIST);
     222       18692 :         if (!NT_STATUS_IS_OK(status)) {
     223           0 :                 DBG_INFO("dptr_create: directory %s "
     224             :                         "not open for LIST access\n",
     225             :                         fsp_str_dbg(fsp));
     226           0 :                 return status;
     227             :         }
     228       18692 :         status = OpenDir_fsp(NULL, conn, fsp, wcard, attr, &dir_hnd);
     229       18692 :         if (!NT_STATUS_IS_OK(status)) {
     230           0 :                 return status;
     231             :         }
     232             : 
     233       18692 :         dptr = talloc_zero(NULL, struct dptr_struct);
     234       18692 :         if(!dptr) {
     235           0 :                 DEBUG(0,("talloc fail in dptr_create.\n"));
     236           0 :                 TALLOC_FREE(dir_hnd);
     237           0 :                 return NT_STATUS_NO_MEMORY;
     238             :         }
     239             : 
     240       18692 :         dptr->dir_hnd = dir_hnd;
     241       18692 :         dptr->wcard = talloc_strdup(dptr, wcard);
     242       18692 :         if (!dptr->wcard) {
     243           0 :                 TALLOC_FREE(dptr);
     244           0 :                 TALLOC_FREE(dir_hnd);
     245           0 :                 return NT_STATUS_NO_MEMORY;
     246             :         }
     247       18692 :         if ((req != NULL && req->posix_pathnames) || ISDOT(wcard)) {
     248          92 :                 dptr->has_wild = True;
     249             :         } else {
     250       18600 :                 dptr->has_wild = ms_has_wild(dptr->wcard);
     251             :         }
     252             : 
     253       18692 :         dptr->attr = attr;
     254             : 
     255       18692 :         if (sconn->using_smb2) {
     256       10033 :                 goto done;
     257             :         }
     258             : 
     259        8659 :         if(old_handle) {
     260             : 
     261             :                 /*
     262             :                  * This is an old-style SMBsearch request. Ensure the
     263             :                  * value we return will fit in the range 1-255.
     264             :                  */
     265             : 
     266         176 :                 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
     267             : 
     268         176 :                 if(dptr->dnum == -1 || dptr->dnum > 254) {
     269           0 :                         DBG_ERR("returned %d: Error - all old "
     270             :                                 "dirptrs in use ?\n",
     271             :                                 dptr->dnum);
     272           0 :                         TALLOC_FREE(dptr);
     273           0 :                         TALLOC_FREE(dir_hnd);
     274           0 :                         return NT_STATUS_TOO_MANY_OPENED_FILES;
     275             :                 }
     276             :         } else {
     277             : 
     278             :                 /*
     279             :                  * This is a new-style trans2 request. Allocate from
     280             :                  * a range that will return 256 - MAX_DIRECTORY_HANDLES.
     281             :                  */
     282             : 
     283        8483 :                 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
     284             : 
     285        8483 :                 if(dptr->dnum == -1 || dptr->dnum < 255) {
     286           0 :                         DBG_ERR("returned %d: Error - all new "
     287             :                                 "dirptrs in use ?\n",
     288             :                                 dptr->dnum);
     289           0 :                         TALLOC_FREE(dptr);
     290           0 :                         TALLOC_FREE(dir_hnd);
     291           0 :                         return NT_STATUS_TOO_MANY_OPENED_FILES;
     292             :                 }
     293             :         }
     294             : 
     295        8659 :         bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
     296             : 
     297        8659 :         dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
     298             : 
     299        8659 :         DLIST_ADD(sconn->searches.dirptrs, dptr);
     300             : 
     301       18692 : done:
     302       18692 :         DBG_INFO("creating new dirptr [%d] for path [%s]\n",
     303             :                  dptr->dnum, fsp_str_dbg(fsp));
     304             : 
     305       18692 :         *dptr_ret = dptr;
     306             : 
     307       18692 :         return NT_STATUS_OK;
     308             : }
     309             : 
     310             : 
     311             : /****************************************************************************
     312             :  Wrapper functions to access the lower level directory handles.
     313             : ****************************************************************************/
     314             : 
     315       18692 : void dptr_CloseDir(files_struct *fsp)
     316             : {
     317       18692 :         struct smbd_server_connection *sconn = NULL;
     318             : 
     319       18692 :         if (fsp->dptr == NULL) {
     320           0 :                 return;
     321             :         }
     322       18692 :         sconn = fsp->conn->sconn;
     323             : 
     324             :         /*
     325             :          * The destructor for the struct smb_Dir (fsp->dptr->dir_hnd)
     326             :          * now handles all resource deallocation.
     327             :          */
     328             : 
     329       18692 :         DBG_INFO("closing dptr key %d\n", fsp->dptr->dnum);
     330             : 
     331       18692 :         if (sconn != NULL && !sconn->using_smb2) {
     332        8659 :                 DLIST_REMOVE(sconn->searches.dirptrs, fsp->dptr);
     333             : 
     334             :                 /*
     335             :                  * Free the dnum in the bitmap. Remember the dnum value is
     336             :                  * always biased by one with respect to the bitmap.
     337             :                  */
     338             : 
     339        8659 :                 if (!bitmap_query(sconn->searches.dptr_bmap,
     340        8659 :                                   fsp->dptr->dnum - 1))
     341             :                 {
     342           0 :                         DBG_ERR("closing dnum = %d and bitmap not set !\n",
     343             :                                 fsp->dptr->dnum);
     344             :                 }
     345             : 
     346        8659 :                 bitmap_clear(sconn->searches.dptr_bmap, fsp->dptr->dnum - 1);
     347             :         }
     348             : 
     349       18692 :         TALLOC_FREE(fsp->dptr->dir_hnd);
     350       18692 :         TALLOC_FREE(fsp->dptr);
     351             : }
     352             : 
     353        2728 : void dptr_RewindDir(struct dptr_struct *dptr)
     354             : {
     355        2728 :         RewindDir(dptr->dir_hnd);
     356        2728 :         dptr->did_stat = false;
     357        2728 :         TALLOC_FREE(dptr->overflow.fname);
     358        2728 :         TALLOC_FREE(dptr->overflow.smb_fname);
     359        2728 : }
     360             : 
     361       83440 : unsigned int dptr_FileNumber(struct dptr_struct *dptr)
     362             : {
     363       83440 :         return dptr->dir_hnd->file_number;
     364             : }
     365             : 
     366         500 : bool dptr_has_wild(struct dptr_struct *dptr)
     367             : {
     368         500 :         return dptr->has_wild;
     369             : }
     370             : 
     371        8659 : int dptr_dnum(struct dptr_struct *dptr)
     372             : {
     373        8659 :         return dptr->dnum;
     374             : }
     375             : 
     376        1724 : bool dptr_get_priv(struct dptr_struct *dptr)
     377             : {
     378        1724 :         return dptr->priv;
     379             : }
     380             : 
     381           0 : void dptr_set_priv(struct dptr_struct *dptr)
     382             : {
     383           0 :         dptr->priv = true;
     384           0 : }
     385             : 
     386     1301132 : bool dptr_case_sensitive(struct dptr_struct *dptr)
     387             : {
     388     1301132 :         return dptr->dir_hnd->case_sensitive;
     389             : }
     390             : 
     391             : /****************************************************************************
     392             :  Return the next visible file name, skipping veto'd and invisible files.
     393             : ****************************************************************************/
     394             : 
     395     1334064 : char *dptr_ReadDirName(TALLOC_CTX *ctx, struct dptr_struct *dptr)
     396             : {
     397     1334064 :         struct stat_ex st = {
     398             :                 .st_ex_nlink = 0,
     399             :         };
     400     1334064 :         struct smb_Dir *dir_hnd = dptr->dir_hnd;
     401     1334064 :         struct files_struct *dir_fsp = dir_hnd->fsp;
     402     1334064 :         struct smb_filename *dir_name = dir_fsp->fsp_name;
     403         404 :         struct smb_filename smb_fname_base;
     404     1334064 :         bool retry_scanning = false;
     405         404 :         int ret;
     406     1334064 :         int flags = 0;
     407             : 
     408     1334064 :         if (dptr->has_wild) {
     409     1330055 :                 const char *name_temp = NULL;
     410     1330055 :                 char *talloced = NULL;
     411     1330055 :                 name_temp = ReadDirName(dir_hnd, &talloced);
     412     1330055 :                 if (name_temp == NULL) {
     413       26316 :                         return NULL;
     414             :                 }
     415     1303650 :                 if (talloced != NULL) {
     416         430 :                         return talloc_move(ctx, &talloced);
     417             :                 }
     418     1303220 :                 return talloc_strdup(ctx, name_temp);
     419             :         }
     420             : 
     421        4009 :         if (dptr->did_stat) {
     422             :                 /*
     423             :                  * No wildcard, this is not a real directory traverse
     424             :                  * but a "stat" call behind a query_directory. We've
     425             :                  * been here, nothing else to look at.
     426             :                  */
     427        1992 :                 return NULL;
     428             :         }
     429        2017 :         dptr->did_stat = true;
     430             : 
     431             :         /* Create an smb_filename with stream_name == NULL. */
     432        2017 :         smb_fname_base = (struct smb_filename){
     433        2017 :                 .base_name = dptr->wcard,
     434        2017 :                 .flags = dir_name->flags,
     435        2017 :                 .twrp = dir_name->twrp,
     436             :         };
     437             : 
     438        2017 :         if (dir_name->flags & SMB_FILENAME_POSIX_PATH) {
     439           2 :                 flags |= AT_SYMLINK_NOFOLLOW;
     440             :         }
     441             : 
     442        2017 :         ret = SMB_VFS_FSTATAT(
     443             :                 dir_hnd->conn, dir_fsp, &smb_fname_base, &st, flags);
     444        2017 :         if (ret == 0) {
     445        1701 :                 return talloc_strdup(ctx, dptr->wcard);
     446             :         }
     447             : 
     448             :         /*
     449             :          * If we get any other error than ENOENT or ENOTDIR
     450             :          * then the file exists, we just can't stat it.
     451             :          */
     452         316 :         if (errno != ENOENT && errno != ENOTDIR) {
     453           0 :                 return talloc_strdup(ctx, dptr->wcard);
     454             :         }
     455             : 
     456             :         /*
     457             :          * A scan will find the long version of a mangled name as
     458             :          * wildcard.
     459             :          */
     460         632 :         retry_scanning |= mangle_is_mangled(dptr->wcard,
     461         316 :                                             dir_hnd->conn->params);
     462             : 
     463             :         /*
     464             :          * Also retry scanning if the client requested case
     465             :          * insensitive semantics and the file system does not provide
     466             :          * it.
     467             :          */
     468         632 :         retry_scanning |= (!dir_hnd->case_sensitive &&
     469         316 :                            (dir_hnd->conn->fs_capabilities &
     470             :                             FILE_CASE_SENSITIVE_SEARCH));
     471             : 
     472         316 :         if (retry_scanning) {
     473         316 :                 char *found_name = NULL;
     474           0 :                 NTSTATUS status;
     475             : 
     476         316 :                 status = get_real_filename_at(dir_fsp,
     477         316 :                                               dptr->wcard,
     478             :                                               ctx,
     479             :                                               &found_name);
     480         316 :                 if (NT_STATUS_IS_OK(status)) {
     481          47 :                         return found_name;
     482             :                 }
     483             :         }
     484             : 
     485         269 :         return NULL;
     486             : }
     487             : 
     488           6 : struct files_struct *dir_hnd_fetch_fsp(struct smb_Dir *dir_hnd)
     489             : {
     490           6 :         return dir_hnd->fsp;
     491             : }
     492             : 
     493             : /****************************************************************************
     494             :  Fetch the fsp associated with the dptr_num.
     495             : ****************************************************************************/
     496             : 
     497        2056 : files_struct *dptr_fetch_lanman2_fsp(struct smbd_server_connection *sconn,
     498             :                                        int dptr_num)
     499             : {
     500        2056 :         struct dptr_struct *dptr  = dptr_get(sconn, dptr_num);
     501        2056 :         if (dptr == NULL) {
     502           8 :                 return NULL;
     503             :         }
     504        2048 :         DBG_NOTICE("fetching dirptr %d for path %s\n",
     505             :                    dptr_num,
     506             :                    dptr->dir_hnd->dir_smb_fname->base_name);
     507        2048 :         return dptr->dir_hnd->fsp;
     508             : }
     509             : 
     510      942894 : bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
     511             :                            struct dptr_struct *dirptr,
     512             :                            const char *mask,
     513             :                            uint32_t dirtype,
     514             :                            bool dont_descend,
     515             :                            bool ask_sharemode,
     516             :                            bool get_dosmode_in,
     517             :                            bool (*match_fn)(TALLOC_CTX *ctx,
     518             :                                             void *private_data,
     519             :                                             const char *dname,
     520             :                                             const char *mask,
     521             :                                             char **_fname),
     522             :                            void *private_data,
     523             :                            char **_fname,
     524             :                            struct smb_filename **_smb_fname,
     525             :                            uint32_t *_mode)
     526             : {
     527      942894 :         struct smb_Dir *dir_hnd = dirptr->dir_hnd;
     528      942894 :         connection_struct *conn = dir_hnd->conn;
     529      942894 :         struct smb_filename *dir_fname = dir_hnd->dir_smb_fname;
     530      942894 :         bool posix = (dir_fname->flags & SMB_FILENAME_POSIX_PATH);
     531      942894 :         const bool toplevel = ISDOT(dir_fname->base_name);
     532         316 :         NTSTATUS status;
     533             : 
     534      942894 :         *_smb_fname = NULL;
     535      942894 :         *_mode = 0;
     536             : 
     537      942894 :         if (dirptr->overflow.smb_fname != NULL) {
     538         668 :                 *_fname = talloc_move(ctx, &dirptr->overflow.fname);
     539         668 :                 *_smb_fname = talloc_move(ctx, &dirptr->overflow.smb_fname);
     540         668 :                 *_mode = dirptr->overflow.mode;
     541         668 :                 return true;
     542             :         }
     543             : 
     544      942226 :         if (dont_descend && (dptr_FileNumber(dirptr) >= 2)) {
     545             :                 /*
     546             :                  * . and .. were returned first, we're done showing
     547             :                  * the directory as empty.
     548             :                  */
     549           0 :                 return false;
     550             :         }
     551             : 
     552       23704 :         while (true) {
     553      965526 :                 char *dname = NULL;
     554      965526 :                 char *fname = NULL;
     555      965526 :                 struct smb_filename *smb_fname = NULL;
     556      965526 :                 uint32_t mode = 0;
     557      965526 :                 bool get_dosmode = get_dosmode_in;
     558         404 :                 bool toplevel_dotdot;
     559         404 :                 bool visible;
     560         404 :                 bool ok;
     561             : 
     562      965526 :                 dname = dptr_ReadDirName(ctx, dirptr);
     563             : 
     564      965526 :                 DBG_DEBUG("dir [%s] dirptr [%p] offset [%u] => "
     565             :                           "dname [%s]\n",
     566             :                           smb_fname_str_dbg(dir_fname),
     567             :                           dirptr,
     568             :                           dir_hnd->file_number,
     569             :                           dname ? dname : "(finished)");
     570             : 
     571      965526 :                 if (dname == NULL) {
     572      942226 :                         return false;
     573             :                 }
     574             : 
     575      937904 :                 if (IS_VETO_PATH(conn, dname)) {
     576           6 :                         TALLOC_FREE(dname);
     577       23300 :                         continue;
     578             :                 }
     579             : 
     580             :                 /*
     581             :                  * fname may get mangled, dname is never mangled.
     582             :                  * Whenever we're accessing the filesystem we use
     583             :                  * pathreal which is composed from dname.
     584             :                  */
     585             : 
     586      937898 :                 ok = match_fn(ctx, private_data, dname, mask, &fname);
     587      937898 :                 if (!ok) {
     588        6248 :                         TALLOC_FREE(dname);
     589        6248 :                         continue;
     590             :                 }
     591             : 
     592      931650 :                 toplevel_dotdot = toplevel && ISDOTDOT(dname);
     593             : 
     594      931965 :                 smb_fname = synthetic_smb_fname(talloc_tos(),
     595             :                                                 toplevel_dotdot ? "." : dname,
     596             :                                                 NULL,
     597             :                                                 NULL,
     598             :                                                 dir_fname->twrp,
     599             :                                                 dir_fname->flags);
     600      931650 :                 if (smb_fname == NULL) {
     601           0 :                         TALLOC_FREE(dname);
     602           0 :                         return false;
     603             :                 }
     604             : 
     605             :                 /*
     606             :                  * UCF_POSIX_PATHNAMES to avoid the readdir fallback
     607             :                  * if we get raced between readdir and unlink.
     608             :                  */
     609      931650 :                 status = openat_pathref_fsp_lcomp(dir_hnd->fsp,
     610             :                                                   smb_fname,
     611             :                                                   UCF_POSIX_PATHNAMES);
     612      931650 :                 if (!NT_STATUS_IS_OK(status)) {
     613           6 :                         DBG_DEBUG("Could not open %s: %s\n",
     614             :                                   dname,
     615             :                                   nt_errstr(status));
     616           6 :                         TALLOC_FREE(smb_fname);
     617           6 :                         TALLOC_FREE(fname);
     618           6 :                         TALLOC_FREE(dname);
     619           6 :                         continue;
     620             :                 }
     621             : 
     622      931644 :                 visible = is_visible_fsp(smb_fname->fsp);
     623      931644 :                 if (!visible) {
     624          32 :                         TALLOC_FREE(smb_fname);
     625          32 :                         TALLOC_FREE(fname);
     626          32 :                         TALLOC_FREE(dname);
     627          32 :                         continue;
     628             :                 }
     629             : 
     630      931612 :                 if (!S_ISLNK(smb_fname->st.st_ex_mode)) {
     631      928870 :                         goto done;
     632             :                 }
     633             : 
     634        3114 :                 if (lp_host_msdfs() && lp_msdfs_root(SNUM(conn)) &&
     635         372 :                     is_msdfs_link(dir_hnd->fsp, smb_fname))
     636             :                 {
     637         370 :                         DBG_INFO("Masquerading msdfs link %s as a directory\n",
     638             :                                  smb_fname->base_name);
     639             : 
     640         370 :                         smb_fname->st.st_ex_mode = (smb_fname->st.st_ex_mode &
     641         370 :                                                     ~S_IFMT) |
     642             :                                                    S_IFDIR;
     643             : 
     644         370 :                         mode = dos_mode_msdfs(conn, dname, &smb_fname->st);
     645         370 :                         get_dosmode = false;
     646         370 :                         ask_sharemode = false;
     647         370 :                         goto done;
     648             :                 }
     649             : 
     650        2372 :                 if (posix) {
     651             :                         /*
     652             :                          * Posix always wants to see symlinks.
     653             :                          */
     654          52 :                         ask_sharemode = false;
     655          52 :                         goto done;
     656             :                 }
     657             : 
     658        2320 :                 if (!lp_follow_symlinks(SNUM(conn))) {
     659             :                         /*
     660             :                          * Hide symlinks not followed
     661             :                          */
     662           0 :                         TALLOC_FREE(smb_fname);
     663           0 :                         TALLOC_FREE(fname);
     664           0 :                         TALLOC_FREE(dname);
     665           0 :                         continue;
     666             :                 }
     667             : 
     668             :                 /*
     669             :                  * We have to find out if it's a dangling
     670             :                  * symlink. Use the fat logic behind
     671             :                  * openat_pathref_fsp().
     672             :                  */
     673             : 
     674             :                 {
     675        2320 :                         struct files_struct *fsp = smb_fname->fsp;
     676        2320 :                         smb_fname_fsp_unlink(smb_fname);
     677        2320 :                         fd_close(fsp);
     678        2320 :                         file_free(NULL, fsp);
     679             :                 }
     680             : 
     681        2320 :                 status = openat_pathref_fsp(dir_hnd->fsp, smb_fname);
     682             : 
     683        2320 :                 if (!NT_STATUS_IS_OK(status)) {
     684             :                         /*
     685             :                          * Dangling symlink. Hide.
     686             :                          */
     687         492 :                         TALLOC_FREE(smb_fname);
     688         492 :                         TALLOC_FREE(fname);
     689         492 :                         TALLOC_FREE(dname);
     690         492 :                         continue;
     691             :                 }
     692             : 
     693        1828 : done:
     694      931120 :                 if (get_dosmode) {
     695      910612 :                         mode = fdos_mode(smb_fname->fsp);
     696      910612 :                         smb_fname->st = smb_fname->fsp->fsp_name->st;
     697             :                 }
     698             : 
     699      931120 :                 if (!dir_check_ftype(mode, dirtype)) {
     700       16516 :                         DBG_INFO("[%s] attribs 0x%" PRIx32 " didn't match "
     701             :                                  "0x%" PRIx32 "\n",
     702             :                                  fname,
     703             :                                  mode,
     704             :                                  dirtype);
     705       16516 :                         TALLOC_FREE(smb_fname);
     706       16516 :                         TALLOC_FREE(dname);
     707       16516 :                         TALLOC_FREE(fname);
     708       16516 :                         continue;
     709             :                 }
     710             : 
     711      914604 :                 if (ask_sharemode && !S_ISDIR(smb_fname->st.st_ex_mode)) {
     712         115 :                         struct timespec write_time_ts;
     713         115 :                         struct file_id fileid;
     714             : 
     715      716914 :                         fileid = vfs_file_id_from_sbuf(conn,
     716      716914 :                                                        &smb_fname->st);
     717      716914 :                         get_file_infos(fileid, 0, NULL, &write_time_ts);
     718      716914 :                         if (!is_omit_timespec(&write_time_ts)) {
     719         918 :                                 update_stat_ex_mtime(&smb_fname->st,
     720             :                                                      write_time_ts);
     721             :                         }
     722             :                 }
     723             : 
     724      914604 :                 if (toplevel_dotdot) {
     725             :                         /*
     726             :                          * Ensure posix fileid and sids are hidden
     727             :                          */
     728        1489 :                         smb_fname->st.st_ex_ino = 0;
     729        1489 :                         smb_fname->st.st_ex_dev = 0;
     730        1489 :                         smb_fname->st.st_ex_uid = -1;
     731        1489 :                         smb_fname->st.st_ex_gid = -1;
     732             :                 }
     733             : 
     734      914604 :                 DBG_NOTICE("mask=[%s] found %s fname=%s (%s)\n",
     735             :                            mask,
     736             :                            smb_fname_str_dbg(smb_fname),
     737             :                            dname,
     738             :                            fname);
     739             : 
     740      914604 :                 TALLOC_FREE(dname);
     741             : 
     742      914604 :                 *_smb_fname = talloc_move(ctx, &smb_fname);
     743      914604 :                 *_fname = fname;
     744      914604 :                 *_mode = mode;
     745             : 
     746      914604 :                 return true;
     747             :         }
     748             : 
     749             :         return false;
     750             : }
     751             : 
     752         668 : void smbd_dirptr_push_overflow(struct dptr_struct *dirptr,
     753             :                                char **_fname,
     754             :                                struct smb_filename **_smb_fname,
     755             :                                uint32_t mode)
     756             : {
     757         668 :         SMB_ASSERT(dirptr->overflow.fname == NULL);
     758         668 :         SMB_ASSERT(dirptr->overflow.smb_fname == NULL);
     759             : 
     760         668 :         dirptr->overflow.fname = talloc_move(dirptr, _fname);
     761         668 :         dirptr->overflow.smb_fname = talloc_move(dirptr, _smb_fname);
     762         668 :         dirptr->overflow.mode = mode;
     763         668 : }
     764             : 
     765      893725 : void smbd_dirptr_set_last_name_sent(struct dptr_struct *dirptr,
     766             :                                     char **_fname)
     767             : {
     768      893725 :         TALLOC_FREE(dirptr->last_name_sent);
     769      893725 :         dirptr->last_name_sent = talloc_move(dirptr, _fname);
     770      893725 : }
     771             : 
     772        1424 : char *smbd_dirptr_get_last_name_sent(struct dptr_struct *dirptr)
     773             : {
     774        1424 :         return dirptr->last_name_sent;
     775             : }
     776             : 
     777             : /*******************************************************************
     778             :  Check to see if a user can read an fsp . This is only approximate,
     779             :  it is used as part of the "hide unreadable" option. Don't
     780             :  use it for anything security sensitive.
     781             : ********************************************************************/
     782             : 
     783         118 : static bool user_can_read_fsp(struct files_struct *fsp)
     784             : {
     785           0 :         NTSTATUS status;
     786         118 :         uint32_t rejected_share_access = 0;
     787         118 :         uint32_t rejected_mask = 0;
     788         118 :         struct security_descriptor *sd = NULL;
     789         118 :         uint32_t access_mask = FILE_READ_DATA|
     790             :                                 FILE_READ_EA|
     791             :                                 FILE_READ_ATTRIBUTES|
     792             :                                 SEC_STD_READ_CONTROL;
     793             : 
     794             :         /*
     795             :          * Never hide files from the root user.
     796             :          * We use (uid_t)0 here not sec_initial_uid()
     797             :          * as make test uses a single user context.
     798             :          */
     799             : 
     800         118 :         if (get_current_uid(fsp->conn) == (uid_t)0) {
     801           0 :                 return true;
     802             :         }
     803             : 
     804             :         /*
     805             :          * We can't directly use smbd_check_access_rights_fsp()
     806             :          * here, as this implicitly grants FILE_READ_ATTRIBUTES
     807             :          * which the Windows access-based-enumeration code
     808             :          * explicitly checks for on the file security descriptor.
     809             :          * See bug:
     810             :          *
     811             :          * https://bugzilla.samba.org/show_bug.cgi?id=10252
     812             :          *
     813             :          * and the smb2.acl2.ACCESSBASED test for details.
     814             :          */
     815             : 
     816         118 :         rejected_share_access = access_mask & ~(fsp->conn->share_access);
     817         118 :         if (rejected_share_access) {
     818           0 :                 DBG_DEBUG("rejected share access 0x%x "
     819             :                         "on %s (0x%x)\n",
     820             :                         (unsigned int)access_mask,
     821             :                         fsp_str_dbg(fsp),
     822             :                         (unsigned int)rejected_share_access);
     823           0 :                 return false;
     824             :         }
     825             : 
     826         118 :         status = SMB_VFS_FGET_NT_ACL(metadata_fsp(fsp),
     827             :                         (SECINFO_OWNER |
     828             :                          SECINFO_GROUP |
     829             :                          SECINFO_DACL),
     830             :                         talloc_tos(),
     831             :                         &sd);
     832             : 
     833         118 :         if (!NT_STATUS_IS_OK(status)) {
     834           0 :                 DBG_DEBUG("Could not get acl "
     835             :                         "on %s: %s\n",
     836             :                         fsp_str_dbg(fsp),
     837             :                         nt_errstr(status));
     838           0 :                 return false;
     839             :         }
     840             : 
     841         118 :         status = se_file_access_check(sd,
     842         118 :                                 get_current_nttok(fsp->conn),
     843             :                                 false,
     844             :                                 access_mask,
     845             :                                 &rejected_mask);
     846             : 
     847         118 :         TALLOC_FREE(sd);
     848             : 
     849         118 :         if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
     850          14 :                 DBG_DEBUG("rejected bits 0x%x read access for %s\n",
     851             :                         (unsigned int)rejected_mask,
     852             :                         fsp_str_dbg(fsp));
     853          14 :                 return false;
     854             :         }
     855         104 :         return true;
     856             : }
     857             : 
     858             : /*******************************************************************
     859             :  Check to see if a user can write to an fsp.
     860             :  Always return true for directories.
     861             :  This is only approximate,
     862             :  it is used as part of the "hide unwriteable" option. Don't
     863             :  use it for anything security sensitive.
     864             : ********************************************************************/
     865             : 
     866         110 : static bool user_can_write_fsp(struct files_struct *fsp)
     867             : {
     868             :         /*
     869             :          * Never hide files from the root user.
     870             :          * We use (uid_t)0 here not sec_initial_uid()
     871             :          * as make test uses a single user context.
     872             :          */
     873             : 
     874         110 :         if (get_current_uid(fsp->conn) == (uid_t)0) {
     875           0 :                 return true;
     876             :         }
     877             : 
     878         110 :         if (fsp->fsp_flags.is_directory) {
     879          18 :                 return true;
     880             :         }
     881             : 
     882          92 :         return can_write_to_fsp(fsp);
     883             : }
     884             : 
     885             : /*******************************************************************
     886             :   Is a file a "special" type ?
     887             : ********************************************************************/
     888             : 
     889           0 : static bool file_is_special(connection_struct *conn,
     890             :                             const struct smb_filename *smb_fname)
     891             : {
     892             :         /*
     893             :          * Never hide files from the root user.
     894             :          * We use (uid_t)0 here not sec_initial_uid()
     895             :          * as make test uses a single user context.
     896             :          */
     897             : 
     898           0 :         if (get_current_uid(conn) == (uid_t)0) {
     899           0 :                 return False;
     900             :         }
     901             : 
     902           0 :         SMB_ASSERT(VALID_STAT(smb_fname->st));
     903             : 
     904           0 :         if (S_ISREG(smb_fname->st.st_ex_mode) ||
     905           0 :             S_ISDIR(smb_fname->st.st_ex_mode) ||
     906           0 :             S_ISLNK(smb_fname->st.st_ex_mode))
     907           0 :                 return False;
     908             : 
     909           0 :         return True;
     910             : }
     911             : 
     912             : /*******************************************************************
     913             :  Should the file be seen by the client?
     914             : ********************************************************************/
     915             : 
     916      931792 : bool is_visible_fsp(struct files_struct *fsp)
     917             : {
     918      931792 :         bool hide_unreadable = false;
     919      931792 :         bool hide_unwriteable = false;
     920      931792 :         bool hide_special = false;
     921      931792 :         int hide_new_files_timeout = 0;
     922      931792 :         const char *last_component = NULL;
     923             : 
     924             :         /*
     925             :          * If the file does not exist, there's no point checking
     926             :          * the configuration options. We succeed, on the basis that the
     927             :          * checks *might* have passed if the file was present.
     928             :          */
     929      931792 :         if (fsp == NULL) {
     930           0 :                 return true;
     931             :         }
     932             : 
     933      931792 :         hide_unreadable = lp_hide_unreadable(SNUM(fsp->conn));
     934      931792 :         hide_unwriteable = lp_hide_unwriteable_files(SNUM(fsp->conn));
     935      931792 :         hide_special = lp_hide_special_files(SNUM(fsp->conn));
     936      931792 :         hide_new_files_timeout = lp_hide_new_files_timeout(SNUM(fsp->conn));
     937             : 
     938      931792 :         if (!hide_unreadable &&
     939      931301 :             !hide_unwriteable &&
     940      931492 :             !hide_special &&
     941         321 :             (hide_new_files_timeout == 0))
     942             :         {
     943      930821 :                 return true;
     944             :         }
     945             : 
     946         650 :         fsp = metadata_fsp(fsp);
     947             : 
     948             :         /* Get the last component of the base name. */
     949         650 :         last_component = strrchr_m(fsp->fsp_name->base_name, '/');
     950         650 :         if (!last_component) {
     951         578 :                 last_component = fsp->fsp_name->base_name;
     952             :         } else {
     953          72 :                 last_component++; /* Go past '/' */
     954             :         }
     955             : 
     956         650 :         if (ISDOT(last_component) || ISDOTDOT(last_component)) {
     957         100 :                 return true; /* . and .. are always visible. */
     958             :         }
     959             : 
     960         550 :         if (fsp_get_pathref_fd(fsp) == -1) {
     961             :                 /*
     962             :                  * Symlink in POSIX mode or MS-DFS.
     963             :                  * We've checked veto files so the
     964             :                  * only thing we can check is the
     965             :                  * hide_new_files_timeout.
     966             :                  */
     967           7 :                 if ((hide_new_files_timeout != 0) &&
     968           7 :                     !S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
     969           0 :                         double age = timespec_elapsed(
     970           0 :                                 &fsp->fsp_name->st.st_ex_mtime);
     971             : 
     972           0 :                         if (age < (double)hide_new_files_timeout) {
     973           0 :                                 return false;
     974             :                         }
     975             :                 }
     976           7 :                 return true;
     977             :         }
     978             : 
     979             :         /* Honour _hide unreadable_ option */
     980         543 :         if (hide_unreadable && !user_can_read_fsp(fsp)) {
     981          14 :                 DBG_DEBUG("file %s is unreadable.\n", fsp_str_dbg(fsp));
     982          14 :                 return false;
     983             :         }
     984             : 
     985             :         /* Honour _hide unwriteable_ option */
     986         529 :         if (hide_unwriteable && !user_can_write_fsp(fsp)) {
     987          12 :                 DBG_DEBUG("file %s is unwritable.\n", fsp_str_dbg(fsp));
     988          12 :                 return false;
     989             :         }
     990             : 
     991             :         /* Honour _hide_special_ option */
     992         517 :         if (hide_special && file_is_special(fsp->conn, fsp->fsp_name)) {
     993           0 :                 DBG_DEBUG("file %s is special.\n", fsp_str_dbg(fsp));
     994           0 :                 return false;
     995             :         }
     996             : 
     997         517 :         if ((hide_new_files_timeout != 0) &&
     998         315 :             !S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
     999          12 :                 double age = timespec_elapsed(&fsp->fsp_name->st.st_ex_mtime);
    1000             : 
    1001          12 :                 if (age < (double)hide_new_files_timeout) {
    1002          10 :                         return false;
    1003             :                 }
    1004             :         }
    1005             : 
    1006         507 :         return true;
    1007             : }
    1008             : 
    1009      304454 : static int smb_Dir_destructor(struct smb_Dir *dir_hnd)
    1010             : {
    1011      304454 :         files_struct *fsp = dir_hnd->fsp;
    1012             : 
    1013      304454 :         SMB_VFS_CLOSEDIR(dir_hnd->conn, dir_hnd->dir);
    1014      304454 :         fsp_set_fd(fsp, -1);
    1015      304454 :         if (fsp->dptr != NULL) {
    1016       18692 :                 SMB_ASSERT(fsp->dptr->dir_hnd == dir_hnd);
    1017       18692 :                 fsp->dptr->dir_hnd = NULL;
    1018             :         }
    1019      304454 :         dir_hnd->fsp = NULL;
    1020      304454 :         return 0;
    1021             : }
    1022             : 
    1023             : /*******************************************************************
    1024             :  Open a directory.
    1025             : ********************************************************************/
    1026             : 
    1027      285762 : static int smb_Dir_OpenDir_destructor(struct smb_Dir *dir_hnd)
    1028             : {
    1029      285762 :         files_struct *fsp = dir_hnd->fsp;
    1030             : 
    1031      285762 :         smb_Dir_destructor(dir_hnd);
    1032      285762 :         file_free(NULL, fsp);
    1033      285762 :         return 0;
    1034             : }
    1035             : 
    1036       13167 : NTSTATUS OpenDir(TALLOC_CTX *mem_ctx,
    1037             :                  connection_struct *conn,
    1038             :                  const struct smb_filename *smb_dname,
    1039             :                  const char *mask,
    1040             :                  uint32_t attr,
    1041             :                  struct smb_Dir **_dir_hnd)
    1042             : {
    1043       13167 :         struct files_struct *fsp = NULL;
    1044       13167 :         struct smb_Dir *dir_hnd = NULL;
    1045          74 :         NTSTATUS status;
    1046             : 
    1047       13167 :         status = open_internal_dirfsp(conn,
    1048             :                                       smb_dname,
    1049             :                                       O_RDONLY,
    1050             :                                       &fsp);
    1051       13167 :         if (!NT_STATUS_IS_OK(status)) {
    1052           0 :                 return status;
    1053             :         }
    1054             : 
    1055       13167 :         status = OpenDir_fsp(mem_ctx, conn, fsp, mask, attr, &dir_hnd);
    1056       13167 :         if (!NT_STATUS_IS_OK(status)) {
    1057           0 :                 return status;
    1058             :         }
    1059             : 
    1060             :         /*
    1061             :          * This overwrites the destructor set by OpenDir_fsp() but
    1062             :          * smb_Dir_OpenDir_destructor() calls the OpenDir_fsp()
    1063             :          * destructor.
    1064             :          */
    1065       13167 :         talloc_set_destructor(dir_hnd, smb_Dir_OpenDir_destructor);
    1066             : 
    1067       13167 :         *_dir_hnd = dir_hnd;
    1068       13167 :         return NT_STATUS_OK;
    1069             : }
    1070             : 
    1071      272596 : NTSTATUS OpenDir_from_pathref(TALLOC_CTX *mem_ctx,
    1072             :                               struct files_struct *dirfsp,
    1073             :                               const char *mask,
    1074             :                               uint32_t attr,
    1075             :                               struct smb_Dir **_dir_hnd)
    1076             : {
    1077      272596 :         struct files_struct *fsp = NULL;
    1078      272596 :         struct smb_Dir *dir_hnd = NULL;
    1079         883 :         NTSTATUS status;
    1080             : 
    1081      272596 :         status = openat_internal_dir_from_pathref(dirfsp, O_RDONLY, &fsp);
    1082      272596 :         if (!NT_STATUS_IS_OK(status)) {
    1083           1 :                 return status;
    1084             :         }
    1085             : 
    1086      272595 :         status = OpenDir_fsp(mem_ctx, fsp->conn, fsp, mask, attr, &dir_hnd);
    1087      272595 :         if (!NT_STATUS_IS_OK(status)) {
    1088           0 :                 return status;
    1089             :         }
    1090             : 
    1091             :         /*
    1092             :          * This overwrites the destructor set by OpenDir_fsp() but
    1093             :          * smb_Dir_OpenDir_destructor() calls the OpenDir_fsp()
    1094             :          * destructor.
    1095             :          */
    1096      272595 :         talloc_set_destructor(dir_hnd, smb_Dir_OpenDir_destructor);
    1097             : 
    1098      272595 :         *_dir_hnd = dir_hnd;
    1099      272595 :         return NT_STATUS_OK;
    1100             : }
    1101             : 
    1102             : /*******************************************************************
    1103             :  Open a directory from an fsp.
    1104             : ********************************************************************/
    1105             : 
    1106      304454 : static NTSTATUS OpenDir_fsp(
    1107             :         TALLOC_CTX *mem_ctx,
    1108             :         connection_struct *conn,
    1109             :         files_struct *fsp,
    1110             :         const char *mask,
    1111             :         uint32_t attr,
    1112             :         struct smb_Dir **_dir_hnd)
    1113             : {
    1114      304454 :         struct smb_Dir *dir_hnd = talloc_zero(mem_ctx, struct smb_Dir);
    1115        1133 :         NTSTATUS status;
    1116             : 
    1117      304454 :         if (!dir_hnd) {
    1118           0 :                 return NT_STATUS_NO_MEMORY;
    1119             :         }
    1120             : 
    1121      304454 :         if (!fsp->fsp_flags.is_directory) {
    1122           0 :                 status = NT_STATUS_INVALID_HANDLE;
    1123           0 :                 goto fail;
    1124             :         }
    1125             : 
    1126      304454 :         if (fsp_get_io_fd(fsp) == -1) {
    1127           0 :                 status = NT_STATUS_INVALID_HANDLE;
    1128           0 :                 goto fail;
    1129             :         }
    1130             : 
    1131      304454 :         dir_hnd->conn = conn;
    1132             : 
    1133      304454 :         dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, fsp->fsp_name);
    1134      304454 :         if (!dir_hnd->dir_smb_fname) {
    1135           0 :                 status = NT_STATUS_NO_MEMORY;
    1136           0 :                 goto fail;
    1137             :         }
    1138             : 
    1139      304454 :         dir_hnd->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
    1140      304454 :         if (dir_hnd->dir == NULL) {
    1141           0 :                 status = map_nt_error_from_unix(errno);
    1142           0 :                 goto fail;
    1143             :         }
    1144      304454 :         dir_hnd->fsp = fsp;
    1145      304454 :         if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
    1146           8 :                 dir_hnd->case_sensitive = true;
    1147             :         } else {
    1148      304446 :                 dir_hnd->case_sensitive = conn->case_sensitive;
    1149             :         }
    1150             : 
    1151      304454 :         talloc_set_destructor(dir_hnd, smb_Dir_destructor);
    1152             : 
    1153      304454 :         *_dir_hnd = dir_hnd;
    1154      304454 :         return NT_STATUS_OK;
    1155             : 
    1156           0 :   fail:
    1157           0 :         TALLOC_FREE(dir_hnd);
    1158           0 :         return status;
    1159             : }
    1160             : 
    1161             : 
    1162             : /*******************************************************************
    1163             :  Read from a directory.
    1164             :  Return directory entry, current offset, and optional stat information.
    1165             :  Don't check for veto or invisible files.
    1166             : ********************************************************************/
    1167             : 
    1168   160980989 : const char *ReadDirName(struct smb_Dir *dir_hnd, char **ptalloced)
    1169             : {
    1170        7211 :         const char *n;
    1171   160980989 :         char *talloced = NULL;
    1172   160980989 :         connection_struct *conn = dir_hnd->conn;
    1173             : 
    1174   160980989 :         if (dir_hnd->file_number < 2) {
    1175      610288 :                 if (dir_hnd->file_number == 0) {
    1176      304101 :                         n = ".";
    1177             :                 } else {
    1178      305141 :                         n = "..";
    1179             :                 }
    1180      610288 :                 dir_hnd->file_number++;
    1181      610288 :                 *ptalloced = NULL;
    1182      610288 :                 return n;
    1183             :         }
    1184             : 
    1185   321336198 :         while ((n = vfs_readdirname(conn,
    1186   160970616 :                                     dir_hnd->fsp,
    1187             :                                     dir_hnd->dir,
    1188             :                                     &talloced))) {
    1189             :                 /* Ignore . and .. - we've already returned them. */
    1190   160663864 :                 if (ISDOT(n) || ISDOTDOT(n)) {
    1191      599915 :                         TALLOC_FREE(talloced);
    1192      599915 :                         continue;
    1193             :                 }
    1194   160063949 :                 *ptalloced = talloced;
    1195   160063949 :                 dir_hnd->file_number++;
    1196   160063949 :                 return n;
    1197             :         }
    1198      306752 :         *ptalloced = NULL;
    1199      306752 :         return NULL;
    1200             : }
    1201             : 
    1202             : /*******************************************************************
    1203             :  Rewind to the start.
    1204             : ********************************************************************/
    1205             : 
    1206        2732 : void RewindDir(struct smb_Dir *dir_hnd)
    1207             : {
    1208        2732 :         SMB_VFS_REWINDDIR(dir_hnd->conn, dir_hnd->dir);
    1209        2732 :         dir_hnd->file_number = 0;
    1210        2732 : }
    1211             : 
    1212             : struct files_below_forall_state {
    1213             :         char *dirpath;
    1214             :         ssize_t dirpath_len;
    1215             :         int (*fn)(struct file_id fid, const struct share_mode_data *data,
    1216             :                   void *private_data);
    1217             :         void *private_data;
    1218             : };
    1219             : 
    1220       18759 : static int files_below_forall_fn(struct file_id fid,
    1221             :                                  const struct share_mode_data *data,
    1222             :                                  void *private_data)
    1223             : {
    1224       18759 :         struct files_below_forall_state *state = private_data;
    1225           0 :         char tmpbuf[PATH_MAX];
    1226           0 :         char *fullpath, *to_free;
    1227           0 :         ssize_t len;
    1228             : 
    1229       18759 :         len = full_path_tos(data->servicepath, data->base_name,
    1230             :                             tmpbuf, sizeof(tmpbuf),
    1231             :                             &fullpath, &to_free);
    1232       18759 :         if (len == -1) {
    1233           0 :                 return 0;
    1234             :         }
    1235       18759 :         if (state->dirpath_len >= len) {
    1236             :                 /*
    1237             :                  * Filter files above dirpath
    1238             :                  */
    1239       16453 :                 goto out;
    1240             :         }
    1241        2306 :         if (fullpath[state->dirpath_len] != '/') {
    1242             :                 /*
    1243             :                  * Filter file that don't have a path separator at the end of
    1244             :                  * dirpath's length
    1245             :                  */
    1246        2252 :                 goto out;
    1247             :         }
    1248             : 
    1249          54 :         if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
    1250             :                 /*
    1251             :                  * Not a parent
    1252             :                  */
    1253          42 :                 goto out;
    1254             :         }
    1255             : 
    1256          12 :         TALLOC_FREE(to_free);
    1257          12 :         return state->fn(fid, data, state->private_data);
    1258             : 
    1259       18747 : out:
    1260       18747 :         TALLOC_FREE(to_free);
    1261       18747 :         return 0;
    1262             : }
    1263             : 
    1264        6299 : static int files_below_forall(connection_struct *conn,
    1265             :                               const struct smb_filename *dir_name,
    1266             :                               int (*fn)(struct file_id fid,
    1267             :                                         const struct share_mode_data *data,
    1268             :                                         void *private_data),
    1269             :                               void *private_data)
    1270             : {
    1271        6299 :         struct files_below_forall_state state = {
    1272             :                         .fn = fn,
    1273             :                         .private_data = private_data,
    1274             :         };
    1275           0 :         int ret;
    1276           0 :         char tmpbuf[PATH_MAX];
    1277           0 :         char *to_free;
    1278             : 
    1279       12598 :         state.dirpath_len = full_path_tos(conn->connectpath,
    1280        6299 :                                           dir_name->base_name,
    1281             :                                           tmpbuf, sizeof(tmpbuf),
    1282             :                                           &state.dirpath, &to_free);
    1283        6299 :         if (state.dirpath_len == -1) {
    1284           0 :                 return -1;
    1285             :         }
    1286             : 
    1287        6299 :         ret = share_mode_forall(files_below_forall_fn, &state);
    1288        6299 :         TALLOC_FREE(to_free);
    1289        6299 :         return ret;
    1290             : }
    1291             : 
    1292             : struct have_file_open_below_state {
    1293             :         bool found_one;
    1294             : };
    1295             : 
    1296          12 : static int have_file_open_below_fn(struct file_id fid,
    1297             :                                    const struct share_mode_data *data,
    1298             :                                    void *private_data)
    1299             : {
    1300          12 :         struct have_file_open_below_state *state = private_data;
    1301          12 :         state->found_one = true;
    1302          12 :         return 1;
    1303             : }
    1304             : 
    1305        6299 : bool have_file_open_below(connection_struct *conn,
    1306             :                                  const struct smb_filename *name)
    1307             : {
    1308        6299 :         struct have_file_open_below_state state = {
    1309             :                 .found_one = false,
    1310             :         };
    1311           0 :         int ret;
    1312             : 
    1313        6299 :         if (!VALID_STAT(name->st)) {
    1314           0 :                 return false;
    1315             :         }
    1316        6299 :         if (!S_ISDIR(name->st.st_ex_mode)) {
    1317           0 :                 return false;
    1318             :         }
    1319             : 
    1320        6299 :         ret = files_below_forall(conn, name, have_file_open_below_fn, &state);
    1321        6299 :         if (ret == -1) {
    1322           0 :                 return false;
    1323             :         }
    1324             : 
    1325        6299 :         return state.found_one;
    1326             : }
    1327             : 
    1328             : /*****************************************************************
    1329             :  Is this directory empty ?
    1330             : *****************************************************************/
    1331             : 
    1332       11248 : NTSTATUS can_delete_directory_fsp(files_struct *fsp)
    1333             : {
    1334       11248 :         NTSTATUS status = NT_STATUS_OK;
    1335       11248 :         const char *dname = NULL;
    1336       11248 :         char *talloced = NULL;
    1337       11248 :         struct connection_struct *conn = fsp->conn;
    1338       11248 :         struct smb_Dir *dir_hnd = NULL;
    1339             : 
    1340       11248 :         status = OpenDir(
    1341       11248 :                 talloc_tos(), conn, fsp->fsp_name, NULL, 0, &dir_hnd);
    1342       11248 :         if (!NT_STATUS_IS_OK(status)) {
    1343           0 :                 return status;
    1344             :         }
    1345             : 
    1346       33752 :         while ((dname = ReadDirName(dir_hnd, &talloced))) {
    1347       22648 :                 struct smb_filename *smb_dname_full = NULL;
    1348       22648 :                 struct smb_filename *direntry_fname = NULL;
    1349       22648 :                 char *fullname = NULL;
    1350         148 :                 int ret;
    1351             : 
    1352       22648 :                 if (ISDOT(dname) || (ISDOTDOT(dname))) {
    1353       22496 :                         TALLOC_FREE(talloced);
    1354       22504 :                         continue;
    1355             :                 }
    1356         152 :                 if (IS_VETO_PATH(conn, dname)) {
    1357           4 :                         TALLOC_FREE(talloced);
    1358           4 :                         continue;
    1359             :                 }
    1360             : 
    1361         148 :                 fullname = talloc_asprintf(talloc_tos(),
    1362             :                                            "%s/%s",
    1363         148 :                                            fsp->fsp_name->base_name,
    1364             :                                            dname);
    1365         148 :                 if (fullname == NULL) {
    1366           0 :                         status = NT_STATUS_NO_MEMORY;
    1367           0 :                         break;
    1368             :                 }
    1369             : 
    1370         148 :                 smb_dname_full = synthetic_smb_fname(talloc_tos(),
    1371             :                                                      fullname,
    1372             :                                                      NULL,
    1373             :                                                      NULL,
    1374         142 :                                                      fsp->fsp_name->twrp,
    1375         148 :                                                      fsp->fsp_name->flags);
    1376         148 :                 if (smb_dname_full == NULL) {
    1377           0 :                         TALLOC_FREE(talloced);
    1378           0 :                         TALLOC_FREE(fullname);
    1379           0 :                         status = NT_STATUS_NO_MEMORY;
    1380           0 :                         break;
    1381             :                 }
    1382             : 
    1383         148 :                 ret = SMB_VFS_LSTAT(conn, smb_dname_full);
    1384         148 :                 if (ret != 0) {
    1385           0 :                         status = map_nt_error_from_unix(errno);
    1386           0 :                         TALLOC_FREE(talloced);
    1387           0 :                         TALLOC_FREE(fullname);
    1388           0 :                         TALLOC_FREE(smb_dname_full);
    1389           0 :                         break;
    1390             :                 }
    1391             : 
    1392         148 :                 if (S_ISLNK(smb_dname_full->st.st_ex_mode)) {
    1393             :                         /* Could it be an msdfs link ? */
    1394           8 :                         if (lp_host_msdfs() &&
    1395           4 :                             lp_msdfs_root(SNUM(conn))) {
    1396           0 :                                 struct smb_filename *smb_dname;
    1397           2 :                                 smb_dname = synthetic_smb_fname(talloc_tos(),
    1398             :                                                         dname,
    1399             :                                                         NULL,
    1400           2 :                                                         &smb_dname_full->st,
    1401           2 :                                                         fsp->fsp_name->twrp,
    1402           2 :                                                         fsp->fsp_name->flags);
    1403           2 :                                 if (smb_dname == NULL) {
    1404           0 :                                         TALLOC_FREE(talloced);
    1405           0 :                                         TALLOC_FREE(fullname);
    1406           0 :                                         TALLOC_FREE(smb_dname_full);
    1407           0 :                                         status = NT_STATUS_NO_MEMORY;
    1408           0 :                                         break;
    1409             :                                 }
    1410           2 :                                 if (is_msdfs_link(fsp, smb_dname)) {
    1411           0 :                                         TALLOC_FREE(talloced);
    1412           0 :                                         TALLOC_FREE(fullname);
    1413           0 :                                         TALLOC_FREE(smb_dname_full);
    1414           0 :                                         TALLOC_FREE(smb_dname);
    1415           0 :                                         DBG_DEBUG("got msdfs link name %s "
    1416             :                                                 "- can't delete directory %s\n",
    1417             :                                                 dname,
    1418             :                                                 fsp_str_dbg(fsp));
    1419           0 :                                         status = NT_STATUS_DIRECTORY_NOT_EMPTY;
    1420           0 :                                         break;
    1421             :                                 }
    1422           2 :                                 TALLOC_FREE(smb_dname);
    1423             :                         }
    1424             :                         /* Not a DFS link - could it be a dangling symlink ? */
    1425           4 :                         ret = SMB_VFS_STAT(conn, smb_dname_full);
    1426           4 :                         if (ret == -1 && (errno == ENOENT || errno == ELOOP)) {
    1427             :                                 /*
    1428             :                                  * Dangling symlink.
    1429             :                                  * Allow if "delete veto files = yes"
    1430             :                                  */
    1431           4 :                                 if (lp_delete_veto_files(SNUM(conn))) {
    1432           2 :                                         TALLOC_FREE(talloced);
    1433           2 :                                         TALLOC_FREE(fullname);
    1434           2 :                                         TALLOC_FREE(smb_dname_full);
    1435           2 :                                         continue;
    1436             :                                 }
    1437             :                         }
    1438           2 :                         DBG_DEBUG("got symlink name %s - "
    1439             :                                 "can't delete directory %s\n",
    1440             :                                 dname,
    1441             :                                 fsp_str_dbg(fsp));
    1442           2 :                         TALLOC_FREE(talloced);
    1443           2 :                         TALLOC_FREE(fullname);
    1444           2 :                         TALLOC_FREE(smb_dname_full);
    1445           2 :                         status = NT_STATUS_DIRECTORY_NOT_EMPTY;
    1446           2 :                         break;
    1447             :                 }
    1448             : 
    1449             :                 /* Not a symlink, get a pathref. */
    1450         144 :                 status = synthetic_pathref(talloc_tos(),
    1451             :                                            fsp,
    1452             :                                            dname,
    1453             :                                            NULL,
    1454         144 :                                            &smb_dname_full->st,
    1455         138 :                                            fsp->fsp_name->twrp,
    1456         144 :                                            fsp->fsp_name->flags,
    1457             :                                            &direntry_fname);
    1458         144 :                 if (!NT_STATUS_IS_OK(status)) {
    1459           0 :                         status = map_nt_error_from_unix(errno);
    1460           0 :                         TALLOC_FREE(talloced);
    1461           0 :                         TALLOC_FREE(fullname);
    1462           0 :                         TALLOC_FREE(smb_dname_full);
    1463           0 :                         break;
    1464             :                 }
    1465             : 
    1466         144 :                 if (!is_visible_fsp(direntry_fname->fsp)) {
    1467             :                         /*
    1468             :                          * Hidden file.
    1469             :                          * Allow if "delete veto files = yes"
    1470             :                          */
    1471           4 :                         if (lp_delete_veto_files(SNUM(conn))) {
    1472           2 :                                 TALLOC_FREE(talloced);
    1473           2 :                                 TALLOC_FREE(fullname);
    1474           2 :                                 TALLOC_FREE(smb_dname_full);
    1475           2 :                                 TALLOC_FREE(direntry_fname);
    1476           2 :                                 continue;
    1477             :                         }
    1478             :                 }
    1479             : 
    1480         142 :                 TALLOC_FREE(talloced);
    1481         142 :                 TALLOC_FREE(fullname);
    1482         142 :                 TALLOC_FREE(smb_dname_full);
    1483         142 :                 TALLOC_FREE(direntry_fname);
    1484             : 
    1485         142 :                 DBG_DEBUG("got name %s - can't delete\n", dname);
    1486         136 :                 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
    1487         136 :                 break;
    1488             :         }
    1489       11248 :         TALLOC_FREE(talloced);
    1490       11248 :         TALLOC_FREE(dir_hnd);
    1491             : 
    1492       11248 :         if (!NT_STATUS_IS_OK(status)) {
    1493         144 :                 return status;
    1494             :         }
    1495             : 
    1496       21650 :         if (!(fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) &&
    1497       16665 :             lp_strict_rename(SNUM(conn)) &&
    1498        6119 :             have_file_open_below(fsp->conn, fsp->fsp_name))
    1499             :         {
    1500           0 :                 return NT_STATUS_ACCESS_DENIED;
    1501             :         }
    1502             : 
    1503       11104 :         return NT_STATUS_OK;
    1504             : }

Generated by: LCOV version 1.14