smbd: can_delete_directory_fsp() returns NTSTATUS
[Samba.git] / source3 / smbd / dir.c
blobc9cc6b73e584b30d967ed1e6c7b0f1d9569830df
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 uint16_t spid;
71 struct connection_struct *conn;
72 struct smb_Dir *dir_hnd;
73 bool expect_close;
74 char *wcard;
75 uint32_t attr;
76 struct smb_filename *smb_dname;
77 bool has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
78 bool did_stat; /* Optimisation for non-wcard searches. */
79 bool priv; /* Directory handle opened with privilege. */
80 uint32_t counter;
81 struct memcache *dptr_cache;
84 static NTSTATUS OpenDir_fsp(
85 TALLOC_CTX *mem_ctx,
86 connection_struct *conn,
87 files_struct *fsp,
88 const char *mask,
89 uint32_t attr,
90 struct smb_Dir **_dir_hnd);
92 static void DirCacheAdd(struct smb_Dir *dir_hnd, const char *name, long offset);
94 static int smb_Dir_destructor(struct smb_Dir *dir_hnd);
96 static bool SearchDir(struct smb_Dir *dir_hnd, const char *name, long *poffset);
98 #define INVALID_DPTR_KEY (-3)
100 /****************************************************************************
101 Initialise the dir bitmap.
102 ****************************************************************************/
104 bool init_dptrs(struct smbd_server_connection *sconn)
106 if (sconn->searches.dptr_bmap) {
107 return true;
110 sconn->searches.dptr_bmap = bitmap_talloc(
111 sconn, MAX_DIRECTORY_HANDLES);
113 if (sconn->searches.dptr_bmap == NULL) {
114 return false;
117 return true;
120 /****************************************************************************
121 Get the struct dptr_struct for a dir index.
122 ****************************************************************************/
124 static struct dptr_struct *dptr_get(struct smbd_server_connection *sconn,
125 int key)
127 struct dptr_struct *dptr;
129 for (dptr = sconn->searches.dirptrs; dptr != NULL; dptr = dptr->next) {
130 if(dptr->dnum != key) {
131 continue;
133 DLIST_PROMOTE(sconn->searches.dirptrs, dptr);
134 return dptr;
136 return(NULL);
139 /****************************************************************************
140 Get the dir path for a dir index.
141 ****************************************************************************/
143 const char *dptr_path(struct smbd_server_connection *sconn, int key)
145 struct dptr_struct *dptr = dptr_get(sconn, key);
146 if (dptr)
147 return(dptr->smb_dname->base_name);
148 return(NULL);
151 /****************************************************************************
152 Get the dir wcard for a dir index.
153 ****************************************************************************/
155 const char *dptr_wcard(struct smbd_server_connection *sconn, int key)
157 struct dptr_struct *dptr = dptr_get(sconn, key);
158 if (dptr)
159 return(dptr->wcard);
160 return(NULL);
163 /****************************************************************************
164 Get the dir attrib for a dir index.
165 ****************************************************************************/
167 uint16_t dptr_attr(struct smbd_server_connection *sconn, int key)
169 struct dptr_struct *dptr = dptr_get(sconn, key);
170 if (dptr)
171 return(dptr->attr);
172 return(0);
175 /****************************************************************************
176 Close all dptrs for a cnum.
177 ****************************************************************************/
179 void dptr_closecnum(connection_struct *conn)
181 struct dptr_struct *dptr, *next;
182 struct smbd_server_connection *sconn = conn->sconn;
184 if (sconn == NULL) {
185 return;
188 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
189 next = dptr->next;
190 if (dptr->conn == conn) {
192 * Need to make a copy, "dptr" will be gone
193 * after close_file_free() returns
195 struct files_struct *fsp = dptr->dir_hnd->fsp;
196 close_file_free(NULL, &fsp, NORMAL_CLOSE);
201 /****************************************************************************
202 Create a new dir ptr. If the flag old_handle is true then we must allocate
203 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
204 one byte long. If old_handle is false we allocate from the range
205 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
206 a directory handle is never zero.
207 wcard must not be zero.
208 ****************************************************************************/
210 NTSTATUS dptr_create(connection_struct *conn,
211 struct smb_request *req,
212 files_struct *fsp,
213 bool old_handle,
214 bool expect_close,
215 uint16_t spid,
216 const char *wcard,
217 uint32_t attr,
218 struct dptr_struct **dptr_ret)
220 struct smbd_server_connection *sconn = conn->sconn;
221 struct dptr_struct *dptr = NULL;
222 struct smb_Dir *dir_hnd = NULL;
223 NTSTATUS status;
225 DBG_INFO("dir=%s\n", fsp_str_dbg(fsp));
227 if (sconn == NULL) {
228 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
229 return NT_STATUS_INTERNAL_ERROR;
232 if (!wcard) {
233 return NT_STATUS_INVALID_PARAMETER;
236 if (!(fsp->access_mask & SEC_DIR_LIST)) {
237 DBG_INFO("dptr_create: directory %s "
238 "not open for LIST access\n",
239 fsp_str_dbg(fsp));
240 return NT_STATUS_ACCESS_DENIED;
242 status = OpenDir_fsp(NULL, conn, fsp, wcard, attr, &dir_hnd);
243 if (!NT_STATUS_IS_OK(status)) {
244 return status;
247 dptr = talloc_zero(NULL, struct dptr_struct);
248 if(!dptr) {
249 DEBUG(0,("talloc fail in dptr_create.\n"));
250 TALLOC_FREE(dir_hnd);
251 return NT_STATUS_NO_MEMORY;
254 dptr->smb_dname = cp_smb_filename(dptr, fsp->fsp_name);
255 if (dptr->smb_dname == NULL) {
256 TALLOC_FREE(dptr);
257 TALLOC_FREE(dir_hnd);
258 return NT_STATUS_NO_MEMORY;
260 dptr->conn = conn;
261 dptr->dir_hnd = dir_hnd;
262 dptr->spid = spid;
263 dptr->expect_close = expect_close;
264 dptr->wcard = talloc_strdup(dptr, wcard);
265 if (!dptr->wcard) {
266 TALLOC_FREE(dptr);
267 TALLOC_FREE(dir_hnd);
268 return NT_STATUS_NO_MEMORY;
270 if ((req != NULL && req->posix_pathnames) ||
271 (wcard[0] == '.' && wcard[1] == 0)) {
272 dptr->has_wild = True;
273 } else {
274 dptr->has_wild = ms_has_wild(dptr->wcard);
277 dptr->attr = attr;
279 if (sconn->using_smb2) {
280 goto done;
283 if(old_handle) {
286 * This is an old-style SMBsearch request. Ensure the
287 * value we return will fit in the range 1-255.
290 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
292 if(dptr->dnum == -1 || dptr->dnum > 254) {
293 DBG_ERR("returned %d: Error - all old "
294 "dirptrs in use ?\n",
295 dptr->dnum);
296 TALLOC_FREE(dptr);
297 TALLOC_FREE(dir_hnd);
298 return NT_STATUS_TOO_MANY_OPENED_FILES;
300 } else {
303 * This is a new-style trans2 request. Allocate from
304 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
307 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
309 if(dptr->dnum == -1 || dptr->dnum < 255) {
310 DBG_ERR("returned %d: Error - all new "
311 "dirptrs in use ?\n",
312 dptr->dnum);
313 TALLOC_FREE(dptr);
314 TALLOC_FREE(dir_hnd);
315 return NT_STATUS_TOO_MANY_OPENED_FILES;
319 bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
321 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
323 DLIST_ADD(sconn->searches.dirptrs, dptr);
325 done:
326 DBG_INFO("creating new dirptr [%d] for path [%s], expect_close = %d\n",
327 dptr->dnum, fsp_str_dbg(fsp), expect_close);
329 *dptr_ret = dptr;
331 return NT_STATUS_OK;
335 /****************************************************************************
336 Wrapper functions to access the lower level directory handles.
337 ****************************************************************************/
339 void dptr_CloseDir(files_struct *fsp)
341 struct smbd_server_connection *sconn = NULL;
343 if (fsp->dptr == NULL) {
344 return;
346 sconn = fsp->dptr->conn->sconn;
349 * The destructor for the struct smb_Dir (fsp->dptr->dir_hnd)
350 * now handles all resource deallocation.
353 DBG_INFO("closing dptr key %d\n", fsp->dptr->dnum);
355 if (sconn != NULL && !sconn->using_smb2) {
356 DLIST_REMOVE(sconn->searches.dirptrs, fsp->dptr);
359 * Free the dnum in the bitmap. Remember the dnum value is
360 * always biased by one with respect to the bitmap.
363 if (!bitmap_query(sconn->searches.dptr_bmap,
364 fsp->dptr->dnum - 1))
366 DBG_ERR("closing dnum = %d and bitmap not set !\n",
367 fsp->dptr->dnum);
370 bitmap_clear(sconn->searches.dptr_bmap, fsp->dptr->dnum - 1);
373 TALLOC_FREE(fsp->dptr->dir_hnd);
374 TALLOC_FREE(fsp->dptr);
377 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
379 SeekDir(dptr->dir_hnd, offset);
382 long dptr_TellDir(struct dptr_struct *dptr)
384 return TellDir(dptr->dir_hnd);
387 bool dptr_has_wild(struct dptr_struct *dptr)
389 return dptr->has_wild;
392 int dptr_dnum(struct dptr_struct *dptr)
394 return dptr->dnum;
397 bool dptr_get_priv(struct dptr_struct *dptr)
399 return dptr->priv;
402 void dptr_set_priv(struct dptr_struct *dptr)
404 dptr->priv = true;
407 bool dptr_case_sensitive(struct dptr_struct *dptr)
409 return dptr->dir_hnd->case_sensitive;
412 /****************************************************************************
413 Return the next visible file name, skipping veto'd and invisible files.
414 ****************************************************************************/
416 static char *dptr_ReadDirName(TALLOC_CTX *ctx,
417 struct dptr_struct *dptr,
418 long *poffset,
419 SMB_STRUCT_STAT *pst)
421 struct smb_filename smb_fname_base;
422 char *name = NULL;
423 const char *name_temp = NULL;
424 char *talloced = NULL;
425 char *pathreal = NULL;
426 char *found_name = NULL;
427 int ret;
429 SET_STAT_INVALID(*pst);
431 if (dptr->has_wild || dptr->did_stat) {
432 name_temp = ReadDirName(dptr->dir_hnd, poffset, pst,
433 &talloced);
434 if (name_temp == NULL) {
435 return NULL;
437 if (talloced != NULL) {
438 return talloc_move(ctx, &talloced);
440 return talloc_strdup(ctx, name_temp);
443 /* If poffset is -1 then we know we returned this name before and we
444 * have no wildcards. We're at the end of the directory. */
445 if (*poffset == END_OF_DIRECTORY_OFFSET) {
446 return NULL;
449 /* We know the stored wcard contains no wildcard characters.
450 * See if we can match with a stat call. If we can't, then set
451 * did_stat to true to ensure we only do this once and keep
452 * searching. */
454 dptr->did_stat = true;
456 if (VALID_STAT(*pst)) {
457 name = talloc_strdup(ctx, dptr->wcard);
458 goto ret;
461 pathreal = talloc_asprintf(ctx,
462 "%s/%s",
463 dptr->smb_dname->base_name,
464 dptr->wcard);
465 if (!pathreal)
466 return NULL;
468 /* Create an smb_filename with stream_name == NULL. */
469 smb_fname_base = (struct smb_filename) {
470 .base_name = pathreal,
471 .flags = dptr->dir_hnd->fsp->fsp_name->flags,
472 .twrp = dptr->smb_dname->twrp,
475 if (vfs_stat(dptr->conn, &smb_fname_base) == 0) {
476 *pst = smb_fname_base.st;
477 name = talloc_strdup(ctx, dptr->wcard);
478 goto clean;
479 } else {
480 /* If we get any other error than ENOENT or ENOTDIR
481 then the file exists we just can't stat it. */
482 if (errno != ENOENT && errno != ENOTDIR) {
483 name = talloc_strdup(ctx, dptr->wcard);
484 goto clean;
488 /* Stat failed. We know this is authoritative if we are
489 * providing case sensitive semantics or the underlying
490 * filesystem is case sensitive.
492 if (dptr->dir_hnd->case_sensitive ||
493 !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
495 goto clean;
499 * Try case-insensitive stat if the fs has the ability. This avoids
500 * scanning the whole directory.
502 ret = SMB_VFS_GET_REAL_FILENAME(dptr->conn,
503 dptr->smb_dname,
504 dptr->wcard,
505 ctx,
506 &found_name);
507 if (ret == 0) {
508 name = found_name;
509 goto clean;
510 } else if (errno == ENOENT) {
511 /* The case-insensitive lookup was authoritative. */
512 goto clean;
515 TALLOC_FREE(pathreal);
517 name_temp = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced);
518 if (name_temp == NULL) {
519 return NULL;
521 if (talloced != NULL) {
522 return talloc_move(ctx, &talloced);
524 return talloc_strdup(ctx, name_temp);
526 clean:
527 TALLOC_FREE(pathreal);
528 ret:
529 /* We need to set the underlying dir_hnd offset to -1
530 * also as this function is usually called with the
531 * output from TellDir. */
532 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
533 return name;
536 /****************************************************************************
537 Search for a file by name.
538 ****************************************************************************/
540 bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
542 SET_STAT_INVALID(*pst);
544 if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
545 /* This is a singleton directory and we're already at the end. */
546 *poffset = END_OF_DIRECTORY_OFFSET;
547 return False;
550 return SearchDir(dptr->dir_hnd, name, poffset);
553 /****************************************************************************
554 Map a native directory offset to a 32-bit cookie.
555 ****************************************************************************/
557 static uint32_t map_dir_offset_to_wire(struct dptr_struct *dptr, long offset)
559 DATA_BLOB key;
560 DATA_BLOB val;
562 if (offset == END_OF_DIRECTORY_OFFSET) {
563 return WIRE_END_OF_DIRECTORY_OFFSET;
564 } else if(offset == START_OF_DIRECTORY_OFFSET) {
565 return WIRE_START_OF_DIRECTORY_OFFSET;
566 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
567 return WIRE_DOT_DOT_DIRECTORY_OFFSET;
569 if (sizeof(long) == 4) {
570 /* 32-bit machine. We can cheat... */
571 return (uint32_t)offset;
573 if (dptr->dptr_cache == NULL) {
574 /* Lazy initialize cache. */
575 dptr->dptr_cache = memcache_init(dptr, 0);
576 if (dptr->dptr_cache == NULL) {
577 return WIRE_END_OF_DIRECTORY_OFFSET;
579 } else {
580 /* Have we seen this offset before ? */
581 key.data = (void *)&offset;
582 key.length = sizeof(offset);
583 if (memcache_lookup(dptr->dptr_cache,
584 SMB1_SEARCH_OFFSET_MAP,
585 key,
586 &val)) {
587 uint32_t wire_offset;
588 SMB_ASSERT(val.length == sizeof(wire_offset));
589 memcpy(&wire_offset, val.data, sizeof(wire_offset));
590 DEBUG(10,("found wire %u <-> offset %ld\n",
591 (unsigned int)wire_offset,
592 (long)offset));
593 return wire_offset;
596 /* Allocate a new wire cookie. */
597 do {
598 dptr->counter++;
599 } while (dptr->counter == WIRE_START_OF_DIRECTORY_OFFSET ||
600 dptr->counter == WIRE_END_OF_DIRECTORY_OFFSET ||
601 dptr->counter == WIRE_DOT_DOT_DIRECTORY_OFFSET);
602 /* Store it in the cache. */
603 key.data = (void *)&offset;
604 key.length = sizeof(offset);
605 val.data = (void *)&dptr->counter;
606 val.length = sizeof(dptr->counter); /* MUST BE uint32_t ! */
607 memcache_add(dptr->dptr_cache,
608 SMB1_SEARCH_OFFSET_MAP,
609 key,
610 val);
611 /* And the reverse mapping for lookup from
612 map_wire_to_dir_offset(). */
613 memcache_add(dptr->dptr_cache,
614 SMB1_SEARCH_OFFSET_MAP,
615 val,
616 key);
617 DEBUG(10,("stored wire %u <-> offset %ld\n",
618 (unsigned int)dptr->counter,
619 (long)offset));
620 return dptr->counter;
623 /****************************************************************************
624 Fill the 5 byte server reserved dptr field.
625 ****************************************************************************/
627 bool dptr_fill(struct smbd_server_connection *sconn,
628 char *buf1,unsigned int key)
630 unsigned char *buf = (unsigned char *)buf1;
631 struct dptr_struct *dptr = dptr_get(sconn, key);
632 uint32_t wire_offset;
633 if (!dptr) {
634 DEBUG(1,("filling null dirptr %d\n",key));
635 return(False);
637 wire_offset = map_dir_offset_to_wire(dptr,TellDir(dptr->dir_hnd));
638 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
639 (long)dptr->dir_hnd,(int)wire_offset));
640 buf[0] = key;
641 SIVAL(buf,1,wire_offset);
642 return(True);
645 /****************************************************************************
646 Map a 32-bit wire cookie to a native directory offset.
647 ****************************************************************************/
649 static long map_wire_to_dir_offset(struct dptr_struct *dptr, uint32_t wire_offset)
651 DATA_BLOB key;
652 DATA_BLOB val;
654 if (wire_offset == WIRE_END_OF_DIRECTORY_OFFSET) {
655 return END_OF_DIRECTORY_OFFSET;
656 } else if(wire_offset == WIRE_START_OF_DIRECTORY_OFFSET) {
657 return START_OF_DIRECTORY_OFFSET;
658 } else if (wire_offset == WIRE_DOT_DOT_DIRECTORY_OFFSET) {
659 return DOT_DOT_DIRECTORY_OFFSET;
661 if (sizeof(long) == 4) {
662 /* 32-bit machine. We can cheat... */
663 return (long)wire_offset;
665 if (dptr->dptr_cache == NULL) {
666 /* Logic error, cache should be initialized. */
667 return END_OF_DIRECTORY_OFFSET;
669 key.data = (void *)&wire_offset;
670 key.length = sizeof(wire_offset);
671 if (memcache_lookup(dptr->dptr_cache,
672 SMB1_SEARCH_OFFSET_MAP,
673 key,
674 &val)) {
675 /* Found mapping. */
676 long offset;
677 SMB_ASSERT(val.length == sizeof(offset));
678 memcpy(&offset, val.data, sizeof(offset));
679 DEBUG(10,("lookup wire %u <-> offset %ld\n",
680 (unsigned int)wire_offset,
681 (long)offset));
682 return offset;
684 return END_OF_DIRECTORY_OFFSET;
687 /****************************************************************************
688 Return the associated fsp and seek the dir_hnd on it it given the 5 byte
689 server field.
690 ****************************************************************************/
692 files_struct *dptr_fetch_fsp(struct smbd_server_connection *sconn,
693 char *buf, int *num)
695 unsigned int key = *(unsigned char *)buf;
696 struct dptr_struct *dptr = dptr_get(sconn, key);
697 uint32_t wire_offset;
698 long seekoff;
700 if (dptr == NULL) {
701 DEBUG(3,("fetched null dirptr %d\n",key));
702 return(NULL);
704 *num = key;
705 wire_offset = IVAL(buf,1);
706 seekoff = map_wire_to_dir_offset(dptr, wire_offset);
707 SeekDir(dptr->dir_hnd,seekoff);
708 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
709 key, dptr->smb_dname->base_name, (int)seekoff));
710 return dptr->dir_hnd->fsp;
713 struct files_struct *dir_hnd_fetch_fsp(struct smb_Dir *dir_hnd)
715 return dir_hnd->fsp;
718 /****************************************************************************
719 Fetch the fsp associated with the dptr_num.
720 ****************************************************************************/
722 files_struct *dptr_fetch_lanman2_fsp(struct smbd_server_connection *sconn,
723 int dptr_num)
725 struct dptr_struct *dptr = dptr_get(sconn, dptr_num);
726 if (dptr == NULL) {
727 return NULL;
729 DBG_NOTICE("fetching dirptr %d for path %s\n",
730 dptr_num,
731 dptr->smb_dname->base_name);
732 return dptr->dir_hnd->fsp;
735 static bool mangle_mask_match(connection_struct *conn,
736 const char *filename,
737 const char *mask)
739 char mname[13];
741 if (!name_to_8_3(filename,mname,False,conn->params)) {
742 return False;
744 return mask_match_search(mname,mask,False);
747 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
748 struct dptr_struct *dirptr,
749 const char *mask,
750 uint32_t dirtype,
751 bool dont_descend,
752 bool ask_sharemode,
753 bool get_dosmode_in,
754 bool (*match_fn)(TALLOC_CTX *ctx,
755 void *private_data,
756 const char *dname,
757 const char *mask,
758 char **_fname),
759 bool (*mode_fn)(TALLOC_CTX *ctx,
760 void *private_data,
761 struct files_struct *dirfsp,
762 struct smb_filename *atname,
763 struct smb_filename *smb_fname,
764 bool get_dosmode,
765 uint32_t *_mode),
766 void *private_data,
767 char **_fname,
768 struct smb_filename **_smb_fname,
769 uint32_t *_mode,
770 long *_prev_offset)
772 connection_struct *conn = dirptr->conn;
773 size_t slashlen;
774 size_t pathlen;
775 const char *dpath = dirptr->smb_dname->base_name;
776 bool dirptr_path_is_dot = ISDOT(dpath);
777 NTSTATUS status;
778 int ret;
780 *_smb_fname = NULL;
781 *_mode = 0;
783 pathlen = strlen(dpath);
784 slashlen = ( dpath[pathlen-1] != '/') ? 1 : 0;
786 while (true) {
787 long cur_offset;
788 long prev_offset;
789 SMB_STRUCT_STAT sbuf = { 0 };
790 char *dname = NULL;
791 bool isdots;
792 char *fname = NULL;
793 char *pathreal = NULL;
794 struct smb_filename *atname = NULL;
795 struct smb_filename *smb_fname = NULL;
796 uint32_t mode = 0;
797 bool check_dfs_symlink = false;
798 bool get_dosmode = get_dosmode_in;
799 bool ok;
801 cur_offset = dptr_TellDir(dirptr);
802 prev_offset = cur_offset;
803 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
805 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
806 (long)dirptr, cur_offset));
808 if (dname == NULL) {
809 return false;
812 isdots = (ISDOT(dname) || ISDOTDOT(dname));
813 if (dont_descend && !isdots) {
814 TALLOC_FREE(dname);
815 continue;
818 if (IS_VETO_PATH(conn, dname)) {
819 TALLOC_FREE(dname);
820 continue;
824 * fname may get mangled, dname is never mangled.
825 * Whenever we're accessing the filesystem we use
826 * pathreal which is composed from dname.
829 ok = match_fn(ctx, private_data, dname, mask, &fname);
830 if (!ok) {
831 TALLOC_FREE(dname);
832 continue;
836 * This used to be
837 * pathreal = talloc_asprintf(ctx, "%s%s%s", dirptr->path,
838 * needslash?"/":"", dname);
839 * but this was measurably slower than doing the memcpy.
842 pathreal = talloc_array(
843 ctx, char,
844 pathlen + slashlen + talloc_get_size(dname));
845 if (!pathreal) {
846 TALLOC_FREE(dname);
847 TALLOC_FREE(fname);
848 return false;
852 * We don't want to pass ./xxx to modules below us so don't
853 * add the path if it is just . by itself.
855 if (dirptr_path_is_dot) {
856 memcpy(pathreal, dname, talloc_get_size(dname));
857 } else {
858 memcpy(pathreal, dpath, pathlen);
859 pathreal[pathlen] = '/';
860 memcpy(pathreal + slashlen + pathlen, dname,
861 talloc_get_size(dname));
864 /* Create smb_fname with NULL stream_name. */
865 smb_fname = synthetic_smb_fname(talloc_tos(),
866 pathreal,
867 NULL,
868 &sbuf,
869 dirptr->smb_dname->twrp,
870 dirptr->smb_dname->flags);
871 TALLOC_FREE(pathreal);
872 if (smb_fname == NULL) {
873 TALLOC_FREE(dname);
874 TALLOC_FREE(fname);
875 return false;
878 if (!VALID_STAT(smb_fname->st)) {
880 * If stat() fails with ENOENT it might be a
881 * msdfs-symlink in Windows context, this is checked
882 * below, for now we just want to fill stat info as good
883 * as we can.
885 ret = vfs_stat(conn, smb_fname);
886 if (ret != 0 && errno != ENOENT) {
887 TALLOC_FREE(smb_fname);
888 TALLOC_FREE(dname);
889 TALLOC_FREE(fname);
890 continue;
894 /* Create smb_fname with NULL stream_name. */
895 atname = synthetic_smb_fname(talloc_tos(),
896 dname,
897 NULL,
898 &smb_fname->st,
899 dirptr->smb_dname->twrp,
900 dirptr->smb_dname->flags);
901 if (atname == NULL) {
902 TALLOC_FREE(dname);
903 TALLOC_FREE(fname);
904 TALLOC_FREE(smb_fname);
905 return false;
909 * openat_pathref_fsp() will return
910 * NT_STATUS_OBJECT_NAME_NOT_FOUND in non-POSIX context when
911 * hitting a dangling symlink. It may be a DFS symlink, this is
912 * checked below by the mode_fn() call, so we have to allow this
913 * here.
915 * NT_STATUS_STOPPED_ON_SYMLINK is returned in POSIX context
916 * when hitting a symlink and ensures we always return directory
917 * entries that are symlinks in POSIX context.
919 status = openat_pathref_fsp(dirptr->dir_hnd->fsp, atname);
920 if (!NT_STATUS_IS_OK(status) &&
921 !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND))
923 TALLOC_FREE(atname);
924 TALLOC_FREE(dname);
925 TALLOC_FREE(fname);
926 TALLOC_FREE(smb_fname);
927 continue;
928 } else if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
929 if (!(atname->flags & SMB_FILENAME_POSIX_PATH)) {
930 check_dfs_symlink = true;
933 * Check if it's a symlink. We only want to return this
934 * if it's a DFS symlink or in POSIX mode. Disable
935 * getting dosmode in the mode_fn() and prime the mode
936 * as FILE_ATTRIBUTE_NORMAL.
938 mode = FILE_ATTRIBUTE_NORMAL;
939 get_dosmode = false;
942 status = move_smb_fname_fsp_link(smb_fname, atname);
943 if (!NT_STATUS_IS_OK(status)) {
944 DBG_WARNING("Failed to move pathref for [%s]: %s\n",
945 smb_fname_str_dbg(smb_fname),
946 nt_errstr(status));
947 TALLOC_FREE(atname);
948 TALLOC_FREE(smb_fname);
949 TALLOC_FREE(dname);
950 TALLOC_FREE(fname);
951 continue;
954 if (!is_visible_fsp(smb_fname->fsp)) {
955 TALLOC_FREE(atname);
956 TALLOC_FREE(smb_fname);
957 TALLOC_FREE(dname);
958 TALLOC_FREE(fname);
959 continue;
963 * Don't leak metadata about the containing
964 * directory of the share.
966 if (dirptr_path_is_dot && ISDOTDOT(dname)) {
968 * Making a copy here, then freeing
969 * the original will close the smb_fname->fsp.
971 struct smb_filename *tmp_smb_fname =
972 cp_smb_filename(ctx, smb_fname);
974 if (tmp_smb_fname == NULL) {
975 TALLOC_FREE(atname);
976 TALLOC_FREE(smb_fname);
977 TALLOC_FREE(dname);
978 TALLOC_FREE(fname);
979 return false;
981 TALLOC_FREE(smb_fname);
982 smb_fname = tmp_smb_fname;
983 mode = FILE_ATTRIBUTE_DIRECTORY;
984 get_dosmode = false;
987 ok = mode_fn(ctx,
988 private_data,
989 dirptr->dir_hnd->fsp,
990 atname,
991 smb_fname,
992 get_dosmode,
993 &mode);
994 if (!ok) {
995 TALLOC_FREE(atname);
996 TALLOC_FREE(smb_fname);
997 TALLOC_FREE(dname);
998 TALLOC_FREE(fname);
999 continue;
1002 TALLOC_FREE(atname);
1005 * The only valid cases where we return the directory entry if
1006 * it's a symlink are:
1008 * 1. POSIX context, always return it, or
1010 * 2. a DFS symlink where the mode_fn() call above has verified
1011 * this and set mode to FILE_ATTRIBUTE_REPARSE_POINT.
1013 if (check_dfs_symlink &&
1014 !(mode & FILE_ATTRIBUTE_REPARSE_POINT))
1016 TALLOC_FREE(smb_fname);
1017 TALLOC_FREE(dname);
1018 TALLOC_FREE(fname);
1019 continue;
1022 if (!dir_check_ftype(mode, dirtype)) {
1023 DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
1024 fname, (unsigned int)mode, (unsigned int)dirtype));
1025 TALLOC_FREE(smb_fname);
1026 TALLOC_FREE(dname);
1027 TALLOC_FREE(fname);
1028 continue;
1031 if (ask_sharemode && !S_ISDIR(smb_fname->st.st_ex_mode)) {
1032 struct timespec write_time_ts;
1033 struct file_id fileid;
1035 fileid = vfs_file_id_from_sbuf(conn,
1036 &smb_fname->st);
1037 get_file_infos(fileid, 0, NULL, &write_time_ts);
1038 if (!is_omit_timespec(&write_time_ts)) {
1039 update_stat_ex_mtime(&smb_fname->st,
1040 write_time_ts);
1044 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
1045 "fname=%s (%s)\n",
1046 mask, smb_fname_str_dbg(smb_fname),
1047 dname, fname));
1049 if (!conn->sconn->using_smb2) {
1051 * The dircache is only needed for SMB1 because SMB1
1052 * uses a name for the resume wheras SMB2 always
1053 * continues from the next position (unless it's told to
1054 * restart or close-and-reopen the listing).
1056 DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
1059 TALLOC_FREE(dname);
1061 *_smb_fname = talloc_move(ctx, &smb_fname);
1062 if (*_smb_fname == NULL) {
1063 return false;
1065 *_fname = fname;
1066 *_mode = mode;
1067 *_prev_offset = prev_offset;
1069 return true;
1072 return false;
1075 /****************************************************************************
1076 Get an 8.3 directory entry.
1077 ****************************************************************************/
1079 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
1080 void *private_data,
1081 const char *dname,
1082 const char *mask,
1083 char **_fname)
1085 connection_struct *conn = (connection_struct *)private_data;
1087 if ((strcmp(mask,"*.*") == 0) ||
1088 mask_match_search(dname, mask, false) ||
1089 mangle_mask_match(conn, dname, mask)) {
1090 char mname[13];
1091 const char *fname;
1093 * Ensure we can push the original name as UCS2. If
1094 * not, then just don't return this name.
1096 NTSTATUS status;
1097 size_t ret_len = 0;
1098 size_t len = (strlen(dname) + 2) * 4; /* Allow enough space. */
1099 uint8_t *tmp = talloc_array(talloc_tos(),
1100 uint8_t,
1101 len);
1103 status = srvstr_push(NULL,
1104 FLAGS2_UNICODE_STRINGS,
1105 tmp,
1106 dname,
1107 len,
1108 STR_TERMINATE,
1109 &ret_len);
1111 TALLOC_FREE(tmp);
1113 if (!NT_STATUS_IS_OK(status)) {
1114 return false;
1117 if (!mangle_is_8_3(dname, false, conn->params)) {
1118 bool ok = name_to_8_3(dname, mname, false,
1119 conn->params);
1120 if (!ok) {
1121 return false;
1123 fname = mname;
1124 } else {
1125 fname = dname;
1128 *_fname = talloc_strdup(ctx, fname);
1129 if (*_fname == NULL) {
1130 return false;
1133 return true;
1136 return false;
1139 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1140 void *private_data,
1141 struct files_struct *dirfsp,
1142 struct smb_filename *atname,
1143 struct smb_filename *smb_fname,
1144 bool get_dosmode,
1145 uint32_t *_mode)
1147 connection_struct *conn = (connection_struct *)private_data;
1149 if (!VALID_STAT(smb_fname->st)) {
1150 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1151 DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1152 "Couldn't stat [%s]. Error "
1153 "= %s\n",
1154 smb_fname_str_dbg(smb_fname),
1155 strerror(errno)));
1156 return false;
1160 if (get_dosmode) {
1161 *_mode = fdos_mode(smb_fname->fsp);
1162 smb_fname->st = smb_fname->fsp->fsp_name->st;
1164 return true;
1167 bool get_dir_entry(TALLOC_CTX *ctx,
1168 struct dptr_struct *dirptr,
1169 const char *mask,
1170 uint32_t dirtype,
1171 char **_fname,
1172 off_t *_size,
1173 uint32_t *_mode,
1174 struct timespec *_date,
1175 bool check_descend,
1176 bool ask_sharemode)
1178 connection_struct *conn = dirptr->conn;
1179 char *fname = NULL;
1180 struct smb_filename *smb_fname = NULL;
1181 uint32_t mode = 0;
1182 long prev_offset;
1183 bool ok;
1185 ok = smbd_dirptr_get_entry(ctx,
1186 dirptr,
1187 mask,
1188 dirtype,
1189 check_descend,
1190 ask_sharemode,
1191 true,
1192 smbd_dirptr_8_3_match_fn,
1193 smbd_dirptr_8_3_mode_fn,
1194 conn,
1195 &fname,
1196 &smb_fname,
1197 &mode,
1198 &prev_offset);
1199 if (!ok) {
1200 return false;
1203 *_fname = talloc_move(ctx, &fname);
1204 *_size = smb_fname->st.st_ex_size;
1205 *_mode = mode;
1206 *_date = smb_fname->st.st_ex_mtime;
1207 TALLOC_FREE(smb_fname);
1208 return true;
1211 /*******************************************************************
1212 Check to see if a user can read an fsp . This is only approximate,
1213 it is used as part of the "hide unreadable" option. Don't
1214 use it for anything security sensitive.
1215 ********************************************************************/
1217 static bool user_can_read_fsp(struct files_struct *fsp)
1219 NTSTATUS status;
1220 uint32_t rejected_share_access = 0;
1221 uint32_t rejected_mask = 0;
1222 struct security_descriptor *sd = NULL;
1223 uint32_t access_mask = FILE_READ_DATA|
1224 FILE_READ_EA|
1225 FILE_READ_ATTRIBUTES|
1226 SEC_STD_READ_CONTROL;
1229 * Never hide files from the root user.
1230 * We use (uid_t)0 here not sec_initial_uid()
1231 * as make test uses a single user context.
1234 if (get_current_uid(fsp->conn) == (uid_t)0) {
1235 return true;
1239 * We can't directly use smbd_check_access_rights_fsp()
1240 * here, as this implicitly grants FILE_READ_ATTRIBUTES
1241 * which the Windows access-based-enumeration code
1242 * explicitly checks for on the file security descriptor.
1243 * See bug:
1245 * https://bugzilla.samba.org/show_bug.cgi?id=10252
1247 * and the smb2.acl2.ACCESSBASED test for details.
1250 rejected_share_access = access_mask & ~(fsp->conn->share_access);
1251 if (rejected_share_access) {
1252 DBG_DEBUG("rejected share access 0x%x "
1253 "on %s (0x%x)\n",
1254 (unsigned int)access_mask,
1255 fsp_str_dbg(fsp),
1256 (unsigned int)rejected_share_access);
1257 return false;
1260 status = SMB_VFS_FGET_NT_ACL(fsp,
1261 (SECINFO_OWNER |
1262 SECINFO_GROUP |
1263 SECINFO_DACL),
1264 talloc_tos(),
1265 &sd);
1267 if (!NT_STATUS_IS_OK(status)) {
1268 DBG_DEBUG("Could not get acl "
1269 "on %s: %s\n",
1270 fsp_str_dbg(fsp),
1271 nt_errstr(status));
1272 return false;
1275 status = se_file_access_check(sd,
1276 get_current_nttok(fsp->conn),
1277 false,
1278 access_mask,
1279 &rejected_mask);
1281 TALLOC_FREE(sd);
1283 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1284 DBG_DEBUG("rejected bits 0x%x read access for %s\n",
1285 (unsigned int)rejected_mask,
1286 fsp_str_dbg(fsp));
1287 return false;
1289 return true;
1292 /*******************************************************************
1293 Check to see if a user can write to an fsp.
1294 Always return true for directories.
1295 This is only approximate,
1296 it is used as part of the "hide unwriteable" option. Don't
1297 use it for anything security sensitive.
1298 ********************************************************************/
1300 static bool user_can_write_fsp(struct files_struct *fsp)
1303 * Never hide files from the root user.
1304 * We use (uid_t)0 here not sec_initial_uid()
1305 * as make test uses a single user context.
1308 if (get_current_uid(fsp->conn) == (uid_t)0) {
1309 return true;
1312 if (fsp->fsp_flags.is_directory) {
1313 return true;
1316 return can_write_to_fsp(fsp);
1319 /*******************************************************************
1320 Is a file a "special" type ?
1321 ********************************************************************/
1323 static bool file_is_special(connection_struct *conn,
1324 const struct smb_filename *smb_fname)
1327 * Never hide files from the root user.
1328 * We use (uid_t)0 here not sec_initial_uid()
1329 * as make test uses a single user context.
1332 if (get_current_uid(conn) == (uid_t)0) {
1333 return False;
1336 SMB_ASSERT(VALID_STAT(smb_fname->st));
1338 if (S_ISREG(smb_fname->st.st_ex_mode) ||
1339 S_ISDIR(smb_fname->st.st_ex_mode) ||
1340 S_ISLNK(smb_fname->st.st_ex_mode))
1341 return False;
1343 return True;
1346 /*******************************************************************
1347 Should the file be seen by the client?
1348 ********************************************************************/
1350 bool is_visible_fsp(struct files_struct *fsp)
1352 bool hide_unreadable = false;
1353 bool hide_unwriteable = false;
1354 bool hide_special = false;
1355 int hide_new_files_timeout = 0;
1356 const char *last_component = NULL;
1359 * If the file does not exist, there's no point checking
1360 * the configuration options. We succeed, on the basis that the
1361 * checks *might* have passed if the file was present.
1363 if (fsp == NULL) {
1364 return true;
1367 hide_unreadable = lp_hide_unreadable(SNUM(fsp->conn));
1368 hide_unwriteable = lp_hide_unwriteable_files(SNUM(fsp->conn));
1369 hide_special = lp_hide_special_files(SNUM(fsp->conn));
1370 hide_new_files_timeout = lp_hide_new_files_timeout(SNUM(fsp->conn));
1372 if (!hide_unreadable &&
1373 !hide_unwriteable &&
1374 !hide_special &&
1375 (hide_new_files_timeout == 0))
1377 return true;
1380 fsp = metadata_fsp(fsp);
1382 /* Get the last component of the base name. */
1383 last_component = strrchr_m(fsp->fsp_name->base_name, '/');
1384 if (!last_component) {
1385 last_component = fsp->fsp_name->base_name;
1386 } else {
1387 last_component++; /* Go past '/' */
1390 if (ISDOT(last_component) || ISDOTDOT(last_component)) {
1391 return true; /* . and .. are always visible. */
1394 if (fsp_get_pathref_fd(fsp) == -1) {
1396 * Symlink in POSIX mode or MS-DFS.
1397 * We've checked veto files so the
1398 * only thing we can check is the
1399 * hide_new_files_timeout.
1401 if (hide_new_files_timeout != 0) {
1402 double age = timespec_elapsed(
1403 &fsp->fsp_name->st.st_ex_mtime);
1405 if (age < (double)hide_new_files_timeout) {
1406 return false;
1409 return true;
1412 if (hide_unreadable ||
1413 hide_unwriteable ||
1414 hide_special ||
1415 (hide_new_files_timeout != 0))
1417 /* Honour _hide unreadable_ option */
1418 if (hide_unreadable &&
1419 !user_can_read_fsp(fsp))
1421 DBG_DEBUG("file %s is unreadable.\n",
1422 fsp_str_dbg(fsp));
1423 return false;
1425 /* Honour _hide unwriteable_ option */
1426 if (hide_unwriteable &&
1427 !user_can_write_fsp(fsp))
1429 DBG_DEBUG("file %s is unwritable.\n",
1430 fsp_str_dbg(fsp));
1431 return false;
1433 /* Honour _hide_special_ option */
1434 if (hide_special && file_is_special(fsp->conn, fsp->fsp_name)) {
1435 DBG_DEBUG("file %s is special.\n",
1436 fsp_str_dbg(fsp));
1437 return false;
1440 if (hide_new_files_timeout != 0) {
1441 double age = timespec_elapsed(
1442 &fsp->fsp_name->st.st_ex_mtime);
1444 if (age < (double)hide_new_files_timeout) {
1445 return false;
1450 return true;
1453 static int smb_Dir_destructor(struct smb_Dir *dir_hnd)
1455 files_struct *fsp = dir_hnd->fsp;
1457 SMB_VFS_CLOSEDIR(dir_hnd->conn, dir_hnd->dir);
1458 fsp_set_fd(fsp, -1);
1459 if (fsp->dptr != NULL) {
1460 SMB_ASSERT(fsp->dptr->dir_hnd == dir_hnd);
1461 fsp->dptr->dir_hnd = NULL;
1463 dir_hnd->fsp = NULL;
1464 return 0;
1467 /*******************************************************************
1468 Open a directory.
1469 ********************************************************************/
1471 static int smb_Dir_OpenDir_destructor(struct smb_Dir *dir_hnd)
1473 files_struct *fsp = dir_hnd->fsp;
1475 smb_Dir_destructor(dir_hnd);
1476 file_free(NULL, fsp);
1477 return 0;
1480 NTSTATUS OpenDir_ntstatus(TALLOC_CTX *mem_ctx,
1481 connection_struct *conn,
1482 const struct smb_filename *smb_dname,
1483 const char *mask,
1484 uint32_t attr,
1485 struct smb_Dir **_dir_hnd)
1487 struct files_struct *fsp = NULL;
1488 struct smb_Dir *dir_hnd = NULL;
1489 NTSTATUS status;
1491 status = open_internal_dirfsp(conn,
1492 smb_dname,
1493 O_RDONLY,
1494 &fsp);
1495 if (!NT_STATUS_IS_OK(status)) {
1496 return status;
1499 status = OpenDir_fsp(mem_ctx, conn, fsp, mask, attr, &dir_hnd);
1500 if (!NT_STATUS_IS_OK(status)) {
1501 return status;
1505 * This overwrites the destructor set by smb_Dir_OpenDir_destructor(),
1506 * but smb_Dir_OpenDir_destructor() calls the OpenDir_fsp() destructor.
1508 talloc_set_destructor(dir_hnd, smb_Dir_OpenDir_destructor);
1510 *_dir_hnd = dir_hnd;
1511 return NT_STATUS_OK;
1514 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx,
1515 connection_struct *conn,
1516 const struct smb_filename *smb_dname,
1517 const char *mask,
1518 uint32_t attr)
1520 struct smb_Dir *dir_hnd = NULL;
1521 NTSTATUS status;
1523 status = OpenDir_ntstatus(
1524 mem_ctx, conn, smb_dname, mask, attr, &dir_hnd);
1525 if (!NT_STATUS_IS_OK(status)) {
1526 /* Ensure we return the actual error from status in errno. */
1527 errno = map_errno_from_nt_status(status);
1528 return NULL;
1531 return dir_hnd;
1533 /*******************************************************************
1534 Open a directory from an fsp.
1535 ********************************************************************/
1537 static NTSTATUS OpenDir_fsp(
1538 TALLOC_CTX *mem_ctx,
1539 connection_struct *conn,
1540 files_struct *fsp,
1541 const char *mask,
1542 uint32_t attr,
1543 struct smb_Dir **_dir_hnd)
1545 struct smb_Dir *dir_hnd = talloc_zero(mem_ctx, struct smb_Dir);
1546 NTSTATUS status;
1548 if (!dir_hnd) {
1549 return NT_STATUS_NO_MEMORY;
1552 if (!fsp->fsp_flags.is_directory) {
1553 status = NT_STATUS_INVALID_HANDLE;
1554 goto fail;
1557 if (fsp_get_io_fd(fsp) == -1) {
1558 status = NT_STATUS_INVALID_HANDLE;
1559 goto fail;
1562 dir_hnd->conn = conn;
1564 if (!conn->sconn->using_smb2) {
1566 * The dircache is only needed for SMB1 because SMB1 uses a name
1567 * for the resume wheras SMB2 always continues from the next
1568 * position (unless it's told to restart or close-and-reopen the
1569 * listing).
1571 dir_hnd->name_cache_size =
1572 lp_directory_name_cache_size(SNUM(conn));
1575 dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, fsp->fsp_name);
1576 if (!dir_hnd->dir_smb_fname) {
1577 status = NT_STATUS_NO_MEMORY;
1578 goto fail;
1581 dir_hnd->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1582 if (dir_hnd->dir == NULL) {
1583 status = map_nt_error_from_unix(errno);
1584 goto fail;
1586 dir_hnd->fsp = fsp;
1587 if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
1588 dir_hnd->case_sensitive = true;
1589 } else {
1590 dir_hnd->case_sensitive = conn->case_sensitive;
1593 talloc_set_destructor(dir_hnd, smb_Dir_destructor);
1595 *_dir_hnd = dir_hnd;
1596 return NT_STATUS_OK;
1598 fail:
1599 TALLOC_FREE(dir_hnd);
1600 return status;
1604 /*******************************************************************
1605 Read from a directory.
1606 Return directory entry, current offset, and optional stat information.
1607 Don't check for veto or invisible files.
1608 ********************************************************************/
1610 const char *ReadDirName(struct smb_Dir *dir_hnd, long *poffset,
1611 SMB_STRUCT_STAT *sbuf, char **ptalloced)
1613 const char *n;
1614 char *talloced = NULL;
1615 connection_struct *conn = dir_hnd->conn;
1617 /* Cheat to allow . and .. to be the first entries returned. */
1618 if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1619 (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dir_hnd->file_number < 2))
1621 if (dir_hnd->file_number == 0) {
1622 n = ".";
1623 *poffset = dir_hnd->offset = START_OF_DIRECTORY_OFFSET;
1624 } else {
1625 n = "..";
1626 *poffset = dir_hnd->offset = DOT_DOT_DIRECTORY_OFFSET;
1628 dir_hnd->file_number++;
1629 *ptalloced = NULL;
1630 return n;
1633 if (*poffset == END_OF_DIRECTORY_OFFSET) {
1634 *poffset = dir_hnd->offset = END_OF_DIRECTORY_OFFSET;
1635 return NULL;
1638 /* A real offset, seek to it. */
1639 SeekDir(dir_hnd, *poffset);
1641 while ((n = vfs_readdirname(conn, dir_hnd->fsp, dir_hnd->dir, sbuf, &talloced))) {
1642 /* Ignore . and .. - we've already returned them. */
1643 if (*n == '.') {
1644 if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1645 TALLOC_FREE(talloced);
1646 continue;
1649 *poffset = dir_hnd->offset = SMB_VFS_TELLDIR(conn, dir_hnd->dir);
1650 *ptalloced = talloced;
1651 dir_hnd->file_number++;
1652 return n;
1654 *poffset = dir_hnd->offset = END_OF_DIRECTORY_OFFSET;
1655 *ptalloced = NULL;
1656 return NULL;
1659 /*******************************************************************
1660 Rewind to the start.
1661 ********************************************************************/
1663 void RewindDir(struct smb_Dir *dir_hnd, long *poffset)
1665 SMB_VFS_REWINDDIR(dir_hnd->conn, dir_hnd->dir);
1666 dir_hnd->file_number = 0;
1667 dir_hnd->offset = START_OF_DIRECTORY_OFFSET;
1668 *poffset = START_OF_DIRECTORY_OFFSET;
1671 /*******************************************************************
1672 Seek a dir.
1673 ********************************************************************/
1675 void SeekDir(struct smb_Dir *dirp, long offset)
1677 if (offset != dirp->offset) {
1678 if (offset == START_OF_DIRECTORY_OFFSET) {
1679 RewindDir(dirp, &offset);
1681 * Ok we should really set the file number here
1682 * to 1 to enable ".." to be returned next. Trouble
1683 * is I'm worried about callers using SeekDir(dirp,0)
1684 * as equivalent to RewindDir(). So leave this alone
1685 * for now.
1687 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
1688 RewindDir(dirp, &offset);
1690 * Set the file number to 2 - we want to get the first
1691 * real file entry (the one we return after "..")
1692 * on the next ReadDir.
1694 dirp->file_number = 2;
1695 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1696 ; /* Don't seek in this case. */
1697 } else {
1698 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1700 dirp->offset = offset;
1704 /*******************************************************************
1705 Tell a dir position.
1706 ********************************************************************/
1708 long TellDir(struct smb_Dir *dir_hnd)
1710 return(dir_hnd->offset);
1713 /*******************************************************************
1714 Add an entry into the dcache.
1715 ********************************************************************/
1717 static void DirCacheAdd(struct smb_Dir *dir_hnd, const char *name, long offset)
1719 struct name_cache_entry *e;
1721 if (dir_hnd->name_cache_size == 0) {
1722 return;
1725 if (dir_hnd->name_cache == NULL) {
1726 dir_hnd->name_cache = talloc_zero_array(dir_hnd,
1727 struct name_cache_entry,
1728 dir_hnd->name_cache_size);
1730 if (dir_hnd->name_cache == NULL) {
1731 return;
1735 dir_hnd->name_cache_index = (dir_hnd->name_cache_index+1) %
1736 dir_hnd->name_cache_size;
1737 e = &dir_hnd->name_cache[dir_hnd->name_cache_index];
1738 TALLOC_FREE(e->name);
1739 e->name = talloc_strdup(dir_hnd, name);
1740 e->offset = offset;
1743 /*******************************************************************
1744 Find an entry by name. Leave us at the offset after it.
1745 Don't check for veto or invisible files.
1746 ********************************************************************/
1748 static bool SearchDir(struct smb_Dir *dir_hnd, const char *name, long *poffset)
1750 int i;
1751 const char *entry = NULL;
1752 char *talloced = NULL;
1753 connection_struct *conn = dir_hnd->conn;
1755 /* Search back in the name cache. */
1756 if (dir_hnd->name_cache_size && dir_hnd->name_cache) {
1757 for (i = dir_hnd->name_cache_index; i >= 0; i--) {
1758 struct name_cache_entry *e = &dir_hnd->name_cache[i];
1759 if (e->name && (dir_hnd->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1760 *poffset = e->offset;
1761 SeekDir(dir_hnd, e->offset);
1762 return True;
1765 for (i = dir_hnd->name_cache_size - 1;
1766 i > dir_hnd->name_cache_index; i--) {
1767 struct name_cache_entry *e = &dir_hnd->name_cache[i];
1768 if (e->name && (dir_hnd->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1769 *poffset = e->offset;
1770 SeekDir(dir_hnd, e->offset);
1771 return True;
1776 /* Not found in the name cache. Rewind directory and start from scratch. */
1777 SMB_VFS_REWINDDIR(conn, dir_hnd->dir);
1778 dir_hnd->file_number = 0;
1779 *poffset = START_OF_DIRECTORY_OFFSET;
1780 while ((entry = ReadDirName(dir_hnd, poffset, NULL, &talloced))) {
1781 if (dir_hnd->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1782 TALLOC_FREE(talloced);
1783 return True;
1785 TALLOC_FREE(talloced);
1787 return False;
1790 struct files_below_forall_state {
1791 char *dirpath;
1792 ssize_t dirpath_len;
1793 int (*fn)(struct file_id fid, const struct share_mode_data *data,
1794 void *private_data);
1795 void *private_data;
1798 static int files_below_forall_fn(struct file_id fid,
1799 const struct share_mode_data *data,
1800 void *private_data)
1802 struct files_below_forall_state *state = private_data;
1803 char tmpbuf[PATH_MAX];
1804 char *fullpath, *to_free;
1805 ssize_t len;
1807 len = full_path_tos(data->servicepath, data->base_name,
1808 tmpbuf, sizeof(tmpbuf),
1809 &fullpath, &to_free);
1810 if (len == -1) {
1811 return 0;
1813 if (state->dirpath_len >= len) {
1815 * Filter files above dirpath
1817 goto out;
1819 if (fullpath[state->dirpath_len] != '/') {
1821 * Filter file that don't have a path separator at the end of
1822 * dirpath's length
1824 goto out;
1827 if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
1829 * Not a parent
1831 goto out;
1834 TALLOC_FREE(to_free);
1835 return state->fn(fid, data, state->private_data);
1837 out:
1838 TALLOC_FREE(to_free);
1839 return 0;
1842 static int files_below_forall(connection_struct *conn,
1843 const struct smb_filename *dir_name,
1844 int (*fn)(struct file_id fid,
1845 const struct share_mode_data *data,
1846 void *private_data),
1847 void *private_data)
1849 struct files_below_forall_state state = {
1850 .fn = fn,
1851 .private_data = private_data,
1853 int ret;
1854 char tmpbuf[PATH_MAX];
1855 char *to_free;
1857 state.dirpath_len = full_path_tos(conn->connectpath,
1858 dir_name->base_name,
1859 tmpbuf, sizeof(tmpbuf),
1860 &state.dirpath, &to_free);
1861 if (state.dirpath_len == -1) {
1862 return -1;
1865 ret = share_mode_forall(files_below_forall_fn, &state);
1866 TALLOC_FREE(to_free);
1867 return ret;
1870 struct have_file_open_below_state {
1871 bool found_one;
1874 static int have_file_open_below_fn(struct file_id fid,
1875 const struct share_mode_data *data,
1876 void *private_data)
1878 struct have_file_open_below_state *state = private_data;
1879 state->found_one = true;
1880 return 1;
1883 bool have_file_open_below(connection_struct *conn,
1884 const struct smb_filename *name)
1886 struct have_file_open_below_state state = {
1887 .found_one = false,
1889 int ret;
1891 if (!VALID_STAT(name->st)) {
1892 return false;
1894 if (!S_ISDIR(name->st.st_ex_mode)) {
1895 return false;
1898 ret = files_below_forall(conn, name, have_file_open_below_fn, &state);
1899 if (ret == -1) {
1900 return false;
1903 return state.found_one;
1906 /*****************************************************************
1907 Is this directory empty ?
1908 *****************************************************************/
1910 NTSTATUS can_delete_directory_fsp(files_struct *fsp)
1912 NTSTATUS status = NT_STATUS_OK;
1913 long dirpos = 0;
1914 const char *dname = NULL;
1915 char *talloced = NULL;
1916 SMB_STRUCT_STAT st;
1917 struct connection_struct *conn = fsp->conn;
1918 struct smb_Dir *dir_hnd = NULL;
1920 status = OpenDir_ntstatus(
1921 talloc_tos(), conn, fsp->fsp_name, NULL, 0, &dir_hnd);
1922 if (!NT_STATUS_IS_OK(status)) {
1923 return status;
1926 while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) {
1927 struct smb_filename *smb_dname_full = NULL;
1928 struct smb_filename *direntry_fname = NULL;
1929 char *fullname = NULL;
1930 int ret;
1932 if (ISDOT(dname) || (ISDOTDOT(dname))) {
1933 TALLOC_FREE(talloced);
1934 continue;
1936 if (IS_VETO_PATH(conn, dname)) {
1937 TALLOC_FREE(talloced);
1938 continue;
1941 fullname = talloc_asprintf(talloc_tos(),
1942 "%s/%s",
1943 fsp->fsp_name->base_name,
1944 dname);
1945 if (fullname == NULL) {
1946 status = NT_STATUS_NO_MEMORY;
1947 break;
1950 smb_dname_full = synthetic_smb_fname(talloc_tos(),
1951 fullname,
1952 NULL,
1953 NULL,
1954 fsp->fsp_name->twrp,
1955 fsp->fsp_name->flags);
1956 if (smb_dname_full == NULL) {
1957 TALLOC_FREE(talloced);
1958 TALLOC_FREE(fullname);
1959 status = NT_STATUS_NO_MEMORY;
1960 break;
1963 ret = SMB_VFS_LSTAT(conn, smb_dname_full);
1964 if (ret != 0) {
1965 status = map_nt_error_from_unix(errno);
1966 TALLOC_FREE(talloced);
1967 TALLOC_FREE(fullname);
1968 TALLOC_FREE(smb_dname_full);
1969 break;
1972 if (S_ISLNK(smb_dname_full->st.st_ex_mode)) {
1973 /* Could it be an msdfs link ? */
1974 if (lp_host_msdfs() &&
1975 lp_msdfs_root(SNUM(conn))) {
1976 struct smb_filename *smb_dname;
1977 smb_dname = synthetic_smb_fname(talloc_tos(),
1978 dname,
1979 NULL,
1980 &smb_dname_full->st,
1981 fsp->fsp_name->twrp,
1982 fsp->fsp_name->flags);
1983 if (smb_dname == NULL) {
1984 TALLOC_FREE(talloced);
1985 TALLOC_FREE(fullname);
1986 TALLOC_FREE(smb_dname_full);
1987 status = NT_STATUS_NO_MEMORY;
1988 break;
1990 if (is_msdfs_link(fsp, smb_dname)) {
1991 TALLOC_FREE(talloced);
1992 TALLOC_FREE(fullname);
1993 TALLOC_FREE(smb_dname_full);
1994 TALLOC_FREE(smb_dname);
1995 DBG_DEBUG("got msdfs link name %s "
1996 "- can't delete directory %s\n",
1997 dname,
1998 fsp_str_dbg(fsp));
1999 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
2000 break;
2002 TALLOC_FREE(smb_dname);
2004 /* Not a DFS link - could it be a dangling symlink ? */
2005 ret = SMB_VFS_STAT(conn, smb_dname_full);
2006 if (ret == -1 && (errno == ENOENT || errno == ELOOP)) {
2008 * Dangling symlink.
2009 * Allow if "delete veto files = yes"
2011 if (lp_delete_veto_files(SNUM(conn))) {
2012 TALLOC_FREE(talloced);
2013 TALLOC_FREE(fullname);
2014 TALLOC_FREE(smb_dname_full);
2015 continue;
2018 DBG_DEBUG("got symlink name %s - "
2019 "can't delete directory %s\n",
2020 dname,
2021 fsp_str_dbg(fsp));
2022 TALLOC_FREE(talloced);
2023 TALLOC_FREE(fullname);
2024 TALLOC_FREE(smb_dname_full);
2025 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
2026 break;
2029 /* Not a symlink, get a pathref. */
2030 status = synthetic_pathref(talloc_tos(),
2031 fsp,
2032 dname,
2033 NULL,
2034 &smb_dname_full->st,
2035 fsp->fsp_name->twrp,
2036 fsp->fsp_name->flags,
2037 &direntry_fname);
2038 if (!NT_STATUS_IS_OK(status)) {
2039 status = map_nt_error_from_unix(errno);
2040 TALLOC_FREE(talloced);
2041 TALLOC_FREE(fullname);
2042 TALLOC_FREE(smb_dname_full);
2043 break;
2046 if (!is_visible_fsp(direntry_fname->fsp)) {
2047 TALLOC_FREE(talloced);
2048 TALLOC_FREE(fullname);
2049 TALLOC_FREE(smb_dname_full);
2050 TALLOC_FREE(direntry_fname);
2051 continue;
2054 TALLOC_FREE(talloced);
2055 TALLOC_FREE(fullname);
2056 TALLOC_FREE(smb_dname_full);
2057 TALLOC_FREE(direntry_fname);
2059 DBG_DEBUG("got name %s - can't delete\n", dname);
2060 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
2061 break;
2063 TALLOC_FREE(talloced);
2064 TALLOC_FREE(dir_hnd);
2066 if (!NT_STATUS_IS_OK(status)) {
2067 return status;
2070 if (!(fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) &&
2071 lp_strict_rename(SNUM(conn)) &&
2072 have_file_open_below(fsp->conn, fsp->fsp_name))
2074 return NT_STATUS_ACCESS_DENIED;
2077 return NT_STATUS_OK;