1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5*3eb3c573Smarks * Common Development and Distribution License (the "License"). 6*3eb3c573Smarks * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 21fa9e4066Sahrens /* 22d2443e76Smarks * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23fa9e4066Sahrens * Use is subject to license terms. 24fa9e4066Sahrens */ 25fa9e4066Sahrens 26fa9e4066Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 27fa9e4066Sahrens 28fa9e4066Sahrens #include <stdlib.h> 29fa9e4066Sahrens #include <string.h> 30fa9e4066Sahrens #include <unistd.h> 31fa9e4066Sahrens #include <limits.h> 32fa9e4066Sahrens #include <grp.h> 33fa9e4066Sahrens #include <pwd.h> 34*3eb3c573Smarks #include <strings.h> 35fa9e4066Sahrens #include <sys/types.h> 36fa9e4066Sahrens #include <sys/acl.h> 37fa9e4066Sahrens #include <errno.h> 38fa9e4066Sahrens #include <sys/stat.h> 395a5eeccaSmarks #include <sys/varargs.h> 40fa9e4066Sahrens #include <locale.h> 41fa9e4066Sahrens #include <aclutils.h> 42fa9e4066Sahrens #include <acl_common.h> 43*3eb3c573Smarks #include <sys/avl.h> 44*3eb3c573Smarks 45*3eb3c573Smarks #define offsetof(s, m) ((size_t)(&(((s *)0)->m))) 46fa9e4066Sahrens 47fa9e4066Sahrens #define ACL_PATH 0 48fa9e4066Sahrens #define ACL_FD 1 49fa9e4066Sahrens 50fa9e4066Sahrens #define ACE_POSIX_SUPPORTED_BITS (ACE_READ_DATA | \ 51fa9e4066Sahrens ACE_WRITE_DATA | ACE_APPEND_DATA | ACE_EXECUTE | \ 52fa9e4066Sahrens ACE_READ_ATTRIBUTES | ACE_READ_ACL | ACE_WRITE_ACL) 53fa9e4066Sahrens 54fa9e4066Sahrens 55fa9e4066Sahrens #define ACL_SYNCHRONIZE_SET_DENY 0x0000001 56*3eb3c573Smarks #define ACL_SYNCHRONIZE_SET_ALLOW 0x0000002 57*3eb3c573Smarks #define ACL_SYNCHRONIZE_ERR_DENY 0x0000004 58*3eb3c573Smarks #define ACL_SYNCHRONIZE_ERR_ALLOW 0x0000008 59fa9e4066Sahrens 60fa9e4066Sahrens #define ACL_WRITE_OWNER_SET_DENY 0x0000010 61*3eb3c573Smarks #define ACL_WRITE_OWNER_SET_ALLOW 0x0000020 62*3eb3c573Smarks #define ACL_WRITE_OWNER_ERR_DENY 0x0000040 63*3eb3c573Smarks #define ACL_WRITE_OWNER_ERR_ALLOW 0x0000080 64fa9e4066Sahrens 65*3eb3c573Smarks #define ACL_DELETE_SET_DENY 0x0000100 66*3eb3c573Smarks #define ACL_DELETE_SET_ALLOW 0x0000200 67*3eb3c573Smarks #define ACL_DELETE_ERR_DENY 0x0000400 68*3eb3c573Smarks #define ACL_DELETE_ERR_ALLOW 0x0000800 69*3eb3c573Smarks 70fa9e4066Sahrens #define ACL_WRITE_ATTRS_OWNER_SET_DENY 0x0001000 71*3eb3c573Smarks #define ACL_WRITE_ATTRS_OWNER_SET_ALLOW 0x0002000 72*3eb3c573Smarks #define ACL_WRITE_ATTRS_OWNER_ERR_DENY 0x0004000 73*3eb3c573Smarks #define ACL_WRITE_ATTRS_OWNER_ERR_ALLOW 0x0008000 74fa9e4066Sahrens 75fa9e4066Sahrens #define ACL_WRITE_ATTRS_WRITER_SET_DENY 0x0010000 76fa9e4066Sahrens #define ACL_WRITE_ATTRS_WRITER_SET_ALLOW 0x0020000 77*3eb3c573Smarks #define ACL_WRITE_ATTRS_WRITER_ERR_DENY 0x0040000 78*3eb3c573Smarks #define ACL_WRITE_ATTRS_WRITER_ERR_ALLOW 0x0080000 79fa9e4066Sahrens 80*3eb3c573Smarks #define ACL_WRITE_NAMED_WRITER_SET_DENY 0x0100000 81*3eb3c573Smarks #define ACL_WRITE_NAMED_WRITER_SET_ALLOW 0x0200000 82*3eb3c573Smarks #define ACL_WRITE_NAMED_WRITER_ERR_DENY 0x0400000 83*3eb3c573Smarks #define ACL_WRITE_NAMED_WRITER_ERR_ALLOW 0x0800000 84*3eb3c573Smarks 85fa9e4066Sahrens #define ACL_READ_NAMED_READER_SET_DENY 0x1000000 86*3eb3c573Smarks #define ACL_READ_NAMED_READER_SET_ALLOW 0x2000000 87*3eb3c573Smarks #define ACL_READ_NAMED_READER_ERR_DENY 0x4000000 88*3eb3c573Smarks #define ACL_READ_NAMED_READER_ERR_ALLOW 0x8000000 89*3eb3c573Smarks 90*3eb3c573Smarks 91*3eb3c573Smarks #define ACE_VALID_MASK_BITS (\ 92*3eb3c573Smarks ACE_READ_DATA | \ 93*3eb3c573Smarks ACE_LIST_DIRECTORY | \ 94*3eb3c573Smarks ACE_WRITE_DATA | \ 95*3eb3c573Smarks ACE_ADD_FILE | \ 96*3eb3c573Smarks ACE_APPEND_DATA | \ 97*3eb3c573Smarks ACE_ADD_SUBDIRECTORY | \ 98*3eb3c573Smarks ACE_READ_NAMED_ATTRS | \ 99*3eb3c573Smarks ACE_WRITE_NAMED_ATTRS | \ 100*3eb3c573Smarks ACE_EXECUTE | \ 101*3eb3c573Smarks ACE_DELETE_CHILD | \ 102*3eb3c573Smarks ACE_READ_ATTRIBUTES | \ 103*3eb3c573Smarks ACE_WRITE_ATTRIBUTES | \ 104*3eb3c573Smarks ACE_DELETE | \ 105*3eb3c573Smarks ACE_READ_ACL | \ 106*3eb3c573Smarks ACE_WRITE_ACL | \ 107*3eb3c573Smarks ACE_WRITE_OWNER | \ 108*3eb3c573Smarks ACE_SYNCHRONIZE) 109*3eb3c573Smarks 110*3eb3c573Smarks #define ACE_MASK_UNDEFINED 0x80000000 111*3eb3c573Smarks 112*3eb3c573Smarks #define ACE_VALID_FLAG_BITS (ACE_FILE_INHERIT_ACE | \ 113*3eb3c573Smarks ACE_DIRECTORY_INHERIT_ACE | \ 114*3eb3c573Smarks ACE_NO_PROPAGATE_INHERIT_ACE | ACE_INHERIT_ONLY_ACE | \ 115*3eb3c573Smarks ACE_SUCCESSFUL_ACCESS_ACE_FLAG | ACE_FAILED_ACCESS_ACE_FLAG | \ 116*3eb3c573Smarks ACE_IDENTIFIER_GROUP | ACE_OWNER | ACE_GROUP | ACE_EVERYONE) 117*3eb3c573Smarks 118*3eb3c573Smarks /* 119*3eb3c573Smarks * ACL conversion helpers 120*3eb3c573Smarks */ 121*3eb3c573Smarks 122*3eb3c573Smarks typedef enum { 123*3eb3c573Smarks ace_unused, 124*3eb3c573Smarks ace_user_obj, 125*3eb3c573Smarks ace_user, 126*3eb3c573Smarks ace_group, /* includes GROUP and GROUP_OBJ */ 127*3eb3c573Smarks ace_other_obj 128*3eb3c573Smarks } ace_to_aent_state_t; 129*3eb3c573Smarks 130*3eb3c573Smarks typedef struct acevals { 131*3eb3c573Smarks uid_t key; 132*3eb3c573Smarks avl_node_t avl; 133*3eb3c573Smarks uint32_t mask; 134*3eb3c573Smarks uint32_t allowed; 135*3eb3c573Smarks uint32_t denied; 136*3eb3c573Smarks int aent_type; 137*3eb3c573Smarks } acevals_t; 138*3eb3c573Smarks 139*3eb3c573Smarks typedef struct ace_list { 140*3eb3c573Smarks acevals_t user_obj; 141*3eb3c573Smarks avl_tree_t user; 142*3eb3c573Smarks int numusers; 143*3eb3c573Smarks acevals_t group_obj; 144*3eb3c573Smarks avl_tree_t group; 145*3eb3c573Smarks int numgroups; 146*3eb3c573Smarks acevals_t other_obj; 147*3eb3c573Smarks uint32_t acl_mask; 148*3eb3c573Smarks int hasmask; 149*3eb3c573Smarks int dfacl_flag; 150*3eb3c573Smarks ace_to_aent_state_t state; 151*3eb3c573Smarks int seen; /* bitmask of all aclent_t a_type values seen */ 152*3eb3c573Smarks } ace_list_t; 153d2443e76Smarks 154fa9e4066Sahrens typedef union { 155fa9e4066Sahrens const char *file; 156fa9e4066Sahrens int fd; 157fa9e4066Sahrens } acl_inp; 158fa9e4066Sahrens 159fa9e4066Sahrens acl_t * 160fa9e4066Sahrens acl_alloc(enum acl_type type) 161fa9e4066Sahrens { 162fa9e4066Sahrens acl_t *aclp; 163fa9e4066Sahrens 164fa9e4066Sahrens aclp = malloc(sizeof (acl_t)); 165fa9e4066Sahrens 166fa9e4066Sahrens if (aclp == NULL) 167fa9e4066Sahrens return (NULL); 168fa9e4066Sahrens 169fa9e4066Sahrens aclp->acl_aclp = NULL; 170fa9e4066Sahrens aclp->acl_cnt = 0; 171fa9e4066Sahrens 172fa9e4066Sahrens switch (type) { 173fa9e4066Sahrens case ACE_T: 174fa9e4066Sahrens aclp->acl_type = ACE_T; 175fa9e4066Sahrens aclp->acl_entry_size = sizeof (ace_t); 176fa9e4066Sahrens break; 177fa9e4066Sahrens case ACLENT_T: 178fa9e4066Sahrens aclp->acl_type = ACLENT_T; 179fa9e4066Sahrens aclp->acl_entry_size = sizeof (aclent_t); 180fa9e4066Sahrens break; 181fa9e4066Sahrens default: 182fa9e4066Sahrens acl_free(aclp); 183fa9e4066Sahrens aclp = NULL; 184fa9e4066Sahrens } 185fa9e4066Sahrens return (aclp); 186fa9e4066Sahrens } 187fa9e4066Sahrens 188fa9e4066Sahrens /* 189fa9e4066Sahrens * Free acl_t structure 190fa9e4066Sahrens */ 191fa9e4066Sahrens void 192fa9e4066Sahrens acl_free(acl_t *aclp) 193fa9e4066Sahrens { 194fa9e4066Sahrens if (aclp == NULL) 195fa9e4066Sahrens return; 196fa9e4066Sahrens 197fa9e4066Sahrens if (aclp->acl_aclp) 198fa9e4066Sahrens free(aclp->acl_aclp); 199fa9e4066Sahrens free(aclp); 200fa9e4066Sahrens } 201fa9e4066Sahrens 202fa9e4066Sahrens /* 203fa9e4066Sahrens * Determine whether a file has a trivial ACL 204fa9e4066Sahrens * returns: 0 = trivial 205fa9e4066Sahrens * 1 = nontrivial 206fa9e4066Sahrens * <0 some other system failure, such as ENOENT or EPERM 207fa9e4066Sahrens */ 208fa9e4066Sahrens int 209fa9e4066Sahrens acl_trivial(const char *filename) 210fa9e4066Sahrens { 211fa9e4066Sahrens int acl_flavor; 212fa9e4066Sahrens int aclcnt; 213fa9e4066Sahrens int cntcmd; 214fa9e4066Sahrens int val = 0; 215fa9e4066Sahrens ace_t *acep; 216fa9e4066Sahrens 217fa9e4066Sahrens acl_flavor = pathconf(filename, _PC_ACL_ENABLED); 218fa9e4066Sahrens if (acl_flavor == -1) 219fa9e4066Sahrens return (-1); 220fa9e4066Sahrens 221fa9e4066Sahrens if (acl_flavor == _ACL_ACE_ENABLED) 222fa9e4066Sahrens cntcmd = ACE_GETACLCNT; 223fa9e4066Sahrens else 224fa9e4066Sahrens cntcmd = GETACLCNT; 225fa9e4066Sahrens 226fa9e4066Sahrens aclcnt = acl(filename, cntcmd, 0, NULL); 227fa9e4066Sahrens if (aclcnt > 0) { 228fa9e4066Sahrens if (acl_flavor == _ACL_ACE_ENABLED) { 229fa9e4066Sahrens acep = malloc(sizeof (ace_t) * aclcnt); 230fa9e4066Sahrens if (acep == NULL) 231fa9e4066Sahrens return (-1); 232fa9e4066Sahrens if (acl(filename, ACE_GETACL, 233fa9e4066Sahrens aclcnt, acep) < 0) { 234fa9e4066Sahrens free(acep); 235fa9e4066Sahrens return (-1); 236fa9e4066Sahrens } 237fa9e4066Sahrens 238fa9e4066Sahrens val = ace_trivial(acep, aclcnt); 239fa9e4066Sahrens free(acep); 240d2443e76Smarks 241fa9e4066Sahrens } else if (aclcnt > MIN_ACL_ENTRIES) 242fa9e4066Sahrens val = 1; 243fa9e4066Sahrens } 244fa9e4066Sahrens return (val); 245fa9e4066Sahrens } 246fa9e4066Sahrens 247fa9e4066Sahrens static uint32_t 248fa9e4066Sahrens access_mask_set(int haswriteperm, int hasreadperm, int isowner, int isallow) 249fa9e4066Sahrens { 250fa9e4066Sahrens uint32_t access_mask = 0; 251fa9e4066Sahrens int acl_produce; 252fa9e4066Sahrens int synchronize_set = 0, write_owner_set = 0; 253fa9e4066Sahrens int delete_set = 0, write_attrs_set = 0; 254fa9e4066Sahrens int read_named_set = 0, write_named_set = 0; 255fa9e4066Sahrens 256fa9e4066Sahrens acl_produce = (ACL_SYNCHRONIZE_SET_ALLOW | 257fa9e4066Sahrens ACL_WRITE_ATTRS_OWNER_SET_ALLOW | 258fa9e4066Sahrens ACL_WRITE_ATTRS_WRITER_SET_DENY); 259fa9e4066Sahrens 260fa9e4066Sahrens if (isallow) { 261fa9e4066Sahrens synchronize_set = ACL_SYNCHRONIZE_SET_ALLOW; 262fa9e4066Sahrens write_owner_set = ACL_WRITE_OWNER_SET_ALLOW; 263fa9e4066Sahrens delete_set = ACL_DELETE_SET_ALLOW; 264fa9e4066Sahrens if (hasreadperm) 265fa9e4066Sahrens read_named_set = ACL_READ_NAMED_READER_SET_ALLOW; 266fa9e4066Sahrens if (haswriteperm) 267fa9e4066Sahrens write_named_set = ACL_WRITE_NAMED_WRITER_SET_ALLOW; 268fa9e4066Sahrens if (isowner) 269fa9e4066Sahrens write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_ALLOW; 270fa9e4066Sahrens else if (haswriteperm) 271fa9e4066Sahrens write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_ALLOW; 272fa9e4066Sahrens } else { 273fa9e4066Sahrens 274fa9e4066Sahrens synchronize_set = ACL_SYNCHRONIZE_SET_DENY; 275fa9e4066Sahrens write_owner_set = ACL_WRITE_OWNER_SET_DENY; 276fa9e4066Sahrens delete_set = ACL_DELETE_SET_DENY; 277fa9e4066Sahrens if (hasreadperm) 278fa9e4066Sahrens read_named_set = ACL_READ_NAMED_READER_SET_DENY; 279fa9e4066Sahrens if (haswriteperm) 280fa9e4066Sahrens write_named_set = ACL_WRITE_NAMED_WRITER_SET_DENY; 281fa9e4066Sahrens if (isowner) 282fa9e4066Sahrens write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_DENY; 283fa9e4066Sahrens else if (haswriteperm) 284fa9e4066Sahrens write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_DENY; 285fa9e4066Sahrens else 286fa9e4066Sahrens /* 287fa9e4066Sahrens * If the entity is not the owner and does not 288fa9e4066Sahrens * have write permissions ACE_WRITE_ATTRIBUTES will 289fa9e4066Sahrens * always go in the DENY ACE. 290fa9e4066Sahrens */ 291fa9e4066Sahrens access_mask |= ACE_WRITE_ATTRIBUTES; 292fa9e4066Sahrens } 293fa9e4066Sahrens 294fa9e4066Sahrens if (acl_produce & synchronize_set) 295fa9e4066Sahrens access_mask |= ACE_SYNCHRONIZE; 296fa9e4066Sahrens if (acl_produce & write_owner_set) 297fa9e4066Sahrens access_mask |= ACE_WRITE_OWNER; 298fa9e4066Sahrens if (acl_produce & delete_set) 299fa9e4066Sahrens access_mask |= ACE_DELETE; 300fa9e4066Sahrens if (acl_produce & write_attrs_set) 301fa9e4066Sahrens access_mask |= ACE_WRITE_ATTRIBUTES; 302fa9e4066Sahrens if (acl_produce & read_named_set) 303fa9e4066Sahrens access_mask |= ACE_READ_NAMED_ATTRS; 304fa9e4066Sahrens if (acl_produce & write_named_set) 305fa9e4066Sahrens access_mask |= ACE_WRITE_NAMED_ATTRS; 306fa9e4066Sahrens 307fa9e4066Sahrens return (access_mask); 308fa9e4066Sahrens } 309fa9e4066Sahrens 310fa9e4066Sahrens /* 311fa9e4066Sahrens * Given an mode_t, convert it into an access_mask as used 312fa9e4066Sahrens * by nfsace, assuming aclent_t -> nfsace semantics. 313fa9e4066Sahrens */ 314fa9e4066Sahrens static uint32_t 315fa9e4066Sahrens mode_to_ace_access(mode_t mode, int isdir, int isowner, int isallow) 316fa9e4066Sahrens { 317fa9e4066Sahrens uint32_t access = 0; 318fa9e4066Sahrens int haswriteperm = 0; 319fa9e4066Sahrens int hasreadperm = 0; 320fa9e4066Sahrens 321fa9e4066Sahrens if (isallow) { 322fa9e4066Sahrens haswriteperm = (mode & 02); 323fa9e4066Sahrens hasreadperm = (mode & 04); 324fa9e4066Sahrens } else { 325fa9e4066Sahrens haswriteperm = !(mode & 02); 326fa9e4066Sahrens hasreadperm = !(mode & 04); 327fa9e4066Sahrens } 328fa9e4066Sahrens 329fa9e4066Sahrens /* 330fa9e4066Sahrens * The following call takes care of correctly setting the following 331fa9e4066Sahrens * mask bits in the access_mask: 332fa9e4066Sahrens * ACE_SYNCHRONIZE, ACE_WRITE_OWNER, ACE_DELETE, 333fa9e4066Sahrens * ACE_WRITE_ATTRIBUTES, ACE_WRITE_NAMED_ATTRS, ACE_READ_NAMED_ATTRS 334fa9e4066Sahrens */ 335fa9e4066Sahrens access = access_mask_set(haswriteperm, hasreadperm, isowner, isallow); 336fa9e4066Sahrens 337fa9e4066Sahrens if (isallow) { 338fa9e4066Sahrens access |= ACE_READ_ACL | ACE_READ_ATTRIBUTES; 339fa9e4066Sahrens if (isowner) 340fa9e4066Sahrens access |= ACE_WRITE_ACL; 341fa9e4066Sahrens } else { 342fa9e4066Sahrens if (! isowner) 343fa9e4066Sahrens access |= ACE_WRITE_ACL; 344fa9e4066Sahrens } 345fa9e4066Sahrens 346fa9e4066Sahrens /* read */ 347fa9e4066Sahrens if (mode & 04) { 348fa9e4066Sahrens access |= ACE_READ_DATA; 349fa9e4066Sahrens } 350fa9e4066Sahrens /* write */ 351fa9e4066Sahrens if (mode & 02) { 352fa9e4066Sahrens access |= ACE_WRITE_DATA | 353fa9e4066Sahrens ACE_APPEND_DATA; 354fa9e4066Sahrens if (isdir) 355fa9e4066Sahrens access |= ACE_DELETE_CHILD; 356fa9e4066Sahrens } 357fa9e4066Sahrens /* exec */ 358fa9e4066Sahrens if (mode & 01) { 359fa9e4066Sahrens access |= ACE_EXECUTE; 360fa9e4066Sahrens } 361fa9e4066Sahrens 362fa9e4066Sahrens return (access); 363fa9e4066Sahrens } 364fa9e4066Sahrens 365fa9e4066Sahrens /* 366fa9e4066Sahrens * Given an nfsace (presumably an ALLOW entry), make a 367fa9e4066Sahrens * corresponding DENY entry at the address given. 368fa9e4066Sahrens */ 369fa9e4066Sahrens static void 370fa9e4066Sahrens ace_make_deny(ace_t *allow, ace_t *deny, int isdir, int isowner) 371fa9e4066Sahrens { 372fa9e4066Sahrens (void) memcpy(deny, allow, sizeof (ace_t)); 373fa9e4066Sahrens 374fa9e4066Sahrens deny->a_who = allow->a_who; 375fa9e4066Sahrens 376fa9e4066Sahrens deny->a_type = ACE_ACCESS_DENIED_ACE_TYPE; 377fa9e4066Sahrens deny->a_access_mask ^= ACE_POSIX_SUPPORTED_BITS; 378fa9e4066Sahrens if (isdir) 379fa9e4066Sahrens deny->a_access_mask ^= ACE_DELETE_CHILD; 380fa9e4066Sahrens 381fa9e4066Sahrens deny->a_access_mask &= ~(ACE_SYNCHRONIZE | ACE_WRITE_OWNER | 382fa9e4066Sahrens ACE_DELETE | ACE_WRITE_ATTRIBUTES | ACE_READ_NAMED_ATTRS | 383fa9e4066Sahrens ACE_WRITE_NAMED_ATTRS); 384fa9e4066Sahrens deny->a_access_mask |= access_mask_set((allow->a_access_mask & 385fa9e4066Sahrens ACE_WRITE_DATA), (allow->a_access_mask & ACE_READ_DATA), isowner, 386fa9e4066Sahrens B_FALSE); 387fa9e4066Sahrens } 388fa9e4066Sahrens /* 389fa9e4066Sahrens * Make an initial pass over an array of aclent_t's. Gather 390fa9e4066Sahrens * information such as an ACL_MASK (if any), number of users, 391fa9e4066Sahrens * number of groups, and whether the array needs to be sorted. 392fa9e4066Sahrens */ 393fa9e4066Sahrens static int 394fa9e4066Sahrens ln_aent_preprocess(aclent_t *aclent, int n, 395fa9e4066Sahrens int *hasmask, mode_t *mask, 396fa9e4066Sahrens int *numuser, int *numgroup, int *needsort) 397fa9e4066Sahrens { 398fa9e4066Sahrens int error = 0; 399fa9e4066Sahrens int i; 400fa9e4066Sahrens int curtype = 0; 401fa9e4066Sahrens 402fa9e4066Sahrens *hasmask = 0; 403fa9e4066Sahrens *mask = 07; 404fa9e4066Sahrens *needsort = 0; 405fa9e4066Sahrens *numuser = 0; 406fa9e4066Sahrens *numgroup = 0; 407fa9e4066Sahrens 408fa9e4066Sahrens for (i = 0; i < n; i++) { 409fa9e4066Sahrens if (aclent[i].a_type < curtype) 410fa9e4066Sahrens *needsort = 1; 411fa9e4066Sahrens else if (aclent[i].a_type > curtype) 412fa9e4066Sahrens curtype = aclent[i].a_type; 413fa9e4066Sahrens if (aclent[i].a_type & USER) 414fa9e4066Sahrens (*numuser)++; 415fa9e4066Sahrens if (aclent[i].a_type & (GROUP | GROUP_OBJ)) 416fa9e4066Sahrens (*numgroup)++; 417fa9e4066Sahrens if (aclent[i].a_type & CLASS_OBJ) { 418fa9e4066Sahrens if (*hasmask) { 419fa9e4066Sahrens error = EINVAL; 420fa9e4066Sahrens goto out; 421fa9e4066Sahrens } else { 422fa9e4066Sahrens *hasmask = 1; 423fa9e4066Sahrens *mask = aclent[i].a_perm; 424fa9e4066Sahrens } 425fa9e4066Sahrens } 426fa9e4066Sahrens } 427fa9e4066Sahrens 428fa9e4066Sahrens if ((! *hasmask) && (*numuser + *numgroup > 1)) { 429fa9e4066Sahrens error = EINVAL; 430fa9e4066Sahrens goto out; 431fa9e4066Sahrens } 432fa9e4066Sahrens 433fa9e4066Sahrens out: 434fa9e4066Sahrens return (error); 435fa9e4066Sahrens } 436fa9e4066Sahrens 437fa9e4066Sahrens /* 438fa9e4066Sahrens * Convert an array of aclent_t into an array of nfsace entries, 439fa9e4066Sahrens * following POSIX draft -> nfsv4 conversion semantics as outlined in 440fa9e4066Sahrens * the IETF draft. 441fa9e4066Sahrens */ 442fa9e4066Sahrens static int 443fa9e4066Sahrens ln_aent_to_ace(aclent_t *aclent, int n, ace_t **acepp, int *rescount, int isdir) 444fa9e4066Sahrens { 445fa9e4066Sahrens int error = 0; 446fa9e4066Sahrens mode_t mask; 447fa9e4066Sahrens int numuser, numgroup, needsort; 448fa9e4066Sahrens int resultsize = 0; 449fa9e4066Sahrens int i, groupi = 0, skip; 450fa9e4066Sahrens ace_t *acep, *result = NULL; 451fa9e4066Sahrens int hasmask; 452fa9e4066Sahrens 453fa9e4066Sahrens error = ln_aent_preprocess(aclent, n, &hasmask, &mask, 454fa9e4066Sahrens &numuser, &numgroup, &needsort); 455fa9e4066Sahrens if (error != 0) 456fa9e4066Sahrens goto out; 457fa9e4066Sahrens 458fa9e4066Sahrens /* allow + deny for each aclent */ 459fa9e4066Sahrens resultsize = n * 2; 460fa9e4066Sahrens if (hasmask) { 461fa9e4066Sahrens /* 462fa9e4066Sahrens * stick extra deny on the group_obj and on each 463fa9e4066Sahrens * user|group for the mask (the group_obj was added 464fa9e4066Sahrens * into the count for numgroup) 465fa9e4066Sahrens */ 466fa9e4066Sahrens resultsize += numuser + numgroup; 467fa9e4066Sahrens /* ... and don't count the mask itself */ 468fa9e4066Sahrens resultsize -= 2; 469fa9e4066Sahrens } 470fa9e4066Sahrens 471fa9e4066Sahrens /* sort the source if necessary */ 472fa9e4066Sahrens if (needsort) 473fa9e4066Sahrens ksort((caddr_t)aclent, n, sizeof (aclent_t), cmp2acls); 474fa9e4066Sahrens 475fa9e4066Sahrens result = acep = calloc(1, resultsize * sizeof (ace_t)); 476fa9e4066Sahrens if (result == NULL) 477fa9e4066Sahrens goto out; 478fa9e4066Sahrens 479fa9e4066Sahrens for (i = 0; i < n; i++) { 480fa9e4066Sahrens /* 481fa9e4066Sahrens * don't process CLASS_OBJ (mask); mask was grabbed in 482fa9e4066Sahrens * ln_aent_preprocess() 483fa9e4066Sahrens */ 484fa9e4066Sahrens if (aclent[i].a_type & CLASS_OBJ) 485fa9e4066Sahrens continue; 486fa9e4066Sahrens 487fa9e4066Sahrens /* If we need an ACL_MASK emulator, prepend it now */ 488fa9e4066Sahrens if ((hasmask) && 489fa9e4066Sahrens (aclent[i].a_type & (USER | GROUP | GROUP_OBJ))) { 490fa9e4066Sahrens acep->a_type = ACE_ACCESS_DENIED_ACE_TYPE; 491fa9e4066Sahrens acep->a_flags = 0; 492fa9e4066Sahrens if (aclent[i].a_type & GROUP_OBJ) { 493fa9e4066Sahrens acep->a_who = -1; 494fa9e4066Sahrens acep->a_flags |= 495fa9e4066Sahrens (ACE_IDENTIFIER_GROUP|ACE_GROUP); 496fa9e4066Sahrens } else if (aclent[i].a_type & USER) { 497fa9e4066Sahrens acep->a_who = aclent[i].a_id; 498fa9e4066Sahrens } else { 499fa9e4066Sahrens acep->a_who = aclent[i].a_id; 500fa9e4066Sahrens acep->a_flags |= ACE_IDENTIFIER_GROUP; 501fa9e4066Sahrens } 502fa9e4066Sahrens if (aclent[i].a_type & ACL_DEFAULT) { 503fa9e4066Sahrens acep->a_flags |= ACE_INHERIT_ONLY_ACE | 504fa9e4066Sahrens ACE_FILE_INHERIT_ACE | 505fa9e4066Sahrens ACE_DIRECTORY_INHERIT_ACE; 506fa9e4066Sahrens } 507fa9e4066Sahrens /* 508fa9e4066Sahrens * Set the access mask for the prepended deny 509fa9e4066Sahrens * ace. To do this, we invert the mask (found 510fa9e4066Sahrens * in ln_aent_preprocess()) then convert it to an 511fa9e4066Sahrens * DENY ace access_mask. 512fa9e4066Sahrens */ 513fa9e4066Sahrens acep->a_access_mask = mode_to_ace_access((mask ^ 07), 514fa9e4066Sahrens isdir, 0, 0); 515fa9e4066Sahrens acep += 1; 516fa9e4066Sahrens } 517fa9e4066Sahrens 518fa9e4066Sahrens /* handle a_perm -> access_mask */ 519fa9e4066Sahrens acep->a_access_mask = mode_to_ace_access(aclent[i].a_perm, 520fa9e4066Sahrens isdir, aclent[i].a_type & USER_OBJ, 1); 521fa9e4066Sahrens 522fa9e4066Sahrens /* emulate a default aclent */ 523fa9e4066Sahrens if (aclent[i].a_type & ACL_DEFAULT) { 524fa9e4066Sahrens acep->a_flags |= ACE_INHERIT_ONLY_ACE | 525fa9e4066Sahrens ACE_FILE_INHERIT_ACE | 526fa9e4066Sahrens ACE_DIRECTORY_INHERIT_ACE; 527fa9e4066Sahrens } 528fa9e4066Sahrens 529fa9e4066Sahrens /* 530fa9e4066Sahrens * handle a_perm and a_id 531fa9e4066Sahrens * 532fa9e4066Sahrens * this must be done last, since it involves the 533fa9e4066Sahrens * corresponding deny aces, which are handled 534fa9e4066Sahrens * differently for each different a_type. 535fa9e4066Sahrens */ 536fa9e4066Sahrens if (aclent[i].a_type & USER_OBJ) { 537fa9e4066Sahrens acep->a_who = -1; 538fa9e4066Sahrens acep->a_flags |= ACE_OWNER; 539fa9e4066Sahrens ace_make_deny(acep, acep + 1, isdir, B_TRUE); 540fa9e4066Sahrens acep += 2; 541fa9e4066Sahrens } else if (aclent[i].a_type & USER) { 542fa9e4066Sahrens acep->a_who = aclent[i].a_id; 543fa9e4066Sahrens ace_make_deny(acep, acep + 1, isdir, B_FALSE); 544fa9e4066Sahrens acep += 2; 545fa9e4066Sahrens } else if (aclent[i].a_type & (GROUP_OBJ | GROUP)) { 546fa9e4066Sahrens if (aclent[i].a_type & GROUP_OBJ) { 547fa9e4066Sahrens acep->a_who = -1; 548fa9e4066Sahrens acep->a_flags |= ACE_GROUP; 549fa9e4066Sahrens } else { 550fa9e4066Sahrens acep->a_who = aclent[i].a_id; 551fa9e4066Sahrens } 552fa9e4066Sahrens acep->a_flags |= ACE_IDENTIFIER_GROUP; 553fa9e4066Sahrens /* 554fa9e4066Sahrens * Set the corresponding deny for the group ace. 555fa9e4066Sahrens * 556fa9e4066Sahrens * The deny aces go after all of the groups, unlike 557fa9e4066Sahrens * everything else, where they immediately follow 558fa9e4066Sahrens * the allow ace. 559fa9e4066Sahrens * 560fa9e4066Sahrens * We calculate "skip", the number of slots to 561fa9e4066Sahrens * skip ahead for the deny ace, here. 562fa9e4066Sahrens * 563fa9e4066Sahrens * The pattern is: 564fa9e4066Sahrens * MD1 A1 MD2 A2 MD3 A3 D1 D2 D3 565fa9e4066Sahrens * thus, skip is 566fa9e4066Sahrens * (2 * numgroup) - 1 - groupi 567fa9e4066Sahrens * (2 * numgroup) to account for MD + A 568fa9e4066Sahrens * - 1 to account for the fact that we're on the 569fa9e4066Sahrens * access (A), not the mask (MD) 570fa9e4066Sahrens * - groupi to account for the fact that we have 571fa9e4066Sahrens * passed up groupi number of MD's. 572fa9e4066Sahrens */ 573fa9e4066Sahrens skip = (2 * numgroup) - 1 - groupi; 574fa9e4066Sahrens ace_make_deny(acep, acep + skip, isdir, B_FALSE); 575fa9e4066Sahrens /* 576fa9e4066Sahrens * If we just did the last group, skip acep past 577fa9e4066Sahrens * all of the denies; else, just move ahead one. 578fa9e4066Sahrens */ 579fa9e4066Sahrens if (++groupi >= numgroup) 580fa9e4066Sahrens acep += numgroup + 1; 581fa9e4066Sahrens else 582fa9e4066Sahrens acep += 1; 583fa9e4066Sahrens } else if (aclent[i].a_type & OTHER_OBJ) { 584fa9e4066Sahrens acep->a_who = -1; 585fa9e4066Sahrens acep->a_flags |= ACE_EVERYONE; 586fa9e4066Sahrens ace_make_deny(acep, acep + 1, isdir, B_FALSE); 587fa9e4066Sahrens acep += 2; 588fa9e4066Sahrens } else { 589fa9e4066Sahrens error = EINVAL; 590fa9e4066Sahrens goto out; 591fa9e4066Sahrens } 592fa9e4066Sahrens } 593fa9e4066Sahrens 594fa9e4066Sahrens *acepp = result; 595fa9e4066Sahrens *rescount = resultsize; 596fa9e4066Sahrens 597fa9e4066Sahrens out: 598fa9e4066Sahrens if (error != 0) { 599fa9e4066Sahrens if ((result != NULL) && (resultsize > 0)) { 600fa9e4066Sahrens free(result); 601fa9e4066Sahrens } 602fa9e4066Sahrens } 603fa9e4066Sahrens 604fa9e4066Sahrens return (error); 605fa9e4066Sahrens } 606fa9e4066Sahrens 607fa9e4066Sahrens static int 608fa9e4066Sahrens convert_aent_to_ace(aclent_t *aclentp, int aclcnt, int isdir, 609fa9e4066Sahrens ace_t **retacep, int *retacecnt) 610fa9e4066Sahrens { 611fa9e4066Sahrens ace_t *acep; 612fa9e4066Sahrens ace_t *dfacep; 613fa9e4066Sahrens int acecnt = 0; 614fa9e4066Sahrens int dfacecnt = 0; 615fa9e4066Sahrens int dfaclstart = 0; 616fa9e4066Sahrens int dfaclcnt = 0; 617fa9e4066Sahrens aclent_t *aclp; 618fa9e4066Sahrens int i; 619fa9e4066Sahrens int error; 620fa9e4066Sahrens 621fa9e4066Sahrens ksort((caddr_t)aclentp, aclcnt, sizeof (aclent_t), cmp2acls); 622fa9e4066Sahrens 623fa9e4066Sahrens for (i = 0, aclp = aclentp; i < aclcnt; aclp++, i++) { 624fa9e4066Sahrens if (aclp->a_type & ACL_DEFAULT) 625fa9e4066Sahrens break; 626fa9e4066Sahrens } 627fa9e4066Sahrens 628fa9e4066Sahrens if (i < aclcnt) { 629*3eb3c573Smarks dfaclstart = i; 630*3eb3c573Smarks dfaclcnt = aclcnt - i; 631fa9e4066Sahrens } 632fa9e4066Sahrens 633fa9e4066Sahrens if (dfaclcnt && isdir == 0) { 634fa9e4066Sahrens return (-1); 635fa9e4066Sahrens } 636fa9e4066Sahrens 637fa9e4066Sahrens error = ln_aent_to_ace(aclentp, i, &acep, &acecnt, isdir); 638fa9e4066Sahrens if (error) 639fa9e4066Sahrens return (-1); 640fa9e4066Sahrens 641fa9e4066Sahrens if (dfaclcnt) { 642fa9e4066Sahrens error = ln_aent_to_ace(&aclentp[dfaclstart], dfaclcnt, 643fa9e4066Sahrens &dfacep, &dfacecnt, isdir); 644fa9e4066Sahrens if (error) { 645fa9e4066Sahrens if (acep) { 646fa9e4066Sahrens free(acep); 647fa9e4066Sahrens } 648fa9e4066Sahrens return (-1); 649fa9e4066Sahrens } 650fa9e4066Sahrens } 651fa9e4066Sahrens 652*3eb3c573Smarks if (dfacecnt != 0) { 653*3eb3c573Smarks acep = realloc(acep, sizeof (ace_t) * (acecnt + dfacecnt)); 654*3eb3c573Smarks if (acep == NULL) 655fa9e4066Sahrens return (-1); 656fa9e4066Sahrens if (dfaclcnt) { 657*3eb3c573Smarks (void) memcpy(acep + acecnt, dfacep, 658fa9e4066Sahrens sizeof (ace_t) * dfacecnt); 659fa9e4066Sahrens } 660*3eb3c573Smarks } 661fa9e4066Sahrens if (dfaclcnt) 662fa9e4066Sahrens free(dfacep); 663fa9e4066Sahrens 664fa9e4066Sahrens *retacecnt = acecnt + dfacecnt; 665*3eb3c573Smarks *retacep = acep; 666fa9e4066Sahrens return (0); 667fa9e4066Sahrens } 668fa9e4066Sahrens 669*3eb3c573Smarks static void 670*3eb3c573Smarks acevals_init(acevals_t *vals, uid_t key) 671*3eb3c573Smarks { 672*3eb3c573Smarks bzero(vals, sizeof (*vals)); 673*3eb3c573Smarks vals->allowed = ACE_MASK_UNDEFINED; 674*3eb3c573Smarks vals->denied = ACE_MASK_UNDEFINED; 675*3eb3c573Smarks vals->mask = ACE_MASK_UNDEFINED; 676*3eb3c573Smarks vals->key = key; 677*3eb3c573Smarks } 678*3eb3c573Smarks 679*3eb3c573Smarks static void 680*3eb3c573Smarks ace_list_init(ace_list_t *al, int dfacl_flag) 681*3eb3c573Smarks { 682*3eb3c573Smarks acevals_init(&al->user_obj, NULL); 683*3eb3c573Smarks acevals_init(&al->group_obj, NULL); 684*3eb3c573Smarks acevals_init(&al->other_obj, NULL); 685*3eb3c573Smarks al->numusers = 0; 686*3eb3c573Smarks al->numgroups = 0; 687*3eb3c573Smarks al->acl_mask = 0; 688*3eb3c573Smarks al->hasmask = 0; 689*3eb3c573Smarks al->state = ace_unused; 690*3eb3c573Smarks al->seen = 0; 691*3eb3c573Smarks al->dfacl_flag = dfacl_flag; 692*3eb3c573Smarks } 693*3eb3c573Smarks 694*3eb3c573Smarks /* 695*3eb3c573Smarks * Find or create an acevals holder for a given id and avl tree. 696*3eb3c573Smarks * 697*3eb3c573Smarks * Note that only one thread will ever touch these avl trees, so 698*3eb3c573Smarks * there is no need for locking. 699*3eb3c573Smarks */ 700*3eb3c573Smarks static acevals_t * 701*3eb3c573Smarks acevals_find(ace_t *ace, avl_tree_t *avl, int *num) 702*3eb3c573Smarks { 703*3eb3c573Smarks acevals_t key, *rc; 704*3eb3c573Smarks avl_index_t where; 705*3eb3c573Smarks 706*3eb3c573Smarks key.key = ace->a_who; 707*3eb3c573Smarks rc = avl_find(avl, &key, &where); 708*3eb3c573Smarks if (rc != NULL) 709*3eb3c573Smarks return (rc); 710*3eb3c573Smarks 711*3eb3c573Smarks /* this memory is freed by ln_ace_to_aent()->ace_list_free() */ 712*3eb3c573Smarks rc = calloc(1, sizeof (acevals_t)); 713*3eb3c573Smarks if (rc == NULL) 714*3eb3c573Smarks return (rc); 715*3eb3c573Smarks acevals_init(rc, ace->a_who); 716*3eb3c573Smarks avl_insert(avl, rc, where); 717*3eb3c573Smarks (*num)++; 718*3eb3c573Smarks 719*3eb3c573Smarks return (rc); 720*3eb3c573Smarks } 721fa9e4066Sahrens 722fa9e4066Sahrens static int 723*3eb3c573Smarks access_mask_check(ace_t *acep, int mask_bit, int isowner) 724*3eb3c573Smarks { 725*3eb3c573Smarks int set_deny, err_deny; 726*3eb3c573Smarks int set_allow, err_allow; 727*3eb3c573Smarks int acl_consume; 728*3eb3c573Smarks int haswriteperm, hasreadperm; 729*3eb3c573Smarks 730*3eb3c573Smarks if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) { 731*3eb3c573Smarks haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 0 : 1; 732*3eb3c573Smarks hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 0 : 1; 733*3eb3c573Smarks } else { 734*3eb3c573Smarks haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 1 : 0; 735*3eb3c573Smarks hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 1 : 0; 736*3eb3c573Smarks } 737*3eb3c573Smarks 738*3eb3c573Smarks acl_consume = (ACL_SYNCHRONIZE_ERR_DENY | 739*3eb3c573Smarks ACL_DELETE_ERR_DENY | 740*3eb3c573Smarks ACL_WRITE_OWNER_ERR_DENY | 741*3eb3c573Smarks ACL_WRITE_OWNER_ERR_ALLOW | 742*3eb3c573Smarks ACL_WRITE_ATTRS_OWNER_SET_ALLOW | 743*3eb3c573Smarks ACL_WRITE_ATTRS_OWNER_ERR_DENY | 744*3eb3c573Smarks ACL_WRITE_ATTRS_WRITER_SET_DENY | 745*3eb3c573Smarks ACL_WRITE_ATTRS_WRITER_ERR_ALLOW | 746*3eb3c573Smarks ACL_WRITE_NAMED_WRITER_ERR_DENY | 747*3eb3c573Smarks ACL_READ_NAMED_READER_ERR_DENY); 748*3eb3c573Smarks 749*3eb3c573Smarks if (mask_bit == ACE_SYNCHRONIZE) { 750*3eb3c573Smarks set_deny = ACL_SYNCHRONIZE_SET_DENY; 751*3eb3c573Smarks err_deny = ACL_SYNCHRONIZE_ERR_DENY; 752*3eb3c573Smarks set_allow = ACL_SYNCHRONIZE_SET_ALLOW; 753*3eb3c573Smarks err_allow = ACL_SYNCHRONIZE_ERR_ALLOW; 754*3eb3c573Smarks } else if (mask_bit == ACE_WRITE_OWNER) { 755*3eb3c573Smarks set_deny = ACL_WRITE_OWNER_SET_DENY; 756*3eb3c573Smarks err_deny = ACL_WRITE_OWNER_ERR_DENY; 757*3eb3c573Smarks set_allow = ACL_WRITE_OWNER_SET_ALLOW; 758*3eb3c573Smarks err_allow = ACL_WRITE_OWNER_ERR_ALLOW; 759*3eb3c573Smarks } else if (mask_bit == ACE_DELETE) { 760*3eb3c573Smarks set_deny = ACL_DELETE_SET_DENY; 761*3eb3c573Smarks err_deny = ACL_DELETE_ERR_DENY; 762*3eb3c573Smarks set_allow = ACL_DELETE_SET_ALLOW; 763*3eb3c573Smarks err_allow = ACL_DELETE_ERR_ALLOW; 764*3eb3c573Smarks } else if (mask_bit == ACE_WRITE_ATTRIBUTES) { 765*3eb3c573Smarks if (isowner) { 766*3eb3c573Smarks set_deny = ACL_WRITE_ATTRS_OWNER_SET_DENY; 767*3eb3c573Smarks err_deny = ACL_WRITE_ATTRS_OWNER_ERR_DENY; 768*3eb3c573Smarks set_allow = ACL_WRITE_ATTRS_OWNER_SET_ALLOW; 769*3eb3c573Smarks err_allow = ACL_WRITE_ATTRS_OWNER_ERR_ALLOW; 770*3eb3c573Smarks } else if (haswriteperm) { 771*3eb3c573Smarks set_deny = ACL_WRITE_ATTRS_WRITER_SET_DENY; 772*3eb3c573Smarks err_deny = ACL_WRITE_ATTRS_WRITER_ERR_DENY; 773*3eb3c573Smarks set_allow = ACL_WRITE_ATTRS_WRITER_SET_ALLOW; 774*3eb3c573Smarks err_allow = ACL_WRITE_ATTRS_WRITER_ERR_ALLOW; 775*3eb3c573Smarks } else { 776*3eb3c573Smarks if ((acep->a_access_mask & mask_bit) && 777*3eb3c573Smarks (acep->a_type & ACE_ACCESS_ALLOWED_ACE_TYPE)) { 778*3eb3c573Smarks return (ENOTSUP); 779*3eb3c573Smarks } 780*3eb3c573Smarks return (0); 781*3eb3c573Smarks } 782*3eb3c573Smarks } else if (mask_bit == ACE_READ_NAMED_ATTRS) { 783*3eb3c573Smarks if (!hasreadperm) 784*3eb3c573Smarks return (0); 785*3eb3c573Smarks 786*3eb3c573Smarks set_deny = ACL_READ_NAMED_READER_SET_DENY; 787*3eb3c573Smarks err_deny = ACL_READ_NAMED_READER_ERR_DENY; 788*3eb3c573Smarks set_allow = ACL_READ_NAMED_READER_SET_ALLOW; 789*3eb3c573Smarks err_allow = ACL_READ_NAMED_READER_ERR_ALLOW; 790*3eb3c573Smarks } else if (mask_bit == ACE_WRITE_NAMED_ATTRS) { 791*3eb3c573Smarks if (!haswriteperm) 792*3eb3c573Smarks return (0); 793*3eb3c573Smarks 794*3eb3c573Smarks set_deny = ACL_WRITE_NAMED_WRITER_SET_DENY; 795*3eb3c573Smarks err_deny = ACL_WRITE_NAMED_WRITER_ERR_DENY; 796*3eb3c573Smarks set_allow = ACL_WRITE_NAMED_WRITER_SET_ALLOW; 797*3eb3c573Smarks err_allow = ACL_WRITE_NAMED_WRITER_ERR_ALLOW; 798*3eb3c573Smarks } else { 799*3eb3c573Smarks return (EINVAL); 800*3eb3c573Smarks } 801*3eb3c573Smarks 802*3eb3c573Smarks if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) { 803*3eb3c573Smarks if (acl_consume & set_deny) { 804*3eb3c573Smarks if (!(acep->a_access_mask & mask_bit)) { 805*3eb3c573Smarks return (ENOTSUP); 806*3eb3c573Smarks } 807*3eb3c573Smarks } else if (acl_consume & err_deny) { 808*3eb3c573Smarks if (acep->a_access_mask & mask_bit) { 809*3eb3c573Smarks return (ENOTSUP); 810*3eb3c573Smarks } 811*3eb3c573Smarks } 812*3eb3c573Smarks } else { 813*3eb3c573Smarks /* ACE_ACCESS_ALLOWED_ACE_TYPE */ 814*3eb3c573Smarks if (acl_consume & set_allow) { 815*3eb3c573Smarks if (!(acep->a_access_mask & mask_bit)) { 816*3eb3c573Smarks return (ENOTSUP); 817*3eb3c573Smarks } 818*3eb3c573Smarks } else if (acl_consume & err_allow) { 819*3eb3c573Smarks if (acep->a_access_mask & mask_bit) { 820*3eb3c573Smarks return (ENOTSUP); 821*3eb3c573Smarks } 822*3eb3c573Smarks } 823*3eb3c573Smarks } 824*3eb3c573Smarks return (0); 825*3eb3c573Smarks } 826*3eb3c573Smarks 827*3eb3c573Smarks static int 828*3eb3c573Smarks ace_to_aent_legal(ace_t *acep) 829*3eb3c573Smarks { 830*3eb3c573Smarks int error = 0; 831*3eb3c573Smarks int isowner; 832*3eb3c573Smarks 833*3eb3c573Smarks /* only ALLOW or DENY */ 834*3eb3c573Smarks if ((acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE) && 835*3eb3c573Smarks (acep->a_type != ACE_ACCESS_DENIED_ACE_TYPE)) { 836*3eb3c573Smarks error = ENOTSUP; 837*3eb3c573Smarks goto out; 838*3eb3c573Smarks } 839*3eb3c573Smarks 840*3eb3c573Smarks /* check for invalid flags */ 841*3eb3c573Smarks if (acep->a_flags & ~(ACE_VALID_FLAG_BITS)) { 842*3eb3c573Smarks error = EINVAL; 843*3eb3c573Smarks goto out; 844*3eb3c573Smarks } 845*3eb3c573Smarks 846*3eb3c573Smarks /* some flags are illegal */ 847*3eb3c573Smarks if (acep->a_flags & (ACE_SUCCESSFUL_ACCESS_ACE_FLAG | 848*3eb3c573Smarks ACE_FAILED_ACCESS_ACE_FLAG | 849*3eb3c573Smarks ACE_NO_PROPAGATE_INHERIT_ACE)) { 850*3eb3c573Smarks error = ENOTSUP; 851*3eb3c573Smarks goto out; 852*3eb3c573Smarks } 853*3eb3c573Smarks 854*3eb3c573Smarks /* check for invalid masks */ 855*3eb3c573Smarks if (acep->a_access_mask & ~(ACE_VALID_MASK_BITS)) { 856*3eb3c573Smarks error = EINVAL; 857*3eb3c573Smarks goto out; 858*3eb3c573Smarks } 859*3eb3c573Smarks 860*3eb3c573Smarks if ((acep->a_flags & ACE_OWNER)) { 861*3eb3c573Smarks isowner = 1; 862*3eb3c573Smarks } else { 863*3eb3c573Smarks isowner = 0; 864*3eb3c573Smarks } 865*3eb3c573Smarks 866*3eb3c573Smarks error = access_mask_check(acep, ACE_SYNCHRONIZE, isowner); 867*3eb3c573Smarks if (error) 868*3eb3c573Smarks goto out; 869*3eb3c573Smarks 870*3eb3c573Smarks error = access_mask_check(acep, ACE_WRITE_OWNER, isowner); 871*3eb3c573Smarks if (error) 872*3eb3c573Smarks goto out; 873*3eb3c573Smarks 874*3eb3c573Smarks error = access_mask_check(acep, ACE_DELETE, isowner); 875*3eb3c573Smarks if (error) 876*3eb3c573Smarks goto out; 877*3eb3c573Smarks 878*3eb3c573Smarks error = access_mask_check(acep, ACE_WRITE_ATTRIBUTES, isowner); 879*3eb3c573Smarks if (error) 880*3eb3c573Smarks goto out; 881*3eb3c573Smarks 882*3eb3c573Smarks error = access_mask_check(acep, ACE_READ_NAMED_ATTRS, isowner); 883*3eb3c573Smarks if (error) 884*3eb3c573Smarks goto out; 885*3eb3c573Smarks 886*3eb3c573Smarks error = access_mask_check(acep, ACE_WRITE_NAMED_ATTRS, isowner); 887*3eb3c573Smarks if (error) 888*3eb3c573Smarks goto out; 889*3eb3c573Smarks 890*3eb3c573Smarks /* more detailed checking of masks */ 891*3eb3c573Smarks if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) { 892*3eb3c573Smarks if (! (acep->a_access_mask & ACE_READ_ATTRIBUTES)) { 893*3eb3c573Smarks error = ENOTSUP; 894*3eb3c573Smarks goto out; 895*3eb3c573Smarks } 896*3eb3c573Smarks if ((acep->a_access_mask & ACE_WRITE_DATA) && 897*3eb3c573Smarks (! (acep->a_access_mask & ACE_APPEND_DATA))) { 898*3eb3c573Smarks error = ENOTSUP; 899*3eb3c573Smarks goto out; 900*3eb3c573Smarks } 901*3eb3c573Smarks if ((! (acep->a_access_mask & ACE_WRITE_DATA)) && 902*3eb3c573Smarks (acep->a_access_mask & ACE_APPEND_DATA)) { 903*3eb3c573Smarks error = ENOTSUP; 904*3eb3c573Smarks goto out; 905*3eb3c573Smarks } 906*3eb3c573Smarks } 907*3eb3c573Smarks 908*3eb3c573Smarks /* ACL enforcement */ 909*3eb3c573Smarks if ((acep->a_access_mask & ACE_READ_ACL) && 910*3eb3c573Smarks (acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE)) { 911*3eb3c573Smarks error = ENOTSUP; 912*3eb3c573Smarks goto out; 913*3eb3c573Smarks } 914*3eb3c573Smarks if (acep->a_access_mask & ACE_WRITE_ACL) { 915*3eb3c573Smarks if ((acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) && 916*3eb3c573Smarks (isowner)) { 917*3eb3c573Smarks error = ENOTSUP; 918*3eb3c573Smarks goto out; 919*3eb3c573Smarks } 920*3eb3c573Smarks if ((acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) && 921*3eb3c573Smarks (! isowner)) { 922*3eb3c573Smarks error = ENOTSUP; 923*3eb3c573Smarks goto out; 924*3eb3c573Smarks } 925*3eb3c573Smarks } 926*3eb3c573Smarks 927*3eb3c573Smarks out: 928*3eb3c573Smarks return (error); 929*3eb3c573Smarks } 930*3eb3c573Smarks 931*3eb3c573Smarks static int 932*3eb3c573Smarks ace_mask_to_mode(uint32_t mask, o_mode_t *modep, int isdir) 933*3eb3c573Smarks { 934*3eb3c573Smarks int error = 0; 935*3eb3c573Smarks o_mode_t mode = 0; 936*3eb3c573Smarks uint32_t bits, wantbits; 937*3eb3c573Smarks 938*3eb3c573Smarks /* read */ 939*3eb3c573Smarks if (mask & ACE_READ_DATA) 940*3eb3c573Smarks mode |= 04; 941*3eb3c573Smarks 942*3eb3c573Smarks /* write */ 943*3eb3c573Smarks wantbits = (ACE_WRITE_DATA | ACE_APPEND_DATA); 944*3eb3c573Smarks if (isdir) 945*3eb3c573Smarks wantbits |= ACE_DELETE_CHILD; 946*3eb3c573Smarks bits = mask & wantbits; 947*3eb3c573Smarks if (bits != 0) { 948*3eb3c573Smarks if (bits != wantbits) { 949*3eb3c573Smarks error = ENOTSUP; 950*3eb3c573Smarks goto out; 951*3eb3c573Smarks } 952*3eb3c573Smarks mode |= 02; 953*3eb3c573Smarks } 954*3eb3c573Smarks 955*3eb3c573Smarks /* exec */ 956*3eb3c573Smarks if (mask & ACE_EXECUTE) { 957*3eb3c573Smarks mode |= 01; 958*3eb3c573Smarks } 959*3eb3c573Smarks 960*3eb3c573Smarks *modep = mode; 961*3eb3c573Smarks 962*3eb3c573Smarks out: 963*3eb3c573Smarks return (error); 964*3eb3c573Smarks } 965*3eb3c573Smarks 966*3eb3c573Smarks static int 967*3eb3c573Smarks ace_allow_to_mode(uint32_t mask, o_mode_t *modep, int isdir) 968*3eb3c573Smarks { 969*3eb3c573Smarks /* ACE_READ_ACL and ACE_READ_ATTRIBUTES must both be set */ 970*3eb3c573Smarks if ((mask & (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) != 971*3eb3c573Smarks (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) { 972*3eb3c573Smarks return (ENOTSUP); 973*3eb3c573Smarks } 974*3eb3c573Smarks 975*3eb3c573Smarks return (ace_mask_to_mode(mask, modep, isdir)); 976*3eb3c573Smarks } 977*3eb3c573Smarks 978*3eb3c573Smarks static int 979*3eb3c573Smarks acevals_to_aent(acevals_t *vals, aclent_t *dest, ace_list_t *list, 980*3eb3c573Smarks uid_t owner, gid_t group, int isdir) 981*3eb3c573Smarks { 982*3eb3c573Smarks int error; 983*3eb3c573Smarks uint32_t flips = ACE_POSIX_SUPPORTED_BITS; 984*3eb3c573Smarks 985*3eb3c573Smarks if (isdir) 986*3eb3c573Smarks flips |= ACE_DELETE_CHILD; 987*3eb3c573Smarks if (vals->allowed != (vals->denied ^ flips)) { 988*3eb3c573Smarks error = ENOTSUP; 989*3eb3c573Smarks goto out; 990*3eb3c573Smarks } 991*3eb3c573Smarks if ((list->hasmask) && (list->acl_mask != vals->mask) && 992*3eb3c573Smarks (vals->aent_type & (USER | GROUP | GROUP_OBJ))) { 993*3eb3c573Smarks error = ENOTSUP; 994*3eb3c573Smarks goto out; 995*3eb3c573Smarks } 996*3eb3c573Smarks error = ace_allow_to_mode(vals->allowed, &dest->a_perm, isdir); 997*3eb3c573Smarks if (error != 0) 998*3eb3c573Smarks goto out; 999*3eb3c573Smarks dest->a_type = vals->aent_type; 1000*3eb3c573Smarks if (dest->a_type & (USER | GROUP)) { 1001*3eb3c573Smarks dest->a_id = vals->key; 1002*3eb3c573Smarks } else if (dest->a_type & USER_OBJ) { 1003*3eb3c573Smarks dest->a_id = owner; 1004*3eb3c573Smarks } else if (dest->a_type & GROUP_OBJ) { 1005*3eb3c573Smarks dest->a_id = group; 1006*3eb3c573Smarks } else if (dest->a_type & OTHER_OBJ) { 1007*3eb3c573Smarks dest->a_id = 0; 1008*3eb3c573Smarks } else { 1009*3eb3c573Smarks error = EINVAL; 1010*3eb3c573Smarks goto out; 1011*3eb3c573Smarks } 1012*3eb3c573Smarks 1013*3eb3c573Smarks out: 1014*3eb3c573Smarks return (error); 1015*3eb3c573Smarks } 1016*3eb3c573Smarks 1017*3eb3c573Smarks static int 1018*3eb3c573Smarks ace_list_to_aent(ace_list_t *list, aclent_t **aclentp, int *aclcnt, 1019*3eb3c573Smarks uid_t owner, gid_t group, int isdir) 1020*3eb3c573Smarks { 1021*3eb3c573Smarks int error = 0; 1022*3eb3c573Smarks aclent_t *aent, *result = NULL; 1023*3eb3c573Smarks acevals_t *vals; 1024*3eb3c573Smarks int resultcount; 1025*3eb3c573Smarks 1026*3eb3c573Smarks if ((list->seen & (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) != 1027*3eb3c573Smarks (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) { 1028*3eb3c573Smarks error = ENOTSUP; 1029*3eb3c573Smarks goto out; 1030*3eb3c573Smarks } 1031*3eb3c573Smarks if ((! list->hasmask) && (list->numusers + list->numgroups > 0)) { 1032*3eb3c573Smarks error = ENOTSUP; 1033*3eb3c573Smarks goto out; 1034*3eb3c573Smarks } 1035*3eb3c573Smarks 1036*3eb3c573Smarks resultcount = 3 + list->numusers + list->numgroups; 1037*3eb3c573Smarks /* 1038*3eb3c573Smarks * This must be the same condition as below, when we add the CLASS_OBJ 1039*3eb3c573Smarks * (aka ACL mask) 1040*3eb3c573Smarks */ 1041*3eb3c573Smarks if ((list->hasmask) || (! list->dfacl_flag)) 1042*3eb3c573Smarks resultcount += 1; 1043*3eb3c573Smarks 1044*3eb3c573Smarks result = aent = calloc(1, resultcount * sizeof (aclent_t)); 1045*3eb3c573Smarks 1046*3eb3c573Smarks if (result == NULL) { 1047*3eb3c573Smarks error = ENOMEM; 1048*3eb3c573Smarks goto out; 1049*3eb3c573Smarks } 1050*3eb3c573Smarks 1051*3eb3c573Smarks /* USER_OBJ */ 1052*3eb3c573Smarks if (!(list->user_obj.aent_type & USER_OBJ)) { 1053*3eb3c573Smarks error = EINVAL; 1054*3eb3c573Smarks goto out; 1055*3eb3c573Smarks } 1056*3eb3c573Smarks 1057*3eb3c573Smarks error = acevals_to_aent(&list->user_obj, aent, list, owner, group, 1058*3eb3c573Smarks isdir); 1059*3eb3c573Smarks 1060*3eb3c573Smarks if (error != 0) 1061*3eb3c573Smarks goto out; 1062*3eb3c573Smarks ++aent; 1063*3eb3c573Smarks /* USER */ 1064*3eb3c573Smarks vals = NULL; 1065*3eb3c573Smarks for (vals = avl_first(&list->user); vals != NULL; 1066*3eb3c573Smarks vals = AVL_NEXT(&list->user, vals)) { 1067*3eb3c573Smarks if (!(vals->aent_type & USER)) { 1068*3eb3c573Smarks error = EINVAL; 1069*3eb3c573Smarks goto out; 1070*3eb3c573Smarks } 1071*3eb3c573Smarks error = acevals_to_aent(vals, aent, list, owner, group, 1072*3eb3c573Smarks isdir); 1073*3eb3c573Smarks if (error != 0) 1074*3eb3c573Smarks goto out; 1075*3eb3c573Smarks ++aent; 1076*3eb3c573Smarks } 1077*3eb3c573Smarks /* GROUP_OBJ */ 1078*3eb3c573Smarks if (!(list->group_obj.aent_type & GROUP_OBJ)) { 1079*3eb3c573Smarks error = EINVAL; 1080*3eb3c573Smarks goto out; 1081*3eb3c573Smarks } 1082*3eb3c573Smarks error = acevals_to_aent(&list->group_obj, aent, list, owner, group, 1083*3eb3c573Smarks isdir); 1084*3eb3c573Smarks if (error != 0) 1085*3eb3c573Smarks goto out; 1086*3eb3c573Smarks ++aent; 1087*3eb3c573Smarks /* GROUP */ 1088*3eb3c573Smarks vals = NULL; 1089*3eb3c573Smarks for (vals = avl_first(&list->group); vals != NULL; 1090*3eb3c573Smarks vals = AVL_NEXT(&list->group, vals)) { 1091*3eb3c573Smarks if (!(vals->aent_type & GROUP)) { 1092*3eb3c573Smarks error = EINVAL; 1093*3eb3c573Smarks goto out; 1094*3eb3c573Smarks } 1095*3eb3c573Smarks error = acevals_to_aent(vals, aent, list, owner, group, 1096*3eb3c573Smarks isdir); 1097*3eb3c573Smarks if (error != 0) 1098*3eb3c573Smarks goto out; 1099*3eb3c573Smarks ++aent; 1100*3eb3c573Smarks } 1101*3eb3c573Smarks /* 1102*3eb3c573Smarks * CLASS_OBJ (aka ACL_MASK) 1103*3eb3c573Smarks * 1104*3eb3c573Smarks * An ACL_MASK is not fabricated if the ACL is a default ACL. 1105*3eb3c573Smarks * This is to follow UFS's behavior. 1106*3eb3c573Smarks */ 1107*3eb3c573Smarks if ((list->hasmask) || (! list->dfacl_flag)) { 1108*3eb3c573Smarks if (list->hasmask) { 1109*3eb3c573Smarks uint32_t flips = ACE_POSIX_SUPPORTED_BITS; 1110*3eb3c573Smarks if (isdir) 1111*3eb3c573Smarks flips |= ACE_DELETE_CHILD; 1112*3eb3c573Smarks error = ace_mask_to_mode(list->acl_mask ^ flips, 1113*3eb3c573Smarks &aent->a_perm, isdir); 1114*3eb3c573Smarks if (error != 0) 1115*3eb3c573Smarks goto out; 1116*3eb3c573Smarks } else { 1117*3eb3c573Smarks /* fabricate the ACL_MASK from the group permissions */ 1118*3eb3c573Smarks error = ace_mask_to_mode(list->group_obj.allowed, 1119*3eb3c573Smarks &aent->a_perm, isdir); 1120*3eb3c573Smarks if (error != 0) 1121*3eb3c573Smarks goto out; 1122*3eb3c573Smarks } 1123*3eb3c573Smarks aent->a_id = 0; 1124*3eb3c573Smarks aent->a_type = CLASS_OBJ | list->dfacl_flag; 1125*3eb3c573Smarks ++aent; 1126*3eb3c573Smarks } 1127*3eb3c573Smarks /* OTHER_OBJ */ 1128*3eb3c573Smarks if (!(list->other_obj.aent_type & OTHER_OBJ)) { 1129*3eb3c573Smarks error = EINVAL; 1130*3eb3c573Smarks goto out; 1131*3eb3c573Smarks } 1132*3eb3c573Smarks error = acevals_to_aent(&list->other_obj, aent, list, owner, group, 1133*3eb3c573Smarks isdir); 1134*3eb3c573Smarks if (error != 0) 1135*3eb3c573Smarks goto out; 1136*3eb3c573Smarks ++aent; 1137*3eb3c573Smarks 1138*3eb3c573Smarks *aclentp = result; 1139*3eb3c573Smarks *aclcnt = resultcount; 1140*3eb3c573Smarks 1141*3eb3c573Smarks out: 1142*3eb3c573Smarks if (error != 0) { 1143*3eb3c573Smarks if (result != NULL) 1144*3eb3c573Smarks free(result); 1145*3eb3c573Smarks } 1146*3eb3c573Smarks 1147*3eb3c573Smarks return (error); 1148*3eb3c573Smarks } 1149*3eb3c573Smarks 1150*3eb3c573Smarks /* 1151*3eb3c573Smarks * free all data associated with an ace_list 1152*3eb3c573Smarks */ 1153*3eb3c573Smarks static void 1154*3eb3c573Smarks ace_list_free(ace_list_t *al) 1155*3eb3c573Smarks { 1156*3eb3c573Smarks acevals_t *node; 1157*3eb3c573Smarks void *cookie; 1158*3eb3c573Smarks 1159*3eb3c573Smarks if (al == NULL) 1160*3eb3c573Smarks return; 1161*3eb3c573Smarks 1162*3eb3c573Smarks cookie = NULL; 1163*3eb3c573Smarks while ((node = avl_destroy_nodes(&al->user, &cookie)) != NULL) 1164*3eb3c573Smarks free(node); 1165*3eb3c573Smarks cookie = NULL; 1166*3eb3c573Smarks while ((node = avl_destroy_nodes(&al->group, &cookie)) != NULL) 1167*3eb3c573Smarks free(node); 1168*3eb3c573Smarks 1169*3eb3c573Smarks avl_destroy(&al->user); 1170*3eb3c573Smarks avl_destroy(&al->group); 1171*3eb3c573Smarks 1172*3eb3c573Smarks /* free the container itself */ 1173*3eb3c573Smarks free(al); 1174*3eb3c573Smarks } 1175*3eb3c573Smarks 1176*3eb3c573Smarks static int 1177*3eb3c573Smarks acevals_compare(const void *va, const void *vb) 1178*3eb3c573Smarks { 1179*3eb3c573Smarks const acevals_t *a = va, *b = vb; 1180*3eb3c573Smarks 1181*3eb3c573Smarks if (a->key == b->key) 1182*3eb3c573Smarks return (0); 1183*3eb3c573Smarks 1184*3eb3c573Smarks if (a->key > b->key) 1185*3eb3c573Smarks return (1); 1186*3eb3c573Smarks 1187*3eb3c573Smarks else 1188*3eb3c573Smarks return (-1); 1189*3eb3c573Smarks } 1190*3eb3c573Smarks 1191*3eb3c573Smarks /* 1192*3eb3c573Smarks * Convert a list of ace_t entries to equivalent regular and default 1193*3eb3c573Smarks * aclent_t lists. Return error (ENOTSUP) when conversion is not possible. 1194*3eb3c573Smarks */ 1195*3eb3c573Smarks static int 1196*3eb3c573Smarks ln_ace_to_aent(ace_t *ace, int n, uid_t owner, gid_t group, 1197*3eb3c573Smarks aclent_t **aclentp, int *aclcnt, aclent_t **dfaclentp, int *dfaclcnt, 1198*3eb3c573Smarks int isdir) 1199*3eb3c573Smarks { 1200*3eb3c573Smarks int error = 0; 1201*3eb3c573Smarks ace_t *acep; 1202*3eb3c573Smarks uint32_t bits; 1203*3eb3c573Smarks int i; 1204*3eb3c573Smarks ace_list_t *normacl = NULL, *dfacl = NULL, *acl; 1205*3eb3c573Smarks acevals_t *vals; 1206*3eb3c573Smarks 1207*3eb3c573Smarks *aclentp = NULL; 1208*3eb3c573Smarks *aclcnt = 0; 1209*3eb3c573Smarks *dfaclentp = NULL; 1210*3eb3c573Smarks *dfaclcnt = 0; 1211*3eb3c573Smarks 1212*3eb3c573Smarks /* we need at least user_obj, group_obj, and other_obj */ 1213*3eb3c573Smarks if (n < 6) { 1214*3eb3c573Smarks error = ENOTSUP; 1215*3eb3c573Smarks goto out; 1216*3eb3c573Smarks } 1217*3eb3c573Smarks if (ace == NULL) { 1218*3eb3c573Smarks error = EINVAL; 1219*3eb3c573Smarks goto out; 1220*3eb3c573Smarks } 1221*3eb3c573Smarks 1222*3eb3c573Smarks normacl = calloc(1, sizeof (ace_list_t)); 1223*3eb3c573Smarks 1224*3eb3c573Smarks if (normacl == NULL) { 1225*3eb3c573Smarks error = errno; 1226*3eb3c573Smarks goto out; 1227*3eb3c573Smarks } 1228*3eb3c573Smarks 1229*3eb3c573Smarks avl_create(&normacl->user, acevals_compare, sizeof (acevals_t), 1230*3eb3c573Smarks offsetof(acevals_t, avl)); 1231*3eb3c573Smarks avl_create(&normacl->group, acevals_compare, sizeof (acevals_t), 1232*3eb3c573Smarks offsetof(acevals_t, avl)); 1233*3eb3c573Smarks 1234*3eb3c573Smarks ace_list_init(normacl, 0); 1235*3eb3c573Smarks 1236*3eb3c573Smarks dfacl = calloc(1, sizeof (ace_list_t)); 1237*3eb3c573Smarks if (dfacl == NULL) { 1238*3eb3c573Smarks error = errno; 1239*3eb3c573Smarks goto out; 1240*3eb3c573Smarks } 1241*3eb3c573Smarks avl_create(&dfacl->user, acevals_compare, sizeof (acevals_t), 1242*3eb3c573Smarks offsetof(acevals_t, avl)); 1243*3eb3c573Smarks avl_create(&dfacl->group, acevals_compare, sizeof (acevals_t), 1244*3eb3c573Smarks offsetof(acevals_t, avl)); 1245*3eb3c573Smarks ace_list_init(dfacl, ACL_DEFAULT); 1246*3eb3c573Smarks 1247*3eb3c573Smarks /* process every ace_t... */ 1248*3eb3c573Smarks for (i = 0; i < n; i++) { 1249*3eb3c573Smarks acep = &ace[i]; 1250*3eb3c573Smarks 1251*3eb3c573Smarks /* rule out certain cases quickly */ 1252*3eb3c573Smarks error = ace_to_aent_legal(acep); 1253*3eb3c573Smarks if (error != 0) 1254*3eb3c573Smarks goto out; 1255*3eb3c573Smarks 1256*3eb3c573Smarks /* 1257*3eb3c573Smarks * Turn off these bits in order to not have to worry about 1258*3eb3c573Smarks * them when doing the checks for compliments. 1259*3eb3c573Smarks */ 1260*3eb3c573Smarks acep->a_access_mask &= ~(ACE_WRITE_OWNER | ACE_DELETE | 1261*3eb3c573Smarks ACE_SYNCHRONIZE | ACE_WRITE_ATTRIBUTES | 1262*3eb3c573Smarks ACE_READ_NAMED_ATTRS | ACE_WRITE_NAMED_ATTRS); 1263*3eb3c573Smarks 1264*3eb3c573Smarks /* see if this should be a regular or default acl */ 1265*3eb3c573Smarks bits = acep->a_flags & 1266*3eb3c573Smarks (ACE_INHERIT_ONLY_ACE | 1267*3eb3c573Smarks ACE_FILE_INHERIT_ACE | 1268*3eb3c573Smarks ACE_DIRECTORY_INHERIT_ACE); 1269*3eb3c573Smarks if (bits != 0) { 1270*3eb3c573Smarks /* all or nothing on these inherit bits */ 1271*3eb3c573Smarks if (bits != (ACE_INHERIT_ONLY_ACE | 1272*3eb3c573Smarks ACE_FILE_INHERIT_ACE | 1273*3eb3c573Smarks ACE_DIRECTORY_INHERIT_ACE)) { 1274*3eb3c573Smarks error = ENOTSUP; 1275*3eb3c573Smarks goto out; 1276*3eb3c573Smarks } 1277*3eb3c573Smarks acl = dfacl; 1278*3eb3c573Smarks } else { 1279*3eb3c573Smarks acl = normacl; 1280*3eb3c573Smarks } 1281*3eb3c573Smarks 1282*3eb3c573Smarks if ((acep->a_flags & ACE_OWNER)) { 1283*3eb3c573Smarks if (acl->state > ace_user_obj) { 1284*3eb3c573Smarks error = ENOTSUP; 1285*3eb3c573Smarks goto out; 1286*3eb3c573Smarks } 1287*3eb3c573Smarks acl->state = ace_user_obj; 1288*3eb3c573Smarks acl->seen |= USER_OBJ; 1289*3eb3c573Smarks vals = &acl->user_obj; 1290*3eb3c573Smarks vals->aent_type = USER_OBJ | acl->dfacl_flag; 1291*3eb3c573Smarks } else if ((acep->a_flags & ACE_EVERYONE)) { 1292*3eb3c573Smarks acl->state = ace_other_obj; 1293*3eb3c573Smarks acl->seen |= OTHER_OBJ; 1294*3eb3c573Smarks vals = &acl->other_obj; 1295*3eb3c573Smarks vals->aent_type = OTHER_OBJ | acl->dfacl_flag; 1296*3eb3c573Smarks } else if (acep->a_flags & ACE_IDENTIFIER_GROUP) { 1297*3eb3c573Smarks if (acl->state > ace_group) { 1298*3eb3c573Smarks error = ENOTSUP; 1299*3eb3c573Smarks goto out; 1300*3eb3c573Smarks } 1301*3eb3c573Smarks if ((acep->a_flags & ACE_GROUP)) { 1302*3eb3c573Smarks acl->seen |= GROUP_OBJ; 1303*3eb3c573Smarks vals = &acl->group_obj; 1304*3eb3c573Smarks vals->aent_type = GROUP_OBJ | acl->dfacl_flag; 1305*3eb3c573Smarks } else { 1306*3eb3c573Smarks acl->seen |= GROUP; 1307*3eb3c573Smarks vals = acevals_find(acep, &acl->group, 1308*3eb3c573Smarks &acl->numgroups); 1309*3eb3c573Smarks if (vals == NULL) { 1310*3eb3c573Smarks error = ENOMEM; 1311*3eb3c573Smarks goto out; 1312*3eb3c573Smarks } 1313*3eb3c573Smarks vals->aent_type = GROUP | acl->dfacl_flag; 1314*3eb3c573Smarks } 1315*3eb3c573Smarks acl->state = ace_group; 1316*3eb3c573Smarks } else { 1317*3eb3c573Smarks if (acl->state > ace_user) { 1318*3eb3c573Smarks error = ENOTSUP; 1319*3eb3c573Smarks goto out; 1320*3eb3c573Smarks } 1321*3eb3c573Smarks acl->state = ace_user; 1322*3eb3c573Smarks acl->seen |= USER; 1323*3eb3c573Smarks vals = acevals_find(acep, &acl->user, 1324*3eb3c573Smarks &acl->numusers); 1325*3eb3c573Smarks if (vals == NULL) { 1326*3eb3c573Smarks error = ENOMEM; 1327*3eb3c573Smarks goto out; 1328*3eb3c573Smarks } 1329*3eb3c573Smarks vals->aent_type = USER | acl->dfacl_flag; 1330*3eb3c573Smarks } 1331*3eb3c573Smarks 1332*3eb3c573Smarks if (!(acl->state > ace_unused)) { 1333*3eb3c573Smarks error = EINVAL; 1334*3eb3c573Smarks goto out; 1335*3eb3c573Smarks } 1336*3eb3c573Smarks 1337*3eb3c573Smarks if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) { 1338*3eb3c573Smarks /* no more than one allowed per aclent_t */ 1339*3eb3c573Smarks if (vals->allowed != ACE_MASK_UNDEFINED) { 1340*3eb3c573Smarks error = ENOTSUP; 1341*3eb3c573Smarks goto out; 1342*3eb3c573Smarks } 1343*3eb3c573Smarks vals->allowed = acep->a_access_mask; 1344*3eb3c573Smarks } else { 1345*3eb3c573Smarks /* 1346*3eb3c573Smarks * it's a DENY; if there was a previous DENY, it 1347*3eb3c573Smarks * must have been an ACL_MASK. 1348*3eb3c573Smarks */ 1349*3eb3c573Smarks if (vals->denied != ACE_MASK_UNDEFINED) { 1350*3eb3c573Smarks /* ACL_MASK is for USER and GROUP only */ 1351*3eb3c573Smarks if ((acl->state != ace_user) && 1352*3eb3c573Smarks (acl->state != ace_group)) { 1353*3eb3c573Smarks error = ENOTSUP; 1354*3eb3c573Smarks goto out; 1355*3eb3c573Smarks } 1356*3eb3c573Smarks 1357*3eb3c573Smarks if (! acl->hasmask) { 1358*3eb3c573Smarks acl->hasmask = 1; 1359*3eb3c573Smarks acl->acl_mask = vals->denied; 1360*3eb3c573Smarks /* check for mismatched ACL_MASK emulations */ 1361*3eb3c573Smarks } else if (acl->acl_mask != vals->denied) { 1362*3eb3c573Smarks error = ENOTSUP; 1363*3eb3c573Smarks goto out; 1364*3eb3c573Smarks } 1365*3eb3c573Smarks vals->mask = vals->denied; 1366*3eb3c573Smarks } 1367*3eb3c573Smarks vals->denied = acep->a_access_mask; 1368*3eb3c573Smarks } 1369*3eb3c573Smarks } 1370*3eb3c573Smarks 1371*3eb3c573Smarks /* done collating; produce the aclent_t lists */ 1372*3eb3c573Smarks if (normacl->state != ace_unused) { 1373*3eb3c573Smarks error = ace_list_to_aent(normacl, aclentp, aclcnt, 1374*3eb3c573Smarks owner, group, isdir); 1375*3eb3c573Smarks if (error != 0) { 1376*3eb3c573Smarks goto out; 1377*3eb3c573Smarks } 1378*3eb3c573Smarks } 1379*3eb3c573Smarks if (dfacl->state != ace_unused) { 1380*3eb3c573Smarks error = ace_list_to_aent(dfacl, dfaclentp, dfaclcnt, 1381*3eb3c573Smarks owner, group, isdir); 1382*3eb3c573Smarks if (error != 0) { 1383*3eb3c573Smarks goto out; 1384*3eb3c573Smarks } 1385*3eb3c573Smarks } 1386*3eb3c573Smarks 1387*3eb3c573Smarks out: 1388*3eb3c573Smarks if (normacl != NULL) 1389*3eb3c573Smarks ace_list_free(normacl); 1390*3eb3c573Smarks if (dfacl != NULL) 1391*3eb3c573Smarks ace_list_free(dfacl); 1392*3eb3c573Smarks 1393*3eb3c573Smarks return (error); 1394*3eb3c573Smarks } 1395*3eb3c573Smarks 1396*3eb3c573Smarks static int 1397*3eb3c573Smarks convert_ace_to_aent(ace_t *acebufp, int acecnt, int isdir, 1398*3eb3c573Smarks uid_t owner, gid_t group, aclent_t **retaclentp, int *retaclcnt) 1399*3eb3c573Smarks { 1400*3eb3c573Smarks int error; 1401*3eb3c573Smarks aclent_t *aclentp, *dfaclentp; 1402*3eb3c573Smarks int aclcnt, dfaclcnt; 1403*3eb3c573Smarks 1404*3eb3c573Smarks error = ln_ace_to_aent(acebufp, acecnt, owner, group, 1405*3eb3c573Smarks &aclentp, &aclcnt, &dfaclentp, &dfaclcnt, isdir); 1406*3eb3c573Smarks 1407*3eb3c573Smarks if (error) 1408*3eb3c573Smarks return (error); 1409*3eb3c573Smarks 1410*3eb3c573Smarks 1411*3eb3c573Smarks if (dfaclcnt != 0) { 1412*3eb3c573Smarks /* 1413*3eb3c573Smarks * Slap aclentp and dfaclentp into a single array. 1414*3eb3c573Smarks */ 1415*3eb3c573Smarks aclentp = realloc(aclentp, (sizeof (aclent_t) * aclcnt) + 1416*3eb3c573Smarks (sizeof (aclent_t) * dfaclcnt)); 1417*3eb3c573Smarks if (aclentp != NULL) { 1418*3eb3c573Smarks (void) memcpy(aclentp + aclcnt, 1419*3eb3c573Smarks dfaclentp, sizeof (aclent_t) * dfaclcnt); 1420*3eb3c573Smarks } else { 1421*3eb3c573Smarks error = -1; 1422*3eb3c573Smarks } 1423*3eb3c573Smarks } 1424*3eb3c573Smarks 1425*3eb3c573Smarks if (aclentp) { 1426*3eb3c573Smarks *retaclentp = aclentp; 1427*3eb3c573Smarks *retaclcnt = aclcnt + dfaclcnt; 1428*3eb3c573Smarks } 1429*3eb3c573Smarks 1430*3eb3c573Smarks if (dfaclentp) 1431*3eb3c573Smarks free(dfaclentp); 1432*3eb3c573Smarks 1433*3eb3c573Smarks return (error); 1434*3eb3c573Smarks } 1435*3eb3c573Smarks 1436fa9e4066Sahrens cacl_get(acl_inp inp, int get_flag, int type, acl_t **aclp) 1437fa9e4066Sahrens { 1438fa9e4066Sahrens const char *fname; 1439fa9e4066Sahrens int fd; 1440fa9e4066Sahrens int ace_acl = 0; 1441fa9e4066Sahrens int error; 1442fa9e4066Sahrens int getcmd, cntcmd; 1443fa9e4066Sahrens acl_t *acl_info; 1444fa9e4066Sahrens int save_errno; 1445fa9e4066Sahrens int stat_error; 1446fa9e4066Sahrens struct stat64 statbuf; 1447fa9e4066Sahrens 1448fa9e4066Sahrens *aclp = NULL; 1449fa9e4066Sahrens if (type == ACL_PATH) { 1450fa9e4066Sahrens fname = inp.file; 1451fa9e4066Sahrens ace_acl = pathconf(fname, _PC_ACL_ENABLED); 1452fa9e4066Sahrens } else { 1453fa9e4066Sahrens fd = inp.fd; 1454fa9e4066Sahrens ace_acl = fpathconf(fd, _PC_ACL_ENABLED); 1455fa9e4066Sahrens } 1456fa9e4066Sahrens 1457fa9e4066Sahrens if (ace_acl == -1) 1458fa9e4066Sahrens return (-1); 1459fa9e4066Sahrens 1460fa9e4066Sahrens /* 1461fa9e4066Sahrens * if acl's aren't supported then 1462fa9e4066Sahrens * send it through the old GETACL interface 1463fa9e4066Sahrens */ 1464fa9e4066Sahrens if (ace_acl == 0) { 1465fa9e4066Sahrens ace_acl = _ACL_ACLENT_ENABLED; 1466fa9e4066Sahrens } 1467fa9e4066Sahrens 1468fa9e4066Sahrens if (ace_acl & _ACL_ACE_ENABLED) { 1469fa9e4066Sahrens cntcmd = ACE_GETACLCNT; 1470fa9e4066Sahrens getcmd = ACE_GETACL; 1471fa9e4066Sahrens acl_info = acl_alloc(ACE_T); 1472fa9e4066Sahrens } else { 1473fa9e4066Sahrens cntcmd = GETACLCNT; 1474fa9e4066Sahrens getcmd = GETACL; 1475fa9e4066Sahrens acl_info = acl_alloc(ACLENT_T); 1476fa9e4066Sahrens } 1477fa9e4066Sahrens 1478fa9e4066Sahrens if (acl_info == NULL) 1479fa9e4066Sahrens return (-1); 1480fa9e4066Sahrens 1481fa9e4066Sahrens if (type == ACL_PATH) { 1482fa9e4066Sahrens acl_info->acl_cnt = acl(fname, cntcmd, 0, NULL); 1483fa9e4066Sahrens } else { 1484fa9e4066Sahrens acl_info->acl_cnt = facl(fd, cntcmd, 0, NULL); 1485fa9e4066Sahrens } 1486fa9e4066Sahrens 1487fa9e4066Sahrens save_errno = errno; 1488fa9e4066Sahrens if (acl_info->acl_cnt < 0) { 1489fa9e4066Sahrens acl_free(acl_info); 1490fa9e4066Sahrens errno = save_errno; 1491fa9e4066Sahrens return (-1); 1492fa9e4066Sahrens } 1493fa9e4066Sahrens 1494fa9e4066Sahrens if (acl_info->acl_cnt == 0) { 1495fa9e4066Sahrens acl_free(acl_info); 1496fa9e4066Sahrens errno = save_errno; 1497fa9e4066Sahrens return (0); 1498fa9e4066Sahrens } 1499fa9e4066Sahrens 1500fa9e4066Sahrens acl_info->acl_aclp = 1501fa9e4066Sahrens malloc(acl_info->acl_cnt * acl_info->acl_entry_size); 1502fa9e4066Sahrens save_errno = errno; 1503fa9e4066Sahrens 1504fa9e4066Sahrens if (acl_info->acl_aclp == NULL) { 1505fa9e4066Sahrens acl_free(acl_info); 1506fa9e4066Sahrens errno = save_errno; 1507fa9e4066Sahrens return (-1); 1508fa9e4066Sahrens } 1509fa9e4066Sahrens 1510fa9e4066Sahrens if (type == ACL_PATH) { 1511fa9e4066Sahrens stat_error = stat64(fname, &statbuf); 1512fa9e4066Sahrens error = acl(fname, getcmd, acl_info->acl_cnt, 1513fa9e4066Sahrens acl_info->acl_aclp); 1514fa9e4066Sahrens } else { 1515fa9e4066Sahrens stat_error = fstat64(fd, &statbuf); 1516fa9e4066Sahrens error = facl(fd, getcmd, acl_info->acl_cnt, 1517fa9e4066Sahrens acl_info->acl_aclp); 1518fa9e4066Sahrens } 1519fa9e4066Sahrens 1520fa9e4066Sahrens save_errno = errno; 1521fa9e4066Sahrens if (error == -1) { 1522fa9e4066Sahrens acl_free(acl_info); 1523fa9e4066Sahrens errno = save_errno; 1524fa9e4066Sahrens return (-1); 1525fa9e4066Sahrens } 1526fa9e4066Sahrens 1527fa9e4066Sahrens 1528fa9e4066Sahrens if (stat_error == 0) { 1529fa9e4066Sahrens acl_info->acl_flags = 1530fa9e4066Sahrens (S_ISDIR(statbuf.st_mode) ? ACL_IS_DIR : 0); 1531fa9e4066Sahrens } else 1532fa9e4066Sahrens acl_info->acl_flags = 0; 1533fa9e4066Sahrens 1534fa9e4066Sahrens switch (acl_info->acl_type) { 1535fa9e4066Sahrens case ACLENT_T: 1536fa9e4066Sahrens if (acl_info->acl_cnt <= MIN_ACL_ENTRIES) 1537fa9e4066Sahrens acl_info->acl_flags |= ACL_IS_TRIVIAL; 1538fa9e4066Sahrens break; 1539fa9e4066Sahrens case ACE_T: 1540fa9e4066Sahrens if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0) 1541fa9e4066Sahrens acl_info->acl_flags |= ACL_IS_TRIVIAL; 1542fa9e4066Sahrens break; 1543fa9e4066Sahrens default: 1544fa9e4066Sahrens errno = EINVAL; 1545fa9e4066Sahrens acl_free(acl_info); 1546fa9e4066Sahrens return (-1); 1547fa9e4066Sahrens } 1548fa9e4066Sahrens 1549fa9e4066Sahrens if ((acl_info->acl_flags & ACL_IS_TRIVIAL) && 1550fa9e4066Sahrens (get_flag & ACL_NO_TRIVIAL)) { 1551fa9e4066Sahrens acl_free(acl_info); 1552fa9e4066Sahrens errno = 0; 1553fa9e4066Sahrens return (0); 1554fa9e4066Sahrens } 1555fa9e4066Sahrens 1556fa9e4066Sahrens *aclp = acl_info; 1557fa9e4066Sahrens return (0); 1558fa9e4066Sahrens } 1559fa9e4066Sahrens 1560fa9e4066Sahrens /* 1561fa9e4066Sahrens * return -1 on failure, otherwise the number of acl 1562fa9e4066Sahrens * entries is returned 1563fa9e4066Sahrens */ 1564fa9e4066Sahrens int 1565fa9e4066Sahrens acl_get(const char *path, int get_flag, acl_t **aclp) 1566fa9e4066Sahrens { 1567fa9e4066Sahrens acl_inp acl_inp; 1568fa9e4066Sahrens acl_inp.file = path; 1569fa9e4066Sahrens 1570fa9e4066Sahrens return (cacl_get(acl_inp, get_flag, ACL_PATH, aclp)); 1571fa9e4066Sahrens } 1572fa9e4066Sahrens 1573fa9e4066Sahrens int 1574fa9e4066Sahrens facl_get(int fd, int get_flag, acl_t **aclp) 1575fa9e4066Sahrens { 1576fa9e4066Sahrens 1577fa9e4066Sahrens acl_inp acl_inp; 1578fa9e4066Sahrens acl_inp.fd = fd; 1579fa9e4066Sahrens 1580fa9e4066Sahrens return (cacl_get(acl_inp, get_flag, ACL_FD, aclp)); 1581fa9e4066Sahrens } 1582fa9e4066Sahrens 1583*3eb3c573Smarks static int 1584*3eb3c573Smarks acl_translate(acl_t *aclp, int target_flavor, int isdir, uid_t owner, 1585*3eb3c573Smarks gid_t group) 1586*3eb3c573Smarks { 1587*3eb3c573Smarks int aclcnt; 1588*3eb3c573Smarks void *acldata; 1589*3eb3c573Smarks int error; 1590*3eb3c573Smarks 1591*3eb3c573Smarks /* 1592*3eb3c573Smarks * See if we need to translate 1593*3eb3c573Smarks */ 1594*3eb3c573Smarks if ((target_flavor == _ACL_ACE_ENABLED && aclp->acl_type == ACE_T) || 1595*3eb3c573Smarks (target_flavor == _ACL_ACLENT_ENABLED && 1596*3eb3c573Smarks aclp->acl_type == ACLENT_T)) 1597*3eb3c573Smarks return (0); 1598*3eb3c573Smarks 1599*3eb3c573Smarks if (target_flavor == -1) 1600*3eb3c573Smarks return (-1); 1601*3eb3c573Smarks 1602*3eb3c573Smarks if (target_flavor == _ACL_ACE_ENABLED && 1603*3eb3c573Smarks aclp->acl_type == ACLENT_T) { 1604*3eb3c573Smarks error = convert_aent_to_ace(aclp->acl_aclp, 1605*3eb3c573Smarks aclp->acl_cnt, isdir, (ace_t **)&acldata, &aclcnt); 1606*3eb3c573Smarks if (error) { 1607*3eb3c573Smarks errno = error; 1608*3eb3c573Smarks return (-1); 1609*3eb3c573Smarks } 1610*3eb3c573Smarks } else if (target_flavor == _ACL_ACLENT_ENABLED && 1611*3eb3c573Smarks aclp->acl_type == ACE_T) { 1612*3eb3c573Smarks error = convert_ace_to_aent(aclp->acl_aclp, aclp->acl_cnt, 1613*3eb3c573Smarks isdir, owner, group, (aclent_t **)&acldata, &aclcnt); 1614*3eb3c573Smarks if (error) { 1615*3eb3c573Smarks errno = error; 1616*3eb3c573Smarks return (-1); 1617*3eb3c573Smarks } 1618*3eb3c573Smarks } else { 1619*3eb3c573Smarks errno = ENOTSUP; 1620*3eb3c573Smarks return (-1); 1621*3eb3c573Smarks } 1622*3eb3c573Smarks 1623*3eb3c573Smarks /* 1624*3eb3c573Smarks * replace old acl with newly translated acl 1625*3eb3c573Smarks */ 1626*3eb3c573Smarks free(aclp->acl_aclp); 1627*3eb3c573Smarks aclp->acl_aclp = acldata; 1628*3eb3c573Smarks aclp->acl_cnt = aclcnt; 1629*3eb3c573Smarks aclp->acl_type = (target_flavor == _ACL_ACE_ENABLED) ? ACE_T : ACLENT_T; 1630*3eb3c573Smarks return (0); 1631*3eb3c573Smarks } 1632*3eb3c573Smarks 1633fa9e4066Sahrens /* 1634fa9e4066Sahrens * Set an ACL, translates acl to ace_t when appropriate. 1635fa9e4066Sahrens */ 1636fa9e4066Sahrens static int 1637fa9e4066Sahrens cacl_set(acl_inp *acl_inp, acl_t *aclp, int type) 1638fa9e4066Sahrens { 1639fa9e4066Sahrens int error = 0; 1640fa9e4066Sahrens int acl_flavor_target; 1641fa9e4066Sahrens struct stat64 statbuf; 1642fa9e4066Sahrens int stat_error; 1643fa9e4066Sahrens int isdir; 1644fa9e4066Sahrens 1645fa9e4066Sahrens 1646fa9e4066Sahrens if (type == ACL_PATH) { 1647fa9e4066Sahrens stat_error = stat64(acl_inp->file, &statbuf); 1648fa9e4066Sahrens if (stat_error) 1649fa9e4066Sahrens return (-1); 1650fa9e4066Sahrens acl_flavor_target = pathconf(acl_inp->file, _PC_ACL_ENABLED); 1651fa9e4066Sahrens } else { 1652fa9e4066Sahrens stat_error = fstat64(acl_inp->fd, &statbuf); 1653fa9e4066Sahrens if (stat_error) 1654fa9e4066Sahrens return (-1); 1655fa9e4066Sahrens acl_flavor_target = fpathconf(acl_inp->fd, _PC_ACL_ENABLED); 1656fa9e4066Sahrens } 1657fa9e4066Sahrens 1658fa9e4066Sahrens isdir = S_ISDIR(statbuf.st_mode); 1659fa9e4066Sahrens 1660*3eb3c573Smarks if ((error = acl_translate(aclp, acl_flavor_target, isdir, 1661*3eb3c573Smarks statbuf.st_uid, statbuf.st_gid)) != 0) { 1662*3eb3c573Smarks return (error); 1663fa9e4066Sahrens } 1664fa9e4066Sahrens 1665fa9e4066Sahrens if (type == ACL_PATH) { 1666fa9e4066Sahrens error = acl(acl_inp->file, 1667fa9e4066Sahrens (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, 1668fa9e4066Sahrens aclp->acl_cnt, aclp->acl_aclp); 1669fa9e4066Sahrens } else { 1670fa9e4066Sahrens error = facl(acl_inp->fd, 1671fa9e4066Sahrens (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, 1672fa9e4066Sahrens aclp->acl_cnt, aclp->acl_aclp); 1673fa9e4066Sahrens } 1674fa9e4066Sahrens 1675fa9e4066Sahrens return (error); 1676fa9e4066Sahrens } 1677fa9e4066Sahrens 1678fa9e4066Sahrens int 1679fa9e4066Sahrens acl_set(const char *path, acl_t *aclp) 1680fa9e4066Sahrens { 1681fa9e4066Sahrens acl_inp acl_inp; 1682fa9e4066Sahrens 1683fa9e4066Sahrens acl_inp.file = path; 1684fa9e4066Sahrens 1685fa9e4066Sahrens return (cacl_set(&acl_inp, aclp, ACL_PATH)); 1686fa9e4066Sahrens } 1687fa9e4066Sahrens 1688fa9e4066Sahrens int 1689fa9e4066Sahrens facl_set(int fd, acl_t *aclp) 1690fa9e4066Sahrens { 1691fa9e4066Sahrens acl_inp acl_inp; 1692fa9e4066Sahrens 1693fa9e4066Sahrens acl_inp.fd = fd; 1694fa9e4066Sahrens 1695fa9e4066Sahrens return (cacl_set(&acl_inp, aclp, ACL_FD)); 1696fa9e4066Sahrens } 1697fa9e4066Sahrens 1698fa9e4066Sahrens int 1699fa9e4066Sahrens acl_cnt(acl_t *aclp) 1700fa9e4066Sahrens { 1701fa9e4066Sahrens return (aclp->acl_cnt); 1702fa9e4066Sahrens } 1703fa9e4066Sahrens 1704fa9e4066Sahrens int 1705fa9e4066Sahrens acl_type(acl_t *aclp) 1706fa9e4066Sahrens { 1707fa9e4066Sahrens return (aclp->acl_type); 1708fa9e4066Sahrens } 1709fa9e4066Sahrens 1710fa9e4066Sahrens acl_t * 1711fa9e4066Sahrens acl_dup(acl_t *aclp) 1712fa9e4066Sahrens { 1713fa9e4066Sahrens acl_t *newaclp; 1714fa9e4066Sahrens 1715fa9e4066Sahrens newaclp = acl_alloc(aclp->acl_type); 1716fa9e4066Sahrens if (newaclp == NULL) 1717fa9e4066Sahrens return (NULL); 1718fa9e4066Sahrens 1719fa9e4066Sahrens newaclp->acl_aclp = malloc(aclp->acl_entry_size * aclp->acl_cnt); 1720fa9e4066Sahrens if (newaclp->acl_aclp == NULL) { 1721fa9e4066Sahrens acl_free(newaclp); 1722fa9e4066Sahrens return (NULL); 1723fa9e4066Sahrens } 1724fa9e4066Sahrens 1725fa9e4066Sahrens (void) memcpy(newaclp->acl_aclp, 1726fa9e4066Sahrens aclp->acl_aclp, aclp->acl_entry_size * aclp->acl_cnt); 1727fa9e4066Sahrens newaclp->acl_cnt = aclp->acl_cnt; 1728fa9e4066Sahrens 1729fa9e4066Sahrens return (newaclp); 1730fa9e4066Sahrens } 1731fa9e4066Sahrens 1732fa9e4066Sahrens int 1733fa9e4066Sahrens acl_flags(acl_t *aclp) 1734fa9e4066Sahrens { 1735fa9e4066Sahrens return (aclp->acl_flags); 1736fa9e4066Sahrens } 1737fa9e4066Sahrens 1738fa9e4066Sahrens void * 1739fa9e4066Sahrens acl_data(acl_t *aclp) 1740fa9e4066Sahrens { 1741fa9e4066Sahrens return (aclp->acl_aclp); 1742fa9e4066Sahrens } 1743fa9e4066Sahrens 1744fa9e4066Sahrens /* 1745fa9e4066Sahrens * Remove an ACL from a file and create a trivial ACL based 1746fa9e4066Sahrens * off of the mode argument. After acl has been set owner/group 1747fa9e4066Sahrens * are updated to match owner,group arguments 1748fa9e4066Sahrens */ 1749fa9e4066Sahrens int 1750fa9e4066Sahrens acl_strip(const char *file, uid_t owner, gid_t group, mode_t mode) 1751fa9e4066Sahrens { 1752fa9e4066Sahrens int error = 0; 1753fa9e4066Sahrens aclent_t min_acl[MIN_ACL_ENTRIES]; 1754fa9e4066Sahrens ace_t min_ace_acl[6]; /* owner, group, everyone + complement denies */ 1755fa9e4066Sahrens int acl_flavor; 1756fa9e4066Sahrens int aclcnt; 1757fa9e4066Sahrens 1758fa9e4066Sahrens acl_flavor = pathconf(file, _PC_ACL_ENABLED); 1759fa9e4066Sahrens 1760fa9e4066Sahrens if (acl_flavor == -1) 1761fa9e4066Sahrens return (-1); 1762fa9e4066Sahrens /* 1763fa9e4066Sahrens * force it through aclent flavor when file system doesn't 1764fa9e4066Sahrens * understand question 1765fa9e4066Sahrens */ 1766fa9e4066Sahrens if (acl_flavor == 0) 1767fa9e4066Sahrens acl_flavor = _ACL_ACLENT_ENABLED; 1768fa9e4066Sahrens 1769fa9e4066Sahrens if (acl_flavor & _ACL_ACLENT_ENABLED) { 1770fa9e4066Sahrens min_acl[0].a_type = USER_OBJ; 1771fa9e4066Sahrens min_acl[0].a_id = owner; 1772fa9e4066Sahrens min_acl[0].a_perm = ((mode & 0700) >> 6); 1773fa9e4066Sahrens min_acl[1].a_type = GROUP_OBJ; 1774fa9e4066Sahrens min_acl[1].a_id = group; 1775fa9e4066Sahrens min_acl[1].a_perm = ((mode & 0070) >> 3); 1776fa9e4066Sahrens min_acl[2].a_type = CLASS_OBJ; 1777fa9e4066Sahrens min_acl[2].a_id = (uid_t)-1; 1778fa9e4066Sahrens min_acl[2].a_perm = ((mode & 0070) >> 3); 1779fa9e4066Sahrens min_acl[3].a_type = OTHER_OBJ; 1780fa9e4066Sahrens min_acl[3].a_id = (uid_t)-1; 1781fa9e4066Sahrens min_acl[3].a_perm = (mode & 0007); 1782fa9e4066Sahrens aclcnt = 4; 1783fa9e4066Sahrens error = acl(file, SETACL, aclcnt, min_acl); 1784fa9e4066Sahrens } else if (acl_flavor & _ACL_ACE_ENABLED) { 1785fa9e4066Sahrens (void) memcpy(min_ace_acl, trivial_acl, sizeof (ace_t) * 6); 1786fa9e4066Sahrens 1787fa9e4066Sahrens /* 1788fa9e4066Sahrens * Make aces match request mode 1789fa9e4066Sahrens */ 1790fa9e4066Sahrens adjust_ace_pair(&min_ace_acl[0], (mode & 0700) >> 6); 1791fa9e4066Sahrens adjust_ace_pair(&min_ace_acl[2], (mode & 0070) >> 3); 1792fa9e4066Sahrens adjust_ace_pair(&min_ace_acl[4], mode & 0007); 1793fa9e4066Sahrens 1794fa9e4066Sahrens error = acl(file, ACE_SETACL, 6, min_ace_acl); 1795fa9e4066Sahrens } else { 1796fa9e4066Sahrens errno = EINVAL; 1797fa9e4066Sahrens error = 1; 1798fa9e4066Sahrens } 1799fa9e4066Sahrens 1800fa9e4066Sahrens if (error == 0) 1801fa9e4066Sahrens error = chown(file, owner, group); 1802fa9e4066Sahrens return (error); 1803fa9e4066Sahrens } 1804fa9e4066Sahrens 1805fa9e4066Sahrens static int 1806fa9e4066Sahrens ace_match(void *entry1, void *entry2) 1807fa9e4066Sahrens { 1808fa9e4066Sahrens ace_t *p1 = (ace_t *)entry1; 1809fa9e4066Sahrens ace_t *p2 = (ace_t *)entry2; 1810fa9e4066Sahrens ace_t ace1, ace2; 1811fa9e4066Sahrens 1812fa9e4066Sahrens ace1 = *p1; 1813fa9e4066Sahrens ace2 = *p2; 1814fa9e4066Sahrens 1815fa9e4066Sahrens /* 1816fa9e4066Sahrens * Need to fixup who field for abstrations for 1817fa9e4066Sahrens * accurate comparison, since field is undefined. 1818fa9e4066Sahrens */ 1819fa9e4066Sahrens if (ace1.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE)) 1820fa9e4066Sahrens ace1.a_who = -1; 1821fa9e4066Sahrens if (ace2.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE)) 1822fa9e4066Sahrens ace2.a_who = -1; 1823fa9e4066Sahrens return (memcmp(&ace1, &ace2, sizeof (ace_t))); 1824fa9e4066Sahrens } 1825fa9e4066Sahrens 1826fa9e4066Sahrens static int 1827fa9e4066Sahrens aclent_match(void *entry1, void *entry2) 1828fa9e4066Sahrens { 1829fa9e4066Sahrens aclent_t *aclent1 = (aclent_t *)entry1; 1830fa9e4066Sahrens aclent_t *aclent2 = (aclent_t *)entry2; 1831fa9e4066Sahrens 1832fa9e4066Sahrens return (memcmp(aclent1, aclent2, sizeof (aclent_t))); 1833fa9e4066Sahrens } 1834fa9e4066Sahrens 1835fa9e4066Sahrens /* 1836fa9e4066Sahrens * Find acl entries in acl that correspond to removeacl. Search 1837fa9e4066Sahrens * is started from slot. The flag argument indicates whether to 1838fa9e4066Sahrens * remove all matches or just the first match. 1839fa9e4066Sahrens */ 1840fa9e4066Sahrens int 1841fa9e4066Sahrens acl_removeentries(acl_t *acl, acl_t *removeacl, int start_slot, int flag) 1842fa9e4066Sahrens { 1843fa9e4066Sahrens int i, j; 1844fa9e4066Sahrens int match; 1845fa9e4066Sahrens int (*acl_match)(void *acl1, void *acl2); 1846fa9e4066Sahrens void *acl_entry, *remove_entry; 1847fa9e4066Sahrens void *start; 1848fa9e4066Sahrens int found = 0; 1849fa9e4066Sahrens 1850fa9e4066Sahrens if (flag != ACL_REMOVE_ALL && flag != ACL_REMOVE_FIRST) 1851fa9e4066Sahrens flag = ACL_REMOVE_FIRST; 1852fa9e4066Sahrens 1853fa9e4066Sahrens if (acl == NULL || removeacl == NULL) 1854fa9e4066Sahrens return (EACL_NO_ACL_ENTRY); 1855fa9e4066Sahrens 1856fa9e4066Sahrens if (acl->acl_type != removeacl->acl_type) 1857fa9e4066Sahrens return (EACL_DIFF_TYPE); 1858fa9e4066Sahrens 1859fa9e4066Sahrens if (acl->acl_type == ACLENT_T) 1860fa9e4066Sahrens acl_match = aclent_match; 1861fa9e4066Sahrens else 1862fa9e4066Sahrens acl_match = ace_match; 1863fa9e4066Sahrens 1864fa9e4066Sahrens for (i = 0, remove_entry = removeacl->acl_aclp; 1865fa9e4066Sahrens i != removeacl->acl_cnt; i++) { 1866fa9e4066Sahrens 1867fa9e4066Sahrens j = 0; 1868fa9e4066Sahrens acl_entry = (char *)acl->acl_aclp + 1869fa9e4066Sahrens (acl->acl_entry_size * start_slot); 1870fa9e4066Sahrens for (;;) { 1871fa9e4066Sahrens match = acl_match(acl_entry, remove_entry); 1872fa9e4066Sahrens if (match == 0) { 1873fa9e4066Sahrens found++; 1874fa9e4066Sahrens start = (char *)acl_entry + 1875fa9e4066Sahrens acl->acl_entry_size; 1876fa9e4066Sahrens (void) memmove(acl_entry, start, 1877fa9e4066Sahrens acl->acl_entry_size * 1878fa9e4066Sahrens acl->acl_cnt-- - (j + 1)); 1879fa9e4066Sahrens 1880fa9e4066Sahrens if (flag == ACL_REMOVE_FIRST) 1881fa9e4066Sahrens break; 1882fa9e4066Sahrens /* 1883fa9e4066Sahrens * List has changed, restart search from 1884fa9e4066Sahrens * beginning. 1885fa9e4066Sahrens */ 1886fa9e4066Sahrens acl_entry = acl->acl_aclp; 1887fa9e4066Sahrens j = 0; 1888fa9e4066Sahrens continue; 1889fa9e4066Sahrens } 1890fa9e4066Sahrens acl_entry = ((char *)acl_entry + acl->acl_entry_size); 1891fa9e4066Sahrens if (++j >= acl->acl_cnt) { 1892fa9e4066Sahrens break; 1893fa9e4066Sahrens } 1894fa9e4066Sahrens } 1895fa9e4066Sahrens } 1896fa9e4066Sahrens 1897fa9e4066Sahrens return ((found == 0) ? EACL_NO_ACL_ENTRY : 0); 1898fa9e4066Sahrens } 1899fa9e4066Sahrens 1900fa9e4066Sahrens /* 1901fa9e4066Sahrens * Replace entires entries in acl1 with the corresponding entries 1902fa9e4066Sahrens * in newentries. The where argument specifies where to begin 1903fa9e4066Sahrens * the replacement. If the where argument is 1 greater than the 1904fa9e4066Sahrens * number of acl entries in acl1 then they are appended. If the 1905fa9e4066Sahrens * where argument is 2+ greater than the number of acl entries then 1906fa9e4066Sahrens * EACL_INVALID_SLOT is returned. 1907fa9e4066Sahrens */ 1908fa9e4066Sahrens int 1909fa9e4066Sahrens acl_modifyentries(acl_t *acl1, acl_t *newentries, int where) 1910fa9e4066Sahrens { 1911fa9e4066Sahrens 1912fa9e4066Sahrens int slot; 1913fa9e4066Sahrens int slots_needed; 1914fa9e4066Sahrens int slots_left; 1915fa9e4066Sahrens int newsize; 1916fa9e4066Sahrens 1917fa9e4066Sahrens if (acl1 == NULL || newentries == NULL) 1918fa9e4066Sahrens return (EACL_NO_ACL_ENTRY); 1919fa9e4066Sahrens 1920fa9e4066Sahrens if (where < 0 || where >= acl1->acl_cnt) 1921fa9e4066Sahrens return (EACL_INVALID_SLOT); 1922fa9e4066Sahrens 1923fa9e4066Sahrens if (acl1->acl_type != newentries->acl_type) 1924fa9e4066Sahrens return (EACL_DIFF_TYPE); 1925fa9e4066Sahrens 1926fa9e4066Sahrens slot = where; 1927fa9e4066Sahrens 1928fa9e4066Sahrens slots_left = acl1->acl_cnt - slot + 1; 1929fa9e4066Sahrens if (slots_left < newentries->acl_cnt) { 1930fa9e4066Sahrens slots_needed = newentries->acl_cnt - slots_left; 1931fa9e4066Sahrens newsize = (acl1->acl_entry_size * acl1->acl_cnt) + 1932fa9e4066Sahrens (acl1->acl_entry_size * slots_needed); 1933fa9e4066Sahrens acl1->acl_aclp = realloc(acl1->acl_aclp, newsize); 1934fa9e4066Sahrens if (acl1->acl_aclp == NULL) 1935fa9e4066Sahrens return (-1); 1936fa9e4066Sahrens } 1937fa9e4066Sahrens (void) memcpy((char *)acl1->acl_aclp + (acl1->acl_entry_size * slot), 1938fa9e4066Sahrens newentries->acl_aclp, 1939fa9e4066Sahrens newentries->acl_entry_size * newentries->acl_cnt); 1940fa9e4066Sahrens 1941fa9e4066Sahrens /* 1942fa9e4066Sahrens * Did ACL grow? 1943fa9e4066Sahrens */ 1944fa9e4066Sahrens 1945fa9e4066Sahrens if ((slot + newentries->acl_cnt) > acl1->acl_cnt) { 1946fa9e4066Sahrens acl1->acl_cnt = slot + newentries->acl_cnt; 1947fa9e4066Sahrens } 1948fa9e4066Sahrens 1949fa9e4066Sahrens return (0); 1950fa9e4066Sahrens } 1951fa9e4066Sahrens 1952fa9e4066Sahrens /* 1953fa9e4066Sahrens * Add acl2 entries into acl1. The where argument specifies where 1954fa9e4066Sahrens * to add the entries. 1955fa9e4066Sahrens */ 1956fa9e4066Sahrens int 1957fa9e4066Sahrens acl_addentries(acl_t *acl1, acl_t *acl2, int where) 1958fa9e4066Sahrens { 1959fa9e4066Sahrens 1960fa9e4066Sahrens int newsize; 1961fa9e4066Sahrens int len; 1962fa9e4066Sahrens void *start; 1963fa9e4066Sahrens void *to; 1964fa9e4066Sahrens 1965fa9e4066Sahrens if (acl1 == NULL || acl2 == NULL) 1966fa9e4066Sahrens return (EACL_NO_ACL_ENTRY); 1967fa9e4066Sahrens 1968fa9e4066Sahrens if (acl1->acl_type != acl2->acl_type) 1969fa9e4066Sahrens return (EACL_DIFF_TYPE); 1970fa9e4066Sahrens 1971fa9e4066Sahrens /* 1972fa9e4066Sahrens * allow where to specify 1 past last slot for an append operation 1973fa9e4066Sahrens * but anything greater is an error. 1974fa9e4066Sahrens */ 1975fa9e4066Sahrens if (where < 0 || where > acl1->acl_cnt) 1976fa9e4066Sahrens return (EACL_INVALID_SLOT); 1977fa9e4066Sahrens 1978fa9e4066Sahrens newsize = (acl2->acl_entry_size * acl2->acl_cnt) + 1979fa9e4066Sahrens (acl1->acl_entry_size * acl1->acl_cnt); 1980fa9e4066Sahrens acl1->acl_aclp = realloc(acl1->acl_aclp, newsize); 1981fa9e4066Sahrens if (acl1->acl_aclp == NULL) 1982fa9e4066Sahrens return (-1); 1983fa9e4066Sahrens 1984fa9e4066Sahrens /* 1985fa9e4066Sahrens * first push down entries where new ones will be inserted 1986fa9e4066Sahrens */ 1987fa9e4066Sahrens 1988fa9e4066Sahrens to = (void *)((char *)acl1->acl_aclp + 1989fa9e4066Sahrens ((where + acl2->acl_cnt) * acl1->acl_entry_size)); 1990fa9e4066Sahrens 1991fa9e4066Sahrens start = (void *)((char *)acl1->acl_aclp + 1992fa9e4066Sahrens where * acl1->acl_entry_size); 1993fa9e4066Sahrens 1994fa9e4066Sahrens if (where < acl1->acl_cnt) { 1995fa9e4066Sahrens len = (acl1->acl_cnt - where) * acl1->acl_entry_size; 1996fa9e4066Sahrens (void) memmove(to, start, len); 1997fa9e4066Sahrens } 1998fa9e4066Sahrens 1999fa9e4066Sahrens /* 2000fa9e4066Sahrens * now stick in new entries. 2001fa9e4066Sahrens */ 2002fa9e4066Sahrens 2003fa9e4066Sahrens (void) memmove(start, acl2->acl_aclp, 2004fa9e4066Sahrens acl2->acl_cnt * acl2->acl_entry_size); 2005fa9e4066Sahrens 2006fa9e4066Sahrens acl1->acl_cnt += acl2->acl_cnt; 2007fa9e4066Sahrens return (0); 2008fa9e4066Sahrens } 2009fa9e4066Sahrens 2010fa9e4066Sahrens /* 2011fa9e4066Sahrens * return text for an ACL error. 2012fa9e4066Sahrens */ 2013fa9e4066Sahrens char * 2014fa9e4066Sahrens acl_strerror(int errnum) 2015fa9e4066Sahrens { 2016fa9e4066Sahrens switch (errnum) { 2017fa9e4066Sahrens case EACL_GRP_ERROR: 2018fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 20195a5eeccaSmarks "There is more than one group or default group entry")); 2020fa9e4066Sahrens case EACL_USER_ERROR: 2021fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 20225a5eeccaSmarks "There is more than one user or default user entry")); 2023fa9e4066Sahrens case EACL_OTHER_ERROR: 2024fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2025fa9e4066Sahrens "There is more than one other entry")); 2026fa9e4066Sahrens case EACL_CLASS_ERROR: 2027fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2028fa9e4066Sahrens "There is more than one mask entry")); 2029fa9e4066Sahrens case EACL_DUPLICATE_ERROR: 2030fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2031fa9e4066Sahrens "Duplicate user or group entries")); 2032fa9e4066Sahrens case EACL_MISS_ERROR: 2033fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2034fa9e4066Sahrens "Missing user/group owner, other, mask entry")); 2035fa9e4066Sahrens case EACL_MEM_ERROR: 2036fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2037fa9e4066Sahrens "Memory error")); 2038fa9e4066Sahrens case EACL_ENTRY_ERROR: 2039fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2040fa9e4066Sahrens "Unrecognized entry type")); 2041fa9e4066Sahrens case EACL_INHERIT_ERROR: 2042fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2043fa9e4066Sahrens "Invalid inheritance flags")); 2044fa9e4066Sahrens case EACL_FLAGS_ERROR: 2045fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2046fa9e4066Sahrens "Unrecognized entry flags")); 2047fa9e4066Sahrens case EACL_PERM_MASK_ERROR: 2048fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2049fa9e4066Sahrens "Invalid ACL permissions")); 2050fa9e4066Sahrens case EACL_COUNT_ERROR: 2051fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2052fa9e4066Sahrens "Invalid ACL count")); 2053fa9e4066Sahrens case EACL_INVALID_SLOT: 2054fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2055fa9e4066Sahrens "Invalid ACL entry number specified")); 2056fa9e4066Sahrens case EACL_NO_ACL_ENTRY: 2057fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2058fa9e4066Sahrens "ACL entry doesn't exist")); 2059fa9e4066Sahrens case EACL_DIFF_TYPE: 2060fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2061fa9e4066Sahrens "ACL type's are different")); 2062fa9e4066Sahrens case EACL_INVALID_USER_GROUP: 2063fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "Invalid user or group")); 2064fa9e4066Sahrens case EACL_INVALID_STR: 2065fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "ACL string is invalid")); 2066fa9e4066Sahrens case EACL_FIELD_NOT_BLANK: 2067fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "Field expected to be blank")); 2068fa9e4066Sahrens case EACL_INVALID_ACCESS_TYPE: 2069fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "Invalid access type")); 2070fa9e4066Sahrens case EACL_UNKNOWN_DATA: 2071fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "Unrecognized entry")); 2072fa9e4066Sahrens case EACL_MISSING_FIELDS: 2073fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2074fa9e4066Sahrens "ACL specification missing required fields")); 2075fa9e4066Sahrens case EACL_INHERIT_NOTDIR: 2076fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2077fa9e4066Sahrens "Inheritance flags are only allowed on directories")); 2078fa9e4066Sahrens case -1: 2079fa9e4066Sahrens return (strerror(errno)); 2080fa9e4066Sahrens default: 2081fa9e4066Sahrens errno = EINVAL; 2082fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "Unknown error")); 2083fa9e4066Sahrens } 2084fa9e4066Sahrens } 20855a5eeccaSmarks 20865a5eeccaSmarks extern int yyinteractive; 20875a5eeccaSmarks 20885a5eeccaSmarks /* PRINTFLIKE1 */ 20895a5eeccaSmarks void 20905a5eeccaSmarks acl_error(const char *fmt, ...) 20915a5eeccaSmarks { 20925a5eeccaSmarks va_list va; 20935a5eeccaSmarks 20945a5eeccaSmarks if (yyinteractive == 0) 20955a5eeccaSmarks return; 20965a5eeccaSmarks 20975a5eeccaSmarks va_start(va, fmt); 20985a5eeccaSmarks (void) vfprintf(stderr, fmt, va); 20995a5eeccaSmarks va_end(va); 21005a5eeccaSmarks } 2101