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 inherit_new_acl(handle, smb_fname, fsp, parent_desc, false);
597 errno = map_errno_from_nt_status(status);
601 static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t mode)
603 struct smb_filename *smb_fname = NULL;
606 SMB_STRUCT_STAT sbuf;
607 struct security_descriptor *parent_desc = NULL;
609 ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
610 if (ret == -1 && errno == ENOENT) {
611 /* We're creating a new directory. */
612 status = check_parent_acl_common(handle, path,
613 SEC_DIR_ADD_SUBDIR, &parent_desc);
614 if (!NT_STATUS_IS_OK(status)) {
615 errno = map_errno_from_nt_status(status);
620 ret = SMB_VFS_NEXT_MKDIR(handle, path, mode);
625 status = create_synthetic_smb_fname(talloc_tos(), path, NULL, NULL,
627 if (!NT_STATUS_IS_OK(status)) {
628 errno = map_errno_from_nt_status(status);
632 /* New directory - inherit from parent. */
633 inherit_new_acl(handle, smb_fname, NULL, parent_desc, true);
634 TALLOC_FREE(smb_fname);
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 & (OWNER_SECURITY_INFORMATION|
682 GROUP_SECURITY_INFORMATION|
683 DACL_SECURITY_INFORMATION)) !=
684 (OWNER_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,
692 (OWNER_SECURITY_INFORMATION|
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 & OWNER_SECURITY_INFORMATION) {
703 nc_psd->owner_sid = psd->owner_sid;
705 security_info_sent |= OWNER_SECURITY_INFORMATION;
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);