17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5354a1801Ssamf * Common Development and Distribution License (the "License"). 6354a1801Ssamf * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*e913d9ecSLisa Week * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * The following naming convention is used in function names. 287c478bd9Sstevel@tonic-gate * 297c478bd9Sstevel@tonic-gate * If an argument is one or more aclent_t, we use "aent". 307c478bd9Sstevel@tonic-gate * If an argument is one or more nfsace4, we use "ace4". 317c478bd9Sstevel@tonic-gate * If an argument is one or more ace_t, we use "acet". 327c478bd9Sstevel@tonic-gate * 337c478bd9Sstevel@tonic-gate * If there is an aggregate of the one above... 347c478bd9Sstevel@tonic-gate * If it's contained in a vsecattr_t, we prepend "vs_". 357c478bd9Sstevel@tonic-gate * If it's contained in an "array" (pointer) and length, we prepend "ln_". 367c478bd9Sstevel@tonic-gate * 377c478bd9Sstevel@tonic-gate * Thus, for example, suppose you have a function that converts an 387c478bd9Sstevel@tonic-gate * array of aclent_t structures into an array of nfsace4 structures, 397c478bd9Sstevel@tonic-gate * it's name would be "ln_aent_to_ace4". 407c478bd9Sstevel@tonic-gate */ 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #include <sys/acl.h> 437c478bd9Sstevel@tonic-gate #include <nfs/nfs4_kprot.h> 447c478bd9Sstevel@tonic-gate #include <nfs/nfs4.h> 457c478bd9Sstevel@tonic-gate #include <nfs/rnode4.h> 467c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 477c478bd9Sstevel@tonic-gate #include <sys/systm.h> 487c478bd9Sstevel@tonic-gate #include <sys/sdt.h> 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate #define ACE4_POSIX_SUPPORTED_BITS (ACE4_READ_DATA | \ 517c478bd9Sstevel@tonic-gate ACE4_WRITE_DATA | \ 527c478bd9Sstevel@tonic-gate ACE4_APPEND_DATA | \ 537c478bd9Sstevel@tonic-gate ACE4_EXECUTE | \ 547c478bd9Sstevel@tonic-gate ACE4_READ_ATTRIBUTES | \ 557c478bd9Sstevel@tonic-gate ACE4_READ_ACL | \ 567c478bd9Sstevel@tonic-gate ACE4_WRITE_ACL) 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate static int ace4vals_compare(const void *, const void *); 597c478bd9Sstevel@tonic-gate static int nfs4_ace4_list_construct(void *, void *, int); 607c478bd9Sstevel@tonic-gate static void nfs4_ace4_list_destroy(void *, void *); 617c478bd9Sstevel@tonic-gate static void ace4_list_free(ace4_list_t *); 627c478bd9Sstevel@tonic-gate static void ace4vals_init(ace4vals_t *, utf8string *); 637c478bd9Sstevel@tonic-gate static void ace4_list_init(ace4_list_t *, int); 647c478bd9Sstevel@tonic-gate static int ln_aent_preprocess(aclent_t *, int, 657c478bd9Sstevel@tonic-gate int *, o_mode_t *, int *, int *, int *); 667c478bd9Sstevel@tonic-gate static void ace4_make_deny(nfsace4 *, nfsace4 *, int, int, int); 677c478bd9Sstevel@tonic-gate static acemask4 mode_to_ace4_access(o_mode_t, int, int, int, int); 687c478bd9Sstevel@tonic-gate static int ln_aent_to_ace4(aclent_t *, int, nfsace4 **, int *, int, int); 697c478bd9Sstevel@tonic-gate static int ace4_mask_to_mode(acemask4, o_mode_t *, int); 707c478bd9Sstevel@tonic-gate static int ace4_allow_to_mode(acemask4, o_mode_t *, int); 717c478bd9Sstevel@tonic-gate static ace4vals_t *ace4vals_find(nfsace4 *, avl_tree_t *, int *); 727c478bd9Sstevel@tonic-gate static int ace4_to_aent_legal(nfsace4 *, int); 737c478bd9Sstevel@tonic-gate static int ace4vals_to_aent(ace4vals_t *, aclent_t *, ace4_list_t *, 74*e913d9ecSLisa Week uid_t, gid_t, int, int); 757c478bd9Sstevel@tonic-gate static int ace4_list_to_aent(ace4_list_t *, aclent_t **, int *, uid_t, gid_t, 76*e913d9ecSLisa Week int, int); 777c478bd9Sstevel@tonic-gate static int ln_ace4_to_aent(nfsace4 *ace4, int n, uid_t, gid_t, 78*e913d9ecSLisa Week aclent_t **, int *, aclent_t **, int *, int, int); 797c478bd9Sstevel@tonic-gate static int ace4_cmp(nfsace4 *, nfsace4 *); 80fa9e4066Sahrens static int acet_to_ace4(ace_t *, nfsace4 *, int); 81*e913d9ecSLisa Week static int ace4_to_acet(nfsace4 *, ace_t *, uid_t, gid_t, int); 82*e913d9ecSLisa Week static int validate_idmapping(utf8string *, uid_t *, int, int); 837c478bd9Sstevel@tonic-gate static int u8s_mapped_to_nobody(utf8string *, uid_t, int); 84*e913d9ecSLisa Week static void remap_id(uid_t *, int); 85fa9e4066Sahrens static void ace4_mask_to_acet_mask(acemask4, uint32_t *); 86fa9e4066Sahrens static void acet_mask_to_ace4_mask(uint32_t, acemask4 *); 87fa9e4066Sahrens static void ace4_flags_to_acet_flags(aceflag4, uint16_t *); 88fa9e4066Sahrens static void acet_flags_to_ace4_flags(uint16_t, aceflag4 *); 89fa9e4066Sahrens 907c478bd9Sstevel@tonic-gate /* 917c478bd9Sstevel@tonic-gate * The following two functions check and set ACE4_SYNCRONIZE, ACE4_WRITE_OWNER, 927c478bd9Sstevel@tonic-gate * ACE4_DELETE and ACE4_WRITE_ATTRIBUTES. 937c478bd9Sstevel@tonic-gate */ 947c478bd9Sstevel@tonic-gate static int access_mask_check(nfsace4 *, int, int, int); 957c478bd9Sstevel@tonic-gate static acemask4 access_mask_set(int, int, int, int, int); 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate static int nfs4_acl_debug = 0; 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate #define ACL_SYNCHRONIZE_SET_DENY 0x0000001 1007c478bd9Sstevel@tonic-gate #define ACL_SYNCHRONIZE_SET_ALLOW 0x0000002 1017c478bd9Sstevel@tonic-gate #define ACL_SYNCHRONIZE_ERR_DENY 0x0000004 1027c478bd9Sstevel@tonic-gate #define ACL_SYNCHRONIZE_ERR_ALLOW 0x0000008 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate #define ACL_WRITE_OWNER_SET_DENY 0x0000010 1057c478bd9Sstevel@tonic-gate #define ACL_WRITE_OWNER_SET_ALLOW 0x0000020 1067c478bd9Sstevel@tonic-gate #define ACL_WRITE_OWNER_ERR_DENY 0x0000040 1077c478bd9Sstevel@tonic-gate #define ACL_WRITE_OWNER_ERR_ALLOW 0x0000080 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate #define ACL_DELETE_SET_DENY 0x0000100 1107c478bd9Sstevel@tonic-gate #define ACL_DELETE_SET_ALLOW 0x0000200 1117c478bd9Sstevel@tonic-gate #define ACL_DELETE_ERR_DENY 0x0000400 1127c478bd9Sstevel@tonic-gate #define ACL_DELETE_ERR_ALLOW 0x0000800 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate #define ACL_WRITE_ATTRS_OWNER_SET_DENY 0x0001000 1157c478bd9Sstevel@tonic-gate #define ACL_WRITE_ATTRS_OWNER_SET_ALLOW 0x0002000 1167c478bd9Sstevel@tonic-gate #define ACL_WRITE_ATTRS_OWNER_ERR_DENY 0x0004000 1177c478bd9Sstevel@tonic-gate #define ACL_WRITE_ATTRS_OWNER_ERR_ALLOW 0x0008000 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate #define ACL_WRITE_ATTRS_WRITER_SET_DENY 0x0010000 1207c478bd9Sstevel@tonic-gate #define ACL_WRITE_ATTRS_WRITER_SET_ALLOW 0x0020000 1217c478bd9Sstevel@tonic-gate #define ACL_WRITE_ATTRS_WRITER_ERR_DENY 0x0040000 1227c478bd9Sstevel@tonic-gate #define ACL_WRITE_ATTRS_WRITER_ERR_ALLOW 0x0080000 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate #define ACL_WRITE_NAMED_WRITER_SET_DENY 0x0100000 1257c478bd9Sstevel@tonic-gate #define ACL_WRITE_NAMED_WRITER_SET_ALLOW 0x0200000 1267c478bd9Sstevel@tonic-gate #define ACL_WRITE_NAMED_WRITER_ERR_DENY 0x0400000 1277c478bd9Sstevel@tonic-gate #define ACL_WRITE_NAMED_WRITER_ERR_ALLOW 0x0800000 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate #define ACL_READ_NAMED_READER_SET_DENY 0x1000000 1307c478bd9Sstevel@tonic-gate #define ACL_READ_NAMED_READER_SET_ALLOW 0x2000000 1317c478bd9Sstevel@tonic-gate #define ACL_READ_NAMED_READER_ERR_DENY 0x4000000 1327c478bd9Sstevel@tonic-gate #define ACL_READ_NAMED_READER_ERR_ALLOW 0x8000000 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate /* 1357c478bd9Sstevel@tonic-gate * What we will send the server upon setting an ACL on our client 1367c478bd9Sstevel@tonic-gate */ 1377c478bd9Sstevel@tonic-gate static int nfs4_acl_client_produce = 1387c478bd9Sstevel@tonic-gate (ACL_SYNCHRONIZE_SET_ALLOW | 1397c478bd9Sstevel@tonic-gate ACL_WRITE_ATTRS_OWNER_SET_ALLOW | 1407c478bd9Sstevel@tonic-gate ACL_WRITE_ATTRS_WRITER_SET_DENY); 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate /* 1437c478bd9Sstevel@tonic-gate * What we will accept upon getting an ACL on our client 1447c478bd9Sstevel@tonic-gate */ 1457c478bd9Sstevel@tonic-gate static int nfs4_acl_client_consume = 1467c478bd9Sstevel@tonic-gate (ACL_WRITE_OWNER_ERR_DENY | 1477c478bd9Sstevel@tonic-gate ACL_WRITE_OWNER_ERR_ALLOW | 1487c478bd9Sstevel@tonic-gate ACL_WRITE_ATTRS_OWNER_ERR_DENY | 1497c478bd9Sstevel@tonic-gate ACL_WRITE_ATTRS_OWNER_SET_ALLOW | 1507c478bd9Sstevel@tonic-gate ACL_WRITE_ATTRS_WRITER_ERR_ALLOW | 1517c478bd9Sstevel@tonic-gate ACL_WRITE_ATTRS_WRITER_SET_DENY); 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate /* 1547c478bd9Sstevel@tonic-gate * What we will produce as an ACL on a newly created file 1557c478bd9Sstevel@tonic-gate */ 1567c478bd9Sstevel@tonic-gate static int nfs4_acl_server_produce = 1577c478bd9Sstevel@tonic-gate (ACL_SYNCHRONIZE_SET_ALLOW | 1587c478bd9Sstevel@tonic-gate ACL_WRITE_ATTRS_OWNER_SET_ALLOW | 1597c478bd9Sstevel@tonic-gate ACL_WRITE_ATTRS_WRITER_SET_DENY); 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate /* 1627c478bd9Sstevel@tonic-gate * What we will accept upon setting an ACL on our server 1637c478bd9Sstevel@tonic-gate */ 1647c478bd9Sstevel@tonic-gate static int nfs4_acl_server_consume = 1657c478bd9Sstevel@tonic-gate (ACL_SYNCHRONIZE_ERR_DENY | 1667c478bd9Sstevel@tonic-gate ACL_DELETE_ERR_DENY | 1677c478bd9Sstevel@tonic-gate ACL_WRITE_OWNER_ERR_DENY | 1687c478bd9Sstevel@tonic-gate ACL_WRITE_OWNER_ERR_ALLOW | 1697c478bd9Sstevel@tonic-gate ACL_WRITE_ATTRS_OWNER_SET_ALLOW | 1707c478bd9Sstevel@tonic-gate ACL_WRITE_ATTRS_OWNER_ERR_DENY | 1717c478bd9Sstevel@tonic-gate ACL_WRITE_ATTRS_WRITER_SET_DENY | 1727c478bd9Sstevel@tonic-gate ACL_WRITE_ATTRS_WRITER_ERR_ALLOW | 1737c478bd9Sstevel@tonic-gate ACL_WRITE_NAMED_WRITER_ERR_DENY | 1747c478bd9Sstevel@tonic-gate ACL_READ_NAMED_READER_ERR_DENY); 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate static kmem_cache_t *nfs4_ace4vals_cache = NULL; 1777c478bd9Sstevel@tonic-gate static kmem_cache_t *nfs4_ace4_list_cache = NULL; 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate static int 1807c478bd9Sstevel@tonic-gate ace4vals_compare(const void *va, const void *vb) 1817c478bd9Sstevel@tonic-gate { 1827c478bd9Sstevel@tonic-gate const ace4vals_t *a = va, *b = vb; 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate if ((a->key == NULL) && (b->key == NULL)) 1857c478bd9Sstevel@tonic-gate return (0); 1867c478bd9Sstevel@tonic-gate else if (a->key == NULL) 1877c478bd9Sstevel@tonic-gate return (-1); 1887c478bd9Sstevel@tonic-gate else if (b->key == NULL) 1897c478bd9Sstevel@tonic-gate return (1); 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate return (utf8_compare(a->key, b->key)); 1927c478bd9Sstevel@tonic-gate } 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1957c478bd9Sstevel@tonic-gate static int 1967c478bd9Sstevel@tonic-gate nfs4_ace4_list_construct(void *voidp, void *arg, int kmem_flags) 1977c478bd9Sstevel@tonic-gate { 1987c478bd9Sstevel@tonic-gate ace4_list_t *a4l = voidp; 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate avl_create(&a4l->user, ace4vals_compare, sizeof (ace4vals_t), 2017c478bd9Sstevel@tonic-gate offsetof(ace4vals_t, avl)); 2027c478bd9Sstevel@tonic-gate avl_create(&a4l->group, ace4vals_compare, sizeof (ace4vals_t), 2037c478bd9Sstevel@tonic-gate offsetof(ace4vals_t, avl)); 2047c478bd9Sstevel@tonic-gate return (0); 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2087c478bd9Sstevel@tonic-gate static void 2097c478bd9Sstevel@tonic-gate nfs4_ace4_list_destroy(void *voidp, void *arg) 2107c478bd9Sstevel@tonic-gate { 2117c478bd9Sstevel@tonic-gate ace4_list_t *a4l = voidp; 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate avl_destroy(&a4l->user); 2147c478bd9Sstevel@tonic-gate avl_destroy(&a4l->group); 2157c478bd9Sstevel@tonic-gate } 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate void 2187c478bd9Sstevel@tonic-gate nfs4_acl_init(void) 2197c478bd9Sstevel@tonic-gate { 2207c478bd9Sstevel@tonic-gate nfs4_ace4vals_cache = kmem_cache_create("nfs4_ace4vals_cache", 2217c478bd9Sstevel@tonic-gate sizeof (ace4vals_t), 0, 2227c478bd9Sstevel@tonic-gate NULL, NULL, 2237c478bd9Sstevel@tonic-gate NULL, NULL, 2247c478bd9Sstevel@tonic-gate NULL, 2257c478bd9Sstevel@tonic-gate 0); 2267c478bd9Sstevel@tonic-gate nfs4_ace4_list_cache = kmem_cache_create("nfs4_ace4_list_cache", 2277c478bd9Sstevel@tonic-gate sizeof (ace4_list_t), 0, 2287c478bd9Sstevel@tonic-gate nfs4_ace4_list_construct, nfs4_ace4_list_destroy, 2297c478bd9Sstevel@tonic-gate NULL, NULL, 2307c478bd9Sstevel@tonic-gate NULL, 2317c478bd9Sstevel@tonic-gate 0); 2327c478bd9Sstevel@tonic-gate } 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate void 2357c478bd9Sstevel@tonic-gate vs_acet_destroy(vsecattr_t *vsp) 2367c478bd9Sstevel@tonic-gate { 2377c478bd9Sstevel@tonic-gate if (vsp->vsa_mask != (VSA_ACE | VSA_ACECNT)) 2387c478bd9Sstevel@tonic-gate return; 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate if ((vsp->vsa_aclentp != NULL) && 2417c478bd9Sstevel@tonic-gate (vsp->vsa_aclcnt > 0) && 2427c478bd9Sstevel@tonic-gate (vsp->vsa_mask & VSA_ACE) && 2437c478bd9Sstevel@tonic-gate (vsp->vsa_mask & VSA_ACECNT)) 2447c478bd9Sstevel@tonic-gate kmem_free(vsp->vsa_aclentp, 2457c478bd9Sstevel@tonic-gate vsp->vsa_aclcnt * sizeof (ace_t)); 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate vsp->vsa_aclentp = NULL; 2487c478bd9Sstevel@tonic-gate vsp->vsa_aclcnt = 0; 2497c478bd9Sstevel@tonic-gate } 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate void 2527c478bd9Sstevel@tonic-gate vs_ace4_destroy(vsecattr_t *vsp) 2537c478bd9Sstevel@tonic-gate { 2547c478bd9Sstevel@tonic-gate nfsace4 *ace4; 2557c478bd9Sstevel@tonic-gate int i; 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate if (vsp->vsa_mask != (VSA_ACE | VSA_ACECNT)) 2587c478bd9Sstevel@tonic-gate return; 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate if ((vsp->vsa_aclentp != NULL) && 2617c478bd9Sstevel@tonic-gate (vsp->vsa_aclcnt > 0) && 2627c478bd9Sstevel@tonic-gate (vsp->vsa_mask & VSA_ACE) && 2637c478bd9Sstevel@tonic-gate (vsp->vsa_mask & VSA_ACECNT)) { 2647c478bd9Sstevel@tonic-gate for (i = 0; i < vsp->vsa_aclcnt; i++) { 2657c478bd9Sstevel@tonic-gate ace4 = (nfsace4 *)vsp->vsa_aclentp + i; 2667c478bd9Sstevel@tonic-gate if ((ace4->who.utf8string_len > 0) && 2677c478bd9Sstevel@tonic-gate (ace4->who.utf8string_val != NULL)) 2687c478bd9Sstevel@tonic-gate kmem_free(ace4->who.utf8string_val, 2697c478bd9Sstevel@tonic-gate ace4->who.utf8string_len); 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate ace4->who.utf8string_val = NULL; 2727c478bd9Sstevel@tonic-gate ace4->who.utf8string_len = 0; 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate kmem_free(vsp->vsa_aclentp, 2767c478bd9Sstevel@tonic-gate vsp->vsa_aclcnt * sizeof (nfsace4)); 2777c478bd9Sstevel@tonic-gate } 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate vsp->vsa_aclentp = NULL; 2807c478bd9Sstevel@tonic-gate vsp->vsa_aclcnt = 0; 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate void 2847c478bd9Sstevel@tonic-gate vs_aent_destroy(vsecattr_t *vsp) 2857c478bd9Sstevel@tonic-gate { 2867c478bd9Sstevel@tonic-gate if (vsp->vsa_mask & (VSA_ACE | VSA_ACECNT)) 2877c478bd9Sstevel@tonic-gate return; 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate if ((vsp->vsa_aclentp != NULL) && 2907c478bd9Sstevel@tonic-gate (vsp->vsa_aclcnt > 0) && 2917c478bd9Sstevel@tonic-gate (vsp->vsa_mask & VSA_ACL) && 2927c478bd9Sstevel@tonic-gate (vsp->vsa_mask & VSA_ACLCNT)) 2937c478bd9Sstevel@tonic-gate kmem_free(vsp->vsa_aclentp, 2947c478bd9Sstevel@tonic-gate vsp->vsa_aclcnt * sizeof (aclent_t)); 2957c478bd9Sstevel@tonic-gate if ((vsp->vsa_dfaclentp != NULL) && 2967c478bd9Sstevel@tonic-gate (vsp->vsa_dfaclcnt > 0) && 2977c478bd9Sstevel@tonic-gate (vsp->vsa_mask & VSA_DFACL) && 2987c478bd9Sstevel@tonic-gate (vsp->vsa_mask & VSA_DFACLCNT)) 2997c478bd9Sstevel@tonic-gate kmem_free(vsp->vsa_dfaclentp, 3007c478bd9Sstevel@tonic-gate vsp->vsa_dfaclcnt * sizeof (aclent_t)); 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate vsp->vsa_aclentp = NULL; 3037c478bd9Sstevel@tonic-gate vsp->vsa_aclcnt = 0; 3047c478bd9Sstevel@tonic-gate 3057c478bd9Sstevel@tonic-gate vsp->vsa_dfaclentp = NULL; 3067c478bd9Sstevel@tonic-gate vsp->vsa_aclcnt = 0; 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate /* 3107c478bd9Sstevel@tonic-gate * free all data associated with an ace4_list 3117c478bd9Sstevel@tonic-gate */ 3127c478bd9Sstevel@tonic-gate static void 3137c478bd9Sstevel@tonic-gate ace4_list_free(ace4_list_t *a4l) 3147c478bd9Sstevel@tonic-gate { 3157c478bd9Sstevel@tonic-gate ace4vals_t *node; 3167c478bd9Sstevel@tonic-gate void *cookie; 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate if (a4l == NULL) 3197c478bd9Sstevel@tonic-gate return; 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate /* free all nodes, but don't destroy the trees themselves */ 3227c478bd9Sstevel@tonic-gate cookie = NULL; 3237c478bd9Sstevel@tonic-gate while ((node = avl_destroy_nodes(&a4l->user, &cookie)) != NULL) 3247c478bd9Sstevel@tonic-gate kmem_cache_free(nfs4_ace4vals_cache, node); 3257c478bd9Sstevel@tonic-gate cookie = NULL; 3267c478bd9Sstevel@tonic-gate while ((node = avl_destroy_nodes(&a4l->group, &cookie)) != NULL) 3277c478bd9Sstevel@tonic-gate kmem_cache_free(nfs4_ace4vals_cache, node); 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate /* free the container itself */ 3307c478bd9Sstevel@tonic-gate kmem_cache_free(nfs4_ace4_list_cache, a4l); 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate static void 3347c478bd9Sstevel@tonic-gate ace4vals_init(ace4vals_t *vals, utf8string *key) 3357c478bd9Sstevel@tonic-gate { 3367c478bd9Sstevel@tonic-gate bzero(vals, sizeof (*vals)); 3377c478bd9Sstevel@tonic-gate vals->allowed = ACE4_MASK_UNDEFINED; 3387c478bd9Sstevel@tonic-gate vals->denied = ACE4_MASK_UNDEFINED; 3397c478bd9Sstevel@tonic-gate vals->mask = ACE4_MASK_UNDEFINED; 3407c478bd9Sstevel@tonic-gate vals->key = key; 3417c478bd9Sstevel@tonic-gate } 3427c478bd9Sstevel@tonic-gate 3437c478bd9Sstevel@tonic-gate static void 3447c478bd9Sstevel@tonic-gate ace4_list_init(ace4_list_t *a4l, int dfacl_flag) 3457c478bd9Sstevel@tonic-gate { 3467c478bd9Sstevel@tonic-gate ace4vals_init(&a4l->user_obj, NULL); 3477c478bd9Sstevel@tonic-gate ace4vals_init(&a4l->group_obj, NULL); 3487c478bd9Sstevel@tonic-gate ace4vals_init(&a4l->other_obj, NULL); 3497c478bd9Sstevel@tonic-gate a4l->numusers = 0; 3507c478bd9Sstevel@tonic-gate a4l->numgroups = 0; 3517c478bd9Sstevel@tonic-gate a4l->acl_mask = 0; 3527c478bd9Sstevel@tonic-gate a4l->hasmask = 0; 3537c478bd9Sstevel@tonic-gate a4l->state = ace4_unused; 3547c478bd9Sstevel@tonic-gate a4l->seen = 0; 3557c478bd9Sstevel@tonic-gate a4l->dfacl_flag = dfacl_flag; 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate /* 3597c478bd9Sstevel@tonic-gate * Make an initial pass over an array of aclent_t's. Gather 3607c478bd9Sstevel@tonic-gate * information such as an ACL_MASK (if any), number of users, 3617c478bd9Sstevel@tonic-gate * number of groups, and whether the array needs to be sorted. 3627c478bd9Sstevel@tonic-gate */ 3637c478bd9Sstevel@tonic-gate static int 3647c478bd9Sstevel@tonic-gate ln_aent_preprocess(aclent_t *aclent, int n, 3657c478bd9Sstevel@tonic-gate int *hasmask, o_mode_t *mask, 3667c478bd9Sstevel@tonic-gate int *numuser, int *numgroup, int *needsort) 3677c478bd9Sstevel@tonic-gate { 3687c478bd9Sstevel@tonic-gate int error = 0; 3697c478bd9Sstevel@tonic-gate int i; 3707c478bd9Sstevel@tonic-gate int curtype = 0; 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate *hasmask = 0; 3737c478bd9Sstevel@tonic-gate *mask = 07; 3747c478bd9Sstevel@tonic-gate *needsort = 0; 3757c478bd9Sstevel@tonic-gate *numuser = 0; 3767c478bd9Sstevel@tonic-gate *numgroup = 0; 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 3797c478bd9Sstevel@tonic-gate if (aclent[i].a_type < curtype) 3807c478bd9Sstevel@tonic-gate *needsort = 1; 3817c478bd9Sstevel@tonic-gate else if (aclent[i].a_type > curtype) 3827c478bd9Sstevel@tonic-gate curtype = aclent[i].a_type; 3837c478bd9Sstevel@tonic-gate if (aclent[i].a_type & USER) 3847c478bd9Sstevel@tonic-gate (*numuser)++; 3857c478bd9Sstevel@tonic-gate if (aclent[i].a_type & (GROUP | GROUP_OBJ)) 3867c478bd9Sstevel@tonic-gate (*numgroup)++; 3877c478bd9Sstevel@tonic-gate if (aclent[i].a_type & CLASS_OBJ) { 3887c478bd9Sstevel@tonic-gate if (*hasmask) { 3897c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 3907c478bd9Sstevel@tonic-gate "ln_aent_preprocess: multiple CLASS_OBJs " 3917c478bd9Sstevel@tonic-gate "(masks) found")); 3927c478bd9Sstevel@tonic-gate error = EINVAL; 3937c478bd9Sstevel@tonic-gate goto out; 3947c478bd9Sstevel@tonic-gate } else { 3957c478bd9Sstevel@tonic-gate *hasmask = 1; 3967c478bd9Sstevel@tonic-gate *mask = aclent[i].a_perm; 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate if ((! *hasmask) && (*numuser + *numgroup > 1)) { 4027c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 4037c478bd9Sstevel@tonic-gate "ln_aent_preprocess: no CLASS_OBJs " 4047c478bd9Sstevel@tonic-gate "(masks) found")); 4057c478bd9Sstevel@tonic-gate error = EINVAL; 4067c478bd9Sstevel@tonic-gate goto out; 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate out: 4107c478bd9Sstevel@tonic-gate return (error); 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate static acemask4 4147c478bd9Sstevel@tonic-gate access_mask_set(int haswriteperm, int hasreadperm, int isowner, int isallow, 4157c478bd9Sstevel@tonic-gate int isserver) 4167c478bd9Sstevel@tonic-gate { 4177c478bd9Sstevel@tonic-gate acemask4 access_mask = 0; 4187c478bd9Sstevel@tonic-gate int nfs4_acl_produce; 4197c478bd9Sstevel@tonic-gate int synchronize_set = 0, write_owner_set = 0; 4207c478bd9Sstevel@tonic-gate int delete_set = 0, write_attrs_set = 0; 4217c478bd9Sstevel@tonic-gate int read_named_set = 0, write_named_set = 0; 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate if (isserver) 4247c478bd9Sstevel@tonic-gate nfs4_acl_produce = nfs4_acl_server_produce; 4257c478bd9Sstevel@tonic-gate else 4267c478bd9Sstevel@tonic-gate nfs4_acl_produce = nfs4_acl_client_produce; 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate if (isallow) { 4297c478bd9Sstevel@tonic-gate synchronize_set = ACL_SYNCHRONIZE_SET_ALLOW; 4307c478bd9Sstevel@tonic-gate write_owner_set = ACL_WRITE_OWNER_SET_ALLOW; 4317c478bd9Sstevel@tonic-gate delete_set = ACL_DELETE_SET_ALLOW; 4327c478bd9Sstevel@tonic-gate if (hasreadperm) 4337c478bd9Sstevel@tonic-gate read_named_set = ACL_READ_NAMED_READER_SET_ALLOW; 4347c478bd9Sstevel@tonic-gate if (haswriteperm) 4357c478bd9Sstevel@tonic-gate write_named_set = ACL_WRITE_NAMED_WRITER_SET_ALLOW; 4367c478bd9Sstevel@tonic-gate if (isowner) 4377c478bd9Sstevel@tonic-gate write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_ALLOW; 4387c478bd9Sstevel@tonic-gate else if (haswriteperm) 4397c478bd9Sstevel@tonic-gate write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_ALLOW; 4407c478bd9Sstevel@tonic-gate } else { 4417c478bd9Sstevel@tonic-gate synchronize_set = ACL_SYNCHRONIZE_SET_DENY; 4427c478bd9Sstevel@tonic-gate write_owner_set = ACL_WRITE_OWNER_SET_DENY; 4437c478bd9Sstevel@tonic-gate delete_set = ACL_DELETE_SET_DENY; 4447c478bd9Sstevel@tonic-gate if (hasreadperm) 4457c478bd9Sstevel@tonic-gate read_named_set = ACL_READ_NAMED_READER_SET_DENY; 4467c478bd9Sstevel@tonic-gate if (haswriteperm) 4477c478bd9Sstevel@tonic-gate write_named_set = ACL_WRITE_NAMED_WRITER_SET_DENY; 4487c478bd9Sstevel@tonic-gate if (isowner) 4497c478bd9Sstevel@tonic-gate write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_DENY; 4507c478bd9Sstevel@tonic-gate else if (haswriteperm) 4517c478bd9Sstevel@tonic-gate write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_DENY; 4527c478bd9Sstevel@tonic-gate else 4537c478bd9Sstevel@tonic-gate /* 4547c478bd9Sstevel@tonic-gate * If the entity is not the owner and does not 4557c478bd9Sstevel@tonic-gate * have write permissions ACE4_WRITE_ATTRIBUTES will 4567c478bd9Sstevel@tonic-gate * always go in the DENY ACE. 4577c478bd9Sstevel@tonic-gate */ 4587c478bd9Sstevel@tonic-gate access_mask |= ACE4_WRITE_ATTRIBUTES; 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate if (nfs4_acl_produce & synchronize_set) 4627c478bd9Sstevel@tonic-gate access_mask |= ACE4_SYNCHRONIZE; 4637c478bd9Sstevel@tonic-gate if (nfs4_acl_produce & write_owner_set) 4647c478bd9Sstevel@tonic-gate access_mask |= ACE4_WRITE_OWNER; 4657c478bd9Sstevel@tonic-gate if (nfs4_acl_produce & delete_set) 4667c478bd9Sstevel@tonic-gate access_mask |= ACE4_DELETE; 4677c478bd9Sstevel@tonic-gate if (nfs4_acl_produce & write_attrs_set) 4687c478bd9Sstevel@tonic-gate access_mask |= ACE4_WRITE_ATTRIBUTES; 4697c478bd9Sstevel@tonic-gate if (nfs4_acl_produce & read_named_set) 4707c478bd9Sstevel@tonic-gate access_mask |= ACE4_READ_NAMED_ATTRS; 4717c478bd9Sstevel@tonic-gate if (nfs4_acl_produce & write_named_set) 4727c478bd9Sstevel@tonic-gate access_mask |= ACE4_WRITE_NAMED_ATTRS; 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate return (access_mask); 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate /* 4787c478bd9Sstevel@tonic-gate * Given an nfsace4 (presumably an ALLOW entry), make a 4797c478bd9Sstevel@tonic-gate * corresponding DENY entry at the address given. 4807c478bd9Sstevel@tonic-gate */ 4817c478bd9Sstevel@tonic-gate static void 4827c478bd9Sstevel@tonic-gate ace4_make_deny(nfsace4 *allow, nfsace4 *deny, int isdir, int isowner, 4837c478bd9Sstevel@tonic-gate int isserver) 4847c478bd9Sstevel@tonic-gate { 4857c478bd9Sstevel@tonic-gate bcopy(allow, deny, sizeof (nfsace4)); 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate (void) utf8_copy(&allow->who, &deny->who); 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate deny->type = ACE4_ACCESS_DENIED_ACE_TYPE; 4907c478bd9Sstevel@tonic-gate deny->access_mask ^= ACE4_POSIX_SUPPORTED_BITS; 4917c478bd9Sstevel@tonic-gate if (isdir) 4927c478bd9Sstevel@tonic-gate deny->access_mask ^= ACE4_DELETE_CHILD; 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate deny->access_mask &= ~(ACE4_SYNCHRONIZE | ACE4_WRITE_OWNER | 4957c478bd9Sstevel@tonic-gate ACE4_DELETE | ACE4_WRITE_ATTRIBUTES | ACE4_READ_NAMED_ATTRS | 4967c478bd9Sstevel@tonic-gate ACE4_WRITE_NAMED_ATTRS); 4977c478bd9Sstevel@tonic-gate deny->access_mask |= access_mask_set((allow->access_mask & 4987c478bd9Sstevel@tonic-gate ACE4_WRITE_DATA), (allow->access_mask & ACE4_READ_DATA), isowner, 4997c478bd9Sstevel@tonic-gate FALSE, isserver); 5007c478bd9Sstevel@tonic-gate } 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate /* 5037c478bd9Sstevel@tonic-gate * Given an o_mode_t, convert it into an access_mask as used 5047c478bd9Sstevel@tonic-gate * by nfsace4, assuming aclent_t -> nfsace4 semantics. 5057c478bd9Sstevel@tonic-gate */ 5067c478bd9Sstevel@tonic-gate static acemask4 5077c478bd9Sstevel@tonic-gate mode_to_ace4_access(o_mode_t mode, int isdir, int isowner, int isallow, 5087c478bd9Sstevel@tonic-gate int isserver) 5097c478bd9Sstevel@tonic-gate { 5107c478bd9Sstevel@tonic-gate acemask4 access = 0; 5117c478bd9Sstevel@tonic-gate int haswriteperm = 0; 5127c478bd9Sstevel@tonic-gate int hasreadperm = 0; 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate if (isallow) { 5157c478bd9Sstevel@tonic-gate haswriteperm = (mode & 02); 5167c478bd9Sstevel@tonic-gate hasreadperm = (mode & 04); 5177c478bd9Sstevel@tonic-gate } else { 5187c478bd9Sstevel@tonic-gate haswriteperm = !(mode & 02); 5197c478bd9Sstevel@tonic-gate hasreadperm = !(mode & 04); 5207c478bd9Sstevel@tonic-gate } 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate /* 5237c478bd9Sstevel@tonic-gate * The following call takes care of correctly setting the following 5247c478bd9Sstevel@tonic-gate * mask bits in the access_mask: 5257c478bd9Sstevel@tonic-gate * ACE4_SYNCHRONIZE, ACE4_WRITE_OWNER, ACE4_DELETE, 5267c478bd9Sstevel@tonic-gate * ACE4_WRITE_ATTRIBUTES, ACE4_WRITE_NAMED_ATTRS, ACE4_READ_NAMED_ATTRS 5277c478bd9Sstevel@tonic-gate */ 5287c478bd9Sstevel@tonic-gate access = access_mask_set(haswriteperm, hasreadperm, isowner, isallow, 5297c478bd9Sstevel@tonic-gate isserver); 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate if (isallow) { 5327c478bd9Sstevel@tonic-gate access |= ACE4_READ_ACL | ACE4_READ_ATTRIBUTES; 5337c478bd9Sstevel@tonic-gate if (isowner) 5347c478bd9Sstevel@tonic-gate access |= ACE4_WRITE_ACL; 5357c478bd9Sstevel@tonic-gate } else { 5367c478bd9Sstevel@tonic-gate if (! isowner) 5377c478bd9Sstevel@tonic-gate access |= ACE4_WRITE_ACL; 5387c478bd9Sstevel@tonic-gate } 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate /* read */ 5417c478bd9Sstevel@tonic-gate if (mode & 04) { 5427c478bd9Sstevel@tonic-gate access |= ACE4_READ_DATA; 5437c478bd9Sstevel@tonic-gate } 5447c478bd9Sstevel@tonic-gate /* write */ 5457c478bd9Sstevel@tonic-gate if (mode & 02) { 5467c478bd9Sstevel@tonic-gate access |= ACE4_WRITE_DATA | 5477c478bd9Sstevel@tonic-gate ACE4_APPEND_DATA; 5487c478bd9Sstevel@tonic-gate if (isdir) 5497c478bd9Sstevel@tonic-gate access |= ACE4_DELETE_CHILD; 5507c478bd9Sstevel@tonic-gate } 5517c478bd9Sstevel@tonic-gate /* exec */ 5527c478bd9Sstevel@tonic-gate if (mode & 01) { 5537c478bd9Sstevel@tonic-gate access |= ACE4_EXECUTE; 5547c478bd9Sstevel@tonic-gate } 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate return (access); 5577c478bd9Sstevel@tonic-gate } 5587c478bd9Sstevel@tonic-gate 5597c478bd9Sstevel@tonic-gate /* 5607c478bd9Sstevel@tonic-gate * Convert an array of aclent_t into an array of nfsace4 entries, 5617c478bd9Sstevel@tonic-gate * following POSIX draft -> nfsv4 conversion semantics as outlined in 5627c478bd9Sstevel@tonic-gate * the IETF draft. 5637c478bd9Sstevel@tonic-gate */ 5647c478bd9Sstevel@tonic-gate static int 5657c478bd9Sstevel@tonic-gate ln_aent_to_ace4(aclent_t *aclent, int n, nfsace4 **acepp, int *rescount, 5667c478bd9Sstevel@tonic-gate int isdir, int isserver) 5677c478bd9Sstevel@tonic-gate { 5687c478bd9Sstevel@tonic-gate int error = 0; 5697c478bd9Sstevel@tonic-gate o_mode_t mask; 5707c478bd9Sstevel@tonic-gate int numuser, numgroup, needsort; 5717c478bd9Sstevel@tonic-gate int resultsize = 0; 5727c478bd9Sstevel@tonic-gate int i, groupi = 0, skip; 5737c478bd9Sstevel@tonic-gate nfsace4 *acep, *result = NULL; 5747c478bd9Sstevel@tonic-gate int hasmask; 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate error = ln_aent_preprocess(aclent, n, &hasmask, &mask, 5777c478bd9Sstevel@tonic-gate &numuser, &numgroup, &needsort); 5787c478bd9Sstevel@tonic-gate if (error != 0) 5797c478bd9Sstevel@tonic-gate goto out; 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate /* allow + deny for each aclent */ 5827c478bd9Sstevel@tonic-gate resultsize = n * 2; 5837c478bd9Sstevel@tonic-gate if (hasmask) { 5847c478bd9Sstevel@tonic-gate /* 5857c478bd9Sstevel@tonic-gate * stick extra deny on the group_obj and on each 5867c478bd9Sstevel@tonic-gate * user|group for the mask (the group_obj was added 5877c478bd9Sstevel@tonic-gate * into the count for numgroup) 5887c478bd9Sstevel@tonic-gate */ 5897c478bd9Sstevel@tonic-gate resultsize += numuser + numgroup; 5907c478bd9Sstevel@tonic-gate /* ... and don't count the mask itself */ 5917c478bd9Sstevel@tonic-gate resultsize -= 2; 5927c478bd9Sstevel@tonic-gate } 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate /* sort the source if necessary */ 5957c478bd9Sstevel@tonic-gate if (needsort) 5967c478bd9Sstevel@tonic-gate ksort((caddr_t)aclent, n, sizeof (aclent_t), cmp2acls); 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate result = acep = kmem_zalloc(resultsize * sizeof (nfsace4), KM_SLEEP); 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 6017c478bd9Sstevel@tonic-gate /* 6027c478bd9Sstevel@tonic-gate * don't process CLASS_OBJ (mask); mask was grabbed in 6037c478bd9Sstevel@tonic-gate * ln_aent_preprocess() 6047c478bd9Sstevel@tonic-gate */ 6057c478bd9Sstevel@tonic-gate if (aclent[i].a_type & CLASS_OBJ) 6067c478bd9Sstevel@tonic-gate continue; 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate /* If we need an ACL_MASK emulator, prepend it now */ 6097c478bd9Sstevel@tonic-gate if ((hasmask) && 6107c478bd9Sstevel@tonic-gate (aclent[i].a_type & (USER | GROUP | GROUP_OBJ))) { 6117c478bd9Sstevel@tonic-gate acep->type = ACE4_ACCESS_DENIED_ACE_TYPE; 6127c478bd9Sstevel@tonic-gate acep->flag = 0; 6137c478bd9Sstevel@tonic-gate if (aclent[i].a_type & GROUP_OBJ) { 6147c478bd9Sstevel@tonic-gate (void) str_to_utf8(ACE4_WHO_GROUP, &acep->who); 6157c478bd9Sstevel@tonic-gate acep->flag |= ACE4_IDENTIFIER_GROUP; 6167c478bd9Sstevel@tonic-gate error = 0; 6177c478bd9Sstevel@tonic-gate } else if (aclent[i].a_type & USER) { 618*e913d9ecSLisa Week /* 619*e913d9ecSLisa Week * On the client, we do not allow an ACL with 620*e913d9ecSLisa Week * ACEs containing the UID_UNKNOWN user to be 621*e913d9ecSLisa Week * set. This is because having UID_UNKNOWN in 622*e913d9ecSLisa Week * an ACE can only come from the user having 623*e913d9ecSLisa Week * done a read-modify-write ACL manipulation 624*e913d9ecSLisa Week * (e.g. setfacl -m or chmod A+) when there 625*e913d9ecSLisa Week * was an ACE with an unmappable group already 626*e913d9ecSLisa Week * present. 627*e913d9ecSLisa Week */ 628*e913d9ecSLisa Week if (aclent[i].a_id == UID_UNKNOWN && 629*e913d9ecSLisa Week !isserver) { 630*e913d9ecSLisa Week DTRACE_PROBE( 631*e913d9ecSLisa Week nfs4clnt__err__acl__uid__unknown); 632*e913d9ecSLisa Week NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 633*e913d9ecSLisa Week "ln_aent_to_ace4: UID_UNKNOWN is " 634*e913d9ecSLisa Week "not allowed in the ACL")); 635*e913d9ecSLisa Week error = EACCES; 636*e913d9ecSLisa Week goto out; 637*e913d9ecSLisa Week } 638*e913d9ecSLisa Week 6397c478bd9Sstevel@tonic-gate error = nfs_idmap_uid_str(aclent[i].a_id, 6407c478bd9Sstevel@tonic-gate &acep->who, isserver); 6417c478bd9Sstevel@tonic-gate } else { 642*e913d9ecSLisa Week /* 643*e913d9ecSLisa Week * Same rule as UID_UNKNOWN (above). 644*e913d9ecSLisa Week */ 645*e913d9ecSLisa Week if (aclent[i].a_id == GID_UNKNOWN && 646*e913d9ecSLisa Week !isserver) { 647*e913d9ecSLisa Week DTRACE_PROBE( 648*e913d9ecSLisa Week nfs4clnt__err__acl__gid__unknown); 649*e913d9ecSLisa Week NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 650*e913d9ecSLisa Week "ln_aent_to_ace4: GID_UNKNOWN is " 651*e913d9ecSLisa Week "not allowed in the ACL")); 652*e913d9ecSLisa Week error = EACCES; 653*e913d9ecSLisa Week goto out; 654*e913d9ecSLisa Week } 655*e913d9ecSLisa Week 6567c478bd9Sstevel@tonic-gate error = nfs_idmap_gid_str(aclent[i].a_id, 6577c478bd9Sstevel@tonic-gate &acep->who, isserver); 6587c478bd9Sstevel@tonic-gate acep->flag |= ACE4_IDENTIFIER_GROUP; 6597c478bd9Sstevel@tonic-gate } 6607c478bd9Sstevel@tonic-gate if (error != 0) { 6617c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 6627c478bd9Sstevel@tonic-gate "ln_aent_to_ace4: idmap translate " 6637c478bd9Sstevel@tonic-gate "failed with %d", error)); 6647c478bd9Sstevel@tonic-gate goto out; 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate if (aclent[i].a_type & ACL_DEFAULT) { 6677c478bd9Sstevel@tonic-gate acep->flag |= ACE4_INHERIT_ONLY_ACE | 6687c478bd9Sstevel@tonic-gate ACE4_FILE_INHERIT_ACE | 6697c478bd9Sstevel@tonic-gate ACE4_DIRECTORY_INHERIT_ACE; 6707c478bd9Sstevel@tonic-gate } 6717c478bd9Sstevel@tonic-gate /* 6727c478bd9Sstevel@tonic-gate * Set the access mask for the prepended deny 6737c478bd9Sstevel@tonic-gate * ace. To do this, we invert the mask (found 6747c478bd9Sstevel@tonic-gate * in ln_aent_preprocess()) then convert it to an 6757c478bd9Sstevel@tonic-gate * DENY ace access_mask. 6767c478bd9Sstevel@tonic-gate */ 6777c478bd9Sstevel@tonic-gate acep->access_mask = mode_to_ace4_access((mask ^ 07), 6787c478bd9Sstevel@tonic-gate isdir, 0, 0, isserver); 6797c478bd9Sstevel@tonic-gate acep += 1; 6807c478bd9Sstevel@tonic-gate } 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate /* handle a_perm -> access_mask */ 6837c478bd9Sstevel@tonic-gate acep->access_mask = mode_to_ace4_access(aclent[i].a_perm, 6847c478bd9Sstevel@tonic-gate isdir, aclent[i].a_type & USER_OBJ, 1, isserver); 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate /* emulate a default aclent */ 6877c478bd9Sstevel@tonic-gate if (aclent[i].a_type & ACL_DEFAULT) { 6887c478bd9Sstevel@tonic-gate acep->flag |= ACE4_INHERIT_ONLY_ACE | 6897c478bd9Sstevel@tonic-gate ACE4_FILE_INHERIT_ACE | 6907c478bd9Sstevel@tonic-gate ACE4_DIRECTORY_INHERIT_ACE; 6917c478bd9Sstevel@tonic-gate } 6927c478bd9Sstevel@tonic-gate 6937c478bd9Sstevel@tonic-gate /* 6947c478bd9Sstevel@tonic-gate * handle a_perm and a_id 6957c478bd9Sstevel@tonic-gate * 6967c478bd9Sstevel@tonic-gate * this must be done last, since it involves the 6977c478bd9Sstevel@tonic-gate * corresponding deny aces, which are handled 6987c478bd9Sstevel@tonic-gate * differently for each different a_type. 6997c478bd9Sstevel@tonic-gate */ 7007c478bd9Sstevel@tonic-gate if (aclent[i].a_type & USER_OBJ) { 7017c478bd9Sstevel@tonic-gate (void) str_to_utf8(ACE4_WHO_OWNER, &acep->who); 7027c478bd9Sstevel@tonic-gate ace4_make_deny(acep, acep + 1, isdir, TRUE, isserver); 7037c478bd9Sstevel@tonic-gate acep += 2; 7047c478bd9Sstevel@tonic-gate } else if (aclent[i].a_type & USER) { 7057c478bd9Sstevel@tonic-gate error = nfs_idmap_uid_str(aclent[i].a_id, &acep->who, 7067c478bd9Sstevel@tonic-gate isserver); 7077c478bd9Sstevel@tonic-gate if (error != 0) { 7087c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 7097c478bd9Sstevel@tonic-gate "ln_aent_to_ace4: uid idmap failed " 7107c478bd9Sstevel@tonic-gate "with error %d", error)); 7117c478bd9Sstevel@tonic-gate goto out; 7127c478bd9Sstevel@tonic-gate } 7137c478bd9Sstevel@tonic-gate ace4_make_deny(acep, acep + 1, isdir, FALSE, isserver); 7147c478bd9Sstevel@tonic-gate acep += 2; 7157c478bd9Sstevel@tonic-gate } else if (aclent[i].a_type & (GROUP_OBJ | GROUP)) { 7167c478bd9Sstevel@tonic-gate if (aclent[i].a_type & GROUP_OBJ) { 7177c478bd9Sstevel@tonic-gate (void) str_to_utf8(ACE4_WHO_GROUP, &acep->who); 7187c478bd9Sstevel@tonic-gate error = 0; 7197c478bd9Sstevel@tonic-gate } else { 7207c478bd9Sstevel@tonic-gate error = nfs_idmap_gid_str(aclent[i].a_id, 7217c478bd9Sstevel@tonic-gate &acep->who, isserver); 7227c478bd9Sstevel@tonic-gate } 7237c478bd9Sstevel@tonic-gate if (error != 0) { 7247c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 7257c478bd9Sstevel@tonic-gate "ln_aent_to_ace4: gid idmap failed " 7267c478bd9Sstevel@tonic-gate "with error %d", error)); 7277c478bd9Sstevel@tonic-gate goto out; 7287c478bd9Sstevel@tonic-gate } 7297c478bd9Sstevel@tonic-gate acep->flag |= ACE4_IDENTIFIER_GROUP; 7307c478bd9Sstevel@tonic-gate /* 7317c478bd9Sstevel@tonic-gate * Set the corresponding deny for the group ace. 7327c478bd9Sstevel@tonic-gate * 7337c478bd9Sstevel@tonic-gate * The deny aces go after all of the groups, unlike 7347c478bd9Sstevel@tonic-gate * everything else, where they immediately follow 7357c478bd9Sstevel@tonic-gate * the allow ace. 7367c478bd9Sstevel@tonic-gate * 7377c478bd9Sstevel@tonic-gate * We calculate "skip", the number of slots to 7387c478bd9Sstevel@tonic-gate * skip ahead for the deny ace, here. 7397c478bd9Sstevel@tonic-gate * 7407c478bd9Sstevel@tonic-gate * The pattern is: 7417c478bd9Sstevel@tonic-gate * MD1 A1 MD2 A2 MD3 A3 D1 D2 D3 7427c478bd9Sstevel@tonic-gate * thus, skip is 7437c478bd9Sstevel@tonic-gate * (2 * numgroup) - 1 - groupi 7447c478bd9Sstevel@tonic-gate * (2 * numgroup) to account for MD + A 7457c478bd9Sstevel@tonic-gate * - 1 to account for the fact that we're on the 7467c478bd9Sstevel@tonic-gate * access (A), not the mask (MD) 7477c478bd9Sstevel@tonic-gate * - groupi to account for the fact that we have 7487c478bd9Sstevel@tonic-gate * passed up groupi number of MD's. 7497c478bd9Sstevel@tonic-gate */ 7507c478bd9Sstevel@tonic-gate skip = (2 * numgroup) - 1 - groupi; 7517c478bd9Sstevel@tonic-gate ace4_make_deny(acep, acep + skip, isdir, FALSE, 7527c478bd9Sstevel@tonic-gate isserver); 7537c478bd9Sstevel@tonic-gate /* 7547c478bd9Sstevel@tonic-gate * If we just did the last group, skip acep past 7557c478bd9Sstevel@tonic-gate * all of the denies; else, just move ahead one. 7567c478bd9Sstevel@tonic-gate */ 7577c478bd9Sstevel@tonic-gate if (++groupi >= numgroup) 7587c478bd9Sstevel@tonic-gate acep += numgroup + 1; 7597c478bd9Sstevel@tonic-gate else 7607c478bd9Sstevel@tonic-gate acep += 1; 7617c478bd9Sstevel@tonic-gate } else if (aclent[i].a_type & OTHER_OBJ) { 7627c478bd9Sstevel@tonic-gate (void) str_to_utf8(ACE4_WHO_EVERYONE, &acep->who); 7637c478bd9Sstevel@tonic-gate ace4_make_deny(acep, acep + 1, isdir, FALSE, isserver); 7647c478bd9Sstevel@tonic-gate acep += 2; 7657c478bd9Sstevel@tonic-gate } else { 7667c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 7677c478bd9Sstevel@tonic-gate "ln_aent_to_ace4: aclent_t with invalid type: %x", 7687c478bd9Sstevel@tonic-gate aclent[i].a_type)); 7697c478bd9Sstevel@tonic-gate error = EINVAL; 7707c478bd9Sstevel@tonic-gate goto out; 7717c478bd9Sstevel@tonic-gate } 7727c478bd9Sstevel@tonic-gate } 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate *acepp = result; 7757c478bd9Sstevel@tonic-gate *rescount = resultsize; 7767c478bd9Sstevel@tonic-gate 7777c478bd9Sstevel@tonic-gate out: 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate if (error != 0) { 7807c478bd9Sstevel@tonic-gate if ((result != NULL) && (resultsize > 0)) { 7817c478bd9Sstevel@tonic-gate /* free any embedded "who" strings */ 7827c478bd9Sstevel@tonic-gate for (i = 0; i < resultsize; i++) { 7837c478bd9Sstevel@tonic-gate acep = result + i; 7847c478bd9Sstevel@tonic-gate if ((acep->who.utf8string_len > 0) && 7857c478bd9Sstevel@tonic-gate (acep->who.utf8string_val != NULL)) { 7867c478bd9Sstevel@tonic-gate kmem_free(acep->who.utf8string_val, 7877c478bd9Sstevel@tonic-gate acep->who.utf8string_len); 7887c478bd9Sstevel@tonic-gate } 7897c478bd9Sstevel@tonic-gate } 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate /* free the nfsace4 block */ 7927c478bd9Sstevel@tonic-gate kmem_free(result, resultsize * sizeof (nfsace4)); 7937c478bd9Sstevel@tonic-gate } 7947c478bd9Sstevel@tonic-gate } 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate return (error); 7977c478bd9Sstevel@tonic-gate } 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate /* 8007c478bd9Sstevel@tonic-gate * Convert a POSIX draft ACL (in a vsecattr_t) to an NFSv4 ACL, following 8017c478bd9Sstevel@tonic-gate * the semantics of the IETF draft, draft-ietf-nfsv4-acl-mapping-01.txt. 8027c478bd9Sstevel@tonic-gate */ 8037c478bd9Sstevel@tonic-gate int 8047c478bd9Sstevel@tonic-gate vs_aent_to_ace4(vsecattr_t *aclentacl, vsecattr_t *vs_ace4, 8057c478bd9Sstevel@tonic-gate int isdir, int isserver) 8067c478bd9Sstevel@tonic-gate { 8077c478bd9Sstevel@tonic-gate int error = 0; 8087c478bd9Sstevel@tonic-gate nfsace4 *acebuf = NULL; 8097c478bd9Sstevel@tonic-gate int acecnt = 0; 8107c478bd9Sstevel@tonic-gate nfsace4 *dfacebuf = NULL; 8117c478bd9Sstevel@tonic-gate int dfacecnt = 0; 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate /* initialize vs_ace4 in case we can't complete our work */ 8147c478bd9Sstevel@tonic-gate vs_ace4->vsa_mask = 0; 8157c478bd9Sstevel@tonic-gate vs_ace4->vsa_aclentp = NULL; 8167c478bd9Sstevel@tonic-gate vs_ace4->vsa_aclcnt = 0; 8177c478bd9Sstevel@tonic-gate vs_ace4->vsa_dfaclentp = NULL; 8187c478bd9Sstevel@tonic-gate vs_ace4->vsa_dfaclcnt = 0; 819da6c28aaSamw vs_ace4->vsa_aclentsz = 0; 8207c478bd9Sstevel@tonic-gate 8217c478bd9Sstevel@tonic-gate if (! (aclentacl->vsa_mask & (VSA_ACL | VSA_ACLCNT | 8227c478bd9Sstevel@tonic-gate VSA_DFACL | VSA_DFACLCNT))) { 8237c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 8247c478bd9Sstevel@tonic-gate "vs_aent_to_ace4: vsa_mask lacking proper mask")); 8257c478bd9Sstevel@tonic-gate error = EINVAL; 8267c478bd9Sstevel@tonic-gate goto out; 8277c478bd9Sstevel@tonic-gate } 8287c478bd9Sstevel@tonic-gate 8297c478bd9Sstevel@tonic-gate if ((aclentacl->vsa_aclcnt < 3) && 8307c478bd9Sstevel@tonic-gate (aclentacl->vsa_mask & (VSA_ACL | VSA_ACLCNT))) { 8317c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 8327c478bd9Sstevel@tonic-gate "vs_aent_to_ace4: too small vsa_aclcnt, %d", 8337c478bd9Sstevel@tonic-gate aclentacl->vsa_aclcnt)); 8347c478bd9Sstevel@tonic-gate error = EINVAL; 8357c478bd9Sstevel@tonic-gate goto out; 8367c478bd9Sstevel@tonic-gate } 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate if ((aclentacl->vsa_dfaclcnt != 0) && (aclentacl->vsa_dfaclcnt < 3) && 8397c478bd9Sstevel@tonic-gate (aclentacl->vsa_mask & (VSA_DFACL | VSA_DFACLCNT))) { 8407c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 8417c478bd9Sstevel@tonic-gate "vs_aent_to_ace4: too small vsa_dfaclcnt, %d", 8427c478bd9Sstevel@tonic-gate aclentacl->vsa_dfaclcnt)); 8437c478bd9Sstevel@tonic-gate error = EINVAL; 8447c478bd9Sstevel@tonic-gate goto out; 8457c478bd9Sstevel@tonic-gate } 8467c478bd9Sstevel@tonic-gate 8477c478bd9Sstevel@tonic-gate if (aclentacl->vsa_aclcnt > 0) { 8487c478bd9Sstevel@tonic-gate error = ln_aent_to_ace4(aclentacl->vsa_aclentp, 849*e913d9ecSLisa Week aclentacl->vsa_aclcnt, &acebuf, &acecnt, isdir, isserver); 8507c478bd9Sstevel@tonic-gate if (error != 0) 8517c478bd9Sstevel@tonic-gate goto out; 8527c478bd9Sstevel@tonic-gate } 8537c478bd9Sstevel@tonic-gate if (aclentacl->vsa_dfaclcnt > 0) { 8547c478bd9Sstevel@tonic-gate error = ln_aent_to_ace4(aclentacl->vsa_dfaclentp, 855*e913d9ecSLisa Week aclentacl->vsa_dfaclcnt, &dfacebuf, &dfacecnt, isdir, 856*e913d9ecSLisa Week isserver); 8577c478bd9Sstevel@tonic-gate if (error != 0) 8587c478bd9Sstevel@tonic-gate goto out; 8597c478bd9Sstevel@tonic-gate } 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate vs_ace4->vsa_aclcnt = acecnt + dfacecnt; 8627c478bd9Sstevel@tonic-gate /* on error, this is freed by vs_ace4_destroy() */ 8637c478bd9Sstevel@tonic-gate if (vs_ace4->vsa_aclcnt > 0) 8647c478bd9Sstevel@tonic-gate vs_ace4->vsa_aclentp = kmem_zalloc(vs_ace4->vsa_aclcnt * 8657c478bd9Sstevel@tonic-gate sizeof (nfsace4), KM_SLEEP); 8667c478bd9Sstevel@tonic-gate /* 8677c478bd9Sstevel@tonic-gate * When we bcopy the nfsace4's, the result (in vsa_aclentp) 8687c478bd9Sstevel@tonic-gate * will have its "who.utf8string_val" pointer pointing to the 8697c478bd9Sstevel@tonic-gate * allocated strings. Thus, when we free acebuf and dbacebuf, 8707c478bd9Sstevel@tonic-gate * we don't need to free these strings. 8717c478bd9Sstevel@tonic-gate */ 8727c478bd9Sstevel@tonic-gate if (acecnt > 0) 8737c478bd9Sstevel@tonic-gate bcopy(acebuf, vs_ace4->vsa_aclentp, acecnt * sizeof (nfsace4)); 8747c478bd9Sstevel@tonic-gate if (dfacecnt > 0) 8757c478bd9Sstevel@tonic-gate bcopy(dfacebuf, (nfsace4 *) vs_ace4->vsa_aclentp + acecnt, 8767c478bd9Sstevel@tonic-gate dfacecnt * sizeof (nfsace4)); 8777c478bd9Sstevel@tonic-gate vs_ace4->vsa_mask = VSA_ACE | VSA_ACECNT; 8787c478bd9Sstevel@tonic-gate 8797c478bd9Sstevel@tonic-gate out: 8807c478bd9Sstevel@tonic-gate if (error != 0) 8817c478bd9Sstevel@tonic-gate vs_ace4_destroy(vs_ace4); 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate if (acebuf != NULL) 8847c478bd9Sstevel@tonic-gate kmem_free(acebuf, acecnt * sizeof (nfsace4)); 8857c478bd9Sstevel@tonic-gate if (dfacebuf != NULL) 8867c478bd9Sstevel@tonic-gate kmem_free(dfacebuf, dfacecnt * sizeof (nfsace4)); 8877c478bd9Sstevel@tonic-gate 8887c478bd9Sstevel@tonic-gate return (error); 8897c478bd9Sstevel@tonic-gate } 8907c478bd9Sstevel@tonic-gate 8917c478bd9Sstevel@tonic-gate static int 8927c478bd9Sstevel@tonic-gate ace4_mask_to_mode(acemask4 mask, o_mode_t *modep, int isdir) 8937c478bd9Sstevel@tonic-gate { 8947c478bd9Sstevel@tonic-gate int error = 0; 8957c478bd9Sstevel@tonic-gate o_mode_t mode = 0; 8967c478bd9Sstevel@tonic-gate acemask4 bits, wantbits; 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate /* read */ 8997c478bd9Sstevel@tonic-gate if (mask & ACE4_READ_DATA) 9007c478bd9Sstevel@tonic-gate mode |= 04; 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate /* write */ 9037c478bd9Sstevel@tonic-gate wantbits = (ACE4_WRITE_DATA | 9047c478bd9Sstevel@tonic-gate ACE4_APPEND_DATA); 9057c478bd9Sstevel@tonic-gate if (isdir) 9067c478bd9Sstevel@tonic-gate wantbits |= ACE4_DELETE_CHILD; 9077c478bd9Sstevel@tonic-gate bits = mask & wantbits; 9087c478bd9Sstevel@tonic-gate if (bits != 0) { 9097c478bd9Sstevel@tonic-gate if (bits != wantbits) { 9107c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 9117c478bd9Sstevel@tonic-gate "ace4_mask_to_mode: bad subset of write flags " 9127c478bd9Sstevel@tonic-gate "%x", bits)); 9137c478bd9Sstevel@tonic-gate error = ENOTSUP; 9147c478bd9Sstevel@tonic-gate goto out; 9157c478bd9Sstevel@tonic-gate } 9167c478bd9Sstevel@tonic-gate mode |= 02; 9177c478bd9Sstevel@tonic-gate } 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate /* exec */ 9207c478bd9Sstevel@tonic-gate if (mask & ACE4_EXECUTE) { 9217c478bd9Sstevel@tonic-gate mode |= 01; 9227c478bd9Sstevel@tonic-gate } 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate *modep = mode; 9257c478bd9Sstevel@tonic-gate 9267c478bd9Sstevel@tonic-gate out: 9277c478bd9Sstevel@tonic-gate return (error); 9287c478bd9Sstevel@tonic-gate } 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate static int 9317c478bd9Sstevel@tonic-gate ace4_allow_to_mode(acemask4 mask, o_mode_t *modep, int isdir) 9327c478bd9Sstevel@tonic-gate { 9337c478bd9Sstevel@tonic-gate /* ACE4_READ_ACL and ACE4_READ_ATTRIBUTES must both be set */ 9347c478bd9Sstevel@tonic-gate if ((mask & (ACE4_READ_ACL | ACE4_READ_ATTRIBUTES)) != 9357c478bd9Sstevel@tonic-gate (ACE4_READ_ACL | ACE4_READ_ATTRIBUTES)) { 9367c478bd9Sstevel@tonic-gate return (ENOTSUP); 9377c478bd9Sstevel@tonic-gate } 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate return (ace4_mask_to_mode(mask, modep, isdir)); 9407c478bd9Sstevel@tonic-gate } 9417c478bd9Sstevel@tonic-gate 9427c478bd9Sstevel@tonic-gate /* 9437c478bd9Sstevel@tonic-gate * Find or create an ace4vals holder for a given id and avl tree. 9447c478bd9Sstevel@tonic-gate * 9457c478bd9Sstevel@tonic-gate * Note that only one thread will ever touch these avl trees, so 9467c478bd9Sstevel@tonic-gate * there is no need for locking. 9477c478bd9Sstevel@tonic-gate */ 9487c478bd9Sstevel@tonic-gate static ace4vals_t * 9497c478bd9Sstevel@tonic-gate ace4vals_find(nfsace4 *ace4, avl_tree_t *avl, int *num) 9507c478bd9Sstevel@tonic-gate { 9517c478bd9Sstevel@tonic-gate ace4vals_t key, *rc; 9527c478bd9Sstevel@tonic-gate avl_index_t where; 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate key.key = &ace4->who; 9557c478bd9Sstevel@tonic-gate rc = avl_find(avl, &key, &where); 9567c478bd9Sstevel@tonic-gate if (rc != NULL) 9577c478bd9Sstevel@tonic-gate return (rc); 9587c478bd9Sstevel@tonic-gate 9597c478bd9Sstevel@tonic-gate /* this memory is freed by ln_ace4_to_aent()->ace4_list_free() */ 9607c478bd9Sstevel@tonic-gate rc = kmem_cache_alloc(nfs4_ace4vals_cache, KM_SLEEP); 9617c478bd9Sstevel@tonic-gate ace4vals_init(rc, &ace4->who); 9627c478bd9Sstevel@tonic-gate avl_insert(avl, rc, where); 9637c478bd9Sstevel@tonic-gate (*num)++; 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate return (rc); 9667c478bd9Sstevel@tonic-gate } 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate static int 9697c478bd9Sstevel@tonic-gate access_mask_check(nfsace4 *ace4p, int mask_bit, int isserver, int isowner) 9707c478bd9Sstevel@tonic-gate { 9717c478bd9Sstevel@tonic-gate int set_deny, err_deny; 9727c478bd9Sstevel@tonic-gate int set_allow, err_allow; 9737c478bd9Sstevel@tonic-gate int nfs4_acl_consume; 9747c478bd9Sstevel@tonic-gate int haswriteperm, hasreadperm; 9757c478bd9Sstevel@tonic-gate 9767c478bd9Sstevel@tonic-gate if (ace4p->type == ACE4_ACCESS_DENIED_ACE_TYPE) { 9777c478bd9Sstevel@tonic-gate haswriteperm = (ace4p->access_mask & ACE4_WRITE_DATA) ? 0 : 1; 9787c478bd9Sstevel@tonic-gate hasreadperm = (ace4p->access_mask & ACE4_READ_DATA) ? 0 : 1; 9797c478bd9Sstevel@tonic-gate } else { 9807c478bd9Sstevel@tonic-gate haswriteperm = (ace4p->access_mask & ACE4_WRITE_DATA) ? 1 : 0; 9817c478bd9Sstevel@tonic-gate hasreadperm = (ace4p->access_mask & ACE4_READ_DATA) ? 1 : 0; 9827c478bd9Sstevel@tonic-gate } 9837c478bd9Sstevel@tonic-gate 9847c478bd9Sstevel@tonic-gate if (isserver) 9857c478bd9Sstevel@tonic-gate nfs4_acl_consume = nfs4_acl_server_consume; 9867c478bd9Sstevel@tonic-gate else 9877c478bd9Sstevel@tonic-gate nfs4_acl_consume = nfs4_acl_client_consume; 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate if (mask_bit == ACE4_SYNCHRONIZE) { 9907c478bd9Sstevel@tonic-gate set_deny = ACL_SYNCHRONIZE_SET_DENY; 9917c478bd9Sstevel@tonic-gate err_deny = ACL_SYNCHRONIZE_ERR_DENY; 9927c478bd9Sstevel@tonic-gate set_allow = ACL_SYNCHRONIZE_SET_ALLOW; 9937c478bd9Sstevel@tonic-gate err_allow = ACL_SYNCHRONIZE_ERR_ALLOW; 9947c478bd9Sstevel@tonic-gate } else if (mask_bit == ACE4_WRITE_OWNER) { 9957c478bd9Sstevel@tonic-gate set_deny = ACL_WRITE_OWNER_SET_DENY; 9967c478bd9Sstevel@tonic-gate err_deny = ACL_WRITE_OWNER_ERR_DENY; 9977c478bd9Sstevel@tonic-gate set_allow = ACL_WRITE_OWNER_SET_ALLOW; 9987c478bd9Sstevel@tonic-gate err_allow = ACL_WRITE_OWNER_ERR_ALLOW; 9997c478bd9Sstevel@tonic-gate } else if (mask_bit == ACE4_DELETE) { 10007c478bd9Sstevel@tonic-gate set_deny = ACL_DELETE_SET_DENY; 10017c478bd9Sstevel@tonic-gate err_deny = ACL_DELETE_ERR_DENY; 10027c478bd9Sstevel@tonic-gate set_allow = ACL_DELETE_SET_ALLOW; 10037c478bd9Sstevel@tonic-gate err_allow = ACL_DELETE_ERR_ALLOW; 10047c478bd9Sstevel@tonic-gate } else if (mask_bit == ACE4_WRITE_ATTRIBUTES) { 10057c478bd9Sstevel@tonic-gate if (isowner) { 10067c478bd9Sstevel@tonic-gate set_deny = ACL_WRITE_ATTRS_OWNER_SET_DENY; 10077c478bd9Sstevel@tonic-gate err_deny = ACL_WRITE_ATTRS_OWNER_ERR_DENY; 10087c478bd9Sstevel@tonic-gate set_allow = ACL_WRITE_ATTRS_OWNER_SET_ALLOW; 10097c478bd9Sstevel@tonic-gate err_allow = ACL_WRITE_ATTRS_OWNER_ERR_ALLOW; 10107c478bd9Sstevel@tonic-gate } else if (haswriteperm) { 10117c478bd9Sstevel@tonic-gate set_deny = ACL_WRITE_ATTRS_WRITER_SET_DENY; 10127c478bd9Sstevel@tonic-gate err_deny = ACL_WRITE_ATTRS_WRITER_ERR_DENY; 10137c478bd9Sstevel@tonic-gate set_allow = ACL_WRITE_ATTRS_WRITER_SET_ALLOW; 10147c478bd9Sstevel@tonic-gate err_allow = ACL_WRITE_ATTRS_WRITER_ERR_ALLOW; 10157c478bd9Sstevel@tonic-gate } else { 10167c478bd9Sstevel@tonic-gate if ((ace4p->access_mask & mask_bit) && 10177c478bd9Sstevel@tonic-gate (ace4p->type & ACE4_ACCESS_ALLOWED_ACE_TYPE)) { 10187c478bd9Sstevel@tonic-gate return (ENOTSUP); 10197c478bd9Sstevel@tonic-gate } 10207c478bd9Sstevel@tonic-gate return (0); 10217c478bd9Sstevel@tonic-gate } 10227c478bd9Sstevel@tonic-gate } else if (mask_bit == ACE4_READ_NAMED_ATTRS) { 10237c478bd9Sstevel@tonic-gate if (!hasreadperm) 10247c478bd9Sstevel@tonic-gate return (0); 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate set_deny = ACL_READ_NAMED_READER_SET_DENY; 10277c478bd9Sstevel@tonic-gate err_deny = ACL_READ_NAMED_READER_ERR_DENY; 10287c478bd9Sstevel@tonic-gate set_allow = ACL_READ_NAMED_READER_SET_ALLOW; 10297c478bd9Sstevel@tonic-gate err_allow = ACL_READ_NAMED_READER_ERR_ALLOW; 10307c478bd9Sstevel@tonic-gate } else if (mask_bit == ACE4_WRITE_NAMED_ATTRS) { 10317c478bd9Sstevel@tonic-gate if (!haswriteperm) 10327c478bd9Sstevel@tonic-gate return (0); 10337c478bd9Sstevel@tonic-gate 10347c478bd9Sstevel@tonic-gate set_deny = ACL_WRITE_NAMED_WRITER_SET_DENY; 10357c478bd9Sstevel@tonic-gate err_deny = ACL_WRITE_NAMED_WRITER_ERR_DENY; 10367c478bd9Sstevel@tonic-gate set_allow = ACL_WRITE_NAMED_WRITER_SET_ALLOW; 10377c478bd9Sstevel@tonic-gate err_allow = ACL_WRITE_NAMED_WRITER_ERR_ALLOW; 10387c478bd9Sstevel@tonic-gate } else 10397c478bd9Sstevel@tonic-gate return (EINVAL); 10407c478bd9Sstevel@tonic-gate 10417c478bd9Sstevel@tonic-gate if (ace4p->type == ACE4_ACCESS_DENIED_ACE_TYPE) { 10427c478bd9Sstevel@tonic-gate if (nfs4_acl_consume & set_deny) { 10437c478bd9Sstevel@tonic-gate if (!(ace4p->access_mask & mask_bit)) { 10447c478bd9Sstevel@tonic-gate return (ENOTSUP); 10457c478bd9Sstevel@tonic-gate } 10467c478bd9Sstevel@tonic-gate } else if (nfs4_acl_consume & err_deny) { 10477c478bd9Sstevel@tonic-gate if (ace4p->access_mask & mask_bit) { 10487c478bd9Sstevel@tonic-gate return (ENOTSUP); 10497c478bd9Sstevel@tonic-gate } 10507c478bd9Sstevel@tonic-gate } 10517c478bd9Sstevel@tonic-gate } else { 10527c478bd9Sstevel@tonic-gate /* ACE4_ACCESS_ALLOWED_ACE_TYPE */ 10537c478bd9Sstevel@tonic-gate if (nfs4_acl_consume & set_allow) { 10547c478bd9Sstevel@tonic-gate if (!(ace4p->access_mask & mask_bit)) { 10557c478bd9Sstevel@tonic-gate return (ENOTSUP); 10567c478bd9Sstevel@tonic-gate } 10577c478bd9Sstevel@tonic-gate } else if (nfs4_acl_consume & err_allow) { 10587c478bd9Sstevel@tonic-gate if (ace4p->access_mask & mask_bit) { 10597c478bd9Sstevel@tonic-gate return (ENOTSUP); 10607c478bd9Sstevel@tonic-gate } 10617c478bd9Sstevel@tonic-gate } 10627c478bd9Sstevel@tonic-gate } 10637c478bd9Sstevel@tonic-gate return (0); 10647c478bd9Sstevel@tonic-gate } 10657c478bd9Sstevel@tonic-gate 10667c478bd9Sstevel@tonic-gate static int 10677c478bd9Sstevel@tonic-gate ace4_to_aent_legal(nfsace4 *ace4p, int isserver) 10687c478bd9Sstevel@tonic-gate { 10697c478bd9Sstevel@tonic-gate int error = 0; 10707c478bd9Sstevel@tonic-gate int isowner; 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate /* check for NULL who string */ 10737c478bd9Sstevel@tonic-gate if (ace4p->who.utf8string_val == NULL) { 10747c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 10757c478bd9Sstevel@tonic-gate "ace4_to_aent_legal: NULL who string")); 10767c478bd9Sstevel@tonic-gate error = EINVAL; 10777c478bd9Sstevel@tonic-gate goto out; 10787c478bd9Sstevel@tonic-gate } 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate /* only ALLOW or DENY */ 10817c478bd9Sstevel@tonic-gate if ((ace4p->type != ACE4_ACCESS_ALLOWED_ACE_TYPE) && 10827c478bd9Sstevel@tonic-gate (ace4p->type != ACE4_ACCESS_DENIED_ACE_TYPE)) { 10837c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 10847c478bd9Sstevel@tonic-gate "ace4_to_aent_legal: neither allow nor deny")); 10857c478bd9Sstevel@tonic-gate error = ENOTSUP; 10867c478bd9Sstevel@tonic-gate goto out; 10877c478bd9Sstevel@tonic-gate } 10887c478bd9Sstevel@tonic-gate 10897c478bd9Sstevel@tonic-gate /* check for invalid flags */ 10907c478bd9Sstevel@tonic-gate if (ace4p->flag & ~(ACE4_VALID_FLAG_BITS)) { 10917c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 10927c478bd9Sstevel@tonic-gate "ace4_to_aent_legal: invalid flags: %x", ace4p->flag)); 10937c478bd9Sstevel@tonic-gate error = EINVAL; 10947c478bd9Sstevel@tonic-gate goto out; 10957c478bd9Sstevel@tonic-gate } 10967c478bd9Sstevel@tonic-gate 10977c478bd9Sstevel@tonic-gate /* some flags are illegal */ 10987c478bd9Sstevel@tonic-gate if (ace4p->flag & (ACE4_SUCCESSFUL_ACCESS_ACE_FLAG | 10997c478bd9Sstevel@tonic-gate ACE4_FAILED_ACCESS_ACE_FLAG | 11007c478bd9Sstevel@tonic-gate ACE4_NO_PROPAGATE_INHERIT_ACE)) { 11017c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 11027c478bd9Sstevel@tonic-gate "ace4_to_aent_legal: illegal flags: %x", ace4p->flag)); 11037c478bd9Sstevel@tonic-gate error = ENOTSUP; 11047c478bd9Sstevel@tonic-gate goto out; 11057c478bd9Sstevel@tonic-gate } 11067c478bd9Sstevel@tonic-gate 11077c478bd9Sstevel@tonic-gate /* check for invalid masks */ 11087c478bd9Sstevel@tonic-gate if (ace4p->access_mask & ~(ACE4_VALID_MASK_BITS)) { 11097c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 11107c478bd9Sstevel@tonic-gate "ace4_to_aent_legal: invalid mask: %x", 11117c478bd9Sstevel@tonic-gate ace4p->access_mask)); 11127c478bd9Sstevel@tonic-gate error = EINVAL; 11137c478bd9Sstevel@tonic-gate goto out; 11147c478bd9Sstevel@tonic-gate } 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate if ((ace4p->who.utf8string_len == 6) && 11177c478bd9Sstevel@tonic-gate (bcmp(ACE4_WHO_OWNER, ace4p->who.utf8string_val, 6) == 0)) { 11187c478bd9Sstevel@tonic-gate isowner = 1; 11197c478bd9Sstevel@tonic-gate } else { 11207c478bd9Sstevel@tonic-gate isowner = 0; 11217c478bd9Sstevel@tonic-gate } 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate error = access_mask_check(ace4p, ACE4_SYNCHRONIZE, isserver, isowner); 11247c478bd9Sstevel@tonic-gate if (error) 11257c478bd9Sstevel@tonic-gate goto out; 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate error = access_mask_check(ace4p, ACE4_WRITE_OWNER, isserver, isowner); 11287c478bd9Sstevel@tonic-gate if (error) 11297c478bd9Sstevel@tonic-gate goto out; 11307c478bd9Sstevel@tonic-gate 11317c478bd9Sstevel@tonic-gate error = access_mask_check(ace4p, ACE4_DELETE, isserver, isowner); 11327c478bd9Sstevel@tonic-gate if (error) 11337c478bd9Sstevel@tonic-gate goto out; 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate error = access_mask_check(ace4p, ACE4_WRITE_ATTRIBUTES, isserver, 11367c478bd9Sstevel@tonic-gate isowner); 11377c478bd9Sstevel@tonic-gate if (error) 11387c478bd9Sstevel@tonic-gate goto out; 11397c478bd9Sstevel@tonic-gate 11407c478bd9Sstevel@tonic-gate error = access_mask_check(ace4p, ACE4_READ_NAMED_ATTRS, isserver, 11417c478bd9Sstevel@tonic-gate isowner); 11427c478bd9Sstevel@tonic-gate if (error) 11437c478bd9Sstevel@tonic-gate goto out; 11447c478bd9Sstevel@tonic-gate 11457c478bd9Sstevel@tonic-gate error = access_mask_check(ace4p, ACE4_WRITE_NAMED_ATTRS, isserver, 11467c478bd9Sstevel@tonic-gate isowner); 11477c478bd9Sstevel@tonic-gate if (error) 11487c478bd9Sstevel@tonic-gate goto out; 11497c478bd9Sstevel@tonic-gate 11507c478bd9Sstevel@tonic-gate /* more detailed checking of masks */ 11517c478bd9Sstevel@tonic-gate if (ace4p->type == ACE4_ACCESS_ALLOWED_ACE_TYPE) { 11527c478bd9Sstevel@tonic-gate if (! (ace4p->access_mask & ACE4_READ_ATTRIBUTES)) { 11537c478bd9Sstevel@tonic-gate error = ENOTSUP; 11547c478bd9Sstevel@tonic-gate goto out; 11557c478bd9Sstevel@tonic-gate } 11567c478bd9Sstevel@tonic-gate if ((ace4p->access_mask & ACE4_WRITE_DATA) && 11577c478bd9Sstevel@tonic-gate (! (ace4p->access_mask & ACE4_APPEND_DATA))) { 11587c478bd9Sstevel@tonic-gate error = ENOTSUP; 11597c478bd9Sstevel@tonic-gate goto out; 11607c478bd9Sstevel@tonic-gate } 11617c478bd9Sstevel@tonic-gate if ((! (ace4p->access_mask & ACE4_WRITE_DATA)) && 11627c478bd9Sstevel@tonic-gate (ace4p->access_mask & ACE4_APPEND_DATA)) { 11637c478bd9Sstevel@tonic-gate error = ENOTSUP; 11647c478bd9Sstevel@tonic-gate goto out; 11657c478bd9Sstevel@tonic-gate } 11667c478bd9Sstevel@tonic-gate } 11677c478bd9Sstevel@tonic-gate 11687c478bd9Sstevel@tonic-gate /* ACL enforcement */ 11697c478bd9Sstevel@tonic-gate if ((ace4p->access_mask & ACE4_READ_ACL) && 11707c478bd9Sstevel@tonic-gate (ace4p->type != ACE4_ACCESS_ALLOWED_ACE_TYPE)) { 11717c478bd9Sstevel@tonic-gate error = ENOTSUP; 11727c478bd9Sstevel@tonic-gate goto out; 11737c478bd9Sstevel@tonic-gate } 11747c478bd9Sstevel@tonic-gate if (ace4p->access_mask & ACE4_WRITE_ACL) { 11757c478bd9Sstevel@tonic-gate if ((ace4p->type == ACE4_ACCESS_DENIED_ACE_TYPE) && 11767c478bd9Sstevel@tonic-gate (isowner)) { 11777c478bd9Sstevel@tonic-gate error = ENOTSUP; 11787c478bd9Sstevel@tonic-gate goto out; 11797c478bd9Sstevel@tonic-gate } 11807c478bd9Sstevel@tonic-gate if ((ace4p->type == ACE4_ACCESS_ALLOWED_ACE_TYPE) && 11817c478bd9Sstevel@tonic-gate (! isowner)) { 11827c478bd9Sstevel@tonic-gate error = ENOTSUP; 11837c478bd9Sstevel@tonic-gate goto out; 11847c478bd9Sstevel@tonic-gate } 11857c478bd9Sstevel@tonic-gate } 11867c478bd9Sstevel@tonic-gate 11877c478bd9Sstevel@tonic-gate out: 11887c478bd9Sstevel@tonic-gate return (error); 11897c478bd9Sstevel@tonic-gate } 11907c478bd9Sstevel@tonic-gate 11917c478bd9Sstevel@tonic-gate static int 11927c478bd9Sstevel@tonic-gate ace4vals_to_aent(ace4vals_t *vals, aclent_t *dest, ace4_list_t *list, 1193*e913d9ecSLisa Week uid_t owner, gid_t group, int isdir, int isserver) 11947c478bd9Sstevel@tonic-gate { 11957c478bd9Sstevel@tonic-gate int error; 11967c478bd9Sstevel@tonic-gate acemask4 flips = ACE4_POSIX_SUPPORTED_BITS; 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate if (isdir) 11997c478bd9Sstevel@tonic-gate flips |= ACE4_DELETE_CHILD; 12007c478bd9Sstevel@tonic-gate if (vals->allowed != (vals->denied ^ flips)) { 12017c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 12027c478bd9Sstevel@tonic-gate "ace4vals_to_aent: mis-matched allow/deny pair: %x/%x", 12037c478bd9Sstevel@tonic-gate vals->allowed, vals->denied)); 12047c478bd9Sstevel@tonic-gate error = ENOTSUP; 12057c478bd9Sstevel@tonic-gate goto out; 12067c478bd9Sstevel@tonic-gate } 12077c478bd9Sstevel@tonic-gate if ((list->hasmask) && (list->acl_mask != vals->mask) && 12087c478bd9Sstevel@tonic-gate (vals->aent_type & (USER | GROUP | GROUP_OBJ))) { 12097c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 12107c478bd9Sstevel@tonic-gate "ace4vals_to_aent: entry is missing mask")); 12117c478bd9Sstevel@tonic-gate error = ENOTSUP; 12127c478bd9Sstevel@tonic-gate goto out; 12137c478bd9Sstevel@tonic-gate } 12147c478bd9Sstevel@tonic-gate error = ace4_allow_to_mode(vals->allowed, &dest->a_perm, isdir); 12157c478bd9Sstevel@tonic-gate if (error != 0) 12167c478bd9Sstevel@tonic-gate goto out; 12177c478bd9Sstevel@tonic-gate dest->a_type = vals->aent_type; 12187c478bd9Sstevel@tonic-gate if (dest->a_type & (USER | GROUP)) { 12197c478bd9Sstevel@tonic-gate if (dest->a_type & USER) 12207c478bd9Sstevel@tonic-gate error = nfs_idmap_str_uid(vals->key, &dest->a_id, 12217c478bd9Sstevel@tonic-gate isserver); 12227c478bd9Sstevel@tonic-gate else 12237c478bd9Sstevel@tonic-gate error = nfs_idmap_str_gid(vals->key, &dest->a_id, 12247c478bd9Sstevel@tonic-gate isserver); 12257c478bd9Sstevel@tonic-gate if (error != 0) { 12267c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 12277c478bd9Sstevel@tonic-gate "ace4vals_to_aent: idmap failed with %d", error)); 12287c478bd9Sstevel@tonic-gate if (isserver && (error == EPERM)) 12297c478bd9Sstevel@tonic-gate error = NFS4ERR_BADOWNER; 12307c478bd9Sstevel@tonic-gate goto out; 12317c478bd9Sstevel@tonic-gate } 12327c478bd9Sstevel@tonic-gate 1233*e913d9ecSLisa Week error = validate_idmapping(vals->key, &dest->a_id, 1234*e913d9ecSLisa Week (dest->a_type & USER ? 1 : 0), isserver); 12357c478bd9Sstevel@tonic-gate if (error != 0) { 12367c478bd9Sstevel@tonic-gate goto out; 12377c478bd9Sstevel@tonic-gate } 12387c478bd9Sstevel@tonic-gate } else if (dest->a_type & USER_OBJ) { 12397c478bd9Sstevel@tonic-gate dest->a_id = owner; 12407c478bd9Sstevel@tonic-gate } else if (dest->a_type & GROUP_OBJ) { 12417c478bd9Sstevel@tonic-gate dest->a_id = group; 12427c478bd9Sstevel@tonic-gate } else if (dest->a_type & OTHER_OBJ) { 12437c478bd9Sstevel@tonic-gate dest->a_id = 0; 12447c478bd9Sstevel@tonic-gate } else { 12457c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 12467c478bd9Sstevel@tonic-gate "ace4vals_to_aent: dest->a_type invalid: %x " 12477c478bd9Sstevel@tonic-gate "(internal error)", dest->a_type)); 12487c478bd9Sstevel@tonic-gate error = EINVAL; 12497c478bd9Sstevel@tonic-gate goto out; 12507c478bd9Sstevel@tonic-gate } 12517c478bd9Sstevel@tonic-gate 12527c478bd9Sstevel@tonic-gate out: 12537c478bd9Sstevel@tonic-gate return (error); 12547c478bd9Sstevel@tonic-gate } 12557c478bd9Sstevel@tonic-gate 12567c478bd9Sstevel@tonic-gate static int 12577c478bd9Sstevel@tonic-gate ace4_list_to_aent(ace4_list_t *list, aclent_t **aclentp, int *aclcnt, 1258*e913d9ecSLisa Week uid_t owner, gid_t group, int isdir, int isserver) 12597c478bd9Sstevel@tonic-gate { 12607c478bd9Sstevel@tonic-gate int error = 0; 12617c478bd9Sstevel@tonic-gate aclent_t *aent, *result = NULL; 12627c478bd9Sstevel@tonic-gate ace4vals_t *vals; 12637c478bd9Sstevel@tonic-gate int resultcount; 12647c478bd9Sstevel@tonic-gate 12657c478bd9Sstevel@tonic-gate if ((list->seen & (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) != 12667c478bd9Sstevel@tonic-gate (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) { 12677c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1268*e913d9ecSLisa Week "ace4_list_to_aent: required aclent_t entites missing")); 12697c478bd9Sstevel@tonic-gate error = ENOTSUP; 12707c478bd9Sstevel@tonic-gate goto out; 12717c478bd9Sstevel@tonic-gate } 12727c478bd9Sstevel@tonic-gate if ((! list->hasmask) && (list->numusers + list->numgroups > 0)) { 12737c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 12747c478bd9Sstevel@tonic-gate "ace4_list_to_aent: CLASS_OBJ (mask) missing")); 12757c478bd9Sstevel@tonic-gate error = ENOTSUP; 12767c478bd9Sstevel@tonic-gate goto out; 12777c478bd9Sstevel@tonic-gate } 12787c478bd9Sstevel@tonic-gate 12797c478bd9Sstevel@tonic-gate resultcount = 3 + list->numusers + list->numgroups; 12807c478bd9Sstevel@tonic-gate /* 12817c478bd9Sstevel@tonic-gate * This must be the same condition as below, when we add the CLASS_OBJ 12827c478bd9Sstevel@tonic-gate * (aka ACL mask) 12837c478bd9Sstevel@tonic-gate */ 12847c478bd9Sstevel@tonic-gate if ((list->hasmask) || (! list->dfacl_flag)) 12857c478bd9Sstevel@tonic-gate resultcount += 1; 12867c478bd9Sstevel@tonic-gate 12877c478bd9Sstevel@tonic-gate result = aent = kmem_alloc(resultcount * sizeof (aclent_t), KM_SLEEP); 12887c478bd9Sstevel@tonic-gate 12897c478bd9Sstevel@tonic-gate /* USER_OBJ */ 12907c478bd9Sstevel@tonic-gate ASSERT(list->user_obj.aent_type & USER_OBJ); 12917c478bd9Sstevel@tonic-gate error = ace4vals_to_aent(&list->user_obj, aent, list, owner, group, 1292*e913d9ecSLisa Week isdir, isserver); 12937c478bd9Sstevel@tonic-gate 12947c478bd9Sstevel@tonic-gate if (error != 0) 12957c478bd9Sstevel@tonic-gate goto out; 12967c478bd9Sstevel@tonic-gate ++aent; 12977c478bd9Sstevel@tonic-gate /* USER */ 12987c478bd9Sstevel@tonic-gate vals = NULL; 12997c478bd9Sstevel@tonic-gate for (vals = avl_first(&list->user); vals != NULL; 13007c478bd9Sstevel@tonic-gate vals = AVL_NEXT(&list->user, vals)) { 13017c478bd9Sstevel@tonic-gate ASSERT(vals->aent_type & USER); 13027c478bd9Sstevel@tonic-gate error = ace4vals_to_aent(vals, aent, list, owner, group, 1303*e913d9ecSLisa Week isdir, isserver); 13047c478bd9Sstevel@tonic-gate if (error != 0) 13057c478bd9Sstevel@tonic-gate goto out; 13067c478bd9Sstevel@tonic-gate ++aent; 13077c478bd9Sstevel@tonic-gate } 13087c478bd9Sstevel@tonic-gate /* GROUP_OBJ */ 13097c478bd9Sstevel@tonic-gate ASSERT(list->group_obj.aent_type & GROUP_OBJ); 13107c478bd9Sstevel@tonic-gate error = ace4vals_to_aent(&list->group_obj, aent, list, owner, group, 1311*e913d9ecSLisa Week isdir, isserver); 13127c478bd9Sstevel@tonic-gate if (error != 0) 13137c478bd9Sstevel@tonic-gate goto out; 13147c478bd9Sstevel@tonic-gate ++aent; 13157c478bd9Sstevel@tonic-gate /* GROUP */ 13167c478bd9Sstevel@tonic-gate vals = NULL; 13177c478bd9Sstevel@tonic-gate for (vals = avl_first(&list->group); vals != NULL; 13187c478bd9Sstevel@tonic-gate vals = AVL_NEXT(&list->group, vals)) { 13197c478bd9Sstevel@tonic-gate ASSERT(vals->aent_type & GROUP); 13207c478bd9Sstevel@tonic-gate error = ace4vals_to_aent(vals, aent, list, owner, group, 1321*e913d9ecSLisa Week isdir, isserver); 13227c478bd9Sstevel@tonic-gate if (error != 0) 13237c478bd9Sstevel@tonic-gate goto out; 13247c478bd9Sstevel@tonic-gate ++aent; 13257c478bd9Sstevel@tonic-gate } 13267c478bd9Sstevel@tonic-gate /* 13277c478bd9Sstevel@tonic-gate * CLASS_OBJ (aka ACL_MASK) 13287c478bd9Sstevel@tonic-gate * 13297c478bd9Sstevel@tonic-gate * An ACL_MASK is not fabricated if the ACL is a default ACL. 13307c478bd9Sstevel@tonic-gate * This is to follow UFS's behavior. 13317c478bd9Sstevel@tonic-gate */ 13327c478bd9Sstevel@tonic-gate if ((list->hasmask) || (! list->dfacl_flag)) { 13337c478bd9Sstevel@tonic-gate if (list->hasmask) { 13347c478bd9Sstevel@tonic-gate acemask4 flips = ACE4_POSIX_SUPPORTED_BITS; 13357c478bd9Sstevel@tonic-gate if (isdir) 13367c478bd9Sstevel@tonic-gate flips |= ACE4_DELETE_CHILD; 13377c478bd9Sstevel@tonic-gate error = ace4_mask_to_mode(list->acl_mask ^ flips, 13387c478bd9Sstevel@tonic-gate &aent->a_perm, isdir); 13397c478bd9Sstevel@tonic-gate if (error != 0) 13407c478bd9Sstevel@tonic-gate goto out; 13417c478bd9Sstevel@tonic-gate } else { 13427c478bd9Sstevel@tonic-gate /* fabricate the ACL_MASK from the group permissions */ 13437c478bd9Sstevel@tonic-gate error = ace4_mask_to_mode(list->group_obj.allowed, 13447c478bd9Sstevel@tonic-gate &aent->a_perm, isdir); 13457c478bd9Sstevel@tonic-gate if (error != 0) 13467c478bd9Sstevel@tonic-gate goto out; 13477c478bd9Sstevel@tonic-gate } 13487c478bd9Sstevel@tonic-gate aent->a_id = 0; 13497c478bd9Sstevel@tonic-gate aent->a_type = CLASS_OBJ | list->dfacl_flag; 13507c478bd9Sstevel@tonic-gate ++aent; 13517c478bd9Sstevel@tonic-gate } 13527c478bd9Sstevel@tonic-gate /* OTHER_OBJ */ 13537c478bd9Sstevel@tonic-gate ASSERT(list->other_obj.aent_type & OTHER_OBJ); 13547c478bd9Sstevel@tonic-gate error = ace4vals_to_aent(&list->other_obj, aent, list, owner, group, 1355*e913d9ecSLisa Week isdir, isserver); 13567c478bd9Sstevel@tonic-gate if (error != 0) 13577c478bd9Sstevel@tonic-gate goto out; 13587c478bd9Sstevel@tonic-gate ++aent; 13597c478bd9Sstevel@tonic-gate 13607c478bd9Sstevel@tonic-gate *aclentp = result; 13617c478bd9Sstevel@tonic-gate *aclcnt = resultcount; 13627c478bd9Sstevel@tonic-gate 13637c478bd9Sstevel@tonic-gate out: 13647c478bd9Sstevel@tonic-gate if (error != 0) { 13657c478bd9Sstevel@tonic-gate if (result != NULL) 13667c478bd9Sstevel@tonic-gate kmem_free(result, resultcount * sizeof (aclent_t)); 13677c478bd9Sstevel@tonic-gate } 13687c478bd9Sstevel@tonic-gate 13697c478bd9Sstevel@tonic-gate return (error); 13707c478bd9Sstevel@tonic-gate } 13717c478bd9Sstevel@tonic-gate 13727c478bd9Sstevel@tonic-gate /* 13737c478bd9Sstevel@tonic-gate * Convert a list of nfsace4 entries to equivalent regular and default 13747c478bd9Sstevel@tonic-gate * aclent_t lists. Return error (ENOTSUP) when conversion is not possible. 13757c478bd9Sstevel@tonic-gate */ 13767c478bd9Sstevel@tonic-gate static int 13777c478bd9Sstevel@tonic-gate ln_ace4_to_aent(nfsace4 *ace4, int n, 13787c478bd9Sstevel@tonic-gate uid_t owner, gid_t group, 13797c478bd9Sstevel@tonic-gate aclent_t **aclentp, int *aclcnt, 13807c478bd9Sstevel@tonic-gate aclent_t **dfaclentp, int *dfaclcnt, 1381*e913d9ecSLisa Week int isdir, int isserver) 13827c478bd9Sstevel@tonic-gate { 13837c478bd9Sstevel@tonic-gate int error = 0; 13847c478bd9Sstevel@tonic-gate nfsace4 *ace4p; 13857c478bd9Sstevel@tonic-gate acemask4 bits; 13867c478bd9Sstevel@tonic-gate int i; 13877c478bd9Sstevel@tonic-gate ace4_list_t *normacl = NULL, *dfacl = NULL, *acl; 13887c478bd9Sstevel@tonic-gate ace4vals_t *vals; 13897c478bd9Sstevel@tonic-gate 13907c478bd9Sstevel@tonic-gate *aclentp = NULL; 13917c478bd9Sstevel@tonic-gate *aclcnt = 0; 13927c478bd9Sstevel@tonic-gate *dfaclentp = NULL; 13937c478bd9Sstevel@tonic-gate *dfaclcnt = 0; 13947c478bd9Sstevel@tonic-gate 13957c478bd9Sstevel@tonic-gate /* we need at least user_obj, group_obj, and other_obj */ 13967c478bd9Sstevel@tonic-gate if (n < 6) { 13977c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 13987c478bd9Sstevel@tonic-gate "ln_ace4_to_aent: too few nfsace4 entries: %d", n)); 13997c478bd9Sstevel@tonic-gate error = ENOTSUP; 14007c478bd9Sstevel@tonic-gate goto out; 14017c478bd9Sstevel@tonic-gate } 14027c478bd9Sstevel@tonic-gate if (ace4 == NULL) { 14037c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 14047c478bd9Sstevel@tonic-gate "ln_ace4_to_aent: NULL source")); 14057c478bd9Sstevel@tonic-gate error = EINVAL; 14067c478bd9Sstevel@tonic-gate goto out; 14077c478bd9Sstevel@tonic-gate } 14087c478bd9Sstevel@tonic-gate 14097c478bd9Sstevel@tonic-gate normacl = kmem_cache_alloc(nfs4_ace4_list_cache, KM_SLEEP); 14107c478bd9Sstevel@tonic-gate ace4_list_init(normacl, 0); 14117c478bd9Sstevel@tonic-gate dfacl = kmem_cache_alloc(nfs4_ace4_list_cache, KM_SLEEP); 14127c478bd9Sstevel@tonic-gate ace4_list_init(dfacl, ACL_DEFAULT); 14137c478bd9Sstevel@tonic-gate 14147c478bd9Sstevel@tonic-gate /* process every nfsace4... */ 14157c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 14167c478bd9Sstevel@tonic-gate ace4p = &ace4[i]; 14177c478bd9Sstevel@tonic-gate 14187c478bd9Sstevel@tonic-gate /* rule out certain cases quickly */ 14197c478bd9Sstevel@tonic-gate error = ace4_to_aent_legal(ace4p, isserver); 14207c478bd9Sstevel@tonic-gate if (error != 0) 14217c478bd9Sstevel@tonic-gate goto out; 14227c478bd9Sstevel@tonic-gate 14237c478bd9Sstevel@tonic-gate /* 14247c478bd9Sstevel@tonic-gate * Turn off these bits in order to not have to worry about 14257c478bd9Sstevel@tonic-gate * them when doing the checks for compliments. 14267c478bd9Sstevel@tonic-gate */ 14277c478bd9Sstevel@tonic-gate ace4p->access_mask &= ~(ACE4_WRITE_OWNER | ACE4_DELETE | 14287c478bd9Sstevel@tonic-gate ACE4_SYNCHRONIZE | ACE4_WRITE_ATTRIBUTES | 14297c478bd9Sstevel@tonic-gate ACE4_READ_NAMED_ATTRS | ACE4_WRITE_NAMED_ATTRS); 14307c478bd9Sstevel@tonic-gate 14317c478bd9Sstevel@tonic-gate /* see if this should be a regular or default acl */ 14327c478bd9Sstevel@tonic-gate bits = ace4p->flag & 14337c478bd9Sstevel@tonic-gate (ACE4_INHERIT_ONLY_ACE | 14347c478bd9Sstevel@tonic-gate ACE4_FILE_INHERIT_ACE | 14357c478bd9Sstevel@tonic-gate ACE4_DIRECTORY_INHERIT_ACE); 14367c478bd9Sstevel@tonic-gate if (bits != 0) { 14377c478bd9Sstevel@tonic-gate /* all or nothing on these inherit bits */ 14387c478bd9Sstevel@tonic-gate if (bits != (ACE4_INHERIT_ONLY_ACE | 14397c478bd9Sstevel@tonic-gate ACE4_FILE_INHERIT_ACE | 14407c478bd9Sstevel@tonic-gate ACE4_DIRECTORY_INHERIT_ACE)) { 14417c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 14427c478bd9Sstevel@tonic-gate "ln_ace4_to_aent: bad inherit flags " 14437c478bd9Sstevel@tonic-gate "%x", bits)); 14447c478bd9Sstevel@tonic-gate error = ENOTSUP; 14457c478bd9Sstevel@tonic-gate goto out; 14467c478bd9Sstevel@tonic-gate } 14477c478bd9Sstevel@tonic-gate acl = dfacl; 14487c478bd9Sstevel@tonic-gate } else { 14497c478bd9Sstevel@tonic-gate acl = normacl; 14507c478bd9Sstevel@tonic-gate } 14517c478bd9Sstevel@tonic-gate 14527c478bd9Sstevel@tonic-gate if ((ace4p->who.utf8string_len == 6) && 14537c478bd9Sstevel@tonic-gate (bcmp(ACE4_WHO_OWNER, 14547c478bd9Sstevel@tonic-gate ace4p->who.utf8string_val, 6) == 0)) { 14557c478bd9Sstevel@tonic-gate if (acl->state > ace4_user_obj) { 14567c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 14577c478bd9Sstevel@tonic-gate "ln_ace4_to_aent: OWNER@ found " 14587c478bd9Sstevel@tonic-gate "out of order")); 14597c478bd9Sstevel@tonic-gate error = ENOTSUP; 14607c478bd9Sstevel@tonic-gate goto out; 14617c478bd9Sstevel@tonic-gate } 14627c478bd9Sstevel@tonic-gate acl->state = ace4_user_obj; 14637c478bd9Sstevel@tonic-gate acl->seen |= USER_OBJ; 14647c478bd9Sstevel@tonic-gate vals = &acl->user_obj; 14657c478bd9Sstevel@tonic-gate vals->aent_type = USER_OBJ | acl->dfacl_flag; 14667c478bd9Sstevel@tonic-gate } else if ((ace4p->who.utf8string_len == 9) && 14677c478bd9Sstevel@tonic-gate (bcmp(ACE4_WHO_EVERYONE, ace4p->who.utf8string_val, 9) 14687c478bd9Sstevel@tonic-gate == 0)) { 14697c478bd9Sstevel@tonic-gate acl->state = ace4_other_obj; 14707c478bd9Sstevel@tonic-gate acl->seen |= OTHER_OBJ; 14717c478bd9Sstevel@tonic-gate vals = &acl->other_obj; 14727c478bd9Sstevel@tonic-gate vals->aent_type = OTHER_OBJ | acl->dfacl_flag; 1473354a1801Ssamf } else if ((ace4p->who.utf8string_len == 6) && 1474354a1801Ssamf (bcmp(ACE4_WHO_GROUP, ace4p->who.utf8string_val, 6) == 0)) { 1475354a1801Ssamf if (acl->state > ace4_group) { 1476354a1801Ssamf NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1477354a1801Ssamf "ln_ace4_to_aent: group entry found " 1478354a1801Ssamf "out of order")); 1479354a1801Ssamf error = ENOTSUP; 1480354a1801Ssamf goto out; 1481354a1801Ssamf } 1482354a1801Ssamf acl->seen |= GROUP_OBJ; 1483354a1801Ssamf vals = &acl->group_obj; 1484354a1801Ssamf vals->aent_type = GROUP_OBJ | acl->dfacl_flag; 1485354a1801Ssamf acl->state = ace4_group; 14867c478bd9Sstevel@tonic-gate } else if (ace4p->flag & ACE4_IDENTIFIER_GROUP) { 14877c478bd9Sstevel@tonic-gate if (acl->state > ace4_group) { 14887c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 14897c478bd9Sstevel@tonic-gate "ln_ace4_to_aent: group entry found " 14907c478bd9Sstevel@tonic-gate "out of order")); 14917c478bd9Sstevel@tonic-gate error = ENOTSUP; 14927c478bd9Sstevel@tonic-gate goto out; 14937c478bd9Sstevel@tonic-gate } 14947c478bd9Sstevel@tonic-gate acl->seen |= GROUP; 14957c478bd9Sstevel@tonic-gate vals = ace4vals_find(ace4p, &acl->group, 14967c478bd9Sstevel@tonic-gate &acl->numgroups); 14977c478bd9Sstevel@tonic-gate vals->aent_type = GROUP | acl->dfacl_flag; 14987c478bd9Sstevel@tonic-gate acl->state = ace4_group; 14997c478bd9Sstevel@tonic-gate } else { 15007c478bd9Sstevel@tonic-gate if (acl->state > ace4_user) { 15017c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 15027c478bd9Sstevel@tonic-gate "ln_ace4_to_aent: user entry found " 15037c478bd9Sstevel@tonic-gate "out of order")); 15047c478bd9Sstevel@tonic-gate error = ENOTSUP; 15057c478bd9Sstevel@tonic-gate goto out; 15067c478bd9Sstevel@tonic-gate } 15077c478bd9Sstevel@tonic-gate acl->state = ace4_user; 15087c478bd9Sstevel@tonic-gate acl->seen |= USER; 15097c478bd9Sstevel@tonic-gate vals = ace4vals_find(ace4p, &acl->user, 15107c478bd9Sstevel@tonic-gate &acl->numusers); 15117c478bd9Sstevel@tonic-gate vals->aent_type = USER | acl->dfacl_flag; 15127c478bd9Sstevel@tonic-gate } 15137c478bd9Sstevel@tonic-gate ASSERT(acl->state > ace4_unused); 15147c478bd9Sstevel@tonic-gate 15157c478bd9Sstevel@tonic-gate if (ace4p->type == ACE4_ACCESS_ALLOWED_ACE_TYPE) { 15167c478bd9Sstevel@tonic-gate /* no more than one allowed per aclent_t */ 15177c478bd9Sstevel@tonic-gate if (vals->allowed != ACE4_MASK_UNDEFINED) { 15187c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 15197c478bd9Sstevel@tonic-gate "ln_ace4_to_aent: too many ALLOWs " 15207c478bd9Sstevel@tonic-gate "for one entity")); 15217c478bd9Sstevel@tonic-gate error = ENOTSUP; 15227c478bd9Sstevel@tonic-gate goto out; 15237c478bd9Sstevel@tonic-gate } 15247c478bd9Sstevel@tonic-gate vals->allowed = ace4p->access_mask; 15257c478bd9Sstevel@tonic-gate } else { 15267c478bd9Sstevel@tonic-gate /* 15277c478bd9Sstevel@tonic-gate * it's a DENY; if there was a previous DENY, it 15287c478bd9Sstevel@tonic-gate * must have been an ACL_MASK. 15297c478bd9Sstevel@tonic-gate */ 15307c478bd9Sstevel@tonic-gate if (vals->denied != ACE4_MASK_UNDEFINED) { 15317c478bd9Sstevel@tonic-gate /* ACL_MASK is for USER and GROUP only */ 15327c478bd9Sstevel@tonic-gate if ((acl->state != ace4_user) && 15337c478bd9Sstevel@tonic-gate (acl->state != ace4_group)) { 15347c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 15357c478bd9Sstevel@tonic-gate "ln_ace4_to_aent: ACL_MASK-like " 15367c478bd9Sstevel@tonic-gate "DENY found on non-user/non-group " 15377c478bd9Sstevel@tonic-gate "entity")); 15387c478bd9Sstevel@tonic-gate error = ENOTSUP; 15397c478bd9Sstevel@tonic-gate goto out; 15407c478bd9Sstevel@tonic-gate } 15417c478bd9Sstevel@tonic-gate 15427c478bd9Sstevel@tonic-gate if (! acl->hasmask) { 15437c478bd9Sstevel@tonic-gate acl->hasmask = 1; 15447c478bd9Sstevel@tonic-gate acl->acl_mask = vals->denied; 15457c478bd9Sstevel@tonic-gate /* check for mismatched ACL_MASK emulations */ 15467c478bd9Sstevel@tonic-gate } else if (acl->acl_mask != vals->denied) { 15477c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 15487c478bd9Sstevel@tonic-gate "ln_ace4_to_aent: ACL_MASK " 15497c478bd9Sstevel@tonic-gate "mismatch")); 15507c478bd9Sstevel@tonic-gate error = ENOTSUP; 15517c478bd9Sstevel@tonic-gate goto out; 15527c478bd9Sstevel@tonic-gate } 15537c478bd9Sstevel@tonic-gate vals->mask = vals->denied; 15547c478bd9Sstevel@tonic-gate } 15557c478bd9Sstevel@tonic-gate vals->denied = ace4p->access_mask; 15567c478bd9Sstevel@tonic-gate } 15577c478bd9Sstevel@tonic-gate } 15587c478bd9Sstevel@tonic-gate 15597c478bd9Sstevel@tonic-gate /* done collating; produce the aclent_t lists */ 15607c478bd9Sstevel@tonic-gate if (normacl->state != ace4_unused) { 15617c478bd9Sstevel@tonic-gate error = ace4_list_to_aent(normacl, aclentp, aclcnt, 1562*e913d9ecSLisa Week owner, group, isdir, isserver); 15637c478bd9Sstevel@tonic-gate if (error != 0) 15647c478bd9Sstevel@tonic-gate goto out; 15657c478bd9Sstevel@tonic-gate } 15667c478bd9Sstevel@tonic-gate if (dfacl->state != ace4_unused) { 15677c478bd9Sstevel@tonic-gate error = ace4_list_to_aent(dfacl, dfaclentp, dfaclcnt, 1568*e913d9ecSLisa Week owner, group, isdir, isserver); 15697c478bd9Sstevel@tonic-gate if (error != 0) 15707c478bd9Sstevel@tonic-gate goto out; 15717c478bd9Sstevel@tonic-gate } 15727c478bd9Sstevel@tonic-gate 15737c478bd9Sstevel@tonic-gate out: 15747c478bd9Sstevel@tonic-gate if (normacl != NULL) 15757c478bd9Sstevel@tonic-gate ace4_list_free(normacl); 15767c478bd9Sstevel@tonic-gate if (dfacl != NULL) 15777c478bd9Sstevel@tonic-gate ace4_list_free(dfacl); 15787c478bd9Sstevel@tonic-gate 15797c478bd9Sstevel@tonic-gate return (error); 15807c478bd9Sstevel@tonic-gate } 15817c478bd9Sstevel@tonic-gate 15827c478bd9Sstevel@tonic-gate /* 15837c478bd9Sstevel@tonic-gate * Convert an NFSv4 ACL (in a vsecattr_t) to a POSIX draft ACL, following 15847c478bd9Sstevel@tonic-gate * the semantics of NFSv4_to_POSIX.html. Contact fsh-group@sun.com to 15857c478bd9Sstevel@tonic-gate * obtain this document. 15867c478bd9Sstevel@tonic-gate */ 15877c478bd9Sstevel@tonic-gate int 15887c478bd9Sstevel@tonic-gate vs_ace4_to_aent(vsecattr_t *vs_ace4, vsecattr_t *vs_aent, 1589*e913d9ecSLisa Week uid_t owner, gid_t group, int isdir, int isserver) 15907c478bd9Sstevel@tonic-gate { 15917c478bd9Sstevel@tonic-gate int error = 0; 15927c478bd9Sstevel@tonic-gate 15937c478bd9Sstevel@tonic-gate error = ln_ace4_to_aent(vs_ace4->vsa_aclentp, vs_ace4->vsa_aclcnt, 15947c478bd9Sstevel@tonic-gate owner, group, 15957c478bd9Sstevel@tonic-gate (aclent_t **)&vs_aent->vsa_aclentp, &vs_aent->vsa_aclcnt, 15967c478bd9Sstevel@tonic-gate (aclent_t **)&vs_aent->vsa_dfaclentp, &vs_aent->vsa_dfaclcnt, 1597*e913d9ecSLisa Week isdir, isserver); 15987c478bd9Sstevel@tonic-gate if (error != 0) 15997c478bd9Sstevel@tonic-gate goto out; 16007c478bd9Sstevel@tonic-gate 16017c478bd9Sstevel@tonic-gate vs_aent->vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL | VSA_DFACLCNT; 16027c478bd9Sstevel@tonic-gate if ((vs_aent->vsa_aclcnt == 0) && (vs_aent->vsa_dfaclcnt == 0)) { 16037c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 16047c478bd9Sstevel@tonic-gate "vs_ace4_to_aent: neither ACL nor default ACL found")); 16057c478bd9Sstevel@tonic-gate error = ENOTSUP; 16067c478bd9Sstevel@tonic-gate goto out; 16077c478bd9Sstevel@tonic-gate } 16087c478bd9Sstevel@tonic-gate 16097c478bd9Sstevel@tonic-gate out: 16107c478bd9Sstevel@tonic-gate if (error != 0) { 16117c478bd9Sstevel@tonic-gate if (vs_aent != NULL) 16127c478bd9Sstevel@tonic-gate vs_aent_destroy(vs_aent); 16137c478bd9Sstevel@tonic-gate } 16147c478bd9Sstevel@tonic-gate 16157c478bd9Sstevel@tonic-gate return (error); 16167c478bd9Sstevel@tonic-gate } 16177c478bd9Sstevel@tonic-gate 16187c478bd9Sstevel@tonic-gate /* 16197c478bd9Sstevel@tonic-gate * compare two ace4 acls 16207c478bd9Sstevel@tonic-gate */ 16217c478bd9Sstevel@tonic-gate 16227c478bd9Sstevel@tonic-gate static int 16237c478bd9Sstevel@tonic-gate ace4_cmp(nfsace4 *a, nfsace4 *b) 16247c478bd9Sstevel@tonic-gate { 16257c478bd9Sstevel@tonic-gate if (a->type < b->type) 16267c478bd9Sstevel@tonic-gate return (-1); 16277c478bd9Sstevel@tonic-gate if (a->type > b->type) 16287c478bd9Sstevel@tonic-gate return (1); 16297c478bd9Sstevel@tonic-gate if (a->flag < b->flag) 16307c478bd9Sstevel@tonic-gate return (-1); 16317c478bd9Sstevel@tonic-gate if (a->flag > b->flag) 16327c478bd9Sstevel@tonic-gate return (1); 16337c478bd9Sstevel@tonic-gate if (a->access_mask < b->access_mask) 16347c478bd9Sstevel@tonic-gate return (-1); 16357c478bd9Sstevel@tonic-gate if (a->access_mask > b->access_mask) 16367c478bd9Sstevel@tonic-gate return (1); 16377c478bd9Sstevel@tonic-gate return (utf8_compare(&a->who, &b->who)); 16387c478bd9Sstevel@tonic-gate } 16397c478bd9Sstevel@tonic-gate 16407c478bd9Sstevel@tonic-gate int 16417c478bd9Sstevel@tonic-gate ln_ace4_cmp(nfsace4 *a, nfsace4* b, int n) 16427c478bd9Sstevel@tonic-gate { 16437c478bd9Sstevel@tonic-gate int rc; 16447c478bd9Sstevel@tonic-gate int i; 16457c478bd9Sstevel@tonic-gate 16467c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 16477c478bd9Sstevel@tonic-gate rc = ace4_cmp(a + i, b + i); 16487c478bd9Sstevel@tonic-gate if (rc != 0) 16497c478bd9Sstevel@tonic-gate return (rc); 16507c478bd9Sstevel@tonic-gate } 16517c478bd9Sstevel@tonic-gate return (0); 16527c478bd9Sstevel@tonic-gate } 16537c478bd9Sstevel@tonic-gate 16547c478bd9Sstevel@tonic-gate /* 16557c478bd9Sstevel@tonic-gate * Convert an ace_t to an nfsace4; the primary difference being 16567c478bd9Sstevel@tonic-gate * strings versus integer uid/gids. 16577c478bd9Sstevel@tonic-gate */ 16587c478bd9Sstevel@tonic-gate static int 1659fa9e4066Sahrens acet_to_ace4(ace_t *ace, nfsace4 *nfsace4, int isserver) 16607c478bd9Sstevel@tonic-gate { 16617c478bd9Sstevel@tonic-gate int error = 0; 16627c478bd9Sstevel@tonic-gate 16637c478bd9Sstevel@tonic-gate if (ace == NULL) { 16647c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 16657c478bd9Sstevel@tonic-gate "acet_to_ace4: NULL source")); 16667c478bd9Sstevel@tonic-gate error = EINVAL; 16677c478bd9Sstevel@tonic-gate goto out; 16687c478bd9Sstevel@tonic-gate } 16697c478bd9Sstevel@tonic-gate if (nfsace4 == NULL) { 16707c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 16717c478bd9Sstevel@tonic-gate "acet_to_ace4: NULL destination")); 16727c478bd9Sstevel@tonic-gate error = EINVAL; 16737c478bd9Sstevel@tonic-gate goto out; 16747c478bd9Sstevel@tonic-gate } 16757c478bd9Sstevel@tonic-gate 16767c478bd9Sstevel@tonic-gate switch (ace->a_type) { 1677fa9e4066Sahrens case ACE_ACCESS_ALLOWED_ACE_TYPE: 16787c478bd9Sstevel@tonic-gate nfsace4->type = ACE4_ACCESS_ALLOWED_ACE_TYPE; 16797c478bd9Sstevel@tonic-gate break; 1680fa9e4066Sahrens case ACE_ACCESS_DENIED_ACE_TYPE: 16817c478bd9Sstevel@tonic-gate nfsace4->type = ACE4_ACCESS_DENIED_ACE_TYPE; 16827c478bd9Sstevel@tonic-gate break; 16837c478bd9Sstevel@tonic-gate default: 1684fa9e4066Sahrens NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1685fa9e4066Sahrens "acet_to_ace4: unsupported type: %x", ace->a_type)); 16867c478bd9Sstevel@tonic-gate error = ENOTSUP; 16877c478bd9Sstevel@tonic-gate break; 16887c478bd9Sstevel@tonic-gate } 16897c478bd9Sstevel@tonic-gate if (error != 0) 16907c478bd9Sstevel@tonic-gate goto out; 16917c478bd9Sstevel@tonic-gate 1692fa9e4066Sahrens acet_mask_to_ace4_mask(ace->a_access_mask, &nfsace4->access_mask); 1693fa9e4066Sahrens acet_flags_to_ace4_flags(ace->a_flags, &nfsace4->flag); 16947c478bd9Sstevel@tonic-gate 1695fa9e4066Sahrens if (ace->a_flags & ACE_GROUP) { 16967c478bd9Sstevel@tonic-gate nfsace4->flag |= ACE4_IDENTIFIER_GROUP; 16977c478bd9Sstevel@tonic-gate (void) str_to_utf8(ACE4_WHO_GROUP, &nfsace4->who); 1698fa9e4066Sahrens } else if (ace->a_flags & ACE_IDENTIFIER_GROUP) { 1699fa9e4066Sahrens nfsace4->flag |= ACE4_IDENTIFIER_GROUP; 1700*e913d9ecSLisa Week /* 1701*e913d9ecSLisa Week * On the client, we do not allow an ACL with ACEs containing 1702*e913d9ecSLisa Week * the "unknown"/GID_UNKNOWN group to be set. This is because 1703*e913d9ecSLisa Week * it having GID_UNKNOWN in an ACE can only come from 1704*e913d9ecSLisa Week * the user having done a read-modify-write ACL manipulation 1705*e913d9ecSLisa Week * (e.g. setfacl -m or chmod A+) when there was an ACE with 1706*e913d9ecSLisa Week * an unmappable group already present. 1707*e913d9ecSLisa Week */ 1708*e913d9ecSLisa Week if (ace->a_who == GID_UNKNOWN && !isserver) { 1709*e913d9ecSLisa Week DTRACE_PROBE(nfs4clnt__err__acl__gid__unknown); 1710*e913d9ecSLisa Week NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1711*e913d9ecSLisa Week "acet_to_ace4: GID_UNKNOWN is not allowed in " 1712*e913d9ecSLisa Week "the ACL")); 1713*e913d9ecSLisa Week error = EACCES; 1714*e913d9ecSLisa Week goto out; 1715*e913d9ecSLisa Week } 1716fa9e4066Sahrens error = nfs_idmap_gid_str(ace->a_who, &nfsace4->who, isserver); 17177c478bd9Sstevel@tonic-gate if (error != 0) 17187c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 17197c478bd9Sstevel@tonic-gate "acet_to_ace4: idmap failed with %d", error)); 1720fa9e4066Sahrens } else if (ace->a_flags & ACE_OWNER) { 1721fa9e4066Sahrens (void) str_to_utf8(ACE4_WHO_OWNER, &nfsace4->who); 1722fa9e4066Sahrens } else if (ace->a_flags & ACE_EVERYONE) { 1723fa9e4066Sahrens (void) str_to_utf8(ACE4_WHO_EVERYONE, &nfsace4->who); 1724fa9e4066Sahrens } else { 1725*e913d9ecSLisa Week /* 1726*e913d9ecSLisa Week * Same rule as GID_UNKNOWN (above). 1727*e913d9ecSLisa Week */ 1728*e913d9ecSLisa Week if (ace->a_who == UID_UNKNOWN && !isserver) { 1729*e913d9ecSLisa Week DTRACE_PROBE(nfs4clnt__err__acl__uid__unknown); 1730*e913d9ecSLisa Week NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1731*e913d9ecSLisa Week "acet_to_ace4: UID_UNKNOWN is not allowed in " 1732*e913d9ecSLisa Week "the ACL")); 1733*e913d9ecSLisa Week error = EACCES; 1734*e913d9ecSLisa Week goto out; 1735*e913d9ecSLisa Week } 1736fa9e4066Sahrens error = nfs_idmap_uid_str(ace->a_who, &nfsace4->who, isserver); 1737fa9e4066Sahrens if (error != 0) 1738fa9e4066Sahrens NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1739fa9e4066Sahrens "acet_to_ace4: idmap failed with %d", error)); 1740fa9e4066Sahrens } 17417c478bd9Sstevel@tonic-gate 1742fa9e4066Sahrens out: 17437c478bd9Sstevel@tonic-gate return (error); 17447c478bd9Sstevel@tonic-gate } 17457c478bd9Sstevel@tonic-gate 17467c478bd9Sstevel@tonic-gate /* 17477c478bd9Sstevel@tonic-gate * Convert an nfsace4 to an ace_t, the primary difference being 17487c478bd9Sstevel@tonic-gate * integer uid/gids versus strings. 17497c478bd9Sstevel@tonic-gate */ 17507c478bd9Sstevel@tonic-gate static int 17517c478bd9Sstevel@tonic-gate ace4_to_acet(nfsace4 *nfsace4, ace_t *ace, uid_t owner, gid_t group, 1752*e913d9ecSLisa Week int isserver) 17537c478bd9Sstevel@tonic-gate { 17547c478bd9Sstevel@tonic-gate int error = 0; 17557c478bd9Sstevel@tonic-gate 17567c478bd9Sstevel@tonic-gate if (nfsace4 == NULL) { 17577c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 17587c478bd9Sstevel@tonic-gate "ace4_to_acet: NULL source")); 17597c478bd9Sstevel@tonic-gate return (EINVAL); 17607c478bd9Sstevel@tonic-gate } 17617c478bd9Sstevel@tonic-gate if (ace == NULL) { 17627c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 17637c478bd9Sstevel@tonic-gate "ace4_to_acet: NULL destination")); 17647c478bd9Sstevel@tonic-gate return (EINVAL); 17657c478bd9Sstevel@tonic-gate } 17667c478bd9Sstevel@tonic-gate 17677c478bd9Sstevel@tonic-gate switch (nfsace4->type) { 17687c478bd9Sstevel@tonic-gate case ACE4_ACCESS_ALLOWED_ACE_TYPE: 1769fa9e4066Sahrens ace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; 17707c478bd9Sstevel@tonic-gate break; 17717c478bd9Sstevel@tonic-gate case ACE4_ACCESS_DENIED_ACE_TYPE: 1772fa9e4066Sahrens ace->a_type = ACE_ACCESS_DENIED_ACE_TYPE; 17737c478bd9Sstevel@tonic-gate break; 17747c478bd9Sstevel@tonic-gate default: 1775fa9e4066Sahrens NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1776fa9e4066Sahrens "ace4_to_acet: unsupported type: %x", nfsace4->type)); 17777c478bd9Sstevel@tonic-gate error = ENOTSUP; 17787c478bd9Sstevel@tonic-gate break; 17797c478bd9Sstevel@tonic-gate } 17807c478bd9Sstevel@tonic-gate if (error != 0) 17817c478bd9Sstevel@tonic-gate goto out; 17827c478bd9Sstevel@tonic-gate 17837c478bd9Sstevel@tonic-gate if (nfsace4->flag & ~(ACE4_VALID_FLAG_BITS)) { 17847c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 17857c478bd9Sstevel@tonic-gate "ace4_to_acet: invalid flags: %x", nfsace4->flag)); 17867c478bd9Sstevel@tonic-gate error = EINVAL; 17877c478bd9Sstevel@tonic-gate goto out; 17887c478bd9Sstevel@tonic-gate } 17897c478bd9Sstevel@tonic-gate 17907c478bd9Sstevel@tonic-gate /* check for invalid masks */ 17917c478bd9Sstevel@tonic-gate if (nfsace4->access_mask & ~(ACE4_VALID_MASK_BITS)) { 17927c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 17937c478bd9Sstevel@tonic-gate "ace4_to_acet: invalid mask: %x", nfsace4->access_mask)); 17947c478bd9Sstevel@tonic-gate error = EINVAL; 17957c478bd9Sstevel@tonic-gate goto out; 17967c478bd9Sstevel@tonic-gate } 17977c478bd9Sstevel@tonic-gate 1798fa9e4066Sahrens ace4_mask_to_acet_mask(nfsace4->access_mask, &ace->a_access_mask); 1799fa9e4066Sahrens 1800fa9e4066Sahrens if (nfsace4->flag & ~ACE_NFSV4_SUP_FLAGS) { 1801fa9e4066Sahrens NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1802fa9e4066Sahrens "ace4_to_acet: unsupported flags: %x", nfsace4->flag)); 18037c478bd9Sstevel@tonic-gate error = ENOTSUP; 18047c478bd9Sstevel@tonic-gate goto out; 18057c478bd9Sstevel@tonic-gate } 1806fa9e4066Sahrens ace4_flags_to_acet_flags(nfsace4->flag, &ace->a_flags); 18077c478bd9Sstevel@tonic-gate 18087c478bd9Sstevel@tonic-gate if ((nfsace4->who.utf8string_len == 6) && 18097c478bd9Sstevel@tonic-gate (bcmp(ACE4_WHO_GROUP, 18107c478bd9Sstevel@tonic-gate nfsace4->who.utf8string_val, 6)) == 0) { 18117c478bd9Sstevel@tonic-gate ace->a_who = group; 1812354a1801Ssamf ace->a_flags |= ACE_GROUP | ACE_IDENTIFIER_GROUP; 1813354a1801Ssamf } else if ((nfsace4->who.utf8string_len == 6) && 1814354a1801Ssamf (bcmp(ACE4_WHO_OWNER, 1815354a1801Ssamf nfsace4->who.utf8string_val, 6) == 0)) { 1816354a1801Ssamf ace->a_flags |= ACE_OWNER; 1817354a1801Ssamf ace->a_who = owner; 1818354a1801Ssamf } else if ((nfsace4->who.utf8string_len == 9) && 1819354a1801Ssamf (bcmp(ACE4_WHO_EVERYONE, 1820354a1801Ssamf nfsace4->who.utf8string_val, 9) == 0)) { 1821354a1801Ssamf ace->a_flags |= ACE_EVERYONE; 1822354a1801Ssamf ace->a_who = 0; 1823354a1801Ssamf } else if (nfsace4->flag & ACE4_IDENTIFIER_GROUP) { 1824fa9e4066Sahrens ace->a_flags |= ACE_IDENTIFIER_GROUP; 18257c478bd9Sstevel@tonic-gate error = nfs_idmap_str_gid(&nfsace4->who, 18267c478bd9Sstevel@tonic-gate &ace->a_who, isserver); 18277c478bd9Sstevel@tonic-gate if (error != 0) { 18287c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 18297c478bd9Sstevel@tonic-gate "ace4_to_acet: idmap failed with %d", 18307c478bd9Sstevel@tonic-gate error)); 18317c478bd9Sstevel@tonic-gate if (isserver && (error == EPERM)) 18327c478bd9Sstevel@tonic-gate error = NFS4ERR_BADOWNER; 18337c478bd9Sstevel@tonic-gate goto out; 18347c478bd9Sstevel@tonic-gate } 18357c478bd9Sstevel@tonic-gate error = validate_idmapping(&nfsace4->who, 1836*e913d9ecSLisa Week &ace->a_who, FALSE, isserver); 1837354a1801Ssamf if (error != 0) 18387c478bd9Sstevel@tonic-gate goto out; 18397c478bd9Sstevel@tonic-gate } else { 18407c478bd9Sstevel@tonic-gate error = nfs_idmap_str_uid(&nfsace4->who, 18417c478bd9Sstevel@tonic-gate &ace->a_who, isserver); 18427c478bd9Sstevel@tonic-gate if (error != 0) { 18437c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 18447c478bd9Sstevel@tonic-gate "ace4_to_acet: idmap failed with %d", 18457c478bd9Sstevel@tonic-gate error)); 18467c478bd9Sstevel@tonic-gate if (isserver && (error == EPERM)) 18477c478bd9Sstevel@tonic-gate error = NFS4ERR_BADOWNER; 18487c478bd9Sstevel@tonic-gate goto out; 18497c478bd9Sstevel@tonic-gate } 18507c478bd9Sstevel@tonic-gate error = validate_idmapping(&nfsace4->who, 1851*e913d9ecSLisa Week &ace->a_who, TRUE, isserver); 1852354a1801Ssamf if (error != 0) 18537c478bd9Sstevel@tonic-gate goto out; 18547c478bd9Sstevel@tonic-gate } 18557c478bd9Sstevel@tonic-gate 18567c478bd9Sstevel@tonic-gate out: 18577c478bd9Sstevel@tonic-gate return (error); 18587c478bd9Sstevel@tonic-gate } 18597c478bd9Sstevel@tonic-gate 1860fa9e4066Sahrens static void 1861fa9e4066Sahrens ace4_mask_to_acet_mask(acemask4 ace4_mask, uint32_t *acet_mask) 1862fa9e4066Sahrens { 1863fa9e4066Sahrens *acet_mask = 0; 1864fa9e4066Sahrens 1865fa9e4066Sahrens if (ace4_mask & ACE4_READ_DATA) 1866fa9e4066Sahrens *acet_mask |= ACE_READ_DATA; 1867fa9e4066Sahrens if (ace4_mask & ACE4_WRITE_DATA) 1868fa9e4066Sahrens *acet_mask |= ACE_WRITE_DATA; 1869fa9e4066Sahrens if (ace4_mask & ACE4_APPEND_DATA) 1870fa9e4066Sahrens *acet_mask |= ACE_APPEND_DATA; 1871fa9e4066Sahrens if (ace4_mask & ACE4_READ_NAMED_ATTRS) 1872fa9e4066Sahrens *acet_mask |= ACE_READ_NAMED_ATTRS; 1873fa9e4066Sahrens if (ace4_mask & ACE4_WRITE_NAMED_ATTRS) 1874fa9e4066Sahrens *acet_mask |= ACE_WRITE_NAMED_ATTRS; 1875fa9e4066Sahrens if (ace4_mask & ACE4_EXECUTE) 1876fa9e4066Sahrens *acet_mask |= ACE_EXECUTE; 1877fa9e4066Sahrens if (ace4_mask & ACE4_DELETE_CHILD) 1878fa9e4066Sahrens *acet_mask |= ACE_DELETE_CHILD; 1879fa9e4066Sahrens if (ace4_mask & ACE4_READ_ATTRIBUTES) 1880fa9e4066Sahrens *acet_mask |= ACE_READ_ATTRIBUTES; 1881fa9e4066Sahrens if (ace4_mask & ACE4_WRITE_ATTRIBUTES) 1882fa9e4066Sahrens *acet_mask |= ACE_WRITE_ATTRIBUTES; 1883fa9e4066Sahrens if (ace4_mask & ACE4_DELETE) 1884fa9e4066Sahrens *acet_mask |= ACE_DELETE; 1885fa9e4066Sahrens if (ace4_mask & ACE4_READ_ACL) 1886fa9e4066Sahrens *acet_mask |= ACE_READ_ACL; 1887fa9e4066Sahrens if (ace4_mask & ACE4_WRITE_ACL) 1888fa9e4066Sahrens *acet_mask |= ACE_WRITE_ACL; 1889fa9e4066Sahrens if (ace4_mask & ACE4_WRITE_OWNER) 1890fa9e4066Sahrens *acet_mask |= ACE_WRITE_OWNER; 1891fa9e4066Sahrens if (ace4_mask & ACE4_SYNCHRONIZE) 1892fa9e4066Sahrens *acet_mask |= ACE_SYNCHRONIZE; 1893fa9e4066Sahrens } 1894fa9e4066Sahrens 1895fa9e4066Sahrens static void 1896fa9e4066Sahrens acet_mask_to_ace4_mask(uint32_t acet_mask, acemask4 *ace4_mask) 1897fa9e4066Sahrens { 1898fa9e4066Sahrens *ace4_mask = 0; 1899fa9e4066Sahrens 1900fa9e4066Sahrens if (acet_mask & ACE_READ_DATA) 1901fa9e4066Sahrens *ace4_mask |= ACE4_READ_DATA; 1902fa9e4066Sahrens if (acet_mask & ACE_WRITE_DATA) 1903fa9e4066Sahrens *ace4_mask |= ACE4_WRITE_DATA; 1904fa9e4066Sahrens if (acet_mask & ACE_APPEND_DATA) 1905fa9e4066Sahrens *ace4_mask |= ACE_APPEND_DATA; 1906fa9e4066Sahrens if (acet_mask & ACE4_READ_NAMED_ATTRS) 1907fa9e4066Sahrens *ace4_mask |= ACE_READ_NAMED_ATTRS; 1908fa9e4066Sahrens if (acet_mask & ACE_WRITE_NAMED_ATTRS) 1909fa9e4066Sahrens *ace4_mask |= ACE4_WRITE_NAMED_ATTRS; 1910fa9e4066Sahrens if (acet_mask & ACE_EXECUTE) 1911fa9e4066Sahrens *ace4_mask |= ACE4_EXECUTE; 1912fa9e4066Sahrens if (acet_mask & ACE_DELETE_CHILD) 1913fa9e4066Sahrens *ace4_mask |= ACE4_DELETE_CHILD; 1914fa9e4066Sahrens if (acet_mask & ACE_READ_ATTRIBUTES) 1915fa9e4066Sahrens *ace4_mask |= ACE4_READ_ATTRIBUTES; 1916fa9e4066Sahrens if (acet_mask & ACE_WRITE_ATTRIBUTES) 1917fa9e4066Sahrens *ace4_mask |= ACE4_WRITE_ATTRIBUTES; 1918fa9e4066Sahrens if (acet_mask & ACE_DELETE) 1919fa9e4066Sahrens *ace4_mask |= ACE4_DELETE; 1920fa9e4066Sahrens if (acet_mask & ACE_READ_ACL) 1921fa9e4066Sahrens *ace4_mask |= ACE4_READ_ACL; 1922fa9e4066Sahrens if (acet_mask & ACE_WRITE_ACL) 1923fa9e4066Sahrens *ace4_mask |= ACE4_WRITE_ACL; 1924fa9e4066Sahrens if (acet_mask & ACE_WRITE_OWNER) 1925fa9e4066Sahrens *ace4_mask |= ACE4_WRITE_OWNER; 1926fa9e4066Sahrens if (acet_mask & ACE_SYNCHRONIZE) 1927fa9e4066Sahrens *ace4_mask |= ACE4_SYNCHRONIZE; 1928fa9e4066Sahrens } 1929fa9e4066Sahrens 1930fa9e4066Sahrens static void 1931fa9e4066Sahrens ace4_flags_to_acet_flags(aceflag4 ace4_flags, uint16_t *acet_flags) 1932fa9e4066Sahrens { 1933fa9e4066Sahrens *acet_flags = 0; 1934fa9e4066Sahrens 1935fa9e4066Sahrens if (ace4_flags & ACE4_FILE_INHERIT_ACE) 1936fa9e4066Sahrens *acet_flags |= ACE_FILE_INHERIT_ACE; 1937fa9e4066Sahrens if (ace4_flags & ACE4_DIRECTORY_INHERIT_ACE) 1938fa9e4066Sahrens *acet_flags |= ACE_DIRECTORY_INHERIT_ACE; 1939fa9e4066Sahrens if (ace4_flags & ACE4_NO_PROPAGATE_INHERIT_ACE) 1940fa9e4066Sahrens *acet_flags |= ACE_NO_PROPAGATE_INHERIT_ACE; 1941fa9e4066Sahrens if (ace4_flags & ACE4_INHERIT_ONLY_ACE) 1942fa9e4066Sahrens *acet_flags |= ACE_INHERIT_ONLY_ACE; 1943fa9e4066Sahrens if (ace4_flags & ACE4_SUCCESSFUL_ACCESS_ACE_FLAG) 1944fa9e4066Sahrens *acet_flags |= ACE_SUCCESSFUL_ACCESS_ACE_FLAG; 1945fa9e4066Sahrens if (ace4_flags & ACE4_FAILED_ACCESS_ACE_FLAG) 1946fa9e4066Sahrens *acet_flags |= ACE_FAILED_ACCESS_ACE_FLAG; 1947354a1801Ssamf /* ACE_IDENTIFIER_GROUP is handled in ace4_to_acet() */ 1948fa9e4066Sahrens } 1949fa9e4066Sahrens 1950fa9e4066Sahrens static void 1951fa9e4066Sahrens acet_flags_to_ace4_flags(uint16_t acet_flags, aceflag4 *ace4_flags) 1952fa9e4066Sahrens { 1953fa9e4066Sahrens *ace4_flags = 0; 1954fa9e4066Sahrens 1955fa9e4066Sahrens if (acet_flags & ACE_FILE_INHERIT_ACE) 1956fa9e4066Sahrens *ace4_flags |= ACE4_FILE_INHERIT_ACE; 1957fa9e4066Sahrens if (acet_flags & ACE_DIRECTORY_INHERIT_ACE) 1958fa9e4066Sahrens *ace4_flags |= ACE4_DIRECTORY_INHERIT_ACE; 1959fa9e4066Sahrens if (acet_flags & ACE_NO_PROPAGATE_INHERIT_ACE) 1960fa9e4066Sahrens *ace4_flags |= ACE4_NO_PROPAGATE_INHERIT_ACE; 1961fa9e4066Sahrens if (acet_flags & ACE_INHERIT_ONLY_ACE) 1962fa9e4066Sahrens *ace4_flags |= ACE4_INHERIT_ONLY_ACE; 1963fa9e4066Sahrens if (acet_flags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG) 1964fa9e4066Sahrens *ace4_flags |= ACE4_SUCCESSFUL_ACCESS_ACE_FLAG; 1965fa9e4066Sahrens if (acet_flags & ACE_FAILED_ACCESS_ACE_FLAG) 1966fa9e4066Sahrens *ace4_flags |= ACE4_FAILED_ACCESS_ACE_FLAG; 1967354a1801Ssamf /* ACE4_IDENTIFIER_GROUP is handled in acet_to_ace4() */ 1968fa9e4066Sahrens } 1969fa9e4066Sahrens 19707c478bd9Sstevel@tonic-gate int 19717c478bd9Sstevel@tonic-gate vs_ace4_to_acet(vsecattr_t *vs_ace4, vsecattr_t *vs_acet, 1972*e913d9ecSLisa Week uid_t owner, gid_t group, int isserver) 19737c478bd9Sstevel@tonic-gate { 19747c478bd9Sstevel@tonic-gate int error; 19757c478bd9Sstevel@tonic-gate int i; 19767c478bd9Sstevel@tonic-gate 19777c478bd9Sstevel@tonic-gate if ((vs_ace4->vsa_mask & (VSA_ACE | VSA_ACECNT)) != 19787c478bd9Sstevel@tonic-gate (VSA_ACE | VSA_ACECNT)) 19797c478bd9Sstevel@tonic-gate return (EINVAL); 19807c478bd9Sstevel@tonic-gate if (vs_ace4->vsa_aclcnt < 0) 19817c478bd9Sstevel@tonic-gate return (EINVAL); 19827c478bd9Sstevel@tonic-gate if ((vs_ace4->vsa_aclcnt == 0) || (vs_ace4->vsa_aclentp == NULL)) 19837c478bd9Sstevel@tonic-gate return (0); 19847c478bd9Sstevel@tonic-gate 1985da6c28aaSamw if (vs_ace4->vsa_aclcnt > 0) { 19867c478bd9Sstevel@tonic-gate vs_acet->vsa_aclentp = kmem_alloc(vs_ace4->vsa_aclcnt * 19877c478bd9Sstevel@tonic-gate sizeof (ace_t), KM_SLEEP); 1988da6c28aaSamw vs_acet->vsa_aclentsz = vs_ace4->vsa_aclcnt * sizeof (ace_t); 1989da6c28aaSamw } else 19907c478bd9Sstevel@tonic-gate vs_acet->vsa_aclentp = NULL; 19917c478bd9Sstevel@tonic-gate vs_acet->vsa_aclcnt = vs_ace4->vsa_aclcnt; 19927c478bd9Sstevel@tonic-gate vs_acet->vsa_mask = VSA_ACE | VSA_ACECNT; 19937c478bd9Sstevel@tonic-gate 19947c478bd9Sstevel@tonic-gate for (i = 0; i < vs_ace4->vsa_aclcnt; i++) { 19957c478bd9Sstevel@tonic-gate error = ace4_to_acet((nfsace4 *)(vs_ace4->vsa_aclentp) + i, 19967c478bd9Sstevel@tonic-gate (ace_t *)(vs_acet->vsa_aclentp) + i, owner, group, 1997*e913d9ecSLisa Week isserver); 19987c478bd9Sstevel@tonic-gate if (error != 0) 19997c478bd9Sstevel@tonic-gate goto out; 20007c478bd9Sstevel@tonic-gate } 20017c478bd9Sstevel@tonic-gate 20027c478bd9Sstevel@tonic-gate out: 20037c478bd9Sstevel@tonic-gate if (error != 0) 20047c478bd9Sstevel@tonic-gate vs_acet_destroy(vs_acet); 20057c478bd9Sstevel@tonic-gate 20067c478bd9Sstevel@tonic-gate return (error); 20077c478bd9Sstevel@tonic-gate } 20087c478bd9Sstevel@tonic-gate 20097c478bd9Sstevel@tonic-gate int 20107c478bd9Sstevel@tonic-gate vs_acet_to_ace4(vsecattr_t *vs_acet, vsecattr_t *vs_ace4, 2011fa9e4066Sahrens int isserver) 20127c478bd9Sstevel@tonic-gate { 20137c478bd9Sstevel@tonic-gate int error = 0; 20147c478bd9Sstevel@tonic-gate int i; 20157c478bd9Sstevel@tonic-gate 20167c478bd9Sstevel@tonic-gate if (! (vs_acet->vsa_mask & VSA_ACE)) { 20177c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 20187c478bd9Sstevel@tonic-gate "vs_acet_to_ace4: VSA_ACE missing from mask")); 20197c478bd9Sstevel@tonic-gate return (EINVAL); 20207c478bd9Sstevel@tonic-gate } 20217c478bd9Sstevel@tonic-gate 20227c478bd9Sstevel@tonic-gate if (vs_acet->vsa_aclcnt > 0) 20237c478bd9Sstevel@tonic-gate vs_ace4->vsa_aclentp = kmem_zalloc(vs_acet->vsa_aclcnt * 20247c478bd9Sstevel@tonic-gate sizeof (nfsace4), KM_SLEEP); 20257c478bd9Sstevel@tonic-gate else 20267c478bd9Sstevel@tonic-gate vs_ace4->vsa_aclentp = NULL; 20277c478bd9Sstevel@tonic-gate vs_ace4->vsa_aclcnt = vs_acet->vsa_aclcnt; 20287c478bd9Sstevel@tonic-gate vs_ace4->vsa_mask = VSA_ACE | VSA_ACECNT; 20297c478bd9Sstevel@tonic-gate 20307c478bd9Sstevel@tonic-gate for (i = 0; i < vs_acet->vsa_aclcnt; i++) { 20317c478bd9Sstevel@tonic-gate error = acet_to_ace4((ace_t *)(vs_acet->vsa_aclentp) + i, 2032fa9e4066Sahrens (nfsace4 *)(vs_ace4->vsa_aclentp) + i, isserver); 20337c478bd9Sstevel@tonic-gate if (error != 0) 20347c478bd9Sstevel@tonic-gate goto out; 20357c478bd9Sstevel@tonic-gate } 20367c478bd9Sstevel@tonic-gate 20377c478bd9Sstevel@tonic-gate out: 20387c478bd9Sstevel@tonic-gate if (error != 0) 20397c478bd9Sstevel@tonic-gate vs_ace4_destroy(vs_ace4); 20407c478bd9Sstevel@tonic-gate 20417c478bd9Sstevel@tonic-gate return (error); 20427c478bd9Sstevel@tonic-gate } 20437c478bd9Sstevel@tonic-gate 20447c478bd9Sstevel@tonic-gate void 20457c478bd9Sstevel@tonic-gate nfs4_acl_fill_cache(rnode4_t *rp, vsecattr_t *vsap) 20467c478bd9Sstevel@tonic-gate { 20477c478bd9Sstevel@tonic-gate size_t aclsize; 20487c478bd9Sstevel@tonic-gate vsecattr_t *rvsap; 20497c478bd9Sstevel@tonic-gate nfsace4 *tmp_ace4, *ace4; 20507c478bd9Sstevel@tonic-gate int i; 20517c478bd9Sstevel@tonic-gate 20527c478bd9Sstevel@tonic-gate mutex_enter(&rp->r_statelock); 20537c478bd9Sstevel@tonic-gate if (rp->r_secattr != NULL) 20547c478bd9Sstevel@tonic-gate rvsap = rp->r_secattr; 20557c478bd9Sstevel@tonic-gate else { 20567c478bd9Sstevel@tonic-gate rvsap = kmem_zalloc(sizeof (*rvsap), KM_NOSLEEP); 20577c478bd9Sstevel@tonic-gate if (rvsap == NULL) { 20587c478bd9Sstevel@tonic-gate mutex_exit(&rp->r_statelock); 20597c478bd9Sstevel@tonic-gate return; 20607c478bd9Sstevel@tonic-gate } 20617c478bd9Sstevel@tonic-gate rp->r_secattr = rvsap; 20627c478bd9Sstevel@tonic-gate } 20637c478bd9Sstevel@tonic-gate 20647c478bd9Sstevel@tonic-gate if (vsap->vsa_mask & VSA_ACE) { 20657c478bd9Sstevel@tonic-gate if (rvsap->vsa_aclentp != NULL) { 20667c478bd9Sstevel@tonic-gate if (rvsap->vsa_aclcnt != vsap->vsa_aclcnt) { 20677c478bd9Sstevel@tonic-gate vs_ace4_destroy(rvsap); 20687c478bd9Sstevel@tonic-gate rvsap->vsa_aclentp = NULL; 20697c478bd9Sstevel@tonic-gate } else { 20707c478bd9Sstevel@tonic-gate /* 20717c478bd9Sstevel@tonic-gate * The counts are equal so we don't have to 20727c478bd9Sstevel@tonic-gate * destroy the acl entries because we'd only 20737c478bd9Sstevel@tonic-gate * have to re-allocate them, but we do have to 20747c478bd9Sstevel@tonic-gate * destroy all of the who utf8strings. 20757c478bd9Sstevel@tonic-gate * The acl that we are now filling the cache 20767c478bd9Sstevel@tonic-gate * with may have the same amount of entries as 20777c478bd9Sstevel@tonic-gate * what is currently cached, but those entries 20787c478bd9Sstevel@tonic-gate * may not be the same. 20797c478bd9Sstevel@tonic-gate */ 20807c478bd9Sstevel@tonic-gate ace4 = (nfsace4 *) rvsap->vsa_aclentp; 20817c478bd9Sstevel@tonic-gate for (i = 0; i < rvsap->vsa_aclcnt; i++) { 20827c478bd9Sstevel@tonic-gate if (ace4[i].who.utf8string_val != NULL) 20837c478bd9Sstevel@tonic-gate kmem_free( 20847c478bd9Sstevel@tonic-gate ace4[i].who.utf8string_val, 20857c478bd9Sstevel@tonic-gate ace4[i].who.utf8string_len); 20867c478bd9Sstevel@tonic-gate } 20877c478bd9Sstevel@tonic-gate } 20887c478bd9Sstevel@tonic-gate } 20897c478bd9Sstevel@tonic-gate if (vsap->vsa_aclcnt > 0) { 20907c478bd9Sstevel@tonic-gate aclsize = vsap->vsa_aclcnt * sizeof (nfsace4); 20917c478bd9Sstevel@tonic-gate 20927c478bd9Sstevel@tonic-gate if (rvsap->vsa_aclentp == NULL) { 20937c478bd9Sstevel@tonic-gate rvsap->vsa_aclentp = kmem_alloc(aclsize, 20947c478bd9Sstevel@tonic-gate KM_SLEEP); 20957c478bd9Sstevel@tonic-gate } 20967c478bd9Sstevel@tonic-gate 20977c478bd9Sstevel@tonic-gate bcopy(vsap->vsa_aclentp, rvsap->vsa_aclentp, aclsize); 20987c478bd9Sstevel@tonic-gate 20997c478bd9Sstevel@tonic-gate tmp_ace4 = (nfsace4 *) vsap->vsa_aclentp; 21007c478bd9Sstevel@tonic-gate ace4 = (nfsace4 *) rvsap->vsa_aclentp; 21017c478bd9Sstevel@tonic-gate for (i = 0; i < vsap->vsa_aclcnt; i++) { 21027c478bd9Sstevel@tonic-gate (void) utf8_copy(&tmp_ace4[i].who, 21037c478bd9Sstevel@tonic-gate &ace4[i].who); 21047c478bd9Sstevel@tonic-gate } 21057c478bd9Sstevel@tonic-gate } 21067c478bd9Sstevel@tonic-gate rvsap->vsa_aclcnt = vsap->vsa_aclcnt; 21077c478bd9Sstevel@tonic-gate rvsap->vsa_mask |= VSA_ACE | VSA_ACECNT; 21087c478bd9Sstevel@tonic-gate } 21097c478bd9Sstevel@tonic-gate if (vsap->vsa_mask & VSA_ACECNT) { 21107c478bd9Sstevel@tonic-gate if (rvsap->vsa_aclentp != NULL) { 21117c478bd9Sstevel@tonic-gate /* 21127c478bd9Sstevel@tonic-gate * If the caller requested to only cache the 21137c478bd9Sstevel@tonic-gate * count, get rid of the acl whether or not the 21147c478bd9Sstevel@tonic-gate * counts are equal because it may be invalid. 21157c478bd9Sstevel@tonic-gate */ 21167c478bd9Sstevel@tonic-gate if (vsap->vsa_mask == VSA_ACECNT || 21177c478bd9Sstevel@tonic-gate rvsap->vsa_aclcnt != vsap->vsa_aclcnt) { 21187c478bd9Sstevel@tonic-gate vs_ace4_destroy(rvsap); 21197c478bd9Sstevel@tonic-gate rvsap->vsa_aclentp = NULL; 21207c478bd9Sstevel@tonic-gate rvsap->vsa_mask &= ~VSA_ACE; 21217c478bd9Sstevel@tonic-gate } 21227c478bd9Sstevel@tonic-gate } 21237c478bd9Sstevel@tonic-gate rvsap->vsa_aclcnt = vsap->vsa_aclcnt; 21247c478bd9Sstevel@tonic-gate rvsap->vsa_mask |= VSA_ACECNT; 21257c478bd9Sstevel@tonic-gate } 21267c478bd9Sstevel@tonic-gate mutex_exit(&rp->r_statelock); 21277c478bd9Sstevel@tonic-gate } 21287c478bd9Sstevel@tonic-gate 21297c478bd9Sstevel@tonic-gate /* 21307c478bd9Sstevel@tonic-gate * This should ONLY be called on the ACL cache (rnode4_t.r_secattr). The cache 21317c478bd9Sstevel@tonic-gate * is stored as a nfsv4 acl meaning the vsecattr_t.vsa_aclentp is a list of 21327c478bd9Sstevel@tonic-gate * nfsace4 entries and vsecattr_t.vsa_dfaclentp is NULL or not populated. 21337c478bd9Sstevel@tonic-gate */ 21347c478bd9Sstevel@tonic-gate void 21357c478bd9Sstevel@tonic-gate nfs4_acl_free_cache(vsecattr_t *vsap) 21367c478bd9Sstevel@tonic-gate { 21377c478bd9Sstevel@tonic-gate if (vsap == NULL) 21387c478bd9Sstevel@tonic-gate return; 21397c478bd9Sstevel@tonic-gate 21407c478bd9Sstevel@tonic-gate if (vsap->vsa_aclentp != NULL) 21417c478bd9Sstevel@tonic-gate vs_ace4_destroy(vsap); 21427c478bd9Sstevel@tonic-gate 21437c478bd9Sstevel@tonic-gate kmem_free(vsap, sizeof (*vsap)); 21447c478bd9Sstevel@tonic-gate vsap = NULL; 21457c478bd9Sstevel@tonic-gate } 21467c478bd9Sstevel@tonic-gate 21477c478bd9Sstevel@tonic-gate static int 2148*e913d9ecSLisa Week validate_idmapping(utf8string *orig_who, uid_t *mapped_id, int isuser, 2149*e913d9ecSLisa Week int isserver) 21507c478bd9Sstevel@tonic-gate { 2151*e913d9ecSLisa Week if (u8s_mapped_to_nobody(orig_who, *mapped_id, isuser)) { 21527c478bd9Sstevel@tonic-gate if (isserver) { 21537c478bd9Sstevel@tonic-gate char *who = NULL; 21547c478bd9Sstevel@tonic-gate uint_t len = 0; 2155*e913d9ecSLisa Week /* SERVER */ 21567c478bd9Sstevel@tonic-gate /* 21577c478bd9Sstevel@tonic-gate * This code path gets executed on the server 21587c478bd9Sstevel@tonic-gate * in the case that we are setting an ACL. 21597c478bd9Sstevel@tonic-gate * 21607c478bd9Sstevel@tonic-gate * We silently got our who value (who@domain) 21617c478bd9Sstevel@tonic-gate * mapped to "nobody" (possibly because the 21627c478bd9Sstevel@tonic-gate * nfsmapid daemon was unresponsive). 21637c478bd9Sstevel@tonic-gate * We NEVER want to silently map the user or 21647c478bd9Sstevel@tonic-gate * group to "nobody" as this could end up 21657c478bd9Sstevel@tonic-gate * wrongly giving access to user or group 21667c478bd9Sstevel@tonic-gate * "nobody" rather than the entity it was 21677c478bd9Sstevel@tonic-gate * meant for. 21687c478bd9Sstevel@tonic-gate */ 21697c478bd9Sstevel@tonic-gate who = utf8_to_str(orig_who, &len, NULL); 21707c478bd9Sstevel@tonic-gate DTRACE_PROBE1(nfs4__acl__nobody, char *, who); 21717c478bd9Sstevel@tonic-gate if (who != NULL) 21727c478bd9Sstevel@tonic-gate kmem_free(who, len); 21737c478bd9Sstevel@tonic-gate return (NFS4ERR_BADOWNER); 21747c478bd9Sstevel@tonic-gate } else { 21757c478bd9Sstevel@tonic-gate char *who = NULL; 21767c478bd9Sstevel@tonic-gate uint_t len = 0; 21777c478bd9Sstevel@tonic-gate /* CLIENT */ 21787c478bd9Sstevel@tonic-gate /* 21797c478bd9Sstevel@tonic-gate * This code path gets executed on the client 21807c478bd9Sstevel@tonic-gate * when we are getting an ACL. 21817c478bd9Sstevel@tonic-gate * 2182*e913d9ecSLisa Week * We do not want to silently map user or group to 2183*e913d9ecSLisa Week * "nobody" because of the semantics that an ACL 2184*e913d9ecSLisa Week * modification interface (i.e. - setfacl -m, chmod A+) 21857c478bd9Sstevel@tonic-gate * may use to modify an ACL (i.e. - get the ACL 21867c478bd9Sstevel@tonic-gate * then use it as a basis for setting the 2187*e913d9ecSLisa Week * modified ACL). Therefore, change the mapping. 21887c478bd9Sstevel@tonic-gate */ 21897c478bd9Sstevel@tonic-gate who = utf8_to_str(orig_who, &len, NULL); 21907c478bd9Sstevel@tonic-gate DTRACE_PROBE1(nfs4__acl__nobody, char *, who); 21917c478bd9Sstevel@tonic-gate if (who != NULL) 21927c478bd9Sstevel@tonic-gate kmem_free(who, len); 2193*e913d9ecSLisa Week 2194*e913d9ecSLisa Week /* 2195*e913d9ecSLisa Week * Re-mapped from UID_NOBODY/GID_NOBODY 2196*e913d9ecSLisa Week * to UID_UNKNOWN/GID_UNKNOWN and return. 2197*e913d9ecSLisa Week */ 2198*e913d9ecSLisa Week remap_id(mapped_id, isuser); 21997c478bd9Sstevel@tonic-gate return (0); 22007c478bd9Sstevel@tonic-gate } 22017c478bd9Sstevel@tonic-gate } 22027c478bd9Sstevel@tonic-gate return (0); 22037c478bd9Sstevel@tonic-gate } 22047c478bd9Sstevel@tonic-gate /* 22057c478bd9Sstevel@tonic-gate * Returns 1 if the who, utf8string was mapped to UID_NOBODY or GID_NOBODY. 22067c478bd9Sstevel@tonic-gate * Returns 0 if the who, utf8string was mapped correctly. 22077c478bd9Sstevel@tonic-gate */ 22087c478bd9Sstevel@tonic-gate static int 22097c478bd9Sstevel@tonic-gate u8s_mapped_to_nobody(utf8string *orig_who, uid_t mapped_id, int isuser) 22107c478bd9Sstevel@tonic-gate { 22117c478bd9Sstevel@tonic-gate if (orig_who->utf8string_len == 6 && 22127c478bd9Sstevel@tonic-gate bcmp("nobody", orig_who->utf8string_val, 6) == 0) 22137c478bd9Sstevel@tonic-gate return (0); 22147c478bd9Sstevel@tonic-gate 22157c478bd9Sstevel@tonic-gate if (isuser) 22167c478bd9Sstevel@tonic-gate return (mapped_id == UID_NOBODY); 22177c478bd9Sstevel@tonic-gate 22187c478bd9Sstevel@tonic-gate return (mapped_id == GID_NOBODY); 22197c478bd9Sstevel@tonic-gate } 2220*e913d9ecSLisa Week 2221*e913d9ecSLisa Week /* 2222*e913d9ecSLisa Week * This function is used in the case that the utf8string passed over the wire 2223*e913d9ecSLisa Week * was mapped to UID_NOBODY or GID_NOBODY and we will remap the id to 2224*e913d9ecSLisa Week * to the appropriate mapping. That is UID_UNKNOWN or GID_UNKNOWN. 2225*e913d9ecSLisa Week */ 2226*e913d9ecSLisa Week static void 2227*e913d9ecSLisa Week remap_id(uid_t *id, int isuser) 2228*e913d9ecSLisa Week { 2229*e913d9ecSLisa Week if (isuser) 2230*e913d9ecSLisa Week *id = UID_UNKNOWN; 2231*e913d9ecSLisa Week 2232*e913d9ecSLisa Week *id = GID_UNKNOWN; 2233*e913d9ecSLisa Week } 2234