/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
#include <acl/acl_common.h>
#include <smbsrv/smb_fsops.h>
#include <smbsrv/smb_idmap.h>
#include <smbsrv/smb_kproto.h>
/*
* ACE groups within a DACL
*
* This is from lower to higher ACE order priority
*/
#define SMB_AG_START 0
#define SMB_AG_ALW_INHRT 0
/*
* Default ACL:
* owner: full access
* SYSTEM: full access
*/
#ifdef _KERNEL
};
#endif /* _KERNEL */
/*
* Note:
*
* smb_acl_xxx functions work with smb_acl_t which represents the CIFS format
* smb_fsacl_xxx functions work with acl_t which represents the Solaris native
* format
*/
#ifdef _KERNEL
static int smb_fsacl_inheritable(acl_t *, int);
#endif /* _KERNEL */
{
int size;
return (acl);
}
void
{
int i, size;
void *ace;
return;
}
/*
* smb_acl_len
*
* Returns the size of given ACL in bytes. Note that this
* is not an in-memory size, it's the ACL's size as it would
* appear on the wire
*/
{
}
{
int i;
return (B_FALSE);
/*
* we are rejecting ACLs with object-specific ACEs for now
*/
return (B_FALSE);
}
return (B_FALSE);
}
return (B_TRUE);
}
/*
* smb_acl_sort
*
* Sorts the given ACL in place if it needs to be sorted.
*
* The following is an excerpt from MSDN website.
*
* Order of ACEs in a DACL
*
* For Windows NT versions 4.0 and earlier, the preferred order of ACEs
* is simple: In a DACL, all access-denied ACEs should precede any
* access-allowed ACEs.
*
* For Windows 2000 or later, the proper order of ACEs is more complicated
* because of the introduction of object-specific ACEs and automatic
* inheritance.
*
* The following describes the preferred order:
*
* To ensure that noninherited ACEs have precedence over inherited ACEs,
* place all noninherited ACEs in a group before any inherited ACEs. This
* ordering ensures, for example, that a noninherited access-denied ACE
* is enforced regardless of any inherited ACE that allows access.
* Within the groups of noninherited ACEs and inherited ACEs, order ACEs
* according to ACE type, as the following shows:
* . Access-denied ACEs that apply to the object itself
* . Access-denied ACEs that apply to a subobject of the
* object, such as a property set or property
* . Access-allowed ACEs that apply to the object itself
* . Access-allowed ACEs that apply to a subobject of the object
*
* So, here is the desired ACE order
*
* deny-direct, allow-direct, deny-inherited, allow-inherited
*
* Of course, not all ACE types are required in an ACL.
*/
void
{
int ag, i;
/*
* ACL with no entry is a valid ACL and it means
* no access for anybody.
*/
return;
}
for (i = SMB_AG_START; i < SMB_AG_NUM; i++) {
}
case ACCESS_DENIED_ACE_TYPE:
break;
case ACCESS_ALLOWED_ACE_TYPE:
break;
default:
/*
* This is the lowest priority group so we put
* evertything unknown here.
*/
break;
}
/* Add the ACE to the selected group */
}
/*
* start with highest priority ACE group and append
* the ACEs to the ACL.
*/
}
}
}
/*
* smb_acl_from_zfs
*
* Converts given ZFS ACL to a Windows ACL.
*
* A pointer to allocated memory for the Win ACL will be
* returned upon successful conversion.
*/
{
int numaces;
if (idm_stat != IDMAP_SUCCESS)
return (NULL);
return (NULL);
}
break;
}
}
return (acl);
}
/*
* smb_acl_to_zfs
*
* Converts given Windows ACL to a ZFS ACL.
*
* fs_acl will contain a pointer to the created ZFS ACL.
* The allocated memory should be freed by calling
* smb_fsacl_free().
*
* Since the output parameter, fs_acl, is allocated in this
* function, the caller has to make sure *fs_acl is NULL which
* means it's not pointing to any memory.
*/
{
char *sidstr;
int i;
return (NT_STATUS_INVALID_ACL);
if (which_acl == SMB_DACL_SECINFO) {
}
return (NT_STATUS_SUCCESS);
}
if (idm_stat != IDMAP_SUCCESS)
return (NT_STATUS_INTERNAL_ERROR);
if (idm_stat != IDMAP_SUCCESS) {
return (NT_STATUS_INTERNAL_ERROR);
}
}
}
if (idm_stat != IDMAP_SUCCESS) {
return (NT_STATUS_NONE_MAPPED);
}
/*
* Set the ACEs group flag based on the type of ID returned.
*/
continue;
}
return (NT_STATUS_SUCCESS);
}
static boolean_t
{
struct {
char *sid;
} map[] = {
{ NT_WORLD_SIDSTR, ACE_EVERYONE },
(ACE_GROUP | ACE_IDENTIFIER_GROUP) },
};
int i;
return (B_TRUE);
}
}
return (B_FALSE);
}
/*
* smb_fsacl_getsids
*
*/
static idmap_stat
{
int i, idtype;
case ACE_OWNER:
break;
case (ACE_GROUP | ACE_IDENTIFIER_GROUP):
/* owning group */
break;
case ACE_IDENTIFIER_GROUP:
/* regular group */
break;
case ACE_EVERYONE:
break;
default:
/* user entry */
}
if (idm_stat != IDMAP_SUCCESS) {
return (idm_stat);
}
}
return (idm_stat);
}
/*
* smb_fsacl_null_empty
*
* NULL DACL means everyone full-access
* Empty DACL means everyone full-deny
*
* ZFS ACL must have at least one entry so smb server has
* to simulate the aforementioned expected behavior by adding
* an entry in case the requested DACL is null or empty. Adding
* a everyone full-deny entry has proved to be problematic in
* tests since a deny entry takes precedence over allow entries.
* So, instead of adding a everyone full-deny, an owner ACE with
* owner implicit permissions will be set.
*/
static acl_t *
{
if (null) {
} else {
}
return (zacl);
}
/*
* FS ACL (acl_t) Functions
*/
acl_t *
{
return (acl);
}
void
{
if (acl)
}
/*
* smb_fsop_aclmerge
*
* smb_fsop_aclread/write routines which interact with filesystem
* work with single ACL. This routine merges given DACL and SACL
* which might have been created during CIFS to FS conversion into
* one single ACL.
*/
acl_t *
{
int dacl_size;
return (acl);
}
/*
* smb_fsacl_split
*
* NULL even if they're specified in 'which_acl', which means the target
*/
void
{
int i;
naccess++;
naudit++;
}
if (naccess) {
}
if (naudit) {
}
*access_ace = *zace;
access_ace++;
audit_ace++;
}
}
}
/*
* ACE Inheritance Rules
*
* The system propagates inheritable ACEs to child objects according to a
* set of inheritance rules. The system places inherited ACEs in the child's
* DACL according to the preferred order of ACEs in a DACL. For Windows
* 2000 or later, the system sets the INHERITED_ACE flag in all inherited ACEs.
*
* The following table shows the ACEs inherited by container and noncontainer
* child objects for different combinations of inheritance flags. These
* inheritance rules work the same for both DACLs and SACLs.
*
* Parent ACE type Effect on Child ACL
* ----------------------- -------------------
* OBJECT_INHERIT_ACE only Noncontainer child objects:
* Inherited as an effective ACE.
* Container child objects:
* Containers inherit an inherit-only ACE
* unless the NO_PROPAGATE_INHERIT_ACE bit
* flag is also set.
*
* CONTAINER_INHERIT_ACE only Noncontainer child objects:
* No effect on the child object.
* Container child objects:
* The child object inherits an effective ACE.
* The inherited ACE is inheritable unless the
* NO_PROPAGATE_INHERIT_ACE bit flag is also set.
*
* CONTAINER_INHERIT_ACE and
* OBJECT_INHERIT_ACE Noncontainer child objects:
* Inherited as an effective ACE.
* Container child objects:
* The child object inherits an effective ACE.
* The inherited ACE is inheritable unless the
* NO_PROPAGATE_INHERIT_ACE bit flag is also set
*
* No inheritance flags set No effect on child container or noncontainer
* objects.
*
* If an inherited ACE is an effective ACE for the child object, the system
* maps any generic rights to the specific rights for the child object.
* Similarly, the system maps generic SIDs, such as CREATOR_OWNER, to the
* appropriate SID. If an inherited ACE is an inherit-only ACE, any generic
* rights or generic SIDs are left unchanged so that they can be mapped
* appropriately when the ACE is inherited by the next generation of child
* objects.
*
* For a case in which a container object inherits an ACE that is both
* effective on the container and inheritable by its descendants, the
* container may inherit two ACEs. This occurs if the inheritable ACE
* contains generic information. The container inherits an inherit-only
* ACE containing the generic information and an effective-only ACE in
* which the generic information has been mapped.
*/
#ifdef _KERNEL
/*
* smb_fsacl_inherit
*
* Manufacture the inherited ACL from the given ACL considering
* returned ACL is used in smb_fsop_create/smb_fsop_mkdir functions.
* This function implements Windows inheritance rules explained above.
*
*/
acl_t *
{
int num_inheritable = 0;
int numaces;
if (num_inheritable == 0) {
if (which_acl == SMB_DACL_SECINFO) {
/* No inheritable access ACEs -> default DACL */
} else {
return (NULL);
}
}
if (use_default) {
return (new_zacl);
}
/*
* Files inherit an effective ACE.
*
* Dirs inherit an effective ACE.
* The inherited ACE is inheritable unless the
* ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set
*/
new_zace++;
(ZACE_IS_PROPAGATE(dir_zace))) {
new_zace++;
}
break;
case ACE_FILE_INHERIT_ACE:
/*
* Files inherit as an effective ACE.
*
* Dirs inherit an inherit-only ACE
* unless the ACE_NO_PROPAGATE_INHERIT_ACE bit
* flag is also set.
*/
if (is_dir == 0) {
new_zace++;
} else if (ZACE_IS_PROPAGATE(dir_zace)) {
new_zace++;
}
break;
/*
* No effect on files
*
* Dirs inherit an effective ACE.
* The inherited ACE is inheritable unless the
* ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set.
*/
if (is_dir == 0)
break;
new_zace++;
if (ZACE_IS_CREATOR(dir_zace) &&
(ZACE_IS_PROPAGATE(dir_zace))) {
new_zace++;
}
break;
default:
break;
}
}
return (new_zacl);
}
#endif /* _KERNEL */
/*
* smb_fsacl_from_vsa
*
* Converts given vsecattr_t structure to a acl_t structure.
*
* The allocated memory for retuned acl_t should be freed by
* calling acl_free().
*/
acl_t *
{
int numacls;
return (NULL);
switch (acl_type) {
case ACLENT_T:
KM_SLEEP);
aclbsize);
break;
case ACE_T:
aclbsize);
break;
default:
return (NULL);
}
return (acl_info);
}
/*
* smb_fsacl_to_vsa
*
* Converts given acl_t structure to a vsecattr_t structure.
*
* IMPORTANT:
* Upon successful return the memory allocated for vsa_aclentp
* should be freed by calling kmem_free(). The size is returned
* in aclbsize.
*/
int
{
int error = 0;
int numacls;
*aclbsize = 0;
case ACLENT_T:
/*
* Minimum ACL size is three entries so might as well
* bail out here. Also limit request size to prevent user
* from allocating too much kernel memory. Maximum size
* is MAX_ACL_ENTRIES for the ACL part and MAX_ACL_ENTRIES
* for the default ACL part.
*/
break;
}
*aclbsize);
/* Sort the acl list */
/* Break into acl and default acl lists */
break;
}
/* Find where defaults start (if any) */
}
/* Adjust if they're all defaults */
if (vsecattr->vsa_aclcnt == 0) {
}
/* Only directories can have defaults */
if (vsecattr->vsa_dfaclcnt &&
}
break;
case ACE_T:
break;
}
*aclbsize);
break;
default:
}
return (error);
}
#ifdef _KERNEL
/*
* smb_fsacl_inheritable
*
* Checks to see if there are any inheritable ACEs in the
* given ZFS ACL. Returns the number of inheritable ACEs.
*
* The inherited ACL could be different based on the type of
*
* Note that the input ACL is a ZFS ACL not Windows ACL.
*/
static int
{
int numaces;
int num_inheritable = 0;
return (0);
/*
* Files inherit an effective ACE.
*
* Dirs inherit an effective ACE.
* The inherited ACE is inheritable unless the
* ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set
*/
(ZACE_IS_PROPAGATE(zace))) {
}
break;
case ACE_FILE_INHERIT_ACE:
/*
* Files inherit as an effective ACE.
*
* Dirs inherit an inherit-only ACE
* unless the ACE_NO_PROPAGATE_INHERIT_ACE bit
* flag is also set.
*/
if (is_dir == 0)
else if (ZACE_IS_PROPAGATE(zace))
break;
/*
* No effect on files
*
* Dirs inherit an effective ACE.
* The inherited ACE is inheritable unless the
* ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set.
*/
if (is_dir == 0)
break;
if (ZACE_IS_CREATOR(zace) &&
break;
default:
break;
}
}
return (num_inheritable);
}
#endif /* _KERNEL */
/*
* ACE Functions
*/
/*
* This is generic (ACL version 2) vs. object-specific
* (ACL version 4) ACE types.
*/
{
switch (type) {
return (B_TRUE);
default:
break;
}
return (B_FALSE);
}
{
switch (type) {
return (B_TRUE);
default:
break;
}
return (B_FALSE);
}
{
switch (type) {
return (B_TRUE);
default:
break;
}
return (B_FALSE);
}
/*
* smb_ace_len
*
* Returns the length of the given ACE as it appears in an
* ACL on the wire (i.e. a flat buffer which contains the SID)
*/
static uint16_t
{
return (0);
}
#ifdef _KERNEL
static void
{
/* This is an effective ACE so remove the inherit_only flag */
/* Mark this ACE as inherited */
/*
* If this is a file or NO_PROPAGATE is set then this inherited
* ACE is not inheritable so clear the inheritance flags
*/
/*
* This is a non-inheritable effective ACE.
*/
if (ZACE_IS_CREATOR_OWNER(dir_zace)) {
} else if (ZACE_IS_CREATOR_GROUP(dir_zace)) {
}
}
#endif /* _KERNEL */
/*
* smb_ace_mask_g2s
*
* Converts generic access bits in the given mask (if any)
* to file specific bits. Generic access masks shouldn't be
* stored in filesystem ACEs.
*/
static uint32_t
{
if (mask & GENERIC_ALL) {
| GENERIC_EXECUTE);
mask |= FILE_ALL_ACCESS;
return (mask);
}
if (mask & GENERIC_READ) {
mask &= ~GENERIC_READ;
}
if (mask & GENERIC_WRITE) {
mask &= ~GENERIC_WRITE;
}
if (mask & GENERIC_EXECUTE) {
mask &= ~GENERIC_EXECUTE;
}
return (mask);
}
/*
* smb_ace_flags_tozfs
*
* This function maps the flags which have different values
* in Windows and Solaris. The ones with the same value are
* transferred untouched.
*/
static uint16_t
{
if (c_flags & FAILED_ACCESS_ACE_FLAG)
if (c_flags & INHERITED_ACE)
return (z_flags);
}
static uint8_t
{
if (z_flags & ACE_INHERITED_ACE)
c_flags |= INHERITED_ACE;
return (c_flags);
}
static boolean_t
{
min_len = sizeof (smb_acehdr_t);
return (B_FALSE);
(which_acl != SMB_DACL_SECINFO))
return (B_FALSE);
(which_acl != SMB_SACL_SECINFO))
return (B_FALSE);
return (B_FALSE);
return (B_FALSE);
}
/*
* object-specific ACE validation will be added later.
*/
return (B_TRUE);
}