1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 5789Sahrens * Common Development and Distribution License, Version 1.0 only 6789Sahrens * (the "License"). You may not use this file except in compliance 7789Sahrens * with the License. 8789Sahrens * 9789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10789Sahrens * or http://www.opensolaris.org/os/licensing. 11789Sahrens * See the License for the specific language governing permissions 12789Sahrens * and limitations under the License. 13789Sahrens * 14789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 15789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16789Sahrens * If applicable, add the following below this CDDL HEADER, with the 17789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 18789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 19789Sahrens * 20789Sahrens * CDDL HEADER END 21789Sahrens */ 22789Sahrens /* 231231Smarks * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24789Sahrens * Use is subject to license terms. 25789Sahrens */ 26789Sahrens 27789Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 28789Sahrens 29789Sahrens #include <stdlib.h> 30789Sahrens #include <string.h> 31789Sahrens #include <unistd.h> 32789Sahrens #include <limits.h> 33789Sahrens #include <grp.h> 34789Sahrens #include <pwd.h> 35789Sahrens #include <sys/types.h> 36789Sahrens #include <sys/acl.h> 37789Sahrens #include <errno.h> 38789Sahrens #include <sys/stat.h> 39*1420Smarks #include <sys/varargs.h> 40789Sahrens #include <locale.h> 41789Sahrens #include <aclutils.h> 42789Sahrens #include <acl_common.h> 43789Sahrens 44789Sahrens #define ACL_PATH 0 45789Sahrens #define ACL_FD 1 46789Sahrens 47789Sahrens #define ACE_POSIX_SUPPORTED_BITS (ACE_READ_DATA | \ 48789Sahrens ACE_WRITE_DATA | ACE_APPEND_DATA | ACE_EXECUTE | \ 49789Sahrens ACE_READ_ATTRIBUTES | ACE_READ_ACL | ACE_WRITE_ACL) 50789Sahrens 51789Sahrens 52789Sahrens #define ACL_SYNCHRONIZE_SET_ALLOW 0x0000002 53789Sahrens #define ACL_SYNCHRONIZE_SET_DENY 0x0000001 54789Sahrens 55789Sahrens #define ACL_WRITE_OWNER_SET_ALLOW 0x0000020 56789Sahrens #define ACL_WRITE_OWNER_SET_DENY 0x0000010 57789Sahrens 58789Sahrens #define ACL_WRITE_ATTRS_OWNER_SET_ALLOW 0x0002000 59789Sahrens #define ACL_WRITE_ATTRS_OWNER_SET_DENY 0x0001000 60789Sahrens 61789Sahrens #define ACL_WRITE_ATTRS_WRITER_SET_DENY 0x0010000 62789Sahrens 63789Sahrens #define ACL_DELETE_SET_ALLOW 0x0000200 64789Sahrens #define ACL_DELETE_SET_DENY 0x0000100 65789Sahrens 66789Sahrens #define ACL_READ_NAMED_READER_SET_ALLOW 0x2000000 67789Sahrens 68789Sahrens #define ACL_WRITE_NAMED_WRITER_SET_ALLOW 0x0200000 69789Sahrens #define ACL_WRITE_NAMED_WRITER_SET_DENY 0x0100000 70789Sahrens 71789Sahrens #define ACL_WRITE_ATTRS_OWNER_SET_ALLOW 0x0002000 72789Sahrens #define ACL_WRITE_ATTRS_WRITER_SET_ALLOW 0x0020000 73789Sahrens 74789Sahrens #define ACL_WRITE_OWNER_ERR_DENY 0x0000040 75789Sahrens #define ACL_READ_NAMED_READER_SET_DENY 0x1000000 761231Smarks 77789Sahrens typedef union { 78789Sahrens const char *file; 79789Sahrens int fd; 80789Sahrens } acl_inp; 81789Sahrens 82789Sahrens acl_t * 83789Sahrens acl_alloc(enum acl_type type) 84789Sahrens { 85789Sahrens acl_t *aclp; 86789Sahrens 87789Sahrens aclp = malloc(sizeof (acl_t)); 88789Sahrens 89789Sahrens if (aclp == NULL) 90789Sahrens return (NULL); 91789Sahrens 92789Sahrens aclp->acl_aclp = NULL; 93789Sahrens aclp->acl_cnt = 0; 94789Sahrens 95789Sahrens switch (type) { 96789Sahrens case ACE_T: 97789Sahrens aclp->acl_type = ACE_T; 98789Sahrens aclp->acl_entry_size = sizeof (ace_t); 99789Sahrens break; 100789Sahrens case ACLENT_T: 101789Sahrens aclp->acl_type = ACLENT_T; 102789Sahrens aclp->acl_entry_size = sizeof (aclent_t); 103789Sahrens break; 104789Sahrens default: 105789Sahrens acl_free(aclp); 106789Sahrens aclp = NULL; 107789Sahrens } 108789Sahrens return (aclp); 109789Sahrens } 110789Sahrens 111789Sahrens /* 112789Sahrens * Free acl_t structure 113789Sahrens */ 114789Sahrens void 115789Sahrens acl_free(acl_t *aclp) 116789Sahrens { 117789Sahrens if (aclp == NULL) 118789Sahrens return; 119789Sahrens 120789Sahrens if (aclp->acl_aclp) 121789Sahrens free(aclp->acl_aclp); 122789Sahrens free(aclp); 123789Sahrens } 124789Sahrens 125789Sahrens /* 126789Sahrens * Determine whether a file has a trivial ACL 127789Sahrens * returns: 0 = trivial 128789Sahrens * 1 = nontrivial 129789Sahrens * <0 some other system failure, such as ENOENT or EPERM 130789Sahrens */ 131789Sahrens int 132789Sahrens acl_trivial(const char *filename) 133789Sahrens { 134789Sahrens int acl_flavor; 135789Sahrens int aclcnt; 136789Sahrens int cntcmd; 137789Sahrens int val = 0; 138789Sahrens ace_t *acep; 139789Sahrens 140789Sahrens acl_flavor = pathconf(filename, _PC_ACL_ENABLED); 141789Sahrens if (acl_flavor == -1) 142789Sahrens return (-1); 143789Sahrens 144789Sahrens if (acl_flavor == _ACL_ACE_ENABLED) 145789Sahrens cntcmd = ACE_GETACLCNT; 146789Sahrens else 147789Sahrens cntcmd = GETACLCNT; 148789Sahrens 149789Sahrens aclcnt = acl(filename, cntcmd, 0, NULL); 150789Sahrens if (aclcnt > 0) { 151789Sahrens if (acl_flavor == _ACL_ACE_ENABLED) { 1521231Smarks acep = malloc(sizeof (ace_t) * aclcnt); 1531231Smarks if (acep == NULL) 1541231Smarks return (-1); 1551231Smarks if (acl(filename, ACE_GETACL, 1561231Smarks aclcnt, acep) < 0) { 1571231Smarks free(acep); 1581231Smarks return (-1); 1591231Smarks } 160789Sahrens 1611231Smarks val = ace_trivial(acep, aclcnt); 1621231Smarks free(acep); 1631231Smarks 164789Sahrens } else if (aclcnt > MIN_ACL_ENTRIES) 165789Sahrens val = 1; 166789Sahrens } 167789Sahrens return (val); 168789Sahrens } 169789Sahrens 170789Sahrens static uint32_t 171789Sahrens access_mask_set(int haswriteperm, int hasreadperm, int isowner, int isallow) 172789Sahrens { 173789Sahrens uint32_t access_mask = 0; 174789Sahrens int acl_produce; 175789Sahrens int synchronize_set = 0, write_owner_set = 0; 176789Sahrens int delete_set = 0, write_attrs_set = 0; 177789Sahrens int read_named_set = 0, write_named_set = 0; 178789Sahrens 179789Sahrens acl_produce = (ACL_SYNCHRONIZE_SET_ALLOW | 180789Sahrens ACL_WRITE_ATTRS_OWNER_SET_ALLOW | 181789Sahrens ACL_WRITE_ATTRS_WRITER_SET_DENY); 182789Sahrens 183789Sahrens if (isallow) { 184789Sahrens synchronize_set = ACL_SYNCHRONIZE_SET_ALLOW; 185789Sahrens write_owner_set = ACL_WRITE_OWNER_SET_ALLOW; 186789Sahrens delete_set = ACL_DELETE_SET_ALLOW; 187789Sahrens if (hasreadperm) 188789Sahrens read_named_set = ACL_READ_NAMED_READER_SET_ALLOW; 189789Sahrens if (haswriteperm) 190789Sahrens write_named_set = ACL_WRITE_NAMED_WRITER_SET_ALLOW; 191789Sahrens if (isowner) 192789Sahrens write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_ALLOW; 193789Sahrens else if (haswriteperm) 194789Sahrens write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_ALLOW; 195789Sahrens } else { 196789Sahrens 197789Sahrens synchronize_set = ACL_SYNCHRONIZE_SET_DENY; 198789Sahrens write_owner_set = ACL_WRITE_OWNER_SET_DENY; 199789Sahrens delete_set = ACL_DELETE_SET_DENY; 200789Sahrens if (hasreadperm) 201789Sahrens read_named_set = ACL_READ_NAMED_READER_SET_DENY; 202789Sahrens if (haswriteperm) 203789Sahrens write_named_set = ACL_WRITE_NAMED_WRITER_SET_DENY; 204789Sahrens if (isowner) 205789Sahrens write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_DENY; 206789Sahrens else if (haswriteperm) 207789Sahrens write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_DENY; 208789Sahrens else 209789Sahrens /* 210789Sahrens * If the entity is not the owner and does not 211789Sahrens * have write permissions ACE_WRITE_ATTRIBUTES will 212789Sahrens * always go in the DENY ACE. 213789Sahrens */ 214789Sahrens access_mask |= ACE_WRITE_ATTRIBUTES; 215789Sahrens } 216789Sahrens 217789Sahrens if (acl_produce & synchronize_set) 218789Sahrens access_mask |= ACE_SYNCHRONIZE; 219789Sahrens if (acl_produce & write_owner_set) 220789Sahrens access_mask |= ACE_WRITE_OWNER; 221789Sahrens if (acl_produce & delete_set) 222789Sahrens access_mask |= ACE_DELETE; 223789Sahrens if (acl_produce & write_attrs_set) 224789Sahrens access_mask |= ACE_WRITE_ATTRIBUTES; 225789Sahrens if (acl_produce & read_named_set) 226789Sahrens access_mask |= ACE_READ_NAMED_ATTRS; 227789Sahrens if (acl_produce & write_named_set) 228789Sahrens access_mask |= ACE_WRITE_NAMED_ATTRS; 229789Sahrens 230789Sahrens return (access_mask); 231789Sahrens } 232789Sahrens 233789Sahrens /* 234789Sahrens * Given an mode_t, convert it into an access_mask as used 235789Sahrens * by nfsace, assuming aclent_t -> nfsace semantics. 236789Sahrens */ 237789Sahrens static uint32_t 238789Sahrens mode_to_ace_access(mode_t mode, int isdir, int isowner, int isallow) 239789Sahrens { 240789Sahrens uint32_t access = 0; 241789Sahrens int haswriteperm = 0; 242789Sahrens int hasreadperm = 0; 243789Sahrens 244789Sahrens if (isallow) { 245789Sahrens haswriteperm = (mode & 02); 246789Sahrens hasreadperm = (mode & 04); 247789Sahrens } else { 248789Sahrens haswriteperm = !(mode & 02); 249789Sahrens hasreadperm = !(mode & 04); 250789Sahrens } 251789Sahrens 252789Sahrens /* 253789Sahrens * The following call takes care of correctly setting the following 254789Sahrens * mask bits in the access_mask: 255789Sahrens * ACE_SYNCHRONIZE, ACE_WRITE_OWNER, ACE_DELETE, 256789Sahrens * ACE_WRITE_ATTRIBUTES, ACE_WRITE_NAMED_ATTRS, ACE_READ_NAMED_ATTRS 257789Sahrens */ 258789Sahrens access = access_mask_set(haswriteperm, hasreadperm, isowner, isallow); 259789Sahrens 260789Sahrens if (isallow) { 261789Sahrens access |= ACE_READ_ACL | ACE_READ_ATTRIBUTES; 262789Sahrens if (isowner) 263789Sahrens access |= ACE_WRITE_ACL; 264789Sahrens } else { 265789Sahrens if (! isowner) 266789Sahrens access |= ACE_WRITE_ACL; 267789Sahrens } 268789Sahrens 269789Sahrens /* read */ 270789Sahrens if (mode & 04) { 271789Sahrens access |= ACE_READ_DATA; 272789Sahrens } 273789Sahrens /* write */ 274789Sahrens if (mode & 02) { 275789Sahrens access |= ACE_WRITE_DATA | 276789Sahrens ACE_APPEND_DATA; 277789Sahrens if (isdir) 278789Sahrens access |= ACE_DELETE_CHILD; 279789Sahrens } 280789Sahrens /* exec */ 281789Sahrens if (mode & 01) { 282789Sahrens access |= ACE_EXECUTE; 283789Sahrens } 284789Sahrens 285789Sahrens return (access); 286789Sahrens } 287789Sahrens 288789Sahrens /* 289789Sahrens * Given an nfsace (presumably an ALLOW entry), make a 290789Sahrens * corresponding DENY entry at the address given. 291789Sahrens */ 292789Sahrens static void 293789Sahrens ace_make_deny(ace_t *allow, ace_t *deny, int isdir, int isowner) 294789Sahrens { 295789Sahrens (void) memcpy(deny, allow, sizeof (ace_t)); 296789Sahrens 297789Sahrens deny->a_who = allow->a_who; 298789Sahrens 299789Sahrens deny->a_type = ACE_ACCESS_DENIED_ACE_TYPE; 300789Sahrens deny->a_access_mask ^= ACE_POSIX_SUPPORTED_BITS; 301789Sahrens if (isdir) 302789Sahrens deny->a_access_mask ^= ACE_DELETE_CHILD; 303789Sahrens 304789Sahrens deny->a_access_mask &= ~(ACE_SYNCHRONIZE | ACE_WRITE_OWNER | 305789Sahrens ACE_DELETE | ACE_WRITE_ATTRIBUTES | ACE_READ_NAMED_ATTRS | 306789Sahrens ACE_WRITE_NAMED_ATTRS); 307789Sahrens deny->a_access_mask |= access_mask_set((allow->a_access_mask & 308789Sahrens ACE_WRITE_DATA), (allow->a_access_mask & ACE_READ_DATA), isowner, 309789Sahrens B_FALSE); 310789Sahrens } 311789Sahrens /* 312789Sahrens * Make an initial pass over an array of aclent_t's. Gather 313789Sahrens * information such as an ACL_MASK (if any), number of users, 314789Sahrens * number of groups, and whether the array needs to be sorted. 315789Sahrens */ 316789Sahrens static int 317789Sahrens ln_aent_preprocess(aclent_t *aclent, int n, 318789Sahrens int *hasmask, mode_t *mask, 319789Sahrens int *numuser, int *numgroup, int *needsort) 320789Sahrens { 321789Sahrens int error = 0; 322789Sahrens int i; 323789Sahrens int curtype = 0; 324789Sahrens 325789Sahrens *hasmask = 0; 326789Sahrens *mask = 07; 327789Sahrens *needsort = 0; 328789Sahrens *numuser = 0; 329789Sahrens *numgroup = 0; 330789Sahrens 331789Sahrens for (i = 0; i < n; i++) { 332789Sahrens if (aclent[i].a_type < curtype) 333789Sahrens *needsort = 1; 334789Sahrens else if (aclent[i].a_type > curtype) 335789Sahrens curtype = aclent[i].a_type; 336789Sahrens if (aclent[i].a_type & USER) 337789Sahrens (*numuser)++; 338789Sahrens if (aclent[i].a_type & (GROUP | GROUP_OBJ)) 339789Sahrens (*numgroup)++; 340789Sahrens if (aclent[i].a_type & CLASS_OBJ) { 341789Sahrens if (*hasmask) { 342789Sahrens error = EINVAL; 343789Sahrens goto out; 344789Sahrens } else { 345789Sahrens *hasmask = 1; 346789Sahrens *mask = aclent[i].a_perm; 347789Sahrens } 348789Sahrens } 349789Sahrens } 350789Sahrens 351789Sahrens if ((! *hasmask) && (*numuser + *numgroup > 1)) { 352789Sahrens error = EINVAL; 353789Sahrens goto out; 354789Sahrens } 355789Sahrens 356789Sahrens out: 357789Sahrens return (error); 358789Sahrens } 359789Sahrens 360789Sahrens /* 361789Sahrens * Convert an array of aclent_t into an array of nfsace entries, 362789Sahrens * following POSIX draft -> nfsv4 conversion semantics as outlined in 363789Sahrens * the IETF draft. 364789Sahrens */ 365789Sahrens static int 366789Sahrens ln_aent_to_ace(aclent_t *aclent, int n, ace_t **acepp, int *rescount, int isdir) 367789Sahrens { 368789Sahrens int error = 0; 369789Sahrens mode_t mask; 370789Sahrens int numuser, numgroup, needsort; 371789Sahrens int resultsize = 0; 372789Sahrens int i, groupi = 0, skip; 373789Sahrens ace_t *acep, *result = NULL; 374789Sahrens int hasmask; 375789Sahrens 376789Sahrens error = ln_aent_preprocess(aclent, n, &hasmask, &mask, 377789Sahrens &numuser, &numgroup, &needsort); 378789Sahrens if (error != 0) 379789Sahrens goto out; 380789Sahrens 381789Sahrens /* allow + deny for each aclent */ 382789Sahrens resultsize = n * 2; 383789Sahrens if (hasmask) { 384789Sahrens /* 385789Sahrens * stick extra deny on the group_obj and on each 386789Sahrens * user|group for the mask (the group_obj was added 387789Sahrens * into the count for numgroup) 388789Sahrens */ 389789Sahrens resultsize += numuser + numgroup; 390789Sahrens /* ... and don't count the mask itself */ 391789Sahrens resultsize -= 2; 392789Sahrens } 393789Sahrens 394789Sahrens /* sort the source if necessary */ 395789Sahrens if (needsort) 396789Sahrens ksort((caddr_t)aclent, n, sizeof (aclent_t), cmp2acls); 397789Sahrens 398789Sahrens result = acep = calloc(1, resultsize * sizeof (ace_t)); 399789Sahrens if (result == NULL) 400789Sahrens goto out; 401789Sahrens 402789Sahrens for (i = 0; i < n; i++) { 403789Sahrens /* 404789Sahrens * don't process CLASS_OBJ (mask); mask was grabbed in 405789Sahrens * ln_aent_preprocess() 406789Sahrens */ 407789Sahrens if (aclent[i].a_type & CLASS_OBJ) 408789Sahrens continue; 409789Sahrens 410789Sahrens /* If we need an ACL_MASK emulator, prepend it now */ 411789Sahrens if ((hasmask) && 412789Sahrens (aclent[i].a_type & (USER | GROUP | GROUP_OBJ))) { 413789Sahrens acep->a_type = ACE_ACCESS_DENIED_ACE_TYPE; 414789Sahrens acep->a_flags = 0; 415789Sahrens if (aclent[i].a_type & GROUP_OBJ) { 416789Sahrens acep->a_who = -1; 417789Sahrens acep->a_flags |= 418789Sahrens (ACE_IDENTIFIER_GROUP|ACE_GROUP); 419789Sahrens } else if (aclent[i].a_type & USER) { 420789Sahrens acep->a_who = aclent[i].a_id; 421789Sahrens } else { 422789Sahrens acep->a_who = aclent[i].a_id; 423789Sahrens acep->a_flags |= ACE_IDENTIFIER_GROUP; 424789Sahrens } 425789Sahrens if (aclent[i].a_type & ACL_DEFAULT) { 426789Sahrens acep->a_flags |= ACE_INHERIT_ONLY_ACE | 427789Sahrens ACE_FILE_INHERIT_ACE | 428789Sahrens ACE_DIRECTORY_INHERIT_ACE; 429789Sahrens } 430789Sahrens /* 431789Sahrens * Set the access mask for the prepended deny 432789Sahrens * ace. To do this, we invert the mask (found 433789Sahrens * in ln_aent_preprocess()) then convert it to an 434789Sahrens * DENY ace access_mask. 435789Sahrens */ 436789Sahrens acep->a_access_mask = mode_to_ace_access((mask ^ 07), 437789Sahrens isdir, 0, 0); 438789Sahrens acep += 1; 439789Sahrens } 440789Sahrens 441789Sahrens /* handle a_perm -> access_mask */ 442789Sahrens acep->a_access_mask = mode_to_ace_access(aclent[i].a_perm, 443789Sahrens isdir, aclent[i].a_type & USER_OBJ, 1); 444789Sahrens 445789Sahrens /* emulate a default aclent */ 446789Sahrens if (aclent[i].a_type & ACL_DEFAULT) { 447789Sahrens acep->a_flags |= ACE_INHERIT_ONLY_ACE | 448789Sahrens ACE_FILE_INHERIT_ACE | 449789Sahrens ACE_DIRECTORY_INHERIT_ACE; 450789Sahrens } 451789Sahrens 452789Sahrens /* 453789Sahrens * handle a_perm and a_id 454789Sahrens * 455789Sahrens * this must be done last, since it involves the 456789Sahrens * corresponding deny aces, which are handled 457789Sahrens * differently for each different a_type. 458789Sahrens */ 459789Sahrens if (aclent[i].a_type & USER_OBJ) { 460789Sahrens acep->a_who = -1; 461789Sahrens acep->a_flags |= ACE_OWNER; 462789Sahrens ace_make_deny(acep, acep + 1, isdir, B_TRUE); 463789Sahrens acep += 2; 464789Sahrens } else if (aclent[i].a_type & USER) { 465789Sahrens acep->a_who = aclent[i].a_id; 466789Sahrens ace_make_deny(acep, acep + 1, isdir, B_FALSE); 467789Sahrens acep += 2; 468789Sahrens } else if (aclent[i].a_type & (GROUP_OBJ | GROUP)) { 469789Sahrens if (aclent[i].a_type & GROUP_OBJ) { 470789Sahrens acep->a_who = -1; 471789Sahrens acep->a_flags |= ACE_GROUP; 472789Sahrens } else { 473789Sahrens acep->a_who = aclent[i].a_id; 474789Sahrens } 475789Sahrens acep->a_flags |= ACE_IDENTIFIER_GROUP; 476789Sahrens /* 477789Sahrens * Set the corresponding deny for the group ace. 478789Sahrens * 479789Sahrens * The deny aces go after all of the groups, unlike 480789Sahrens * everything else, where they immediately follow 481789Sahrens * the allow ace. 482789Sahrens * 483789Sahrens * We calculate "skip", the number of slots to 484789Sahrens * skip ahead for the deny ace, here. 485789Sahrens * 486789Sahrens * The pattern is: 487789Sahrens * MD1 A1 MD2 A2 MD3 A3 D1 D2 D3 488789Sahrens * thus, skip is 489789Sahrens * (2 * numgroup) - 1 - groupi 490789Sahrens * (2 * numgroup) to account for MD + A 491789Sahrens * - 1 to account for the fact that we're on the 492789Sahrens * access (A), not the mask (MD) 493789Sahrens * - groupi to account for the fact that we have 494789Sahrens * passed up groupi number of MD's. 495789Sahrens */ 496789Sahrens skip = (2 * numgroup) - 1 - groupi; 497789Sahrens ace_make_deny(acep, acep + skip, isdir, B_FALSE); 498789Sahrens /* 499789Sahrens * If we just did the last group, skip acep past 500789Sahrens * all of the denies; else, just move ahead one. 501789Sahrens */ 502789Sahrens if (++groupi >= numgroup) 503789Sahrens acep += numgroup + 1; 504789Sahrens else 505789Sahrens acep += 1; 506789Sahrens } else if (aclent[i].a_type & OTHER_OBJ) { 507789Sahrens acep->a_who = -1; 508789Sahrens acep->a_flags |= ACE_EVERYONE; 509789Sahrens ace_make_deny(acep, acep + 1, isdir, B_FALSE); 510789Sahrens acep += 2; 511789Sahrens } else { 512789Sahrens error = EINVAL; 513789Sahrens goto out; 514789Sahrens } 515789Sahrens } 516789Sahrens 517789Sahrens *acepp = result; 518789Sahrens *rescount = resultsize; 519789Sahrens 520789Sahrens out: 521789Sahrens if (error != 0) { 522789Sahrens if ((result != NULL) && (resultsize > 0)) { 523789Sahrens free(result); 524789Sahrens } 525789Sahrens } 526789Sahrens 527789Sahrens return (error); 528789Sahrens } 529789Sahrens 530789Sahrens static int 531789Sahrens convert_aent_to_ace(aclent_t *aclentp, int aclcnt, int isdir, 532789Sahrens ace_t **retacep, int *retacecnt) 533789Sahrens { 534789Sahrens ace_t *acep; 535789Sahrens ace_t *dfacep; 536789Sahrens ace_t *newacep; 537789Sahrens int acecnt = 0; 538789Sahrens int dfacecnt = 0; 539789Sahrens int dfaclstart = 0; 540789Sahrens int dfaclcnt = 0; 541789Sahrens aclent_t *aclp; 542789Sahrens int i; 543789Sahrens int error; 544789Sahrens 545789Sahrens ksort((caddr_t)aclentp, aclcnt, sizeof (aclent_t), cmp2acls); 546789Sahrens 547789Sahrens for (i = 0, aclp = aclentp; i < aclcnt; aclp++, i++) { 548789Sahrens if (aclp->a_type & ACL_DEFAULT) 549789Sahrens break; 550789Sahrens } 551789Sahrens 552789Sahrens if (i < aclcnt) { 553789Sahrens dfaclstart = aclcnt - i; 554789Sahrens dfaclcnt = i; 555789Sahrens } 556789Sahrens 557789Sahrens if (dfaclcnt && isdir == 0) { 558789Sahrens return (-1); 559789Sahrens } 560789Sahrens 561789Sahrens error = ln_aent_to_ace(aclentp, i, &acep, &acecnt, isdir); 562789Sahrens if (error) 563789Sahrens return (-1); 564789Sahrens 565789Sahrens if (dfaclcnt) { 566789Sahrens error = ln_aent_to_ace(&aclentp[dfaclstart], dfaclcnt, 567789Sahrens &dfacep, &dfacecnt, isdir); 568789Sahrens if (error) { 569789Sahrens if (acep) { 570789Sahrens free(acep); 571789Sahrens } 572789Sahrens return (-1); 573789Sahrens } 574789Sahrens } 575789Sahrens 576789Sahrens newacep = malloc(sizeof (ace_t) * (acecnt + dfacecnt)); 577789Sahrens if (newacep == NULL) 578789Sahrens return (-1); 579789Sahrens 580789Sahrens (void) memcpy(newacep, acep, sizeof (ace_t) * acecnt); 581789Sahrens if (dfaclcnt) { 582789Sahrens (void) memcpy(newacep + acecnt, dfacep, 583789Sahrens sizeof (ace_t) * dfacecnt); 584789Sahrens } 585789Sahrens free(acep); 586789Sahrens if (dfaclcnt) 587789Sahrens free(dfacep); 588789Sahrens 589789Sahrens *retacecnt = acecnt + dfacecnt; 590789Sahrens *retacep = newacep; 591789Sahrens return (0); 592789Sahrens } 593789Sahrens 594789Sahrens 595789Sahrens static int 596789Sahrens cacl_get(acl_inp inp, int get_flag, int type, acl_t **aclp) 597789Sahrens { 598789Sahrens const char *fname; 599789Sahrens int fd; 600789Sahrens int ace_acl = 0; 601789Sahrens int error; 602789Sahrens int getcmd, cntcmd; 603789Sahrens acl_t *acl_info; 604789Sahrens int save_errno; 605789Sahrens int stat_error; 606789Sahrens struct stat64 statbuf; 607789Sahrens 608789Sahrens *aclp = NULL; 609789Sahrens if (type == ACL_PATH) { 610789Sahrens fname = inp.file; 611789Sahrens ace_acl = pathconf(fname, _PC_ACL_ENABLED); 612789Sahrens } else { 613789Sahrens fd = inp.fd; 614789Sahrens ace_acl = fpathconf(fd, _PC_ACL_ENABLED); 615789Sahrens } 616789Sahrens 617789Sahrens if (ace_acl == -1) 618789Sahrens return (-1); 619789Sahrens 620789Sahrens /* 621789Sahrens * if acl's aren't supported then 622789Sahrens * send it through the old GETACL interface 623789Sahrens */ 624789Sahrens if (ace_acl == 0) { 625789Sahrens ace_acl = _ACL_ACLENT_ENABLED; 626789Sahrens } 627789Sahrens 628789Sahrens if (ace_acl & _ACL_ACE_ENABLED) { 629789Sahrens cntcmd = ACE_GETACLCNT; 630789Sahrens getcmd = ACE_GETACL; 631789Sahrens acl_info = acl_alloc(ACE_T); 632789Sahrens } else { 633789Sahrens cntcmd = GETACLCNT; 634789Sahrens getcmd = GETACL; 635789Sahrens acl_info = acl_alloc(ACLENT_T); 636789Sahrens } 637789Sahrens 638789Sahrens if (acl_info == NULL) 639789Sahrens return (-1); 640789Sahrens 641789Sahrens if (type == ACL_PATH) { 642789Sahrens acl_info->acl_cnt = acl(fname, cntcmd, 0, NULL); 643789Sahrens } else { 644789Sahrens acl_info->acl_cnt = facl(fd, cntcmd, 0, NULL); 645789Sahrens } 646789Sahrens 647789Sahrens save_errno = errno; 648789Sahrens if (acl_info->acl_cnt < 0) { 649789Sahrens acl_free(acl_info); 650789Sahrens errno = save_errno; 651789Sahrens return (-1); 652789Sahrens } 653789Sahrens 654789Sahrens if (acl_info->acl_cnt == 0) { 655789Sahrens acl_free(acl_info); 656789Sahrens errno = save_errno; 657789Sahrens return (0); 658789Sahrens } 659789Sahrens 660789Sahrens acl_info->acl_aclp = 661789Sahrens malloc(acl_info->acl_cnt * acl_info->acl_entry_size); 662789Sahrens save_errno = errno; 663789Sahrens 664789Sahrens if (acl_info->acl_aclp == NULL) { 665789Sahrens acl_free(acl_info); 666789Sahrens errno = save_errno; 667789Sahrens return (-1); 668789Sahrens } 669789Sahrens 670789Sahrens if (type == ACL_PATH) { 671789Sahrens stat_error = stat64(fname, &statbuf); 672789Sahrens error = acl(fname, getcmd, acl_info->acl_cnt, 673789Sahrens acl_info->acl_aclp); 674789Sahrens } else { 675789Sahrens stat_error = fstat64(fd, &statbuf); 676789Sahrens error = facl(fd, getcmd, acl_info->acl_cnt, 677789Sahrens acl_info->acl_aclp); 678789Sahrens } 679789Sahrens 680789Sahrens save_errno = errno; 681789Sahrens if (error == -1) { 682789Sahrens acl_free(acl_info); 683789Sahrens errno = save_errno; 684789Sahrens return (-1); 685789Sahrens } 686789Sahrens 687789Sahrens 688789Sahrens if (stat_error == 0) { 689789Sahrens acl_info->acl_flags = 690789Sahrens (S_ISDIR(statbuf.st_mode) ? ACL_IS_DIR : 0); 691789Sahrens } else 692789Sahrens acl_info->acl_flags = 0; 693789Sahrens 694789Sahrens switch (acl_info->acl_type) { 695789Sahrens case ACLENT_T: 696789Sahrens if (acl_info->acl_cnt <= MIN_ACL_ENTRIES) 697789Sahrens acl_info->acl_flags |= ACL_IS_TRIVIAL; 698789Sahrens break; 699789Sahrens case ACE_T: 700789Sahrens if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0) 701789Sahrens acl_info->acl_flags |= ACL_IS_TRIVIAL; 702789Sahrens break; 703789Sahrens default: 704789Sahrens errno = EINVAL; 705789Sahrens acl_free(acl_info); 706789Sahrens return (-1); 707789Sahrens } 708789Sahrens 709789Sahrens if ((acl_info->acl_flags & ACL_IS_TRIVIAL) && 710789Sahrens (get_flag & ACL_NO_TRIVIAL)) { 711789Sahrens acl_free(acl_info); 712789Sahrens errno = 0; 713789Sahrens return (0); 714789Sahrens } 715789Sahrens 716789Sahrens *aclp = acl_info; 717789Sahrens return (0); 718789Sahrens } 719789Sahrens 720789Sahrens /* 721789Sahrens * return -1 on failure, otherwise the number of acl 722789Sahrens * entries is returned 723789Sahrens */ 724789Sahrens int 725789Sahrens acl_get(const char *path, int get_flag, acl_t **aclp) 726789Sahrens { 727789Sahrens acl_inp acl_inp; 728789Sahrens acl_inp.file = path; 729789Sahrens 730789Sahrens return (cacl_get(acl_inp, get_flag, ACL_PATH, aclp)); 731789Sahrens } 732789Sahrens 733789Sahrens int 734789Sahrens facl_get(int fd, int get_flag, acl_t **aclp) 735789Sahrens { 736789Sahrens 737789Sahrens acl_inp acl_inp; 738789Sahrens acl_inp.fd = fd; 739789Sahrens 740789Sahrens return (cacl_get(acl_inp, get_flag, ACL_FD, aclp)); 741789Sahrens } 742789Sahrens 743789Sahrens /* 744789Sahrens * Set an ACL, translates acl to ace_t when appropriate. 745789Sahrens */ 746789Sahrens static int 747789Sahrens cacl_set(acl_inp *acl_inp, acl_t *aclp, int type) 748789Sahrens { 749789Sahrens int error = 0; 750789Sahrens int acl_flavor_target; 751789Sahrens ace_t *acep = NULL; 752789Sahrens int acecnt; 753789Sahrens struct stat64 statbuf; 754789Sahrens int stat_error; 755789Sahrens int isdir; 756789Sahrens 757789Sahrens 758789Sahrens if (type == ACL_PATH) { 759789Sahrens stat_error = stat64(acl_inp->file, &statbuf); 760789Sahrens if (stat_error) 761789Sahrens return (-1); 762789Sahrens acl_flavor_target = pathconf(acl_inp->file, _PC_ACL_ENABLED); 763789Sahrens } else { 764789Sahrens stat_error = fstat64(acl_inp->fd, &statbuf); 765789Sahrens if (stat_error) 766789Sahrens return (-1); 767789Sahrens acl_flavor_target = fpathconf(acl_inp->fd, _PC_ACL_ENABLED); 768789Sahrens } 769789Sahrens 770789Sahrens isdir = S_ISDIR(statbuf.st_mode); 771789Sahrens 772789Sahrens if (acl_flavor_target == -1) 773789Sahrens return (-1); 774789Sahrens 775789Sahrens /* 776789Sahrens * Translate aclent_t ACL's to ACE ACL's. 777789Sahrens */ 778789Sahrens if (acl_flavor_target == _ACL_ACE_ENABLED && 779789Sahrens aclp->acl_type == ACLENT_T) { 780789Sahrens error = convert_aent_to_ace(aclp->acl_aclp, 781789Sahrens aclp->acl_cnt, isdir, &acep, &acecnt); 782789Sahrens if (error) { 783789Sahrens errno = ENOTSUP; 784789Sahrens return (-1); 785789Sahrens } 786789Sahrens /* 787789Sahrens * replace old acl with newly translated acl 788789Sahrens */ 789789Sahrens free(aclp->acl_aclp); 790789Sahrens aclp->acl_aclp = acep; 791789Sahrens aclp->acl_cnt = acecnt; 792789Sahrens aclp->acl_type = ACE_T; 793789Sahrens } 794789Sahrens 795789Sahrens if (type == ACL_PATH) { 796789Sahrens error = acl(acl_inp->file, 797789Sahrens (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, 798789Sahrens aclp->acl_cnt, aclp->acl_aclp); 799789Sahrens } else { 800789Sahrens error = facl(acl_inp->fd, 801789Sahrens (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, 802789Sahrens aclp->acl_cnt, aclp->acl_aclp); 803789Sahrens } 804789Sahrens 805789Sahrens return (error); 806789Sahrens } 807789Sahrens 808789Sahrens int 809789Sahrens acl_set(const char *path, acl_t *aclp) 810789Sahrens { 811789Sahrens acl_inp acl_inp; 812789Sahrens 813789Sahrens acl_inp.file = path; 814789Sahrens 815789Sahrens return (cacl_set(&acl_inp, aclp, ACL_PATH)); 816789Sahrens } 817789Sahrens 818789Sahrens int 819789Sahrens facl_set(int fd, acl_t *aclp) 820789Sahrens { 821789Sahrens acl_inp acl_inp; 822789Sahrens 823789Sahrens acl_inp.fd = fd; 824789Sahrens 825789Sahrens return (cacl_set(&acl_inp, aclp, ACL_FD)); 826789Sahrens } 827789Sahrens 828789Sahrens int 829789Sahrens acl_cnt(acl_t *aclp) 830789Sahrens { 831789Sahrens return (aclp->acl_cnt); 832789Sahrens } 833789Sahrens 834789Sahrens int 835789Sahrens acl_type(acl_t *aclp) 836789Sahrens { 837789Sahrens return (aclp->acl_type); 838789Sahrens } 839789Sahrens 840789Sahrens acl_t * 841789Sahrens acl_dup(acl_t *aclp) 842789Sahrens { 843789Sahrens acl_t *newaclp; 844789Sahrens 845789Sahrens newaclp = acl_alloc(aclp->acl_type); 846789Sahrens if (newaclp == NULL) 847789Sahrens return (NULL); 848789Sahrens 849789Sahrens newaclp->acl_aclp = malloc(aclp->acl_entry_size * aclp->acl_cnt); 850789Sahrens if (newaclp->acl_aclp == NULL) { 851789Sahrens acl_free(newaclp); 852789Sahrens return (NULL); 853789Sahrens } 854789Sahrens 855789Sahrens (void) memcpy(newaclp->acl_aclp, 856789Sahrens aclp->acl_aclp, aclp->acl_entry_size * aclp->acl_cnt); 857789Sahrens newaclp->acl_cnt = aclp->acl_cnt; 858789Sahrens 859789Sahrens return (newaclp); 860789Sahrens } 861789Sahrens 862789Sahrens int 863789Sahrens acl_flags(acl_t *aclp) 864789Sahrens { 865789Sahrens return (aclp->acl_flags); 866789Sahrens } 867789Sahrens 868789Sahrens void * 869789Sahrens acl_data(acl_t *aclp) 870789Sahrens { 871789Sahrens return (aclp->acl_aclp); 872789Sahrens } 873789Sahrens 874789Sahrens /* 875789Sahrens * Remove an ACL from a file and create a trivial ACL based 876789Sahrens * off of the mode argument. After acl has been set owner/group 877789Sahrens * are updated to match owner,group arguments 878789Sahrens */ 879789Sahrens int 880789Sahrens acl_strip(const char *file, uid_t owner, gid_t group, mode_t mode) 881789Sahrens { 882789Sahrens int error = 0; 883789Sahrens aclent_t min_acl[MIN_ACL_ENTRIES]; 884789Sahrens ace_t min_ace_acl[6]; /* owner, group, everyone + complement denies */ 885789Sahrens int acl_flavor; 886789Sahrens int aclcnt; 887789Sahrens 888789Sahrens acl_flavor = pathconf(file, _PC_ACL_ENABLED); 889789Sahrens 890789Sahrens if (acl_flavor == -1) 891789Sahrens return (-1); 892789Sahrens /* 893789Sahrens * force it through aclent flavor when file system doesn't 894789Sahrens * understand question 895789Sahrens */ 896789Sahrens if (acl_flavor == 0) 897789Sahrens acl_flavor = _ACL_ACLENT_ENABLED; 898789Sahrens 899789Sahrens if (acl_flavor & _ACL_ACLENT_ENABLED) { 900789Sahrens min_acl[0].a_type = USER_OBJ; 901789Sahrens min_acl[0].a_id = owner; 902789Sahrens min_acl[0].a_perm = ((mode & 0700) >> 6); 903789Sahrens min_acl[1].a_type = GROUP_OBJ; 904789Sahrens min_acl[1].a_id = group; 905789Sahrens min_acl[1].a_perm = ((mode & 0070) >> 3); 906789Sahrens min_acl[2].a_type = CLASS_OBJ; 907789Sahrens min_acl[2].a_id = (uid_t)-1; 908789Sahrens min_acl[2].a_perm = ((mode & 0070) >> 3); 909789Sahrens min_acl[3].a_type = OTHER_OBJ; 910789Sahrens min_acl[3].a_id = (uid_t)-1; 911789Sahrens min_acl[3].a_perm = (mode & 0007); 912789Sahrens aclcnt = 4; 913789Sahrens error = acl(file, SETACL, aclcnt, min_acl); 914789Sahrens } else if (acl_flavor & _ACL_ACE_ENABLED) { 915789Sahrens (void) memcpy(min_ace_acl, trivial_acl, sizeof (ace_t) * 6); 916789Sahrens 917789Sahrens /* 918789Sahrens * Make aces match request mode 919789Sahrens */ 920789Sahrens adjust_ace_pair(&min_ace_acl[0], (mode & 0700) >> 6); 921789Sahrens adjust_ace_pair(&min_ace_acl[2], (mode & 0070) >> 3); 922789Sahrens adjust_ace_pair(&min_ace_acl[4], mode & 0007); 923789Sahrens 924789Sahrens error = acl(file, ACE_SETACL, 6, min_ace_acl); 925789Sahrens } else { 926789Sahrens errno = EINVAL; 927789Sahrens error = 1; 928789Sahrens } 929789Sahrens 930789Sahrens if (error == 0) 931789Sahrens error = chown(file, owner, group); 932789Sahrens return (error); 933789Sahrens } 934789Sahrens 935789Sahrens static int 936789Sahrens ace_match(void *entry1, void *entry2) 937789Sahrens { 938789Sahrens ace_t *p1 = (ace_t *)entry1; 939789Sahrens ace_t *p2 = (ace_t *)entry2; 940789Sahrens ace_t ace1, ace2; 941789Sahrens 942789Sahrens ace1 = *p1; 943789Sahrens ace2 = *p2; 944789Sahrens 945789Sahrens /* 946789Sahrens * Need to fixup who field for abstrations for 947789Sahrens * accurate comparison, since field is undefined. 948789Sahrens */ 949789Sahrens if (ace1.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE)) 950789Sahrens ace1.a_who = -1; 951789Sahrens if (ace2.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE)) 952789Sahrens ace2.a_who = -1; 953789Sahrens return (memcmp(&ace1, &ace2, sizeof (ace_t))); 954789Sahrens } 955789Sahrens 956789Sahrens static int 957789Sahrens aclent_match(void *entry1, void *entry2) 958789Sahrens { 959789Sahrens aclent_t *aclent1 = (aclent_t *)entry1; 960789Sahrens aclent_t *aclent2 = (aclent_t *)entry2; 961789Sahrens 962789Sahrens return (memcmp(aclent1, aclent2, sizeof (aclent_t))); 963789Sahrens } 964789Sahrens 965789Sahrens /* 966789Sahrens * Find acl entries in acl that correspond to removeacl. Search 967789Sahrens * is started from slot. The flag argument indicates whether to 968789Sahrens * remove all matches or just the first match. 969789Sahrens */ 970789Sahrens int 971789Sahrens acl_removeentries(acl_t *acl, acl_t *removeacl, int start_slot, int flag) 972789Sahrens { 973789Sahrens int i, j; 974789Sahrens int match; 975789Sahrens int (*acl_match)(void *acl1, void *acl2); 976789Sahrens void *acl_entry, *remove_entry; 977789Sahrens void *start; 978789Sahrens int found = 0; 979789Sahrens 980789Sahrens if (flag != ACL_REMOVE_ALL && flag != ACL_REMOVE_FIRST) 981789Sahrens flag = ACL_REMOVE_FIRST; 982789Sahrens 983789Sahrens if (acl == NULL || removeacl == NULL) 984789Sahrens return (EACL_NO_ACL_ENTRY); 985789Sahrens 986789Sahrens if (acl->acl_type != removeacl->acl_type) 987789Sahrens return (EACL_DIFF_TYPE); 988789Sahrens 989789Sahrens if (acl->acl_type == ACLENT_T) 990789Sahrens acl_match = aclent_match; 991789Sahrens else 992789Sahrens acl_match = ace_match; 993789Sahrens 994789Sahrens for (i = 0, remove_entry = removeacl->acl_aclp; 995789Sahrens i != removeacl->acl_cnt; i++) { 996789Sahrens 997789Sahrens j = 0; 998789Sahrens acl_entry = (char *)acl->acl_aclp + 999789Sahrens (acl->acl_entry_size * start_slot); 1000789Sahrens for (;;) { 1001789Sahrens match = acl_match(acl_entry, remove_entry); 1002789Sahrens if (match == 0) { 1003789Sahrens found++; 1004789Sahrens start = (char *)acl_entry + 1005789Sahrens acl->acl_entry_size; 1006789Sahrens (void) memmove(acl_entry, start, 1007789Sahrens acl->acl_entry_size * 1008789Sahrens acl->acl_cnt-- - (j + 1)); 1009789Sahrens 1010789Sahrens if (flag == ACL_REMOVE_FIRST) 1011789Sahrens break; 1012789Sahrens /* 1013789Sahrens * List has changed, restart search from 1014789Sahrens * beginning. 1015789Sahrens */ 1016789Sahrens acl_entry = acl->acl_aclp; 1017789Sahrens j = 0; 1018789Sahrens continue; 1019789Sahrens } 1020789Sahrens acl_entry = ((char *)acl_entry + acl->acl_entry_size); 1021789Sahrens if (++j >= acl->acl_cnt) { 1022789Sahrens break; 1023789Sahrens } 1024789Sahrens } 1025789Sahrens } 1026789Sahrens 1027789Sahrens return ((found == 0) ? EACL_NO_ACL_ENTRY : 0); 1028789Sahrens } 1029789Sahrens 1030789Sahrens /* 1031789Sahrens * Replace entires entries in acl1 with the corresponding entries 1032789Sahrens * in newentries. The where argument specifies where to begin 1033789Sahrens * the replacement. If the where argument is 1 greater than the 1034789Sahrens * number of acl entries in acl1 then they are appended. If the 1035789Sahrens * where argument is 2+ greater than the number of acl entries then 1036789Sahrens * EACL_INVALID_SLOT is returned. 1037789Sahrens */ 1038789Sahrens int 1039789Sahrens acl_modifyentries(acl_t *acl1, acl_t *newentries, int where) 1040789Sahrens { 1041789Sahrens 1042789Sahrens int slot; 1043789Sahrens int slots_needed; 1044789Sahrens int slots_left; 1045789Sahrens int newsize; 1046789Sahrens 1047789Sahrens if (acl1 == NULL || newentries == NULL) 1048789Sahrens return (EACL_NO_ACL_ENTRY); 1049789Sahrens 1050789Sahrens if (where < 0 || where >= acl1->acl_cnt) 1051789Sahrens return (EACL_INVALID_SLOT); 1052789Sahrens 1053789Sahrens if (acl1->acl_type != newentries->acl_type) 1054789Sahrens return (EACL_DIFF_TYPE); 1055789Sahrens 1056789Sahrens slot = where; 1057789Sahrens 1058789Sahrens slots_left = acl1->acl_cnt - slot + 1; 1059789Sahrens if (slots_left < newentries->acl_cnt) { 1060789Sahrens slots_needed = newentries->acl_cnt - slots_left; 1061789Sahrens newsize = (acl1->acl_entry_size * acl1->acl_cnt) + 1062789Sahrens (acl1->acl_entry_size * slots_needed); 1063789Sahrens acl1->acl_aclp = realloc(acl1->acl_aclp, newsize); 1064789Sahrens if (acl1->acl_aclp == NULL) 1065789Sahrens return (-1); 1066789Sahrens } 1067789Sahrens (void) memcpy((char *)acl1->acl_aclp + (acl1->acl_entry_size * slot), 1068789Sahrens newentries->acl_aclp, 1069789Sahrens newentries->acl_entry_size * newentries->acl_cnt); 1070789Sahrens 1071789Sahrens /* 1072789Sahrens * Did ACL grow? 1073789Sahrens */ 1074789Sahrens 1075789Sahrens if ((slot + newentries->acl_cnt) > acl1->acl_cnt) { 1076789Sahrens acl1->acl_cnt = slot + newentries->acl_cnt; 1077789Sahrens } 1078789Sahrens 1079789Sahrens return (0); 1080789Sahrens } 1081789Sahrens 1082789Sahrens /* 1083789Sahrens * Add acl2 entries into acl1. The where argument specifies where 1084789Sahrens * to add the entries. 1085789Sahrens */ 1086789Sahrens int 1087789Sahrens acl_addentries(acl_t *acl1, acl_t *acl2, int where) 1088789Sahrens { 1089789Sahrens 1090789Sahrens int newsize; 1091789Sahrens int len; 1092789Sahrens void *start; 1093789Sahrens void *to; 1094789Sahrens 1095789Sahrens if (acl1 == NULL || acl2 == NULL) 1096789Sahrens return (EACL_NO_ACL_ENTRY); 1097789Sahrens 1098789Sahrens if (acl1->acl_type != acl2->acl_type) 1099789Sahrens return (EACL_DIFF_TYPE); 1100789Sahrens 1101789Sahrens /* 1102789Sahrens * allow where to specify 1 past last slot for an append operation 1103789Sahrens * but anything greater is an error. 1104789Sahrens */ 1105789Sahrens if (where < 0 || where > acl1->acl_cnt) 1106789Sahrens return (EACL_INVALID_SLOT); 1107789Sahrens 1108789Sahrens newsize = (acl2->acl_entry_size * acl2->acl_cnt) + 1109789Sahrens (acl1->acl_entry_size * acl1->acl_cnt); 1110789Sahrens acl1->acl_aclp = realloc(acl1->acl_aclp, newsize); 1111789Sahrens if (acl1->acl_aclp == NULL) 1112789Sahrens return (-1); 1113789Sahrens 1114789Sahrens /* 1115789Sahrens * first push down entries where new ones will be inserted 1116789Sahrens */ 1117789Sahrens 1118789Sahrens to = (void *)((char *)acl1->acl_aclp + 1119789Sahrens ((where + acl2->acl_cnt) * acl1->acl_entry_size)); 1120789Sahrens 1121789Sahrens start = (void *)((char *)acl1->acl_aclp + 1122789Sahrens where * acl1->acl_entry_size); 1123789Sahrens 1124789Sahrens if (where < acl1->acl_cnt) { 1125789Sahrens len = (acl1->acl_cnt - where) * acl1->acl_entry_size; 1126789Sahrens (void) memmove(to, start, len); 1127789Sahrens } 1128789Sahrens 1129789Sahrens /* 1130789Sahrens * now stick in new entries. 1131789Sahrens */ 1132789Sahrens 1133789Sahrens (void) memmove(start, acl2->acl_aclp, 1134789Sahrens acl2->acl_cnt * acl2->acl_entry_size); 1135789Sahrens 1136789Sahrens acl1->acl_cnt += acl2->acl_cnt; 1137789Sahrens return (0); 1138789Sahrens } 1139789Sahrens 1140789Sahrens /* 1141789Sahrens * return text for an ACL error. 1142789Sahrens */ 1143789Sahrens char * 1144789Sahrens acl_strerror(int errnum) 1145789Sahrens { 1146789Sahrens switch (errnum) { 1147789Sahrens case EACL_GRP_ERROR: 1148789Sahrens return (dgettext(TEXT_DOMAIN, 1149*1420Smarks "There is more than one group or default group entry")); 1150789Sahrens case EACL_USER_ERROR: 1151789Sahrens return (dgettext(TEXT_DOMAIN, 1152*1420Smarks "There is more than one user or default user entry")); 1153789Sahrens case EACL_OTHER_ERROR: 1154789Sahrens return (dgettext(TEXT_DOMAIN, 1155789Sahrens "There is more than one other entry")); 1156789Sahrens case EACL_CLASS_ERROR: 1157789Sahrens return (dgettext(TEXT_DOMAIN, 1158789Sahrens "There is more than one mask entry")); 1159789Sahrens case EACL_DUPLICATE_ERROR: 1160789Sahrens return (dgettext(TEXT_DOMAIN, 1161789Sahrens "Duplicate user or group entries")); 1162789Sahrens case EACL_MISS_ERROR: 1163789Sahrens return (dgettext(TEXT_DOMAIN, 1164789Sahrens "Missing user/group owner, other, mask entry")); 1165789Sahrens case EACL_MEM_ERROR: 1166789Sahrens return (dgettext(TEXT_DOMAIN, 1167789Sahrens "Memory error")); 1168789Sahrens case EACL_ENTRY_ERROR: 1169789Sahrens return (dgettext(TEXT_DOMAIN, 1170789Sahrens "Unrecognized entry type")); 1171789Sahrens case EACL_INHERIT_ERROR: 1172789Sahrens return (dgettext(TEXT_DOMAIN, 1173789Sahrens "Invalid inheritance flags")); 1174789Sahrens case EACL_FLAGS_ERROR: 1175789Sahrens return (dgettext(TEXT_DOMAIN, 1176789Sahrens "Unrecognized entry flags")); 1177789Sahrens case EACL_PERM_MASK_ERROR: 1178789Sahrens return (dgettext(TEXT_DOMAIN, 1179789Sahrens "Invalid ACL permissions")); 1180789Sahrens case EACL_COUNT_ERROR: 1181789Sahrens return (dgettext(TEXT_DOMAIN, 1182789Sahrens "Invalid ACL count")); 1183789Sahrens case EACL_INVALID_SLOT: 1184789Sahrens return (dgettext(TEXT_DOMAIN, 1185789Sahrens "Invalid ACL entry number specified")); 1186789Sahrens case EACL_NO_ACL_ENTRY: 1187789Sahrens return (dgettext(TEXT_DOMAIN, 1188789Sahrens "ACL entry doesn't exist")); 1189789Sahrens case EACL_DIFF_TYPE: 1190789Sahrens return (dgettext(TEXT_DOMAIN, 1191789Sahrens "ACL type's are different")); 1192789Sahrens case EACL_INVALID_USER_GROUP: 1193789Sahrens return (dgettext(TEXT_DOMAIN, "Invalid user or group")); 1194789Sahrens case EACL_INVALID_STR: 1195789Sahrens return (dgettext(TEXT_DOMAIN, "ACL string is invalid")); 1196789Sahrens case EACL_FIELD_NOT_BLANK: 1197789Sahrens return (dgettext(TEXT_DOMAIN, "Field expected to be blank")); 1198789Sahrens case EACL_INVALID_ACCESS_TYPE: 1199789Sahrens return (dgettext(TEXT_DOMAIN, "Invalid access type")); 1200789Sahrens case EACL_UNKNOWN_DATA: 1201789Sahrens return (dgettext(TEXT_DOMAIN, "Unrecognized entry")); 1202789Sahrens case EACL_MISSING_FIELDS: 1203789Sahrens return (dgettext(TEXT_DOMAIN, 1204789Sahrens "ACL specification missing required fields")); 1205789Sahrens case EACL_INHERIT_NOTDIR: 1206789Sahrens return (dgettext(TEXT_DOMAIN, 1207789Sahrens "Inheritance flags are only allowed on directories")); 1208789Sahrens case -1: 1209789Sahrens return (strerror(errno)); 1210789Sahrens default: 1211789Sahrens errno = EINVAL; 1212789Sahrens return (dgettext(TEXT_DOMAIN, "Unknown error")); 1213789Sahrens } 1214789Sahrens } 1215*1420Smarks 1216*1420Smarks extern int yyinteractive; 1217*1420Smarks 1218*1420Smarks /* PRINTFLIKE1 */ 1219*1420Smarks void 1220*1420Smarks acl_error(const char *fmt, ...) 1221*1420Smarks { 1222*1420Smarks va_list va; 1223*1420Smarks 1224*1420Smarks if (yyinteractive == 0) 1225*1420Smarks return; 1226*1420Smarks 1227*1420Smarks va_start(va, fmt); 1228*1420Smarks (void) vfprintf(stderr, fmt, va); 1229*1420Smarks va_end(va); 1230*1420Smarks } 1231