1*789Sahrens /* 2*789Sahrens * CDDL HEADER START 3*789Sahrens * 4*789Sahrens * The contents of this file are subject to the terms of the 5*789Sahrens * Common Development and Distribution License, Version 1.0 only 6*789Sahrens * (the "License"). You may not use this file except in compliance 7*789Sahrens * with the License. 8*789Sahrens * 9*789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*789Sahrens * or http://www.opensolaris.org/os/licensing. 11*789Sahrens * See the License for the specific language governing permissions 12*789Sahrens * and limitations under the License. 13*789Sahrens * 14*789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 15*789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*789Sahrens * If applicable, add the following below this CDDL HEADER, with the 17*789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 18*789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 19*789Sahrens * 20*789Sahrens * CDDL HEADER END 21*789Sahrens */ 22*789Sahrens /* 23*789Sahrens * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*789Sahrens * Use is subject to license terms. 25*789Sahrens */ 26*789Sahrens 27*789Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 28*789Sahrens 29*789Sahrens #include <stdlib.h> 30*789Sahrens #include <string.h> 31*789Sahrens #include <unistd.h> 32*789Sahrens #include <limits.h> 33*789Sahrens #include <grp.h> 34*789Sahrens #include <pwd.h> 35*789Sahrens #include <sys/types.h> 36*789Sahrens #include <sys/acl.h> 37*789Sahrens #include <errno.h> 38*789Sahrens #include <sys/stat.h> 39*789Sahrens #include <locale.h> 40*789Sahrens #include <aclutils.h> 41*789Sahrens #include <acl_common.h> 42*789Sahrens 43*789Sahrens #define ACL_PATH 0 44*789Sahrens #define ACL_FD 1 45*789Sahrens 46*789Sahrens #define ACE_POSIX_SUPPORTED_BITS (ACE_READ_DATA | \ 47*789Sahrens ACE_WRITE_DATA | ACE_APPEND_DATA | ACE_EXECUTE | \ 48*789Sahrens ACE_READ_ATTRIBUTES | ACE_READ_ACL | ACE_WRITE_ACL) 49*789Sahrens 50*789Sahrens 51*789Sahrens #define ACL_SYNCHRONIZE_SET_ALLOW 0x0000002 52*789Sahrens #define ACL_SYNCHRONIZE_SET_DENY 0x0000001 53*789Sahrens 54*789Sahrens #define ACL_WRITE_OWNER_SET_ALLOW 0x0000020 55*789Sahrens #define ACL_WRITE_OWNER_SET_DENY 0x0000010 56*789Sahrens 57*789Sahrens #define ACL_WRITE_ATTRS_OWNER_SET_ALLOW 0x0002000 58*789Sahrens #define ACL_WRITE_ATTRS_OWNER_SET_DENY 0x0001000 59*789Sahrens 60*789Sahrens #define ACL_WRITE_ATTRS_WRITER_SET_DENY 0x0010000 61*789Sahrens 62*789Sahrens #define ACL_DELETE_SET_ALLOW 0x0000200 63*789Sahrens #define ACL_DELETE_SET_DENY 0x0000100 64*789Sahrens 65*789Sahrens #define ACL_READ_NAMED_READER_SET_ALLOW 0x2000000 66*789Sahrens 67*789Sahrens #define ACL_WRITE_NAMED_WRITER_SET_ALLOW 0x0200000 68*789Sahrens #define ACL_WRITE_NAMED_WRITER_SET_DENY 0x0100000 69*789Sahrens 70*789Sahrens #define ACL_WRITE_ATTRS_OWNER_SET_ALLOW 0x0002000 71*789Sahrens #define ACL_WRITE_ATTRS_WRITER_SET_ALLOW 0x0020000 72*789Sahrens 73*789Sahrens #define ACL_WRITE_OWNER_ERR_DENY 0x0000040 74*789Sahrens #define ACL_READ_NAMED_READER_SET_DENY 0x1000000 75*789Sahrens #define ACL_WRITE_NAMED_WRITER_SET_ALLO W0x0200000 76*789Sahrens typedef union { 77*789Sahrens const char *file; 78*789Sahrens int fd; 79*789Sahrens } acl_inp; 80*789Sahrens 81*789Sahrens acl_t * 82*789Sahrens acl_alloc(enum acl_type type) 83*789Sahrens { 84*789Sahrens acl_t *aclp; 85*789Sahrens 86*789Sahrens aclp = malloc(sizeof (acl_t)); 87*789Sahrens 88*789Sahrens if (aclp == NULL) 89*789Sahrens return (NULL); 90*789Sahrens 91*789Sahrens aclp->acl_aclp = NULL; 92*789Sahrens aclp->acl_cnt = 0; 93*789Sahrens 94*789Sahrens switch (type) { 95*789Sahrens case ACE_T: 96*789Sahrens aclp->acl_type = ACE_T; 97*789Sahrens aclp->acl_entry_size = sizeof (ace_t); 98*789Sahrens break; 99*789Sahrens case ACLENT_T: 100*789Sahrens aclp->acl_type = ACLENT_T; 101*789Sahrens aclp->acl_entry_size = sizeof (aclent_t); 102*789Sahrens break; 103*789Sahrens default: 104*789Sahrens acl_free(aclp); 105*789Sahrens aclp = NULL; 106*789Sahrens } 107*789Sahrens return (aclp); 108*789Sahrens } 109*789Sahrens 110*789Sahrens /* 111*789Sahrens * Free acl_t structure 112*789Sahrens */ 113*789Sahrens void 114*789Sahrens acl_free(acl_t *aclp) 115*789Sahrens { 116*789Sahrens if (aclp == NULL) 117*789Sahrens return; 118*789Sahrens 119*789Sahrens if (aclp->acl_aclp) 120*789Sahrens free(aclp->acl_aclp); 121*789Sahrens free(aclp); 122*789Sahrens } 123*789Sahrens 124*789Sahrens /* 125*789Sahrens * Determine whether a file has a trivial ACL 126*789Sahrens * returns: 0 = trivial 127*789Sahrens * 1 = nontrivial 128*789Sahrens * <0 some other system failure, such as ENOENT or EPERM 129*789Sahrens */ 130*789Sahrens int 131*789Sahrens acl_trivial(const char *filename) 132*789Sahrens { 133*789Sahrens int acl_flavor; 134*789Sahrens int aclcnt; 135*789Sahrens int cntcmd; 136*789Sahrens int val = 0; 137*789Sahrens ace_t *acep; 138*789Sahrens 139*789Sahrens acl_flavor = pathconf(filename, _PC_ACL_ENABLED); 140*789Sahrens if (acl_flavor == -1) 141*789Sahrens return (-1); 142*789Sahrens 143*789Sahrens if (acl_flavor == _ACL_ACE_ENABLED) 144*789Sahrens cntcmd = ACE_GETACLCNT; 145*789Sahrens else 146*789Sahrens cntcmd = GETACLCNT; 147*789Sahrens 148*789Sahrens aclcnt = acl(filename, cntcmd, 0, NULL); 149*789Sahrens if (aclcnt > 0) { 150*789Sahrens if (acl_flavor == _ACL_ACE_ENABLED) { 151*789Sahrens if (aclcnt != 6) 152*789Sahrens val = 1; 153*789Sahrens else { 154*789Sahrens acep = malloc(sizeof (ace_t) * aclcnt); 155*789Sahrens if (acep == NULL) 156*789Sahrens return (-1); 157*789Sahrens if (acl(filename, ACE_GETACL, 158*789Sahrens aclcnt, acep) < 0) { 159*789Sahrens free(acep); 160*789Sahrens return (-1); 161*789Sahrens } 162*789Sahrens 163*789Sahrens val = ace_trivial(acep, aclcnt); 164*789Sahrens free(acep); 165*789Sahrens } 166*789Sahrens } else if (aclcnt > MIN_ACL_ENTRIES) 167*789Sahrens val = 1; 168*789Sahrens } 169*789Sahrens return (val); 170*789Sahrens } 171*789Sahrens 172*789Sahrens static uint32_t 173*789Sahrens access_mask_set(int haswriteperm, int hasreadperm, int isowner, int isallow) 174*789Sahrens { 175*789Sahrens uint32_t access_mask = 0; 176*789Sahrens int acl_produce; 177*789Sahrens int synchronize_set = 0, write_owner_set = 0; 178*789Sahrens int delete_set = 0, write_attrs_set = 0; 179*789Sahrens int read_named_set = 0, write_named_set = 0; 180*789Sahrens 181*789Sahrens acl_produce = (ACL_SYNCHRONIZE_SET_ALLOW | 182*789Sahrens ACL_WRITE_ATTRS_OWNER_SET_ALLOW | 183*789Sahrens ACL_WRITE_ATTRS_WRITER_SET_DENY); 184*789Sahrens 185*789Sahrens if (isallow) { 186*789Sahrens synchronize_set = ACL_SYNCHRONIZE_SET_ALLOW; 187*789Sahrens write_owner_set = ACL_WRITE_OWNER_SET_ALLOW; 188*789Sahrens delete_set = ACL_DELETE_SET_ALLOW; 189*789Sahrens if (hasreadperm) 190*789Sahrens read_named_set = ACL_READ_NAMED_READER_SET_ALLOW; 191*789Sahrens if (haswriteperm) 192*789Sahrens write_named_set = ACL_WRITE_NAMED_WRITER_SET_ALLOW; 193*789Sahrens if (isowner) 194*789Sahrens write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_ALLOW; 195*789Sahrens else if (haswriteperm) 196*789Sahrens write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_ALLOW; 197*789Sahrens } else { 198*789Sahrens 199*789Sahrens synchronize_set = ACL_SYNCHRONIZE_SET_DENY; 200*789Sahrens write_owner_set = ACL_WRITE_OWNER_SET_DENY; 201*789Sahrens delete_set = ACL_DELETE_SET_DENY; 202*789Sahrens if (hasreadperm) 203*789Sahrens read_named_set = ACL_READ_NAMED_READER_SET_DENY; 204*789Sahrens if (haswriteperm) 205*789Sahrens write_named_set = ACL_WRITE_NAMED_WRITER_SET_DENY; 206*789Sahrens if (isowner) 207*789Sahrens write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_DENY; 208*789Sahrens else if (haswriteperm) 209*789Sahrens write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_DENY; 210*789Sahrens else 211*789Sahrens /* 212*789Sahrens * If the entity is not the owner and does not 213*789Sahrens * have write permissions ACE_WRITE_ATTRIBUTES will 214*789Sahrens * always go in the DENY ACE. 215*789Sahrens */ 216*789Sahrens access_mask |= ACE_WRITE_ATTRIBUTES; 217*789Sahrens } 218*789Sahrens 219*789Sahrens if (acl_produce & synchronize_set) 220*789Sahrens access_mask |= ACE_SYNCHRONIZE; 221*789Sahrens if (acl_produce & write_owner_set) 222*789Sahrens access_mask |= ACE_WRITE_OWNER; 223*789Sahrens if (acl_produce & delete_set) 224*789Sahrens access_mask |= ACE_DELETE; 225*789Sahrens if (acl_produce & write_attrs_set) 226*789Sahrens access_mask |= ACE_WRITE_ATTRIBUTES; 227*789Sahrens if (acl_produce & read_named_set) 228*789Sahrens access_mask |= ACE_READ_NAMED_ATTRS; 229*789Sahrens if (acl_produce & write_named_set) 230*789Sahrens access_mask |= ACE_WRITE_NAMED_ATTRS; 231*789Sahrens 232*789Sahrens return (access_mask); 233*789Sahrens } 234*789Sahrens 235*789Sahrens /* 236*789Sahrens * Given an mode_t, convert it into an access_mask as used 237*789Sahrens * by nfsace, assuming aclent_t -> nfsace semantics. 238*789Sahrens */ 239*789Sahrens static uint32_t 240*789Sahrens mode_to_ace_access(mode_t mode, int isdir, int isowner, int isallow) 241*789Sahrens { 242*789Sahrens uint32_t access = 0; 243*789Sahrens int haswriteperm = 0; 244*789Sahrens int hasreadperm = 0; 245*789Sahrens 246*789Sahrens if (isallow) { 247*789Sahrens haswriteperm = (mode & 02); 248*789Sahrens hasreadperm = (mode & 04); 249*789Sahrens } else { 250*789Sahrens haswriteperm = !(mode & 02); 251*789Sahrens hasreadperm = !(mode & 04); 252*789Sahrens } 253*789Sahrens 254*789Sahrens /* 255*789Sahrens * The following call takes care of correctly setting the following 256*789Sahrens * mask bits in the access_mask: 257*789Sahrens * ACE_SYNCHRONIZE, ACE_WRITE_OWNER, ACE_DELETE, 258*789Sahrens * ACE_WRITE_ATTRIBUTES, ACE_WRITE_NAMED_ATTRS, ACE_READ_NAMED_ATTRS 259*789Sahrens */ 260*789Sahrens access = access_mask_set(haswriteperm, hasreadperm, isowner, isallow); 261*789Sahrens 262*789Sahrens if (isallow) { 263*789Sahrens access |= ACE_READ_ACL | ACE_READ_ATTRIBUTES; 264*789Sahrens if (isowner) 265*789Sahrens access |= ACE_WRITE_ACL; 266*789Sahrens } else { 267*789Sahrens if (! isowner) 268*789Sahrens access |= ACE_WRITE_ACL; 269*789Sahrens } 270*789Sahrens 271*789Sahrens /* read */ 272*789Sahrens if (mode & 04) { 273*789Sahrens access |= ACE_READ_DATA; 274*789Sahrens } 275*789Sahrens /* write */ 276*789Sahrens if (mode & 02) { 277*789Sahrens access |= ACE_WRITE_DATA | 278*789Sahrens ACE_APPEND_DATA; 279*789Sahrens if (isdir) 280*789Sahrens access |= ACE_DELETE_CHILD; 281*789Sahrens } 282*789Sahrens /* exec */ 283*789Sahrens if (mode & 01) { 284*789Sahrens access |= ACE_EXECUTE; 285*789Sahrens } 286*789Sahrens 287*789Sahrens return (access); 288*789Sahrens } 289*789Sahrens 290*789Sahrens /* 291*789Sahrens * Given an nfsace (presumably an ALLOW entry), make a 292*789Sahrens * corresponding DENY entry at the address given. 293*789Sahrens */ 294*789Sahrens static void 295*789Sahrens ace_make_deny(ace_t *allow, ace_t *deny, int isdir, int isowner) 296*789Sahrens { 297*789Sahrens (void) memcpy(deny, allow, sizeof (ace_t)); 298*789Sahrens 299*789Sahrens deny->a_who = allow->a_who; 300*789Sahrens 301*789Sahrens deny->a_type = ACE_ACCESS_DENIED_ACE_TYPE; 302*789Sahrens deny->a_access_mask ^= ACE_POSIX_SUPPORTED_BITS; 303*789Sahrens if (isdir) 304*789Sahrens deny->a_access_mask ^= ACE_DELETE_CHILD; 305*789Sahrens 306*789Sahrens deny->a_access_mask &= ~(ACE_SYNCHRONIZE | ACE_WRITE_OWNER | 307*789Sahrens ACE_DELETE | ACE_WRITE_ATTRIBUTES | ACE_READ_NAMED_ATTRS | 308*789Sahrens ACE_WRITE_NAMED_ATTRS); 309*789Sahrens deny->a_access_mask |= access_mask_set((allow->a_access_mask & 310*789Sahrens ACE_WRITE_DATA), (allow->a_access_mask & ACE_READ_DATA), isowner, 311*789Sahrens B_FALSE); 312*789Sahrens } 313*789Sahrens /* 314*789Sahrens * Make an initial pass over an array of aclent_t's. Gather 315*789Sahrens * information such as an ACL_MASK (if any), number of users, 316*789Sahrens * number of groups, and whether the array needs to be sorted. 317*789Sahrens */ 318*789Sahrens static int 319*789Sahrens ln_aent_preprocess(aclent_t *aclent, int n, 320*789Sahrens int *hasmask, mode_t *mask, 321*789Sahrens int *numuser, int *numgroup, int *needsort) 322*789Sahrens { 323*789Sahrens int error = 0; 324*789Sahrens int i; 325*789Sahrens int curtype = 0; 326*789Sahrens 327*789Sahrens *hasmask = 0; 328*789Sahrens *mask = 07; 329*789Sahrens *needsort = 0; 330*789Sahrens *numuser = 0; 331*789Sahrens *numgroup = 0; 332*789Sahrens 333*789Sahrens for (i = 0; i < n; i++) { 334*789Sahrens if (aclent[i].a_type < curtype) 335*789Sahrens *needsort = 1; 336*789Sahrens else if (aclent[i].a_type > curtype) 337*789Sahrens curtype = aclent[i].a_type; 338*789Sahrens if (aclent[i].a_type & USER) 339*789Sahrens (*numuser)++; 340*789Sahrens if (aclent[i].a_type & (GROUP | GROUP_OBJ)) 341*789Sahrens (*numgroup)++; 342*789Sahrens if (aclent[i].a_type & CLASS_OBJ) { 343*789Sahrens if (*hasmask) { 344*789Sahrens error = EINVAL; 345*789Sahrens goto out; 346*789Sahrens } else { 347*789Sahrens *hasmask = 1; 348*789Sahrens *mask = aclent[i].a_perm; 349*789Sahrens } 350*789Sahrens } 351*789Sahrens } 352*789Sahrens 353*789Sahrens if ((! *hasmask) && (*numuser + *numgroup > 1)) { 354*789Sahrens error = EINVAL; 355*789Sahrens goto out; 356*789Sahrens } 357*789Sahrens 358*789Sahrens out: 359*789Sahrens return (error); 360*789Sahrens } 361*789Sahrens 362*789Sahrens /* 363*789Sahrens * Convert an array of aclent_t into an array of nfsace entries, 364*789Sahrens * following POSIX draft -> nfsv4 conversion semantics as outlined in 365*789Sahrens * the IETF draft. 366*789Sahrens */ 367*789Sahrens static int 368*789Sahrens ln_aent_to_ace(aclent_t *aclent, int n, ace_t **acepp, int *rescount, int isdir) 369*789Sahrens { 370*789Sahrens int error = 0; 371*789Sahrens mode_t mask; 372*789Sahrens int numuser, numgroup, needsort; 373*789Sahrens int resultsize = 0; 374*789Sahrens int i, groupi = 0, skip; 375*789Sahrens ace_t *acep, *result = NULL; 376*789Sahrens int hasmask; 377*789Sahrens 378*789Sahrens error = ln_aent_preprocess(aclent, n, &hasmask, &mask, 379*789Sahrens &numuser, &numgroup, &needsort); 380*789Sahrens if (error != 0) 381*789Sahrens goto out; 382*789Sahrens 383*789Sahrens /* allow + deny for each aclent */ 384*789Sahrens resultsize = n * 2; 385*789Sahrens if (hasmask) { 386*789Sahrens /* 387*789Sahrens * stick extra deny on the group_obj and on each 388*789Sahrens * user|group for the mask (the group_obj was added 389*789Sahrens * into the count for numgroup) 390*789Sahrens */ 391*789Sahrens resultsize += numuser + numgroup; 392*789Sahrens /* ... and don't count the mask itself */ 393*789Sahrens resultsize -= 2; 394*789Sahrens } 395*789Sahrens 396*789Sahrens /* sort the source if necessary */ 397*789Sahrens if (needsort) 398*789Sahrens ksort((caddr_t)aclent, n, sizeof (aclent_t), cmp2acls); 399*789Sahrens 400*789Sahrens result = acep = calloc(1, resultsize * sizeof (ace_t)); 401*789Sahrens if (result == NULL) 402*789Sahrens goto out; 403*789Sahrens 404*789Sahrens for (i = 0; i < n; i++) { 405*789Sahrens /* 406*789Sahrens * don't process CLASS_OBJ (mask); mask was grabbed in 407*789Sahrens * ln_aent_preprocess() 408*789Sahrens */ 409*789Sahrens if (aclent[i].a_type & CLASS_OBJ) 410*789Sahrens continue; 411*789Sahrens 412*789Sahrens /* If we need an ACL_MASK emulator, prepend it now */ 413*789Sahrens if ((hasmask) && 414*789Sahrens (aclent[i].a_type & (USER | GROUP | GROUP_OBJ))) { 415*789Sahrens acep->a_type = ACE_ACCESS_DENIED_ACE_TYPE; 416*789Sahrens acep->a_flags = 0; 417*789Sahrens if (aclent[i].a_type & GROUP_OBJ) { 418*789Sahrens acep->a_who = -1; 419*789Sahrens acep->a_flags |= 420*789Sahrens (ACE_IDENTIFIER_GROUP|ACE_GROUP); 421*789Sahrens } else if (aclent[i].a_type & USER) { 422*789Sahrens acep->a_who = aclent[i].a_id; 423*789Sahrens } else { 424*789Sahrens acep->a_who = aclent[i].a_id; 425*789Sahrens acep->a_flags |= ACE_IDENTIFIER_GROUP; 426*789Sahrens } 427*789Sahrens if (aclent[i].a_type & ACL_DEFAULT) { 428*789Sahrens acep->a_flags |= ACE_INHERIT_ONLY_ACE | 429*789Sahrens ACE_FILE_INHERIT_ACE | 430*789Sahrens ACE_DIRECTORY_INHERIT_ACE; 431*789Sahrens } 432*789Sahrens /* 433*789Sahrens * Set the access mask for the prepended deny 434*789Sahrens * ace. To do this, we invert the mask (found 435*789Sahrens * in ln_aent_preprocess()) then convert it to an 436*789Sahrens * DENY ace access_mask. 437*789Sahrens */ 438*789Sahrens acep->a_access_mask = mode_to_ace_access((mask ^ 07), 439*789Sahrens isdir, 0, 0); 440*789Sahrens acep += 1; 441*789Sahrens } 442*789Sahrens 443*789Sahrens /* handle a_perm -> access_mask */ 444*789Sahrens acep->a_access_mask = mode_to_ace_access(aclent[i].a_perm, 445*789Sahrens isdir, aclent[i].a_type & USER_OBJ, 1); 446*789Sahrens 447*789Sahrens /* emulate a default aclent */ 448*789Sahrens if (aclent[i].a_type & ACL_DEFAULT) { 449*789Sahrens acep->a_flags |= ACE_INHERIT_ONLY_ACE | 450*789Sahrens ACE_FILE_INHERIT_ACE | 451*789Sahrens ACE_DIRECTORY_INHERIT_ACE; 452*789Sahrens } 453*789Sahrens 454*789Sahrens /* 455*789Sahrens * handle a_perm and a_id 456*789Sahrens * 457*789Sahrens * this must be done last, since it involves the 458*789Sahrens * corresponding deny aces, which are handled 459*789Sahrens * differently for each different a_type. 460*789Sahrens */ 461*789Sahrens if (aclent[i].a_type & USER_OBJ) { 462*789Sahrens acep->a_who = -1; 463*789Sahrens acep->a_flags |= ACE_OWNER; 464*789Sahrens ace_make_deny(acep, acep + 1, isdir, B_TRUE); 465*789Sahrens acep += 2; 466*789Sahrens } else if (aclent[i].a_type & USER) { 467*789Sahrens acep->a_who = aclent[i].a_id; 468*789Sahrens ace_make_deny(acep, acep + 1, isdir, B_FALSE); 469*789Sahrens acep += 2; 470*789Sahrens } else if (aclent[i].a_type & (GROUP_OBJ | GROUP)) { 471*789Sahrens if (aclent[i].a_type & GROUP_OBJ) { 472*789Sahrens acep->a_who = -1; 473*789Sahrens acep->a_flags |= ACE_GROUP; 474*789Sahrens } else { 475*789Sahrens acep->a_who = aclent[i].a_id; 476*789Sahrens } 477*789Sahrens acep->a_flags |= ACE_IDENTIFIER_GROUP; 478*789Sahrens /* 479*789Sahrens * Set the corresponding deny for the group ace. 480*789Sahrens * 481*789Sahrens * The deny aces go after all of the groups, unlike 482*789Sahrens * everything else, where they immediately follow 483*789Sahrens * the allow ace. 484*789Sahrens * 485*789Sahrens * We calculate "skip", the number of slots to 486*789Sahrens * skip ahead for the deny ace, here. 487*789Sahrens * 488*789Sahrens * The pattern is: 489*789Sahrens * MD1 A1 MD2 A2 MD3 A3 D1 D2 D3 490*789Sahrens * thus, skip is 491*789Sahrens * (2 * numgroup) - 1 - groupi 492*789Sahrens * (2 * numgroup) to account for MD + A 493*789Sahrens * - 1 to account for the fact that we're on the 494*789Sahrens * access (A), not the mask (MD) 495*789Sahrens * - groupi to account for the fact that we have 496*789Sahrens * passed up groupi number of MD's. 497*789Sahrens */ 498*789Sahrens skip = (2 * numgroup) - 1 - groupi; 499*789Sahrens ace_make_deny(acep, acep + skip, isdir, B_FALSE); 500*789Sahrens /* 501*789Sahrens * If we just did the last group, skip acep past 502*789Sahrens * all of the denies; else, just move ahead one. 503*789Sahrens */ 504*789Sahrens if (++groupi >= numgroup) 505*789Sahrens acep += numgroup + 1; 506*789Sahrens else 507*789Sahrens acep += 1; 508*789Sahrens } else if (aclent[i].a_type & OTHER_OBJ) { 509*789Sahrens acep->a_who = -1; 510*789Sahrens acep->a_flags |= ACE_EVERYONE; 511*789Sahrens ace_make_deny(acep, acep + 1, isdir, B_FALSE); 512*789Sahrens acep += 2; 513*789Sahrens } else { 514*789Sahrens error = EINVAL; 515*789Sahrens goto out; 516*789Sahrens } 517*789Sahrens } 518*789Sahrens 519*789Sahrens *acepp = result; 520*789Sahrens *rescount = resultsize; 521*789Sahrens 522*789Sahrens out: 523*789Sahrens if (error != 0) { 524*789Sahrens if ((result != NULL) && (resultsize > 0)) { 525*789Sahrens free(result); 526*789Sahrens } 527*789Sahrens } 528*789Sahrens 529*789Sahrens return (error); 530*789Sahrens } 531*789Sahrens 532*789Sahrens static int 533*789Sahrens convert_aent_to_ace(aclent_t *aclentp, int aclcnt, int isdir, 534*789Sahrens ace_t **retacep, int *retacecnt) 535*789Sahrens { 536*789Sahrens ace_t *acep; 537*789Sahrens ace_t *dfacep; 538*789Sahrens ace_t *newacep; 539*789Sahrens int acecnt = 0; 540*789Sahrens int dfacecnt = 0; 541*789Sahrens int dfaclstart = 0; 542*789Sahrens int dfaclcnt = 0; 543*789Sahrens aclent_t *aclp; 544*789Sahrens int i; 545*789Sahrens int error; 546*789Sahrens 547*789Sahrens ksort((caddr_t)aclentp, aclcnt, sizeof (aclent_t), cmp2acls); 548*789Sahrens 549*789Sahrens for (i = 0, aclp = aclentp; i < aclcnt; aclp++, i++) { 550*789Sahrens if (aclp->a_type & ACL_DEFAULT) 551*789Sahrens break; 552*789Sahrens } 553*789Sahrens 554*789Sahrens if (i < aclcnt) { 555*789Sahrens dfaclstart = aclcnt - i; 556*789Sahrens dfaclcnt = i; 557*789Sahrens } 558*789Sahrens 559*789Sahrens if (dfaclcnt && isdir == 0) { 560*789Sahrens return (-1); 561*789Sahrens } 562*789Sahrens 563*789Sahrens error = ln_aent_to_ace(aclentp, i, &acep, &acecnt, isdir); 564*789Sahrens if (error) 565*789Sahrens return (-1); 566*789Sahrens 567*789Sahrens if (dfaclcnt) { 568*789Sahrens error = ln_aent_to_ace(&aclentp[dfaclstart], dfaclcnt, 569*789Sahrens &dfacep, &dfacecnt, isdir); 570*789Sahrens if (error) { 571*789Sahrens if (acep) { 572*789Sahrens free(acep); 573*789Sahrens } 574*789Sahrens return (-1); 575*789Sahrens } 576*789Sahrens } 577*789Sahrens 578*789Sahrens newacep = malloc(sizeof (ace_t) * (acecnt + dfacecnt)); 579*789Sahrens if (newacep == NULL) 580*789Sahrens return (-1); 581*789Sahrens 582*789Sahrens (void) memcpy(newacep, acep, sizeof (ace_t) * acecnt); 583*789Sahrens if (dfaclcnt) { 584*789Sahrens (void) memcpy(newacep + acecnt, dfacep, 585*789Sahrens sizeof (ace_t) * dfacecnt); 586*789Sahrens } 587*789Sahrens free(acep); 588*789Sahrens if (dfaclcnt) 589*789Sahrens free(dfacep); 590*789Sahrens 591*789Sahrens *retacecnt = acecnt + dfacecnt; 592*789Sahrens *retacep = newacep; 593*789Sahrens return (0); 594*789Sahrens } 595*789Sahrens 596*789Sahrens 597*789Sahrens static int 598*789Sahrens cacl_get(acl_inp inp, int get_flag, int type, acl_t **aclp) 599*789Sahrens { 600*789Sahrens const char *fname; 601*789Sahrens int fd; 602*789Sahrens int ace_acl = 0; 603*789Sahrens int error; 604*789Sahrens int getcmd, cntcmd; 605*789Sahrens acl_t *acl_info; 606*789Sahrens int save_errno; 607*789Sahrens int stat_error; 608*789Sahrens struct stat64 statbuf; 609*789Sahrens 610*789Sahrens *aclp = NULL; 611*789Sahrens if (type == ACL_PATH) { 612*789Sahrens fname = inp.file; 613*789Sahrens ace_acl = pathconf(fname, _PC_ACL_ENABLED); 614*789Sahrens } else { 615*789Sahrens fd = inp.fd; 616*789Sahrens ace_acl = fpathconf(fd, _PC_ACL_ENABLED); 617*789Sahrens } 618*789Sahrens 619*789Sahrens if (ace_acl == -1) 620*789Sahrens return (-1); 621*789Sahrens 622*789Sahrens /* 623*789Sahrens * if acl's aren't supported then 624*789Sahrens * send it through the old GETACL interface 625*789Sahrens */ 626*789Sahrens if (ace_acl == 0) { 627*789Sahrens ace_acl = _ACL_ACLENT_ENABLED; 628*789Sahrens } 629*789Sahrens 630*789Sahrens if (ace_acl & _ACL_ACE_ENABLED) { 631*789Sahrens cntcmd = ACE_GETACLCNT; 632*789Sahrens getcmd = ACE_GETACL; 633*789Sahrens acl_info = acl_alloc(ACE_T); 634*789Sahrens } else { 635*789Sahrens cntcmd = GETACLCNT; 636*789Sahrens getcmd = GETACL; 637*789Sahrens acl_info = acl_alloc(ACLENT_T); 638*789Sahrens } 639*789Sahrens 640*789Sahrens if (acl_info == NULL) 641*789Sahrens return (-1); 642*789Sahrens 643*789Sahrens if (type == ACL_PATH) { 644*789Sahrens acl_info->acl_cnt = acl(fname, cntcmd, 0, NULL); 645*789Sahrens } else { 646*789Sahrens acl_info->acl_cnt = facl(fd, cntcmd, 0, NULL); 647*789Sahrens } 648*789Sahrens 649*789Sahrens save_errno = errno; 650*789Sahrens if (acl_info->acl_cnt < 0) { 651*789Sahrens acl_free(acl_info); 652*789Sahrens errno = save_errno; 653*789Sahrens return (-1); 654*789Sahrens } 655*789Sahrens 656*789Sahrens if (acl_info->acl_cnt == 0) { 657*789Sahrens acl_free(acl_info); 658*789Sahrens errno = save_errno; 659*789Sahrens return (0); 660*789Sahrens } 661*789Sahrens 662*789Sahrens acl_info->acl_aclp = 663*789Sahrens malloc(acl_info->acl_cnt * acl_info->acl_entry_size); 664*789Sahrens save_errno = errno; 665*789Sahrens 666*789Sahrens if (acl_info->acl_aclp == NULL) { 667*789Sahrens acl_free(acl_info); 668*789Sahrens errno = save_errno; 669*789Sahrens return (-1); 670*789Sahrens } 671*789Sahrens 672*789Sahrens if (type == ACL_PATH) { 673*789Sahrens stat_error = stat64(fname, &statbuf); 674*789Sahrens error = acl(fname, getcmd, acl_info->acl_cnt, 675*789Sahrens acl_info->acl_aclp); 676*789Sahrens } else { 677*789Sahrens stat_error = fstat64(fd, &statbuf); 678*789Sahrens error = facl(fd, getcmd, acl_info->acl_cnt, 679*789Sahrens acl_info->acl_aclp); 680*789Sahrens } 681*789Sahrens 682*789Sahrens save_errno = errno; 683*789Sahrens if (error == -1) { 684*789Sahrens acl_free(acl_info); 685*789Sahrens errno = save_errno; 686*789Sahrens return (-1); 687*789Sahrens } 688*789Sahrens 689*789Sahrens 690*789Sahrens if (stat_error == 0) { 691*789Sahrens acl_info->acl_flags = 692*789Sahrens (S_ISDIR(statbuf.st_mode) ? ACL_IS_DIR : 0); 693*789Sahrens } else 694*789Sahrens acl_info->acl_flags = 0; 695*789Sahrens 696*789Sahrens switch (acl_info->acl_type) { 697*789Sahrens case ACLENT_T: 698*789Sahrens if (acl_info->acl_cnt <= MIN_ACL_ENTRIES) 699*789Sahrens acl_info->acl_flags |= ACL_IS_TRIVIAL; 700*789Sahrens break; 701*789Sahrens case ACE_T: 702*789Sahrens if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0) 703*789Sahrens acl_info->acl_flags |= ACL_IS_TRIVIAL; 704*789Sahrens break; 705*789Sahrens default: 706*789Sahrens errno = EINVAL; 707*789Sahrens acl_free(acl_info); 708*789Sahrens return (-1); 709*789Sahrens } 710*789Sahrens 711*789Sahrens if ((acl_info->acl_flags & ACL_IS_TRIVIAL) && 712*789Sahrens (get_flag & ACL_NO_TRIVIAL)) { 713*789Sahrens acl_free(acl_info); 714*789Sahrens errno = 0; 715*789Sahrens return (0); 716*789Sahrens } 717*789Sahrens 718*789Sahrens *aclp = acl_info; 719*789Sahrens return (0); 720*789Sahrens } 721*789Sahrens 722*789Sahrens /* 723*789Sahrens * return -1 on failure, otherwise the number of acl 724*789Sahrens * entries is returned 725*789Sahrens */ 726*789Sahrens int 727*789Sahrens acl_get(const char *path, int get_flag, acl_t **aclp) 728*789Sahrens { 729*789Sahrens acl_inp acl_inp; 730*789Sahrens acl_inp.file = path; 731*789Sahrens 732*789Sahrens return (cacl_get(acl_inp, get_flag, ACL_PATH, aclp)); 733*789Sahrens } 734*789Sahrens 735*789Sahrens int 736*789Sahrens facl_get(int fd, int get_flag, acl_t **aclp) 737*789Sahrens { 738*789Sahrens 739*789Sahrens acl_inp acl_inp; 740*789Sahrens acl_inp.fd = fd; 741*789Sahrens 742*789Sahrens return (cacl_get(acl_inp, get_flag, ACL_FD, aclp)); 743*789Sahrens } 744*789Sahrens 745*789Sahrens /* 746*789Sahrens * Set an ACL, translates acl to ace_t when appropriate. 747*789Sahrens */ 748*789Sahrens static int 749*789Sahrens cacl_set(acl_inp *acl_inp, acl_t *aclp, int type) 750*789Sahrens { 751*789Sahrens int error = 0; 752*789Sahrens int acl_flavor_target; 753*789Sahrens ace_t *acep = NULL; 754*789Sahrens int acecnt; 755*789Sahrens struct stat64 statbuf; 756*789Sahrens int stat_error; 757*789Sahrens int isdir; 758*789Sahrens 759*789Sahrens 760*789Sahrens if (type == ACL_PATH) { 761*789Sahrens stat_error = stat64(acl_inp->file, &statbuf); 762*789Sahrens if (stat_error) 763*789Sahrens return (-1); 764*789Sahrens acl_flavor_target = pathconf(acl_inp->file, _PC_ACL_ENABLED); 765*789Sahrens } else { 766*789Sahrens stat_error = fstat64(acl_inp->fd, &statbuf); 767*789Sahrens if (stat_error) 768*789Sahrens return (-1); 769*789Sahrens acl_flavor_target = fpathconf(acl_inp->fd, _PC_ACL_ENABLED); 770*789Sahrens } 771*789Sahrens 772*789Sahrens isdir = S_ISDIR(statbuf.st_mode); 773*789Sahrens 774*789Sahrens if (acl_flavor_target == -1) 775*789Sahrens return (-1); 776*789Sahrens 777*789Sahrens /* 778*789Sahrens * Translate aclent_t ACL's to ACE ACL's. 779*789Sahrens */ 780*789Sahrens if (acl_flavor_target == _ACL_ACE_ENABLED && 781*789Sahrens aclp->acl_type == ACLENT_T) { 782*789Sahrens error = convert_aent_to_ace(aclp->acl_aclp, 783*789Sahrens aclp->acl_cnt, isdir, &acep, &acecnt); 784*789Sahrens if (error) { 785*789Sahrens errno = ENOTSUP; 786*789Sahrens return (-1); 787*789Sahrens } 788*789Sahrens /* 789*789Sahrens * replace old acl with newly translated acl 790*789Sahrens */ 791*789Sahrens free(aclp->acl_aclp); 792*789Sahrens aclp->acl_aclp = acep; 793*789Sahrens aclp->acl_cnt = acecnt; 794*789Sahrens aclp->acl_type = ACE_T; 795*789Sahrens } 796*789Sahrens 797*789Sahrens if (type == ACL_PATH) { 798*789Sahrens error = acl(acl_inp->file, 799*789Sahrens (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, 800*789Sahrens aclp->acl_cnt, aclp->acl_aclp); 801*789Sahrens } else { 802*789Sahrens error = facl(acl_inp->fd, 803*789Sahrens (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, 804*789Sahrens aclp->acl_cnt, aclp->acl_aclp); 805*789Sahrens } 806*789Sahrens 807*789Sahrens return (error); 808*789Sahrens } 809*789Sahrens 810*789Sahrens int 811*789Sahrens acl_set(const char *path, acl_t *aclp) 812*789Sahrens { 813*789Sahrens acl_inp acl_inp; 814*789Sahrens 815*789Sahrens acl_inp.file = path; 816*789Sahrens 817*789Sahrens return (cacl_set(&acl_inp, aclp, ACL_PATH)); 818*789Sahrens } 819*789Sahrens 820*789Sahrens int 821*789Sahrens facl_set(int fd, acl_t *aclp) 822*789Sahrens { 823*789Sahrens acl_inp acl_inp; 824*789Sahrens 825*789Sahrens acl_inp.fd = fd; 826*789Sahrens 827*789Sahrens return (cacl_set(&acl_inp, aclp, ACL_FD)); 828*789Sahrens } 829*789Sahrens 830*789Sahrens int 831*789Sahrens acl_cnt(acl_t *aclp) 832*789Sahrens { 833*789Sahrens return (aclp->acl_cnt); 834*789Sahrens } 835*789Sahrens 836*789Sahrens int 837*789Sahrens acl_type(acl_t *aclp) 838*789Sahrens { 839*789Sahrens return (aclp->acl_type); 840*789Sahrens } 841*789Sahrens 842*789Sahrens acl_t * 843*789Sahrens acl_dup(acl_t *aclp) 844*789Sahrens { 845*789Sahrens acl_t *newaclp; 846*789Sahrens 847*789Sahrens newaclp = acl_alloc(aclp->acl_type); 848*789Sahrens if (newaclp == NULL) 849*789Sahrens return (NULL); 850*789Sahrens 851*789Sahrens newaclp->acl_aclp = malloc(aclp->acl_entry_size * aclp->acl_cnt); 852*789Sahrens if (newaclp->acl_aclp == NULL) { 853*789Sahrens acl_free(newaclp); 854*789Sahrens return (NULL); 855*789Sahrens } 856*789Sahrens 857*789Sahrens (void) memcpy(newaclp->acl_aclp, 858*789Sahrens aclp->acl_aclp, aclp->acl_entry_size * aclp->acl_cnt); 859*789Sahrens newaclp->acl_cnt = aclp->acl_cnt; 860*789Sahrens 861*789Sahrens return (newaclp); 862*789Sahrens } 863*789Sahrens 864*789Sahrens int 865*789Sahrens acl_flags(acl_t *aclp) 866*789Sahrens { 867*789Sahrens return (aclp->acl_flags); 868*789Sahrens } 869*789Sahrens 870*789Sahrens void * 871*789Sahrens acl_data(acl_t *aclp) 872*789Sahrens { 873*789Sahrens return (aclp->acl_aclp); 874*789Sahrens } 875*789Sahrens 876*789Sahrens /* 877*789Sahrens * Remove an ACL from a file and create a trivial ACL based 878*789Sahrens * off of the mode argument. After acl has been set owner/group 879*789Sahrens * are updated to match owner,group arguments 880*789Sahrens */ 881*789Sahrens int 882*789Sahrens acl_strip(const char *file, uid_t owner, gid_t group, mode_t mode) 883*789Sahrens { 884*789Sahrens int error = 0; 885*789Sahrens aclent_t min_acl[MIN_ACL_ENTRIES]; 886*789Sahrens ace_t min_ace_acl[6]; /* owner, group, everyone + complement denies */ 887*789Sahrens int acl_flavor; 888*789Sahrens int aclcnt; 889*789Sahrens 890*789Sahrens acl_flavor = pathconf(file, _PC_ACL_ENABLED); 891*789Sahrens 892*789Sahrens if (acl_flavor == -1) 893*789Sahrens return (-1); 894*789Sahrens /* 895*789Sahrens * force it through aclent flavor when file system doesn't 896*789Sahrens * understand question 897*789Sahrens */ 898*789Sahrens if (acl_flavor == 0) 899*789Sahrens acl_flavor = _ACL_ACLENT_ENABLED; 900*789Sahrens 901*789Sahrens if (acl_flavor & _ACL_ACLENT_ENABLED) { 902*789Sahrens min_acl[0].a_type = USER_OBJ; 903*789Sahrens min_acl[0].a_id = owner; 904*789Sahrens min_acl[0].a_perm = ((mode & 0700) >> 6); 905*789Sahrens min_acl[1].a_type = GROUP_OBJ; 906*789Sahrens min_acl[1].a_id = group; 907*789Sahrens min_acl[1].a_perm = ((mode & 0070) >> 3); 908*789Sahrens min_acl[2].a_type = CLASS_OBJ; 909*789Sahrens min_acl[2].a_id = (uid_t)-1; 910*789Sahrens min_acl[2].a_perm = ((mode & 0070) >> 3); 911*789Sahrens min_acl[3].a_type = OTHER_OBJ; 912*789Sahrens min_acl[3].a_id = (uid_t)-1; 913*789Sahrens min_acl[3].a_perm = (mode & 0007); 914*789Sahrens aclcnt = 4; 915*789Sahrens error = acl(file, SETACL, aclcnt, min_acl); 916*789Sahrens } else if (acl_flavor & _ACL_ACE_ENABLED) { 917*789Sahrens (void) memcpy(min_ace_acl, trivial_acl, sizeof (ace_t) * 6); 918*789Sahrens 919*789Sahrens /* 920*789Sahrens * Make aces match request mode 921*789Sahrens */ 922*789Sahrens adjust_ace_pair(&min_ace_acl[0], (mode & 0700) >> 6); 923*789Sahrens adjust_ace_pair(&min_ace_acl[2], (mode & 0070) >> 3); 924*789Sahrens adjust_ace_pair(&min_ace_acl[4], mode & 0007); 925*789Sahrens 926*789Sahrens error = acl(file, ACE_SETACL, 6, min_ace_acl); 927*789Sahrens } else { 928*789Sahrens errno = EINVAL; 929*789Sahrens error = 1; 930*789Sahrens } 931*789Sahrens 932*789Sahrens if (error == 0) 933*789Sahrens error = chown(file, owner, group); 934*789Sahrens return (error); 935*789Sahrens } 936*789Sahrens 937*789Sahrens static int 938*789Sahrens ace_match(void *entry1, void *entry2) 939*789Sahrens { 940*789Sahrens ace_t *p1 = (ace_t *)entry1; 941*789Sahrens ace_t *p2 = (ace_t *)entry2; 942*789Sahrens ace_t ace1, ace2; 943*789Sahrens 944*789Sahrens ace1 = *p1; 945*789Sahrens ace2 = *p2; 946*789Sahrens 947*789Sahrens /* 948*789Sahrens * Need to fixup who field for abstrations for 949*789Sahrens * accurate comparison, since field is undefined. 950*789Sahrens */ 951*789Sahrens if (ace1.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE)) 952*789Sahrens ace1.a_who = -1; 953*789Sahrens if (ace2.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE)) 954*789Sahrens ace2.a_who = -1; 955*789Sahrens return (memcmp(&ace1, &ace2, sizeof (ace_t))); 956*789Sahrens } 957*789Sahrens 958*789Sahrens static int 959*789Sahrens aclent_match(void *entry1, void *entry2) 960*789Sahrens { 961*789Sahrens aclent_t *aclent1 = (aclent_t *)entry1; 962*789Sahrens aclent_t *aclent2 = (aclent_t *)entry2; 963*789Sahrens 964*789Sahrens return (memcmp(aclent1, aclent2, sizeof (aclent_t))); 965*789Sahrens } 966*789Sahrens 967*789Sahrens /* 968*789Sahrens * Find acl entries in acl that correspond to removeacl. Search 969*789Sahrens * is started from slot. The flag argument indicates whether to 970*789Sahrens * remove all matches or just the first match. 971*789Sahrens */ 972*789Sahrens int 973*789Sahrens acl_removeentries(acl_t *acl, acl_t *removeacl, int start_slot, int flag) 974*789Sahrens { 975*789Sahrens int i, j; 976*789Sahrens int match; 977*789Sahrens int (*acl_match)(void *acl1, void *acl2); 978*789Sahrens void *acl_entry, *remove_entry; 979*789Sahrens void *start; 980*789Sahrens int found = 0; 981*789Sahrens 982*789Sahrens if (flag != ACL_REMOVE_ALL && flag != ACL_REMOVE_FIRST) 983*789Sahrens flag = ACL_REMOVE_FIRST; 984*789Sahrens 985*789Sahrens if (acl == NULL || removeacl == NULL) 986*789Sahrens return (EACL_NO_ACL_ENTRY); 987*789Sahrens 988*789Sahrens if (acl->acl_type != removeacl->acl_type) 989*789Sahrens return (EACL_DIFF_TYPE); 990*789Sahrens 991*789Sahrens if (acl->acl_type == ACLENT_T) 992*789Sahrens acl_match = aclent_match; 993*789Sahrens else 994*789Sahrens acl_match = ace_match; 995*789Sahrens 996*789Sahrens for (i = 0, remove_entry = removeacl->acl_aclp; 997*789Sahrens i != removeacl->acl_cnt; i++) { 998*789Sahrens 999*789Sahrens j = 0; 1000*789Sahrens acl_entry = (char *)acl->acl_aclp + 1001*789Sahrens (acl->acl_entry_size * start_slot); 1002*789Sahrens for (;;) { 1003*789Sahrens match = acl_match(acl_entry, remove_entry); 1004*789Sahrens if (match == 0) { 1005*789Sahrens found++; 1006*789Sahrens start = (char *)acl_entry + 1007*789Sahrens acl->acl_entry_size; 1008*789Sahrens (void) memmove(acl_entry, start, 1009*789Sahrens acl->acl_entry_size * 1010*789Sahrens acl->acl_cnt-- - (j + 1)); 1011*789Sahrens 1012*789Sahrens if (flag == ACL_REMOVE_FIRST) 1013*789Sahrens break; 1014*789Sahrens /* 1015*789Sahrens * List has changed, restart search from 1016*789Sahrens * beginning. 1017*789Sahrens */ 1018*789Sahrens acl_entry = acl->acl_aclp; 1019*789Sahrens j = 0; 1020*789Sahrens continue; 1021*789Sahrens } 1022*789Sahrens acl_entry = ((char *)acl_entry + acl->acl_entry_size); 1023*789Sahrens if (++j >= acl->acl_cnt) { 1024*789Sahrens break; 1025*789Sahrens } 1026*789Sahrens } 1027*789Sahrens } 1028*789Sahrens 1029*789Sahrens return ((found == 0) ? EACL_NO_ACL_ENTRY : 0); 1030*789Sahrens } 1031*789Sahrens 1032*789Sahrens /* 1033*789Sahrens * Replace entires entries in acl1 with the corresponding entries 1034*789Sahrens * in newentries. The where argument specifies where to begin 1035*789Sahrens * the replacement. If the where argument is 1 greater than the 1036*789Sahrens * number of acl entries in acl1 then they are appended. If the 1037*789Sahrens * where argument is 2+ greater than the number of acl entries then 1038*789Sahrens * EACL_INVALID_SLOT is returned. 1039*789Sahrens */ 1040*789Sahrens int 1041*789Sahrens acl_modifyentries(acl_t *acl1, acl_t *newentries, int where) 1042*789Sahrens { 1043*789Sahrens 1044*789Sahrens int slot; 1045*789Sahrens int slots_needed; 1046*789Sahrens int slots_left; 1047*789Sahrens int newsize; 1048*789Sahrens 1049*789Sahrens if (acl1 == NULL || newentries == NULL) 1050*789Sahrens return (EACL_NO_ACL_ENTRY); 1051*789Sahrens 1052*789Sahrens if (where < 0 || where >= acl1->acl_cnt) 1053*789Sahrens return (EACL_INVALID_SLOT); 1054*789Sahrens 1055*789Sahrens if (acl1->acl_type != newentries->acl_type) 1056*789Sahrens return (EACL_DIFF_TYPE); 1057*789Sahrens 1058*789Sahrens slot = where; 1059*789Sahrens 1060*789Sahrens slots_left = acl1->acl_cnt - slot + 1; 1061*789Sahrens if (slots_left < newentries->acl_cnt) { 1062*789Sahrens slots_needed = newentries->acl_cnt - slots_left; 1063*789Sahrens newsize = (acl1->acl_entry_size * acl1->acl_cnt) + 1064*789Sahrens (acl1->acl_entry_size * slots_needed); 1065*789Sahrens acl1->acl_aclp = realloc(acl1->acl_aclp, newsize); 1066*789Sahrens if (acl1->acl_aclp == NULL) 1067*789Sahrens return (-1); 1068*789Sahrens } 1069*789Sahrens (void) memcpy((char *)acl1->acl_aclp + (acl1->acl_entry_size * slot), 1070*789Sahrens newentries->acl_aclp, 1071*789Sahrens newentries->acl_entry_size * newentries->acl_cnt); 1072*789Sahrens 1073*789Sahrens /* 1074*789Sahrens * Did ACL grow? 1075*789Sahrens */ 1076*789Sahrens 1077*789Sahrens if ((slot + newentries->acl_cnt) > acl1->acl_cnt) { 1078*789Sahrens acl1->acl_cnt = slot + newentries->acl_cnt; 1079*789Sahrens } 1080*789Sahrens 1081*789Sahrens return (0); 1082*789Sahrens } 1083*789Sahrens 1084*789Sahrens /* 1085*789Sahrens * Add acl2 entries into acl1. The where argument specifies where 1086*789Sahrens * to add the entries. 1087*789Sahrens */ 1088*789Sahrens int 1089*789Sahrens acl_addentries(acl_t *acl1, acl_t *acl2, int where) 1090*789Sahrens { 1091*789Sahrens 1092*789Sahrens int newsize; 1093*789Sahrens int len; 1094*789Sahrens void *start; 1095*789Sahrens void *to; 1096*789Sahrens 1097*789Sahrens if (acl1 == NULL || acl2 == NULL) 1098*789Sahrens return (EACL_NO_ACL_ENTRY); 1099*789Sahrens 1100*789Sahrens if (acl1->acl_type != acl2->acl_type) 1101*789Sahrens return (EACL_DIFF_TYPE); 1102*789Sahrens 1103*789Sahrens /* 1104*789Sahrens * allow where to specify 1 past last slot for an append operation 1105*789Sahrens * but anything greater is an error. 1106*789Sahrens */ 1107*789Sahrens if (where < 0 || where > acl1->acl_cnt) 1108*789Sahrens return (EACL_INVALID_SLOT); 1109*789Sahrens 1110*789Sahrens newsize = (acl2->acl_entry_size * acl2->acl_cnt) + 1111*789Sahrens (acl1->acl_entry_size * acl1->acl_cnt); 1112*789Sahrens acl1->acl_aclp = realloc(acl1->acl_aclp, newsize); 1113*789Sahrens if (acl1->acl_aclp == NULL) 1114*789Sahrens return (-1); 1115*789Sahrens 1116*789Sahrens /* 1117*789Sahrens * first push down entries where new ones will be inserted 1118*789Sahrens */ 1119*789Sahrens 1120*789Sahrens to = (void *)((char *)acl1->acl_aclp + 1121*789Sahrens ((where + acl2->acl_cnt) * acl1->acl_entry_size)); 1122*789Sahrens 1123*789Sahrens start = (void *)((char *)acl1->acl_aclp + 1124*789Sahrens where * acl1->acl_entry_size); 1125*789Sahrens 1126*789Sahrens if (where < acl1->acl_cnt) { 1127*789Sahrens len = (acl1->acl_cnt - where) * acl1->acl_entry_size; 1128*789Sahrens (void) memmove(to, start, len); 1129*789Sahrens } 1130*789Sahrens 1131*789Sahrens /* 1132*789Sahrens * now stick in new entries. 1133*789Sahrens */ 1134*789Sahrens 1135*789Sahrens (void) memmove(start, acl2->acl_aclp, 1136*789Sahrens acl2->acl_cnt * acl2->acl_entry_size); 1137*789Sahrens 1138*789Sahrens acl1->acl_cnt += acl2->acl_cnt; 1139*789Sahrens return (0); 1140*789Sahrens } 1141*789Sahrens 1142*789Sahrens static void 1143*789Sahrens aclent_perms(int perm, char *txt_perms) 1144*789Sahrens { 1145*789Sahrens if (perm & S_IROTH) 1146*789Sahrens txt_perms[0] = 'r'; 1147*789Sahrens else 1148*789Sahrens txt_perms[0] = '-'; 1149*789Sahrens if (perm & S_IWOTH) 1150*789Sahrens txt_perms[1] = 'w'; 1151*789Sahrens else 1152*789Sahrens txt_perms[1] = '-'; 1153*789Sahrens if (perm & S_IXOTH) 1154*789Sahrens txt_perms[2] = 'x'; 1155*789Sahrens else 1156*789Sahrens txt_perms[2] = '-'; 1157*789Sahrens txt_perms[3] = '\0'; 1158*789Sahrens } 1159*789Sahrens 1160*789Sahrens static char * 1161*789Sahrens pruname(uid_t uid) 1162*789Sahrens { 1163*789Sahrens struct passwd *passwdp; 1164*789Sahrens static char uidp[10]; /* big enough */ 1165*789Sahrens 1166*789Sahrens passwdp = getpwuid(uid); 1167*789Sahrens if (passwdp == (struct passwd *)NULL) { 1168*789Sahrens /* could not get passwd information: display uid instead */ 1169*789Sahrens (void) sprintf(uidp, "%ld", (long)uid); 1170*789Sahrens return (uidp); 1171*789Sahrens } else 1172*789Sahrens return (passwdp->pw_name); 1173*789Sahrens } 1174*789Sahrens 1175*789Sahrens static char * 1176*789Sahrens prgname(gid_t gid) 1177*789Sahrens { 1178*789Sahrens struct group *groupp; 1179*789Sahrens static char gidp[10]; /* big enough */ 1180*789Sahrens 1181*789Sahrens groupp = getgrgid(gid); 1182*789Sahrens if (groupp == (struct group *)NULL) { 1183*789Sahrens /* could not get group information: display gid instead */ 1184*789Sahrens (void) sprintf(gidp, "%ld", (long)gid); 1185*789Sahrens return (gidp); 1186*789Sahrens } else 1187*789Sahrens return (groupp->gr_name); 1188*789Sahrens } 1189*789Sahrens static void 1190*789Sahrens aclent_printacl(acl_t *aclp) 1191*789Sahrens { 1192*789Sahrens aclent_t *tp; 1193*789Sahrens int aclcnt; 1194*789Sahrens int mask; 1195*789Sahrens int slot = 0; 1196*789Sahrens char perm[4]; 1197*789Sahrens 1198*789Sahrens /* display ACL: assume it is sorted. */ 1199*789Sahrens aclcnt = aclp->acl_cnt; 1200*789Sahrens for (tp = aclp->acl_aclp; aclcnt--; tp++) { 1201*789Sahrens if (tp->a_type == CLASS_OBJ) 1202*789Sahrens mask = tp->a_perm; 1203*789Sahrens } 1204*789Sahrens aclcnt = aclp->acl_cnt; 1205*789Sahrens for (tp = aclp->acl_aclp; aclcnt--; tp++) { 1206*789Sahrens (void) printf(" %d:", slot++); 1207*789Sahrens switch (tp->a_type) { 1208*789Sahrens case USER: 1209*789Sahrens aclent_perms(tp->a_perm, perm); 1210*789Sahrens (void) printf("user:%s:%s\t\t", 1211*789Sahrens pruname(tp->a_id), perm); 1212*789Sahrens aclent_perms((tp->a_perm & mask), perm); 1213*789Sahrens (void) printf("#effective:%s\n", perm); 1214*789Sahrens break; 1215*789Sahrens case USER_OBJ: 1216*789Sahrens /* no need to display uid */ 1217*789Sahrens aclent_perms(tp->a_perm, perm); 1218*789Sahrens (void) printf("user::%s\n", perm); 1219*789Sahrens break; 1220*789Sahrens case GROUP: 1221*789Sahrens aclent_perms(tp->a_perm, perm); 1222*789Sahrens (void) printf("group:%s:%s\t\t", 1223*789Sahrens prgname(tp->a_id), perm); 1224*789Sahrens aclent_perms(tp->a_perm & mask, perm); 1225*789Sahrens (void) printf("#effective:%s\n", perm); 1226*789Sahrens break; 1227*789Sahrens case GROUP_OBJ: 1228*789Sahrens aclent_perms(tp->a_perm, perm); 1229*789Sahrens (void) printf("group::%s\t\t", perm); 1230*789Sahrens aclent_perms(tp->a_perm & mask, perm); 1231*789Sahrens (void) printf("#effective:%s\n", perm); 1232*789Sahrens break; 1233*789Sahrens case CLASS_OBJ: 1234*789Sahrens aclent_perms(tp->a_perm, perm); 1235*789Sahrens (void) printf("mask:%s\n", perm); 1236*789Sahrens break; 1237*789Sahrens case OTHER_OBJ: 1238*789Sahrens aclent_perms(tp->a_perm, perm); 1239*789Sahrens (void) printf("other:%s\n", perm); 1240*789Sahrens break; 1241*789Sahrens case DEF_USER: 1242*789Sahrens aclent_perms(tp->a_perm, perm); 1243*789Sahrens (void) printf("default:user:%s:%s\n", 1244*789Sahrens pruname(tp->a_id), perm); 1245*789Sahrens break; 1246*789Sahrens case DEF_USER_OBJ: 1247*789Sahrens aclent_perms(tp->a_perm, perm); 1248*789Sahrens (void) printf("default:user::%s\n", perm); 1249*789Sahrens break; 1250*789Sahrens case DEF_GROUP: 1251*789Sahrens aclent_perms(tp->a_perm, perm); 1252*789Sahrens (void) printf("default:group:%s:%s\n", 1253*789Sahrens prgname(tp->a_id), perm); 1254*789Sahrens break; 1255*789Sahrens case DEF_GROUP_OBJ: 1256*789Sahrens aclent_perms(tp->a_perm, perm); 1257*789Sahrens (void) printf("default:group::%s\n", perm); 1258*789Sahrens break; 1259*789Sahrens case DEF_CLASS_OBJ: 1260*789Sahrens aclent_perms(tp->a_perm, perm); 1261*789Sahrens (void) printf("default:mask:%s\n", perm); 1262*789Sahrens break; 1263*789Sahrens case DEF_OTHER_OBJ: 1264*789Sahrens aclent_perms(tp->a_perm, perm); 1265*789Sahrens (void) printf("default:other:%s\n", perm); 1266*789Sahrens break; 1267*789Sahrens default: 1268*789Sahrens (void) fprintf(stderr, 1269*789Sahrens gettext("unrecognized entry\n")); 1270*789Sahrens break; 1271*789Sahrens } 1272*789Sahrens } 1273*789Sahrens } 1274*789Sahrens 1275*789Sahrens static void 1276*789Sahrens split_line(char *str, int cols) 1277*789Sahrens { 1278*789Sahrens char *ptr; 1279*789Sahrens int len; 1280*789Sahrens int i; 1281*789Sahrens int last_split; 1282*789Sahrens char pad[11]; 1283*789Sahrens int pad_len; 1284*789Sahrens 1285*789Sahrens len = strlen(str); 1286*789Sahrens ptr = str; 1287*789Sahrens (void) strcpy(pad, ""); 1288*789Sahrens pad_len = 0; 1289*789Sahrens 1290*789Sahrens ptr = str; 1291*789Sahrens last_split = 0; 1292*789Sahrens for (i = 0; i != len; i++) { 1293*789Sahrens if ((i + pad_len + 4) >= cols) { 1294*789Sahrens (void) printf("%s%.*s\n", pad, last_split, ptr); 1295*789Sahrens ptr = &ptr[last_split]; 1296*789Sahrens len = strlen(ptr); 1297*789Sahrens i = 0; 1298*789Sahrens pad_len = 4; 1299*789Sahrens (void) strcpy(pad, " "); 1300*789Sahrens } else { 1301*789Sahrens if (ptr[i] == '/' || ptr[i] == ':') { 1302*789Sahrens last_split = i; 1303*789Sahrens } 1304*789Sahrens } 1305*789Sahrens } 1306*789Sahrens if (i == len) { 1307*789Sahrens (void) printf("%s%s\n", pad, ptr); 1308*789Sahrens } 1309*789Sahrens } 1310*789Sahrens 1311*789Sahrens static void 1312*789Sahrens ace_printacl(acl_t *aclp, int cols) 1313*789Sahrens { 1314*789Sahrens int slot = 0; 1315*789Sahrens char *token; 1316*789Sahrens char *acltext; 1317*789Sahrens 1318*789Sahrens acltext = acl_totext(aclp); 1319*789Sahrens 1320*789Sahrens if (acltext == NULL) 1321*789Sahrens return; 1322*789Sahrens 1323*789Sahrens token = strtok(acltext, ","); 1324*789Sahrens if (token == NULL) { 1325*789Sahrens free(acltext); 1326*789Sahrens return; 1327*789Sahrens } 1328*789Sahrens 1329*789Sahrens do { 1330*789Sahrens (void) printf(" %d:", slot++); 1331*789Sahrens split_line(token, cols - 5); 1332*789Sahrens } while (token = strtok(NULL, ",")); 1333*789Sahrens free(acltext); 1334*789Sahrens } 1335*789Sahrens 1336*789Sahrens /* 1337*789Sahrens * pretty print an ACL. 1338*789Sahrens * For aclent_t ACL's the format is 1339*789Sahrens * similar to the old format used by getfacl, 1340*789Sahrens * with the addition of adding a "slot" number 1341*789Sahrens * before each entry. 1342*789Sahrens * 1343*789Sahrens * for ace_t ACL's the cols variable will break up 1344*789Sahrens * the long lines into multiple lines and will also 1345*789Sahrens * print a "slot" number. 1346*789Sahrens */ 1347*789Sahrens void 1348*789Sahrens acl_printacl(acl_t *aclp, int cols) 1349*789Sahrens { 1350*789Sahrens 1351*789Sahrens switch (aclp->acl_type) { 1352*789Sahrens case ACLENT_T: 1353*789Sahrens aclent_printacl(aclp); 1354*789Sahrens break; 1355*789Sahrens case ACE_T: 1356*789Sahrens ace_printacl(aclp, cols); 1357*789Sahrens break; 1358*789Sahrens } 1359*789Sahrens } 1360*789Sahrens 1361*789Sahrens 1362*789Sahrens /* 1363*789Sahrens * return text for an ACL error. 1364*789Sahrens */ 1365*789Sahrens char * 1366*789Sahrens acl_strerror(int errnum) 1367*789Sahrens { 1368*789Sahrens switch (errnum) { 1369*789Sahrens case EACL_GRP_ERROR: 1370*789Sahrens return (dgettext(TEXT_DOMAIN, 1371*789Sahrens "There is more than one user group owner entry")); 1372*789Sahrens case EACL_USER_ERROR: 1373*789Sahrens return (dgettext(TEXT_DOMAIN, 1374*789Sahrens "There is more than one user owner entry")); 1375*789Sahrens case EACL_OTHER_ERROR: 1376*789Sahrens return (dgettext(TEXT_DOMAIN, 1377*789Sahrens "There is more than one other entry")); 1378*789Sahrens case EACL_CLASS_ERROR: 1379*789Sahrens return (dgettext(TEXT_DOMAIN, 1380*789Sahrens "There is more than one mask entry")); 1381*789Sahrens case EACL_DUPLICATE_ERROR: 1382*789Sahrens return (dgettext(TEXT_DOMAIN, 1383*789Sahrens "Duplicate user or group entries")); 1384*789Sahrens case EACL_MISS_ERROR: 1385*789Sahrens return (dgettext(TEXT_DOMAIN, 1386*789Sahrens "Missing user/group owner, other, mask entry")); 1387*789Sahrens case EACL_MEM_ERROR: 1388*789Sahrens return (dgettext(TEXT_DOMAIN, 1389*789Sahrens "Memory error")); 1390*789Sahrens case EACL_ENTRY_ERROR: 1391*789Sahrens return (dgettext(TEXT_DOMAIN, 1392*789Sahrens "Unrecognized entry type")); 1393*789Sahrens case EACL_INHERIT_ERROR: 1394*789Sahrens return (dgettext(TEXT_DOMAIN, 1395*789Sahrens "Invalid inheritance flags")); 1396*789Sahrens case EACL_FLAGS_ERROR: 1397*789Sahrens return (dgettext(TEXT_DOMAIN, 1398*789Sahrens "Unrecognized entry flags")); 1399*789Sahrens case EACL_PERM_MASK_ERROR: 1400*789Sahrens return (dgettext(TEXT_DOMAIN, 1401*789Sahrens "Invalid ACL permissions")); 1402*789Sahrens case EACL_COUNT_ERROR: 1403*789Sahrens return (dgettext(TEXT_DOMAIN, 1404*789Sahrens "Invalid ACL count")); 1405*789Sahrens case EACL_INVALID_SLOT: 1406*789Sahrens return (dgettext(TEXT_DOMAIN, 1407*789Sahrens "Invalid ACL entry number specified")); 1408*789Sahrens case EACL_NO_ACL_ENTRY: 1409*789Sahrens return (dgettext(TEXT_DOMAIN, 1410*789Sahrens "ACL entry doesn't exist")); 1411*789Sahrens case EACL_DIFF_TYPE: 1412*789Sahrens return (dgettext(TEXT_DOMAIN, 1413*789Sahrens "ACL type's are different")); 1414*789Sahrens case EACL_INVALID_USER_GROUP: 1415*789Sahrens return (dgettext(TEXT_DOMAIN, "Invalid user or group")); 1416*789Sahrens case EACL_INVALID_STR: 1417*789Sahrens return (dgettext(TEXT_DOMAIN, "ACL string is invalid")); 1418*789Sahrens case EACL_FIELD_NOT_BLANK: 1419*789Sahrens return (dgettext(TEXT_DOMAIN, "Field expected to be blank")); 1420*789Sahrens case EACL_INVALID_ACCESS_TYPE: 1421*789Sahrens return (dgettext(TEXT_DOMAIN, "Invalid access type")); 1422*789Sahrens case EACL_UNKNOWN_DATA: 1423*789Sahrens return (dgettext(TEXT_DOMAIN, "Unrecognized entry")); 1424*789Sahrens case EACL_MISSING_FIELDS: 1425*789Sahrens return (dgettext(TEXT_DOMAIN, 1426*789Sahrens "ACL specification missing required fields")); 1427*789Sahrens case EACL_INHERIT_NOTDIR: 1428*789Sahrens return (dgettext(TEXT_DOMAIN, 1429*789Sahrens "Inheritance flags are only allowed on directories")); 1430*789Sahrens case -1: 1431*789Sahrens return (strerror(errno)); 1432*789Sahrens default: 1433*789Sahrens errno = EINVAL; 1434*789Sahrens return (dgettext(TEXT_DOMAIN, "Unknown error")); 1435*789Sahrens } 1436*789Sahrens } 1437