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 "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"
33 This module implements directory related functions for Samba.
36 /* "Special" directory offsets. */
37 #define END_OF_DIRECTORY_OFFSET ((long)-1)
38 #define START_OF_DIRECTORY_OFFSET ((long)0)
39 #define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
41 /* "Special" directory offsets in 32-bit wire format. */
42 #define WIRE_END_OF_DIRECTORY_OFFSET ((uint32_t)0xFFFFFFFF)
43 #define WIRE_START_OF_DIRECTORY_OFFSET ((uint32_t)0)
44 #define WIRE_DOT_DOT_DIRECTORY_OFFSET ((uint32_t)0x80000000)
46 /* Make directory handle internals available. */
48 struct name_cache_entry
{
54 connection_struct
*conn
;
57 struct smb_filename
*dir_smb_fname
;
58 size_t name_cache_size
;
59 struct name_cache_entry
*name_cache
;
60 unsigned int name_cache_index
;
61 unsigned int file_number
;
63 files_struct
*fsp
; /* Back pointer to containing fsp, only
64 set from OpenDir_fsp(). */
68 struct dptr_struct
*next
, *prev
;
71 struct connection_struct
*conn
;
72 struct smb_Dir
*dir_hnd
;
76 struct smb_filename
*smb_dname
;
77 bool has_wild
; /* Set to true if the wcard entry has MS wildcard characters in it. */
78 bool did_stat
; /* Optimisation for non-wcard searches. */
79 bool priv
; /* Directory handle opened with privilege. */
81 struct memcache
*dptr_cache
;
84 static NTSTATUS
OpenDir_fsp(
86 connection_struct
*conn
,
90 struct smb_Dir
**_dir_hnd
);
92 static void DirCacheAdd(struct smb_Dir
*dir_hnd
, const char *name
, long offset
);
94 static int smb_Dir_destructor(struct smb_Dir
*dir_hnd
);
96 static bool SearchDir(struct smb_Dir
*dir_hnd
, const char *name
, long *poffset
);
98 #define INVALID_DPTR_KEY (-3)
100 /****************************************************************************
101 Initialise the dir bitmap.
102 ****************************************************************************/
104 bool init_dptrs(struct smbd_server_connection
*sconn
)
106 if (sconn
->searches
.dptr_bmap
) {
110 sconn
->searches
.dptr_bmap
= bitmap_talloc(
111 sconn
, MAX_DIRECTORY_HANDLES
);
113 if (sconn
->searches
.dptr_bmap
== NULL
) {
120 /****************************************************************************
121 Get the struct dptr_struct for a dir index.
122 ****************************************************************************/
124 static struct dptr_struct
*dptr_get(struct smbd_server_connection
*sconn
,
127 struct dptr_struct
*dptr
;
129 for (dptr
= sconn
->searches
.dirptrs
; dptr
!= NULL
; dptr
= dptr
->next
) {
130 if(dptr
->dnum
!= key
) {
133 DLIST_PROMOTE(sconn
->searches
.dirptrs
, dptr
);
139 /****************************************************************************
140 Get the dir path for a dir index.
141 ****************************************************************************/
143 const char *dptr_path(struct smbd_server_connection
*sconn
, int key
)
145 struct dptr_struct
*dptr
= dptr_get(sconn
, key
);
147 return(dptr
->smb_dname
->base_name
);
151 /****************************************************************************
152 Get the dir wcard for a dir index.
153 ****************************************************************************/
155 const char *dptr_wcard(struct smbd_server_connection
*sconn
, int key
)
157 struct dptr_struct
*dptr
= dptr_get(sconn
, key
);
163 /****************************************************************************
164 Get the dir attrib for a dir index.
165 ****************************************************************************/
167 uint16_t dptr_attr(struct smbd_server_connection
*sconn
, int key
)
169 struct dptr_struct
*dptr
= dptr_get(sconn
, key
);
175 /****************************************************************************
176 Close all dptrs for a cnum.
177 ****************************************************************************/
179 void dptr_closecnum(connection_struct
*conn
)
181 struct dptr_struct
*dptr
, *next
;
182 struct smbd_server_connection
*sconn
= conn
->sconn
;
188 for(dptr
= sconn
->searches
.dirptrs
; dptr
; dptr
= next
) {
190 if (dptr
->conn
== conn
) {
192 * Need to make a copy, "dptr" will be gone
193 * after close_file_free() returns
195 struct files_struct
*fsp
= dptr
->dir_hnd
->fsp
;
196 close_file_free(NULL
, &fsp
, NORMAL_CLOSE
);
201 /****************************************************************************
202 Create a new dir ptr. If the flag old_handle is true then we must allocate
203 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
204 one byte long. If old_handle is false we allocate from the range
205 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
206 a directory handle is never zero.
207 wcard must not be zero.
208 ****************************************************************************/
210 NTSTATUS
dptr_create(connection_struct
*conn
,
211 struct smb_request
*req
,
218 struct dptr_struct
**dptr_ret
)
220 struct smbd_server_connection
*sconn
= conn
->sconn
;
221 struct dptr_struct
*dptr
= NULL
;
222 struct smb_Dir
*dir_hnd
= NULL
;
225 DBG_INFO("dir=%s\n", fsp_str_dbg(fsp
));
228 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
229 return NT_STATUS_INTERNAL_ERROR
;
233 return NT_STATUS_INVALID_PARAMETER
;
236 if (!(fsp
->access_mask
& SEC_DIR_LIST
)) {
237 DBG_INFO("dptr_create: directory %s "
238 "not open for LIST access\n",
240 return NT_STATUS_ACCESS_DENIED
;
242 status
= OpenDir_fsp(NULL
, conn
, fsp
, wcard
, attr
, &dir_hnd
);
243 if (!NT_STATUS_IS_OK(status
)) {
247 dptr
= talloc_zero(NULL
, struct dptr_struct
);
249 DEBUG(0,("talloc fail in dptr_create.\n"));
250 TALLOC_FREE(dir_hnd
);
251 return NT_STATUS_NO_MEMORY
;
254 dptr
->smb_dname
= cp_smb_filename(dptr
, fsp
->fsp_name
);
255 if (dptr
->smb_dname
== NULL
) {
257 TALLOC_FREE(dir_hnd
);
258 return NT_STATUS_NO_MEMORY
;
261 dptr
->dir_hnd
= dir_hnd
;
263 dptr
->expect_close
= expect_close
;
264 dptr
->wcard
= talloc_strdup(dptr
, wcard
);
267 TALLOC_FREE(dir_hnd
);
268 return NT_STATUS_NO_MEMORY
;
270 if ((req
!= NULL
&& req
->posix_pathnames
) ||
271 (wcard
[0] == '.' && wcard
[1] == 0)) {
272 dptr
->has_wild
= True
;
274 dptr
->has_wild
= ms_has_wild(dptr
->wcard
);
279 if (sconn
->using_smb2
) {
286 * This is an old-style SMBsearch request. Ensure the
287 * value we return will fit in the range 1-255.
290 dptr
->dnum
= bitmap_find(sconn
->searches
.dptr_bmap
, 0);
292 if(dptr
->dnum
== -1 || dptr
->dnum
> 254) {
293 DBG_ERR("returned %d: Error - all old "
294 "dirptrs in use ?\n",
297 TALLOC_FREE(dir_hnd
);
298 return NT_STATUS_TOO_MANY_OPENED_FILES
;
303 * This is a new-style trans2 request. Allocate from
304 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
307 dptr
->dnum
= bitmap_find(sconn
->searches
.dptr_bmap
, 255);
309 if(dptr
->dnum
== -1 || dptr
->dnum
< 255) {
310 DBG_ERR("returned %d: Error - all new "
311 "dirptrs in use ?\n",
314 TALLOC_FREE(dir_hnd
);
315 return NT_STATUS_TOO_MANY_OPENED_FILES
;
319 bitmap_set(sconn
->searches
.dptr_bmap
, dptr
->dnum
);
321 dptr
->dnum
+= 1; /* Always bias the dnum by one - no zero dnums allowed. */
323 DLIST_ADD(sconn
->searches
.dirptrs
, dptr
);
326 DBG_INFO("creating new dirptr [%d] for path [%s], expect_close = %d\n",
327 dptr
->dnum
, fsp_str_dbg(fsp
), expect_close
);
335 /****************************************************************************
336 Wrapper functions to access the lower level directory handles.
337 ****************************************************************************/
339 void dptr_CloseDir(files_struct
*fsp
)
341 struct smbd_server_connection
*sconn
= NULL
;
343 if (fsp
->dptr
== NULL
) {
346 sconn
= fsp
->dptr
->conn
->sconn
;
349 * The destructor for the struct smb_Dir (fsp->dptr->dir_hnd)
350 * now handles all resource deallocation.
353 DBG_INFO("closing dptr key %d\n", fsp
->dptr
->dnum
);
355 if (sconn
!= NULL
&& !sconn
->using_smb2
) {
356 DLIST_REMOVE(sconn
->searches
.dirptrs
, fsp
->dptr
);
359 * Free the dnum in the bitmap. Remember the dnum value is
360 * always biased by one with respect to the bitmap.
363 if (!bitmap_query(sconn
->searches
.dptr_bmap
,
364 fsp
->dptr
->dnum
- 1))
366 DBG_ERR("closing dnum = %d and bitmap not set !\n",
370 bitmap_clear(sconn
->searches
.dptr_bmap
, fsp
->dptr
->dnum
- 1);
373 TALLOC_FREE(fsp
->dptr
->dir_hnd
);
374 TALLOC_FREE(fsp
->dptr
);
377 void dptr_SeekDir(struct dptr_struct
*dptr
, long offset
)
379 SeekDir(dptr
->dir_hnd
, offset
);
382 long dptr_TellDir(struct dptr_struct
*dptr
)
384 return TellDir(dptr
->dir_hnd
);
387 bool dptr_has_wild(struct dptr_struct
*dptr
)
389 return dptr
->has_wild
;
392 int dptr_dnum(struct dptr_struct
*dptr
)
397 bool dptr_get_priv(struct dptr_struct
*dptr
)
402 void dptr_set_priv(struct dptr_struct
*dptr
)
407 bool dptr_case_sensitive(struct dptr_struct
*dptr
)
409 return dptr
->dir_hnd
->case_sensitive
;
412 /****************************************************************************
413 Return the next visible file name, skipping veto'd and invisible files.
414 ****************************************************************************/
416 static char *dptr_ReadDirName(TALLOC_CTX
*ctx
,
417 struct dptr_struct
*dptr
,
419 SMB_STRUCT_STAT
*pst
)
421 struct smb_filename smb_fname_base
;
423 const char *name_temp
= NULL
;
424 char *talloced
= NULL
;
425 char *pathreal
= NULL
;
426 char *found_name
= NULL
;
429 SET_STAT_INVALID(*pst
);
431 if (dptr
->has_wild
|| dptr
->did_stat
) {
432 name_temp
= ReadDirName(dptr
->dir_hnd
, poffset
, pst
,
434 if (name_temp
== NULL
) {
437 if (talloced
!= NULL
) {
438 return talloc_move(ctx
, &talloced
);
440 return talloc_strdup(ctx
, name_temp
);
443 /* If poffset is -1 then we know we returned this name before and we
444 * have no wildcards. We're at the end of the directory. */
445 if (*poffset
== END_OF_DIRECTORY_OFFSET
) {
449 /* We know the stored wcard contains no wildcard characters.
450 * See if we can match with a stat call. If we can't, then set
451 * did_stat to true to ensure we only do this once and keep
454 dptr
->did_stat
= true;
456 if (VALID_STAT(*pst
)) {
457 name
= talloc_strdup(ctx
, dptr
->wcard
);
461 pathreal
= talloc_asprintf(ctx
,
463 dptr
->smb_dname
->base_name
,
468 /* Create an smb_filename with stream_name == NULL. */
469 smb_fname_base
= (struct smb_filename
) {
470 .base_name
= pathreal
,
471 .flags
= dptr
->dir_hnd
->fsp
->fsp_name
->flags
,
472 .twrp
= dptr
->smb_dname
->twrp
,
475 if (vfs_stat(dptr
->conn
, &smb_fname_base
) == 0) {
476 *pst
= smb_fname_base
.st
;
477 name
= talloc_strdup(ctx
, dptr
->wcard
);
480 /* If we get any other error than ENOENT or ENOTDIR
481 then the file exists we just can't stat it. */
482 if (errno
!= ENOENT
&& errno
!= ENOTDIR
) {
483 name
= talloc_strdup(ctx
, dptr
->wcard
);
488 /* Stat failed. We know this is authoritative if we are
489 * providing case sensitive semantics or the underlying
490 * filesystem is case sensitive.
492 if (dptr
->dir_hnd
->case_sensitive
||
493 !(dptr
->conn
->fs_capabilities
& FILE_CASE_SENSITIVE_SEARCH
))
499 * Try case-insensitive stat if the fs has the ability. This avoids
500 * scanning the whole directory.
502 ret
= SMB_VFS_GET_REAL_FILENAME(dptr
->conn
,
510 } else if (errno
== ENOENT
) {
511 /* The case-insensitive lookup was authoritative. */
515 TALLOC_FREE(pathreal
);
517 name_temp
= ReadDirName(dptr
->dir_hnd
, poffset
, pst
, &talloced
);
518 if (name_temp
== NULL
) {
521 if (talloced
!= NULL
) {
522 return talloc_move(ctx
, &talloced
);
524 return talloc_strdup(ctx
, name_temp
);
527 TALLOC_FREE(pathreal
);
529 /* We need to set the underlying dir_hnd offset to -1
530 * also as this function is usually called with the
531 * output from TellDir. */
532 dptr
->dir_hnd
->offset
= *poffset
= END_OF_DIRECTORY_OFFSET
;
536 /****************************************************************************
537 Search for a file by name.
538 ****************************************************************************/
540 bool dptr_SearchDir(struct dptr_struct
*dptr
, const char *name
, long *poffset
, SMB_STRUCT_STAT
*pst
)
542 SET_STAT_INVALID(*pst
);
544 if (!dptr
->has_wild
&& (dptr
->dir_hnd
->offset
== END_OF_DIRECTORY_OFFSET
)) {
545 /* This is a singleton directory and we're already at the end. */
546 *poffset
= END_OF_DIRECTORY_OFFSET
;
550 return SearchDir(dptr
->dir_hnd
, name
, poffset
);
553 /****************************************************************************
554 Map a native directory offset to a 32-bit cookie.
555 ****************************************************************************/
557 static uint32_t map_dir_offset_to_wire(struct dptr_struct
*dptr
, long offset
)
562 if (offset
== END_OF_DIRECTORY_OFFSET
) {
563 return WIRE_END_OF_DIRECTORY_OFFSET
;
564 } else if(offset
== START_OF_DIRECTORY_OFFSET
) {
565 return WIRE_START_OF_DIRECTORY_OFFSET
;
566 } else if (offset
== DOT_DOT_DIRECTORY_OFFSET
) {
567 return WIRE_DOT_DOT_DIRECTORY_OFFSET
;
569 if (sizeof(long) == 4) {
570 /* 32-bit machine. We can cheat... */
571 return (uint32_t)offset
;
573 if (dptr
->dptr_cache
== NULL
) {
574 /* Lazy initialize cache. */
575 dptr
->dptr_cache
= memcache_init(dptr
, 0);
576 if (dptr
->dptr_cache
== NULL
) {
577 return WIRE_END_OF_DIRECTORY_OFFSET
;
580 /* Have we seen this offset before ? */
581 key
.data
= (void *)&offset
;
582 key
.length
= sizeof(offset
);
583 if (memcache_lookup(dptr
->dptr_cache
,
584 SMB1_SEARCH_OFFSET_MAP
,
587 uint32_t wire_offset
;
588 SMB_ASSERT(val
.length
== sizeof(wire_offset
));
589 memcpy(&wire_offset
, val
.data
, sizeof(wire_offset
));
590 DEBUG(10,("found wire %u <-> offset %ld\n",
591 (unsigned int)wire_offset
,
596 /* Allocate a new wire cookie. */
599 } while (dptr
->counter
== WIRE_START_OF_DIRECTORY_OFFSET
||
600 dptr
->counter
== WIRE_END_OF_DIRECTORY_OFFSET
||
601 dptr
->counter
== WIRE_DOT_DOT_DIRECTORY_OFFSET
);
602 /* Store it in the cache. */
603 key
.data
= (void *)&offset
;
604 key
.length
= sizeof(offset
);
605 val
.data
= (void *)&dptr
->counter
;
606 val
.length
= sizeof(dptr
->counter
); /* MUST BE uint32_t ! */
607 memcache_add(dptr
->dptr_cache
,
608 SMB1_SEARCH_OFFSET_MAP
,
611 /* And the reverse mapping for lookup from
612 map_wire_to_dir_offset(). */
613 memcache_add(dptr
->dptr_cache
,
614 SMB1_SEARCH_OFFSET_MAP
,
617 DEBUG(10,("stored wire %u <-> offset %ld\n",
618 (unsigned int)dptr
->counter
,
620 return dptr
->counter
;
623 /****************************************************************************
624 Fill the 5 byte server reserved dptr field.
625 ****************************************************************************/
627 bool dptr_fill(struct smbd_server_connection
*sconn
,
628 char *buf1
,unsigned int key
)
630 unsigned char *buf
= (unsigned char *)buf1
;
631 struct dptr_struct
*dptr
= dptr_get(sconn
, key
);
632 uint32_t wire_offset
;
634 DEBUG(1,("filling null dirptr %d\n",key
));
637 wire_offset
= map_dir_offset_to_wire(dptr
,TellDir(dptr
->dir_hnd
));
638 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key
,
639 (long)dptr
->dir_hnd
,(int)wire_offset
));
641 SIVAL(buf
,1,wire_offset
);
645 /****************************************************************************
646 Map a 32-bit wire cookie to a native directory offset.
647 ****************************************************************************/
649 static long map_wire_to_dir_offset(struct dptr_struct
*dptr
, uint32_t wire_offset
)
654 if (wire_offset
== WIRE_END_OF_DIRECTORY_OFFSET
) {
655 return END_OF_DIRECTORY_OFFSET
;
656 } else if(wire_offset
== WIRE_START_OF_DIRECTORY_OFFSET
) {
657 return START_OF_DIRECTORY_OFFSET
;
658 } else if (wire_offset
== WIRE_DOT_DOT_DIRECTORY_OFFSET
) {
659 return DOT_DOT_DIRECTORY_OFFSET
;
661 if (sizeof(long) == 4) {
662 /* 32-bit machine. We can cheat... */
663 return (long)wire_offset
;
665 if (dptr
->dptr_cache
== NULL
) {
666 /* Logic error, cache should be initialized. */
667 return END_OF_DIRECTORY_OFFSET
;
669 key
.data
= (void *)&wire_offset
;
670 key
.length
= sizeof(wire_offset
);
671 if (memcache_lookup(dptr
->dptr_cache
,
672 SMB1_SEARCH_OFFSET_MAP
,
677 SMB_ASSERT(val
.length
== sizeof(offset
));
678 memcpy(&offset
, val
.data
, sizeof(offset
));
679 DEBUG(10,("lookup wire %u <-> offset %ld\n",
680 (unsigned int)wire_offset
,
684 return END_OF_DIRECTORY_OFFSET
;
687 /****************************************************************************
688 Return the associated fsp and seek the dir_hnd on it it given the 5 byte
690 ****************************************************************************/
692 files_struct
*dptr_fetch_fsp(struct smbd_server_connection
*sconn
,
695 unsigned int key
= *(unsigned char *)buf
;
696 struct dptr_struct
*dptr
= dptr_get(sconn
, key
);
697 uint32_t wire_offset
;
701 DEBUG(3,("fetched null dirptr %d\n",key
));
705 wire_offset
= IVAL(buf
,1);
706 seekoff
= map_wire_to_dir_offset(dptr
, wire_offset
);
707 SeekDir(dptr
->dir_hnd
,seekoff
);
708 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
709 key
, dptr
->smb_dname
->base_name
, (int)seekoff
));
710 return dptr
->dir_hnd
->fsp
;
713 struct files_struct
*dir_hnd_fetch_fsp(struct smb_Dir
*dir_hnd
)
718 /****************************************************************************
719 Fetch the fsp associated with the dptr_num.
720 ****************************************************************************/
722 files_struct
*dptr_fetch_lanman2_fsp(struct smbd_server_connection
*sconn
,
725 struct dptr_struct
*dptr
= dptr_get(sconn
, dptr_num
);
729 DBG_NOTICE("fetching dirptr %d for path %s\n",
731 dptr
->smb_dname
->base_name
);
732 return dptr
->dir_hnd
->fsp
;
735 static bool mangle_mask_match(connection_struct
*conn
,
736 const char *filename
,
741 if (!name_to_8_3(filename
,mname
,False
,conn
->params
)) {
744 return mask_match_search(mname
,mask
,False
);
747 bool smbd_dirptr_get_entry(TALLOC_CTX
*ctx
,
748 struct dptr_struct
*dirptr
,
754 bool (*match_fn
)(TALLOC_CTX
*ctx
,
759 bool (*mode_fn
)(TALLOC_CTX
*ctx
,
761 struct files_struct
*dirfsp
,
762 struct smb_filename
*atname
,
763 struct smb_filename
*smb_fname
,
768 struct smb_filename
**_smb_fname
,
772 connection_struct
*conn
= dirptr
->conn
;
775 const char *dpath
= dirptr
->smb_dname
->base_name
;
776 bool dirptr_path_is_dot
= ISDOT(dpath
);
783 pathlen
= strlen(dpath
);
784 slashlen
= ( dpath
[pathlen
-1] != '/') ? 1 : 0;
789 SMB_STRUCT_STAT sbuf
= { 0 };
793 char *pathreal
= NULL
;
794 struct smb_filename
*atname
= NULL
;
795 struct smb_filename
*smb_fname
= NULL
;
797 bool check_dfs_symlink
= false;
798 bool get_dosmode
= get_dosmode_in
;
801 cur_offset
= dptr_TellDir(dirptr
);
802 prev_offset
= cur_offset
;
803 dname
= dptr_ReadDirName(ctx
, dirptr
, &cur_offset
, &sbuf
);
805 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
806 (long)dirptr
, cur_offset
));
812 isdots
= (ISDOT(dname
) || ISDOTDOT(dname
));
813 if (dont_descend
&& !isdots
) {
818 if (IS_VETO_PATH(conn
, dname
)) {
824 * fname may get mangled, dname is never mangled.
825 * Whenever we're accessing the filesystem we use
826 * pathreal which is composed from dname.
829 ok
= match_fn(ctx
, private_data
, dname
, mask
, &fname
);
837 * pathreal = talloc_asprintf(ctx, "%s%s%s", dirptr->path,
838 * needslash?"/":"", dname);
839 * but this was measurably slower than doing the memcpy.
842 pathreal
= talloc_array(
844 pathlen
+ slashlen
+ talloc_get_size(dname
));
852 * We don't want to pass ./xxx to modules below us so don't
853 * add the path if it is just . by itself.
855 if (dirptr_path_is_dot
) {
856 memcpy(pathreal
, dname
, talloc_get_size(dname
));
858 memcpy(pathreal
, dpath
, pathlen
);
859 pathreal
[pathlen
] = '/';
860 memcpy(pathreal
+ slashlen
+ pathlen
, dname
,
861 talloc_get_size(dname
));
864 /* Create smb_fname with NULL stream_name. */
865 smb_fname
= synthetic_smb_fname(talloc_tos(),
869 dirptr
->smb_dname
->twrp
,
870 dirptr
->smb_dname
->flags
);
871 TALLOC_FREE(pathreal
);
872 if (smb_fname
== NULL
) {
878 if (!VALID_STAT(smb_fname
->st
)) {
880 * If stat() fails with ENOENT it might be a
881 * msdfs-symlink in Windows context, this is checked
882 * below, for now we just want to fill stat info as good
885 ret
= vfs_stat(conn
, smb_fname
);
886 if (ret
!= 0 && errno
!= ENOENT
) {
887 TALLOC_FREE(smb_fname
);
894 /* Create smb_fname with NULL stream_name. */
895 atname
= synthetic_smb_fname(talloc_tos(),
899 dirptr
->smb_dname
->twrp
,
900 dirptr
->smb_dname
->flags
);
901 if (atname
== NULL
) {
904 TALLOC_FREE(smb_fname
);
909 * openat_pathref_fsp() will return
910 * NT_STATUS_OBJECT_NAME_NOT_FOUND in non-POSIX context when
911 * hitting a dangling symlink. It may be a DFS symlink, this is
912 * checked below by the mode_fn() call, so we have to allow this
915 * NT_STATUS_STOPPED_ON_SYMLINK is returned in POSIX context
916 * when hitting a symlink and ensures we always return directory
917 * entries that are symlinks in POSIX context.
919 status
= openat_pathref_fsp(dirptr
->dir_hnd
->fsp
, atname
);
920 if (!NT_STATUS_IS_OK(status
) &&
921 !NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
))
926 TALLOC_FREE(smb_fname
);
928 } else if (NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
929 if (!(atname
->flags
& SMB_FILENAME_POSIX_PATH
)) {
930 check_dfs_symlink
= true;
933 * Check if it's a symlink. We only want to return this
934 * if it's a DFS symlink or in POSIX mode. Disable
935 * getting dosmode in the mode_fn() and prime the mode
936 * as FILE_ATTRIBUTE_NORMAL.
938 mode
= FILE_ATTRIBUTE_NORMAL
;
942 status
= move_smb_fname_fsp_link(smb_fname
, atname
);
943 if (!NT_STATUS_IS_OK(status
)) {
944 DBG_WARNING("Failed to move pathref for [%s]: %s\n",
945 smb_fname_str_dbg(smb_fname
),
948 TALLOC_FREE(smb_fname
);
954 if (!is_visible_fsp(smb_fname
->fsp
)) {
956 TALLOC_FREE(smb_fname
);
963 * Don't leak metadata about the containing
964 * directory of the share.
966 if (dirptr_path_is_dot
&& ISDOTDOT(dname
)) {
968 * Making a copy here, then freeing
969 * the original will close the smb_fname->fsp.
971 struct smb_filename
*tmp_smb_fname
=
972 cp_smb_filename(ctx
, smb_fname
);
974 if (tmp_smb_fname
== NULL
) {
976 TALLOC_FREE(smb_fname
);
981 TALLOC_FREE(smb_fname
);
982 smb_fname
= tmp_smb_fname
;
983 mode
= FILE_ATTRIBUTE_DIRECTORY
;
989 dirptr
->dir_hnd
->fsp
,
996 TALLOC_FREE(smb_fname
);
1002 TALLOC_FREE(atname
);
1005 * The only valid cases where we return the directory entry if
1006 * it's a symlink are:
1008 * 1. POSIX context, always return it, or
1010 * 2. a DFS symlink where the mode_fn() call above has verified
1011 * this and set mode to FILE_ATTRIBUTE_REPARSE_POINT.
1013 if (check_dfs_symlink
&&
1014 !(mode
& FILE_ATTRIBUTE_REPARSE_POINT
))
1016 TALLOC_FREE(smb_fname
);
1022 if (!dir_check_ftype(mode
, dirtype
)) {
1023 DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
1024 fname
, (unsigned int)mode
, (unsigned int)dirtype
));
1025 TALLOC_FREE(smb_fname
);
1031 if (ask_sharemode
&& !S_ISDIR(smb_fname
->st
.st_ex_mode
)) {
1032 struct timespec write_time_ts
;
1033 struct file_id fileid
;
1035 fileid
= vfs_file_id_from_sbuf(conn
,
1037 get_file_infos(fileid
, 0, NULL
, &write_time_ts
);
1038 if (!is_omit_timespec(&write_time_ts
)) {
1039 update_stat_ex_mtime(&smb_fname
->st
,
1044 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
1046 mask
, smb_fname_str_dbg(smb_fname
),
1049 if (!conn
->sconn
->using_smb2
) {
1051 * The dircache is only needed for SMB1 because SMB1
1052 * uses a name for the resume wheras SMB2 always
1053 * continues from the next position (unless it's told to
1054 * restart or close-and-reopen the listing).
1056 DirCacheAdd(dirptr
->dir_hnd
, dname
, cur_offset
);
1061 *_smb_fname
= talloc_move(ctx
, &smb_fname
);
1062 if (*_smb_fname
== NULL
) {
1067 *_prev_offset
= prev_offset
;
1075 /****************************************************************************
1076 Get an 8.3 directory entry.
1077 ****************************************************************************/
1079 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX
*ctx
,
1085 connection_struct
*conn
= (connection_struct
*)private_data
;
1087 if ((strcmp(mask
,"*.*") == 0) ||
1088 mask_match_search(dname
, mask
, false) ||
1089 mangle_mask_match(conn
, dname
, mask
)) {
1093 * Ensure we can push the original name as UCS2. If
1094 * not, then just don't return this name.
1098 size_t len
= (strlen(dname
) + 2) * 4; /* Allow enough space. */
1099 uint8_t *tmp
= talloc_array(talloc_tos(),
1103 status
= srvstr_push(NULL
,
1104 FLAGS2_UNICODE_STRINGS
,
1113 if (!NT_STATUS_IS_OK(status
)) {
1117 if (!mangle_is_8_3(dname
, false, conn
->params
)) {
1118 bool ok
= name_to_8_3(dname
, mname
, false,
1128 *_fname
= talloc_strdup(ctx
, fname
);
1129 if (*_fname
== NULL
) {
1139 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX
*ctx
,
1141 struct files_struct
*dirfsp
,
1142 struct smb_filename
*atname
,
1143 struct smb_filename
*smb_fname
,
1147 connection_struct
*conn
= (connection_struct
*)private_data
;
1149 if (!VALID_STAT(smb_fname
->st
)) {
1150 if ((SMB_VFS_STAT(conn
, smb_fname
)) != 0) {
1151 DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1152 "Couldn't stat [%s]. Error "
1154 smb_fname_str_dbg(smb_fname
),
1161 *_mode
= fdos_mode(smb_fname
->fsp
);
1162 smb_fname
->st
= smb_fname
->fsp
->fsp_name
->st
;
1167 bool get_dir_entry(TALLOC_CTX
*ctx
,
1168 struct dptr_struct
*dirptr
,
1174 struct timespec
*_date
,
1178 connection_struct
*conn
= dirptr
->conn
;
1180 struct smb_filename
*smb_fname
= NULL
;
1185 ok
= smbd_dirptr_get_entry(ctx
,
1192 smbd_dirptr_8_3_match_fn
,
1193 smbd_dirptr_8_3_mode_fn
,
1203 *_fname
= talloc_move(ctx
, &fname
);
1204 *_size
= smb_fname
->st
.st_ex_size
;
1206 *_date
= smb_fname
->st
.st_ex_mtime
;
1207 TALLOC_FREE(smb_fname
);
1211 /*******************************************************************
1212 Check to see if a user can read an fsp . This is only approximate,
1213 it is used as part of the "hide unreadable" option. Don't
1214 use it for anything security sensitive.
1215 ********************************************************************/
1217 static bool user_can_read_fsp(struct files_struct
*fsp
)
1220 uint32_t rejected_share_access
= 0;
1221 uint32_t rejected_mask
= 0;
1222 struct security_descriptor
*sd
= NULL
;
1223 uint32_t access_mask
= FILE_READ_DATA
|
1225 FILE_READ_ATTRIBUTES
|
1226 SEC_STD_READ_CONTROL
;
1229 * Never hide files from the root user.
1230 * We use (uid_t)0 here not sec_initial_uid()
1231 * as make test uses a single user context.
1234 if (get_current_uid(fsp
->conn
) == (uid_t
)0) {
1239 * We can't directly use smbd_check_access_rights_fsp()
1240 * here, as this implicitly grants FILE_READ_ATTRIBUTES
1241 * which the Windows access-based-enumeration code
1242 * explicitly checks for on the file security descriptor.
1245 * https://bugzilla.samba.org/show_bug.cgi?id=10252
1247 * and the smb2.acl2.ACCESSBASED test for details.
1250 rejected_share_access
= access_mask
& ~(fsp
->conn
->share_access
);
1251 if (rejected_share_access
) {
1252 DBG_DEBUG("rejected share access 0x%x "
1254 (unsigned int)access_mask
,
1256 (unsigned int)rejected_share_access
);
1260 status
= SMB_VFS_FGET_NT_ACL(fsp
,
1267 if (!NT_STATUS_IS_OK(status
)) {
1268 DBG_DEBUG("Could not get acl "
1275 status
= se_file_access_check(sd
,
1276 get_current_nttok(fsp
->conn
),
1283 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
1284 DBG_DEBUG("rejected bits 0x%x read access for %s\n",
1285 (unsigned int)rejected_mask
,
1292 /*******************************************************************
1293 Check to see if a user can write to an fsp.
1294 Always return true for directories.
1295 This is only approximate,
1296 it is used as part of the "hide unwriteable" option. Don't
1297 use it for anything security sensitive.
1298 ********************************************************************/
1300 static bool user_can_write_fsp(struct files_struct
*fsp
)
1303 * Never hide files from the root user.
1304 * We use (uid_t)0 here not sec_initial_uid()
1305 * as make test uses a single user context.
1308 if (get_current_uid(fsp
->conn
) == (uid_t
)0) {
1312 if (fsp
->fsp_flags
.is_directory
) {
1316 return can_write_to_fsp(fsp
);
1319 /*******************************************************************
1320 Is a file a "special" type ?
1321 ********************************************************************/
1323 static bool file_is_special(connection_struct
*conn
,
1324 const struct smb_filename
*smb_fname
)
1327 * Never hide files from the root user.
1328 * We use (uid_t)0 here not sec_initial_uid()
1329 * as make test uses a single user context.
1332 if (get_current_uid(conn
) == (uid_t
)0) {
1336 SMB_ASSERT(VALID_STAT(smb_fname
->st
));
1338 if (S_ISREG(smb_fname
->st
.st_ex_mode
) ||
1339 S_ISDIR(smb_fname
->st
.st_ex_mode
) ||
1340 S_ISLNK(smb_fname
->st
.st_ex_mode
))
1346 /*******************************************************************
1347 Should the file be seen by the client?
1348 ********************************************************************/
1350 bool is_visible_fsp(struct files_struct
*fsp
)
1352 bool hide_unreadable
= false;
1353 bool hide_unwriteable
= false;
1354 bool hide_special
= false;
1355 int hide_new_files_timeout
= 0;
1356 const char *last_component
= NULL
;
1359 * If the file does not exist, there's no point checking
1360 * the configuration options. We succeed, on the basis that the
1361 * checks *might* have passed if the file was present.
1367 hide_unreadable
= lp_hide_unreadable(SNUM(fsp
->conn
));
1368 hide_unwriteable
= lp_hide_unwriteable_files(SNUM(fsp
->conn
));
1369 hide_special
= lp_hide_special_files(SNUM(fsp
->conn
));
1370 hide_new_files_timeout
= lp_hide_new_files_timeout(SNUM(fsp
->conn
));
1372 if (!hide_unreadable
&&
1373 !hide_unwriteable
&&
1375 (hide_new_files_timeout
== 0))
1380 fsp
= metadata_fsp(fsp
);
1382 /* Get the last component of the base name. */
1383 last_component
= strrchr_m(fsp
->fsp_name
->base_name
, '/');
1384 if (!last_component
) {
1385 last_component
= fsp
->fsp_name
->base_name
;
1387 last_component
++; /* Go past '/' */
1390 if (ISDOT(last_component
) || ISDOTDOT(last_component
)) {
1391 return true; /* . and .. are always visible. */
1394 if (fsp_get_pathref_fd(fsp
) == -1) {
1396 * Symlink in POSIX mode or MS-DFS.
1397 * We've checked veto files so the
1398 * only thing we can check is the
1399 * hide_new_files_timeout.
1401 if (hide_new_files_timeout
!= 0) {
1402 double age
= timespec_elapsed(
1403 &fsp
->fsp_name
->st
.st_ex_mtime
);
1405 if (age
< (double)hide_new_files_timeout
) {
1412 if (hide_unreadable
||
1415 (hide_new_files_timeout
!= 0))
1417 /* Honour _hide unreadable_ option */
1418 if (hide_unreadable
&&
1419 !user_can_read_fsp(fsp
))
1421 DBG_DEBUG("file %s is unreadable.\n",
1425 /* Honour _hide unwriteable_ option */
1426 if (hide_unwriteable
&&
1427 !user_can_write_fsp(fsp
))
1429 DBG_DEBUG("file %s is unwritable.\n",
1433 /* Honour _hide_special_ option */
1434 if (hide_special
&& file_is_special(fsp
->conn
, fsp
->fsp_name
)) {
1435 DBG_DEBUG("file %s is special.\n",
1440 if (hide_new_files_timeout
!= 0) {
1441 double age
= timespec_elapsed(
1442 &fsp
->fsp_name
->st
.st_ex_mtime
);
1444 if (age
< (double)hide_new_files_timeout
) {
1453 static int smb_Dir_destructor(struct smb_Dir
*dir_hnd
)
1455 files_struct
*fsp
= dir_hnd
->fsp
;
1457 SMB_VFS_CLOSEDIR(dir_hnd
->conn
, dir_hnd
->dir
);
1458 fsp_set_fd(fsp
, -1);
1459 if (fsp
->dptr
!= NULL
) {
1460 SMB_ASSERT(fsp
->dptr
->dir_hnd
== dir_hnd
);
1461 fsp
->dptr
->dir_hnd
= NULL
;
1463 dir_hnd
->fsp
= NULL
;
1467 /*******************************************************************
1469 ********************************************************************/
1471 static int smb_Dir_OpenDir_destructor(struct smb_Dir
*dir_hnd
)
1473 files_struct
*fsp
= dir_hnd
->fsp
;
1475 smb_Dir_destructor(dir_hnd
);
1476 file_free(NULL
, fsp
);
1480 NTSTATUS
OpenDir_ntstatus(TALLOC_CTX
*mem_ctx
,
1481 connection_struct
*conn
,
1482 const struct smb_filename
*smb_dname
,
1485 struct smb_Dir
**_dir_hnd
)
1487 struct files_struct
*fsp
= NULL
;
1488 struct smb_Dir
*dir_hnd
= NULL
;
1491 status
= open_internal_dirfsp(conn
,
1495 if (!NT_STATUS_IS_OK(status
)) {
1499 status
= OpenDir_fsp(mem_ctx
, conn
, fsp
, mask
, attr
, &dir_hnd
);
1500 if (!NT_STATUS_IS_OK(status
)) {
1505 * This overwrites the destructor set by smb_Dir_OpenDir_destructor(),
1506 * but smb_Dir_OpenDir_destructor() calls the OpenDir_fsp() destructor.
1508 talloc_set_destructor(dir_hnd
, smb_Dir_OpenDir_destructor
);
1510 *_dir_hnd
= dir_hnd
;
1511 return NT_STATUS_OK
;
1514 struct smb_Dir
*OpenDir(TALLOC_CTX
*mem_ctx
,
1515 connection_struct
*conn
,
1516 const struct smb_filename
*smb_dname
,
1520 struct smb_Dir
*dir_hnd
= NULL
;
1523 status
= OpenDir_ntstatus(
1524 mem_ctx
, conn
, smb_dname
, mask
, attr
, &dir_hnd
);
1525 if (!NT_STATUS_IS_OK(status
)) {
1526 /* Ensure we return the actual error from status in errno. */
1527 errno
= map_errno_from_nt_status(status
);
1533 /*******************************************************************
1534 Open a directory from an fsp.
1535 ********************************************************************/
1537 static NTSTATUS
OpenDir_fsp(
1538 TALLOC_CTX
*mem_ctx
,
1539 connection_struct
*conn
,
1543 struct smb_Dir
**_dir_hnd
)
1545 struct smb_Dir
*dir_hnd
= talloc_zero(mem_ctx
, struct smb_Dir
);
1549 return NT_STATUS_NO_MEMORY
;
1552 if (!fsp
->fsp_flags
.is_directory
) {
1553 status
= NT_STATUS_INVALID_HANDLE
;
1557 if (fsp_get_io_fd(fsp
) == -1) {
1558 status
= NT_STATUS_INVALID_HANDLE
;
1562 dir_hnd
->conn
= conn
;
1564 if (!conn
->sconn
->using_smb2
) {
1566 * The dircache is only needed for SMB1 because SMB1 uses a name
1567 * for the resume wheras SMB2 always continues from the next
1568 * position (unless it's told to restart or close-and-reopen the
1571 dir_hnd
->name_cache_size
=
1572 lp_directory_name_cache_size(SNUM(conn
));
1575 dir_hnd
->dir_smb_fname
= cp_smb_filename(dir_hnd
, fsp
->fsp_name
);
1576 if (!dir_hnd
->dir_smb_fname
) {
1577 status
= NT_STATUS_NO_MEMORY
;
1581 dir_hnd
->dir
= SMB_VFS_FDOPENDIR(fsp
, mask
, attr
);
1582 if (dir_hnd
->dir
== NULL
) {
1583 status
= map_nt_error_from_unix(errno
);
1587 if (fsp
->posix_flags
& FSP_POSIX_FLAGS_OPEN
) {
1588 dir_hnd
->case_sensitive
= true;
1590 dir_hnd
->case_sensitive
= conn
->case_sensitive
;
1593 talloc_set_destructor(dir_hnd
, smb_Dir_destructor
);
1595 *_dir_hnd
= dir_hnd
;
1596 return NT_STATUS_OK
;
1599 TALLOC_FREE(dir_hnd
);
1604 /*******************************************************************
1605 Read from a directory.
1606 Return directory entry, current offset, and optional stat information.
1607 Don't check for veto or invisible files.
1608 ********************************************************************/
1610 const char *ReadDirName(struct smb_Dir
*dir_hnd
, long *poffset
,
1611 SMB_STRUCT_STAT
*sbuf
, char **ptalloced
)
1614 char *talloced
= NULL
;
1615 connection_struct
*conn
= dir_hnd
->conn
;
1617 /* Cheat to allow . and .. to be the first entries returned. */
1618 if (((*poffset
== START_OF_DIRECTORY_OFFSET
) ||
1619 (*poffset
== DOT_DOT_DIRECTORY_OFFSET
)) && (dir_hnd
->file_number
< 2))
1621 if (dir_hnd
->file_number
== 0) {
1623 *poffset
= dir_hnd
->offset
= START_OF_DIRECTORY_OFFSET
;
1626 *poffset
= dir_hnd
->offset
= DOT_DOT_DIRECTORY_OFFSET
;
1628 dir_hnd
->file_number
++;
1633 if (*poffset
== END_OF_DIRECTORY_OFFSET
) {
1634 *poffset
= dir_hnd
->offset
= END_OF_DIRECTORY_OFFSET
;
1638 /* A real offset, seek to it. */
1639 SeekDir(dir_hnd
, *poffset
);
1641 while ((n
= vfs_readdirname(conn
, dir_hnd
->fsp
, dir_hnd
->dir
, sbuf
, &talloced
))) {
1642 /* Ignore . and .. - we've already returned them. */
1644 if ((n
[1] == '\0') || (n
[1] == '.' && n
[2] == '\0')) {
1645 TALLOC_FREE(talloced
);
1649 *poffset
= dir_hnd
->offset
= SMB_VFS_TELLDIR(conn
, dir_hnd
->dir
);
1650 *ptalloced
= talloced
;
1651 dir_hnd
->file_number
++;
1654 *poffset
= dir_hnd
->offset
= END_OF_DIRECTORY_OFFSET
;
1659 /*******************************************************************
1660 Rewind to the start.
1661 ********************************************************************/
1663 void RewindDir(struct smb_Dir
*dir_hnd
, long *poffset
)
1665 SMB_VFS_REWINDDIR(dir_hnd
->conn
, dir_hnd
->dir
);
1666 dir_hnd
->file_number
= 0;
1667 dir_hnd
->offset
= START_OF_DIRECTORY_OFFSET
;
1668 *poffset
= START_OF_DIRECTORY_OFFSET
;
1671 /*******************************************************************
1673 ********************************************************************/
1675 void SeekDir(struct smb_Dir
*dirp
, long offset
)
1677 if (offset
!= dirp
->offset
) {
1678 if (offset
== START_OF_DIRECTORY_OFFSET
) {
1679 RewindDir(dirp
, &offset
);
1681 * Ok we should really set the file number here
1682 * to 1 to enable ".." to be returned next. Trouble
1683 * is I'm worried about callers using SeekDir(dirp,0)
1684 * as equivalent to RewindDir(). So leave this alone
1687 } else if (offset
== DOT_DOT_DIRECTORY_OFFSET
) {
1688 RewindDir(dirp
, &offset
);
1690 * Set the file number to 2 - we want to get the first
1691 * real file entry (the one we return after "..")
1692 * on the next ReadDir.
1694 dirp
->file_number
= 2;
1695 } else if (offset
== END_OF_DIRECTORY_OFFSET
) {
1696 ; /* Don't seek in this case. */
1698 SMB_VFS_SEEKDIR(dirp
->conn
, dirp
->dir
, offset
);
1700 dirp
->offset
= offset
;
1704 /*******************************************************************
1705 Tell a dir position.
1706 ********************************************************************/
1708 long TellDir(struct smb_Dir
*dir_hnd
)
1710 return(dir_hnd
->offset
);
1713 /*******************************************************************
1714 Add an entry into the dcache.
1715 ********************************************************************/
1717 static void DirCacheAdd(struct smb_Dir
*dir_hnd
, const char *name
, long offset
)
1719 struct name_cache_entry
*e
;
1721 if (dir_hnd
->name_cache_size
== 0) {
1725 if (dir_hnd
->name_cache
== NULL
) {
1726 dir_hnd
->name_cache
= talloc_zero_array(dir_hnd
,
1727 struct name_cache_entry
,
1728 dir_hnd
->name_cache_size
);
1730 if (dir_hnd
->name_cache
== NULL
) {
1735 dir_hnd
->name_cache_index
= (dir_hnd
->name_cache_index
+1) %
1736 dir_hnd
->name_cache_size
;
1737 e
= &dir_hnd
->name_cache
[dir_hnd
->name_cache_index
];
1738 TALLOC_FREE(e
->name
);
1739 e
->name
= talloc_strdup(dir_hnd
, name
);
1743 /*******************************************************************
1744 Find an entry by name. Leave us at the offset after it.
1745 Don't check for veto or invisible files.
1746 ********************************************************************/
1748 static bool SearchDir(struct smb_Dir
*dir_hnd
, const char *name
, long *poffset
)
1751 const char *entry
= NULL
;
1752 char *talloced
= NULL
;
1753 connection_struct
*conn
= dir_hnd
->conn
;
1755 /* Search back in the name cache. */
1756 if (dir_hnd
->name_cache_size
&& dir_hnd
->name_cache
) {
1757 for (i
= dir_hnd
->name_cache_index
; i
>= 0; i
--) {
1758 struct name_cache_entry
*e
= &dir_hnd
->name_cache
[i
];
1759 if (e
->name
&& (dir_hnd
->case_sensitive
? (strcmp(e
->name
, name
) == 0) : strequal(e
->name
, name
))) {
1760 *poffset
= e
->offset
;
1761 SeekDir(dir_hnd
, e
->offset
);
1765 for (i
= dir_hnd
->name_cache_size
- 1;
1766 i
> dir_hnd
->name_cache_index
; i
--) {
1767 struct name_cache_entry
*e
= &dir_hnd
->name_cache
[i
];
1768 if (e
->name
&& (dir_hnd
->case_sensitive
? (strcmp(e
->name
, name
) == 0) : strequal(e
->name
, name
))) {
1769 *poffset
= e
->offset
;
1770 SeekDir(dir_hnd
, e
->offset
);
1776 /* Not found in the name cache. Rewind directory and start from scratch. */
1777 SMB_VFS_REWINDDIR(conn
, dir_hnd
->dir
);
1778 dir_hnd
->file_number
= 0;
1779 *poffset
= START_OF_DIRECTORY_OFFSET
;
1780 while ((entry
= ReadDirName(dir_hnd
, poffset
, NULL
, &talloced
))) {
1781 if (dir_hnd
->case_sensitive
? (strcmp(entry
, name
) == 0) : strequal(entry
, name
)) {
1782 TALLOC_FREE(talloced
);
1785 TALLOC_FREE(talloced
);
1790 struct files_below_forall_state
{
1792 ssize_t dirpath_len
;
1793 int (*fn
)(struct file_id fid
, const struct share_mode_data
*data
,
1794 void *private_data
);
1798 static int files_below_forall_fn(struct file_id fid
,
1799 const struct share_mode_data
*data
,
1802 struct files_below_forall_state
*state
= private_data
;
1803 char tmpbuf
[PATH_MAX
];
1804 char *fullpath
, *to_free
;
1807 len
= full_path_tos(data
->servicepath
, data
->base_name
,
1808 tmpbuf
, sizeof(tmpbuf
),
1809 &fullpath
, &to_free
);
1813 if (state
->dirpath_len
>= len
) {
1815 * Filter files above dirpath
1819 if (fullpath
[state
->dirpath_len
] != '/') {
1821 * Filter file that don't have a path separator at the end of
1827 if (memcmp(state
->dirpath
, fullpath
, state
->dirpath_len
) != 0) {
1834 TALLOC_FREE(to_free
);
1835 return state
->fn(fid
, data
, state
->private_data
);
1838 TALLOC_FREE(to_free
);
1842 static int files_below_forall(connection_struct
*conn
,
1843 const struct smb_filename
*dir_name
,
1844 int (*fn
)(struct file_id fid
,
1845 const struct share_mode_data
*data
,
1846 void *private_data
),
1849 struct files_below_forall_state state
= {
1851 .private_data
= private_data
,
1854 char tmpbuf
[PATH_MAX
];
1857 state
.dirpath_len
= full_path_tos(conn
->connectpath
,
1858 dir_name
->base_name
,
1859 tmpbuf
, sizeof(tmpbuf
),
1860 &state
.dirpath
, &to_free
);
1861 if (state
.dirpath_len
== -1) {
1865 ret
= share_mode_forall(files_below_forall_fn
, &state
);
1866 TALLOC_FREE(to_free
);
1870 struct have_file_open_below_state
{
1874 static int have_file_open_below_fn(struct file_id fid
,
1875 const struct share_mode_data
*data
,
1878 struct have_file_open_below_state
*state
= private_data
;
1879 state
->found_one
= true;
1883 bool have_file_open_below(connection_struct
*conn
,
1884 const struct smb_filename
*name
)
1886 struct have_file_open_below_state state
= {
1891 if (!VALID_STAT(name
->st
)) {
1894 if (!S_ISDIR(name
->st
.st_ex_mode
)) {
1898 ret
= files_below_forall(conn
, name
, have_file_open_below_fn
, &state
);
1903 return state
.found_one
;
1906 /*****************************************************************
1907 Is this directory empty ?
1908 *****************************************************************/
1910 NTSTATUS
can_delete_directory_fsp(files_struct
*fsp
)
1912 NTSTATUS status
= NT_STATUS_OK
;
1914 const char *dname
= NULL
;
1915 char *talloced
= NULL
;
1917 struct connection_struct
*conn
= fsp
->conn
;
1918 struct smb_Dir
*dir_hnd
= NULL
;
1920 status
= OpenDir_ntstatus(
1921 talloc_tos(), conn
, fsp
->fsp_name
, NULL
, 0, &dir_hnd
);
1922 if (!NT_STATUS_IS_OK(status
)) {
1926 while ((dname
= ReadDirName(dir_hnd
, &dirpos
, &st
, &talloced
))) {
1927 struct smb_filename
*smb_dname_full
= NULL
;
1928 struct smb_filename
*direntry_fname
= NULL
;
1929 char *fullname
= NULL
;
1932 if (ISDOT(dname
) || (ISDOTDOT(dname
))) {
1933 TALLOC_FREE(talloced
);
1936 if (IS_VETO_PATH(conn
, dname
)) {
1937 TALLOC_FREE(talloced
);
1941 fullname
= talloc_asprintf(talloc_tos(),
1943 fsp
->fsp_name
->base_name
,
1945 if (fullname
== NULL
) {
1946 status
= NT_STATUS_NO_MEMORY
;
1950 smb_dname_full
= synthetic_smb_fname(talloc_tos(),
1954 fsp
->fsp_name
->twrp
,
1955 fsp
->fsp_name
->flags
);
1956 if (smb_dname_full
== NULL
) {
1957 TALLOC_FREE(talloced
);
1958 TALLOC_FREE(fullname
);
1959 status
= NT_STATUS_NO_MEMORY
;
1963 ret
= SMB_VFS_LSTAT(conn
, smb_dname_full
);
1965 status
= map_nt_error_from_unix(errno
);
1966 TALLOC_FREE(talloced
);
1967 TALLOC_FREE(fullname
);
1968 TALLOC_FREE(smb_dname_full
);
1972 if (S_ISLNK(smb_dname_full
->st
.st_ex_mode
)) {
1973 /* Could it be an msdfs link ? */
1974 if (lp_host_msdfs() &&
1975 lp_msdfs_root(SNUM(conn
))) {
1976 struct smb_filename
*smb_dname
;
1977 smb_dname
= synthetic_smb_fname(talloc_tos(),
1980 &smb_dname_full
->st
,
1981 fsp
->fsp_name
->twrp
,
1982 fsp
->fsp_name
->flags
);
1983 if (smb_dname
== NULL
) {
1984 TALLOC_FREE(talloced
);
1985 TALLOC_FREE(fullname
);
1986 TALLOC_FREE(smb_dname_full
);
1987 status
= NT_STATUS_NO_MEMORY
;
1990 if (is_msdfs_link(fsp
, smb_dname
)) {
1991 TALLOC_FREE(talloced
);
1992 TALLOC_FREE(fullname
);
1993 TALLOC_FREE(smb_dname_full
);
1994 TALLOC_FREE(smb_dname
);
1995 DBG_DEBUG("got msdfs link name %s "
1996 "- can't delete directory %s\n",
1999 status
= NT_STATUS_DIRECTORY_NOT_EMPTY
;
2002 TALLOC_FREE(smb_dname
);
2004 /* Not a DFS link - could it be a dangling symlink ? */
2005 ret
= SMB_VFS_STAT(conn
, smb_dname_full
);
2006 if (ret
== -1 && (errno
== ENOENT
|| errno
== ELOOP
)) {
2009 * Allow if "delete veto files = yes"
2011 if (lp_delete_veto_files(SNUM(conn
))) {
2012 TALLOC_FREE(talloced
);
2013 TALLOC_FREE(fullname
);
2014 TALLOC_FREE(smb_dname_full
);
2018 DBG_DEBUG("got symlink name %s - "
2019 "can't delete directory %s\n",
2022 TALLOC_FREE(talloced
);
2023 TALLOC_FREE(fullname
);
2024 TALLOC_FREE(smb_dname_full
);
2025 status
= NT_STATUS_DIRECTORY_NOT_EMPTY
;
2029 /* Not a symlink, get a pathref. */
2030 status
= synthetic_pathref(talloc_tos(),
2034 &smb_dname_full
->st
,
2035 fsp
->fsp_name
->twrp
,
2036 fsp
->fsp_name
->flags
,
2038 if (!NT_STATUS_IS_OK(status
)) {
2039 status
= map_nt_error_from_unix(errno
);
2040 TALLOC_FREE(talloced
);
2041 TALLOC_FREE(fullname
);
2042 TALLOC_FREE(smb_dname_full
);
2046 if (!is_visible_fsp(direntry_fname
->fsp
)) {
2047 TALLOC_FREE(talloced
);
2048 TALLOC_FREE(fullname
);
2049 TALLOC_FREE(smb_dname_full
);
2050 TALLOC_FREE(direntry_fname
);
2054 TALLOC_FREE(talloced
);
2055 TALLOC_FREE(fullname
);
2056 TALLOC_FREE(smb_dname_full
);
2057 TALLOC_FREE(direntry_fname
);
2059 DBG_DEBUG("got name %s - can't delete\n", dname
);
2060 status
= NT_STATUS_DIRECTORY_NOT_EMPTY
;
2063 TALLOC_FREE(talloced
);
2064 TALLOC_FREE(dir_hnd
);
2066 if (!NT_STATUS_IS_OK(status
)) {
2070 if (!(fsp
->posix_flags
& FSP_POSIX_FLAGS_RENAME
) &&
2071 lp_strict_rename(SNUM(conn
)) &&
2072 have_file_open_below(fsp
->conn
, fsp
->fsp_name
))
2074 return NT_STATUS_ACCESS_DENIED
;
2077 return NT_STATUS_OK
;