winbindd: remove unused single_domains array
[Samba.git] / source3 / smbd / dir.c
blob1348d12298c68e1818615349602010141468865f
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 static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx,
1634 connection_struct *conn,
1635 const struct smb_filename *smb_dname,
1636 const char *mask,
1637 uint32_t attr)
1639 struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1640 struct smbd_server_connection *sconn = conn->sconn;
1642 if (!dirp) {
1643 return NULL;
1646 dirp->dir = SMB_VFS_OPENDIR(conn, smb_dname, mask, attr);
1648 if (!dirp->dir) {
1649 DEBUG(5,("OpenDir: Can't open %s. %s\n",
1650 smb_dname->base_name,
1651 strerror(errno) ));
1652 goto fail;
1655 dirp->conn = conn;
1656 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1658 if (sconn && !sconn->using_smb2) {
1659 sconn->searches.dirhandles_open++;
1661 talloc_set_destructor(dirp, smb_Dir_destructor);
1663 return dirp;
1665 fail:
1666 TALLOC_FREE(dirp);
1667 return NULL;
1670 /****************************************************************************
1671 Open a directory handle by pathname, ensuring it's under the share path.
1672 ****************************************************************************/
1674 static struct smb_Dir *open_dir_safely(TALLOC_CTX *ctx,
1675 connection_struct *conn,
1676 const struct smb_filename *smb_dname,
1677 const char *wcard,
1678 uint32_t attr)
1680 struct smb_Dir *dir_hnd = NULL;
1681 struct smb_filename *smb_fname_cwd = NULL;
1682 char *saved_dir = vfs_GetWd(ctx, conn);
1683 NTSTATUS status;
1685 if (saved_dir == NULL) {
1686 return NULL;
1689 if (vfs_ChDir(conn, smb_dname->base_name) == -1) {
1690 goto out;
1693 smb_fname_cwd = synthetic_smb_fname(talloc_tos(),
1694 ".",
1695 NULL,
1696 NULL,
1697 smb_dname->flags);
1698 if (smb_fname_cwd == NULL) {
1699 goto out;
1703 * Now the directory is pinned, use
1704 * REALPATH to ensure we can access it.
1706 status = check_name(conn, ".");
1707 if (!NT_STATUS_IS_OK(status)) {
1708 goto out;
1711 dir_hnd = OpenDir_internal(ctx,
1712 conn,
1713 smb_fname_cwd,
1714 wcard,
1715 attr);
1717 if (dir_hnd == NULL) {
1718 goto out;
1722 * OpenDir_internal only gets "." as the dir name.
1723 * Store the real dir name here.
1726 dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, smb_dname);
1727 if (!dir_hnd->dir_smb_fname) {
1728 TALLOC_FREE(dir_hnd);
1729 errno = ENOMEM;
1732 out:
1734 vfs_ChDir(conn, saved_dir);
1735 TALLOC_FREE(saved_dir);
1736 return dir_hnd;
1739 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1740 const struct smb_filename *smb_dname,
1741 const char *mask,
1742 uint32_t attr)
1744 return open_dir_safely(mem_ctx,
1745 conn,
1746 smb_dname,
1747 mask,
1748 attr);
1751 /*******************************************************************
1752 Open a directory from an fsp.
1753 ********************************************************************/
1755 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
1756 files_struct *fsp,
1757 const char *mask,
1758 uint32_t attr)
1760 struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1761 struct smbd_server_connection *sconn = conn->sconn;
1763 if (!dirp) {
1764 goto fail;
1767 if (!fsp->is_directory) {
1768 errno = EBADF;
1769 goto fail;
1772 if (fsp->fh->fd == -1) {
1773 errno = EBADF;
1774 goto fail;
1777 dirp->conn = conn;
1778 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1780 dirp->dir_smb_fname = cp_smb_filename(dirp, fsp->fsp_name);
1781 if (!dirp->dir_smb_fname) {
1782 errno = ENOMEM;
1783 goto fail;
1786 dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1787 if (dirp->dir != NULL) {
1788 dirp->fsp = fsp;
1789 } else {
1790 DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1791 "NULL (%s)\n",
1792 dirp->dir_smb_fname->base_name,
1793 strerror(errno)));
1794 if (errno != ENOSYS) {
1795 goto fail;
1799 if (dirp->dir == NULL) {
1800 /* FDOPENDIR is not supported. Use OPENDIR instead. */
1801 TALLOC_FREE(dirp);
1802 return open_dir_safely(mem_ctx,
1803 conn,
1804 fsp->fsp_name,
1805 mask,
1806 attr);
1809 if (sconn && !sconn->using_smb2) {
1810 sconn->searches.dirhandles_open++;
1812 talloc_set_destructor(dirp, smb_Dir_destructor);
1814 return dirp;
1816 fail:
1817 TALLOC_FREE(dirp);
1818 return NULL;
1822 /*******************************************************************
1823 Read from a directory.
1824 Return directory entry, current offset, and optional stat information.
1825 Don't check for veto or invisible files.
1826 ********************************************************************/
1828 const char *ReadDirName(struct smb_Dir *dirp, long *poffset,
1829 SMB_STRUCT_STAT *sbuf, char **ptalloced)
1831 const char *n;
1832 char *talloced = NULL;
1833 connection_struct *conn = dirp->conn;
1835 /* Cheat to allow . and .. to be the first entries returned. */
1836 if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1837 (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2))
1839 if (dirp->file_number == 0) {
1840 n = ".";
1841 *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1842 } else {
1843 n = "..";
1844 *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1846 dirp->file_number++;
1847 *ptalloced = NULL;
1848 return n;
1851 if (*poffset == END_OF_DIRECTORY_OFFSET) {
1852 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1853 return NULL;
1856 /* A real offset, seek to it. */
1857 SeekDir(dirp, *poffset);
1859 while ((n = vfs_readdirname(conn, dirp->dir, sbuf, &talloced))) {
1860 /* Ignore . and .. - we've already returned them. */
1861 if (*n == '.') {
1862 if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1863 TALLOC_FREE(talloced);
1864 continue;
1867 *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1868 *ptalloced = talloced;
1869 dirp->file_number++;
1870 return n;
1872 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1873 *ptalloced = NULL;
1874 return NULL;
1877 /*******************************************************************
1878 Rewind to the start.
1879 ********************************************************************/
1881 void RewindDir(struct smb_Dir *dirp, long *poffset)
1883 SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1884 dirp->file_number = 0;
1885 dirp->offset = START_OF_DIRECTORY_OFFSET;
1886 *poffset = START_OF_DIRECTORY_OFFSET;
1889 /*******************************************************************
1890 Seek a dir.
1891 ********************************************************************/
1893 void SeekDir(struct smb_Dir *dirp, long offset)
1895 if (offset != dirp->offset) {
1896 if (offset == START_OF_DIRECTORY_OFFSET) {
1897 RewindDir(dirp, &offset);
1899 * Ok we should really set the file number here
1900 * to 1 to enable ".." to be returned next. Trouble
1901 * is I'm worried about callers using SeekDir(dirp,0)
1902 * as equivalent to RewindDir(). So leave this alone
1903 * for now.
1905 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
1906 RewindDir(dirp, &offset);
1908 * Set the file number to 2 - we want to get the first
1909 * real file entry (the one we return after "..")
1910 * on the next ReadDir.
1912 dirp->file_number = 2;
1913 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1914 ; /* Don't seek in this case. */
1915 } else {
1916 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1918 dirp->offset = offset;
1922 /*******************************************************************
1923 Tell a dir position.
1924 ********************************************************************/
1926 long TellDir(struct smb_Dir *dirp)
1928 return(dirp->offset);
1931 /*******************************************************************
1932 Add an entry into the dcache.
1933 ********************************************************************/
1935 static void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
1937 struct name_cache_entry *e;
1939 if (dirp->name_cache_size == 0) {
1940 return;
1943 if (dirp->name_cache == NULL) {
1944 dirp->name_cache = talloc_zero_array(
1945 dirp, struct name_cache_entry, dirp->name_cache_size);
1947 if (dirp->name_cache == NULL) {
1948 return;
1952 dirp->name_cache_index = (dirp->name_cache_index+1) %
1953 dirp->name_cache_size;
1954 e = &dirp->name_cache[dirp->name_cache_index];
1955 TALLOC_FREE(e->name);
1956 e->name = talloc_strdup(dirp, name);
1957 e->offset = offset;
1960 /*******************************************************************
1961 Find an entry by name. Leave us at the offset after it.
1962 Don't check for veto or invisible files.
1963 ********************************************************************/
1965 bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1967 int i;
1968 const char *entry = NULL;
1969 char *talloced = NULL;
1970 connection_struct *conn = dirp->conn;
1972 /* Search back in the name cache. */
1973 if (dirp->name_cache_size && dirp->name_cache) {
1974 for (i = dirp->name_cache_index; i >= 0; i--) {
1975 struct name_cache_entry *e = &dirp->name_cache[i];
1976 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1977 *poffset = e->offset;
1978 SeekDir(dirp, e->offset);
1979 return True;
1982 for (i = dirp->name_cache_size - 1; i > dirp->name_cache_index; i--) {
1983 struct name_cache_entry *e = &dirp->name_cache[i];
1984 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1985 *poffset = e->offset;
1986 SeekDir(dirp, e->offset);
1987 return True;
1992 /* Not found in the name cache. Rewind directory and start from scratch. */
1993 SMB_VFS_REWINDDIR(conn, dirp->dir);
1994 dirp->file_number = 0;
1995 *poffset = START_OF_DIRECTORY_OFFSET;
1996 while ((entry = ReadDirName(dirp, poffset, NULL, &talloced))) {
1997 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1998 TALLOC_FREE(talloced);
1999 return True;
2001 TALLOC_FREE(talloced);
2003 return False;
2006 struct files_below_forall_state {
2007 char *dirpath;
2008 size_t dirpath_len;
2009 int (*fn)(struct file_id fid, const struct share_mode_data *data,
2010 void *private_data);
2011 void *private_data;
2014 static int files_below_forall_fn(struct file_id fid,
2015 const struct share_mode_data *data,
2016 void *private_data)
2018 struct files_below_forall_state *state = private_data;
2019 char tmpbuf[PATH_MAX];
2020 char *fullpath, *to_free;
2021 size_t len;
2023 len = full_path_tos(data->servicepath, data->base_name,
2024 tmpbuf, sizeof(tmpbuf),
2025 &fullpath, &to_free);
2026 if (len == -1) {
2027 return 0;
2029 if (state->dirpath_len >= len) {
2031 * Filter files above dirpath
2033 return 0;
2035 if (fullpath[state->dirpath_len] != '/') {
2037 * Filter file that don't have a path separator at the end of
2038 * dirpath's length
2040 return 0;
2043 if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
2045 * Not a parent
2047 return 0;
2050 return state->fn(fid, data, state->private_data);
2053 static int files_below_forall(connection_struct *conn,
2054 const struct smb_filename *dir_name,
2055 int (*fn)(struct file_id fid,
2056 const struct share_mode_data *data,
2057 void *private_data),
2058 void *private_data)
2060 struct files_below_forall_state state = {
2061 .fn = fn,
2062 .private_data = private_data,
2064 int ret;
2065 char tmpbuf[PATH_MAX];
2066 char *to_free;
2068 state.dirpath_len = full_path_tos(conn->connectpath,
2069 dir_name->base_name,
2070 tmpbuf, sizeof(tmpbuf),
2071 &state.dirpath, &to_free);
2072 if (state.dirpath_len == -1) {
2073 return -1;
2076 ret = share_mode_forall(files_below_forall_fn, &state);
2077 TALLOC_FREE(to_free);
2078 return ret;
2081 struct have_file_open_below_state {
2082 bool found_one;
2085 static int have_file_open_below_fn(struct file_id fid,
2086 const struct share_mode_data *data,
2087 void *private_data)
2089 struct have_file_open_below_state *state = private_data;
2090 state->found_one = true;
2091 return 1;
2094 bool have_file_open_below(connection_struct *conn,
2095 const struct smb_filename *name)
2097 struct have_file_open_below_state state = {
2098 .found_one = false,
2100 int ret;
2102 if (!VALID_STAT(name->st)) {
2103 return false;
2105 if (!S_ISDIR(name->st.st_ex_mode)) {
2106 return false;
2109 ret = files_below_forall(conn, name, have_file_open_below_fn, &state);
2110 if (ret == -1) {
2111 return false;
2114 return state.found_one;
2117 /*****************************************************************
2118 Is this directory empty ?
2119 *****************************************************************/
2121 NTSTATUS can_delete_directory_fsp(files_struct *fsp)
2123 NTSTATUS status = NT_STATUS_OK;
2124 long dirpos = 0;
2125 const char *dname = NULL;
2126 const char *dirname = fsp->fsp_name->base_name;
2127 char *talloced = NULL;
2128 SMB_STRUCT_STAT st;
2129 struct connection_struct *conn = fsp->conn;
2130 struct smb_Dir *dir_hnd = OpenDir_fsp(talloc_tos(),
2131 conn,
2132 fsp,
2133 NULL,
2136 if (!dir_hnd) {
2137 return map_nt_error_from_unix(errno);
2140 while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) {
2141 /* Quick check for "." and ".." */
2142 if (dname[0] == '.') {
2143 if (!dname[1] || (dname[1] == '.' && !dname[2])) {
2144 TALLOC_FREE(talloced);
2145 continue;
2149 if (!is_visible_file(conn, dirname, dname, &st, True)) {
2150 TALLOC_FREE(talloced);
2151 continue;
2154 DEBUG(10,("got name %s - can't delete\n",
2155 dname ));
2156 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
2157 break;
2159 TALLOC_FREE(talloced);
2160 TALLOC_FREE(dir_hnd);
2162 if (!NT_STATUS_IS_OK(status)) {
2163 return status;
2166 if (!(fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) &&
2167 lp_strict_rename(SNUM(conn)) &&
2168 have_file_open_below(fsp->conn, fsp->fsp_name))
2170 return NT_STATUS_ACCESS_DENIED;
2173 return NT_STATUS_OK;