traffic_packets: provision request data for packet_drsuapi_13
[Samba.git] / source3 / smbd / dir.c
blob8bb66b8193617d6b094c1e54df96543e50a21334
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;
162 const int dirhandles_open = sconn->searches.dirhandles_open;
164 for (dptr = sconn->searches.dirptrs; dptr != NULL; dptr = dptr->next) {
165 if(dptr->dnum != key) {
166 continue;
169 if (!forclose && (dptr->dir_hnd == NULL)) {
170 if (dirhandles_open >= MAX_OPEN_DIRECTORIES) {
171 dptr_idleoldest(sconn);
173 DBG_INFO("Reopening dptr key %d\n",key);
175 dptr->dir_hnd = OpenDir(NULL,
176 dptr->conn,
177 dptr->smb_dname,
178 dptr->wcard,
179 dptr->attr);
181 if (dptr->dir_hnd == NULL) {
182 DBG_INFO("Failed to open %s (%s)\n",
183 dptr->smb_dname->base_name,
184 strerror(errno));
185 return NULL;
188 DLIST_PROMOTE(sconn->searches.dirptrs, dptr);
189 return dptr;
191 return(NULL);
194 /****************************************************************************
195 Get the dir path for a dir index.
196 ****************************************************************************/
198 const char *dptr_path(struct smbd_server_connection *sconn, int key)
200 struct dptr_struct *dptr = dptr_get(sconn, key, false);
201 if (dptr)
202 return(dptr->smb_dname->base_name);
203 return(NULL);
206 /****************************************************************************
207 Get the dir wcard for a dir index.
208 ****************************************************************************/
210 const char *dptr_wcard(struct smbd_server_connection *sconn, int key)
212 struct dptr_struct *dptr = dptr_get(sconn, key, false);
213 if (dptr)
214 return(dptr->wcard);
215 return(NULL);
218 /****************************************************************************
219 Get the dir attrib for a dir index.
220 ****************************************************************************/
222 uint16_t dptr_attr(struct smbd_server_connection *sconn, int key)
224 struct dptr_struct *dptr = dptr_get(sconn, key, false);
225 if (dptr)
226 return(dptr->attr);
227 return(0);
230 /****************************************************************************
231 Close a dptr (internal func).
232 ****************************************************************************/
234 static void dptr_close_internal(struct dptr_struct *dptr)
236 struct smbd_server_connection *sconn = dptr->conn->sconn;
238 DEBUG(4,("closing dptr key %d\n",dptr->dnum));
240 if (sconn == NULL) {
241 goto done;
244 if (sconn->using_smb2) {
245 goto done;
248 DLIST_REMOVE(sconn->searches.dirptrs, dptr);
251 * Free the dnum in the bitmap. Remember the dnum value is always
252 * biased by one with respect to the bitmap.
255 if (!bitmap_query(sconn->searches.dptr_bmap, dptr->dnum - 1)) {
256 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
257 dptr->dnum ));
260 bitmap_clear(sconn->searches.dptr_bmap, dptr->dnum - 1);
262 done:
263 TALLOC_FREE(dptr->dir_hnd);
264 TALLOC_FREE(dptr);
267 /****************************************************************************
268 Close a dptr given a key.
269 ****************************************************************************/
271 void dptr_close(struct smbd_server_connection *sconn, int *key)
273 struct dptr_struct *dptr;
275 if(*key == INVALID_DPTR_KEY)
276 return;
278 /* OS/2 seems to use -1 to indicate "close all directories" */
279 if (*key == -1) {
280 struct dptr_struct *next;
281 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
282 next = dptr->next;
283 dptr_close_internal(dptr);
285 *key = INVALID_DPTR_KEY;
286 return;
289 dptr = dptr_get(sconn, *key, true);
291 if (!dptr) {
292 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
293 return;
296 dptr_close_internal(dptr);
298 *key = INVALID_DPTR_KEY;
301 /****************************************************************************
302 Close all dptrs for a cnum.
303 ****************************************************************************/
305 void dptr_closecnum(connection_struct *conn)
307 struct dptr_struct *dptr, *next;
308 struct smbd_server_connection *sconn = conn->sconn;
310 if (sconn == NULL) {
311 return;
314 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
315 next = dptr->next;
316 if (dptr->conn == conn) {
317 dptr_close_internal(dptr);
322 /****************************************************************************
323 Idle all dptrs for a cnum.
324 ****************************************************************************/
326 void dptr_idlecnum(connection_struct *conn)
328 struct dptr_struct *dptr;
329 struct smbd_server_connection *sconn = conn->sconn;
331 if (sconn == NULL) {
332 return;
335 for(dptr = sconn->searches.dirptrs; dptr; dptr = dptr->next) {
336 if (dptr->conn == conn && dptr->dir_hnd) {
337 dptr_idle(dptr);
342 /****************************************************************************
343 Close a dptr that matches a given path, only if it matches the spid also.
344 ****************************************************************************/
346 void dptr_closepath(struct smbd_server_connection *sconn,
347 char *path,uint16_t spid)
349 struct dptr_struct *dptr, *next;
350 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
351 next = dptr->next;
352 if (spid == dptr->spid &&
353 strequal(dptr->smb_dname->base_name,path)) {
354 dptr_close_internal(dptr);
359 /****************************************************************************
360 Try and close the oldest handle not marked for
361 expect close in the hope that the client has
362 finished with that one.
363 ****************************************************************************/
365 static void dptr_close_oldest(struct smbd_server_connection *sconn,
366 bool old)
368 struct dptr_struct *dptr;
371 * Go to the end of the list.
373 for(dptr = sconn->searches.dirptrs; dptr && dptr->next; dptr = dptr->next)
376 if(!dptr) {
377 DEBUG(0,("No old dptrs available to close oldest ?\n"));
378 return;
382 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
383 * does not have expect_close set. If 'old' is false, close
384 * one of the new dnum handles.
387 for(; dptr; dptr = DLIST_PREV(dptr)) {
388 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
389 (!old && (dptr->dnum > 255))) {
390 dptr_close_internal(dptr);
391 return;
396 /****************************************************************************
397 Safely do an OpenDir as root, ensuring we're in the right place.
398 ****************************************************************************/
400 static struct smb_Dir *open_dir_with_privilege(connection_struct *conn,
401 struct smb_request *req,
402 const struct smb_filename *smb_dname,
403 const char *wcard,
404 uint32_t attr)
406 struct smb_Dir *dir_hnd = NULL;
407 struct smb_filename *smb_fname_cwd = NULL;
408 struct smb_filename *saved_dir_fname = vfs_GetWd(talloc_tos(), conn);
409 struct privilege_paths *priv_paths = req->priv_paths;
410 int ret;
412 if (saved_dir_fname == NULL) {
413 return NULL;
416 if (vfs_ChDir(conn, smb_dname) == -1) {
417 return NULL;
420 /* Now check the stat value is the same. */
421 smb_fname_cwd = synthetic_smb_fname(talloc_tos(),
422 ".",
423 NULL,
424 NULL,
425 smb_dname->flags);
426 if (smb_fname_cwd == NULL) {
427 goto out;
429 ret = SMB_VFS_STAT(conn, smb_fname_cwd);
430 if (ret != 0) {
431 goto out;
434 if (!check_same_stat(&smb_fname_cwd->st, &priv_paths->parent_name.st)) {
435 DEBUG(0,("open_dir_with_privilege: stat mismatch between %s "
436 "and %s\n",
437 smb_dname->base_name,
438 smb_fname_str_dbg(&priv_paths->parent_name)));
439 goto out;
442 dir_hnd = OpenDir(NULL, conn, smb_fname_cwd, wcard, attr);
444 out:
446 vfs_ChDir(conn, saved_dir_fname);
447 TALLOC_FREE(saved_dir_fname);
448 return dir_hnd;
451 /****************************************************************************
452 Create a new dir ptr. If the flag old_handle is true then we must allocate
453 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
454 one byte long. If old_handle is false we allocate from the range
455 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
456 a directory handle is never zero.
457 wcard must not be zero.
458 ****************************************************************************/
460 NTSTATUS dptr_create(connection_struct *conn,
461 struct smb_request *req,
462 files_struct *fsp,
463 const struct smb_filename *smb_dname,
464 bool old_handle,
465 bool expect_close,
466 uint16_t spid,
467 const char *wcard,
468 bool wcard_has_wild,
469 uint32_t attr,
470 struct dptr_struct **dptr_ret)
472 struct smbd_server_connection *sconn = conn->sconn;
473 struct dptr_struct *dptr = NULL;
474 struct smb_Dir *dir_hnd;
476 if (fsp && fsp->is_directory && fsp->fh->fd != -1) {
477 smb_dname = fsp->fsp_name;
480 DEBUG(5,("dptr_create dir=%s\n", smb_dname->base_name));
482 if (sconn == NULL) {
483 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
484 return NT_STATUS_INTERNAL_ERROR;
487 if (!wcard) {
488 return NT_STATUS_INVALID_PARAMETER;
491 if (fsp) {
492 if (!(fsp->access_mask & SEC_DIR_LIST)) {
493 DEBUG(5,("dptr_create: directory %s "
494 "not open for LIST access\n",
495 smb_dname->base_name));
496 return NT_STATUS_ACCESS_DENIED;
498 dir_hnd = OpenDir_fsp(NULL, conn, fsp, wcard, attr);
499 } else {
500 int ret;
501 bool backup_intent = (req && req->priv_paths);
502 NTSTATUS status;
503 struct smb_filename *smb_dname_cp =
504 cp_smb_filename(talloc_tos(), smb_dname);
506 if (smb_dname_cp == NULL) {
507 return NT_STATUS_NO_MEMORY;
510 if (req != NULL && req->posix_pathnames) {
511 ret = SMB_VFS_LSTAT(conn, smb_dname_cp);
512 } else {
513 ret = SMB_VFS_STAT(conn, smb_dname_cp);
515 if (ret == -1) {
516 status = map_nt_error_from_unix(errno);
517 TALLOC_FREE(smb_dname_cp);
518 return status;
520 if (!S_ISDIR(smb_dname_cp->st.st_ex_mode)) {
521 TALLOC_FREE(smb_dname_cp);
522 return NT_STATUS_NOT_A_DIRECTORY;
524 status = smbd_check_access_rights(conn,
525 smb_dname_cp,
526 backup_intent,
527 SEC_DIR_LIST);
528 if (!NT_STATUS_IS_OK(status)) {
529 TALLOC_FREE(smb_dname_cp);
530 return status;
532 if (backup_intent) {
533 dir_hnd = open_dir_with_privilege(conn,
534 req,
535 smb_dname_cp,
536 wcard,
537 attr);
538 } else {
539 dir_hnd = OpenDir(NULL,
540 conn,
541 smb_dname_cp,
542 wcard,
543 attr);
545 TALLOC_FREE(smb_dname_cp);
548 if (!dir_hnd) {
549 return map_nt_error_from_unix(errno);
552 if (sconn->searches.dirhandles_open >= MAX_OPEN_DIRECTORIES) {
553 dptr_idleoldest(sconn);
556 dptr = talloc_zero(NULL, struct dptr_struct);
557 if(!dptr) {
558 DEBUG(0,("talloc fail in dptr_create.\n"));
559 TALLOC_FREE(dir_hnd);
560 return NT_STATUS_NO_MEMORY;
563 dptr->smb_dname = cp_smb_filename(dptr, smb_dname);
564 if (!dptr->smb_dname) {
565 TALLOC_FREE(dptr);
566 TALLOC_FREE(dir_hnd);
567 return NT_STATUS_NO_MEMORY;
569 dptr->conn = conn;
570 dptr->dir_hnd = dir_hnd;
571 dptr->spid = spid;
572 dptr->expect_close = expect_close;
573 dptr->wcard = talloc_strdup(dptr, wcard);
574 if (!dptr->wcard) {
575 TALLOC_FREE(dptr);
576 TALLOC_FREE(dir_hnd);
577 return NT_STATUS_NO_MEMORY;
579 if ((req != NULL && req->posix_pathnames) ||
580 (wcard[0] == '.' && wcard[1] == 0)) {
581 dptr->has_wild = True;
582 } else {
583 dptr->has_wild = wcard_has_wild;
586 dptr->attr = attr;
588 if (sconn->using_smb2) {
589 goto done;
592 if(old_handle) {
595 * This is an old-style SMBsearch request. Ensure the
596 * value we return will fit in the range 1-255.
599 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
601 if(dptr->dnum == -1 || dptr->dnum > 254) {
604 * Try and close the oldest handle not marked for
605 * expect close in the hope that the client has
606 * finished with that one.
609 dptr_close_oldest(sconn, true);
611 /* Now try again... */
612 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
613 if(dptr->dnum == -1 || dptr->dnum > 254) {
614 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
615 TALLOC_FREE(dptr);
616 TALLOC_FREE(dir_hnd);
617 return NT_STATUS_TOO_MANY_OPENED_FILES;
620 } else {
623 * This is a new-style trans2 request. Allocate from
624 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
627 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
629 if(dptr->dnum == -1 || dptr->dnum < 255) {
632 * Try and close the oldest handle close in the hope that
633 * the client has finished with that one. This will only
634 * happen in the case of the Win98 client bug where it leaks
635 * directory handles.
638 dptr_close_oldest(sconn, false);
640 /* Now try again... */
641 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
643 if(dptr->dnum == -1 || dptr->dnum < 255) {
644 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
645 TALLOC_FREE(dptr);
646 TALLOC_FREE(dir_hnd);
647 return NT_STATUS_TOO_MANY_OPENED_FILES;
652 bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
654 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
656 DLIST_ADD(sconn->searches.dirptrs, dptr);
658 done:
659 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
660 dptr->dnum,
661 dptr->smb_dname->base_name,
662 expect_close));
664 *dptr_ret = dptr;
666 return NT_STATUS_OK;
670 /****************************************************************************
671 Wrapper functions to access the lower level directory handles.
672 ****************************************************************************/
674 void dptr_CloseDir(files_struct *fsp)
676 if (fsp->dptr) {
678 * The destructor for the struct smb_Dir
679 * (fsp->dptr->dir_hnd) now handles
680 * all resource deallocation.
682 dptr_close_internal(fsp->dptr);
683 fsp->dptr = NULL;
687 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
689 SeekDir(dptr->dir_hnd, offset);
692 long dptr_TellDir(struct dptr_struct *dptr)
694 return TellDir(dptr->dir_hnd);
697 bool dptr_has_wild(struct dptr_struct *dptr)
699 return dptr->has_wild;
702 int dptr_dnum(struct dptr_struct *dptr)
704 return dptr->dnum;
707 bool dptr_get_priv(struct dptr_struct *dptr)
709 return dptr->priv;
712 void dptr_set_priv(struct dptr_struct *dptr)
714 dptr->priv = true;
717 /****************************************************************************
718 Return the next visible file name, skipping veto'd and invisible files.
719 ****************************************************************************/
721 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr,
722 long *poffset, SMB_STRUCT_STAT *pst,
723 char **ptalloced)
725 /* Normal search for the next file. */
726 const char *name;
727 char *talloced = NULL;
729 while ((name = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced))
730 != NULL) {
731 if (is_visible_file(dptr->conn,
732 dptr->smb_dname->base_name,
733 name,
734 pst,
735 true)) {
736 *ptalloced = talloced;
737 return name;
739 TALLOC_FREE(talloced);
741 return NULL;
744 /****************************************************************************
745 Return the next visible file name, skipping veto'd and invisible files.
746 ****************************************************************************/
748 static char *dptr_ReadDirName(TALLOC_CTX *ctx,
749 struct dptr_struct *dptr,
750 long *poffset,
751 SMB_STRUCT_STAT *pst)
753 struct smb_filename smb_fname_base;
754 char *name = NULL;
755 const char *name_temp = NULL;
756 char *talloced = NULL;
757 char *pathreal = NULL;
758 char *found_name = NULL;
759 int ret;
761 SET_STAT_INVALID(*pst);
763 if (dptr->has_wild || dptr->did_stat) {
764 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst,
765 &talloced);
766 if (name_temp == NULL) {
767 return NULL;
769 if (talloced != NULL) {
770 return talloc_move(ctx, &talloced);
772 return talloc_strdup(ctx, name_temp);
775 /* If poffset is -1 then we know we returned this name before and we
776 * have no wildcards. We're at the end of the directory. */
777 if (*poffset == END_OF_DIRECTORY_OFFSET) {
778 return NULL;
781 /* We know the stored wcard contains no wildcard characters.
782 * See if we can match with a stat call. If we can't, then set
783 * did_stat to true to ensure we only do this once and keep
784 * searching. */
786 dptr->did_stat = true;
788 /* First check if it should be visible. */
789 if (!is_visible_file(dptr->conn,
790 dptr->smb_dname->base_name,
791 dptr->wcard,
792 pst,
793 true)) {
794 /* This only returns false if the file was found, but
795 is explicitly not visible. Set us to end of
796 directory, but return NULL as we know we can't ever
797 find it. */
798 goto ret;
801 if (VALID_STAT(*pst)) {
802 name = talloc_strdup(ctx, dptr->wcard);
803 goto ret;
806 pathreal = talloc_asprintf(ctx,
807 "%s/%s",
808 dptr->smb_dname->base_name,
809 dptr->wcard);
810 if (!pathreal)
811 return NULL;
813 /* Create an smb_filename with stream_name == NULL. */
814 smb_fname_base = (struct smb_filename) { .base_name = pathreal };
816 if (SMB_VFS_STAT(dptr->conn, &smb_fname_base) == 0) {
817 *pst = smb_fname_base.st;
818 name = talloc_strdup(ctx, dptr->wcard);
819 goto clean;
820 } else {
821 /* If we get any other error than ENOENT or ENOTDIR
822 then the file exists we just can't stat it. */
823 if (errno != ENOENT && errno != ENOTDIR) {
824 name = talloc_strdup(ctx, dptr->wcard);
825 goto clean;
829 /* Stat failed. We know this is authoratiative if we are
830 * providing case sensitive semantics or the underlying
831 * filesystem is case sensitive.
833 if (dptr->conn->case_sensitive ||
834 !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
836 goto clean;
840 * Try case-insensitive stat if the fs has the ability. This avoids
841 * scanning the whole directory.
843 ret = SMB_VFS_GET_REAL_FILENAME(dptr->conn,
844 dptr->smb_dname->base_name,
845 dptr->wcard,
846 ctx,
847 &found_name);
848 if (ret == 0) {
849 name = found_name;
850 goto clean;
851 } else if (errno == ENOENT) {
852 /* The case-insensitive lookup was authoritative. */
853 goto clean;
856 TALLOC_FREE(pathreal);
858 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst, &talloced);
859 if (name_temp == NULL) {
860 return NULL;
862 if (talloced != NULL) {
863 return talloc_move(ctx, &talloced);
865 return talloc_strdup(ctx, name_temp);
867 clean:
868 TALLOC_FREE(pathreal);
869 ret:
870 /* We need to set the underlying dir_hnd offset to -1
871 * also as this function is usually called with the
872 * output from TellDir. */
873 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
874 return name;
877 /****************************************************************************
878 Search for a file by name, skipping veto'ed and not visible files.
879 ****************************************************************************/
881 bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
883 SET_STAT_INVALID(*pst);
885 if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
886 /* This is a singleton directory and we're already at the end. */
887 *poffset = END_OF_DIRECTORY_OFFSET;
888 return False;
891 return SearchDir(dptr->dir_hnd, name, poffset);
894 /****************************************************************************
895 Map a native directory offset to a 32-bit cookie.
896 ****************************************************************************/
898 static uint32_t map_dir_offset_to_wire(struct dptr_struct *dptr, long offset)
900 DATA_BLOB key;
901 DATA_BLOB val;
903 if (offset == END_OF_DIRECTORY_OFFSET) {
904 return WIRE_END_OF_DIRECTORY_OFFSET;
905 } else if(offset == START_OF_DIRECTORY_OFFSET) {
906 return WIRE_START_OF_DIRECTORY_OFFSET;
907 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
908 return WIRE_DOT_DOT_DIRECTORY_OFFSET;
910 if (sizeof(long) == 4) {
911 /* 32-bit machine. We can cheat... */
912 return (uint32_t)offset;
914 if (dptr->dptr_cache == NULL) {
915 /* Lazy initialize cache. */
916 dptr->dptr_cache = memcache_init(dptr, 0);
917 if (dptr->dptr_cache == NULL) {
918 return WIRE_END_OF_DIRECTORY_OFFSET;
920 } else {
921 /* Have we seen this offset before ? */
922 key.data = (void *)&offset;
923 key.length = sizeof(offset);
924 if (memcache_lookup(dptr->dptr_cache,
925 SMB1_SEARCH_OFFSET_MAP,
926 key,
927 &val)) {
928 uint32_t wire_offset;
929 SMB_ASSERT(val.length == sizeof(wire_offset));
930 memcpy(&wire_offset, val.data, sizeof(wire_offset));
931 DEBUG(10,("found wire %u <-> offset %ld\n",
932 (unsigned int)wire_offset,
933 (long)offset));
934 return wire_offset;
937 /* Allocate a new wire cookie. */
938 do {
939 dptr->counter++;
940 } while (dptr->counter == WIRE_START_OF_DIRECTORY_OFFSET ||
941 dptr->counter == WIRE_END_OF_DIRECTORY_OFFSET ||
942 dptr->counter == WIRE_DOT_DOT_DIRECTORY_OFFSET);
943 /* Store it in the cache. */
944 key.data = (void *)&offset;
945 key.length = sizeof(offset);
946 val.data = (void *)&dptr->counter;
947 val.length = sizeof(dptr->counter); /* MUST BE uint32_t ! */
948 memcache_add(dptr->dptr_cache,
949 SMB1_SEARCH_OFFSET_MAP,
950 key,
951 val);
952 /* And the reverse mapping for lookup from
953 map_wire_to_dir_offset(). */
954 memcache_add(dptr->dptr_cache,
955 SMB1_SEARCH_OFFSET_MAP,
956 val,
957 key);
958 DEBUG(10,("stored wire %u <-> offset %ld\n",
959 (unsigned int)dptr->counter,
960 (long)offset));
961 return dptr->counter;
964 /****************************************************************************
965 Fill the 5 byte server reserved dptr field.
966 ****************************************************************************/
968 bool dptr_fill(struct smbd_server_connection *sconn,
969 char *buf1,unsigned int key)
971 unsigned char *buf = (unsigned char *)buf1;
972 struct dptr_struct *dptr = dptr_get(sconn, key, false);
973 uint32_t wire_offset;
974 if (!dptr) {
975 DEBUG(1,("filling null dirptr %d\n",key));
976 return(False);
978 wire_offset = map_dir_offset_to_wire(dptr,TellDir(dptr->dir_hnd));
979 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
980 (long)dptr->dir_hnd,(int)wire_offset));
981 buf[0] = key;
982 SIVAL(buf,1,wire_offset);
983 return(True);
986 /****************************************************************************
987 Map a 32-bit wire cookie to a native directory offset.
988 ****************************************************************************/
990 static long map_wire_to_dir_offset(struct dptr_struct *dptr, uint32_t wire_offset)
992 DATA_BLOB key;
993 DATA_BLOB val;
995 if (wire_offset == WIRE_END_OF_DIRECTORY_OFFSET) {
996 return END_OF_DIRECTORY_OFFSET;
997 } else if(wire_offset == WIRE_START_OF_DIRECTORY_OFFSET) {
998 return START_OF_DIRECTORY_OFFSET;
999 } else if (wire_offset == WIRE_DOT_DOT_DIRECTORY_OFFSET) {
1000 return DOT_DOT_DIRECTORY_OFFSET;
1002 if (sizeof(long) == 4) {
1003 /* 32-bit machine. We can cheat... */
1004 return (long)wire_offset;
1006 if (dptr->dptr_cache == NULL) {
1007 /* Logic error, cache should be initialized. */
1008 return END_OF_DIRECTORY_OFFSET;
1010 key.data = (void *)&wire_offset;
1011 key.length = sizeof(wire_offset);
1012 if (memcache_lookup(dptr->dptr_cache,
1013 SMB1_SEARCH_OFFSET_MAP,
1014 key,
1015 &val)) {
1016 /* Found mapping. */
1017 long offset;
1018 SMB_ASSERT(val.length == sizeof(offset));
1019 memcpy(&offset, val.data, sizeof(offset));
1020 DEBUG(10,("lookup wire %u <-> offset %ld\n",
1021 (unsigned int)wire_offset,
1022 (long)offset));
1023 return offset;
1025 return END_OF_DIRECTORY_OFFSET;
1028 /****************************************************************************
1029 Fetch the dir ptr and seek it given the 5 byte server field.
1030 ****************************************************************************/
1032 struct dptr_struct *dptr_fetch(struct smbd_server_connection *sconn,
1033 char *buf, int *num)
1035 unsigned int key = *(unsigned char *)buf;
1036 struct dptr_struct *dptr = dptr_get(sconn, key, false);
1037 uint32_t wire_offset;
1038 long seekoff;
1040 if (!dptr) {
1041 DEBUG(3,("fetched null dirptr %d\n",key));
1042 return(NULL);
1044 *num = key;
1045 wire_offset = IVAL(buf,1);
1046 seekoff = map_wire_to_dir_offset(dptr, wire_offset);
1047 SeekDir(dptr->dir_hnd,seekoff);
1048 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
1049 key, dptr->smb_dname->base_name, (int)seekoff));
1050 return(dptr);
1053 /****************************************************************************
1054 Fetch the dir ptr.
1055 ****************************************************************************/
1057 struct dptr_struct *dptr_fetch_lanman2(struct smbd_server_connection *sconn,
1058 int dptr_num)
1060 struct dptr_struct *dptr = dptr_get(sconn, dptr_num, false);
1062 if (!dptr) {
1063 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
1064 return(NULL);
1066 DEBUG(3,("fetching dirptr %d for path %s\n",
1067 dptr_num,
1068 dptr->smb_dname->base_name));
1069 return(dptr);
1072 static bool mangle_mask_match(connection_struct *conn,
1073 const char *filename,
1074 const char *mask)
1076 char mname[13];
1078 if (!name_to_8_3(filename,mname,False,conn->params)) {
1079 return False;
1081 return mask_match_search(mname,mask,False);
1084 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
1085 struct dptr_struct *dirptr,
1086 const char *mask,
1087 uint32_t dirtype,
1088 bool dont_descend,
1089 bool ask_sharemode,
1090 bool (*match_fn)(TALLOC_CTX *ctx,
1091 void *private_data,
1092 const char *dname,
1093 const char *mask,
1094 char **_fname),
1095 bool (*mode_fn)(TALLOC_CTX *ctx,
1096 void *private_data,
1097 struct smb_filename *smb_fname,
1098 uint32_t *_mode),
1099 void *private_data,
1100 char **_fname,
1101 struct smb_filename **_smb_fname,
1102 uint32_t *_mode,
1103 long *_prev_offset)
1105 connection_struct *conn = dirptr->conn;
1106 size_t slashlen;
1107 size_t pathlen;
1108 const char *dpath = dirptr->smb_dname->base_name;
1109 bool dirptr_path_is_dot = ISDOT(dpath);
1111 *_smb_fname = NULL;
1112 *_mode = 0;
1114 pathlen = strlen(dpath);
1115 slashlen = ( dpath[pathlen-1] != '/') ? 1 : 0;
1117 while (true) {
1118 long cur_offset;
1119 long prev_offset;
1120 SMB_STRUCT_STAT sbuf = { 0 };
1121 char *dname = NULL;
1122 bool isdots;
1123 char *fname = NULL;
1124 char *pathreal = NULL;
1125 struct smb_filename smb_fname;
1126 uint32_t mode = 0;
1127 bool ok;
1129 cur_offset = dptr_TellDir(dirptr);
1130 prev_offset = cur_offset;
1131 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
1133 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
1134 (long)dirptr, cur_offset));
1136 if (dname == NULL) {
1137 return false;
1140 isdots = (ISDOT(dname) || ISDOTDOT(dname));
1141 if (dont_descend && !isdots) {
1142 TALLOC_FREE(dname);
1143 continue;
1147 * fname may get mangled, dname is never mangled.
1148 * Whenever we're accessing the filesystem we use
1149 * pathreal which is composed from dname.
1152 ok = match_fn(ctx, private_data, dname, mask, &fname);
1153 if (!ok) {
1154 TALLOC_FREE(dname);
1155 continue;
1159 * This used to be
1160 * pathreal = talloc_asprintf(ctx, "%s%s%s", dirptr->path,
1161 * needslash?"/":"", dname);
1162 * but this was measurably slower than doing the memcpy.
1165 pathreal = talloc_array(
1166 ctx, char,
1167 pathlen + slashlen + talloc_get_size(dname));
1168 if (!pathreal) {
1169 TALLOC_FREE(dname);
1170 TALLOC_FREE(fname);
1171 return false;
1175 * We don't want to pass ./xxx to modules below us so don't
1176 * add the path if it is just . by itself.
1178 if (dirptr_path_is_dot) {
1179 memcpy(pathreal, dname, talloc_get_size(dname));
1180 } else {
1181 memcpy(pathreal, dpath, pathlen);
1182 pathreal[pathlen] = '/';
1183 memcpy(pathreal + slashlen + pathlen, dname,
1184 talloc_get_size(dname));
1187 /* Create smb_fname with NULL stream_name. */
1188 smb_fname = (struct smb_filename) {
1189 .base_name = pathreal, .st = sbuf
1192 ok = mode_fn(ctx, private_data, &smb_fname, &mode);
1193 if (!ok) {
1194 TALLOC_FREE(dname);
1195 TALLOC_FREE(fname);
1196 TALLOC_FREE(pathreal);
1197 continue;
1200 if (!dir_check_ftype(mode, dirtype)) {
1201 DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
1202 fname, (unsigned int)mode, (unsigned int)dirtype));
1203 TALLOC_FREE(dname);
1204 TALLOC_FREE(fname);
1205 TALLOC_FREE(pathreal);
1206 continue;
1209 if (ask_sharemode) {
1210 struct timespec write_time_ts;
1211 struct file_id fileid;
1213 fileid = vfs_file_id_from_sbuf(conn,
1214 &smb_fname.st);
1215 get_file_infos(fileid, 0, NULL, &write_time_ts);
1216 if (!null_timespec(write_time_ts)) {
1217 update_stat_ex_mtime(&smb_fname.st,
1218 write_time_ts);
1222 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
1223 "fname=%s (%s)\n",
1224 mask, smb_fname_str_dbg(&smb_fname),
1225 dname, fname));
1227 if (!conn->sconn->using_smb2) {
1229 * The dircache is only needed for SMB1 because SMB1
1230 * uses a name for the resume wheras SMB2 always
1231 * continues from the next position (unless it's told to
1232 * restart or close-and-reopen the listing).
1234 DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
1237 TALLOC_FREE(dname);
1239 *_smb_fname = cp_smb_filename(ctx, &smb_fname);
1240 TALLOC_FREE(pathreal);
1241 if (*_smb_fname == NULL) {
1242 return false;
1244 *_fname = fname;
1245 *_mode = mode;
1246 *_prev_offset = prev_offset;
1248 return true;
1251 return false;
1254 /****************************************************************************
1255 Get an 8.3 directory entry.
1256 ****************************************************************************/
1258 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
1259 void *private_data,
1260 const char *dname,
1261 const char *mask,
1262 char **_fname)
1264 connection_struct *conn = (connection_struct *)private_data;
1266 if ((strcmp(mask,"*.*") == 0) ||
1267 mask_match_search(dname, mask, false) ||
1268 mangle_mask_match(conn, dname, mask)) {
1269 char mname[13];
1270 const char *fname;
1272 * Ensure we can push the original name as UCS2. If
1273 * not, then just don't return this name.
1275 NTSTATUS status;
1276 size_t ret_len = 0;
1277 size_t len = (strlen(dname) + 2) * 4; /* Allow enough space. */
1278 uint8_t *tmp = talloc_array(talloc_tos(),
1279 uint8_t,
1280 len);
1282 status = srvstr_push(NULL,
1283 FLAGS2_UNICODE_STRINGS,
1284 tmp,
1285 dname,
1286 len,
1287 STR_TERMINATE,
1288 &ret_len);
1290 TALLOC_FREE(tmp);
1292 if (!NT_STATUS_IS_OK(status)) {
1293 return false;
1296 if (!mangle_is_8_3(dname, false, conn->params)) {
1297 bool ok = name_to_8_3(dname, mname, false,
1298 conn->params);
1299 if (!ok) {
1300 return false;
1302 fname = mname;
1303 } else {
1304 fname = dname;
1307 *_fname = talloc_strdup(ctx, fname);
1308 if (*_fname == NULL) {
1309 return false;
1312 return true;
1315 return false;
1318 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1319 void *private_data,
1320 struct smb_filename *smb_fname,
1321 uint32_t *_mode)
1323 connection_struct *conn = (connection_struct *)private_data;
1325 if (!VALID_STAT(smb_fname->st)) {
1326 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1327 DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1328 "Couldn't stat [%s]. Error "
1329 "= %s\n",
1330 smb_fname_str_dbg(smb_fname),
1331 strerror(errno)));
1332 return false;
1336 *_mode = dos_mode(conn, smb_fname);
1337 return true;
1340 bool get_dir_entry(TALLOC_CTX *ctx,
1341 struct dptr_struct *dirptr,
1342 const char *mask,
1343 uint32_t dirtype,
1344 char **_fname,
1345 off_t *_size,
1346 uint32_t *_mode,
1347 struct timespec *_date,
1348 bool check_descend,
1349 bool ask_sharemode)
1351 connection_struct *conn = dirptr->conn;
1352 char *fname = NULL;
1353 struct smb_filename *smb_fname = NULL;
1354 uint32_t mode = 0;
1355 long prev_offset;
1356 bool ok;
1358 ok = smbd_dirptr_get_entry(ctx,
1359 dirptr,
1360 mask,
1361 dirtype,
1362 check_descend,
1363 ask_sharemode,
1364 smbd_dirptr_8_3_match_fn,
1365 smbd_dirptr_8_3_mode_fn,
1366 conn,
1367 &fname,
1368 &smb_fname,
1369 &mode,
1370 &prev_offset);
1371 if (!ok) {
1372 return false;
1375 *_fname = talloc_move(ctx, &fname);
1376 *_size = smb_fname->st.st_ex_size;
1377 *_mode = mode;
1378 *_date = smb_fname->st.st_ex_mtime;
1379 TALLOC_FREE(smb_fname);
1380 return true;
1383 /*******************************************************************
1384 Check to see if a user can read a file. This is only approximate,
1385 it is used as part of the "hide unreadable" option. Don't
1386 use it for anything security sensitive.
1387 ********************************************************************/
1389 static bool user_can_read_file(connection_struct *conn,
1390 struct smb_filename *smb_fname)
1392 NTSTATUS status;
1393 uint32_t rejected_share_access = 0;
1394 uint32_t rejected_mask = 0;
1395 struct security_descriptor *sd = NULL;
1396 uint32_t access_mask = FILE_READ_DATA|
1397 FILE_READ_EA|
1398 FILE_READ_ATTRIBUTES|
1399 SEC_STD_READ_CONTROL;
1402 * Never hide files from the root user.
1403 * We use (uid_t)0 here not sec_initial_uid()
1404 * as make test uses a single user context.
1407 if (get_current_uid(conn) == (uid_t)0) {
1408 return True;
1412 * We can't directly use smbd_check_access_rights()
1413 * here, as this implicitly grants FILE_READ_ATTRIBUTES
1414 * which the Windows access-based-enumeration code
1415 * explicitly checks for on the file security descriptor.
1416 * See bug:
1418 * https://bugzilla.samba.org/show_bug.cgi?id=10252
1420 * and the smb2.acl2.ACCESSBASED test for details.
1423 rejected_share_access = access_mask & ~(conn->share_access);
1424 if (rejected_share_access) {
1425 DEBUG(10, ("rejected share access 0x%x "
1426 "on %s (0x%x)\n",
1427 (unsigned int)access_mask,
1428 smb_fname_str_dbg(smb_fname),
1429 (unsigned int)rejected_share_access ));
1430 return false;
1433 status = SMB_VFS_GET_NT_ACL(conn,
1434 smb_fname,
1435 (SECINFO_OWNER |
1436 SECINFO_GROUP |
1437 SECINFO_DACL),
1438 talloc_tos(),
1439 &sd);
1441 if (!NT_STATUS_IS_OK(status)) {
1442 DEBUG(10, ("Could not get acl "
1443 "on %s: %s\n",
1444 smb_fname_str_dbg(smb_fname),
1445 nt_errstr(status)));
1446 return false;
1449 status = se_file_access_check(sd,
1450 get_current_nttok(conn),
1451 false,
1452 access_mask,
1453 &rejected_mask);
1455 TALLOC_FREE(sd);
1457 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1458 DEBUG(10,("rejected bits 0x%x read access for %s\n",
1459 (unsigned int)rejected_mask,
1460 smb_fname_str_dbg(smb_fname) ));
1461 return false;
1463 return true;
1466 /*******************************************************************
1467 Check to see if a user can write a file (and only files, we do not
1468 check dirs on this one). This is only approximate,
1469 it is used as part of the "hide unwriteable" option. Don't
1470 use it for anything security sensitive.
1471 ********************************************************************/
1473 static bool user_can_write_file(connection_struct *conn,
1474 const struct smb_filename *smb_fname)
1477 * Never hide files from the root user.
1478 * We use (uid_t)0 here not sec_initial_uid()
1479 * as make test uses a single user context.
1482 if (get_current_uid(conn) == (uid_t)0) {
1483 return True;
1486 SMB_ASSERT(VALID_STAT(smb_fname->st));
1488 /* Pseudo-open the file */
1490 if(S_ISDIR(smb_fname->st.st_ex_mode)) {
1491 return True;
1494 return can_write_to_file(conn, smb_fname);
1497 /*******************************************************************
1498 Is a file a "special" type ?
1499 ********************************************************************/
1501 static bool file_is_special(connection_struct *conn,
1502 const struct smb_filename *smb_fname)
1505 * Never hide files from the root user.
1506 * We use (uid_t)0 here not sec_initial_uid()
1507 * as make test uses a single user context.
1510 if (get_current_uid(conn) == (uid_t)0) {
1511 return False;
1514 SMB_ASSERT(VALID_STAT(smb_fname->st));
1516 if (S_ISREG(smb_fname->st.st_ex_mode) ||
1517 S_ISDIR(smb_fname->st.st_ex_mode) ||
1518 S_ISLNK(smb_fname->st.st_ex_mode))
1519 return False;
1521 return True;
1524 /*******************************************************************
1525 Should the file be seen by the client?
1526 NOTE: A successful return is no guarantee of the file's existence.
1527 ********************************************************************/
1529 bool is_visible_file(connection_struct *conn, const char *dir_path,
1530 const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
1532 bool hide_unreadable = lp_hide_unreadable(SNUM(conn));
1533 bool hide_unwriteable = lp_hide_unwriteable_files(SNUM(conn));
1534 bool hide_special = lp_hide_special_files(SNUM(conn));
1535 char *entry = NULL;
1536 struct smb_filename *smb_fname_base = NULL;
1537 bool ret = false;
1539 if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1540 return True; /* . and .. are always visible. */
1543 /* If it's a vetoed file, pretend it doesn't even exist */
1544 if (use_veto && IS_VETO_PATH(conn, name)) {
1545 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1546 return False;
1549 if (hide_unreadable || hide_unwriteable || hide_special) {
1550 entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name);
1551 if (!entry) {
1552 ret = false;
1553 goto out;
1556 /* Create an smb_filename with stream_name == NULL. */
1557 smb_fname_base = synthetic_smb_fname(talloc_tos(),
1558 entry,
1559 NULL,
1560 pst,
1562 if (smb_fname_base == NULL) {
1563 ret = false;
1564 goto out;
1567 /* If the file name does not exist, there's no point checking
1568 * the configuration options. We succeed, on the basis that the
1569 * checks *might* have passed if the file was present.
1571 if (!VALID_STAT(*pst)) {
1572 if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
1573 ret = true;
1574 goto out;
1576 *pst = smb_fname_base->st;
1579 /* Honour _hide unreadable_ option */
1580 if (hide_unreadable &&
1581 !user_can_read_file(conn, smb_fname_base)) {
1582 DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1583 entry ));
1584 ret = false;
1585 goto out;
1587 /* Honour _hide unwriteable_ option */
1588 if (hide_unwriteable && !user_can_write_file(conn,
1589 smb_fname_base)) {
1590 DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1591 entry ));
1592 ret = false;
1593 goto out;
1595 /* Honour _hide_special_ option */
1596 if (hide_special && file_is_special(conn, smb_fname_base)) {
1597 DEBUG(10,("is_visible_file: file %s is special.\n",
1598 entry ));
1599 ret = false;
1600 goto out;
1604 ret = true;
1605 out:
1606 TALLOC_FREE(smb_fname_base);
1607 TALLOC_FREE(entry);
1608 return ret;
1611 static int smb_Dir_destructor(struct smb_Dir *dirp)
1613 if (dirp->dir != NULL) {
1614 SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1615 if (dirp->fsp != NULL) {
1617 * The SMB_VFS_CLOSEDIR above
1618 * closes the underlying fd inside
1619 * dirp->fsp.
1621 dirp->fsp->fh->fd = -1;
1622 if (dirp->fsp->dptr != NULL) {
1623 SMB_ASSERT(dirp->fsp->dptr->dir_hnd == dirp);
1624 dirp->fsp->dptr->dir_hnd = NULL;
1626 dirp->fsp = NULL;
1629 if (dirp->conn->sconn && !dirp->conn->sconn->using_smb2) {
1630 dirp->conn->sconn->searches.dirhandles_open--;
1632 return 0;
1635 /*******************************************************************
1636 Open a directory.
1637 ********************************************************************/
1639 static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx,
1640 connection_struct *conn,
1641 const struct smb_filename *smb_dname,
1642 const char *mask,
1643 uint32_t attr)
1645 struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1646 struct smbd_server_connection *sconn = conn->sconn;
1648 if (!dirp) {
1649 return NULL;
1652 dirp->dir = SMB_VFS_OPENDIR(conn, smb_dname, mask, attr);
1654 if (!dirp->dir) {
1655 DEBUG(5,("OpenDir: Can't open %s. %s\n",
1656 smb_dname->base_name,
1657 strerror(errno) ));
1658 goto fail;
1661 dirp->conn = conn;
1663 if (!conn->sconn->using_smb2) {
1665 * The dircache is only needed for SMB1 because SMB1 uses a name
1666 * for the resume wheras SMB2 always continues from the next
1667 * position (unless it's told to restart or close-and-reopen the
1668 * listing).
1670 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1673 if (sconn && !sconn->using_smb2) {
1674 sconn->searches.dirhandles_open++;
1676 talloc_set_destructor(dirp, smb_Dir_destructor);
1678 return dirp;
1680 fail:
1681 TALLOC_FREE(dirp);
1682 return NULL;
1685 /****************************************************************************
1686 Open a directory handle by pathname, ensuring it's under the share path.
1687 ****************************************************************************/
1689 static struct smb_Dir *open_dir_safely(TALLOC_CTX *ctx,
1690 connection_struct *conn,
1691 const struct smb_filename *smb_dname,
1692 const char *wcard,
1693 uint32_t attr)
1695 struct smb_Dir *dir_hnd = NULL;
1696 struct smb_filename *smb_fname_cwd = NULL;
1697 struct smb_filename *saved_dir_fname = vfs_GetWd(ctx, conn);
1698 NTSTATUS status;
1700 if (saved_dir_fname == NULL) {
1701 return NULL;
1704 if (vfs_ChDir(conn, smb_dname) == -1) {
1705 goto out;
1708 smb_fname_cwd = synthetic_smb_fname(talloc_tos(),
1709 ".",
1710 NULL,
1711 NULL,
1712 smb_dname->flags);
1713 if (smb_fname_cwd == NULL) {
1714 goto out;
1718 * Now the directory is pinned, use
1719 * REALPATH to ensure we can access it.
1721 status = check_name(conn, smb_fname_cwd);
1722 if (!NT_STATUS_IS_OK(status)) {
1723 goto out;
1726 dir_hnd = OpenDir_internal(ctx,
1727 conn,
1728 smb_fname_cwd,
1729 wcard,
1730 attr);
1732 if (dir_hnd == NULL) {
1733 goto out;
1737 * OpenDir_internal only gets "." as the dir name.
1738 * Store the real dir name here.
1741 dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, smb_dname);
1742 if (!dir_hnd->dir_smb_fname) {
1743 TALLOC_FREE(dir_hnd);
1744 errno = ENOMEM;
1747 out:
1749 vfs_ChDir(conn, saved_dir_fname);
1750 TALLOC_FREE(saved_dir_fname);
1751 return dir_hnd;
1754 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1755 const struct smb_filename *smb_dname,
1756 const char *mask,
1757 uint32_t attr)
1759 return open_dir_safely(mem_ctx,
1760 conn,
1761 smb_dname,
1762 mask,
1763 attr);
1766 /*******************************************************************
1767 Open a directory from an fsp.
1768 ********************************************************************/
1770 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
1771 files_struct *fsp,
1772 const char *mask,
1773 uint32_t attr)
1775 struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1776 struct smbd_server_connection *sconn = conn->sconn;
1778 if (!dirp) {
1779 goto fail;
1782 if (!fsp->is_directory) {
1783 errno = EBADF;
1784 goto fail;
1787 if (fsp->fh->fd == -1) {
1788 errno = EBADF;
1789 goto fail;
1792 dirp->conn = conn;
1794 if (!conn->sconn->using_smb2) {
1796 * The dircache is only needed for SMB1 because SMB1 uses a name
1797 * for the resume wheras SMB2 always continues from the next
1798 * position (unless it's told to restart or close-and-reopen the
1799 * listing).
1801 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1804 dirp->dir_smb_fname = cp_smb_filename(dirp, fsp->fsp_name);
1805 if (!dirp->dir_smb_fname) {
1806 errno = ENOMEM;
1807 goto fail;
1810 dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1811 if (dirp->dir != NULL) {
1812 dirp->fsp = fsp;
1813 } else {
1814 DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1815 "NULL (%s)\n",
1816 dirp->dir_smb_fname->base_name,
1817 strerror(errno)));
1818 if (errno != ENOSYS) {
1819 goto fail;
1823 if (dirp->dir == NULL) {
1824 /* FDOPENDIR is not supported. Use OPENDIR instead. */
1825 TALLOC_FREE(dirp);
1826 return open_dir_safely(mem_ctx,
1827 conn,
1828 fsp->fsp_name,
1829 mask,
1830 attr);
1833 if (sconn && !sconn->using_smb2) {
1834 sconn->searches.dirhandles_open++;
1836 talloc_set_destructor(dirp, smb_Dir_destructor);
1838 return dirp;
1840 fail:
1841 TALLOC_FREE(dirp);
1842 return NULL;
1846 /*******************************************************************
1847 Read from a directory.
1848 Return directory entry, current offset, and optional stat information.
1849 Don't check for veto or invisible files.
1850 ********************************************************************/
1852 const char *ReadDirName(struct smb_Dir *dirp, long *poffset,
1853 SMB_STRUCT_STAT *sbuf, char **ptalloced)
1855 const char *n;
1856 char *talloced = NULL;
1857 connection_struct *conn = dirp->conn;
1859 /* Cheat to allow . and .. to be the first entries returned. */
1860 if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1861 (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2))
1863 if (dirp->file_number == 0) {
1864 n = ".";
1865 *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1866 } else {
1867 n = "..";
1868 *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1870 dirp->file_number++;
1871 *ptalloced = NULL;
1872 return n;
1875 if (*poffset == END_OF_DIRECTORY_OFFSET) {
1876 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1877 return NULL;
1880 /* A real offset, seek to it. */
1881 SeekDir(dirp, *poffset);
1883 while ((n = vfs_readdirname(conn, dirp->dir, sbuf, &talloced))) {
1884 /* Ignore . and .. - we've already returned them. */
1885 if (*n == '.') {
1886 if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1887 TALLOC_FREE(talloced);
1888 continue;
1891 *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1892 *ptalloced = talloced;
1893 dirp->file_number++;
1894 return n;
1896 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1897 *ptalloced = NULL;
1898 return NULL;
1901 /*******************************************************************
1902 Rewind to the start.
1903 ********************************************************************/
1905 void RewindDir(struct smb_Dir *dirp, long *poffset)
1907 SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1908 dirp->file_number = 0;
1909 dirp->offset = START_OF_DIRECTORY_OFFSET;
1910 *poffset = START_OF_DIRECTORY_OFFSET;
1913 /*******************************************************************
1914 Seek a dir.
1915 ********************************************************************/
1917 void SeekDir(struct smb_Dir *dirp, long offset)
1919 if (offset != dirp->offset) {
1920 if (offset == START_OF_DIRECTORY_OFFSET) {
1921 RewindDir(dirp, &offset);
1923 * Ok we should really set the file number here
1924 * to 1 to enable ".." to be returned next. Trouble
1925 * is I'm worried about callers using SeekDir(dirp,0)
1926 * as equivalent to RewindDir(). So leave this alone
1927 * for now.
1929 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
1930 RewindDir(dirp, &offset);
1932 * Set the file number to 2 - we want to get the first
1933 * real file entry (the one we return after "..")
1934 * on the next ReadDir.
1936 dirp->file_number = 2;
1937 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1938 ; /* Don't seek in this case. */
1939 } else {
1940 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1942 dirp->offset = offset;
1946 /*******************************************************************
1947 Tell a dir position.
1948 ********************************************************************/
1950 long TellDir(struct smb_Dir *dirp)
1952 return(dirp->offset);
1955 /*******************************************************************
1956 Add an entry into the dcache.
1957 ********************************************************************/
1959 static void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
1961 struct name_cache_entry *e;
1963 if (dirp->name_cache_size == 0) {
1964 return;
1967 if (dirp->name_cache == NULL) {
1968 dirp->name_cache = talloc_zero_array(
1969 dirp, struct name_cache_entry, dirp->name_cache_size);
1971 if (dirp->name_cache == NULL) {
1972 return;
1976 dirp->name_cache_index = (dirp->name_cache_index+1) %
1977 dirp->name_cache_size;
1978 e = &dirp->name_cache[dirp->name_cache_index];
1979 TALLOC_FREE(e->name);
1980 e->name = talloc_strdup(dirp, name);
1981 e->offset = offset;
1984 /*******************************************************************
1985 Find an entry by name. Leave us at the offset after it.
1986 Don't check for veto or invisible files.
1987 ********************************************************************/
1989 bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1991 int i;
1992 const char *entry = NULL;
1993 char *talloced = NULL;
1994 connection_struct *conn = dirp->conn;
1996 /* Search back in the name cache. */
1997 if (dirp->name_cache_size && dirp->name_cache) {
1998 for (i = dirp->name_cache_index; i >= 0; i--) {
1999 struct name_cache_entry *e = &dirp->name_cache[i];
2000 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
2001 *poffset = e->offset;
2002 SeekDir(dirp, e->offset);
2003 return True;
2006 for (i = dirp->name_cache_size - 1; i > dirp->name_cache_index; i--) {
2007 struct name_cache_entry *e = &dirp->name_cache[i];
2008 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
2009 *poffset = e->offset;
2010 SeekDir(dirp, e->offset);
2011 return True;
2016 /* Not found in the name cache. Rewind directory and start from scratch. */
2017 SMB_VFS_REWINDDIR(conn, dirp->dir);
2018 dirp->file_number = 0;
2019 *poffset = START_OF_DIRECTORY_OFFSET;
2020 while ((entry = ReadDirName(dirp, poffset, NULL, &talloced))) {
2021 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
2022 TALLOC_FREE(talloced);
2023 return True;
2025 TALLOC_FREE(talloced);
2027 return False;
2030 struct files_below_forall_state {
2031 char *dirpath;
2032 size_t dirpath_len;
2033 int (*fn)(struct file_id fid, const struct share_mode_data *data,
2034 void *private_data);
2035 void *private_data;
2038 static int files_below_forall_fn(struct file_id fid,
2039 const struct share_mode_data *data,
2040 void *private_data)
2042 struct files_below_forall_state *state = private_data;
2043 char tmpbuf[PATH_MAX];
2044 char *fullpath, *to_free;
2045 size_t len;
2047 len = full_path_tos(data->servicepath, data->base_name,
2048 tmpbuf, sizeof(tmpbuf),
2049 &fullpath, &to_free);
2050 if (len == -1) {
2051 return 0;
2053 if (state->dirpath_len >= len) {
2055 * Filter files above dirpath
2057 goto out;
2059 if (fullpath[state->dirpath_len] != '/') {
2061 * Filter file that don't have a path separator at the end of
2062 * dirpath's length
2064 goto out;
2067 if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
2069 * Not a parent
2071 goto out;
2074 TALLOC_FREE(to_free);
2075 return state->fn(fid, data, state->private_data);
2077 out:
2078 TALLOC_FREE(to_free);
2079 return 0;
2082 static int files_below_forall(connection_struct *conn,
2083 const struct smb_filename *dir_name,
2084 int (*fn)(struct file_id fid,
2085 const struct share_mode_data *data,
2086 void *private_data),
2087 void *private_data)
2089 struct files_below_forall_state state = {
2090 .fn = fn,
2091 .private_data = private_data,
2093 int ret;
2094 char tmpbuf[PATH_MAX];
2095 char *to_free;
2097 state.dirpath_len = full_path_tos(conn->connectpath,
2098 dir_name->base_name,
2099 tmpbuf, sizeof(tmpbuf),
2100 &state.dirpath, &to_free);
2101 if (state.dirpath_len == -1) {
2102 return -1;
2105 ret = share_mode_forall(files_below_forall_fn, &state);
2106 TALLOC_FREE(to_free);
2107 return ret;
2110 struct have_file_open_below_state {
2111 bool found_one;
2114 static int have_file_open_below_fn(struct file_id fid,
2115 const struct share_mode_data *data,
2116 void *private_data)
2118 struct have_file_open_below_state *state = private_data;
2119 state->found_one = true;
2120 return 1;
2123 bool have_file_open_below(connection_struct *conn,
2124 const struct smb_filename *name)
2126 struct have_file_open_below_state state = {
2127 .found_one = false,
2129 int ret;
2131 if (!VALID_STAT(name->st)) {
2132 return false;
2134 if (!S_ISDIR(name->st.st_ex_mode)) {
2135 return false;
2138 ret = files_below_forall(conn, name, have_file_open_below_fn, &state);
2139 if (ret == -1) {
2140 return false;
2143 return state.found_one;
2146 /*****************************************************************
2147 Is this directory empty ?
2148 *****************************************************************/
2150 NTSTATUS can_delete_directory_fsp(files_struct *fsp)
2152 NTSTATUS status = NT_STATUS_OK;
2153 long dirpos = 0;
2154 const char *dname = NULL;
2155 const char *dirname = fsp->fsp_name->base_name;
2156 char *talloced = NULL;
2157 SMB_STRUCT_STAT st;
2158 struct connection_struct *conn = fsp->conn;
2159 struct smb_Dir *dir_hnd = OpenDir(talloc_tos(),
2160 conn,
2161 fsp->fsp_name,
2162 NULL,
2165 if (!dir_hnd) {
2166 return map_nt_error_from_unix(errno);
2169 while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) {
2170 /* Quick check for "." and ".." */
2171 if (dname[0] == '.') {
2172 if (!dname[1] || (dname[1] == '.' && !dname[2])) {
2173 TALLOC_FREE(talloced);
2174 continue;
2178 if (!is_visible_file(conn, dirname, dname, &st, True)) {
2179 TALLOC_FREE(talloced);
2180 continue;
2183 DEBUG(10,("got name %s - can't delete\n",
2184 dname ));
2185 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
2186 break;
2188 TALLOC_FREE(talloced);
2189 TALLOC_FREE(dir_hnd);
2191 if (!NT_STATUS_IS_OK(status)) {
2192 return status;
2195 if (!(fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) &&
2196 lp_strict_rename(SNUM(conn)) &&
2197 have_file_open_below(fsp->conn, fsp->fsp_name))
2199 return NT_STATUS_ACCESS_DENIED;
2202 return NT_STATUS_OK;