129bd2886SAlan Wright /* 229bd2886SAlan Wright * CDDL HEADER START 329bd2886SAlan Wright * 429bd2886SAlan Wright * The contents of this file are subject to the terms of the 529bd2886SAlan Wright * Common Development and Distribution License (the "License"). 629bd2886SAlan Wright * You may not use this file except in compliance with the License. 729bd2886SAlan Wright * 829bd2886SAlan Wright * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 929bd2886SAlan Wright * or http://www.opensolaris.org/os/licensing. 1029bd2886SAlan Wright * See the License for the specific language governing permissions 1129bd2886SAlan Wright * and limitations under the License. 1229bd2886SAlan Wright * 1329bd2886SAlan Wright * When distributing Covered Code, include this CDDL HEADER in each 1429bd2886SAlan Wright * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1529bd2886SAlan Wright * If applicable, add the following below this CDDL HEADER, with the 1629bd2886SAlan Wright * fields enclosed by brackets "[]" replaced with your own identifying 1729bd2886SAlan Wright * information: Portions Copyright [yyyy] [name of copyright owner] 1829bd2886SAlan Wright * 1929bd2886SAlan Wright * CDDL HEADER END 2029bd2886SAlan Wright */ 2129bd2886SAlan Wright /* 22*f96bd5c8SAlan Wright * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 2329bd2886SAlan Wright * Use is subject to license terms. 2429bd2886SAlan Wright */ 2529bd2886SAlan Wright 2629bd2886SAlan Wright #include <stddef.h> 2729bd2886SAlan Wright #include <strings.h> 2829bd2886SAlan Wright #include <assert.h> 2929bd2886SAlan Wright 30bbf6f00cSJordan Brown #include <smbsrv/smb.h> 3129bd2886SAlan Wright #include <smbsrv/smb_sid.h> 3229bd2886SAlan Wright #include <smbsrv/smb_idmap.h> 3329bd2886SAlan Wright 3429bd2886SAlan Wright #define ACE_ALL_TYPES 0x001F 3529bd2886SAlan Wright 3629bd2886SAlan Wright /* 3729bd2886SAlan Wright * ACE groups within a DACL 3829bd2886SAlan Wright * 3929bd2886SAlan Wright * This is from lower to higher ACE order priority 4029bd2886SAlan Wright */ 4129bd2886SAlan Wright #define SMB_AG_START 0 4229bd2886SAlan Wright #define SMB_AG_ALW_INHRT 0 4329bd2886SAlan Wright #define SMB_AG_DNY_INHRT 1 4429bd2886SAlan Wright #define SMB_AG_ALW_DRCT 2 4529bd2886SAlan Wright #define SMB_AG_DNY_DRCT 3 4629bd2886SAlan Wright #define SMB_AG_NUM 4 4729bd2886SAlan Wright 4829bd2886SAlan Wright #define DEFAULT_DACL_ACENUM 2 4929bd2886SAlan Wright acl_t *acl_alloc(enum acl_type); 5029bd2886SAlan Wright 51*f96bd5c8SAlan Wright static idmap_stat smb_fsacl_getsids(smb_idmap_batch_t *, acl_t *); 5229bd2886SAlan Wright static acl_t *smb_fsacl_null_empty(boolean_t); 5329bd2886SAlan Wright static uint16_t smb_ace_len(smb_ace_t *); 5429bd2886SAlan Wright static uint32_t smb_ace_mask_g2s(uint32_t); 5529bd2886SAlan Wright static uint16_t smb_ace_flags_tozfs(uint8_t); 5629bd2886SAlan Wright static uint8_t smb_ace_flags_fromzfs(uint16_t); 57*f96bd5c8SAlan Wright static boolean_t smb_ace_wellknown_update(const char *, ace_t *); 5829bd2886SAlan Wright 5929bd2886SAlan Wright smb_acl_t * 6029bd2886SAlan Wright smb_acl_alloc(uint8_t revision, uint16_t bsize, uint16_t acecnt) 6129bd2886SAlan Wright { 6229bd2886SAlan Wright smb_acl_t *acl; 6329bd2886SAlan Wright int size; 6429bd2886SAlan Wright 6529bd2886SAlan Wright size = sizeof (smb_acl_t) + (acecnt * sizeof (smb_ace_t)); 6629bd2886SAlan Wright if ((acl = malloc(size)) == NULL) 6729bd2886SAlan Wright return (NULL); 6829bd2886SAlan Wright 6929bd2886SAlan Wright acl->sl_revision = revision; 7029bd2886SAlan Wright acl->sl_bsize = bsize; 7129bd2886SAlan Wright acl->sl_acecnt = acecnt; 7229bd2886SAlan Wright acl->sl_aces = (smb_ace_t *)(acl + 1); 7329bd2886SAlan Wright 7429bd2886SAlan Wright list_create(&acl->sl_sorted, sizeof (smb_ace_t), 7529bd2886SAlan Wright offsetof(smb_ace_t, se_sln)); 7629bd2886SAlan Wright return (acl); 7729bd2886SAlan Wright } 7829bd2886SAlan Wright 7929bd2886SAlan Wright void 8029bd2886SAlan Wright smb_acl_free(smb_acl_t *acl) 8129bd2886SAlan Wright { 8229bd2886SAlan Wright int i; 8329bd2886SAlan Wright void *ace; 8429bd2886SAlan Wright 8529bd2886SAlan Wright if (acl == NULL) 8629bd2886SAlan Wright return; 8729bd2886SAlan Wright 8829bd2886SAlan Wright for (i = 0; i < acl->sl_acecnt; i++) 8929bd2886SAlan Wright smb_sid_free(acl->sl_aces[i].se_sid); 9029bd2886SAlan Wright 9129bd2886SAlan Wright while ((ace = list_head(&acl->sl_sorted)) != NULL) 9229bd2886SAlan Wright list_remove(&acl->sl_sorted, ace); 9329bd2886SAlan Wright list_destroy(&acl->sl_sorted); 9429bd2886SAlan Wright free(acl); 9529bd2886SAlan Wright 9629bd2886SAlan Wright } 9729bd2886SAlan Wright 9829bd2886SAlan Wright /* 9929bd2886SAlan Wright * smb_acl_len 10029bd2886SAlan Wright * 10129bd2886SAlan Wright * Returns the size of given ACL in bytes. Note that this 10229bd2886SAlan Wright * is not an in-memory size, it's the ACL's size as it would 10329bd2886SAlan Wright * appear on the wire 10429bd2886SAlan Wright */ 10529bd2886SAlan Wright uint16_t 10629bd2886SAlan Wright smb_acl_len(smb_acl_t *acl) 10729bd2886SAlan Wright { 10829bd2886SAlan Wright return ((acl) ? acl->sl_bsize : 0); 10929bd2886SAlan Wright } 11029bd2886SAlan Wright 11129bd2886SAlan Wright /*ARGSUSED*/ 11229bd2886SAlan Wright boolean_t 11329bd2886SAlan Wright smb_acl_isvalid(smb_acl_t *acl, int which_acl) 11429bd2886SAlan Wright { 11529bd2886SAlan Wright if (acl->sl_bsize < SMB_ACL_HDRSIZE) 11629bd2886SAlan Wright return (B_FALSE); 11729bd2886SAlan Wright 11829bd2886SAlan Wright if (acl->sl_revision != ACL_REVISION) { 11929bd2886SAlan Wright /* 12029bd2886SAlan Wright * we are rejecting ACLs with object-specific ACEs for now 12129bd2886SAlan Wright */ 12229bd2886SAlan Wright return (B_FALSE); 12329bd2886SAlan Wright } 12429bd2886SAlan Wright 12529bd2886SAlan Wright return (B_TRUE); 12629bd2886SAlan Wright } 12729bd2886SAlan Wright 12829bd2886SAlan Wright /* 12929bd2886SAlan Wright * smb_acl_sort 13029bd2886SAlan Wright * 13129bd2886SAlan Wright * Sorts the given ACL in place if it needs to be sorted. 13229bd2886SAlan Wright * 13329bd2886SAlan Wright * The following is an excerpt from MSDN website. 13429bd2886SAlan Wright * 13529bd2886SAlan Wright * Order of ACEs in a DACL 13629bd2886SAlan Wright * 13729bd2886SAlan Wright * For Windows NT versions 4.0 and earlier, the preferred order of ACEs 13829bd2886SAlan Wright * is simple: In a DACL, all access-denied ACEs should precede any 13929bd2886SAlan Wright * access-allowed ACEs. 14029bd2886SAlan Wright * 14129bd2886SAlan Wright * For Windows 2000 or later, the proper order of ACEs is more complicated 14229bd2886SAlan Wright * because of the introduction of object-specific ACEs and automatic 14329bd2886SAlan Wright * inheritance. 14429bd2886SAlan Wright * 14529bd2886SAlan Wright * The following describes the preferred order: 14629bd2886SAlan Wright * 14729bd2886SAlan Wright * To ensure that noninherited ACEs have precedence over inherited ACEs, 14829bd2886SAlan Wright * place all noninherited ACEs in a group before any inherited ACEs. This 14929bd2886SAlan Wright * ordering ensures, for example, that a noninherited access-denied ACE 15029bd2886SAlan Wright * is enforced regardless of any inherited ACE that allows access. 15129bd2886SAlan Wright * Within the groups of noninherited ACEs and inherited ACEs, order ACEs 15229bd2886SAlan Wright * according to ACE type, as the following shows: 15329bd2886SAlan Wright * . Access-denied ACEs that apply to the object itself 15429bd2886SAlan Wright * . Access-denied ACEs that apply to a subobject of the 15529bd2886SAlan Wright * object, such as a property set or property 15629bd2886SAlan Wright * . Access-allowed ACEs that apply to the object itself 15729bd2886SAlan Wright * . Access-allowed ACEs that apply to a subobject of the object 15829bd2886SAlan Wright * 15929bd2886SAlan Wright * So, here is the desired ACE order 16029bd2886SAlan Wright * 16129bd2886SAlan Wright * deny-direct, allow-direct, deny-inherited, allow-inherited 16229bd2886SAlan Wright * 16329bd2886SAlan Wright * Of course, not all ACE types are required in an ACL. 16429bd2886SAlan Wright */ 16529bd2886SAlan Wright void 16629bd2886SAlan Wright smb_acl_sort(smb_acl_t *acl) 16729bd2886SAlan Wright { 16829bd2886SAlan Wright list_t ace_grps[SMB_AG_NUM]; 16929bd2886SAlan Wright list_t *alist; 17029bd2886SAlan Wright smb_ace_t *ace; 17129bd2886SAlan Wright uint8_t ace_flags; 17229bd2886SAlan Wright int ag, i; 17329bd2886SAlan Wright 17429bd2886SAlan Wright assert(acl); 17529bd2886SAlan Wright 17629bd2886SAlan Wright if (acl->sl_acecnt == 0) { 17729bd2886SAlan Wright /* 17829bd2886SAlan Wright * ACL with no entry is a valid ACL and it means 17929bd2886SAlan Wright * no access for anybody. 18029bd2886SAlan Wright */ 18129bd2886SAlan Wright return; 18229bd2886SAlan Wright } 18329bd2886SAlan Wright 18429bd2886SAlan Wright for (i = SMB_AG_START; i < SMB_AG_NUM; i++) { 18529bd2886SAlan Wright list_create(&ace_grps[i], sizeof (smb_ace_t), 18629bd2886SAlan Wright offsetof(smb_ace_t, se_sln)); 18729bd2886SAlan Wright } 18829bd2886SAlan Wright 18929bd2886SAlan Wright for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; ++i, ace++) { 19029bd2886SAlan Wright ace_flags = ace->se_hdr.se_flags; 19129bd2886SAlan Wright 19229bd2886SAlan Wright switch (ace->se_hdr.se_type) { 19329bd2886SAlan Wright case ACCESS_DENIED_ACE_TYPE: 19429bd2886SAlan Wright ag = (ace_flags & INHERITED_ACE) ? 19529bd2886SAlan Wright SMB_AG_DNY_INHRT : SMB_AG_DNY_DRCT; 19629bd2886SAlan Wright break; 19729bd2886SAlan Wright 19829bd2886SAlan Wright case ACCESS_ALLOWED_ACE_TYPE: 19929bd2886SAlan Wright ag = (ace_flags & INHERITED_ACE) ? 20029bd2886SAlan Wright SMB_AG_ALW_INHRT : SMB_AG_ALW_DRCT; 20129bd2886SAlan Wright break; 20229bd2886SAlan Wright 20329bd2886SAlan Wright default: 20429bd2886SAlan Wright /* 20529bd2886SAlan Wright * This is the lowest priority group so we put 20629bd2886SAlan Wright * evertything unknown here. 20729bd2886SAlan Wright */ 20829bd2886SAlan Wright ag = SMB_AG_ALW_INHRT; 20929bd2886SAlan Wright break; 21029bd2886SAlan Wright } 21129bd2886SAlan Wright 21229bd2886SAlan Wright /* Add the ACE to the selected group */ 21329bd2886SAlan Wright list_insert_tail(&ace_grps[ag], ace); 21429bd2886SAlan Wright } 21529bd2886SAlan Wright 21629bd2886SAlan Wright /* 21729bd2886SAlan Wright * start with highest priority ACE group and append 21829bd2886SAlan Wright * the ACEs to the ACL. 21929bd2886SAlan Wright */ 22029bd2886SAlan Wright for (i = SMB_AG_NUM - 1; i >= SMB_AG_START; i--) { 22129bd2886SAlan Wright alist = &ace_grps[i]; 22229bd2886SAlan Wright while ((ace = list_head(alist)) != NULL) { 22329bd2886SAlan Wright list_remove(alist, ace); 22429bd2886SAlan Wright list_insert_tail(&acl->sl_sorted, ace); 22529bd2886SAlan Wright } 22629bd2886SAlan Wright list_destroy(alist); 22729bd2886SAlan Wright } 22829bd2886SAlan Wright } 22929bd2886SAlan Wright 23029bd2886SAlan Wright /* 23129bd2886SAlan Wright * smb_acl_from_zfs 23229bd2886SAlan Wright * 23329bd2886SAlan Wright * Converts given ZFS ACL to a Windows ACL. 23429bd2886SAlan Wright * 23529bd2886SAlan Wright * A pointer to allocated memory for the Windows ACL will be 23629bd2886SAlan Wright * returned upon successful conversion. 23729bd2886SAlan Wright */ 23829bd2886SAlan Wright smb_acl_t * 239*f96bd5c8SAlan Wright smb_acl_from_zfs(acl_t *zacl) 24029bd2886SAlan Wright { 24129bd2886SAlan Wright ace_t *zace; 24229bd2886SAlan Wright int numaces; 24329bd2886SAlan Wright smb_acl_t *acl; 24429bd2886SAlan Wright smb_ace_t *ace; 24529bd2886SAlan Wright smb_idmap_batch_t sib; 24629bd2886SAlan Wright smb_idmap_t *sim; 24729bd2886SAlan Wright idmap_stat idm_stat; 24829bd2886SAlan Wright 24929bd2886SAlan Wright idm_stat = smb_idmap_batch_create(&sib, zacl->acl_cnt, 25029bd2886SAlan Wright SMB_IDMAP_ID2SID); 25129bd2886SAlan Wright if (idm_stat != IDMAP_SUCCESS) 25229bd2886SAlan Wright return (NULL); 25329bd2886SAlan Wright 254*f96bd5c8SAlan Wright if (smb_fsacl_getsids(&sib, zacl) != IDMAP_SUCCESS) { 25529bd2886SAlan Wright smb_idmap_batch_destroy(&sib); 25629bd2886SAlan Wright return (NULL); 25729bd2886SAlan Wright } 25829bd2886SAlan Wright 25929bd2886SAlan Wright acl = smb_acl_alloc(ACL_REVISION, SMB_ACL_HDRSIZE, zacl->acl_cnt); 26029bd2886SAlan Wright 26129bd2886SAlan Wright sim = sib.sib_maps; 26229bd2886SAlan Wright for (numaces = 0, zace = zacl->acl_aclp; 26329bd2886SAlan Wright numaces < zacl->acl_cnt; 26429bd2886SAlan Wright zace++, numaces++, sim++) { 26529bd2886SAlan Wright assert(sim->sim_sid); 26629bd2886SAlan Wright if (sim->sim_sid == NULL) { 26729bd2886SAlan Wright smb_acl_free(acl); 26829bd2886SAlan Wright acl = NULL; 26929bd2886SAlan Wright break; 27029bd2886SAlan Wright } 27129bd2886SAlan Wright 27229bd2886SAlan Wright ace = &acl->sl_aces[numaces]; 27329bd2886SAlan Wright ace->se_hdr.se_type = zace->a_type; 27429bd2886SAlan Wright ace->se_hdr.se_flags = smb_ace_flags_fromzfs(zace->a_flags); 27529bd2886SAlan Wright ace->se_mask = zace->a_access_mask; 27629bd2886SAlan Wright ace->se_sid = smb_sid_dup(sim->sim_sid); 27729bd2886SAlan Wright ace->se_hdr.se_bsize = smb_ace_len(ace); 27829bd2886SAlan Wright 27929bd2886SAlan Wright acl->sl_bsize += ace->se_hdr.se_bsize; 28029bd2886SAlan Wright } 28129bd2886SAlan Wright 28229bd2886SAlan Wright smb_idmap_batch_destroy(&sib); 28329bd2886SAlan Wright return (acl); 28429bd2886SAlan Wright } 28529bd2886SAlan Wright 28629bd2886SAlan Wright /* 28729bd2886SAlan Wright * smb_acl_to_zfs 28829bd2886SAlan Wright * 28929bd2886SAlan Wright * Converts given Windows ACL to a ZFS ACL. 29029bd2886SAlan Wright * 29129bd2886SAlan Wright * fs_acl will contain a pointer to the created ZFS ACL. 29229bd2886SAlan Wright * The allocated memory should be freed by calling 29329bd2886SAlan Wright * smb_fsacl_free(). 29429bd2886SAlan Wright * 29529bd2886SAlan Wright * Since the output parameter, fs_acl, is allocated in this 29629bd2886SAlan Wright * function, the caller has to make sure *fs_acl is NULL which 29729bd2886SAlan Wright * means it's not pointing to any memory. 29829bd2886SAlan Wright */ 29929bd2886SAlan Wright uint32_t 30029bd2886SAlan Wright smb_acl_to_zfs(smb_acl_t *acl, uint32_t flags, int which_acl, acl_t **fs_acl) 30129bd2886SAlan Wright { 302*f96bd5c8SAlan Wright char sidstr[SMB_SID_STRSZ]; 30329bd2886SAlan Wright smb_ace_t *ace; 30429bd2886SAlan Wright acl_t *zacl; 30529bd2886SAlan Wright ace_t *zace; 30629bd2886SAlan Wright smb_idmap_batch_t sib; 30729bd2886SAlan Wright smb_idmap_t *sim; 30829bd2886SAlan Wright idmap_stat idm_stat; 30929bd2886SAlan Wright int i; 31029bd2886SAlan Wright 31129bd2886SAlan Wright assert(fs_acl); 31229bd2886SAlan Wright assert(*fs_acl == NULL); 31329bd2886SAlan Wright 31429bd2886SAlan Wright if (acl && !smb_acl_isvalid(acl, which_acl)) 31529bd2886SAlan Wright return (NT_STATUS_INVALID_ACL); 31629bd2886SAlan Wright 31729bd2886SAlan Wright if ((acl == NULL) || (acl->sl_acecnt == 0)) { 31829bd2886SAlan Wright if (which_acl == SMB_DACL_SECINFO) { 31929bd2886SAlan Wright *fs_acl = smb_fsacl_null_empty(acl == NULL); 32029bd2886SAlan Wright } 32129bd2886SAlan Wright 32229bd2886SAlan Wright return (NT_STATUS_SUCCESS); 32329bd2886SAlan Wright } 32429bd2886SAlan Wright 32529bd2886SAlan Wright idm_stat = smb_idmap_batch_create(&sib, acl->sl_acecnt, 32629bd2886SAlan Wright SMB_IDMAP_SID2ID); 32729bd2886SAlan Wright if (idm_stat != IDMAP_SUCCESS) 32829bd2886SAlan Wright return (NT_STATUS_INTERNAL_ERROR); 32929bd2886SAlan Wright 33029bd2886SAlan Wright zacl = smb_fsacl_alloc(acl->sl_acecnt, flags); 33129bd2886SAlan Wright 33229bd2886SAlan Wright zace = zacl->acl_aclp; 33329bd2886SAlan Wright ace = acl->sl_aces; 33429bd2886SAlan Wright sim = sib.sib_maps; 33529bd2886SAlan Wright 33629bd2886SAlan Wright for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) { 33729bd2886SAlan Wright zace->a_type = ace->se_hdr.se_type & ACE_ALL_TYPES; 33829bd2886SAlan Wright zace->a_access_mask = smb_ace_mask_g2s(ace->se_mask); 33929bd2886SAlan Wright zace->a_flags = smb_ace_flags_tozfs(ace->se_hdr.se_flags); 340*f96bd5c8SAlan Wright zace->a_who = (uid_t)-1; 34129bd2886SAlan Wright 342*f96bd5c8SAlan Wright smb_sid_tostr(ace->se_sid, sidstr); 343*f96bd5c8SAlan Wright 344*f96bd5c8SAlan Wright if (!smb_ace_wellknown_update(sidstr, zace)) { 34529bd2886SAlan Wright sim->sim_id = &zace->a_who; 34629bd2886SAlan Wright idm_stat = smb_idmap_batch_getid(sib.sib_idmaph, sim, 347*f96bd5c8SAlan Wright ace->se_sid, SMB_IDMAP_UNKNOWN); 34829bd2886SAlan Wright 34929bd2886SAlan Wright if (idm_stat != IDMAP_SUCCESS) { 35029bd2886SAlan Wright smb_fsacl_free(zacl); 35129bd2886SAlan Wright smb_idmap_batch_destroy(&sib); 35229bd2886SAlan Wright return (NT_STATUS_INTERNAL_ERROR); 35329bd2886SAlan Wright } 35429bd2886SAlan Wright } 35529bd2886SAlan Wright } 35629bd2886SAlan Wright 35729bd2886SAlan Wright idm_stat = smb_idmap_batch_getmappings(&sib); 35829bd2886SAlan Wright if (idm_stat != IDMAP_SUCCESS) { 35929bd2886SAlan Wright smb_fsacl_free(zacl); 36029bd2886SAlan Wright smb_idmap_batch_destroy(&sib); 36129bd2886SAlan Wright return (NT_STATUS_NONE_MAPPED); 36229bd2886SAlan Wright } 36329bd2886SAlan Wright 36429bd2886SAlan Wright /* 36529bd2886SAlan Wright * Set the ACEs group flag based on the type of ID returned. 36629bd2886SAlan Wright */ 36729bd2886SAlan Wright zace = zacl->acl_aclp; 36829bd2886SAlan Wright ace = acl->sl_aces; 36929bd2886SAlan Wright sim = sib.sib_maps; 37029bd2886SAlan Wright for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) { 371*f96bd5c8SAlan Wright if (zace->a_who == (uid_t)-1) 37229bd2886SAlan Wright continue; 37329bd2886SAlan Wright 37429bd2886SAlan Wright if (sim->sim_idtype == SMB_IDMAP_GROUP) 37529bd2886SAlan Wright zace->a_flags |= ACE_IDENTIFIER_GROUP; 37629bd2886SAlan Wright } 37729bd2886SAlan Wright 37829bd2886SAlan Wright smb_idmap_batch_destroy(&sib); 37929bd2886SAlan Wright 38029bd2886SAlan Wright *fs_acl = zacl; 38129bd2886SAlan Wright return (NT_STATUS_SUCCESS); 38229bd2886SAlan Wright } 38329bd2886SAlan Wright 384*f96bd5c8SAlan Wright static boolean_t 385*f96bd5c8SAlan Wright smb_ace_wellknown_update(const char *sid, ace_t *zace) 386*f96bd5c8SAlan Wright { 387*f96bd5c8SAlan Wright struct { 388*f96bd5c8SAlan Wright char *sid; 389*f96bd5c8SAlan Wright uint16_t flags; 390*f96bd5c8SAlan Wright } map[] = { 391*f96bd5c8SAlan Wright { NT_WORLD_SIDSTR, ACE_EVERYONE }, 392*f96bd5c8SAlan Wright { NT_BUILTIN_CURRENT_OWNER_SIDSTR, ACE_OWNER }, 393*f96bd5c8SAlan Wright { NT_BUILTIN_CURRENT_GROUP_SIDSTR, 394*f96bd5c8SAlan Wright (ACE_GROUP | ACE_IDENTIFIER_GROUP) }, 395*f96bd5c8SAlan Wright }; 396*f96bd5c8SAlan Wright 397*f96bd5c8SAlan Wright int i; 398*f96bd5c8SAlan Wright 399*f96bd5c8SAlan Wright for (i = 0; i < (sizeof (map) / sizeof (map[0])); ++i) { 400*f96bd5c8SAlan Wright if (strcmp(sid, map[i].sid) == 0) { 401*f96bd5c8SAlan Wright zace->a_flags |= map[i].flags; 402*f96bd5c8SAlan Wright return (B_TRUE); 403*f96bd5c8SAlan Wright } 404*f96bd5c8SAlan Wright } 405*f96bd5c8SAlan Wright 406*f96bd5c8SAlan Wright return (B_FALSE); 407*f96bd5c8SAlan Wright } 408*f96bd5c8SAlan Wright 40929bd2886SAlan Wright /* 41029bd2886SAlan Wright * smb_fsacl_getsids 41129bd2886SAlan Wright * 41229bd2886SAlan Wright * Batch all the uid/gid in given ZFS ACL to get their corresponding SIDs. 41329bd2886SAlan Wright */ 41429bd2886SAlan Wright static idmap_stat 415*f96bd5c8SAlan Wright smb_fsacl_getsids(smb_idmap_batch_t *sib, acl_t *zacl) 41629bd2886SAlan Wright { 41729bd2886SAlan Wright ace_t *zace; 41829bd2886SAlan Wright idmap_stat idm_stat; 41929bd2886SAlan Wright smb_idmap_t *sim; 42029bd2886SAlan Wright uid_t id; 42129bd2886SAlan Wright int i, idtype; 42229bd2886SAlan Wright 42329bd2886SAlan Wright sim = sib->sib_maps; 42429bd2886SAlan Wright 42529bd2886SAlan Wright for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; 42629bd2886SAlan Wright zace++, i++, sim++) { 42729bd2886SAlan Wright switch (zace->a_flags & ACE_TYPE_FLAGS) { 42829bd2886SAlan Wright case ACE_OWNER: 429*f96bd5c8SAlan Wright idtype = SMB_IDMAP_OWNERAT; 43029bd2886SAlan Wright break; 43129bd2886SAlan Wright 43229bd2886SAlan Wright case (ACE_GROUP | ACE_IDENTIFIER_GROUP): 43329bd2886SAlan Wright /* owning group */ 434*f96bd5c8SAlan Wright idtype = SMB_IDMAP_GROUPAT; 43529bd2886SAlan Wright break; 43629bd2886SAlan Wright 43729bd2886SAlan Wright case ACE_IDENTIFIER_GROUP: 43829bd2886SAlan Wright /* regular group */ 43929bd2886SAlan Wright id = zace->a_who; 44029bd2886SAlan Wright idtype = SMB_IDMAP_GROUP; 44129bd2886SAlan Wright break; 44229bd2886SAlan Wright 44329bd2886SAlan Wright case ACE_EVERYONE: 44429bd2886SAlan Wright idtype = SMB_IDMAP_EVERYONE; 44529bd2886SAlan Wright break; 44629bd2886SAlan Wright 44729bd2886SAlan Wright default: 44829bd2886SAlan Wright /* user entry */ 44929bd2886SAlan Wright id = zace->a_who; 45029bd2886SAlan Wright idtype = SMB_IDMAP_USER; 45129bd2886SAlan Wright } 45229bd2886SAlan Wright 45329bd2886SAlan Wright idm_stat = smb_idmap_batch_getsid(sib->sib_idmaph, sim, 45429bd2886SAlan Wright id, idtype); 45529bd2886SAlan Wright 45629bd2886SAlan Wright if (idm_stat != IDMAP_SUCCESS) { 45729bd2886SAlan Wright return (idm_stat); 45829bd2886SAlan Wright } 45929bd2886SAlan Wright } 46029bd2886SAlan Wright 46129bd2886SAlan Wright idm_stat = smb_idmap_batch_getmappings(sib); 46229bd2886SAlan Wright return (idm_stat); 46329bd2886SAlan Wright } 46429bd2886SAlan Wright 46529bd2886SAlan Wright /* 46629bd2886SAlan Wright * smb_fsacl_null_empty 46729bd2886SAlan Wright * 46829bd2886SAlan Wright * NULL DACL means everyone full-access 46929bd2886SAlan Wright * Empty DACL means everyone full-deny 47029bd2886SAlan Wright * 47129bd2886SAlan Wright * ZFS ACL must have at least one entry so smb server has 47229bd2886SAlan Wright * to simulate the aforementioned expected behavior by adding 47329bd2886SAlan Wright * an entry in case the requested DACL is null or empty. Adding 47429bd2886SAlan Wright * a everyone full-deny entry has proved to be problematic in 47529bd2886SAlan Wright * tests since a deny entry takes precedence over allow entries. 47629bd2886SAlan Wright * So, instead of adding a everyone full-deny, an owner ACE with 47729bd2886SAlan Wright * owner implicit permissions will be set. 47829bd2886SAlan Wright */ 47929bd2886SAlan Wright static acl_t * 48029bd2886SAlan Wright smb_fsacl_null_empty(boolean_t null) 48129bd2886SAlan Wright { 48229bd2886SAlan Wright acl_t *zacl; 48329bd2886SAlan Wright ace_t *zace; 48429bd2886SAlan Wright 48529bd2886SAlan Wright zacl = smb_fsacl_alloc(1, ACL_AUTO_INHERIT); 48629bd2886SAlan Wright zace = zacl->acl_aclp; 48729bd2886SAlan Wright 48829bd2886SAlan Wright zace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; 48929bd2886SAlan Wright if (null) { 49029bd2886SAlan Wright zace->a_access_mask = ACE_ALL_PERMS; 49129bd2886SAlan Wright zace->a_flags = ACE_EVERYONE; 49229bd2886SAlan Wright } else { 49329bd2886SAlan Wright zace->a_access_mask = ACE_READ_ACL | ACE_WRITE_ACL | 49429bd2886SAlan Wright ACE_READ_ATTRIBUTES; 49529bd2886SAlan Wright zace->a_flags = ACE_OWNER; 49629bd2886SAlan Wright } 49729bd2886SAlan Wright 49829bd2886SAlan Wright return (zacl); 49929bd2886SAlan Wright } 50029bd2886SAlan Wright 50129bd2886SAlan Wright /* 50229bd2886SAlan Wright * FS ACL (acl_t) Functions 50329bd2886SAlan Wright */ 50429bd2886SAlan Wright acl_t * 50529bd2886SAlan Wright smb_fsacl_alloc(int acenum, int flags) 50629bd2886SAlan Wright { 50729bd2886SAlan Wright acl_t *acl; 50829bd2886SAlan Wright 50929bd2886SAlan Wright acl = acl_alloc(ACE_T); 51029bd2886SAlan Wright acl->acl_cnt = acenum; 51129bd2886SAlan Wright if ((acl->acl_aclp = malloc(acl->acl_entry_size * acenum)) == NULL) 51229bd2886SAlan Wright return (NULL); 51329bd2886SAlan Wright 51429bd2886SAlan Wright acl->acl_flags = flags; 51529bd2886SAlan Wright return (acl); 51629bd2886SAlan Wright } 51729bd2886SAlan Wright 51829bd2886SAlan Wright void 51929bd2886SAlan Wright smb_fsacl_free(acl_t *acl) 52029bd2886SAlan Wright { 52129bd2886SAlan Wright if (acl) 52229bd2886SAlan Wright acl_free(acl); 52329bd2886SAlan Wright } 52429bd2886SAlan Wright 52529bd2886SAlan Wright /* 52629bd2886SAlan Wright * ACE Functions 52729bd2886SAlan Wright */ 52829bd2886SAlan Wright 52929bd2886SAlan Wright /* 53029bd2886SAlan Wright * smb_ace_len 53129bd2886SAlan Wright * 53229bd2886SAlan Wright * Returns the length of the given ACE as it appears in an 53329bd2886SAlan Wright * ACL on the wire (i.e. a flat buffer which contains the SID) 53429bd2886SAlan Wright */ 53529bd2886SAlan Wright static uint16_t 53629bd2886SAlan Wright smb_ace_len(smb_ace_t *ace) 53729bd2886SAlan Wright { 53829bd2886SAlan Wright assert(ace); 53929bd2886SAlan Wright assert(ace->se_sid); 54029bd2886SAlan Wright 54129bd2886SAlan Wright if (ace == NULL) 54229bd2886SAlan Wright return (0); 54329bd2886SAlan Wright 54429bd2886SAlan Wright return (SMB_ACE_HDRSIZE + sizeof (ace->se_mask) + 54529bd2886SAlan Wright smb_sid_len(ace->se_sid)); 54629bd2886SAlan Wright } 54729bd2886SAlan Wright 54829bd2886SAlan Wright /* 54929bd2886SAlan Wright * smb_ace_mask_g2s 55029bd2886SAlan Wright * 55129bd2886SAlan Wright * Converts generic access bits in the given mask (if any) 55229bd2886SAlan Wright * to file specific bits. Generic access masks shouldn't be 55329bd2886SAlan Wright * stored in filesystem ACEs. 55429bd2886SAlan Wright */ 55529bd2886SAlan Wright static uint32_t 55629bd2886SAlan Wright smb_ace_mask_g2s(uint32_t mask) 55729bd2886SAlan Wright { 55829bd2886SAlan Wright if (mask & GENERIC_ALL) { 55929bd2886SAlan Wright mask &= ~(GENERIC_ALL | GENERIC_READ | GENERIC_WRITE 56029bd2886SAlan Wright | GENERIC_EXECUTE); 56129bd2886SAlan Wright 56229bd2886SAlan Wright mask |= FILE_ALL_ACCESS; 56329bd2886SAlan Wright return (mask); 56429bd2886SAlan Wright } 56529bd2886SAlan Wright 56629bd2886SAlan Wright if (mask & GENERIC_READ) { 56729bd2886SAlan Wright mask &= ~GENERIC_READ; 56829bd2886SAlan Wright mask |= FILE_GENERIC_READ; 56929bd2886SAlan Wright } 57029bd2886SAlan Wright 57129bd2886SAlan Wright if (mask & GENERIC_WRITE) { 57229bd2886SAlan Wright mask &= ~GENERIC_WRITE; 57329bd2886SAlan Wright mask |= FILE_GENERIC_WRITE; 57429bd2886SAlan Wright } 57529bd2886SAlan Wright 57629bd2886SAlan Wright if (mask & GENERIC_EXECUTE) { 57729bd2886SAlan Wright mask &= ~GENERIC_EXECUTE; 57829bd2886SAlan Wright mask |= FILE_GENERIC_EXECUTE; 57929bd2886SAlan Wright } 58029bd2886SAlan Wright 58129bd2886SAlan Wright return (mask); 58229bd2886SAlan Wright } 58329bd2886SAlan Wright 58429bd2886SAlan Wright /* 58529bd2886SAlan Wright * smb_ace_flags_tozfs 58629bd2886SAlan Wright * 58729bd2886SAlan Wright * This function maps the flags which have different values 58829bd2886SAlan Wright * in Windows and Solaris. The ones with the same value are 58929bd2886SAlan Wright * transferred untouched. 59029bd2886SAlan Wright */ 59129bd2886SAlan Wright static uint16_t 59229bd2886SAlan Wright smb_ace_flags_tozfs(uint8_t c_flags) 59329bd2886SAlan Wright { 59429bd2886SAlan Wright uint16_t z_flags = 0; 59529bd2886SAlan Wright 59629bd2886SAlan Wright if (c_flags & SUCCESSFUL_ACCESS_ACE_FLAG) 59729bd2886SAlan Wright z_flags |= ACE_SUCCESSFUL_ACCESS_ACE_FLAG; 59829bd2886SAlan Wright 59929bd2886SAlan Wright if (c_flags & FAILED_ACCESS_ACE_FLAG) 60029bd2886SAlan Wright z_flags |= ACE_FAILED_ACCESS_ACE_FLAG; 60129bd2886SAlan Wright 60229bd2886SAlan Wright if (c_flags & INHERITED_ACE) 60329bd2886SAlan Wright z_flags |= ACE_INHERITED_ACE; 60429bd2886SAlan Wright 60529bd2886SAlan Wright z_flags |= (c_flags & ACE_INHERIT_FLAGS); 60629bd2886SAlan Wright 60729bd2886SAlan Wright return (z_flags); 60829bd2886SAlan Wright } 60929bd2886SAlan Wright 61029bd2886SAlan Wright static uint8_t 61129bd2886SAlan Wright smb_ace_flags_fromzfs(uint16_t z_flags) 61229bd2886SAlan Wright { 61329bd2886SAlan Wright uint8_t c_flags; 61429bd2886SAlan Wright 61529bd2886SAlan Wright c_flags = z_flags & ACE_INHERIT_FLAGS; 61629bd2886SAlan Wright 61729bd2886SAlan Wright if (z_flags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG) 61829bd2886SAlan Wright c_flags |= SUCCESSFUL_ACCESS_ACE_FLAG; 61929bd2886SAlan Wright 62029bd2886SAlan Wright if (z_flags & ACE_FAILED_ACCESS_ACE_FLAG) 62129bd2886SAlan Wright c_flags |= FAILED_ACCESS_ACE_FLAG; 62229bd2886SAlan Wright 62329bd2886SAlan Wright if (z_flags & ACE_INHERITED_ACE) 62429bd2886SAlan Wright c_flags |= INHERITED_ACE; 62529bd2886SAlan Wright 62629bd2886SAlan Wright return (c_flags); 62729bd2886SAlan Wright } 628