prefork tests: re-enable restart tests for MIT Kerberos
[Samba.git] / source3 / smbd / dir.c
blob2c59cb898ec064142c28be82d96efbdf721447d5
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 Get the struct dptr_struct for a dir index.
112 ****************************************************************************/
114 static struct dptr_struct *dptr_get(struct smbd_server_connection *sconn,
115 int key)
117 struct dptr_struct *dptr;
119 for (dptr = sconn->searches.dirptrs; dptr != NULL; dptr = dptr->next) {
120 if(dptr->dnum != key) {
121 continue;
123 DLIST_PROMOTE(sconn->searches.dirptrs, dptr);
124 return dptr;
126 return(NULL);
129 /****************************************************************************
130 Get the dir path for a dir index.
131 ****************************************************************************/
133 const char *dptr_path(struct smbd_server_connection *sconn, int key)
135 struct dptr_struct *dptr = dptr_get(sconn, key);
136 if (dptr)
137 return(dptr->smb_dname->base_name);
138 return(NULL);
141 /****************************************************************************
142 Get the dir wcard for a dir index.
143 ****************************************************************************/
145 const char *dptr_wcard(struct smbd_server_connection *sconn, int key)
147 struct dptr_struct *dptr = dptr_get(sconn, key);
148 if (dptr)
149 return(dptr->wcard);
150 return(NULL);
153 /****************************************************************************
154 Get the dir attrib for a dir index.
155 ****************************************************************************/
157 uint16_t dptr_attr(struct smbd_server_connection *sconn, int key)
159 struct dptr_struct *dptr = dptr_get(sconn, key);
160 if (dptr)
161 return(dptr->attr);
162 return(0);
165 /****************************************************************************
166 Close a dptr (internal func).
167 ****************************************************************************/
169 static void dptr_close_internal(struct dptr_struct *dptr)
171 struct smbd_server_connection *sconn = dptr->conn->sconn;
173 DEBUG(4,("closing dptr key %d\n",dptr->dnum));
175 if (sconn == NULL) {
176 goto done;
179 if (sconn->using_smb2) {
180 goto done;
183 DLIST_REMOVE(sconn->searches.dirptrs, dptr);
186 * Free the dnum in the bitmap. Remember the dnum value is always
187 * biased by one with respect to the bitmap.
190 if (!bitmap_query(sconn->searches.dptr_bmap, dptr->dnum - 1)) {
191 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
192 dptr->dnum ));
195 bitmap_clear(sconn->searches.dptr_bmap, dptr->dnum - 1);
197 done:
198 TALLOC_FREE(dptr->dir_hnd);
199 TALLOC_FREE(dptr);
202 /****************************************************************************
203 Close a dptr given a key.
204 ****************************************************************************/
206 void dptr_close(struct smbd_server_connection *sconn, int *key)
208 struct dptr_struct *dptr;
210 if(*key == INVALID_DPTR_KEY)
211 return;
213 /* OS/2 seems to use -1 to indicate "close all directories" */
214 if (*key == -1) {
215 struct dptr_struct *next;
216 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
217 next = dptr->next;
218 dptr_close_internal(dptr);
220 *key = INVALID_DPTR_KEY;
221 return;
224 dptr = dptr_get(sconn, *key);
226 if (!dptr) {
227 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
228 return;
231 dptr_close_internal(dptr);
233 *key = INVALID_DPTR_KEY;
236 /****************************************************************************
237 Close all dptrs for a cnum.
238 ****************************************************************************/
240 void dptr_closecnum(connection_struct *conn)
242 struct dptr_struct *dptr, *next;
243 struct smbd_server_connection *sconn = conn->sconn;
245 if (sconn == NULL) {
246 return;
249 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
250 next = dptr->next;
251 if (dptr->conn == conn) {
252 dptr_close_internal(dptr);
257 /****************************************************************************
258 Are there any SMB1 searches active on this connection struct ?
259 ****************************************************************************/
261 bool dptr_activecnum(const struct smbd_server_connection *sconn,
262 const struct connection_struct *conn)
264 const struct dptr_struct *dptr;
266 for(dptr = sconn->searches.dirptrs; dptr; dptr = dptr->next) {
267 if (dptr->conn == conn) {
268 return true;
271 return false;
274 /****************************************************************************
275 Close a dptr that matches a given path, only if it matches the spid also.
276 ****************************************************************************/
278 void dptr_closepath(struct smbd_server_connection *sconn,
279 char *path,uint16_t spid)
281 struct dptr_struct *dptr, *next;
282 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
283 next = dptr->next;
284 if (spid == dptr->spid &&
285 strequal(dptr->smb_dname->base_name,path)) {
286 dptr_close_internal(dptr);
291 /****************************************************************************
292 Safely do an OpenDir as root, ensuring we're in the right place.
293 ****************************************************************************/
295 static struct smb_Dir *open_dir_with_privilege(connection_struct *conn,
296 struct smb_request *req,
297 const struct smb_filename *smb_dname,
298 const char *wcard,
299 uint32_t attr)
301 struct smb_Dir *dir_hnd = NULL;
302 struct smb_filename *smb_fname_cwd = NULL;
303 struct smb_filename *saved_dir_fname = vfs_GetWd(talloc_tos(), conn);
304 struct privilege_paths *priv_paths = req->priv_paths;
305 int ret;
307 if (saved_dir_fname == NULL) {
308 return NULL;
311 if (vfs_ChDir(conn, smb_dname) == -1) {
312 return NULL;
315 /* Now check the stat value is the same. */
316 smb_fname_cwd = synthetic_smb_fname(talloc_tos(),
317 ".",
318 NULL,
319 NULL,
320 smb_dname->flags);
321 if (smb_fname_cwd == NULL) {
322 goto out;
324 ret = SMB_VFS_STAT(conn, smb_fname_cwd);
325 if (ret != 0) {
326 goto out;
329 if (!check_same_stat(&smb_fname_cwd->st, &priv_paths->parent_name.st)) {
330 DEBUG(0,("open_dir_with_privilege: stat mismatch between %s "
331 "and %s\n",
332 smb_dname->base_name,
333 smb_fname_str_dbg(&priv_paths->parent_name)));
334 goto out;
337 dir_hnd = OpenDir(NULL, conn, smb_fname_cwd, wcard, attr);
339 out:
341 vfs_ChDir(conn, saved_dir_fname);
342 TALLOC_FREE(saved_dir_fname);
343 return dir_hnd;
346 /****************************************************************************
347 Create a new dir ptr. If the flag old_handle is true then we must allocate
348 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
349 one byte long. If old_handle is false we allocate from the range
350 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
351 a directory handle is never zero.
352 wcard must not be zero.
353 ****************************************************************************/
355 NTSTATUS dptr_create(connection_struct *conn,
356 struct smb_request *req,
357 files_struct *fsp,
358 const struct smb_filename *smb_dname,
359 bool old_handle,
360 bool expect_close,
361 uint16_t spid,
362 const char *wcard,
363 bool wcard_has_wild,
364 uint32_t attr,
365 struct dptr_struct **dptr_ret)
367 struct smbd_server_connection *sconn = conn->sconn;
368 struct dptr_struct *dptr = NULL;
369 struct smb_Dir *dir_hnd;
371 if (fsp && fsp->is_directory && fsp->fh->fd != -1) {
372 smb_dname = fsp->fsp_name;
375 DEBUG(5,("dptr_create dir=%s\n", smb_dname->base_name));
377 if (sconn == NULL) {
378 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
379 return NT_STATUS_INTERNAL_ERROR;
382 if (!wcard) {
383 return NT_STATUS_INVALID_PARAMETER;
386 if (fsp) {
387 if (!(fsp->access_mask & SEC_DIR_LIST)) {
388 DEBUG(5,("dptr_create: directory %s "
389 "not open for LIST access\n",
390 smb_dname->base_name));
391 return NT_STATUS_ACCESS_DENIED;
393 dir_hnd = OpenDir_fsp(NULL, conn, fsp, wcard, attr);
394 } else {
395 int ret;
396 bool backup_intent = (req && req->priv_paths);
397 NTSTATUS status;
398 struct smb_filename *smb_dname_cp =
399 cp_smb_filename(talloc_tos(), smb_dname);
401 if (smb_dname_cp == NULL) {
402 return NT_STATUS_NO_MEMORY;
405 if (req != NULL && req->posix_pathnames) {
406 ret = SMB_VFS_LSTAT(conn, smb_dname_cp);
407 } else {
408 ret = SMB_VFS_STAT(conn, smb_dname_cp);
410 if (ret == -1) {
411 status = map_nt_error_from_unix(errno);
412 TALLOC_FREE(smb_dname_cp);
413 return status;
415 if (!S_ISDIR(smb_dname_cp->st.st_ex_mode)) {
416 TALLOC_FREE(smb_dname_cp);
417 return NT_STATUS_NOT_A_DIRECTORY;
419 status = smbd_check_access_rights(conn,
420 smb_dname_cp,
421 backup_intent,
422 SEC_DIR_LIST);
423 if (!NT_STATUS_IS_OK(status)) {
424 TALLOC_FREE(smb_dname_cp);
425 return status;
427 if (backup_intent) {
428 dir_hnd = open_dir_with_privilege(conn,
429 req,
430 smb_dname_cp,
431 wcard,
432 attr);
433 } else {
434 dir_hnd = OpenDir(NULL,
435 conn,
436 smb_dname_cp,
437 wcard,
438 attr);
440 TALLOC_FREE(smb_dname_cp);
443 if (!dir_hnd) {
444 return map_nt_error_from_unix(errno);
447 dptr = talloc_zero(NULL, struct dptr_struct);
448 if(!dptr) {
449 DEBUG(0,("talloc fail in dptr_create.\n"));
450 TALLOC_FREE(dir_hnd);
451 return NT_STATUS_NO_MEMORY;
454 dptr->smb_dname = cp_smb_filename(dptr, smb_dname);
455 if (!dptr->smb_dname) {
456 TALLOC_FREE(dptr);
457 TALLOC_FREE(dir_hnd);
458 return NT_STATUS_NO_MEMORY;
460 dptr->conn = conn;
461 dptr->dir_hnd = dir_hnd;
462 dptr->spid = spid;
463 dptr->expect_close = expect_close;
464 dptr->wcard = talloc_strdup(dptr, wcard);
465 if (!dptr->wcard) {
466 TALLOC_FREE(dptr);
467 TALLOC_FREE(dir_hnd);
468 return NT_STATUS_NO_MEMORY;
470 if ((req != NULL && req->posix_pathnames) ||
471 (wcard[0] == '.' && wcard[1] == 0)) {
472 dptr->has_wild = True;
473 } else {
474 dptr->has_wild = wcard_has_wild;
477 dptr->attr = attr;
479 if (sconn->using_smb2) {
480 goto done;
483 if(old_handle) {
486 * This is an old-style SMBsearch request. Ensure the
487 * value we return will fit in the range 1-255.
490 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
492 if(dptr->dnum == -1 || dptr->dnum > 254) {
493 DBG_ERR("returned %d: Error - all old "
494 "dirptrs in use ?\n",
495 dptr->dnum);
496 TALLOC_FREE(dptr);
497 TALLOC_FREE(dir_hnd);
498 return NT_STATUS_TOO_MANY_OPENED_FILES;
500 } else {
503 * This is a new-style trans2 request. Allocate from
504 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
507 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
509 if(dptr->dnum == -1 || dptr->dnum < 255) {
510 DBG_ERR("returned %d: Error - all new "
511 "dirptrs in use ?\n",
512 dptr->dnum);
513 TALLOC_FREE(dptr);
514 TALLOC_FREE(dir_hnd);
515 return NT_STATUS_TOO_MANY_OPENED_FILES;
519 bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
521 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
523 DLIST_ADD(sconn->searches.dirptrs, dptr);
525 done:
526 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
527 dptr->dnum,
528 dptr->smb_dname->base_name,
529 expect_close));
531 *dptr_ret = dptr;
533 return NT_STATUS_OK;
537 /****************************************************************************
538 Wrapper functions to access the lower level directory handles.
539 ****************************************************************************/
541 void dptr_CloseDir(files_struct *fsp)
543 if (fsp->dptr) {
545 * The destructor for the struct smb_Dir
546 * (fsp->dptr->dir_hnd) now handles
547 * all resource deallocation.
549 dptr_close_internal(fsp->dptr);
550 fsp->dptr = NULL;
554 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
556 SeekDir(dptr->dir_hnd, offset);
559 long dptr_TellDir(struct dptr_struct *dptr)
561 return TellDir(dptr->dir_hnd);
564 bool dptr_has_wild(struct dptr_struct *dptr)
566 return dptr->has_wild;
569 int dptr_dnum(struct dptr_struct *dptr)
571 return dptr->dnum;
574 bool dptr_get_priv(struct dptr_struct *dptr)
576 return dptr->priv;
579 void dptr_set_priv(struct dptr_struct *dptr)
581 dptr->priv = true;
584 /****************************************************************************
585 Return the next visible file name, skipping veto'd and invisible files.
586 ****************************************************************************/
588 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr,
589 long *poffset, SMB_STRUCT_STAT *pst,
590 char **ptalloced)
592 /* Normal search for the next file. */
593 const char *name;
594 char *talloced = NULL;
596 while ((name = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced))
597 != NULL) {
598 if (is_visible_file(dptr->conn,
599 dptr->smb_dname->base_name,
600 name,
601 pst,
602 true)) {
603 *ptalloced = talloced;
604 return name;
606 TALLOC_FREE(talloced);
608 return NULL;
611 /****************************************************************************
612 Return the next visible file name, skipping veto'd and invisible files.
613 ****************************************************************************/
615 static char *dptr_ReadDirName(TALLOC_CTX *ctx,
616 struct dptr_struct *dptr,
617 long *poffset,
618 SMB_STRUCT_STAT *pst)
620 struct smb_filename smb_fname_base;
621 char *name = NULL;
622 const char *name_temp = NULL;
623 char *talloced = NULL;
624 char *pathreal = NULL;
625 char *found_name = NULL;
626 int ret;
628 SET_STAT_INVALID(*pst);
630 if (dptr->has_wild || dptr->did_stat) {
631 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst,
632 &talloced);
633 if (name_temp == NULL) {
634 return NULL;
636 if (talloced != NULL) {
637 return talloc_move(ctx, &talloced);
639 return talloc_strdup(ctx, name_temp);
642 /* If poffset is -1 then we know we returned this name before and we
643 * have no wildcards. We're at the end of the directory. */
644 if (*poffset == END_OF_DIRECTORY_OFFSET) {
645 return NULL;
648 /* We know the stored wcard contains no wildcard characters.
649 * See if we can match with a stat call. If we can't, then set
650 * did_stat to true to ensure we only do this once and keep
651 * searching. */
653 dptr->did_stat = true;
655 /* First check if it should be visible. */
656 if (!is_visible_file(dptr->conn,
657 dptr->smb_dname->base_name,
658 dptr->wcard,
659 pst,
660 true)) {
661 /* This only returns false if the file was found, but
662 is explicitly not visible. Set us to end of
663 directory, but return NULL as we know we can't ever
664 find it. */
665 goto ret;
668 if (VALID_STAT(*pst)) {
669 name = talloc_strdup(ctx, dptr->wcard);
670 goto ret;
673 pathreal = talloc_asprintf(ctx,
674 "%s/%s",
675 dptr->smb_dname->base_name,
676 dptr->wcard);
677 if (!pathreal)
678 return NULL;
680 /* Create an smb_filename with stream_name == NULL. */
681 smb_fname_base = (struct smb_filename) { .base_name = pathreal };
683 if (SMB_VFS_STAT(dptr->conn, &smb_fname_base) == 0) {
684 *pst = smb_fname_base.st;
685 name = talloc_strdup(ctx, dptr->wcard);
686 goto clean;
687 } else {
688 /* If we get any other error than ENOENT or ENOTDIR
689 then the file exists we just can't stat it. */
690 if (errno != ENOENT && errno != ENOTDIR) {
691 name = talloc_strdup(ctx, dptr->wcard);
692 goto clean;
696 /* Stat failed. We know this is authoratiative if we are
697 * providing case sensitive semantics or the underlying
698 * filesystem is case sensitive.
700 if (dptr->conn->case_sensitive ||
701 !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
703 goto clean;
707 * Try case-insensitive stat if the fs has the ability. This avoids
708 * scanning the whole directory.
710 ret = SMB_VFS_GET_REAL_FILENAME(dptr->conn,
711 dptr->smb_dname->base_name,
712 dptr->wcard,
713 ctx,
714 &found_name);
715 if (ret == 0) {
716 name = found_name;
717 goto clean;
718 } else if (errno == ENOENT) {
719 /* The case-insensitive lookup was authoritative. */
720 goto clean;
723 TALLOC_FREE(pathreal);
725 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst, &talloced);
726 if (name_temp == NULL) {
727 return NULL;
729 if (talloced != NULL) {
730 return talloc_move(ctx, &talloced);
732 return talloc_strdup(ctx, name_temp);
734 clean:
735 TALLOC_FREE(pathreal);
736 ret:
737 /* We need to set the underlying dir_hnd offset to -1
738 * also as this function is usually called with the
739 * output from TellDir. */
740 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
741 return name;
744 /****************************************************************************
745 Search for a file by name, skipping veto'ed and not visible files.
746 ****************************************************************************/
748 bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
750 SET_STAT_INVALID(*pst);
752 if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
753 /* This is a singleton directory and we're already at the end. */
754 *poffset = END_OF_DIRECTORY_OFFSET;
755 return False;
758 return SearchDir(dptr->dir_hnd, name, poffset);
761 /****************************************************************************
762 Map a native directory offset to a 32-bit cookie.
763 ****************************************************************************/
765 static uint32_t map_dir_offset_to_wire(struct dptr_struct *dptr, long offset)
767 DATA_BLOB key;
768 DATA_BLOB val;
770 if (offset == END_OF_DIRECTORY_OFFSET) {
771 return WIRE_END_OF_DIRECTORY_OFFSET;
772 } else if(offset == START_OF_DIRECTORY_OFFSET) {
773 return WIRE_START_OF_DIRECTORY_OFFSET;
774 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
775 return WIRE_DOT_DOT_DIRECTORY_OFFSET;
777 if (sizeof(long) == 4) {
778 /* 32-bit machine. We can cheat... */
779 return (uint32_t)offset;
781 if (dptr->dptr_cache == NULL) {
782 /* Lazy initialize cache. */
783 dptr->dptr_cache = memcache_init(dptr, 0);
784 if (dptr->dptr_cache == NULL) {
785 return WIRE_END_OF_DIRECTORY_OFFSET;
787 } else {
788 /* Have we seen this offset before ? */
789 key.data = (void *)&offset;
790 key.length = sizeof(offset);
791 if (memcache_lookup(dptr->dptr_cache,
792 SMB1_SEARCH_OFFSET_MAP,
793 key,
794 &val)) {
795 uint32_t wire_offset;
796 SMB_ASSERT(val.length == sizeof(wire_offset));
797 memcpy(&wire_offset, val.data, sizeof(wire_offset));
798 DEBUG(10,("found wire %u <-> offset %ld\n",
799 (unsigned int)wire_offset,
800 (long)offset));
801 return wire_offset;
804 /* Allocate a new wire cookie. */
805 do {
806 dptr->counter++;
807 } while (dptr->counter == WIRE_START_OF_DIRECTORY_OFFSET ||
808 dptr->counter == WIRE_END_OF_DIRECTORY_OFFSET ||
809 dptr->counter == WIRE_DOT_DOT_DIRECTORY_OFFSET);
810 /* Store it in the cache. */
811 key.data = (void *)&offset;
812 key.length = sizeof(offset);
813 val.data = (void *)&dptr->counter;
814 val.length = sizeof(dptr->counter); /* MUST BE uint32_t ! */
815 memcache_add(dptr->dptr_cache,
816 SMB1_SEARCH_OFFSET_MAP,
817 key,
818 val);
819 /* And the reverse mapping for lookup from
820 map_wire_to_dir_offset(). */
821 memcache_add(dptr->dptr_cache,
822 SMB1_SEARCH_OFFSET_MAP,
823 val,
824 key);
825 DEBUG(10,("stored wire %u <-> offset %ld\n",
826 (unsigned int)dptr->counter,
827 (long)offset));
828 return dptr->counter;
831 /****************************************************************************
832 Fill the 5 byte server reserved dptr field.
833 ****************************************************************************/
835 bool dptr_fill(struct smbd_server_connection *sconn,
836 char *buf1,unsigned int key)
838 unsigned char *buf = (unsigned char *)buf1;
839 struct dptr_struct *dptr = dptr_get(sconn, key);
840 uint32_t wire_offset;
841 if (!dptr) {
842 DEBUG(1,("filling null dirptr %d\n",key));
843 return(False);
845 wire_offset = map_dir_offset_to_wire(dptr,TellDir(dptr->dir_hnd));
846 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
847 (long)dptr->dir_hnd,(int)wire_offset));
848 buf[0] = key;
849 SIVAL(buf,1,wire_offset);
850 return(True);
853 /****************************************************************************
854 Map a 32-bit wire cookie to a native directory offset.
855 ****************************************************************************/
857 static long map_wire_to_dir_offset(struct dptr_struct *dptr, uint32_t wire_offset)
859 DATA_BLOB key;
860 DATA_BLOB val;
862 if (wire_offset == WIRE_END_OF_DIRECTORY_OFFSET) {
863 return END_OF_DIRECTORY_OFFSET;
864 } else if(wire_offset == WIRE_START_OF_DIRECTORY_OFFSET) {
865 return START_OF_DIRECTORY_OFFSET;
866 } else if (wire_offset == WIRE_DOT_DOT_DIRECTORY_OFFSET) {
867 return DOT_DOT_DIRECTORY_OFFSET;
869 if (sizeof(long) == 4) {
870 /* 32-bit machine. We can cheat... */
871 return (long)wire_offset;
873 if (dptr->dptr_cache == NULL) {
874 /* Logic error, cache should be initialized. */
875 return END_OF_DIRECTORY_OFFSET;
877 key.data = (void *)&wire_offset;
878 key.length = sizeof(wire_offset);
879 if (memcache_lookup(dptr->dptr_cache,
880 SMB1_SEARCH_OFFSET_MAP,
881 key,
882 &val)) {
883 /* Found mapping. */
884 long offset;
885 SMB_ASSERT(val.length == sizeof(offset));
886 memcpy(&offset, val.data, sizeof(offset));
887 DEBUG(10,("lookup wire %u <-> offset %ld\n",
888 (unsigned int)wire_offset,
889 (long)offset));
890 return offset;
892 return END_OF_DIRECTORY_OFFSET;
895 /****************************************************************************
896 Fetch the dir ptr and seek it given the 5 byte server field.
897 ****************************************************************************/
899 struct dptr_struct *dptr_fetch(struct smbd_server_connection *sconn,
900 char *buf, int *num)
902 unsigned int key = *(unsigned char *)buf;
903 struct dptr_struct *dptr = dptr_get(sconn, key);
904 uint32_t wire_offset;
905 long seekoff;
907 if (!dptr) {
908 DEBUG(3,("fetched null dirptr %d\n",key));
909 return(NULL);
911 *num = key;
912 wire_offset = IVAL(buf,1);
913 seekoff = map_wire_to_dir_offset(dptr, wire_offset);
914 SeekDir(dptr->dir_hnd,seekoff);
915 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
916 key, dptr->smb_dname->base_name, (int)seekoff));
917 return(dptr);
920 /****************************************************************************
921 Fetch the dir ptr.
922 ****************************************************************************/
924 struct dptr_struct *dptr_fetch_lanman2(struct smbd_server_connection *sconn,
925 int dptr_num)
927 struct dptr_struct *dptr = dptr_get(sconn, dptr_num);
929 if (!dptr) {
930 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
931 return(NULL);
933 DEBUG(3,("fetching dirptr %d for path %s\n",
934 dptr_num,
935 dptr->smb_dname->base_name));
936 return(dptr);
939 static bool mangle_mask_match(connection_struct *conn,
940 const char *filename,
941 const char *mask)
943 char mname[13];
945 if (!name_to_8_3(filename,mname,False,conn->params)) {
946 return False;
948 return mask_match_search(mname,mask,False);
951 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
952 struct dptr_struct *dirptr,
953 const char *mask,
954 uint32_t dirtype,
955 bool dont_descend,
956 bool ask_sharemode,
957 bool get_dosmode,
958 bool (*match_fn)(TALLOC_CTX *ctx,
959 void *private_data,
960 const char *dname,
961 const char *mask,
962 char **_fname),
963 bool (*mode_fn)(TALLOC_CTX *ctx,
964 void *private_data,
965 struct smb_filename *smb_fname,
966 bool get_dosmode,
967 uint32_t *_mode),
968 void *private_data,
969 char **_fname,
970 struct smb_filename **_smb_fname,
971 uint32_t *_mode,
972 long *_prev_offset)
974 connection_struct *conn = dirptr->conn;
975 size_t slashlen;
976 size_t pathlen;
977 const char *dpath = dirptr->smb_dname->base_name;
978 bool dirptr_path_is_dot = ISDOT(dpath);
980 *_smb_fname = NULL;
981 *_mode = 0;
983 pathlen = strlen(dpath);
984 slashlen = ( dpath[pathlen-1] != '/') ? 1 : 0;
986 while (true) {
987 long cur_offset;
988 long prev_offset;
989 SMB_STRUCT_STAT sbuf = { 0 };
990 char *dname = NULL;
991 bool isdots;
992 char *fname = NULL;
993 char *pathreal = NULL;
994 struct smb_filename smb_fname;
995 uint32_t mode = 0;
996 bool ok;
998 cur_offset = dptr_TellDir(dirptr);
999 prev_offset = cur_offset;
1000 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
1002 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
1003 (long)dirptr, cur_offset));
1005 if (dname == NULL) {
1006 return false;
1009 isdots = (ISDOT(dname) || ISDOTDOT(dname));
1010 if (dont_descend && !isdots) {
1011 TALLOC_FREE(dname);
1012 continue;
1016 * fname may get mangled, dname is never mangled.
1017 * Whenever we're accessing the filesystem we use
1018 * pathreal which is composed from dname.
1021 ok = match_fn(ctx, private_data, dname, mask, &fname);
1022 if (!ok) {
1023 TALLOC_FREE(dname);
1024 continue;
1028 * This used to be
1029 * pathreal = talloc_asprintf(ctx, "%s%s%s", dirptr->path,
1030 * needslash?"/":"", dname);
1031 * but this was measurably slower than doing the memcpy.
1034 pathreal = talloc_array(
1035 ctx, char,
1036 pathlen + slashlen + talloc_get_size(dname));
1037 if (!pathreal) {
1038 TALLOC_FREE(dname);
1039 TALLOC_FREE(fname);
1040 return false;
1044 * We don't want to pass ./xxx to modules below us so don't
1045 * add the path if it is just . by itself.
1047 if (dirptr_path_is_dot) {
1048 memcpy(pathreal, dname, talloc_get_size(dname));
1049 } else {
1050 memcpy(pathreal, dpath, pathlen);
1051 pathreal[pathlen] = '/';
1052 memcpy(pathreal + slashlen + pathlen, dname,
1053 talloc_get_size(dname));
1056 /* Create smb_fname with NULL stream_name. */
1057 smb_fname = (struct smb_filename) {
1058 .base_name = pathreal, .st = sbuf
1061 ok = mode_fn(ctx, private_data, &smb_fname, get_dosmode, &mode);
1062 if (!ok) {
1063 TALLOC_FREE(dname);
1064 TALLOC_FREE(fname);
1065 TALLOC_FREE(pathreal);
1066 continue;
1069 if (!dir_check_ftype(mode, dirtype)) {
1070 DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
1071 fname, (unsigned int)mode, (unsigned int)dirtype));
1072 TALLOC_FREE(dname);
1073 TALLOC_FREE(fname);
1074 TALLOC_FREE(pathreal);
1075 continue;
1078 if (ask_sharemode) {
1079 struct timespec write_time_ts;
1080 struct file_id fileid;
1082 fileid = vfs_file_id_from_sbuf(conn,
1083 &smb_fname.st);
1084 get_file_infos(fileid, 0, NULL, &write_time_ts);
1085 if (!null_timespec(write_time_ts)) {
1086 update_stat_ex_mtime(&smb_fname.st,
1087 write_time_ts);
1091 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
1092 "fname=%s (%s)\n",
1093 mask, smb_fname_str_dbg(&smb_fname),
1094 dname, fname));
1096 if (!conn->sconn->using_smb2) {
1098 * The dircache is only needed for SMB1 because SMB1
1099 * uses a name for the resume wheras SMB2 always
1100 * continues from the next position (unless it's told to
1101 * restart or close-and-reopen the listing).
1103 DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
1106 TALLOC_FREE(dname);
1108 *_smb_fname = cp_smb_filename(ctx, &smb_fname);
1109 TALLOC_FREE(pathreal);
1110 if (*_smb_fname == NULL) {
1111 return false;
1113 *_fname = fname;
1114 *_mode = mode;
1115 *_prev_offset = prev_offset;
1117 return true;
1120 return false;
1123 /****************************************************************************
1124 Get an 8.3 directory entry.
1125 ****************************************************************************/
1127 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
1128 void *private_data,
1129 const char *dname,
1130 const char *mask,
1131 char **_fname)
1133 connection_struct *conn = (connection_struct *)private_data;
1135 if ((strcmp(mask,"*.*") == 0) ||
1136 mask_match_search(dname, mask, false) ||
1137 mangle_mask_match(conn, dname, mask)) {
1138 char mname[13];
1139 const char *fname;
1141 * Ensure we can push the original name as UCS2. If
1142 * not, then just don't return this name.
1144 NTSTATUS status;
1145 size_t ret_len = 0;
1146 size_t len = (strlen(dname) + 2) * 4; /* Allow enough space. */
1147 uint8_t *tmp = talloc_array(talloc_tos(),
1148 uint8_t,
1149 len);
1151 status = srvstr_push(NULL,
1152 FLAGS2_UNICODE_STRINGS,
1153 tmp,
1154 dname,
1155 len,
1156 STR_TERMINATE,
1157 &ret_len);
1159 TALLOC_FREE(tmp);
1161 if (!NT_STATUS_IS_OK(status)) {
1162 return false;
1165 if (!mangle_is_8_3(dname, false, conn->params)) {
1166 bool ok = name_to_8_3(dname, mname, false,
1167 conn->params);
1168 if (!ok) {
1169 return false;
1171 fname = mname;
1172 } else {
1173 fname = dname;
1176 *_fname = talloc_strdup(ctx, fname);
1177 if (*_fname == NULL) {
1178 return false;
1181 return true;
1184 return false;
1187 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1188 void *private_data,
1189 struct smb_filename *smb_fname,
1190 bool get_dosmode,
1191 uint32_t *_mode)
1193 connection_struct *conn = (connection_struct *)private_data;
1195 if (!VALID_STAT(smb_fname->st)) {
1196 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1197 DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1198 "Couldn't stat [%s]. Error "
1199 "= %s\n",
1200 smb_fname_str_dbg(smb_fname),
1201 strerror(errno)));
1202 return false;
1206 *_mode = dos_mode(conn, smb_fname);
1207 return true;
1210 bool get_dir_entry(TALLOC_CTX *ctx,
1211 struct dptr_struct *dirptr,
1212 const char *mask,
1213 uint32_t dirtype,
1214 char **_fname,
1215 off_t *_size,
1216 uint32_t *_mode,
1217 struct timespec *_date,
1218 bool check_descend,
1219 bool ask_sharemode)
1221 connection_struct *conn = dirptr->conn;
1222 char *fname = NULL;
1223 struct smb_filename *smb_fname = NULL;
1224 uint32_t mode = 0;
1225 long prev_offset;
1226 bool ok;
1228 ok = smbd_dirptr_get_entry(ctx,
1229 dirptr,
1230 mask,
1231 dirtype,
1232 check_descend,
1233 ask_sharemode,
1234 true,
1235 smbd_dirptr_8_3_match_fn,
1236 smbd_dirptr_8_3_mode_fn,
1237 conn,
1238 &fname,
1239 &smb_fname,
1240 &mode,
1241 &prev_offset);
1242 if (!ok) {
1243 return false;
1246 *_fname = talloc_move(ctx, &fname);
1247 *_size = smb_fname->st.st_ex_size;
1248 *_mode = mode;
1249 *_date = smb_fname->st.st_ex_mtime;
1250 TALLOC_FREE(smb_fname);
1251 return true;
1254 /*******************************************************************
1255 Check to see if a user can read a file. This is only approximate,
1256 it is used as part of the "hide unreadable" option. Don't
1257 use it for anything security sensitive.
1258 ********************************************************************/
1260 static bool user_can_read_file(connection_struct *conn,
1261 struct smb_filename *smb_fname)
1263 NTSTATUS status;
1264 uint32_t rejected_share_access = 0;
1265 uint32_t rejected_mask = 0;
1266 struct security_descriptor *sd = NULL;
1267 uint32_t access_mask = FILE_READ_DATA|
1268 FILE_READ_EA|
1269 FILE_READ_ATTRIBUTES|
1270 SEC_STD_READ_CONTROL;
1273 * Never hide files from the root user.
1274 * We use (uid_t)0 here not sec_initial_uid()
1275 * as make test uses a single user context.
1278 if (get_current_uid(conn) == (uid_t)0) {
1279 return True;
1283 * We can't directly use smbd_check_access_rights()
1284 * here, as this implicitly grants FILE_READ_ATTRIBUTES
1285 * which the Windows access-based-enumeration code
1286 * explicitly checks for on the file security descriptor.
1287 * See bug:
1289 * https://bugzilla.samba.org/show_bug.cgi?id=10252
1291 * and the smb2.acl2.ACCESSBASED test for details.
1294 rejected_share_access = access_mask & ~(conn->share_access);
1295 if (rejected_share_access) {
1296 DEBUG(10, ("rejected share access 0x%x "
1297 "on %s (0x%x)\n",
1298 (unsigned int)access_mask,
1299 smb_fname_str_dbg(smb_fname),
1300 (unsigned int)rejected_share_access ));
1301 return false;
1304 status = SMB_VFS_GET_NT_ACL(conn,
1305 smb_fname,
1306 (SECINFO_OWNER |
1307 SECINFO_GROUP |
1308 SECINFO_DACL),
1309 talloc_tos(),
1310 &sd);
1312 if (!NT_STATUS_IS_OK(status)) {
1313 DEBUG(10, ("Could not get acl "
1314 "on %s: %s\n",
1315 smb_fname_str_dbg(smb_fname),
1316 nt_errstr(status)));
1317 return false;
1320 status = se_file_access_check(sd,
1321 get_current_nttok(conn),
1322 false,
1323 access_mask,
1324 &rejected_mask);
1326 TALLOC_FREE(sd);
1328 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1329 DEBUG(10,("rejected bits 0x%x read access for %s\n",
1330 (unsigned int)rejected_mask,
1331 smb_fname_str_dbg(smb_fname) ));
1332 return false;
1334 return true;
1337 /*******************************************************************
1338 Check to see if a user can write a file (and only files, we do not
1339 check dirs on this one). This is only approximate,
1340 it is used as part of the "hide unwriteable" option. Don't
1341 use it for anything security sensitive.
1342 ********************************************************************/
1344 static bool user_can_write_file(connection_struct *conn,
1345 const struct smb_filename *smb_fname)
1348 * Never hide files from the root user.
1349 * We use (uid_t)0 here not sec_initial_uid()
1350 * as make test uses a single user context.
1353 if (get_current_uid(conn) == (uid_t)0) {
1354 return True;
1357 SMB_ASSERT(VALID_STAT(smb_fname->st));
1359 /* Pseudo-open the file */
1361 if(S_ISDIR(smb_fname->st.st_ex_mode)) {
1362 return True;
1365 return can_write_to_file(conn, smb_fname);
1368 /*******************************************************************
1369 Is a file a "special" type ?
1370 ********************************************************************/
1372 static bool file_is_special(connection_struct *conn,
1373 const struct smb_filename *smb_fname)
1376 * Never hide files from the root user.
1377 * We use (uid_t)0 here not sec_initial_uid()
1378 * as make test uses a single user context.
1381 if (get_current_uid(conn) == (uid_t)0) {
1382 return False;
1385 SMB_ASSERT(VALID_STAT(smb_fname->st));
1387 if (S_ISREG(smb_fname->st.st_ex_mode) ||
1388 S_ISDIR(smb_fname->st.st_ex_mode) ||
1389 S_ISLNK(smb_fname->st.st_ex_mode))
1390 return False;
1392 return True;
1395 /*******************************************************************
1396 Should the file be seen by the client?
1397 NOTE: A successful return is no guarantee of the file's existence.
1398 ********************************************************************/
1400 bool is_visible_file(connection_struct *conn, const char *dir_path,
1401 const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
1403 bool hide_unreadable = lp_hide_unreadable(SNUM(conn));
1404 bool hide_unwriteable = lp_hide_unwriteable_files(SNUM(conn));
1405 bool hide_special = lp_hide_special_files(SNUM(conn));
1406 int hide_new_files_timeout = lp_hide_new_files_timeout(SNUM(conn));
1407 char *entry = NULL;
1408 struct smb_filename *smb_fname_base = NULL;
1409 bool ret = false;
1411 if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1412 return True; /* . and .. are always visible. */
1415 /* If it's a vetoed file, pretend it doesn't even exist */
1416 if (use_veto && IS_VETO_PATH(conn, name)) {
1417 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1418 return False;
1421 if (hide_unreadable ||
1422 hide_unwriteable ||
1423 hide_special ||
1424 (hide_new_files_timeout != 0))
1426 entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name);
1427 if (!entry) {
1428 ret = false;
1429 goto out;
1432 /* Create an smb_filename with stream_name == NULL. */
1433 smb_fname_base = synthetic_smb_fname(talloc_tos(),
1434 entry,
1435 NULL,
1436 pst,
1438 if (smb_fname_base == NULL) {
1439 ret = false;
1440 goto out;
1443 /* If the file name does not exist, there's no point checking
1444 * the configuration options. We succeed, on the basis that the
1445 * checks *might* have passed if the file was present.
1447 if (!VALID_STAT(*pst)) {
1448 if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
1449 ret = true;
1450 goto out;
1452 *pst = smb_fname_base->st;
1455 /* Honour _hide unreadable_ option */
1456 if (hide_unreadable &&
1457 !user_can_read_file(conn, smb_fname_base)) {
1458 DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1459 entry ));
1460 ret = false;
1461 goto out;
1463 /* Honour _hide unwriteable_ option */
1464 if (hide_unwriteable && !user_can_write_file(conn,
1465 smb_fname_base)) {
1466 DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1467 entry ));
1468 ret = false;
1469 goto out;
1471 /* Honour _hide_special_ option */
1472 if (hide_special && file_is_special(conn, smb_fname_base)) {
1473 DEBUG(10,("is_visible_file: file %s is special.\n",
1474 entry ));
1475 ret = false;
1476 goto out;
1479 if (hide_new_files_timeout != 0) {
1481 double age = timespec_elapsed(
1482 &smb_fname_base->st.st_ex_mtime);
1484 if (age < (double)hide_new_files_timeout) {
1485 ret = false;
1486 goto out;
1491 ret = true;
1492 out:
1493 TALLOC_FREE(smb_fname_base);
1494 TALLOC_FREE(entry);
1495 return ret;
1498 static int smb_Dir_destructor(struct smb_Dir *dirp)
1500 if (dirp->dir != NULL) {
1501 SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1502 if (dirp->fsp != NULL) {
1504 * The SMB_VFS_CLOSEDIR above
1505 * closes the underlying fd inside
1506 * dirp->fsp.
1508 dirp->fsp->fh->fd = -1;
1509 if (dirp->fsp->dptr != NULL) {
1510 SMB_ASSERT(dirp->fsp->dptr->dir_hnd == dirp);
1511 dirp->fsp->dptr->dir_hnd = NULL;
1513 dirp->fsp = NULL;
1516 return 0;
1519 /*******************************************************************
1520 Open a directory.
1521 ********************************************************************/
1523 static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx,
1524 connection_struct *conn,
1525 const struct smb_filename *smb_dname,
1526 const char *mask,
1527 uint32_t attr)
1529 struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1531 if (!dirp) {
1532 return NULL;
1535 dirp->dir = SMB_VFS_OPENDIR(conn, smb_dname, mask, attr);
1537 if (!dirp->dir) {
1538 DEBUG(5,("OpenDir: Can't open %s. %s\n",
1539 smb_dname->base_name,
1540 strerror(errno) ));
1541 goto fail;
1544 dirp->conn = conn;
1546 if (!conn->sconn->using_smb2) {
1548 * The dircache is only needed for SMB1 because SMB1 uses a name
1549 * for the resume wheras SMB2 always continues from the next
1550 * position (unless it's told to restart or close-and-reopen the
1551 * listing).
1553 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1556 talloc_set_destructor(dirp, smb_Dir_destructor);
1558 return dirp;
1560 fail:
1561 TALLOC_FREE(dirp);
1562 return NULL;
1565 /****************************************************************************
1566 Open a directory handle by pathname, ensuring it's under the share path.
1567 ****************************************************************************/
1569 static struct smb_Dir *open_dir_safely(TALLOC_CTX *ctx,
1570 connection_struct *conn,
1571 const struct smb_filename *smb_dname,
1572 const char *wcard,
1573 uint32_t attr)
1575 struct smb_Dir *dir_hnd = NULL;
1576 struct smb_filename *smb_fname_cwd = NULL;
1577 struct smb_filename *saved_dir_fname = vfs_GetWd(ctx, conn);
1578 NTSTATUS status;
1580 if (saved_dir_fname == NULL) {
1581 return NULL;
1584 if (vfs_ChDir(conn, smb_dname) == -1) {
1585 goto out;
1588 smb_fname_cwd = synthetic_smb_fname(talloc_tos(),
1589 ".",
1590 NULL,
1591 NULL,
1592 smb_dname->flags);
1593 if (smb_fname_cwd == NULL) {
1594 goto out;
1598 * Now the directory is pinned, use
1599 * REALPATH to ensure we can access it.
1601 status = check_name(conn, smb_fname_cwd);
1602 if (!NT_STATUS_IS_OK(status)) {
1603 goto out;
1606 dir_hnd = OpenDir_internal(ctx,
1607 conn,
1608 smb_fname_cwd,
1609 wcard,
1610 attr);
1612 if (dir_hnd == NULL) {
1613 goto out;
1617 * OpenDir_internal only gets "." as the dir name.
1618 * Store the real dir name here.
1621 dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, smb_dname);
1622 if (!dir_hnd->dir_smb_fname) {
1623 TALLOC_FREE(dir_hnd);
1624 errno = ENOMEM;
1627 out:
1629 vfs_ChDir(conn, saved_dir_fname);
1630 TALLOC_FREE(saved_dir_fname);
1631 return dir_hnd;
1634 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1635 const struct smb_filename *smb_dname,
1636 const char *mask,
1637 uint32_t attr)
1639 return open_dir_safely(mem_ctx,
1640 conn,
1641 smb_dname,
1642 mask,
1643 attr);
1646 /*******************************************************************
1647 Open a directory from an fsp.
1648 ********************************************************************/
1650 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
1651 files_struct *fsp,
1652 const char *mask,
1653 uint32_t attr)
1655 struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1657 if (!dirp) {
1658 goto fail;
1661 if (!fsp->is_directory) {
1662 errno = EBADF;
1663 goto fail;
1666 if (fsp->fh->fd == -1) {
1667 errno = EBADF;
1668 goto fail;
1671 dirp->conn = conn;
1673 if (!conn->sconn->using_smb2) {
1675 * The dircache is only needed for SMB1 because SMB1 uses a name
1676 * for the resume wheras SMB2 always continues from the next
1677 * position (unless it's told to restart or close-and-reopen the
1678 * listing).
1680 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1683 dirp->dir_smb_fname = cp_smb_filename(dirp, fsp->fsp_name);
1684 if (!dirp->dir_smb_fname) {
1685 errno = ENOMEM;
1686 goto fail;
1689 dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1690 if (dirp->dir != NULL) {
1691 dirp->fsp = fsp;
1692 } else {
1693 DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1694 "NULL (%s)\n",
1695 dirp->dir_smb_fname->base_name,
1696 strerror(errno)));
1697 if (errno != ENOSYS) {
1698 goto fail;
1702 if (dirp->dir == NULL) {
1703 /* FDOPENDIR is not supported. Use OPENDIR instead. */
1704 TALLOC_FREE(dirp);
1705 return open_dir_safely(mem_ctx,
1706 conn,
1707 fsp->fsp_name,
1708 mask,
1709 attr);
1712 talloc_set_destructor(dirp, smb_Dir_destructor);
1714 return dirp;
1716 fail:
1717 TALLOC_FREE(dirp);
1718 return NULL;
1722 /*******************************************************************
1723 Read from a directory.
1724 Return directory entry, current offset, and optional stat information.
1725 Don't check for veto or invisible files.
1726 ********************************************************************/
1728 const char *ReadDirName(struct smb_Dir *dirp, long *poffset,
1729 SMB_STRUCT_STAT *sbuf, char **ptalloced)
1731 const char *n;
1732 char *talloced = NULL;
1733 connection_struct *conn = dirp->conn;
1735 /* Cheat to allow . and .. to be the first entries returned. */
1736 if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1737 (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2))
1739 if (dirp->file_number == 0) {
1740 n = ".";
1741 *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1742 } else {
1743 n = "..";
1744 *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1746 dirp->file_number++;
1747 *ptalloced = NULL;
1748 return n;
1751 if (*poffset == END_OF_DIRECTORY_OFFSET) {
1752 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1753 return NULL;
1756 /* A real offset, seek to it. */
1757 SeekDir(dirp, *poffset);
1759 while ((n = vfs_readdirname(conn, dirp->dir, sbuf, &talloced))) {
1760 /* Ignore . and .. - we've already returned them. */
1761 if (*n == '.') {
1762 if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1763 TALLOC_FREE(talloced);
1764 continue;
1767 *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1768 *ptalloced = talloced;
1769 dirp->file_number++;
1770 return n;
1772 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1773 *ptalloced = NULL;
1774 return NULL;
1777 /*******************************************************************
1778 Rewind to the start.
1779 ********************************************************************/
1781 void RewindDir(struct smb_Dir *dirp, long *poffset)
1783 SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1784 dirp->file_number = 0;
1785 dirp->offset = START_OF_DIRECTORY_OFFSET;
1786 *poffset = START_OF_DIRECTORY_OFFSET;
1789 /*******************************************************************
1790 Seek a dir.
1791 ********************************************************************/
1793 void SeekDir(struct smb_Dir *dirp, long offset)
1795 if (offset != dirp->offset) {
1796 if (offset == START_OF_DIRECTORY_OFFSET) {
1797 RewindDir(dirp, &offset);
1799 * Ok we should really set the file number here
1800 * to 1 to enable ".." to be returned next. Trouble
1801 * is I'm worried about callers using SeekDir(dirp,0)
1802 * as equivalent to RewindDir(). So leave this alone
1803 * for now.
1805 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
1806 RewindDir(dirp, &offset);
1808 * Set the file number to 2 - we want to get the first
1809 * real file entry (the one we return after "..")
1810 * on the next ReadDir.
1812 dirp->file_number = 2;
1813 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1814 ; /* Don't seek in this case. */
1815 } else {
1816 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1818 dirp->offset = offset;
1822 /*******************************************************************
1823 Tell a dir position.
1824 ********************************************************************/
1826 long TellDir(struct smb_Dir *dirp)
1828 return(dirp->offset);
1831 /*******************************************************************
1832 Add an entry into the dcache.
1833 ********************************************************************/
1835 static void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
1837 struct name_cache_entry *e;
1839 if (dirp->name_cache_size == 0) {
1840 return;
1843 if (dirp->name_cache == NULL) {
1844 dirp->name_cache = talloc_zero_array(
1845 dirp, struct name_cache_entry, dirp->name_cache_size);
1847 if (dirp->name_cache == NULL) {
1848 return;
1852 dirp->name_cache_index = (dirp->name_cache_index+1) %
1853 dirp->name_cache_size;
1854 e = &dirp->name_cache[dirp->name_cache_index];
1855 TALLOC_FREE(e->name);
1856 e->name = talloc_strdup(dirp, name);
1857 e->offset = offset;
1860 /*******************************************************************
1861 Find an entry by name. Leave us at the offset after it.
1862 Don't check for veto or invisible files.
1863 ********************************************************************/
1865 bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1867 int i;
1868 const char *entry = NULL;
1869 char *talloced = NULL;
1870 connection_struct *conn = dirp->conn;
1872 /* Search back in the name cache. */
1873 if (dirp->name_cache_size && dirp->name_cache) {
1874 for (i = dirp->name_cache_index; i >= 0; i--) {
1875 struct name_cache_entry *e = &dirp->name_cache[i];
1876 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1877 *poffset = e->offset;
1878 SeekDir(dirp, e->offset);
1879 return True;
1882 for (i = dirp->name_cache_size - 1; i > dirp->name_cache_index; i--) {
1883 struct name_cache_entry *e = &dirp->name_cache[i];
1884 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1885 *poffset = e->offset;
1886 SeekDir(dirp, e->offset);
1887 return True;
1892 /* Not found in the name cache. Rewind directory and start from scratch. */
1893 SMB_VFS_REWINDDIR(conn, dirp->dir);
1894 dirp->file_number = 0;
1895 *poffset = START_OF_DIRECTORY_OFFSET;
1896 while ((entry = ReadDirName(dirp, poffset, NULL, &talloced))) {
1897 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1898 TALLOC_FREE(talloced);
1899 return True;
1901 TALLOC_FREE(talloced);
1903 return False;
1906 struct files_below_forall_state {
1907 char *dirpath;
1908 size_t dirpath_len;
1909 int (*fn)(struct file_id fid, const struct share_mode_data *data,
1910 void *private_data);
1911 void *private_data;
1914 static int files_below_forall_fn(struct file_id fid,
1915 const struct share_mode_data *data,
1916 void *private_data)
1918 struct files_below_forall_state *state = private_data;
1919 char tmpbuf[PATH_MAX];
1920 char *fullpath, *to_free;
1921 size_t len;
1923 len = full_path_tos(data->servicepath, data->base_name,
1924 tmpbuf, sizeof(tmpbuf),
1925 &fullpath, &to_free);
1926 if (len == -1) {
1927 return 0;
1929 if (state->dirpath_len >= len) {
1931 * Filter files above dirpath
1933 goto out;
1935 if (fullpath[state->dirpath_len] != '/') {
1937 * Filter file that don't have a path separator at the end of
1938 * dirpath's length
1940 goto out;
1943 if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
1945 * Not a parent
1947 goto out;
1950 TALLOC_FREE(to_free);
1951 return state->fn(fid, data, state->private_data);
1953 out:
1954 TALLOC_FREE(to_free);
1955 return 0;
1958 static int files_below_forall(connection_struct *conn,
1959 const struct smb_filename *dir_name,
1960 int (*fn)(struct file_id fid,
1961 const struct share_mode_data *data,
1962 void *private_data),
1963 void *private_data)
1965 struct files_below_forall_state state = {
1966 .fn = fn,
1967 .private_data = private_data,
1969 int ret;
1970 char tmpbuf[PATH_MAX];
1971 char *to_free;
1973 state.dirpath_len = full_path_tos(conn->connectpath,
1974 dir_name->base_name,
1975 tmpbuf, sizeof(tmpbuf),
1976 &state.dirpath, &to_free);
1977 if (state.dirpath_len == -1) {
1978 return -1;
1981 ret = share_mode_forall(files_below_forall_fn, &state);
1982 TALLOC_FREE(to_free);
1983 return ret;
1986 struct have_file_open_below_state {
1987 bool found_one;
1990 static int have_file_open_below_fn(struct file_id fid,
1991 const struct share_mode_data *data,
1992 void *private_data)
1994 struct have_file_open_below_state *state = private_data;
1995 state->found_one = true;
1996 return 1;
1999 bool have_file_open_below(connection_struct *conn,
2000 const struct smb_filename *name)
2002 struct have_file_open_below_state state = {
2003 .found_one = false,
2005 int ret;
2007 if (!VALID_STAT(name->st)) {
2008 return false;
2010 if (!S_ISDIR(name->st.st_ex_mode)) {
2011 return false;
2014 ret = files_below_forall(conn, name, have_file_open_below_fn, &state);
2015 if (ret == -1) {
2016 return false;
2019 return state.found_one;
2022 /*****************************************************************
2023 Is this directory empty ?
2024 *****************************************************************/
2026 NTSTATUS can_delete_directory_fsp(files_struct *fsp)
2028 NTSTATUS status = NT_STATUS_OK;
2029 long dirpos = 0;
2030 const char *dname = NULL;
2031 const char *dirname = fsp->fsp_name->base_name;
2032 char *talloced = NULL;
2033 SMB_STRUCT_STAT st;
2034 struct connection_struct *conn = fsp->conn;
2035 struct smb_Dir *dir_hnd = OpenDir(talloc_tos(),
2036 conn,
2037 fsp->fsp_name,
2038 NULL,
2041 if (!dir_hnd) {
2042 return map_nt_error_from_unix(errno);
2045 while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) {
2046 /* Quick check for "." and ".." */
2047 if (dname[0] == '.') {
2048 if (!dname[1] || (dname[1] == '.' && !dname[2])) {
2049 TALLOC_FREE(talloced);
2050 continue;
2054 if (!is_visible_file(conn, dirname, dname, &st, True)) {
2055 TALLOC_FREE(talloced);
2056 continue;
2059 DEBUG(10,("got name %s - can't delete\n",
2060 dname ));
2061 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
2062 break;
2064 TALLOC_FREE(talloced);
2065 TALLOC_FREE(dir_hnd);
2067 if (!NT_STATUS_IS_OK(status)) {
2068 return status;
2071 if (!(fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) &&
2072 lp_strict_rename(SNUM(conn)) &&
2073 have_file_open_below(fsp->conn, fsp->fsp_name))
2075 return NT_STATUS_ACCESS_DENIED;
2078 return NT_STATUS_OK;