docs: Fix typo in man smb.conf.
[Samba.git] / source3 / smbd / dir.c
blob3c6f00096fa829bb96d44a1d6a4373800fb10120
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 "smbd/smbd.h"
24 #include "smbd/globals.h"
25 #include "libcli/security/security.h"
26 #include "lib/util/bitmap.h"
27 #include "../lib/util/memcache.h"
28 #include "../librpc/gen_ndr/open_files.h"
31 This module implements directory related functions for Samba.
34 /* "Special" directory offsets. */
35 #define END_OF_DIRECTORY_OFFSET ((long)-1)
36 #define START_OF_DIRECTORY_OFFSET ((long)0)
37 #define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
39 /* "Special" directory offsets in 32-bit wire format. */
40 #define WIRE_END_OF_DIRECTORY_OFFSET ((uint32_t)0xFFFFFFFF)
41 #define WIRE_START_OF_DIRECTORY_OFFSET ((uint32_t)0)
42 #define WIRE_DOT_DOT_DIRECTORY_OFFSET ((uint32_t)0x80000000)
44 /* Make directory handle internals available. */
46 struct name_cache_entry {
47 char *name;
48 long offset;
51 struct smb_Dir {
52 connection_struct *conn;
53 DIR *dir;
54 long offset;
55 struct smb_filename *dir_smb_fname;
56 size_t name_cache_size;
57 struct name_cache_entry *name_cache;
58 unsigned int name_cache_index;
59 unsigned int file_number;
60 files_struct *fsp; /* Back pointer to containing fsp, only
61 set from OpenDir_fsp(). */
64 struct dptr_struct {
65 struct dptr_struct *next, *prev;
66 int dnum;
67 uint16_t spid;
68 struct connection_struct *conn;
69 struct smb_Dir *dir_hnd;
70 bool expect_close;
71 char *wcard;
72 uint32_t attr;
73 struct smb_filename *smb_dname;
74 bool has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
75 bool did_stat; /* Optimisation for non-wcard searches. */
76 bool priv; /* Directory handle opened with privilege. */
77 uint32_t counter;
78 struct memcache *dptr_cache;
81 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
82 files_struct *fsp,
83 const char *mask,
84 uint32_t attr);
86 static void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset);
88 #define INVALID_DPTR_KEY (-3)
90 /****************************************************************************
91 Initialise the dir bitmap.
92 ****************************************************************************/
94 bool init_dptrs(struct smbd_server_connection *sconn)
96 if (sconn->searches.dptr_bmap) {
97 return true;
100 sconn->searches.dptr_bmap = bitmap_talloc(
101 sconn, MAX_DIRECTORY_HANDLES);
103 if (sconn->searches.dptr_bmap == NULL) {
104 return false;
107 return true;
110 /****************************************************************************
111 Idle a dptr - the directory is closed but the control info is kept.
112 ****************************************************************************/
114 static void dptr_idle(struct dptr_struct *dptr)
116 if (dptr->dir_hnd) {
117 DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
118 TALLOC_FREE(dptr->dir_hnd);
119 TALLOC_FREE(dptr->dptr_cache);
120 dptr->counter = 0;
124 /****************************************************************************
125 Idle the oldest dptr.
126 ****************************************************************************/
128 static void dptr_idleoldest(struct smbd_server_connection *sconn)
130 struct dptr_struct *dptr;
133 * Go to the end of the list.
135 dptr = DLIST_TAIL(sconn->searches.dirptrs);
137 if(!dptr) {
138 DEBUG(0,("No dptrs available to idle ?\n"));
139 return;
143 * Idle the oldest pointer.
146 for(; dptr; dptr = DLIST_PREV(dptr)) {
147 if (dptr->dir_hnd) {
148 dptr_idle(dptr);
149 return;
154 /****************************************************************************
155 Get the struct dptr_struct for a dir index.
156 ****************************************************************************/
158 static struct dptr_struct *dptr_get(struct smbd_server_connection *sconn,
159 int key, bool forclose)
161 struct dptr_struct *dptr;
163 for(dptr = sconn->searches.dirptrs; dptr; dptr = dptr->next) {
164 if(dptr->dnum == key) {
165 if (!forclose && !dptr->dir_hnd) {
166 if (sconn->searches.dirhandles_open >= MAX_OPEN_DIRECTORIES)
167 dptr_idleoldest(sconn);
168 DEBUG(4,("dptr_get: Reopening dptr key %d\n",key));
170 if (!(dptr->dir_hnd = OpenDir(NULL,
171 dptr->conn,
172 dptr->smb_dname,
173 dptr->wcard,
174 dptr->attr))) {
175 DEBUG(4,("dptr_get: Failed to "
176 "open %s (%s)\n",
177 dptr->smb_dname->base_name,
178 strerror(errno)));
179 return NULL;
182 DLIST_PROMOTE(sconn->searches.dirptrs,dptr);
183 return dptr;
186 return(NULL);
189 /****************************************************************************
190 Get the dir path for a dir index.
191 ****************************************************************************/
193 const char *dptr_path(struct smbd_server_connection *sconn, int key)
195 struct dptr_struct *dptr = dptr_get(sconn, key, false);
196 if (dptr)
197 return(dptr->smb_dname->base_name);
198 return(NULL);
201 /****************************************************************************
202 Get the dir wcard for a dir index.
203 ****************************************************************************/
205 const char *dptr_wcard(struct smbd_server_connection *sconn, int key)
207 struct dptr_struct *dptr = dptr_get(sconn, key, false);
208 if (dptr)
209 return(dptr->wcard);
210 return(NULL);
213 /****************************************************************************
214 Get the dir attrib for a dir index.
215 ****************************************************************************/
217 uint16_t dptr_attr(struct smbd_server_connection *sconn, int key)
219 struct dptr_struct *dptr = dptr_get(sconn, key, false);
220 if (dptr)
221 return(dptr->attr);
222 return(0);
225 /****************************************************************************
226 Close a dptr (internal func).
227 ****************************************************************************/
229 static void dptr_close_internal(struct dptr_struct *dptr)
231 struct smbd_server_connection *sconn = dptr->conn->sconn;
233 DEBUG(4,("closing dptr key %d\n",dptr->dnum));
235 if (sconn == NULL) {
236 goto done;
239 if (sconn->using_smb2) {
240 goto done;
243 DLIST_REMOVE(sconn->searches.dirptrs, dptr);
246 * Free the dnum in the bitmap. Remember the dnum value is always
247 * biased by one with respect to the bitmap.
250 if (!bitmap_query(sconn->searches.dptr_bmap, dptr->dnum - 1)) {
251 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
252 dptr->dnum ));
255 bitmap_clear(sconn->searches.dptr_bmap, dptr->dnum - 1);
257 done:
258 TALLOC_FREE(dptr->dir_hnd);
259 TALLOC_FREE(dptr);
262 /****************************************************************************
263 Close a dptr given a key.
264 ****************************************************************************/
266 void dptr_close(struct smbd_server_connection *sconn, int *key)
268 struct dptr_struct *dptr;
270 if(*key == INVALID_DPTR_KEY)
271 return;
273 /* OS/2 seems to use -1 to indicate "close all directories" */
274 if (*key == -1) {
275 struct dptr_struct *next;
276 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
277 next = dptr->next;
278 dptr_close_internal(dptr);
280 *key = INVALID_DPTR_KEY;
281 return;
284 dptr = dptr_get(sconn, *key, true);
286 if (!dptr) {
287 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
288 return;
291 dptr_close_internal(dptr);
293 *key = INVALID_DPTR_KEY;
296 /****************************************************************************
297 Close all dptrs for a cnum.
298 ****************************************************************************/
300 void dptr_closecnum(connection_struct *conn)
302 struct dptr_struct *dptr, *next;
303 struct smbd_server_connection *sconn = conn->sconn;
305 if (sconn == NULL) {
306 return;
309 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
310 next = dptr->next;
311 if (dptr->conn == conn) {
312 dptr_close_internal(dptr);
317 /****************************************************************************
318 Idle all dptrs for a cnum.
319 ****************************************************************************/
321 void dptr_idlecnum(connection_struct *conn)
323 struct dptr_struct *dptr;
324 struct smbd_server_connection *sconn = conn->sconn;
326 if (sconn == NULL) {
327 return;
330 for(dptr = sconn->searches.dirptrs; dptr; dptr = dptr->next) {
331 if (dptr->conn == conn && dptr->dir_hnd) {
332 dptr_idle(dptr);
337 /****************************************************************************
338 Close a dptr that matches a given path, only if it matches the spid also.
339 ****************************************************************************/
341 void dptr_closepath(struct smbd_server_connection *sconn,
342 char *path,uint16_t spid)
344 struct dptr_struct *dptr, *next;
345 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
346 next = dptr->next;
347 if (spid == dptr->spid &&
348 strequal(dptr->smb_dname->base_name,path)) {
349 dptr_close_internal(dptr);
354 /****************************************************************************
355 Try and close the oldest handle not marked for
356 expect close in the hope that the client has
357 finished with that one.
358 ****************************************************************************/
360 static void dptr_close_oldest(struct smbd_server_connection *sconn,
361 bool old)
363 struct dptr_struct *dptr;
366 * Go to the end of the list.
368 for(dptr = sconn->searches.dirptrs; dptr && dptr->next; dptr = dptr->next)
371 if(!dptr) {
372 DEBUG(0,("No old dptrs available to close oldest ?\n"));
373 return;
377 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
378 * does not have expect_close set. If 'old' is false, close
379 * one of the new dnum handles.
382 for(; dptr; dptr = DLIST_PREV(dptr)) {
383 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
384 (!old && (dptr->dnum > 255))) {
385 dptr_close_internal(dptr);
386 return;
391 /****************************************************************************
392 Safely do an OpenDir as root, ensuring we're in the right place.
393 ****************************************************************************/
395 static struct smb_Dir *open_dir_with_privilege(connection_struct *conn,
396 struct smb_request *req,
397 const struct smb_filename *smb_dname,
398 const char *wcard,
399 uint32_t attr)
401 struct smb_Dir *dir_hnd = NULL;
402 struct smb_filename *smb_fname_cwd;
403 char *saved_dir = vfs_GetWd(talloc_tos(), conn);
404 struct privilege_paths *priv_paths = req->priv_paths;
405 int ret;
407 if (saved_dir == NULL) {
408 return NULL;
411 if (vfs_ChDir(conn, smb_dname->base_name) == -1) {
412 return NULL;
415 /* Now check the stat value is the same. */
416 smb_fname_cwd = synthetic_smb_fname(talloc_tos(),
417 ".",
418 NULL,
419 NULL,
420 smb_dname->flags);
421 if (smb_fname_cwd == NULL) {
422 goto out;
424 ret = SMB_VFS_STAT(conn, smb_fname_cwd);
425 if (ret != 0) {
426 goto out;
429 if (!check_same_stat(&smb_fname_cwd->st, &priv_paths->parent_name.st)) {
430 DEBUG(0,("open_dir_with_privilege: stat mismatch between %s "
431 "and %s\n",
432 smb_dname->base_name,
433 smb_fname_str_dbg(&priv_paths->parent_name)));
434 goto out;
437 dir_hnd = OpenDir(NULL, conn, smb_fname_cwd, wcard, attr);
439 out:
441 vfs_ChDir(conn, saved_dir);
442 return dir_hnd;
445 /****************************************************************************
446 Create a new dir ptr. If the flag old_handle is true then we must allocate
447 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
448 one byte long. If old_handle is false we allocate from the range
449 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
450 a directory handle is never zero.
451 wcard must not be zero.
452 ****************************************************************************/
454 NTSTATUS dptr_create(connection_struct *conn,
455 struct smb_request *req,
456 files_struct *fsp,
457 const struct smb_filename *smb_dname,
458 bool old_handle,
459 bool expect_close,
460 uint16_t spid,
461 const char *wcard,
462 bool wcard_has_wild,
463 uint32_t attr,
464 struct dptr_struct **dptr_ret)
466 struct smbd_server_connection *sconn = conn->sconn;
467 struct dptr_struct *dptr = NULL;
468 struct smb_Dir *dir_hnd;
470 if (fsp && fsp->is_directory && fsp->fh->fd != -1) {
471 smb_dname = fsp->fsp_name;
474 DEBUG(5,("dptr_create dir=%s\n", smb_dname->base_name));
476 if (sconn == NULL) {
477 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
478 return NT_STATUS_INTERNAL_ERROR;
481 if (!wcard) {
482 return NT_STATUS_INVALID_PARAMETER;
485 if (fsp) {
486 if (!(fsp->access_mask & SEC_DIR_LIST)) {
487 DEBUG(5,("dptr_create: directory %s "
488 "not open for LIST access\n",
489 smb_dname->base_name));
490 return NT_STATUS_ACCESS_DENIED;
492 dir_hnd = OpenDir_fsp(NULL, conn, fsp, wcard, attr);
493 } else {
494 int ret;
495 bool backup_intent = (req && req->priv_paths);
496 NTSTATUS status;
497 struct smb_filename *smb_dname_cp =
498 cp_smb_filename(talloc_tos(), smb_dname);
500 if (smb_dname_cp == NULL) {
501 return NT_STATUS_NO_MEMORY;
504 if (req != NULL && req->posix_pathnames) {
505 ret = SMB_VFS_LSTAT(conn, smb_dname_cp);
506 } else {
507 ret = SMB_VFS_STAT(conn, smb_dname_cp);
509 if (ret == -1) {
510 status = map_nt_error_from_unix(errno);
511 TALLOC_FREE(smb_dname_cp);
512 return status;
514 if (!S_ISDIR(smb_dname_cp->st.st_ex_mode)) {
515 TALLOC_FREE(smb_dname_cp);
516 return NT_STATUS_NOT_A_DIRECTORY;
518 status = smbd_check_access_rights(conn,
519 smb_dname_cp,
520 backup_intent,
521 SEC_DIR_LIST);
522 if (!NT_STATUS_IS_OK(status)) {
523 TALLOC_FREE(smb_dname_cp);
524 return status;
526 if (backup_intent) {
527 dir_hnd = open_dir_with_privilege(conn,
528 req,
529 smb_dname_cp,
530 wcard,
531 attr);
532 } else {
533 dir_hnd = OpenDir(NULL,
534 conn,
535 smb_dname_cp,
536 wcard,
537 attr);
539 TALLOC_FREE(smb_dname_cp);
542 if (!dir_hnd) {
543 return map_nt_error_from_unix(errno);
546 if (sconn->searches.dirhandles_open >= MAX_OPEN_DIRECTORIES) {
547 dptr_idleoldest(sconn);
550 dptr = talloc_zero(NULL, struct dptr_struct);
551 if(!dptr) {
552 DEBUG(0,("talloc fail in dptr_create.\n"));
553 TALLOC_FREE(dir_hnd);
554 return NT_STATUS_NO_MEMORY;
557 dptr->smb_dname = cp_smb_filename(dptr, smb_dname);
558 if (!dptr->smb_dname) {
559 TALLOC_FREE(dptr);
560 TALLOC_FREE(dir_hnd);
561 return NT_STATUS_NO_MEMORY;
563 dptr->conn = conn;
564 dptr->dir_hnd = dir_hnd;
565 dptr->spid = spid;
566 dptr->expect_close = expect_close;
567 dptr->wcard = talloc_strdup(dptr, wcard);
568 if (!dptr->wcard) {
569 TALLOC_FREE(dptr);
570 TALLOC_FREE(dir_hnd);
571 return NT_STATUS_NO_MEMORY;
573 if ((req != NULL && req->posix_pathnames) ||
574 (wcard[0] == '.' && wcard[1] == 0)) {
575 dptr->has_wild = True;
576 } else {
577 dptr->has_wild = wcard_has_wild;
580 dptr->attr = attr;
582 if (sconn->using_smb2) {
583 goto done;
586 if(old_handle) {
589 * This is an old-style SMBsearch request. Ensure the
590 * value we return will fit in the range 1-255.
593 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
595 if(dptr->dnum == -1 || dptr->dnum > 254) {
598 * Try and close the oldest handle not marked for
599 * expect close in the hope that the client has
600 * finished with that one.
603 dptr_close_oldest(sconn, true);
605 /* Now try again... */
606 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
607 if(dptr->dnum == -1 || dptr->dnum > 254) {
608 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
609 TALLOC_FREE(dptr);
610 TALLOC_FREE(dir_hnd);
611 return NT_STATUS_TOO_MANY_OPENED_FILES;
614 } else {
617 * This is a new-style trans2 request. Allocate from
618 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
621 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
623 if(dptr->dnum == -1 || dptr->dnum < 255) {
626 * Try and close the oldest handle close in the hope that
627 * the client has finished with that one. This will only
628 * happen in the case of the Win98 client bug where it leaks
629 * directory handles.
632 dptr_close_oldest(sconn, false);
634 /* Now try again... */
635 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
637 if(dptr->dnum == -1 || dptr->dnum < 255) {
638 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
639 TALLOC_FREE(dptr);
640 TALLOC_FREE(dir_hnd);
641 return NT_STATUS_TOO_MANY_OPENED_FILES;
646 bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
648 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
650 DLIST_ADD(sconn->searches.dirptrs, dptr);
652 done:
653 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
654 dptr->dnum,
655 dptr->smb_dname->base_name,
656 expect_close));
658 *dptr_ret = dptr;
660 return NT_STATUS_OK;
664 /****************************************************************************
665 Wrapper functions to access the lower level directory handles.
666 ****************************************************************************/
668 void dptr_CloseDir(files_struct *fsp)
670 if (fsp->dptr) {
672 * The destructor for the struct smb_Dir
673 * (fsp->dptr->dir_hnd) now handles
674 * all resource deallocation.
676 dptr_close_internal(fsp->dptr);
677 fsp->dptr = NULL;
681 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
683 SeekDir(dptr->dir_hnd, offset);
686 long dptr_TellDir(struct dptr_struct *dptr)
688 return TellDir(dptr->dir_hnd);
691 bool dptr_has_wild(struct dptr_struct *dptr)
693 return dptr->has_wild;
696 int dptr_dnum(struct dptr_struct *dptr)
698 return dptr->dnum;
701 bool dptr_get_priv(struct dptr_struct *dptr)
703 return dptr->priv;
706 void dptr_set_priv(struct dptr_struct *dptr)
708 dptr->priv = true;
711 /****************************************************************************
712 Return the next visible file name, skipping veto'd and invisible files.
713 ****************************************************************************/
715 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr,
716 long *poffset, SMB_STRUCT_STAT *pst,
717 char **ptalloced)
719 /* Normal search for the next file. */
720 const char *name;
721 char *talloced = NULL;
723 while ((name = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced))
724 != NULL) {
725 if (is_visible_file(dptr->conn,
726 dptr->smb_dname->base_name,
727 name,
728 pst,
729 true)) {
730 *ptalloced = talloced;
731 return name;
733 TALLOC_FREE(talloced);
735 return NULL;
738 /****************************************************************************
739 Return the next visible file name, skipping veto'd and invisible files.
740 ****************************************************************************/
742 static char *dptr_ReadDirName(TALLOC_CTX *ctx,
743 struct dptr_struct *dptr,
744 long *poffset,
745 SMB_STRUCT_STAT *pst)
747 struct smb_filename smb_fname_base;
748 char *name = NULL;
749 const char *name_temp = NULL;
750 char *talloced = NULL;
751 char *pathreal = NULL;
752 char *found_name = NULL;
753 int ret;
755 SET_STAT_INVALID(*pst);
757 if (dptr->has_wild || dptr->did_stat) {
758 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst,
759 &talloced);
760 if (name_temp == NULL) {
761 return NULL;
763 if (talloced != NULL) {
764 return talloc_move(ctx, &talloced);
766 return talloc_strdup(ctx, name_temp);
769 /* If poffset is -1 then we know we returned this name before and we
770 * have no wildcards. We're at the end of the directory. */
771 if (*poffset == END_OF_DIRECTORY_OFFSET) {
772 return NULL;
775 /* We know the stored wcard contains no wildcard characters.
776 * See if we can match with a stat call. If we can't, then set
777 * did_stat to true to ensure we only do this once and keep
778 * searching. */
780 dptr->did_stat = true;
782 /* First check if it should be visible. */
783 if (!is_visible_file(dptr->conn,
784 dptr->smb_dname->base_name,
785 dptr->wcard,
786 pst,
787 true)) {
788 /* This only returns false if the file was found, but
789 is explicitly not visible. Set us to end of
790 directory, but return NULL as we know we can't ever
791 find it. */
792 goto ret;
795 if (VALID_STAT(*pst)) {
796 name = talloc_strdup(ctx, dptr->wcard);
797 goto ret;
800 pathreal = talloc_asprintf(ctx,
801 "%s/%s",
802 dptr->smb_dname->base_name,
803 dptr->wcard);
804 if (!pathreal)
805 return NULL;
807 /* Create an smb_filename with stream_name == NULL. */
808 smb_fname_base = (struct smb_filename) { .base_name = pathreal };
810 if (SMB_VFS_STAT(dptr->conn, &smb_fname_base) == 0) {
811 *pst = smb_fname_base.st;
812 name = talloc_strdup(ctx, dptr->wcard);
813 goto clean;
814 } else {
815 /* If we get any other error than ENOENT or ENOTDIR
816 then the file exists we just can't stat it. */
817 if (errno != ENOENT && errno != ENOTDIR) {
818 name = talloc_strdup(ctx, dptr->wcard);
819 goto clean;
823 /* Stat failed. We know this is authoratiative if we are
824 * providing case sensitive semantics or the underlying
825 * filesystem is case sensitive.
827 if (dptr->conn->case_sensitive ||
828 !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
830 goto clean;
834 * Try case-insensitive stat if the fs has the ability. This avoids
835 * scanning the whole directory.
837 ret = SMB_VFS_GET_REAL_FILENAME(dptr->conn,
838 dptr->smb_dname->base_name,
839 dptr->wcard,
840 ctx,
841 &found_name);
842 if (ret == 0) {
843 name = found_name;
844 goto clean;
845 } else if (errno == ENOENT) {
846 /* The case-insensitive lookup was authoritative. */
847 goto clean;
850 TALLOC_FREE(pathreal);
852 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst, &talloced);
853 if (name_temp == NULL) {
854 return NULL;
856 if (talloced != NULL) {
857 return talloc_move(ctx, &talloced);
859 return talloc_strdup(ctx, name_temp);
861 clean:
862 TALLOC_FREE(pathreal);
863 ret:
864 /* We need to set the underlying dir_hnd offset to -1
865 * also as this function is usually called with the
866 * output from TellDir. */
867 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
868 return name;
871 /****************************************************************************
872 Search for a file by name, skipping veto'ed and not visible files.
873 ****************************************************************************/
875 bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
877 SET_STAT_INVALID(*pst);
879 if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
880 /* This is a singleton directory and we're already at the end. */
881 *poffset = END_OF_DIRECTORY_OFFSET;
882 return False;
885 return SearchDir(dptr->dir_hnd, name, poffset);
888 /****************************************************************************
889 Initialize variables & state data at the beginning of all search SMB requests.
890 ****************************************************************************/
891 void dptr_init_search_op(struct dptr_struct *dptr)
893 SMB_VFS_INIT_SEARCH_OP(dptr->conn, dptr->dir_hnd->dir);
896 /****************************************************************************
897 Map a native directory offset to a 32-bit cookie.
898 ****************************************************************************/
900 static uint32_t map_dir_offset_to_wire(struct dptr_struct *dptr, long offset)
902 DATA_BLOB key;
903 DATA_BLOB val;
905 if (offset == END_OF_DIRECTORY_OFFSET) {
906 return WIRE_END_OF_DIRECTORY_OFFSET;
907 } else if(offset == START_OF_DIRECTORY_OFFSET) {
908 return WIRE_START_OF_DIRECTORY_OFFSET;
909 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
910 return WIRE_DOT_DOT_DIRECTORY_OFFSET;
912 if (sizeof(long) == 4) {
913 /* 32-bit machine. We can cheat... */
914 return (uint32_t)offset;
916 if (dptr->dptr_cache == NULL) {
917 /* Lazy initialize cache. */
918 dptr->dptr_cache = memcache_init(dptr, 0);
919 if (dptr->dptr_cache == NULL) {
920 return WIRE_END_OF_DIRECTORY_OFFSET;
922 } else {
923 /* Have we seen this offset before ? */
924 key.data = (void *)&offset;
925 key.length = sizeof(offset);
926 if (memcache_lookup(dptr->dptr_cache,
927 SMB1_SEARCH_OFFSET_MAP,
928 key,
929 &val)) {
930 uint32_t wire_offset;
931 SMB_ASSERT(val.length == sizeof(wire_offset));
932 memcpy(&wire_offset, val.data, sizeof(wire_offset));
933 DEBUG(10,("found wire %u <-> offset %ld\n",
934 (unsigned int)wire_offset,
935 (long)offset));
936 return wire_offset;
939 /* Allocate a new wire cookie. */
940 do {
941 dptr->counter++;
942 } while (dptr->counter == WIRE_START_OF_DIRECTORY_OFFSET ||
943 dptr->counter == WIRE_END_OF_DIRECTORY_OFFSET ||
944 dptr->counter == WIRE_DOT_DOT_DIRECTORY_OFFSET);
945 /* Store it in the cache. */
946 key.data = (void *)&offset;
947 key.length = sizeof(offset);
948 val.data = (void *)&dptr->counter;
949 val.length = sizeof(dptr->counter); /* MUST BE uint32_t ! */
950 memcache_add(dptr->dptr_cache,
951 SMB1_SEARCH_OFFSET_MAP,
952 key,
953 val);
954 /* And the reverse mapping for lookup from
955 map_wire_to_dir_offset(). */
956 memcache_add(dptr->dptr_cache,
957 SMB1_SEARCH_OFFSET_MAP,
958 val,
959 key);
960 DEBUG(10,("stored wire %u <-> offset %ld\n",
961 (unsigned int)dptr->counter,
962 (long)offset));
963 return dptr->counter;
966 /****************************************************************************
967 Fill the 5 byte server reserved dptr field.
968 ****************************************************************************/
970 bool dptr_fill(struct smbd_server_connection *sconn,
971 char *buf1,unsigned int key)
973 unsigned char *buf = (unsigned char *)buf1;
974 struct dptr_struct *dptr = dptr_get(sconn, key, false);
975 uint32_t wire_offset;
976 if (!dptr) {
977 DEBUG(1,("filling null dirptr %d\n",key));
978 return(False);
980 wire_offset = map_dir_offset_to_wire(dptr,TellDir(dptr->dir_hnd));
981 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
982 (long)dptr->dir_hnd,(int)wire_offset));
983 buf[0] = key;
984 SIVAL(buf,1,wire_offset);
985 return(True);
988 /****************************************************************************
989 Map a 32-bit wire cookie to a native directory offset.
990 ****************************************************************************/
992 static long map_wire_to_dir_offset(struct dptr_struct *dptr, uint32_t wire_offset)
994 DATA_BLOB key;
995 DATA_BLOB val;
997 if (wire_offset == WIRE_END_OF_DIRECTORY_OFFSET) {
998 return END_OF_DIRECTORY_OFFSET;
999 } else if(wire_offset == WIRE_START_OF_DIRECTORY_OFFSET) {
1000 return START_OF_DIRECTORY_OFFSET;
1001 } else if (wire_offset == WIRE_DOT_DOT_DIRECTORY_OFFSET) {
1002 return DOT_DOT_DIRECTORY_OFFSET;
1004 if (sizeof(long) == 4) {
1005 /* 32-bit machine. We can cheat... */
1006 return (long)wire_offset;
1008 if (dptr->dptr_cache == NULL) {
1009 /* Logic error, cache should be initialized. */
1010 return END_OF_DIRECTORY_OFFSET;
1012 key.data = (void *)&wire_offset;
1013 key.length = sizeof(wire_offset);
1014 if (memcache_lookup(dptr->dptr_cache,
1015 SMB1_SEARCH_OFFSET_MAP,
1016 key,
1017 &val)) {
1018 /* Found mapping. */
1019 long offset;
1020 SMB_ASSERT(val.length == sizeof(offset));
1021 memcpy(&offset, val.data, sizeof(offset));
1022 DEBUG(10,("lookup wire %u <-> offset %ld\n",
1023 (unsigned int)wire_offset,
1024 (long)offset));
1025 return offset;
1027 return END_OF_DIRECTORY_OFFSET;
1030 /****************************************************************************
1031 Fetch the dir ptr and seek it given the 5 byte server field.
1032 ****************************************************************************/
1034 struct dptr_struct *dptr_fetch(struct smbd_server_connection *sconn,
1035 char *buf, int *num)
1037 unsigned int key = *(unsigned char *)buf;
1038 struct dptr_struct *dptr = dptr_get(sconn, key, false);
1039 uint32_t wire_offset;
1040 long seekoff;
1042 if (!dptr) {
1043 DEBUG(3,("fetched null dirptr %d\n",key));
1044 return(NULL);
1046 *num = key;
1047 wire_offset = IVAL(buf,1);
1048 seekoff = map_wire_to_dir_offset(dptr, wire_offset);
1049 SeekDir(dptr->dir_hnd,seekoff);
1050 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
1051 key, dptr->smb_dname->base_name, (int)seekoff));
1052 return(dptr);
1055 /****************************************************************************
1056 Fetch the dir ptr.
1057 ****************************************************************************/
1059 struct dptr_struct *dptr_fetch_lanman2(struct smbd_server_connection *sconn,
1060 int dptr_num)
1062 struct dptr_struct *dptr = dptr_get(sconn, dptr_num, false);
1064 if (!dptr) {
1065 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
1066 return(NULL);
1068 DEBUG(3,("fetching dirptr %d for path %s\n",
1069 dptr_num,
1070 dptr->smb_dname->base_name));
1071 return(dptr);
1074 static bool mangle_mask_match(connection_struct *conn,
1075 const char *filename,
1076 const char *mask)
1078 char mname[13];
1080 if (!name_to_8_3(filename,mname,False,conn->params)) {
1081 return False;
1083 return mask_match_search(mname,mask,False);
1086 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
1087 struct dptr_struct *dirptr,
1088 const char *mask,
1089 uint32_t dirtype,
1090 bool dont_descend,
1091 bool ask_sharemode,
1092 bool (*match_fn)(TALLOC_CTX *ctx,
1093 void *private_data,
1094 const char *dname,
1095 const char *mask,
1096 char **_fname),
1097 bool (*mode_fn)(TALLOC_CTX *ctx,
1098 void *private_data,
1099 struct smb_filename *smb_fname,
1100 uint32_t *_mode),
1101 void *private_data,
1102 char **_fname,
1103 struct smb_filename **_smb_fname,
1104 uint32_t *_mode,
1105 long *_prev_offset)
1107 connection_struct *conn = dirptr->conn;
1108 size_t slashlen;
1109 size_t pathlen;
1110 const char *dpath = dirptr->smb_dname->base_name;
1111 bool dirptr_path_is_dot = ISDOT(dpath);
1113 *_smb_fname = NULL;
1114 *_mode = 0;
1116 pathlen = strlen(dpath);
1117 slashlen = ( dpath[pathlen-1] != '/') ? 1 : 0;
1119 while (true) {
1120 long cur_offset;
1121 long prev_offset;
1122 SMB_STRUCT_STAT sbuf = { 0 };
1123 char *dname = NULL;
1124 bool isdots;
1125 char *fname = NULL;
1126 char *pathreal = NULL;
1127 struct smb_filename smb_fname;
1128 uint32_t mode = 0;
1129 bool ok;
1131 cur_offset = dptr_TellDir(dirptr);
1132 prev_offset = cur_offset;
1133 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
1135 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
1136 (long)dirptr, cur_offset));
1138 if (dname == NULL) {
1139 return false;
1142 isdots = (ISDOT(dname) || ISDOTDOT(dname));
1143 if (dont_descend && !isdots) {
1144 TALLOC_FREE(dname);
1145 continue;
1149 * fname may get mangled, dname is never mangled.
1150 * Whenever we're accessing the filesystem we use
1151 * pathreal which is composed from dname.
1154 ok = match_fn(ctx, private_data, dname, mask, &fname);
1155 if (!ok) {
1156 TALLOC_FREE(dname);
1157 continue;
1161 * This used to be
1162 * pathreal = talloc_asprintf(ctx, "%s%s%s", dirptr->path,
1163 * needslash?"/":"", dname);
1164 * but this was measurably slower than doing the memcpy.
1167 pathreal = talloc_array(
1168 ctx, char,
1169 pathlen + slashlen + talloc_get_size(dname));
1170 if (!pathreal) {
1171 TALLOC_FREE(dname);
1172 TALLOC_FREE(fname);
1173 return false;
1177 * We don't want to pass ./xxx to modules below us so don't
1178 * add the path if it is just . by itself.
1180 if (dirptr_path_is_dot) {
1181 memcpy(pathreal, dname, talloc_get_size(dname));
1182 } else {
1183 memcpy(pathreal, dpath, pathlen);
1184 pathreal[pathlen] = '/';
1185 memcpy(pathreal + slashlen + pathlen, dname,
1186 talloc_get_size(dname));
1189 /* Create smb_fname with NULL stream_name. */
1190 smb_fname = (struct smb_filename) {
1191 .base_name = pathreal, .st = sbuf
1194 ok = mode_fn(ctx, private_data, &smb_fname, &mode);
1195 if (!ok) {
1196 TALLOC_FREE(dname);
1197 TALLOC_FREE(fname);
1198 TALLOC_FREE(pathreal);
1199 continue;
1202 if (!dir_check_ftype(mode, dirtype)) {
1203 DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
1204 fname, (unsigned int)mode, (unsigned int)dirtype));
1205 TALLOC_FREE(dname);
1206 TALLOC_FREE(fname);
1207 TALLOC_FREE(pathreal);
1208 continue;
1211 if (ask_sharemode) {
1212 struct timespec write_time_ts;
1213 struct file_id fileid;
1215 fileid = vfs_file_id_from_sbuf(conn,
1216 &smb_fname.st);
1217 get_file_infos(fileid, 0, NULL, &write_time_ts);
1218 if (!null_timespec(write_time_ts)) {
1219 update_stat_ex_mtime(&smb_fname.st,
1220 write_time_ts);
1224 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
1225 "fname=%s (%s)\n",
1226 mask, smb_fname_str_dbg(&smb_fname),
1227 dname, fname));
1229 DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
1231 TALLOC_FREE(dname);
1233 *_smb_fname = cp_smb_filename(ctx, &smb_fname);
1234 TALLOC_FREE(pathreal);
1235 if (*_smb_fname == NULL) {
1236 return false;
1238 *_fname = fname;
1239 *_mode = mode;
1240 *_prev_offset = prev_offset;
1242 return true;
1245 return false;
1248 /****************************************************************************
1249 Get an 8.3 directory entry.
1250 ****************************************************************************/
1252 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
1253 void *private_data,
1254 const char *dname,
1255 const char *mask,
1256 char **_fname)
1258 connection_struct *conn = (connection_struct *)private_data;
1260 if ((strcmp(mask,"*.*") == 0) ||
1261 mask_match_search(dname, mask, false) ||
1262 mangle_mask_match(conn, dname, mask)) {
1263 char mname[13];
1264 const char *fname;
1266 * Ensure we can push the original name as UCS2. If
1267 * not, then just don't return this name.
1269 NTSTATUS status;
1270 size_t ret_len = 0;
1271 size_t len = (strlen(dname) + 2) * 4; /* Allow enough space. */
1272 uint8_t *tmp = talloc_array(talloc_tos(),
1273 uint8_t,
1274 len);
1276 status = srvstr_push(NULL,
1277 FLAGS2_UNICODE_STRINGS,
1278 tmp,
1279 dname,
1280 len,
1281 STR_TERMINATE,
1282 &ret_len);
1284 TALLOC_FREE(tmp);
1286 if (!NT_STATUS_IS_OK(status)) {
1287 return false;
1290 if (!mangle_is_8_3(dname, false, conn->params)) {
1291 bool ok = name_to_8_3(dname, mname, false,
1292 conn->params);
1293 if (!ok) {
1294 return false;
1296 fname = mname;
1297 } else {
1298 fname = dname;
1301 *_fname = talloc_strdup(ctx, fname);
1302 if (*_fname == NULL) {
1303 return false;
1306 return true;
1309 return false;
1312 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1313 void *private_data,
1314 struct smb_filename *smb_fname,
1315 uint32_t *_mode)
1317 connection_struct *conn = (connection_struct *)private_data;
1319 if (!VALID_STAT(smb_fname->st)) {
1320 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1321 DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1322 "Couldn't stat [%s]. Error "
1323 "= %s\n",
1324 smb_fname_str_dbg(smb_fname),
1325 strerror(errno)));
1326 return false;
1330 *_mode = dos_mode(conn, smb_fname);
1331 return true;
1334 bool get_dir_entry(TALLOC_CTX *ctx,
1335 struct dptr_struct *dirptr,
1336 const char *mask,
1337 uint32_t dirtype,
1338 char **_fname,
1339 off_t *_size,
1340 uint32_t *_mode,
1341 struct timespec *_date,
1342 bool check_descend,
1343 bool ask_sharemode)
1345 connection_struct *conn = dirptr->conn;
1346 char *fname = NULL;
1347 struct smb_filename *smb_fname = NULL;
1348 uint32_t mode = 0;
1349 long prev_offset;
1350 bool ok;
1352 ok = smbd_dirptr_get_entry(ctx,
1353 dirptr,
1354 mask,
1355 dirtype,
1356 check_descend,
1357 ask_sharemode,
1358 smbd_dirptr_8_3_match_fn,
1359 smbd_dirptr_8_3_mode_fn,
1360 conn,
1361 &fname,
1362 &smb_fname,
1363 &mode,
1364 &prev_offset);
1365 if (!ok) {
1366 return false;
1369 *_fname = talloc_move(ctx, &fname);
1370 *_size = smb_fname->st.st_ex_size;
1371 *_mode = mode;
1372 *_date = smb_fname->st.st_ex_mtime;
1373 TALLOC_FREE(smb_fname);
1374 return true;
1377 /*******************************************************************
1378 Check to see if a user can read a file. This is only approximate,
1379 it is used as part of the "hide unreadable" option. Don't
1380 use it for anything security sensitive.
1381 ********************************************************************/
1383 static bool user_can_read_file(connection_struct *conn,
1384 struct smb_filename *smb_fname)
1386 NTSTATUS status;
1387 uint32_t rejected_share_access = 0;
1388 uint32_t rejected_mask = 0;
1389 struct security_descriptor *sd = NULL;
1390 uint32_t access_mask = FILE_READ_DATA|
1391 FILE_READ_EA|
1392 FILE_READ_ATTRIBUTES|
1393 SEC_STD_READ_CONTROL;
1396 * Never hide files from the root user.
1397 * We use (uid_t)0 here not sec_initial_uid()
1398 * as make test uses a single user context.
1401 if (get_current_uid(conn) == (uid_t)0) {
1402 return True;
1406 * We can't directly use smbd_check_access_rights()
1407 * here, as this implicitly grants FILE_READ_ATTRIBUTES
1408 * which the Windows access-based-enumeration code
1409 * explicitly checks for on the file security descriptor.
1410 * See bug:
1412 * https://bugzilla.samba.org/show_bug.cgi?id=10252
1414 * and the smb2.acl2.ACCESSBASED test for details.
1417 rejected_share_access = access_mask & ~(conn->share_access);
1418 if (rejected_share_access) {
1419 DEBUG(10, ("rejected share access 0x%x "
1420 "on %s (0x%x)\n",
1421 (unsigned int)access_mask,
1422 smb_fname_str_dbg(smb_fname),
1423 (unsigned int)rejected_share_access ));
1424 return false;
1427 status = SMB_VFS_GET_NT_ACL(conn,
1428 smb_fname,
1429 (SECINFO_OWNER |
1430 SECINFO_GROUP |
1431 SECINFO_DACL),
1432 talloc_tos(),
1433 &sd);
1435 if (!NT_STATUS_IS_OK(status)) {
1436 DEBUG(10, ("Could not get acl "
1437 "on %s: %s\n",
1438 smb_fname_str_dbg(smb_fname),
1439 nt_errstr(status)));
1440 return false;
1443 status = se_file_access_check(sd,
1444 get_current_nttok(conn),
1445 false,
1446 access_mask,
1447 &rejected_mask);
1449 TALLOC_FREE(sd);
1451 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1452 DEBUG(10,("rejected bits 0x%x read access for %s\n",
1453 (unsigned int)rejected_mask,
1454 smb_fname_str_dbg(smb_fname) ));
1455 return false;
1457 return true;
1460 /*******************************************************************
1461 Check to see if a user can write a file (and only files, we do not
1462 check dirs on this one). This is only approximate,
1463 it is used as part of the "hide unwriteable" option. Don't
1464 use it for anything security sensitive.
1465 ********************************************************************/
1467 static bool user_can_write_file(connection_struct *conn,
1468 const struct smb_filename *smb_fname)
1471 * Never hide files from the root user.
1472 * We use (uid_t)0 here not sec_initial_uid()
1473 * as make test uses a single user context.
1476 if (get_current_uid(conn) == (uid_t)0) {
1477 return True;
1480 SMB_ASSERT(VALID_STAT(smb_fname->st));
1482 /* Pseudo-open the file */
1484 if(S_ISDIR(smb_fname->st.st_ex_mode)) {
1485 return True;
1488 return can_write_to_file(conn, smb_fname);
1491 /*******************************************************************
1492 Is a file a "special" type ?
1493 ********************************************************************/
1495 static bool file_is_special(connection_struct *conn,
1496 const struct smb_filename *smb_fname)
1499 * Never hide files from the root user.
1500 * We use (uid_t)0 here not sec_initial_uid()
1501 * as make test uses a single user context.
1504 if (get_current_uid(conn) == (uid_t)0) {
1505 return False;
1508 SMB_ASSERT(VALID_STAT(smb_fname->st));
1510 if (S_ISREG(smb_fname->st.st_ex_mode) ||
1511 S_ISDIR(smb_fname->st.st_ex_mode) ||
1512 S_ISLNK(smb_fname->st.st_ex_mode))
1513 return False;
1515 return True;
1518 /*******************************************************************
1519 Should the file be seen by the client?
1520 NOTE: A successful return is no guarantee of the file's existence.
1521 ********************************************************************/
1523 bool is_visible_file(connection_struct *conn, const char *dir_path,
1524 const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
1526 bool hide_unreadable = lp_hide_unreadable(SNUM(conn));
1527 bool hide_unwriteable = lp_hide_unwriteable_files(SNUM(conn));
1528 bool hide_special = lp_hide_special_files(SNUM(conn));
1529 char *entry = NULL;
1530 struct smb_filename *smb_fname_base = NULL;
1531 bool ret = false;
1533 if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1534 return True; /* . and .. are always visible. */
1537 /* If it's a vetoed file, pretend it doesn't even exist */
1538 if (use_veto && IS_VETO_PATH(conn, name)) {
1539 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1540 return False;
1543 if (hide_unreadable || hide_unwriteable || hide_special) {
1544 entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name);
1545 if (!entry) {
1546 ret = false;
1547 goto out;
1550 /* Create an smb_filename with stream_name == NULL. */
1551 smb_fname_base = synthetic_smb_fname(talloc_tos(),
1552 entry,
1553 NULL,
1554 pst,
1556 if (smb_fname_base == NULL) {
1557 ret = false;
1558 goto out;
1561 /* If the file name does not exist, there's no point checking
1562 * the configuration options. We succeed, on the basis that the
1563 * checks *might* have passed if the file was present.
1565 if (!VALID_STAT(*pst)) {
1566 if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
1567 ret = true;
1568 goto out;
1570 *pst = smb_fname_base->st;
1573 /* Honour _hide unreadable_ option */
1574 if (hide_unreadable &&
1575 !user_can_read_file(conn, smb_fname_base)) {
1576 DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1577 entry ));
1578 ret = false;
1579 goto out;
1581 /* Honour _hide unwriteable_ option */
1582 if (hide_unwriteable && !user_can_write_file(conn,
1583 smb_fname_base)) {
1584 DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1585 entry ));
1586 ret = false;
1587 goto out;
1589 /* Honour _hide_special_ option */
1590 if (hide_special && file_is_special(conn, smb_fname_base)) {
1591 DEBUG(10,("is_visible_file: file %s is special.\n",
1592 entry ));
1593 ret = false;
1594 goto out;
1598 ret = true;
1599 out:
1600 TALLOC_FREE(smb_fname_base);
1601 TALLOC_FREE(entry);
1602 return ret;
1605 static int smb_Dir_destructor(struct smb_Dir *dirp)
1607 if (dirp->dir != NULL) {
1608 SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1609 if (dirp->fsp != NULL) {
1611 * The SMB_VFS_CLOSEDIR above
1612 * closes the underlying fd inside
1613 * dirp->fsp.
1615 dirp->fsp->fh->fd = -1;
1616 if (dirp->fsp->dptr != NULL) {
1617 SMB_ASSERT(dirp->fsp->dptr->dir_hnd == dirp);
1618 dirp->fsp->dptr->dir_hnd = NULL;
1620 dirp->fsp = NULL;
1623 if (dirp->conn->sconn && !dirp->conn->sconn->using_smb2) {
1624 dirp->conn->sconn->searches.dirhandles_open--;
1626 return 0;
1629 /*******************************************************************
1630 Open a directory.
1631 ********************************************************************/
1633 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1634 const struct smb_filename *smb_dname,
1635 const char *mask,
1636 uint32_t attr)
1638 struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1639 struct smbd_server_connection *sconn = conn->sconn;
1641 if (!dirp) {
1642 return NULL;
1645 dirp->conn = conn;
1646 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1648 dirp->dir_smb_fname = cp_smb_filename(dirp, smb_dname);
1649 if (!dirp->dir_smb_fname) {
1650 errno = ENOMEM;
1651 goto fail;
1654 if (sconn && !sconn->using_smb2) {
1655 sconn->searches.dirhandles_open++;
1657 talloc_set_destructor(dirp, smb_Dir_destructor);
1659 dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_smb_fname, mask, attr);
1661 if (!dirp->dir) {
1662 DEBUG(5,("OpenDir: Can't open %s. %s\n",
1663 dirp->dir_smb_fname->base_name,
1664 strerror(errno) ));
1665 goto fail;
1668 return dirp;
1670 fail:
1671 TALLOC_FREE(dirp);
1672 return NULL;
1675 /*******************************************************************
1676 Open a directory from an fsp.
1677 ********************************************************************/
1679 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
1680 files_struct *fsp,
1681 const char *mask,
1682 uint32_t attr)
1684 struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1685 struct smbd_server_connection *sconn = conn->sconn;
1687 if (!dirp) {
1688 return NULL;
1691 dirp->conn = conn;
1692 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1694 dirp->dir_smb_fname = cp_smb_filename(dirp, fsp->fsp_name);
1695 if (!dirp->dir_smb_fname) {
1696 errno = ENOMEM;
1697 goto fail;
1700 if (sconn && !sconn->using_smb2) {
1701 sconn->searches.dirhandles_open++;
1703 talloc_set_destructor(dirp, smb_Dir_destructor);
1705 if (fsp->is_directory && fsp->fh->fd != -1) {
1706 dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1707 if (dirp->dir != NULL) {
1708 dirp->fsp = fsp;
1709 } else {
1710 DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1711 "NULL (%s)\n",
1712 dirp->dir_smb_fname->base_name,
1713 strerror(errno)));
1714 if (errno != ENOSYS) {
1715 return NULL;
1720 if (dirp->dir == NULL) {
1721 /* FDOPENDIR didn't work. Use OPENDIR instead. */
1722 dirp->dir = SMB_VFS_OPENDIR(conn,
1723 dirp->dir_smb_fname,
1724 mask,
1725 attr);
1728 if (!dirp->dir) {
1729 DEBUG(5,("OpenDir_fsp: Can't open %s. %s\n",
1730 dirp->dir_smb_fname->base_name,
1731 strerror(errno) ));
1732 goto fail;
1735 return dirp;
1737 fail:
1738 TALLOC_FREE(dirp);
1739 return NULL;
1743 /*******************************************************************
1744 Read from a directory.
1745 Return directory entry, current offset, and optional stat information.
1746 Don't check for veto or invisible files.
1747 ********************************************************************/
1749 const char *ReadDirName(struct smb_Dir *dirp, long *poffset,
1750 SMB_STRUCT_STAT *sbuf, char **ptalloced)
1752 const char *n;
1753 char *talloced = NULL;
1754 connection_struct *conn = dirp->conn;
1756 /* Cheat to allow . and .. to be the first entries returned. */
1757 if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1758 (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2))
1760 if (dirp->file_number == 0) {
1761 n = ".";
1762 *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1763 } else {
1764 n = "..";
1765 *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1767 dirp->file_number++;
1768 *ptalloced = NULL;
1769 return n;
1772 if (*poffset == END_OF_DIRECTORY_OFFSET) {
1773 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1774 return NULL;
1777 /* A real offset, seek to it. */
1778 SeekDir(dirp, *poffset);
1780 while ((n = vfs_readdirname(conn, dirp->dir, sbuf, &talloced))) {
1781 /* Ignore . and .. - we've already returned them. */
1782 if (*n == '.') {
1783 if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1784 TALLOC_FREE(talloced);
1785 continue;
1788 *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1789 *ptalloced = talloced;
1790 dirp->file_number++;
1791 return n;
1793 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1794 *ptalloced = NULL;
1795 return NULL;
1798 /*******************************************************************
1799 Rewind to the start.
1800 ********************************************************************/
1802 void RewindDir(struct smb_Dir *dirp, long *poffset)
1804 SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1805 dirp->file_number = 0;
1806 dirp->offset = START_OF_DIRECTORY_OFFSET;
1807 *poffset = START_OF_DIRECTORY_OFFSET;
1810 /*******************************************************************
1811 Seek a dir.
1812 ********************************************************************/
1814 void SeekDir(struct smb_Dir *dirp, long offset)
1816 if (offset != dirp->offset) {
1817 if (offset == START_OF_DIRECTORY_OFFSET) {
1818 RewindDir(dirp, &offset);
1820 * Ok we should really set the file number here
1821 * to 1 to enable ".." to be returned next. Trouble
1822 * is I'm worried about callers using SeekDir(dirp,0)
1823 * as equivalent to RewindDir(). So leave this alone
1824 * for now.
1826 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
1827 RewindDir(dirp, &offset);
1829 * Set the file number to 2 - we want to get the first
1830 * real file entry (the one we return after "..")
1831 * on the next ReadDir.
1833 dirp->file_number = 2;
1834 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1835 ; /* Don't seek in this case. */
1836 } else {
1837 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1839 dirp->offset = offset;
1843 /*******************************************************************
1844 Tell a dir position.
1845 ********************************************************************/
1847 long TellDir(struct smb_Dir *dirp)
1849 return(dirp->offset);
1852 /*******************************************************************
1853 Add an entry into the dcache.
1854 ********************************************************************/
1856 static void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
1858 struct name_cache_entry *e;
1860 if (dirp->name_cache_size == 0) {
1861 return;
1864 if (dirp->name_cache == NULL) {
1865 dirp->name_cache = talloc_zero_array(
1866 dirp, struct name_cache_entry, dirp->name_cache_size);
1868 if (dirp->name_cache == NULL) {
1869 return;
1873 dirp->name_cache_index = (dirp->name_cache_index+1) %
1874 dirp->name_cache_size;
1875 e = &dirp->name_cache[dirp->name_cache_index];
1876 TALLOC_FREE(e->name);
1877 e->name = talloc_strdup(dirp, name);
1878 e->offset = offset;
1881 /*******************************************************************
1882 Find an entry by name. Leave us at the offset after it.
1883 Don't check for veto or invisible files.
1884 ********************************************************************/
1886 bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1888 int i;
1889 const char *entry = NULL;
1890 char *talloced = NULL;
1891 connection_struct *conn = dirp->conn;
1893 /* Search back in the name cache. */
1894 if (dirp->name_cache_size && dirp->name_cache) {
1895 for (i = dirp->name_cache_index; i >= 0; i--) {
1896 struct name_cache_entry *e = &dirp->name_cache[i];
1897 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1898 *poffset = e->offset;
1899 SeekDir(dirp, e->offset);
1900 return True;
1903 for (i = dirp->name_cache_size - 1; i > dirp->name_cache_index; i--) {
1904 struct name_cache_entry *e = &dirp->name_cache[i];
1905 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1906 *poffset = e->offset;
1907 SeekDir(dirp, e->offset);
1908 return True;
1913 /* Not found in the name cache. Rewind directory and start from scratch. */
1914 SMB_VFS_REWINDDIR(conn, dirp->dir);
1915 dirp->file_number = 0;
1916 *poffset = START_OF_DIRECTORY_OFFSET;
1917 while ((entry = ReadDirName(dirp, poffset, NULL, &talloced))) {
1918 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1919 TALLOC_FREE(talloced);
1920 return True;
1922 TALLOC_FREE(talloced);
1924 return False;
1927 struct files_below_forall_state {
1928 char *dirpath;
1929 size_t dirpath_len;
1930 int (*fn)(struct file_id fid, const struct share_mode_data *data,
1931 void *private_data);
1932 void *private_data;
1935 static int files_below_forall_fn(struct file_id fid,
1936 const struct share_mode_data *data,
1937 void *private_data)
1939 struct files_below_forall_state *state = private_data;
1940 char tmpbuf[PATH_MAX];
1941 char *fullpath, *to_free;
1942 size_t len;
1944 len = full_path_tos(data->servicepath, data->base_name,
1945 tmpbuf, sizeof(tmpbuf),
1946 &fullpath, &to_free);
1947 if (len == -1) {
1948 return 0;
1950 if (state->dirpath_len >= len) {
1952 * Filter files above dirpath
1954 return 0;
1956 if (fullpath[state->dirpath_len] != '/') {
1958 * Filter file that don't have a path separator at the end of
1959 * dirpath's length
1961 return 0;
1964 if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
1966 * Not a parent
1968 return 0;
1971 return state->fn(fid, data, state->private_data);
1974 static int files_below_forall(connection_struct *conn,
1975 const struct smb_filename *dir_name,
1976 int (*fn)(struct file_id fid,
1977 const struct share_mode_data *data,
1978 void *private_data),
1979 void *private_data)
1981 struct files_below_forall_state state = {
1982 .fn = fn,
1983 .private_data = private_data,
1985 int ret;
1986 char tmpbuf[PATH_MAX];
1987 char *to_free;
1989 state.dirpath_len = full_path_tos(conn->connectpath,
1990 dir_name->base_name,
1991 tmpbuf, sizeof(tmpbuf),
1992 &state.dirpath, &to_free);
1993 if (state.dirpath_len == -1) {
1994 return -1;
1997 ret = share_mode_forall(files_below_forall_fn, &state);
1998 TALLOC_FREE(to_free);
1999 return ret;
2002 struct have_file_open_below_state {
2003 bool found_one;
2006 static int have_file_open_below_fn(struct file_id fid,
2007 const struct share_mode_data *data,
2008 void *private_data)
2010 struct have_file_open_below_state *state = private_data;
2011 state->found_one = true;
2012 return 1;
2015 bool have_file_open_below(connection_struct *conn,
2016 const struct smb_filename *name)
2018 struct have_file_open_below_state state = {
2019 .found_one = false,
2021 int ret;
2023 if (!VALID_STAT(name->st)) {
2024 return false;
2026 if (!S_ISDIR(name->st.st_ex_mode)) {
2027 return false;
2030 ret = files_below_forall(conn, name, have_file_open_below_fn, &state);
2031 if (ret == -1) {
2032 return false;
2035 return state.found_one;
2038 /*****************************************************************
2039 Is this directory empty ?
2040 *****************************************************************/
2042 NTSTATUS can_delete_directory_fsp(files_struct *fsp)
2044 NTSTATUS status = NT_STATUS_OK;
2045 long dirpos = 0;
2046 const char *dname = NULL;
2047 const char *dirname = fsp->fsp_name->base_name;
2048 char *talloced = NULL;
2049 SMB_STRUCT_STAT st;
2050 struct connection_struct *conn = fsp->conn;
2051 struct smb_Dir *dir_hnd = OpenDir_fsp(talloc_tos(),
2052 conn,
2053 fsp,
2054 NULL,
2057 if (!dir_hnd) {
2058 return map_nt_error_from_unix(errno);
2061 while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) {
2062 /* Quick check for "." and ".." */
2063 if (dname[0] == '.') {
2064 if (!dname[1] || (dname[1] == '.' && !dname[2])) {
2065 TALLOC_FREE(talloced);
2066 continue;
2070 if (!is_visible_file(conn, dirname, dname, &st, True)) {
2071 TALLOC_FREE(talloced);
2072 continue;
2075 DEBUG(10,("got name %s - can't delete\n",
2076 dname ));
2077 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
2078 break;
2080 TALLOC_FREE(talloced);
2081 TALLOC_FREE(dir_hnd);
2083 if (!NT_STATUS_IS_OK(status)) {
2084 return status;
2087 if (!(fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) &&
2088 lp_strict_rename(SNUM(conn)) &&
2089 have_file_open_below(fsp->conn, fsp->fsp_name))
2091 return NT_STATUS_ACCESS_DENIED;
2094 return NT_STATUS_OK;