2 Unix SMB/CIFS implementation.
3 Directory handling routines
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 2007
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.
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.
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/>.
22 #include "system/filesys.h"
23 #include "smbd/smbd.h"
24 #include "smbd/globals.h"
25 #include "libcli/security/security.h"
26 #include "lib/util/bitmap.h"
27 #include "../lib/util/memcache.h"
28 #include "../librpc/gen_ndr/open_files.h"
31 This module implements directory related functions for Samba.
34 /* "Special" directory offsets. */
35 #define END_OF_DIRECTORY_OFFSET ((long)-1)
36 #define START_OF_DIRECTORY_OFFSET ((long)0)
37 #define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
39 /* "Special" directory offsets in 32-bit wire format. */
40 #define WIRE_END_OF_DIRECTORY_OFFSET ((uint32_t)0xFFFFFFFF)
41 #define WIRE_START_OF_DIRECTORY_OFFSET ((uint32_t)0)
42 #define WIRE_DOT_DOT_DIRECTORY_OFFSET ((uint32_t)0x80000000)
44 /* Make directory handle internals available. */
46 struct name_cache_entry
{
52 connection_struct
*conn
;
55 struct smb_filename
*dir_smb_fname
;
56 size_t name_cache_size
;
57 struct name_cache_entry
*name_cache
;
58 unsigned int name_cache_index
;
59 unsigned int file_number
;
60 files_struct
*fsp
; /* Back pointer to containing fsp, only
61 set from OpenDir_fsp(). */
65 struct dptr_struct
*next
, *prev
;
68 struct connection_struct
*conn
;
69 struct smb_Dir
*dir_hnd
;
73 struct smb_filename
*smb_dname
;
74 bool has_wild
; /* Set to true if the wcard entry has MS wildcard characters in it. */
75 bool did_stat
; /* Optimisation for non-wcard searches. */
76 bool priv
; /* Directory handle opened with privilege. */
78 struct memcache
*dptr_cache
;
81 static struct smb_Dir
*OpenDir_fsp(TALLOC_CTX
*mem_ctx
, connection_struct
*conn
,
86 static void DirCacheAdd(struct smb_Dir
*dirp
, const char *name
, long offset
);
88 #define INVALID_DPTR_KEY (-3)
90 /****************************************************************************
91 Initialise the dir bitmap.
92 ****************************************************************************/
94 bool init_dptrs(struct smbd_server_connection
*sconn
)
96 if (sconn
->searches
.dptr_bmap
) {
100 sconn
->searches
.dptr_bmap
= bitmap_talloc(
101 sconn
, MAX_DIRECTORY_HANDLES
);
103 if (sconn
->searches
.dptr_bmap
== NULL
) {
110 /****************************************************************************
111 Get the struct dptr_struct for a dir index.
112 ****************************************************************************/
114 static struct dptr_struct
*dptr_get(struct smbd_server_connection
*sconn
,
117 struct dptr_struct
*dptr
;
119 for (dptr
= sconn
->searches
.dirptrs
; dptr
!= NULL
; dptr
= dptr
->next
) {
120 if(dptr
->dnum
!= key
) {
123 DLIST_PROMOTE(sconn
->searches
.dirptrs
, dptr
);
129 /****************************************************************************
130 Get the dir path for a dir index.
131 ****************************************************************************/
133 const char *dptr_path(struct smbd_server_connection
*sconn
, int key
)
135 struct dptr_struct
*dptr
= dptr_get(sconn
, key
);
137 return(dptr
->smb_dname
->base_name
);
141 /****************************************************************************
142 Get the dir wcard for a dir index.
143 ****************************************************************************/
145 const char *dptr_wcard(struct smbd_server_connection
*sconn
, int key
)
147 struct dptr_struct
*dptr
= dptr_get(sconn
, key
);
153 /****************************************************************************
154 Get the dir attrib for a dir index.
155 ****************************************************************************/
157 uint16_t dptr_attr(struct smbd_server_connection
*sconn
, int key
)
159 struct dptr_struct
*dptr
= dptr_get(sconn
, key
);
165 /****************************************************************************
166 Close a dptr (internal func).
167 ****************************************************************************/
169 static void dptr_close_internal(struct dptr_struct
*dptr
)
171 struct smbd_server_connection
*sconn
= dptr
->conn
->sconn
;
173 DEBUG(4,("closing dptr key %d\n",dptr
->dnum
));
179 if (sconn
->using_smb2
) {
183 DLIST_REMOVE(sconn
->searches
.dirptrs
, dptr
);
186 * Free the dnum in the bitmap. Remember the dnum value is always
187 * biased by one with respect to the bitmap.
190 if (!bitmap_query(sconn
->searches
.dptr_bmap
, dptr
->dnum
- 1)) {
191 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
195 bitmap_clear(sconn
->searches
.dptr_bmap
, dptr
->dnum
- 1);
198 TALLOC_FREE(dptr
->dir_hnd
);
202 /****************************************************************************
203 Close a dptr given a key.
204 ****************************************************************************/
206 void dptr_close(struct smbd_server_connection
*sconn
, int *key
)
208 struct dptr_struct
*dptr
;
210 if(*key
== INVALID_DPTR_KEY
)
213 /* OS/2 seems to use -1 to indicate "close all directories" */
215 struct dptr_struct
*next
;
216 for(dptr
= sconn
->searches
.dirptrs
; dptr
; dptr
= next
) {
218 dptr_close_internal(dptr
);
220 *key
= INVALID_DPTR_KEY
;
224 dptr
= dptr_get(sconn
, *key
);
227 DEBUG(0,("Invalid key %d given to dptr_close\n", *key
));
231 dptr_close_internal(dptr
);
233 *key
= INVALID_DPTR_KEY
;
236 /****************************************************************************
237 Close all dptrs for a cnum.
238 ****************************************************************************/
240 void dptr_closecnum(connection_struct
*conn
)
242 struct dptr_struct
*dptr
, *next
;
243 struct smbd_server_connection
*sconn
= conn
->sconn
;
249 for(dptr
= sconn
->searches
.dirptrs
; dptr
; dptr
= next
) {
251 if (dptr
->conn
== conn
) {
252 dptr_close_internal(dptr
);
257 /****************************************************************************
258 Are there any SMB1 searches active on this connection struct ?
259 ****************************************************************************/
261 bool dptr_activecnum(const struct smbd_server_connection
*sconn
,
262 const struct connection_struct
*conn
)
264 const struct dptr_struct
*dptr
;
266 for(dptr
= sconn
->searches
.dirptrs
; dptr
; dptr
= dptr
->next
) {
267 if (dptr
->conn
== conn
) {
274 /****************************************************************************
275 Close a dptr that matches a given path, only if it matches the spid also.
276 ****************************************************************************/
278 void dptr_closepath(struct smbd_server_connection
*sconn
,
279 char *path
,uint16_t spid
)
281 struct dptr_struct
*dptr
, *next
;
282 for(dptr
= sconn
->searches
.dirptrs
; dptr
; dptr
= next
) {
284 if (spid
== dptr
->spid
&&
285 strequal(dptr
->smb_dname
->base_name
,path
)) {
286 dptr_close_internal(dptr
);
291 /****************************************************************************
292 Safely do an OpenDir as root, ensuring we're in the right place.
293 ****************************************************************************/
295 static struct smb_Dir
*open_dir_with_privilege(connection_struct
*conn
,
296 struct smb_request
*req
,
297 const struct smb_filename
*smb_dname
,
301 struct smb_Dir
*dir_hnd
= NULL
;
302 struct smb_filename
*smb_fname_cwd
= NULL
;
303 struct smb_filename
*saved_dir_fname
= vfs_GetWd(talloc_tos(), conn
);
304 struct privilege_paths
*priv_paths
= req
->priv_paths
;
307 if (saved_dir_fname
== NULL
) {
311 if (vfs_ChDir(conn
, smb_dname
) == -1) {
315 /* Now check the stat value is the same. */
316 smb_fname_cwd
= synthetic_smb_fname(talloc_tos(),
321 if (smb_fname_cwd
== NULL
) {
324 ret
= SMB_VFS_STAT(conn
, smb_fname_cwd
);
329 if (!check_same_stat(&smb_fname_cwd
->st
, &priv_paths
->parent_name
.st
)) {
330 DEBUG(0,("open_dir_with_privilege: stat mismatch between %s "
332 smb_dname
->base_name
,
333 smb_fname_str_dbg(&priv_paths
->parent_name
)));
337 dir_hnd
= OpenDir(NULL
, conn
, smb_fname_cwd
, wcard
, attr
);
341 vfs_ChDir(conn
, saved_dir_fname
);
342 TALLOC_FREE(saved_dir_fname
);
346 /****************************************************************************
347 Create a new dir ptr. If the flag old_handle is true then we must allocate
348 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
349 one byte long. If old_handle is false we allocate from the range
350 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
351 a directory handle is never zero.
352 wcard must not be zero.
353 ****************************************************************************/
355 NTSTATUS
dptr_create(connection_struct
*conn
,
356 struct smb_request
*req
,
358 const struct smb_filename
*smb_dname
,
365 struct dptr_struct
**dptr_ret
)
367 struct smbd_server_connection
*sconn
= conn
->sconn
;
368 struct dptr_struct
*dptr
= NULL
;
369 struct smb_Dir
*dir_hnd
;
371 if (fsp
&& fsp
->is_directory
&& fsp
->fh
->fd
!= -1) {
372 smb_dname
= fsp
->fsp_name
;
375 DEBUG(5,("dptr_create dir=%s\n", smb_dname
->base_name
));
378 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
379 return NT_STATUS_INTERNAL_ERROR
;
383 return NT_STATUS_INVALID_PARAMETER
;
387 if (!(fsp
->access_mask
& SEC_DIR_LIST
)) {
388 DEBUG(5,("dptr_create: directory %s "
389 "not open for LIST access\n",
390 smb_dname
->base_name
));
391 return NT_STATUS_ACCESS_DENIED
;
393 dir_hnd
= OpenDir_fsp(NULL
, conn
, fsp
, wcard
, attr
);
396 bool backup_intent
= (req
&& req
->priv_paths
);
398 struct smb_filename
*smb_dname_cp
=
399 cp_smb_filename(talloc_tos(), smb_dname
);
401 if (smb_dname_cp
== NULL
) {
402 return NT_STATUS_NO_MEMORY
;
405 if (req
!= NULL
&& req
->posix_pathnames
) {
406 ret
= SMB_VFS_LSTAT(conn
, smb_dname_cp
);
408 ret
= SMB_VFS_STAT(conn
, smb_dname_cp
);
411 status
= map_nt_error_from_unix(errno
);
412 TALLOC_FREE(smb_dname_cp
);
415 if (!S_ISDIR(smb_dname_cp
->st
.st_ex_mode
)) {
416 TALLOC_FREE(smb_dname_cp
);
417 return NT_STATUS_NOT_A_DIRECTORY
;
419 status
= smbd_check_access_rights(conn
,
423 if (!NT_STATUS_IS_OK(status
)) {
424 TALLOC_FREE(smb_dname_cp
);
428 dir_hnd
= open_dir_with_privilege(conn
,
434 dir_hnd
= OpenDir(NULL
,
440 TALLOC_FREE(smb_dname_cp
);
444 return map_nt_error_from_unix(errno
);
447 dptr
= talloc_zero(NULL
, struct dptr_struct
);
449 DEBUG(0,("talloc fail in dptr_create.\n"));
450 TALLOC_FREE(dir_hnd
);
451 return NT_STATUS_NO_MEMORY
;
454 dptr
->smb_dname
= cp_smb_filename(dptr
, smb_dname
);
455 if (!dptr
->smb_dname
) {
457 TALLOC_FREE(dir_hnd
);
458 return NT_STATUS_NO_MEMORY
;
461 dptr
->dir_hnd
= dir_hnd
;
463 dptr
->expect_close
= expect_close
;
464 dptr
->wcard
= talloc_strdup(dptr
, wcard
);
467 TALLOC_FREE(dir_hnd
);
468 return NT_STATUS_NO_MEMORY
;
470 if ((req
!= NULL
&& req
->posix_pathnames
) ||
471 (wcard
[0] == '.' && wcard
[1] == 0)) {
472 dptr
->has_wild
= True
;
474 dptr
->has_wild
= wcard_has_wild
;
479 if (sconn
->using_smb2
) {
486 * This is an old-style SMBsearch request. Ensure the
487 * value we return will fit in the range 1-255.
490 dptr
->dnum
= bitmap_find(sconn
->searches
.dptr_bmap
, 0);
492 if(dptr
->dnum
== -1 || dptr
->dnum
> 254) {
493 DBG_ERR("returned %d: Error - all old "
494 "dirptrs in use ?\n",
497 TALLOC_FREE(dir_hnd
);
498 return NT_STATUS_TOO_MANY_OPENED_FILES
;
503 * This is a new-style trans2 request. Allocate from
504 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
507 dptr
->dnum
= bitmap_find(sconn
->searches
.dptr_bmap
, 255);
509 if(dptr
->dnum
== -1 || dptr
->dnum
< 255) {
510 DBG_ERR("returned %d: Error - all new "
511 "dirptrs in use ?\n",
514 TALLOC_FREE(dir_hnd
);
515 return NT_STATUS_TOO_MANY_OPENED_FILES
;
519 bitmap_set(sconn
->searches
.dptr_bmap
, dptr
->dnum
);
521 dptr
->dnum
+= 1; /* Always bias the dnum by one - no zero dnums allowed. */
523 DLIST_ADD(sconn
->searches
.dirptrs
, dptr
);
526 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
528 dptr
->smb_dname
->base_name
,
537 /****************************************************************************
538 Wrapper functions to access the lower level directory handles.
539 ****************************************************************************/
541 void dptr_CloseDir(files_struct
*fsp
)
545 * The destructor for the struct smb_Dir
546 * (fsp->dptr->dir_hnd) now handles
547 * all resource deallocation.
549 dptr_close_internal(fsp
->dptr
);
554 void dptr_SeekDir(struct dptr_struct
*dptr
, long offset
)
556 SeekDir(dptr
->dir_hnd
, offset
);
559 long dptr_TellDir(struct dptr_struct
*dptr
)
561 return TellDir(dptr
->dir_hnd
);
564 bool dptr_has_wild(struct dptr_struct
*dptr
)
566 return dptr
->has_wild
;
569 int dptr_dnum(struct dptr_struct
*dptr
)
574 bool dptr_get_priv(struct dptr_struct
*dptr
)
579 void dptr_set_priv(struct dptr_struct
*dptr
)
584 /****************************************************************************
585 Return the next visible file name, skipping veto'd and invisible files.
586 ****************************************************************************/
588 static const char *dptr_normal_ReadDirName(struct dptr_struct
*dptr
,
589 long *poffset
, SMB_STRUCT_STAT
*pst
,
592 /* Normal search for the next file. */
594 char *talloced
= NULL
;
596 while ((name
= ReadDirName(dptr
->dir_hnd
, poffset
, pst
, &talloced
))
598 if (is_visible_file(dptr
->conn
,
599 dptr
->smb_dname
->base_name
,
603 *ptalloced
= talloced
;
606 TALLOC_FREE(talloced
);
611 /****************************************************************************
612 Return the next visible file name, skipping veto'd and invisible files.
613 ****************************************************************************/
615 static char *dptr_ReadDirName(TALLOC_CTX
*ctx
,
616 struct dptr_struct
*dptr
,
618 SMB_STRUCT_STAT
*pst
)
620 struct smb_filename smb_fname_base
;
622 const char *name_temp
= NULL
;
623 char *talloced
= NULL
;
624 char *pathreal
= NULL
;
625 char *found_name
= NULL
;
628 SET_STAT_INVALID(*pst
);
630 if (dptr
->has_wild
|| dptr
->did_stat
) {
631 name_temp
= dptr_normal_ReadDirName(dptr
, poffset
, pst
,
633 if (name_temp
== NULL
) {
636 if (talloced
!= NULL
) {
637 return talloc_move(ctx
, &talloced
);
639 return talloc_strdup(ctx
, name_temp
);
642 /* If poffset is -1 then we know we returned this name before and we
643 * have no wildcards. We're at the end of the directory. */
644 if (*poffset
== END_OF_DIRECTORY_OFFSET
) {
648 /* We know the stored wcard contains no wildcard characters.
649 * See if we can match with a stat call. If we can't, then set
650 * did_stat to true to ensure we only do this once and keep
653 dptr
->did_stat
= true;
655 /* First check if it should be visible. */
656 if (!is_visible_file(dptr
->conn
,
657 dptr
->smb_dname
->base_name
,
661 /* This only returns false if the file was found, but
662 is explicitly not visible. Set us to end of
663 directory, but return NULL as we know we can't ever
668 if (VALID_STAT(*pst
)) {
669 name
= talloc_strdup(ctx
, dptr
->wcard
);
673 pathreal
= talloc_asprintf(ctx
,
675 dptr
->smb_dname
->base_name
,
680 /* Create an smb_filename with stream_name == NULL. */
681 smb_fname_base
= (struct smb_filename
) { .base_name
= pathreal
};
683 if (SMB_VFS_STAT(dptr
->conn
, &smb_fname_base
) == 0) {
684 *pst
= smb_fname_base
.st
;
685 name
= talloc_strdup(ctx
, dptr
->wcard
);
688 /* If we get any other error than ENOENT or ENOTDIR
689 then the file exists we just can't stat it. */
690 if (errno
!= ENOENT
&& errno
!= ENOTDIR
) {
691 name
= talloc_strdup(ctx
, dptr
->wcard
);
696 /* Stat failed. We know this is authoratiative if we are
697 * providing case sensitive semantics or the underlying
698 * filesystem is case sensitive.
700 if (dptr
->conn
->case_sensitive
||
701 !(dptr
->conn
->fs_capabilities
& FILE_CASE_SENSITIVE_SEARCH
))
707 * Try case-insensitive stat if the fs has the ability. This avoids
708 * scanning the whole directory.
710 ret
= SMB_VFS_GET_REAL_FILENAME(dptr
->conn
,
711 dptr
->smb_dname
->base_name
,
718 } else if (errno
== ENOENT
) {
719 /* The case-insensitive lookup was authoritative. */
723 TALLOC_FREE(pathreal
);
725 name_temp
= dptr_normal_ReadDirName(dptr
, poffset
, pst
, &talloced
);
726 if (name_temp
== NULL
) {
729 if (talloced
!= NULL
) {
730 return talloc_move(ctx
, &talloced
);
732 return talloc_strdup(ctx
, name_temp
);
735 TALLOC_FREE(pathreal
);
737 /* We need to set the underlying dir_hnd offset to -1
738 * also as this function is usually called with the
739 * output from TellDir. */
740 dptr
->dir_hnd
->offset
= *poffset
= END_OF_DIRECTORY_OFFSET
;
744 /****************************************************************************
745 Search for a file by name, skipping veto'ed and not visible files.
746 ****************************************************************************/
748 bool dptr_SearchDir(struct dptr_struct
*dptr
, const char *name
, long *poffset
, SMB_STRUCT_STAT
*pst
)
750 SET_STAT_INVALID(*pst
);
752 if (!dptr
->has_wild
&& (dptr
->dir_hnd
->offset
== END_OF_DIRECTORY_OFFSET
)) {
753 /* This is a singleton directory and we're already at the end. */
754 *poffset
= END_OF_DIRECTORY_OFFSET
;
758 return SearchDir(dptr
->dir_hnd
, name
, poffset
);
761 /****************************************************************************
762 Map a native directory offset to a 32-bit cookie.
763 ****************************************************************************/
765 static uint32_t map_dir_offset_to_wire(struct dptr_struct
*dptr
, long offset
)
770 if (offset
== END_OF_DIRECTORY_OFFSET
) {
771 return WIRE_END_OF_DIRECTORY_OFFSET
;
772 } else if(offset
== START_OF_DIRECTORY_OFFSET
) {
773 return WIRE_START_OF_DIRECTORY_OFFSET
;
774 } else if (offset
== DOT_DOT_DIRECTORY_OFFSET
) {
775 return WIRE_DOT_DOT_DIRECTORY_OFFSET
;
777 if (sizeof(long) == 4) {
778 /* 32-bit machine. We can cheat... */
779 return (uint32_t)offset
;
781 if (dptr
->dptr_cache
== NULL
) {
782 /* Lazy initialize cache. */
783 dptr
->dptr_cache
= memcache_init(dptr
, 0);
784 if (dptr
->dptr_cache
== NULL
) {
785 return WIRE_END_OF_DIRECTORY_OFFSET
;
788 /* Have we seen this offset before ? */
789 key
.data
= (void *)&offset
;
790 key
.length
= sizeof(offset
);
791 if (memcache_lookup(dptr
->dptr_cache
,
792 SMB1_SEARCH_OFFSET_MAP
,
795 uint32_t wire_offset
;
796 SMB_ASSERT(val
.length
== sizeof(wire_offset
));
797 memcpy(&wire_offset
, val
.data
, sizeof(wire_offset
));
798 DEBUG(10,("found wire %u <-> offset %ld\n",
799 (unsigned int)wire_offset
,
804 /* Allocate a new wire cookie. */
807 } while (dptr
->counter
== WIRE_START_OF_DIRECTORY_OFFSET
||
808 dptr
->counter
== WIRE_END_OF_DIRECTORY_OFFSET
||
809 dptr
->counter
== WIRE_DOT_DOT_DIRECTORY_OFFSET
);
810 /* Store it in the cache. */
811 key
.data
= (void *)&offset
;
812 key
.length
= sizeof(offset
);
813 val
.data
= (void *)&dptr
->counter
;
814 val
.length
= sizeof(dptr
->counter
); /* MUST BE uint32_t ! */
815 memcache_add(dptr
->dptr_cache
,
816 SMB1_SEARCH_OFFSET_MAP
,
819 /* And the reverse mapping for lookup from
820 map_wire_to_dir_offset(). */
821 memcache_add(dptr
->dptr_cache
,
822 SMB1_SEARCH_OFFSET_MAP
,
825 DEBUG(10,("stored wire %u <-> offset %ld\n",
826 (unsigned int)dptr
->counter
,
828 return dptr
->counter
;
831 /****************************************************************************
832 Fill the 5 byte server reserved dptr field.
833 ****************************************************************************/
835 bool dptr_fill(struct smbd_server_connection
*sconn
,
836 char *buf1
,unsigned int key
)
838 unsigned char *buf
= (unsigned char *)buf1
;
839 struct dptr_struct
*dptr
= dptr_get(sconn
, key
);
840 uint32_t wire_offset
;
842 DEBUG(1,("filling null dirptr %d\n",key
));
845 wire_offset
= map_dir_offset_to_wire(dptr
,TellDir(dptr
->dir_hnd
));
846 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key
,
847 (long)dptr
->dir_hnd
,(int)wire_offset
));
849 SIVAL(buf
,1,wire_offset
);
853 /****************************************************************************
854 Map a 32-bit wire cookie to a native directory offset.
855 ****************************************************************************/
857 static long map_wire_to_dir_offset(struct dptr_struct
*dptr
, uint32_t wire_offset
)
862 if (wire_offset
== WIRE_END_OF_DIRECTORY_OFFSET
) {
863 return END_OF_DIRECTORY_OFFSET
;
864 } else if(wire_offset
== WIRE_START_OF_DIRECTORY_OFFSET
) {
865 return START_OF_DIRECTORY_OFFSET
;
866 } else if (wire_offset
== WIRE_DOT_DOT_DIRECTORY_OFFSET
) {
867 return DOT_DOT_DIRECTORY_OFFSET
;
869 if (sizeof(long) == 4) {
870 /* 32-bit machine. We can cheat... */
871 return (long)wire_offset
;
873 if (dptr
->dptr_cache
== NULL
) {
874 /* Logic error, cache should be initialized. */
875 return END_OF_DIRECTORY_OFFSET
;
877 key
.data
= (void *)&wire_offset
;
878 key
.length
= sizeof(wire_offset
);
879 if (memcache_lookup(dptr
->dptr_cache
,
880 SMB1_SEARCH_OFFSET_MAP
,
885 SMB_ASSERT(val
.length
== sizeof(offset
));
886 memcpy(&offset
, val
.data
, sizeof(offset
));
887 DEBUG(10,("lookup wire %u <-> offset %ld\n",
888 (unsigned int)wire_offset
,
892 return END_OF_DIRECTORY_OFFSET
;
895 /****************************************************************************
896 Fetch the dir ptr and seek it given the 5 byte server field.
897 ****************************************************************************/
899 struct dptr_struct
*dptr_fetch(struct smbd_server_connection
*sconn
,
902 unsigned int key
= *(unsigned char *)buf
;
903 struct dptr_struct
*dptr
= dptr_get(sconn
, key
);
904 uint32_t wire_offset
;
908 DEBUG(3,("fetched null dirptr %d\n",key
));
912 wire_offset
= IVAL(buf
,1);
913 seekoff
= map_wire_to_dir_offset(dptr
, wire_offset
);
914 SeekDir(dptr
->dir_hnd
,seekoff
);
915 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
916 key
, dptr
->smb_dname
->base_name
, (int)seekoff
));
920 /****************************************************************************
922 ****************************************************************************/
924 struct dptr_struct
*dptr_fetch_lanman2(struct smbd_server_connection
*sconn
,
927 struct dptr_struct
*dptr
= dptr_get(sconn
, dptr_num
);
930 DEBUG(3,("fetched null dirptr %d\n",dptr_num
));
933 DEBUG(3,("fetching dirptr %d for path %s\n",
935 dptr
->smb_dname
->base_name
));
939 static bool mangle_mask_match(connection_struct
*conn
,
940 const char *filename
,
945 if (!name_to_8_3(filename
,mname
,False
,conn
->params
)) {
948 return mask_match_search(mname
,mask
,False
);
951 bool smbd_dirptr_get_entry(TALLOC_CTX
*ctx
,
952 struct dptr_struct
*dirptr
,
958 bool (*match_fn
)(TALLOC_CTX
*ctx
,
963 bool (*mode_fn
)(TALLOC_CTX
*ctx
,
965 struct smb_filename
*smb_fname
,
970 struct smb_filename
**_smb_fname
,
974 connection_struct
*conn
= dirptr
->conn
;
977 const char *dpath
= dirptr
->smb_dname
->base_name
;
978 bool dirptr_path_is_dot
= ISDOT(dpath
);
983 pathlen
= strlen(dpath
);
984 slashlen
= ( dpath
[pathlen
-1] != '/') ? 1 : 0;
989 SMB_STRUCT_STAT sbuf
= { 0 };
993 char *pathreal
= NULL
;
994 struct smb_filename smb_fname
;
998 cur_offset
= dptr_TellDir(dirptr
);
999 prev_offset
= cur_offset
;
1000 dname
= dptr_ReadDirName(ctx
, dirptr
, &cur_offset
, &sbuf
);
1002 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
1003 (long)dirptr
, cur_offset
));
1005 if (dname
== NULL
) {
1009 isdots
= (ISDOT(dname
) || ISDOTDOT(dname
));
1010 if (dont_descend
&& !isdots
) {
1016 * fname may get mangled, dname is never mangled.
1017 * Whenever we're accessing the filesystem we use
1018 * pathreal which is composed from dname.
1021 ok
= match_fn(ctx
, private_data
, dname
, mask
, &fname
);
1029 * pathreal = talloc_asprintf(ctx, "%s%s%s", dirptr->path,
1030 * needslash?"/":"", dname);
1031 * but this was measurably slower than doing the memcpy.
1034 pathreal
= talloc_array(
1036 pathlen
+ slashlen
+ talloc_get_size(dname
));
1044 * We don't want to pass ./xxx to modules below us so don't
1045 * add the path if it is just . by itself.
1047 if (dirptr_path_is_dot
) {
1048 memcpy(pathreal
, dname
, talloc_get_size(dname
));
1050 memcpy(pathreal
, dpath
, pathlen
);
1051 pathreal
[pathlen
] = '/';
1052 memcpy(pathreal
+ slashlen
+ pathlen
, dname
,
1053 talloc_get_size(dname
));
1056 /* Create smb_fname with NULL stream_name. */
1057 smb_fname
= (struct smb_filename
) {
1058 .base_name
= pathreal
, .st
= sbuf
1061 ok
= mode_fn(ctx
, private_data
, &smb_fname
, get_dosmode
, &mode
);
1065 TALLOC_FREE(pathreal
);
1069 if (!dir_check_ftype(mode
, dirtype
)) {
1070 DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
1071 fname
, (unsigned int)mode
, (unsigned int)dirtype
));
1074 TALLOC_FREE(pathreal
);
1078 if (ask_sharemode
) {
1079 struct timespec write_time_ts
;
1080 struct file_id fileid
;
1082 fileid
= vfs_file_id_from_sbuf(conn
,
1084 get_file_infos(fileid
, 0, NULL
, &write_time_ts
);
1085 if (!null_timespec(write_time_ts
)) {
1086 update_stat_ex_mtime(&smb_fname
.st
,
1091 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
1093 mask
, smb_fname_str_dbg(&smb_fname
),
1096 if (!conn
->sconn
->using_smb2
) {
1098 * The dircache is only needed for SMB1 because SMB1
1099 * uses a name for the resume wheras SMB2 always
1100 * continues from the next position (unless it's told to
1101 * restart or close-and-reopen the listing).
1103 DirCacheAdd(dirptr
->dir_hnd
, dname
, cur_offset
);
1108 *_smb_fname
= cp_smb_filename(ctx
, &smb_fname
);
1109 TALLOC_FREE(pathreal
);
1110 if (*_smb_fname
== NULL
) {
1115 *_prev_offset
= prev_offset
;
1123 /****************************************************************************
1124 Get an 8.3 directory entry.
1125 ****************************************************************************/
1127 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX
*ctx
,
1133 connection_struct
*conn
= (connection_struct
*)private_data
;
1135 if ((strcmp(mask
,"*.*") == 0) ||
1136 mask_match_search(dname
, mask
, false) ||
1137 mangle_mask_match(conn
, dname
, mask
)) {
1141 * Ensure we can push the original name as UCS2. If
1142 * not, then just don't return this name.
1146 size_t len
= (strlen(dname
) + 2) * 4; /* Allow enough space. */
1147 uint8_t *tmp
= talloc_array(talloc_tos(),
1151 status
= srvstr_push(NULL
,
1152 FLAGS2_UNICODE_STRINGS
,
1161 if (!NT_STATUS_IS_OK(status
)) {
1165 if (!mangle_is_8_3(dname
, false, conn
->params
)) {
1166 bool ok
= name_to_8_3(dname
, mname
, false,
1176 *_fname
= talloc_strdup(ctx
, fname
);
1177 if (*_fname
== NULL
) {
1187 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX
*ctx
,
1189 struct smb_filename
*smb_fname
,
1193 connection_struct
*conn
= (connection_struct
*)private_data
;
1195 if (!VALID_STAT(smb_fname
->st
)) {
1196 if ((SMB_VFS_STAT(conn
, smb_fname
)) != 0) {
1197 DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1198 "Couldn't stat [%s]. Error "
1200 smb_fname_str_dbg(smb_fname
),
1206 *_mode
= dos_mode(conn
, smb_fname
);
1210 bool get_dir_entry(TALLOC_CTX
*ctx
,
1211 struct dptr_struct
*dirptr
,
1217 struct timespec
*_date
,
1221 connection_struct
*conn
= dirptr
->conn
;
1223 struct smb_filename
*smb_fname
= NULL
;
1228 ok
= smbd_dirptr_get_entry(ctx
,
1235 smbd_dirptr_8_3_match_fn
,
1236 smbd_dirptr_8_3_mode_fn
,
1246 *_fname
= talloc_move(ctx
, &fname
);
1247 *_size
= smb_fname
->st
.st_ex_size
;
1249 *_date
= smb_fname
->st
.st_ex_mtime
;
1250 TALLOC_FREE(smb_fname
);
1254 /*******************************************************************
1255 Check to see if a user can read a file. This is only approximate,
1256 it is used as part of the "hide unreadable" option. Don't
1257 use it for anything security sensitive.
1258 ********************************************************************/
1260 static bool user_can_read_file(connection_struct
*conn
,
1261 struct smb_filename
*smb_fname
)
1264 uint32_t rejected_share_access
= 0;
1265 uint32_t rejected_mask
= 0;
1266 struct security_descriptor
*sd
= NULL
;
1267 uint32_t access_mask
= FILE_READ_DATA
|
1269 FILE_READ_ATTRIBUTES
|
1270 SEC_STD_READ_CONTROL
;
1273 * Never hide files from the root user.
1274 * We use (uid_t)0 here not sec_initial_uid()
1275 * as make test uses a single user context.
1278 if (get_current_uid(conn
) == (uid_t
)0) {
1283 * We can't directly use smbd_check_access_rights()
1284 * here, as this implicitly grants FILE_READ_ATTRIBUTES
1285 * which the Windows access-based-enumeration code
1286 * explicitly checks for on the file security descriptor.
1289 * https://bugzilla.samba.org/show_bug.cgi?id=10252
1291 * and the smb2.acl2.ACCESSBASED test for details.
1294 rejected_share_access
= access_mask
& ~(conn
->share_access
);
1295 if (rejected_share_access
) {
1296 DEBUG(10, ("rejected share access 0x%x "
1298 (unsigned int)access_mask
,
1299 smb_fname_str_dbg(smb_fname
),
1300 (unsigned int)rejected_share_access
));
1304 status
= SMB_VFS_GET_NT_ACL(conn
,
1312 if (!NT_STATUS_IS_OK(status
)) {
1313 DEBUG(10, ("Could not get acl "
1315 smb_fname_str_dbg(smb_fname
),
1316 nt_errstr(status
)));
1320 status
= se_file_access_check(sd
,
1321 get_current_nttok(conn
),
1328 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
1329 DEBUG(10,("rejected bits 0x%x read access for %s\n",
1330 (unsigned int)rejected_mask
,
1331 smb_fname_str_dbg(smb_fname
) ));
1337 /*******************************************************************
1338 Check to see if a user can write a file (and only files, we do not
1339 check dirs on this one). This is only approximate,
1340 it is used as part of the "hide unwriteable" option. Don't
1341 use it for anything security sensitive.
1342 ********************************************************************/
1344 static bool user_can_write_file(connection_struct
*conn
,
1345 const struct smb_filename
*smb_fname
)
1348 * Never hide files from the root user.
1349 * We use (uid_t)0 here not sec_initial_uid()
1350 * as make test uses a single user context.
1353 if (get_current_uid(conn
) == (uid_t
)0) {
1357 SMB_ASSERT(VALID_STAT(smb_fname
->st
));
1359 /* Pseudo-open the file */
1361 if(S_ISDIR(smb_fname
->st
.st_ex_mode
)) {
1365 return can_write_to_file(conn
, smb_fname
);
1368 /*******************************************************************
1369 Is a file a "special" type ?
1370 ********************************************************************/
1372 static bool file_is_special(connection_struct
*conn
,
1373 const struct smb_filename
*smb_fname
)
1376 * Never hide files from the root user.
1377 * We use (uid_t)0 here not sec_initial_uid()
1378 * as make test uses a single user context.
1381 if (get_current_uid(conn
) == (uid_t
)0) {
1385 SMB_ASSERT(VALID_STAT(smb_fname
->st
));
1387 if (S_ISREG(smb_fname
->st
.st_ex_mode
) ||
1388 S_ISDIR(smb_fname
->st
.st_ex_mode
) ||
1389 S_ISLNK(smb_fname
->st
.st_ex_mode
))
1395 /*******************************************************************
1396 Should the file be seen by the client?
1397 NOTE: A successful return is no guarantee of the file's existence.
1398 ********************************************************************/
1400 bool is_visible_file(connection_struct
*conn
, const char *dir_path
,
1401 const char *name
, SMB_STRUCT_STAT
*pst
, bool use_veto
)
1403 bool hide_unreadable
= lp_hide_unreadable(SNUM(conn
));
1404 bool hide_unwriteable
= lp_hide_unwriteable_files(SNUM(conn
));
1405 bool hide_special
= lp_hide_special_files(SNUM(conn
));
1406 int hide_new_files_timeout
= lp_hide_new_files_timeout(SNUM(conn
));
1408 struct smb_filename
*smb_fname_base
= NULL
;
1411 if ((strcmp(".",name
) == 0) || (strcmp("..",name
) == 0)) {
1412 return True
; /* . and .. are always visible. */
1415 /* If it's a vetoed file, pretend it doesn't even exist */
1416 if (use_veto
&& IS_VETO_PATH(conn
, name
)) {
1417 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name
));
1421 if (hide_unreadable
||
1424 (hide_new_files_timeout
!= 0))
1426 entry
= talloc_asprintf(talloc_tos(), "%s/%s", dir_path
, name
);
1432 /* Create an smb_filename with stream_name == NULL. */
1433 smb_fname_base
= synthetic_smb_fname(talloc_tos(),
1438 if (smb_fname_base
== NULL
) {
1443 /* If the file name does not exist, there's no point checking
1444 * the configuration options. We succeed, on the basis that the
1445 * checks *might* have passed if the file was present.
1447 if (!VALID_STAT(*pst
)) {
1448 if (SMB_VFS_STAT(conn
, smb_fname_base
) != 0) {
1452 *pst
= smb_fname_base
->st
;
1455 /* Honour _hide unreadable_ option */
1456 if (hide_unreadable
&&
1457 !user_can_read_file(conn
, smb_fname_base
)) {
1458 DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1463 /* Honour _hide unwriteable_ option */
1464 if (hide_unwriteable
&& !user_can_write_file(conn
,
1466 DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1471 /* Honour _hide_special_ option */
1472 if (hide_special
&& file_is_special(conn
, smb_fname_base
)) {
1473 DEBUG(10,("is_visible_file: file %s is special.\n",
1479 if (hide_new_files_timeout
!= 0) {
1481 double age
= timespec_elapsed(
1482 &smb_fname_base
->st
.st_ex_mtime
);
1484 if (age
< (double)hide_new_files_timeout
) {
1493 TALLOC_FREE(smb_fname_base
);
1498 static int smb_Dir_destructor(struct smb_Dir
*dirp
)
1500 if (dirp
->dir
!= NULL
) {
1501 SMB_VFS_CLOSEDIR(dirp
->conn
,dirp
->dir
);
1502 if (dirp
->fsp
!= NULL
) {
1504 * The SMB_VFS_CLOSEDIR above
1505 * closes the underlying fd inside
1508 dirp
->fsp
->fh
->fd
= -1;
1509 if (dirp
->fsp
->dptr
!= NULL
) {
1510 SMB_ASSERT(dirp
->fsp
->dptr
->dir_hnd
== dirp
);
1511 dirp
->fsp
->dptr
->dir_hnd
= NULL
;
1519 /*******************************************************************
1521 ********************************************************************/
1523 static struct smb_Dir
*OpenDir_internal(TALLOC_CTX
*mem_ctx
,
1524 connection_struct
*conn
,
1525 const struct smb_filename
*smb_dname
,
1529 struct smb_Dir
*dirp
= talloc_zero(mem_ctx
, struct smb_Dir
);
1535 dirp
->dir
= SMB_VFS_OPENDIR(conn
, smb_dname
, mask
, attr
);
1538 DEBUG(5,("OpenDir: Can't open %s. %s\n",
1539 smb_dname
->base_name
,
1546 if (!conn
->sconn
->using_smb2
) {
1548 * The dircache is only needed for SMB1 because SMB1 uses a name
1549 * for the resume wheras SMB2 always continues from the next
1550 * position (unless it's told to restart or close-and-reopen the
1553 dirp
->name_cache_size
= lp_directory_name_cache_size(SNUM(conn
));
1556 talloc_set_destructor(dirp
, smb_Dir_destructor
);
1565 /****************************************************************************
1566 Open a directory handle by pathname, ensuring it's under the share path.
1567 ****************************************************************************/
1569 static struct smb_Dir
*open_dir_safely(TALLOC_CTX
*ctx
,
1570 connection_struct
*conn
,
1571 const struct smb_filename
*smb_dname
,
1575 struct smb_Dir
*dir_hnd
= NULL
;
1576 struct smb_filename
*smb_fname_cwd
= NULL
;
1577 struct smb_filename
*saved_dir_fname
= vfs_GetWd(ctx
, conn
);
1580 if (saved_dir_fname
== NULL
) {
1584 if (vfs_ChDir(conn
, smb_dname
) == -1) {
1588 smb_fname_cwd
= synthetic_smb_fname(talloc_tos(),
1593 if (smb_fname_cwd
== NULL
) {
1598 * Now the directory is pinned, use
1599 * REALPATH to ensure we can access it.
1601 status
= check_name(conn
, smb_fname_cwd
);
1602 if (!NT_STATUS_IS_OK(status
)) {
1606 dir_hnd
= OpenDir_internal(ctx
,
1612 if (dir_hnd
== NULL
) {
1617 * OpenDir_internal only gets "." as the dir name.
1618 * Store the real dir name here.
1621 dir_hnd
->dir_smb_fname
= cp_smb_filename(dir_hnd
, smb_dname
);
1622 if (!dir_hnd
->dir_smb_fname
) {
1623 TALLOC_FREE(dir_hnd
);
1629 vfs_ChDir(conn
, saved_dir_fname
);
1630 TALLOC_FREE(saved_dir_fname
);
1634 struct smb_Dir
*OpenDir(TALLOC_CTX
*mem_ctx
, connection_struct
*conn
,
1635 const struct smb_filename
*smb_dname
,
1639 return open_dir_safely(mem_ctx
,
1646 /*******************************************************************
1647 Open a directory from an fsp.
1648 ********************************************************************/
1650 static struct smb_Dir
*OpenDir_fsp(TALLOC_CTX
*mem_ctx
, connection_struct
*conn
,
1655 struct smb_Dir
*dirp
= talloc_zero(mem_ctx
, struct smb_Dir
);
1661 if (!fsp
->is_directory
) {
1666 if (fsp
->fh
->fd
== -1) {
1673 if (!conn
->sconn
->using_smb2
) {
1675 * The dircache is only needed for SMB1 because SMB1 uses a name
1676 * for the resume wheras SMB2 always continues from the next
1677 * position (unless it's told to restart or close-and-reopen the
1680 dirp
->name_cache_size
= lp_directory_name_cache_size(SNUM(conn
));
1683 dirp
->dir_smb_fname
= cp_smb_filename(dirp
, fsp
->fsp_name
);
1684 if (!dirp
->dir_smb_fname
) {
1689 dirp
->dir
= SMB_VFS_FDOPENDIR(fsp
, mask
, attr
);
1690 if (dirp
->dir
!= NULL
) {
1693 DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1695 dirp
->dir_smb_fname
->base_name
,
1697 if (errno
!= ENOSYS
) {
1702 if (dirp
->dir
== NULL
) {
1703 /* FDOPENDIR is not supported. Use OPENDIR instead. */
1705 return open_dir_safely(mem_ctx
,
1712 talloc_set_destructor(dirp
, smb_Dir_destructor
);
1722 /*******************************************************************
1723 Read from a directory.
1724 Return directory entry, current offset, and optional stat information.
1725 Don't check for veto or invisible files.
1726 ********************************************************************/
1728 const char *ReadDirName(struct smb_Dir
*dirp
, long *poffset
,
1729 SMB_STRUCT_STAT
*sbuf
, char **ptalloced
)
1732 char *talloced
= NULL
;
1733 connection_struct
*conn
= dirp
->conn
;
1735 /* Cheat to allow . and .. to be the first entries returned. */
1736 if (((*poffset
== START_OF_DIRECTORY_OFFSET
) ||
1737 (*poffset
== DOT_DOT_DIRECTORY_OFFSET
)) && (dirp
->file_number
< 2))
1739 if (dirp
->file_number
== 0) {
1741 *poffset
= dirp
->offset
= START_OF_DIRECTORY_OFFSET
;
1744 *poffset
= dirp
->offset
= DOT_DOT_DIRECTORY_OFFSET
;
1746 dirp
->file_number
++;
1751 if (*poffset
== END_OF_DIRECTORY_OFFSET
) {
1752 *poffset
= dirp
->offset
= END_OF_DIRECTORY_OFFSET
;
1756 /* A real offset, seek to it. */
1757 SeekDir(dirp
, *poffset
);
1759 while ((n
= vfs_readdirname(conn
, dirp
->dir
, sbuf
, &talloced
))) {
1760 /* Ignore . and .. - we've already returned them. */
1762 if ((n
[1] == '\0') || (n
[1] == '.' && n
[2] == '\0')) {
1763 TALLOC_FREE(talloced
);
1767 *poffset
= dirp
->offset
= SMB_VFS_TELLDIR(conn
, dirp
->dir
);
1768 *ptalloced
= talloced
;
1769 dirp
->file_number
++;
1772 *poffset
= dirp
->offset
= END_OF_DIRECTORY_OFFSET
;
1777 /*******************************************************************
1778 Rewind to the start.
1779 ********************************************************************/
1781 void RewindDir(struct smb_Dir
*dirp
, long *poffset
)
1783 SMB_VFS_REWINDDIR(dirp
->conn
, dirp
->dir
);
1784 dirp
->file_number
= 0;
1785 dirp
->offset
= START_OF_DIRECTORY_OFFSET
;
1786 *poffset
= START_OF_DIRECTORY_OFFSET
;
1789 /*******************************************************************
1791 ********************************************************************/
1793 void SeekDir(struct smb_Dir
*dirp
, long offset
)
1795 if (offset
!= dirp
->offset
) {
1796 if (offset
== START_OF_DIRECTORY_OFFSET
) {
1797 RewindDir(dirp
, &offset
);
1799 * Ok we should really set the file number here
1800 * to 1 to enable ".." to be returned next. Trouble
1801 * is I'm worried about callers using SeekDir(dirp,0)
1802 * as equivalent to RewindDir(). So leave this alone
1805 } else if (offset
== DOT_DOT_DIRECTORY_OFFSET
) {
1806 RewindDir(dirp
, &offset
);
1808 * Set the file number to 2 - we want to get the first
1809 * real file entry (the one we return after "..")
1810 * on the next ReadDir.
1812 dirp
->file_number
= 2;
1813 } else if (offset
== END_OF_DIRECTORY_OFFSET
) {
1814 ; /* Don't seek in this case. */
1816 SMB_VFS_SEEKDIR(dirp
->conn
, dirp
->dir
, offset
);
1818 dirp
->offset
= offset
;
1822 /*******************************************************************
1823 Tell a dir position.
1824 ********************************************************************/
1826 long TellDir(struct smb_Dir
*dirp
)
1828 return(dirp
->offset
);
1831 /*******************************************************************
1832 Add an entry into the dcache.
1833 ********************************************************************/
1835 static void DirCacheAdd(struct smb_Dir
*dirp
, const char *name
, long offset
)
1837 struct name_cache_entry
*e
;
1839 if (dirp
->name_cache_size
== 0) {
1843 if (dirp
->name_cache
== NULL
) {
1844 dirp
->name_cache
= talloc_zero_array(
1845 dirp
, struct name_cache_entry
, dirp
->name_cache_size
);
1847 if (dirp
->name_cache
== NULL
) {
1852 dirp
->name_cache_index
= (dirp
->name_cache_index
+1) %
1853 dirp
->name_cache_size
;
1854 e
= &dirp
->name_cache
[dirp
->name_cache_index
];
1855 TALLOC_FREE(e
->name
);
1856 e
->name
= talloc_strdup(dirp
, name
);
1860 /*******************************************************************
1861 Find an entry by name. Leave us at the offset after it.
1862 Don't check for veto or invisible files.
1863 ********************************************************************/
1865 bool SearchDir(struct smb_Dir
*dirp
, const char *name
, long *poffset
)
1868 const char *entry
= NULL
;
1869 char *talloced
= NULL
;
1870 connection_struct
*conn
= dirp
->conn
;
1872 /* Search back in the name cache. */
1873 if (dirp
->name_cache_size
&& dirp
->name_cache
) {
1874 for (i
= dirp
->name_cache_index
; i
>= 0; i
--) {
1875 struct name_cache_entry
*e
= &dirp
->name_cache
[i
];
1876 if (e
->name
&& (conn
->case_sensitive
? (strcmp(e
->name
, name
) == 0) : strequal(e
->name
, name
))) {
1877 *poffset
= e
->offset
;
1878 SeekDir(dirp
, e
->offset
);
1882 for (i
= dirp
->name_cache_size
- 1; i
> dirp
->name_cache_index
; i
--) {
1883 struct name_cache_entry
*e
= &dirp
->name_cache
[i
];
1884 if (e
->name
&& (conn
->case_sensitive
? (strcmp(e
->name
, name
) == 0) : strequal(e
->name
, name
))) {
1885 *poffset
= e
->offset
;
1886 SeekDir(dirp
, e
->offset
);
1892 /* Not found in the name cache. Rewind directory and start from scratch. */
1893 SMB_VFS_REWINDDIR(conn
, dirp
->dir
);
1894 dirp
->file_number
= 0;
1895 *poffset
= START_OF_DIRECTORY_OFFSET
;
1896 while ((entry
= ReadDirName(dirp
, poffset
, NULL
, &talloced
))) {
1897 if (conn
->case_sensitive
? (strcmp(entry
, name
) == 0) : strequal(entry
, name
)) {
1898 TALLOC_FREE(talloced
);
1901 TALLOC_FREE(talloced
);
1906 struct files_below_forall_state
{
1909 int (*fn
)(struct file_id fid
, const struct share_mode_data
*data
,
1910 void *private_data
);
1914 static int files_below_forall_fn(struct file_id fid
,
1915 const struct share_mode_data
*data
,
1918 struct files_below_forall_state
*state
= private_data
;
1919 char tmpbuf
[PATH_MAX
];
1920 char *fullpath
, *to_free
;
1923 len
= full_path_tos(data
->servicepath
, data
->base_name
,
1924 tmpbuf
, sizeof(tmpbuf
),
1925 &fullpath
, &to_free
);
1929 if (state
->dirpath_len
>= len
) {
1931 * Filter files above dirpath
1935 if (fullpath
[state
->dirpath_len
] != '/') {
1937 * Filter file that don't have a path separator at the end of
1943 if (memcmp(state
->dirpath
, fullpath
, state
->dirpath_len
) != 0) {
1950 TALLOC_FREE(to_free
);
1951 return state
->fn(fid
, data
, state
->private_data
);
1954 TALLOC_FREE(to_free
);
1958 static int files_below_forall(connection_struct
*conn
,
1959 const struct smb_filename
*dir_name
,
1960 int (*fn
)(struct file_id fid
,
1961 const struct share_mode_data
*data
,
1962 void *private_data
),
1965 struct files_below_forall_state state
= {
1967 .private_data
= private_data
,
1970 char tmpbuf
[PATH_MAX
];
1973 state
.dirpath_len
= full_path_tos(conn
->connectpath
,
1974 dir_name
->base_name
,
1975 tmpbuf
, sizeof(tmpbuf
),
1976 &state
.dirpath
, &to_free
);
1977 if (state
.dirpath_len
== -1) {
1981 ret
= share_mode_forall(files_below_forall_fn
, &state
);
1982 TALLOC_FREE(to_free
);
1986 struct have_file_open_below_state
{
1990 static int have_file_open_below_fn(struct file_id fid
,
1991 const struct share_mode_data
*data
,
1994 struct have_file_open_below_state
*state
= private_data
;
1995 state
->found_one
= true;
1999 bool have_file_open_below(connection_struct
*conn
,
2000 const struct smb_filename
*name
)
2002 struct have_file_open_below_state state
= {
2007 if (!VALID_STAT(name
->st
)) {
2010 if (!S_ISDIR(name
->st
.st_ex_mode
)) {
2014 ret
= files_below_forall(conn
, name
, have_file_open_below_fn
, &state
);
2019 return state
.found_one
;
2022 /*****************************************************************
2023 Is this directory empty ?
2024 *****************************************************************/
2026 NTSTATUS
can_delete_directory_fsp(files_struct
*fsp
)
2028 NTSTATUS status
= NT_STATUS_OK
;
2030 const char *dname
= NULL
;
2031 const char *dirname
= fsp
->fsp_name
->base_name
;
2032 char *talloced
= NULL
;
2034 struct connection_struct
*conn
= fsp
->conn
;
2035 struct smb_Dir
*dir_hnd
= OpenDir(talloc_tos(),
2042 return map_nt_error_from_unix(errno
);
2045 while ((dname
= ReadDirName(dir_hnd
, &dirpos
, &st
, &talloced
))) {
2046 /* Quick check for "." and ".." */
2047 if (dname
[0] == '.') {
2048 if (!dname
[1] || (dname
[1] == '.' && !dname
[2])) {
2049 TALLOC_FREE(talloced
);
2054 if (!is_visible_file(conn
, dirname
, dname
, &st
, True
)) {
2055 TALLOC_FREE(talloced
);
2059 DEBUG(10,("got name %s - can't delete\n",
2061 status
= NT_STATUS_DIRECTORY_NOT_EMPTY
;
2064 TALLOC_FREE(talloced
);
2065 TALLOC_FREE(dir_hnd
);
2067 if (!NT_STATUS_IS_OK(status
)) {
2071 if (!(fsp
->posix_flags
& FSP_POSIX_FLAGS_RENAME
) &&
2072 lp_strict_rename(SNUM(conn
)) &&
2073 have_file_open_below(fsp
->conn
, fsp
->fsp_name
))
2075 return NT_STATUS_ACCESS_DENIED
;
2078 return NT_STATUS_OK
;