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 Pull a DATA_BLOB from an xattr given a pathname.
161 If the hash doesn't match, or doesn't exist - return the underlying
163 *******************************************************************/
165 static NTSTATUS
get_nt_acl_internal(vfs_handle_struct
*handle
,
168 uint32_t security_info
,
169 struct security_descriptor
**ppdesc
)
174 uint8_t hash
[XATTR_SD_HASH_SIZE
];
175 uint8_t hash_tmp
[XATTR_SD_HASH_SIZE
];
176 struct security_descriptor
*psd
= NULL
;
177 struct security_descriptor
*pdesc_next
= NULL
;
179 if (fsp
&& name
== NULL
) {
180 name
= fsp
->fsp_name
->base_name
;
183 DEBUG(10, ("get_nt_acl_internal: name=%s\n", name
));
185 /* Get the full underlying sd for the hash
186 or to return as backup. */
188 status
= SMB_VFS_NEXT_FGET_NT_ACL(handle
,
193 status
= SMB_VFS_NEXT_GET_NT_ACL(handle
,
199 if (!NT_STATUS_IS_OK(status
)) {
200 DEBUG(10, ("get_nt_acl_internal: get_next_acl for file %s "
207 status
= get_acl_blob(talloc_tos(), handle
, fsp
, name
, &blob
);
208 if (!NT_STATUS_IS_OK(status
)) {
209 DEBUG(10, ("get_nt_acl_internal: get_acl_blob returned %s\n",
215 status
= parse_acl_blob(&blob
, &psd
,
216 &hash_type
, &hash
[0]);
217 if (!NT_STATUS_IS_OK(status
)) {
218 DEBUG(10, ("parse_acl_blob returned %s\n",
224 /* Ensure the hash type is one we know. */
226 case XATTR_SD_HASH_TYPE_NONE
:
227 /* No hash, just return blob sd. */
229 case XATTR_SD_HASH_TYPE_SHA256
:
232 DEBUG(10, ("get_nt_acl_internal: ACL blob revision "
233 "mismatch (%u) for file %s\n",
234 (unsigned int)hash_type
,
242 status
= hash_sd_sha256(pdesc_next
, hash_tmp
);
243 if (!NT_STATUS_IS_OK(status
)) {
249 if (memcmp(&hash
[0], &hash_tmp
[0], XATTR_SD_HASH_SIZE
) == 0) {
250 /* Hash matches, return blob sd. */
254 /* Hash doesn't match, return underlying sd. */
260 if (psd
!= pdesc_next
) {
261 /* We're returning the blob, throw
262 * away the filesystem SD. */
263 TALLOC_FREE(pdesc_next
);
266 if (!(security_info
& OWNER_SECURITY_INFORMATION
)) {
267 psd
->owner_sid
= NULL
;
269 if (!(security_info
& GROUP_SECURITY_INFORMATION
)) {
270 psd
->group_sid
= NULL
;
272 if (!(security_info
& DACL_SECURITY_INFORMATION
)) {
275 if (!(security_info
& SACL_SECURITY_INFORMATION
)) {
279 TALLOC_FREE(blob
.data
);
284 /*********************************************************************
285 Create a default ACL by inheriting from the parent. If no inheritance
286 from the parent available, don't set anything. This will leave the actual
287 permissions the new file or directory already got from the filesystem
288 as the NT ACL when read.
289 *********************************************************************/
291 static NTSTATUS
inherit_new_acl(vfs_handle_struct
*handle
,
293 struct security_descriptor
*parent_desc
,
296 TALLOC_CTX
*ctx
= talloc_tos();
297 NTSTATUS status
= NT_STATUS_OK
;
298 struct security_descriptor
*psd
= NULL
;
301 if (!parent_desc
|| !sd_has_inheritable_components(parent_desc
, is_directory
)) {
305 /* Create an inherited descriptor from the parent. */
307 if (DEBUGLEVEL
>= 10) {
308 DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
310 NDR_PRINT_DEBUG(security_descriptor
, parent_desc
);
313 status
= se_create_child_secdesc(ctx
,
317 &handle
->conn
->server_info
->ptok
->user_sids
[PRIMARY_USER_SID_INDEX
],
318 &handle
->conn
->server_info
->ptok
->user_sids
[PRIMARY_GROUP_SID_INDEX
],
320 if (!NT_STATUS_IS_OK(status
)) {
324 if (DEBUGLEVEL
>= 10) {
325 DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
327 NDR_PRINT_DEBUG(security_descriptor
, parent_desc
);
330 return SMB_VFS_FSET_NT_ACL(fsp
,
331 (OWNER_SECURITY_INFORMATION
|
332 GROUP_SECURITY_INFORMATION
|
333 DACL_SECURITY_INFORMATION
),
337 static NTSTATUS
check_parent_acl_common(vfs_handle_struct
*handle
,
339 uint32_t access_mask
,
340 struct security_descriptor
**pp_parent_desc
)
342 char *parent_name
= NULL
;
343 struct security_descriptor
*parent_desc
= NULL
;
344 uint32_t access_granted
= 0;
347 if (!parent_dirname(talloc_tos(), path
, &parent_name
, NULL
)) {
348 return NT_STATUS_NO_MEMORY
;
351 status
= get_nt_acl_internal(handle
,
354 (OWNER_SECURITY_INFORMATION
|
355 GROUP_SECURITY_INFORMATION
|
356 DACL_SECURITY_INFORMATION
),
359 if (!NT_STATUS_IS_OK(status
)) {
360 DEBUG(10,("check_parent_acl_common: get_nt_acl_internal "
361 "on directory %s for "
362 "path %s returned %s\n",
365 nt_errstr(status
) ));
368 status
= smb1_file_se_access_check(parent_desc
,
369 handle
->conn
->server_info
->ptok
,
372 if(!NT_STATUS_IS_OK(status
)) {
373 DEBUG(10,("check_parent_acl_common: access check "
374 "on directory %s for "
375 "path %s for mask 0x%x returned %s\n",
379 nt_errstr(status
) ));
382 if (pp_parent_desc
) {
383 *pp_parent_desc
= parent_desc
;
388 static void free_sd_common(void **ptr
)
393 /*********************************************************************
394 Check ACL on open. For new files inherit from parent directory.
395 *********************************************************************/
397 static int open_acl_common(vfs_handle_struct
*handle
,
398 struct smb_filename
*smb_fname
,
403 uint32_t access_granted
= 0;
404 struct security_descriptor
*pdesc
= NULL
;
405 struct security_descriptor
*parent_desc
= NULL
;
406 bool file_existed
= true;
411 /* Stream open. Base filename open already did the ACL check. */
412 DEBUG(10,("open_acl_common: stream open on %s\n",
414 return SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
, mode
);
417 status
= get_full_smb_filename(talloc_tos(), smb_fname
,
419 if (!NT_STATUS_IS_OK(status
)) {
423 status
= get_nt_acl_internal(handle
,
426 (OWNER_SECURITY_INFORMATION
|
427 GROUP_SECURITY_INFORMATION
|
428 DACL_SECURITY_INFORMATION
),
430 if (NT_STATUS_IS_OK(status
)) {
431 /* See if we can access it. */
432 status
= smb1_file_se_access_check(pdesc
,
433 handle
->conn
->server_info
->ptok
,
436 if (!NT_STATUS_IS_OK(status
)) {
437 DEBUG(10,("open_acl_xattr: %s open "
438 "refused with error %s\n",
440 nt_errstr(status
) ));
443 } else if (NT_STATUS_EQUAL(status
,NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
444 file_existed
= false;
446 * If O_CREAT is true then we're trying to create a file.
447 * Check the parent directory ACL will allow this.
449 if (flags
& O_CREAT
) {
450 struct security_descriptor
*psd
= NULL
;
452 status
= check_parent_acl_common(handle
, fname
,
453 SEC_DIR_ADD_FILE
, &parent_desc
);
454 if (!NT_STATUS_IS_OK(status
)) {
457 /* Cache the parent security descriptor for
458 * later use. We do have an fsp here, but to
459 * keep the code consistent with the directory
460 * case which doesn't, use the handle. */
462 /* Attach this to the conn, move from talloc_tos(). */
463 psd
= (struct security_descriptor
*)talloc_move(handle
->conn
,
467 status
= NT_STATUS_NO_MEMORY
;
470 status
= NT_STATUS_NO_MEMORY
;
471 SMB_VFS_HANDLE_SET_DATA(handle
, psd
, free_sd_common
,
472 struct security_descriptor
*, goto err
);
473 status
= NT_STATUS_OK
;
477 DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
480 nt_errstr(status
) ));
482 fsp
->fh
->fd
= SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
, mode
);
487 errno
= map_errno_from_nt_status(status
);
491 static int mkdir_acl_common(vfs_handle_struct
*handle
, const char *path
, mode_t mode
)
495 SMB_STRUCT_STAT sbuf
;
497 ret
= vfs_stat_smb_fname(handle
->conn
, path
, &sbuf
);
498 if (ret
== -1 && errno
== ENOENT
) {
499 struct security_descriptor
*parent_desc
= NULL
;
500 struct security_descriptor
*psd
= NULL
;
502 /* We're creating a new directory. */
503 status
= check_parent_acl_common(handle
, path
,
504 SEC_DIR_ADD_SUBDIR
, &parent_desc
);
505 if (!NT_STATUS_IS_OK(status
)) {
506 errno
= map_errno_from_nt_status(status
);
510 /* Cache the parent security descriptor for
511 * later use. We don't have an fsp here so
514 /* Attach this to the conn, move from talloc_tos(). */
515 psd
= (struct security_descriptor
*)talloc_move(handle
->conn
,
521 SMB_VFS_HANDLE_SET_DATA(handle
, psd
, free_sd_common
,
522 struct security_descriptor
*, return -1);
525 return SMB_VFS_NEXT_MKDIR(handle
, path
, mode
);
528 /*********************************************************************
529 Fetch a security descriptor given an fsp.
530 *********************************************************************/
532 static NTSTATUS
fget_nt_acl_common(vfs_handle_struct
*handle
, files_struct
*fsp
,
533 uint32_t security_info
, struct security_descriptor
**ppdesc
)
535 return get_nt_acl_internal(handle
, fsp
,
536 NULL
, security_info
, ppdesc
);
539 /*********************************************************************
540 Fetch a security descriptor given a pathname.
541 *********************************************************************/
543 static NTSTATUS
get_nt_acl_common(vfs_handle_struct
*handle
,
544 const char *name
, uint32_t security_info
, struct security_descriptor
**ppdesc
)
546 return get_nt_acl_internal(handle
, NULL
,
547 name
, security_info
, ppdesc
);
550 /*********************************************************************
551 Store a security descriptor given an fsp.
552 *********************************************************************/
554 static NTSTATUS
fset_nt_acl_common(vfs_handle_struct
*handle
, files_struct
*fsp
,
555 uint32_t security_info_sent
, const struct security_descriptor
*psd
)
559 struct security_descriptor
*pdesc_next
= NULL
;
560 uint8_t hash
[XATTR_SD_HASH_SIZE
];
562 if (DEBUGLEVEL
>= 10) {
563 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
565 NDR_PRINT_DEBUG(security_descriptor
,
566 CONST_DISCARD(struct security_descriptor
*,psd
));
569 /* Ensure we have OWNER/GROUP/DACL set. */
571 if ((security_info_sent
& (OWNER_SECURITY_INFORMATION
|
572 GROUP_SECURITY_INFORMATION
|
573 DACL_SECURITY_INFORMATION
)) !=
574 (OWNER_SECURITY_INFORMATION
|
575 GROUP_SECURITY_INFORMATION
|
576 DACL_SECURITY_INFORMATION
)) {
577 /* No we don't - read from the existing SD. */
578 struct security_descriptor
*nc_psd
= NULL
;
580 status
= get_nt_acl_internal(handle
, fsp
,
582 (OWNER_SECURITY_INFORMATION
|
583 GROUP_SECURITY_INFORMATION
|
584 DACL_SECURITY_INFORMATION
),
587 if (!NT_STATUS_IS_OK(status
)) {
591 /* This is safe as nc_psd is discarded at fn exit. */
592 if (security_info_sent
& OWNER_SECURITY_INFORMATION
) {
593 nc_psd
->owner_sid
= psd
->owner_sid
;
595 security_info_sent
|= OWNER_SECURITY_INFORMATION
;
597 if (security_info_sent
& GROUP_SECURITY_INFORMATION
) {
598 nc_psd
->group_sid
= psd
->group_sid
;
600 security_info_sent
|= GROUP_SECURITY_INFORMATION
;
602 if (security_info_sent
& DACL_SECURITY_INFORMATION
) {
603 nc_psd
->dacl
= dup_sec_acl(talloc_tos(), psd
->dacl
);
604 if (nc_psd
->dacl
== NULL
) {
605 return NT_STATUS_NO_MEMORY
;
608 security_info_sent
|= DACL_SECURITY_INFORMATION
;
612 status
= SMB_VFS_NEXT_FSET_NT_ACL(handle
, fsp
, security_info_sent
, psd
);
613 if (!NT_STATUS_IS_OK(status
)) {
617 /* Get the full underlying sd, then hash. */
618 status
= SMB_VFS_NEXT_FGET_NT_ACL(handle
,
623 if (!NT_STATUS_IS_OK(status
)) {
627 status
= hash_sd_sha256(pdesc_next
, hash
);
628 if (!NT_STATUS_IS_OK(status
)) {
632 if (DEBUGLEVEL
>= 10) {
633 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
635 NDR_PRINT_DEBUG(security_descriptor
,
636 CONST_DISCARD(struct security_descriptor
*,psd
));
638 create_acl_blob(psd
, &blob
, XATTR_SD_HASH_TYPE_SHA256
, hash
);
639 store_acl_blob_fsp(handle
, fsp
, &blob
);
644 static SMB_STRUCT_DIR
*opendir_acl_common(vfs_handle_struct
*handle
,
645 const char *fname
, const char *mask
, uint32 attr
)
647 NTSTATUS status
= check_parent_acl_common(handle
, fname
,
650 if (!NT_STATUS_IS_OK(status
)) {
651 errno
= map_errno_from_nt_status(status
);
654 return SMB_VFS_NEXT_OPENDIR(handle
, fname
, mask
, attr
);
657 static NTSTATUS
create_file_acl_common(struct vfs_handle_struct
*handle
,
658 struct smb_request
*req
,
659 uint16_t root_dir_fid
,
660 struct smb_filename
*smb_fname
,
661 uint32_t access_mask
,
662 uint32_t share_access
,
663 uint32_t create_disposition
,
664 uint32_t create_options
,
665 uint32_t file_attributes
,
666 uint32_t oplock_request
,
667 uint64_t allocation_size
,
668 struct security_descriptor
*sd
,
669 struct ea_list
*ea_list
,
670 files_struct
**result
,
673 NTSTATUS status
, status1
;
674 files_struct
*fsp
= NULL
;
676 struct security_descriptor
*parent_sd
= NULL
;
678 status
= SMB_VFS_NEXT_CREATE_FILE(handle
,
694 if (info
!= FILE_WAS_CREATED
) {
695 /* File/directory was opened, not created. */
701 if (!NT_STATUS_IS_OK(status
) || fsp
== NULL
) {
702 /* Only handle success. */
707 /* Security descriptor already set. */
717 /* We must have a cached parent sd in this case.
718 * attached to the handle. */
720 SMB_VFS_HANDLE_GET_DATA(handle
, parent_sd
,
721 struct security_descriptor
,
724 /* New directory - inherit from parent. */
725 status1
= inherit_new_acl(handle
, fsp
, parent_sd
, fsp
->is_directory
);
727 if (!NT_STATUS_IS_OK(status1
)) {
728 DEBUG(1,("create_file_acl_common: error setting "
731 nt_errstr(status1
) ));
736 /* Ensure we never leave attached data around. */
737 SMB_VFS_HANDLE_FREE_DATA(handle
);
739 if (NT_STATUS_IS_OK(status
) && pinfo
) {
746 smb_panic("create_file_acl_common: logic error.\n");