19832Samw@Sun.COM /*
29832Samw@Sun.COM * CDDL HEADER START
39832Samw@Sun.COM *
49832Samw@Sun.COM * The contents of this file are subject to the terms of the
59832Samw@Sun.COM * Common Development and Distribution License (the "License").
69832Samw@Sun.COM * You may not use this file except in compliance with the License.
79832Samw@Sun.COM *
89832Samw@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99832Samw@Sun.COM * or http://www.opensolaris.org/os/licensing.
109832Samw@Sun.COM * See the License for the specific language governing permissions
119832Samw@Sun.COM * and limitations under the License.
129832Samw@Sun.COM *
139832Samw@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
149832Samw@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159832Samw@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
169832Samw@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
179832Samw@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
189832Samw@Sun.COM *
199832Samw@Sun.COM * CDDL HEADER END
209832Samw@Sun.COM */
219832Samw@Sun.COM /*
22*11447Samw@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
239832Samw@Sun.COM * Use is subject to license terms.
249832Samw@Sun.COM */
259832Samw@Sun.COM
269832Samw@Sun.COM #include <stddef.h>
279832Samw@Sun.COM #include <strings.h>
289832Samw@Sun.COM #include <assert.h>
299832Samw@Sun.COM
3010966SJordan.Brown@Sun.COM #include <smbsrv/smb.h>
319832Samw@Sun.COM #include <smbsrv/smb_sid.h>
329832Samw@Sun.COM #include <smbsrv/smb_idmap.h>
339832Samw@Sun.COM
349832Samw@Sun.COM #define ACE_ALL_TYPES 0x001F
359832Samw@Sun.COM
369832Samw@Sun.COM /*
379832Samw@Sun.COM * ACE groups within a DACL
389832Samw@Sun.COM *
399832Samw@Sun.COM * This is from lower to higher ACE order priority
409832Samw@Sun.COM */
419832Samw@Sun.COM #define SMB_AG_START 0
429832Samw@Sun.COM #define SMB_AG_ALW_INHRT 0
439832Samw@Sun.COM #define SMB_AG_DNY_INHRT 1
449832Samw@Sun.COM #define SMB_AG_ALW_DRCT 2
459832Samw@Sun.COM #define SMB_AG_DNY_DRCT 3
469832Samw@Sun.COM #define SMB_AG_NUM 4
479832Samw@Sun.COM
489832Samw@Sun.COM #define DEFAULT_DACL_ACENUM 2
499832Samw@Sun.COM acl_t *acl_alloc(enum acl_type);
509832Samw@Sun.COM
51*11447Samw@Sun.COM static idmap_stat smb_fsacl_getsids(smb_idmap_batch_t *, acl_t *);
529832Samw@Sun.COM static acl_t *smb_fsacl_null_empty(boolean_t);
539832Samw@Sun.COM static uint16_t smb_ace_len(smb_ace_t *);
549832Samw@Sun.COM static uint32_t smb_ace_mask_g2s(uint32_t);
559832Samw@Sun.COM static uint16_t smb_ace_flags_tozfs(uint8_t);
569832Samw@Sun.COM static uint8_t smb_ace_flags_fromzfs(uint16_t);
57*11447Samw@Sun.COM static boolean_t smb_ace_wellknown_update(const char *, ace_t *);
589832Samw@Sun.COM
599832Samw@Sun.COM smb_acl_t *
smb_acl_alloc(uint8_t revision,uint16_t bsize,uint16_t acecnt)609832Samw@Sun.COM smb_acl_alloc(uint8_t revision, uint16_t bsize, uint16_t acecnt)
619832Samw@Sun.COM {
629832Samw@Sun.COM smb_acl_t *acl;
639832Samw@Sun.COM int size;
649832Samw@Sun.COM
659832Samw@Sun.COM size = sizeof (smb_acl_t) + (acecnt * sizeof (smb_ace_t));
669832Samw@Sun.COM if ((acl = malloc(size)) == NULL)
679832Samw@Sun.COM return (NULL);
689832Samw@Sun.COM
699832Samw@Sun.COM acl->sl_revision = revision;
709832Samw@Sun.COM acl->sl_bsize = bsize;
719832Samw@Sun.COM acl->sl_acecnt = acecnt;
729832Samw@Sun.COM acl->sl_aces = (smb_ace_t *)(acl + 1);
739832Samw@Sun.COM
749832Samw@Sun.COM list_create(&acl->sl_sorted, sizeof (smb_ace_t),
759832Samw@Sun.COM offsetof(smb_ace_t, se_sln));
769832Samw@Sun.COM return (acl);
779832Samw@Sun.COM }
789832Samw@Sun.COM
799832Samw@Sun.COM void
smb_acl_free(smb_acl_t * acl)809832Samw@Sun.COM smb_acl_free(smb_acl_t *acl)
819832Samw@Sun.COM {
829832Samw@Sun.COM int i;
839832Samw@Sun.COM void *ace;
849832Samw@Sun.COM
859832Samw@Sun.COM if (acl == NULL)
869832Samw@Sun.COM return;
879832Samw@Sun.COM
889832Samw@Sun.COM for (i = 0; i < acl->sl_acecnt; i++)
899832Samw@Sun.COM smb_sid_free(acl->sl_aces[i].se_sid);
909832Samw@Sun.COM
919832Samw@Sun.COM while ((ace = list_head(&acl->sl_sorted)) != NULL)
929832Samw@Sun.COM list_remove(&acl->sl_sorted, ace);
939832Samw@Sun.COM list_destroy(&acl->sl_sorted);
949832Samw@Sun.COM free(acl);
959832Samw@Sun.COM
969832Samw@Sun.COM }
979832Samw@Sun.COM
989832Samw@Sun.COM /*
999832Samw@Sun.COM * smb_acl_len
1009832Samw@Sun.COM *
1019832Samw@Sun.COM * Returns the size of given ACL in bytes. Note that this
1029832Samw@Sun.COM * is not an in-memory size, it's the ACL's size as it would
1039832Samw@Sun.COM * appear on the wire
1049832Samw@Sun.COM */
1059832Samw@Sun.COM uint16_t
smb_acl_len(smb_acl_t * acl)1069832Samw@Sun.COM smb_acl_len(smb_acl_t *acl)
1079832Samw@Sun.COM {
1089832Samw@Sun.COM return ((acl) ? acl->sl_bsize : 0);
1099832Samw@Sun.COM }
1109832Samw@Sun.COM
1119832Samw@Sun.COM /*ARGSUSED*/
1129832Samw@Sun.COM boolean_t
smb_acl_isvalid(smb_acl_t * acl,int which_acl)1139832Samw@Sun.COM smb_acl_isvalid(smb_acl_t *acl, int which_acl)
1149832Samw@Sun.COM {
1159832Samw@Sun.COM if (acl->sl_bsize < SMB_ACL_HDRSIZE)
1169832Samw@Sun.COM return (B_FALSE);
1179832Samw@Sun.COM
1189832Samw@Sun.COM if (acl->sl_revision != ACL_REVISION) {
1199832Samw@Sun.COM /*
1209832Samw@Sun.COM * we are rejecting ACLs with object-specific ACEs for now
1219832Samw@Sun.COM */
1229832Samw@Sun.COM return (B_FALSE);
1239832Samw@Sun.COM }
1249832Samw@Sun.COM
1259832Samw@Sun.COM return (B_TRUE);
1269832Samw@Sun.COM }
1279832Samw@Sun.COM
1289832Samw@Sun.COM /*
1299832Samw@Sun.COM * smb_acl_sort
1309832Samw@Sun.COM *
1319832Samw@Sun.COM * Sorts the given ACL in place if it needs to be sorted.
1329832Samw@Sun.COM *
1339832Samw@Sun.COM * The following is an excerpt from MSDN website.
1349832Samw@Sun.COM *
1359832Samw@Sun.COM * Order of ACEs in a DACL
1369832Samw@Sun.COM *
1379832Samw@Sun.COM * For Windows NT versions 4.0 and earlier, the preferred order of ACEs
1389832Samw@Sun.COM * is simple: In a DACL, all access-denied ACEs should precede any
1399832Samw@Sun.COM * access-allowed ACEs.
1409832Samw@Sun.COM *
1419832Samw@Sun.COM * For Windows 2000 or later, the proper order of ACEs is more complicated
1429832Samw@Sun.COM * because of the introduction of object-specific ACEs and automatic
1439832Samw@Sun.COM * inheritance.
1449832Samw@Sun.COM *
1459832Samw@Sun.COM * The following describes the preferred order:
1469832Samw@Sun.COM *
1479832Samw@Sun.COM * To ensure that noninherited ACEs have precedence over inherited ACEs,
1489832Samw@Sun.COM * place all noninherited ACEs in a group before any inherited ACEs. This
1499832Samw@Sun.COM * ordering ensures, for example, that a noninherited access-denied ACE
1509832Samw@Sun.COM * is enforced regardless of any inherited ACE that allows access.
1519832Samw@Sun.COM * Within the groups of noninherited ACEs and inherited ACEs, order ACEs
1529832Samw@Sun.COM * according to ACE type, as the following shows:
1539832Samw@Sun.COM * . Access-denied ACEs that apply to the object itself
1549832Samw@Sun.COM * . Access-denied ACEs that apply to a subobject of the
1559832Samw@Sun.COM * object, such as a property set or property
1569832Samw@Sun.COM * . Access-allowed ACEs that apply to the object itself
1579832Samw@Sun.COM * . Access-allowed ACEs that apply to a subobject of the object
1589832Samw@Sun.COM *
1599832Samw@Sun.COM * So, here is the desired ACE order
1609832Samw@Sun.COM *
1619832Samw@Sun.COM * deny-direct, allow-direct, deny-inherited, allow-inherited
1629832Samw@Sun.COM *
1639832Samw@Sun.COM * Of course, not all ACE types are required in an ACL.
1649832Samw@Sun.COM */
1659832Samw@Sun.COM void
smb_acl_sort(smb_acl_t * acl)1669832Samw@Sun.COM smb_acl_sort(smb_acl_t *acl)
1679832Samw@Sun.COM {
1689832Samw@Sun.COM list_t ace_grps[SMB_AG_NUM];
1699832Samw@Sun.COM list_t *alist;
1709832Samw@Sun.COM smb_ace_t *ace;
1719832Samw@Sun.COM uint8_t ace_flags;
1729832Samw@Sun.COM int ag, i;
1739832Samw@Sun.COM
1749832Samw@Sun.COM assert(acl);
1759832Samw@Sun.COM
1769832Samw@Sun.COM if (acl->sl_acecnt == 0) {
1779832Samw@Sun.COM /*
1789832Samw@Sun.COM * ACL with no entry is a valid ACL and it means
1799832Samw@Sun.COM * no access for anybody.
1809832Samw@Sun.COM */
1819832Samw@Sun.COM return;
1829832Samw@Sun.COM }
1839832Samw@Sun.COM
1849832Samw@Sun.COM for (i = SMB_AG_START; i < SMB_AG_NUM; i++) {
1859832Samw@Sun.COM list_create(&ace_grps[i], sizeof (smb_ace_t),
1869832Samw@Sun.COM offsetof(smb_ace_t, se_sln));
1879832Samw@Sun.COM }
1889832Samw@Sun.COM
1899832Samw@Sun.COM for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; ++i, ace++) {
1909832Samw@Sun.COM ace_flags = ace->se_hdr.se_flags;
1919832Samw@Sun.COM
1929832Samw@Sun.COM switch (ace->se_hdr.se_type) {
1939832Samw@Sun.COM case ACCESS_DENIED_ACE_TYPE:
1949832Samw@Sun.COM ag = (ace_flags & INHERITED_ACE) ?
1959832Samw@Sun.COM SMB_AG_DNY_INHRT : SMB_AG_DNY_DRCT;
1969832Samw@Sun.COM break;
1979832Samw@Sun.COM
1989832Samw@Sun.COM case ACCESS_ALLOWED_ACE_TYPE:
1999832Samw@Sun.COM ag = (ace_flags & INHERITED_ACE) ?
2009832Samw@Sun.COM SMB_AG_ALW_INHRT : SMB_AG_ALW_DRCT;
2019832Samw@Sun.COM break;
2029832Samw@Sun.COM
2039832Samw@Sun.COM default:
2049832Samw@Sun.COM /*
2059832Samw@Sun.COM * This is the lowest priority group so we put
2069832Samw@Sun.COM * evertything unknown here.
2079832Samw@Sun.COM */
2089832Samw@Sun.COM ag = SMB_AG_ALW_INHRT;
2099832Samw@Sun.COM break;
2109832Samw@Sun.COM }
2119832Samw@Sun.COM
2129832Samw@Sun.COM /* Add the ACE to the selected group */
2139832Samw@Sun.COM list_insert_tail(&ace_grps[ag], ace);
2149832Samw@Sun.COM }
2159832Samw@Sun.COM
2169832Samw@Sun.COM /*
2179832Samw@Sun.COM * start with highest priority ACE group and append
2189832Samw@Sun.COM * the ACEs to the ACL.
2199832Samw@Sun.COM */
2209832Samw@Sun.COM for (i = SMB_AG_NUM - 1; i >= SMB_AG_START; i--) {
2219832Samw@Sun.COM alist = &ace_grps[i];
2229832Samw@Sun.COM while ((ace = list_head(alist)) != NULL) {
2239832Samw@Sun.COM list_remove(alist, ace);
2249832Samw@Sun.COM list_insert_tail(&acl->sl_sorted, ace);
2259832Samw@Sun.COM }
2269832Samw@Sun.COM list_destroy(alist);
2279832Samw@Sun.COM }
2289832Samw@Sun.COM }
2299832Samw@Sun.COM
2309832Samw@Sun.COM /*
2319832Samw@Sun.COM * smb_acl_from_zfs
2329832Samw@Sun.COM *
2339832Samw@Sun.COM * Converts given ZFS ACL to a Windows ACL.
2349832Samw@Sun.COM *
2359832Samw@Sun.COM * A pointer to allocated memory for the Windows ACL will be
2369832Samw@Sun.COM * returned upon successful conversion.
2379832Samw@Sun.COM */
2389832Samw@Sun.COM smb_acl_t *
smb_acl_from_zfs(acl_t * zacl)239*11447Samw@Sun.COM smb_acl_from_zfs(acl_t *zacl)
2409832Samw@Sun.COM {
2419832Samw@Sun.COM ace_t *zace;
2429832Samw@Sun.COM int numaces;
2439832Samw@Sun.COM smb_acl_t *acl;
2449832Samw@Sun.COM smb_ace_t *ace;
2459832Samw@Sun.COM smb_idmap_batch_t sib;
2469832Samw@Sun.COM smb_idmap_t *sim;
2479832Samw@Sun.COM idmap_stat idm_stat;
2489832Samw@Sun.COM
2499832Samw@Sun.COM idm_stat = smb_idmap_batch_create(&sib, zacl->acl_cnt,
2509832Samw@Sun.COM SMB_IDMAP_ID2SID);
2519832Samw@Sun.COM if (idm_stat != IDMAP_SUCCESS)
2529832Samw@Sun.COM return (NULL);
2539832Samw@Sun.COM
254*11447Samw@Sun.COM if (smb_fsacl_getsids(&sib, zacl) != IDMAP_SUCCESS) {
2559832Samw@Sun.COM smb_idmap_batch_destroy(&sib);
2569832Samw@Sun.COM return (NULL);
2579832Samw@Sun.COM }
2589832Samw@Sun.COM
2599832Samw@Sun.COM acl = smb_acl_alloc(ACL_REVISION, SMB_ACL_HDRSIZE, zacl->acl_cnt);
2609832Samw@Sun.COM
2619832Samw@Sun.COM sim = sib.sib_maps;
2629832Samw@Sun.COM for (numaces = 0, zace = zacl->acl_aclp;
2639832Samw@Sun.COM numaces < zacl->acl_cnt;
2649832Samw@Sun.COM zace++, numaces++, sim++) {
2659832Samw@Sun.COM assert(sim->sim_sid);
2669832Samw@Sun.COM if (sim->sim_sid == NULL) {
2679832Samw@Sun.COM smb_acl_free(acl);
2689832Samw@Sun.COM acl = NULL;
2699832Samw@Sun.COM break;
2709832Samw@Sun.COM }
2719832Samw@Sun.COM
2729832Samw@Sun.COM ace = &acl->sl_aces[numaces];
2739832Samw@Sun.COM ace->se_hdr.se_type = zace->a_type;
2749832Samw@Sun.COM ace->se_hdr.se_flags = smb_ace_flags_fromzfs(zace->a_flags);
2759832Samw@Sun.COM ace->se_mask = zace->a_access_mask;
2769832Samw@Sun.COM ace->se_sid = smb_sid_dup(sim->sim_sid);
2779832Samw@Sun.COM ace->se_hdr.se_bsize = smb_ace_len(ace);
2789832Samw@Sun.COM
2799832Samw@Sun.COM acl->sl_bsize += ace->se_hdr.se_bsize;
2809832Samw@Sun.COM }
2819832Samw@Sun.COM
2829832Samw@Sun.COM smb_idmap_batch_destroy(&sib);
2839832Samw@Sun.COM return (acl);
2849832Samw@Sun.COM }
2859832Samw@Sun.COM
2869832Samw@Sun.COM /*
2879832Samw@Sun.COM * smb_acl_to_zfs
2889832Samw@Sun.COM *
2899832Samw@Sun.COM * Converts given Windows ACL to a ZFS ACL.
2909832Samw@Sun.COM *
2919832Samw@Sun.COM * fs_acl will contain a pointer to the created ZFS ACL.
2929832Samw@Sun.COM * The allocated memory should be freed by calling
2939832Samw@Sun.COM * smb_fsacl_free().
2949832Samw@Sun.COM *
2959832Samw@Sun.COM * Since the output parameter, fs_acl, is allocated in this
2969832Samw@Sun.COM * function, the caller has to make sure *fs_acl is NULL which
2979832Samw@Sun.COM * means it's not pointing to any memory.
2989832Samw@Sun.COM */
2999832Samw@Sun.COM uint32_t
smb_acl_to_zfs(smb_acl_t * acl,uint32_t flags,int which_acl,acl_t ** fs_acl)3009832Samw@Sun.COM smb_acl_to_zfs(smb_acl_t *acl, uint32_t flags, int which_acl, acl_t **fs_acl)
3019832Samw@Sun.COM {
302*11447Samw@Sun.COM char sidstr[SMB_SID_STRSZ];
3039832Samw@Sun.COM smb_ace_t *ace;
3049832Samw@Sun.COM acl_t *zacl;
3059832Samw@Sun.COM ace_t *zace;
3069832Samw@Sun.COM smb_idmap_batch_t sib;
3079832Samw@Sun.COM smb_idmap_t *sim;
3089832Samw@Sun.COM idmap_stat idm_stat;
3099832Samw@Sun.COM int i;
3109832Samw@Sun.COM
3119832Samw@Sun.COM assert(fs_acl);
3129832Samw@Sun.COM assert(*fs_acl == NULL);
3139832Samw@Sun.COM
3149832Samw@Sun.COM if (acl && !smb_acl_isvalid(acl, which_acl))
3159832Samw@Sun.COM return (NT_STATUS_INVALID_ACL);
3169832Samw@Sun.COM
3179832Samw@Sun.COM if ((acl == NULL) || (acl->sl_acecnt == 0)) {
3189832Samw@Sun.COM if (which_acl == SMB_DACL_SECINFO) {
3199832Samw@Sun.COM *fs_acl = smb_fsacl_null_empty(acl == NULL);
3209832Samw@Sun.COM }
3219832Samw@Sun.COM
3229832Samw@Sun.COM return (NT_STATUS_SUCCESS);
3239832Samw@Sun.COM }
3249832Samw@Sun.COM
3259832Samw@Sun.COM idm_stat = smb_idmap_batch_create(&sib, acl->sl_acecnt,
3269832Samw@Sun.COM SMB_IDMAP_SID2ID);
3279832Samw@Sun.COM if (idm_stat != IDMAP_SUCCESS)
3289832Samw@Sun.COM return (NT_STATUS_INTERNAL_ERROR);
3299832Samw@Sun.COM
3309832Samw@Sun.COM zacl = smb_fsacl_alloc(acl->sl_acecnt, flags);
3319832Samw@Sun.COM
3329832Samw@Sun.COM zace = zacl->acl_aclp;
3339832Samw@Sun.COM ace = acl->sl_aces;
3349832Samw@Sun.COM sim = sib.sib_maps;
3359832Samw@Sun.COM
3369832Samw@Sun.COM for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) {
3379832Samw@Sun.COM zace->a_type = ace->se_hdr.se_type & ACE_ALL_TYPES;
3389832Samw@Sun.COM zace->a_access_mask = smb_ace_mask_g2s(ace->se_mask);
3399832Samw@Sun.COM zace->a_flags = smb_ace_flags_tozfs(ace->se_hdr.se_flags);
340*11447Samw@Sun.COM zace->a_who = (uid_t)-1;
3419832Samw@Sun.COM
342*11447Samw@Sun.COM smb_sid_tostr(ace->se_sid, sidstr);
343*11447Samw@Sun.COM
344*11447Samw@Sun.COM if (!smb_ace_wellknown_update(sidstr, zace)) {
3459832Samw@Sun.COM sim->sim_id = &zace->a_who;
3469832Samw@Sun.COM idm_stat = smb_idmap_batch_getid(sib.sib_idmaph, sim,
347*11447Samw@Sun.COM ace->se_sid, SMB_IDMAP_UNKNOWN);
3489832Samw@Sun.COM
3499832Samw@Sun.COM if (idm_stat != IDMAP_SUCCESS) {
3509832Samw@Sun.COM smb_fsacl_free(zacl);
3519832Samw@Sun.COM smb_idmap_batch_destroy(&sib);
3529832Samw@Sun.COM return (NT_STATUS_INTERNAL_ERROR);
3539832Samw@Sun.COM }
3549832Samw@Sun.COM }
3559832Samw@Sun.COM }
3569832Samw@Sun.COM
3579832Samw@Sun.COM idm_stat = smb_idmap_batch_getmappings(&sib);
3589832Samw@Sun.COM if (idm_stat != IDMAP_SUCCESS) {
3599832Samw@Sun.COM smb_fsacl_free(zacl);
3609832Samw@Sun.COM smb_idmap_batch_destroy(&sib);
3619832Samw@Sun.COM return (NT_STATUS_NONE_MAPPED);
3629832Samw@Sun.COM }
3639832Samw@Sun.COM
3649832Samw@Sun.COM /*
3659832Samw@Sun.COM * Set the ACEs group flag based on the type of ID returned.
3669832Samw@Sun.COM */
3679832Samw@Sun.COM zace = zacl->acl_aclp;
3689832Samw@Sun.COM ace = acl->sl_aces;
3699832Samw@Sun.COM sim = sib.sib_maps;
3709832Samw@Sun.COM for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) {
371*11447Samw@Sun.COM if (zace->a_who == (uid_t)-1)
3729832Samw@Sun.COM continue;
3739832Samw@Sun.COM
3749832Samw@Sun.COM if (sim->sim_idtype == SMB_IDMAP_GROUP)
3759832Samw@Sun.COM zace->a_flags |= ACE_IDENTIFIER_GROUP;
3769832Samw@Sun.COM }
3779832Samw@Sun.COM
3789832Samw@Sun.COM smb_idmap_batch_destroy(&sib);
3799832Samw@Sun.COM
3809832Samw@Sun.COM *fs_acl = zacl;
3819832Samw@Sun.COM return (NT_STATUS_SUCCESS);
3829832Samw@Sun.COM }
3839832Samw@Sun.COM
384*11447Samw@Sun.COM static boolean_t
smb_ace_wellknown_update(const char * sid,ace_t * zace)385*11447Samw@Sun.COM smb_ace_wellknown_update(const char *sid, ace_t *zace)
386*11447Samw@Sun.COM {
387*11447Samw@Sun.COM struct {
388*11447Samw@Sun.COM char *sid;
389*11447Samw@Sun.COM uint16_t flags;
390*11447Samw@Sun.COM } map[] = {
391*11447Samw@Sun.COM { NT_WORLD_SIDSTR, ACE_EVERYONE },
392*11447Samw@Sun.COM { NT_BUILTIN_CURRENT_OWNER_SIDSTR, ACE_OWNER },
393*11447Samw@Sun.COM { NT_BUILTIN_CURRENT_GROUP_SIDSTR,
394*11447Samw@Sun.COM (ACE_GROUP | ACE_IDENTIFIER_GROUP) },
395*11447Samw@Sun.COM };
396*11447Samw@Sun.COM
397*11447Samw@Sun.COM int i;
398*11447Samw@Sun.COM
399*11447Samw@Sun.COM for (i = 0; i < (sizeof (map) / sizeof (map[0])); ++i) {
400*11447Samw@Sun.COM if (strcmp(sid, map[i].sid) == 0) {
401*11447Samw@Sun.COM zace->a_flags |= map[i].flags;
402*11447Samw@Sun.COM return (B_TRUE);
403*11447Samw@Sun.COM }
404*11447Samw@Sun.COM }
405*11447Samw@Sun.COM
406*11447Samw@Sun.COM return (B_FALSE);
407*11447Samw@Sun.COM }
408*11447Samw@Sun.COM
4099832Samw@Sun.COM /*
4109832Samw@Sun.COM * smb_fsacl_getsids
4119832Samw@Sun.COM *
4129832Samw@Sun.COM * Batch all the uid/gid in given ZFS ACL to get their corresponding SIDs.
4139832Samw@Sun.COM */
4149832Samw@Sun.COM static idmap_stat
smb_fsacl_getsids(smb_idmap_batch_t * sib,acl_t * zacl)415*11447Samw@Sun.COM smb_fsacl_getsids(smb_idmap_batch_t *sib, acl_t *zacl)
4169832Samw@Sun.COM {
4179832Samw@Sun.COM ace_t *zace;
4189832Samw@Sun.COM idmap_stat idm_stat;
4199832Samw@Sun.COM smb_idmap_t *sim;
4209832Samw@Sun.COM uid_t id;
4219832Samw@Sun.COM int i, idtype;
4229832Samw@Sun.COM
4239832Samw@Sun.COM sim = sib->sib_maps;
4249832Samw@Sun.COM
4259832Samw@Sun.COM for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt;
4269832Samw@Sun.COM zace++, i++, sim++) {
4279832Samw@Sun.COM switch (zace->a_flags & ACE_TYPE_FLAGS) {
4289832Samw@Sun.COM case ACE_OWNER:
429*11447Samw@Sun.COM idtype = SMB_IDMAP_OWNERAT;
4309832Samw@Sun.COM break;
4319832Samw@Sun.COM
4329832Samw@Sun.COM case (ACE_GROUP | ACE_IDENTIFIER_GROUP):
4339832Samw@Sun.COM /* owning group */
434*11447Samw@Sun.COM idtype = SMB_IDMAP_GROUPAT;
4359832Samw@Sun.COM break;
4369832Samw@Sun.COM
4379832Samw@Sun.COM case ACE_IDENTIFIER_GROUP:
4389832Samw@Sun.COM /* regular group */
4399832Samw@Sun.COM id = zace->a_who;
4409832Samw@Sun.COM idtype = SMB_IDMAP_GROUP;
4419832Samw@Sun.COM break;
4429832Samw@Sun.COM
4439832Samw@Sun.COM case ACE_EVERYONE:
4449832Samw@Sun.COM idtype = SMB_IDMAP_EVERYONE;
4459832Samw@Sun.COM break;
4469832Samw@Sun.COM
4479832Samw@Sun.COM default:
4489832Samw@Sun.COM /* user entry */
4499832Samw@Sun.COM id = zace->a_who;
4509832Samw@Sun.COM idtype = SMB_IDMAP_USER;
4519832Samw@Sun.COM }
4529832Samw@Sun.COM
4539832Samw@Sun.COM idm_stat = smb_idmap_batch_getsid(sib->sib_idmaph, sim,
4549832Samw@Sun.COM id, idtype);
4559832Samw@Sun.COM
4569832Samw@Sun.COM if (idm_stat != IDMAP_SUCCESS) {
4579832Samw@Sun.COM return (idm_stat);
4589832Samw@Sun.COM }
4599832Samw@Sun.COM }
4609832Samw@Sun.COM
4619832Samw@Sun.COM idm_stat = smb_idmap_batch_getmappings(sib);
4629832Samw@Sun.COM return (idm_stat);
4639832Samw@Sun.COM }
4649832Samw@Sun.COM
4659832Samw@Sun.COM /*
4669832Samw@Sun.COM * smb_fsacl_null_empty
4679832Samw@Sun.COM *
4689832Samw@Sun.COM * NULL DACL means everyone full-access
4699832Samw@Sun.COM * Empty DACL means everyone full-deny
4709832Samw@Sun.COM *
4719832Samw@Sun.COM * ZFS ACL must have at least one entry so smb server has
4729832Samw@Sun.COM * to simulate the aforementioned expected behavior by adding
4739832Samw@Sun.COM * an entry in case the requested DACL is null or empty. Adding
4749832Samw@Sun.COM * a everyone full-deny entry has proved to be problematic in
4759832Samw@Sun.COM * tests since a deny entry takes precedence over allow entries.
4769832Samw@Sun.COM * So, instead of adding a everyone full-deny, an owner ACE with
4779832Samw@Sun.COM * owner implicit permissions will be set.
4789832Samw@Sun.COM */
4799832Samw@Sun.COM static acl_t *
smb_fsacl_null_empty(boolean_t null)4809832Samw@Sun.COM smb_fsacl_null_empty(boolean_t null)
4819832Samw@Sun.COM {
4829832Samw@Sun.COM acl_t *zacl;
4839832Samw@Sun.COM ace_t *zace;
4849832Samw@Sun.COM
4859832Samw@Sun.COM zacl = smb_fsacl_alloc(1, ACL_AUTO_INHERIT);
4869832Samw@Sun.COM zace = zacl->acl_aclp;
4879832Samw@Sun.COM
4889832Samw@Sun.COM zace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
4899832Samw@Sun.COM if (null) {
4909832Samw@Sun.COM zace->a_access_mask = ACE_ALL_PERMS;
4919832Samw@Sun.COM zace->a_flags = ACE_EVERYONE;
4929832Samw@Sun.COM } else {
4939832Samw@Sun.COM zace->a_access_mask = ACE_READ_ACL | ACE_WRITE_ACL |
4949832Samw@Sun.COM ACE_READ_ATTRIBUTES;
4959832Samw@Sun.COM zace->a_flags = ACE_OWNER;
4969832Samw@Sun.COM }
4979832Samw@Sun.COM
4989832Samw@Sun.COM return (zacl);
4999832Samw@Sun.COM }
5009832Samw@Sun.COM
5019832Samw@Sun.COM /*
5029832Samw@Sun.COM * FS ACL (acl_t) Functions
5039832Samw@Sun.COM */
5049832Samw@Sun.COM acl_t *
smb_fsacl_alloc(int acenum,int flags)5059832Samw@Sun.COM smb_fsacl_alloc(int acenum, int flags)
5069832Samw@Sun.COM {
5079832Samw@Sun.COM acl_t *acl;
5089832Samw@Sun.COM
5099832Samw@Sun.COM acl = acl_alloc(ACE_T);
5109832Samw@Sun.COM acl->acl_cnt = acenum;
5119832Samw@Sun.COM if ((acl->acl_aclp = malloc(acl->acl_entry_size * acenum)) == NULL)
5129832Samw@Sun.COM return (NULL);
5139832Samw@Sun.COM
5149832Samw@Sun.COM acl->acl_flags = flags;
5159832Samw@Sun.COM return (acl);
5169832Samw@Sun.COM }
5179832Samw@Sun.COM
5189832Samw@Sun.COM void
smb_fsacl_free(acl_t * acl)5199832Samw@Sun.COM smb_fsacl_free(acl_t *acl)
5209832Samw@Sun.COM {
5219832Samw@Sun.COM if (acl)
5229832Samw@Sun.COM acl_free(acl);
5239832Samw@Sun.COM }
5249832Samw@Sun.COM
5259832Samw@Sun.COM /*
5269832Samw@Sun.COM * ACE Functions
5279832Samw@Sun.COM */
5289832Samw@Sun.COM
5299832Samw@Sun.COM /*
5309832Samw@Sun.COM * smb_ace_len
5319832Samw@Sun.COM *
5329832Samw@Sun.COM * Returns the length of the given ACE as it appears in an
5339832Samw@Sun.COM * ACL on the wire (i.e. a flat buffer which contains the SID)
5349832Samw@Sun.COM */
5359832Samw@Sun.COM static uint16_t
smb_ace_len(smb_ace_t * ace)5369832Samw@Sun.COM smb_ace_len(smb_ace_t *ace)
5379832Samw@Sun.COM {
5389832Samw@Sun.COM assert(ace);
5399832Samw@Sun.COM assert(ace->se_sid);
5409832Samw@Sun.COM
5419832Samw@Sun.COM if (ace == NULL)
5429832Samw@Sun.COM return (0);
5439832Samw@Sun.COM
5449832Samw@Sun.COM return (SMB_ACE_HDRSIZE + sizeof (ace->se_mask) +
5459832Samw@Sun.COM smb_sid_len(ace->se_sid));
5469832Samw@Sun.COM }
5479832Samw@Sun.COM
5489832Samw@Sun.COM /*
5499832Samw@Sun.COM * smb_ace_mask_g2s
5509832Samw@Sun.COM *
5519832Samw@Sun.COM * Converts generic access bits in the given mask (if any)
5529832Samw@Sun.COM * to file specific bits. Generic access masks shouldn't be
5539832Samw@Sun.COM * stored in filesystem ACEs.
5549832Samw@Sun.COM */
5559832Samw@Sun.COM static uint32_t
smb_ace_mask_g2s(uint32_t mask)5569832Samw@Sun.COM smb_ace_mask_g2s(uint32_t mask)
5579832Samw@Sun.COM {
5589832Samw@Sun.COM if (mask & GENERIC_ALL) {
5599832Samw@Sun.COM mask &= ~(GENERIC_ALL | GENERIC_READ | GENERIC_WRITE
5609832Samw@Sun.COM | GENERIC_EXECUTE);
5619832Samw@Sun.COM
5629832Samw@Sun.COM mask |= FILE_ALL_ACCESS;
5639832Samw@Sun.COM return (mask);
5649832Samw@Sun.COM }
5659832Samw@Sun.COM
5669832Samw@Sun.COM if (mask & GENERIC_READ) {
5679832Samw@Sun.COM mask &= ~GENERIC_READ;
5689832Samw@Sun.COM mask |= FILE_GENERIC_READ;
5699832Samw@Sun.COM }
5709832Samw@Sun.COM
5719832Samw@Sun.COM if (mask & GENERIC_WRITE) {
5729832Samw@Sun.COM mask &= ~GENERIC_WRITE;
5739832Samw@Sun.COM mask |= FILE_GENERIC_WRITE;
5749832Samw@Sun.COM }
5759832Samw@Sun.COM
5769832Samw@Sun.COM if (mask & GENERIC_EXECUTE) {
5779832Samw@Sun.COM mask &= ~GENERIC_EXECUTE;
5789832Samw@Sun.COM mask |= FILE_GENERIC_EXECUTE;
5799832Samw@Sun.COM }
5809832Samw@Sun.COM
5819832Samw@Sun.COM return (mask);
5829832Samw@Sun.COM }
5839832Samw@Sun.COM
5849832Samw@Sun.COM /*
5859832Samw@Sun.COM * smb_ace_flags_tozfs
5869832Samw@Sun.COM *
5879832Samw@Sun.COM * This function maps the flags which have different values
5889832Samw@Sun.COM * in Windows and Solaris. The ones with the same value are
5899832Samw@Sun.COM * transferred untouched.
5909832Samw@Sun.COM */
5919832Samw@Sun.COM static uint16_t
smb_ace_flags_tozfs(uint8_t c_flags)5929832Samw@Sun.COM smb_ace_flags_tozfs(uint8_t c_flags)
5939832Samw@Sun.COM {
5949832Samw@Sun.COM uint16_t z_flags = 0;
5959832Samw@Sun.COM
5969832Samw@Sun.COM if (c_flags & SUCCESSFUL_ACCESS_ACE_FLAG)
5979832Samw@Sun.COM z_flags |= ACE_SUCCESSFUL_ACCESS_ACE_FLAG;
5989832Samw@Sun.COM
5999832Samw@Sun.COM if (c_flags & FAILED_ACCESS_ACE_FLAG)
6009832Samw@Sun.COM z_flags |= ACE_FAILED_ACCESS_ACE_FLAG;
6019832Samw@Sun.COM
6029832Samw@Sun.COM if (c_flags & INHERITED_ACE)
6039832Samw@Sun.COM z_flags |= ACE_INHERITED_ACE;
6049832Samw@Sun.COM
6059832Samw@Sun.COM z_flags |= (c_flags & ACE_INHERIT_FLAGS);
6069832Samw@Sun.COM
6079832Samw@Sun.COM return (z_flags);
6089832Samw@Sun.COM }
6099832Samw@Sun.COM
6109832Samw@Sun.COM static uint8_t
smb_ace_flags_fromzfs(uint16_t z_flags)6119832Samw@Sun.COM smb_ace_flags_fromzfs(uint16_t z_flags)
6129832Samw@Sun.COM {
6139832Samw@Sun.COM uint8_t c_flags;
6149832Samw@Sun.COM
6159832Samw@Sun.COM c_flags = z_flags & ACE_INHERIT_FLAGS;
6169832Samw@Sun.COM
6179832Samw@Sun.COM if (z_flags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG)
6189832Samw@Sun.COM c_flags |= SUCCESSFUL_ACCESS_ACE_FLAG;
6199832Samw@Sun.COM
6209832Samw@Sun.COM if (z_flags & ACE_FAILED_ACCESS_ACE_FLAG)
6219832Samw@Sun.COM c_flags |= FAILED_ACCESS_ACE_FLAG;
6229832Samw@Sun.COM
6239832Samw@Sun.COM if (z_flags & ACE_INHERITED_ACE)
6249832Samw@Sun.COM c_flags |= INHERITED_ACE;
6259832Samw@Sun.COM
6269832Samw@Sun.COM return (c_flags);
6279832Samw@Sun.COM }
628