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. */
330 DEBUG(10, ("get_nt_acl_internal: blob hash "
331 "matches for file %s\n",
336 /* Hash doesn't match, return underlying sd. */
342 if (psd
!= pdesc_next
) {
343 /* We're returning the blob, throw
344 * away the filesystem SD. */
345 TALLOC_FREE(pdesc_next
);
347 SMB_STRUCT_STAT sbuf
;
348 SMB_STRUCT_STAT
*psbuf
= &sbuf
;
349 bool is_directory
= false;
351 * We're returning the underlying ACL from the
352 * filesystem. If it's a directory, and has no
353 * inheritable ACE entries we have to fake them.
356 is_directory
= fsp
->is_directory
;
357 psbuf
= &fsp
->fsp_name
->st
;
359 if (vfs_stat_smb_fname(handle
->conn
,
362 is_directory
= S_ISDIR(sbuf
.st_ex_mode
);
366 !sd_has_inheritable_components(psd
,
368 add_directory_inheritable_components(handle
,
373 /* The underlying POSIX module always sets
374 the ~SEC_DESC_DACL_PROTECTED bit, as ACLs
375 can't be inherited in this way under POSIX.
376 Remove it for Windows-style ACLs. */
377 psd
->type
&= ~SEC_DESC_DACL_PROTECTED
;
380 if (!(security_info
& OWNER_SECURITY_INFORMATION
)) {
381 psd
->owner_sid
= NULL
;
383 if (!(security_info
& GROUP_SECURITY_INFORMATION
)) {
384 psd
->group_sid
= NULL
;
386 if (!(security_info
& DACL_SECURITY_INFORMATION
)) {
389 if (!(security_info
& SACL_SECURITY_INFORMATION
)) {
393 TALLOC_FREE(blob
.data
);
398 /*********************************************************************
399 Create a default ACL by inheriting from the parent. If no inheritance
400 from the parent available, don't set anything. This will leave the actual
401 permissions the new file or directory already got from the filesystem
402 as the NT ACL when read.
403 *********************************************************************/
405 static NTSTATUS
inherit_new_acl(vfs_handle_struct
*handle
,
407 struct security_descriptor
*parent_desc
,
410 TALLOC_CTX
*ctx
= talloc_tos();
411 NTSTATUS status
= NT_STATUS_OK
;
412 struct security_descriptor
*psd
= NULL
;
415 if (!sd_has_inheritable_components(parent_desc
, is_directory
)) {
419 /* Create an inherited descriptor from the parent. */
421 if (DEBUGLEVEL
>= 10) {
422 DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
424 NDR_PRINT_DEBUG(security_descriptor
, parent_desc
);
427 status
= se_create_child_secdesc(ctx
,
431 &handle
->conn
->server_info
->ptok
->user_sids
[PRIMARY_USER_SID_INDEX
],
432 &handle
->conn
->server_info
->ptok
->user_sids
[PRIMARY_GROUP_SID_INDEX
],
434 if (!NT_STATUS_IS_OK(status
)) {
438 if (DEBUGLEVEL
>= 10) {
439 DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
441 NDR_PRINT_DEBUG(security_descriptor
, parent_desc
);
444 return SMB_VFS_FSET_NT_ACL(fsp
,
445 (OWNER_SECURITY_INFORMATION
|
446 GROUP_SECURITY_INFORMATION
|
447 DACL_SECURITY_INFORMATION
),
451 static NTSTATUS
check_parent_acl_common(vfs_handle_struct
*handle
,
453 uint32_t access_mask
,
454 struct security_descriptor
**pp_parent_desc
)
456 char *parent_name
= NULL
;
457 struct security_descriptor
*parent_desc
= NULL
;
458 uint32_t access_granted
= 0;
461 if (!parent_dirname(talloc_tos(), path
, &parent_name
, NULL
)) {
462 return NT_STATUS_NO_MEMORY
;
465 status
= get_nt_acl_internal(handle
,
468 (OWNER_SECURITY_INFORMATION
|
469 GROUP_SECURITY_INFORMATION
|
470 DACL_SECURITY_INFORMATION
),
473 if (!NT_STATUS_IS_OK(status
)) {
474 DEBUG(10,("check_parent_acl_common: get_nt_acl_internal "
475 "on directory %s for "
476 "path %s returned %s\n",
479 nt_errstr(status
) ));
482 status
= smb1_file_se_access_check(handle
->conn
,
484 handle
->conn
->server_info
->ptok
,
487 if(!NT_STATUS_IS_OK(status
)) {
488 DEBUG(10,("check_parent_acl_common: access check "
489 "on directory %s for "
490 "path %s for mask 0x%x returned %s\n",
494 nt_errstr(status
) ));
497 if (pp_parent_desc
) {
498 *pp_parent_desc
= parent_desc
;
503 static void free_sd_common(void **ptr
)
508 /*********************************************************************
509 Check ACL on open. For new files inherit from parent directory.
510 *********************************************************************/
512 static int open_acl_common(vfs_handle_struct
*handle
,
513 struct smb_filename
*smb_fname
,
518 uint32_t access_granted
= 0;
519 struct security_descriptor
*pdesc
= NULL
;
520 struct security_descriptor
*parent_desc
= NULL
;
521 bool file_existed
= true;
526 /* Stream open. Base filename open already did the ACL check. */
527 DEBUG(10,("open_acl_common: stream open on %s\n",
529 return SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
, mode
);
532 status
= get_full_smb_filename(talloc_tos(), smb_fname
,
534 if (!NT_STATUS_IS_OK(status
)) {
538 status
= get_nt_acl_internal(handle
,
541 (OWNER_SECURITY_INFORMATION
|
542 GROUP_SECURITY_INFORMATION
|
543 DACL_SECURITY_INFORMATION
),
545 if (NT_STATUS_IS_OK(status
)) {
546 /* See if we can access it. */
547 status
= smb1_file_se_access_check(handle
->conn
,
549 handle
->conn
->server_info
->ptok
,
552 if (!NT_STATUS_IS_OK(status
)) {
553 DEBUG(10,("open_acl_xattr: %s open "
554 "refused with error %s\n",
556 nt_errstr(status
) ));
559 } else if (NT_STATUS_EQUAL(status
,NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
560 file_existed
= false;
562 * If O_CREAT is true then we're trying to create a file.
563 * Check the parent directory ACL will allow this.
565 if (flags
& O_CREAT
) {
566 struct security_descriptor
*psd
= NULL
;
568 status
= check_parent_acl_common(handle
, fname
,
569 SEC_DIR_ADD_FILE
, &parent_desc
);
570 if (!NT_STATUS_IS_OK(status
)) {
573 /* Cache the parent security descriptor for
574 * later use. We do have an fsp here, but to
575 * keep the code consistent with the directory
576 * case which doesn't, use the handle. */
578 /* Attach this to the conn, move from talloc_tos(). */
579 psd
= (struct security_descriptor
*)talloc_move(handle
->conn
,
583 status
= NT_STATUS_NO_MEMORY
;
586 status
= NT_STATUS_NO_MEMORY
;
587 SMB_VFS_HANDLE_SET_DATA(handle
, psd
, free_sd_common
,
588 struct security_descriptor
*, goto err
);
589 status
= NT_STATUS_OK
;
593 DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
596 nt_errstr(status
) ));
598 fsp
->fh
->fd
= SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
, mode
);
603 errno
= map_errno_from_nt_status(status
);
607 static int mkdir_acl_common(vfs_handle_struct
*handle
, const char *path
, mode_t mode
)
611 SMB_STRUCT_STAT sbuf
;
613 ret
= vfs_stat_smb_fname(handle
->conn
, path
, &sbuf
);
614 if (ret
== -1 && errno
== ENOENT
) {
615 struct security_descriptor
*parent_desc
= NULL
;
616 struct security_descriptor
*psd
= NULL
;
618 /* We're creating a new directory. */
619 status
= check_parent_acl_common(handle
, path
,
620 SEC_DIR_ADD_SUBDIR
, &parent_desc
);
621 if (!NT_STATUS_IS_OK(status
)) {
622 errno
= map_errno_from_nt_status(status
);
626 /* Cache the parent security descriptor for
627 * later use. We don't have an fsp here so
630 /* Attach this to the conn, move from talloc_tos(). */
631 psd
= (struct security_descriptor
*)talloc_move(handle
->conn
,
637 SMB_VFS_HANDLE_SET_DATA(handle
, psd
, free_sd_common
,
638 struct security_descriptor
*, return -1);
641 return SMB_VFS_NEXT_MKDIR(handle
, path
, mode
);
644 /*********************************************************************
645 Fetch a security descriptor given an fsp.
646 *********************************************************************/
648 static NTSTATUS
fget_nt_acl_common(vfs_handle_struct
*handle
, files_struct
*fsp
,
649 uint32_t security_info
, struct security_descriptor
**ppdesc
)
651 return get_nt_acl_internal(handle
, fsp
,
652 NULL
, security_info
, ppdesc
);
655 /*********************************************************************
656 Fetch a security descriptor given a pathname.
657 *********************************************************************/
659 static NTSTATUS
get_nt_acl_common(vfs_handle_struct
*handle
,
660 const char *name
, uint32_t security_info
, struct security_descriptor
**ppdesc
)
662 return get_nt_acl_internal(handle
, NULL
,
663 name
, security_info
, ppdesc
);
666 /*********************************************************************
667 Store a security descriptor given an fsp.
668 *********************************************************************/
670 static NTSTATUS
fset_nt_acl_common(vfs_handle_struct
*handle
, files_struct
*fsp
,
671 uint32_t security_info_sent
, const struct security_descriptor
*orig_psd
)
675 struct security_descriptor
*pdesc_next
= NULL
;
676 struct security_descriptor
*psd
= NULL
;
677 uint8_t hash
[XATTR_SD_HASH_SIZE
];
679 if (DEBUGLEVEL
>= 10) {
680 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
682 NDR_PRINT_DEBUG(security_descriptor
,
683 CONST_DISCARD(struct security_descriptor
*,orig_psd
));
686 status
= get_nt_acl_internal(handle
, fsp
,
688 SECINFO_OWNER
|SECINFO_GROUP
|SECINFO_DACL
|SECINFO_SACL
,
691 if (!NT_STATUS_IS_OK(status
)) {
695 if ((security_info_sent
& SECINFO_OWNER
) && (orig_psd
->owner_sid
!= NULL
)) {
696 psd
->owner_sid
= orig_psd
->owner_sid
;
698 if ((security_info_sent
& SECINFO_GROUP
) && (orig_psd
->group_sid
!= NULL
)) {
699 psd
->group_sid
= orig_psd
->group_sid
;
701 if (security_info_sent
& SECINFO_DACL
) {
702 psd
->dacl
= orig_psd
->dacl
;
704 if (security_info_sent
& SECINFO_SACL
) {
705 psd
->sacl
= orig_psd
->sacl
;
708 status
= SMB_VFS_NEXT_FSET_NT_ACL(handle
, fsp
, security_info_sent
, psd
);
709 if (!NT_STATUS_IS_OK(status
)) {
713 /* Get the full underlying sd, then hash. */
714 status
= SMB_VFS_NEXT_FGET_NT_ACL(handle
,
719 if (!NT_STATUS_IS_OK(status
)) {
723 status
= hash_sd_sha256(pdesc_next
, hash
);
724 if (!NT_STATUS_IS_OK(status
)) {
728 if (DEBUGLEVEL
>= 10) {
729 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
731 NDR_PRINT_DEBUG(security_descriptor
,
732 CONST_DISCARD(struct security_descriptor
*,psd
));
734 create_acl_blob(psd
, &blob
, XATTR_SD_HASH_TYPE_SHA256
, hash
);
735 store_acl_blob_fsp(handle
, fsp
, &blob
);
740 static SMB_STRUCT_DIR
*opendir_acl_common(vfs_handle_struct
*handle
,
741 const char *fname
, const char *mask
, uint32 attr
)
743 NTSTATUS status
= check_parent_acl_common(handle
, fname
,
746 if (!NT_STATUS_IS_OK(status
)) {
747 errno
= map_errno_from_nt_status(status
);
750 return SMB_VFS_NEXT_OPENDIR(handle
, fname
, mask
, attr
);
753 static int acl_common_remove_object(vfs_handle_struct
*handle
,
757 connection_struct
*conn
= handle
->conn
;
759 files_struct
*fsp
= NULL
;
761 char *parent_dir
= NULL
;
762 const char *final_component
= NULL
;
763 struct smb_filename local_fname
;
766 if (!parent_dirname(talloc_tos(), path
,
767 &parent_dir
, &final_component
)) {
768 saved_errno
= ENOMEM
;
772 DEBUG(10,("acl_common_remove_object: removing %s %s/%s\n",
773 is_directory
? "directory" : "file",
774 parent_dir
, final_component
));
776 /* cd into the parent dir to pin it. */
777 ret
= SMB_VFS_CHDIR(conn
, parent_dir
);
783 ZERO_STRUCT(local_fname
);
784 local_fname
.base_name
= CONST_DISCARD(char *,final_component
);
786 /* Must use lstat here. */
787 ret
= SMB_VFS_LSTAT(conn
, &local_fname
);
793 /* Ensure we have this file open with DELETE access. */
794 id
= vfs_file_id_from_sbuf(conn
, &local_fname
.st
);
795 for (fsp
= file_find_di_first(id
); fsp
; file_find_di_next(fsp
)) {
796 if (fsp
->access_mask
& DELETE_ACCESS
&&
797 fsp
->delete_on_close
) {
798 /* We did open this for delete,
799 * allow the delete as root.
806 DEBUG(10,("acl_common_remove_object: %s %s/%s "
807 "not an open file\n",
808 is_directory
? "directory" : "file",
809 parent_dir
, final_component
));
810 saved_errno
= EACCES
;
816 ret
= SMB_VFS_NEXT_RMDIR(handle
, final_component
);
818 ret
= SMB_VFS_NEXT_UNLINK(handle
, &local_fname
);
828 TALLOC_FREE(parent_dir
);
830 vfs_ChDir(conn
, conn
->connectpath
);
837 static int rmdir_acl_common(struct vfs_handle_struct
*handle
,
842 ret
= SMB_VFS_NEXT_RMDIR(handle
, path
);
843 if (!(ret
== -1 && (errno
== EACCES
|| errno
== EPERM
))) {
844 DEBUG(10,("rmdir_acl_common: unlink of %s failed %s\n",
850 return acl_common_remove_object(handle
,
855 static NTSTATUS
create_file_acl_common(struct vfs_handle_struct
*handle
,
856 struct smb_request
*req
,
857 uint16_t root_dir_fid
,
858 struct smb_filename
*smb_fname
,
859 uint32_t access_mask
,
860 uint32_t share_access
,
861 uint32_t create_disposition
,
862 uint32_t create_options
,
863 uint32_t file_attributes
,
864 uint32_t oplock_request
,
865 uint64_t allocation_size
,
866 struct security_descriptor
*sd
,
867 struct ea_list
*ea_list
,
868 files_struct
**result
,
871 NTSTATUS status
, status1
;
872 files_struct
*fsp
= NULL
;
874 struct security_descriptor
*parent_sd
= NULL
;
876 status
= SMB_VFS_NEXT_CREATE_FILE(handle
,
892 if (info
!= FILE_WAS_CREATED
) {
893 /* File/directory was opened, not created. */
899 if (!NT_STATUS_IS_OK(status
) || fsp
== NULL
) {
900 /* Only handle success. */
905 /* Security descriptor already set. */
915 /* We must have a cached parent sd in this case.
916 * attached to the handle. */
918 SMB_VFS_HANDLE_GET_DATA(handle
, parent_sd
,
919 struct security_descriptor
,
926 /* New directory - inherit from parent. */
927 status1
= inherit_new_acl(handle
, fsp
, parent_sd
, fsp
->is_directory
);
929 if (!NT_STATUS_IS_OK(status1
)) {
930 DEBUG(1,("create_file_acl_common: error setting "
933 nt_errstr(status1
) ));
938 /* Ensure we never leave attached data around. */
939 SMB_VFS_HANDLE_FREE_DATA(handle
);
941 if (NT_STATUS_IS_OK(status
) && pinfo
) {
948 smb_panic("create_file_acl_common: logic error.\n");
953 static int unlink_acl_common(struct vfs_handle_struct
*handle
,
954 const struct smb_filename
*smb_fname
)
958 ret
= SMB_VFS_NEXT_UNLINK(handle
, smb_fname
);
959 if (!(ret
== -1 && (errno
== EACCES
|| errno
== EPERM
))) {
960 DEBUG(10,("unlink_acl_common: unlink of %s failed %s\n",
961 smb_fname
->base_name
,
965 /* Don't do anything fancy for streams. */
966 if (smb_fname
->stream_name
) {
970 return acl_common_remove_object(handle
,
971 smb_fname
->base_name
,