smbd: Convert refuse_symlink_fsp() to bool
[samba4-gss.git] / source3 / smbd / dir.c
blob64a747f294f267205a239d348c620d0667494eb0
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"
33 #include "source3/include/serverid.h"
36 This module implements directory related functions for Samba.
39 /* "Special" directory offsets. */
40 #define END_OF_DIRECTORY_OFFSET ((long)-1)
41 #define START_OF_DIRECTORY_OFFSET ((long)0)
42 #define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
44 /* Make directory handle internals available. */
46 struct smb_Dir {
47 connection_struct *conn;
48 DIR *dir;
49 struct smb_filename *dir_smb_fname;
50 unsigned int file_number;
51 bool case_sensitive;
52 files_struct *fsp; /* Back pointer to containing fsp, only
53 set from OpenDir_fsp(). */
56 struct dptr_struct {
57 struct dptr_struct *next, *prev;
58 int dnum;
59 struct smb_Dir *dir_hnd;
60 char *wcard;
61 uint32_t attr;
62 bool has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
63 bool did_stat; /* Optimisation for non-wcard searches. */
64 bool priv; /* Directory handle opened with privilege. */
65 uint32_t counter;
67 char *last_name_sent; /* for name-based trans2 resume */
69 struct {
70 char *fname;
71 struct smb_filename *smb_fname;
72 uint32_t mode;
73 } overflow;
76 static NTSTATUS OpenDir_fsp(
77 TALLOC_CTX *mem_ctx,
78 connection_struct *conn,
79 files_struct *fsp,
80 const char *mask,
81 uint32_t attr,
82 struct smb_Dir **_dir_hnd);
84 static int smb_Dir_destructor(struct smb_Dir *dir_hnd);
86 #define INVALID_DPTR_KEY (-3)
88 /****************************************************************************
89 Initialise the dir bitmap.
90 ****************************************************************************/
92 bool init_dptrs(struct smbd_server_connection *sconn)
94 if (sconn->searches.dptr_bmap) {
95 return true;
98 sconn->searches.dptr_bmap = bitmap_talloc(
99 sconn, MAX_DIRECTORY_HANDLES);
101 if (sconn->searches.dptr_bmap == NULL) {
102 return false;
105 return true;
108 /****************************************************************************
109 Get the struct dptr_struct for a dir index.
110 ****************************************************************************/
112 static struct dptr_struct *dptr_get(struct smbd_server_connection *sconn,
113 int key)
115 struct dptr_struct *dptr;
117 for (dptr = sconn->searches.dirptrs; dptr != NULL; dptr = dptr->next) {
118 if(dptr->dnum != key) {
119 continue;
121 DLIST_PROMOTE(sconn->searches.dirptrs, dptr);
122 return dptr;
124 return(NULL);
127 /****************************************************************************
128 Get the dir path for a dir index.
129 ****************************************************************************/
131 const char *dptr_path(struct smbd_server_connection *sconn, int key)
133 struct dptr_struct *dptr = dptr_get(sconn, key);
134 if (dptr)
135 return(dptr->dir_hnd->dir_smb_fname->base_name);
136 return(NULL);
139 /****************************************************************************
140 Get the dir wcard for a dir index.
141 ****************************************************************************/
143 const char *dptr_wcard(struct smbd_server_connection *sconn, int key)
145 struct dptr_struct *dptr = dptr_get(sconn, key);
146 if (dptr)
147 return(dptr->wcard);
148 return(NULL);
151 /****************************************************************************
152 Get the dir attrib for a dir index.
153 ****************************************************************************/
155 uint16_t dptr_attr(struct smbd_server_connection *sconn, int key)
157 struct dptr_struct *dptr = dptr_get(sconn, key);
158 if (dptr)
159 return(dptr->attr);
160 return(0);
163 /****************************************************************************
164 Close all dptrs for a cnum.
165 ****************************************************************************/
167 void dptr_closecnum(connection_struct *conn)
169 struct dptr_struct *dptr, *next;
170 struct smbd_server_connection *sconn = conn->sconn;
172 if (sconn == NULL) {
173 return;
176 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
177 next = dptr->next;
178 if (dptr->dir_hnd->conn == conn) {
180 * Need to make a copy, "dptr" will be gone
181 * after close_file_free() returns
183 struct files_struct *fsp = dptr->dir_hnd->fsp;
184 close_file_free(NULL, &fsp, NORMAL_CLOSE);
189 /****************************************************************************
190 Create a new dir ptr. If the flag old_handle is true then we must allocate
191 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
192 one byte long. If old_handle is false we allocate from the range
193 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
194 a directory handle is never zero.
195 wcard must not be zero.
196 ****************************************************************************/
198 NTSTATUS dptr_create(connection_struct *conn,
199 struct smb_request *req,
200 files_struct *fsp,
201 bool old_handle,
202 const char *wcard,
203 uint32_t attr,
204 struct dptr_struct **dptr_ret)
206 struct smbd_server_connection *sconn = conn->sconn;
207 struct dptr_struct *dptr = NULL;
208 struct smb_Dir *dir_hnd = NULL;
209 NTSTATUS status;
211 DBG_INFO("dir=%s\n", fsp_str_dbg(fsp));
213 if (sconn == NULL) {
214 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
215 return NT_STATUS_INTERNAL_ERROR;
218 if (!wcard) {
219 return NT_STATUS_INVALID_PARAMETER;
222 status = check_any_access_fsp(fsp, SEC_DIR_LIST);
223 if (!NT_STATUS_IS_OK(status)) {
224 DBG_INFO("dptr_create: directory %s "
225 "not open for LIST access\n",
226 fsp_str_dbg(fsp));
227 return status;
229 status = OpenDir_fsp(NULL, conn, fsp, wcard, attr, &dir_hnd);
230 if (!NT_STATUS_IS_OK(status)) {
231 return status;
234 dptr = talloc_zero(NULL, struct dptr_struct);
235 if(!dptr) {
236 DEBUG(0,("talloc fail in dptr_create.\n"));
237 TALLOC_FREE(dir_hnd);
238 return NT_STATUS_NO_MEMORY;
241 dptr->dir_hnd = dir_hnd;
242 dptr->wcard = talloc_strdup(dptr, wcard);
243 if (!dptr->wcard) {
244 TALLOC_FREE(dptr);
245 TALLOC_FREE(dir_hnd);
246 return NT_STATUS_NO_MEMORY;
248 if ((req != NULL && req->posix_pathnames) || ISDOT(wcard)) {
249 dptr->has_wild = True;
250 } else {
251 dptr->has_wild = ms_has_wild(dptr->wcard);
254 dptr->attr = attr;
256 if (conn_using_smb2(sconn)) {
257 goto done;
260 if(old_handle) {
263 * This is an old-style SMBsearch request. Ensure the
264 * value we return will fit in the range 1-255.
267 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
269 if(dptr->dnum == -1 || dptr->dnum > 254) {
270 DBG_ERR("returned %d: Error - all old "
271 "dirptrs in use ?\n",
272 dptr->dnum);
273 TALLOC_FREE(dptr);
274 TALLOC_FREE(dir_hnd);
275 return NT_STATUS_TOO_MANY_OPENED_FILES;
277 } else {
280 * This is a new-style trans2 request. Allocate from
281 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
284 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
286 if(dptr->dnum == -1 || dptr->dnum < 255) {
287 DBG_ERR("returned %d: Error - all new "
288 "dirptrs in use ?\n",
289 dptr->dnum);
290 TALLOC_FREE(dptr);
291 TALLOC_FREE(dir_hnd);
292 return NT_STATUS_TOO_MANY_OPENED_FILES;
296 bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
298 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
300 DLIST_ADD(sconn->searches.dirptrs, dptr);
302 done:
303 DBG_INFO("creating new dirptr [%d] for path [%s]\n",
304 dptr->dnum, fsp_str_dbg(fsp));
306 *dptr_ret = dptr;
308 return NT_STATUS_OK;
312 /****************************************************************************
313 Wrapper functions to access the lower level directory handles.
314 ****************************************************************************/
316 void dptr_CloseDir(files_struct *fsp)
318 struct smbd_server_connection *sconn = NULL;
320 if (fsp->dptr == NULL) {
321 return;
323 sconn = fsp->conn->sconn;
326 * The destructor for the struct smb_Dir (fsp->dptr->dir_hnd)
327 * now handles all resource deallocation.
330 DBG_INFO("closing dptr key %d\n", fsp->dptr->dnum);
332 if (sconn != NULL && !conn_using_smb2(sconn)) {
333 DLIST_REMOVE(sconn->searches.dirptrs, fsp->dptr);
336 * Free the dnum in the bitmap. Remember the dnum value is
337 * always biased by one with respect to the bitmap.
340 if (!bitmap_query(sconn->searches.dptr_bmap,
341 fsp->dptr->dnum - 1))
343 DBG_ERR("closing dnum = %d and bitmap not set !\n",
344 fsp->dptr->dnum);
347 bitmap_clear(sconn->searches.dptr_bmap, fsp->dptr->dnum - 1);
350 TALLOC_FREE(fsp->dptr->dir_hnd);
351 TALLOC_FREE(fsp->dptr);
354 void dptr_RewindDir(struct dptr_struct *dptr)
356 RewindDir(dptr->dir_hnd);
357 dptr->did_stat = false;
358 TALLOC_FREE(dptr->overflow.fname);
359 TALLOC_FREE(dptr->overflow.smb_fname);
362 unsigned int dptr_FileNumber(struct dptr_struct *dptr)
364 return dptr->dir_hnd->file_number;
367 bool dptr_has_wild(struct dptr_struct *dptr)
369 return dptr->has_wild;
372 int dptr_dnum(struct dptr_struct *dptr)
374 return dptr->dnum;
377 bool dptr_get_priv(struct dptr_struct *dptr)
379 return dptr->priv;
382 void dptr_set_priv(struct dptr_struct *dptr)
384 dptr->priv = true;
387 bool dptr_case_sensitive(struct dptr_struct *dptr)
389 return dptr->dir_hnd->case_sensitive;
392 /****************************************************************************
393 Return the next visible file name, skipping veto'd and invisible files.
394 ****************************************************************************/
396 char *dptr_ReadDirName(TALLOC_CTX *ctx, struct dptr_struct *dptr)
398 struct stat_ex st = {
399 .st_ex_nlink = 0,
401 struct smb_Dir *dir_hnd = dptr->dir_hnd;
402 struct files_struct *dir_fsp = dir_hnd->fsp;
403 struct smb_filename *dir_name = dir_fsp->fsp_name;
404 struct smb_filename smb_fname_base;
405 bool retry_scanning = false;
406 int ret;
407 int flags = 0;
409 if (dptr->has_wild) {
410 const char *name_temp = NULL;
411 char *talloced = NULL;
412 name_temp = ReadDirName(dir_hnd, &talloced);
413 if (name_temp == NULL) {
414 return NULL;
416 if (talloced != NULL) {
417 return talloc_move(ctx, &talloced);
419 return talloc_strdup(ctx, name_temp);
422 if (dptr->did_stat) {
424 * No wildcard, this is not a real directory traverse
425 * but a "stat" call behind a query_directory. We've
426 * been here, nothing else to look at.
428 return NULL;
430 dptr->did_stat = true;
432 /* Create an smb_filename with stream_name == NULL. */
433 smb_fname_base = (struct smb_filename){
434 .base_name = dptr->wcard,
435 .flags = dir_name->flags,
436 .twrp = dir_name->twrp,
439 if (dir_name->flags & SMB_FILENAME_POSIX_PATH) {
440 flags |= AT_SYMLINK_NOFOLLOW;
443 ret = SMB_VFS_FSTATAT(
444 dir_hnd->conn, dir_fsp, &smb_fname_base, &st, flags);
445 if (ret == 0) {
446 return talloc_strdup(ctx, dptr->wcard);
450 * If we get any other error than ENOENT or ENOTDIR
451 * then the file exists, we just can't stat it.
453 if (errno != ENOENT && errno != ENOTDIR) {
454 return talloc_strdup(ctx, dptr->wcard);
458 * A scan will find the long version of a mangled name as
459 * wildcard.
461 retry_scanning |= mangle_is_mangled(dptr->wcard,
462 dir_hnd->conn->params);
465 * Also retry scanning if the client requested case
466 * insensitive semantics and the file system does not provide
467 * it.
469 retry_scanning |= (!dir_hnd->case_sensitive &&
470 (dir_hnd->conn->fs_capabilities &
471 FILE_CASE_SENSITIVE_SEARCH));
473 if (retry_scanning) {
474 char *found_name = NULL;
475 NTSTATUS status;
477 status = get_real_filename_at(dir_fsp,
478 dptr->wcard,
479 ctx,
480 &found_name);
481 if (NT_STATUS_IS_OK(status)) {
482 return found_name;
486 return NULL;
489 struct files_struct *dir_hnd_fetch_fsp(struct smb_Dir *dir_hnd)
491 return dir_hnd->fsp;
494 /****************************************************************************
495 Fetch the fsp associated with the dptr_num.
496 ****************************************************************************/
498 files_struct *dptr_fetch_lanman2_fsp(struct smbd_server_connection *sconn,
499 int dptr_num)
501 struct dptr_struct *dptr = dptr_get(sconn, dptr_num);
502 if (dptr == NULL) {
503 return NULL;
505 DBG_NOTICE("fetching dirptr %d for path %s\n",
506 dptr_num,
507 dptr->dir_hnd->dir_smb_fname->base_name);
508 return dptr->dir_hnd->fsp;
511 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
512 struct dptr_struct *dirptr,
513 const char *mask,
514 uint32_t dirtype,
515 bool dont_descend,
516 bool ask_sharemode,
517 bool get_dosmode_in,
518 bool (*match_fn)(TALLOC_CTX *ctx,
519 void *private_data,
520 const char *dname,
521 const char *mask,
522 char **_fname),
523 void *private_data,
524 char **_fname,
525 struct smb_filename **_smb_fname,
526 uint32_t *_mode)
528 struct smb_Dir *dir_hnd = dirptr->dir_hnd;
529 connection_struct *conn = dir_hnd->conn;
530 struct smb_filename *dir_fname = dir_hnd->dir_smb_fname;
531 bool posix = (dir_fname->flags & SMB_FILENAME_POSIX_PATH);
532 const bool toplevel = ISDOT(dir_fname->base_name);
533 NTSTATUS status;
535 *_smb_fname = NULL;
536 *_mode = 0;
538 if (dirptr->overflow.smb_fname != NULL) {
539 *_fname = talloc_move(ctx, &dirptr->overflow.fname);
540 *_smb_fname = talloc_move(ctx, &dirptr->overflow.smb_fname);
541 *_mode = dirptr->overflow.mode;
542 return true;
545 if (dont_descend && (dptr_FileNumber(dirptr) >= 2)) {
547 * . and .. were returned first, we're done showing
548 * the directory as empty.
550 return false;
553 while (true) {
554 char *dname = NULL;
555 char *fname = NULL;
556 struct smb_filename *smb_fname = NULL;
557 uint32_t mode = 0;
558 bool get_dosmode = get_dosmode_in;
559 bool toplevel_dotdot;
560 bool visible;
561 bool ok;
563 dname = dptr_ReadDirName(ctx, dirptr);
565 DBG_DEBUG("dir [%s] dirptr [%p] offset [%u] => "
566 "dname [%s]\n",
567 smb_fname_str_dbg(dir_fname),
568 dirptr,
569 dir_hnd->file_number,
570 dname ? dname : "(finished)");
572 if (dname == NULL) {
573 return false;
576 if (IS_VETO_PATH(conn, dname)) {
577 TALLOC_FREE(dname);
578 continue;
582 * fname may get mangled, dname is never mangled.
583 * Whenever we're accessing the filesystem we use
584 * pathreal which is composed from dname.
587 ok = match_fn(ctx, private_data, dname, mask, &fname);
588 if (!ok) {
589 TALLOC_FREE(dname);
590 continue;
593 toplevel_dotdot = toplevel && ISDOTDOT(dname);
595 smb_fname = synthetic_smb_fname(talloc_tos(),
596 toplevel_dotdot ? "." : dname,
597 NULL,
598 NULL,
599 dir_fname->twrp,
600 dir_fname->flags);
601 if (smb_fname == NULL) {
602 TALLOC_FREE(dname);
603 return false;
607 * UCF_POSIX_PATHNAMES to avoid the readdir fallback
608 * if we get raced between readdir and unlink.
610 status = openat_pathref_fsp_lcomp(dir_hnd->fsp,
611 smb_fname,
612 UCF_POSIX_PATHNAMES);
613 if (!NT_STATUS_IS_OK(status)) {
614 DBG_DEBUG("Could not open %s: %s\n",
615 dname,
616 nt_errstr(status));
617 TALLOC_FREE(smb_fname);
618 TALLOC_FREE(fname);
619 TALLOC_FREE(dname);
620 continue;
623 visible = is_visible_fsp(smb_fname->fsp);
624 if (!visible) {
625 TALLOC_FREE(smb_fname);
626 TALLOC_FREE(fname);
627 TALLOC_FREE(dname);
628 continue;
631 if (!S_ISLNK(smb_fname->st.st_ex_mode)) {
632 goto done;
635 if (lp_host_msdfs() && lp_msdfs_root(SNUM(conn)) &&
636 is_msdfs_link(dir_hnd->fsp, smb_fname))
638 DBG_INFO("Masquerading msdfs link %s as a directory\n",
639 smb_fname->base_name);
641 smb_fname->st.st_ex_mode = (smb_fname->st.st_ex_mode &
642 ~S_IFMT) |
643 S_IFDIR;
645 mode = dos_mode_msdfs(conn, dname, &smb_fname->st);
646 get_dosmode = false;
647 ask_sharemode = false;
648 goto done;
651 if (posix) {
653 * Posix always wants to see symlinks.
655 ask_sharemode = false;
656 goto done;
659 if (!lp_follow_symlinks(SNUM(conn))) {
661 * Hide symlinks not followed
663 TALLOC_FREE(smb_fname);
664 TALLOC_FREE(fname);
665 TALLOC_FREE(dname);
666 continue;
670 * We have to find out if it's a dangling
671 * symlink. Use the fat logic behind
672 * openat_pathref_fsp().
676 struct files_struct *fsp = smb_fname->fsp;
677 smb_fname_fsp_unlink(smb_fname);
678 fd_close(fsp);
679 file_free(NULL, fsp);
682 status = openat_pathref_fsp(dir_hnd->fsp, smb_fname);
684 if (!NT_STATUS_IS_OK(status)) {
686 * Dangling symlink. Hide.
688 TALLOC_FREE(smb_fname);
689 TALLOC_FREE(fname);
690 TALLOC_FREE(dname);
691 continue;
694 done:
695 if (get_dosmode) {
696 mode = fdos_mode(smb_fname->fsp);
697 smb_fname->st = smb_fname->fsp->fsp_name->st;
700 if (!dir_check_ftype(mode, dirtype)) {
701 DBG_INFO("[%s] attribs 0x%" PRIx32 " didn't match "
702 "0x%" PRIx32 "\n",
703 fname,
704 mode,
705 dirtype);
706 TALLOC_FREE(smb_fname);
707 TALLOC_FREE(dname);
708 TALLOC_FREE(fname);
709 continue;
712 if (ask_sharemode && !S_ISDIR(smb_fname->st.st_ex_mode)) {
713 struct timespec write_time_ts;
714 struct file_id fileid;
716 fileid = vfs_file_id_from_sbuf(conn,
717 &smb_fname->st);
718 get_file_infos(fileid, 0, NULL, &write_time_ts);
719 if (!is_omit_timespec(&write_time_ts)) {
720 update_stat_ex_mtime(&smb_fname->st,
721 write_time_ts);
725 if (toplevel_dotdot) {
727 * Ensure posix fileid and sids are hidden
729 smb_fname->st.st_ex_ino = 0;
730 smb_fname->st.st_ex_dev = 0;
731 smb_fname->st.st_ex_uid = -1;
732 smb_fname->st.st_ex_gid = -1;
735 DBG_NOTICE("mask=[%s] found %s fname=%s (%s)\n",
736 mask,
737 smb_fname_str_dbg(smb_fname),
738 dname,
739 fname);
741 TALLOC_FREE(dname);
743 *_smb_fname = talloc_move(ctx, &smb_fname);
744 *_fname = fname;
745 *_mode = mode;
747 return true;
750 return false;
753 void smbd_dirptr_push_overflow(struct dptr_struct *dirptr,
754 char **_fname,
755 struct smb_filename **_smb_fname,
756 uint32_t mode)
758 SMB_ASSERT(dirptr->overflow.fname == NULL);
759 SMB_ASSERT(dirptr->overflow.smb_fname == NULL);
761 dirptr->overflow.fname = talloc_move(dirptr, _fname);
762 dirptr->overflow.smb_fname = talloc_move(dirptr, _smb_fname);
763 dirptr->overflow.mode = mode;
766 void smbd_dirptr_set_last_name_sent(struct dptr_struct *dirptr,
767 char **_fname)
769 TALLOC_FREE(dirptr->last_name_sent);
770 dirptr->last_name_sent = talloc_move(dirptr, _fname);
773 char *smbd_dirptr_get_last_name_sent(struct dptr_struct *dirptr)
775 return dirptr->last_name_sent;
778 /*******************************************************************
779 Check to see if a user can read an fsp . This is only approximate,
780 it is used as part of the "hide unreadable" option. Don't
781 use it for anything security sensitive.
782 ********************************************************************/
784 static bool user_can_read_fsp(struct files_struct *fsp)
786 NTSTATUS status;
787 uint32_t rejected_share_access = 0;
788 uint32_t rejected_mask = 0;
789 struct security_descriptor *sd = NULL;
790 uint32_t access_mask = FILE_READ_DATA|
791 FILE_READ_EA|
792 FILE_READ_ATTRIBUTES|
793 SEC_STD_READ_CONTROL;
796 * Never hide files from the root user.
797 * We use (uid_t)0 here not sec_initial_uid()
798 * as make test uses a single user context.
801 if (get_current_uid(fsp->conn) == (uid_t)0) {
802 return true;
806 * We can't directly use smbd_check_access_rights_fsp()
807 * here, as this implicitly grants FILE_READ_ATTRIBUTES
808 * which the Windows access-based-enumeration code
809 * explicitly checks for on the file security descriptor.
810 * See bug:
812 * https://bugzilla.samba.org/show_bug.cgi?id=10252
814 * and the smb2.acl2.ACCESSBASED test for details.
817 rejected_share_access = access_mask & ~(fsp->conn->share_access);
818 if (rejected_share_access) {
819 DBG_DEBUG("rejected share access 0x%x "
820 "on %s (0x%x)\n",
821 (unsigned int)access_mask,
822 fsp_str_dbg(fsp),
823 (unsigned int)rejected_share_access);
824 return false;
827 status = SMB_VFS_FGET_NT_ACL(metadata_fsp(fsp),
828 (SECINFO_OWNER |
829 SECINFO_GROUP |
830 SECINFO_DACL),
831 talloc_tos(),
832 &sd);
834 if (!NT_STATUS_IS_OK(status)) {
835 DBG_DEBUG("Could not get acl "
836 "on %s: %s\n",
837 fsp_str_dbg(fsp),
838 nt_errstr(status));
839 return false;
842 status = se_file_access_check(sd,
843 get_current_nttok(fsp->conn),
844 false,
845 access_mask,
846 &rejected_mask);
848 TALLOC_FREE(sd);
850 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
851 DBG_DEBUG("rejected bits 0x%x read access for %s\n",
852 (unsigned int)rejected_mask,
853 fsp_str_dbg(fsp));
854 return false;
856 return true;
859 /*******************************************************************
860 Check to see if a user can write to an fsp.
861 Always return true for directories.
862 This is only approximate,
863 it is used as part of the "hide unwriteable" option. Don't
864 use it for anything security sensitive.
865 ********************************************************************/
867 static bool user_can_write_fsp(struct files_struct *fsp)
870 * Never hide files from the root user.
871 * We use (uid_t)0 here not sec_initial_uid()
872 * as make test uses a single user context.
875 if (get_current_uid(fsp->conn) == (uid_t)0) {
876 return true;
879 if (fsp->fsp_flags.is_directory) {
880 return true;
883 return can_write_to_fsp(fsp);
886 /*******************************************************************
887 Is a file a "special" type ?
888 ********************************************************************/
890 static bool file_is_special(connection_struct *conn,
891 const struct smb_filename *smb_fname)
894 * Never hide files from the root user.
895 * We use (uid_t)0 here not sec_initial_uid()
896 * as make test uses a single user context.
899 if (get_current_uid(conn) == (uid_t)0) {
900 return False;
903 SMB_ASSERT(VALID_STAT(smb_fname->st));
905 if (S_ISREG(smb_fname->st.st_ex_mode) ||
906 S_ISDIR(smb_fname->st.st_ex_mode) ||
907 S_ISLNK(smb_fname->st.st_ex_mode))
908 return False;
910 return True;
913 /*******************************************************************
914 Should the file be seen by the client?
915 ********************************************************************/
917 bool is_visible_fsp(struct files_struct *fsp)
919 bool hide_unreadable = false;
920 bool hide_unwriteable = false;
921 bool hide_special = false;
922 int hide_new_files_timeout = 0;
923 const char *last_component = NULL;
925 hide_unreadable = lp_hide_unreadable(SNUM(fsp->conn));
926 hide_unwriteable = lp_hide_unwriteable_files(SNUM(fsp->conn));
927 hide_special = lp_hide_special_files(SNUM(fsp->conn));
928 hide_new_files_timeout = lp_hide_new_files_timeout(SNUM(fsp->conn));
930 if (!hide_unreadable &&
931 !hide_unwriteable &&
932 !hide_special &&
933 (hide_new_files_timeout == 0))
935 return true;
938 fsp = metadata_fsp(fsp);
940 /* Get the last component of the base name. */
941 last_component = strrchr_m(fsp->fsp_name->base_name, '/');
942 if (!last_component) {
943 last_component = fsp->fsp_name->base_name;
944 } else {
945 last_component++; /* Go past '/' */
948 if (ISDOT(last_component) || ISDOTDOT(last_component)) {
949 return true; /* . and .. are always visible. */
952 if (fsp_get_pathref_fd(fsp) == -1) {
954 * Symlink in POSIX mode or MS-DFS.
955 * We've checked veto files so the
956 * only thing we can check is the
957 * hide_new_files_timeout.
959 if ((hide_new_files_timeout != 0) &&
960 !S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
961 double age = timespec_elapsed(
962 &fsp->fsp_name->st.st_ex_mtime);
964 if (age < (double)hide_new_files_timeout) {
965 return false;
968 return true;
971 /* Honour _hide unreadable_ option */
972 if (hide_unreadable && !user_can_read_fsp(fsp)) {
973 DBG_DEBUG("file %s is unreadable.\n", fsp_str_dbg(fsp));
974 return false;
977 /* Honour _hide unwriteable_ option */
978 if (hide_unwriteable && !user_can_write_fsp(fsp)) {
979 DBG_DEBUG("file %s is unwritable.\n", fsp_str_dbg(fsp));
980 return false;
983 /* Honour _hide_special_ option */
984 if (hide_special && file_is_special(fsp->conn, fsp->fsp_name)) {
985 DBG_DEBUG("file %s is special.\n", fsp_str_dbg(fsp));
986 return false;
989 if ((hide_new_files_timeout != 0) &&
990 !S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
991 double age = timespec_elapsed(&fsp->fsp_name->st.st_ex_mtime);
993 if (age < (double)hide_new_files_timeout) {
994 return false;
998 return true;
1001 static int smb_Dir_destructor(struct smb_Dir *dir_hnd)
1003 files_struct *fsp = dir_hnd->fsp;
1005 SMB_VFS_CLOSEDIR(dir_hnd->conn, dir_hnd->dir);
1006 fsp_set_fd(fsp, -1);
1007 if (fsp->dptr != NULL) {
1008 SMB_ASSERT(fsp->dptr->dir_hnd == dir_hnd);
1009 fsp->dptr->dir_hnd = NULL;
1011 dir_hnd->fsp = NULL;
1012 return 0;
1015 /*******************************************************************
1016 Open a directory.
1017 ********************************************************************/
1019 static int smb_Dir_OpenDir_destructor(struct smb_Dir *dir_hnd)
1021 files_struct *fsp = dir_hnd->fsp;
1023 smb_Dir_destructor(dir_hnd);
1024 file_free(NULL, fsp);
1025 return 0;
1028 NTSTATUS OpenDir(TALLOC_CTX *mem_ctx,
1029 connection_struct *conn,
1030 const struct smb_filename *smb_dname,
1031 const char *mask,
1032 uint32_t attr,
1033 struct smb_Dir **_dir_hnd)
1035 struct files_struct *fsp = NULL;
1036 struct smb_Dir *dir_hnd = NULL;
1037 NTSTATUS status;
1039 status = open_internal_dirfsp(conn,
1040 smb_dname,
1041 O_RDONLY,
1042 &fsp);
1043 if (!NT_STATUS_IS_OK(status)) {
1044 return status;
1047 status = OpenDir_fsp(mem_ctx, conn, fsp, mask, attr, &dir_hnd);
1048 if (!NT_STATUS_IS_OK(status)) {
1049 return status;
1053 * This overwrites the destructor set by OpenDir_fsp() but
1054 * smb_Dir_OpenDir_destructor() calls the OpenDir_fsp()
1055 * destructor.
1057 talloc_set_destructor(dir_hnd, smb_Dir_OpenDir_destructor);
1059 *_dir_hnd = dir_hnd;
1060 return NT_STATUS_OK;
1063 NTSTATUS OpenDir_from_pathref(TALLOC_CTX *mem_ctx,
1064 struct files_struct *dirfsp,
1065 const char *mask,
1066 uint32_t attr,
1067 struct smb_Dir **_dir_hnd)
1069 struct files_struct *fsp = NULL;
1070 struct smb_Dir *dir_hnd = NULL;
1071 NTSTATUS status;
1073 status = openat_internal_dir_from_pathref(dirfsp, O_RDONLY, &fsp);
1074 if (!NT_STATUS_IS_OK(status)) {
1075 return status;
1078 status = OpenDir_fsp(mem_ctx, fsp->conn, fsp, mask, attr, &dir_hnd);
1079 if (!NT_STATUS_IS_OK(status)) {
1080 return status;
1084 * This overwrites the destructor set by OpenDir_fsp() but
1085 * smb_Dir_OpenDir_destructor() calls the OpenDir_fsp()
1086 * destructor.
1088 talloc_set_destructor(dir_hnd, smb_Dir_OpenDir_destructor);
1090 *_dir_hnd = dir_hnd;
1091 return NT_STATUS_OK;
1094 /*******************************************************************
1095 Open a directory from an fsp.
1096 ********************************************************************/
1098 static NTSTATUS OpenDir_fsp(
1099 TALLOC_CTX *mem_ctx,
1100 connection_struct *conn,
1101 files_struct *fsp,
1102 const char *mask,
1103 uint32_t attr,
1104 struct smb_Dir **_dir_hnd)
1106 struct smb_Dir *dir_hnd = talloc_zero(mem_ctx, struct smb_Dir);
1107 NTSTATUS status;
1109 if (!dir_hnd) {
1110 return NT_STATUS_NO_MEMORY;
1113 if (!fsp->fsp_flags.is_directory) {
1114 status = NT_STATUS_INVALID_HANDLE;
1115 goto fail;
1118 if (fsp_get_io_fd(fsp) == -1) {
1119 status = NT_STATUS_INVALID_HANDLE;
1120 goto fail;
1123 dir_hnd->conn = conn;
1125 dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, fsp->fsp_name);
1126 if (!dir_hnd->dir_smb_fname) {
1127 status = NT_STATUS_NO_MEMORY;
1128 goto fail;
1131 dir_hnd->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1132 if (dir_hnd->dir == NULL) {
1133 status = map_nt_error_from_unix(errno);
1134 goto fail;
1136 dir_hnd->fsp = fsp;
1137 if (fsp->fsp_flags.posix_open) {
1138 dir_hnd->case_sensitive = true;
1139 } else {
1140 dir_hnd->case_sensitive = conn->case_sensitive;
1143 talloc_set_destructor(dir_hnd, smb_Dir_destructor);
1145 *_dir_hnd = dir_hnd;
1146 return NT_STATUS_OK;
1148 fail:
1149 TALLOC_FREE(dir_hnd);
1150 return status;
1154 /*******************************************************************
1155 Read from a directory.
1156 Return directory entry, current offset, and optional stat information.
1157 Don't check for veto or invisible files.
1158 ********************************************************************/
1160 const char *ReadDirName(struct smb_Dir *dir_hnd, char **ptalloced)
1162 const char *n;
1163 char *talloced = NULL;
1164 connection_struct *conn = dir_hnd->conn;
1166 if (dir_hnd->file_number < 2) {
1167 if (dir_hnd->file_number == 0) {
1168 n = ".";
1169 } else {
1170 n = "..";
1172 dir_hnd->file_number++;
1173 *ptalloced = NULL;
1174 return n;
1177 while ((n = vfs_readdirname(conn,
1178 dir_hnd->fsp,
1179 dir_hnd->dir,
1180 &talloced))) {
1181 int unlink_flags = INT_MAX;
1182 /* Ignore . and .. - we've already returned them. */
1183 if (ISDOT(n) || ISDOTDOT(n)) {
1184 TALLOC_FREE(talloced);
1185 continue;
1188 * ignore tmp directories, see mkdir_internals()
1190 if (IS_SMBD_TMPNAME(n, &unlink_flags)) {
1191 struct smb_filename *atname = NULL;
1192 const char *fp = NULL;
1193 int ret;
1195 atname = synthetic_smb_fname(talloc_tos(),
1197 NULL,
1198 NULL,
1201 if (atname == NULL) {
1202 TALLOC_FREE(talloced);
1203 continue;
1205 fp = full_path_from_dirfsp_at_basename(atname,
1206 dir_hnd->fsp,
1208 if (fp == NULL) {
1209 TALLOC_FREE(atname);
1210 TALLOC_FREE(talloced);
1211 continue;
1214 if (unlink_flags == INT_MAX) {
1215 DBG_NOTICE("ignoring %s\n", fp);
1216 TALLOC_FREE(atname);
1217 TALLOC_FREE(talloced);
1218 continue;
1222 * We remove the stale tmpname
1223 * as root and ignore any errors
1225 DBG_NOTICE("unlink stale %s\n", fp);
1226 become_root();
1227 ret = SMB_VFS_UNLINKAT(conn,
1228 dir_hnd->fsp,
1229 atname,
1230 unlink_flags);
1231 unbecome_root();
1232 if (ret == 0) {
1233 DBG_NOTICE("unlinked stale %s\n", fp);
1234 } else {
1235 DBG_WARNING("failed to unlink stale %s: %s\n",
1236 fp, strerror(errno));
1238 TALLOC_FREE(atname);
1239 TALLOC_FREE(talloced);
1240 continue;
1242 *ptalloced = talloced;
1243 dir_hnd->file_number++;
1244 return n;
1246 *ptalloced = NULL;
1247 return NULL;
1250 /*******************************************************************
1251 Rewind to the start.
1252 ********************************************************************/
1254 void RewindDir(struct smb_Dir *dir_hnd)
1256 SMB_VFS_REWINDDIR(dir_hnd->conn, dir_hnd->dir);
1257 dir_hnd->file_number = 0;
1260 struct have_file_open_below_state {
1261 bool found_one;
1264 static int have_file_open_below_fn(const struct share_mode_data *data,
1265 const struct share_mode_entry *e,
1266 void *private_data)
1268 struct have_file_open_below_state *state = private_data;
1269 bool exists;
1271 if (e->stale) {
1272 return 0;
1275 if (e->flags & SHARE_MODE_FLAG_POSIX_OPEN) {
1276 /* Ignore POSIX opens */
1277 return 0;
1280 exists = serverid_exists(&e->pid);
1281 if (!exists) {
1282 return 0;
1285 state->found_one = true;
1286 return -1;
1289 bool have_file_open_below(struct files_struct *fsp)
1291 struct have_file_open_below_state state = {
1292 .found_one = false,
1294 int ret;
1296 if (!lp_strict_rename(SNUM(fsp->conn))) {
1297 if (file_find_subpath(fsp)) {
1298 return true;
1300 return false;
1303 if (!VALID_STAT(fsp->fsp_name->st)) {
1304 return false;
1306 if (!S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
1307 return false;
1310 ret = opens_below_forall_read(fsp->conn,
1311 fsp->fsp_name,
1312 have_file_open_below_fn,
1313 &state);
1314 if (ret == -1) {
1315 return false;
1318 return state.found_one;
1321 struct opens_below_forall_read_state {
1322 char *dirpath;
1323 ssize_t dirpath_len;
1324 int (*fn)(const struct share_mode_data *data,
1325 const struct share_mode_entry *e,
1326 void *private_data);
1327 void *private_data;
1330 static int opens_below_forall_read_fn(struct file_id fid,
1331 const struct share_mode_data *data,
1332 const struct share_mode_entry *entry,
1333 void *private_data)
1335 struct opens_below_forall_read_state *state = private_data;
1336 char tmpbuf[PATH_MAX];
1337 char *fullpath = NULL;
1338 char *to_free = NULL;
1339 ssize_t len;
1341 len = full_path_tos(data->servicepath,
1342 data->base_name,
1343 tmpbuf,
1344 sizeof(tmpbuf),
1345 &fullpath,
1346 &to_free);
1347 if (len == -1) {
1348 return -1;
1350 if (state->dirpath_len >= len) {
1352 * Filter files above dirpath
1354 goto out;
1356 if (fullpath[state->dirpath_len] != '/') {
1358 * Filter file that don't have a path separator at the end of
1359 * dirpath's length
1361 goto out;
1364 if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
1366 * Not a parent
1368 goto out;
1371 TALLOC_FREE(to_free);
1372 return state->fn(data, entry, state->private_data);
1374 out:
1375 TALLOC_FREE(to_free);
1376 return 1;
1379 bool opens_below_forall_read(struct connection_struct *conn,
1380 const struct smb_filename *dir_name,
1381 int (*fn)(const struct share_mode_data *data,
1382 const struct share_mode_entry *e,
1383 void *private_data),
1384 void *private_data)
1386 struct opens_below_forall_read_state state = {
1387 .fn = fn,
1388 .private_data = private_data,
1390 int ret;
1391 char tmpbuf[PATH_MAX];
1392 char *to_free = NULL;
1394 state.dirpath_len = full_path_tos(conn->connectpath,
1395 dir_name->base_name,
1396 tmpbuf,
1397 sizeof(tmpbuf),
1398 &state.dirpath,
1399 &to_free);
1400 if (state.dirpath_len == -1) {
1401 return false;
1404 ret = share_entry_forall_read(opens_below_forall_read_fn, &state);
1405 TALLOC_FREE(to_free);
1406 if (ret == -1) {
1407 return false;
1409 return true;
1412 struct opens_below_forall_state {
1413 char *dirpath;
1414 ssize_t dirpath_len;
1415 int (*fn)(struct share_mode_data *data,
1416 struct share_mode_entry *e,
1417 void *private_data);
1418 void *private_data;
1421 static int opens_below_forall_fn(struct file_id fid,
1422 struct share_mode_data *data,
1423 struct share_mode_entry *entry,
1424 void *private_data)
1426 struct opens_below_forall_state *state = private_data;
1427 char tmpbuf[PATH_MAX];
1428 char *fullpath = NULL;
1429 char *to_free = NULL;
1430 ssize_t len;
1432 len = full_path_tos(data->servicepath,
1433 data->base_name,
1434 tmpbuf,
1435 sizeof(tmpbuf),
1436 &fullpath,
1437 &to_free);
1438 if (len == -1) {
1439 return -1;
1441 if (state->dirpath_len >= len) {
1443 * Filter files above dirpath
1445 goto out;
1447 if (fullpath[state->dirpath_len] != '/') {
1449 * Filter file that don't have a path separator at the end of
1450 * dirpath's length
1452 goto out;
1455 if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
1457 * Not a parent
1459 goto out;
1462 TALLOC_FREE(to_free);
1463 return state->fn(data, entry, state->private_data);
1465 out:
1466 TALLOC_FREE(to_free);
1467 return 1;
1470 bool opens_below_forall(struct connection_struct *conn,
1471 const struct smb_filename *dir_name,
1472 int (*fn)(struct share_mode_data *data,
1473 struct share_mode_entry *e,
1474 void *private_data),
1475 void *private_data)
1477 struct opens_below_forall_state state = {
1478 .fn = fn,
1479 .private_data = private_data,
1481 int ret;
1482 char tmpbuf[PATH_MAX];
1483 char *to_free = NULL;
1485 state.dirpath_len = full_path_tos(conn->connectpath,
1486 dir_name->base_name,
1487 tmpbuf,
1488 sizeof(tmpbuf),
1489 &state.dirpath,
1490 &to_free);
1491 if (state.dirpath_len == -1) {
1492 return false;
1495 ret = share_entry_forall(opens_below_forall_fn, &state);
1496 TALLOC_FREE(to_free);
1497 if (ret == -1) {
1498 return false;
1500 return true;
1503 /*****************************************************************
1504 Is this directory empty ?
1505 *****************************************************************/
1507 NTSTATUS can_delete_directory_fsp(files_struct *fsp)
1509 NTSTATUS status = NT_STATUS_OK;
1510 const char *dname = NULL;
1511 char *talloced = NULL;
1512 struct connection_struct *conn = fsp->conn;
1513 struct smb_Dir *dir_hnd = NULL;
1515 status = OpenDir(
1516 talloc_tos(), conn, fsp->fsp_name, NULL, 0, &dir_hnd);
1517 if (!NT_STATUS_IS_OK(status)) {
1518 return status;
1521 while ((dname = ReadDirName(dir_hnd, &talloced))) {
1522 struct smb_filename *smb_dname_full = NULL;
1523 struct smb_filename *direntry_fname = NULL;
1524 char *fullname = NULL;
1525 int ret;
1527 if (ISDOT(dname) || (ISDOTDOT(dname))) {
1528 TALLOC_FREE(talloced);
1529 continue;
1531 if (IS_VETO_PATH(conn, dname)) {
1532 TALLOC_FREE(talloced);
1533 continue;
1536 fullname = talloc_asprintf(talloc_tos(),
1537 "%s/%s",
1538 fsp->fsp_name->base_name,
1539 dname);
1540 if (fullname == NULL) {
1541 status = NT_STATUS_NO_MEMORY;
1542 break;
1545 smb_dname_full = synthetic_smb_fname(talloc_tos(),
1546 fullname,
1547 NULL,
1548 NULL,
1549 fsp->fsp_name->twrp,
1550 fsp->fsp_name->flags);
1551 if (smb_dname_full == NULL) {
1552 TALLOC_FREE(talloced);
1553 TALLOC_FREE(fullname);
1554 status = NT_STATUS_NO_MEMORY;
1555 break;
1558 ret = SMB_VFS_LSTAT(conn, smb_dname_full);
1559 if (ret != 0) {
1560 status = map_nt_error_from_unix(errno);
1561 TALLOC_FREE(talloced);
1562 TALLOC_FREE(fullname);
1563 TALLOC_FREE(smb_dname_full);
1564 break;
1567 if (S_ISLNK(smb_dname_full->st.st_ex_mode)) {
1568 /* Could it be an msdfs link ? */
1569 if (lp_host_msdfs() &&
1570 lp_msdfs_root(SNUM(conn))) {
1571 struct smb_filename *smb_dname;
1572 smb_dname = synthetic_smb_fname(talloc_tos(),
1573 dname,
1574 NULL,
1575 &smb_dname_full->st,
1576 fsp->fsp_name->twrp,
1577 fsp->fsp_name->flags);
1578 if (smb_dname == NULL) {
1579 TALLOC_FREE(talloced);
1580 TALLOC_FREE(fullname);
1581 TALLOC_FREE(smb_dname_full);
1582 status = NT_STATUS_NO_MEMORY;
1583 break;
1585 if (is_msdfs_link(fsp, smb_dname)) {
1586 TALLOC_FREE(talloced);
1587 TALLOC_FREE(fullname);
1588 TALLOC_FREE(smb_dname_full);
1589 TALLOC_FREE(smb_dname);
1590 DBG_DEBUG("got msdfs link name %s "
1591 "- can't delete directory %s\n",
1592 dname,
1593 fsp_str_dbg(fsp));
1594 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1595 break;
1597 TALLOC_FREE(smb_dname);
1599 /* Not a DFS link - could it be a dangling symlink ? */
1600 ret = SMB_VFS_STAT(conn, smb_dname_full);
1601 if (ret == -1 && (errno == ENOENT || errno == ELOOP)) {
1603 * Dangling symlink.
1604 * Allow if "delete veto files = yes"
1606 if (lp_delete_veto_files(SNUM(conn))) {
1607 TALLOC_FREE(talloced);
1608 TALLOC_FREE(fullname);
1609 TALLOC_FREE(smb_dname_full);
1610 continue;
1613 DBG_DEBUG("got symlink name %s - "
1614 "can't delete directory %s\n",
1615 dname,
1616 fsp_str_dbg(fsp));
1617 TALLOC_FREE(talloced);
1618 TALLOC_FREE(fullname);
1619 TALLOC_FREE(smb_dname_full);
1620 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1621 break;
1624 /* Not a symlink, get a pathref. */
1625 status = synthetic_pathref(talloc_tos(),
1626 fsp,
1627 dname,
1628 NULL,
1629 &smb_dname_full->st,
1630 fsp->fsp_name->twrp,
1631 fsp->fsp_name->flags,
1632 &direntry_fname);
1633 if (!NT_STATUS_IS_OK(status)) {
1634 status = map_nt_error_from_unix(errno);
1635 TALLOC_FREE(talloced);
1636 TALLOC_FREE(fullname);
1637 TALLOC_FREE(smb_dname_full);
1638 break;
1641 if (!is_visible_fsp(direntry_fname->fsp)) {
1643 * Hidden file.
1644 * Allow if "delete veto files = yes"
1646 if (lp_delete_veto_files(SNUM(conn))) {
1647 TALLOC_FREE(talloced);
1648 TALLOC_FREE(fullname);
1649 TALLOC_FREE(smb_dname_full);
1650 TALLOC_FREE(direntry_fname);
1651 continue;
1655 TALLOC_FREE(talloced);
1656 TALLOC_FREE(fullname);
1657 TALLOC_FREE(smb_dname_full);
1658 TALLOC_FREE(direntry_fname);
1660 DBG_DEBUG("got name %s - can't delete\n", dname);
1661 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1662 break;
1664 TALLOC_FREE(talloced);
1665 TALLOC_FREE(dir_hnd);
1667 if (!NT_STATUS_IS_OK(status)) {
1668 return status;
1671 if (have_file_open_below(fsp)) {
1672 return NT_STATUS_ACCESS_DENIED;
1675 return NT_STATUS_OK;