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 "../librpc/gen_ndr/ndr_security.h"
24 static NTSTATUS
create_acl_blob(const struct security_descriptor
*psd
,
27 uint8_t hash
[XATTR_SD_HASH_SIZE
]);
29 static NTSTATUS
get_acl_blob(TALLOC_CTX
*ctx
,
30 vfs_handle_struct
*handle
,
35 static NTSTATUS
store_acl_blob_fsp(vfs_handle_struct
*handle
,
39 #define HASH_SECURITY_INFO (SECINFO_OWNER | \
40 GROUP_SECURITY_INFORMATION | \
41 DACL_SECURITY_INFORMATION | \
42 SACL_SECURITY_INFORMATION)
44 /*******************************************************************
45 Hash a security descriptor.
46 *******************************************************************/
48 static NTSTATUS
hash_sd_sha256(struct security_descriptor
*psd
,
55 memset(hash
, '\0', XATTR_SD_HASH_SIZE
);
56 status
= create_acl_blob(psd
, &blob
, XATTR_SD_HASH_TYPE_SHA256
, hash
);
57 if (!NT_STATUS_IS_OK(status
)) {
62 SHA256_Update(&tctx
, blob
.data
, blob
.length
);
63 SHA256_Final(hash
, &tctx
);
68 /*******************************************************************
69 Parse out a struct security_descriptor from a DATA_BLOB.
70 *******************************************************************/
72 static NTSTATUS
parse_acl_blob(const DATA_BLOB
*pblob
,
73 struct security_descriptor
**ppdesc
,
74 uint16_t *p_hash_type
,
75 uint8_t hash
[XATTR_SD_HASH_SIZE
])
77 TALLOC_CTX
*ctx
= talloc_tos();
78 struct xattr_NTACL xacl
;
79 enum ndr_err_code ndr_err
;
82 ndr_err
= ndr_pull_struct_blob(pblob
, ctx
, &xacl
,
83 (ndr_pull_flags_fn_t
)ndr_pull_xattr_NTACL
);
85 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
86 DEBUG(5, ("parse_acl_blob: ndr_pull_xattr_NTACL failed: %s\n",
87 ndr_errstr(ndr_err
)));
88 return ndr_map_error2ntstatus(ndr_err
);;
91 switch (xacl
.version
) {
93 *ppdesc
= make_sec_desc(ctx
, SD_REVISION
,
94 xacl
.info
.sd_hs2
->sd
->type
| SEC_DESC_SELF_RELATIVE
,
95 xacl
.info
.sd_hs2
->sd
->owner_sid
,
96 xacl
.info
.sd_hs2
->sd
->group_sid
,
97 xacl
.info
.sd_hs2
->sd
->sacl
,
98 xacl
.info
.sd_hs2
->sd
->dacl
,
100 /* No hash - null out. */
101 *p_hash_type
= XATTR_SD_HASH_TYPE_NONE
;
102 memset(hash
, '\0', XATTR_SD_HASH_SIZE
);
105 *ppdesc
= make_sec_desc(ctx
, SD_REVISION
,
106 xacl
.info
.sd_hs3
->sd
->type
| SEC_DESC_SELF_RELATIVE
,
107 xacl
.info
.sd_hs3
->sd
->owner_sid
,
108 xacl
.info
.sd_hs3
->sd
->group_sid
,
109 xacl
.info
.sd_hs3
->sd
->sacl
,
110 xacl
.info
.sd_hs3
->sd
->dacl
,
112 *p_hash_type
= xacl
.info
.sd_hs3
->hash_type
;
113 /* Current version 3. */
114 memcpy(hash
, xacl
.info
.sd_hs3
->hash
, XATTR_SD_HASH_SIZE
);
117 return NT_STATUS_REVISION_MISMATCH
;
120 TALLOC_FREE(xacl
.info
.sd
);
122 return (*ppdesc
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
125 /*******************************************************************
126 Create a DATA_BLOB from a security descriptor.
127 *******************************************************************/
129 static NTSTATUS
create_acl_blob(const struct security_descriptor
*psd
,
132 uint8_t hash
[XATTR_SD_HASH_SIZE
])
134 struct xattr_NTACL xacl
;
135 struct security_descriptor_hash_v3 sd_hs3
;
136 enum ndr_err_code ndr_err
;
137 TALLOC_CTX
*ctx
= talloc_tos();
143 xacl
.info
.sd_hs3
= &sd_hs3
;
144 xacl
.info
.sd_hs3
->sd
= CONST_DISCARD(struct security_descriptor
*, psd
);
145 xacl
.info
.sd_hs3
->hash_type
= hash_type
;
146 memcpy(&xacl
.info
.sd_hs3
->hash
[0], hash
, XATTR_SD_HASH_SIZE
);
148 ndr_err
= ndr_push_struct_blob(
150 (ndr_push_flags_fn_t
)ndr_push_xattr_NTACL
);
152 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
153 DEBUG(5, ("create_acl_blob: ndr_push_xattr_NTACL failed: %s\n",
154 ndr_errstr(ndr_err
)));
155 return ndr_map_error2ntstatus(ndr_err
);;
161 /*******************************************************************
162 Add in 3 inheritable components for a non-inheritable directory ACL.
163 CREATOR_OWNER/CREATOR_GROUP/WORLD.
164 *******************************************************************/
166 static void add_directory_inheritable_components(vfs_handle_struct
*handle
,
168 SMB_STRUCT_STAT
*psbuf
,
169 struct security_descriptor
*psd
)
171 struct connection_struct
*conn
= handle
->conn
;
172 int num_aces
= (psd
->dacl
? psd
->dacl
->num_aces
: 0);
173 struct smb_filename smb_fname
;
174 enum security_ace_type acltype
;
175 uint32_t access_mask
;
179 struct security_ace
*new_ace_list
= TALLOC_ZERO_ARRAY(talloc_tos(),
183 if (new_ace_list
== NULL
) {
187 /* Fake a quick smb_filename. */
188 ZERO_STRUCT(smb_fname
);
189 smb_fname
.st
= *psbuf
;
190 smb_fname
.base_name
= CONST_DISCARD(char *, name
);
192 dir_mode
= unix_mode(conn
,
193 FILE_ATTRIBUTE_DIRECTORY
, &smb_fname
, NULL
);
194 file_mode
= unix_mode(conn
,
195 FILE_ATTRIBUTE_ARCHIVE
, &smb_fname
, NULL
);
197 mode
= dir_mode
| file_mode
;
199 DEBUG(10, ("add_directory_inheritable_components: directory %s, "
202 (unsigned int)mode
));
205 memcpy(new_ace_list
, psd
->dacl
->aces
,
206 num_aces
* sizeof(struct security_ace
));
208 access_mask
= map_canon_ace_perms(SNUM(conn
), &acltype
,
211 init_sec_ace(&new_ace_list
[num_aces
],
212 &global_sid_Creator_Owner
,
215 SEC_ACE_FLAG_CONTAINER_INHERIT
|
216 SEC_ACE_FLAG_OBJECT_INHERIT
|
217 SEC_ACE_FLAG_INHERIT_ONLY
);
218 access_mask
= map_canon_ace_perms(SNUM(conn
), &acltype
,
219 (mode
<< 3) & 0700, false);
220 init_sec_ace(&new_ace_list
[num_aces
+1],
221 &global_sid_Creator_Group
,
224 SEC_ACE_FLAG_CONTAINER_INHERIT
|
225 SEC_ACE_FLAG_OBJECT_INHERIT
|
226 SEC_ACE_FLAG_INHERIT_ONLY
);
227 access_mask
= map_canon_ace_perms(SNUM(conn
), &acltype
,
228 (mode
<< 6) & 0700, false);
229 init_sec_ace(&new_ace_list
[num_aces
+2],
233 SEC_ACE_FLAG_CONTAINER_INHERIT
|
234 SEC_ACE_FLAG_OBJECT_INHERIT
|
235 SEC_ACE_FLAG_INHERIT_ONLY
);
236 psd
->dacl
->aces
= new_ace_list
;
237 psd
->dacl
->num_aces
+= 3;
240 /*******************************************************************
241 Pull a DATA_BLOB from an xattr given a pathname.
242 If the hash doesn't match, or doesn't exist - return the underlying
244 *******************************************************************/
246 static NTSTATUS
get_nt_acl_internal(vfs_handle_struct
*handle
,
249 uint32_t security_info
,
250 struct security_descriptor
**ppdesc
)
255 uint8_t hash
[XATTR_SD_HASH_SIZE
];
256 uint8_t hash_tmp
[XATTR_SD_HASH_SIZE
];
257 struct security_descriptor
*psd
= NULL
;
258 struct security_descriptor
*pdesc_next
= NULL
;
260 if (fsp
&& name
== NULL
) {
261 name
= fsp
->fsp_name
->base_name
;
264 DEBUG(10, ("get_nt_acl_internal: name=%s\n", name
));
266 /* Get the full underlying sd for the hash
267 or to return as backup. */
269 status
= SMB_VFS_NEXT_FGET_NT_ACL(handle
,
274 status
= SMB_VFS_NEXT_GET_NT_ACL(handle
,
280 if (!NT_STATUS_IS_OK(status
)) {
281 DEBUG(10, ("get_nt_acl_internal: get_next_acl for file %s "
288 status
= get_acl_blob(talloc_tos(), handle
, fsp
, name
, &blob
);
289 if (!NT_STATUS_IS_OK(status
)) {
290 DEBUG(10, ("get_nt_acl_internal: get_acl_blob returned %s\n",
296 status
= parse_acl_blob(&blob
, &psd
,
297 &hash_type
, &hash
[0]);
298 if (!NT_STATUS_IS_OK(status
)) {
299 DEBUG(10, ("parse_acl_blob returned %s\n",
305 /* Ensure the hash type is one we know. */
307 case XATTR_SD_HASH_TYPE_NONE
:
308 /* No hash, just return blob sd. */
310 case XATTR_SD_HASH_TYPE_SHA256
:
313 DEBUG(10, ("get_nt_acl_internal: ACL blob revision "
314 "mismatch (%u) for file %s\n",
315 (unsigned int)hash_type
,
323 status
= hash_sd_sha256(pdesc_next
, hash_tmp
);
324 if (!NT_STATUS_IS_OK(status
)) {
330 if (memcmp(&hash
[0], &hash_tmp
[0], XATTR_SD_HASH_SIZE
) == 0) {
331 /* Hash matches, return blob sd. */
335 /* Hash doesn't match, return underlying sd. */
341 if (psd
!= pdesc_next
) {
342 /* We're returning the blob, throw
343 * away the filesystem SD. */
344 TALLOC_FREE(pdesc_next
);
346 SMB_STRUCT_STAT sbuf
;
347 SMB_STRUCT_STAT
*psbuf
= &sbuf
;
348 bool is_directory
= false;
350 * We're returning the underlying ACL from the
351 * filesystem. If it's a directory, and has no
352 * inheritable ACE entries we have to fake them.
355 is_directory
= fsp
->is_directory
;
356 psbuf
= &fsp
->fsp_name
->st
;
358 if (vfs_stat_smb_fname(handle
->conn
,
361 is_directory
= S_ISDIR(sbuf
.st_ex_mode
);
365 !sd_has_inheritable_components(psd
,
367 add_directory_inheritable_components(handle
,
374 if (!(security_info
& SECINFO_OWNER
)) {
375 psd
->owner_sid
= NULL
;
377 if (!(security_info
& GROUP_SECURITY_INFORMATION
)) {
378 psd
->group_sid
= NULL
;
380 if (!(security_info
& DACL_SECURITY_INFORMATION
)) {
383 if (!(security_info
& SACL_SECURITY_INFORMATION
)) {
387 TALLOC_FREE(blob
.data
);
392 /*********************************************************************
393 Create a default ACL by inheriting from the parent. If no inheritance
394 from the parent available, don't set anything. This will leave the actual
395 permissions the new file or directory already got from the filesystem
396 as the NT ACL when read.
397 *********************************************************************/
399 static NTSTATUS
inherit_new_acl(vfs_handle_struct
*handle
,
401 struct security_descriptor
*parent_desc
,
404 TALLOC_CTX
*ctx
= talloc_tos();
405 NTSTATUS status
= NT_STATUS_OK
;
406 struct security_descriptor
*psd
= NULL
;
409 if (!sd_has_inheritable_components(parent_desc
, is_directory
)) {
413 /* Create an inherited descriptor from the parent. */
415 if (DEBUGLEVEL
>= 10) {
416 DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
418 NDR_PRINT_DEBUG(security_descriptor
, parent_desc
);
421 status
= se_create_child_secdesc(ctx
,
425 &handle
->conn
->server_info
->ptok
->user_sids
[PRIMARY_USER_SID_INDEX
],
426 &handle
->conn
->server_info
->ptok
->user_sids
[PRIMARY_GROUP_SID_INDEX
],
428 if (!NT_STATUS_IS_OK(status
)) {
432 if (DEBUGLEVEL
>= 10) {
433 DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
435 NDR_PRINT_DEBUG(security_descriptor
, parent_desc
);
438 return SMB_VFS_FSET_NT_ACL(fsp
,
440 GROUP_SECURITY_INFORMATION
|
441 DACL_SECURITY_INFORMATION
),
445 static NTSTATUS
check_parent_acl_common(vfs_handle_struct
*handle
,
447 uint32_t access_mask
,
448 struct security_descriptor
**pp_parent_desc
)
450 char *parent_name
= NULL
;
451 struct security_descriptor
*parent_desc
= NULL
;
452 uint32_t access_granted
= 0;
455 if (!parent_dirname(talloc_tos(), path
, &parent_name
, NULL
)) {
456 return NT_STATUS_NO_MEMORY
;
459 status
= get_nt_acl_internal(handle
,
463 GROUP_SECURITY_INFORMATION
|
464 DACL_SECURITY_INFORMATION
),
467 if (!NT_STATUS_IS_OK(status
)) {
468 DEBUG(10,("check_parent_acl_common: get_nt_acl_internal "
469 "on directory %s for "
470 "path %s returned %s\n",
473 nt_errstr(status
) ));
476 if (pp_parent_desc
) {
477 *pp_parent_desc
= parent_desc
;
479 status
= smb1_file_se_access_check(handle
->conn
,
481 get_current_nttok(handle
->conn
),
484 if(!NT_STATUS_IS_OK(status
)) {
485 DEBUG(10,("check_parent_acl_common: access check "
486 "on directory %s for "
487 "path %s for mask 0x%x returned %s\n",
491 nt_errstr(status
) ));
497 static void free_sd_common(void **ptr
)
502 /*********************************************************************
503 Check ACL on open. For new files inherit from parent directory.
504 *********************************************************************/
506 static int open_acl_common(vfs_handle_struct
*handle
,
507 struct smb_filename
*smb_fname
,
512 uint32_t access_granted
= 0;
513 struct security_descriptor
*pdesc
= NULL
;
514 struct security_descriptor
*parent_desc
= NULL
;
515 bool file_existed
= true;
520 /* Stream open. Base filename open already did the ACL check. */
521 DEBUG(10,("open_acl_common: stream open on %s\n",
523 return SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
, mode
);
526 status
= get_full_smb_filename(talloc_tos(), smb_fname
,
528 if (!NT_STATUS_IS_OK(status
)) {
532 status
= get_nt_acl_internal(handle
,
536 GROUP_SECURITY_INFORMATION
|
537 DACL_SECURITY_INFORMATION
),
539 if (NT_STATUS_IS_OK(status
)) {
540 /* See if we can access it. */
541 status
= smb1_file_se_access_check(handle
->conn
,
543 get_current_nttok(handle
->conn
),
546 if (!NT_STATUS_IS_OK(status
)) {
547 DEBUG(10,("open_acl_xattr: %s open "
548 "refused with error %s\n",
550 nt_errstr(status
) ));
553 } else if (NT_STATUS_EQUAL(status
,NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
554 file_existed
= false;
556 * If O_CREAT is true then we're trying to create a file.
557 * Check the parent directory ACL will allow this.
559 if (flags
& O_CREAT
) {
560 struct security_descriptor
*psd
= NULL
;
562 status
= check_parent_acl_common(handle
, fname
,
563 SEC_DIR_ADD_FILE
, &parent_desc
);
564 if (!NT_STATUS_IS_OK(status
)) {
567 /* Cache the parent security descriptor for
568 * later use. We do have an fsp here, but to
569 * keep the code consistent with the directory
570 * case which doesn't, use the handle. */
572 /* Attach this to the conn, move from talloc_tos(). */
573 psd
= (struct security_descriptor
*)talloc_move(handle
->conn
,
577 status
= NT_STATUS_NO_MEMORY
;
580 status
= NT_STATUS_NO_MEMORY
;
581 SMB_VFS_HANDLE_SET_DATA(handle
, psd
, free_sd_common
,
582 struct security_descriptor
*, goto err
);
583 status
= NT_STATUS_OK
;
587 DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
590 nt_errstr(status
) ));
592 fsp
->fh
->fd
= SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
, mode
);
597 errno
= map_errno_from_nt_status(status
);
601 static int mkdir_acl_common(vfs_handle_struct
*handle
, const char *path
, mode_t mode
)
605 SMB_STRUCT_STAT sbuf
;
607 ret
= vfs_stat_smb_fname(handle
->conn
, path
, &sbuf
);
608 if (ret
== -1 && errno
== ENOENT
) {
609 struct security_descriptor
*parent_desc
= NULL
;
610 struct security_descriptor
*psd
= NULL
;
612 /* We're creating a new directory. */
613 status
= check_parent_acl_common(handle
, path
,
614 SEC_DIR_ADD_SUBDIR
, &parent_desc
);
615 if (!NT_STATUS_IS_OK(status
)) {
616 errno
= map_errno_from_nt_status(status
);
620 /* Cache the parent security descriptor for
621 * later use. We don't have an fsp here so
624 /* Attach this to the conn, move from talloc_tos(). */
625 psd
= (struct security_descriptor
*)talloc_move(handle
->conn
,
631 SMB_VFS_HANDLE_SET_DATA(handle
, psd
, free_sd_common
,
632 struct security_descriptor
*, return -1);
635 return SMB_VFS_NEXT_MKDIR(handle
, path
, mode
);
638 /*********************************************************************
639 Fetch a security descriptor given an fsp.
640 *********************************************************************/
642 static NTSTATUS
fget_nt_acl_common(vfs_handle_struct
*handle
, files_struct
*fsp
,
643 uint32_t security_info
, struct security_descriptor
**ppdesc
)
645 return get_nt_acl_internal(handle
, fsp
,
646 NULL
, security_info
, ppdesc
);
649 /*********************************************************************
650 Fetch a security descriptor given a pathname.
651 *********************************************************************/
653 static NTSTATUS
get_nt_acl_common(vfs_handle_struct
*handle
,
654 const char *name
, uint32_t security_info
, struct security_descriptor
**ppdesc
)
656 return get_nt_acl_internal(handle
, NULL
,
657 name
, security_info
, ppdesc
);
660 /*********************************************************************
661 Store a security descriptor given an fsp.
662 *********************************************************************/
664 static NTSTATUS
fset_nt_acl_common(vfs_handle_struct
*handle
, files_struct
*fsp
,
665 uint32_t security_info_sent
, const struct security_descriptor
*psd
)
669 struct security_descriptor
*pdesc_next
= NULL
;
670 uint8_t hash
[XATTR_SD_HASH_SIZE
];
672 if (DEBUGLEVEL
>= 10) {
673 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
675 NDR_PRINT_DEBUG(security_descriptor
,
676 CONST_DISCARD(struct security_descriptor
*,psd
));
679 /* Ensure we have OWNER/GROUP/DACL set. */
681 if ((security_info_sent
& (SECINFO_OWNER
|
682 GROUP_SECURITY_INFORMATION
|
683 DACL_SECURITY_INFORMATION
)) !=
685 GROUP_SECURITY_INFORMATION
|
686 DACL_SECURITY_INFORMATION
)) {
687 /* No we don't - read from the existing SD. */
688 struct security_descriptor
*nc_psd
= NULL
;
690 status
= get_nt_acl_internal(handle
, fsp
,
693 GROUP_SECURITY_INFORMATION
|
694 DACL_SECURITY_INFORMATION
),
697 if (!NT_STATUS_IS_OK(status
)) {
701 /* This is safe as nc_psd is discarded at fn exit. */
702 if (security_info_sent
& SECINFO_OWNER
) {
703 nc_psd
->owner_sid
= psd
->owner_sid
;
705 security_info_sent
|= SECINFO_OWNER
;
707 if (security_info_sent
& GROUP_SECURITY_INFORMATION
) {
708 nc_psd
->group_sid
= psd
->group_sid
;
710 security_info_sent
|= GROUP_SECURITY_INFORMATION
;
712 if (security_info_sent
& DACL_SECURITY_INFORMATION
) {
713 nc_psd
->dacl
= dup_sec_acl(talloc_tos(), psd
->dacl
);
714 if (nc_psd
->dacl
== NULL
) {
715 return NT_STATUS_NO_MEMORY
;
718 security_info_sent
|= DACL_SECURITY_INFORMATION
;
722 status
= SMB_VFS_NEXT_FSET_NT_ACL(handle
, fsp
, security_info_sent
, psd
);
723 if (!NT_STATUS_IS_OK(status
)) {
727 /* Get the full underlying sd, then hash. */
728 status
= SMB_VFS_NEXT_FGET_NT_ACL(handle
,
733 if (!NT_STATUS_IS_OK(status
)) {
737 status
= hash_sd_sha256(pdesc_next
, hash
);
738 if (!NT_STATUS_IS_OK(status
)) {
742 if (DEBUGLEVEL
>= 10) {
743 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
745 NDR_PRINT_DEBUG(security_descriptor
,
746 CONST_DISCARD(struct security_descriptor
*,psd
));
748 create_acl_blob(psd
, &blob
, XATTR_SD_HASH_TYPE_SHA256
, hash
);
749 store_acl_blob_fsp(handle
, fsp
, &blob
);
754 static SMB_STRUCT_DIR
*opendir_acl_common(vfs_handle_struct
*handle
,
755 const char *fname
, const char *mask
, uint32 attr
)
757 NTSTATUS status
= check_parent_acl_common(handle
, fname
,
760 if (!NT_STATUS_IS_OK(status
)) {
761 errno
= map_errno_from_nt_status(status
);
764 return SMB_VFS_NEXT_OPENDIR(handle
, fname
, mask
, attr
);
767 static int acl_common_remove_object(vfs_handle_struct
*handle
,
771 connection_struct
*conn
= handle
->conn
;
773 files_struct
*fsp
= NULL
;
775 char *parent_dir
= NULL
;
776 const char *final_component
= NULL
;
777 struct smb_filename local_fname
;
780 if (!parent_dirname(talloc_tos(), path
,
781 &parent_dir
, &final_component
)) {
782 saved_errno
= ENOMEM
;
786 DEBUG(10,("acl_common_remove_object: removing %s %s/%s\n",
787 is_directory
? "directory" : "file",
788 parent_dir
, final_component
));
790 /* cd into the parent dir to pin it. */
791 ret
= SMB_VFS_CHDIR(conn
, parent_dir
);
797 ZERO_STRUCT(local_fname
);
798 local_fname
.base_name
= CONST_DISCARD(char *,final_component
);
800 /* Must use lstat here. */
801 ret
= SMB_VFS_LSTAT(conn
, &local_fname
);
807 /* Ensure we have this file open with DELETE access. */
808 id
= vfs_file_id_from_sbuf(conn
, &local_fname
.st
);
809 for (fsp
= file_find_di_first(id
); fsp
; file_find_di_next(fsp
)) {
810 if (fsp
->access_mask
& DELETE_ACCESS
&&
811 fsp
->delete_on_close
) {
812 /* We did open this for delete,
813 * allow the delete as root.
820 DEBUG(10,("acl_common_remove_object: %s %s/%s "
821 "not an open file\n",
822 is_directory
? "directory" : "file",
823 parent_dir
, final_component
));
824 saved_errno
= EACCES
;
830 ret
= SMB_VFS_NEXT_RMDIR(handle
, final_component
);
832 ret
= SMB_VFS_NEXT_UNLINK(handle
, &local_fname
);
842 TALLOC_FREE(parent_dir
);
844 vfs_ChDir(conn
, conn
->connectpath
);
851 static int rmdir_acl_common(struct vfs_handle_struct
*handle
,
856 ret
= SMB_VFS_NEXT_RMDIR(handle
, path
);
857 if (!(ret
== -1 && (errno
== EACCES
|| errno
== EPERM
))) {
858 DEBUG(10,("rmdir_acl_common: unlink of %s failed %s\n",
864 return acl_common_remove_object(handle
,
869 static NTSTATUS
create_file_acl_common(struct vfs_handle_struct
*handle
,
870 struct smb_request
*req
,
871 uint16_t root_dir_fid
,
872 struct smb_filename
*smb_fname
,
873 uint32_t access_mask
,
874 uint32_t share_access
,
875 uint32_t create_disposition
,
876 uint32_t create_options
,
877 uint32_t file_attributes
,
878 uint32_t oplock_request
,
879 uint64_t allocation_size
,
880 uint32_t private_flags
,
881 struct security_descriptor
*sd
,
882 struct ea_list
*ea_list
,
883 files_struct
**result
,
886 NTSTATUS status
, status1
;
887 files_struct
*fsp
= NULL
;
889 struct security_descriptor
*parent_sd
= NULL
;
891 status
= SMB_VFS_NEXT_CREATE_FILE(handle
,
908 if (info
!= FILE_WAS_CREATED
) {
909 /* File/directory was opened, not created. */
915 if (!NT_STATUS_IS_OK(status
) || fsp
== NULL
) {
916 /* Only handle success. */
921 /* Security descriptor already set. */
931 /* We must have a cached parent sd in this case.
932 * attached to the handle. */
934 SMB_VFS_HANDLE_GET_DATA(handle
, parent_sd
,
935 struct security_descriptor
,
942 /* New directory - inherit from parent. */
943 status1
= inherit_new_acl(handle
, fsp
, parent_sd
, fsp
->is_directory
);
945 if (!NT_STATUS_IS_OK(status1
)) {
946 DEBUG(1,("create_file_acl_common: error setting "
949 nt_errstr(status1
) ));
954 /* Ensure we never leave attached data around. */
955 SMB_VFS_HANDLE_FREE_DATA(handle
);
957 if (NT_STATUS_IS_OK(status
) && pinfo
) {
964 smb_panic("create_file_acl_common: logic error.\n");
969 static int unlink_acl_common(struct vfs_handle_struct
*handle
,
970 const struct smb_filename
*smb_fname
)
974 ret
= SMB_VFS_NEXT_UNLINK(handle
, smb_fname
);
975 if (!(ret
== -1 && (errno
== EACCES
|| errno
== EPERM
))) {
976 DEBUG(10,("unlink_acl_common: unlink of %s failed %s\n",
977 smb_fname
->base_name
,
981 /* Don't do anything fancy for streams. */
982 if (smb_fname
->stream_name
) {
986 return acl_common_remove_object(handle
,
987 smb_fname
->base_name
,