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 static NTSTATUS
store_acl_blob_pathname(vfs_handle_struct
*handle
,
41 #define HASH_SECURITY_INFO (OWNER_SECURITY_INFORMATION | \
42 GROUP_SECURITY_INFORMATION | \
43 DACL_SECURITY_INFORMATION | \
44 SACL_SECURITY_INFORMATION)
46 /*******************************************************************
47 Hash a security descriptor.
48 *******************************************************************/
50 static NTSTATUS
hash_sd_sha256(struct security_descriptor
*psd
,
57 memset(hash
, '\0', XATTR_SD_HASH_SIZE
);
58 status
= create_acl_blob(psd
, &blob
, XATTR_SD_HASH_TYPE_SHA256
, hash
);
59 if (!NT_STATUS_IS_OK(status
)) {
64 SHA256_Update(&tctx
, blob
.data
, blob
.length
);
65 SHA256_Final(hash
, &tctx
);
70 /*******************************************************************
71 Parse out a struct security_descriptor from a DATA_BLOB.
72 *******************************************************************/
74 static NTSTATUS
parse_acl_blob(const DATA_BLOB
*pblob
,
75 struct security_descriptor
**ppdesc
,
76 uint16_t *p_hash_type
,
77 uint8_t hash
[XATTR_SD_HASH_SIZE
])
79 TALLOC_CTX
*ctx
= talloc_tos();
80 struct xattr_NTACL xacl
;
81 enum ndr_err_code ndr_err
;
84 ndr_err
= ndr_pull_struct_blob(pblob
, ctx
, NULL
, &xacl
,
85 (ndr_pull_flags_fn_t
)ndr_pull_xattr_NTACL
);
87 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
88 DEBUG(5, ("parse_acl_blob: ndr_pull_xattr_NTACL failed: %s\n",
89 ndr_errstr(ndr_err
)));
90 return ndr_map_error2ntstatus(ndr_err
);;
93 switch (xacl
.version
) {
95 *ppdesc
= make_sec_desc(ctx
, SEC_DESC_REVISION
,
96 xacl
.info
.sd_hs2
->sd
->type
| SEC_DESC_SELF_RELATIVE
,
97 xacl
.info
.sd_hs2
->sd
->owner_sid
,
98 xacl
.info
.sd_hs2
->sd
->group_sid
,
99 xacl
.info
.sd_hs2
->sd
->sacl
,
100 xacl
.info
.sd_hs2
->sd
->dacl
,
102 /* No hash - null out. */
103 *p_hash_type
= XATTR_SD_HASH_TYPE_NONE
;
104 memset(hash
, '\0', XATTR_SD_HASH_SIZE
);
107 *ppdesc
= make_sec_desc(ctx
, SEC_DESC_REVISION
,
108 xacl
.info
.sd_hs3
->sd
->type
| SEC_DESC_SELF_RELATIVE
,
109 xacl
.info
.sd_hs3
->sd
->owner_sid
,
110 xacl
.info
.sd_hs3
->sd
->group_sid
,
111 xacl
.info
.sd_hs3
->sd
->sacl
,
112 xacl
.info
.sd_hs3
->sd
->dacl
,
114 *p_hash_type
= xacl
.info
.sd_hs3
->hash_type
;
115 /* Current version 3. */
116 memcpy(hash
, xacl
.info
.sd_hs3
->hash
, XATTR_SD_HASH_SIZE
);
119 return NT_STATUS_REVISION_MISMATCH
;
122 TALLOC_FREE(xacl
.info
.sd
);
124 return (*ppdesc
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
127 /*******************************************************************
128 Create a DATA_BLOB from a security descriptor.
129 *******************************************************************/
131 static NTSTATUS
create_acl_blob(const struct security_descriptor
*psd
,
134 uint8_t hash
[XATTR_SD_HASH_SIZE
])
136 struct xattr_NTACL xacl
;
137 struct security_descriptor_hash_v3 sd_hs3
;
138 enum ndr_err_code ndr_err
;
139 TALLOC_CTX
*ctx
= talloc_tos();
145 xacl
.info
.sd_hs3
= &sd_hs3
;
146 xacl
.info
.sd_hs3
->sd
= CONST_DISCARD(struct security_descriptor
*, psd
);
147 xacl
.info
.sd_hs3
->hash_type
= hash_type
;
148 memcpy(&xacl
.info
.sd_hs3
->hash
[0], hash
, XATTR_SD_HASH_SIZE
);
150 ndr_err
= ndr_push_struct_blob(
151 pblob
, ctx
, NULL
, &xacl
,
152 (ndr_push_flags_fn_t
)ndr_push_xattr_NTACL
);
154 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
155 DEBUG(5, ("create_acl_blob: ndr_push_xattr_NTACL failed: %s\n",
156 ndr_errstr(ndr_err
)));
157 return ndr_map_error2ntstatus(ndr_err
);;
163 /*******************************************************************
164 Pull a DATA_BLOB from an xattr given a pathname.
165 If the hash doesn't match, or doesn't exist - return the underlying
167 *******************************************************************/
169 static NTSTATUS
get_nt_acl_internal(vfs_handle_struct
*handle
,
172 uint32_t security_info
,
173 struct security_descriptor
**ppdesc
)
178 uint8_t hash
[XATTR_SD_HASH_SIZE
];
179 uint8_t hash_tmp
[XATTR_SD_HASH_SIZE
];
180 struct security_descriptor
*psd
= NULL
;
181 struct security_descriptor
*pdesc_next
= NULL
;
183 if (fsp
&& name
== NULL
) {
184 name
= fsp
->fsp_name
->base_name
;
187 DEBUG(10, ("get_nt_acl_internal: name=%s\n", name
));
189 /* Get the full underlying sd for the hash
190 or to return as backup. */
192 status
= SMB_VFS_NEXT_FGET_NT_ACL(handle
,
197 status
= SMB_VFS_NEXT_GET_NT_ACL(handle
,
203 if (!NT_STATUS_IS_OK(status
)) {
204 DEBUG(10, ("get_nt_acl_internal: get_next_acl for file %s "
211 status
= get_acl_blob(talloc_tos(), handle
, fsp
, name
, &blob
);
212 if (!NT_STATUS_IS_OK(status
)) {
213 DEBUG(10, ("get_nt_acl_internal: get_acl_blob returned %s\n",
219 status
= parse_acl_blob(&blob
, &psd
,
220 &hash_type
, &hash
[0]);
221 if (!NT_STATUS_IS_OK(status
)) {
222 DEBUG(10, ("parse_acl_blob returned %s\n",
228 /* Ensure the hash type is one we know. */
230 case XATTR_SD_HASH_TYPE_NONE
:
231 /* No hash, just return blob sd. */
233 case XATTR_SD_HASH_TYPE_SHA256
:
236 DEBUG(10, ("get_nt_acl_internal: ACL blob revision "
237 "mismatch (%u) for file %s\n",
238 (unsigned int)hash_type
,
246 status
= hash_sd_sha256(pdesc_next
, hash_tmp
);
247 if (!NT_STATUS_IS_OK(status
)) {
253 if (memcmp(&hash
[0], &hash_tmp
[0], XATTR_SD_HASH_SIZE
) == 0) {
254 /* Hash matches, return blob sd. */
258 /* Hash doesn't match, return underlying sd. */
264 if (psd
!= pdesc_next
) {
265 /* We're returning the blob, throw
266 * away the filesystem SD. */
267 TALLOC_FREE(pdesc_next
);
270 if (!(security_info
& OWNER_SECURITY_INFORMATION
)) {
271 psd
->owner_sid
= NULL
;
273 if (!(security_info
& GROUP_SECURITY_INFORMATION
)) {
274 psd
->group_sid
= NULL
;
276 if (!(security_info
& DACL_SECURITY_INFORMATION
)) {
279 if (!(security_info
& SACL_SECURITY_INFORMATION
)) {
283 TALLOC_FREE(blob
.data
);
289 /*********************************************************************
290 Create a default security descriptor for a file in case no inheritance
291 exists. All permissions to the owner and SYSTEM.
292 *********************************************************************/
294 static struct security_descriptor
*default_file_sd(TALLOC_CTX
*mem_ctx
,
295 SMB_STRUCT_STAT
*psbuf
,
298 struct dom_sid owner_sid
, group_sid
;
300 struct security_ace
*pace
= NULL
;
301 struct security_acl
*pacl
= NULL
;
303 uid_to_sid(&owner_sid
, psbuf
->st_ex_uid
);
304 gid_to_sid(&group_sid
, psbuf
->st_ex_gid
);
306 pace
= TALLOC_ARRAY(mem_ctx
, struct security_ace
, 2);
311 /* If force_inherit is set, this means we are initializing the ACEs for
312 * a container and we want the ACEs for owner_sid and "SYSTEM" to be
313 * inheritable by their children (See Bug #6802).
316 init_sec_ace(&pace
[0], &owner_sid
, SEC_ACE_TYPE_ACCESS_ALLOWED
,
317 SEC_RIGHTS_FILE_ALL
, (force_inherit
?
318 (SEC_ACE_FLAG_OBJECT_INHERIT
|
319 SEC_ACE_FLAG_CONTAINER_INHERIT
) :
322 init_sec_ace(&pace
[1], &global_sid_System
, SEC_ACE_TYPE_ACCESS_ALLOWED
,
323 SEC_RIGHTS_FILE_ALL
, (force_inherit
?
324 (SEC_ACE_FLAG_OBJECT_INHERIT
|
325 SEC_ACE_FLAG_CONTAINER_INHERIT
) :
328 pacl
= make_sec_acl(mem_ctx
,
335 return make_sec_desc(mem_ctx
,
336 SECURITY_DESCRIPTOR_REVISION_1
,
337 SEC_DESC_SELF_RELATIVE
|SEC_DESC_DACL_PRESENT
,
346 /*********************************************************************
347 Create a default ACL by inheriting from the parent. If no inheritance
348 from the parent available, just use the actual permissions the new
349 file or directory already got from the filesystem.
350 *********************************************************************/
352 static NTSTATUS
inherit_new_acl(vfs_handle_struct
*handle
,
353 struct smb_filename
*smb_fname
,
355 struct security_descriptor
*parent_desc
,
358 TALLOC_CTX
*ctx
= talloc_tos();
359 NTSTATUS status
= NT_STATUS_OK
;
360 struct security_descriptor
*psd
= NULL
;
361 struct security_descriptor
*pdesc_next
= NULL
;
364 uint8_t hash
[XATTR_SD_HASH_SIZE
];
366 if (parent_desc
== NULL
) {
367 /* We don't already have the parent sd, fetch it now. */
370 if (!parent_dirname(ctx
, smb_fname
->base_name
, &parent_name
, NULL
)) {
371 return NT_STATUS_NO_MEMORY
;
374 DEBUG(10,("inherit_new_acl: check directory %s\n",
377 status
= get_nt_acl_internal(handle
,
380 (OWNER_SECURITY_INFORMATION
|
381 GROUP_SECURITY_INFORMATION
|
382 DACL_SECURITY_INFORMATION
),
385 if (!NT_STATUS_IS_OK(status
)) {
386 DEBUG(10,("inherit_new_acl: directory %s failed "
387 "to get acl BLOB %s\n",
389 nt_errstr(status
) ));
395 * Object must exist. Read the current SD off the filesystem
399 status
= SMB_VFS_NEXT_FGET_NT_ACL(handle
,
404 status
= SMB_VFS_NEXT_GET_NT_ACL(handle
,
405 smb_fname
->base_name
,
410 if (!NT_STATUS_IS_OK(status
)) {
411 DEBUG(10,("inherit_new_acl: get_next_acl \n"
412 "failed for %s (%s)\n",
413 smb_fname_str_dbg(smb_fname
),
414 nt_errstr(status
) ));
418 if (parent_desc
&& 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 is:\n"));
423 NDR_PRINT_DEBUG(security_descriptor
, parent_desc
);
426 status
= se_create_child_secdesc(ctx
,
430 &handle
->conn
->server_info
->ptok
->user_sids
[PRIMARY_USER_SID_INDEX
],
431 &handle
->conn
->server_info
->ptok
->user_sids
[PRIMARY_GROUP_SID_INDEX
],
433 if (!NT_STATUS_IS_OK(status
)) {
438 DEBUG(10,("inherit_new_acl: using current permissions.\n"
439 "to set Windows acl for %s\n",
440 smb_fname_str_dbg(smb_fname
) ));
444 if (DEBUGLEVEL
>= 10) {
445 DEBUG(10,("inherit_new_acl: child acl is:\n"));
446 NDR_PRINT_DEBUG(security_descriptor
, psd
);
449 status
= hash_sd_sha256(pdesc_next
, hash
);
450 if (!NT_STATUS_IS_OK(status
)) {
453 status
= create_acl_blob(psd
, &blob
, XATTR_SD_HASH_TYPE_SHA256
, hash
);
454 if (!NT_STATUS_IS_OK(status
)) {
458 return store_acl_blob_fsp(handle
, fsp
, &blob
);
460 return store_acl_blob_pathname(handle
, smb_fname
->base_name
,
465 static NTSTATUS
check_parent_acl_common(vfs_handle_struct
*handle
,
467 uint32_t access_mask
,
468 struct security_descriptor
**pp_parent_desc
)
470 char *parent_name
= NULL
;
471 struct security_descriptor
*parent_desc
= NULL
;
472 uint32_t access_granted
= 0;
475 if (!parent_dirname(talloc_tos(), path
, &parent_name
, NULL
)) {
476 return NT_STATUS_NO_MEMORY
;
479 status
= get_nt_acl_internal(handle
,
482 (OWNER_SECURITY_INFORMATION
|
483 GROUP_SECURITY_INFORMATION
|
484 DACL_SECURITY_INFORMATION
),
487 if (!NT_STATUS_IS_OK(status
)) {
488 DEBUG(10,("check_parent_acl_common: get_nt_acl_internal "
489 "on directory %s for "
490 "path %s returned %s\n",
493 nt_errstr(status
) ));
496 status
= smb1_file_se_access_check(parent_desc
,
497 handle
->conn
->server_info
->ptok
,
500 if(!NT_STATUS_IS_OK(status
)) {
501 DEBUG(10,("check_parent_acl_common: access check "
502 "on directory %s for "
503 "path %s for mask 0x%x returned %s\n",
507 nt_errstr(status
) ));
510 if (pp_parent_desc
) {
511 *pp_parent_desc
= parent_desc
;
516 /*********************************************************************
517 Check ACL on open. For new files inherit from parent directory.
518 *********************************************************************/
520 static int open_acl_common(vfs_handle_struct
*handle
,
521 struct smb_filename
*smb_fname
,
526 uint32_t access_granted
= 0;
527 struct security_descriptor
*pdesc
= NULL
;
528 struct security_descriptor
*parent_desc
= NULL
;
529 bool file_existed
= true;
534 /* Stream open. Base filename open already did the ACL check. */
535 DEBUG(10,("open_acl_common: stream open on %s\n",
536 smb_fname_str_dbg(smb_fname
) ));
537 return SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
, mode
);
540 status
= get_full_smb_filename(talloc_tos(), smb_fname
,
542 if (!NT_STATUS_IS_OK(status
)) {
546 status
= get_nt_acl_internal(handle
,
549 (OWNER_SECURITY_INFORMATION
|
550 GROUP_SECURITY_INFORMATION
|
551 DACL_SECURITY_INFORMATION
),
553 if (NT_STATUS_IS_OK(status
)) {
554 /* See if we can access it. */
555 status
= smb1_file_se_access_check(pdesc
,
556 handle
->conn
->server_info
->ptok
,
559 if (!NT_STATUS_IS_OK(status
)) {
560 DEBUG(10,("open_acl_xattr: file %s open "
561 "refused with error %s\n",
562 smb_fname_str_dbg(smb_fname
),
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 status
= check_parent_acl_common(handle
, fname
,
574 SEC_DIR_ADD_FILE
, &parent_desc
);
575 if (!NT_STATUS_IS_OK(status
)) {
581 DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
582 "file %s returned %s\n",
583 smb_fname_str_dbg(smb_fname
),
584 nt_errstr(status
) ));
586 fsp
->fh
->fd
= SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
, mode
);
588 if (!file_existed
&& fsp
->fh
->fd
!= -1) {
589 /* File was created. Inherit from parent directory. */
590 status
= fsp_set_smb_fname(fsp
, smb_fname
);
591 if (!NT_STATUS_IS_OK(status
)) {
594 inherit_new_acl(handle
, smb_fname
, fsp
, parent_desc
, false);
601 errno
= map_errno_from_nt_status(status
);
605 static int mkdir_acl_common(vfs_handle_struct
*handle
, const char *path
, mode_t mode
)
607 struct smb_filename
*smb_fname
= NULL
;
610 SMB_STRUCT_STAT sbuf
;
611 struct security_descriptor
*parent_desc
= NULL
;
613 ret
= vfs_stat_smb_fname(handle
->conn
, path
, &sbuf
);
614 if (ret
== -1 && errno
== ENOENT
) {
615 /* We're creating a new directory. */
616 status
= check_parent_acl_common(handle
, path
,
617 SEC_DIR_ADD_SUBDIR
, &parent_desc
);
618 if (!NT_STATUS_IS_OK(status
)) {
619 errno
= map_errno_from_nt_status(status
);
624 ret
= SMB_VFS_NEXT_MKDIR(handle
, path
, mode
);
629 status
= create_synthetic_smb_fname(talloc_tos(), path
, NULL
, NULL
,
631 if (!NT_STATUS_IS_OK(status
)) {
632 errno
= map_errno_from_nt_status(status
);
636 /* New directory - inherit from parent. */
637 inherit_new_acl(handle
, smb_fname
, NULL
, parent_desc
, true);
638 TALLOC_FREE(smb_fname
);
642 /*********************************************************************
643 Fetch a security descriptor given an fsp.
644 *********************************************************************/
646 static NTSTATUS
fget_nt_acl_common(vfs_handle_struct
*handle
, files_struct
*fsp
,
647 uint32_t security_info
, struct security_descriptor
**ppdesc
)
649 return get_nt_acl_internal(handle
, fsp
,
650 NULL
, security_info
, ppdesc
);
653 /*********************************************************************
654 Fetch a security descriptor given a pathname.
655 *********************************************************************/
657 static NTSTATUS
get_nt_acl_common(vfs_handle_struct
*handle
,
658 const char *name
, uint32_t security_info
, struct security_descriptor
**ppdesc
)
660 return get_nt_acl_internal(handle
, NULL
,
661 name
, security_info
, ppdesc
);
664 /*********************************************************************
665 Store a security descriptor given an fsp.
666 *********************************************************************/
668 static NTSTATUS
fset_nt_acl_common(vfs_handle_struct
*handle
, files_struct
*fsp
,
669 uint32_t security_info_sent
, const struct security_descriptor
*psd
)
673 struct security_descriptor
*pdesc_next
= NULL
;
674 uint8_t hash
[XATTR_SD_HASH_SIZE
];
676 if (DEBUGLEVEL
>= 10) {
677 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
679 NDR_PRINT_DEBUG(security_descriptor
,
680 CONST_DISCARD(struct security_descriptor
*,psd
));
683 /* Ensure we have OWNER/GROUP/DACL set. */
685 if ((security_info_sent
& (OWNER_SECURITY_INFORMATION
|
686 GROUP_SECURITY_INFORMATION
|
687 DACL_SECURITY_INFORMATION
)) !=
688 (OWNER_SECURITY_INFORMATION
|
689 GROUP_SECURITY_INFORMATION
|
690 DACL_SECURITY_INFORMATION
)) {
691 /* No we don't - read from the existing SD. */
692 struct security_descriptor
*nc_psd
= NULL
;
694 status
= get_nt_acl_internal(handle
, fsp
,
696 (OWNER_SECURITY_INFORMATION
|
697 GROUP_SECURITY_INFORMATION
|
698 DACL_SECURITY_INFORMATION
),
701 if (!NT_STATUS_IS_OK(status
)) {
705 /* This is safe as nc_psd is discarded at fn exit. */
706 if (security_info_sent
& OWNER_SECURITY_INFORMATION
) {
707 nc_psd
->owner_sid
= psd
->owner_sid
;
709 security_info_sent
|= OWNER_SECURITY_INFORMATION
;
711 if (security_info_sent
& GROUP_SECURITY_INFORMATION
) {
712 nc_psd
->group_sid
= psd
->group_sid
;
714 security_info_sent
|= GROUP_SECURITY_INFORMATION
;
716 if (security_info_sent
& DACL_SECURITY_INFORMATION
) {
717 nc_psd
->dacl
= dup_sec_acl(talloc_tos(), psd
->dacl
);
718 if (nc_psd
->dacl
== NULL
) {
719 return NT_STATUS_NO_MEMORY
;
722 security_info_sent
|= DACL_SECURITY_INFORMATION
;
726 status
= SMB_VFS_NEXT_FSET_NT_ACL(handle
, fsp
, security_info_sent
, psd
);
727 if (!NT_STATUS_IS_OK(status
)) {
731 /* Get the full underlying sd, then hash. */
732 status
= SMB_VFS_NEXT_FGET_NT_ACL(handle
,
737 if (!NT_STATUS_IS_OK(status
)) {
741 status
= hash_sd_sha256(pdesc_next
, hash
);
742 if (!NT_STATUS_IS_OK(status
)) {
746 if (DEBUGLEVEL
>= 10) {
747 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
749 NDR_PRINT_DEBUG(security_descriptor
,
750 CONST_DISCARD(struct security_descriptor
*,psd
));
752 create_acl_blob(psd
, &blob
, XATTR_SD_HASH_TYPE_SHA256
, hash
);
753 store_acl_blob_fsp(handle
, fsp
, &blob
);
758 static SMB_STRUCT_DIR
*opendir_acl_common(vfs_handle_struct
*handle
,
759 const char *fname
, const char *mask
, uint32 attr
)
761 NTSTATUS status
= check_parent_acl_common(handle
, fname
,
764 if (!NT_STATUS_IS_OK(status
)) {
765 errno
= map_errno_from_nt_status(status
);
768 return SMB_VFS_NEXT_OPENDIR(handle
, fname
, mask
, attr
);