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) {
111 /****************************************************************************
112 Idle a dptr - the directory is closed but the control info is kept.
113 ****************************************************************************/
115 static void dptr_idle(struct dptr_struct *dptr)
118 DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
119 TALLOC_FREE(dptr->dir_hnd);
120 TALLOC_FREE(dptr->dptr_cache);
125 /****************************************************************************
126 Idle the oldest dptr.
127 ****************************************************************************/
129 static void dptr_idleoldest(struct smbd_server_connection *sconn)
131 struct dptr_struct *dptr;
134 * Go to the end of the list.
136 dptr = DLIST_TAIL(sconn->searches.dirptrs);
139 DEBUG(0,("No dptrs available to idle ?\n"));
144 * Idle the oldest pointer.
147 for(; dptr; dptr = DLIST_PREV(dptr)) {
156 /****************************************************************************
157 Get the struct dptr_struct for a dir index.
158 ****************************************************************************/
160 static struct dptr_struct *dptr_get(struct smbd_server_connection *sconn,
161 int key, bool forclose)
163 struct dptr_struct *dptr;
165 for (dptr = sconn->searches.dirptrs; dptr != NULL; dptr = dptr->next) {
166 if(dptr->dnum != key) {
169 DLIST_PROMOTE(sconn->searches.dirptrs, dptr);
175 /****************************************************************************
176 Get the dir path for a dir index.
177 ****************************************************************************/
179 const char *dptr_path(struct smbd_server_connection *sconn, int key)
181 struct dptr_struct *dptr = dptr_get(sconn, key, false);
183 return(dptr->smb_dname->base_name);
187 /****************************************************************************
188 Get the dir wcard for a dir index.
189 ****************************************************************************/
191 const char *dptr_wcard(struct smbd_server_connection *sconn, int key)
193 struct dptr_struct *dptr = dptr_get(sconn, key, false);
199 /****************************************************************************
200 Get the dir attrib for a dir index.
201 ****************************************************************************/
203 uint16_t dptr_attr(struct smbd_server_connection *sconn, int key)
205 struct dptr_struct *dptr = dptr_get(sconn, key, false);
211 /****************************************************************************
212 Close a dptr (internal func).
213 ****************************************************************************/
215 static void dptr_close_internal(struct dptr_struct *dptr)
217 struct smbd_server_connection *sconn = dptr->conn->sconn;
219 DEBUG(4,("closing dptr key %d\n",dptr->dnum));
225 if (sconn->using_smb2) {
229 DLIST_REMOVE(sconn->searches.dirptrs, dptr);
232 * Free the dnum in the bitmap. Remember the dnum value is always
233 * biased by one with respect to the bitmap.
236 if (!bitmap_query(sconn->searches.dptr_bmap, dptr->dnum - 1)) {
237 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
241 bitmap_clear(sconn->searches.dptr_bmap, dptr->dnum - 1);
244 TALLOC_FREE(dptr->dir_hnd);
248 /****************************************************************************
249 Close a dptr given a key.
250 ****************************************************************************/
252 void dptr_close(struct smbd_server_connection *sconn, int *key)
254 struct dptr_struct *dptr;
256 if(*key == INVALID_DPTR_KEY)
259 /* OS/2 seems to use -1 to indicate "close all directories" */
261 struct dptr_struct *next;
262 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
264 dptr_close_internal(dptr);
266 *key = INVALID_DPTR_KEY;
270 dptr = dptr_get(sconn, *key, true);
273 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
277 dptr_close_internal(dptr);
279 *key = INVALID_DPTR_KEY;
282 /****************************************************************************
283 Close all dptrs for a cnum.
284 ****************************************************************************/
286 void dptr_closecnum(connection_struct *conn)
288 struct dptr_struct *dptr, *next;
289 struct smbd_server_connection *sconn = conn->sconn;
295 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
297 if (dptr->conn == conn) {
298 dptr_close_internal(dptr);
303 /****************************************************************************
304 Are there any SMB1 searches active on this connection struct ?
305 ****************************************************************************/
307 bool dptr_activecnum(const struct smbd_server_connection *sconn,
308 const struct connection_struct *conn)
310 const struct dptr_struct *dptr;
312 for(dptr = sconn->searches.dirptrs; dptr; dptr = dptr->next) {
313 if (dptr->conn == conn) {
320 /****************************************************************************
321 Close a dptr that matches a given path, only if it matches the spid also.
322 ****************************************************************************/
324 void dptr_closepath(struct smbd_server_connection *sconn,
325 char *path,uint16_t spid)
327 struct dptr_struct *dptr, *next;
328 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
330 if (spid == dptr->spid &&
331 strequal(dptr->smb_dname->base_name,path)) {
332 dptr_close_internal(dptr);
337 /****************************************************************************
338 Try and close the oldest handle not marked for
339 expect close in the hope that the client has
340 finished with that one.
341 ****************************************************************************/
343 static void dptr_close_oldest(struct smbd_server_connection *sconn,
346 struct dptr_struct *dptr;
349 * Go to the end of the list.
351 for(dptr = sconn->searches.dirptrs; dptr && dptr->next; dptr = dptr->next)
355 DEBUG(0,("No old dptrs available to close oldest ?\n"));
360 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
361 * does not have expect_close set. If 'old' is false, close
362 * one of the new dnum handles.
365 for(; dptr; dptr = DLIST_PREV(dptr)) {
366 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
367 (!old && (dptr->dnum > 255))) {
368 dptr_close_internal(dptr);
374 /****************************************************************************
375 Safely do an OpenDir as root, ensuring we're in the right place.
376 ****************************************************************************/
378 static struct smb_Dir *open_dir_with_privilege(connection_struct *conn,
379 struct smb_request *req,
380 const struct smb_filename *smb_dname,
384 struct smb_Dir *dir_hnd = NULL;
385 struct smb_filename *smb_fname_cwd = NULL;
386 struct smb_filename *saved_dir_fname = vfs_GetWd(talloc_tos(), conn);
387 struct privilege_paths *priv_paths = req->priv_paths;
390 if (saved_dir_fname == NULL) {
394 if (vfs_ChDir(conn, smb_dname) == -1) {
398 /* Now check the stat value is the same. */
399 smb_fname_cwd = synthetic_smb_fname(talloc_tos(),
404 if (smb_fname_cwd == NULL) {
407 ret = SMB_VFS_STAT(conn, smb_fname_cwd);
412 if (!check_same_stat(&smb_fname_cwd->st, &priv_paths->parent_name.st)) {
413 DEBUG(0,("open_dir_with_privilege: stat mismatch between %s "
415 smb_dname->base_name,
416 smb_fname_str_dbg(&priv_paths->parent_name)));
420 dir_hnd = OpenDir(NULL, conn, smb_fname_cwd, wcard, attr);
424 vfs_ChDir(conn, saved_dir_fname);
425 TALLOC_FREE(saved_dir_fname);
429 /****************************************************************************
430 Create a new dir ptr. If the flag old_handle is true then we must allocate
431 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
432 one byte long. If old_handle is false we allocate from the range
433 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
434 a directory handle is never zero.
435 wcard must not be zero.
436 ****************************************************************************/
438 NTSTATUS dptr_create(connection_struct *conn,
439 struct smb_request *req,
441 const struct smb_filename *smb_dname,
448 struct dptr_struct **dptr_ret)
450 struct smbd_server_connection *sconn = conn->sconn;
451 struct dptr_struct *dptr = NULL;
452 struct smb_Dir *dir_hnd;
454 if (fsp && fsp->is_directory && fsp->fh->fd != -1) {
455 smb_dname = fsp->fsp_name;
458 DEBUG(5,("dptr_create dir=%s\n", smb_dname->base_name));
461 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
462 return NT_STATUS_INTERNAL_ERROR;
466 return NT_STATUS_INVALID_PARAMETER;
470 if (!(fsp->access_mask & SEC_DIR_LIST)) {
471 DEBUG(5,("dptr_create: directory %s "
472 "not open for LIST access\n",
473 smb_dname->base_name));
474 return NT_STATUS_ACCESS_DENIED;
476 dir_hnd = OpenDir_fsp(NULL, conn, fsp, wcard, attr);
479 bool backup_intent = (req && req->priv_paths);
481 struct smb_filename *smb_dname_cp =
482 cp_smb_filename(talloc_tos(), smb_dname);
484 if (smb_dname_cp == NULL) {
485 return NT_STATUS_NO_MEMORY;
488 if (req != NULL && req->posix_pathnames) {
489 ret = SMB_VFS_LSTAT(conn, smb_dname_cp);
491 ret = SMB_VFS_STAT(conn, smb_dname_cp);
494 status = map_nt_error_from_unix(errno);
495 TALLOC_FREE(smb_dname_cp);
498 if (!S_ISDIR(smb_dname_cp->st.st_ex_mode)) {
499 TALLOC_FREE(smb_dname_cp);
500 return NT_STATUS_NOT_A_DIRECTORY;
502 status = smbd_check_access_rights(conn,
506 if (!NT_STATUS_IS_OK(status)) {
507 TALLOC_FREE(smb_dname_cp);
511 dir_hnd = open_dir_with_privilege(conn,
517 dir_hnd = OpenDir(NULL,
523 TALLOC_FREE(smb_dname_cp);
527 return map_nt_error_from_unix(errno);
530 dptr = talloc_zero(NULL, struct dptr_struct);
532 DEBUG(0,("talloc fail in dptr_create.\n"));
533 TALLOC_FREE(dir_hnd);
534 return NT_STATUS_NO_MEMORY;
537 dptr->smb_dname = cp_smb_filename(dptr, smb_dname);
538 if (!dptr->smb_dname) {
540 TALLOC_FREE(dir_hnd);
541 return NT_STATUS_NO_MEMORY;
544 dptr->dir_hnd = dir_hnd;
546 dptr->expect_close = expect_close;
547 dptr->wcard = talloc_strdup(dptr, wcard);
550 TALLOC_FREE(dir_hnd);
551 return NT_STATUS_NO_MEMORY;
553 if ((req != NULL && req->posix_pathnames) ||
554 (wcard[0] == '.' && wcard[1] == 0)) {
555 dptr->has_wild = True;
557 dptr->has_wild = wcard_has_wild;
562 if (sconn->using_smb2) {
569 * This is an old-style SMBsearch request. Ensure the
570 * value we return will fit in the range 1-255.
573 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
575 if(dptr->dnum == -1 || dptr->dnum > 254) {
578 * Try and close the oldest handle not marked for
579 * expect close in the hope that the client has
580 * finished with that one.
583 dptr_close_oldest(sconn, true);
585 /* Now try again... */
586 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
587 if(dptr->dnum == -1 || dptr->dnum > 254) {
588 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
590 TALLOC_FREE(dir_hnd);
591 return NT_STATUS_TOO_MANY_OPENED_FILES;
597 * This is a new-style trans2 request. Allocate from
598 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
601 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
603 if(dptr->dnum == -1 || dptr->dnum < 255) {
606 * Try and close the oldest handle close in the hope that
607 * the client has finished with that one. This will only
608 * happen in the case of the Win98 client bug where it leaks
612 dptr_close_oldest(sconn, false);
614 /* Now try again... */
615 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
617 if(dptr->dnum == -1 || dptr->dnum < 255) {
618 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
620 TALLOC_FREE(dir_hnd);
621 return NT_STATUS_TOO_MANY_OPENED_FILES;
626 bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
628 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
630 DLIST_ADD(sconn->searches.dirptrs, dptr);
633 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
635 dptr->smb_dname->base_name,
644 /****************************************************************************
645 Wrapper functions to access the lower level directory handles.
646 ****************************************************************************/
648 void dptr_CloseDir(files_struct *fsp)
652 * The destructor for the struct smb_Dir
653 * (fsp->dptr->dir_hnd) now handles
654 * all resource deallocation.
656 dptr_close_internal(fsp->dptr);
661 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
663 SeekDir(dptr->dir_hnd, offset);
666 long dptr_TellDir(struct dptr_struct *dptr)
668 return TellDir(dptr->dir_hnd);
671 bool dptr_has_wild(struct dptr_struct *dptr)
673 return dptr->has_wild;
676 int dptr_dnum(struct dptr_struct *dptr)
681 bool dptr_get_priv(struct dptr_struct *dptr)
686 void dptr_set_priv(struct dptr_struct *dptr)
691 /****************************************************************************
692 Return the next visible file name, skipping veto'd and invisible files.
693 ****************************************************************************/
695 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr,
696 long *poffset, SMB_STRUCT_STAT *pst,
699 /* Normal search for the next file. */
701 char *talloced = NULL;
703 while ((name = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced))
705 if (is_visible_file(dptr->conn,
706 dptr->smb_dname->base_name,
710 *ptalloced = talloced;
713 TALLOC_FREE(talloced);
718 /****************************************************************************
719 Return the next visible file name, skipping veto'd and invisible files.
720 ****************************************************************************/
722 static char *dptr_ReadDirName(TALLOC_CTX *ctx,
723 struct dptr_struct *dptr,
725 SMB_STRUCT_STAT *pst)
727 struct smb_filename smb_fname_base;
729 const char *name_temp = NULL;
730 char *talloced = NULL;
731 char *pathreal = NULL;
732 char *found_name = NULL;
735 SET_STAT_INVALID(*pst);
737 if (dptr->has_wild || dptr->did_stat) {
738 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst,
740 if (name_temp == NULL) {
743 if (talloced != NULL) {
744 return talloc_move(ctx, &talloced);
746 return talloc_strdup(ctx, name_temp);
749 /* If poffset is -1 then we know we returned this name before and we
750 * have no wildcards. We're at the end of the directory. */
751 if (*poffset == END_OF_DIRECTORY_OFFSET) {
755 /* We know the stored wcard contains no wildcard characters.
756 * See if we can match with a stat call. If we can't, then set
757 * did_stat to true to ensure we only do this once and keep
760 dptr->did_stat = true;
762 /* First check if it should be visible. */
763 if (!is_visible_file(dptr->conn,
764 dptr->smb_dname->base_name,
768 /* This only returns false if the file was found, but
769 is explicitly not visible. Set us to end of
770 directory, but return NULL as we know we can't ever
775 if (VALID_STAT(*pst)) {
776 name = talloc_strdup(ctx, dptr->wcard);
780 pathreal = talloc_asprintf(ctx,
782 dptr->smb_dname->base_name,
787 /* Create an smb_filename with stream_name == NULL. */
788 smb_fname_base = (struct smb_filename) { .base_name = pathreal };
790 if (SMB_VFS_STAT(dptr->conn, &smb_fname_base) == 0) {
791 *pst = smb_fname_base.st;
792 name = talloc_strdup(ctx, dptr->wcard);
795 /* If we get any other error than ENOENT or ENOTDIR
796 then the file exists we just can't stat it. */
797 if (errno != ENOENT && errno != ENOTDIR) {
798 name = talloc_strdup(ctx, dptr->wcard);
803 /* Stat failed. We know this is authoratiative if we are
804 * providing case sensitive semantics or the underlying
805 * filesystem is case sensitive.
807 if (dptr->conn->case_sensitive ||
808 !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
814 * Try case-insensitive stat if the fs has the ability. This avoids
815 * scanning the whole directory.
817 ret = SMB_VFS_GET_REAL_FILENAME(dptr->conn,
818 dptr->smb_dname->base_name,
825 } else if (errno == ENOENT) {
826 /* The case-insensitive lookup was authoritative. */
830 TALLOC_FREE(pathreal);
832 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst, &talloced);
833 if (name_temp == NULL) {
836 if (talloced != NULL) {
837 return talloc_move(ctx, &talloced);
839 return talloc_strdup(ctx, name_temp);
842 TALLOC_FREE(pathreal);
844 /* We need to set the underlying dir_hnd offset to -1
845 * also as this function is usually called with the
846 * output from TellDir. */
847 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
851 /****************************************************************************
852 Search for a file by name, skipping veto'ed and not visible files.
853 ****************************************************************************/
855 bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
857 SET_STAT_INVALID(*pst);
859 if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
860 /* This is a singleton directory and we're already at the end. */
861 *poffset = END_OF_DIRECTORY_OFFSET;
865 return SearchDir(dptr->dir_hnd, name, poffset);
868 /****************************************************************************
869 Map a native directory offset to a 32-bit cookie.
870 ****************************************************************************/
872 static uint32_t map_dir_offset_to_wire(struct dptr_struct *dptr, long offset)
877 if (offset == END_OF_DIRECTORY_OFFSET) {
878 return WIRE_END_OF_DIRECTORY_OFFSET;
879 } else if(offset == START_OF_DIRECTORY_OFFSET) {
880 return WIRE_START_OF_DIRECTORY_OFFSET;
881 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
882 return WIRE_DOT_DOT_DIRECTORY_OFFSET;
884 if (sizeof(long) == 4) {
885 /* 32-bit machine. We can cheat... */
886 return (uint32_t)offset;
888 if (dptr->dptr_cache == NULL) {
889 /* Lazy initialize cache. */
890 dptr->dptr_cache = memcache_init(dptr, 0);
891 if (dptr->dptr_cache == NULL) {
892 return WIRE_END_OF_DIRECTORY_OFFSET;
895 /* Have we seen this offset before ? */
896 key.data = (void *)&offset;
897 key.length = sizeof(offset);
898 if (memcache_lookup(dptr->dptr_cache,
899 SMB1_SEARCH_OFFSET_MAP,
902 uint32_t wire_offset;
903 SMB_ASSERT(val.length == sizeof(wire_offset));
904 memcpy(&wire_offset, val.data, sizeof(wire_offset));
905 DEBUG(10,("found wire %u <-> offset %ld\n",
906 (unsigned int)wire_offset,
911 /* Allocate a new wire cookie. */
914 } while (dptr->counter == WIRE_START_OF_DIRECTORY_OFFSET ||
915 dptr->counter == WIRE_END_OF_DIRECTORY_OFFSET ||
916 dptr->counter == WIRE_DOT_DOT_DIRECTORY_OFFSET);
917 /* Store it in the cache. */
918 key.data = (void *)&offset;
919 key.length = sizeof(offset);
920 val.data = (void *)&dptr->counter;
921 val.length = sizeof(dptr->counter); /* MUST BE uint32_t ! */
922 memcache_add(dptr->dptr_cache,
923 SMB1_SEARCH_OFFSET_MAP,
926 /* And the reverse mapping for lookup from
927 map_wire_to_dir_offset(). */
928 memcache_add(dptr->dptr_cache,
929 SMB1_SEARCH_OFFSET_MAP,
932 DEBUG(10,("stored wire %u <-> offset %ld\n",
933 (unsigned int)dptr->counter,
935 return dptr->counter;
938 /****************************************************************************
939 Fill the 5 byte server reserved dptr field.
940 ****************************************************************************/
942 bool dptr_fill(struct smbd_server_connection *sconn,
943 char *buf1,unsigned int key)
945 unsigned char *buf = (unsigned char *)buf1;
946 struct dptr_struct *dptr = dptr_get(sconn, key, false);
947 uint32_t wire_offset;
949 DEBUG(1,("filling null dirptr %d\n",key));
952 wire_offset = map_dir_offset_to_wire(dptr,TellDir(dptr->dir_hnd));
953 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
954 (long)dptr->dir_hnd,(int)wire_offset));
956 SIVAL(buf,1,wire_offset);
960 /****************************************************************************
961 Map a 32-bit wire cookie to a native directory offset.
962 ****************************************************************************/
964 static long map_wire_to_dir_offset(struct dptr_struct *dptr, uint32_t wire_offset)
969 if (wire_offset == WIRE_END_OF_DIRECTORY_OFFSET) {
970 return END_OF_DIRECTORY_OFFSET;
971 } else if(wire_offset == WIRE_START_OF_DIRECTORY_OFFSET) {
972 return START_OF_DIRECTORY_OFFSET;
973 } else if (wire_offset == WIRE_DOT_DOT_DIRECTORY_OFFSET) {
974 return DOT_DOT_DIRECTORY_OFFSET;
976 if (sizeof(long) == 4) {
977 /* 32-bit machine. We can cheat... */
978 return (long)wire_offset;
980 if (dptr->dptr_cache == NULL) {
981 /* Logic error, cache should be initialized. */
982 return END_OF_DIRECTORY_OFFSET;
984 key.data = (void *)&wire_offset;
985 key.length = sizeof(wire_offset);
986 if (memcache_lookup(dptr->dptr_cache,
987 SMB1_SEARCH_OFFSET_MAP,
992 SMB_ASSERT(val.length == sizeof(offset));
993 memcpy(&offset, val.data, sizeof(offset));
994 DEBUG(10,("lookup wire %u <-> offset %ld\n",
995 (unsigned int)wire_offset,
999 return END_OF_DIRECTORY_OFFSET;
1002 /****************************************************************************
1003 Fetch the dir ptr and seek it given the 5 byte server field.
1004 ****************************************************************************/
1006 struct dptr_struct *dptr_fetch(struct smbd_server_connection *sconn,
1007 char *buf, int *num)
1009 unsigned int key = *(unsigned char *)buf;
1010 struct dptr_struct *dptr = dptr_get(sconn, key, false);
1011 uint32_t wire_offset;
1015 DEBUG(3,("fetched null dirptr %d\n",key));
1019 wire_offset = IVAL(buf,1);
1020 seekoff = map_wire_to_dir_offset(dptr, wire_offset);
1021 SeekDir(dptr->dir_hnd,seekoff);
1022 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
1023 key, dptr->smb_dname->base_name, (int)seekoff));
1027 /****************************************************************************
1029 ****************************************************************************/
1031 struct dptr_struct *dptr_fetch_lanman2(struct smbd_server_connection *sconn,
1034 struct dptr_struct *dptr = dptr_get(sconn, dptr_num, false);
1037 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
1040 DEBUG(3,("fetching dirptr %d for path %s\n",
1042 dptr->smb_dname->base_name));
1046 static bool mangle_mask_match(connection_struct *conn,
1047 const char *filename,
1052 if (!name_to_8_3(filename,mname,False,conn->params)) {
1055 return mask_match_search(mname,mask,False);
1058 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
1059 struct dptr_struct *dirptr,
1065 bool (*match_fn)(TALLOC_CTX *ctx,
1070 bool (*mode_fn)(TALLOC_CTX *ctx,
1072 struct smb_filename *smb_fname,
1077 struct smb_filename **_smb_fname,
1081 connection_struct *conn = dirptr->conn;
1084 const char *dpath = dirptr->smb_dname->base_name;
1085 bool dirptr_path_is_dot = ISDOT(dpath);
1090 pathlen = strlen(dpath);
1091 slashlen = ( dpath[pathlen-1] != '/') ? 1 : 0;
1096 SMB_STRUCT_STAT sbuf = { 0 };
1100 char *pathreal = NULL;
1101 struct smb_filename smb_fname;
1105 cur_offset = dptr_TellDir(dirptr);
1106 prev_offset = cur_offset;
1107 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
1109 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
1110 (long)dirptr, cur_offset));
1112 if (dname == NULL) {
1116 isdots = (ISDOT(dname) || ISDOTDOT(dname));
1117 if (dont_descend && !isdots) {
1123 * fname may get mangled, dname is never mangled.
1124 * Whenever we're accessing the filesystem we use
1125 * pathreal which is composed from dname.
1128 ok = match_fn(ctx, private_data, dname, mask, &fname);
1136 * pathreal = talloc_asprintf(ctx, "%s%s%s", dirptr->path,
1137 * needslash?"/":"", dname);
1138 * but this was measurably slower than doing the memcpy.
1141 pathreal = talloc_array(
1143 pathlen + slashlen + talloc_get_size(dname));
1151 * We don't want to pass ./xxx to modules below us so don't
1152 * add the path if it is just . by itself.
1154 if (dirptr_path_is_dot) {
1155 memcpy(pathreal, dname, talloc_get_size(dname));
1157 memcpy(pathreal, dpath, pathlen);
1158 pathreal[pathlen] = '/';
1159 memcpy(pathreal + slashlen + pathlen, dname,
1160 talloc_get_size(dname));
1163 /* Create smb_fname with NULL stream_name. */
1164 smb_fname = (struct smb_filename) {
1165 .base_name = pathreal, .st = sbuf
1168 ok = mode_fn(ctx, private_data, &smb_fname, get_dosmode, &mode);
1172 TALLOC_FREE(pathreal);
1176 if (!dir_check_ftype(mode, dirtype)) {
1177 DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
1178 fname, (unsigned int)mode, (unsigned int)dirtype));
1181 TALLOC_FREE(pathreal);
1185 if (ask_sharemode) {
1186 struct timespec write_time_ts;
1187 struct file_id fileid;
1189 fileid = vfs_file_id_from_sbuf(conn,
1191 get_file_infos(fileid, 0, NULL, &write_time_ts);
1192 if (!null_timespec(write_time_ts)) {
1193 update_stat_ex_mtime(&smb_fname.st,
1198 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
1200 mask, smb_fname_str_dbg(&smb_fname),
1203 if (!conn->sconn->using_smb2) {
1205 * The dircache is only needed for SMB1 because SMB1
1206 * uses a name for the resume wheras SMB2 always
1207 * continues from the next position (unless it's told to
1208 * restart or close-and-reopen the listing).
1210 DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
1215 *_smb_fname = cp_smb_filename(ctx, &smb_fname);
1216 TALLOC_FREE(pathreal);
1217 if (*_smb_fname == NULL) {
1222 *_prev_offset = prev_offset;
1230 /****************************************************************************
1231 Get an 8.3 directory entry.
1232 ****************************************************************************/
1234 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
1240 connection_struct *conn = (connection_struct *)private_data;
1242 if ((strcmp(mask,"*.*") == 0) ||
1243 mask_match_search(dname, mask, false) ||
1244 mangle_mask_match(conn, dname, mask)) {
1248 * Ensure we can push the original name as UCS2. If
1249 * not, then just don't return this name.
1253 size_t len = (strlen(dname) + 2) * 4; /* Allow enough space. */
1254 uint8_t *tmp = talloc_array(talloc_tos(),
1258 status = srvstr_push(NULL,
1259 FLAGS2_UNICODE_STRINGS,
1268 if (!NT_STATUS_IS_OK(status)) {
1272 if (!mangle_is_8_3(dname, false, conn->params)) {
1273 bool ok = name_to_8_3(dname, mname, false,
1283 *_fname = talloc_strdup(ctx, fname);
1284 if (*_fname == NULL) {
1294 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1296 struct smb_filename *smb_fname,
1300 connection_struct *conn = (connection_struct *)private_data;
1302 if (!VALID_STAT(smb_fname->st)) {
1303 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1304 DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1305 "Couldn't stat [%s]. Error "
1307 smb_fname_str_dbg(smb_fname),
1313 *_mode = dos_mode(conn, smb_fname);
1317 bool get_dir_entry(TALLOC_CTX *ctx,
1318 struct dptr_struct *dirptr,
1324 struct timespec *_date,
1328 connection_struct *conn = dirptr->conn;
1330 struct smb_filename *smb_fname = NULL;
1335 ok = smbd_dirptr_get_entry(ctx,
1342 smbd_dirptr_8_3_match_fn,
1343 smbd_dirptr_8_3_mode_fn,
1353 *_fname = talloc_move(ctx, &fname);
1354 *_size = smb_fname->st.st_ex_size;
1356 *_date = smb_fname->st.st_ex_mtime;
1357 TALLOC_FREE(smb_fname);
1361 /*******************************************************************
1362 Check to see if a user can read a file. This is only approximate,
1363 it is used as part of the "hide unreadable" option. Don't
1364 use it for anything security sensitive.
1365 ********************************************************************/
1367 static bool user_can_read_file(connection_struct *conn,
1368 struct smb_filename *smb_fname)
1371 uint32_t rejected_share_access = 0;
1372 uint32_t rejected_mask = 0;
1373 struct security_descriptor *sd = NULL;
1374 uint32_t access_mask = FILE_READ_DATA|
1376 FILE_READ_ATTRIBUTES|
1377 SEC_STD_READ_CONTROL;
1380 * Never hide files from the root user.
1381 * We use (uid_t)0 here not sec_initial_uid()
1382 * as make test uses a single user context.
1385 if (get_current_uid(conn) == (uid_t)0) {
1390 * We can't directly use smbd_check_access_rights()
1391 * here, as this implicitly grants FILE_READ_ATTRIBUTES
1392 * which the Windows access-based-enumeration code
1393 * explicitly checks for on the file security descriptor.
1396 * https://bugzilla.samba.org/show_bug.cgi?id=10252
1398 * and the smb2.acl2.ACCESSBASED test for details.
1401 rejected_share_access = access_mask & ~(conn->share_access);
1402 if (rejected_share_access) {
1403 DEBUG(10, ("rejected share access 0x%x "
1405 (unsigned int)access_mask,
1406 smb_fname_str_dbg(smb_fname),
1407 (unsigned int)rejected_share_access ));
1411 status = SMB_VFS_GET_NT_ACL(conn,
1419 if (!NT_STATUS_IS_OK(status)) {
1420 DEBUG(10, ("Could not get acl "
1422 smb_fname_str_dbg(smb_fname),
1423 nt_errstr(status)));
1427 status = se_file_access_check(sd,
1428 get_current_nttok(conn),
1435 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1436 DEBUG(10,("rejected bits 0x%x read access for %s\n",
1437 (unsigned int)rejected_mask,
1438 smb_fname_str_dbg(smb_fname) ));
1444 /*******************************************************************
1445 Check to see if a user can write a file (and only files, we do not
1446 check dirs on this one). This is only approximate,
1447 it is used as part of the "hide unwriteable" option. Don't
1448 use it for anything security sensitive.
1449 ********************************************************************/
1451 static bool user_can_write_file(connection_struct *conn,
1452 const struct smb_filename *smb_fname)
1455 * Never hide files from the root user.
1456 * We use (uid_t)0 here not sec_initial_uid()
1457 * as make test uses a single user context.
1460 if (get_current_uid(conn) == (uid_t)0) {
1464 SMB_ASSERT(VALID_STAT(smb_fname->st));
1466 /* Pseudo-open the file */
1468 if(S_ISDIR(smb_fname->st.st_ex_mode)) {
1472 return can_write_to_file(conn, smb_fname);
1475 /*******************************************************************
1476 Is a file a "special" type ?
1477 ********************************************************************/
1479 static bool file_is_special(connection_struct *conn,
1480 const struct smb_filename *smb_fname)
1483 * Never hide files from the root user.
1484 * We use (uid_t)0 here not sec_initial_uid()
1485 * as make test uses a single user context.
1488 if (get_current_uid(conn) == (uid_t)0) {
1492 SMB_ASSERT(VALID_STAT(smb_fname->st));
1494 if (S_ISREG(smb_fname->st.st_ex_mode) ||
1495 S_ISDIR(smb_fname->st.st_ex_mode) ||
1496 S_ISLNK(smb_fname->st.st_ex_mode))
1502 /*******************************************************************
1503 Should the file be seen by the client?
1504 NOTE: A successful return is no guarantee of the file's existence.
1505 ********************************************************************/
1507 bool is_visible_file(connection_struct *conn, const char *dir_path,
1508 const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
1510 bool hide_unreadable = lp_hide_unreadable(SNUM(conn));
1511 bool hide_unwriteable = lp_hide_unwriteable_files(SNUM(conn));
1512 bool hide_special = lp_hide_special_files(SNUM(conn));
1513 int hide_new_files_timeout = lp_hide_new_files_timeout(SNUM(conn));
1515 struct smb_filename *smb_fname_base = NULL;
1518 if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1519 return True; /* . and .. are always visible. */
1522 /* If it's a vetoed file, pretend it doesn't even exist */
1523 if (use_veto && IS_VETO_PATH(conn, name)) {
1524 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1528 if (hide_unreadable ||
1531 (hide_new_files_timeout != 0))
1533 entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name);
1539 /* Create an smb_filename with stream_name == NULL. */
1540 smb_fname_base = synthetic_smb_fname(talloc_tos(),
1545 if (smb_fname_base == NULL) {
1550 /* If the file name does not exist, there's no point checking
1551 * the configuration options. We succeed, on the basis that the
1552 * checks *might* have passed if the file was present.
1554 if (!VALID_STAT(*pst)) {
1555 if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
1559 *pst = smb_fname_base->st;
1562 /* Honour _hide unreadable_ option */
1563 if (hide_unreadable &&
1564 !user_can_read_file(conn, smb_fname_base)) {
1565 DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1570 /* Honour _hide unwriteable_ option */
1571 if (hide_unwriteable && !user_can_write_file(conn,
1573 DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1578 /* Honour _hide_special_ option */
1579 if (hide_special && file_is_special(conn, smb_fname_base)) {
1580 DEBUG(10,("is_visible_file: file %s is special.\n",
1586 if (hide_new_files_timeout != 0) {
1588 double age = timespec_elapsed(
1589 &smb_fname_base->st.st_ex_mtime);
1591 if (age < (double)hide_new_files_timeout) {
1600 TALLOC_FREE(smb_fname_base);
1605 static int smb_Dir_destructor(struct smb_Dir *dirp)
1607 if (dirp->dir != NULL) {
1608 SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1609 if (dirp->fsp != NULL) {
1611 * The SMB_VFS_CLOSEDIR above
1612 * closes the underlying fd inside
1615 dirp->fsp->fh->fd = -1;
1616 if (dirp->fsp->dptr != NULL) {
1617 SMB_ASSERT(dirp->fsp->dptr->dir_hnd == dirp);
1618 dirp->fsp->dptr->dir_hnd = NULL;
1623 if (dirp->conn->sconn && !dirp->conn->sconn->using_smb2) {
1624 dirp->conn->sconn->searches.dirhandles_open--;
1629 /*******************************************************************
1631 ********************************************************************/
1633 static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx,
1634 connection_struct *conn,
1635 const struct smb_filename *smb_dname,
1639 struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1640 struct smbd_server_connection *sconn = conn->sconn;
1646 dirp->dir = SMB_VFS_OPENDIR(conn, smb_dname, mask, attr);
1649 DEBUG(5,("OpenDir: Can't open %s. %s\n",
1650 smb_dname->base_name,
1657 if (!conn->sconn->using_smb2) {
1659 * The dircache is only needed for SMB1 because SMB1 uses a name
1660 * for the resume wheras SMB2 always continues from the next
1661 * position (unless it's told to restart or close-and-reopen the
1664 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1667 if (sconn && !sconn->using_smb2) {
1668 sconn->searches.dirhandles_open++;
1670 talloc_set_destructor(dirp, smb_Dir_destructor);
1679 /****************************************************************************
1680 Open a directory handle by pathname, ensuring it's under the share path.
1681 ****************************************************************************/
1683 static struct smb_Dir *open_dir_safely(TALLOC_CTX *ctx,
1684 connection_struct *conn,
1685 const struct smb_filename *smb_dname,
1689 struct smb_Dir *dir_hnd = NULL;
1690 struct smb_filename *smb_fname_cwd = NULL;
1691 struct smb_filename *saved_dir_fname = vfs_GetWd(ctx, conn);
1694 if (saved_dir_fname == NULL) {
1698 if (vfs_ChDir(conn, smb_dname) == -1) {
1702 smb_fname_cwd = synthetic_smb_fname(talloc_tos(),
1707 if (smb_fname_cwd == NULL) {
1712 * Now the directory is pinned, use
1713 * REALPATH to ensure we can access it.
1715 status = check_name(conn, smb_fname_cwd);
1716 if (!NT_STATUS_IS_OK(status)) {
1720 dir_hnd = OpenDir_internal(ctx,
1726 if (dir_hnd == NULL) {
1731 * OpenDir_internal only gets "." as the dir name.
1732 * Store the real dir name here.
1735 dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, smb_dname);
1736 if (!dir_hnd->dir_smb_fname) {
1737 TALLOC_FREE(dir_hnd);
1743 vfs_ChDir(conn, saved_dir_fname);
1744 TALLOC_FREE(saved_dir_fname);
1748 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1749 const struct smb_filename *smb_dname,
1753 return open_dir_safely(mem_ctx,
1760 /*******************************************************************
1761 Open a directory from an fsp.
1762 ********************************************************************/
1764 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
1769 struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1770 struct smbd_server_connection *sconn = conn->sconn;
1776 if (!fsp->is_directory) {
1781 if (fsp->fh->fd == -1) {
1788 if (!conn->sconn->using_smb2) {
1790 * The dircache is only needed for SMB1 because SMB1 uses a name
1791 * for the resume wheras SMB2 always continues from the next
1792 * position (unless it's told to restart or close-and-reopen the
1795 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1798 dirp->dir_smb_fname = cp_smb_filename(dirp, fsp->fsp_name);
1799 if (!dirp->dir_smb_fname) {
1804 dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1805 if (dirp->dir != NULL) {
1808 DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1810 dirp->dir_smb_fname->base_name,
1812 if (errno != ENOSYS) {
1817 if (dirp->dir == NULL) {
1818 /* FDOPENDIR is not supported. Use OPENDIR instead. */
1820 return open_dir_safely(mem_ctx,
1827 if (sconn && !sconn->using_smb2) {
1828 sconn->searches.dirhandles_open++;
1830 talloc_set_destructor(dirp, smb_Dir_destructor);
1840 /*******************************************************************
1841 Read from a directory.
1842 Return directory entry, current offset, and optional stat information.
1843 Don't check for veto or invisible files.
1844 ********************************************************************/
1846 const char *ReadDirName(struct smb_Dir *dirp, long *poffset,
1847 SMB_STRUCT_STAT *sbuf, char **ptalloced)
1850 char *talloced = NULL;
1851 connection_struct *conn = dirp->conn;
1853 /* Cheat to allow . and .. to be the first entries returned. */
1854 if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1855 (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2))
1857 if (dirp->file_number == 0) {
1859 *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1862 *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1864 dirp->file_number++;
1869 if (*poffset == END_OF_DIRECTORY_OFFSET) {
1870 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1874 /* A real offset, seek to it. */
1875 SeekDir(dirp, *poffset);
1877 while ((n = vfs_readdirname(conn, dirp->dir, sbuf, &talloced))) {
1878 /* Ignore . and .. - we've already returned them. */
1880 if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1881 TALLOC_FREE(talloced);
1885 *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1886 *ptalloced = talloced;
1887 dirp->file_number++;
1890 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1895 /*******************************************************************
1896 Rewind to the start.
1897 ********************************************************************/
1899 void RewindDir(struct smb_Dir *dirp, long *poffset)
1901 SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1902 dirp->file_number = 0;
1903 dirp->offset = START_OF_DIRECTORY_OFFSET;
1904 *poffset = START_OF_DIRECTORY_OFFSET;
1907 /*******************************************************************
1909 ********************************************************************/
1911 void SeekDir(struct smb_Dir *dirp, long offset)
1913 if (offset != dirp->offset) {
1914 if (offset == START_OF_DIRECTORY_OFFSET) {
1915 RewindDir(dirp, &offset);
1917 * Ok we should really set the file number here
1918 * to 1 to enable ".." to be returned next. Trouble
1919 * is I'm worried about callers using SeekDir(dirp,0)
1920 * as equivalent to RewindDir(). So leave this alone
1923 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
1924 RewindDir(dirp, &offset);
1926 * Set the file number to 2 - we want to get the first
1927 * real file entry (the one we return after "..")
1928 * on the next ReadDir.
1930 dirp->file_number = 2;
1931 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1932 ; /* Don't seek in this case. */
1934 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1936 dirp->offset = offset;
1940 /*******************************************************************
1941 Tell a dir position.
1942 ********************************************************************/
1944 long TellDir(struct smb_Dir *dirp)
1946 return(dirp->offset);
1949 /*******************************************************************
1950 Add an entry into the dcache.
1951 ********************************************************************/
1953 static void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
1955 struct name_cache_entry *e;
1957 if (dirp->name_cache_size == 0) {
1961 if (dirp->name_cache == NULL) {
1962 dirp->name_cache = talloc_zero_array(
1963 dirp, struct name_cache_entry, dirp->name_cache_size);
1965 if (dirp->name_cache == NULL) {
1970 dirp->name_cache_index = (dirp->name_cache_index+1) %
1971 dirp->name_cache_size;
1972 e = &dirp->name_cache[dirp->name_cache_index];
1973 TALLOC_FREE(e->name);
1974 e->name = talloc_strdup(dirp, name);
1978 /*******************************************************************
1979 Find an entry by name. Leave us at the offset after it.
1980 Don't check for veto or invisible files.
1981 ********************************************************************/
1983 bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1986 const char *entry = NULL;
1987 char *talloced = NULL;
1988 connection_struct *conn = dirp->conn;
1990 /* Search back in the name cache. */
1991 if (dirp->name_cache_size && dirp->name_cache) {
1992 for (i = dirp->name_cache_index; i >= 0; i--) {
1993 struct name_cache_entry *e = &dirp->name_cache[i];
1994 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1995 *poffset = e->offset;
1996 SeekDir(dirp, e->offset);
2000 for (i = dirp->name_cache_size - 1; i > dirp->name_cache_index; i--) {
2001 struct name_cache_entry *e = &dirp->name_cache[i];
2002 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
2003 *poffset = e->offset;
2004 SeekDir(dirp, e->offset);
2010 /* Not found in the name cache. Rewind directory and start from scratch. */
2011 SMB_VFS_REWINDDIR(conn, dirp->dir);
2012 dirp->file_number = 0;
2013 *poffset = START_OF_DIRECTORY_OFFSET;
2014 while ((entry = ReadDirName(dirp, poffset, NULL, &talloced))) {
2015 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
2016 TALLOC_FREE(talloced);
2019 TALLOC_FREE(talloced);
2024 struct files_below_forall_state {
2027 int (*fn)(struct file_id fid, const struct share_mode_data *data,
2028 void *private_data);
2032 static int files_below_forall_fn(struct file_id fid,
2033 const struct share_mode_data *data,
2036 struct files_below_forall_state *state = private_data;
2037 char tmpbuf[PATH_MAX];
2038 char *fullpath, *to_free;
2041 len = full_path_tos(data->servicepath, data->base_name,
2042 tmpbuf, sizeof(tmpbuf),
2043 &fullpath, &to_free);
2047 if (state->dirpath_len >= len) {
2049 * Filter files above dirpath
2053 if (fullpath[state->dirpath_len] != '/') {
2055 * Filter file that don't have a path separator at the end of
2061 if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
2068 TALLOC_FREE(to_free);
2069 return state->fn(fid, data, state->private_data);
2072 TALLOC_FREE(to_free);
2076 static int files_below_forall(connection_struct *conn,
2077 const struct smb_filename *dir_name,
2078 int (*fn)(struct file_id fid,
2079 const struct share_mode_data *data,
2080 void *private_data),
2083 struct files_below_forall_state state = {
2085 .private_data = private_data,
2088 char tmpbuf[PATH_MAX];
2091 state.dirpath_len = full_path_tos(conn->connectpath,
2092 dir_name->base_name,
2093 tmpbuf, sizeof(tmpbuf),
2094 &state.dirpath, &to_free);
2095 if (state.dirpath_len == -1) {
2099 ret = share_mode_forall(files_below_forall_fn, &state);
2100 TALLOC_FREE(to_free);
2104 struct have_file_open_below_state {
2108 static int have_file_open_below_fn(struct file_id fid,
2109 const struct share_mode_data *data,
2112 struct have_file_open_below_state *state = private_data;
2113 state->found_one = true;
2117 bool have_file_open_below(connection_struct *conn,
2118 const struct smb_filename *name)
2120 struct have_file_open_below_state state = {
2125 if (!VALID_STAT(name->st)) {
2128 if (!S_ISDIR(name->st.st_ex_mode)) {
2132 ret = files_below_forall(conn, name, have_file_open_below_fn, &state);
2137 return state.found_one;
2140 /*****************************************************************
2141 Is this directory empty ?
2142 *****************************************************************/
2144 NTSTATUS can_delete_directory_fsp(files_struct *fsp)
2146 NTSTATUS status = NT_STATUS_OK;
2148 const char *dname = NULL;
2149 const char *dirname = fsp->fsp_name->base_name;
2150 char *talloced = NULL;
2152 struct connection_struct *conn = fsp->conn;
2153 struct smb_Dir *dir_hnd = OpenDir(talloc_tos(),
2160 return map_nt_error_from_unix(errno);
2163 while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) {
2164 /* Quick check for "." and ".." */
2165 if (dname[0] == '.') {
2166 if (!dname[1] || (dname[1] == '.' && !dname[2])) {
2167 TALLOC_FREE(talloced);
2172 if (!is_visible_file(conn, dirname, dname, &st, True)) {
2173 TALLOC_FREE(talloced);
2177 DEBUG(10,("got name %s - can't delete\n",
2179 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
2182 TALLOC_FREE(talloced);
2183 TALLOC_FREE(dir_hnd);
2185 if (!NT_STATUS_IS_OK(status)) {
2189 if (!(fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) &&
2190 lp_strict_rename(SNUM(conn)) &&
2191 have_file_open_below(fsp->conn, fsp->fsp_name))
2193 return NT_STATUS_ACCESS_DENIED;
2196 return NT_STATUS_OK;