s3: smbd: Remove 'is_dfs' parameter to check_path_syntax_smb2().
[Samba.git] / source3 / smbd / dir.c
blob859c8f0dc83448c0a1b4b9af60adbaf2c3f1c228
1 /*
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/>.
21 #include "includes.h"
22 #include "system/filesys.h"
23 #include "locking/share_mode_lock.h"
24 #include "smbd/smbd.h"
25 #include "smbd/globals.h"
26 #include "libcli/security/security.h"
27 #include "lib/util/bitmap.h"
28 #include "../lib/util/memcache.h"
29 #include "../librpc/gen_ndr/open_files.h"
30 #include "lib/util/string_wrappers.h"
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 {
49 char *name;
50 long offset;
53 struct smb_Dir {
54 connection_struct *conn;
55 DIR *dir;
56 long offset;
57 struct smb_filename *dir_smb_fname;
58 size_t name_cache_size;
59 struct name_cache_entry *name_cache;
60 unsigned int name_cache_index;
61 unsigned int file_number;
62 bool case_sensitive;
63 files_struct *fsp; /* Back pointer to containing fsp, only
64 set from OpenDir_fsp(). */
67 struct dptr_struct {
68 struct dptr_struct *next, *prev;
69 int dnum;
70 struct connection_struct *conn;
71 struct smb_Dir *dir_hnd;
72 char *wcard;
73 uint32_t attr;
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. */
77 uint32_t counter;
78 struct memcache *dptr_cache;
81 static NTSTATUS OpenDir_fsp(
82 TALLOC_CTX *mem_ctx,
83 connection_struct *conn,
84 files_struct *fsp,
85 const char *mask,
86 uint32_t attr,
87 struct smb_Dir **_dir_hnd);
89 static void DirCacheAdd(struct smb_Dir *dir_hnd, const char *name, long offset);
91 static int smb_Dir_destructor(struct smb_Dir *dir_hnd);
93 static bool SearchDir(struct smb_Dir *dir_hnd, const char *name, long *poffset);
95 #define INVALID_DPTR_KEY (-3)
97 /****************************************************************************
98 Initialise the dir bitmap.
99 ****************************************************************************/
101 bool init_dptrs(struct smbd_server_connection *sconn)
103 if (sconn->searches.dptr_bmap) {
104 return true;
107 sconn->searches.dptr_bmap = bitmap_talloc(
108 sconn, MAX_DIRECTORY_HANDLES);
110 if (sconn->searches.dptr_bmap == NULL) {
111 return false;
114 return true;
117 /****************************************************************************
118 Get the struct dptr_struct for a dir index.
119 ****************************************************************************/
121 static struct dptr_struct *dptr_get(struct smbd_server_connection *sconn,
122 int key)
124 struct dptr_struct *dptr;
126 for (dptr = sconn->searches.dirptrs; dptr != NULL; dptr = dptr->next) {
127 if(dptr->dnum != key) {
128 continue;
130 DLIST_PROMOTE(sconn->searches.dirptrs, dptr);
131 return dptr;
133 return(NULL);
136 /****************************************************************************
137 Get the dir path for a dir index.
138 ****************************************************************************/
140 const char *dptr_path(struct smbd_server_connection *sconn, int key)
142 struct dptr_struct *dptr = dptr_get(sconn, key);
143 if (dptr)
144 return(dptr->dir_hnd->dir_smb_fname->base_name);
145 return(NULL);
148 /****************************************************************************
149 Get the dir wcard for a dir index.
150 ****************************************************************************/
152 const char *dptr_wcard(struct smbd_server_connection *sconn, int key)
154 struct dptr_struct *dptr = dptr_get(sconn, key);
155 if (dptr)
156 return(dptr->wcard);
157 return(NULL);
160 /****************************************************************************
161 Get the dir attrib for a dir index.
162 ****************************************************************************/
164 uint16_t dptr_attr(struct smbd_server_connection *sconn, int key)
166 struct dptr_struct *dptr = dptr_get(sconn, key);
167 if (dptr)
168 return(dptr->attr);
169 return(0);
172 /****************************************************************************
173 Close all dptrs for a cnum.
174 ****************************************************************************/
176 void dptr_closecnum(connection_struct *conn)
178 struct dptr_struct *dptr, *next;
179 struct smbd_server_connection *sconn = conn->sconn;
181 if (sconn == NULL) {
182 return;
185 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
186 next = dptr->next;
187 if (dptr->conn == conn) {
189 * Need to make a copy, "dptr" will be gone
190 * after close_file_free() returns
192 struct files_struct *fsp = dptr->dir_hnd->fsp;
193 close_file_free(NULL, &fsp, NORMAL_CLOSE);
198 /****************************************************************************
199 Create a new dir ptr. If the flag old_handle is true then we must allocate
200 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
201 one byte long. If old_handle is false we allocate from the range
202 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
203 a directory handle is never zero.
204 wcard must not be zero.
205 ****************************************************************************/
207 NTSTATUS dptr_create(connection_struct *conn,
208 struct smb_request *req,
209 files_struct *fsp,
210 bool old_handle,
211 const char *wcard,
212 uint32_t attr,
213 struct dptr_struct **dptr_ret)
215 struct smbd_server_connection *sconn = conn->sconn;
216 struct dptr_struct *dptr = NULL;
217 struct smb_Dir *dir_hnd = NULL;
218 NTSTATUS status;
220 DBG_INFO("dir=%s\n", fsp_str_dbg(fsp));
222 if (sconn == NULL) {
223 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
224 return NT_STATUS_INTERNAL_ERROR;
227 if (!wcard) {
228 return NT_STATUS_INVALID_PARAMETER;
231 if (!(fsp->access_mask & SEC_DIR_LIST)) {
232 DBG_INFO("dptr_create: directory %s "
233 "not open for LIST access\n",
234 fsp_str_dbg(fsp));
235 return NT_STATUS_ACCESS_DENIED;
237 status = OpenDir_fsp(NULL, conn, fsp, wcard, attr, &dir_hnd);
238 if (!NT_STATUS_IS_OK(status)) {
239 return status;
242 dptr = talloc_zero(NULL, struct dptr_struct);
243 if(!dptr) {
244 DEBUG(0,("talloc fail in dptr_create.\n"));
245 TALLOC_FREE(dir_hnd);
246 return NT_STATUS_NO_MEMORY;
249 dptr->conn = conn;
250 dptr->dir_hnd = dir_hnd;
251 dptr->wcard = talloc_strdup(dptr, wcard);
252 if (!dptr->wcard) {
253 TALLOC_FREE(dptr);
254 TALLOC_FREE(dir_hnd);
255 return NT_STATUS_NO_MEMORY;
257 if ((req != NULL && req->posix_pathnames) || ISDOT(wcard)) {
258 dptr->has_wild = True;
259 } else {
260 dptr->has_wild = ms_has_wild(dptr->wcard);
263 dptr->attr = attr;
265 if (sconn->using_smb2) {
266 goto done;
269 if(old_handle) {
272 * This is an old-style SMBsearch request. Ensure the
273 * value we return will fit in the range 1-255.
276 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
278 if(dptr->dnum == -1 || dptr->dnum > 254) {
279 DBG_ERR("returned %d: Error - all old "
280 "dirptrs in use ?\n",
281 dptr->dnum);
282 TALLOC_FREE(dptr);
283 TALLOC_FREE(dir_hnd);
284 return NT_STATUS_TOO_MANY_OPENED_FILES;
286 } else {
289 * This is a new-style trans2 request. Allocate from
290 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
293 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
295 if(dptr->dnum == -1 || dptr->dnum < 255) {
296 DBG_ERR("returned %d: Error - all new "
297 "dirptrs in use ?\n",
298 dptr->dnum);
299 TALLOC_FREE(dptr);
300 TALLOC_FREE(dir_hnd);
301 return NT_STATUS_TOO_MANY_OPENED_FILES;
305 bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
307 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
309 DLIST_ADD(sconn->searches.dirptrs, dptr);
311 done:
312 DBG_INFO("creating new dirptr [%d] for path [%s]\n",
313 dptr->dnum, fsp_str_dbg(fsp));
315 *dptr_ret = dptr;
317 return NT_STATUS_OK;
321 /****************************************************************************
322 Wrapper functions to access the lower level directory handles.
323 ****************************************************************************/
325 void dptr_CloseDir(files_struct *fsp)
327 struct smbd_server_connection *sconn = NULL;
329 if (fsp->dptr == NULL) {
330 return;
332 sconn = fsp->dptr->conn->sconn;
335 * The destructor for the struct smb_Dir (fsp->dptr->dir_hnd)
336 * now handles all resource deallocation.
339 DBG_INFO("closing dptr key %d\n", fsp->dptr->dnum);
341 if (sconn != NULL && !sconn->using_smb2) {
342 DLIST_REMOVE(sconn->searches.dirptrs, fsp->dptr);
345 * Free the dnum in the bitmap. Remember the dnum value is
346 * always biased by one with respect to the bitmap.
349 if (!bitmap_query(sconn->searches.dptr_bmap,
350 fsp->dptr->dnum - 1))
352 DBG_ERR("closing dnum = %d and bitmap not set !\n",
353 fsp->dptr->dnum);
356 bitmap_clear(sconn->searches.dptr_bmap, fsp->dptr->dnum - 1);
359 TALLOC_FREE(fsp->dptr->dir_hnd);
360 TALLOC_FREE(fsp->dptr);
363 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
365 SeekDir(dptr->dir_hnd, offset);
368 long dptr_TellDir(struct dptr_struct *dptr)
370 return TellDir(dptr->dir_hnd);
373 bool dptr_has_wild(struct dptr_struct *dptr)
375 return dptr->has_wild;
378 int dptr_dnum(struct dptr_struct *dptr)
380 return dptr->dnum;
383 bool dptr_get_priv(struct dptr_struct *dptr)
385 return dptr->priv;
388 void dptr_set_priv(struct dptr_struct *dptr)
390 dptr->priv = true;
393 bool dptr_case_sensitive(struct dptr_struct *dptr)
395 return dptr->dir_hnd->case_sensitive;
398 /****************************************************************************
399 Return the next visible file name, skipping veto'd and invisible files.
400 ****************************************************************************/
402 static char *dptr_ReadDirName(TALLOC_CTX *ctx,
403 struct dptr_struct *dptr,
404 long *poffset,
405 SMB_STRUCT_STAT *pst)
407 struct smb_filename smb_fname_base;
408 char *name = NULL;
409 const char *name_temp = NULL;
410 char *talloced = NULL;
411 char *pathreal = NULL;
412 char *found_name = NULL;
413 NTSTATUS status;
415 SET_STAT_INVALID(*pst);
417 if (dptr->has_wild || dptr->did_stat) {
418 name_temp = ReadDirName(dptr->dir_hnd, poffset, pst,
419 &talloced);
420 if (name_temp == NULL) {
421 return NULL;
423 if (talloced != NULL) {
424 return talloc_move(ctx, &talloced);
426 return talloc_strdup(ctx, name_temp);
429 /* If poffset is -1 then we know we returned this name before and we
430 * have no wildcards. We're at the end of the directory. */
431 if (*poffset == END_OF_DIRECTORY_OFFSET) {
432 return NULL;
435 /* We know the stored wcard contains no wildcard characters.
436 * See if we can match with a stat call. If we can't, then set
437 * did_stat to true to ensure we only do this once and keep
438 * searching. */
440 dptr->did_stat = true;
442 if (VALID_STAT(*pst)) {
443 name = talloc_strdup(ctx, dptr->wcard);
444 goto ret;
447 pathreal = talloc_asprintf(ctx,
448 "%s/%s",
449 dptr->dir_hnd->dir_smb_fname->base_name,
450 dptr->wcard);
451 if (!pathreal)
452 return NULL;
454 /* Create an smb_filename with stream_name == NULL. */
455 smb_fname_base = (struct smb_filename) {
456 .base_name = pathreal,
457 .flags = dptr->dir_hnd->fsp->fsp_name->flags,
458 .twrp = dptr->dir_hnd->fsp->fsp_name->twrp,
461 if (vfs_stat(dptr->conn, &smb_fname_base) == 0) {
462 *pst = smb_fname_base.st;
463 name = talloc_strdup(ctx, dptr->wcard);
464 goto clean;
465 } else {
466 /* If we get any other error than ENOENT or ENOTDIR
467 then the file exists we just can't stat it. */
468 if (errno != ENOENT && errno != ENOTDIR) {
469 name = talloc_strdup(ctx, dptr->wcard);
470 goto clean;
474 /* Stat failed. We know this is authoritative if we are
475 * providing case sensitive semantics or the underlying
476 * filesystem is case sensitive.
478 if (dptr->dir_hnd->case_sensitive ||
479 !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
481 goto clean;
485 * Try case-insensitive stat if the fs has the ability. This avoids
486 * scanning the whole directory.
488 status = SMB_VFS_GET_REAL_FILENAME_AT(dptr->conn,
489 dptr->dir_hnd->fsp,
490 dptr->wcard,
491 ctx,
492 &found_name);
493 if (NT_STATUS_IS_OK(status)) {
494 name = found_name;
495 goto clean;
497 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
498 /* The case-insensitive lookup was authoritative. */
499 goto clean;
502 TALLOC_FREE(pathreal);
504 name_temp = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced);
505 if (name_temp == NULL) {
506 return NULL;
508 if (talloced != NULL) {
509 return talloc_move(ctx, &talloced);
511 return talloc_strdup(ctx, name_temp);
513 clean:
514 TALLOC_FREE(pathreal);
515 ret:
516 /* We need to set the underlying dir_hnd offset to -1
517 * also as this function is usually called with the
518 * output from TellDir. */
519 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
520 return name;
523 /****************************************************************************
524 Search for a file by name.
525 ****************************************************************************/
527 bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
529 SET_STAT_INVALID(*pst);
531 if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
532 /* This is a singleton directory and we're already at the end. */
533 *poffset = END_OF_DIRECTORY_OFFSET;
534 return False;
537 return SearchDir(dptr->dir_hnd, name, poffset);
540 /****************************************************************************
541 Map a native directory offset to a 32-bit cookie.
542 ****************************************************************************/
544 static uint32_t map_dir_offset_to_wire(struct dptr_struct *dptr, long offset)
546 DATA_BLOB key;
547 DATA_BLOB val;
549 if (offset == END_OF_DIRECTORY_OFFSET) {
550 return WIRE_END_OF_DIRECTORY_OFFSET;
552 if (offset == START_OF_DIRECTORY_OFFSET) {
553 return WIRE_START_OF_DIRECTORY_OFFSET;
555 if (offset == DOT_DOT_DIRECTORY_OFFSET) {
556 return WIRE_DOT_DOT_DIRECTORY_OFFSET;
558 if (sizeof(long) == 4) {
559 /* 32-bit machine. We can cheat... */
560 return (uint32_t)offset;
562 if (dptr->dptr_cache == NULL) {
563 /* Lazy initialize cache. */
564 dptr->dptr_cache = memcache_init(dptr, 0);
565 if (dptr->dptr_cache == NULL) {
566 return WIRE_END_OF_DIRECTORY_OFFSET;
568 } else {
569 /* Have we seen this offset before ? */
570 key.data = (void *)&offset;
571 key.length = sizeof(offset);
572 if (memcache_lookup(dptr->dptr_cache,
573 SMB1_SEARCH_OFFSET_MAP,
574 key,
575 &val)) {
576 uint32_t wire_offset;
577 SMB_ASSERT(val.length == sizeof(wire_offset));
578 memcpy(&wire_offset, val.data, sizeof(wire_offset));
579 DEBUG(10,("found wire %u <-> offset %ld\n",
580 (unsigned int)wire_offset,
581 (long)offset));
582 return wire_offset;
585 /* Allocate a new wire cookie. */
586 do {
587 dptr->counter++;
588 } while (dptr->counter == WIRE_START_OF_DIRECTORY_OFFSET ||
589 dptr->counter == WIRE_END_OF_DIRECTORY_OFFSET ||
590 dptr->counter == WIRE_DOT_DOT_DIRECTORY_OFFSET);
591 /* Store it in the cache. */
592 key.data = (void *)&offset;
593 key.length = sizeof(offset);
594 val.data = (void *)&dptr->counter;
595 val.length = sizeof(dptr->counter); /* MUST BE uint32_t ! */
596 memcache_add(dptr->dptr_cache,
597 SMB1_SEARCH_OFFSET_MAP,
598 key,
599 val);
600 /* And the reverse mapping for lookup from
601 map_wire_to_dir_offset(). */
602 memcache_add(dptr->dptr_cache,
603 SMB1_SEARCH_OFFSET_MAP,
604 val,
605 key);
606 DEBUG(10,("stored wire %u <-> offset %ld\n",
607 (unsigned int)dptr->counter,
608 (long)offset));
609 return dptr->counter;
612 /****************************************************************************
613 Fill the 5 byte server reserved dptr field.
614 ****************************************************************************/
616 bool dptr_fill(struct smbd_server_connection *sconn,
617 char *buf1,unsigned int key)
619 unsigned char *buf = (unsigned char *)buf1;
620 struct dptr_struct *dptr = dptr_get(sconn, key);
621 uint32_t wire_offset;
622 if (!dptr) {
623 DEBUG(1,("filling null dirptr %d\n",key));
624 return(False);
626 wire_offset = map_dir_offset_to_wire(dptr,TellDir(dptr->dir_hnd));
627 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
628 (long)dptr->dir_hnd,(int)wire_offset));
629 buf[0] = key;
630 SIVAL(buf,1,wire_offset);
631 return(True);
634 /****************************************************************************
635 Map a 32-bit wire cookie to a native directory offset.
636 ****************************************************************************/
638 static long map_wire_to_dir_offset(struct dptr_struct *dptr, uint32_t wire_offset)
640 DATA_BLOB key;
641 DATA_BLOB val;
643 if (wire_offset == WIRE_END_OF_DIRECTORY_OFFSET) {
644 return END_OF_DIRECTORY_OFFSET;
645 } else if(wire_offset == WIRE_START_OF_DIRECTORY_OFFSET) {
646 return START_OF_DIRECTORY_OFFSET;
647 } else if (wire_offset == WIRE_DOT_DOT_DIRECTORY_OFFSET) {
648 return DOT_DOT_DIRECTORY_OFFSET;
650 if (sizeof(long) == 4) {
651 /* 32-bit machine. We can cheat... */
652 return (long)wire_offset;
654 if (dptr->dptr_cache == NULL) {
655 /* Logic error, cache should be initialized. */
656 return END_OF_DIRECTORY_OFFSET;
658 key.data = (void *)&wire_offset;
659 key.length = sizeof(wire_offset);
660 if (memcache_lookup(dptr->dptr_cache,
661 SMB1_SEARCH_OFFSET_MAP,
662 key,
663 &val)) {
664 /* Found mapping. */
665 long offset;
666 SMB_ASSERT(val.length == sizeof(offset));
667 memcpy(&offset, val.data, sizeof(offset));
668 DEBUG(10,("lookup wire %u <-> offset %ld\n",
669 (unsigned int)wire_offset,
670 (long)offset));
671 return offset;
673 return END_OF_DIRECTORY_OFFSET;
676 /****************************************************************************
677 Return the associated fsp and seek the dir_hnd on it it given the 5 byte
678 server field.
679 ****************************************************************************/
681 files_struct *dptr_fetch_fsp(struct smbd_server_connection *sconn,
682 char *buf, int *num)
684 unsigned int key = *(unsigned char *)buf;
685 struct dptr_struct *dptr = dptr_get(sconn, key);
686 uint32_t wire_offset;
687 long seekoff;
689 if (dptr == NULL) {
690 DEBUG(3,("fetched null dirptr %d\n",key));
691 return(NULL);
693 *num = key;
694 wire_offset = IVAL(buf,1);
695 seekoff = map_wire_to_dir_offset(dptr, wire_offset);
696 SeekDir(dptr->dir_hnd,seekoff);
697 DBG_NOTICE("fetching dirptr %d for path %s at offset %ld\n",
698 key,
699 dptr->dir_hnd->dir_smb_fname->base_name,
700 seekoff);
701 return dptr->dir_hnd->fsp;
704 struct files_struct *dir_hnd_fetch_fsp(struct smb_Dir *dir_hnd)
706 return dir_hnd->fsp;
709 /****************************************************************************
710 Fetch the fsp associated with the dptr_num.
711 ****************************************************************************/
713 files_struct *dptr_fetch_lanman2_fsp(struct smbd_server_connection *sconn,
714 int dptr_num)
716 struct dptr_struct *dptr = dptr_get(sconn, dptr_num);
717 if (dptr == NULL) {
718 return NULL;
720 DBG_NOTICE("fetching dirptr %d for path %s\n",
721 dptr_num,
722 dptr->dir_hnd->dir_smb_fname->base_name);
723 return dptr->dir_hnd->fsp;
726 static bool mangle_mask_match(connection_struct *conn,
727 const char *filename,
728 const char *mask)
730 char mname[13];
732 if (!name_to_8_3(filename,mname,False,conn->params)) {
733 return False;
735 return mask_match_search(mname,mask,False);
738 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
739 struct dptr_struct *dirptr,
740 const char *mask,
741 uint32_t dirtype,
742 bool dont_descend,
743 bool ask_sharemode,
744 bool get_dosmode_in,
745 bool (*match_fn)(TALLOC_CTX *ctx,
746 void *private_data,
747 const char *dname,
748 const char *mask,
749 char **_fname),
750 bool (*mode_fn)(TALLOC_CTX *ctx,
751 void *private_data,
752 struct files_struct *dirfsp,
753 struct smb_filename *atname,
754 struct smb_filename *smb_fname,
755 bool get_dosmode,
756 uint32_t *_mode),
757 void *private_data,
758 char **_fname,
759 struct smb_filename **_smb_fname,
760 uint32_t *_mode,
761 long *_prev_offset)
763 connection_struct *conn = dirptr->conn;
764 size_t slashlen;
765 size_t pathlen;
766 const char *dpath = dirptr->dir_hnd->dir_smb_fname->base_name;
767 bool dirptr_path_is_dot = ISDOT(dpath);
768 NTSTATUS status;
769 int ret;
771 *_smb_fname = NULL;
772 *_mode = 0;
774 pathlen = strlen(dpath);
775 slashlen = ( dpath[pathlen-1] != '/') ? 1 : 0;
777 while (true) {
778 long cur_offset;
779 long prev_offset;
780 SMB_STRUCT_STAT sbuf = { 0 };
781 char *dname = NULL;
782 bool isdots;
783 char *fname = NULL;
784 char *pathreal = NULL;
785 struct smb_filename *atname = NULL;
786 struct smb_filename *smb_fname = NULL;
787 uint32_t mode = 0;
788 bool check_dfs_symlink = false;
789 bool get_dosmode = get_dosmode_in;
790 bool ok;
792 cur_offset = dptr_TellDir(dirptr);
793 prev_offset = cur_offset;
794 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
796 DBG_DEBUG("dir [%s] dirptr [0x%lx] offset [%ld] => dname [%s]\n",
797 smb_fname_str_dbg(dirptr->dir_hnd->dir_smb_fname),
798 (long)dirptr,
799 cur_offset, dname ? dname : "(finished)");
801 if (dname == NULL) {
802 return false;
805 isdots = (ISDOT(dname) || ISDOTDOT(dname));
806 if (dont_descend && !isdots) {
807 TALLOC_FREE(dname);
808 continue;
811 if (IS_VETO_PATH(conn, dname)) {
812 TALLOC_FREE(dname);
813 continue;
817 * fname may get mangled, dname is never mangled.
818 * Whenever we're accessing the filesystem we use
819 * pathreal which is composed from dname.
822 ok = match_fn(ctx, private_data, dname, mask, &fname);
823 if (!ok) {
824 TALLOC_FREE(dname);
825 continue;
829 * This used to be
830 * pathreal = talloc_asprintf(ctx, "%s%s%s", dirptr->path,
831 * needslash?"/":"", dname);
832 * but this was measurably slower than doing the memcpy.
835 pathreal = talloc_array(
836 ctx, char,
837 pathlen + slashlen + talloc_get_size(dname));
838 if (!pathreal) {
839 TALLOC_FREE(dname);
840 TALLOC_FREE(fname);
841 return false;
845 * We don't want to pass ./xxx to modules below us so don't
846 * add the path if it is just . by itself.
848 if (dirptr_path_is_dot) {
849 memcpy(pathreal, dname, talloc_get_size(dname));
850 } else {
851 memcpy(pathreal, dpath, pathlen);
852 pathreal[pathlen] = '/';
853 memcpy(pathreal + slashlen + pathlen, dname,
854 talloc_get_size(dname));
857 /* Create smb_fname with NULL stream_name. */
858 smb_fname = synthetic_smb_fname(
859 talloc_tos(),
860 pathreal,
861 NULL,
862 &sbuf,
863 dirptr->dir_hnd->dir_smb_fname->twrp,
864 dirptr->dir_hnd->dir_smb_fname->flags);
865 TALLOC_FREE(pathreal);
866 if (smb_fname == NULL) {
867 TALLOC_FREE(dname);
868 TALLOC_FREE(fname);
869 return false;
872 if (!VALID_STAT(smb_fname->st)) {
874 * If stat() fails with ENOENT it might be a
875 * msdfs-symlink in Windows context, this is checked
876 * below, for now we just want to fill stat info as good
877 * as we can.
879 ret = vfs_stat(conn, smb_fname);
880 if (ret != 0 && errno != ENOENT) {
881 TALLOC_FREE(smb_fname);
882 TALLOC_FREE(dname);
883 TALLOC_FREE(fname);
884 continue;
888 /* Create smb_fname with NULL stream_name. */
889 atname = synthetic_smb_fname(
890 talloc_tos(),
891 dname,
892 NULL,
893 &smb_fname->st,
894 dirptr->dir_hnd->dir_smb_fname->twrp,
895 dirptr->dir_hnd->dir_smb_fname->flags);
896 if (atname == NULL) {
897 TALLOC_FREE(dname);
898 TALLOC_FREE(fname);
899 TALLOC_FREE(smb_fname);
900 return false;
904 * openat_pathref_fsp() will return
905 * NT_STATUS_OBJECT_NAME_NOT_FOUND in non-POSIX context when
906 * hitting a dangling symlink. It may be a DFS symlink, this is
907 * checked below by the mode_fn() call, so we have to allow this
908 * here.
910 * NT_STATUS_STOPPED_ON_SYMLINK is returned in POSIX context
911 * when hitting a symlink and ensures we always return directory
912 * entries that are symlinks in POSIX context.
914 status = openat_pathref_fsp(dirptr->dir_hnd->fsp, atname);
915 if (!NT_STATUS_IS_OK(status) &&
916 !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND))
918 TALLOC_FREE(atname);
919 TALLOC_FREE(dname);
920 TALLOC_FREE(fname);
921 TALLOC_FREE(smb_fname);
922 continue;
925 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
926 if (!(atname->flags & SMB_FILENAME_POSIX_PATH)) {
927 check_dfs_symlink = true;
930 * Check if it's a symlink. We only want to return this
931 * if it's a DFS symlink or in POSIX mode. Disable
932 * getting dosmode in the mode_fn() and prime the mode
933 * as FILE_ATTRIBUTE_NORMAL.
935 mode = FILE_ATTRIBUTE_NORMAL;
936 get_dosmode = false;
939 status = move_smb_fname_fsp_link(smb_fname, atname);
940 if (!NT_STATUS_IS_OK(status)) {
941 DBG_WARNING("Failed to move pathref for [%s]: %s\n",
942 smb_fname_str_dbg(smb_fname),
943 nt_errstr(status));
944 TALLOC_FREE(atname);
945 TALLOC_FREE(smb_fname);
946 TALLOC_FREE(dname);
947 TALLOC_FREE(fname);
948 continue;
951 if (!is_visible_fsp(smb_fname->fsp)) {
952 TALLOC_FREE(atname);
953 TALLOC_FREE(smb_fname);
954 TALLOC_FREE(dname);
955 TALLOC_FREE(fname);
956 continue;
960 * Don't leak metadata about the containing
961 * directory of the share.
963 if (dirptr_path_is_dot && ISDOTDOT(dname)) {
965 * Making a copy here, then freeing
966 * the original will close the smb_fname->fsp.
968 struct smb_filename *tmp_smb_fname =
969 cp_smb_filename(ctx, smb_fname);
971 if (tmp_smb_fname == NULL) {
972 TALLOC_FREE(atname);
973 TALLOC_FREE(smb_fname);
974 TALLOC_FREE(dname);
975 TALLOC_FREE(fname);
976 return false;
978 TALLOC_FREE(smb_fname);
979 smb_fname = tmp_smb_fname;
980 mode = FILE_ATTRIBUTE_DIRECTORY;
981 get_dosmode = false;
983 /* Ensure posix fileid and sids are hidden
985 smb_fname->st.st_ex_ino = 0;
986 smb_fname->st.st_ex_dev = 0;
987 smb_fname->st.st_ex_uid = -1;
988 smb_fname->st.st_ex_gid = -1;
991 ok = mode_fn(ctx,
992 private_data,
993 dirptr->dir_hnd->fsp,
994 atname,
995 smb_fname,
996 get_dosmode,
997 &mode);
998 if (!ok) {
999 TALLOC_FREE(atname);
1000 TALLOC_FREE(smb_fname);
1001 TALLOC_FREE(dname);
1002 TALLOC_FREE(fname);
1003 continue;
1006 TALLOC_FREE(atname);
1009 * The only valid cases where we return the directory entry if
1010 * it's a symlink are:
1012 * 1. POSIX context, always return it, or
1014 * 2. a DFS symlink where the mode_fn() call above has verified
1015 * this and set mode to FILE_ATTRIBUTE_REPARSE_POINT.
1017 if (check_dfs_symlink &&
1018 !(mode & FILE_ATTRIBUTE_REPARSE_POINT))
1020 TALLOC_FREE(smb_fname);
1021 TALLOC_FREE(dname);
1022 TALLOC_FREE(fname);
1023 continue;
1026 if (!dir_check_ftype(mode, dirtype)) {
1027 DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
1028 fname, (unsigned int)mode, (unsigned int)dirtype));
1029 TALLOC_FREE(smb_fname);
1030 TALLOC_FREE(dname);
1031 TALLOC_FREE(fname);
1032 continue;
1035 if (ask_sharemode && !S_ISDIR(smb_fname->st.st_ex_mode)) {
1036 struct timespec write_time_ts;
1037 struct file_id fileid;
1039 fileid = vfs_file_id_from_sbuf(conn,
1040 &smb_fname->st);
1041 get_file_infos(fileid, 0, NULL, &write_time_ts);
1042 if (!is_omit_timespec(&write_time_ts)) {
1043 update_stat_ex_mtime(&smb_fname->st,
1044 write_time_ts);
1048 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
1049 "fname=%s (%s)\n",
1050 mask, smb_fname_str_dbg(smb_fname),
1051 dname, fname));
1053 if (!conn->sconn->using_smb2) {
1055 * The dircache is only needed for SMB1 because SMB1
1056 * uses a name for the resume wheras SMB2 always
1057 * continues from the next position (unless it's told to
1058 * restart or close-and-reopen the listing).
1060 DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
1063 TALLOC_FREE(dname);
1065 *_smb_fname = talloc_move(ctx, &smb_fname);
1066 if (*_smb_fname == NULL) {
1067 return false;
1069 *_fname = fname;
1070 *_mode = mode;
1071 *_prev_offset = prev_offset;
1073 return true;
1076 return false;
1079 /****************************************************************************
1080 Get an 8.3 directory entry.
1081 ****************************************************************************/
1083 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
1084 void *private_data,
1085 const char *dname,
1086 const char *mask,
1087 char **_fname)
1089 connection_struct *conn = (connection_struct *)private_data;
1091 if ((strcmp(mask,"*.*") == 0) ||
1092 mask_match_search(dname, mask, false) ||
1093 mangle_mask_match(conn, dname, mask)) {
1094 char mname[13];
1095 const char *fname;
1097 * Ensure we can push the original name as UCS2. If
1098 * not, then just don't return this name.
1100 NTSTATUS status;
1101 size_t ret_len = 0;
1102 size_t len = (strlen(dname) + 2) * 4; /* Allow enough space. */
1103 uint8_t *tmp = talloc_array(talloc_tos(),
1104 uint8_t,
1105 len);
1107 status = srvstr_push(NULL,
1108 FLAGS2_UNICODE_STRINGS,
1109 tmp,
1110 dname,
1111 len,
1112 STR_TERMINATE,
1113 &ret_len);
1115 TALLOC_FREE(tmp);
1117 if (!NT_STATUS_IS_OK(status)) {
1118 return false;
1121 if (!mangle_is_8_3(dname, false, conn->params)) {
1122 bool ok = name_to_8_3(dname, mname, false,
1123 conn->params);
1124 if (!ok) {
1125 return false;
1127 fname = mname;
1128 } else {
1129 fname = dname;
1132 *_fname = talloc_strdup(ctx, fname);
1133 if (*_fname == NULL) {
1134 return false;
1137 return true;
1140 return false;
1143 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1144 void *private_data,
1145 struct files_struct *dirfsp,
1146 struct smb_filename *atname,
1147 struct smb_filename *smb_fname,
1148 bool get_dosmode,
1149 uint32_t *_mode)
1151 connection_struct *conn = (connection_struct *)private_data;
1153 if (!VALID_STAT(smb_fname->st)) {
1154 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1155 DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1156 "Couldn't stat [%s]. Error "
1157 "= %s\n",
1158 smb_fname_str_dbg(smb_fname),
1159 strerror(errno)));
1160 return false;
1164 if (get_dosmode) {
1165 *_mode = fdos_mode(smb_fname->fsp);
1166 smb_fname->st = smb_fname->fsp->fsp_name->st;
1168 return true;
1171 bool get_dir_entry(TALLOC_CTX *ctx,
1172 struct dptr_struct *dirptr,
1173 const char *mask,
1174 uint32_t dirtype,
1175 char **_fname,
1176 off_t *_size,
1177 uint32_t *_mode,
1178 struct timespec *_date,
1179 bool check_descend,
1180 bool ask_sharemode)
1182 connection_struct *conn = dirptr->conn;
1183 char *fname = NULL;
1184 struct smb_filename *smb_fname = NULL;
1185 uint32_t mode = 0;
1186 long prev_offset;
1187 bool ok;
1189 ok = smbd_dirptr_get_entry(ctx,
1190 dirptr,
1191 mask,
1192 dirtype,
1193 check_descend,
1194 ask_sharemode,
1195 true,
1196 smbd_dirptr_8_3_match_fn,
1197 smbd_dirptr_8_3_mode_fn,
1198 conn,
1199 &fname,
1200 &smb_fname,
1201 &mode,
1202 &prev_offset);
1203 if (!ok) {
1204 return false;
1207 *_fname = talloc_move(ctx, &fname);
1208 *_size = smb_fname->st.st_ex_size;
1209 *_mode = mode;
1210 *_date = smb_fname->st.st_ex_mtime;
1211 TALLOC_FREE(smb_fname);
1212 return true;
1215 /*******************************************************************
1216 Check to see if a user can read an fsp . This is only approximate,
1217 it is used as part of the "hide unreadable" option. Don't
1218 use it for anything security sensitive.
1219 ********************************************************************/
1221 static bool user_can_read_fsp(struct files_struct *fsp)
1223 NTSTATUS status;
1224 uint32_t rejected_share_access = 0;
1225 uint32_t rejected_mask = 0;
1226 struct security_descriptor *sd = NULL;
1227 uint32_t access_mask = FILE_READ_DATA|
1228 FILE_READ_EA|
1229 FILE_READ_ATTRIBUTES|
1230 SEC_STD_READ_CONTROL;
1233 * Never hide files from the root user.
1234 * We use (uid_t)0 here not sec_initial_uid()
1235 * as make test uses a single user context.
1238 if (get_current_uid(fsp->conn) == (uid_t)0) {
1239 return true;
1243 * We can't directly use smbd_check_access_rights_fsp()
1244 * here, as this implicitly grants FILE_READ_ATTRIBUTES
1245 * which the Windows access-based-enumeration code
1246 * explicitly checks for on the file security descriptor.
1247 * See bug:
1249 * https://bugzilla.samba.org/show_bug.cgi?id=10252
1251 * and the smb2.acl2.ACCESSBASED test for details.
1254 rejected_share_access = access_mask & ~(fsp->conn->share_access);
1255 if (rejected_share_access) {
1256 DBG_DEBUG("rejected share access 0x%x "
1257 "on %s (0x%x)\n",
1258 (unsigned int)access_mask,
1259 fsp_str_dbg(fsp),
1260 (unsigned int)rejected_share_access);
1261 return false;
1264 status = SMB_VFS_FGET_NT_ACL(metadata_fsp(fsp),
1265 (SECINFO_OWNER |
1266 SECINFO_GROUP |
1267 SECINFO_DACL),
1268 talloc_tos(),
1269 &sd);
1271 if (!NT_STATUS_IS_OK(status)) {
1272 DBG_DEBUG("Could not get acl "
1273 "on %s: %s\n",
1274 fsp_str_dbg(fsp),
1275 nt_errstr(status));
1276 return false;
1279 status = se_file_access_check(sd,
1280 get_current_nttok(fsp->conn),
1281 false,
1282 access_mask,
1283 &rejected_mask);
1285 TALLOC_FREE(sd);
1287 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1288 DBG_DEBUG("rejected bits 0x%x read access for %s\n",
1289 (unsigned int)rejected_mask,
1290 fsp_str_dbg(fsp));
1291 return false;
1293 return true;
1296 /*******************************************************************
1297 Check to see if a user can write to an fsp.
1298 Always return true for directories.
1299 This is only approximate,
1300 it is used as part of the "hide unwriteable" option. Don't
1301 use it for anything security sensitive.
1302 ********************************************************************/
1304 static bool user_can_write_fsp(struct files_struct *fsp)
1307 * Never hide files from the root user.
1308 * We use (uid_t)0 here not sec_initial_uid()
1309 * as make test uses a single user context.
1312 if (get_current_uid(fsp->conn) == (uid_t)0) {
1313 return true;
1316 if (fsp->fsp_flags.is_directory) {
1317 return true;
1320 return can_write_to_fsp(fsp);
1323 /*******************************************************************
1324 Is a file a "special" type ?
1325 ********************************************************************/
1327 static bool file_is_special(connection_struct *conn,
1328 const struct smb_filename *smb_fname)
1331 * Never hide files from the root user.
1332 * We use (uid_t)0 here not sec_initial_uid()
1333 * as make test uses a single user context.
1336 if (get_current_uid(conn) == (uid_t)0) {
1337 return False;
1340 SMB_ASSERT(VALID_STAT(smb_fname->st));
1342 if (S_ISREG(smb_fname->st.st_ex_mode) ||
1343 S_ISDIR(smb_fname->st.st_ex_mode) ||
1344 S_ISLNK(smb_fname->st.st_ex_mode))
1345 return False;
1347 return True;
1350 /*******************************************************************
1351 Should the file be seen by the client?
1352 ********************************************************************/
1354 bool is_visible_fsp(struct files_struct *fsp)
1356 bool hide_unreadable = false;
1357 bool hide_unwriteable = false;
1358 bool hide_special = false;
1359 int hide_new_files_timeout = 0;
1360 const char *last_component = NULL;
1363 * If the file does not exist, there's no point checking
1364 * the configuration options. We succeed, on the basis that the
1365 * checks *might* have passed if the file was present.
1367 if (fsp == NULL) {
1368 return true;
1371 hide_unreadable = lp_hide_unreadable(SNUM(fsp->conn));
1372 hide_unwriteable = lp_hide_unwriteable_files(SNUM(fsp->conn));
1373 hide_special = lp_hide_special_files(SNUM(fsp->conn));
1374 hide_new_files_timeout = lp_hide_new_files_timeout(SNUM(fsp->conn));
1376 if (!hide_unreadable &&
1377 !hide_unwriteable &&
1378 !hide_special &&
1379 (hide_new_files_timeout == 0))
1381 return true;
1384 fsp = metadata_fsp(fsp);
1386 /* Get the last component of the base name. */
1387 last_component = strrchr_m(fsp->fsp_name->base_name, '/');
1388 if (!last_component) {
1389 last_component = fsp->fsp_name->base_name;
1390 } else {
1391 last_component++; /* Go past '/' */
1394 if (ISDOT(last_component) || ISDOTDOT(last_component)) {
1395 return true; /* . and .. are always visible. */
1398 if (fsp_get_pathref_fd(fsp) == -1) {
1400 * Symlink in POSIX mode or MS-DFS.
1401 * We've checked veto files so the
1402 * only thing we can check is the
1403 * hide_new_files_timeout.
1405 if ((hide_new_files_timeout != 0) &&
1406 !S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
1407 double age = timespec_elapsed(
1408 &fsp->fsp_name->st.st_ex_mtime);
1410 if (age < (double)hide_new_files_timeout) {
1411 return false;
1414 return true;
1417 /* Honour _hide unreadable_ option */
1418 if (hide_unreadable && !user_can_read_fsp(fsp)) {
1419 DBG_DEBUG("file %s is unreadable.\n", fsp_str_dbg(fsp));
1420 return false;
1423 /* Honour _hide unwriteable_ option */
1424 if (hide_unwriteable && !user_can_write_fsp(fsp)) {
1425 DBG_DEBUG("file %s is unwritable.\n", fsp_str_dbg(fsp));
1426 return false;
1429 /* Honour _hide_special_ option */
1430 if (hide_special && file_is_special(fsp->conn, fsp->fsp_name)) {
1431 DBG_DEBUG("file %s is special.\n", fsp_str_dbg(fsp));
1432 return false;
1435 if ((hide_new_files_timeout != 0) &&
1436 !S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
1437 double age = timespec_elapsed(&fsp->fsp_name->st.st_ex_mtime);
1439 if (age < (double)hide_new_files_timeout) {
1440 return false;
1444 return true;
1447 static int smb_Dir_destructor(struct smb_Dir *dir_hnd)
1449 files_struct *fsp = dir_hnd->fsp;
1451 SMB_VFS_CLOSEDIR(dir_hnd->conn, dir_hnd->dir);
1452 fsp_set_fd(fsp, -1);
1453 if (fsp->dptr != NULL) {
1454 SMB_ASSERT(fsp->dptr->dir_hnd == dir_hnd);
1455 fsp->dptr->dir_hnd = NULL;
1457 dir_hnd->fsp = NULL;
1458 return 0;
1461 /*******************************************************************
1462 Open a directory.
1463 ********************************************************************/
1465 static int smb_Dir_OpenDir_destructor(struct smb_Dir *dir_hnd)
1467 files_struct *fsp = dir_hnd->fsp;
1469 smb_Dir_destructor(dir_hnd);
1470 file_free(NULL, fsp);
1471 return 0;
1474 NTSTATUS OpenDir(TALLOC_CTX *mem_ctx,
1475 connection_struct *conn,
1476 const struct smb_filename *smb_dname,
1477 const char *mask,
1478 uint32_t attr,
1479 struct smb_Dir **_dir_hnd)
1481 struct files_struct *fsp = NULL;
1482 struct smb_Dir *dir_hnd = NULL;
1483 NTSTATUS status;
1485 status = open_internal_dirfsp(conn,
1486 smb_dname,
1487 O_RDONLY,
1488 &fsp);
1489 if (!NT_STATUS_IS_OK(status)) {
1490 return status;
1493 status = OpenDir_fsp(mem_ctx, conn, fsp, mask, attr, &dir_hnd);
1494 if (!NT_STATUS_IS_OK(status)) {
1495 return status;
1499 * This overwrites the destructor set by OpenDir_fsp() but
1500 * smb_Dir_OpenDir_destructor() calls the OpenDir_fsp()
1501 * destructor.
1503 talloc_set_destructor(dir_hnd, smb_Dir_OpenDir_destructor);
1505 *_dir_hnd = dir_hnd;
1506 return NT_STATUS_OK;
1509 NTSTATUS OpenDir_from_pathref(TALLOC_CTX *mem_ctx,
1510 struct files_struct *dirfsp,
1511 const char *mask,
1512 uint32_t attr,
1513 struct smb_Dir **_dir_hnd)
1515 struct files_struct *fsp = NULL;
1516 struct smb_Dir *dir_hnd = NULL;
1517 NTSTATUS status;
1519 status = openat_internal_dir_from_pathref(dirfsp, O_RDONLY, &fsp);
1520 if (!NT_STATUS_IS_OK(status)) {
1521 return status;
1524 status = OpenDir_fsp(mem_ctx, fsp->conn, fsp, mask, attr, &dir_hnd);
1525 if (!NT_STATUS_IS_OK(status)) {
1526 return status;
1530 * This overwrites the destructor set by OpenDir_fsp() but
1531 * smb_Dir_OpenDir_destructor() calls the OpenDir_fsp()
1532 * destructor.
1534 talloc_set_destructor(dir_hnd, smb_Dir_OpenDir_destructor);
1536 *_dir_hnd = dir_hnd;
1537 return NT_STATUS_OK;
1540 /*******************************************************************
1541 Open a directory from an fsp.
1542 ********************************************************************/
1544 static NTSTATUS OpenDir_fsp(
1545 TALLOC_CTX *mem_ctx,
1546 connection_struct *conn,
1547 files_struct *fsp,
1548 const char *mask,
1549 uint32_t attr,
1550 struct smb_Dir **_dir_hnd)
1552 struct smb_Dir *dir_hnd = talloc_zero(mem_ctx, struct smb_Dir);
1553 NTSTATUS status;
1555 if (!dir_hnd) {
1556 return NT_STATUS_NO_MEMORY;
1559 if (!fsp->fsp_flags.is_directory) {
1560 status = NT_STATUS_INVALID_HANDLE;
1561 goto fail;
1564 if (fsp_get_io_fd(fsp) == -1) {
1565 status = NT_STATUS_INVALID_HANDLE;
1566 goto fail;
1569 dir_hnd->conn = conn;
1571 if (!conn->sconn->using_smb2) {
1573 * The dircache is only needed for SMB1 because SMB1 uses a name
1574 * for the resume wheras SMB2 always continues from the next
1575 * position (unless it's told to restart or close-and-reopen the
1576 * listing).
1578 dir_hnd->name_cache_size =
1579 lp_directory_name_cache_size(SNUM(conn));
1582 dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, fsp->fsp_name);
1583 if (!dir_hnd->dir_smb_fname) {
1584 status = NT_STATUS_NO_MEMORY;
1585 goto fail;
1588 dir_hnd->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1589 if (dir_hnd->dir == NULL) {
1590 status = map_nt_error_from_unix(errno);
1591 goto fail;
1593 dir_hnd->fsp = fsp;
1594 if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
1595 dir_hnd->case_sensitive = true;
1596 } else {
1597 dir_hnd->case_sensitive = conn->case_sensitive;
1600 talloc_set_destructor(dir_hnd, smb_Dir_destructor);
1602 *_dir_hnd = dir_hnd;
1603 return NT_STATUS_OK;
1605 fail:
1606 TALLOC_FREE(dir_hnd);
1607 return status;
1611 /*******************************************************************
1612 Read from a directory.
1613 Return directory entry, current offset, and optional stat information.
1614 Don't check for veto or invisible files.
1615 ********************************************************************/
1617 const char *ReadDirName(struct smb_Dir *dir_hnd, long *poffset,
1618 SMB_STRUCT_STAT *sbuf, char **ptalloced)
1620 const char *n;
1621 char *talloced = NULL;
1622 connection_struct *conn = dir_hnd->conn;
1624 /* Cheat to allow . and .. to be the first entries returned. */
1625 if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1626 (*poffset == DOT_DOT_DIRECTORY_OFFSET)) &&
1627 (dir_hnd->file_number < 2))
1629 if (dir_hnd->file_number == 0) {
1630 n = ".";
1631 *poffset = dir_hnd->offset = START_OF_DIRECTORY_OFFSET;
1632 } else {
1633 n = "..";
1634 *poffset = dir_hnd->offset = DOT_DOT_DIRECTORY_OFFSET;
1636 dir_hnd->file_number++;
1637 *ptalloced = NULL;
1638 return n;
1641 if (*poffset == END_OF_DIRECTORY_OFFSET) {
1642 *poffset = dir_hnd->offset = END_OF_DIRECTORY_OFFSET;
1643 return NULL;
1646 /* A real offset, seek to it. */
1647 SeekDir(dir_hnd, *poffset);
1649 while ((n = vfs_readdirname(conn, dir_hnd->fsp, dir_hnd->dir, sbuf, &talloced))) {
1650 /* Ignore . and .. - we've already returned them. */
1651 if (ISDOT(n) || ISDOTDOT(n)) {
1652 TALLOC_FREE(talloced);
1653 continue;
1655 *poffset = dir_hnd->offset = SMB_VFS_TELLDIR(conn, dir_hnd->dir);
1656 *ptalloced = talloced;
1657 dir_hnd->file_number++;
1658 return n;
1660 *poffset = dir_hnd->offset = END_OF_DIRECTORY_OFFSET;
1661 *ptalloced = NULL;
1662 return NULL;
1665 /*******************************************************************
1666 Rewind to the start.
1667 ********************************************************************/
1669 void RewindDir(struct smb_Dir *dir_hnd, long *poffset)
1671 SMB_VFS_REWINDDIR(dir_hnd->conn, dir_hnd->dir);
1672 dir_hnd->file_number = 0;
1673 dir_hnd->offset = START_OF_DIRECTORY_OFFSET;
1674 *poffset = START_OF_DIRECTORY_OFFSET;
1677 /*******************************************************************
1678 Seek a dir.
1679 ********************************************************************/
1681 void SeekDir(struct smb_Dir *dirp, long offset)
1683 if (offset == dirp->offset) {
1685 * Nothing to do
1687 return;
1690 if (offset == START_OF_DIRECTORY_OFFSET) {
1691 RewindDir(dirp, &offset);
1693 * Ok we should really set the file number here
1694 * to 1 to enable ".." to be returned next. Trouble
1695 * is I'm worried about callers using SeekDir(dirp,0)
1696 * as equivalent to RewindDir(). So leave this alone
1697 * for now.
1699 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
1700 RewindDir(dirp, &offset);
1702 * Set the file number to 2 - we want to get the first
1703 * real file entry (the one we return after "..")
1704 * on the next ReadDir.
1706 dirp->file_number = 2;
1707 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1708 ; /* Don't seek in this case. */
1709 } else {
1710 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1712 dirp->offset = offset;
1715 /*******************************************************************
1716 Tell a dir position.
1717 ********************************************************************/
1719 long TellDir(struct smb_Dir *dir_hnd)
1721 return(dir_hnd->offset);
1724 /*******************************************************************
1725 Add an entry into the dcache.
1726 ********************************************************************/
1728 static void DirCacheAdd(struct smb_Dir *dir_hnd, const char *name, long offset)
1730 struct name_cache_entry *e;
1732 if (dir_hnd->name_cache_size == 0) {
1733 return;
1736 if (dir_hnd->name_cache == NULL) {
1737 dir_hnd->name_cache = talloc_zero_array(dir_hnd,
1738 struct name_cache_entry,
1739 dir_hnd->name_cache_size);
1741 if (dir_hnd->name_cache == NULL) {
1742 return;
1746 dir_hnd->name_cache_index = (dir_hnd->name_cache_index+1) %
1747 dir_hnd->name_cache_size;
1748 e = &dir_hnd->name_cache[dir_hnd->name_cache_index];
1749 TALLOC_FREE(e->name);
1750 e->name = talloc_strdup(dir_hnd, name);
1751 e->offset = offset;
1754 /*******************************************************************
1755 Find an entry by name. Leave us at the offset after it.
1756 Don't check for veto or invisible files.
1757 ********************************************************************/
1759 static bool SearchDir(struct smb_Dir *dir_hnd, const char *name, long *poffset)
1761 int i;
1762 const char *entry = NULL;
1763 char *talloced = NULL;
1764 connection_struct *conn = dir_hnd->conn;
1766 /* Search back in the name cache. */
1767 if (dir_hnd->name_cache_size && dir_hnd->name_cache) {
1768 for (i = dir_hnd->name_cache_index; i >= 0; i--) {
1769 struct name_cache_entry *e = &dir_hnd->name_cache[i];
1770 if (e->name && (dir_hnd->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1771 *poffset = e->offset;
1772 SeekDir(dir_hnd, e->offset);
1773 return True;
1776 for (i = dir_hnd->name_cache_size - 1;
1777 i > dir_hnd->name_cache_index; i--) {
1778 struct name_cache_entry *e = &dir_hnd->name_cache[i];
1779 if (e->name && (dir_hnd->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1780 *poffset = e->offset;
1781 SeekDir(dir_hnd, e->offset);
1782 return True;
1787 /* Not found in the name cache. Rewind directory and start from scratch. */
1788 SMB_VFS_REWINDDIR(conn, dir_hnd->dir);
1789 dir_hnd->file_number = 0;
1790 *poffset = START_OF_DIRECTORY_OFFSET;
1791 while ((entry = ReadDirName(dir_hnd, poffset, NULL, &talloced))) {
1792 if (dir_hnd->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1793 TALLOC_FREE(talloced);
1794 return True;
1796 TALLOC_FREE(talloced);
1798 return False;
1801 struct files_below_forall_state {
1802 char *dirpath;
1803 ssize_t dirpath_len;
1804 int (*fn)(struct file_id fid, const struct share_mode_data *data,
1805 void *private_data);
1806 void *private_data;
1809 static int files_below_forall_fn(struct file_id fid,
1810 const struct share_mode_data *data,
1811 void *private_data)
1813 struct files_below_forall_state *state = private_data;
1814 char tmpbuf[PATH_MAX];
1815 char *fullpath, *to_free;
1816 ssize_t len;
1818 len = full_path_tos(data->servicepath, data->base_name,
1819 tmpbuf, sizeof(tmpbuf),
1820 &fullpath, &to_free);
1821 if (len == -1) {
1822 return 0;
1824 if (state->dirpath_len >= len) {
1826 * Filter files above dirpath
1828 goto out;
1830 if (fullpath[state->dirpath_len] != '/') {
1832 * Filter file that don't have a path separator at the end of
1833 * dirpath's length
1835 goto out;
1838 if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
1840 * Not a parent
1842 goto out;
1845 TALLOC_FREE(to_free);
1846 return state->fn(fid, data, state->private_data);
1848 out:
1849 TALLOC_FREE(to_free);
1850 return 0;
1853 static int files_below_forall(connection_struct *conn,
1854 const struct smb_filename *dir_name,
1855 int (*fn)(struct file_id fid,
1856 const struct share_mode_data *data,
1857 void *private_data),
1858 void *private_data)
1860 struct files_below_forall_state state = {
1861 .fn = fn,
1862 .private_data = private_data,
1864 int ret;
1865 char tmpbuf[PATH_MAX];
1866 char *to_free;
1868 state.dirpath_len = full_path_tos(conn->connectpath,
1869 dir_name->base_name,
1870 tmpbuf, sizeof(tmpbuf),
1871 &state.dirpath, &to_free);
1872 if (state.dirpath_len == -1) {
1873 return -1;
1876 ret = share_mode_forall(files_below_forall_fn, &state);
1877 TALLOC_FREE(to_free);
1878 return ret;
1881 struct have_file_open_below_state {
1882 bool found_one;
1885 static int have_file_open_below_fn(struct file_id fid,
1886 const struct share_mode_data *data,
1887 void *private_data)
1889 struct have_file_open_below_state *state = private_data;
1890 state->found_one = true;
1891 return 1;
1894 bool have_file_open_below(connection_struct *conn,
1895 const struct smb_filename *name)
1897 struct have_file_open_below_state state = {
1898 .found_one = false,
1900 int ret;
1902 if (!VALID_STAT(name->st)) {
1903 return false;
1905 if (!S_ISDIR(name->st.st_ex_mode)) {
1906 return false;
1909 ret = files_below_forall(conn, name, have_file_open_below_fn, &state);
1910 if (ret == -1) {
1911 return false;
1914 return state.found_one;
1917 /*****************************************************************
1918 Is this directory empty ?
1919 *****************************************************************/
1921 NTSTATUS can_delete_directory_fsp(files_struct *fsp)
1923 NTSTATUS status = NT_STATUS_OK;
1924 long dirpos = 0;
1925 const char *dname = NULL;
1926 char *talloced = NULL;
1927 struct connection_struct *conn = fsp->conn;
1928 struct smb_Dir *dir_hnd = NULL;
1930 status = OpenDir(
1931 talloc_tos(), conn, fsp->fsp_name, NULL, 0, &dir_hnd);
1932 if (!NT_STATUS_IS_OK(status)) {
1933 return status;
1936 while ((dname = ReadDirName(dir_hnd, &dirpos, NULL, &talloced))) {
1937 struct smb_filename *smb_dname_full = NULL;
1938 struct smb_filename *direntry_fname = NULL;
1939 char *fullname = NULL;
1940 int ret;
1942 if (ISDOT(dname) || (ISDOTDOT(dname))) {
1943 TALLOC_FREE(talloced);
1944 continue;
1946 if (IS_VETO_PATH(conn, dname)) {
1947 TALLOC_FREE(talloced);
1948 continue;
1951 fullname = talloc_asprintf(talloc_tos(),
1952 "%s/%s",
1953 fsp->fsp_name->base_name,
1954 dname);
1955 if (fullname == NULL) {
1956 status = NT_STATUS_NO_MEMORY;
1957 break;
1960 smb_dname_full = synthetic_smb_fname(talloc_tos(),
1961 fullname,
1962 NULL,
1963 NULL,
1964 fsp->fsp_name->twrp,
1965 fsp->fsp_name->flags);
1966 if (smb_dname_full == NULL) {
1967 TALLOC_FREE(talloced);
1968 TALLOC_FREE(fullname);
1969 status = NT_STATUS_NO_MEMORY;
1970 break;
1973 ret = SMB_VFS_LSTAT(conn, smb_dname_full);
1974 if (ret != 0) {
1975 status = map_nt_error_from_unix(errno);
1976 TALLOC_FREE(talloced);
1977 TALLOC_FREE(fullname);
1978 TALLOC_FREE(smb_dname_full);
1979 break;
1982 if (S_ISLNK(smb_dname_full->st.st_ex_mode)) {
1983 /* Could it be an msdfs link ? */
1984 if (lp_host_msdfs() &&
1985 lp_msdfs_root(SNUM(conn))) {
1986 struct smb_filename *smb_dname;
1987 smb_dname = synthetic_smb_fname(talloc_tos(),
1988 dname,
1989 NULL,
1990 &smb_dname_full->st,
1991 fsp->fsp_name->twrp,
1992 fsp->fsp_name->flags);
1993 if (smb_dname == NULL) {
1994 TALLOC_FREE(talloced);
1995 TALLOC_FREE(fullname);
1996 TALLOC_FREE(smb_dname_full);
1997 status = NT_STATUS_NO_MEMORY;
1998 break;
2000 if (is_msdfs_link(fsp, smb_dname)) {
2001 TALLOC_FREE(talloced);
2002 TALLOC_FREE(fullname);
2003 TALLOC_FREE(smb_dname_full);
2004 TALLOC_FREE(smb_dname);
2005 DBG_DEBUG("got msdfs link name %s "
2006 "- can't delete directory %s\n",
2007 dname,
2008 fsp_str_dbg(fsp));
2009 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
2010 break;
2012 TALLOC_FREE(smb_dname);
2014 /* Not a DFS link - could it be a dangling symlink ? */
2015 ret = SMB_VFS_STAT(conn, smb_dname_full);
2016 if (ret == -1 && (errno == ENOENT || errno == ELOOP)) {
2018 * Dangling symlink.
2019 * Allow if "delete veto files = yes"
2021 if (lp_delete_veto_files(SNUM(conn))) {
2022 TALLOC_FREE(talloced);
2023 TALLOC_FREE(fullname);
2024 TALLOC_FREE(smb_dname_full);
2025 continue;
2028 DBG_DEBUG("got symlink name %s - "
2029 "can't delete directory %s\n",
2030 dname,
2031 fsp_str_dbg(fsp));
2032 TALLOC_FREE(talloced);
2033 TALLOC_FREE(fullname);
2034 TALLOC_FREE(smb_dname_full);
2035 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
2036 break;
2039 /* Not a symlink, get a pathref. */
2040 status = synthetic_pathref(talloc_tos(),
2041 fsp,
2042 dname,
2043 NULL,
2044 &smb_dname_full->st,
2045 fsp->fsp_name->twrp,
2046 fsp->fsp_name->flags,
2047 &direntry_fname);
2048 if (!NT_STATUS_IS_OK(status)) {
2049 status = map_nt_error_from_unix(errno);
2050 TALLOC_FREE(talloced);
2051 TALLOC_FREE(fullname);
2052 TALLOC_FREE(smb_dname_full);
2053 break;
2056 if (!is_visible_fsp(direntry_fname->fsp)) {
2058 * Hidden file.
2059 * Allow if "delete veto files = yes"
2061 if (lp_delete_veto_files(SNUM(conn))) {
2062 TALLOC_FREE(talloced);
2063 TALLOC_FREE(fullname);
2064 TALLOC_FREE(smb_dname_full);
2065 TALLOC_FREE(direntry_fname);
2066 continue;
2070 TALLOC_FREE(talloced);
2071 TALLOC_FREE(fullname);
2072 TALLOC_FREE(smb_dname_full);
2073 TALLOC_FREE(direntry_fname);
2075 DBG_DEBUG("got name %s - can't delete\n", dname);
2076 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
2077 break;
2079 TALLOC_FREE(talloced);
2080 TALLOC_FREE(dir_hnd);
2082 if (!NT_STATUS_IS_OK(status)) {
2083 return status;
2086 if (!(fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) &&
2087 lp_strict_rename(SNUM(conn)) &&
2088 have_file_open_below(fsp->conn, fsp->fsp_name))
2090 return NT_STATUS_ACCESS_DENIED;
2093 return NT_STATUS_OK;