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