dcerpc.idl Add symbolic constant for /root/ncalrpc_as_system
[Samba.git] / source3 / smbd / dir.c
blobcb54be4de76a62e510671bca5dfa720ac12f62a8
1 /*
2 Unix SMB/CIFS implementation.
3 Directory handling routines
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 2007
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "system/filesys.h"
23 #include "smbd/smbd.h"
24 #include "smbd/globals.h"
25 #include "libcli/security/security.h"
26 #include "lib/util/bitmap.h"
27 #include "../lib/util/memcache.h"
28 #include "../librpc/gen_ndr/open_files.h"
31 This module implements directory related functions for Samba.
34 /* "Special" directory offsets. */
35 #define END_OF_DIRECTORY_OFFSET ((long)-1)
36 #define START_OF_DIRECTORY_OFFSET ((long)0)
37 #define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
39 /* "Special" directory offsets in 32-bit wire format. */
40 #define WIRE_END_OF_DIRECTORY_OFFSET ((uint32_t)0xFFFFFFFF)
41 #define WIRE_START_OF_DIRECTORY_OFFSET ((uint32_t)0)
42 #define WIRE_DOT_DOT_DIRECTORY_OFFSET ((uint32_t)0x80000000)
44 /* Make directory handle internals available. */
46 struct name_cache_entry {
47 char *name;
48 long offset;
51 struct smb_Dir {
52 connection_struct *conn;
53 DIR *dir;
54 long offset;
55 struct smb_filename *dir_smb_fname;
56 size_t name_cache_size;
57 struct name_cache_entry *name_cache;
58 unsigned int name_cache_index;
59 unsigned int file_number;
60 files_struct *fsp; /* Back pointer to containing fsp, only
61 set from OpenDir_fsp(). */
64 struct dptr_struct {
65 struct dptr_struct *next, *prev;
66 int dnum;
67 uint16_t spid;
68 struct connection_struct *conn;
69 struct smb_Dir *dir_hnd;
70 bool expect_close;
71 char *wcard;
72 uint32_t attr;
73 struct smb_filename *smb_dname;
74 bool has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
75 bool did_stat; /* Optimisation for non-wcard searches. */
76 bool priv; /* Directory handle opened with privilege. */
77 uint32_t counter;
78 struct memcache *dptr_cache;
81 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
82 files_struct *fsp,
83 const char *mask,
84 uint32_t attr);
86 static void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset);
88 #define INVALID_DPTR_KEY (-3)
90 /****************************************************************************
91 Initialise the dir bitmap.
92 ****************************************************************************/
94 bool init_dptrs(struct smbd_server_connection *sconn)
96 if (sconn->searches.dptr_bmap) {
97 return true;
100 sconn->searches.dptr_bmap = bitmap_talloc(
101 sconn, MAX_DIRECTORY_HANDLES);
103 if (sconn->searches.dptr_bmap == NULL) {
104 return false;
107 return true;
110 /****************************************************************************
111 Idle a dptr - the directory is closed but the control info is kept.
112 ****************************************************************************/
114 static void dptr_idle(struct dptr_struct *dptr)
116 if (dptr->dir_hnd) {
117 DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
118 TALLOC_FREE(dptr->dir_hnd);
119 TALLOC_FREE(dptr->dptr_cache);
120 dptr->counter = 0;
124 /****************************************************************************
125 Idle the oldest dptr.
126 ****************************************************************************/
128 static void dptr_idleoldest(struct smbd_server_connection *sconn)
130 struct dptr_struct *dptr;
133 * Go to the end of the list.
135 dptr = DLIST_TAIL(sconn->searches.dirptrs);
137 if(!dptr) {
138 DEBUG(0,("No dptrs available to idle ?\n"));
139 return;
143 * Idle the oldest pointer.
146 for(; dptr; dptr = DLIST_PREV(dptr)) {
147 if (dptr->dir_hnd) {
148 dptr_idle(dptr);
149 return;
154 /****************************************************************************
155 Get the struct dptr_struct for a dir index.
156 ****************************************************************************/
158 static struct dptr_struct *dptr_get(struct smbd_server_connection *sconn,
159 int key, bool forclose)
161 struct dptr_struct *dptr;
163 for(dptr = sconn->searches.dirptrs; dptr; dptr = dptr->next) {
164 if(dptr->dnum == key) {
165 if (!forclose && !dptr->dir_hnd) {
166 if (sconn->searches.dirhandles_open >= MAX_OPEN_DIRECTORIES)
167 dptr_idleoldest(sconn);
168 DEBUG(4,("dptr_get: Reopening dptr key %d\n",key));
170 if (!(dptr->dir_hnd = OpenDir(NULL,
171 dptr->conn,
172 dptr->smb_dname,
173 dptr->wcard,
174 dptr->attr))) {
175 DEBUG(4,("dptr_get: Failed to "
176 "open %s (%s)\n",
177 dptr->smb_dname->base_name,
178 strerror(errno)));
179 return NULL;
182 DLIST_PROMOTE(sconn->searches.dirptrs,dptr);
183 return dptr;
186 return(NULL);
189 /****************************************************************************
190 Get the dir path for a dir index.
191 ****************************************************************************/
193 const char *dptr_path(struct smbd_server_connection *sconn, int key)
195 struct dptr_struct *dptr = dptr_get(sconn, key, false);
196 if (dptr)
197 return(dptr->smb_dname->base_name);
198 return(NULL);
201 /****************************************************************************
202 Get the dir wcard for a dir index.
203 ****************************************************************************/
205 const char *dptr_wcard(struct smbd_server_connection *sconn, int key)
207 struct dptr_struct *dptr = dptr_get(sconn, key, false);
208 if (dptr)
209 return(dptr->wcard);
210 return(NULL);
213 /****************************************************************************
214 Get the dir attrib for a dir index.
215 ****************************************************************************/
217 uint16_t dptr_attr(struct smbd_server_connection *sconn, int key)
219 struct dptr_struct *dptr = dptr_get(sconn, key, false);
220 if (dptr)
221 return(dptr->attr);
222 return(0);
225 /****************************************************************************
226 Close a dptr (internal func).
227 ****************************************************************************/
229 static void dptr_close_internal(struct dptr_struct *dptr)
231 struct smbd_server_connection *sconn = dptr->conn->sconn;
233 DEBUG(4,("closing dptr key %d\n",dptr->dnum));
235 if (sconn == NULL) {
236 goto done;
239 if (sconn->using_smb2) {
240 goto done;
243 DLIST_REMOVE(sconn->searches.dirptrs, dptr);
246 * Free the dnum in the bitmap. Remember the dnum value is always
247 * biased by one with respect to the bitmap.
250 if (!bitmap_query(sconn->searches.dptr_bmap, dptr->dnum - 1)) {
251 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
252 dptr->dnum ));
255 bitmap_clear(sconn->searches.dptr_bmap, dptr->dnum - 1);
257 done:
258 TALLOC_FREE(dptr->dir_hnd);
259 TALLOC_FREE(dptr);
262 /****************************************************************************
263 Close a dptr given a key.
264 ****************************************************************************/
266 void dptr_close(struct smbd_server_connection *sconn, int *key)
268 struct dptr_struct *dptr;
270 if(*key == INVALID_DPTR_KEY)
271 return;
273 /* OS/2 seems to use -1 to indicate "close all directories" */
274 if (*key == -1) {
275 struct dptr_struct *next;
276 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
277 next = dptr->next;
278 dptr_close_internal(dptr);
280 *key = INVALID_DPTR_KEY;
281 return;
284 dptr = dptr_get(sconn, *key, true);
286 if (!dptr) {
287 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
288 return;
291 dptr_close_internal(dptr);
293 *key = INVALID_DPTR_KEY;
296 /****************************************************************************
297 Close all dptrs for a cnum.
298 ****************************************************************************/
300 void dptr_closecnum(connection_struct *conn)
302 struct dptr_struct *dptr, *next;
303 struct smbd_server_connection *sconn = conn->sconn;
305 if (sconn == NULL) {
306 return;
309 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
310 next = dptr->next;
311 if (dptr->conn == conn) {
312 dptr_close_internal(dptr);
317 /****************************************************************************
318 Idle all dptrs for a cnum.
319 ****************************************************************************/
321 void dptr_idlecnum(connection_struct *conn)
323 struct dptr_struct *dptr;
324 struct smbd_server_connection *sconn = conn->sconn;
326 if (sconn == NULL) {
327 return;
330 for(dptr = sconn->searches.dirptrs; dptr; dptr = dptr->next) {
331 if (dptr->conn == conn && dptr->dir_hnd) {
332 dptr_idle(dptr);
337 /****************************************************************************
338 Close a dptr that matches a given path, only if it matches the spid also.
339 ****************************************************************************/
341 void dptr_closepath(struct smbd_server_connection *sconn,
342 char *path,uint16_t spid)
344 struct dptr_struct *dptr, *next;
345 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
346 next = dptr->next;
347 if (spid == dptr->spid &&
348 strequal(dptr->smb_dname->base_name,path)) {
349 dptr_close_internal(dptr);
354 /****************************************************************************
355 Try and close the oldest handle not marked for
356 expect close in the hope that the client has
357 finished with that one.
358 ****************************************************************************/
360 static void dptr_close_oldest(struct smbd_server_connection *sconn,
361 bool old)
363 struct dptr_struct *dptr;
366 * Go to the end of the list.
368 for(dptr = sconn->searches.dirptrs; dptr && dptr->next; dptr = dptr->next)
371 if(!dptr) {
372 DEBUG(0,("No old dptrs available to close oldest ?\n"));
373 return;
377 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
378 * does not have expect_close set. If 'old' is false, close
379 * one of the new dnum handles.
382 for(; dptr; dptr = DLIST_PREV(dptr)) {
383 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
384 (!old && (dptr->dnum > 255))) {
385 dptr_close_internal(dptr);
386 return;
391 /****************************************************************************
392 Safely do an OpenDir as root, ensuring we're in the right place.
393 ****************************************************************************/
395 static struct smb_Dir *open_dir_with_privilege(connection_struct *conn,
396 struct smb_request *req,
397 const struct smb_filename *smb_dname,
398 const char *wcard,
399 uint32_t attr)
401 struct smb_Dir *dir_hnd = NULL;
402 struct smb_filename *smb_fname_cwd = NULL;
403 struct smb_filename *saved_dir_fname = vfs_GetWd(talloc_tos(), conn);
404 struct privilege_paths *priv_paths = req->priv_paths;
405 int ret;
407 if (saved_dir_fname == NULL) {
408 return NULL;
411 if (vfs_ChDir(conn, smb_dname) == -1) {
412 return NULL;
415 /* Now check the stat value is the same. */
416 smb_fname_cwd = synthetic_smb_fname(talloc_tos(),
417 ".",
418 NULL,
419 NULL,
420 smb_dname->flags);
421 if (smb_fname_cwd == NULL) {
422 goto out;
424 ret = SMB_VFS_STAT(conn, smb_fname_cwd);
425 if (ret != 0) {
426 goto out;
429 if (!check_same_stat(&smb_fname_cwd->st, &priv_paths->parent_name.st)) {
430 DEBUG(0,("open_dir_with_privilege: stat mismatch between %s "
431 "and %s\n",
432 smb_dname->base_name,
433 smb_fname_str_dbg(&priv_paths->parent_name)));
434 goto out;
437 dir_hnd = OpenDir(NULL, conn, smb_fname_cwd, wcard, attr);
439 out:
441 vfs_ChDir(conn, saved_dir_fname);
442 TALLOC_FREE(saved_dir_fname);
443 return dir_hnd;
446 /****************************************************************************
447 Create a new dir ptr. If the flag old_handle is true then we must allocate
448 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
449 one byte long. If old_handle is false we allocate from the range
450 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
451 a directory handle is never zero.
452 wcard must not be zero.
453 ****************************************************************************/
455 NTSTATUS dptr_create(connection_struct *conn,
456 struct smb_request *req,
457 files_struct *fsp,
458 const struct smb_filename *smb_dname,
459 bool old_handle,
460 bool expect_close,
461 uint16_t spid,
462 const char *wcard,
463 bool wcard_has_wild,
464 uint32_t attr,
465 struct dptr_struct **dptr_ret)
467 struct smbd_server_connection *sconn = conn->sconn;
468 struct dptr_struct *dptr = NULL;
469 struct smb_Dir *dir_hnd;
471 if (fsp && fsp->is_directory && fsp->fh->fd != -1) {
472 smb_dname = fsp->fsp_name;
475 DEBUG(5,("dptr_create dir=%s\n", smb_dname->base_name));
477 if (sconn == NULL) {
478 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
479 return NT_STATUS_INTERNAL_ERROR;
482 if (!wcard) {
483 return NT_STATUS_INVALID_PARAMETER;
486 if (fsp) {
487 if (!(fsp->access_mask & SEC_DIR_LIST)) {
488 DEBUG(5,("dptr_create: directory %s "
489 "not open for LIST access\n",
490 smb_dname->base_name));
491 return NT_STATUS_ACCESS_DENIED;
493 dir_hnd = OpenDir_fsp(NULL, conn, fsp, wcard, attr);
494 } else {
495 int ret;
496 bool backup_intent = (req && req->priv_paths);
497 NTSTATUS status;
498 struct smb_filename *smb_dname_cp =
499 cp_smb_filename(talloc_tos(), smb_dname);
501 if (smb_dname_cp == NULL) {
502 return NT_STATUS_NO_MEMORY;
505 if (req != NULL && req->posix_pathnames) {
506 ret = SMB_VFS_LSTAT(conn, smb_dname_cp);
507 } else {
508 ret = SMB_VFS_STAT(conn, smb_dname_cp);
510 if (ret == -1) {
511 status = map_nt_error_from_unix(errno);
512 TALLOC_FREE(smb_dname_cp);
513 return status;
515 if (!S_ISDIR(smb_dname_cp->st.st_ex_mode)) {
516 TALLOC_FREE(smb_dname_cp);
517 return NT_STATUS_NOT_A_DIRECTORY;
519 status = smbd_check_access_rights(conn,
520 smb_dname_cp,
521 backup_intent,
522 SEC_DIR_LIST);
523 if (!NT_STATUS_IS_OK(status)) {
524 TALLOC_FREE(smb_dname_cp);
525 return status;
527 if (backup_intent) {
528 dir_hnd = open_dir_with_privilege(conn,
529 req,
530 smb_dname_cp,
531 wcard,
532 attr);
533 } else {
534 dir_hnd = OpenDir(NULL,
535 conn,
536 smb_dname_cp,
537 wcard,
538 attr);
540 TALLOC_FREE(smb_dname_cp);
543 if (!dir_hnd) {
544 return map_nt_error_from_unix(errno);
547 if (sconn->searches.dirhandles_open >= MAX_OPEN_DIRECTORIES) {
548 dptr_idleoldest(sconn);
551 dptr = talloc_zero(NULL, struct dptr_struct);
552 if(!dptr) {
553 DEBUG(0,("talloc fail in dptr_create.\n"));
554 TALLOC_FREE(dir_hnd);
555 return NT_STATUS_NO_MEMORY;
558 dptr->smb_dname = cp_smb_filename(dptr, smb_dname);
559 if (!dptr->smb_dname) {
560 TALLOC_FREE(dptr);
561 TALLOC_FREE(dir_hnd);
562 return NT_STATUS_NO_MEMORY;
564 dptr->conn = conn;
565 dptr->dir_hnd = dir_hnd;
566 dptr->spid = spid;
567 dptr->expect_close = expect_close;
568 dptr->wcard = talloc_strdup(dptr, wcard);
569 if (!dptr->wcard) {
570 TALLOC_FREE(dptr);
571 TALLOC_FREE(dir_hnd);
572 return NT_STATUS_NO_MEMORY;
574 if ((req != NULL && req->posix_pathnames) ||
575 (wcard[0] == '.' && wcard[1] == 0)) {
576 dptr->has_wild = True;
577 } else {
578 dptr->has_wild = wcard_has_wild;
581 dptr->attr = attr;
583 if (sconn->using_smb2) {
584 goto done;
587 if(old_handle) {
590 * This is an old-style SMBsearch request. Ensure the
591 * value we return will fit in the range 1-255.
594 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
596 if(dptr->dnum == -1 || dptr->dnum > 254) {
599 * Try and close the oldest handle not marked for
600 * expect close in the hope that the client has
601 * finished with that one.
604 dptr_close_oldest(sconn, true);
606 /* Now try again... */
607 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
608 if(dptr->dnum == -1 || dptr->dnum > 254) {
609 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
610 TALLOC_FREE(dptr);
611 TALLOC_FREE(dir_hnd);
612 return NT_STATUS_TOO_MANY_OPENED_FILES;
615 } else {
618 * This is a new-style trans2 request. Allocate from
619 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
622 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
624 if(dptr->dnum == -1 || dptr->dnum < 255) {
627 * Try and close the oldest handle close in the hope that
628 * the client has finished with that one. This will only
629 * happen in the case of the Win98 client bug where it leaks
630 * directory handles.
633 dptr_close_oldest(sconn, false);
635 /* Now try again... */
636 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
638 if(dptr->dnum == -1 || dptr->dnum < 255) {
639 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
640 TALLOC_FREE(dptr);
641 TALLOC_FREE(dir_hnd);
642 return NT_STATUS_TOO_MANY_OPENED_FILES;
647 bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
649 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
651 DLIST_ADD(sconn->searches.dirptrs, dptr);
653 done:
654 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
655 dptr->dnum,
656 dptr->smb_dname->base_name,
657 expect_close));
659 *dptr_ret = dptr;
661 return NT_STATUS_OK;
665 /****************************************************************************
666 Wrapper functions to access the lower level directory handles.
667 ****************************************************************************/
669 void dptr_CloseDir(files_struct *fsp)
671 if (fsp->dptr) {
673 * The destructor for the struct smb_Dir
674 * (fsp->dptr->dir_hnd) now handles
675 * all resource deallocation.
677 dptr_close_internal(fsp->dptr);
678 fsp->dptr = NULL;
682 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
684 SeekDir(dptr->dir_hnd, offset);
687 long dptr_TellDir(struct dptr_struct *dptr)
689 return TellDir(dptr->dir_hnd);
692 bool dptr_has_wild(struct dptr_struct *dptr)
694 return dptr->has_wild;
697 int dptr_dnum(struct dptr_struct *dptr)
699 return dptr->dnum;
702 bool dptr_get_priv(struct dptr_struct *dptr)
704 return dptr->priv;
707 void dptr_set_priv(struct dptr_struct *dptr)
709 dptr->priv = true;
712 /****************************************************************************
713 Return the next visible file name, skipping veto'd and invisible files.
714 ****************************************************************************/
716 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr,
717 long *poffset, SMB_STRUCT_STAT *pst,
718 char **ptalloced)
720 /* Normal search for the next file. */
721 const char *name;
722 char *talloced = NULL;
724 while ((name = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced))
725 != NULL) {
726 if (is_visible_file(dptr->conn,
727 dptr->smb_dname->base_name,
728 name,
729 pst,
730 true)) {
731 *ptalloced = talloced;
732 return name;
734 TALLOC_FREE(talloced);
736 return NULL;
739 /****************************************************************************
740 Return the next visible file name, skipping veto'd and invisible files.
741 ****************************************************************************/
743 static char *dptr_ReadDirName(TALLOC_CTX *ctx,
744 struct dptr_struct *dptr,
745 long *poffset,
746 SMB_STRUCT_STAT *pst)
748 struct smb_filename smb_fname_base;
749 char *name = NULL;
750 const char *name_temp = NULL;
751 char *talloced = NULL;
752 char *pathreal = NULL;
753 char *found_name = NULL;
754 int ret;
756 SET_STAT_INVALID(*pst);
758 if (dptr->has_wild || dptr->did_stat) {
759 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst,
760 &talloced);
761 if (name_temp == NULL) {
762 return NULL;
764 if (talloced != NULL) {
765 return talloc_move(ctx, &talloced);
767 return talloc_strdup(ctx, name_temp);
770 /* If poffset is -1 then we know we returned this name before and we
771 * have no wildcards. We're at the end of the directory. */
772 if (*poffset == END_OF_DIRECTORY_OFFSET) {
773 return NULL;
776 /* We know the stored wcard contains no wildcard characters.
777 * See if we can match with a stat call. If we can't, then set
778 * did_stat to true to ensure we only do this once and keep
779 * searching. */
781 dptr->did_stat = true;
783 /* First check if it should be visible. */
784 if (!is_visible_file(dptr->conn,
785 dptr->smb_dname->base_name,
786 dptr->wcard,
787 pst,
788 true)) {
789 /* This only returns false if the file was found, but
790 is explicitly not visible. Set us to end of
791 directory, but return NULL as we know we can't ever
792 find it. */
793 goto ret;
796 if (VALID_STAT(*pst)) {
797 name = talloc_strdup(ctx, dptr->wcard);
798 goto ret;
801 pathreal = talloc_asprintf(ctx,
802 "%s/%s",
803 dptr->smb_dname->base_name,
804 dptr->wcard);
805 if (!pathreal)
806 return NULL;
808 /* Create an smb_filename with stream_name == NULL. */
809 smb_fname_base = (struct smb_filename) { .base_name = pathreal };
811 if (SMB_VFS_STAT(dptr->conn, &smb_fname_base) == 0) {
812 *pst = smb_fname_base.st;
813 name = talloc_strdup(ctx, dptr->wcard);
814 goto clean;
815 } else {
816 /* If we get any other error than ENOENT or ENOTDIR
817 then the file exists we just can't stat it. */
818 if (errno != ENOENT && errno != ENOTDIR) {
819 name = talloc_strdup(ctx, dptr->wcard);
820 goto clean;
824 /* Stat failed. We know this is authoratiative if we are
825 * providing case sensitive semantics or the underlying
826 * filesystem is case sensitive.
828 if (dptr->conn->case_sensitive ||
829 !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
831 goto clean;
835 * Try case-insensitive stat if the fs has the ability. This avoids
836 * scanning the whole directory.
838 ret = SMB_VFS_GET_REAL_FILENAME(dptr->conn,
839 dptr->smb_dname->base_name,
840 dptr->wcard,
841 ctx,
842 &found_name);
843 if (ret == 0) {
844 name = found_name;
845 goto clean;
846 } else if (errno == ENOENT) {
847 /* The case-insensitive lookup was authoritative. */
848 goto clean;
851 TALLOC_FREE(pathreal);
853 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst, &talloced);
854 if (name_temp == NULL) {
855 return NULL;
857 if (talloced != NULL) {
858 return talloc_move(ctx, &talloced);
860 return talloc_strdup(ctx, name_temp);
862 clean:
863 TALLOC_FREE(pathreal);
864 ret:
865 /* We need to set the underlying dir_hnd offset to -1
866 * also as this function is usually called with the
867 * output from TellDir. */
868 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
869 return name;
872 /****************************************************************************
873 Search for a file by name, skipping veto'ed and not visible files.
874 ****************************************************************************/
876 bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
878 SET_STAT_INVALID(*pst);
880 if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
881 /* This is a singleton directory and we're already at the end. */
882 *poffset = END_OF_DIRECTORY_OFFSET;
883 return False;
886 return SearchDir(dptr->dir_hnd, name, poffset);
889 /****************************************************************************
890 Initialize variables & state data at the beginning of all search SMB requests.
891 ****************************************************************************/
892 void dptr_init_search_op(struct dptr_struct *dptr)
894 SMB_VFS_INIT_SEARCH_OP(dptr->conn, dptr->dir_hnd->dir);
897 /****************************************************************************
898 Map a native directory offset to a 32-bit cookie.
899 ****************************************************************************/
901 static uint32_t map_dir_offset_to_wire(struct dptr_struct *dptr, long offset)
903 DATA_BLOB key;
904 DATA_BLOB val;
906 if (offset == END_OF_DIRECTORY_OFFSET) {
907 return WIRE_END_OF_DIRECTORY_OFFSET;
908 } else if(offset == START_OF_DIRECTORY_OFFSET) {
909 return WIRE_START_OF_DIRECTORY_OFFSET;
910 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
911 return WIRE_DOT_DOT_DIRECTORY_OFFSET;
913 if (sizeof(long) == 4) {
914 /* 32-bit machine. We can cheat... */
915 return (uint32_t)offset;
917 if (dptr->dptr_cache == NULL) {
918 /* Lazy initialize cache. */
919 dptr->dptr_cache = memcache_init(dptr, 0);
920 if (dptr->dptr_cache == NULL) {
921 return WIRE_END_OF_DIRECTORY_OFFSET;
923 } else {
924 /* Have we seen this offset before ? */
925 key.data = (void *)&offset;
926 key.length = sizeof(offset);
927 if (memcache_lookup(dptr->dptr_cache,
928 SMB1_SEARCH_OFFSET_MAP,
929 key,
930 &val)) {
931 uint32_t wire_offset;
932 SMB_ASSERT(val.length == sizeof(wire_offset));
933 memcpy(&wire_offset, val.data, sizeof(wire_offset));
934 DEBUG(10,("found wire %u <-> offset %ld\n",
935 (unsigned int)wire_offset,
936 (long)offset));
937 return wire_offset;
940 /* Allocate a new wire cookie. */
941 do {
942 dptr->counter++;
943 } while (dptr->counter == WIRE_START_OF_DIRECTORY_OFFSET ||
944 dptr->counter == WIRE_END_OF_DIRECTORY_OFFSET ||
945 dptr->counter == WIRE_DOT_DOT_DIRECTORY_OFFSET);
946 /* Store it in the cache. */
947 key.data = (void *)&offset;
948 key.length = sizeof(offset);
949 val.data = (void *)&dptr->counter;
950 val.length = sizeof(dptr->counter); /* MUST BE uint32_t ! */
951 memcache_add(dptr->dptr_cache,
952 SMB1_SEARCH_OFFSET_MAP,
953 key,
954 val);
955 /* And the reverse mapping for lookup from
956 map_wire_to_dir_offset(). */
957 memcache_add(dptr->dptr_cache,
958 SMB1_SEARCH_OFFSET_MAP,
959 val,
960 key);
961 DEBUG(10,("stored wire %u <-> offset %ld\n",
962 (unsigned int)dptr->counter,
963 (long)offset));
964 return dptr->counter;
967 /****************************************************************************
968 Fill the 5 byte server reserved dptr field.
969 ****************************************************************************/
971 bool dptr_fill(struct smbd_server_connection *sconn,
972 char *buf1,unsigned int key)
974 unsigned char *buf = (unsigned char *)buf1;
975 struct dptr_struct *dptr = dptr_get(sconn, key, false);
976 uint32_t wire_offset;
977 if (!dptr) {
978 DEBUG(1,("filling null dirptr %d\n",key));
979 return(False);
981 wire_offset = map_dir_offset_to_wire(dptr,TellDir(dptr->dir_hnd));
982 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
983 (long)dptr->dir_hnd,(int)wire_offset));
984 buf[0] = key;
985 SIVAL(buf,1,wire_offset);
986 return(True);
989 /****************************************************************************
990 Map a 32-bit wire cookie to a native directory offset.
991 ****************************************************************************/
993 static long map_wire_to_dir_offset(struct dptr_struct *dptr, uint32_t wire_offset)
995 DATA_BLOB key;
996 DATA_BLOB val;
998 if (wire_offset == WIRE_END_OF_DIRECTORY_OFFSET) {
999 return END_OF_DIRECTORY_OFFSET;
1000 } else if(wire_offset == WIRE_START_OF_DIRECTORY_OFFSET) {
1001 return START_OF_DIRECTORY_OFFSET;
1002 } else if (wire_offset == WIRE_DOT_DOT_DIRECTORY_OFFSET) {
1003 return DOT_DOT_DIRECTORY_OFFSET;
1005 if (sizeof(long) == 4) {
1006 /* 32-bit machine. We can cheat... */
1007 return (long)wire_offset;
1009 if (dptr->dptr_cache == NULL) {
1010 /* Logic error, cache should be initialized. */
1011 return END_OF_DIRECTORY_OFFSET;
1013 key.data = (void *)&wire_offset;
1014 key.length = sizeof(wire_offset);
1015 if (memcache_lookup(dptr->dptr_cache,
1016 SMB1_SEARCH_OFFSET_MAP,
1017 key,
1018 &val)) {
1019 /* Found mapping. */
1020 long offset;
1021 SMB_ASSERT(val.length == sizeof(offset));
1022 memcpy(&offset, val.data, sizeof(offset));
1023 DEBUG(10,("lookup wire %u <-> offset %ld\n",
1024 (unsigned int)wire_offset,
1025 (long)offset));
1026 return offset;
1028 return END_OF_DIRECTORY_OFFSET;
1031 /****************************************************************************
1032 Fetch the dir ptr and seek it given the 5 byte server field.
1033 ****************************************************************************/
1035 struct dptr_struct *dptr_fetch(struct smbd_server_connection *sconn,
1036 char *buf, int *num)
1038 unsigned int key = *(unsigned char *)buf;
1039 struct dptr_struct *dptr = dptr_get(sconn, key, false);
1040 uint32_t wire_offset;
1041 long seekoff;
1043 if (!dptr) {
1044 DEBUG(3,("fetched null dirptr %d\n",key));
1045 return(NULL);
1047 *num = key;
1048 wire_offset = IVAL(buf,1);
1049 seekoff = map_wire_to_dir_offset(dptr, wire_offset);
1050 SeekDir(dptr->dir_hnd,seekoff);
1051 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
1052 key, dptr->smb_dname->base_name, (int)seekoff));
1053 return(dptr);
1056 /****************************************************************************
1057 Fetch the dir ptr.
1058 ****************************************************************************/
1060 struct dptr_struct *dptr_fetch_lanman2(struct smbd_server_connection *sconn,
1061 int dptr_num)
1063 struct dptr_struct *dptr = dptr_get(sconn, dptr_num, false);
1065 if (!dptr) {
1066 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
1067 return(NULL);
1069 DEBUG(3,("fetching dirptr %d for path %s\n",
1070 dptr_num,
1071 dptr->smb_dname->base_name));
1072 return(dptr);
1075 static bool mangle_mask_match(connection_struct *conn,
1076 const char *filename,
1077 const char *mask)
1079 char mname[13];
1081 if (!name_to_8_3(filename,mname,False,conn->params)) {
1082 return False;
1084 return mask_match_search(mname,mask,False);
1087 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
1088 struct dptr_struct *dirptr,
1089 const char *mask,
1090 uint32_t dirtype,
1091 bool dont_descend,
1092 bool ask_sharemode,
1093 bool (*match_fn)(TALLOC_CTX *ctx,
1094 void *private_data,
1095 const char *dname,
1096 const char *mask,
1097 char **_fname),
1098 bool (*mode_fn)(TALLOC_CTX *ctx,
1099 void *private_data,
1100 struct smb_filename *smb_fname,
1101 uint32_t *_mode),
1102 void *private_data,
1103 char **_fname,
1104 struct smb_filename **_smb_fname,
1105 uint32_t *_mode,
1106 long *_prev_offset)
1108 connection_struct *conn = dirptr->conn;
1109 size_t slashlen;
1110 size_t pathlen;
1111 const char *dpath = dirptr->smb_dname->base_name;
1112 bool dirptr_path_is_dot = ISDOT(dpath);
1114 *_smb_fname = NULL;
1115 *_mode = 0;
1117 pathlen = strlen(dpath);
1118 slashlen = ( dpath[pathlen-1] != '/') ? 1 : 0;
1120 while (true) {
1121 long cur_offset;
1122 long prev_offset;
1123 SMB_STRUCT_STAT sbuf = { 0 };
1124 char *dname = NULL;
1125 bool isdots;
1126 char *fname = NULL;
1127 char *pathreal = NULL;
1128 struct smb_filename smb_fname;
1129 uint32_t mode = 0;
1130 bool ok;
1132 cur_offset = dptr_TellDir(dirptr);
1133 prev_offset = cur_offset;
1134 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
1136 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
1137 (long)dirptr, cur_offset));
1139 if (dname == NULL) {
1140 return false;
1143 isdots = (ISDOT(dname) || ISDOTDOT(dname));
1144 if (dont_descend && !isdots) {
1145 TALLOC_FREE(dname);
1146 continue;
1150 * fname may get mangled, dname is never mangled.
1151 * Whenever we're accessing the filesystem we use
1152 * pathreal which is composed from dname.
1155 ok = match_fn(ctx, private_data, dname, mask, &fname);
1156 if (!ok) {
1157 TALLOC_FREE(dname);
1158 continue;
1162 * This used to be
1163 * pathreal = talloc_asprintf(ctx, "%s%s%s", dirptr->path,
1164 * needslash?"/":"", dname);
1165 * but this was measurably slower than doing the memcpy.
1168 pathreal = talloc_array(
1169 ctx, char,
1170 pathlen + slashlen + talloc_get_size(dname));
1171 if (!pathreal) {
1172 TALLOC_FREE(dname);
1173 TALLOC_FREE(fname);
1174 return false;
1178 * We don't want to pass ./xxx to modules below us so don't
1179 * add the path if it is just . by itself.
1181 if (dirptr_path_is_dot) {
1182 memcpy(pathreal, dname, talloc_get_size(dname));
1183 } else {
1184 memcpy(pathreal, dpath, pathlen);
1185 pathreal[pathlen] = '/';
1186 memcpy(pathreal + slashlen + pathlen, dname,
1187 talloc_get_size(dname));
1190 /* Create smb_fname with NULL stream_name. */
1191 smb_fname = (struct smb_filename) {
1192 .base_name = pathreal, .st = sbuf
1195 ok = mode_fn(ctx, private_data, &smb_fname, &mode);
1196 if (!ok) {
1197 TALLOC_FREE(dname);
1198 TALLOC_FREE(fname);
1199 TALLOC_FREE(pathreal);
1200 continue;
1203 if (!dir_check_ftype(mode, dirtype)) {
1204 DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
1205 fname, (unsigned int)mode, (unsigned int)dirtype));
1206 TALLOC_FREE(dname);
1207 TALLOC_FREE(fname);
1208 TALLOC_FREE(pathreal);
1209 continue;
1212 if (ask_sharemode) {
1213 struct timespec write_time_ts;
1214 struct file_id fileid;
1216 fileid = vfs_file_id_from_sbuf(conn,
1217 &smb_fname.st);
1218 get_file_infos(fileid, 0, NULL, &write_time_ts);
1219 if (!null_timespec(write_time_ts)) {
1220 update_stat_ex_mtime(&smb_fname.st,
1221 write_time_ts);
1225 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
1226 "fname=%s (%s)\n",
1227 mask, smb_fname_str_dbg(&smb_fname),
1228 dname, fname));
1230 DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
1232 TALLOC_FREE(dname);
1234 *_smb_fname = cp_smb_filename(ctx, &smb_fname);
1235 TALLOC_FREE(pathreal);
1236 if (*_smb_fname == NULL) {
1237 return false;
1239 *_fname = fname;
1240 *_mode = mode;
1241 *_prev_offset = prev_offset;
1243 return true;
1246 return false;
1249 /****************************************************************************
1250 Get an 8.3 directory entry.
1251 ****************************************************************************/
1253 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
1254 void *private_data,
1255 const char *dname,
1256 const char *mask,
1257 char **_fname)
1259 connection_struct *conn = (connection_struct *)private_data;
1261 if ((strcmp(mask,"*.*") == 0) ||
1262 mask_match_search(dname, mask, false) ||
1263 mangle_mask_match(conn, dname, mask)) {
1264 char mname[13];
1265 const char *fname;
1267 * Ensure we can push the original name as UCS2. If
1268 * not, then just don't return this name.
1270 NTSTATUS status;
1271 size_t ret_len = 0;
1272 size_t len = (strlen(dname) + 2) * 4; /* Allow enough space. */
1273 uint8_t *tmp = talloc_array(talloc_tos(),
1274 uint8_t,
1275 len);
1277 status = srvstr_push(NULL,
1278 FLAGS2_UNICODE_STRINGS,
1279 tmp,
1280 dname,
1281 len,
1282 STR_TERMINATE,
1283 &ret_len);
1285 TALLOC_FREE(tmp);
1287 if (!NT_STATUS_IS_OK(status)) {
1288 return false;
1291 if (!mangle_is_8_3(dname, false, conn->params)) {
1292 bool ok = name_to_8_3(dname, mname, false,
1293 conn->params);
1294 if (!ok) {
1295 return false;
1297 fname = mname;
1298 } else {
1299 fname = dname;
1302 *_fname = talloc_strdup(ctx, fname);
1303 if (*_fname == NULL) {
1304 return false;
1307 return true;
1310 return false;
1313 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1314 void *private_data,
1315 struct smb_filename *smb_fname,
1316 uint32_t *_mode)
1318 connection_struct *conn = (connection_struct *)private_data;
1320 if (!VALID_STAT(smb_fname->st)) {
1321 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1322 DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1323 "Couldn't stat [%s]. Error "
1324 "= %s\n",
1325 smb_fname_str_dbg(smb_fname),
1326 strerror(errno)));
1327 return false;
1331 *_mode = dos_mode(conn, smb_fname);
1332 return true;
1335 bool get_dir_entry(TALLOC_CTX *ctx,
1336 struct dptr_struct *dirptr,
1337 const char *mask,
1338 uint32_t dirtype,
1339 char **_fname,
1340 off_t *_size,
1341 uint32_t *_mode,
1342 struct timespec *_date,
1343 bool check_descend,
1344 bool ask_sharemode)
1346 connection_struct *conn = dirptr->conn;
1347 char *fname = NULL;
1348 struct smb_filename *smb_fname = NULL;
1349 uint32_t mode = 0;
1350 long prev_offset;
1351 bool ok;
1353 ok = smbd_dirptr_get_entry(ctx,
1354 dirptr,
1355 mask,
1356 dirtype,
1357 check_descend,
1358 ask_sharemode,
1359 smbd_dirptr_8_3_match_fn,
1360 smbd_dirptr_8_3_mode_fn,
1361 conn,
1362 &fname,
1363 &smb_fname,
1364 &mode,
1365 &prev_offset);
1366 if (!ok) {
1367 return false;
1370 *_fname = talloc_move(ctx, &fname);
1371 *_size = smb_fname->st.st_ex_size;
1372 *_mode = mode;
1373 *_date = smb_fname->st.st_ex_mtime;
1374 TALLOC_FREE(smb_fname);
1375 return true;
1378 /*******************************************************************
1379 Check to see if a user can read a file. This is only approximate,
1380 it is used as part of the "hide unreadable" option. Don't
1381 use it for anything security sensitive.
1382 ********************************************************************/
1384 static bool user_can_read_file(connection_struct *conn,
1385 struct smb_filename *smb_fname)
1387 NTSTATUS status;
1388 uint32_t rejected_share_access = 0;
1389 uint32_t rejected_mask = 0;
1390 struct security_descriptor *sd = NULL;
1391 uint32_t access_mask = FILE_READ_DATA|
1392 FILE_READ_EA|
1393 FILE_READ_ATTRIBUTES|
1394 SEC_STD_READ_CONTROL;
1397 * Never hide files from the root user.
1398 * We use (uid_t)0 here not sec_initial_uid()
1399 * as make test uses a single user context.
1402 if (get_current_uid(conn) == (uid_t)0) {
1403 return True;
1407 * We can't directly use smbd_check_access_rights()
1408 * here, as this implicitly grants FILE_READ_ATTRIBUTES
1409 * which the Windows access-based-enumeration code
1410 * explicitly checks for on the file security descriptor.
1411 * See bug:
1413 * https://bugzilla.samba.org/show_bug.cgi?id=10252
1415 * and the smb2.acl2.ACCESSBASED test for details.
1418 rejected_share_access = access_mask & ~(conn->share_access);
1419 if (rejected_share_access) {
1420 DEBUG(10, ("rejected share access 0x%x "
1421 "on %s (0x%x)\n",
1422 (unsigned int)access_mask,
1423 smb_fname_str_dbg(smb_fname),
1424 (unsigned int)rejected_share_access ));
1425 return false;
1428 status = SMB_VFS_GET_NT_ACL(conn,
1429 smb_fname,
1430 (SECINFO_OWNER |
1431 SECINFO_GROUP |
1432 SECINFO_DACL),
1433 talloc_tos(),
1434 &sd);
1436 if (!NT_STATUS_IS_OK(status)) {
1437 DEBUG(10, ("Could not get acl "
1438 "on %s: %s\n",
1439 smb_fname_str_dbg(smb_fname),
1440 nt_errstr(status)));
1441 return false;
1444 status = se_file_access_check(sd,
1445 get_current_nttok(conn),
1446 false,
1447 access_mask,
1448 &rejected_mask);
1450 TALLOC_FREE(sd);
1452 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1453 DEBUG(10,("rejected bits 0x%x read access for %s\n",
1454 (unsigned int)rejected_mask,
1455 smb_fname_str_dbg(smb_fname) ));
1456 return false;
1458 return true;
1461 /*******************************************************************
1462 Check to see if a user can write a file (and only files, we do not
1463 check dirs on this one). This is only approximate,
1464 it is used as part of the "hide unwriteable" option. Don't
1465 use it for anything security sensitive.
1466 ********************************************************************/
1468 static bool user_can_write_file(connection_struct *conn,
1469 const struct smb_filename *smb_fname)
1472 * Never hide files from the root user.
1473 * We use (uid_t)0 here not sec_initial_uid()
1474 * as make test uses a single user context.
1477 if (get_current_uid(conn) == (uid_t)0) {
1478 return True;
1481 SMB_ASSERT(VALID_STAT(smb_fname->st));
1483 /* Pseudo-open the file */
1485 if(S_ISDIR(smb_fname->st.st_ex_mode)) {
1486 return True;
1489 return can_write_to_file(conn, smb_fname);
1492 /*******************************************************************
1493 Is a file a "special" type ?
1494 ********************************************************************/
1496 static bool file_is_special(connection_struct *conn,
1497 const struct smb_filename *smb_fname)
1500 * Never hide files from the root user.
1501 * We use (uid_t)0 here not sec_initial_uid()
1502 * as make test uses a single user context.
1505 if (get_current_uid(conn) == (uid_t)0) {
1506 return False;
1509 SMB_ASSERT(VALID_STAT(smb_fname->st));
1511 if (S_ISREG(smb_fname->st.st_ex_mode) ||
1512 S_ISDIR(smb_fname->st.st_ex_mode) ||
1513 S_ISLNK(smb_fname->st.st_ex_mode))
1514 return False;
1516 return True;
1519 /*******************************************************************
1520 Should the file be seen by the client?
1521 NOTE: A successful return is no guarantee of the file's existence.
1522 ********************************************************************/
1524 bool is_visible_file(connection_struct *conn, const char *dir_path,
1525 const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
1527 bool hide_unreadable = lp_hide_unreadable(SNUM(conn));
1528 bool hide_unwriteable = lp_hide_unwriteable_files(SNUM(conn));
1529 bool hide_special = lp_hide_special_files(SNUM(conn));
1530 char *entry = NULL;
1531 struct smb_filename *smb_fname_base = NULL;
1532 bool ret = false;
1534 if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1535 return True; /* . and .. are always visible. */
1538 /* If it's a vetoed file, pretend it doesn't even exist */
1539 if (use_veto && IS_VETO_PATH(conn, name)) {
1540 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1541 return False;
1544 if (hide_unreadable || hide_unwriteable || hide_special) {
1545 entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name);
1546 if (!entry) {
1547 ret = false;
1548 goto out;
1551 /* Create an smb_filename with stream_name == NULL. */
1552 smb_fname_base = synthetic_smb_fname(talloc_tos(),
1553 entry,
1554 NULL,
1555 pst,
1557 if (smb_fname_base == NULL) {
1558 ret = false;
1559 goto out;
1562 /* If the file name does not exist, there's no point checking
1563 * the configuration options. We succeed, on the basis that the
1564 * checks *might* have passed if the file was present.
1566 if (!VALID_STAT(*pst)) {
1567 if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
1568 ret = true;
1569 goto out;
1571 *pst = smb_fname_base->st;
1574 /* Honour _hide unreadable_ option */
1575 if (hide_unreadable &&
1576 !user_can_read_file(conn, smb_fname_base)) {
1577 DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1578 entry ));
1579 ret = false;
1580 goto out;
1582 /* Honour _hide unwriteable_ option */
1583 if (hide_unwriteable && !user_can_write_file(conn,
1584 smb_fname_base)) {
1585 DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1586 entry ));
1587 ret = false;
1588 goto out;
1590 /* Honour _hide_special_ option */
1591 if (hide_special && file_is_special(conn, smb_fname_base)) {
1592 DEBUG(10,("is_visible_file: file %s is special.\n",
1593 entry ));
1594 ret = false;
1595 goto out;
1599 ret = true;
1600 out:
1601 TALLOC_FREE(smb_fname_base);
1602 TALLOC_FREE(entry);
1603 return ret;
1606 static int smb_Dir_destructor(struct smb_Dir *dirp)
1608 if (dirp->dir != NULL) {
1609 SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1610 if (dirp->fsp != NULL) {
1612 * The SMB_VFS_CLOSEDIR above
1613 * closes the underlying fd inside
1614 * dirp->fsp.
1616 dirp->fsp->fh->fd = -1;
1617 if (dirp->fsp->dptr != NULL) {
1618 SMB_ASSERT(dirp->fsp->dptr->dir_hnd == dirp);
1619 dirp->fsp->dptr->dir_hnd = NULL;
1621 dirp->fsp = NULL;
1624 if (dirp->conn->sconn && !dirp->conn->sconn->using_smb2) {
1625 dirp->conn->sconn->searches.dirhandles_open--;
1627 return 0;
1630 /*******************************************************************
1631 Open a directory.
1632 ********************************************************************/
1634 static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx,
1635 connection_struct *conn,
1636 const struct smb_filename *smb_dname,
1637 const char *mask,
1638 uint32_t attr)
1640 struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1641 struct smbd_server_connection *sconn = conn->sconn;
1643 if (!dirp) {
1644 return NULL;
1647 dirp->dir = SMB_VFS_OPENDIR(conn, smb_dname, mask, attr);
1649 if (!dirp->dir) {
1650 DEBUG(5,("OpenDir: Can't open %s. %s\n",
1651 smb_dname->base_name,
1652 strerror(errno) ));
1653 goto fail;
1656 dirp->conn = conn;
1657 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1659 if (sconn && !sconn->using_smb2) {
1660 sconn->searches.dirhandles_open++;
1662 talloc_set_destructor(dirp, smb_Dir_destructor);
1664 return dirp;
1666 fail:
1667 TALLOC_FREE(dirp);
1668 return NULL;
1671 /****************************************************************************
1672 Open a directory handle by pathname, ensuring it's under the share path.
1673 ****************************************************************************/
1675 static struct smb_Dir *open_dir_safely(TALLOC_CTX *ctx,
1676 connection_struct *conn,
1677 const struct smb_filename *smb_dname,
1678 const char *wcard,
1679 uint32_t attr)
1681 struct smb_Dir *dir_hnd = NULL;
1682 struct smb_filename *smb_fname_cwd = NULL;
1683 struct smb_filename *saved_dir_fname = vfs_GetWd(ctx, conn);
1684 NTSTATUS status;
1686 if (saved_dir_fname == NULL) {
1687 return NULL;
1690 if (vfs_ChDir(conn, smb_dname) == -1) {
1691 goto out;
1694 smb_fname_cwd = synthetic_smb_fname(talloc_tos(),
1695 ".",
1696 NULL,
1697 NULL,
1698 smb_dname->flags);
1699 if (smb_fname_cwd == NULL) {
1700 goto out;
1704 * Now the directory is pinned, use
1705 * REALPATH to ensure we can access it.
1707 status = check_name(conn, smb_fname_cwd);
1708 if (!NT_STATUS_IS_OK(status)) {
1709 goto out;
1712 dir_hnd = OpenDir_internal(ctx,
1713 conn,
1714 smb_fname_cwd,
1715 wcard,
1716 attr);
1718 if (dir_hnd == NULL) {
1719 goto out;
1723 * OpenDir_internal only gets "." as the dir name.
1724 * Store the real dir name here.
1727 dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, smb_dname);
1728 if (!dir_hnd->dir_smb_fname) {
1729 TALLOC_FREE(dir_hnd);
1730 errno = ENOMEM;
1733 out:
1735 vfs_ChDir(conn, saved_dir_fname);
1736 TALLOC_FREE(saved_dir_fname);
1737 return dir_hnd;
1740 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1741 const struct smb_filename *smb_dname,
1742 const char *mask,
1743 uint32_t attr)
1745 return open_dir_safely(mem_ctx,
1746 conn,
1747 smb_dname,
1748 mask,
1749 attr);
1752 /*******************************************************************
1753 Open a directory from an fsp.
1754 ********************************************************************/
1756 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
1757 files_struct *fsp,
1758 const char *mask,
1759 uint32_t attr)
1761 struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1762 struct smbd_server_connection *sconn = conn->sconn;
1764 if (!dirp) {
1765 goto fail;
1768 if (!fsp->is_directory) {
1769 errno = EBADF;
1770 goto fail;
1773 if (fsp->fh->fd == -1) {
1774 errno = EBADF;
1775 goto fail;
1778 dirp->conn = conn;
1779 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1781 dirp->dir_smb_fname = cp_smb_filename(dirp, fsp->fsp_name);
1782 if (!dirp->dir_smb_fname) {
1783 errno = ENOMEM;
1784 goto fail;
1787 dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1788 if (dirp->dir != NULL) {
1789 dirp->fsp = fsp;
1790 } else {
1791 DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1792 "NULL (%s)\n",
1793 dirp->dir_smb_fname->base_name,
1794 strerror(errno)));
1795 if (errno != ENOSYS) {
1796 goto fail;
1800 if (dirp->dir == NULL) {
1801 /* FDOPENDIR is not supported. Use OPENDIR instead. */
1802 TALLOC_FREE(dirp);
1803 return open_dir_safely(mem_ctx,
1804 conn,
1805 fsp->fsp_name,
1806 mask,
1807 attr);
1810 if (sconn && !sconn->using_smb2) {
1811 sconn->searches.dirhandles_open++;
1813 talloc_set_destructor(dirp, smb_Dir_destructor);
1815 return dirp;
1817 fail:
1818 TALLOC_FREE(dirp);
1819 return NULL;
1823 /*******************************************************************
1824 Read from a directory.
1825 Return directory entry, current offset, and optional stat information.
1826 Don't check for veto or invisible files.
1827 ********************************************************************/
1829 const char *ReadDirName(struct smb_Dir *dirp, long *poffset,
1830 SMB_STRUCT_STAT *sbuf, char **ptalloced)
1832 const char *n;
1833 char *talloced = NULL;
1834 connection_struct *conn = dirp->conn;
1836 /* Cheat to allow . and .. to be the first entries returned. */
1837 if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1838 (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2))
1840 if (dirp->file_number == 0) {
1841 n = ".";
1842 *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1843 } else {
1844 n = "..";
1845 *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1847 dirp->file_number++;
1848 *ptalloced = NULL;
1849 return n;
1852 if (*poffset == END_OF_DIRECTORY_OFFSET) {
1853 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1854 return NULL;
1857 /* A real offset, seek to it. */
1858 SeekDir(dirp, *poffset);
1860 while ((n = vfs_readdirname(conn, dirp->dir, sbuf, &talloced))) {
1861 /* Ignore . and .. - we've already returned them. */
1862 if (*n == '.') {
1863 if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1864 TALLOC_FREE(talloced);
1865 continue;
1868 *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1869 *ptalloced = talloced;
1870 dirp->file_number++;
1871 return n;
1873 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1874 *ptalloced = NULL;
1875 return NULL;
1878 /*******************************************************************
1879 Rewind to the start.
1880 ********************************************************************/
1882 void RewindDir(struct smb_Dir *dirp, long *poffset)
1884 SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1885 dirp->file_number = 0;
1886 dirp->offset = START_OF_DIRECTORY_OFFSET;
1887 *poffset = START_OF_DIRECTORY_OFFSET;
1890 /*******************************************************************
1891 Seek a dir.
1892 ********************************************************************/
1894 void SeekDir(struct smb_Dir *dirp, long offset)
1896 if (offset != dirp->offset) {
1897 if (offset == START_OF_DIRECTORY_OFFSET) {
1898 RewindDir(dirp, &offset);
1900 * Ok we should really set the file number here
1901 * to 1 to enable ".." to be returned next. Trouble
1902 * is I'm worried about callers using SeekDir(dirp,0)
1903 * as equivalent to RewindDir(). So leave this alone
1904 * for now.
1906 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
1907 RewindDir(dirp, &offset);
1909 * Set the file number to 2 - we want to get the first
1910 * real file entry (the one we return after "..")
1911 * on the next ReadDir.
1913 dirp->file_number = 2;
1914 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1915 ; /* Don't seek in this case. */
1916 } else {
1917 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1919 dirp->offset = offset;
1923 /*******************************************************************
1924 Tell a dir position.
1925 ********************************************************************/
1927 long TellDir(struct smb_Dir *dirp)
1929 return(dirp->offset);
1932 /*******************************************************************
1933 Add an entry into the dcache.
1934 ********************************************************************/
1936 static void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
1938 struct name_cache_entry *e;
1940 if (dirp->name_cache_size == 0) {
1941 return;
1944 if (dirp->name_cache == NULL) {
1945 dirp->name_cache = talloc_zero_array(
1946 dirp, struct name_cache_entry, dirp->name_cache_size);
1948 if (dirp->name_cache == NULL) {
1949 return;
1953 dirp->name_cache_index = (dirp->name_cache_index+1) %
1954 dirp->name_cache_size;
1955 e = &dirp->name_cache[dirp->name_cache_index];
1956 TALLOC_FREE(e->name);
1957 e->name = talloc_strdup(dirp, name);
1958 e->offset = offset;
1961 /*******************************************************************
1962 Find an entry by name. Leave us at the offset after it.
1963 Don't check for veto or invisible files.
1964 ********************************************************************/
1966 bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1968 int i;
1969 const char *entry = NULL;
1970 char *talloced = NULL;
1971 connection_struct *conn = dirp->conn;
1973 /* Search back in the name cache. */
1974 if (dirp->name_cache_size && dirp->name_cache) {
1975 for (i = dirp->name_cache_index; i >= 0; i--) {
1976 struct name_cache_entry *e = &dirp->name_cache[i];
1977 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1978 *poffset = e->offset;
1979 SeekDir(dirp, e->offset);
1980 return True;
1983 for (i = dirp->name_cache_size - 1; i > dirp->name_cache_index; i--) {
1984 struct name_cache_entry *e = &dirp->name_cache[i];
1985 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1986 *poffset = e->offset;
1987 SeekDir(dirp, e->offset);
1988 return True;
1993 /* Not found in the name cache. Rewind directory and start from scratch. */
1994 SMB_VFS_REWINDDIR(conn, dirp->dir);
1995 dirp->file_number = 0;
1996 *poffset = START_OF_DIRECTORY_OFFSET;
1997 while ((entry = ReadDirName(dirp, poffset, NULL, &talloced))) {
1998 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1999 TALLOC_FREE(talloced);
2000 return True;
2002 TALLOC_FREE(talloced);
2004 return False;
2007 struct files_below_forall_state {
2008 char *dirpath;
2009 size_t dirpath_len;
2010 int (*fn)(struct file_id fid, const struct share_mode_data *data,
2011 void *private_data);
2012 void *private_data;
2015 static int files_below_forall_fn(struct file_id fid,
2016 const struct share_mode_data *data,
2017 void *private_data)
2019 struct files_below_forall_state *state = private_data;
2020 char tmpbuf[PATH_MAX];
2021 char *fullpath, *to_free;
2022 size_t len;
2024 len = full_path_tos(data->servicepath, data->base_name,
2025 tmpbuf, sizeof(tmpbuf),
2026 &fullpath, &to_free);
2027 if (len == -1) {
2028 return 0;
2030 if (state->dirpath_len >= len) {
2032 * Filter files above dirpath
2034 return 0;
2036 if (fullpath[state->dirpath_len] != '/') {
2038 * Filter file that don't have a path separator at the end of
2039 * dirpath's length
2041 return 0;
2044 if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
2046 * Not a parent
2048 return 0;
2051 return state->fn(fid, data, state->private_data);
2054 static int files_below_forall(connection_struct *conn,
2055 const struct smb_filename *dir_name,
2056 int (*fn)(struct file_id fid,
2057 const struct share_mode_data *data,
2058 void *private_data),
2059 void *private_data)
2061 struct files_below_forall_state state = {
2062 .fn = fn,
2063 .private_data = private_data,
2065 int ret;
2066 char tmpbuf[PATH_MAX];
2067 char *to_free;
2069 state.dirpath_len = full_path_tos(conn->connectpath,
2070 dir_name->base_name,
2071 tmpbuf, sizeof(tmpbuf),
2072 &state.dirpath, &to_free);
2073 if (state.dirpath_len == -1) {
2074 return -1;
2077 ret = share_mode_forall(files_below_forall_fn, &state);
2078 TALLOC_FREE(to_free);
2079 return ret;
2082 struct have_file_open_below_state {
2083 bool found_one;
2086 static int have_file_open_below_fn(struct file_id fid,
2087 const struct share_mode_data *data,
2088 void *private_data)
2090 struct have_file_open_below_state *state = private_data;
2091 state->found_one = true;
2092 return 1;
2095 bool have_file_open_below(connection_struct *conn,
2096 const struct smb_filename *name)
2098 struct have_file_open_below_state state = {
2099 .found_one = false,
2101 int ret;
2103 if (!VALID_STAT(name->st)) {
2104 return false;
2106 if (!S_ISDIR(name->st.st_ex_mode)) {
2107 return false;
2110 ret = files_below_forall(conn, name, have_file_open_below_fn, &state);
2111 if (ret == -1) {
2112 return false;
2115 return state.found_one;
2118 /*****************************************************************
2119 Is this directory empty ?
2120 *****************************************************************/
2122 NTSTATUS can_delete_directory_fsp(files_struct *fsp)
2124 NTSTATUS status = NT_STATUS_OK;
2125 long dirpos = 0;
2126 const char *dname = NULL;
2127 const char *dirname = fsp->fsp_name->base_name;
2128 char *talloced = NULL;
2129 SMB_STRUCT_STAT st;
2130 struct connection_struct *conn = fsp->conn;
2131 struct smb_Dir *dir_hnd = OpenDir_fsp(talloc_tos(),
2132 conn,
2133 fsp,
2134 NULL,
2137 if (!dir_hnd) {
2138 return map_nt_error_from_unix(errno);
2141 while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) {
2142 /* Quick check for "." and ".." */
2143 if (dname[0] == '.') {
2144 if (!dname[1] || (dname[1] == '.' && !dname[2])) {
2145 TALLOC_FREE(talloced);
2146 continue;
2150 if (!is_visible_file(conn, dirname, dname, &st, True)) {
2151 TALLOC_FREE(talloced);
2152 continue;
2155 DEBUG(10,("got name %s - can't delete\n",
2156 dname ));
2157 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
2158 break;
2160 TALLOC_FREE(talloced);
2161 TALLOC_FREE(dir_hnd);
2163 if (!NT_STATUS_IS_OK(status)) {
2164 return status;
2167 if (!(fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) &&
2168 lp_strict_rename(SNUM(conn)) &&
2169 have_file_open_below(fsp->conn, fsp->fsp_name))
2171 return NT_STATUS_ACCESS_DENIED;
2174 return NT_STATUS_OK;