smb_acl.c revision da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0
/*
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Platform SDK: Security
*
* 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.
*/
#include <smbsrv/smb_incl.h>
#include <smbsrv/smb_fsops.h>
#include <smbsrv/smb_idmap.h>
#define ZACE_IS_OWNGRP(zace) \
#define ZACE_IS_USER(zace) \
#define ZACE_IS_PROPAGATE(zace) \
#define ZACE_IS_CREATOR_OWNER(zace) \
#define ZACE_IS_CREATOR_GROUP(zace) \
#define ZACE_IS_CREATOR(zace) \
static int smb_ace_common_add(
static int
{
smb_ace_t *p;
min_len = sizeof (smb_ace_hdr_t);
return (0);
(which_acl != SMB_DACL_SECINFO)) {
return (0);
}
(which_acl != SMB_SACL_SECINFO)) {
return (0);
}
/*LINTED E_BAD_PTR_CAST_ALIGN*/
return (0); /* won't handle empty SubAuthority[] */
if (nt_sid_is_valid(&p->se_sid) == 0)
return (0);
return (0);
}
/*
* XXX object-specific ACE validation will be added later.
*/
return (1);
}
int
{
unsigned char *scan;
unsigned char *scan_end;
return (0);
/*
* XXX we are rejecting ACLs with object-specific ACEs for now
*/
return (0);
}
/*LINTED E_BAD_PTR_CAST_ALIGN*/
return (0);
return (0); /* overflow */
return (0);
count++;
}
return (1);
}
static void
{
}
{
unsigned char *scan_beg;
unsigned char *scan_end;
unsigned char *scan;
count = 0;
/*LINTED E_BAD_PTR_CAST_ALIGN*/
count++;
}
return (length);
}
/*
* Append the generic ACE to the ACL. This is used to put any
* kind of ACE on the ACL so the argument is declared as a void*. We cast it
* to an ACCESS_ALLOWED_ACE just because there is no sense of a generic ACE.
*/
static int
{
/* no room in the acl for this ace */
return (0);
}
/* append the ace to the acl and inc ace count */
return (1);
}
/*
* Helper for the ACL sort routine
*/
typedef struct smb_ace_entry {
/*
* 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
#define SMB_AG_DNY_INHRT 1
#define SMB_AG_ALW_DRCT 2
#define SMB_AG_DNY_DRCT 3
#define SMB_AG_NUM 4
/*
* smb_acl_do_sort
*
* Sorts the given ACL, acl, and returns the result
* in a newly allocated memory.
*
* 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
*
* Of course, not all ACE types are required in an ACL.
*/
static smb_acl_t *
{
int i;
*sorted_acl = *acl;
/* start with no ACE in the sorted ACL */
sorted_acl->sl_acecnt = 0;
/*
* start with highest priority ACE group and append
* the ACEs to the ACL.
*/
while (nae) {
return (NULL);
}
}
}
return (sorted_acl);
}
/*
* smb_acl_need_sort
*
* Here is the desired ACE order
*
* deny-direct, allow-direct, deny-inherited, allow-inherited
*
* If any ace has been encountered which belongs to a group
* with lower priority of the specified ace_grp then the acl
* should be sorted.
*/
static int
{
int i;
for (i = SMB_AG_START; i < ace_grp; i++)
if (!list_is_empty(&ace_grps[i]))
return (1);
return (0);
}
/*
* smb_acl_sort
*
* Returns NULL upon failure.
* Returns pointer to the passed (original) acl if no sort is required.
* Returns pointer to a new acl upon successful sort in which case the
* caller is responsible for freeing the allocated memory.
*/
{
int ace_list_size;
int ag;
int do_sort = 0;
uint16_t i;
/*
* ACL with no entry is a valid ACL and it means
* no access for anybody.
*/
return (acl);
}
for (i = SMB_AG_START; i < SMB_AG_NUM; i++) {
}
/*
* Allocate the helper entries to group the ACEs based on
* the desired priorities.
*/
case ACCESS_DENIED_ACE_TYPE:
if (ace_flags & INHERITED_ACE) {
} else {
}
break;
case ACCESS_ALLOWED_ACE_TYPE:
if (ace_flags & INHERITED_ACE) {
} else {
}
break;
default:
/*
* This is the lowest priority group so we put
* evertything unknown here.
*/
break;
}
/* Put the element on the appropriate list */
}
if (do_sort)
else
sorted_acl = acl;
for (i = SMB_AG_START; i < SMB_AG_NUM; i++) {
void *ent;
}
return (sorted_acl);
}
static int
{
/* won't fit */
return (0);
}
/*LINTED E_BAD_PTR_CAST_ALIGN*/
return (1);
}
{
return (NULL);
/*LINTED E_BAD_PTR_CAST_ALIGN*/
return (ace);
}
count++;
}
return (NULL);
}
int
{
unsigned char *dest_end;
return (0);
/*LINTED E_BAD_PTR_CAST_ALIGN*/
/*LINTED E_BAD_PTR_CAST_ALIGN*/
count++;
}
/*LINTED E_PTRDIFF_OVERFLOW*/
}
/*
* smb_ace_len
*
* Returns the length of an ACE with the given SID
*
* struct smb_ace {
* smb_ace_hdr_t se_header;
* uint32_t se_mask;
* nt_sid_t se_sid;
* };
*/
{
return (sizeof (smb_ace_hdr_t)
}
/*
* 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.
*/
{
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_acl_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_acl_grow
*
* Grow the acl size by given number of bytes in 'grow'
* Returns pointer to the newly allocated memory.
*/
static smb_acl_t *
{
return (new_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;
int status;
if (idm_stat != IDMAP_SUCCESS)
return (NULL);
return (NULL);
}
break;
}
/* Make room for this ACE */
if (status == 0) {
break;
}
}
return (acl);
}
/*
* SID for Everyone group: S-1-1-0.
*/
nt_sid_t everyone_sid = {
1,
{ 0 }
};
/*
* smb_acl_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.
*/
acl_t *
smb_acl_null_empty(int null)
{
if (null) {
} else {
}
return (zacl);
}
/*
* 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_fsop_aclfree().
*
* 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.
*/
{
int i, isdir;
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);
isdir);
else {
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);
}
/*
* smb_acl_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.
*
*
* FI DI NP #F #D
* ---- ---- ---- ---- ----
* - - ? 0 0
* X - - 1 1
* X - X 1 0
* - X - 0 1
* - X X 0 1
* X X - 1 1
* X X X 1 1
*
*
* FI DI NP #F #D
* ---- ---- ---- ---- ----
* - - ? 0 0
* X - - 1r 1c
* X - X 1r 0
* - X - 0 2
* - X X 0 1r
* X X - 1r 2
* X X X 1r 1r
*
* Legend:
*
* FI: File Inherit
* DI: Dir Inherit
* NP: No Propagate
* #F: #ACE for a new file
* #D: #ACE for a new dir
*
* X: bit is set
* -: bit is not set
* ?: don't care
*
*/
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);
}
#define DEFAULT_DACL_ACENUM 2
/*
* Default ACL:
* owner: full access
* SYSTEM: full access
*/
};
/*
* smb_acl_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.
*
*/
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);
}
static void
{
/*
*/
if (ZACE_IS_CREATOR_OWNER(dir_zace)) {
} else if (ZACE_IS_CREATOR_GROUP(dir_zace)) {
}
}
static uint16_t
{
if (c_flags & FAILED_ACCESS_ACE_FLAG)
if (c_flags & INHERITED_ACE)
/*
* ZFS doesn't like any inheritance flags to be set on a
* file's ACE, only directories. Windows doesn't care.
*/
if (isdir)
return (z_flags);
}
static uint8_t
{
if (z_flags & ACE_INHERITED_ACE)
c_flags |= INHERITED_ACE;
return (c_flags);
}
/*
* This is generic (ACL version 2) vs. object-specific
* (ACL version 4) ACE types.
*/
int
smb_ace_is_generic(int type)
{
switch (type) {
return (1);
default:
break;
}
return (0);
}
int
smb_ace_is_access(int type)
{
switch (type) {
return (1);
default:
break;
}
return (0);
}
int
smb_ace_is_audit(int type)
{
switch (type) {
return (1);
default:
break;
}
return (0);
}