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 static NTSTATUS
create_acl_blob(const struct security_descriptor
*psd
,
25 uint8_t hash
[XATTR_SD_HASH_SIZE
]);
27 static NTSTATUS
get_acl_blob(TALLOC_CTX
*ctx
,
28 vfs_handle_struct
*handle
,
33 static NTSTATUS
store_acl_blob_fsp(vfs_handle_struct
*handle
,
37 #define HASH_SECURITY_INFO (OWNER_SECURITY_INFORMATION | \
38 GROUP_SECURITY_INFORMATION | \
39 DACL_SECURITY_INFORMATION | \
40 SACL_SECURITY_INFORMATION)
42 /*******************************************************************
43 Hash a security descriptor.
44 *******************************************************************/
46 static NTSTATUS
hash_sd_sha256(struct security_descriptor
*psd
,
53 memset(hash
, '\0', XATTR_SD_HASH_SIZE
);
54 status
= create_acl_blob(psd
, &blob
, XATTR_SD_HASH_TYPE_SHA256
, hash
);
55 if (!NT_STATUS_IS_OK(status
)) {
60 SHA256_Update(&tctx
, blob
.data
, blob
.length
);
61 SHA256_Final(hash
, &tctx
);
66 /*******************************************************************
67 Parse out a struct security_descriptor from a DATA_BLOB.
68 *******************************************************************/
70 static NTSTATUS
parse_acl_blob(const DATA_BLOB
*pblob
,
71 struct security_descriptor
**ppdesc
,
72 uint16_t *p_hash_type
,
73 uint8_t hash
[XATTR_SD_HASH_SIZE
])
75 TALLOC_CTX
*ctx
= talloc_tos();
76 struct xattr_NTACL xacl
;
77 enum ndr_err_code ndr_err
;
80 ndr_err
= ndr_pull_struct_blob(pblob
, ctx
, NULL
, &xacl
,
81 (ndr_pull_flags_fn_t
)ndr_pull_xattr_NTACL
);
83 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
84 DEBUG(5, ("parse_acl_blob: ndr_pull_xattr_NTACL failed: %s\n",
85 ndr_errstr(ndr_err
)));
86 return ndr_map_error2ntstatus(ndr_err
);;
89 switch (xacl
.version
) {
91 *ppdesc
= make_sec_desc(ctx
, SEC_DESC_REVISION
,
92 xacl
.info
.sd_hs2
->sd
->type
| SEC_DESC_SELF_RELATIVE
,
93 xacl
.info
.sd_hs2
->sd
->owner_sid
,
94 xacl
.info
.sd_hs2
->sd
->group_sid
,
95 xacl
.info
.sd_hs2
->sd
->sacl
,
96 xacl
.info
.sd_hs2
->sd
->dacl
,
98 /* No hash - null out. */
99 *p_hash_type
= XATTR_SD_HASH_TYPE_NONE
;
100 memset(hash
, '\0', XATTR_SD_HASH_SIZE
);
103 *ppdesc
= make_sec_desc(ctx
, SEC_DESC_REVISION
,
104 xacl
.info
.sd_hs3
->sd
->type
| SEC_DESC_SELF_RELATIVE
,
105 xacl
.info
.sd_hs3
->sd
->owner_sid
,
106 xacl
.info
.sd_hs3
->sd
->group_sid
,
107 xacl
.info
.sd_hs3
->sd
->sacl
,
108 xacl
.info
.sd_hs3
->sd
->dacl
,
110 *p_hash_type
= xacl
.info
.sd_hs3
->hash_type
;
111 /* Current version 3. */
112 memcpy(hash
, xacl
.info
.sd_hs3
->hash
, XATTR_SD_HASH_SIZE
);
115 return NT_STATUS_REVISION_MISMATCH
;
118 TALLOC_FREE(xacl
.info
.sd
);
120 return (*ppdesc
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
123 /*******************************************************************
124 Create a DATA_BLOB from a security descriptor.
125 *******************************************************************/
127 static NTSTATUS
create_acl_blob(const struct security_descriptor
*psd
,
130 uint8_t hash
[XATTR_SD_HASH_SIZE
])
132 struct xattr_NTACL xacl
;
133 struct security_descriptor_hash_v3 sd_hs3
;
134 enum ndr_err_code ndr_err
;
135 TALLOC_CTX
*ctx
= talloc_tos();
141 xacl
.info
.sd_hs3
= &sd_hs3
;
142 xacl
.info
.sd_hs3
->sd
= CONST_DISCARD(struct security_descriptor
*, psd
);
143 xacl
.info
.sd_hs3
->hash_type
= hash_type
;
144 memcpy(&xacl
.info
.sd_hs3
->hash
[0], hash
, XATTR_SD_HASH_SIZE
);
146 ndr_err
= ndr_push_struct_blob(
147 pblob
, ctx
, NULL
, &xacl
,
148 (ndr_push_flags_fn_t
)ndr_push_xattr_NTACL
);
150 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
151 DEBUG(5, ("create_acl_blob: ndr_push_xattr_NTACL failed: %s\n",
152 ndr_errstr(ndr_err
)));
153 return ndr_map_error2ntstatus(ndr_err
);;
159 /*******************************************************************
160 Add in 3 inheritable components for a non-inheritable directory ACL.
161 CREATOR_OWNER/CREATOR_GROUP/WORLD.
162 *******************************************************************/
164 static void add_directory_inheritable_components(vfs_handle_struct
*handle
,
166 SMB_STRUCT_STAT
*psbuf
,
167 struct security_descriptor
*psd
)
169 struct connection_struct
*conn
= handle
->conn
;
170 int num_aces
= (psd
->dacl
? psd
->dacl
->num_aces
: 0);
171 struct smb_filename smb_fname
;
172 enum security_ace_type acltype
;
173 uint32_t access_mask
;
177 struct security_ace
*new_ace_list
= TALLOC_ZERO_ARRAY(talloc_tos(),
181 if (new_ace_list
== NULL
) {
185 /* Fake a quick smb_filename. */
186 ZERO_STRUCT(smb_fname
);
187 smb_fname
.st
= *psbuf
;
188 smb_fname
.base_name
= CONST_DISCARD(char *, name
);
190 dir_mode
= unix_mode(conn
,
191 FILE_ATTRIBUTE_DIRECTORY
, &smb_fname
, NULL
);
192 file_mode
= unix_mode(conn
,
193 FILE_ATTRIBUTE_ARCHIVE
, &smb_fname
, NULL
);
195 mode
= dir_mode
| file_mode
;
197 DEBUG(10, ("add_directory_inheritable_components: directory %s, "
200 (unsigned int)mode
));
203 memcpy(new_ace_list
, psd
->dacl
->aces
,
204 num_aces
* sizeof(struct security_ace
));
206 access_mask
= map_canon_ace_perms(SNUM(conn
), &acltype
,
209 init_sec_ace(&new_ace_list
[num_aces
],
210 &global_sid_Creator_Owner
,
213 SEC_ACE_FLAG_CONTAINER_INHERIT
|
214 SEC_ACE_FLAG_OBJECT_INHERIT
|
215 SEC_ACE_FLAG_INHERIT_ONLY
);
216 access_mask
= map_canon_ace_perms(SNUM(conn
), &acltype
,
217 (mode
<< 3) & 0700, false);
218 init_sec_ace(&new_ace_list
[num_aces
+1],
219 &global_sid_Creator_Group
,
222 SEC_ACE_FLAG_CONTAINER_INHERIT
|
223 SEC_ACE_FLAG_OBJECT_INHERIT
|
224 SEC_ACE_FLAG_INHERIT_ONLY
);
225 access_mask
= map_canon_ace_perms(SNUM(conn
), &acltype
,
226 (mode
<< 6) & 0700, false);
227 init_sec_ace(&new_ace_list
[num_aces
+2],
231 SEC_ACE_FLAG_CONTAINER_INHERIT
|
232 SEC_ACE_FLAG_OBJECT_INHERIT
|
233 SEC_ACE_FLAG_INHERIT_ONLY
);
234 psd
->dacl
->aces
= new_ace_list
;
235 psd
->dacl
->num_aces
+= 3;
238 /*******************************************************************
239 Pull a DATA_BLOB from an xattr given a pathname.
240 If the hash doesn't match, or doesn't exist - return the underlying
242 *******************************************************************/
244 static NTSTATUS
get_nt_acl_internal(vfs_handle_struct
*handle
,
247 uint32_t security_info
,
248 struct security_descriptor
**ppdesc
)
253 uint8_t hash
[XATTR_SD_HASH_SIZE
];
254 uint8_t hash_tmp
[XATTR_SD_HASH_SIZE
];
255 struct security_descriptor
*psd
= NULL
;
256 struct security_descriptor
*pdesc_next
= NULL
;
258 if (fsp
&& name
== NULL
) {
259 name
= fsp
->fsp_name
->base_name
;
262 DEBUG(10, ("get_nt_acl_internal: name=%s\n", name
));
264 /* Get the full underlying sd for the hash
265 or to return as backup. */
267 status
= SMB_VFS_NEXT_FGET_NT_ACL(handle
,
272 status
= SMB_VFS_NEXT_GET_NT_ACL(handle
,
278 if (!NT_STATUS_IS_OK(status
)) {
279 DEBUG(10, ("get_nt_acl_internal: get_next_acl for file %s "
286 status
= get_acl_blob(talloc_tos(), handle
, fsp
, name
, &blob
);
287 if (!NT_STATUS_IS_OK(status
)) {
288 DEBUG(10, ("get_nt_acl_internal: get_acl_blob returned %s\n",
294 status
= parse_acl_blob(&blob
, &psd
,
295 &hash_type
, &hash
[0]);
296 if (!NT_STATUS_IS_OK(status
)) {
297 DEBUG(10, ("parse_acl_blob returned %s\n",
303 /* Ensure the hash type is one we know. */
305 case XATTR_SD_HASH_TYPE_NONE
:
306 /* No hash, just return blob sd. */
308 case XATTR_SD_HASH_TYPE_SHA256
:
311 DEBUG(10, ("get_nt_acl_internal: ACL blob revision "
312 "mismatch (%u) for file %s\n",
313 (unsigned int)hash_type
,
321 status
= hash_sd_sha256(pdesc_next
, hash_tmp
);
322 if (!NT_STATUS_IS_OK(status
)) {
328 if (memcmp(&hash
[0], &hash_tmp
[0], XATTR_SD_HASH_SIZE
) == 0) {
329 /* Hash matches, return blob sd. */
333 /* Hash doesn't match, return underlying sd. */
339 if (psd
!= pdesc_next
) {
340 /* We're returning the blob, throw
341 * away the filesystem SD. */
342 TALLOC_FREE(pdesc_next
);
344 SMB_STRUCT_STAT sbuf
;
345 SMB_STRUCT_STAT
*psbuf
= &sbuf
;
346 bool is_directory
= false;
348 * We're returning the underlying ACL from the
349 * filesystem. If it's a directory, and has no
350 * inheritable ACE entries we have to fake them.
353 is_directory
= fsp
->is_directory
;
354 psbuf
= &fsp
->fsp_name
->st
;
356 if (vfs_stat_smb_fname(handle
->conn
,
359 is_directory
= S_ISDIR(sbuf
.st_ex_mode
);
363 !sd_has_inheritable_components(psd
,
365 add_directory_inheritable_components(handle
,
372 if (!(security_info
& OWNER_SECURITY_INFORMATION
)) {
373 psd
->owner_sid
= NULL
;
375 if (!(security_info
& GROUP_SECURITY_INFORMATION
)) {
376 psd
->group_sid
= NULL
;
378 if (!(security_info
& DACL_SECURITY_INFORMATION
)) {
381 if (!(security_info
& SACL_SECURITY_INFORMATION
)) {
385 TALLOC_FREE(blob
.data
);
390 /*********************************************************************
391 Create a default ACL by inheriting from the parent. If no inheritance
392 from the parent available, don't set anything. This will leave the actual
393 permissions the new file or directory already got from the filesystem
394 as the NT ACL when read.
395 *********************************************************************/
397 static NTSTATUS
inherit_new_acl(vfs_handle_struct
*handle
,
399 struct security_descriptor
*parent_desc
,
402 TALLOC_CTX
*ctx
= talloc_tos();
403 NTSTATUS status
= NT_STATUS_OK
;
404 struct security_descriptor
*psd
= NULL
;
407 if (!sd_has_inheritable_components(parent_desc
, is_directory
)) {
411 /* Create an inherited descriptor from the parent. */
413 if (DEBUGLEVEL
>= 10) {
414 DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
416 NDR_PRINT_DEBUG(security_descriptor
, parent_desc
);
419 status
= se_create_child_secdesc(ctx
,
423 &handle
->conn
->server_info
->ptok
->user_sids
[PRIMARY_USER_SID_INDEX
],
424 &handle
->conn
->server_info
->ptok
->user_sids
[PRIMARY_GROUP_SID_INDEX
],
426 if (!NT_STATUS_IS_OK(status
)) {
430 if (DEBUGLEVEL
>= 10) {
431 DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
433 NDR_PRINT_DEBUG(security_descriptor
, parent_desc
);
436 return SMB_VFS_FSET_NT_ACL(fsp
,
437 (OWNER_SECURITY_INFORMATION
|
438 GROUP_SECURITY_INFORMATION
|
439 DACL_SECURITY_INFORMATION
),
443 static NTSTATUS
check_parent_acl_common(vfs_handle_struct
*handle
,
445 uint32_t access_mask
,
446 struct security_descriptor
**pp_parent_desc
)
448 char *parent_name
= NULL
;
449 struct security_descriptor
*parent_desc
= NULL
;
450 uint32_t access_granted
= 0;
453 if (!parent_dirname(talloc_tos(), path
, &parent_name
, NULL
)) {
454 return NT_STATUS_NO_MEMORY
;
457 status
= get_nt_acl_internal(handle
,
460 (OWNER_SECURITY_INFORMATION
|
461 GROUP_SECURITY_INFORMATION
|
462 DACL_SECURITY_INFORMATION
),
465 if (!NT_STATUS_IS_OK(status
)) {
466 DEBUG(10,("check_parent_acl_common: get_nt_acl_internal "
467 "on directory %s for "
468 "path %s returned %s\n",
471 nt_errstr(status
) ));
474 status
= smb1_file_se_access_check(parent_desc
,
475 handle
->conn
->server_info
->ptok
,
478 if(!NT_STATUS_IS_OK(status
)) {
479 DEBUG(10,("check_parent_acl_common: access check "
480 "on directory %s for "
481 "path %s for mask 0x%x returned %s\n",
485 nt_errstr(status
) ));
488 if (pp_parent_desc
) {
489 *pp_parent_desc
= parent_desc
;
494 static void free_sd_common(void **ptr
)
499 /*********************************************************************
500 Check ACL on open. For new files inherit from parent directory.
501 *********************************************************************/
503 static int open_acl_common(vfs_handle_struct
*handle
,
504 struct smb_filename
*smb_fname
,
509 uint32_t access_granted
= 0;
510 struct security_descriptor
*pdesc
= NULL
;
511 struct security_descriptor
*parent_desc
= NULL
;
512 bool file_existed
= true;
517 /* Stream open. Base filename open already did the ACL check. */
518 DEBUG(10,("open_acl_common: stream open on %s\n",
520 return SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
, mode
);
523 status
= get_full_smb_filename(talloc_tos(), smb_fname
,
525 if (!NT_STATUS_IS_OK(status
)) {
529 status
= get_nt_acl_internal(handle
,
532 (OWNER_SECURITY_INFORMATION
|
533 GROUP_SECURITY_INFORMATION
|
534 DACL_SECURITY_INFORMATION
),
536 if (NT_STATUS_IS_OK(status
)) {
537 /* See if we can access it. */
538 status
= smb1_file_se_access_check(pdesc
,
539 handle
->conn
->server_info
->ptok
,
542 if (!NT_STATUS_IS_OK(status
)) {
543 DEBUG(10,("open_acl_xattr: %s open "
544 "refused with error %s\n",
546 nt_errstr(status
) ));
549 } else if (NT_STATUS_EQUAL(status
,NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
550 file_existed
= false;
552 * If O_CREAT is true then we're trying to create a file.
553 * Check the parent directory ACL will allow this.
555 if (flags
& O_CREAT
) {
556 struct security_descriptor
*psd
= NULL
;
558 status
= check_parent_acl_common(handle
, fname
,
559 SEC_DIR_ADD_FILE
, &parent_desc
);
560 if (!NT_STATUS_IS_OK(status
)) {
563 /* Cache the parent security descriptor for
564 * later use. We do have an fsp here, but to
565 * keep the code consistent with the directory
566 * case which doesn't, use the handle. */
568 /* Attach this to the conn, move from talloc_tos(). */
569 psd
= (struct security_descriptor
*)talloc_move(handle
->conn
,
573 status
= NT_STATUS_NO_MEMORY
;
576 status
= NT_STATUS_NO_MEMORY
;
577 SMB_VFS_HANDLE_SET_DATA(handle
, psd
, free_sd_common
,
578 struct security_descriptor
*, goto err
);
579 status
= NT_STATUS_OK
;
583 DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
586 nt_errstr(status
) ));
588 fsp
->fh
->fd
= SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
, mode
);
593 errno
= map_errno_from_nt_status(status
);
597 static int mkdir_acl_common(vfs_handle_struct
*handle
, const char *path
, mode_t mode
)
601 SMB_STRUCT_STAT sbuf
;
603 ret
= vfs_stat_smb_fname(handle
->conn
, path
, &sbuf
);
604 if (ret
== -1 && errno
== ENOENT
) {
605 struct security_descriptor
*parent_desc
= NULL
;
606 struct security_descriptor
*psd
= NULL
;
608 /* We're creating a new directory. */
609 status
= check_parent_acl_common(handle
, path
,
610 SEC_DIR_ADD_SUBDIR
, &parent_desc
);
611 if (!NT_STATUS_IS_OK(status
)) {
612 errno
= map_errno_from_nt_status(status
);
616 /* Cache the parent security descriptor for
617 * later use. We don't have an fsp here so
620 /* Attach this to the conn, move from talloc_tos(). */
621 psd
= (struct security_descriptor
*)talloc_move(handle
->conn
,
627 SMB_VFS_HANDLE_SET_DATA(handle
, psd
, free_sd_common
,
628 struct security_descriptor
*, return -1);
631 return SMB_VFS_NEXT_MKDIR(handle
, path
, mode
);
634 /*********************************************************************
635 Fetch a security descriptor given an fsp.
636 *********************************************************************/
638 static NTSTATUS
fget_nt_acl_common(vfs_handle_struct
*handle
, files_struct
*fsp
,
639 uint32_t security_info
, struct security_descriptor
**ppdesc
)
641 return get_nt_acl_internal(handle
, fsp
,
642 NULL
, security_info
, ppdesc
);
645 /*********************************************************************
646 Fetch a security descriptor given a pathname.
647 *********************************************************************/
649 static NTSTATUS
get_nt_acl_common(vfs_handle_struct
*handle
,
650 const char *name
, uint32_t security_info
, struct security_descriptor
**ppdesc
)
652 return get_nt_acl_internal(handle
, NULL
,
653 name
, security_info
, ppdesc
);
656 /*********************************************************************
657 Store a security descriptor given an fsp.
658 *********************************************************************/
660 static NTSTATUS
fset_nt_acl_common(vfs_handle_struct
*handle
, files_struct
*fsp
,
661 uint32_t security_info_sent
, const struct security_descriptor
*psd
)
665 struct security_descriptor
*pdesc_next
= NULL
;
666 uint8_t hash
[XATTR_SD_HASH_SIZE
];
668 if (DEBUGLEVEL
>= 10) {
669 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
671 NDR_PRINT_DEBUG(security_descriptor
,
672 CONST_DISCARD(struct security_descriptor
*,psd
));
675 /* Ensure we have OWNER/GROUP/DACL set. */
677 if ((security_info_sent
& (OWNER_SECURITY_INFORMATION
|
678 GROUP_SECURITY_INFORMATION
|
679 DACL_SECURITY_INFORMATION
)) !=
680 (OWNER_SECURITY_INFORMATION
|
681 GROUP_SECURITY_INFORMATION
|
682 DACL_SECURITY_INFORMATION
)) {
683 /* No we don't - read from the existing SD. */
684 struct security_descriptor
*nc_psd
= NULL
;
686 status
= get_nt_acl_internal(handle
, fsp
,
688 (OWNER_SECURITY_INFORMATION
|
689 GROUP_SECURITY_INFORMATION
|
690 DACL_SECURITY_INFORMATION
),
693 if (!NT_STATUS_IS_OK(status
)) {
697 /* This is safe as nc_psd is discarded at fn exit. */
698 if (security_info_sent
& OWNER_SECURITY_INFORMATION
) {
699 nc_psd
->owner_sid
= psd
->owner_sid
;
701 security_info_sent
|= OWNER_SECURITY_INFORMATION
;
703 if (security_info_sent
& GROUP_SECURITY_INFORMATION
) {
704 nc_psd
->group_sid
= psd
->group_sid
;
706 security_info_sent
|= GROUP_SECURITY_INFORMATION
;
708 if (security_info_sent
& DACL_SECURITY_INFORMATION
) {
709 nc_psd
->dacl
= dup_sec_acl(talloc_tos(), psd
->dacl
);
710 if (nc_psd
->dacl
== NULL
) {
711 return NT_STATUS_NO_MEMORY
;
714 security_info_sent
|= DACL_SECURITY_INFORMATION
;
718 status
= SMB_VFS_NEXT_FSET_NT_ACL(handle
, fsp
, security_info_sent
, psd
);
719 if (!NT_STATUS_IS_OK(status
)) {
723 /* Get the full underlying sd, then hash. */
724 status
= SMB_VFS_NEXT_FGET_NT_ACL(handle
,
729 if (!NT_STATUS_IS_OK(status
)) {
733 status
= hash_sd_sha256(pdesc_next
, hash
);
734 if (!NT_STATUS_IS_OK(status
)) {
738 if (DEBUGLEVEL
>= 10) {
739 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
741 NDR_PRINT_DEBUG(security_descriptor
,
742 CONST_DISCARD(struct security_descriptor
*,psd
));
744 create_acl_blob(psd
, &blob
, XATTR_SD_HASH_TYPE_SHA256
, hash
);
745 store_acl_blob_fsp(handle
, fsp
, &blob
);
750 static SMB_STRUCT_DIR
*opendir_acl_common(vfs_handle_struct
*handle
,
751 const char *fname
, const char *mask
, uint32 attr
)
753 NTSTATUS status
= check_parent_acl_common(handle
, fname
,
756 if (!NT_STATUS_IS_OK(status
)) {
757 errno
= map_errno_from_nt_status(status
);
760 return SMB_VFS_NEXT_OPENDIR(handle
, fname
, mask
, attr
);
763 static int acl_common_remove_object(vfs_handle_struct
*handle
,
767 connection_struct
*conn
= handle
->conn
;
769 files_struct
*fsp
= NULL
;
771 char *parent_dir
= NULL
;
772 const char *final_component
= NULL
;
773 struct smb_filename local_fname
;
776 if (!parent_dirname(talloc_tos(), path
,
777 &parent_dir
, &final_component
)) {
778 saved_errno
= ENOMEM
;
782 DEBUG(10,("acl_common_remove_object: removing %s %s/%s\n",
783 is_directory
? "directory" : "file",
784 parent_dir
, final_component
));
786 /* cd into the parent dir to pin it. */
787 ret
= SMB_VFS_CHDIR(conn
, parent_dir
);
793 ZERO_STRUCT(local_fname
);
794 local_fname
.base_name
= CONST_DISCARD(char *,final_component
);
796 /* Must use lstat here. */
797 ret
= SMB_VFS_LSTAT(conn
, &local_fname
);
803 /* Ensure we have this file open with DELETE access. */
804 id
= vfs_file_id_from_sbuf(conn
, &local_fname
.st
);
805 for (fsp
= file_find_di_first(id
); fsp
; file_find_di_next(fsp
)) {
806 if (fsp
->access_mask
& DELETE_ACCESS
&&
807 fsp
->delete_on_close
) {
808 /* We did open this for delete,
809 * allow the delete as root.
816 DEBUG(10,("acl_common_remove_object: %s %s/%s "
817 "not an open file\n",
818 is_directory
? "directory" : "file",
819 parent_dir
, final_component
));
820 saved_errno
= EACCES
;
826 ret
= SMB_VFS_NEXT_RMDIR(handle
, final_component
);
828 ret
= SMB_VFS_NEXT_UNLINK(handle
, &local_fname
);
838 TALLOC_FREE(parent_dir
);
840 vfs_ChDir(conn
, conn
->connectpath
);
847 static int rmdir_acl_common(struct vfs_handle_struct
*handle
,
852 ret
= SMB_VFS_NEXT_RMDIR(handle
, path
);
853 if (!(ret
== -1 && (errno
== EACCES
|| errno
== EPERM
))) {
854 DEBUG(10,("rmdir_acl_common: unlink of %s failed %s\n",
860 return acl_common_remove_object(handle
,
865 static NTSTATUS
create_file_acl_common(struct vfs_handle_struct
*handle
,
866 struct smb_request
*req
,
867 uint16_t root_dir_fid
,
868 struct smb_filename
*smb_fname
,
869 uint32_t access_mask
,
870 uint32_t share_access
,
871 uint32_t create_disposition
,
872 uint32_t create_options
,
873 uint32_t file_attributes
,
874 uint32_t oplock_request
,
875 uint64_t allocation_size
,
876 uint32_t private_flags
,
877 struct security_descriptor
*sd
,
878 struct ea_list
*ea_list
,
879 files_struct
**result
,
882 NTSTATUS status
, status1
;
883 files_struct
*fsp
= NULL
;
885 struct security_descriptor
*parent_sd
= NULL
;
887 status
= SMB_VFS_NEXT_CREATE_FILE(handle
,
904 if (info
!= FILE_WAS_CREATED
) {
905 /* File/directory was opened, not created. */
911 if (!NT_STATUS_IS_OK(status
) || fsp
== NULL
) {
912 /* Only handle success. */
917 /* Security descriptor already set. */
927 /* We must have a cached parent sd in this case.
928 * attached to the handle. */
930 SMB_VFS_HANDLE_GET_DATA(handle
, parent_sd
,
931 struct security_descriptor
,
938 /* New directory - inherit from parent. */
939 status1
= inherit_new_acl(handle
, fsp
, parent_sd
, fsp
->is_directory
);
941 if (!NT_STATUS_IS_OK(status1
)) {
942 DEBUG(1,("create_file_acl_common: error setting "
945 nt_errstr(status1
) ));
950 /* Ensure we never leave attached data around. */
951 SMB_VFS_HANDLE_FREE_DATA(handle
);
953 if (NT_STATUS_IS_OK(status
) && pinfo
) {
960 smb_panic("create_file_acl_common: logic error.\n");
965 static int unlink_acl_common(struct vfs_handle_struct
*handle
,
966 const struct smb_filename
*smb_fname
)
970 ret
= SMB_VFS_NEXT_UNLINK(handle
, smb_fname
);
971 if (!(ret
== -1 && (errno
== EACCES
|| errno
== EPERM
))) {
972 DEBUG(10,("unlink_acl_common: unlink of %s failed %s\n",
973 smb_fname
->base_name
,
977 /* Don't do anything fancy for streams. */
978 if (smb_fname
->stream_name
) {
982 return acl_common_remove_object(handle
,
983 smb_fname
->base_name
,