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
);
396 if (DEBUGLEVEL
>= 10) {
397 DEBUG(10,("get_nt_acl_internal: returning acl for %s is:\n",
399 NDR_PRINT_DEBUG(security_descriptor
, psd
);
405 /*********************************************************************
406 Create a default ACL by inheriting from the parent. If no inheritance
407 from the parent available, don't set anything. This will leave the actual
408 permissions the new file or directory already got from the filesystem
409 as the NT ACL when read.
410 *********************************************************************/
412 static NTSTATUS
inherit_new_acl(vfs_handle_struct
*handle
,
414 struct security_descriptor
*parent_desc
,
417 TALLOC_CTX
*ctx
= talloc_tos();
418 NTSTATUS status
= NT_STATUS_OK
;
419 struct security_descriptor
*psd
= NULL
;
422 if (!sd_has_inheritable_components(parent_desc
, is_directory
)) {
426 /* Create an inherited descriptor from the parent. */
428 if (DEBUGLEVEL
>= 10) {
429 DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
431 NDR_PRINT_DEBUG(security_descriptor
, parent_desc
);
434 status
= se_create_child_secdesc(ctx
,
438 &handle
->conn
->server_info
->ptok
->user_sids
[PRIMARY_USER_SID_INDEX
],
439 &handle
->conn
->server_info
->ptok
->user_sids
[PRIMARY_GROUP_SID_INDEX
],
441 if (!NT_STATUS_IS_OK(status
)) {
445 if (DEBUGLEVEL
>= 10) {
446 DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
448 NDR_PRINT_DEBUG(security_descriptor
, parent_desc
);
451 return SMB_VFS_FSET_NT_ACL(fsp
,
452 (OWNER_SECURITY_INFORMATION
|
453 GROUP_SECURITY_INFORMATION
|
454 DACL_SECURITY_INFORMATION
),
458 static NTSTATUS
check_parent_acl_common(vfs_handle_struct
*handle
,
460 uint32_t access_mask
,
461 struct security_descriptor
**pp_parent_desc
)
463 char *parent_name
= NULL
;
464 struct security_descriptor
*parent_desc
= NULL
;
465 uint32_t access_granted
= 0;
468 if (!parent_dirname(talloc_tos(), path
, &parent_name
, NULL
)) {
469 return NT_STATUS_NO_MEMORY
;
472 status
= get_nt_acl_internal(handle
,
475 (OWNER_SECURITY_INFORMATION
|
476 GROUP_SECURITY_INFORMATION
|
477 DACL_SECURITY_INFORMATION
),
480 if (!NT_STATUS_IS_OK(status
)) {
481 DEBUG(10,("check_parent_acl_common: get_nt_acl_internal "
482 "on directory %s for "
483 "path %s returned %s\n",
486 nt_errstr(status
) ));
489 status
= smb1_file_se_access_check(handle
->conn
,
491 handle
->conn
->server_info
->ptok
,
494 if(!NT_STATUS_IS_OK(status
)) {
495 DEBUG(10,("check_parent_acl_common: access check "
496 "on directory %s for "
497 "path %s for mask 0x%x returned %s\n",
501 nt_errstr(status
) ));
504 if (pp_parent_desc
) {
505 *pp_parent_desc
= parent_desc
;
510 static void free_sd_common(void **ptr
)
515 /*********************************************************************
516 Check ACL on open. For new files inherit from parent directory.
517 *********************************************************************/
519 static int open_acl_common(vfs_handle_struct
*handle
,
520 struct smb_filename
*smb_fname
,
525 uint32_t access_granted
= 0;
526 struct security_descriptor
*pdesc
= NULL
;
527 struct security_descriptor
*parent_desc
= NULL
;
528 bool file_existed
= true;
533 /* Stream open. Base filename open already did the ACL check. */
534 DEBUG(10,("open_acl_common: stream open on %s\n",
536 return SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
, mode
);
539 status
= get_full_smb_filename(talloc_tos(), smb_fname
,
541 if (!NT_STATUS_IS_OK(status
)) {
545 status
= get_nt_acl_internal(handle
,
548 (OWNER_SECURITY_INFORMATION
|
549 GROUP_SECURITY_INFORMATION
|
550 DACL_SECURITY_INFORMATION
),
552 if (NT_STATUS_IS_OK(status
)) {
553 /* See if we can access it. */
554 status
= smb1_file_se_access_check(handle
->conn
,
556 handle
->conn
->server_info
->ptok
,
559 if (!NT_STATUS_IS_OK(status
)) {
560 DEBUG(10,("open_acl_xattr: %s open "
561 "refused with error %s\n",
563 nt_errstr(status
) ));
566 } else if (NT_STATUS_EQUAL(status
,NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
567 file_existed
= false;
569 * If O_CREAT is true then we're trying to create a file.
570 * Check the parent directory ACL will allow this.
572 if (flags
& O_CREAT
) {
573 struct security_descriptor
*psd
= NULL
;
575 status
= check_parent_acl_common(handle
, fname
,
576 SEC_DIR_ADD_FILE
, &parent_desc
);
577 if (!NT_STATUS_IS_OK(status
)) {
580 /* Cache the parent security descriptor for
581 * later use. We do have an fsp here, but to
582 * keep the code consistent with the directory
583 * case which doesn't, use the handle. */
585 /* Attach this to the conn, move from talloc_tos(). */
586 psd
= (struct security_descriptor
*)talloc_move(handle
->conn
,
590 status
= NT_STATUS_NO_MEMORY
;
593 status
= NT_STATUS_NO_MEMORY
;
594 SMB_VFS_HANDLE_SET_DATA(handle
, psd
, free_sd_common
,
595 struct security_descriptor
*, goto err
);
596 status
= NT_STATUS_OK
;
600 DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
603 nt_errstr(status
) ));
605 fsp
->fh
->fd
= SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
, mode
);
610 errno
= map_errno_from_nt_status(status
);
614 static int mkdir_acl_common(vfs_handle_struct
*handle
, const char *path
, mode_t mode
)
618 SMB_STRUCT_STAT sbuf
;
620 ret
= vfs_stat_smb_fname(handle
->conn
, path
, &sbuf
);
621 if (ret
== -1 && errno
== ENOENT
) {
622 struct security_descriptor
*parent_desc
= NULL
;
623 struct security_descriptor
*psd
= NULL
;
625 /* We're creating a new directory. */
626 status
= check_parent_acl_common(handle
, path
,
627 SEC_DIR_ADD_SUBDIR
, &parent_desc
);
628 if (!NT_STATUS_IS_OK(status
)) {
629 errno
= map_errno_from_nt_status(status
);
633 /* Cache the parent security descriptor for
634 * later use. We don't have an fsp here so
637 /* Attach this to the conn, move from talloc_tos(). */
638 psd
= (struct security_descriptor
*)talloc_move(handle
->conn
,
644 SMB_VFS_HANDLE_SET_DATA(handle
, psd
, free_sd_common
,
645 struct security_descriptor
*, return -1);
648 return SMB_VFS_NEXT_MKDIR(handle
, path
, mode
);
651 /*********************************************************************
652 Fetch a security descriptor given an fsp.
653 *********************************************************************/
655 static NTSTATUS
fget_nt_acl_common(vfs_handle_struct
*handle
, files_struct
*fsp
,
656 uint32_t security_info
, struct security_descriptor
**ppdesc
)
658 return get_nt_acl_internal(handle
, fsp
,
659 NULL
, security_info
, ppdesc
);
662 /*********************************************************************
663 Fetch a security descriptor given a pathname.
664 *********************************************************************/
666 static NTSTATUS
get_nt_acl_common(vfs_handle_struct
*handle
,
667 const char *name
, uint32_t security_info
, struct security_descriptor
**ppdesc
)
669 return get_nt_acl_internal(handle
, NULL
,
670 name
, security_info
, ppdesc
);
673 /*********************************************************************
674 Store a security descriptor given an fsp.
675 *********************************************************************/
677 static NTSTATUS
fset_nt_acl_common(vfs_handle_struct
*handle
, files_struct
*fsp
,
678 uint32_t security_info_sent
, const struct security_descriptor
*orig_psd
)
682 struct security_descriptor
*pdesc_next
= NULL
;
683 struct security_descriptor
*psd
= NULL
;
684 uint8_t hash
[XATTR_SD_HASH_SIZE
];
686 if (DEBUGLEVEL
>= 10) {
687 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
689 NDR_PRINT_DEBUG(security_descriptor
,
690 CONST_DISCARD(struct security_descriptor
*,orig_psd
));
693 status
= get_nt_acl_internal(handle
, fsp
,
695 SECINFO_OWNER
|SECINFO_GROUP
|SECINFO_DACL
|SECINFO_SACL
,
698 if (!NT_STATUS_IS_OK(status
)) {
702 if ((security_info_sent
& SECINFO_OWNER
) && (orig_psd
->owner_sid
!= NULL
)) {
703 psd
->owner_sid
= orig_psd
->owner_sid
;
705 if ((security_info_sent
& SECINFO_GROUP
) && (orig_psd
->group_sid
!= NULL
)) {
706 psd
->group_sid
= orig_psd
->group_sid
;
708 if (security_info_sent
& SECINFO_DACL
) {
709 psd
->dacl
= orig_psd
->dacl
;
711 if (security_info_sent
& SECINFO_SACL
) {
712 psd
->sacl
= orig_psd
->sacl
;
715 status
= SMB_VFS_NEXT_FSET_NT_ACL(handle
, fsp
, security_info_sent
, psd
);
716 if (!NT_STATUS_IS_OK(status
)) {
720 /* Get the full underlying sd, then hash. */
721 status
= SMB_VFS_NEXT_FGET_NT_ACL(handle
,
726 if (!NT_STATUS_IS_OK(status
)) {
730 status
= hash_sd_sha256(pdesc_next
, hash
);
731 if (!NT_STATUS_IS_OK(status
)) {
735 if (DEBUGLEVEL
>= 10) {
736 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
738 NDR_PRINT_DEBUG(security_descriptor
,
739 CONST_DISCARD(struct security_descriptor
*,psd
));
741 create_acl_blob(psd
, &blob
, XATTR_SD_HASH_TYPE_SHA256
, hash
);
742 store_acl_blob_fsp(handle
, fsp
, &blob
);
747 static SMB_STRUCT_DIR
*opendir_acl_common(vfs_handle_struct
*handle
,
748 const char *fname
, const char *mask
, uint32 attr
)
750 NTSTATUS status
= check_parent_acl_common(handle
, fname
,
753 if (!NT_STATUS_IS_OK(status
)) {
754 errno
= map_errno_from_nt_status(status
);
757 return SMB_VFS_NEXT_OPENDIR(handle
, fname
, mask
, attr
);
760 static int acl_common_remove_object(vfs_handle_struct
*handle
,
764 connection_struct
*conn
= handle
->conn
;
766 files_struct
*fsp
= NULL
;
768 char *parent_dir
= NULL
;
769 const char *final_component
= NULL
;
770 struct smb_filename local_fname
;
773 if (!parent_dirname(talloc_tos(), path
,
774 &parent_dir
, &final_component
)) {
775 saved_errno
= ENOMEM
;
779 DEBUG(10,("acl_common_remove_object: removing %s %s/%s\n",
780 is_directory
? "directory" : "file",
781 parent_dir
, final_component
));
783 /* cd into the parent dir to pin it. */
784 ret
= SMB_VFS_CHDIR(conn
, parent_dir
);
790 ZERO_STRUCT(local_fname
);
791 local_fname
.base_name
= CONST_DISCARD(char *,final_component
);
793 /* Must use lstat here. */
794 ret
= SMB_VFS_LSTAT(conn
, &local_fname
);
800 /* Ensure we have this file open with DELETE access. */
801 id
= vfs_file_id_from_sbuf(conn
, &local_fname
.st
);
802 for (fsp
= file_find_di_first(id
); fsp
; file_find_di_next(fsp
)) {
803 if (fsp
->access_mask
& DELETE_ACCESS
&&
804 fsp
->delete_on_close
) {
805 /* We did open this for delete,
806 * allow the delete as root.
813 DEBUG(10,("acl_common_remove_object: %s %s/%s "
814 "not an open file\n",
815 is_directory
? "directory" : "file",
816 parent_dir
, final_component
));
817 saved_errno
= EACCES
;
823 ret
= SMB_VFS_NEXT_RMDIR(handle
, final_component
);
825 ret
= SMB_VFS_NEXT_UNLINK(handle
, &local_fname
);
835 TALLOC_FREE(parent_dir
);
837 vfs_ChDir(conn
, conn
->connectpath
);
844 static int rmdir_acl_common(struct vfs_handle_struct
*handle
,
849 ret
= SMB_VFS_NEXT_RMDIR(handle
, path
);
850 if (!(ret
== -1 && (errno
== EACCES
|| errno
== EPERM
))) {
851 DEBUG(10,("rmdir_acl_common: unlink of %s failed %s\n",
857 return acl_common_remove_object(handle
,
862 static NTSTATUS
create_file_acl_common(struct vfs_handle_struct
*handle
,
863 struct smb_request
*req
,
864 uint16_t root_dir_fid
,
865 struct smb_filename
*smb_fname
,
866 uint32_t access_mask
,
867 uint32_t share_access
,
868 uint32_t create_disposition
,
869 uint32_t create_options
,
870 uint32_t file_attributes
,
871 uint32_t oplock_request
,
872 uint64_t allocation_size
,
873 struct security_descriptor
*sd
,
874 struct ea_list
*ea_list
,
875 files_struct
**result
,
878 NTSTATUS status
, status1
;
879 files_struct
*fsp
= NULL
;
881 struct security_descriptor
*parent_sd
= NULL
;
883 status
= SMB_VFS_NEXT_CREATE_FILE(handle
,
899 if (!NT_STATUS_IS_OK(status
)) {
903 if (info
!= FILE_WAS_CREATED
) {
904 /* File/directory was opened, not created. */
911 /* Only handle success. */
916 /* Security descriptor already set. */
926 /* We must have a cached parent sd in this case.
927 * attached to the handle. */
929 SMB_VFS_HANDLE_GET_DATA(handle
, parent_sd
,
930 struct security_descriptor
,
937 /* New directory - inherit from parent. */
938 status1
= inherit_new_acl(handle
, fsp
, parent_sd
, fsp
->is_directory
);
940 if (!NT_STATUS_IS_OK(status1
)) {
941 DEBUG(1,("create_file_acl_common: error setting "
944 nt_errstr(status1
) ));
949 /* Ensure we never leave attached data around. */
950 SMB_VFS_HANDLE_FREE_DATA(handle
);
952 if (NT_STATUS_IS_OK(status
) && pinfo
) {
959 smb_panic("create_file_acl_common: logic error.\n");
964 static int unlink_acl_common(struct vfs_handle_struct
*handle
,
965 const struct smb_filename
*smb_fname
)
969 ret
= SMB_VFS_NEXT_UNLINK(handle
, smb_fname
);
970 if (!(ret
== -1 && (errno
== EACCES
|| errno
== EPERM
))) {
971 DEBUG(10,("unlink_acl_common: unlink of %s failed %s\n",
972 smb_fname
->base_name
,
976 /* Don't do anything fancy for streams. */
977 if (smb_fname
->stream_name
) {
981 return acl_common_remove_object(handle
,
982 smb_fname
->base_name
,