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