2 * Store Windows ACLs in data store - common functions.
3 * #included into modules/vfs_acl_xattr.c and modules/vfs_acl_tdb.c
5 * Copyright (C) Volker Lendecke, 2008
6 * Copyright (C) Jeremy Allison, 2009
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "smbd/smbd.h"
23 #include "system/filesys.h"
24 #include "../libcli/security/security.h"
25 #include "../librpc/gen_ndr/ndr_security.h"
26 #include "../lib/util/bitmap.h"
28 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
31 uint8_t hash[XATTR_SD_HASH_SIZE]);
33 static NTSTATUS get_acl_blob(TALLOC_CTX *ctx,
34 vfs_handle_struct *handle,
39 static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle,
43 #define HASH_SECURITY_INFO (SECINFO_OWNER | \
48 /*******************************************************************
49 Hash a security descriptor.
50 *******************************************************************/
52 static NTSTATUS hash_sd_sha256(struct security_descriptor *psd,
59 memset(hash, '\0', XATTR_SD_HASH_SIZE);
60 status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
61 if (!NT_STATUS_IS_OK(status)) {
65 samba_SHA256_Init(&tctx);
66 samba_SHA256_Update(&tctx, blob.data, blob.length);
67 samba_SHA256_Final(hash, &tctx);
72 /*******************************************************************
73 Parse out a struct security_descriptor from a DATA_BLOB.
74 *******************************************************************/
76 static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob,
77 struct security_descriptor **ppdesc,
78 uint16_t *p_hash_type,
79 uint8_t hash[XATTR_SD_HASH_SIZE])
81 TALLOC_CTX *ctx = talloc_tos();
82 struct xattr_NTACL xacl;
83 enum ndr_err_code ndr_err;
86 ndr_err = ndr_pull_struct_blob(pblob, ctx, &xacl,
87 (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
89 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
90 DEBUG(5, ("parse_acl_blob: ndr_pull_xattr_NTACL failed: %s\n",
91 ndr_errstr(ndr_err)));
92 return ndr_map_error2ntstatus(ndr_err);
95 switch (xacl.version) {
97 *ppdesc = make_sec_desc(ctx, SD_REVISION,
98 xacl.info.sd->type | SEC_DESC_SELF_RELATIVE,
99 xacl.info.sd->owner_sid,
100 xacl.info.sd->group_sid,
104 /* No hash - null out. */
105 *p_hash_type = XATTR_SD_HASH_TYPE_NONE;
106 memset(hash, '\0', XATTR_SD_HASH_SIZE);
109 *ppdesc = make_sec_desc(ctx, SD_REVISION,
110 xacl.info.sd_hs2->sd->type | SEC_DESC_SELF_RELATIVE,
111 xacl.info.sd_hs2->sd->owner_sid,
112 xacl.info.sd_hs2->sd->group_sid,
113 xacl.info.sd_hs2->sd->sacl,
114 xacl.info.sd_hs2->sd->dacl,
116 /* No hash - null out. */
117 *p_hash_type = XATTR_SD_HASH_TYPE_NONE;
118 memset(hash, '\0', XATTR_SD_HASH_SIZE);
121 *ppdesc = make_sec_desc(ctx, SD_REVISION,
122 xacl.info.sd_hs3->sd->type | SEC_DESC_SELF_RELATIVE,
123 xacl.info.sd_hs3->sd->owner_sid,
124 xacl.info.sd_hs3->sd->group_sid,
125 xacl.info.sd_hs3->sd->sacl,
126 xacl.info.sd_hs3->sd->dacl,
128 *p_hash_type = xacl.info.sd_hs3->hash_type;
129 /* Current version 3. */
130 memcpy(hash, xacl.info.sd_hs3->hash, XATTR_SD_HASH_SIZE);
133 return NT_STATUS_REVISION_MISMATCH;
136 TALLOC_FREE(xacl.info.sd);
138 return (*ppdesc != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
141 /*******************************************************************
142 Create a DATA_BLOB from a security descriptor.
143 *******************************************************************/
145 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
148 uint8_t hash[XATTR_SD_HASH_SIZE])
150 struct xattr_NTACL xacl;
151 struct security_descriptor_hash_v3 sd_hs3;
152 enum ndr_err_code ndr_err;
153 TALLOC_CTX *ctx = talloc_tos();
159 xacl.info.sd_hs3 = &sd_hs3;
160 xacl.info.sd_hs3->sd = discard_const_p(struct security_descriptor, psd);
161 xacl.info.sd_hs3->hash_type = hash_type;
162 memcpy(&xacl.info.sd_hs3->hash[0], hash, XATTR_SD_HASH_SIZE);
164 ndr_err = ndr_push_struct_blob(
166 (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
168 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
169 DEBUG(5, ("create_acl_blob: ndr_push_xattr_NTACL failed: %s\n",
170 ndr_errstr(ndr_err)));
171 return ndr_map_error2ntstatus(ndr_err);
177 /*******************************************************************
178 Add in 3 inheritable components for a non-inheritable directory ACL.
179 CREATOR_OWNER/CREATOR_GROUP/WORLD.
180 *******************************************************************/
182 static void add_directory_inheritable_components(vfs_handle_struct *handle,
184 SMB_STRUCT_STAT *psbuf,
185 struct security_descriptor *psd)
187 struct connection_struct *conn = handle->conn;
188 int num_aces = (psd->dacl ? psd->dacl->num_aces : 0);
189 struct smb_filename smb_fname;
190 enum security_ace_type acltype;
191 uint32_t access_mask;
195 struct security_ace *new_ace_list = talloc_zero_array(talloc_tos(),
199 if (new_ace_list == NULL) {
203 /* Fake a quick smb_filename. */
204 ZERO_STRUCT(smb_fname);
205 smb_fname.st = *psbuf;
206 smb_fname.base_name = discard_const_p(char, name);
208 dir_mode = unix_mode(conn,
209 FILE_ATTRIBUTE_DIRECTORY, &smb_fname, NULL);
210 file_mode = unix_mode(conn,
211 FILE_ATTRIBUTE_ARCHIVE, &smb_fname, NULL);
213 mode = dir_mode | file_mode;
215 DEBUG(10, ("add_directory_inheritable_components: directory %s, "
218 (unsigned int)mode ));
221 memcpy(new_ace_list, psd->dacl->aces,
222 num_aces * sizeof(struct security_ace));
224 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
227 init_sec_ace(&new_ace_list[num_aces],
228 &global_sid_Creator_Owner,
231 SEC_ACE_FLAG_CONTAINER_INHERIT|
232 SEC_ACE_FLAG_OBJECT_INHERIT|
233 SEC_ACE_FLAG_INHERIT_ONLY);
234 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
235 (mode << 3) & 0700, false);
236 init_sec_ace(&new_ace_list[num_aces+1],
237 &global_sid_Creator_Group,
240 SEC_ACE_FLAG_CONTAINER_INHERIT|
241 SEC_ACE_FLAG_OBJECT_INHERIT|
242 SEC_ACE_FLAG_INHERIT_ONLY);
243 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
244 (mode << 6) & 0700, false);
245 init_sec_ace(&new_ace_list[num_aces+2],
249 SEC_ACE_FLAG_CONTAINER_INHERIT|
250 SEC_ACE_FLAG_OBJECT_INHERIT|
251 SEC_ACE_FLAG_INHERIT_ONLY);
252 psd->dacl->aces = new_ace_list;
253 psd->dacl->num_aces += 3;
256 /*******************************************************************
257 Pull a DATA_BLOB from an xattr given a pathname.
258 If the hash doesn't match, or doesn't exist - return the underlying
260 *******************************************************************/
262 static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
265 uint32_t security_info,
266 struct security_descriptor **ppdesc)
268 DATA_BLOB blob = data_blob_null;
270 uint16_t hash_type = XATTR_SD_HASH_TYPE_NONE;
271 uint8_t hash[XATTR_SD_HASH_SIZE];
272 uint8_t hash_tmp[XATTR_SD_HASH_SIZE];
273 struct security_descriptor *psd = NULL;
274 struct security_descriptor *pdesc_next = NULL;
275 bool ignore_file_system_acl = lp_parm_bool(SNUM(handle->conn),
277 "ignore system acls",
280 if (fsp && name == NULL) {
281 name = fsp->fsp_name->base_name;
284 DEBUG(10, ("get_nt_acl_internal: name=%s\n", name));
286 /* Get the full underlying sd for the hash
287 or to return as backup. */
289 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
294 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
300 if (!NT_STATUS_IS_OK(status)) {
301 DEBUG(10, ("get_nt_acl_internal: get_next_acl for file %s "
308 status = get_acl_blob(talloc_tos(), handle, fsp, name, &blob);
309 if (!NT_STATUS_IS_OK(status)) {
310 DEBUG(10, ("get_nt_acl_internal: get_acl_blob returned %s\n",
316 status = parse_acl_blob(&blob, &psd,
317 &hash_type, &hash[0]);
318 if (!NT_STATUS_IS_OK(status)) {
319 DEBUG(10, ("parse_acl_blob returned %s\n",
325 /* Ensure the hash type is one we know. */
327 case XATTR_SD_HASH_TYPE_NONE:
328 /* No hash, just return blob sd. */
330 case XATTR_SD_HASH_TYPE_SHA256:
333 DEBUG(10, ("get_nt_acl_internal: ACL blob revision "
334 "mismatch (%u) for file %s\n",
335 (unsigned int)hash_type,
342 if (ignore_file_system_acl) {
346 status = hash_sd_sha256(pdesc_next, hash_tmp);
347 if (!NT_STATUS_IS_OK(status)) {
353 if (memcmp(&hash[0], &hash_tmp[0], XATTR_SD_HASH_SIZE) == 0) {
354 /* Hash matches, return blob sd. */
355 DEBUG(10, ("get_nt_acl_internal: blob hash "
356 "matches for file %s\n",
361 /* Hash doesn't match, return underlying sd. */
367 if (psd != pdesc_next) {
368 /* We're returning the blob, throw
369 * away the filesystem SD. */
370 TALLOC_FREE(pdesc_next);
372 SMB_STRUCT_STAT sbuf;
373 SMB_STRUCT_STAT *psbuf = &sbuf;
374 bool is_directory = false;
376 * We're returning the underlying ACL from the
377 * filesystem. If it's a directory, and has no
378 * inheritable ACE entries we have to fake them.
381 status = vfs_stat_fsp(fsp);
382 if (!NT_STATUS_IS_OK(status)) {
385 psbuf = &fsp->fsp_name->st;
387 int ret = vfs_stat_smb_fname(handle->conn,
391 return map_nt_error_from_unix(errno);
394 is_directory = S_ISDIR(sbuf.st_ex_mode);
396 if (ignore_file_system_acl) {
397 TALLOC_FREE(pdesc_next);
398 status = make_default_filesystem_acl(talloc_tos(),
402 if (!NT_STATUS_IS_OK(status)) {
407 !sd_has_inheritable_components(psd,
409 add_directory_inheritable_components(handle,
414 /* The underlying POSIX module always sets
415 the ~SEC_DESC_DACL_PROTECTED bit, as ACLs
416 can't be inherited in this way under POSIX.
417 Remove it for Windows-style ACLs. */
418 psd->type &= ~SEC_DESC_DACL_PROTECTED;
422 if (!(security_info & SECINFO_OWNER)) {
423 psd->owner_sid = NULL;
425 if (!(security_info & SECINFO_GROUP)) {
426 psd->group_sid = NULL;
428 if (!(security_info & SECINFO_DACL)) {
431 if (!(security_info & SECINFO_SACL)) {
435 TALLOC_FREE(blob.data);
438 if (DEBUGLEVEL >= 10) {
439 DEBUG(10,("get_nt_acl_internal: returning acl for %s is:\n",
441 NDR_PRINT_DEBUG(security_descriptor, psd);
447 /*********************************************************************
448 Create a default ACL by inheriting from the parent. If no inheritance
449 from the parent available, don't set anything. This will leave the actual
450 permissions the new file or directory already got from the filesystem
451 as the NT ACL when read.
452 *********************************************************************/
454 static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
456 struct security_descriptor *parent_desc,
459 TALLOC_CTX *ctx = talloc_tos();
460 NTSTATUS status = NT_STATUS_OK;
461 struct security_descriptor *psd = NULL;
462 struct dom_sid *owner_sid = NULL;
463 struct dom_sid *group_sid = NULL;
464 uint32_t security_info_sent = (SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL);
465 bool inherit_owner = lp_inherit_owner(SNUM(handle->conn));
466 bool inheritable_components = sd_has_inheritable_components(parent_desc,
470 if (!inheritable_components && !inherit_owner) {
471 /* Nothing to inherit and not setting owner. */
475 /* Create an inherited descriptor from the parent. */
477 if (DEBUGLEVEL >= 10) {
478 DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
480 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
483 /* Inherit from parent descriptor if "inherit owner" set. */
485 owner_sid = parent_desc->owner_sid;
486 group_sid = parent_desc->group_sid;
489 if (owner_sid == NULL) {
490 owner_sid = &handle->conn->session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
492 if (group_sid == NULL) {
493 group_sid = &handle->conn->session_info->security_token->sids[PRIMARY_GROUP_SID_INDEX];
496 status = se_create_child_secdesc(ctx,
503 if (!NT_STATUS_IS_OK(status)) {
507 /* If inheritable_components == false,
508 se_create_child_secdesc()
509 creates a security desriptor with a NULL dacl
510 entry, but with SEC_DESC_DACL_PRESENT. We need
511 to remove that flag. */
513 if (!inheritable_components) {
514 security_info_sent &= ~SECINFO_DACL;
515 psd->type &= ~SEC_DESC_DACL_PRESENT;
518 if (DEBUGLEVEL >= 10) {
519 DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
521 NDR_PRINT_DEBUG(security_descriptor, psd);
525 /* We need to be root to force this. */
528 status = SMB_VFS_FSET_NT_ACL(fsp,
537 static NTSTATUS get_parent_acl_common(vfs_handle_struct *handle,
539 struct security_descriptor **pp_parent_desc)
541 char *parent_name = NULL;
544 if (!parent_dirname(talloc_tos(), path, &parent_name, NULL)) {
545 return NT_STATUS_NO_MEMORY;
548 status = get_nt_acl_internal(handle,
556 if (!NT_STATUS_IS_OK(status)) {
557 DEBUG(10,("get_parent_acl_common: get_nt_acl_internal "
558 "on directory %s for "
559 "path %s returned %s\n",
562 nt_errstr(status) ));
567 static NTSTATUS check_parent_acl_common(vfs_handle_struct *handle,
569 uint32_t access_mask,
570 struct security_descriptor **pp_parent_desc)
572 char *parent_name = NULL;
573 struct security_descriptor *parent_desc = NULL;
574 uint32_t access_granted = 0;
577 status = get_parent_acl_common(handle, path, &parent_desc);
578 if (!NT_STATUS_IS_OK(status)) {
581 if (pp_parent_desc) {
582 *pp_parent_desc = parent_desc;
584 status = smb1_file_se_access_check(handle->conn,
586 get_current_nttok(handle->conn),
589 if(!NT_STATUS_IS_OK(status)) {
590 DEBUG(10,("check_parent_acl_common: access check "
591 "on directory %s for "
592 "path %s for mask 0x%x returned %s\n",
596 nt_errstr(status) ));
602 /*********************************************************************
603 Check ACL on open. For new files inherit from parent directory.
604 *********************************************************************/
606 static int open_acl_common(vfs_handle_struct *handle,
607 struct smb_filename *smb_fname,
612 uint32_t access_granted = 0;
613 struct security_descriptor *pdesc = NULL;
614 bool file_existed = true;
619 /* Stream open. Base filename open already did the ACL check. */
620 DEBUG(10,("open_acl_common: stream open on %s\n",
622 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
625 status = get_full_smb_filename(talloc_tos(), smb_fname,
627 if (!NT_STATUS_IS_OK(status)) {
631 status = get_nt_acl_internal(handle,
638 if (NT_STATUS_IS_OK(status)) {
639 /* See if we can access it. */
640 status = smb1_file_se_access_check(handle->conn,
642 get_current_nttok(handle->conn),
645 if (!NT_STATUS_IS_OK(status)) {
646 DEBUG(10,("open_acl_xattr: %s open "
647 "refused with error %s\n",
649 nt_errstr(status) ));
652 } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
653 file_existed = false;
655 * If O_CREAT is true then we're trying to create a file.
656 * Check the parent directory ACL will allow this.
658 if (flags & O_CREAT) {
659 struct security_descriptor *parent_desc = NULL;
660 struct security_descriptor **pp_psd = NULL;
662 status = check_parent_acl_common(handle, fname,
663 SEC_DIR_ADD_FILE, &parent_desc);
664 if (!NT_STATUS_IS_OK(status)) {
668 /* Cache the parent security descriptor for
671 pp_psd = (struct security_descriptor **)
672 VFS_ADD_FSP_EXTENSION(handle,
674 struct security_descriptor *,
677 status = NT_STATUS_NO_MEMORY;
681 *pp_psd = parent_desc;
682 status = NT_STATUS_OK;
686 DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
689 nt_errstr(status) ));
691 fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
696 errno = map_errno_from_nt_status(status);
700 static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t mode)
704 SMB_STRUCT_STAT sbuf;
706 ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
707 if (ret == -1 && errno == ENOENT) {
708 /* We're creating a new directory. */
709 status = check_parent_acl_common(handle, path,
710 SEC_DIR_ADD_SUBDIR, NULL);
711 if (!NT_STATUS_IS_OK(status)) {
712 errno = map_errno_from_nt_status(status);
717 return SMB_VFS_NEXT_MKDIR(handle, path, mode);
720 /*********************************************************************
721 Fetch a security descriptor given an fsp.
722 *********************************************************************/
724 static NTSTATUS fget_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
725 uint32_t security_info, struct security_descriptor **ppdesc)
727 return get_nt_acl_internal(handle, fsp,
728 NULL, security_info, ppdesc);
731 /*********************************************************************
732 Fetch a security descriptor given a pathname.
733 *********************************************************************/
735 static NTSTATUS get_nt_acl_common(vfs_handle_struct *handle,
736 const char *name, uint32_t security_info, struct security_descriptor **ppdesc)
738 return get_nt_acl_internal(handle, NULL,
739 name, security_info, ppdesc);
742 /*********************************************************************
743 Store a security descriptor given an fsp.
744 *********************************************************************/
746 static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
747 uint32_t security_info_sent, const struct security_descriptor *orig_psd)
751 struct security_descriptor *pdesc_next = NULL;
752 struct security_descriptor *psd = NULL;
753 uint8_t hash[XATTR_SD_HASH_SIZE];
755 if (DEBUGLEVEL >= 10) {
756 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
758 NDR_PRINT_DEBUG(security_descriptor,
759 discard_const_p(struct security_descriptor, orig_psd));
762 status = get_nt_acl_internal(handle, fsp,
764 SECINFO_OWNER|SECINFO_GROUP|SECINFO_DACL|SECINFO_SACL,
767 if (!NT_STATUS_IS_OK(status)) {
771 psd->revision = orig_psd->revision;
772 /* All our SD's are self relative. */
773 psd->type = orig_psd->type | SEC_DESC_SELF_RELATIVE;
775 if ((security_info_sent & SECINFO_OWNER) && (orig_psd->owner_sid != NULL)) {
776 psd->owner_sid = orig_psd->owner_sid;
778 if ((security_info_sent & SECINFO_GROUP) && (orig_psd->group_sid != NULL)) {
779 psd->group_sid = orig_psd->group_sid;
781 if (security_info_sent & SECINFO_DACL) {
782 psd->dacl = orig_psd->dacl;
783 psd->type |= SEC_DESC_DACL_PRESENT;
785 if (security_info_sent & SECINFO_SACL) {
786 psd->sacl = orig_psd->sacl;
787 psd->type |= SEC_DESC_SACL_PRESENT;
790 status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
791 if (!NT_STATUS_IS_OK(status)) {
795 /* Get the full underlying sd, then hash. */
796 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
801 if (!NT_STATUS_IS_OK(status)) {
805 status = hash_sd_sha256(pdesc_next, hash);
806 if (!NT_STATUS_IS_OK(status)) {
810 if (DEBUGLEVEL >= 10) {
811 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
813 NDR_PRINT_DEBUG(security_descriptor,
814 discard_const_p(struct security_descriptor, psd));
816 create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
817 store_acl_blob_fsp(handle, fsp, &blob);
822 static SMB_STRUCT_DIR *opendir_acl_common(vfs_handle_struct *handle,
823 const char *fname, const char *mask, uint32 attr)
825 NTSTATUS status = check_parent_acl_common(handle, fname,
828 if (!NT_STATUS_IS_OK(status)) {
829 errno = map_errno_from_nt_status(status);
832 return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
835 static int acl_common_remove_object(vfs_handle_struct *handle,
839 connection_struct *conn = handle->conn;
841 files_struct *fsp = NULL;
843 char *parent_dir = NULL;
844 const char *final_component = NULL;
845 struct smb_filename local_fname;
847 char *saved_dir = NULL;
849 saved_dir = vfs_GetWd(talloc_tos(),conn);
855 if (!parent_dirname(talloc_tos(), path,
856 &parent_dir, &final_component)) {
857 saved_errno = ENOMEM;
861 DEBUG(10,("acl_common_remove_object: removing %s %s/%s\n",
862 is_directory ? "directory" : "file",
863 parent_dir, final_component ));
865 /* cd into the parent dir to pin it. */
866 ret = vfs_ChDir(conn, parent_dir);
872 ZERO_STRUCT(local_fname);
873 local_fname.base_name = discard_const_p(char, final_component);
875 /* Must use lstat here. */
876 ret = SMB_VFS_LSTAT(conn, &local_fname);
882 /* Ensure we have this file open with DELETE access. */
883 id = vfs_file_id_from_sbuf(conn, &local_fname.st);
884 for (fsp = file_find_di_first(conn->sconn, id); fsp;
885 fsp = file_find_di_next(fsp)) {
886 if (fsp->access_mask & DELETE_ACCESS &&
887 fsp->delete_on_close) {
888 /* We did open this for delete,
889 * allow the delete as root.
896 DEBUG(10,("acl_common_remove_object: %s %s/%s "
897 "not an open file\n",
898 is_directory ? "directory" : "file",
899 parent_dir, final_component ));
900 saved_errno = EACCES;
906 ret = SMB_VFS_NEXT_RMDIR(handle, final_component);
908 ret = SMB_VFS_NEXT_UNLINK(handle, &local_fname);
918 TALLOC_FREE(parent_dir);
921 vfs_ChDir(conn, saved_dir);
929 static int rmdir_acl_common(struct vfs_handle_struct *handle,
934 ret = SMB_VFS_NEXT_RMDIR(handle, path);
935 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
936 DEBUG(10,("rmdir_acl_common: unlink of %s failed %s\n",
942 return acl_common_remove_object(handle,
947 static NTSTATUS create_file_acl_common(struct vfs_handle_struct *handle,
948 struct smb_request *req,
949 uint16_t root_dir_fid,
950 struct smb_filename *smb_fname,
951 uint32_t access_mask,
952 uint32_t share_access,
953 uint32_t create_disposition,
954 uint32_t create_options,
955 uint32_t file_attributes,
956 uint32_t oplock_request,
957 uint64_t allocation_size,
958 uint32_t private_flags,
959 struct security_descriptor *sd,
960 struct ea_list *ea_list,
961 files_struct **result,
964 NTSTATUS status, status1;
965 files_struct *fsp = NULL;
967 struct security_descriptor *parent_sd = NULL;
968 struct security_descriptor **pp_parent_sd = NULL;
970 status = SMB_VFS_NEXT_CREATE_FILE(handle,
987 if (!NT_STATUS_IS_OK(status)) {
991 if (info != FILE_WAS_CREATED) {
992 /* File/directory was opened, not created. */
999 /* Only handle success. */
1004 /* Security descriptor already set. */
1008 if (fsp->base_fsp) {
1013 /* See if we have a cached parent sd, if so, use it. */
1014 pp_parent_sd = (struct security_descriptor **)VFS_FETCH_FSP_EXTENSION(handle, fsp);
1015 if (!pp_parent_sd) {
1016 /* Must be a directory, fetch again (sigh). */
1017 status = get_parent_acl_common(handle,
1018 fsp->fsp_name->base_name,
1020 if (!NT_STATUS_IS_OK(status)) {
1024 parent_sd = *pp_parent_sd;
1031 /* New directory - inherit from parent. */
1032 status1 = inherit_new_acl(handle, fsp, parent_sd, fsp->is_directory);
1034 if (!NT_STATUS_IS_OK(status1)) {
1035 DEBUG(1,("create_file_acl_common: error setting "
1038 nt_errstr(status1) ));
1044 VFS_REMOVE_FSP_EXTENSION(handle, fsp);
1047 if (NT_STATUS_IS_OK(status) && pinfo) {
1054 smb_panic("create_file_acl_common: logic error.\n");
1059 static int unlink_acl_common(struct vfs_handle_struct *handle,
1060 const struct smb_filename *smb_fname)
1064 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1065 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
1066 DEBUG(10,("unlink_acl_common: unlink of %s failed %s\n",
1067 smb_fname->base_name,
1071 /* Don't do anything fancy for streams. */
1072 if (smb_fname->stream_name) {
1076 return acl_common_remove_object(handle,
1077 smb_fname->base_name,
1081 static int chmod_acl_module_common(struct vfs_handle_struct *handle,
1082 const char *path, mode_t mode)
1084 if (lp_posix_pathnames()) {
1085 /* Only allow this on POSIX pathnames. */
1086 return SMB_VFS_NEXT_CHMOD(handle, path, mode);
1091 static int fchmod_acl_module_common(struct vfs_handle_struct *handle,
1092 struct files_struct *fsp, mode_t mode)
1094 if (fsp->posix_open) {
1095 /* Only allow this on POSIX opens. */
1096 return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
1101 static int chmod_acl_acl_module_common(struct vfs_handle_struct *handle,
1102 const char *name, mode_t mode)
1104 if (lp_posix_pathnames()) {
1105 /* Only allow this on POSIX pathnames. */
1106 return SMB_VFS_NEXT_CHMOD_ACL(handle, name, mode);
1111 static int fchmod_acl_acl_module_common(struct vfs_handle_struct *handle,
1112 struct files_struct *fsp, mode_t mode)
1114 if (fsp->posix_open) {
1115 /* Only allow this on POSIX opens. */
1116 return SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, mode);