1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 5*1462Smarks * Common Development and Distribution License (the "License"). 6*1462Smarks * 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 /* 221231Smarks * Copyright 2006 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 <stdlib.h> 29789Sahrens #include <string.h> 30789Sahrens #include <unistd.h> 31789Sahrens #include <limits.h> 32789Sahrens #include <grp.h> 33789Sahrens #include <pwd.h> 34*1462Smarks #include <strings.h> 35789Sahrens #include <sys/types.h> 36789Sahrens #include <sys/acl.h> 37789Sahrens #include <errno.h> 38789Sahrens #include <sys/stat.h> 391420Smarks #include <sys/varargs.h> 40789Sahrens #include <locale.h> 41789Sahrens #include <aclutils.h> 42789Sahrens #include <acl_common.h> 43*1462Smarks #include <sys/avl.h> 44*1462Smarks 45*1462Smarks #define offsetof(s, m) ((size_t)(&(((s *)0)->m))) 46789Sahrens 47789Sahrens #define ACL_PATH 0 48789Sahrens #define ACL_FD 1 49789Sahrens 50789Sahrens #define ACE_POSIX_SUPPORTED_BITS (ACE_READ_DATA | \ 51789Sahrens ACE_WRITE_DATA | ACE_APPEND_DATA | ACE_EXECUTE | \ 52789Sahrens ACE_READ_ATTRIBUTES | ACE_READ_ACL | ACE_WRITE_ACL) 53789Sahrens 54789Sahrens 55*1462Smarks #define ACL_SYNCHRONIZE_SET_DENY 0x0000001 56789Sahrens #define ACL_SYNCHRONIZE_SET_ALLOW 0x0000002 57*1462Smarks #define ACL_SYNCHRONIZE_ERR_DENY 0x0000004 58*1462Smarks #define ACL_SYNCHRONIZE_ERR_ALLOW 0x0000008 59789Sahrens 60*1462Smarks #define ACL_WRITE_OWNER_SET_DENY 0x0000010 61789Sahrens #define ACL_WRITE_OWNER_SET_ALLOW 0x0000020 62*1462Smarks #define ACL_WRITE_OWNER_ERR_DENY 0x0000040 63*1462Smarks #define ACL_WRITE_OWNER_ERR_ALLOW 0x0000080 64789Sahrens 65*1462Smarks #define ACL_DELETE_SET_DENY 0x0000100 66*1462Smarks #define ACL_DELETE_SET_ALLOW 0x0000200 67*1462Smarks #define ACL_DELETE_ERR_DENY 0x0000400 68*1462Smarks #define ACL_DELETE_ERR_ALLOW 0x0000800 69*1462Smarks 70*1462Smarks #define ACL_WRITE_ATTRS_OWNER_SET_DENY 0x0001000 71789Sahrens #define ACL_WRITE_ATTRS_OWNER_SET_ALLOW 0x0002000 72*1462Smarks #define ACL_WRITE_ATTRS_OWNER_ERR_DENY 0x0004000 73*1462Smarks #define ACL_WRITE_ATTRS_OWNER_ERR_ALLOW 0x0008000 74789Sahrens 75789Sahrens #define ACL_WRITE_ATTRS_WRITER_SET_DENY 0x0010000 76*1462Smarks #define ACL_WRITE_ATTRS_WRITER_SET_ALLOW 0x0020000 77*1462Smarks #define ACL_WRITE_ATTRS_WRITER_ERR_DENY 0x0040000 78*1462Smarks #define ACL_WRITE_ATTRS_WRITER_ERR_ALLOW 0x0080000 79789Sahrens 80*1462Smarks #define ACL_WRITE_NAMED_WRITER_SET_DENY 0x0100000 81789Sahrens #define ACL_WRITE_NAMED_WRITER_SET_ALLOW 0x0200000 82*1462Smarks #define ACL_WRITE_NAMED_WRITER_ERR_DENY 0x0400000 83*1462Smarks #define ACL_WRITE_NAMED_WRITER_ERR_ALLOW 0x0800000 84*1462Smarks 85*1462Smarks #define ACL_READ_NAMED_READER_SET_DENY 0x1000000 86*1462Smarks #define ACL_READ_NAMED_READER_SET_ALLOW 0x2000000 87*1462Smarks #define ACL_READ_NAMED_READER_ERR_DENY 0x4000000 88*1462Smarks #define ACL_READ_NAMED_READER_ERR_ALLOW 0x8000000 89*1462Smarks 90*1462Smarks 91*1462Smarks #define ACE_VALID_MASK_BITS (\ 92*1462Smarks ACE_READ_DATA | \ 93*1462Smarks ACE_LIST_DIRECTORY | \ 94*1462Smarks ACE_WRITE_DATA | \ 95*1462Smarks ACE_ADD_FILE | \ 96*1462Smarks ACE_APPEND_DATA | \ 97*1462Smarks ACE_ADD_SUBDIRECTORY | \ 98*1462Smarks ACE_READ_NAMED_ATTRS | \ 99*1462Smarks ACE_WRITE_NAMED_ATTRS | \ 100*1462Smarks ACE_EXECUTE | \ 101*1462Smarks ACE_DELETE_CHILD | \ 102*1462Smarks ACE_READ_ATTRIBUTES | \ 103*1462Smarks ACE_WRITE_ATTRIBUTES | \ 104*1462Smarks ACE_DELETE | \ 105*1462Smarks ACE_READ_ACL | \ 106*1462Smarks ACE_WRITE_ACL | \ 107*1462Smarks ACE_WRITE_OWNER | \ 108*1462Smarks ACE_SYNCHRONIZE) 109*1462Smarks 110*1462Smarks #define ACE_MASK_UNDEFINED 0x80000000 111*1462Smarks 112*1462Smarks #define ACE_VALID_FLAG_BITS (ACE_FILE_INHERIT_ACE | \ 113*1462Smarks ACE_DIRECTORY_INHERIT_ACE | \ 114*1462Smarks ACE_NO_PROPAGATE_INHERIT_ACE | ACE_INHERIT_ONLY_ACE | \ 115*1462Smarks ACE_SUCCESSFUL_ACCESS_ACE_FLAG | ACE_FAILED_ACCESS_ACE_FLAG | \ 116*1462Smarks ACE_IDENTIFIER_GROUP | ACE_OWNER | ACE_GROUP | ACE_EVERYONE) 117789Sahrens 118*1462Smarks /* 119*1462Smarks * ACL conversion helpers 120*1462Smarks */ 121*1462Smarks 122*1462Smarks typedef enum { 123*1462Smarks ace_unused, 124*1462Smarks ace_user_obj, 125*1462Smarks ace_user, 126*1462Smarks ace_group, /* includes GROUP and GROUP_OBJ */ 127*1462Smarks ace_other_obj 128*1462Smarks } ace_to_aent_state_t; 129789Sahrens 130*1462Smarks typedef struct acevals { 131*1462Smarks uid_t key; 132*1462Smarks avl_node_t avl; 133*1462Smarks uint32_t mask; 134*1462Smarks uint32_t allowed; 135*1462Smarks uint32_t denied; 136*1462Smarks int aent_type; 137*1462Smarks } acevals_t; 138*1462Smarks 139*1462Smarks typedef struct ace_list { 140*1462Smarks acevals_t user_obj; 141*1462Smarks avl_tree_t user; 142*1462Smarks int numusers; 143*1462Smarks acevals_t group_obj; 144*1462Smarks avl_tree_t group; 145*1462Smarks int numgroups; 146*1462Smarks acevals_t other_obj; 147*1462Smarks uint32_t acl_mask; 148*1462Smarks int hasmask; 149*1462Smarks int dfacl_flag; 150*1462Smarks ace_to_aent_state_t state; 151*1462Smarks int seen; /* bitmask of all aclent_t a_type values seen */ 152*1462Smarks } ace_list_t; 1531231Smarks 154789Sahrens typedef union { 155789Sahrens const char *file; 156789Sahrens int fd; 157789Sahrens } acl_inp; 158789Sahrens 159789Sahrens acl_t * 160789Sahrens acl_alloc(enum acl_type type) 161789Sahrens { 162789Sahrens acl_t *aclp; 163789Sahrens 164789Sahrens aclp = malloc(sizeof (acl_t)); 165789Sahrens 166789Sahrens if (aclp == NULL) 167789Sahrens return (NULL); 168789Sahrens 169789Sahrens aclp->acl_aclp = NULL; 170789Sahrens aclp->acl_cnt = 0; 171789Sahrens 172789Sahrens switch (type) { 173789Sahrens case ACE_T: 174789Sahrens aclp->acl_type = ACE_T; 175789Sahrens aclp->acl_entry_size = sizeof (ace_t); 176789Sahrens break; 177789Sahrens case ACLENT_T: 178789Sahrens aclp->acl_type = ACLENT_T; 179789Sahrens aclp->acl_entry_size = sizeof (aclent_t); 180789Sahrens break; 181789Sahrens default: 182789Sahrens acl_free(aclp); 183789Sahrens aclp = NULL; 184789Sahrens } 185789Sahrens return (aclp); 186789Sahrens } 187789Sahrens 188789Sahrens /* 189789Sahrens * Free acl_t structure 190789Sahrens */ 191789Sahrens void 192789Sahrens acl_free(acl_t *aclp) 193789Sahrens { 194789Sahrens if (aclp == NULL) 195789Sahrens return; 196789Sahrens 197789Sahrens if (aclp->acl_aclp) 198789Sahrens free(aclp->acl_aclp); 199789Sahrens free(aclp); 200789Sahrens } 201789Sahrens 202789Sahrens /* 203789Sahrens * Determine whether a file has a trivial ACL 204789Sahrens * returns: 0 = trivial 205789Sahrens * 1 = nontrivial 206789Sahrens * <0 some other system failure, such as ENOENT or EPERM 207789Sahrens */ 208789Sahrens int 209789Sahrens acl_trivial(const char *filename) 210789Sahrens { 211789Sahrens int acl_flavor; 212789Sahrens int aclcnt; 213789Sahrens int cntcmd; 214789Sahrens int val = 0; 215789Sahrens ace_t *acep; 216789Sahrens 217789Sahrens acl_flavor = pathconf(filename, _PC_ACL_ENABLED); 218789Sahrens if (acl_flavor == -1) 219789Sahrens return (-1); 220789Sahrens 221789Sahrens if (acl_flavor == _ACL_ACE_ENABLED) 222789Sahrens cntcmd = ACE_GETACLCNT; 223789Sahrens else 224789Sahrens cntcmd = GETACLCNT; 225789Sahrens 226789Sahrens aclcnt = acl(filename, cntcmd, 0, NULL); 227789Sahrens if (aclcnt > 0) { 228789Sahrens if (acl_flavor == _ACL_ACE_ENABLED) { 2291231Smarks acep = malloc(sizeof (ace_t) * aclcnt); 2301231Smarks if (acep == NULL) 2311231Smarks return (-1); 2321231Smarks if (acl(filename, ACE_GETACL, 2331231Smarks aclcnt, acep) < 0) { 2341231Smarks free(acep); 2351231Smarks return (-1); 2361231Smarks } 237789Sahrens 2381231Smarks val = ace_trivial(acep, aclcnt); 2391231Smarks free(acep); 2401231Smarks 241789Sahrens } else if (aclcnt > MIN_ACL_ENTRIES) 242789Sahrens val = 1; 243789Sahrens } 244789Sahrens return (val); 245789Sahrens } 246789Sahrens 247789Sahrens static uint32_t 248789Sahrens access_mask_set(int haswriteperm, int hasreadperm, int isowner, int isallow) 249789Sahrens { 250789Sahrens uint32_t access_mask = 0; 251789Sahrens int acl_produce; 252789Sahrens int synchronize_set = 0, write_owner_set = 0; 253789Sahrens int delete_set = 0, write_attrs_set = 0; 254789Sahrens int read_named_set = 0, write_named_set = 0; 255789Sahrens 256789Sahrens acl_produce = (ACL_SYNCHRONIZE_SET_ALLOW | 257789Sahrens ACL_WRITE_ATTRS_OWNER_SET_ALLOW | 258789Sahrens ACL_WRITE_ATTRS_WRITER_SET_DENY); 259789Sahrens 260789Sahrens if (isallow) { 261789Sahrens synchronize_set = ACL_SYNCHRONIZE_SET_ALLOW; 262789Sahrens write_owner_set = ACL_WRITE_OWNER_SET_ALLOW; 263789Sahrens delete_set = ACL_DELETE_SET_ALLOW; 264789Sahrens if (hasreadperm) 265789Sahrens read_named_set = ACL_READ_NAMED_READER_SET_ALLOW; 266789Sahrens if (haswriteperm) 267789Sahrens write_named_set = ACL_WRITE_NAMED_WRITER_SET_ALLOW; 268789Sahrens if (isowner) 269789Sahrens write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_ALLOW; 270789Sahrens else if (haswriteperm) 271789Sahrens write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_ALLOW; 272789Sahrens } else { 273789Sahrens 274789Sahrens synchronize_set = ACL_SYNCHRONIZE_SET_DENY; 275789Sahrens write_owner_set = ACL_WRITE_OWNER_SET_DENY; 276789Sahrens delete_set = ACL_DELETE_SET_DENY; 277789Sahrens if (hasreadperm) 278789Sahrens read_named_set = ACL_READ_NAMED_READER_SET_DENY; 279789Sahrens if (haswriteperm) 280789Sahrens write_named_set = ACL_WRITE_NAMED_WRITER_SET_DENY; 281789Sahrens if (isowner) 282789Sahrens write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_DENY; 283789Sahrens else if (haswriteperm) 284789Sahrens write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_DENY; 285789Sahrens else 286789Sahrens /* 287789Sahrens * If the entity is not the owner and does not 288789Sahrens * have write permissions ACE_WRITE_ATTRIBUTES will 289789Sahrens * always go in the DENY ACE. 290789Sahrens */ 291789Sahrens access_mask |= ACE_WRITE_ATTRIBUTES; 292789Sahrens } 293789Sahrens 294789Sahrens if (acl_produce & synchronize_set) 295789Sahrens access_mask |= ACE_SYNCHRONIZE; 296789Sahrens if (acl_produce & write_owner_set) 297789Sahrens access_mask |= ACE_WRITE_OWNER; 298789Sahrens if (acl_produce & delete_set) 299789Sahrens access_mask |= ACE_DELETE; 300789Sahrens if (acl_produce & write_attrs_set) 301789Sahrens access_mask |= ACE_WRITE_ATTRIBUTES; 302789Sahrens if (acl_produce & read_named_set) 303789Sahrens access_mask |= ACE_READ_NAMED_ATTRS; 304789Sahrens if (acl_produce & write_named_set) 305789Sahrens access_mask |= ACE_WRITE_NAMED_ATTRS; 306789Sahrens 307789Sahrens return (access_mask); 308789Sahrens } 309789Sahrens 310789Sahrens /* 311789Sahrens * Given an mode_t, convert it into an access_mask as used 312789Sahrens * by nfsace, assuming aclent_t -> nfsace semantics. 313789Sahrens */ 314789Sahrens static uint32_t 315789Sahrens mode_to_ace_access(mode_t mode, int isdir, int isowner, int isallow) 316789Sahrens { 317789Sahrens uint32_t access = 0; 318789Sahrens int haswriteperm = 0; 319789Sahrens int hasreadperm = 0; 320789Sahrens 321789Sahrens if (isallow) { 322789Sahrens haswriteperm = (mode & 02); 323789Sahrens hasreadperm = (mode & 04); 324789Sahrens } else { 325789Sahrens haswriteperm = !(mode & 02); 326789Sahrens hasreadperm = !(mode & 04); 327789Sahrens } 328789Sahrens 329789Sahrens /* 330789Sahrens * The following call takes care of correctly setting the following 331789Sahrens * mask bits in the access_mask: 332789Sahrens * ACE_SYNCHRONIZE, ACE_WRITE_OWNER, ACE_DELETE, 333789Sahrens * ACE_WRITE_ATTRIBUTES, ACE_WRITE_NAMED_ATTRS, ACE_READ_NAMED_ATTRS 334789Sahrens */ 335789Sahrens access = access_mask_set(haswriteperm, hasreadperm, isowner, isallow); 336789Sahrens 337789Sahrens if (isallow) { 338789Sahrens access |= ACE_READ_ACL | ACE_READ_ATTRIBUTES; 339789Sahrens if (isowner) 340789Sahrens access |= ACE_WRITE_ACL; 341789Sahrens } else { 342789Sahrens if (! isowner) 343789Sahrens access |= ACE_WRITE_ACL; 344789Sahrens } 345789Sahrens 346789Sahrens /* read */ 347789Sahrens if (mode & 04) { 348789Sahrens access |= ACE_READ_DATA; 349789Sahrens } 350789Sahrens /* write */ 351789Sahrens if (mode & 02) { 352789Sahrens access |= ACE_WRITE_DATA | 353789Sahrens ACE_APPEND_DATA; 354789Sahrens if (isdir) 355789Sahrens access |= ACE_DELETE_CHILD; 356789Sahrens } 357789Sahrens /* exec */ 358789Sahrens if (mode & 01) { 359789Sahrens access |= ACE_EXECUTE; 360789Sahrens } 361789Sahrens 362789Sahrens return (access); 363789Sahrens } 364789Sahrens 365789Sahrens /* 366789Sahrens * Given an nfsace (presumably an ALLOW entry), make a 367789Sahrens * corresponding DENY entry at the address given. 368789Sahrens */ 369789Sahrens static void 370789Sahrens ace_make_deny(ace_t *allow, ace_t *deny, int isdir, int isowner) 371789Sahrens { 372789Sahrens (void) memcpy(deny, allow, sizeof (ace_t)); 373789Sahrens 374789Sahrens deny->a_who = allow->a_who; 375789Sahrens 376789Sahrens deny->a_type = ACE_ACCESS_DENIED_ACE_TYPE; 377789Sahrens deny->a_access_mask ^= ACE_POSIX_SUPPORTED_BITS; 378789Sahrens if (isdir) 379789Sahrens deny->a_access_mask ^= ACE_DELETE_CHILD; 380789Sahrens 381789Sahrens deny->a_access_mask &= ~(ACE_SYNCHRONIZE | ACE_WRITE_OWNER | 382789Sahrens ACE_DELETE | ACE_WRITE_ATTRIBUTES | ACE_READ_NAMED_ATTRS | 383789Sahrens ACE_WRITE_NAMED_ATTRS); 384789Sahrens deny->a_access_mask |= access_mask_set((allow->a_access_mask & 385789Sahrens ACE_WRITE_DATA), (allow->a_access_mask & ACE_READ_DATA), isowner, 386789Sahrens B_FALSE); 387789Sahrens } 388789Sahrens /* 389789Sahrens * Make an initial pass over an array of aclent_t's. Gather 390789Sahrens * information such as an ACL_MASK (if any), number of users, 391789Sahrens * number of groups, and whether the array needs to be sorted. 392789Sahrens */ 393789Sahrens static int 394789Sahrens ln_aent_preprocess(aclent_t *aclent, int n, 395789Sahrens int *hasmask, mode_t *mask, 396789Sahrens int *numuser, int *numgroup, int *needsort) 397789Sahrens { 398789Sahrens int error = 0; 399789Sahrens int i; 400789Sahrens int curtype = 0; 401789Sahrens 402789Sahrens *hasmask = 0; 403789Sahrens *mask = 07; 404789Sahrens *needsort = 0; 405789Sahrens *numuser = 0; 406789Sahrens *numgroup = 0; 407789Sahrens 408789Sahrens for (i = 0; i < n; i++) { 409789Sahrens if (aclent[i].a_type < curtype) 410789Sahrens *needsort = 1; 411789Sahrens else if (aclent[i].a_type > curtype) 412789Sahrens curtype = aclent[i].a_type; 413789Sahrens if (aclent[i].a_type & USER) 414789Sahrens (*numuser)++; 415789Sahrens if (aclent[i].a_type & (GROUP | GROUP_OBJ)) 416789Sahrens (*numgroup)++; 417789Sahrens if (aclent[i].a_type & CLASS_OBJ) { 418789Sahrens if (*hasmask) { 419789Sahrens error = EINVAL; 420789Sahrens goto out; 421789Sahrens } else { 422789Sahrens *hasmask = 1; 423789Sahrens *mask = aclent[i].a_perm; 424789Sahrens } 425789Sahrens } 426789Sahrens } 427789Sahrens 428789Sahrens if ((! *hasmask) && (*numuser + *numgroup > 1)) { 429789Sahrens error = EINVAL; 430789Sahrens goto out; 431789Sahrens } 432789Sahrens 433789Sahrens out: 434789Sahrens return (error); 435789Sahrens } 436789Sahrens 437789Sahrens /* 438789Sahrens * Convert an array of aclent_t into an array of nfsace entries, 439789Sahrens * following POSIX draft -> nfsv4 conversion semantics as outlined in 440789Sahrens * the IETF draft. 441789Sahrens */ 442789Sahrens static int 443789Sahrens ln_aent_to_ace(aclent_t *aclent, int n, ace_t **acepp, int *rescount, int isdir) 444789Sahrens { 445789Sahrens int error = 0; 446789Sahrens mode_t mask; 447789Sahrens int numuser, numgroup, needsort; 448789Sahrens int resultsize = 0; 449789Sahrens int i, groupi = 0, skip; 450789Sahrens ace_t *acep, *result = NULL; 451789Sahrens int hasmask; 452789Sahrens 453789Sahrens error = ln_aent_preprocess(aclent, n, &hasmask, &mask, 454789Sahrens &numuser, &numgroup, &needsort); 455789Sahrens if (error != 0) 456789Sahrens goto out; 457789Sahrens 458789Sahrens /* allow + deny for each aclent */ 459789Sahrens resultsize = n * 2; 460789Sahrens if (hasmask) { 461789Sahrens /* 462789Sahrens * stick extra deny on the group_obj and on each 463789Sahrens * user|group for the mask (the group_obj was added 464789Sahrens * into the count for numgroup) 465789Sahrens */ 466789Sahrens resultsize += numuser + numgroup; 467789Sahrens /* ... and don't count the mask itself */ 468789Sahrens resultsize -= 2; 469789Sahrens } 470789Sahrens 471789Sahrens /* sort the source if necessary */ 472789Sahrens if (needsort) 473789Sahrens ksort((caddr_t)aclent, n, sizeof (aclent_t), cmp2acls); 474789Sahrens 475789Sahrens result = acep = calloc(1, resultsize * sizeof (ace_t)); 476789Sahrens if (result == NULL) 477789Sahrens goto out; 478789Sahrens 479789Sahrens for (i = 0; i < n; i++) { 480789Sahrens /* 481789Sahrens * don't process CLASS_OBJ (mask); mask was grabbed in 482789Sahrens * ln_aent_preprocess() 483789Sahrens */ 484789Sahrens if (aclent[i].a_type & CLASS_OBJ) 485789Sahrens continue; 486789Sahrens 487789Sahrens /* If we need an ACL_MASK emulator, prepend it now */ 488789Sahrens if ((hasmask) && 489789Sahrens (aclent[i].a_type & (USER | GROUP | GROUP_OBJ))) { 490789Sahrens acep->a_type = ACE_ACCESS_DENIED_ACE_TYPE; 491789Sahrens acep->a_flags = 0; 492789Sahrens if (aclent[i].a_type & GROUP_OBJ) { 493789Sahrens acep->a_who = -1; 494789Sahrens acep->a_flags |= 495789Sahrens (ACE_IDENTIFIER_GROUP|ACE_GROUP); 496789Sahrens } else if (aclent[i].a_type & USER) { 497789Sahrens acep->a_who = aclent[i].a_id; 498789Sahrens } else { 499789Sahrens acep->a_who = aclent[i].a_id; 500789Sahrens acep->a_flags |= ACE_IDENTIFIER_GROUP; 501789Sahrens } 502789Sahrens if (aclent[i].a_type & ACL_DEFAULT) { 503789Sahrens acep->a_flags |= ACE_INHERIT_ONLY_ACE | 504789Sahrens ACE_FILE_INHERIT_ACE | 505789Sahrens ACE_DIRECTORY_INHERIT_ACE; 506789Sahrens } 507789Sahrens /* 508789Sahrens * Set the access mask for the prepended deny 509789Sahrens * ace. To do this, we invert the mask (found 510789Sahrens * in ln_aent_preprocess()) then convert it to an 511789Sahrens * DENY ace access_mask. 512789Sahrens */ 513789Sahrens acep->a_access_mask = mode_to_ace_access((mask ^ 07), 514789Sahrens isdir, 0, 0); 515789Sahrens acep += 1; 516789Sahrens } 517789Sahrens 518789Sahrens /* handle a_perm -> access_mask */ 519789Sahrens acep->a_access_mask = mode_to_ace_access(aclent[i].a_perm, 520789Sahrens isdir, aclent[i].a_type & USER_OBJ, 1); 521789Sahrens 522789Sahrens /* emulate a default aclent */ 523789Sahrens if (aclent[i].a_type & ACL_DEFAULT) { 524789Sahrens acep->a_flags |= ACE_INHERIT_ONLY_ACE | 525789Sahrens ACE_FILE_INHERIT_ACE | 526789Sahrens ACE_DIRECTORY_INHERIT_ACE; 527789Sahrens } 528789Sahrens 529789Sahrens /* 530789Sahrens * handle a_perm and a_id 531789Sahrens * 532789Sahrens * this must be done last, since it involves the 533789Sahrens * corresponding deny aces, which are handled 534789Sahrens * differently for each different a_type. 535789Sahrens */ 536789Sahrens if (aclent[i].a_type & USER_OBJ) { 537789Sahrens acep->a_who = -1; 538789Sahrens acep->a_flags |= ACE_OWNER; 539789Sahrens ace_make_deny(acep, acep + 1, isdir, B_TRUE); 540789Sahrens acep += 2; 541789Sahrens } else if (aclent[i].a_type & USER) { 542789Sahrens acep->a_who = aclent[i].a_id; 543789Sahrens ace_make_deny(acep, acep + 1, isdir, B_FALSE); 544789Sahrens acep += 2; 545789Sahrens } else if (aclent[i].a_type & (GROUP_OBJ | GROUP)) { 546789Sahrens if (aclent[i].a_type & GROUP_OBJ) { 547789Sahrens acep->a_who = -1; 548789Sahrens acep->a_flags |= ACE_GROUP; 549789Sahrens } else { 550789Sahrens acep->a_who = aclent[i].a_id; 551789Sahrens } 552789Sahrens acep->a_flags |= ACE_IDENTIFIER_GROUP; 553789Sahrens /* 554789Sahrens * Set the corresponding deny for the group ace. 555789Sahrens * 556789Sahrens * The deny aces go after all of the groups, unlike 557789Sahrens * everything else, where they immediately follow 558789Sahrens * the allow ace. 559789Sahrens * 560789Sahrens * We calculate "skip", the number of slots to 561789Sahrens * skip ahead for the deny ace, here. 562789Sahrens * 563789Sahrens * The pattern is: 564789Sahrens * MD1 A1 MD2 A2 MD3 A3 D1 D2 D3 565789Sahrens * thus, skip is 566789Sahrens * (2 * numgroup) - 1 - groupi 567789Sahrens * (2 * numgroup) to account for MD + A 568789Sahrens * - 1 to account for the fact that we're on the 569789Sahrens * access (A), not the mask (MD) 570789Sahrens * - groupi to account for the fact that we have 571789Sahrens * passed up groupi number of MD's. 572789Sahrens */ 573789Sahrens skip = (2 * numgroup) - 1 - groupi; 574789Sahrens ace_make_deny(acep, acep + skip, isdir, B_FALSE); 575789Sahrens /* 576789Sahrens * If we just did the last group, skip acep past 577789Sahrens * all of the denies; else, just move ahead one. 578789Sahrens */ 579789Sahrens if (++groupi >= numgroup) 580789Sahrens acep += numgroup + 1; 581789Sahrens else 582789Sahrens acep += 1; 583789Sahrens } else if (aclent[i].a_type & OTHER_OBJ) { 584789Sahrens acep->a_who = -1; 585789Sahrens acep->a_flags |= ACE_EVERYONE; 586789Sahrens ace_make_deny(acep, acep + 1, isdir, B_FALSE); 587789Sahrens acep += 2; 588789Sahrens } else { 589789Sahrens error = EINVAL; 590789Sahrens goto out; 591789Sahrens } 592789Sahrens } 593789Sahrens 594789Sahrens *acepp = result; 595789Sahrens *rescount = resultsize; 596789Sahrens 597789Sahrens out: 598789Sahrens if (error != 0) { 599789Sahrens if ((result != NULL) && (resultsize > 0)) { 600789Sahrens free(result); 601789Sahrens } 602789Sahrens } 603789Sahrens 604789Sahrens return (error); 605789Sahrens } 606789Sahrens 607789Sahrens static int 608789Sahrens convert_aent_to_ace(aclent_t *aclentp, int aclcnt, int isdir, 609789Sahrens ace_t **retacep, int *retacecnt) 610789Sahrens { 611789Sahrens ace_t *acep; 612789Sahrens ace_t *dfacep; 613789Sahrens int acecnt = 0; 614789Sahrens int dfacecnt = 0; 615789Sahrens int dfaclstart = 0; 616789Sahrens int dfaclcnt = 0; 617789Sahrens aclent_t *aclp; 618789Sahrens int i; 619789Sahrens int error; 620789Sahrens 621789Sahrens ksort((caddr_t)aclentp, aclcnt, sizeof (aclent_t), cmp2acls); 622789Sahrens 623789Sahrens for (i = 0, aclp = aclentp; i < aclcnt; aclp++, i++) { 624789Sahrens if (aclp->a_type & ACL_DEFAULT) 625789Sahrens break; 626789Sahrens } 627789Sahrens 628789Sahrens if (i < aclcnt) { 629*1462Smarks dfaclstart = i; 630*1462Smarks dfaclcnt = aclcnt - i; 631789Sahrens } 632789Sahrens 633789Sahrens if (dfaclcnt && isdir == 0) { 634789Sahrens return (-1); 635789Sahrens } 636789Sahrens 637789Sahrens error = ln_aent_to_ace(aclentp, i, &acep, &acecnt, isdir); 638789Sahrens if (error) 639789Sahrens return (-1); 640789Sahrens 641789Sahrens if (dfaclcnt) { 642789Sahrens error = ln_aent_to_ace(&aclentp[dfaclstart], dfaclcnt, 643789Sahrens &dfacep, &dfacecnt, isdir); 644789Sahrens if (error) { 645789Sahrens if (acep) { 646789Sahrens free(acep); 647789Sahrens } 648789Sahrens return (-1); 649789Sahrens } 650789Sahrens } 651789Sahrens 652*1462Smarks if (dfacecnt != 0) { 653*1462Smarks acep = realloc(acep, sizeof (ace_t) * (acecnt + dfacecnt)); 654*1462Smarks if (acep == NULL) 655*1462Smarks return (-1); 656*1462Smarks if (dfaclcnt) { 657*1462Smarks (void) memcpy(acep + acecnt, dfacep, 658*1462Smarks sizeof (ace_t) * dfacecnt); 659*1462Smarks } 660789Sahrens } 661789Sahrens if (dfaclcnt) 662789Sahrens free(dfacep); 663789Sahrens 664789Sahrens *retacecnt = acecnt + dfacecnt; 665*1462Smarks *retacep = acep; 666*1462Smarks return (0); 667*1462Smarks } 668*1462Smarks 669*1462Smarks static void 670*1462Smarks acevals_init(acevals_t *vals, uid_t key) 671*1462Smarks { 672*1462Smarks bzero(vals, sizeof (*vals)); 673*1462Smarks vals->allowed = ACE_MASK_UNDEFINED; 674*1462Smarks vals->denied = ACE_MASK_UNDEFINED; 675*1462Smarks vals->mask = ACE_MASK_UNDEFINED; 676*1462Smarks vals->key = key; 677*1462Smarks } 678*1462Smarks 679*1462Smarks static void 680*1462Smarks ace_list_init(ace_list_t *al, int dfacl_flag) 681*1462Smarks { 682*1462Smarks acevals_init(&al->user_obj, NULL); 683*1462Smarks acevals_init(&al->group_obj, NULL); 684*1462Smarks acevals_init(&al->other_obj, NULL); 685*1462Smarks al->numusers = 0; 686*1462Smarks al->numgroups = 0; 687*1462Smarks al->acl_mask = 0; 688*1462Smarks al->hasmask = 0; 689*1462Smarks al->state = ace_unused; 690*1462Smarks al->seen = 0; 691*1462Smarks al->dfacl_flag = dfacl_flag; 692*1462Smarks } 693*1462Smarks 694*1462Smarks /* 695*1462Smarks * Find or create an acevals holder for a given id and avl tree. 696*1462Smarks * 697*1462Smarks * Note that only one thread will ever touch these avl trees, so 698*1462Smarks * there is no need for locking. 699*1462Smarks */ 700*1462Smarks static acevals_t * 701*1462Smarks acevals_find(ace_t *ace, avl_tree_t *avl, int *num) 702*1462Smarks { 703*1462Smarks acevals_t key, *rc; 704*1462Smarks avl_index_t where; 705*1462Smarks 706*1462Smarks key.key = ace->a_who; 707*1462Smarks rc = avl_find(avl, &key, &where); 708*1462Smarks if (rc != NULL) 709*1462Smarks return (rc); 710*1462Smarks 711*1462Smarks /* this memory is freed by ln_ace_to_aent()->ace_list_free() */ 712*1462Smarks rc = calloc(1, sizeof (acevals_t)); 713*1462Smarks if (rc == NULL) 714*1462Smarks return (rc); 715*1462Smarks acevals_init(rc, ace->a_who); 716*1462Smarks avl_insert(avl, rc, where); 717*1462Smarks (*num)++; 718*1462Smarks 719*1462Smarks return (rc); 720*1462Smarks } 721*1462Smarks 722*1462Smarks static int 723*1462Smarks access_mask_check(ace_t *acep, int mask_bit, int isowner) 724*1462Smarks { 725*1462Smarks int set_deny, err_deny; 726*1462Smarks int set_allow, err_allow; 727*1462Smarks int acl_consume; 728*1462Smarks int haswriteperm, hasreadperm; 729*1462Smarks 730*1462Smarks if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) { 731*1462Smarks haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 0 : 1; 732*1462Smarks hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 0 : 1; 733*1462Smarks } else { 734*1462Smarks haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 1 : 0; 735*1462Smarks hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 1 : 0; 736*1462Smarks } 737*1462Smarks 738*1462Smarks acl_consume = (ACL_SYNCHRONIZE_ERR_DENY | 739*1462Smarks ACL_DELETE_ERR_DENY | 740*1462Smarks ACL_WRITE_OWNER_ERR_DENY | 741*1462Smarks ACL_WRITE_OWNER_ERR_ALLOW | 742*1462Smarks ACL_WRITE_ATTRS_OWNER_SET_ALLOW | 743*1462Smarks ACL_WRITE_ATTRS_OWNER_ERR_DENY | 744*1462Smarks ACL_WRITE_ATTRS_WRITER_SET_DENY | 745*1462Smarks ACL_WRITE_ATTRS_WRITER_ERR_ALLOW | 746*1462Smarks ACL_WRITE_NAMED_WRITER_ERR_DENY | 747*1462Smarks ACL_READ_NAMED_READER_ERR_DENY); 748*1462Smarks 749*1462Smarks if (mask_bit == ACE_SYNCHRONIZE) { 750*1462Smarks set_deny = ACL_SYNCHRONIZE_SET_DENY; 751*1462Smarks err_deny = ACL_SYNCHRONIZE_ERR_DENY; 752*1462Smarks set_allow = ACL_SYNCHRONIZE_SET_ALLOW; 753*1462Smarks err_allow = ACL_SYNCHRONIZE_ERR_ALLOW; 754*1462Smarks } else if (mask_bit == ACE_WRITE_OWNER) { 755*1462Smarks set_deny = ACL_WRITE_OWNER_SET_DENY; 756*1462Smarks err_deny = ACL_WRITE_OWNER_ERR_DENY; 757*1462Smarks set_allow = ACL_WRITE_OWNER_SET_ALLOW; 758*1462Smarks err_allow = ACL_WRITE_OWNER_ERR_ALLOW; 759*1462Smarks } else if (mask_bit == ACE_DELETE) { 760*1462Smarks set_deny = ACL_DELETE_SET_DENY; 761*1462Smarks err_deny = ACL_DELETE_ERR_DENY; 762*1462Smarks set_allow = ACL_DELETE_SET_ALLOW; 763*1462Smarks err_allow = ACL_DELETE_ERR_ALLOW; 764*1462Smarks } else if (mask_bit == ACE_WRITE_ATTRIBUTES) { 765*1462Smarks if (isowner) { 766*1462Smarks set_deny = ACL_WRITE_ATTRS_OWNER_SET_DENY; 767*1462Smarks err_deny = ACL_WRITE_ATTRS_OWNER_ERR_DENY; 768*1462Smarks set_allow = ACL_WRITE_ATTRS_OWNER_SET_ALLOW; 769*1462Smarks err_allow = ACL_WRITE_ATTRS_OWNER_ERR_ALLOW; 770*1462Smarks } else if (haswriteperm) { 771*1462Smarks set_deny = ACL_WRITE_ATTRS_WRITER_SET_DENY; 772*1462Smarks err_deny = ACL_WRITE_ATTRS_WRITER_ERR_DENY; 773*1462Smarks set_allow = ACL_WRITE_ATTRS_WRITER_SET_ALLOW; 774*1462Smarks err_allow = ACL_WRITE_ATTRS_WRITER_ERR_ALLOW; 775*1462Smarks } else { 776*1462Smarks if ((acep->a_access_mask & mask_bit) && 777*1462Smarks (acep->a_type & ACE_ACCESS_ALLOWED_ACE_TYPE)) { 778*1462Smarks return (ENOTSUP); 779*1462Smarks } 780*1462Smarks return (0); 781*1462Smarks } 782*1462Smarks } else if (mask_bit == ACE_READ_NAMED_ATTRS) { 783*1462Smarks if (!hasreadperm) 784*1462Smarks return (0); 785*1462Smarks 786*1462Smarks set_deny = ACL_READ_NAMED_READER_SET_DENY; 787*1462Smarks err_deny = ACL_READ_NAMED_READER_ERR_DENY; 788*1462Smarks set_allow = ACL_READ_NAMED_READER_SET_ALLOW; 789*1462Smarks err_allow = ACL_READ_NAMED_READER_ERR_ALLOW; 790*1462Smarks } else if (mask_bit == ACE_WRITE_NAMED_ATTRS) { 791*1462Smarks if (!haswriteperm) 792*1462Smarks return (0); 793*1462Smarks 794*1462Smarks set_deny = ACL_WRITE_NAMED_WRITER_SET_DENY; 795*1462Smarks err_deny = ACL_WRITE_NAMED_WRITER_ERR_DENY; 796*1462Smarks set_allow = ACL_WRITE_NAMED_WRITER_SET_ALLOW; 797*1462Smarks err_allow = ACL_WRITE_NAMED_WRITER_ERR_ALLOW; 798*1462Smarks } else { 799*1462Smarks return (EINVAL); 800*1462Smarks } 801*1462Smarks 802*1462Smarks if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) { 803*1462Smarks if (acl_consume & set_deny) { 804*1462Smarks if (!(acep->a_access_mask & mask_bit)) { 805*1462Smarks return (ENOTSUP); 806*1462Smarks } 807*1462Smarks } else if (acl_consume & err_deny) { 808*1462Smarks if (acep->a_access_mask & mask_bit) { 809*1462Smarks return (ENOTSUP); 810*1462Smarks } 811*1462Smarks } 812*1462Smarks } else { 813*1462Smarks /* ACE_ACCESS_ALLOWED_ACE_TYPE */ 814*1462Smarks if (acl_consume & set_allow) { 815*1462Smarks if (!(acep->a_access_mask & mask_bit)) { 816*1462Smarks return (ENOTSUP); 817*1462Smarks } 818*1462Smarks } else if (acl_consume & err_allow) { 819*1462Smarks if (acep->a_access_mask & mask_bit) { 820*1462Smarks return (ENOTSUP); 821*1462Smarks } 822*1462Smarks } 823*1462Smarks } 824789Sahrens return (0); 825789Sahrens } 826789Sahrens 827*1462Smarks static int 828*1462Smarks ace_to_aent_legal(ace_t *acep) 829*1462Smarks { 830*1462Smarks int error = 0; 831*1462Smarks int isowner; 832*1462Smarks 833*1462Smarks /* only ALLOW or DENY */ 834*1462Smarks if ((acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE) && 835*1462Smarks (acep->a_type != ACE_ACCESS_DENIED_ACE_TYPE)) { 836*1462Smarks error = ENOTSUP; 837*1462Smarks goto out; 838*1462Smarks } 839*1462Smarks 840*1462Smarks /* check for invalid flags */ 841*1462Smarks if (acep->a_flags & ~(ACE_VALID_FLAG_BITS)) { 842*1462Smarks error = EINVAL; 843*1462Smarks goto out; 844*1462Smarks } 845*1462Smarks 846*1462Smarks /* some flags are illegal */ 847*1462Smarks if (acep->a_flags & (ACE_SUCCESSFUL_ACCESS_ACE_FLAG | 848*1462Smarks ACE_FAILED_ACCESS_ACE_FLAG | 849*1462Smarks ACE_NO_PROPAGATE_INHERIT_ACE)) { 850*1462Smarks error = ENOTSUP; 851*1462Smarks goto out; 852*1462Smarks } 853*1462Smarks 854*1462Smarks /* check for invalid masks */ 855*1462Smarks if (acep->a_access_mask & ~(ACE_VALID_MASK_BITS)) { 856*1462Smarks error = EINVAL; 857*1462Smarks goto out; 858*1462Smarks } 859*1462Smarks 860*1462Smarks if ((acep->a_flags & ACE_OWNER)) { 861*1462Smarks isowner = 1; 862*1462Smarks } else { 863*1462Smarks isowner = 0; 864*1462Smarks } 865*1462Smarks 866*1462Smarks error = access_mask_check(acep, ACE_SYNCHRONIZE, isowner); 867*1462Smarks if (error) 868*1462Smarks goto out; 869*1462Smarks 870*1462Smarks error = access_mask_check(acep, ACE_WRITE_OWNER, isowner); 871*1462Smarks if (error) 872*1462Smarks goto out; 873*1462Smarks 874*1462Smarks error = access_mask_check(acep, ACE_DELETE, isowner); 875*1462Smarks if (error) 876*1462Smarks goto out; 877*1462Smarks 878*1462Smarks error = access_mask_check(acep, ACE_WRITE_ATTRIBUTES, isowner); 879*1462Smarks if (error) 880*1462Smarks goto out; 881*1462Smarks 882*1462Smarks error = access_mask_check(acep, ACE_READ_NAMED_ATTRS, isowner); 883*1462Smarks if (error) 884*1462Smarks goto out; 885*1462Smarks 886*1462Smarks error = access_mask_check(acep, ACE_WRITE_NAMED_ATTRS, isowner); 887*1462Smarks if (error) 888*1462Smarks goto out; 889*1462Smarks 890*1462Smarks /* more detailed checking of masks */ 891*1462Smarks if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) { 892*1462Smarks if (! (acep->a_access_mask & ACE_READ_ATTRIBUTES)) { 893*1462Smarks error = ENOTSUP; 894*1462Smarks goto out; 895*1462Smarks } 896*1462Smarks if ((acep->a_access_mask & ACE_WRITE_DATA) && 897*1462Smarks (! (acep->a_access_mask & ACE_APPEND_DATA))) { 898*1462Smarks error = ENOTSUP; 899*1462Smarks goto out; 900*1462Smarks } 901*1462Smarks if ((! (acep->a_access_mask & ACE_WRITE_DATA)) && 902*1462Smarks (acep->a_access_mask & ACE_APPEND_DATA)) { 903*1462Smarks error = ENOTSUP; 904*1462Smarks goto out; 905*1462Smarks } 906*1462Smarks } 907*1462Smarks 908*1462Smarks /* ACL enforcement */ 909*1462Smarks if ((acep->a_access_mask & ACE_READ_ACL) && 910*1462Smarks (acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE)) { 911*1462Smarks error = ENOTSUP; 912*1462Smarks goto out; 913*1462Smarks } 914*1462Smarks if (acep->a_access_mask & ACE_WRITE_ACL) { 915*1462Smarks if ((acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) && 916*1462Smarks (isowner)) { 917*1462Smarks error = ENOTSUP; 918*1462Smarks goto out; 919*1462Smarks } 920*1462Smarks if ((acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) && 921*1462Smarks (! isowner)) { 922*1462Smarks error = ENOTSUP; 923*1462Smarks goto out; 924*1462Smarks } 925*1462Smarks } 926*1462Smarks 927*1462Smarks out: 928*1462Smarks return (error); 929*1462Smarks } 930*1462Smarks 931*1462Smarks static int 932*1462Smarks ace_mask_to_mode(uint32_t mask, o_mode_t *modep, int isdir) 933*1462Smarks { 934*1462Smarks int error = 0; 935*1462Smarks o_mode_t mode = 0; 936*1462Smarks uint32_t bits, wantbits; 937*1462Smarks 938*1462Smarks /* read */ 939*1462Smarks if (mask & ACE_READ_DATA) 940*1462Smarks mode |= 04; 941*1462Smarks 942*1462Smarks /* write */ 943*1462Smarks wantbits = (ACE_WRITE_DATA | ACE_APPEND_DATA); 944*1462Smarks if (isdir) 945*1462Smarks wantbits |= ACE_DELETE_CHILD; 946*1462Smarks bits = mask & wantbits; 947*1462Smarks if (bits != 0) { 948*1462Smarks if (bits != wantbits) { 949*1462Smarks error = ENOTSUP; 950*1462Smarks goto out; 951*1462Smarks } 952*1462Smarks mode |= 02; 953*1462Smarks } 954*1462Smarks 955*1462Smarks /* exec */ 956*1462Smarks if (mask & ACE_EXECUTE) { 957*1462Smarks mode |= 01; 958*1462Smarks } 959*1462Smarks 960*1462Smarks *modep = mode; 961*1462Smarks 962*1462Smarks out: 963*1462Smarks return (error); 964*1462Smarks } 965*1462Smarks 966*1462Smarks static int 967*1462Smarks ace_allow_to_mode(uint32_t mask, o_mode_t *modep, int isdir) 968*1462Smarks { 969*1462Smarks /* ACE_READ_ACL and ACE_READ_ATTRIBUTES must both be set */ 970*1462Smarks if ((mask & (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) != 971*1462Smarks (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) { 972*1462Smarks return (ENOTSUP); 973*1462Smarks } 974*1462Smarks 975*1462Smarks return (ace_mask_to_mode(mask, modep, isdir)); 976*1462Smarks } 977*1462Smarks 978*1462Smarks static int 979*1462Smarks acevals_to_aent(acevals_t *vals, aclent_t *dest, ace_list_t *list, 980*1462Smarks uid_t owner, gid_t group, int isdir) 981*1462Smarks { 982*1462Smarks int error; 983*1462Smarks uint32_t flips = ACE_POSIX_SUPPORTED_BITS; 984*1462Smarks 985*1462Smarks if (isdir) 986*1462Smarks flips |= ACE_DELETE_CHILD; 987*1462Smarks if (vals->allowed != (vals->denied ^ flips)) { 988*1462Smarks error = ENOTSUP; 989*1462Smarks goto out; 990*1462Smarks } 991*1462Smarks if ((list->hasmask) && (list->acl_mask != vals->mask) && 992*1462Smarks (vals->aent_type & (USER | GROUP | GROUP_OBJ))) { 993*1462Smarks error = ENOTSUP; 994*1462Smarks goto out; 995*1462Smarks } 996*1462Smarks error = ace_allow_to_mode(vals->allowed, &dest->a_perm, isdir); 997*1462Smarks if (error != 0) 998*1462Smarks goto out; 999*1462Smarks dest->a_type = vals->aent_type; 1000*1462Smarks if (dest->a_type & (USER | GROUP)) { 1001*1462Smarks dest->a_id = vals->key; 1002*1462Smarks } else if (dest->a_type & USER_OBJ) { 1003*1462Smarks dest->a_id = owner; 1004*1462Smarks } else if (dest->a_type & GROUP_OBJ) { 1005*1462Smarks dest->a_id = group; 1006*1462Smarks } else if (dest->a_type & OTHER_OBJ) { 1007*1462Smarks dest->a_id = 0; 1008*1462Smarks } else { 1009*1462Smarks error = EINVAL; 1010*1462Smarks goto out; 1011*1462Smarks } 1012*1462Smarks 1013*1462Smarks out: 1014*1462Smarks return (error); 1015*1462Smarks } 1016789Sahrens 1017789Sahrens static int 1018*1462Smarks ace_list_to_aent(ace_list_t *list, aclent_t **aclentp, int *aclcnt, 1019*1462Smarks uid_t owner, gid_t group, int isdir) 1020*1462Smarks { 1021*1462Smarks int error = 0; 1022*1462Smarks aclent_t *aent, *result = NULL; 1023*1462Smarks acevals_t *vals; 1024*1462Smarks int resultcount; 1025*1462Smarks 1026*1462Smarks if ((list->seen & (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) != 1027*1462Smarks (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) { 1028*1462Smarks error = ENOTSUP; 1029*1462Smarks goto out; 1030*1462Smarks } 1031*1462Smarks if ((! list->hasmask) && (list->numusers + list->numgroups > 0)) { 1032*1462Smarks error = ENOTSUP; 1033*1462Smarks goto out; 1034*1462Smarks } 1035*1462Smarks 1036*1462Smarks resultcount = 3 + list->numusers + list->numgroups; 1037*1462Smarks /* 1038*1462Smarks * This must be the same condition as below, when we add the CLASS_OBJ 1039*1462Smarks * (aka ACL mask) 1040*1462Smarks */ 1041*1462Smarks if ((list->hasmask) || (! list->dfacl_flag)) 1042*1462Smarks resultcount += 1; 1043*1462Smarks 1044*1462Smarks result = aent = calloc(1, resultcount * sizeof (aclent_t)); 1045*1462Smarks 1046*1462Smarks if (result == NULL) { 1047*1462Smarks error = ENOMEM; 1048*1462Smarks goto out; 1049*1462Smarks } 1050*1462Smarks 1051*1462Smarks /* USER_OBJ */ 1052*1462Smarks if (!(list->user_obj.aent_type & USER_OBJ)) { 1053*1462Smarks error = EINVAL; 1054*1462Smarks goto out; 1055*1462Smarks } 1056*1462Smarks 1057*1462Smarks error = acevals_to_aent(&list->user_obj, aent, list, owner, group, 1058*1462Smarks isdir); 1059*1462Smarks 1060*1462Smarks if (error != 0) 1061*1462Smarks goto out; 1062*1462Smarks ++aent; 1063*1462Smarks /* USER */ 1064*1462Smarks vals = NULL; 1065*1462Smarks for (vals = avl_first(&list->user); vals != NULL; 1066*1462Smarks vals = AVL_NEXT(&list->user, vals)) { 1067*1462Smarks if (!(vals->aent_type & USER)) { 1068*1462Smarks error = EINVAL; 1069*1462Smarks goto out; 1070*1462Smarks } 1071*1462Smarks error = acevals_to_aent(vals, aent, list, owner, group, 1072*1462Smarks isdir); 1073*1462Smarks if (error != 0) 1074*1462Smarks goto out; 1075*1462Smarks ++aent; 1076*1462Smarks } 1077*1462Smarks /* GROUP_OBJ */ 1078*1462Smarks if (!(list->group_obj.aent_type & GROUP_OBJ)) { 1079*1462Smarks error = EINVAL; 1080*1462Smarks goto out; 1081*1462Smarks } 1082*1462Smarks error = acevals_to_aent(&list->group_obj, aent, list, owner, group, 1083*1462Smarks isdir); 1084*1462Smarks if (error != 0) 1085*1462Smarks goto out; 1086*1462Smarks ++aent; 1087*1462Smarks /* GROUP */ 1088*1462Smarks vals = NULL; 1089*1462Smarks for (vals = avl_first(&list->group); vals != NULL; 1090*1462Smarks vals = AVL_NEXT(&list->group, vals)) { 1091*1462Smarks if (!(vals->aent_type & GROUP)) { 1092*1462Smarks error = EINVAL; 1093*1462Smarks goto out; 1094*1462Smarks } 1095*1462Smarks error = acevals_to_aent(vals, aent, list, owner, group, 1096*1462Smarks isdir); 1097*1462Smarks if (error != 0) 1098*1462Smarks goto out; 1099*1462Smarks ++aent; 1100*1462Smarks } 1101*1462Smarks /* 1102*1462Smarks * CLASS_OBJ (aka ACL_MASK) 1103*1462Smarks * 1104*1462Smarks * An ACL_MASK is not fabricated if the ACL is a default ACL. 1105*1462Smarks * This is to follow UFS's behavior. 1106*1462Smarks */ 1107*1462Smarks if ((list->hasmask) || (! list->dfacl_flag)) { 1108*1462Smarks if (list->hasmask) { 1109*1462Smarks uint32_t flips = ACE_POSIX_SUPPORTED_BITS; 1110*1462Smarks if (isdir) 1111*1462Smarks flips |= ACE_DELETE_CHILD; 1112*1462Smarks error = ace_mask_to_mode(list->acl_mask ^ flips, 1113*1462Smarks &aent->a_perm, isdir); 1114*1462Smarks if (error != 0) 1115*1462Smarks goto out; 1116*1462Smarks } else { 1117*1462Smarks /* fabricate the ACL_MASK from the group permissions */ 1118*1462Smarks error = ace_mask_to_mode(list->group_obj.allowed, 1119*1462Smarks &aent->a_perm, isdir); 1120*1462Smarks if (error != 0) 1121*1462Smarks goto out; 1122*1462Smarks } 1123*1462Smarks aent->a_id = 0; 1124*1462Smarks aent->a_type = CLASS_OBJ | list->dfacl_flag; 1125*1462Smarks ++aent; 1126*1462Smarks } 1127*1462Smarks /* OTHER_OBJ */ 1128*1462Smarks if (!(list->other_obj.aent_type & OTHER_OBJ)) { 1129*1462Smarks error = EINVAL; 1130*1462Smarks goto out; 1131*1462Smarks } 1132*1462Smarks error = acevals_to_aent(&list->other_obj, aent, list, owner, group, 1133*1462Smarks isdir); 1134*1462Smarks if (error != 0) 1135*1462Smarks goto out; 1136*1462Smarks ++aent; 1137*1462Smarks 1138*1462Smarks *aclentp = result; 1139*1462Smarks *aclcnt = resultcount; 1140*1462Smarks 1141*1462Smarks out: 1142*1462Smarks if (error != 0) { 1143*1462Smarks if (result != NULL) 1144*1462Smarks free(result); 1145*1462Smarks } 1146*1462Smarks 1147*1462Smarks return (error); 1148*1462Smarks } 1149*1462Smarks 1150*1462Smarks /* 1151*1462Smarks * free all data associated with an ace_list 1152*1462Smarks */ 1153*1462Smarks static void 1154*1462Smarks ace_list_free(ace_list_t *al) 1155*1462Smarks { 1156*1462Smarks acevals_t *node; 1157*1462Smarks void *cookie; 1158*1462Smarks 1159*1462Smarks if (al == NULL) 1160*1462Smarks return; 1161*1462Smarks 1162*1462Smarks cookie = NULL; 1163*1462Smarks while ((node = avl_destroy_nodes(&al->user, &cookie)) != NULL) 1164*1462Smarks free(node); 1165*1462Smarks cookie = NULL; 1166*1462Smarks while ((node = avl_destroy_nodes(&al->group, &cookie)) != NULL) 1167*1462Smarks free(node); 1168*1462Smarks 1169*1462Smarks avl_destroy(&al->user); 1170*1462Smarks avl_destroy(&al->group); 1171*1462Smarks 1172*1462Smarks /* free the container itself */ 1173*1462Smarks free(al); 1174*1462Smarks } 1175*1462Smarks 1176*1462Smarks static int 1177*1462Smarks acevals_compare(const void *va, const void *vb) 1178*1462Smarks { 1179*1462Smarks const acevals_t *a = va, *b = vb; 1180*1462Smarks 1181*1462Smarks if (a->key == b->key) 1182*1462Smarks return (0); 1183*1462Smarks 1184*1462Smarks if (a->key > b->key) 1185*1462Smarks return (1); 1186*1462Smarks 1187*1462Smarks else 1188*1462Smarks return (-1); 1189*1462Smarks } 1190*1462Smarks 1191*1462Smarks /* 1192*1462Smarks * Convert a list of ace_t entries to equivalent regular and default 1193*1462Smarks * aclent_t lists. Return error (ENOTSUP) when conversion is not possible. 1194*1462Smarks */ 1195*1462Smarks static int 1196*1462Smarks ln_ace_to_aent(ace_t *ace, int n, uid_t owner, gid_t group, 1197*1462Smarks aclent_t **aclentp, int *aclcnt, aclent_t **dfaclentp, int *dfaclcnt, 1198*1462Smarks int isdir) 1199*1462Smarks { 1200*1462Smarks int error = 0; 1201*1462Smarks ace_t *acep; 1202*1462Smarks uint32_t bits; 1203*1462Smarks int i; 1204*1462Smarks ace_list_t *normacl = NULL, *dfacl = NULL, *acl; 1205*1462Smarks acevals_t *vals; 1206*1462Smarks 1207*1462Smarks *aclentp = NULL; 1208*1462Smarks *aclcnt = 0; 1209*1462Smarks *dfaclentp = NULL; 1210*1462Smarks *dfaclcnt = 0; 1211*1462Smarks 1212*1462Smarks /* we need at least user_obj, group_obj, and other_obj */ 1213*1462Smarks if (n < 6) { 1214*1462Smarks error = ENOTSUP; 1215*1462Smarks goto out; 1216*1462Smarks } 1217*1462Smarks if (ace == NULL) { 1218*1462Smarks error = EINVAL; 1219*1462Smarks goto out; 1220*1462Smarks } 1221*1462Smarks 1222*1462Smarks normacl = calloc(1, sizeof (ace_list_t)); 1223*1462Smarks 1224*1462Smarks if (normacl == NULL) { 1225*1462Smarks error = errno; 1226*1462Smarks goto out; 1227*1462Smarks } 1228*1462Smarks 1229*1462Smarks avl_create(&normacl->user, acevals_compare, sizeof (acevals_t), 1230*1462Smarks offsetof(acevals_t, avl)); 1231*1462Smarks avl_create(&normacl->group, acevals_compare, sizeof (acevals_t), 1232*1462Smarks offsetof(acevals_t, avl)); 1233*1462Smarks 1234*1462Smarks ace_list_init(normacl, 0); 1235*1462Smarks 1236*1462Smarks dfacl = calloc(1, sizeof (ace_list_t)); 1237*1462Smarks if (dfacl == NULL) { 1238*1462Smarks error = errno; 1239*1462Smarks goto out; 1240*1462Smarks } 1241*1462Smarks avl_create(&dfacl->user, acevals_compare, sizeof (acevals_t), 1242*1462Smarks offsetof(acevals_t, avl)); 1243*1462Smarks avl_create(&dfacl->group, acevals_compare, sizeof (acevals_t), 1244*1462Smarks offsetof(acevals_t, avl)); 1245*1462Smarks ace_list_init(dfacl, ACL_DEFAULT); 1246*1462Smarks 1247*1462Smarks /* process every ace_t... */ 1248*1462Smarks for (i = 0; i < n; i++) { 1249*1462Smarks acep = &ace[i]; 1250*1462Smarks 1251*1462Smarks /* rule out certain cases quickly */ 1252*1462Smarks error = ace_to_aent_legal(acep); 1253*1462Smarks if (error != 0) 1254*1462Smarks goto out; 1255*1462Smarks 1256*1462Smarks /* 1257*1462Smarks * Turn off these bits in order to not have to worry about 1258*1462Smarks * them when doing the checks for compliments. 1259*1462Smarks */ 1260*1462Smarks acep->a_access_mask &= ~(ACE_WRITE_OWNER | ACE_DELETE | 1261*1462Smarks ACE_SYNCHRONIZE | ACE_WRITE_ATTRIBUTES | 1262*1462Smarks ACE_READ_NAMED_ATTRS | ACE_WRITE_NAMED_ATTRS); 1263*1462Smarks 1264*1462Smarks /* see if this should be a regular or default acl */ 1265*1462Smarks bits = acep->a_flags & 1266*1462Smarks (ACE_INHERIT_ONLY_ACE | 1267*1462Smarks ACE_FILE_INHERIT_ACE | 1268*1462Smarks ACE_DIRECTORY_INHERIT_ACE); 1269*1462Smarks if (bits != 0) { 1270*1462Smarks /* all or nothing on these inherit bits */ 1271*1462Smarks if (bits != (ACE_INHERIT_ONLY_ACE | 1272*1462Smarks ACE_FILE_INHERIT_ACE | 1273*1462Smarks ACE_DIRECTORY_INHERIT_ACE)) { 1274*1462Smarks error = ENOTSUP; 1275*1462Smarks goto out; 1276*1462Smarks } 1277*1462Smarks acl = dfacl; 1278*1462Smarks } else { 1279*1462Smarks acl = normacl; 1280*1462Smarks } 1281*1462Smarks 1282*1462Smarks if ((acep->a_flags & ACE_OWNER)) { 1283*1462Smarks if (acl->state > ace_user_obj) { 1284*1462Smarks error = ENOTSUP; 1285*1462Smarks goto out; 1286*1462Smarks } 1287*1462Smarks acl->state = ace_user_obj; 1288*1462Smarks acl->seen |= USER_OBJ; 1289*1462Smarks vals = &acl->user_obj; 1290*1462Smarks vals->aent_type = USER_OBJ | acl->dfacl_flag; 1291*1462Smarks } else if ((acep->a_flags & ACE_EVERYONE)) { 1292*1462Smarks acl->state = ace_other_obj; 1293*1462Smarks acl->seen |= OTHER_OBJ; 1294*1462Smarks vals = &acl->other_obj; 1295*1462Smarks vals->aent_type = OTHER_OBJ | acl->dfacl_flag; 1296*1462Smarks } else if (acep->a_flags & ACE_IDENTIFIER_GROUP) { 1297*1462Smarks if (acl->state > ace_group) { 1298*1462Smarks error = ENOTSUP; 1299*1462Smarks goto out; 1300*1462Smarks } 1301*1462Smarks if ((acep->a_flags & ACE_GROUP)) { 1302*1462Smarks acl->seen |= GROUP_OBJ; 1303*1462Smarks vals = &acl->group_obj; 1304*1462Smarks vals->aent_type = GROUP_OBJ | acl->dfacl_flag; 1305*1462Smarks } else { 1306*1462Smarks acl->seen |= GROUP; 1307*1462Smarks vals = acevals_find(acep, &acl->group, 1308*1462Smarks &acl->numgroups); 1309*1462Smarks if (vals == NULL) { 1310*1462Smarks error = ENOMEM; 1311*1462Smarks goto out; 1312*1462Smarks } 1313*1462Smarks vals->aent_type = GROUP | acl->dfacl_flag; 1314*1462Smarks } 1315*1462Smarks acl->state = ace_group; 1316*1462Smarks } else { 1317*1462Smarks if (acl->state > ace_user) { 1318*1462Smarks error = ENOTSUP; 1319*1462Smarks goto out; 1320*1462Smarks } 1321*1462Smarks acl->state = ace_user; 1322*1462Smarks acl->seen |= USER; 1323*1462Smarks vals = acevals_find(acep, &acl->user, 1324*1462Smarks &acl->numusers); 1325*1462Smarks if (vals == NULL) { 1326*1462Smarks error = ENOMEM; 1327*1462Smarks goto out; 1328*1462Smarks } 1329*1462Smarks vals->aent_type = USER | acl->dfacl_flag; 1330*1462Smarks } 1331*1462Smarks 1332*1462Smarks if (!(acl->state > ace_unused)) { 1333*1462Smarks error = EINVAL; 1334*1462Smarks goto out; 1335*1462Smarks } 1336*1462Smarks 1337*1462Smarks if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) { 1338*1462Smarks /* no more than one allowed per aclent_t */ 1339*1462Smarks if (vals->allowed != ACE_MASK_UNDEFINED) { 1340*1462Smarks error = ENOTSUP; 1341*1462Smarks goto out; 1342*1462Smarks } 1343*1462Smarks vals->allowed = acep->a_access_mask; 1344*1462Smarks } else { 1345*1462Smarks /* 1346*1462Smarks * it's a DENY; if there was a previous DENY, it 1347*1462Smarks * must have been an ACL_MASK. 1348*1462Smarks */ 1349*1462Smarks if (vals->denied != ACE_MASK_UNDEFINED) { 1350*1462Smarks /* ACL_MASK is for USER and GROUP only */ 1351*1462Smarks if ((acl->state != ace_user) && 1352*1462Smarks (acl->state != ace_group)) { 1353*1462Smarks error = ENOTSUP; 1354*1462Smarks goto out; 1355*1462Smarks } 1356*1462Smarks 1357*1462Smarks if (! acl->hasmask) { 1358*1462Smarks acl->hasmask = 1; 1359*1462Smarks acl->acl_mask = vals->denied; 1360*1462Smarks /* check for mismatched ACL_MASK emulations */ 1361*1462Smarks } else if (acl->acl_mask != vals->denied) { 1362*1462Smarks error = ENOTSUP; 1363*1462Smarks goto out; 1364*1462Smarks } 1365*1462Smarks vals->mask = vals->denied; 1366*1462Smarks } 1367*1462Smarks vals->denied = acep->a_access_mask; 1368*1462Smarks } 1369*1462Smarks } 1370*1462Smarks 1371*1462Smarks /* done collating; produce the aclent_t lists */ 1372*1462Smarks if (normacl->state != ace_unused) { 1373*1462Smarks error = ace_list_to_aent(normacl, aclentp, aclcnt, 1374*1462Smarks owner, group, isdir); 1375*1462Smarks if (error != 0) { 1376*1462Smarks goto out; 1377*1462Smarks } 1378*1462Smarks } 1379*1462Smarks if (dfacl->state != ace_unused) { 1380*1462Smarks error = ace_list_to_aent(dfacl, dfaclentp, dfaclcnt, 1381*1462Smarks owner, group, isdir); 1382*1462Smarks if (error != 0) { 1383*1462Smarks goto out; 1384*1462Smarks } 1385*1462Smarks } 1386*1462Smarks 1387*1462Smarks out: 1388*1462Smarks if (normacl != NULL) 1389*1462Smarks ace_list_free(normacl); 1390*1462Smarks if (dfacl != NULL) 1391*1462Smarks ace_list_free(dfacl); 1392*1462Smarks 1393*1462Smarks return (error); 1394*1462Smarks } 1395*1462Smarks 1396*1462Smarks static int 1397*1462Smarks convert_ace_to_aent(ace_t *acebufp, int acecnt, int isdir, 1398*1462Smarks uid_t owner, gid_t group, aclent_t **retaclentp, int *retaclcnt) 1399*1462Smarks { 1400*1462Smarks int error; 1401*1462Smarks aclent_t *aclentp, *dfaclentp; 1402*1462Smarks int aclcnt, dfaclcnt; 1403*1462Smarks 1404*1462Smarks error = ln_ace_to_aent(acebufp, acecnt, owner, group, 1405*1462Smarks &aclentp, &aclcnt, &dfaclentp, &dfaclcnt, isdir); 1406*1462Smarks 1407*1462Smarks if (error) 1408*1462Smarks return (error); 1409*1462Smarks 1410*1462Smarks 1411*1462Smarks if (dfaclcnt != 0) { 1412*1462Smarks /* 1413*1462Smarks * Slap aclentp and dfaclentp into a single array. 1414*1462Smarks */ 1415*1462Smarks aclentp = realloc(aclentp, (sizeof (aclent_t) * aclcnt) + 1416*1462Smarks (sizeof (aclent_t) * dfaclcnt)); 1417*1462Smarks if (aclentp != NULL) { 1418*1462Smarks (void) memcpy(aclentp + aclcnt, 1419*1462Smarks dfaclentp, sizeof (aclent_t) * dfaclcnt); 1420*1462Smarks } else { 1421*1462Smarks error = -1; 1422*1462Smarks } 1423*1462Smarks } 1424*1462Smarks 1425*1462Smarks if (aclentp) { 1426*1462Smarks *retaclentp = aclentp; 1427*1462Smarks *retaclcnt = aclcnt + dfaclcnt; 1428*1462Smarks } 1429*1462Smarks 1430*1462Smarks if (dfaclentp) 1431*1462Smarks free(dfaclentp); 1432*1462Smarks 1433*1462Smarks return (error); 1434*1462Smarks } 1435*1462Smarks 1436789Sahrens cacl_get(acl_inp inp, int get_flag, int type, acl_t **aclp) 1437789Sahrens { 1438789Sahrens const char *fname; 1439789Sahrens int fd; 1440789Sahrens int ace_acl = 0; 1441789Sahrens int error; 1442789Sahrens int getcmd, cntcmd; 1443789Sahrens acl_t *acl_info; 1444789Sahrens int save_errno; 1445789Sahrens int stat_error; 1446789Sahrens struct stat64 statbuf; 1447789Sahrens 1448789Sahrens *aclp = NULL; 1449789Sahrens if (type == ACL_PATH) { 1450789Sahrens fname = inp.file; 1451789Sahrens ace_acl = pathconf(fname, _PC_ACL_ENABLED); 1452789Sahrens } else { 1453789Sahrens fd = inp.fd; 1454789Sahrens ace_acl = fpathconf(fd, _PC_ACL_ENABLED); 1455789Sahrens } 1456789Sahrens 1457789Sahrens if (ace_acl == -1) 1458789Sahrens return (-1); 1459789Sahrens 1460789Sahrens /* 1461789Sahrens * if acl's aren't supported then 1462789Sahrens * send it through the old GETACL interface 1463789Sahrens */ 1464789Sahrens if (ace_acl == 0) { 1465789Sahrens ace_acl = _ACL_ACLENT_ENABLED; 1466789Sahrens } 1467789Sahrens 1468789Sahrens if (ace_acl & _ACL_ACE_ENABLED) { 1469789Sahrens cntcmd = ACE_GETACLCNT; 1470789Sahrens getcmd = ACE_GETACL; 1471789Sahrens acl_info = acl_alloc(ACE_T); 1472789Sahrens } else { 1473789Sahrens cntcmd = GETACLCNT; 1474789Sahrens getcmd = GETACL; 1475789Sahrens acl_info = acl_alloc(ACLENT_T); 1476789Sahrens } 1477789Sahrens 1478789Sahrens if (acl_info == NULL) 1479789Sahrens return (-1); 1480789Sahrens 1481789Sahrens if (type == ACL_PATH) { 1482789Sahrens acl_info->acl_cnt = acl(fname, cntcmd, 0, NULL); 1483789Sahrens } else { 1484789Sahrens acl_info->acl_cnt = facl(fd, cntcmd, 0, NULL); 1485789Sahrens } 1486789Sahrens 1487789Sahrens save_errno = errno; 1488789Sahrens if (acl_info->acl_cnt < 0) { 1489789Sahrens acl_free(acl_info); 1490789Sahrens errno = save_errno; 1491789Sahrens return (-1); 1492789Sahrens } 1493789Sahrens 1494789Sahrens if (acl_info->acl_cnt == 0) { 1495789Sahrens acl_free(acl_info); 1496789Sahrens errno = save_errno; 1497789Sahrens return (0); 1498789Sahrens } 1499789Sahrens 1500789Sahrens acl_info->acl_aclp = 1501789Sahrens malloc(acl_info->acl_cnt * acl_info->acl_entry_size); 1502789Sahrens save_errno = errno; 1503789Sahrens 1504789Sahrens if (acl_info->acl_aclp == NULL) { 1505789Sahrens acl_free(acl_info); 1506789Sahrens errno = save_errno; 1507789Sahrens return (-1); 1508789Sahrens } 1509789Sahrens 1510789Sahrens if (type == ACL_PATH) { 1511789Sahrens stat_error = stat64(fname, &statbuf); 1512789Sahrens error = acl(fname, getcmd, acl_info->acl_cnt, 1513789Sahrens acl_info->acl_aclp); 1514789Sahrens } else { 1515789Sahrens stat_error = fstat64(fd, &statbuf); 1516789Sahrens error = facl(fd, getcmd, acl_info->acl_cnt, 1517789Sahrens acl_info->acl_aclp); 1518789Sahrens } 1519789Sahrens 1520789Sahrens save_errno = errno; 1521789Sahrens if (error == -1) { 1522789Sahrens acl_free(acl_info); 1523789Sahrens errno = save_errno; 1524789Sahrens return (-1); 1525789Sahrens } 1526789Sahrens 1527789Sahrens 1528789Sahrens if (stat_error == 0) { 1529789Sahrens acl_info->acl_flags = 1530789Sahrens (S_ISDIR(statbuf.st_mode) ? ACL_IS_DIR : 0); 1531789Sahrens } else 1532789Sahrens acl_info->acl_flags = 0; 1533789Sahrens 1534789Sahrens switch (acl_info->acl_type) { 1535789Sahrens case ACLENT_T: 1536789Sahrens if (acl_info->acl_cnt <= MIN_ACL_ENTRIES) 1537789Sahrens acl_info->acl_flags |= ACL_IS_TRIVIAL; 1538789Sahrens break; 1539789Sahrens case ACE_T: 1540789Sahrens if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0) 1541789Sahrens acl_info->acl_flags |= ACL_IS_TRIVIAL; 1542789Sahrens break; 1543789Sahrens default: 1544789Sahrens errno = EINVAL; 1545789Sahrens acl_free(acl_info); 1546789Sahrens return (-1); 1547789Sahrens } 1548789Sahrens 1549789Sahrens if ((acl_info->acl_flags & ACL_IS_TRIVIAL) && 1550789Sahrens (get_flag & ACL_NO_TRIVIAL)) { 1551789Sahrens acl_free(acl_info); 1552789Sahrens errno = 0; 1553789Sahrens return (0); 1554789Sahrens } 1555789Sahrens 1556789Sahrens *aclp = acl_info; 1557789Sahrens return (0); 1558789Sahrens } 1559789Sahrens 1560789Sahrens /* 1561789Sahrens * return -1 on failure, otherwise the number of acl 1562789Sahrens * entries is returned 1563789Sahrens */ 1564789Sahrens int 1565789Sahrens acl_get(const char *path, int get_flag, acl_t **aclp) 1566789Sahrens { 1567789Sahrens acl_inp acl_inp; 1568789Sahrens acl_inp.file = path; 1569789Sahrens 1570789Sahrens return (cacl_get(acl_inp, get_flag, ACL_PATH, aclp)); 1571789Sahrens } 1572789Sahrens 1573789Sahrens int 1574789Sahrens facl_get(int fd, int get_flag, acl_t **aclp) 1575789Sahrens { 1576789Sahrens 1577789Sahrens acl_inp acl_inp; 1578789Sahrens acl_inp.fd = fd; 1579789Sahrens 1580789Sahrens return (cacl_get(acl_inp, get_flag, ACL_FD, aclp)); 1581789Sahrens } 1582789Sahrens 1583*1462Smarks static int 1584*1462Smarks acl_translate(acl_t *aclp, int target_flavor, int isdir, uid_t owner, 1585*1462Smarks gid_t group) 1586*1462Smarks { 1587*1462Smarks int aclcnt; 1588*1462Smarks void *acldata; 1589*1462Smarks int error; 1590*1462Smarks 1591*1462Smarks /* 1592*1462Smarks * See if we need to translate 1593*1462Smarks */ 1594*1462Smarks if ((target_flavor == _ACL_ACE_ENABLED && aclp->acl_type == ACE_T) || 1595*1462Smarks (target_flavor == _ACL_ACLENT_ENABLED && 1596*1462Smarks aclp->acl_type == ACLENT_T)) 1597*1462Smarks return (0); 1598*1462Smarks 1599*1462Smarks if (target_flavor == -1) 1600*1462Smarks return (-1); 1601*1462Smarks 1602*1462Smarks if (target_flavor == _ACL_ACE_ENABLED && 1603*1462Smarks aclp->acl_type == ACLENT_T) { 1604*1462Smarks error = convert_aent_to_ace(aclp->acl_aclp, 1605*1462Smarks aclp->acl_cnt, isdir, (ace_t **)&acldata, &aclcnt); 1606*1462Smarks if (error) { 1607*1462Smarks errno = error; 1608*1462Smarks return (-1); 1609*1462Smarks } 1610*1462Smarks } else if (target_flavor == _ACL_ACLENT_ENABLED && 1611*1462Smarks aclp->acl_type == ACE_T) { 1612*1462Smarks error = convert_ace_to_aent(aclp->acl_aclp, aclp->acl_cnt, 1613*1462Smarks isdir, owner, group, (aclent_t **)&acldata, &aclcnt); 1614*1462Smarks if (error) { 1615*1462Smarks errno = error; 1616*1462Smarks return (-1); 1617*1462Smarks } 1618*1462Smarks } else { 1619*1462Smarks errno = ENOTSUP; 1620*1462Smarks return (-1); 1621*1462Smarks } 1622*1462Smarks 1623*1462Smarks /* 1624*1462Smarks * replace old acl with newly translated acl 1625*1462Smarks */ 1626*1462Smarks free(aclp->acl_aclp); 1627*1462Smarks aclp->acl_aclp = acldata; 1628*1462Smarks aclp->acl_cnt = aclcnt; 1629*1462Smarks aclp->acl_type = (target_flavor == _ACL_ACE_ENABLED) ? ACE_T : ACLENT_T; 1630*1462Smarks return (0); 1631*1462Smarks } 1632*1462Smarks 1633789Sahrens /* 1634789Sahrens * Set an ACL, translates acl to ace_t when appropriate. 1635789Sahrens */ 1636789Sahrens static int 1637789Sahrens cacl_set(acl_inp *acl_inp, acl_t *aclp, int type) 1638789Sahrens { 1639789Sahrens int error = 0; 1640789Sahrens int acl_flavor_target; 1641789Sahrens struct stat64 statbuf; 1642789Sahrens int stat_error; 1643789Sahrens int isdir; 1644789Sahrens 1645789Sahrens 1646789Sahrens if (type == ACL_PATH) { 1647789Sahrens stat_error = stat64(acl_inp->file, &statbuf); 1648789Sahrens if (stat_error) 1649789Sahrens return (-1); 1650789Sahrens acl_flavor_target = pathconf(acl_inp->file, _PC_ACL_ENABLED); 1651789Sahrens } else { 1652789Sahrens stat_error = fstat64(acl_inp->fd, &statbuf); 1653789Sahrens if (stat_error) 1654789Sahrens return (-1); 1655789Sahrens acl_flavor_target = fpathconf(acl_inp->fd, _PC_ACL_ENABLED); 1656789Sahrens } 1657789Sahrens 1658789Sahrens isdir = S_ISDIR(statbuf.st_mode); 1659789Sahrens 1660*1462Smarks if ((error = acl_translate(aclp, acl_flavor_target, isdir, 1661*1462Smarks statbuf.st_uid, statbuf.st_gid)) != 0) { 1662*1462Smarks return (error); 1663789Sahrens } 1664789Sahrens 1665789Sahrens if (type == ACL_PATH) { 1666789Sahrens error = acl(acl_inp->file, 1667789Sahrens (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, 1668789Sahrens aclp->acl_cnt, aclp->acl_aclp); 1669789Sahrens } else { 1670789Sahrens error = facl(acl_inp->fd, 1671789Sahrens (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, 1672789Sahrens aclp->acl_cnt, aclp->acl_aclp); 1673789Sahrens } 1674789Sahrens 1675789Sahrens return (error); 1676789Sahrens } 1677789Sahrens 1678789Sahrens int 1679789Sahrens acl_set(const char *path, acl_t *aclp) 1680789Sahrens { 1681789Sahrens acl_inp acl_inp; 1682789Sahrens 1683789Sahrens acl_inp.file = path; 1684789Sahrens 1685789Sahrens return (cacl_set(&acl_inp, aclp, ACL_PATH)); 1686789Sahrens } 1687789Sahrens 1688789Sahrens int 1689789Sahrens facl_set(int fd, acl_t *aclp) 1690789Sahrens { 1691789Sahrens acl_inp acl_inp; 1692789Sahrens 1693789Sahrens acl_inp.fd = fd; 1694789Sahrens 1695789Sahrens return (cacl_set(&acl_inp, aclp, ACL_FD)); 1696789Sahrens } 1697789Sahrens 1698789Sahrens int 1699789Sahrens acl_cnt(acl_t *aclp) 1700789Sahrens { 1701789Sahrens return (aclp->acl_cnt); 1702789Sahrens } 1703789Sahrens 1704789Sahrens int 1705789Sahrens acl_type(acl_t *aclp) 1706789Sahrens { 1707789Sahrens return (aclp->acl_type); 1708789Sahrens } 1709789Sahrens 1710789Sahrens acl_t * 1711789Sahrens acl_dup(acl_t *aclp) 1712789Sahrens { 1713789Sahrens acl_t *newaclp; 1714789Sahrens 1715789Sahrens newaclp = acl_alloc(aclp->acl_type); 1716789Sahrens if (newaclp == NULL) 1717789Sahrens return (NULL); 1718789Sahrens 1719789Sahrens newaclp->acl_aclp = malloc(aclp->acl_entry_size * aclp->acl_cnt); 1720789Sahrens if (newaclp->acl_aclp == NULL) { 1721789Sahrens acl_free(newaclp); 1722789Sahrens return (NULL); 1723789Sahrens } 1724789Sahrens 1725789Sahrens (void) memcpy(newaclp->acl_aclp, 1726789Sahrens aclp->acl_aclp, aclp->acl_entry_size * aclp->acl_cnt); 1727789Sahrens newaclp->acl_cnt = aclp->acl_cnt; 1728789Sahrens 1729789Sahrens return (newaclp); 1730789Sahrens } 1731789Sahrens 1732789Sahrens int 1733789Sahrens acl_flags(acl_t *aclp) 1734789Sahrens { 1735789Sahrens return (aclp->acl_flags); 1736789Sahrens } 1737789Sahrens 1738789Sahrens void * 1739789Sahrens acl_data(acl_t *aclp) 1740789Sahrens { 1741789Sahrens return (aclp->acl_aclp); 1742789Sahrens } 1743789Sahrens 1744789Sahrens /* 1745789Sahrens * Remove an ACL from a file and create a trivial ACL based 1746789Sahrens * off of the mode argument. After acl has been set owner/group 1747789Sahrens * are updated to match owner,group arguments 1748789Sahrens */ 1749789Sahrens int 1750789Sahrens acl_strip(const char *file, uid_t owner, gid_t group, mode_t mode) 1751789Sahrens { 1752789Sahrens int error = 0; 1753789Sahrens aclent_t min_acl[MIN_ACL_ENTRIES]; 1754789Sahrens ace_t min_ace_acl[6]; /* owner, group, everyone + complement denies */ 1755789Sahrens int acl_flavor; 1756789Sahrens int aclcnt; 1757789Sahrens 1758789Sahrens acl_flavor = pathconf(file, _PC_ACL_ENABLED); 1759789Sahrens 1760789Sahrens if (acl_flavor == -1) 1761789Sahrens return (-1); 1762789Sahrens /* 1763789Sahrens * force it through aclent flavor when file system doesn't 1764789Sahrens * understand question 1765789Sahrens */ 1766789Sahrens if (acl_flavor == 0) 1767789Sahrens acl_flavor = _ACL_ACLENT_ENABLED; 1768789Sahrens 1769789Sahrens if (acl_flavor & _ACL_ACLENT_ENABLED) { 1770789Sahrens min_acl[0].a_type = USER_OBJ; 1771789Sahrens min_acl[0].a_id = owner; 1772789Sahrens min_acl[0].a_perm = ((mode & 0700) >> 6); 1773789Sahrens min_acl[1].a_type = GROUP_OBJ; 1774789Sahrens min_acl[1].a_id = group; 1775789Sahrens min_acl[1].a_perm = ((mode & 0070) >> 3); 1776789Sahrens min_acl[2].a_type = CLASS_OBJ; 1777789Sahrens min_acl[2].a_id = (uid_t)-1; 1778789Sahrens min_acl[2].a_perm = ((mode & 0070) >> 3); 1779789Sahrens min_acl[3].a_type = OTHER_OBJ; 1780789Sahrens min_acl[3].a_id = (uid_t)-1; 1781789Sahrens min_acl[3].a_perm = (mode & 0007); 1782789Sahrens aclcnt = 4; 1783789Sahrens error = acl(file, SETACL, aclcnt, min_acl); 1784789Sahrens } else if (acl_flavor & _ACL_ACE_ENABLED) { 1785789Sahrens (void) memcpy(min_ace_acl, trivial_acl, sizeof (ace_t) * 6); 1786789Sahrens 1787789Sahrens /* 1788789Sahrens * Make aces match request mode 1789789Sahrens */ 1790789Sahrens adjust_ace_pair(&min_ace_acl[0], (mode & 0700) >> 6); 1791789Sahrens adjust_ace_pair(&min_ace_acl[2], (mode & 0070) >> 3); 1792789Sahrens adjust_ace_pair(&min_ace_acl[4], mode & 0007); 1793789Sahrens 1794789Sahrens error = acl(file, ACE_SETACL, 6, min_ace_acl); 1795789Sahrens } else { 1796789Sahrens errno = EINVAL; 1797789Sahrens error = 1; 1798789Sahrens } 1799789Sahrens 1800789Sahrens if (error == 0) 1801789Sahrens error = chown(file, owner, group); 1802789Sahrens return (error); 1803789Sahrens } 1804789Sahrens 1805789Sahrens static int 1806789Sahrens ace_match(void *entry1, void *entry2) 1807789Sahrens { 1808789Sahrens ace_t *p1 = (ace_t *)entry1; 1809789Sahrens ace_t *p2 = (ace_t *)entry2; 1810789Sahrens ace_t ace1, ace2; 1811789Sahrens 1812789Sahrens ace1 = *p1; 1813789Sahrens ace2 = *p2; 1814789Sahrens 1815789Sahrens /* 1816789Sahrens * Need to fixup who field for abstrations for 1817789Sahrens * accurate comparison, since field is undefined. 1818789Sahrens */ 1819789Sahrens if (ace1.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE)) 1820789Sahrens ace1.a_who = -1; 1821789Sahrens if (ace2.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE)) 1822789Sahrens ace2.a_who = -1; 1823789Sahrens return (memcmp(&ace1, &ace2, sizeof (ace_t))); 1824789Sahrens } 1825789Sahrens 1826789Sahrens static int 1827789Sahrens aclent_match(void *entry1, void *entry2) 1828789Sahrens { 1829789Sahrens aclent_t *aclent1 = (aclent_t *)entry1; 1830789Sahrens aclent_t *aclent2 = (aclent_t *)entry2; 1831789Sahrens 1832789Sahrens return (memcmp(aclent1, aclent2, sizeof (aclent_t))); 1833789Sahrens } 1834789Sahrens 1835789Sahrens /* 1836789Sahrens * Find acl entries in acl that correspond to removeacl. Search 1837789Sahrens * is started from slot. The flag argument indicates whether to 1838789Sahrens * remove all matches or just the first match. 1839789Sahrens */ 1840789Sahrens int 1841789Sahrens acl_removeentries(acl_t *acl, acl_t *removeacl, int start_slot, int flag) 1842789Sahrens { 1843789Sahrens int i, j; 1844789Sahrens int match; 1845789Sahrens int (*acl_match)(void *acl1, void *acl2); 1846789Sahrens void *acl_entry, *remove_entry; 1847789Sahrens void *start; 1848789Sahrens int found = 0; 1849789Sahrens 1850789Sahrens if (flag != ACL_REMOVE_ALL && flag != ACL_REMOVE_FIRST) 1851789Sahrens flag = ACL_REMOVE_FIRST; 1852789Sahrens 1853789Sahrens if (acl == NULL || removeacl == NULL) 1854789Sahrens return (EACL_NO_ACL_ENTRY); 1855789Sahrens 1856789Sahrens if (acl->acl_type != removeacl->acl_type) 1857789Sahrens return (EACL_DIFF_TYPE); 1858789Sahrens 1859789Sahrens if (acl->acl_type == ACLENT_T) 1860789Sahrens acl_match = aclent_match; 1861789Sahrens else 1862789Sahrens acl_match = ace_match; 1863789Sahrens 1864789Sahrens for (i = 0, remove_entry = removeacl->acl_aclp; 1865789Sahrens i != removeacl->acl_cnt; i++) { 1866789Sahrens 1867789Sahrens j = 0; 1868789Sahrens acl_entry = (char *)acl->acl_aclp + 1869789Sahrens (acl->acl_entry_size * start_slot); 1870789Sahrens for (;;) { 1871789Sahrens match = acl_match(acl_entry, remove_entry); 1872789Sahrens if (match == 0) { 1873789Sahrens found++; 1874789Sahrens start = (char *)acl_entry + 1875789Sahrens acl->acl_entry_size; 1876789Sahrens (void) memmove(acl_entry, start, 1877789Sahrens acl->acl_entry_size * 1878789Sahrens acl->acl_cnt-- - (j + 1)); 1879789Sahrens 1880789Sahrens if (flag == ACL_REMOVE_FIRST) 1881789Sahrens break; 1882789Sahrens /* 1883789Sahrens * List has changed, restart search from 1884789Sahrens * beginning. 1885789Sahrens */ 1886789Sahrens acl_entry = acl->acl_aclp; 1887789Sahrens j = 0; 1888789Sahrens continue; 1889789Sahrens } 1890789Sahrens acl_entry = ((char *)acl_entry + acl->acl_entry_size); 1891789Sahrens if (++j >= acl->acl_cnt) { 1892789Sahrens break; 1893789Sahrens } 1894789Sahrens } 1895789Sahrens } 1896789Sahrens 1897789Sahrens return ((found == 0) ? EACL_NO_ACL_ENTRY : 0); 1898789Sahrens } 1899789Sahrens 1900789Sahrens /* 1901789Sahrens * Replace entires entries in acl1 with the corresponding entries 1902789Sahrens * in newentries. The where argument specifies where to begin 1903789Sahrens * the replacement. If the where argument is 1 greater than the 1904789Sahrens * number of acl entries in acl1 then they are appended. If the 1905789Sahrens * where argument is 2+ greater than the number of acl entries then 1906789Sahrens * EACL_INVALID_SLOT is returned. 1907789Sahrens */ 1908789Sahrens int 1909789Sahrens acl_modifyentries(acl_t *acl1, acl_t *newentries, int where) 1910789Sahrens { 1911789Sahrens 1912789Sahrens int slot; 1913789Sahrens int slots_needed; 1914789Sahrens int slots_left; 1915789Sahrens int newsize; 1916789Sahrens 1917789Sahrens if (acl1 == NULL || newentries == NULL) 1918789Sahrens return (EACL_NO_ACL_ENTRY); 1919789Sahrens 1920789Sahrens if (where < 0 || where >= acl1->acl_cnt) 1921789Sahrens return (EACL_INVALID_SLOT); 1922789Sahrens 1923789Sahrens if (acl1->acl_type != newentries->acl_type) 1924789Sahrens return (EACL_DIFF_TYPE); 1925789Sahrens 1926789Sahrens slot = where; 1927789Sahrens 1928789Sahrens slots_left = acl1->acl_cnt - slot + 1; 1929789Sahrens if (slots_left < newentries->acl_cnt) { 1930789Sahrens slots_needed = newentries->acl_cnt - slots_left; 1931789Sahrens newsize = (acl1->acl_entry_size * acl1->acl_cnt) + 1932789Sahrens (acl1->acl_entry_size * slots_needed); 1933789Sahrens acl1->acl_aclp = realloc(acl1->acl_aclp, newsize); 1934789Sahrens if (acl1->acl_aclp == NULL) 1935789Sahrens return (-1); 1936789Sahrens } 1937789Sahrens (void) memcpy((char *)acl1->acl_aclp + (acl1->acl_entry_size * slot), 1938789Sahrens newentries->acl_aclp, 1939789Sahrens newentries->acl_entry_size * newentries->acl_cnt); 1940789Sahrens 1941789Sahrens /* 1942789Sahrens * Did ACL grow? 1943789Sahrens */ 1944789Sahrens 1945789Sahrens if ((slot + newentries->acl_cnt) > acl1->acl_cnt) { 1946789Sahrens acl1->acl_cnt = slot + newentries->acl_cnt; 1947789Sahrens } 1948789Sahrens 1949789Sahrens return (0); 1950789Sahrens } 1951789Sahrens 1952789Sahrens /* 1953789Sahrens * Add acl2 entries into acl1. The where argument specifies where 1954789Sahrens * to add the entries. 1955789Sahrens */ 1956789Sahrens int 1957789Sahrens acl_addentries(acl_t *acl1, acl_t *acl2, int where) 1958789Sahrens { 1959789Sahrens 1960789Sahrens int newsize; 1961789Sahrens int len; 1962789Sahrens void *start; 1963789Sahrens void *to; 1964789Sahrens 1965789Sahrens if (acl1 == NULL || acl2 == NULL) 1966789Sahrens return (EACL_NO_ACL_ENTRY); 1967789Sahrens 1968789Sahrens if (acl1->acl_type != acl2->acl_type) 1969789Sahrens return (EACL_DIFF_TYPE); 1970789Sahrens 1971789Sahrens /* 1972789Sahrens * allow where to specify 1 past last slot for an append operation 1973789Sahrens * but anything greater is an error. 1974789Sahrens */ 1975789Sahrens if (where < 0 || where > acl1->acl_cnt) 1976789Sahrens return (EACL_INVALID_SLOT); 1977789Sahrens 1978789Sahrens newsize = (acl2->acl_entry_size * acl2->acl_cnt) + 1979789Sahrens (acl1->acl_entry_size * acl1->acl_cnt); 1980789Sahrens acl1->acl_aclp = realloc(acl1->acl_aclp, newsize); 1981789Sahrens if (acl1->acl_aclp == NULL) 1982789Sahrens return (-1); 1983789Sahrens 1984789Sahrens /* 1985789Sahrens * first push down entries where new ones will be inserted 1986789Sahrens */ 1987789Sahrens 1988789Sahrens to = (void *)((char *)acl1->acl_aclp + 1989789Sahrens ((where + acl2->acl_cnt) * acl1->acl_entry_size)); 1990789Sahrens 1991789Sahrens start = (void *)((char *)acl1->acl_aclp + 1992789Sahrens where * acl1->acl_entry_size); 1993789Sahrens 1994789Sahrens if (where < acl1->acl_cnt) { 1995789Sahrens len = (acl1->acl_cnt - where) * acl1->acl_entry_size; 1996789Sahrens (void) memmove(to, start, len); 1997789Sahrens } 1998789Sahrens 1999789Sahrens /* 2000789Sahrens * now stick in new entries. 2001789Sahrens */ 2002789Sahrens 2003789Sahrens (void) memmove(start, acl2->acl_aclp, 2004789Sahrens acl2->acl_cnt * acl2->acl_entry_size); 2005789Sahrens 2006789Sahrens acl1->acl_cnt += acl2->acl_cnt; 2007789Sahrens return (0); 2008789Sahrens } 2009789Sahrens 2010789Sahrens /* 2011789Sahrens * return text for an ACL error. 2012789Sahrens */ 2013789Sahrens char * 2014789Sahrens acl_strerror(int errnum) 2015789Sahrens { 2016789Sahrens switch (errnum) { 2017789Sahrens case EACL_GRP_ERROR: 2018789Sahrens return (dgettext(TEXT_DOMAIN, 20191420Smarks "There is more than one group or default group entry")); 2020789Sahrens case EACL_USER_ERROR: 2021789Sahrens return (dgettext(TEXT_DOMAIN, 20221420Smarks "There is more than one user or default user entry")); 2023789Sahrens case EACL_OTHER_ERROR: 2024789Sahrens return (dgettext(TEXT_DOMAIN, 2025789Sahrens "There is more than one other entry")); 2026789Sahrens case EACL_CLASS_ERROR: 2027789Sahrens return (dgettext(TEXT_DOMAIN, 2028789Sahrens "There is more than one mask entry")); 2029789Sahrens case EACL_DUPLICATE_ERROR: 2030789Sahrens return (dgettext(TEXT_DOMAIN, 2031789Sahrens "Duplicate user or group entries")); 2032789Sahrens case EACL_MISS_ERROR: 2033789Sahrens return (dgettext(TEXT_DOMAIN, 2034789Sahrens "Missing user/group owner, other, mask entry")); 2035789Sahrens case EACL_MEM_ERROR: 2036789Sahrens return (dgettext(TEXT_DOMAIN, 2037789Sahrens "Memory error")); 2038789Sahrens case EACL_ENTRY_ERROR: 2039789Sahrens return (dgettext(TEXT_DOMAIN, 2040789Sahrens "Unrecognized entry type")); 2041789Sahrens case EACL_INHERIT_ERROR: 2042789Sahrens return (dgettext(TEXT_DOMAIN, 2043789Sahrens "Invalid inheritance flags")); 2044789Sahrens case EACL_FLAGS_ERROR: 2045789Sahrens return (dgettext(TEXT_DOMAIN, 2046789Sahrens "Unrecognized entry flags")); 2047789Sahrens case EACL_PERM_MASK_ERROR: 2048789Sahrens return (dgettext(TEXT_DOMAIN, 2049789Sahrens "Invalid ACL permissions")); 2050789Sahrens case EACL_COUNT_ERROR: 2051789Sahrens return (dgettext(TEXT_DOMAIN, 2052789Sahrens "Invalid ACL count")); 2053789Sahrens case EACL_INVALID_SLOT: 2054789Sahrens return (dgettext(TEXT_DOMAIN, 2055789Sahrens "Invalid ACL entry number specified")); 2056789Sahrens case EACL_NO_ACL_ENTRY: 2057789Sahrens return (dgettext(TEXT_DOMAIN, 2058789Sahrens "ACL entry doesn't exist")); 2059789Sahrens case EACL_DIFF_TYPE: 2060789Sahrens return (dgettext(TEXT_DOMAIN, 2061789Sahrens "ACL type's are different")); 2062789Sahrens case EACL_INVALID_USER_GROUP: 2063789Sahrens return (dgettext(TEXT_DOMAIN, "Invalid user or group")); 2064789Sahrens case EACL_INVALID_STR: 2065789Sahrens return (dgettext(TEXT_DOMAIN, "ACL string is invalid")); 2066789Sahrens case EACL_FIELD_NOT_BLANK: 2067789Sahrens return (dgettext(TEXT_DOMAIN, "Field expected to be blank")); 2068789Sahrens case EACL_INVALID_ACCESS_TYPE: 2069789Sahrens return (dgettext(TEXT_DOMAIN, "Invalid access type")); 2070789Sahrens case EACL_UNKNOWN_DATA: 2071789Sahrens return (dgettext(TEXT_DOMAIN, "Unrecognized entry")); 2072789Sahrens case EACL_MISSING_FIELDS: 2073789Sahrens return (dgettext(TEXT_DOMAIN, 2074789Sahrens "ACL specification missing required fields")); 2075789Sahrens case EACL_INHERIT_NOTDIR: 2076789Sahrens return (dgettext(TEXT_DOMAIN, 2077789Sahrens "Inheritance flags are only allowed on directories")); 2078789Sahrens case -1: 2079789Sahrens return (strerror(errno)); 2080789Sahrens default: 2081789Sahrens errno = EINVAL; 2082789Sahrens return (dgettext(TEXT_DOMAIN, "Unknown error")); 2083789Sahrens } 2084789Sahrens } 20851420Smarks 20861420Smarks extern int yyinteractive; 20871420Smarks 20881420Smarks /* PRINTFLIKE1 */ 20891420Smarks void 20901420Smarks acl_error(const char *fmt, ...) 20911420Smarks { 20921420Smarks va_list va; 20931420Smarks 20941420Smarks if (yyinteractive == 0) 20951420Smarks return; 20961420Smarks 20971420Smarks va_start(va, fmt); 20981420Smarks (void) vfprintf(stderr, fmt, va); 20991420Smarks va_end(va); 21001420Smarks } 2101