Revert "pidl: Use non-existent function dissect_ndr_int64()"
[Samba.git] / source3 / smbd / dir.c
blob76eb5756dc8759b98068e0e89d82392e7117f79e
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 "locking/share_mode_lock.h"
24 #include "smbd/smbd.h"
25 #include "smbd/globals.h"
26 #include "libcli/security/security.h"
27 #include "lib/util/bitmap.h"
28 #include "../lib/util/memcache.h"
29 #include "../librpc/gen_ndr/open_files.h"
30 #include "lib/util/string_wrappers.h"
31 #include "libcli/smb/reparse.h"
32 #include "source3/smbd/dir.h"
35 This module implements directory related functions for Samba.
38 /* "Special" directory offsets. */
39 #define END_OF_DIRECTORY_OFFSET ((long)-1)
40 #define START_OF_DIRECTORY_OFFSET ((long)0)
41 #define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
43 /* Make directory handle internals available. */
45 struct smb_Dir {
46 connection_struct *conn;
47 DIR *dir;
48 struct smb_filename *dir_smb_fname;
49 unsigned int file_number;
50 bool case_sensitive;
51 files_struct *fsp; /* Back pointer to containing fsp, only
52 set from OpenDir_fsp(). */
55 struct dptr_struct {
56 struct dptr_struct *next, *prev;
57 int dnum;
58 struct smb_Dir *dir_hnd;
59 char *wcard;
60 uint32_t attr;
61 bool has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
62 bool did_stat; /* Optimisation for non-wcard searches. */
63 bool priv; /* Directory handle opened with privilege. */
64 uint32_t counter;
66 char *last_name_sent; /* for name-based trans2 resume */
68 struct {
69 char *fname;
70 struct smb_filename *smb_fname;
71 uint32_t mode;
72 } overflow;
75 static NTSTATUS OpenDir_fsp(
76 TALLOC_CTX *mem_ctx,
77 connection_struct *conn,
78 files_struct *fsp,
79 const char *mask,
80 uint32_t attr,
81 struct smb_Dir **_dir_hnd);
83 static int smb_Dir_destructor(struct smb_Dir *dir_hnd);
85 #define INVALID_DPTR_KEY (-3)
87 /****************************************************************************
88 Initialise the dir bitmap.
89 ****************************************************************************/
91 bool init_dptrs(struct smbd_server_connection *sconn)
93 if (sconn->searches.dptr_bmap) {
94 return true;
97 sconn->searches.dptr_bmap = bitmap_talloc(
98 sconn, MAX_DIRECTORY_HANDLES);
100 if (sconn->searches.dptr_bmap == NULL) {
101 return false;
104 return true;
107 /****************************************************************************
108 Get the struct dptr_struct for a dir index.
109 ****************************************************************************/
111 static struct dptr_struct *dptr_get(struct smbd_server_connection *sconn,
112 int key)
114 struct dptr_struct *dptr;
116 for (dptr = sconn->searches.dirptrs; dptr != NULL; dptr = dptr->next) {
117 if(dptr->dnum != key) {
118 continue;
120 DLIST_PROMOTE(sconn->searches.dirptrs, dptr);
121 return dptr;
123 return(NULL);
126 /****************************************************************************
127 Get the dir path for a dir index.
128 ****************************************************************************/
130 const char *dptr_path(struct smbd_server_connection *sconn, int key)
132 struct dptr_struct *dptr = dptr_get(sconn, key);
133 if (dptr)
134 return(dptr->dir_hnd->dir_smb_fname->base_name);
135 return(NULL);
138 /****************************************************************************
139 Get the dir wcard for a dir index.
140 ****************************************************************************/
142 const char *dptr_wcard(struct smbd_server_connection *sconn, int key)
144 struct dptr_struct *dptr = dptr_get(sconn, key);
145 if (dptr)
146 return(dptr->wcard);
147 return(NULL);
150 /****************************************************************************
151 Get the dir attrib for a dir index.
152 ****************************************************************************/
154 uint16_t dptr_attr(struct smbd_server_connection *sconn, int key)
156 struct dptr_struct *dptr = dptr_get(sconn, key);
157 if (dptr)
158 return(dptr->attr);
159 return(0);
162 /****************************************************************************
163 Close all dptrs for a cnum.
164 ****************************************************************************/
166 void dptr_closecnum(connection_struct *conn)
168 struct dptr_struct *dptr, *next;
169 struct smbd_server_connection *sconn = conn->sconn;
171 if (sconn == NULL) {
172 return;
175 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
176 next = dptr->next;
177 if (dptr->dir_hnd->conn == conn) {
179 * Need to make a copy, "dptr" will be gone
180 * after close_file_free() returns
182 struct files_struct *fsp = dptr->dir_hnd->fsp;
183 close_file_free(NULL, &fsp, NORMAL_CLOSE);
188 /****************************************************************************
189 Create a new dir ptr. If the flag old_handle is true then we must allocate
190 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
191 one byte long. If old_handle is false we allocate from the range
192 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
193 a directory handle is never zero.
194 wcard must not be zero.
195 ****************************************************************************/
197 NTSTATUS dptr_create(connection_struct *conn,
198 struct smb_request *req,
199 files_struct *fsp,
200 bool old_handle,
201 const char *wcard,
202 uint32_t attr,
203 struct dptr_struct **dptr_ret)
205 struct smbd_server_connection *sconn = conn->sconn;
206 struct dptr_struct *dptr = NULL;
207 struct smb_Dir *dir_hnd = NULL;
208 NTSTATUS status;
210 DBG_INFO("dir=%s\n", fsp_str_dbg(fsp));
212 if (sconn == NULL) {
213 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
214 return NT_STATUS_INTERNAL_ERROR;
217 if (!wcard) {
218 return NT_STATUS_INVALID_PARAMETER;
221 status = check_any_access_fsp(fsp, SEC_DIR_LIST);
222 if (!NT_STATUS_IS_OK(status)) {
223 DBG_INFO("dptr_create: directory %s "
224 "not open for LIST access\n",
225 fsp_str_dbg(fsp));
226 return status;
228 status = OpenDir_fsp(NULL, conn, fsp, wcard, attr, &dir_hnd);
229 if (!NT_STATUS_IS_OK(status)) {
230 return status;
233 dptr = talloc_zero(NULL, struct dptr_struct);
234 if(!dptr) {
235 DEBUG(0,("talloc fail in dptr_create.\n"));
236 TALLOC_FREE(dir_hnd);
237 return NT_STATUS_NO_MEMORY;
240 dptr->dir_hnd = dir_hnd;
241 dptr->wcard = talloc_strdup(dptr, wcard);
242 if (!dptr->wcard) {
243 TALLOC_FREE(dptr);
244 TALLOC_FREE(dir_hnd);
245 return NT_STATUS_NO_MEMORY;
247 if ((req != NULL && req->posix_pathnames) || ISDOT(wcard)) {
248 dptr->has_wild = True;
249 } else {
250 dptr->has_wild = ms_has_wild(dptr->wcard);
253 dptr->attr = attr;
255 if (conn_using_smb2(sconn)) {
256 goto done;
259 if(old_handle) {
262 * This is an old-style SMBsearch request. Ensure the
263 * value we return will fit in the range 1-255.
266 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
268 if(dptr->dnum == -1 || dptr->dnum > 254) {
269 DBG_ERR("returned %d: Error - all old "
270 "dirptrs in use ?\n",
271 dptr->dnum);
272 TALLOC_FREE(dptr);
273 TALLOC_FREE(dir_hnd);
274 return NT_STATUS_TOO_MANY_OPENED_FILES;
276 } else {
279 * This is a new-style trans2 request. Allocate from
280 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
283 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
285 if(dptr->dnum == -1 || dptr->dnum < 255) {
286 DBG_ERR("returned %d: Error - all new "
287 "dirptrs in use ?\n",
288 dptr->dnum);
289 TALLOC_FREE(dptr);
290 TALLOC_FREE(dir_hnd);
291 return NT_STATUS_TOO_MANY_OPENED_FILES;
295 bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
297 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
299 DLIST_ADD(sconn->searches.dirptrs, dptr);
301 done:
302 DBG_INFO("creating new dirptr [%d] for path [%s]\n",
303 dptr->dnum, fsp_str_dbg(fsp));
305 *dptr_ret = dptr;
307 return NT_STATUS_OK;
311 /****************************************************************************
312 Wrapper functions to access the lower level directory handles.
313 ****************************************************************************/
315 void dptr_CloseDir(files_struct *fsp)
317 struct smbd_server_connection *sconn = NULL;
319 if (fsp->dptr == NULL) {
320 return;
322 sconn = fsp->conn->sconn;
325 * The destructor for the struct smb_Dir (fsp->dptr->dir_hnd)
326 * now handles all resource deallocation.
329 DBG_INFO("closing dptr key %d\n", fsp->dptr->dnum);
331 if (sconn != NULL && !conn_using_smb2(sconn)) {
332 DLIST_REMOVE(sconn->searches.dirptrs, fsp->dptr);
335 * Free the dnum in the bitmap. Remember the dnum value is
336 * always biased by one with respect to the bitmap.
339 if (!bitmap_query(sconn->searches.dptr_bmap,
340 fsp->dptr->dnum - 1))
342 DBG_ERR("closing dnum = %d and bitmap not set !\n",
343 fsp->dptr->dnum);
346 bitmap_clear(sconn->searches.dptr_bmap, fsp->dptr->dnum - 1);
349 TALLOC_FREE(fsp->dptr->dir_hnd);
350 TALLOC_FREE(fsp->dptr);
353 void dptr_RewindDir(struct dptr_struct *dptr)
355 RewindDir(dptr->dir_hnd);
356 dptr->did_stat = false;
357 TALLOC_FREE(dptr->overflow.fname);
358 TALLOC_FREE(dptr->overflow.smb_fname);
361 unsigned int dptr_FileNumber(struct dptr_struct *dptr)
363 return dptr->dir_hnd->file_number;
366 bool dptr_has_wild(struct dptr_struct *dptr)
368 return dptr->has_wild;
371 int dptr_dnum(struct dptr_struct *dptr)
373 return dptr->dnum;
376 bool dptr_get_priv(struct dptr_struct *dptr)
378 return dptr->priv;
381 void dptr_set_priv(struct dptr_struct *dptr)
383 dptr->priv = true;
386 bool dptr_case_sensitive(struct dptr_struct *dptr)
388 return dptr->dir_hnd->case_sensitive;
391 /****************************************************************************
392 Return the next visible file name, skipping veto'd and invisible files.
393 ****************************************************************************/
395 char *dptr_ReadDirName(TALLOC_CTX *ctx, struct dptr_struct *dptr)
397 struct stat_ex st = {
398 .st_ex_nlink = 0,
400 struct smb_Dir *dir_hnd = dptr->dir_hnd;
401 struct files_struct *dir_fsp = dir_hnd->fsp;
402 struct smb_filename *dir_name = dir_fsp->fsp_name;
403 struct smb_filename smb_fname_base;
404 bool retry_scanning = false;
405 int ret;
406 int flags = 0;
408 if (dptr->has_wild) {
409 const char *name_temp = NULL;
410 char *talloced = NULL;
411 name_temp = ReadDirName(dir_hnd, &talloced);
412 if (name_temp == NULL) {
413 return NULL;
415 if (talloced != NULL) {
416 return talloc_move(ctx, &talloced);
418 return talloc_strdup(ctx, name_temp);
421 if (dptr->did_stat) {
423 * No wildcard, this is not a real directory traverse
424 * but a "stat" call behind a query_directory. We've
425 * been here, nothing else to look at.
427 return NULL;
429 dptr->did_stat = true;
431 /* Create an smb_filename with stream_name == NULL. */
432 smb_fname_base = (struct smb_filename){
433 .base_name = dptr->wcard,
434 .flags = dir_name->flags,
435 .twrp = dir_name->twrp,
438 if (dir_name->flags & SMB_FILENAME_POSIX_PATH) {
439 flags |= AT_SYMLINK_NOFOLLOW;
442 ret = SMB_VFS_FSTATAT(
443 dir_hnd->conn, dir_fsp, &smb_fname_base, &st, flags);
444 if (ret == 0) {
445 return talloc_strdup(ctx, dptr->wcard);
449 * If we get any other error than ENOENT or ENOTDIR
450 * then the file exists, we just can't stat it.
452 if (errno != ENOENT && errno != ENOTDIR) {
453 return talloc_strdup(ctx, dptr->wcard);
457 * A scan will find the long version of a mangled name as
458 * wildcard.
460 retry_scanning |= mangle_is_mangled(dptr->wcard,
461 dir_hnd->conn->params);
464 * Also retry scanning if the client requested case
465 * insensitive semantics and the file system does not provide
466 * it.
468 retry_scanning |= (!dir_hnd->case_sensitive &&
469 (dir_hnd->conn->fs_capabilities &
470 FILE_CASE_SENSITIVE_SEARCH));
472 if (retry_scanning) {
473 char *found_name = NULL;
474 NTSTATUS status;
476 status = get_real_filename_at(dir_fsp,
477 dptr->wcard,
478 ctx,
479 &found_name);
480 if (NT_STATUS_IS_OK(status)) {
481 return found_name;
485 return NULL;
488 struct files_struct *dir_hnd_fetch_fsp(struct smb_Dir *dir_hnd)
490 return dir_hnd->fsp;
493 /****************************************************************************
494 Fetch the fsp associated with the dptr_num.
495 ****************************************************************************/
497 files_struct *dptr_fetch_lanman2_fsp(struct smbd_server_connection *sconn,
498 int dptr_num)
500 struct dptr_struct *dptr = dptr_get(sconn, dptr_num);
501 if (dptr == NULL) {
502 return NULL;
504 DBG_NOTICE("fetching dirptr %d for path %s\n",
505 dptr_num,
506 dptr->dir_hnd->dir_smb_fname->base_name);
507 return dptr->dir_hnd->fsp;
510 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
511 struct dptr_struct *dirptr,
512 const char *mask,
513 uint32_t dirtype,
514 bool dont_descend,
515 bool ask_sharemode,
516 bool get_dosmode_in,
517 bool (*match_fn)(TALLOC_CTX *ctx,
518 void *private_data,
519 const char *dname,
520 const char *mask,
521 char **_fname),
522 void *private_data,
523 char **_fname,
524 struct smb_filename **_smb_fname,
525 uint32_t *_mode)
527 struct smb_Dir *dir_hnd = dirptr->dir_hnd;
528 connection_struct *conn = dir_hnd->conn;
529 struct smb_filename *dir_fname = dir_hnd->dir_smb_fname;
530 bool posix = (dir_fname->flags & SMB_FILENAME_POSIX_PATH);
531 const bool toplevel = ISDOT(dir_fname->base_name);
532 NTSTATUS status;
534 *_smb_fname = NULL;
535 *_mode = 0;
537 if (dirptr->overflow.smb_fname != NULL) {
538 *_fname = talloc_move(ctx, &dirptr->overflow.fname);
539 *_smb_fname = talloc_move(ctx, &dirptr->overflow.smb_fname);
540 *_mode = dirptr->overflow.mode;
541 return true;
544 if (dont_descend && (dptr_FileNumber(dirptr) >= 2)) {
546 * . and .. were returned first, we're done showing
547 * the directory as empty.
549 return false;
552 while (true) {
553 char *dname = NULL;
554 char *fname = NULL;
555 struct smb_filename *smb_fname = NULL;
556 uint32_t mode = 0;
557 bool get_dosmode = get_dosmode_in;
558 bool toplevel_dotdot;
559 bool visible;
560 bool ok;
562 dname = dptr_ReadDirName(ctx, dirptr);
564 DBG_DEBUG("dir [%s] dirptr [%p] offset [%u] => "
565 "dname [%s]\n",
566 smb_fname_str_dbg(dir_fname),
567 dirptr,
568 dir_hnd->file_number,
569 dname ? dname : "(finished)");
571 if (dname == NULL) {
572 return false;
575 if (IS_VETO_PATH(conn, dname)) {
576 TALLOC_FREE(dname);
577 continue;
581 * fname may get mangled, dname is never mangled.
582 * Whenever we're accessing the filesystem we use
583 * pathreal which is composed from dname.
586 ok = match_fn(ctx, private_data, dname, mask, &fname);
587 if (!ok) {
588 TALLOC_FREE(dname);
589 continue;
592 toplevel_dotdot = toplevel && ISDOTDOT(dname);
594 smb_fname = synthetic_smb_fname(talloc_tos(),
595 toplevel_dotdot ? "." : dname,
596 NULL,
597 NULL,
598 dir_fname->twrp,
599 dir_fname->flags);
600 if (smb_fname == NULL) {
601 TALLOC_FREE(dname);
602 return false;
606 * UCF_POSIX_PATHNAMES to avoid the readdir fallback
607 * if we get raced between readdir and unlink.
609 status = openat_pathref_fsp_lcomp(dir_hnd->fsp,
610 smb_fname,
611 UCF_POSIX_PATHNAMES);
612 if (!NT_STATUS_IS_OK(status)) {
613 DBG_DEBUG("Could not open %s: %s\n",
614 dname,
615 nt_errstr(status));
616 TALLOC_FREE(smb_fname);
617 TALLOC_FREE(fname);
618 TALLOC_FREE(dname);
619 continue;
622 visible = is_visible_fsp(smb_fname->fsp);
623 if (!visible) {
624 TALLOC_FREE(smb_fname);
625 TALLOC_FREE(fname);
626 TALLOC_FREE(dname);
627 continue;
630 if (!S_ISLNK(smb_fname->st.st_ex_mode)) {
631 goto done;
634 if (lp_host_msdfs() && lp_msdfs_root(SNUM(conn)) &&
635 is_msdfs_link(dir_hnd->fsp, smb_fname))
637 DBG_INFO("Masquerading msdfs link %s as a directory\n",
638 smb_fname->base_name);
640 smb_fname->st.st_ex_mode = (smb_fname->st.st_ex_mode &
641 ~S_IFMT) |
642 S_IFDIR;
644 mode = dos_mode_msdfs(conn, dname, &smb_fname->st);
645 get_dosmode = false;
646 ask_sharemode = false;
647 goto done;
650 if (posix) {
652 * Posix always wants to see symlinks.
654 ask_sharemode = false;
655 goto done;
658 if (!lp_follow_symlinks(SNUM(conn))) {
660 * Hide symlinks not followed
662 TALLOC_FREE(smb_fname);
663 TALLOC_FREE(fname);
664 TALLOC_FREE(dname);
665 continue;
669 * We have to find out if it's a dangling
670 * symlink. Use the fat logic behind
671 * openat_pathref_fsp().
675 struct files_struct *fsp = smb_fname->fsp;
676 smb_fname_fsp_unlink(smb_fname);
677 fd_close(fsp);
678 file_free(NULL, fsp);
681 status = openat_pathref_fsp(dir_hnd->fsp, smb_fname);
683 if (!NT_STATUS_IS_OK(status)) {
685 * Dangling symlink. Hide.
687 TALLOC_FREE(smb_fname);
688 TALLOC_FREE(fname);
689 TALLOC_FREE(dname);
690 continue;
693 done:
694 if (get_dosmode) {
695 mode = fdos_mode(smb_fname->fsp);
696 smb_fname->st = smb_fname->fsp->fsp_name->st;
699 if (!dir_check_ftype(mode, dirtype)) {
700 DBG_INFO("[%s] attribs 0x%" PRIx32 " didn't match "
701 "0x%" PRIx32 "\n",
702 fname,
703 mode,
704 dirtype);
705 TALLOC_FREE(smb_fname);
706 TALLOC_FREE(dname);
707 TALLOC_FREE(fname);
708 continue;
711 if (ask_sharemode && !S_ISDIR(smb_fname->st.st_ex_mode)) {
712 struct timespec write_time_ts;
713 struct file_id fileid;
715 fileid = vfs_file_id_from_sbuf(conn,
716 &smb_fname->st);
717 get_file_infos(fileid, 0, NULL, &write_time_ts);
718 if (!is_omit_timespec(&write_time_ts)) {
719 update_stat_ex_mtime(&smb_fname->st,
720 write_time_ts);
724 if (toplevel_dotdot) {
726 * Ensure posix fileid and sids are hidden
728 smb_fname->st.st_ex_ino = 0;
729 smb_fname->st.st_ex_dev = 0;
730 smb_fname->st.st_ex_uid = -1;
731 smb_fname->st.st_ex_gid = -1;
734 DBG_NOTICE("mask=[%s] found %s fname=%s (%s)\n",
735 mask,
736 smb_fname_str_dbg(smb_fname),
737 dname,
738 fname);
740 TALLOC_FREE(dname);
742 *_smb_fname = talloc_move(ctx, &smb_fname);
743 *_fname = fname;
744 *_mode = mode;
746 return true;
749 return false;
752 void smbd_dirptr_push_overflow(struct dptr_struct *dirptr,
753 char **_fname,
754 struct smb_filename **_smb_fname,
755 uint32_t mode)
757 SMB_ASSERT(dirptr->overflow.fname == NULL);
758 SMB_ASSERT(dirptr->overflow.smb_fname == NULL);
760 dirptr->overflow.fname = talloc_move(dirptr, _fname);
761 dirptr->overflow.smb_fname = talloc_move(dirptr, _smb_fname);
762 dirptr->overflow.mode = mode;
765 void smbd_dirptr_set_last_name_sent(struct dptr_struct *dirptr,
766 char **_fname)
768 TALLOC_FREE(dirptr->last_name_sent);
769 dirptr->last_name_sent = talloc_move(dirptr, _fname);
772 char *smbd_dirptr_get_last_name_sent(struct dptr_struct *dirptr)
774 return dirptr->last_name_sent;
777 /*******************************************************************
778 Check to see if a user can read an fsp . This is only approximate,
779 it is used as part of the "hide unreadable" option. Don't
780 use it for anything security sensitive.
781 ********************************************************************/
783 static bool user_can_read_fsp(struct files_struct *fsp)
785 NTSTATUS status;
786 uint32_t rejected_share_access = 0;
787 uint32_t rejected_mask = 0;
788 struct security_descriptor *sd = NULL;
789 uint32_t access_mask = FILE_READ_DATA|
790 FILE_READ_EA|
791 FILE_READ_ATTRIBUTES|
792 SEC_STD_READ_CONTROL;
795 * Never hide files from the root user.
796 * We use (uid_t)0 here not sec_initial_uid()
797 * as make test uses a single user context.
800 if (get_current_uid(fsp->conn) == (uid_t)0) {
801 return true;
805 * We can't directly use smbd_check_access_rights_fsp()
806 * here, as this implicitly grants FILE_READ_ATTRIBUTES
807 * which the Windows access-based-enumeration code
808 * explicitly checks for on the file security descriptor.
809 * See bug:
811 * https://bugzilla.samba.org/show_bug.cgi?id=10252
813 * and the smb2.acl2.ACCESSBASED test for details.
816 rejected_share_access = access_mask & ~(fsp->conn->share_access);
817 if (rejected_share_access) {
818 DBG_DEBUG("rejected share access 0x%x "
819 "on %s (0x%x)\n",
820 (unsigned int)access_mask,
821 fsp_str_dbg(fsp),
822 (unsigned int)rejected_share_access);
823 return false;
826 status = SMB_VFS_FGET_NT_ACL(metadata_fsp(fsp),
827 (SECINFO_OWNER |
828 SECINFO_GROUP |
829 SECINFO_DACL),
830 talloc_tos(),
831 &sd);
833 if (!NT_STATUS_IS_OK(status)) {
834 DBG_DEBUG("Could not get acl "
835 "on %s: %s\n",
836 fsp_str_dbg(fsp),
837 nt_errstr(status));
838 return false;
841 status = se_file_access_check(sd,
842 get_current_nttok(fsp->conn),
843 false,
844 access_mask,
845 &rejected_mask);
847 TALLOC_FREE(sd);
849 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
850 DBG_DEBUG("rejected bits 0x%x read access for %s\n",
851 (unsigned int)rejected_mask,
852 fsp_str_dbg(fsp));
853 return false;
855 return true;
858 /*******************************************************************
859 Check to see if a user can write to an fsp.
860 Always return true for directories.
861 This is only approximate,
862 it is used as part of the "hide unwriteable" option. Don't
863 use it for anything security sensitive.
864 ********************************************************************/
866 static bool user_can_write_fsp(struct files_struct *fsp)
869 * Never hide files from the root user.
870 * We use (uid_t)0 here not sec_initial_uid()
871 * as make test uses a single user context.
874 if (get_current_uid(fsp->conn) == (uid_t)0) {
875 return true;
878 if (fsp->fsp_flags.is_directory) {
879 return true;
882 return can_write_to_fsp(fsp);
885 /*******************************************************************
886 Is a file a "special" type ?
887 ********************************************************************/
889 static bool file_is_special(connection_struct *conn,
890 const struct smb_filename *smb_fname)
893 * Never hide files from the root user.
894 * We use (uid_t)0 here not sec_initial_uid()
895 * as make test uses a single user context.
898 if (get_current_uid(conn) == (uid_t)0) {
899 return False;
902 SMB_ASSERT(VALID_STAT(smb_fname->st));
904 if (S_ISREG(smb_fname->st.st_ex_mode) ||
905 S_ISDIR(smb_fname->st.st_ex_mode) ||
906 S_ISLNK(smb_fname->st.st_ex_mode))
907 return False;
909 return True;
912 /*******************************************************************
913 Should the file be seen by the client?
914 ********************************************************************/
916 bool is_visible_fsp(struct files_struct *fsp)
918 bool hide_unreadable = false;
919 bool hide_unwriteable = false;
920 bool hide_special = false;
921 int hide_new_files_timeout = 0;
922 const char *last_component = NULL;
925 * If the file does not exist, there's no point checking
926 * the configuration options. We succeed, on the basis that the
927 * checks *might* have passed if the file was present.
929 if (fsp == NULL) {
930 return true;
933 hide_unreadable = lp_hide_unreadable(SNUM(fsp->conn));
934 hide_unwriteable = lp_hide_unwriteable_files(SNUM(fsp->conn));
935 hide_special = lp_hide_special_files(SNUM(fsp->conn));
936 hide_new_files_timeout = lp_hide_new_files_timeout(SNUM(fsp->conn));
938 if (!hide_unreadable &&
939 !hide_unwriteable &&
940 !hide_special &&
941 (hide_new_files_timeout == 0))
943 return true;
946 fsp = metadata_fsp(fsp);
948 /* Get the last component of the base name. */
949 last_component = strrchr_m(fsp->fsp_name->base_name, '/');
950 if (!last_component) {
951 last_component = fsp->fsp_name->base_name;
952 } else {
953 last_component++; /* Go past '/' */
956 if (ISDOT(last_component) || ISDOTDOT(last_component)) {
957 return true; /* . and .. are always visible. */
960 if (fsp_get_pathref_fd(fsp) == -1) {
962 * Symlink in POSIX mode or MS-DFS.
963 * We've checked veto files so the
964 * only thing we can check is the
965 * hide_new_files_timeout.
967 if ((hide_new_files_timeout != 0) &&
968 !S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
969 double age = timespec_elapsed(
970 &fsp->fsp_name->st.st_ex_mtime);
972 if (age < (double)hide_new_files_timeout) {
973 return false;
976 return true;
979 /* Honour _hide unreadable_ option */
980 if (hide_unreadable && !user_can_read_fsp(fsp)) {
981 DBG_DEBUG("file %s is unreadable.\n", fsp_str_dbg(fsp));
982 return false;
985 /* Honour _hide unwriteable_ option */
986 if (hide_unwriteable && !user_can_write_fsp(fsp)) {
987 DBG_DEBUG("file %s is unwritable.\n", fsp_str_dbg(fsp));
988 return false;
991 /* Honour _hide_special_ option */
992 if (hide_special && file_is_special(fsp->conn, fsp->fsp_name)) {
993 DBG_DEBUG("file %s is special.\n", fsp_str_dbg(fsp));
994 return false;
997 if ((hide_new_files_timeout != 0) &&
998 !S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
999 double age = timespec_elapsed(&fsp->fsp_name->st.st_ex_mtime);
1001 if (age < (double)hide_new_files_timeout) {
1002 return false;
1006 return true;
1009 static int smb_Dir_destructor(struct smb_Dir *dir_hnd)
1011 files_struct *fsp = dir_hnd->fsp;
1013 SMB_VFS_CLOSEDIR(dir_hnd->conn, dir_hnd->dir);
1014 fsp_set_fd(fsp, -1);
1015 if (fsp->dptr != NULL) {
1016 SMB_ASSERT(fsp->dptr->dir_hnd == dir_hnd);
1017 fsp->dptr->dir_hnd = NULL;
1019 dir_hnd->fsp = NULL;
1020 return 0;
1023 /*******************************************************************
1024 Open a directory.
1025 ********************************************************************/
1027 static int smb_Dir_OpenDir_destructor(struct smb_Dir *dir_hnd)
1029 files_struct *fsp = dir_hnd->fsp;
1031 smb_Dir_destructor(dir_hnd);
1032 file_free(NULL, fsp);
1033 return 0;
1036 NTSTATUS OpenDir(TALLOC_CTX *mem_ctx,
1037 connection_struct *conn,
1038 const struct smb_filename *smb_dname,
1039 const char *mask,
1040 uint32_t attr,
1041 struct smb_Dir **_dir_hnd)
1043 struct files_struct *fsp = NULL;
1044 struct smb_Dir *dir_hnd = NULL;
1045 NTSTATUS status;
1047 status = open_internal_dirfsp(conn,
1048 smb_dname,
1049 O_RDONLY,
1050 &fsp);
1051 if (!NT_STATUS_IS_OK(status)) {
1052 return status;
1055 status = OpenDir_fsp(mem_ctx, conn, fsp, mask, attr, &dir_hnd);
1056 if (!NT_STATUS_IS_OK(status)) {
1057 return status;
1061 * This overwrites the destructor set by OpenDir_fsp() but
1062 * smb_Dir_OpenDir_destructor() calls the OpenDir_fsp()
1063 * destructor.
1065 talloc_set_destructor(dir_hnd, smb_Dir_OpenDir_destructor);
1067 *_dir_hnd = dir_hnd;
1068 return NT_STATUS_OK;
1071 NTSTATUS OpenDir_from_pathref(TALLOC_CTX *mem_ctx,
1072 struct files_struct *dirfsp,
1073 const char *mask,
1074 uint32_t attr,
1075 struct smb_Dir **_dir_hnd)
1077 struct files_struct *fsp = NULL;
1078 struct smb_Dir *dir_hnd = NULL;
1079 NTSTATUS status;
1081 status = openat_internal_dir_from_pathref(dirfsp, O_RDONLY, &fsp);
1082 if (!NT_STATUS_IS_OK(status)) {
1083 return status;
1086 status = OpenDir_fsp(mem_ctx, fsp->conn, fsp, mask, attr, &dir_hnd);
1087 if (!NT_STATUS_IS_OK(status)) {
1088 return status;
1092 * This overwrites the destructor set by OpenDir_fsp() but
1093 * smb_Dir_OpenDir_destructor() calls the OpenDir_fsp()
1094 * destructor.
1096 talloc_set_destructor(dir_hnd, smb_Dir_OpenDir_destructor);
1098 *_dir_hnd = dir_hnd;
1099 return NT_STATUS_OK;
1102 /*******************************************************************
1103 Open a directory from an fsp.
1104 ********************************************************************/
1106 static NTSTATUS OpenDir_fsp(
1107 TALLOC_CTX *mem_ctx,
1108 connection_struct *conn,
1109 files_struct *fsp,
1110 const char *mask,
1111 uint32_t attr,
1112 struct smb_Dir **_dir_hnd)
1114 struct smb_Dir *dir_hnd = talloc_zero(mem_ctx, struct smb_Dir);
1115 NTSTATUS status;
1117 if (!dir_hnd) {
1118 return NT_STATUS_NO_MEMORY;
1121 if (!fsp->fsp_flags.is_directory) {
1122 status = NT_STATUS_INVALID_HANDLE;
1123 goto fail;
1126 if (fsp_get_io_fd(fsp) == -1) {
1127 status = NT_STATUS_INVALID_HANDLE;
1128 goto fail;
1131 dir_hnd->conn = conn;
1133 dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, fsp->fsp_name);
1134 if (!dir_hnd->dir_smb_fname) {
1135 status = NT_STATUS_NO_MEMORY;
1136 goto fail;
1139 dir_hnd->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1140 if (dir_hnd->dir == NULL) {
1141 status = map_nt_error_from_unix(errno);
1142 goto fail;
1144 dir_hnd->fsp = fsp;
1145 if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
1146 dir_hnd->case_sensitive = true;
1147 } else {
1148 dir_hnd->case_sensitive = conn->case_sensitive;
1151 talloc_set_destructor(dir_hnd, smb_Dir_destructor);
1153 *_dir_hnd = dir_hnd;
1154 return NT_STATUS_OK;
1156 fail:
1157 TALLOC_FREE(dir_hnd);
1158 return status;
1162 /*******************************************************************
1163 Read from a directory.
1164 Return directory entry, current offset, and optional stat information.
1165 Don't check for veto or invisible files.
1166 ********************************************************************/
1168 const char *ReadDirName(struct smb_Dir *dir_hnd, char **ptalloced)
1170 const char *n;
1171 char *talloced = NULL;
1172 connection_struct *conn = dir_hnd->conn;
1174 if (dir_hnd->file_number < 2) {
1175 if (dir_hnd->file_number == 0) {
1176 n = ".";
1177 } else {
1178 n = "..";
1180 dir_hnd->file_number++;
1181 *ptalloced = NULL;
1182 return n;
1185 while ((n = vfs_readdirname(conn,
1186 dir_hnd->fsp,
1187 dir_hnd->dir,
1188 &talloced))) {
1189 /* Ignore . and .. - we've already returned them. */
1190 if (ISDOT(n) || ISDOTDOT(n)) {
1191 TALLOC_FREE(talloced);
1192 continue;
1194 *ptalloced = talloced;
1195 dir_hnd->file_number++;
1196 return n;
1198 *ptalloced = NULL;
1199 return NULL;
1202 /*******************************************************************
1203 Rewind to the start.
1204 ********************************************************************/
1206 void RewindDir(struct smb_Dir *dir_hnd)
1208 SMB_VFS_REWINDDIR(dir_hnd->conn, dir_hnd->dir);
1209 dir_hnd->file_number = 0;
1212 struct files_below_forall_state {
1213 char *dirpath;
1214 ssize_t dirpath_len;
1215 int (*fn)(struct file_id fid, const struct share_mode_data *data,
1216 void *private_data);
1217 void *private_data;
1220 static int files_below_forall_fn(struct file_id fid,
1221 const struct share_mode_data *data,
1222 void *private_data)
1224 struct files_below_forall_state *state = private_data;
1225 char tmpbuf[PATH_MAX];
1226 char *fullpath, *to_free;
1227 ssize_t len;
1229 len = full_path_tos(data->servicepath, data->base_name,
1230 tmpbuf, sizeof(tmpbuf),
1231 &fullpath, &to_free);
1232 if (len == -1) {
1233 return 0;
1235 if (state->dirpath_len >= len) {
1237 * Filter files above dirpath
1239 goto out;
1241 if (fullpath[state->dirpath_len] != '/') {
1243 * Filter file that don't have a path separator at the end of
1244 * dirpath's length
1246 goto out;
1249 if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
1251 * Not a parent
1253 goto out;
1256 TALLOC_FREE(to_free);
1257 return state->fn(fid, data, state->private_data);
1259 out:
1260 TALLOC_FREE(to_free);
1261 return 0;
1264 static int files_below_forall(connection_struct *conn,
1265 const struct smb_filename *dir_name,
1266 int (*fn)(struct file_id fid,
1267 const struct share_mode_data *data,
1268 void *private_data),
1269 void *private_data)
1271 struct files_below_forall_state state = {
1272 .fn = fn,
1273 .private_data = private_data,
1275 int ret;
1276 char tmpbuf[PATH_MAX];
1277 char *to_free;
1279 state.dirpath_len = full_path_tos(conn->connectpath,
1280 dir_name->base_name,
1281 tmpbuf, sizeof(tmpbuf),
1282 &state.dirpath, &to_free);
1283 if (state.dirpath_len == -1) {
1284 return -1;
1287 ret = share_mode_forall(files_below_forall_fn, &state);
1288 TALLOC_FREE(to_free);
1289 return ret;
1292 struct have_file_open_below_state {
1293 bool found_one;
1296 static int have_file_open_below_fn(struct file_id fid,
1297 const struct share_mode_data *data,
1298 void *private_data)
1300 struct have_file_open_below_state *state = private_data;
1301 state->found_one = true;
1302 return 1;
1305 bool have_file_open_below(connection_struct *conn,
1306 const struct smb_filename *name)
1308 struct have_file_open_below_state state = {
1309 .found_one = false,
1311 int ret;
1313 if (!VALID_STAT(name->st)) {
1314 return false;
1316 if (!S_ISDIR(name->st.st_ex_mode)) {
1317 return false;
1320 ret = files_below_forall(conn, name, have_file_open_below_fn, &state);
1321 if (ret == -1) {
1322 return false;
1325 return state.found_one;
1328 /*****************************************************************
1329 Is this directory empty ?
1330 *****************************************************************/
1332 NTSTATUS can_delete_directory_fsp(files_struct *fsp)
1334 NTSTATUS status = NT_STATUS_OK;
1335 const char *dname = NULL;
1336 char *talloced = NULL;
1337 struct connection_struct *conn = fsp->conn;
1338 struct smb_Dir *dir_hnd = NULL;
1340 status = OpenDir(
1341 talloc_tos(), conn, fsp->fsp_name, NULL, 0, &dir_hnd);
1342 if (!NT_STATUS_IS_OK(status)) {
1343 return status;
1346 while ((dname = ReadDirName(dir_hnd, &talloced))) {
1347 struct smb_filename *smb_dname_full = NULL;
1348 struct smb_filename *direntry_fname = NULL;
1349 char *fullname = NULL;
1350 int ret;
1352 if (ISDOT(dname) || (ISDOTDOT(dname))) {
1353 TALLOC_FREE(talloced);
1354 continue;
1356 if (IS_VETO_PATH(conn, dname)) {
1357 TALLOC_FREE(talloced);
1358 continue;
1361 fullname = talloc_asprintf(talloc_tos(),
1362 "%s/%s",
1363 fsp->fsp_name->base_name,
1364 dname);
1365 if (fullname == NULL) {
1366 status = NT_STATUS_NO_MEMORY;
1367 break;
1370 smb_dname_full = synthetic_smb_fname(talloc_tos(),
1371 fullname,
1372 NULL,
1373 NULL,
1374 fsp->fsp_name->twrp,
1375 fsp->fsp_name->flags);
1376 if (smb_dname_full == NULL) {
1377 TALLOC_FREE(talloced);
1378 TALLOC_FREE(fullname);
1379 status = NT_STATUS_NO_MEMORY;
1380 break;
1383 ret = SMB_VFS_LSTAT(conn, smb_dname_full);
1384 if (ret != 0) {
1385 status = map_nt_error_from_unix(errno);
1386 TALLOC_FREE(talloced);
1387 TALLOC_FREE(fullname);
1388 TALLOC_FREE(smb_dname_full);
1389 break;
1392 if (S_ISLNK(smb_dname_full->st.st_ex_mode)) {
1393 /* Could it be an msdfs link ? */
1394 if (lp_host_msdfs() &&
1395 lp_msdfs_root(SNUM(conn))) {
1396 struct smb_filename *smb_dname;
1397 smb_dname = synthetic_smb_fname(talloc_tos(),
1398 dname,
1399 NULL,
1400 &smb_dname_full->st,
1401 fsp->fsp_name->twrp,
1402 fsp->fsp_name->flags);
1403 if (smb_dname == NULL) {
1404 TALLOC_FREE(talloced);
1405 TALLOC_FREE(fullname);
1406 TALLOC_FREE(smb_dname_full);
1407 status = NT_STATUS_NO_MEMORY;
1408 break;
1410 if (is_msdfs_link(fsp, smb_dname)) {
1411 TALLOC_FREE(talloced);
1412 TALLOC_FREE(fullname);
1413 TALLOC_FREE(smb_dname_full);
1414 TALLOC_FREE(smb_dname);
1415 DBG_DEBUG("got msdfs link name %s "
1416 "- can't delete directory %s\n",
1417 dname,
1418 fsp_str_dbg(fsp));
1419 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1420 break;
1422 TALLOC_FREE(smb_dname);
1424 /* Not a DFS link - could it be a dangling symlink ? */
1425 ret = SMB_VFS_STAT(conn, smb_dname_full);
1426 if (ret == -1 && (errno == ENOENT || errno == ELOOP)) {
1428 * Dangling symlink.
1429 * Allow if "delete veto files = yes"
1431 if (lp_delete_veto_files(SNUM(conn))) {
1432 TALLOC_FREE(talloced);
1433 TALLOC_FREE(fullname);
1434 TALLOC_FREE(smb_dname_full);
1435 continue;
1438 DBG_DEBUG("got symlink name %s - "
1439 "can't delete directory %s\n",
1440 dname,
1441 fsp_str_dbg(fsp));
1442 TALLOC_FREE(talloced);
1443 TALLOC_FREE(fullname);
1444 TALLOC_FREE(smb_dname_full);
1445 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1446 break;
1449 /* Not a symlink, get a pathref. */
1450 status = synthetic_pathref(talloc_tos(),
1451 fsp,
1452 dname,
1453 NULL,
1454 &smb_dname_full->st,
1455 fsp->fsp_name->twrp,
1456 fsp->fsp_name->flags,
1457 &direntry_fname);
1458 if (!NT_STATUS_IS_OK(status)) {
1459 status = map_nt_error_from_unix(errno);
1460 TALLOC_FREE(talloced);
1461 TALLOC_FREE(fullname);
1462 TALLOC_FREE(smb_dname_full);
1463 break;
1466 if (!is_visible_fsp(direntry_fname->fsp)) {
1468 * Hidden file.
1469 * Allow if "delete veto files = yes"
1471 if (lp_delete_veto_files(SNUM(conn))) {
1472 TALLOC_FREE(talloced);
1473 TALLOC_FREE(fullname);
1474 TALLOC_FREE(smb_dname_full);
1475 TALLOC_FREE(direntry_fname);
1476 continue;
1480 TALLOC_FREE(talloced);
1481 TALLOC_FREE(fullname);
1482 TALLOC_FREE(smb_dname_full);
1483 TALLOC_FREE(direntry_fname);
1485 DBG_DEBUG("got name %s - can't delete\n", dname);
1486 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1487 break;
1489 TALLOC_FREE(talloced);
1490 TALLOC_FREE(dir_hnd);
1492 if (!NT_STATUS_IS_OK(status)) {
1493 return status;
1496 if (!(fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) &&
1497 lp_strict_rename(SNUM(conn)) &&
1498 have_file_open_below(fsp->conn, fsp->fsp_name))
1500 return NT_STATUS_ACCESS_DENIED;
1503 return NT_STATUS_OK;