1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 54321Scasper * Common Development and Distribution License (the "License"). 64321Scasper * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 21789Sahrens /* 224321Scasper * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23789Sahrens * Use is subject to license terms. 24789Sahrens */ 25789Sahrens 26789Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 27789Sahrens 28789Sahrens #include <sys/types.h> 29789Sahrens #include <sys/stat.h> 30*5331Samw #include <sys/avl.h> 31789Sahrens #if defined(_KERNEL) 32789Sahrens #include <sys/systm.h> 33*5331Samw #include <sys/sysmacros.h> 34*5331Samw #include <acl/acl_common.h> 35789Sahrens #else 36789Sahrens #include <errno.h> 37789Sahrens #include <stdlib.h> 38*5331Samw #include <stddef.h> 39789Sahrens #include <strings.h> 40*5331Samw #include <unistd.h> 41789Sahrens #include <assert.h> 42*5331Samw #include <grp.h> 43*5331Samw #include <pwd.h> 44*5331Samw #include <acl_common.h> 45789Sahrens #define ASSERT assert 46789Sahrens #endif 47789Sahrens 48*5331Samw #define ACE_POSIX_SUPPORTED_BITS (ACE_READ_DATA | \ 49*5331Samw ACE_WRITE_DATA | ACE_APPEND_DATA | ACE_EXECUTE | \ 50*5331Samw ACE_READ_ATTRIBUTES | ACE_READ_ACL | ACE_WRITE_ACL) 51*5331Samw 52*5331Samw 53*5331Samw #define ACL_SYNCHRONIZE_SET_DENY 0x0000001 54*5331Samw #define ACL_SYNCHRONIZE_SET_ALLOW 0x0000002 55*5331Samw #define ACL_SYNCHRONIZE_ERR_DENY 0x0000004 56*5331Samw #define ACL_SYNCHRONIZE_ERR_ALLOW 0x0000008 57*5331Samw 58*5331Samw #define ACL_WRITE_OWNER_SET_DENY 0x0000010 59*5331Samw #define ACL_WRITE_OWNER_SET_ALLOW 0x0000020 60*5331Samw #define ACL_WRITE_OWNER_ERR_DENY 0x0000040 61*5331Samw #define ACL_WRITE_OWNER_ERR_ALLOW 0x0000080 62*5331Samw 63*5331Samw #define ACL_DELETE_SET_DENY 0x0000100 64*5331Samw #define ACL_DELETE_SET_ALLOW 0x0000200 65*5331Samw #define ACL_DELETE_ERR_DENY 0x0000400 66*5331Samw #define ACL_DELETE_ERR_ALLOW 0x0000800 67*5331Samw 68*5331Samw #define ACL_WRITE_ATTRS_OWNER_SET_DENY 0x0001000 69*5331Samw #define ACL_WRITE_ATTRS_OWNER_SET_ALLOW 0x0002000 70*5331Samw #define ACL_WRITE_ATTRS_OWNER_ERR_DENY 0x0004000 71*5331Samw #define ACL_WRITE_ATTRS_OWNER_ERR_ALLOW 0x0008000 72*5331Samw 73*5331Samw #define ACL_WRITE_ATTRS_WRITER_SET_DENY 0x0010000 74*5331Samw #define ACL_WRITE_ATTRS_WRITER_SET_ALLOW 0x0020000 75*5331Samw #define ACL_WRITE_ATTRS_WRITER_ERR_DENY 0x0040000 76*5331Samw #define ACL_WRITE_ATTRS_WRITER_ERR_ALLOW 0x0080000 77*5331Samw 78*5331Samw #define ACL_WRITE_NAMED_WRITER_SET_DENY 0x0100000 79*5331Samw #define ACL_WRITE_NAMED_WRITER_SET_ALLOW 0x0200000 80*5331Samw #define ACL_WRITE_NAMED_WRITER_ERR_DENY 0x0400000 81*5331Samw #define ACL_WRITE_NAMED_WRITER_ERR_ALLOW 0x0800000 82*5331Samw 83*5331Samw #define ACL_READ_NAMED_READER_SET_DENY 0x1000000 84*5331Samw #define ACL_READ_NAMED_READER_SET_ALLOW 0x2000000 85*5331Samw #define ACL_READ_NAMED_READER_ERR_DENY 0x4000000 86*5331Samw #define ACL_READ_NAMED_READER_ERR_ALLOW 0x8000000 87*5331Samw 88*5331Samw 89*5331Samw #define ACE_VALID_MASK_BITS (\ 90*5331Samw ACE_READ_DATA | \ 91*5331Samw ACE_LIST_DIRECTORY | \ 92*5331Samw ACE_WRITE_DATA | \ 93*5331Samw ACE_ADD_FILE | \ 94*5331Samw ACE_APPEND_DATA | \ 95*5331Samw ACE_ADD_SUBDIRECTORY | \ 96*5331Samw ACE_READ_NAMED_ATTRS | \ 97*5331Samw ACE_WRITE_NAMED_ATTRS | \ 98*5331Samw ACE_EXECUTE | \ 99*5331Samw ACE_DELETE_CHILD | \ 100*5331Samw ACE_READ_ATTRIBUTES | \ 101*5331Samw ACE_WRITE_ATTRIBUTES | \ 102*5331Samw ACE_DELETE | \ 103*5331Samw ACE_READ_ACL | \ 104*5331Samw ACE_WRITE_ACL | \ 105*5331Samw ACE_WRITE_OWNER | \ 106*5331Samw ACE_SYNCHRONIZE) 107*5331Samw 108*5331Samw #define ACE_MASK_UNDEFINED 0x80000000 109*5331Samw 110*5331Samw #define ACE_VALID_FLAG_BITS (ACE_FILE_INHERIT_ACE | \ 111*5331Samw ACE_DIRECTORY_INHERIT_ACE | \ 112*5331Samw ACE_NO_PROPAGATE_INHERIT_ACE | ACE_INHERIT_ONLY_ACE | \ 113*5331Samw ACE_SUCCESSFUL_ACCESS_ACE_FLAG | ACE_FAILED_ACCESS_ACE_FLAG | \ 114*5331Samw ACE_IDENTIFIER_GROUP | ACE_OWNER | ACE_GROUP | ACE_EVERYONE) 115*5331Samw 116*5331Samw /* 117*5331Samw * ACL conversion helpers 118*5331Samw */ 119*5331Samw 120*5331Samw typedef enum { 121*5331Samw ace_unused, 122*5331Samw ace_user_obj, 123*5331Samw ace_user, 124*5331Samw ace_group, /* includes GROUP and GROUP_OBJ */ 125*5331Samw ace_other_obj 126*5331Samw } ace_to_aent_state_t; 127*5331Samw 128*5331Samw typedef struct acevals { 129*5331Samw uid_t key; 130*5331Samw avl_node_t avl; 131*5331Samw uint32_t mask; 132*5331Samw uint32_t allowed; 133*5331Samw uint32_t denied; 134*5331Samw int aent_type; 135*5331Samw } acevals_t; 136*5331Samw 137*5331Samw typedef struct ace_list { 138*5331Samw acevals_t user_obj; 139*5331Samw avl_tree_t user; 140*5331Samw int numusers; 141*5331Samw acevals_t group_obj; 142*5331Samw avl_tree_t group; 143*5331Samw int numgroups; 144*5331Samw acevals_t other_obj; 145*5331Samw uint32_t acl_mask; 146*5331Samw int hasmask; 147*5331Samw int dfacl_flag; 148*5331Samw ace_to_aent_state_t state; 149*5331Samw int seen; /* bitmask of all aclent_t a_type values seen */ 150*5331Samw } ace_list_t; 151789Sahrens 152789Sahrens ace_t trivial_acl[] = { 1534321Scasper {(uid_t)-1, 0, ACE_OWNER, ACE_ACCESS_DENIED_ACE_TYPE}, 1544321Scasper {(uid_t)-1, ACE_WRITE_ACL|ACE_WRITE_OWNER|ACE_WRITE_ATTRIBUTES| 155789Sahrens ACE_WRITE_NAMED_ATTRS, ACE_OWNER, ACE_ACCESS_ALLOWED_ACE_TYPE}, 1564321Scasper {(uid_t)-1, 0, ACE_GROUP|ACE_IDENTIFIER_GROUP, 1574321Scasper ACE_ACCESS_DENIED_ACE_TYPE}, 1584321Scasper {(uid_t)-1, 0, ACE_GROUP|ACE_IDENTIFIER_GROUP, 1594321Scasper ACE_ACCESS_ALLOWED_ACE_TYPE}, 1604321Scasper {(uid_t)-1, ACE_WRITE_ACL|ACE_WRITE_OWNER| ACE_WRITE_ATTRIBUTES| 161789Sahrens ACE_WRITE_NAMED_ATTRS, ACE_EVERYONE, ACE_ACCESS_DENIED_ACE_TYPE}, 1624321Scasper {(uid_t)-1, ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_READ_NAMED_ATTRS| 163789Sahrens ACE_SYNCHRONIZE, ACE_EVERYONE, ACE_ACCESS_ALLOWED_ACE_TYPE} 164789Sahrens }; 165789Sahrens 166789Sahrens 167789Sahrens void 168*5331Samw adjust_ace_pair_common(void *pair, size_t access_off, 169*5331Samw size_t pairsize, mode_t mode) 170*5331Samw { 171*5331Samw char *datap = (char *)pair; 172*5331Samw uint32_t *amask0 = (uint32_t *)(uintptr_t)(datap + access_off); 173*5331Samw uint32_t *amask1 = (uint32_t *)(uintptr_t)(datap + pairsize + 174*5331Samw access_off); 175*5331Samw if (mode & S_IROTH) 176*5331Samw *amask1 |= ACE_READ_DATA; 177*5331Samw else 178*5331Samw *amask0 |= ACE_READ_DATA; 179*5331Samw if (mode & S_IWOTH) 180*5331Samw *amask1 |= ACE_WRITE_DATA|ACE_APPEND_DATA; 181*5331Samw else 182*5331Samw *amask0 |= ACE_WRITE_DATA|ACE_APPEND_DATA; 183*5331Samw if (mode & S_IXOTH) 184*5331Samw *amask1 |= ACE_EXECUTE; 185*5331Samw else 186*5331Samw *amask0 |= ACE_EXECUTE; 187*5331Samw } 188*5331Samw 189*5331Samw void 190789Sahrens adjust_ace_pair(ace_t *pair, mode_t mode) 191789Sahrens { 192*5331Samw adjust_ace_pair_common(pair, offsetof(ace_t, a_access_mask), 193*5331Samw sizeof (ace_t), mode); 194789Sahrens } 195789Sahrens 196789Sahrens /* 197789Sahrens * ace_trivial: 198789Sahrens * determine whether an ace_t acl is trivial 199789Sahrens * 200*5331Samw * Trivialness implies that the acl is composed of only 201789Sahrens * owner, group, everyone entries. ACL can't 202789Sahrens * have read_acl denied, and write_owner/write_acl/write_attributes 203789Sahrens * can only be owner@ entry. 204789Sahrens */ 205789Sahrens int 206*5331Samw ace_trivial_common(void *acep, int aclcnt, 207*5331Samw uint64_t (*walk)(void *, uint64_t, int aclcnt, 208*5331Samw uint16_t *, uint16_t *, uint32_t *)) 209789Sahrens { 210789Sahrens int owner_seen = 0; 211789Sahrens int group_seen = 0; 212789Sahrens int everyone_seen = 0; 213*5331Samw uint16_t flags; 214*5331Samw uint32_t mask; 215*5331Samw uint16_t type; 216*5331Samw uint64_t cookie = 0; 217789Sahrens 218*5331Samw while (cookie = walk(acep, cookie, aclcnt, &flags, &type, &mask)) { 219*5331Samw switch (flags & ACE_TYPE_FLAGS) { 220789Sahrens case ACE_OWNER: 221789Sahrens if (group_seen || everyone_seen) 222789Sahrens return (1); 223789Sahrens owner_seen++; 224789Sahrens break; 225789Sahrens case ACE_GROUP|ACE_IDENTIFIER_GROUP: 226789Sahrens if (everyone_seen || owner_seen == 0) 227789Sahrens return (1); 228789Sahrens group_seen++; 229789Sahrens break; 230789Sahrens 231789Sahrens case ACE_EVERYONE: 232789Sahrens if (owner_seen == 0 || group_seen == 0) 233789Sahrens return (1); 234789Sahrens everyone_seen++; 235789Sahrens break; 236789Sahrens default: 237789Sahrens return (1); 238789Sahrens 239789Sahrens } 240789Sahrens 241*5331Samw if (flags & (ACE_FILE_INHERIT_ACE| 242789Sahrens ACE_DIRECTORY_INHERIT_ACE|ACE_NO_PROPAGATE_INHERIT_ACE| 243789Sahrens ACE_INHERIT_ONLY_ACE)) 244789Sahrens return (1); 245789Sahrens 246789Sahrens /* 247789Sahrens * Special check for some special bits 248789Sahrens * 249905Smarks * Don't allow anybody to deny reading basic 250905Smarks * attributes or a files ACL. 251789Sahrens */ 252*5331Samw if ((mask & (ACE_READ_ACL|ACE_READ_ATTRIBUTES)) && 253*5331Samw (type == ACE_ACCESS_DENIED_ACE_TYPE)) 254789Sahrens return (1); 255789Sahrens 256789Sahrens /* 257789Sahrens * Allow on owner@ to allow 258789Sahrens * write_acl/write_owner/write_attributes 259789Sahrens */ 260*5331Samw if (type == ACE_ACCESS_ALLOWED_ACE_TYPE && 261*5331Samw (!(flags & ACE_OWNER) && (mask & 262789Sahrens (ACE_WRITE_OWNER|ACE_WRITE_ACL|ACE_WRITE_ATTRIBUTES)))) 263789Sahrens return (1); 264*5331Samw 265789Sahrens } 266789Sahrens 267789Sahrens if ((owner_seen == 0) || (group_seen == 0) || (everyone_seen == 0)) 268*5331Samw return (1); 269789Sahrens 270789Sahrens return (0); 271789Sahrens } 272789Sahrens 273*5331Samw uint64_t 274*5331Samw ace_walk(void *datap, uint64_t cookie, int aclcnt, uint16_t *flags, 275*5331Samw uint16_t *type, uint32_t *mask) 276*5331Samw { 277*5331Samw ace_t *acep = datap; 278*5331Samw 279*5331Samw *flags = acep[cookie].a_flags; 280*5331Samw *type = acep[cookie].a_type; 281*5331Samw *mask = acep[cookie++].a_access_mask; 282*5331Samw 283*5331Samw if (cookie > aclcnt) 284*5331Samw return (0); 285*5331Samw else 286*5331Samw return (cookie); 287*5331Samw } 288*5331Samw 289*5331Samw int 290*5331Samw ace_trivial(ace_t *acep, int aclcnt) 291*5331Samw { 292*5331Samw return (ace_trivial_common(acep, aclcnt, ace_walk)); 293*5331Samw } 294789Sahrens 295789Sahrens /* 296789Sahrens * Generic shellsort, from K&R (1st ed, p 58.), somewhat modified. 297789Sahrens * v = Ptr to array/vector of objs 298789Sahrens * n = # objs in the array 299789Sahrens * s = size of each obj (must be multiples of a word size) 300789Sahrens * f = ptr to function to compare two objs 301789Sahrens * returns (-1 = less than, 0 = equal, 1 = greater than 302789Sahrens */ 303789Sahrens void 304789Sahrens ksort(caddr_t v, int n, int s, int (*f)()) 305789Sahrens { 306789Sahrens int g, i, j, ii; 307789Sahrens unsigned int *p1, *p2; 308789Sahrens unsigned int tmp; 309789Sahrens 310789Sahrens /* No work to do */ 311789Sahrens if (v == NULL || n <= 1) 312789Sahrens return; 313789Sahrens 314789Sahrens /* Sanity check on arguments */ 315789Sahrens ASSERT(((uintptr_t)v & 0x3) == 0 && (s & 0x3) == 0); 316789Sahrens ASSERT(s > 0); 317789Sahrens for (g = n / 2; g > 0; g /= 2) { 318789Sahrens for (i = g; i < n; i++) { 319789Sahrens for (j = i - g; j >= 0 && 320*5331Samw (*f)(v + j * s, v + (j + g) * s) == 1; 321*5331Samw j -= g) { 322789Sahrens p1 = (void *)(v + j * s); 323789Sahrens p2 = (void *)(v + (j + g) * s); 324789Sahrens for (ii = 0; ii < s / 4; ii++) { 325789Sahrens tmp = *p1; 326789Sahrens *p1++ = *p2; 327789Sahrens *p2++ = tmp; 328789Sahrens } 329789Sahrens } 330789Sahrens } 331789Sahrens } 332789Sahrens } 333789Sahrens 334789Sahrens /* 335789Sahrens * Compare two acls, all fields. Returns: 336789Sahrens * -1 (less than) 337789Sahrens * 0 (equal) 338789Sahrens * +1 (greater than) 339789Sahrens */ 340789Sahrens int 341789Sahrens cmp2acls(void *a, void *b) 342789Sahrens { 343789Sahrens aclent_t *x = (aclent_t *)a; 344789Sahrens aclent_t *y = (aclent_t *)b; 345789Sahrens 346789Sahrens /* Compare types */ 347789Sahrens if (x->a_type < y->a_type) 348789Sahrens return (-1); 349789Sahrens if (x->a_type > y->a_type) 350789Sahrens return (1); 351789Sahrens /* Equal types; compare id's */ 352789Sahrens if (x->a_id < y->a_id) 353789Sahrens return (-1); 354789Sahrens if (x->a_id > y->a_id) 355789Sahrens return (1); 356789Sahrens /* Equal ids; compare perms */ 357789Sahrens if (x->a_perm < y->a_perm) 358789Sahrens return (-1); 359789Sahrens if (x->a_perm > y->a_perm) 360789Sahrens return (1); 361789Sahrens /* Totally equal */ 362789Sahrens return (0); 363789Sahrens } 364*5331Samw 365*5331Samw /*ARGSUSED*/ 366*5331Samw static void * 367*5331Samw cacl_realloc(void *ptr, size_t size, size_t new_size) 368*5331Samw { 369*5331Samw #if defined(_KERNEL) 370*5331Samw void *tmp; 371*5331Samw 372*5331Samw tmp = kmem_alloc(new_size, KM_SLEEP); 373*5331Samw (void) memcpy(tmp, ptr, (size < new_size) ? size : new_size); 374*5331Samw kmem_free(ptr, size); 375*5331Samw return (tmp); 376*5331Samw #else 377*5331Samw return (realloc(ptr, new_size)); 378*5331Samw #endif 379*5331Samw } 380*5331Samw 381*5331Samw static int 382*5331Samw cacl_malloc(void **ptr, size_t size) 383*5331Samw { 384*5331Samw #if defined(_KERNEL) 385*5331Samw *ptr = kmem_zalloc(size, KM_SLEEP); 386*5331Samw return (0); 387*5331Samw #else 388*5331Samw *ptr = calloc(1, size); 389*5331Samw if (*ptr == NULL) 390*5331Samw return (errno); 391*5331Samw 392*5331Samw return (0); 393*5331Samw #endif 394*5331Samw } 395*5331Samw 396*5331Samw /*ARGSUSED*/ 397*5331Samw static void 398*5331Samw cacl_free(void *ptr, size_t size) 399*5331Samw { 400*5331Samw #if defined(_KERNEL) 401*5331Samw kmem_free(ptr, size); 402*5331Samw #else 403*5331Samw free(ptr); 404*5331Samw #endif 405*5331Samw } 406*5331Samw 407*5331Samw acl_t * 408*5331Samw acl_alloc(enum acl_type type) 409*5331Samw { 410*5331Samw acl_t *aclp; 411*5331Samw 412*5331Samw if (cacl_malloc((void **)&aclp, sizeof (acl_t)) != 0) 413*5331Samw return (NULL); 414*5331Samw 415*5331Samw aclp->acl_aclp = NULL; 416*5331Samw aclp->acl_cnt = 0; 417*5331Samw 418*5331Samw switch (type) { 419*5331Samw case ACE_T: 420*5331Samw aclp->acl_type = ACE_T; 421*5331Samw aclp->acl_entry_size = sizeof (ace_t); 422*5331Samw break; 423*5331Samw case ACLENT_T: 424*5331Samw aclp->acl_type = ACLENT_T; 425*5331Samw aclp->acl_entry_size = sizeof (aclent_t); 426*5331Samw break; 427*5331Samw default: 428*5331Samw acl_free(aclp); 429*5331Samw aclp = NULL; 430*5331Samw } 431*5331Samw return (aclp); 432*5331Samw } 433*5331Samw 434*5331Samw /* 435*5331Samw * Free acl_t structure 436*5331Samw */ 437*5331Samw void 438*5331Samw acl_free(acl_t *aclp) 439*5331Samw { 440*5331Samw int acl_size; 441*5331Samw 442*5331Samw if (aclp == NULL) 443*5331Samw return; 444*5331Samw 445*5331Samw if (aclp->acl_aclp) { 446*5331Samw acl_size = aclp->acl_cnt * aclp->acl_entry_size; 447*5331Samw cacl_free(aclp->acl_aclp, acl_size); 448*5331Samw } 449*5331Samw 450*5331Samw cacl_free(aclp, sizeof (acl_t)); 451*5331Samw } 452*5331Samw 453*5331Samw static uint32_t 454*5331Samw access_mask_set(int haswriteperm, int hasreadperm, int isowner, int isallow) 455*5331Samw { 456*5331Samw uint32_t access_mask = 0; 457*5331Samw int acl_produce; 458*5331Samw int synchronize_set = 0, write_owner_set = 0; 459*5331Samw int delete_set = 0, write_attrs_set = 0; 460*5331Samw int read_named_set = 0, write_named_set = 0; 461*5331Samw 462*5331Samw acl_produce = (ACL_SYNCHRONIZE_SET_ALLOW | 463*5331Samw ACL_WRITE_ATTRS_OWNER_SET_ALLOW | 464*5331Samw ACL_WRITE_ATTRS_WRITER_SET_DENY); 465*5331Samw 466*5331Samw if (isallow) { 467*5331Samw synchronize_set = ACL_SYNCHRONIZE_SET_ALLOW; 468*5331Samw write_owner_set = ACL_WRITE_OWNER_SET_ALLOW; 469*5331Samw delete_set = ACL_DELETE_SET_ALLOW; 470*5331Samw if (hasreadperm) 471*5331Samw read_named_set = ACL_READ_NAMED_READER_SET_ALLOW; 472*5331Samw if (haswriteperm) 473*5331Samw write_named_set = ACL_WRITE_NAMED_WRITER_SET_ALLOW; 474*5331Samw if (isowner) 475*5331Samw write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_ALLOW; 476*5331Samw else if (haswriteperm) 477*5331Samw write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_ALLOW; 478*5331Samw } else { 479*5331Samw 480*5331Samw synchronize_set = ACL_SYNCHRONIZE_SET_DENY; 481*5331Samw write_owner_set = ACL_WRITE_OWNER_SET_DENY; 482*5331Samw delete_set = ACL_DELETE_SET_DENY; 483*5331Samw if (hasreadperm) 484*5331Samw read_named_set = ACL_READ_NAMED_READER_SET_DENY; 485*5331Samw if (haswriteperm) 486*5331Samw write_named_set = ACL_WRITE_NAMED_WRITER_SET_DENY; 487*5331Samw if (isowner) 488*5331Samw write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_DENY; 489*5331Samw else if (haswriteperm) 490*5331Samw write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_DENY; 491*5331Samw else 492*5331Samw /* 493*5331Samw * If the entity is not the owner and does not 494*5331Samw * have write permissions ACE_WRITE_ATTRIBUTES will 495*5331Samw * always go in the DENY ACE. 496*5331Samw */ 497*5331Samw access_mask |= ACE_WRITE_ATTRIBUTES; 498*5331Samw } 499*5331Samw 500*5331Samw if (acl_produce & synchronize_set) 501*5331Samw access_mask |= ACE_SYNCHRONIZE; 502*5331Samw if (acl_produce & write_owner_set) 503*5331Samw access_mask |= ACE_WRITE_OWNER; 504*5331Samw if (acl_produce & delete_set) 505*5331Samw access_mask |= ACE_DELETE; 506*5331Samw if (acl_produce & write_attrs_set) 507*5331Samw access_mask |= ACE_WRITE_ATTRIBUTES; 508*5331Samw if (acl_produce & read_named_set) 509*5331Samw access_mask |= ACE_READ_NAMED_ATTRS; 510*5331Samw if (acl_produce & write_named_set) 511*5331Samw access_mask |= ACE_WRITE_NAMED_ATTRS; 512*5331Samw 513*5331Samw return (access_mask); 514*5331Samw } 515*5331Samw 516*5331Samw /* 517*5331Samw * Given an mode_t, convert it into an access_mask as used 518*5331Samw * by nfsace, assuming aclent_t -> nfsace semantics. 519*5331Samw */ 520*5331Samw static uint32_t 521*5331Samw mode_to_ace_access(mode_t mode, int isdir, int isowner, int isallow) 522*5331Samw { 523*5331Samw uint32_t access = 0; 524*5331Samw int haswriteperm = 0; 525*5331Samw int hasreadperm = 0; 526*5331Samw 527*5331Samw if (isallow) { 528*5331Samw haswriteperm = (mode & S_IWOTH); 529*5331Samw hasreadperm = (mode & S_IROTH); 530*5331Samw } else { 531*5331Samw haswriteperm = !(mode & S_IWOTH); 532*5331Samw hasreadperm = !(mode & S_IROTH); 533*5331Samw } 534*5331Samw 535*5331Samw /* 536*5331Samw * The following call takes care of correctly setting the following 537*5331Samw * mask bits in the access_mask: 538*5331Samw * ACE_SYNCHRONIZE, ACE_WRITE_OWNER, ACE_DELETE, 539*5331Samw * ACE_WRITE_ATTRIBUTES, ACE_WRITE_NAMED_ATTRS, ACE_READ_NAMED_ATTRS 540*5331Samw */ 541*5331Samw access = access_mask_set(haswriteperm, hasreadperm, isowner, isallow); 542*5331Samw 543*5331Samw if (isallow) { 544*5331Samw access |= ACE_READ_ACL | ACE_READ_ATTRIBUTES; 545*5331Samw if (isowner) 546*5331Samw access |= ACE_WRITE_ACL; 547*5331Samw } else { 548*5331Samw if (! isowner) 549*5331Samw access |= ACE_WRITE_ACL; 550*5331Samw } 551*5331Samw 552*5331Samw /* read */ 553*5331Samw if (mode & S_IROTH) { 554*5331Samw access |= ACE_READ_DATA; 555*5331Samw } 556*5331Samw /* write */ 557*5331Samw if (mode & S_IWOTH) { 558*5331Samw access |= ACE_WRITE_DATA | 559*5331Samw ACE_APPEND_DATA; 560*5331Samw if (isdir) 561*5331Samw access |= ACE_DELETE_CHILD; 562*5331Samw } 563*5331Samw /* exec */ 564*5331Samw if (mode & 01) { 565*5331Samw access |= ACE_EXECUTE; 566*5331Samw } 567*5331Samw 568*5331Samw return (access); 569*5331Samw } 570*5331Samw 571*5331Samw /* 572*5331Samw * Given an nfsace (presumably an ALLOW entry), make a 573*5331Samw * corresponding DENY entry at the address given. 574*5331Samw */ 575*5331Samw static void 576*5331Samw ace_make_deny(ace_t *allow, ace_t *deny, int isdir, int isowner) 577*5331Samw { 578*5331Samw (void) memcpy(deny, allow, sizeof (ace_t)); 579*5331Samw 580*5331Samw deny->a_who = allow->a_who; 581*5331Samw 582*5331Samw deny->a_type = ACE_ACCESS_DENIED_ACE_TYPE; 583*5331Samw deny->a_access_mask ^= ACE_POSIX_SUPPORTED_BITS; 584*5331Samw if (isdir) 585*5331Samw deny->a_access_mask ^= ACE_DELETE_CHILD; 586*5331Samw 587*5331Samw deny->a_access_mask &= ~(ACE_SYNCHRONIZE | ACE_WRITE_OWNER | 588*5331Samw ACE_DELETE | ACE_WRITE_ATTRIBUTES | ACE_READ_NAMED_ATTRS | 589*5331Samw ACE_WRITE_NAMED_ATTRS); 590*5331Samw deny->a_access_mask |= access_mask_set((allow->a_access_mask & 591*5331Samw ACE_WRITE_DATA), (allow->a_access_mask & ACE_READ_DATA), isowner, 592*5331Samw B_FALSE); 593*5331Samw } 594*5331Samw /* 595*5331Samw * Make an initial pass over an array of aclent_t's. Gather 596*5331Samw * information such as an ACL_MASK (if any), number of users, 597*5331Samw * number of groups, and whether the array needs to be sorted. 598*5331Samw */ 599*5331Samw static int 600*5331Samw ln_aent_preprocess(aclent_t *aclent, int n, 601*5331Samw int *hasmask, mode_t *mask, 602*5331Samw int *numuser, int *numgroup, int *needsort) 603*5331Samw { 604*5331Samw int error = 0; 605*5331Samw int i; 606*5331Samw int curtype = 0; 607*5331Samw 608*5331Samw *hasmask = 0; 609*5331Samw *mask = 07; 610*5331Samw *needsort = 0; 611*5331Samw *numuser = 0; 612*5331Samw *numgroup = 0; 613*5331Samw 614*5331Samw for (i = 0; i < n; i++) { 615*5331Samw if (aclent[i].a_type < curtype) 616*5331Samw *needsort = 1; 617*5331Samw else if (aclent[i].a_type > curtype) 618*5331Samw curtype = aclent[i].a_type; 619*5331Samw if (aclent[i].a_type & USER) 620*5331Samw (*numuser)++; 621*5331Samw if (aclent[i].a_type & (GROUP | GROUP_OBJ)) 622*5331Samw (*numgroup)++; 623*5331Samw if (aclent[i].a_type & CLASS_OBJ) { 624*5331Samw if (*hasmask) { 625*5331Samw error = EINVAL; 626*5331Samw goto out; 627*5331Samw } else { 628*5331Samw *hasmask = 1; 629*5331Samw *mask = aclent[i].a_perm; 630*5331Samw } 631*5331Samw } 632*5331Samw } 633*5331Samw 634*5331Samw if ((! *hasmask) && (*numuser + *numgroup > 1)) { 635*5331Samw error = EINVAL; 636*5331Samw goto out; 637*5331Samw } 638*5331Samw 639*5331Samw out: 640*5331Samw return (error); 641*5331Samw } 642*5331Samw 643*5331Samw /* 644*5331Samw * Convert an array of aclent_t into an array of nfsace entries, 645*5331Samw * following POSIX draft -> nfsv4 conversion semantics as outlined in 646*5331Samw * the IETF draft. 647*5331Samw */ 648*5331Samw static int 649*5331Samw ln_aent_to_ace(aclent_t *aclent, int n, ace_t **acepp, int *rescount, int isdir) 650*5331Samw { 651*5331Samw int error = 0; 652*5331Samw mode_t mask; 653*5331Samw int numuser, numgroup, needsort; 654*5331Samw int resultsize = 0; 655*5331Samw int i, groupi = 0, skip; 656*5331Samw ace_t *acep, *result = NULL; 657*5331Samw int hasmask; 658*5331Samw 659*5331Samw error = ln_aent_preprocess(aclent, n, &hasmask, &mask, 660*5331Samw &numuser, &numgroup, &needsort); 661*5331Samw if (error != 0) 662*5331Samw goto out; 663*5331Samw 664*5331Samw /* allow + deny for each aclent */ 665*5331Samw resultsize = n * 2; 666*5331Samw if (hasmask) { 667*5331Samw /* 668*5331Samw * stick extra deny on the group_obj and on each 669*5331Samw * user|group for the mask (the group_obj was added 670*5331Samw * into the count for numgroup) 671*5331Samw */ 672*5331Samw resultsize += numuser + numgroup; 673*5331Samw /* ... and don't count the mask itself */ 674*5331Samw resultsize -= 2; 675*5331Samw } 676*5331Samw 677*5331Samw /* sort the source if necessary */ 678*5331Samw if (needsort) 679*5331Samw ksort((caddr_t)aclent, n, sizeof (aclent_t), cmp2acls); 680*5331Samw 681*5331Samw if (cacl_malloc((void **)&result, resultsize * sizeof (ace_t)) != 0) 682*5331Samw goto out; 683*5331Samw 684*5331Samw acep = result; 685*5331Samw 686*5331Samw for (i = 0; i < n; i++) { 687*5331Samw /* 688*5331Samw * don't process CLASS_OBJ (mask); mask was grabbed in 689*5331Samw * ln_aent_preprocess() 690*5331Samw */ 691*5331Samw if (aclent[i].a_type & CLASS_OBJ) 692*5331Samw continue; 693*5331Samw 694*5331Samw /* If we need an ACL_MASK emulator, prepend it now */ 695*5331Samw if ((hasmask) && 696*5331Samw (aclent[i].a_type & (USER | GROUP | GROUP_OBJ))) { 697*5331Samw acep->a_type = ACE_ACCESS_DENIED_ACE_TYPE; 698*5331Samw acep->a_flags = 0; 699*5331Samw if (aclent[i].a_type & GROUP_OBJ) { 700*5331Samw acep->a_who = (uid_t)-1; 701*5331Samw acep->a_flags |= 702*5331Samw (ACE_IDENTIFIER_GROUP|ACE_GROUP); 703*5331Samw } else if (aclent[i].a_type & USER) { 704*5331Samw acep->a_who = aclent[i].a_id; 705*5331Samw } else { 706*5331Samw acep->a_who = aclent[i].a_id; 707*5331Samw acep->a_flags |= ACE_IDENTIFIER_GROUP; 708*5331Samw } 709*5331Samw if (aclent[i].a_type & ACL_DEFAULT) { 710*5331Samw acep->a_flags |= ACE_INHERIT_ONLY_ACE | 711*5331Samw ACE_FILE_INHERIT_ACE | 712*5331Samw ACE_DIRECTORY_INHERIT_ACE; 713*5331Samw } 714*5331Samw /* 715*5331Samw * Set the access mask for the prepended deny 716*5331Samw * ace. To do this, we invert the mask (found 717*5331Samw * in ln_aent_preprocess()) then convert it to an 718*5331Samw * DENY ace access_mask. 719*5331Samw */ 720*5331Samw acep->a_access_mask = mode_to_ace_access((mask ^ 07), 721*5331Samw isdir, 0, 0); 722*5331Samw acep += 1; 723*5331Samw } 724*5331Samw 725*5331Samw /* handle a_perm -> access_mask */ 726*5331Samw acep->a_access_mask = mode_to_ace_access(aclent[i].a_perm, 727*5331Samw isdir, aclent[i].a_type & USER_OBJ, 1); 728*5331Samw 729*5331Samw /* emulate a default aclent */ 730*5331Samw if (aclent[i].a_type & ACL_DEFAULT) { 731*5331Samw acep->a_flags |= ACE_INHERIT_ONLY_ACE | 732*5331Samw ACE_FILE_INHERIT_ACE | 733*5331Samw ACE_DIRECTORY_INHERIT_ACE; 734*5331Samw } 735*5331Samw 736*5331Samw /* 737*5331Samw * handle a_perm and a_id 738*5331Samw * 739*5331Samw * this must be done last, since it involves the 740*5331Samw * corresponding deny aces, which are handled 741*5331Samw * differently for each different a_type. 742*5331Samw */ 743*5331Samw if (aclent[i].a_type & USER_OBJ) { 744*5331Samw acep->a_who = (uid_t)-1; 745*5331Samw acep->a_flags |= ACE_OWNER; 746*5331Samw ace_make_deny(acep, acep + 1, isdir, B_TRUE); 747*5331Samw acep += 2; 748*5331Samw } else if (aclent[i].a_type & USER) { 749*5331Samw acep->a_who = aclent[i].a_id; 750*5331Samw ace_make_deny(acep, acep + 1, isdir, B_FALSE); 751*5331Samw acep += 2; 752*5331Samw } else if (aclent[i].a_type & (GROUP_OBJ | GROUP)) { 753*5331Samw if (aclent[i].a_type & GROUP_OBJ) { 754*5331Samw acep->a_who = (uid_t)-1; 755*5331Samw acep->a_flags |= ACE_GROUP; 756*5331Samw } else { 757*5331Samw acep->a_who = aclent[i].a_id; 758*5331Samw } 759*5331Samw acep->a_flags |= ACE_IDENTIFIER_GROUP; 760*5331Samw /* 761*5331Samw * Set the corresponding deny for the group ace. 762*5331Samw * 763*5331Samw * The deny aces go after all of the groups, unlike 764*5331Samw * everything else, where they immediately follow 765*5331Samw * the allow ace. 766*5331Samw * 767*5331Samw * We calculate "skip", the number of slots to 768*5331Samw * skip ahead for the deny ace, here. 769*5331Samw * 770*5331Samw * The pattern is: 771*5331Samw * MD1 A1 MD2 A2 MD3 A3 D1 D2 D3 772*5331Samw * thus, skip is 773*5331Samw * (2 * numgroup) - 1 - groupi 774*5331Samw * (2 * numgroup) to account for MD + A 775*5331Samw * - 1 to account for the fact that we're on the 776*5331Samw * access (A), not the mask (MD) 777*5331Samw * - groupi to account for the fact that we have 778*5331Samw * passed up groupi number of MD's. 779*5331Samw */ 780*5331Samw skip = (2 * numgroup) - 1 - groupi; 781*5331Samw ace_make_deny(acep, acep + skip, isdir, B_FALSE); 782*5331Samw /* 783*5331Samw * If we just did the last group, skip acep past 784*5331Samw * all of the denies; else, just move ahead one. 785*5331Samw */ 786*5331Samw if (++groupi >= numgroup) 787*5331Samw acep += numgroup + 1; 788*5331Samw else 789*5331Samw acep += 1; 790*5331Samw } else if (aclent[i].a_type & OTHER_OBJ) { 791*5331Samw acep->a_who = (uid_t)-1; 792*5331Samw acep->a_flags |= ACE_EVERYONE; 793*5331Samw ace_make_deny(acep, acep + 1, isdir, B_FALSE); 794*5331Samw acep += 2; 795*5331Samw } else { 796*5331Samw error = EINVAL; 797*5331Samw goto out; 798*5331Samw } 799*5331Samw } 800*5331Samw 801*5331Samw *acepp = result; 802*5331Samw *rescount = resultsize; 803*5331Samw 804*5331Samw out: 805*5331Samw if (error != 0) { 806*5331Samw if ((result != NULL) && (resultsize > 0)) { 807*5331Samw cacl_free(result, resultsize * sizeof (ace_t)); 808*5331Samw } 809*5331Samw } 810*5331Samw 811*5331Samw return (error); 812*5331Samw } 813*5331Samw 814*5331Samw static int 815*5331Samw convert_aent_to_ace(aclent_t *aclentp, int aclcnt, int isdir, 816*5331Samw ace_t **retacep, int *retacecnt) 817*5331Samw { 818*5331Samw ace_t *acep; 819*5331Samw ace_t *dfacep; 820*5331Samw int acecnt = 0; 821*5331Samw int dfacecnt = 0; 822*5331Samw int dfaclstart = 0; 823*5331Samw int dfaclcnt = 0; 824*5331Samw aclent_t *aclp; 825*5331Samw int i; 826*5331Samw int error; 827*5331Samw int acesz, dfacesz; 828*5331Samw 829*5331Samw ksort((caddr_t)aclentp, aclcnt, sizeof (aclent_t), cmp2acls); 830*5331Samw 831*5331Samw for (i = 0, aclp = aclentp; i < aclcnt; aclp++, i++) { 832*5331Samw if (aclp->a_type & ACL_DEFAULT) 833*5331Samw break; 834*5331Samw } 835*5331Samw 836*5331Samw if (i < aclcnt) { 837*5331Samw dfaclstart = i; 838*5331Samw dfaclcnt = aclcnt - i; 839*5331Samw } 840*5331Samw 841*5331Samw if (dfaclcnt && isdir == 0) { 842*5331Samw return (EINVAL); 843*5331Samw } 844*5331Samw 845*5331Samw error = ln_aent_to_ace(aclentp, i, &acep, &acecnt, isdir); 846*5331Samw if (error) 847*5331Samw return (error); 848*5331Samw 849*5331Samw if (dfaclcnt) { 850*5331Samw error = ln_aent_to_ace(&aclentp[dfaclstart], dfaclcnt, 851*5331Samw &dfacep, &dfacecnt, isdir); 852*5331Samw if (error) { 853*5331Samw if (acep) { 854*5331Samw cacl_free(acep, acecnt * sizeof (ace_t)); 855*5331Samw } 856*5331Samw return (error); 857*5331Samw } 858*5331Samw } 859*5331Samw 860*5331Samw if (dfacecnt != 0) { 861*5331Samw acesz = sizeof (ace_t) * acecnt; 862*5331Samw dfacesz = sizeof (ace_t) * dfacecnt; 863*5331Samw acep = cacl_realloc(acep, acesz, acesz + dfacesz); 864*5331Samw if (acep == NULL) 865*5331Samw return (ENOMEM); 866*5331Samw if (dfaclcnt) { 867*5331Samw (void) memcpy(acep + acecnt, dfacep, dfacesz); 868*5331Samw } 869*5331Samw } 870*5331Samw if (dfaclcnt) 871*5331Samw cacl_free(dfacep, dfacecnt * sizeof (ace_t)); 872*5331Samw 873*5331Samw *retacecnt = acecnt + dfacecnt; 874*5331Samw *retacep = acep; 875*5331Samw return (0); 876*5331Samw } 877*5331Samw 878*5331Samw static int 879*5331Samw ace_mask_to_mode(uint32_t mask, o_mode_t *modep, int isdir) 880*5331Samw { 881*5331Samw int error = 0; 882*5331Samw o_mode_t mode = 0; 883*5331Samw uint32_t bits, wantbits; 884*5331Samw 885*5331Samw /* read */ 886*5331Samw if (mask & ACE_READ_DATA) 887*5331Samw mode |= S_IROTH; 888*5331Samw 889*5331Samw /* write */ 890*5331Samw wantbits = (ACE_WRITE_DATA | ACE_APPEND_DATA); 891*5331Samw if (isdir) 892*5331Samw wantbits |= ACE_DELETE_CHILD; 893*5331Samw bits = mask & wantbits; 894*5331Samw if (bits != 0) { 895*5331Samw if (bits != wantbits) { 896*5331Samw error = ENOTSUP; 897*5331Samw goto out; 898*5331Samw } 899*5331Samw mode |= S_IWOTH; 900*5331Samw } 901*5331Samw 902*5331Samw /* exec */ 903*5331Samw if (mask & ACE_EXECUTE) { 904*5331Samw mode |= S_IXOTH; 905*5331Samw } 906*5331Samw 907*5331Samw *modep = mode; 908*5331Samw 909*5331Samw out: 910*5331Samw return (error); 911*5331Samw } 912*5331Samw 913*5331Samw static void 914*5331Samw acevals_init(acevals_t *vals, uid_t key) 915*5331Samw { 916*5331Samw bzero(vals, sizeof (*vals)); 917*5331Samw vals->allowed = ACE_MASK_UNDEFINED; 918*5331Samw vals->denied = ACE_MASK_UNDEFINED; 919*5331Samw vals->mask = ACE_MASK_UNDEFINED; 920*5331Samw vals->key = key; 921*5331Samw } 922*5331Samw 923*5331Samw static void 924*5331Samw ace_list_init(ace_list_t *al, int dfacl_flag) 925*5331Samw { 926*5331Samw acevals_init(&al->user_obj, NULL); 927*5331Samw acevals_init(&al->group_obj, NULL); 928*5331Samw acevals_init(&al->other_obj, NULL); 929*5331Samw al->numusers = 0; 930*5331Samw al->numgroups = 0; 931*5331Samw al->acl_mask = 0; 932*5331Samw al->hasmask = 0; 933*5331Samw al->state = ace_unused; 934*5331Samw al->seen = 0; 935*5331Samw al->dfacl_flag = dfacl_flag; 936*5331Samw } 937*5331Samw 938*5331Samw /* 939*5331Samw * Find or create an acevals holder for a given id and avl tree. 940*5331Samw * 941*5331Samw * Note that only one thread will ever touch these avl trees, so 942*5331Samw * there is no need for locking. 943*5331Samw */ 944*5331Samw static acevals_t * 945*5331Samw acevals_find(ace_t *ace, avl_tree_t *avl, int *num) 946*5331Samw { 947*5331Samw acevals_t key, *rc; 948*5331Samw avl_index_t where; 949*5331Samw 950*5331Samw key.key = ace->a_who; 951*5331Samw rc = avl_find(avl, &key, &where); 952*5331Samw if (rc != NULL) 953*5331Samw return (rc); 954*5331Samw 955*5331Samw /* this memory is freed by ln_ace_to_aent()->ace_list_free() */ 956*5331Samw if (cacl_malloc((void **)&rc, sizeof (acevals_t)) != 0) 957*5331Samw return (NULL); 958*5331Samw 959*5331Samw acevals_init(rc, ace->a_who); 960*5331Samw avl_insert(avl, rc, where); 961*5331Samw (*num)++; 962*5331Samw 963*5331Samw return (rc); 964*5331Samw } 965*5331Samw 966*5331Samw static int 967*5331Samw access_mask_check(ace_t *acep, int mask_bit, int isowner) 968*5331Samw { 969*5331Samw int set_deny, err_deny; 970*5331Samw int set_allow, err_allow; 971*5331Samw int acl_consume; 972*5331Samw int haswriteperm, hasreadperm; 973*5331Samw 974*5331Samw if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) { 975*5331Samw haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 0 : 1; 976*5331Samw hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 0 : 1; 977*5331Samw } else { 978*5331Samw haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 1 : 0; 979*5331Samw hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 1 : 0; 980*5331Samw } 981*5331Samw 982*5331Samw acl_consume = (ACL_SYNCHRONIZE_ERR_DENY | 983*5331Samw ACL_DELETE_ERR_DENY | 984*5331Samw ACL_WRITE_OWNER_ERR_DENY | 985*5331Samw ACL_WRITE_OWNER_ERR_ALLOW | 986*5331Samw ACL_WRITE_ATTRS_OWNER_SET_ALLOW | 987*5331Samw ACL_WRITE_ATTRS_OWNER_ERR_DENY | 988*5331Samw ACL_WRITE_ATTRS_WRITER_SET_DENY | 989*5331Samw ACL_WRITE_ATTRS_WRITER_ERR_ALLOW | 990*5331Samw ACL_WRITE_NAMED_WRITER_ERR_DENY | 991*5331Samw ACL_READ_NAMED_READER_ERR_DENY); 992*5331Samw 993*5331Samw if (mask_bit == ACE_SYNCHRONIZE) { 994*5331Samw set_deny = ACL_SYNCHRONIZE_SET_DENY; 995*5331Samw err_deny = ACL_SYNCHRONIZE_ERR_DENY; 996*5331Samw set_allow = ACL_SYNCHRONIZE_SET_ALLOW; 997*5331Samw err_allow = ACL_SYNCHRONIZE_ERR_ALLOW; 998*5331Samw } else if (mask_bit == ACE_WRITE_OWNER) { 999*5331Samw set_deny = ACL_WRITE_OWNER_SET_DENY; 1000*5331Samw err_deny = ACL_WRITE_OWNER_ERR_DENY; 1001*5331Samw set_allow = ACL_WRITE_OWNER_SET_ALLOW; 1002*5331Samw err_allow = ACL_WRITE_OWNER_ERR_ALLOW; 1003*5331Samw } else if (mask_bit == ACE_DELETE) { 1004*5331Samw set_deny = ACL_DELETE_SET_DENY; 1005*5331Samw err_deny = ACL_DELETE_ERR_DENY; 1006*5331Samw set_allow = ACL_DELETE_SET_ALLOW; 1007*5331Samw err_allow = ACL_DELETE_ERR_ALLOW; 1008*5331Samw } else if (mask_bit == ACE_WRITE_ATTRIBUTES) { 1009*5331Samw if (isowner) { 1010*5331Samw set_deny = ACL_WRITE_ATTRS_OWNER_SET_DENY; 1011*5331Samw err_deny = ACL_WRITE_ATTRS_OWNER_ERR_DENY; 1012*5331Samw set_allow = ACL_WRITE_ATTRS_OWNER_SET_ALLOW; 1013*5331Samw err_allow = ACL_WRITE_ATTRS_OWNER_ERR_ALLOW; 1014*5331Samw } else if (haswriteperm) { 1015*5331Samw set_deny = ACL_WRITE_ATTRS_WRITER_SET_DENY; 1016*5331Samw err_deny = ACL_WRITE_ATTRS_WRITER_ERR_DENY; 1017*5331Samw set_allow = ACL_WRITE_ATTRS_WRITER_SET_ALLOW; 1018*5331Samw err_allow = ACL_WRITE_ATTRS_WRITER_ERR_ALLOW; 1019*5331Samw } else { 1020*5331Samw if ((acep->a_access_mask & mask_bit) && 1021*5331Samw (acep->a_type & ACE_ACCESS_ALLOWED_ACE_TYPE)) { 1022*5331Samw return (ENOTSUP); 1023*5331Samw } 1024*5331Samw return (0); 1025*5331Samw } 1026*5331Samw } else if (mask_bit == ACE_READ_NAMED_ATTRS) { 1027*5331Samw if (!hasreadperm) 1028*5331Samw return (0); 1029*5331Samw 1030*5331Samw set_deny = ACL_READ_NAMED_READER_SET_DENY; 1031*5331Samw err_deny = ACL_READ_NAMED_READER_ERR_DENY; 1032*5331Samw set_allow = ACL_READ_NAMED_READER_SET_ALLOW; 1033*5331Samw err_allow = ACL_READ_NAMED_READER_ERR_ALLOW; 1034*5331Samw } else if (mask_bit == ACE_WRITE_NAMED_ATTRS) { 1035*5331Samw if (!haswriteperm) 1036*5331Samw return (0); 1037*5331Samw 1038*5331Samw set_deny = ACL_WRITE_NAMED_WRITER_SET_DENY; 1039*5331Samw err_deny = ACL_WRITE_NAMED_WRITER_ERR_DENY; 1040*5331Samw set_allow = ACL_WRITE_NAMED_WRITER_SET_ALLOW; 1041*5331Samw err_allow = ACL_WRITE_NAMED_WRITER_ERR_ALLOW; 1042*5331Samw } else { 1043*5331Samw return (EINVAL); 1044*5331Samw } 1045*5331Samw 1046*5331Samw if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) { 1047*5331Samw if (acl_consume & set_deny) { 1048*5331Samw if (!(acep->a_access_mask & mask_bit)) { 1049*5331Samw return (ENOTSUP); 1050*5331Samw } 1051*5331Samw } else if (acl_consume & err_deny) { 1052*5331Samw if (acep->a_access_mask & mask_bit) { 1053*5331Samw return (ENOTSUP); 1054*5331Samw } 1055*5331Samw } 1056*5331Samw } else { 1057*5331Samw /* ACE_ACCESS_ALLOWED_ACE_TYPE */ 1058*5331Samw if (acl_consume & set_allow) { 1059*5331Samw if (!(acep->a_access_mask & mask_bit)) { 1060*5331Samw return (ENOTSUP); 1061*5331Samw } 1062*5331Samw } else if (acl_consume & err_allow) { 1063*5331Samw if (acep->a_access_mask & mask_bit) { 1064*5331Samw return (ENOTSUP); 1065*5331Samw } 1066*5331Samw } 1067*5331Samw } 1068*5331Samw return (0); 1069*5331Samw } 1070*5331Samw 1071*5331Samw static int 1072*5331Samw ace_to_aent_legal(ace_t *acep) 1073*5331Samw { 1074*5331Samw int error = 0; 1075*5331Samw int isowner; 1076*5331Samw 1077*5331Samw /* only ALLOW or DENY */ 1078*5331Samw if ((acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE) && 1079*5331Samw (acep->a_type != ACE_ACCESS_DENIED_ACE_TYPE)) { 1080*5331Samw error = ENOTSUP; 1081*5331Samw goto out; 1082*5331Samw } 1083*5331Samw 1084*5331Samw /* check for invalid flags */ 1085*5331Samw if (acep->a_flags & ~(ACE_VALID_FLAG_BITS)) { 1086*5331Samw error = EINVAL; 1087*5331Samw goto out; 1088*5331Samw } 1089*5331Samw 1090*5331Samw /* some flags are illegal */ 1091*5331Samw if (acep->a_flags & (ACE_SUCCESSFUL_ACCESS_ACE_FLAG | 1092*5331Samw ACE_FAILED_ACCESS_ACE_FLAG | 1093*5331Samw ACE_NO_PROPAGATE_INHERIT_ACE)) { 1094*5331Samw error = ENOTSUP; 1095*5331Samw goto out; 1096*5331Samw } 1097*5331Samw 1098*5331Samw /* check for invalid masks */ 1099*5331Samw if (acep->a_access_mask & ~(ACE_VALID_MASK_BITS)) { 1100*5331Samw error = EINVAL; 1101*5331Samw goto out; 1102*5331Samw } 1103*5331Samw 1104*5331Samw if ((acep->a_flags & ACE_OWNER)) { 1105*5331Samw isowner = 1; 1106*5331Samw } else { 1107*5331Samw isowner = 0; 1108*5331Samw } 1109*5331Samw 1110*5331Samw error = access_mask_check(acep, ACE_SYNCHRONIZE, isowner); 1111*5331Samw if (error) 1112*5331Samw goto out; 1113*5331Samw 1114*5331Samw error = access_mask_check(acep, ACE_WRITE_OWNER, isowner); 1115*5331Samw if (error) 1116*5331Samw goto out; 1117*5331Samw 1118*5331Samw error = access_mask_check(acep, ACE_DELETE, isowner); 1119*5331Samw if (error) 1120*5331Samw goto out; 1121*5331Samw 1122*5331Samw error = access_mask_check(acep, ACE_WRITE_ATTRIBUTES, isowner); 1123*5331Samw if (error) 1124*5331Samw goto out; 1125*5331Samw 1126*5331Samw error = access_mask_check(acep, ACE_READ_NAMED_ATTRS, isowner); 1127*5331Samw if (error) 1128*5331Samw goto out; 1129*5331Samw 1130*5331Samw error = access_mask_check(acep, ACE_WRITE_NAMED_ATTRS, isowner); 1131*5331Samw if (error) 1132*5331Samw goto out; 1133*5331Samw 1134*5331Samw /* more detailed checking of masks */ 1135*5331Samw if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) { 1136*5331Samw if (! (acep->a_access_mask & ACE_READ_ATTRIBUTES)) { 1137*5331Samw error = ENOTSUP; 1138*5331Samw goto out; 1139*5331Samw } 1140*5331Samw if ((acep->a_access_mask & ACE_WRITE_DATA) && 1141*5331Samw (! (acep->a_access_mask & ACE_APPEND_DATA))) { 1142*5331Samw error = ENOTSUP; 1143*5331Samw goto out; 1144*5331Samw } 1145*5331Samw if ((! (acep->a_access_mask & ACE_WRITE_DATA)) && 1146*5331Samw (acep->a_access_mask & ACE_APPEND_DATA)) { 1147*5331Samw error = ENOTSUP; 1148*5331Samw goto out; 1149*5331Samw } 1150*5331Samw } 1151*5331Samw 1152*5331Samw /* ACL enforcement */ 1153*5331Samw if ((acep->a_access_mask & ACE_READ_ACL) && 1154*5331Samw (acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE)) { 1155*5331Samw error = ENOTSUP; 1156*5331Samw goto out; 1157*5331Samw } 1158*5331Samw if (acep->a_access_mask & ACE_WRITE_ACL) { 1159*5331Samw if ((acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) && 1160*5331Samw (isowner)) { 1161*5331Samw error = ENOTSUP; 1162*5331Samw goto out; 1163*5331Samw } 1164*5331Samw if ((acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) && 1165*5331Samw (! isowner)) { 1166*5331Samw error = ENOTSUP; 1167*5331Samw goto out; 1168*5331Samw } 1169*5331Samw } 1170*5331Samw 1171*5331Samw out: 1172*5331Samw return (error); 1173*5331Samw } 1174*5331Samw 1175*5331Samw static int 1176*5331Samw ace_allow_to_mode(uint32_t mask, o_mode_t *modep, int isdir) 1177*5331Samw { 1178*5331Samw /* ACE_READ_ACL and ACE_READ_ATTRIBUTES must both be set */ 1179*5331Samw if ((mask & (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) != 1180*5331Samw (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) { 1181*5331Samw return (ENOTSUP); 1182*5331Samw } 1183*5331Samw 1184*5331Samw return (ace_mask_to_mode(mask, modep, isdir)); 1185*5331Samw } 1186*5331Samw 1187*5331Samw static int 1188*5331Samw acevals_to_aent(acevals_t *vals, aclent_t *dest, ace_list_t *list, 1189*5331Samw uid_t owner, gid_t group, int isdir) 1190*5331Samw { 1191*5331Samw int error; 1192*5331Samw uint32_t flips = ACE_POSIX_SUPPORTED_BITS; 1193*5331Samw 1194*5331Samw if (isdir) 1195*5331Samw flips |= ACE_DELETE_CHILD; 1196*5331Samw if (vals->allowed != (vals->denied ^ flips)) { 1197*5331Samw error = ENOTSUP; 1198*5331Samw goto out; 1199*5331Samw } 1200*5331Samw if ((list->hasmask) && (list->acl_mask != vals->mask) && 1201*5331Samw (vals->aent_type & (USER | GROUP | GROUP_OBJ))) { 1202*5331Samw error = ENOTSUP; 1203*5331Samw goto out; 1204*5331Samw } 1205*5331Samw error = ace_allow_to_mode(vals->allowed, &dest->a_perm, isdir); 1206*5331Samw if (error != 0) 1207*5331Samw goto out; 1208*5331Samw dest->a_type = vals->aent_type; 1209*5331Samw if (dest->a_type & (USER | GROUP)) { 1210*5331Samw dest->a_id = vals->key; 1211*5331Samw } else if (dest->a_type & USER_OBJ) { 1212*5331Samw dest->a_id = owner; 1213*5331Samw } else if (dest->a_type & GROUP_OBJ) { 1214*5331Samw dest->a_id = group; 1215*5331Samw } else if (dest->a_type & OTHER_OBJ) { 1216*5331Samw dest->a_id = 0; 1217*5331Samw } else { 1218*5331Samw error = EINVAL; 1219*5331Samw goto out; 1220*5331Samw } 1221*5331Samw 1222*5331Samw out: 1223*5331Samw return (error); 1224*5331Samw } 1225*5331Samw 1226*5331Samw 1227*5331Samw static int 1228*5331Samw ace_list_to_aent(ace_list_t *list, aclent_t **aclentp, int *aclcnt, 1229*5331Samw uid_t owner, gid_t group, int isdir) 1230*5331Samw { 1231*5331Samw int error = 0; 1232*5331Samw aclent_t *aent, *result = NULL; 1233*5331Samw acevals_t *vals; 1234*5331Samw int resultcount; 1235*5331Samw 1236*5331Samw if ((list->seen & (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) != 1237*5331Samw (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) { 1238*5331Samw error = ENOTSUP; 1239*5331Samw goto out; 1240*5331Samw } 1241*5331Samw if ((! list->hasmask) && (list->numusers + list->numgroups > 0)) { 1242*5331Samw error = ENOTSUP; 1243*5331Samw goto out; 1244*5331Samw } 1245*5331Samw 1246*5331Samw resultcount = 3 + list->numusers + list->numgroups; 1247*5331Samw /* 1248*5331Samw * This must be the same condition as below, when we add the CLASS_OBJ 1249*5331Samw * (aka ACL mask) 1250*5331Samw */ 1251*5331Samw if ((list->hasmask) || (! list->dfacl_flag)) 1252*5331Samw resultcount += 1; 1253*5331Samw 1254*5331Samw if (cacl_malloc((void **)&result, 1255*5331Samw resultcount * sizeof (aclent_t)) != 0) { 1256*5331Samw error = ENOMEM; 1257*5331Samw goto out; 1258*5331Samw } 1259*5331Samw aent = result; 1260*5331Samw 1261*5331Samw /* USER_OBJ */ 1262*5331Samw if (!(list->user_obj.aent_type & USER_OBJ)) { 1263*5331Samw error = EINVAL; 1264*5331Samw goto out; 1265*5331Samw } 1266*5331Samw 1267*5331Samw error = acevals_to_aent(&list->user_obj, aent, list, owner, group, 1268*5331Samw isdir); 1269*5331Samw 1270*5331Samw if (error != 0) 1271*5331Samw goto out; 1272*5331Samw ++aent; 1273*5331Samw /* USER */ 1274*5331Samw vals = NULL; 1275*5331Samw for (vals = avl_first(&list->user); vals != NULL; 1276*5331Samw vals = AVL_NEXT(&list->user, vals)) { 1277*5331Samw if (!(vals->aent_type & USER)) { 1278*5331Samw error = EINVAL; 1279*5331Samw goto out; 1280*5331Samw } 1281*5331Samw error = acevals_to_aent(vals, aent, list, owner, group, 1282*5331Samw isdir); 1283*5331Samw if (error != 0) 1284*5331Samw goto out; 1285*5331Samw ++aent; 1286*5331Samw } 1287*5331Samw /* GROUP_OBJ */ 1288*5331Samw if (!(list->group_obj.aent_type & GROUP_OBJ)) { 1289*5331Samw error = EINVAL; 1290*5331Samw goto out; 1291*5331Samw } 1292*5331Samw error = acevals_to_aent(&list->group_obj, aent, list, owner, group, 1293*5331Samw isdir); 1294*5331Samw if (error != 0) 1295*5331Samw goto out; 1296*5331Samw ++aent; 1297*5331Samw /* GROUP */ 1298*5331Samw vals = NULL; 1299*5331Samw for (vals = avl_first(&list->group); vals != NULL; 1300*5331Samw vals = AVL_NEXT(&list->group, vals)) { 1301*5331Samw if (!(vals->aent_type & GROUP)) { 1302*5331Samw error = EINVAL; 1303*5331Samw goto out; 1304*5331Samw } 1305*5331Samw error = acevals_to_aent(vals, aent, list, owner, group, 1306*5331Samw isdir); 1307*5331Samw if (error != 0) 1308*5331Samw goto out; 1309*5331Samw ++aent; 1310*5331Samw } 1311*5331Samw /* 1312*5331Samw * CLASS_OBJ (aka ACL_MASK) 1313*5331Samw * 1314*5331Samw * An ACL_MASK is not fabricated if the ACL is a default ACL. 1315*5331Samw * This is to follow UFS's behavior. 1316*5331Samw */ 1317*5331Samw if ((list->hasmask) || (! list->dfacl_flag)) { 1318*5331Samw if (list->hasmask) { 1319*5331Samw uint32_t flips = ACE_POSIX_SUPPORTED_BITS; 1320*5331Samw if (isdir) 1321*5331Samw flips |= ACE_DELETE_CHILD; 1322*5331Samw error = ace_mask_to_mode(list->acl_mask ^ flips, 1323*5331Samw &aent->a_perm, isdir); 1324*5331Samw if (error != 0) 1325*5331Samw goto out; 1326*5331Samw } else { 1327*5331Samw /* fabricate the ACL_MASK from the group permissions */ 1328*5331Samw error = ace_mask_to_mode(list->group_obj.allowed, 1329*5331Samw &aent->a_perm, isdir); 1330*5331Samw if (error != 0) 1331*5331Samw goto out; 1332*5331Samw } 1333*5331Samw aent->a_id = 0; 1334*5331Samw aent->a_type = CLASS_OBJ | list->dfacl_flag; 1335*5331Samw ++aent; 1336*5331Samw } 1337*5331Samw /* OTHER_OBJ */ 1338*5331Samw if (!(list->other_obj.aent_type & OTHER_OBJ)) { 1339*5331Samw error = EINVAL; 1340*5331Samw goto out; 1341*5331Samw } 1342*5331Samw error = acevals_to_aent(&list->other_obj, aent, list, owner, group, 1343*5331Samw isdir); 1344*5331Samw if (error != 0) 1345*5331Samw goto out; 1346*5331Samw ++aent; 1347*5331Samw 1348*5331Samw *aclentp = result; 1349*5331Samw *aclcnt = resultcount; 1350*5331Samw 1351*5331Samw out: 1352*5331Samw if (error != 0) { 1353*5331Samw if (result != NULL) 1354*5331Samw cacl_free(result, resultcount * sizeof (aclent_t)); 1355*5331Samw } 1356*5331Samw 1357*5331Samw return (error); 1358*5331Samw } 1359*5331Samw 1360*5331Samw 1361*5331Samw /* 1362*5331Samw * free all data associated with an ace_list 1363*5331Samw */ 1364*5331Samw static void 1365*5331Samw ace_list_free(ace_list_t *al) 1366*5331Samw { 1367*5331Samw acevals_t *node; 1368*5331Samw void *cookie; 1369*5331Samw 1370*5331Samw if (al == NULL) 1371*5331Samw return; 1372*5331Samw 1373*5331Samw cookie = NULL; 1374*5331Samw while ((node = avl_destroy_nodes(&al->user, &cookie)) != NULL) 1375*5331Samw cacl_free(node, sizeof (acevals_t)); 1376*5331Samw cookie = NULL; 1377*5331Samw while ((node = avl_destroy_nodes(&al->group, &cookie)) != NULL) 1378*5331Samw cacl_free(node, sizeof (acevals_t)); 1379*5331Samw 1380*5331Samw avl_destroy(&al->user); 1381*5331Samw avl_destroy(&al->group); 1382*5331Samw 1383*5331Samw /* free the container itself */ 1384*5331Samw cacl_free(al, sizeof (ace_list_t)); 1385*5331Samw } 1386*5331Samw 1387*5331Samw static int 1388*5331Samw acevals_compare(const void *va, const void *vb) 1389*5331Samw { 1390*5331Samw const acevals_t *a = va, *b = vb; 1391*5331Samw 1392*5331Samw if (a->key == b->key) 1393*5331Samw return (0); 1394*5331Samw 1395*5331Samw if (a->key > b->key) 1396*5331Samw return (1); 1397*5331Samw 1398*5331Samw else 1399*5331Samw return (-1); 1400*5331Samw } 1401*5331Samw 1402*5331Samw /* 1403*5331Samw * Convert a list of ace_t entries to equivalent regular and default 1404*5331Samw * aclent_t lists. Return error (ENOTSUP) when conversion is not possible. 1405*5331Samw */ 1406*5331Samw static int 1407*5331Samw ln_ace_to_aent(ace_t *ace, int n, uid_t owner, gid_t group, 1408*5331Samw aclent_t **aclentp, int *aclcnt, aclent_t **dfaclentp, int *dfaclcnt, 1409*5331Samw int isdir) 1410*5331Samw { 1411*5331Samw int error = 0; 1412*5331Samw ace_t *acep; 1413*5331Samw uint32_t bits; 1414*5331Samw int i; 1415*5331Samw ace_list_t *normacl = NULL, *dfacl = NULL, *acl; 1416*5331Samw acevals_t *vals; 1417*5331Samw 1418*5331Samw *aclentp = NULL; 1419*5331Samw *aclcnt = 0; 1420*5331Samw *dfaclentp = NULL; 1421*5331Samw *dfaclcnt = 0; 1422*5331Samw 1423*5331Samw /* we need at least user_obj, group_obj, and other_obj */ 1424*5331Samw if (n < 6) { 1425*5331Samw error = ENOTSUP; 1426*5331Samw goto out; 1427*5331Samw } 1428*5331Samw if (ace == NULL) { 1429*5331Samw error = EINVAL; 1430*5331Samw goto out; 1431*5331Samw } 1432*5331Samw 1433*5331Samw error = cacl_malloc((void **)&normacl, sizeof (ace_list_t)); 1434*5331Samw if (error != 0) 1435*5331Samw goto out; 1436*5331Samw 1437*5331Samw avl_create(&normacl->user, acevals_compare, sizeof (acevals_t), 1438*5331Samw offsetof(acevals_t, avl)); 1439*5331Samw avl_create(&normacl->group, acevals_compare, sizeof (acevals_t), 1440*5331Samw offsetof(acevals_t, avl)); 1441*5331Samw 1442*5331Samw ace_list_init(normacl, 0); 1443*5331Samw 1444*5331Samw error = cacl_malloc((void **)&dfacl, sizeof (ace_list_t)); 1445*5331Samw if (error != 0) 1446*5331Samw goto out; 1447*5331Samw 1448*5331Samw avl_create(&dfacl->user, acevals_compare, sizeof (acevals_t), 1449*5331Samw offsetof(acevals_t, avl)); 1450*5331Samw avl_create(&dfacl->group, acevals_compare, sizeof (acevals_t), 1451*5331Samw offsetof(acevals_t, avl)); 1452*5331Samw ace_list_init(dfacl, ACL_DEFAULT); 1453*5331Samw 1454*5331Samw /* process every ace_t... */ 1455*5331Samw for (i = 0; i < n; i++) { 1456*5331Samw acep = &ace[i]; 1457*5331Samw 1458*5331Samw /* rule out certain cases quickly */ 1459*5331Samw error = ace_to_aent_legal(acep); 1460*5331Samw if (error != 0) 1461*5331Samw goto out; 1462*5331Samw 1463*5331Samw /* 1464*5331Samw * Turn off these bits in order to not have to worry about 1465*5331Samw * them when doing the checks for compliments. 1466*5331Samw */ 1467*5331Samw acep->a_access_mask &= ~(ACE_WRITE_OWNER | ACE_DELETE | 1468*5331Samw ACE_SYNCHRONIZE | ACE_WRITE_ATTRIBUTES | 1469*5331Samw ACE_READ_NAMED_ATTRS | ACE_WRITE_NAMED_ATTRS); 1470*5331Samw 1471*5331Samw /* see if this should be a regular or default acl */ 1472*5331Samw bits = acep->a_flags & 1473*5331Samw (ACE_INHERIT_ONLY_ACE | 1474*5331Samw ACE_FILE_INHERIT_ACE | 1475*5331Samw ACE_DIRECTORY_INHERIT_ACE); 1476*5331Samw if (bits != 0) { 1477*5331Samw /* all or nothing on these inherit bits */ 1478*5331Samw if (bits != (ACE_INHERIT_ONLY_ACE | 1479*5331Samw ACE_FILE_INHERIT_ACE | 1480*5331Samw ACE_DIRECTORY_INHERIT_ACE)) { 1481*5331Samw error = ENOTSUP; 1482*5331Samw goto out; 1483*5331Samw } 1484*5331Samw acl = dfacl; 1485*5331Samw } else { 1486*5331Samw acl = normacl; 1487*5331Samw } 1488*5331Samw 1489*5331Samw if ((acep->a_flags & ACE_OWNER)) { 1490*5331Samw if (acl->state > ace_user_obj) { 1491*5331Samw error = ENOTSUP; 1492*5331Samw goto out; 1493*5331Samw } 1494*5331Samw acl->state = ace_user_obj; 1495*5331Samw acl->seen |= USER_OBJ; 1496*5331Samw vals = &acl->user_obj; 1497*5331Samw vals->aent_type = USER_OBJ | acl->dfacl_flag; 1498*5331Samw } else if ((acep->a_flags & ACE_EVERYONE)) { 1499*5331Samw acl->state = ace_other_obj; 1500*5331Samw acl->seen |= OTHER_OBJ; 1501*5331Samw vals = &acl->other_obj; 1502*5331Samw vals->aent_type = OTHER_OBJ | acl->dfacl_flag; 1503*5331Samw } else if (acep->a_flags & ACE_IDENTIFIER_GROUP) { 1504*5331Samw if (acl->state > ace_group) { 1505*5331Samw error = ENOTSUP; 1506*5331Samw goto out; 1507*5331Samw } 1508*5331Samw if ((acep->a_flags & ACE_GROUP)) { 1509*5331Samw acl->seen |= GROUP_OBJ; 1510*5331Samw vals = &acl->group_obj; 1511*5331Samw vals->aent_type = GROUP_OBJ | acl->dfacl_flag; 1512*5331Samw } else { 1513*5331Samw acl->seen |= GROUP; 1514*5331Samw vals = acevals_find(acep, &acl->group, 1515*5331Samw &acl->numgroups); 1516*5331Samw if (vals == NULL) { 1517*5331Samw error = ENOMEM; 1518*5331Samw goto out; 1519*5331Samw } 1520*5331Samw vals->aent_type = GROUP | acl->dfacl_flag; 1521*5331Samw } 1522*5331Samw acl->state = ace_group; 1523*5331Samw } else { 1524*5331Samw if (acl->state > ace_user) { 1525*5331Samw error = ENOTSUP; 1526*5331Samw goto out; 1527*5331Samw } 1528*5331Samw acl->state = ace_user; 1529*5331Samw acl->seen |= USER; 1530*5331Samw vals = acevals_find(acep, &acl->user, 1531*5331Samw &acl->numusers); 1532*5331Samw if (vals == NULL) { 1533*5331Samw error = ENOMEM; 1534*5331Samw goto out; 1535*5331Samw } 1536*5331Samw vals->aent_type = USER | acl->dfacl_flag; 1537*5331Samw } 1538*5331Samw 1539*5331Samw if (!(acl->state > ace_unused)) { 1540*5331Samw error = EINVAL; 1541*5331Samw goto out; 1542*5331Samw } 1543*5331Samw 1544*5331Samw if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) { 1545*5331Samw /* no more than one allowed per aclent_t */ 1546*5331Samw if (vals->allowed != ACE_MASK_UNDEFINED) { 1547*5331Samw error = ENOTSUP; 1548*5331Samw goto out; 1549*5331Samw } 1550*5331Samw vals->allowed = acep->a_access_mask; 1551*5331Samw } else { 1552*5331Samw /* 1553*5331Samw * it's a DENY; if there was a previous DENY, it 1554*5331Samw * must have been an ACL_MASK. 1555*5331Samw */ 1556*5331Samw if (vals->denied != ACE_MASK_UNDEFINED) { 1557*5331Samw /* ACL_MASK is for USER and GROUP only */ 1558*5331Samw if ((acl->state != ace_user) && 1559*5331Samw (acl->state != ace_group)) { 1560*5331Samw error = ENOTSUP; 1561*5331Samw goto out; 1562*5331Samw } 1563*5331Samw 1564*5331Samw if (! acl->hasmask) { 1565*5331Samw acl->hasmask = 1; 1566*5331Samw acl->acl_mask = vals->denied; 1567*5331Samw /* check for mismatched ACL_MASK emulations */ 1568*5331Samw } else if (acl->acl_mask != vals->denied) { 1569*5331Samw error = ENOTSUP; 1570*5331Samw goto out; 1571*5331Samw } 1572*5331Samw vals->mask = vals->denied; 1573*5331Samw } 1574*5331Samw vals->denied = acep->a_access_mask; 1575*5331Samw } 1576*5331Samw } 1577*5331Samw 1578*5331Samw /* done collating; produce the aclent_t lists */ 1579*5331Samw if (normacl->state != ace_unused) { 1580*5331Samw error = ace_list_to_aent(normacl, aclentp, aclcnt, 1581*5331Samw owner, group, isdir); 1582*5331Samw if (error != 0) { 1583*5331Samw goto out; 1584*5331Samw } 1585*5331Samw } 1586*5331Samw if (dfacl->state != ace_unused) { 1587*5331Samw error = ace_list_to_aent(dfacl, dfaclentp, dfaclcnt, 1588*5331Samw owner, group, isdir); 1589*5331Samw if (error != 0) { 1590*5331Samw goto out; 1591*5331Samw } 1592*5331Samw } 1593*5331Samw 1594*5331Samw out: 1595*5331Samw if (normacl != NULL) 1596*5331Samw ace_list_free(normacl); 1597*5331Samw if (dfacl != NULL) 1598*5331Samw ace_list_free(dfacl); 1599*5331Samw 1600*5331Samw return (error); 1601*5331Samw } 1602*5331Samw 1603*5331Samw static int 1604*5331Samw convert_ace_to_aent(ace_t *acebufp, int acecnt, int isdir, 1605*5331Samw uid_t owner, gid_t group, aclent_t **retaclentp, int *retaclcnt) 1606*5331Samw { 1607*5331Samw int error = 0; 1608*5331Samw aclent_t *aclentp, *dfaclentp; 1609*5331Samw int aclcnt, dfaclcnt; 1610*5331Samw int aclsz, dfaclsz; 1611*5331Samw 1612*5331Samw error = ln_ace_to_aent(acebufp, acecnt, owner, group, 1613*5331Samw &aclentp, &aclcnt, &dfaclentp, &dfaclcnt, isdir); 1614*5331Samw 1615*5331Samw if (error) 1616*5331Samw return (error); 1617*5331Samw 1618*5331Samw 1619*5331Samw if (dfaclcnt != 0) { 1620*5331Samw /* 1621*5331Samw * Slap aclentp and dfaclentp into a single array. 1622*5331Samw */ 1623*5331Samw aclsz = sizeof (aclent_t) * aclcnt; 1624*5331Samw dfaclsz = sizeof (aclent_t) * dfaclcnt; 1625*5331Samw aclentp = cacl_realloc(aclentp, aclsz, aclsz + dfaclsz); 1626*5331Samw if (aclentp != NULL) { 1627*5331Samw (void) memcpy(aclentp + aclcnt, dfaclentp, dfaclsz); 1628*5331Samw } else { 1629*5331Samw error = ENOMEM; 1630*5331Samw } 1631*5331Samw } 1632*5331Samw 1633*5331Samw if (aclentp) { 1634*5331Samw *retaclentp = aclentp; 1635*5331Samw *retaclcnt = aclcnt + dfaclcnt; 1636*5331Samw } 1637*5331Samw 1638*5331Samw if (dfaclentp) 1639*5331Samw cacl_free(dfaclentp, dfaclsz); 1640*5331Samw 1641*5331Samw return (error); 1642*5331Samw } 1643*5331Samw 1644*5331Samw 1645*5331Samw int 1646*5331Samw acl_translate(acl_t *aclp, int target_flavor, int isdir, uid_t owner, 1647*5331Samw gid_t group) 1648*5331Samw { 1649*5331Samw int aclcnt; 1650*5331Samw void *acldata; 1651*5331Samw int error; 1652*5331Samw 1653*5331Samw /* 1654*5331Samw * See if we need to translate 1655*5331Samw */ 1656*5331Samw if ((target_flavor == _ACL_ACE_ENABLED && aclp->acl_type == ACE_T) || 1657*5331Samw (target_flavor == _ACL_ACLENT_ENABLED && 1658*5331Samw aclp->acl_type == ACLENT_T)) 1659*5331Samw return (0); 1660*5331Samw 1661*5331Samw if (target_flavor == -1) { 1662*5331Samw error = EINVAL; 1663*5331Samw goto out; 1664*5331Samw } 1665*5331Samw 1666*5331Samw if (target_flavor == _ACL_ACE_ENABLED && 1667*5331Samw aclp->acl_type == ACLENT_T) { 1668*5331Samw error = convert_aent_to_ace(aclp->acl_aclp, 1669*5331Samw aclp->acl_cnt, isdir, (ace_t **)&acldata, &aclcnt); 1670*5331Samw if (error) 1671*5331Samw goto out; 1672*5331Samw 1673*5331Samw } else if (target_flavor == _ACL_ACLENT_ENABLED && 1674*5331Samw aclp->acl_type == ACE_T) { 1675*5331Samw error = convert_ace_to_aent(aclp->acl_aclp, aclp->acl_cnt, 1676*5331Samw isdir, owner, group, (aclent_t **)&acldata, &aclcnt); 1677*5331Samw if (error) 1678*5331Samw goto out; 1679*5331Samw } else { 1680*5331Samw error = ENOTSUP; 1681*5331Samw goto out; 1682*5331Samw } 1683*5331Samw 1684*5331Samw /* 1685*5331Samw * replace old acl with newly translated acl 1686*5331Samw */ 1687*5331Samw cacl_free(aclp->acl_aclp, aclp->acl_cnt * aclp->acl_entry_size); 1688*5331Samw aclp->acl_aclp = acldata; 1689*5331Samw aclp->acl_cnt = aclcnt; 1690*5331Samw if (target_flavor == _ACL_ACE_ENABLED) { 1691*5331Samw aclp->acl_type = ACE_T; 1692*5331Samw aclp->acl_entry_size = sizeof (ace_t); 1693*5331Samw } else { 1694*5331Samw aclp->acl_type = ACLENT_T; 1695*5331Samw aclp->acl_entry_size = sizeof (aclent_t); 1696*5331Samw } 1697*5331Samw return (0); 1698*5331Samw 1699*5331Samw out: 1700*5331Samw 1701*5331Samw #if !defined(_KERNEL) 1702*5331Samw errno = error; 1703*5331Samw return (-1); 1704*5331Samw #else 1705*5331Samw return (error); 1706*5331Samw #endif 1707*5331Samw } 1708