s4: torture: Add an async SMB2_OP_FLUSH + SMB2_OP_CLOSE test to smb2.compound_async.
[Samba.git] / source3 / smbd / dir.c
bloba18d70c870a9f3a398a04d8cb5a1e8ce1def0b7c
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 NTSTATUS status;
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 status = SMB_VFS_GET_REAL_FILENAME_AT(dptr->conn,
503 dptr->dir_hnd->fsp,
504 dptr->wcard,
505 ctx,
506 &found_name);
507 if (NT_STATUS_IS_OK(status)) {
508 name = found_name;
509 goto clean;
511 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
512 /* The case-insensitive lookup was authoritative. */
513 goto clean;
516 TALLOC_FREE(pathreal);
518 name_temp = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced);
519 if (name_temp == NULL) {
520 return NULL;
522 if (talloced != NULL) {
523 return talloc_move(ctx, &talloced);
525 return talloc_strdup(ctx, name_temp);
527 clean:
528 TALLOC_FREE(pathreal);
529 ret:
530 /* We need to set the underlying dir_hnd offset to -1
531 * also as this function is usually called with the
532 * output from TellDir. */
533 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
534 return name;
537 /****************************************************************************
538 Search for a file by name.
539 ****************************************************************************/
541 bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
543 SET_STAT_INVALID(*pst);
545 if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
546 /* This is a singleton directory and we're already at the end. */
547 *poffset = END_OF_DIRECTORY_OFFSET;
548 return False;
551 return SearchDir(dptr->dir_hnd, name, poffset);
554 /****************************************************************************
555 Map a native directory offset to a 32-bit cookie.
556 ****************************************************************************/
558 static uint32_t map_dir_offset_to_wire(struct dptr_struct *dptr, long offset)
560 DATA_BLOB key;
561 DATA_BLOB val;
563 if (offset == END_OF_DIRECTORY_OFFSET) {
564 return WIRE_END_OF_DIRECTORY_OFFSET;
566 if (offset == START_OF_DIRECTORY_OFFSET) {
567 return WIRE_START_OF_DIRECTORY_OFFSET;
569 if (offset == DOT_DOT_DIRECTORY_OFFSET) {
570 return WIRE_DOT_DOT_DIRECTORY_OFFSET;
572 if (sizeof(long) == 4) {
573 /* 32-bit machine. We can cheat... */
574 return (uint32_t)offset;
576 if (dptr->dptr_cache == NULL) {
577 /* Lazy initialize cache. */
578 dptr->dptr_cache = memcache_init(dptr, 0);
579 if (dptr->dptr_cache == NULL) {
580 return WIRE_END_OF_DIRECTORY_OFFSET;
582 } else {
583 /* Have we seen this offset before ? */
584 key.data = (void *)&offset;
585 key.length = sizeof(offset);
586 if (memcache_lookup(dptr->dptr_cache,
587 SMB1_SEARCH_OFFSET_MAP,
588 key,
589 &val)) {
590 uint32_t wire_offset;
591 SMB_ASSERT(val.length == sizeof(wire_offset));
592 memcpy(&wire_offset, val.data, sizeof(wire_offset));
593 DEBUG(10,("found wire %u <-> offset %ld\n",
594 (unsigned int)wire_offset,
595 (long)offset));
596 return wire_offset;
599 /* Allocate a new wire cookie. */
600 do {
601 dptr->counter++;
602 } while (dptr->counter == WIRE_START_OF_DIRECTORY_OFFSET ||
603 dptr->counter == WIRE_END_OF_DIRECTORY_OFFSET ||
604 dptr->counter == WIRE_DOT_DOT_DIRECTORY_OFFSET);
605 /* Store it in the cache. */
606 key.data = (void *)&offset;
607 key.length = sizeof(offset);
608 val.data = (void *)&dptr->counter;
609 val.length = sizeof(dptr->counter); /* MUST BE uint32_t ! */
610 memcache_add(dptr->dptr_cache,
611 SMB1_SEARCH_OFFSET_MAP,
612 key,
613 val);
614 /* And the reverse mapping for lookup from
615 map_wire_to_dir_offset(). */
616 memcache_add(dptr->dptr_cache,
617 SMB1_SEARCH_OFFSET_MAP,
618 val,
619 key);
620 DEBUG(10,("stored wire %u <-> offset %ld\n",
621 (unsigned int)dptr->counter,
622 (long)offset));
623 return dptr->counter;
626 /****************************************************************************
627 Fill the 5 byte server reserved dptr field.
628 ****************************************************************************/
630 bool dptr_fill(struct smbd_server_connection *sconn,
631 char *buf1,unsigned int key)
633 unsigned char *buf = (unsigned char *)buf1;
634 struct dptr_struct *dptr = dptr_get(sconn, key);
635 uint32_t wire_offset;
636 if (!dptr) {
637 DEBUG(1,("filling null dirptr %d\n",key));
638 return(False);
640 wire_offset = map_dir_offset_to_wire(dptr,TellDir(dptr->dir_hnd));
641 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
642 (long)dptr->dir_hnd,(int)wire_offset));
643 buf[0] = key;
644 SIVAL(buf,1,wire_offset);
645 return(True);
648 /****************************************************************************
649 Map a 32-bit wire cookie to a native directory offset.
650 ****************************************************************************/
652 static long map_wire_to_dir_offset(struct dptr_struct *dptr, uint32_t wire_offset)
654 DATA_BLOB key;
655 DATA_BLOB val;
657 if (wire_offset == WIRE_END_OF_DIRECTORY_OFFSET) {
658 return END_OF_DIRECTORY_OFFSET;
659 } else if(wire_offset == WIRE_START_OF_DIRECTORY_OFFSET) {
660 return START_OF_DIRECTORY_OFFSET;
661 } else if (wire_offset == WIRE_DOT_DOT_DIRECTORY_OFFSET) {
662 return DOT_DOT_DIRECTORY_OFFSET;
664 if (sizeof(long) == 4) {
665 /* 32-bit machine. We can cheat... */
666 return (long)wire_offset;
668 if (dptr->dptr_cache == NULL) {
669 /* Logic error, cache should be initialized. */
670 return END_OF_DIRECTORY_OFFSET;
672 key.data = (void *)&wire_offset;
673 key.length = sizeof(wire_offset);
674 if (memcache_lookup(dptr->dptr_cache,
675 SMB1_SEARCH_OFFSET_MAP,
676 key,
677 &val)) {
678 /* Found mapping. */
679 long offset;
680 SMB_ASSERT(val.length == sizeof(offset));
681 memcpy(&offset, val.data, sizeof(offset));
682 DEBUG(10,("lookup wire %u <-> offset %ld\n",
683 (unsigned int)wire_offset,
684 (long)offset));
685 return offset;
687 return END_OF_DIRECTORY_OFFSET;
690 /****************************************************************************
691 Return the associated fsp and seek the dir_hnd on it it given the 5 byte
692 server field.
693 ****************************************************************************/
695 files_struct *dptr_fetch_fsp(struct smbd_server_connection *sconn,
696 char *buf, int *num)
698 unsigned int key = *(unsigned char *)buf;
699 struct dptr_struct *dptr = dptr_get(sconn, key);
700 uint32_t wire_offset;
701 long seekoff;
703 if (dptr == NULL) {
704 DEBUG(3,("fetched null dirptr %d\n",key));
705 return(NULL);
707 *num = key;
708 wire_offset = IVAL(buf,1);
709 seekoff = map_wire_to_dir_offset(dptr, wire_offset);
710 SeekDir(dptr->dir_hnd,seekoff);
711 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
712 key, dptr->smb_dname->base_name, (int)seekoff));
713 return dptr->dir_hnd->fsp;
716 struct files_struct *dir_hnd_fetch_fsp(struct smb_Dir *dir_hnd)
718 return dir_hnd->fsp;
721 /****************************************************************************
722 Fetch the fsp associated with the dptr_num.
723 ****************************************************************************/
725 files_struct *dptr_fetch_lanman2_fsp(struct smbd_server_connection *sconn,
726 int dptr_num)
728 struct dptr_struct *dptr = dptr_get(sconn, dptr_num);
729 if (dptr == NULL) {
730 return NULL;
732 DBG_NOTICE("fetching dirptr %d for path %s\n",
733 dptr_num,
734 dptr->smb_dname->base_name);
735 return dptr->dir_hnd->fsp;
738 static bool mangle_mask_match(connection_struct *conn,
739 const char *filename,
740 const char *mask)
742 char mname[13];
744 if (!name_to_8_3(filename,mname,False,conn->params)) {
745 return False;
747 return mask_match_search(mname,mask,False);
750 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
751 struct dptr_struct *dirptr,
752 const char *mask,
753 uint32_t dirtype,
754 bool dont_descend,
755 bool ask_sharemode,
756 bool get_dosmode_in,
757 bool (*match_fn)(TALLOC_CTX *ctx,
758 void *private_data,
759 const char *dname,
760 const char *mask,
761 char **_fname),
762 bool (*mode_fn)(TALLOC_CTX *ctx,
763 void *private_data,
764 struct files_struct *dirfsp,
765 struct smb_filename *atname,
766 struct smb_filename *smb_fname,
767 bool get_dosmode,
768 uint32_t *_mode),
769 void *private_data,
770 char **_fname,
771 struct smb_filename **_smb_fname,
772 uint32_t *_mode,
773 long *_prev_offset)
775 connection_struct *conn = dirptr->conn;
776 size_t slashlen;
777 size_t pathlen;
778 const char *dpath = dirptr->smb_dname->base_name;
779 bool dirptr_path_is_dot = ISDOT(dpath);
780 NTSTATUS status;
781 int ret;
783 *_smb_fname = NULL;
784 *_mode = 0;
786 pathlen = strlen(dpath);
787 slashlen = ( dpath[pathlen-1] != '/') ? 1 : 0;
789 while (true) {
790 long cur_offset;
791 long prev_offset;
792 SMB_STRUCT_STAT sbuf = { 0 };
793 char *dname = NULL;
794 bool isdots;
795 char *fname = NULL;
796 char *pathreal = NULL;
797 struct smb_filename *atname = NULL;
798 struct smb_filename *smb_fname = NULL;
799 uint32_t mode = 0;
800 bool check_dfs_symlink = false;
801 bool get_dosmode = get_dosmode_in;
802 bool ok;
804 cur_offset = dptr_TellDir(dirptr);
805 prev_offset = cur_offset;
806 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
808 DBG_DEBUG("dir [%s] dirptr [0x%lx] offset [%ld] => dname [%s]\n",
809 smb_fname_str_dbg(dirptr->smb_dname), (long)dirptr,
810 cur_offset, dname ? dname : "(finished)");
812 if (dname == NULL) {
813 return false;
816 isdots = (ISDOT(dname) || ISDOTDOT(dname));
817 if (dont_descend && !isdots) {
818 TALLOC_FREE(dname);
819 continue;
822 if (IS_VETO_PATH(conn, dname)) {
823 TALLOC_FREE(dname);
824 continue;
828 * fname may get mangled, dname is never mangled.
829 * Whenever we're accessing the filesystem we use
830 * pathreal which is composed from dname.
833 ok = match_fn(ctx, private_data, dname, mask, &fname);
834 if (!ok) {
835 TALLOC_FREE(dname);
836 continue;
840 * This used to be
841 * pathreal = talloc_asprintf(ctx, "%s%s%s", dirptr->path,
842 * needslash?"/":"", dname);
843 * but this was measurably slower than doing the memcpy.
846 pathreal = talloc_array(
847 ctx, char,
848 pathlen + slashlen + talloc_get_size(dname));
849 if (!pathreal) {
850 TALLOC_FREE(dname);
851 TALLOC_FREE(fname);
852 return false;
856 * We don't want to pass ./xxx to modules below us so don't
857 * add the path if it is just . by itself.
859 if (dirptr_path_is_dot) {
860 memcpy(pathreal, dname, talloc_get_size(dname));
861 } else {
862 memcpy(pathreal, dpath, pathlen);
863 pathreal[pathlen] = '/';
864 memcpy(pathreal + slashlen + pathlen, dname,
865 talloc_get_size(dname));
868 /* Create smb_fname with NULL stream_name. */
869 smb_fname = synthetic_smb_fname(talloc_tos(),
870 pathreal,
871 NULL,
872 &sbuf,
873 dirptr->smb_dname->twrp,
874 dirptr->smb_dname->flags);
875 TALLOC_FREE(pathreal);
876 if (smb_fname == NULL) {
877 TALLOC_FREE(dname);
878 TALLOC_FREE(fname);
879 return false;
882 if (!VALID_STAT(smb_fname->st)) {
884 * If stat() fails with ENOENT it might be a
885 * msdfs-symlink in Windows context, this is checked
886 * below, for now we just want to fill stat info as good
887 * as we can.
889 ret = vfs_stat(conn, smb_fname);
890 if (ret != 0 && errno != ENOENT) {
891 TALLOC_FREE(smb_fname);
892 TALLOC_FREE(dname);
893 TALLOC_FREE(fname);
894 continue;
898 /* Create smb_fname with NULL stream_name. */
899 atname = synthetic_smb_fname(talloc_tos(),
900 dname,
901 NULL,
902 &smb_fname->st,
903 dirptr->smb_dname->twrp,
904 dirptr->smb_dname->flags);
905 if (atname == NULL) {
906 TALLOC_FREE(dname);
907 TALLOC_FREE(fname);
908 TALLOC_FREE(smb_fname);
909 return false;
913 * openat_pathref_fsp() will return
914 * NT_STATUS_OBJECT_NAME_NOT_FOUND in non-POSIX context when
915 * hitting a dangling symlink. It may be a DFS symlink, this is
916 * checked below by the mode_fn() call, so we have to allow this
917 * here.
919 * NT_STATUS_STOPPED_ON_SYMLINK is returned in POSIX context
920 * when hitting a symlink and ensures we always return directory
921 * entries that are symlinks in POSIX context.
923 status = openat_pathref_fsp(dirptr->dir_hnd->fsp, atname);
924 if (!NT_STATUS_IS_OK(status) &&
925 !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND))
927 TALLOC_FREE(atname);
928 TALLOC_FREE(dname);
929 TALLOC_FREE(fname);
930 TALLOC_FREE(smb_fname);
931 continue;
934 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
935 if (!(atname->flags & SMB_FILENAME_POSIX_PATH)) {
936 check_dfs_symlink = true;
939 * Check if it's a symlink. We only want to return this
940 * if it's a DFS symlink or in POSIX mode. Disable
941 * getting dosmode in the mode_fn() and prime the mode
942 * as FILE_ATTRIBUTE_NORMAL.
944 mode = FILE_ATTRIBUTE_NORMAL;
945 get_dosmode = false;
948 status = move_smb_fname_fsp_link(smb_fname, atname);
949 if (!NT_STATUS_IS_OK(status)) {
950 DBG_WARNING("Failed to move pathref for [%s]: %s\n",
951 smb_fname_str_dbg(smb_fname),
952 nt_errstr(status));
953 TALLOC_FREE(atname);
954 TALLOC_FREE(smb_fname);
955 TALLOC_FREE(dname);
956 TALLOC_FREE(fname);
957 continue;
960 if (!is_visible_fsp(smb_fname->fsp)) {
961 TALLOC_FREE(atname);
962 TALLOC_FREE(smb_fname);
963 TALLOC_FREE(dname);
964 TALLOC_FREE(fname);
965 continue;
969 * Don't leak metadata about the containing
970 * directory of the share.
972 if (dirptr_path_is_dot && ISDOTDOT(dname)) {
974 * Making a copy here, then freeing
975 * the original will close the smb_fname->fsp.
977 struct smb_filename *tmp_smb_fname =
978 cp_smb_filename(ctx, smb_fname);
980 if (tmp_smb_fname == NULL) {
981 TALLOC_FREE(atname);
982 TALLOC_FREE(smb_fname);
983 TALLOC_FREE(dname);
984 TALLOC_FREE(fname);
985 return false;
987 TALLOC_FREE(smb_fname);
988 smb_fname = tmp_smb_fname;
989 mode = FILE_ATTRIBUTE_DIRECTORY;
990 get_dosmode = false;
993 ok = mode_fn(ctx,
994 private_data,
995 dirptr->dir_hnd->fsp,
996 atname,
997 smb_fname,
998 get_dosmode,
999 &mode);
1000 if (!ok) {
1001 TALLOC_FREE(atname);
1002 TALLOC_FREE(smb_fname);
1003 TALLOC_FREE(dname);
1004 TALLOC_FREE(fname);
1005 continue;
1008 TALLOC_FREE(atname);
1011 * The only valid cases where we return the directory entry if
1012 * it's a symlink are:
1014 * 1. POSIX context, always return it, or
1016 * 2. a DFS symlink where the mode_fn() call above has verified
1017 * this and set mode to FILE_ATTRIBUTE_REPARSE_POINT.
1019 if (check_dfs_symlink &&
1020 !(mode & FILE_ATTRIBUTE_REPARSE_POINT))
1022 TALLOC_FREE(smb_fname);
1023 TALLOC_FREE(dname);
1024 TALLOC_FREE(fname);
1025 continue;
1028 if (!dir_check_ftype(mode, dirtype)) {
1029 DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
1030 fname, (unsigned int)mode, (unsigned int)dirtype));
1031 TALLOC_FREE(smb_fname);
1032 TALLOC_FREE(dname);
1033 TALLOC_FREE(fname);
1034 continue;
1037 if (ask_sharemode && !S_ISDIR(smb_fname->st.st_ex_mode)) {
1038 struct timespec write_time_ts;
1039 struct file_id fileid;
1041 fileid = vfs_file_id_from_sbuf(conn,
1042 &smb_fname->st);
1043 get_file_infos(fileid, 0, NULL, &write_time_ts);
1044 if (!is_omit_timespec(&write_time_ts)) {
1045 update_stat_ex_mtime(&smb_fname->st,
1046 write_time_ts);
1050 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
1051 "fname=%s (%s)\n",
1052 mask, smb_fname_str_dbg(smb_fname),
1053 dname, fname));
1055 if (!conn->sconn->using_smb2) {
1057 * The dircache is only needed for SMB1 because SMB1
1058 * uses a name for the resume wheras SMB2 always
1059 * continues from the next position (unless it's told to
1060 * restart or close-and-reopen the listing).
1062 DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
1065 TALLOC_FREE(dname);
1067 *_smb_fname = talloc_move(ctx, &smb_fname);
1068 if (*_smb_fname == NULL) {
1069 return false;
1071 *_fname = fname;
1072 *_mode = mode;
1073 *_prev_offset = prev_offset;
1075 return true;
1078 return false;
1081 /****************************************************************************
1082 Get an 8.3 directory entry.
1083 ****************************************************************************/
1085 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
1086 void *private_data,
1087 const char *dname,
1088 const char *mask,
1089 char **_fname)
1091 connection_struct *conn = (connection_struct *)private_data;
1093 if ((strcmp(mask,"*.*") == 0) ||
1094 mask_match_search(dname, mask, false) ||
1095 mangle_mask_match(conn, dname, mask)) {
1096 char mname[13];
1097 const char *fname;
1099 * Ensure we can push the original name as UCS2. If
1100 * not, then just don't return this name.
1102 NTSTATUS status;
1103 size_t ret_len = 0;
1104 size_t len = (strlen(dname) + 2) * 4; /* Allow enough space. */
1105 uint8_t *tmp = talloc_array(talloc_tos(),
1106 uint8_t,
1107 len);
1109 status = srvstr_push(NULL,
1110 FLAGS2_UNICODE_STRINGS,
1111 tmp,
1112 dname,
1113 len,
1114 STR_TERMINATE,
1115 &ret_len);
1117 TALLOC_FREE(tmp);
1119 if (!NT_STATUS_IS_OK(status)) {
1120 return false;
1123 if (!mangle_is_8_3(dname, false, conn->params)) {
1124 bool ok = name_to_8_3(dname, mname, false,
1125 conn->params);
1126 if (!ok) {
1127 return false;
1129 fname = mname;
1130 } else {
1131 fname = dname;
1134 *_fname = talloc_strdup(ctx, fname);
1135 if (*_fname == NULL) {
1136 return false;
1139 return true;
1142 return false;
1145 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1146 void *private_data,
1147 struct files_struct *dirfsp,
1148 struct smb_filename *atname,
1149 struct smb_filename *smb_fname,
1150 bool get_dosmode,
1151 uint32_t *_mode)
1153 connection_struct *conn = (connection_struct *)private_data;
1155 if (!VALID_STAT(smb_fname->st)) {
1156 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1157 DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1158 "Couldn't stat [%s]. Error "
1159 "= %s\n",
1160 smb_fname_str_dbg(smb_fname),
1161 strerror(errno)));
1162 return false;
1166 if (get_dosmode) {
1167 *_mode = fdos_mode(smb_fname->fsp);
1168 smb_fname->st = smb_fname->fsp->fsp_name->st;
1170 return true;
1173 bool get_dir_entry(TALLOC_CTX *ctx,
1174 struct dptr_struct *dirptr,
1175 const char *mask,
1176 uint32_t dirtype,
1177 char **_fname,
1178 off_t *_size,
1179 uint32_t *_mode,
1180 struct timespec *_date,
1181 bool check_descend,
1182 bool ask_sharemode)
1184 connection_struct *conn = dirptr->conn;
1185 char *fname = NULL;
1186 struct smb_filename *smb_fname = NULL;
1187 uint32_t mode = 0;
1188 long prev_offset;
1189 bool ok;
1191 ok = smbd_dirptr_get_entry(ctx,
1192 dirptr,
1193 mask,
1194 dirtype,
1195 check_descend,
1196 ask_sharemode,
1197 true,
1198 smbd_dirptr_8_3_match_fn,
1199 smbd_dirptr_8_3_mode_fn,
1200 conn,
1201 &fname,
1202 &smb_fname,
1203 &mode,
1204 &prev_offset);
1205 if (!ok) {
1206 return false;
1209 *_fname = talloc_move(ctx, &fname);
1210 *_size = smb_fname->st.st_ex_size;
1211 *_mode = mode;
1212 *_date = smb_fname->st.st_ex_mtime;
1213 TALLOC_FREE(smb_fname);
1214 return true;
1217 /*******************************************************************
1218 Check to see if a user can read an fsp . This is only approximate,
1219 it is used as part of the "hide unreadable" option. Don't
1220 use it for anything security sensitive.
1221 ********************************************************************/
1223 static bool user_can_read_fsp(struct files_struct *fsp)
1225 NTSTATUS status;
1226 uint32_t rejected_share_access = 0;
1227 uint32_t rejected_mask = 0;
1228 struct security_descriptor *sd = NULL;
1229 uint32_t access_mask = FILE_READ_DATA|
1230 FILE_READ_EA|
1231 FILE_READ_ATTRIBUTES|
1232 SEC_STD_READ_CONTROL;
1235 * Never hide files from the root user.
1236 * We use (uid_t)0 here not sec_initial_uid()
1237 * as make test uses a single user context.
1240 if (get_current_uid(fsp->conn) == (uid_t)0) {
1241 return true;
1245 * We can't directly use smbd_check_access_rights_fsp()
1246 * here, as this implicitly grants FILE_READ_ATTRIBUTES
1247 * which the Windows access-based-enumeration code
1248 * explicitly checks for on the file security descriptor.
1249 * See bug:
1251 * https://bugzilla.samba.org/show_bug.cgi?id=10252
1253 * and the smb2.acl2.ACCESSBASED test for details.
1256 rejected_share_access = access_mask & ~(fsp->conn->share_access);
1257 if (rejected_share_access) {
1258 DBG_DEBUG("rejected share access 0x%x "
1259 "on %s (0x%x)\n",
1260 (unsigned int)access_mask,
1261 fsp_str_dbg(fsp),
1262 (unsigned int)rejected_share_access);
1263 return false;
1266 status = SMB_VFS_FGET_NT_ACL(metadata_fsp(fsp),
1267 (SECINFO_OWNER |
1268 SECINFO_GROUP |
1269 SECINFO_DACL),
1270 talloc_tos(),
1271 &sd);
1273 if (!NT_STATUS_IS_OK(status)) {
1274 DBG_DEBUG("Could not get acl "
1275 "on %s: %s\n",
1276 fsp_str_dbg(fsp),
1277 nt_errstr(status));
1278 return false;
1281 status = se_file_access_check(sd,
1282 get_current_nttok(fsp->conn),
1283 false,
1284 access_mask,
1285 &rejected_mask);
1287 TALLOC_FREE(sd);
1289 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1290 DBG_DEBUG("rejected bits 0x%x read access for %s\n",
1291 (unsigned int)rejected_mask,
1292 fsp_str_dbg(fsp));
1293 return false;
1295 return true;
1298 /*******************************************************************
1299 Check to see if a user can write to an fsp.
1300 Always return true for directories.
1301 This is only approximate,
1302 it is used as part of the "hide unwriteable" option. Don't
1303 use it for anything security sensitive.
1304 ********************************************************************/
1306 static bool user_can_write_fsp(struct files_struct *fsp)
1309 * Never hide files from the root user.
1310 * We use (uid_t)0 here not sec_initial_uid()
1311 * as make test uses a single user context.
1314 if (get_current_uid(fsp->conn) == (uid_t)0) {
1315 return true;
1318 if (fsp->fsp_flags.is_directory) {
1319 return true;
1322 return can_write_to_fsp(fsp);
1325 /*******************************************************************
1326 Is a file a "special" type ?
1327 ********************************************************************/
1329 static bool file_is_special(connection_struct *conn,
1330 const struct smb_filename *smb_fname)
1333 * Never hide files from the root user.
1334 * We use (uid_t)0 here not sec_initial_uid()
1335 * as make test uses a single user context.
1338 if (get_current_uid(conn) == (uid_t)0) {
1339 return False;
1342 SMB_ASSERT(VALID_STAT(smb_fname->st));
1344 if (S_ISREG(smb_fname->st.st_ex_mode) ||
1345 S_ISDIR(smb_fname->st.st_ex_mode) ||
1346 S_ISLNK(smb_fname->st.st_ex_mode))
1347 return False;
1349 return True;
1352 /*******************************************************************
1353 Should the file be seen by the client?
1354 ********************************************************************/
1356 bool is_visible_fsp(struct files_struct *fsp)
1358 bool hide_unreadable = false;
1359 bool hide_unwriteable = false;
1360 bool hide_special = false;
1361 int hide_new_files_timeout = 0;
1362 const char *last_component = NULL;
1365 * If the file does not exist, there's no point checking
1366 * the configuration options. We succeed, on the basis that the
1367 * checks *might* have passed if the file was present.
1369 if (fsp == NULL) {
1370 return true;
1373 hide_unreadable = lp_hide_unreadable(SNUM(fsp->conn));
1374 hide_unwriteable = lp_hide_unwriteable_files(SNUM(fsp->conn));
1375 hide_special = lp_hide_special_files(SNUM(fsp->conn));
1376 hide_new_files_timeout = lp_hide_new_files_timeout(SNUM(fsp->conn));
1378 if (!hide_unreadable &&
1379 !hide_unwriteable &&
1380 !hide_special &&
1381 (hide_new_files_timeout == 0))
1383 return true;
1386 fsp = metadata_fsp(fsp);
1388 /* Get the last component of the base name. */
1389 last_component = strrchr_m(fsp->fsp_name->base_name, '/');
1390 if (!last_component) {
1391 last_component = fsp->fsp_name->base_name;
1392 } else {
1393 last_component++; /* Go past '/' */
1396 if (ISDOT(last_component) || ISDOTDOT(last_component)) {
1397 return true; /* . and .. are always visible. */
1400 if (fsp_get_pathref_fd(fsp) == -1) {
1402 * Symlink in POSIX mode or MS-DFS.
1403 * We've checked veto files so the
1404 * only thing we can check is the
1405 * hide_new_files_timeout.
1407 if ((hide_new_files_timeout != 0) &&
1408 !S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
1409 double age = timespec_elapsed(
1410 &fsp->fsp_name->st.st_ex_mtime);
1412 if (age < (double)hide_new_files_timeout) {
1413 return false;
1416 return true;
1419 if (hide_unreadable ||
1420 hide_unwriteable ||
1421 hide_special ||
1422 (hide_new_files_timeout != 0))
1424 /* Honour _hide unreadable_ option */
1425 if (hide_unreadable &&
1426 !user_can_read_fsp(fsp))
1428 DBG_DEBUG("file %s is unreadable.\n",
1429 fsp_str_dbg(fsp));
1430 return false;
1432 /* Honour _hide unwriteable_ option */
1433 if (hide_unwriteable &&
1434 !user_can_write_fsp(fsp))
1436 DBG_DEBUG("file %s is unwritable.\n",
1437 fsp_str_dbg(fsp));
1438 return false;
1440 /* Honour _hide_special_ option */
1441 if (hide_special && file_is_special(fsp->conn, fsp->fsp_name)) {
1442 DBG_DEBUG("file %s is special.\n",
1443 fsp_str_dbg(fsp));
1444 return false;
1447 if ((hide_new_files_timeout != 0) &&
1448 !S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
1449 double age = timespec_elapsed(
1450 &fsp->fsp_name->st.st_ex_mtime);
1452 if (age < (double)hide_new_files_timeout) {
1453 return false;
1458 return true;
1461 static int smb_Dir_destructor(struct smb_Dir *dir_hnd)
1463 files_struct *fsp = dir_hnd->fsp;
1465 SMB_VFS_CLOSEDIR(dir_hnd->conn, dir_hnd->dir);
1466 fsp_set_fd(fsp, -1);
1467 if (fsp->dptr != NULL) {
1468 SMB_ASSERT(fsp->dptr->dir_hnd == dir_hnd);
1469 fsp->dptr->dir_hnd = NULL;
1471 dir_hnd->fsp = NULL;
1472 return 0;
1475 /*******************************************************************
1476 Open a directory.
1477 ********************************************************************/
1479 static int smb_Dir_OpenDir_destructor(struct smb_Dir *dir_hnd)
1481 files_struct *fsp = dir_hnd->fsp;
1483 smb_Dir_destructor(dir_hnd);
1484 file_free(NULL, fsp);
1485 return 0;
1488 NTSTATUS OpenDir(TALLOC_CTX *mem_ctx,
1489 connection_struct *conn,
1490 const struct smb_filename *smb_dname,
1491 const char *mask,
1492 uint32_t attr,
1493 struct smb_Dir **_dir_hnd)
1495 struct files_struct *fsp = NULL;
1496 struct smb_Dir *dir_hnd = NULL;
1497 NTSTATUS status;
1499 status = open_internal_dirfsp(conn,
1500 smb_dname,
1501 O_RDONLY,
1502 &fsp);
1503 if (!NT_STATUS_IS_OK(status)) {
1504 return status;
1507 status = OpenDir_fsp(mem_ctx, conn, fsp, mask, attr, &dir_hnd);
1508 if (!NT_STATUS_IS_OK(status)) {
1509 return status;
1513 * This overwrites the destructor set by OpenDir_fsp() but
1514 * smb_Dir_OpenDir_destructor() calls the OpenDir_fsp()
1515 * destructor.
1517 talloc_set_destructor(dir_hnd, smb_Dir_OpenDir_destructor);
1519 *_dir_hnd = dir_hnd;
1520 return NT_STATUS_OK;
1523 NTSTATUS OpenDir_from_pathref(TALLOC_CTX *mem_ctx,
1524 struct files_struct *dirfsp,
1525 const char *mask,
1526 uint32_t attr,
1527 struct smb_Dir **_dir_hnd)
1529 struct files_struct *fsp = NULL;
1530 struct smb_Dir *dir_hnd = NULL;
1531 NTSTATUS status;
1533 status = openat_internal_dir_from_pathref(dirfsp, O_RDONLY, &fsp);
1534 if (!NT_STATUS_IS_OK(status)) {
1535 return status;
1538 status = OpenDir_fsp(mem_ctx, fsp->conn, fsp, mask, attr, &dir_hnd);
1539 if (!NT_STATUS_IS_OK(status)) {
1540 return status;
1544 * This overwrites the destructor set by OpenDir_fsp() but
1545 * smb_Dir_OpenDir_destructor() calls the OpenDir_fsp()
1546 * destructor.
1548 talloc_set_destructor(dir_hnd, smb_Dir_OpenDir_destructor);
1550 *_dir_hnd = dir_hnd;
1551 return NT_STATUS_OK;
1554 /*******************************************************************
1555 Open a directory from an fsp.
1556 ********************************************************************/
1558 static NTSTATUS OpenDir_fsp(
1559 TALLOC_CTX *mem_ctx,
1560 connection_struct *conn,
1561 files_struct *fsp,
1562 const char *mask,
1563 uint32_t attr,
1564 struct smb_Dir **_dir_hnd)
1566 struct smb_Dir *dir_hnd = talloc_zero(mem_ctx, struct smb_Dir);
1567 NTSTATUS status;
1569 if (!dir_hnd) {
1570 return NT_STATUS_NO_MEMORY;
1573 if (!fsp->fsp_flags.is_directory) {
1574 status = NT_STATUS_INVALID_HANDLE;
1575 goto fail;
1578 if (fsp_get_io_fd(fsp) == -1) {
1579 status = NT_STATUS_INVALID_HANDLE;
1580 goto fail;
1583 dir_hnd->conn = conn;
1585 if (!conn->sconn->using_smb2) {
1587 * The dircache is only needed for SMB1 because SMB1 uses a name
1588 * for the resume wheras SMB2 always continues from the next
1589 * position (unless it's told to restart or close-and-reopen the
1590 * listing).
1592 dir_hnd->name_cache_size =
1593 lp_directory_name_cache_size(SNUM(conn));
1596 dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, fsp->fsp_name);
1597 if (!dir_hnd->dir_smb_fname) {
1598 status = NT_STATUS_NO_MEMORY;
1599 goto fail;
1602 dir_hnd->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1603 if (dir_hnd->dir == NULL) {
1604 status = map_nt_error_from_unix(errno);
1605 goto fail;
1607 dir_hnd->fsp = fsp;
1608 if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
1609 dir_hnd->case_sensitive = true;
1610 } else {
1611 dir_hnd->case_sensitive = conn->case_sensitive;
1614 talloc_set_destructor(dir_hnd, smb_Dir_destructor);
1616 *_dir_hnd = dir_hnd;
1617 return NT_STATUS_OK;
1619 fail:
1620 TALLOC_FREE(dir_hnd);
1621 return status;
1625 /*******************************************************************
1626 Read from a directory.
1627 Return directory entry, current offset, and optional stat information.
1628 Don't check for veto or invisible files.
1629 ********************************************************************/
1631 const char *ReadDirName(struct smb_Dir *dir_hnd, long *poffset,
1632 SMB_STRUCT_STAT *sbuf, char **ptalloced)
1634 const char *n;
1635 char *talloced = NULL;
1636 connection_struct *conn = dir_hnd->conn;
1638 /* Cheat to allow . and .. to be the first entries returned. */
1639 if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1640 (*poffset == DOT_DOT_DIRECTORY_OFFSET)) &&
1641 (dir_hnd->file_number < 2))
1643 if (dir_hnd->file_number == 0) {
1644 n = ".";
1645 *poffset = dir_hnd->offset = START_OF_DIRECTORY_OFFSET;
1646 } else {
1647 n = "..";
1648 *poffset = dir_hnd->offset = DOT_DOT_DIRECTORY_OFFSET;
1650 dir_hnd->file_number++;
1651 *ptalloced = NULL;
1652 return n;
1655 if (*poffset == END_OF_DIRECTORY_OFFSET) {
1656 *poffset = dir_hnd->offset = END_OF_DIRECTORY_OFFSET;
1657 return NULL;
1660 /* A real offset, seek to it. */
1661 SeekDir(dir_hnd, *poffset);
1663 while ((n = vfs_readdirname(conn, dir_hnd->fsp, dir_hnd->dir, sbuf, &talloced))) {
1664 /* Ignore . and .. - we've already returned them. */
1665 if (ISDOT(n) || ISDOTDOT(n)) {
1666 TALLOC_FREE(talloced);
1667 continue;
1669 *poffset = dir_hnd->offset = SMB_VFS_TELLDIR(conn, dir_hnd->dir);
1670 *ptalloced = talloced;
1671 dir_hnd->file_number++;
1672 return n;
1674 *poffset = dir_hnd->offset = END_OF_DIRECTORY_OFFSET;
1675 *ptalloced = NULL;
1676 return NULL;
1679 /*******************************************************************
1680 Rewind to the start.
1681 ********************************************************************/
1683 void RewindDir(struct smb_Dir *dir_hnd, long *poffset)
1685 SMB_VFS_REWINDDIR(dir_hnd->conn, dir_hnd->dir);
1686 dir_hnd->file_number = 0;
1687 dir_hnd->offset = START_OF_DIRECTORY_OFFSET;
1688 *poffset = START_OF_DIRECTORY_OFFSET;
1691 /*******************************************************************
1692 Seek a dir.
1693 ********************************************************************/
1695 void SeekDir(struct smb_Dir *dirp, long offset)
1697 if (offset != dirp->offset) {
1698 if (offset == START_OF_DIRECTORY_OFFSET) {
1699 RewindDir(dirp, &offset);
1701 * Ok we should really set the file number here
1702 * to 1 to enable ".." to be returned next. Trouble
1703 * is I'm worried about callers using SeekDir(dirp,0)
1704 * as equivalent to RewindDir(). So leave this alone
1705 * for now.
1707 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
1708 RewindDir(dirp, &offset);
1710 * Set the file number to 2 - we want to get the first
1711 * real file entry (the one we return after "..")
1712 * on the next ReadDir.
1714 dirp->file_number = 2;
1715 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1716 ; /* Don't seek in this case. */
1717 } else {
1718 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1720 dirp->offset = offset;
1724 /*******************************************************************
1725 Tell a dir position.
1726 ********************************************************************/
1728 long TellDir(struct smb_Dir *dir_hnd)
1730 return(dir_hnd->offset);
1733 /*******************************************************************
1734 Add an entry into the dcache.
1735 ********************************************************************/
1737 static void DirCacheAdd(struct smb_Dir *dir_hnd, const char *name, long offset)
1739 struct name_cache_entry *e;
1741 if (dir_hnd->name_cache_size == 0) {
1742 return;
1745 if (dir_hnd->name_cache == NULL) {
1746 dir_hnd->name_cache = talloc_zero_array(dir_hnd,
1747 struct name_cache_entry,
1748 dir_hnd->name_cache_size);
1750 if (dir_hnd->name_cache == NULL) {
1751 return;
1755 dir_hnd->name_cache_index = (dir_hnd->name_cache_index+1) %
1756 dir_hnd->name_cache_size;
1757 e = &dir_hnd->name_cache[dir_hnd->name_cache_index];
1758 TALLOC_FREE(e->name);
1759 e->name = talloc_strdup(dir_hnd, name);
1760 e->offset = offset;
1763 /*******************************************************************
1764 Find an entry by name. Leave us at the offset after it.
1765 Don't check for veto or invisible files.
1766 ********************************************************************/
1768 static bool SearchDir(struct smb_Dir *dir_hnd, const char *name, long *poffset)
1770 int i;
1771 const char *entry = NULL;
1772 char *talloced = NULL;
1773 connection_struct *conn = dir_hnd->conn;
1775 /* Search back in the name cache. */
1776 if (dir_hnd->name_cache_size && dir_hnd->name_cache) {
1777 for (i = dir_hnd->name_cache_index; i >= 0; 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;
1785 for (i = dir_hnd->name_cache_size - 1;
1786 i > dir_hnd->name_cache_index; i--) {
1787 struct name_cache_entry *e = &dir_hnd->name_cache[i];
1788 if (e->name && (dir_hnd->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1789 *poffset = e->offset;
1790 SeekDir(dir_hnd, e->offset);
1791 return True;
1796 /* Not found in the name cache. Rewind directory and start from scratch. */
1797 SMB_VFS_REWINDDIR(conn, dir_hnd->dir);
1798 dir_hnd->file_number = 0;
1799 *poffset = START_OF_DIRECTORY_OFFSET;
1800 while ((entry = ReadDirName(dir_hnd, poffset, NULL, &talloced))) {
1801 if (dir_hnd->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1802 TALLOC_FREE(talloced);
1803 return True;
1805 TALLOC_FREE(talloced);
1807 return False;
1810 struct files_below_forall_state {
1811 char *dirpath;
1812 ssize_t dirpath_len;
1813 int (*fn)(struct file_id fid, const struct share_mode_data *data,
1814 void *private_data);
1815 void *private_data;
1818 static int files_below_forall_fn(struct file_id fid,
1819 const struct share_mode_data *data,
1820 void *private_data)
1822 struct files_below_forall_state *state = private_data;
1823 char tmpbuf[PATH_MAX];
1824 char *fullpath, *to_free;
1825 ssize_t len;
1827 len = full_path_tos(data->servicepath, data->base_name,
1828 tmpbuf, sizeof(tmpbuf),
1829 &fullpath, &to_free);
1830 if (len == -1) {
1831 return 0;
1833 if (state->dirpath_len >= len) {
1835 * Filter files above dirpath
1837 goto out;
1839 if (fullpath[state->dirpath_len] != '/') {
1841 * Filter file that don't have a path separator at the end of
1842 * dirpath's length
1844 goto out;
1847 if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
1849 * Not a parent
1851 goto out;
1854 TALLOC_FREE(to_free);
1855 return state->fn(fid, data, state->private_data);
1857 out:
1858 TALLOC_FREE(to_free);
1859 return 0;
1862 static int files_below_forall(connection_struct *conn,
1863 const struct smb_filename *dir_name,
1864 int (*fn)(struct file_id fid,
1865 const struct share_mode_data *data,
1866 void *private_data),
1867 void *private_data)
1869 struct files_below_forall_state state = {
1870 .fn = fn,
1871 .private_data = private_data,
1873 int ret;
1874 char tmpbuf[PATH_MAX];
1875 char *to_free;
1877 state.dirpath_len = full_path_tos(conn->connectpath,
1878 dir_name->base_name,
1879 tmpbuf, sizeof(tmpbuf),
1880 &state.dirpath, &to_free);
1881 if (state.dirpath_len == -1) {
1882 return -1;
1885 ret = share_mode_forall(files_below_forall_fn, &state);
1886 TALLOC_FREE(to_free);
1887 return ret;
1890 struct have_file_open_below_state {
1891 bool found_one;
1894 static int have_file_open_below_fn(struct file_id fid,
1895 const struct share_mode_data *data,
1896 void *private_data)
1898 struct have_file_open_below_state *state = private_data;
1899 state->found_one = true;
1900 return 1;
1903 bool have_file_open_below(connection_struct *conn,
1904 const struct smb_filename *name)
1906 struct have_file_open_below_state state = {
1907 .found_one = false,
1909 int ret;
1911 if (!VALID_STAT(name->st)) {
1912 return false;
1914 if (!S_ISDIR(name->st.st_ex_mode)) {
1915 return false;
1918 ret = files_below_forall(conn, name, have_file_open_below_fn, &state);
1919 if (ret == -1) {
1920 return false;
1923 return state.found_one;
1926 /*****************************************************************
1927 Is this directory empty ?
1928 *****************************************************************/
1930 NTSTATUS can_delete_directory_fsp(files_struct *fsp)
1932 NTSTATUS status = NT_STATUS_OK;
1933 long dirpos = 0;
1934 const char *dname = NULL;
1935 char *talloced = NULL;
1936 struct connection_struct *conn = fsp->conn;
1937 struct smb_Dir *dir_hnd = NULL;
1939 status = OpenDir(
1940 talloc_tos(), conn, fsp->fsp_name, NULL, 0, &dir_hnd);
1941 if (!NT_STATUS_IS_OK(status)) {
1942 return status;
1945 while ((dname = ReadDirName(dir_hnd, &dirpos, NULL, &talloced))) {
1946 struct smb_filename *smb_dname_full = NULL;
1947 struct smb_filename *direntry_fname = NULL;
1948 char *fullname = NULL;
1949 int ret;
1951 if (ISDOT(dname) || (ISDOTDOT(dname))) {
1952 TALLOC_FREE(talloced);
1953 continue;
1955 if (IS_VETO_PATH(conn, dname)) {
1956 TALLOC_FREE(talloced);
1957 continue;
1960 fullname = talloc_asprintf(talloc_tos(),
1961 "%s/%s",
1962 fsp->fsp_name->base_name,
1963 dname);
1964 if (fullname == NULL) {
1965 status = NT_STATUS_NO_MEMORY;
1966 break;
1969 smb_dname_full = synthetic_smb_fname(talloc_tos(),
1970 fullname,
1971 NULL,
1972 NULL,
1973 fsp->fsp_name->twrp,
1974 fsp->fsp_name->flags);
1975 if (smb_dname_full == NULL) {
1976 TALLOC_FREE(talloced);
1977 TALLOC_FREE(fullname);
1978 status = NT_STATUS_NO_MEMORY;
1979 break;
1982 ret = SMB_VFS_LSTAT(conn, smb_dname_full);
1983 if (ret != 0) {
1984 status = map_nt_error_from_unix(errno);
1985 TALLOC_FREE(talloced);
1986 TALLOC_FREE(fullname);
1987 TALLOC_FREE(smb_dname_full);
1988 break;
1991 if (S_ISLNK(smb_dname_full->st.st_ex_mode)) {
1992 /* Could it be an msdfs link ? */
1993 if (lp_host_msdfs() &&
1994 lp_msdfs_root(SNUM(conn))) {
1995 struct smb_filename *smb_dname;
1996 smb_dname = synthetic_smb_fname(talloc_tos(),
1997 dname,
1998 NULL,
1999 &smb_dname_full->st,
2000 fsp->fsp_name->twrp,
2001 fsp->fsp_name->flags);
2002 if (smb_dname == NULL) {
2003 TALLOC_FREE(talloced);
2004 TALLOC_FREE(fullname);
2005 TALLOC_FREE(smb_dname_full);
2006 status = NT_STATUS_NO_MEMORY;
2007 break;
2009 if (is_msdfs_link(fsp, smb_dname)) {
2010 TALLOC_FREE(talloced);
2011 TALLOC_FREE(fullname);
2012 TALLOC_FREE(smb_dname_full);
2013 TALLOC_FREE(smb_dname);
2014 DBG_DEBUG("got msdfs link name %s "
2015 "- can't delete directory %s\n",
2016 dname,
2017 fsp_str_dbg(fsp));
2018 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
2019 break;
2021 TALLOC_FREE(smb_dname);
2023 /* Not a DFS link - could it be a dangling symlink ? */
2024 ret = SMB_VFS_STAT(conn, smb_dname_full);
2025 if (ret == -1 && (errno == ENOENT || errno == ELOOP)) {
2027 * Dangling symlink.
2028 * Allow if "delete veto files = yes"
2030 if (lp_delete_veto_files(SNUM(conn))) {
2031 TALLOC_FREE(talloced);
2032 TALLOC_FREE(fullname);
2033 TALLOC_FREE(smb_dname_full);
2034 continue;
2037 DBG_DEBUG("got symlink name %s - "
2038 "can't delete directory %s\n",
2039 dname,
2040 fsp_str_dbg(fsp));
2041 TALLOC_FREE(talloced);
2042 TALLOC_FREE(fullname);
2043 TALLOC_FREE(smb_dname_full);
2044 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
2045 break;
2048 /* Not a symlink, get a pathref. */
2049 status = synthetic_pathref(talloc_tos(),
2050 fsp,
2051 dname,
2052 NULL,
2053 &smb_dname_full->st,
2054 fsp->fsp_name->twrp,
2055 fsp->fsp_name->flags,
2056 &direntry_fname);
2057 if (!NT_STATUS_IS_OK(status)) {
2058 status = map_nt_error_from_unix(errno);
2059 TALLOC_FREE(talloced);
2060 TALLOC_FREE(fullname);
2061 TALLOC_FREE(smb_dname_full);
2062 break;
2065 if (!is_visible_fsp(direntry_fname->fsp)) {
2067 * Hidden file.
2068 * Allow if "delete veto files = yes"
2070 if (lp_delete_veto_files(SNUM(conn))) {
2071 TALLOC_FREE(talloced);
2072 TALLOC_FREE(fullname);
2073 TALLOC_FREE(smb_dname_full);
2074 TALLOC_FREE(direntry_fname);
2075 continue;
2079 TALLOC_FREE(talloced);
2080 TALLOC_FREE(fullname);
2081 TALLOC_FREE(smb_dname_full);
2082 TALLOC_FREE(direntry_fname);
2084 DBG_DEBUG("got name %s - can't delete\n", dname);
2085 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
2086 break;
2088 TALLOC_FREE(talloced);
2089 TALLOC_FREE(dir_hnd);
2091 if (!NT_STATUS_IS_OK(status)) {
2092 return status;
2095 if (!(fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) &&
2096 lp_strict_rename(SNUM(conn)) &&
2097 have_file_open_below(fsp->conn, fsp->fsp_name))
2099 return NT_STATUS_ACCESS_DENIED;
2102 return NT_STATUS_OK;