1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 53eb3c573Smarks * Common Development and Distribution License (the "License"). 63eb3c573Smarks * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 21fa9e4066Sahrens /* 22d2443e76Smarks * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23fa9e4066Sahrens * Use is subject to license terms. 24fa9e4066Sahrens */ 25fa9e4066Sahrens 26fa9e4066Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 27fa9e4066Sahrens 28fa9e4066Sahrens #include <stdlib.h> 29fa9e4066Sahrens #include <string.h> 30fa9e4066Sahrens #include <unistd.h> 31fa9e4066Sahrens #include <limits.h> 32fa9e4066Sahrens #include <grp.h> 33fa9e4066Sahrens #include <pwd.h> 343eb3c573Smarks #include <strings.h> 35fa9e4066Sahrens #include <sys/types.h> 36fa9e4066Sahrens #include <sys/acl.h> 37fa9e4066Sahrens #include <errno.h> 38fa9e4066Sahrens #include <sys/stat.h> 395a5eeccaSmarks #include <sys/varargs.h> 40fa9e4066Sahrens #include <locale.h> 41fa9e4066Sahrens #include <aclutils.h> 42fa9e4066Sahrens #include <acl_common.h> 433eb3c573Smarks #include <sys/avl.h> 443eb3c573Smarks 453eb3c573Smarks #define offsetof(s, m) ((size_t)(&(((s *)0)->m))) 46fa9e4066Sahrens 47fa9e4066Sahrens #define ACL_PATH 0 48fa9e4066Sahrens #define ACL_FD 1 49fa9e4066Sahrens 50fa9e4066Sahrens #define ACE_POSIX_SUPPORTED_BITS (ACE_READ_DATA | \ 51fa9e4066Sahrens ACE_WRITE_DATA | ACE_APPEND_DATA | ACE_EXECUTE | \ 52fa9e4066Sahrens ACE_READ_ATTRIBUTES | ACE_READ_ACL | ACE_WRITE_ACL) 53fa9e4066Sahrens 54fa9e4066Sahrens 55fa9e4066Sahrens #define ACL_SYNCHRONIZE_SET_DENY 0x0000001 563eb3c573Smarks #define ACL_SYNCHRONIZE_SET_ALLOW 0x0000002 573eb3c573Smarks #define ACL_SYNCHRONIZE_ERR_DENY 0x0000004 583eb3c573Smarks #define ACL_SYNCHRONIZE_ERR_ALLOW 0x0000008 59fa9e4066Sahrens 60fa9e4066Sahrens #define ACL_WRITE_OWNER_SET_DENY 0x0000010 613eb3c573Smarks #define ACL_WRITE_OWNER_SET_ALLOW 0x0000020 623eb3c573Smarks #define ACL_WRITE_OWNER_ERR_DENY 0x0000040 633eb3c573Smarks #define ACL_WRITE_OWNER_ERR_ALLOW 0x0000080 64fa9e4066Sahrens 653eb3c573Smarks #define ACL_DELETE_SET_DENY 0x0000100 663eb3c573Smarks #define ACL_DELETE_SET_ALLOW 0x0000200 673eb3c573Smarks #define ACL_DELETE_ERR_DENY 0x0000400 683eb3c573Smarks #define ACL_DELETE_ERR_ALLOW 0x0000800 693eb3c573Smarks 70fa9e4066Sahrens #define ACL_WRITE_ATTRS_OWNER_SET_DENY 0x0001000 713eb3c573Smarks #define ACL_WRITE_ATTRS_OWNER_SET_ALLOW 0x0002000 723eb3c573Smarks #define ACL_WRITE_ATTRS_OWNER_ERR_DENY 0x0004000 733eb3c573Smarks #define ACL_WRITE_ATTRS_OWNER_ERR_ALLOW 0x0008000 74fa9e4066Sahrens 75fa9e4066Sahrens #define ACL_WRITE_ATTRS_WRITER_SET_DENY 0x0010000 76fa9e4066Sahrens #define ACL_WRITE_ATTRS_WRITER_SET_ALLOW 0x0020000 773eb3c573Smarks #define ACL_WRITE_ATTRS_WRITER_ERR_DENY 0x0040000 783eb3c573Smarks #define ACL_WRITE_ATTRS_WRITER_ERR_ALLOW 0x0080000 79fa9e4066Sahrens 803eb3c573Smarks #define ACL_WRITE_NAMED_WRITER_SET_DENY 0x0100000 813eb3c573Smarks #define ACL_WRITE_NAMED_WRITER_SET_ALLOW 0x0200000 823eb3c573Smarks #define ACL_WRITE_NAMED_WRITER_ERR_DENY 0x0400000 833eb3c573Smarks #define ACL_WRITE_NAMED_WRITER_ERR_ALLOW 0x0800000 843eb3c573Smarks 85fa9e4066Sahrens #define ACL_READ_NAMED_READER_SET_DENY 0x1000000 863eb3c573Smarks #define ACL_READ_NAMED_READER_SET_ALLOW 0x2000000 873eb3c573Smarks #define ACL_READ_NAMED_READER_ERR_DENY 0x4000000 883eb3c573Smarks #define ACL_READ_NAMED_READER_ERR_ALLOW 0x8000000 893eb3c573Smarks 903eb3c573Smarks 913eb3c573Smarks #define ACE_VALID_MASK_BITS (\ 923eb3c573Smarks ACE_READ_DATA | \ 933eb3c573Smarks ACE_LIST_DIRECTORY | \ 943eb3c573Smarks ACE_WRITE_DATA | \ 953eb3c573Smarks ACE_ADD_FILE | \ 963eb3c573Smarks ACE_APPEND_DATA | \ 973eb3c573Smarks ACE_ADD_SUBDIRECTORY | \ 983eb3c573Smarks ACE_READ_NAMED_ATTRS | \ 993eb3c573Smarks ACE_WRITE_NAMED_ATTRS | \ 1003eb3c573Smarks ACE_EXECUTE | \ 1013eb3c573Smarks ACE_DELETE_CHILD | \ 1023eb3c573Smarks ACE_READ_ATTRIBUTES | \ 1033eb3c573Smarks ACE_WRITE_ATTRIBUTES | \ 1043eb3c573Smarks ACE_DELETE | \ 1053eb3c573Smarks ACE_READ_ACL | \ 1063eb3c573Smarks ACE_WRITE_ACL | \ 1073eb3c573Smarks ACE_WRITE_OWNER | \ 1083eb3c573Smarks ACE_SYNCHRONIZE) 1093eb3c573Smarks 1103eb3c573Smarks #define ACE_MASK_UNDEFINED 0x80000000 1113eb3c573Smarks 1123eb3c573Smarks #define ACE_VALID_FLAG_BITS (ACE_FILE_INHERIT_ACE | \ 1133eb3c573Smarks ACE_DIRECTORY_INHERIT_ACE | \ 1143eb3c573Smarks ACE_NO_PROPAGATE_INHERIT_ACE | ACE_INHERIT_ONLY_ACE | \ 1153eb3c573Smarks ACE_SUCCESSFUL_ACCESS_ACE_FLAG | ACE_FAILED_ACCESS_ACE_FLAG | \ 1163eb3c573Smarks ACE_IDENTIFIER_GROUP | ACE_OWNER | ACE_GROUP | ACE_EVERYONE) 1173eb3c573Smarks 1183eb3c573Smarks /* 1193eb3c573Smarks * ACL conversion helpers 1203eb3c573Smarks */ 1213eb3c573Smarks 1223eb3c573Smarks typedef enum { 1233eb3c573Smarks ace_unused, 1243eb3c573Smarks ace_user_obj, 1253eb3c573Smarks ace_user, 1263eb3c573Smarks ace_group, /* includes GROUP and GROUP_OBJ */ 1273eb3c573Smarks ace_other_obj 1283eb3c573Smarks } ace_to_aent_state_t; 1293eb3c573Smarks 1303eb3c573Smarks typedef struct acevals { 1313eb3c573Smarks uid_t key; 1323eb3c573Smarks avl_node_t avl; 1333eb3c573Smarks uint32_t mask; 1343eb3c573Smarks uint32_t allowed; 1353eb3c573Smarks uint32_t denied; 1363eb3c573Smarks int aent_type; 1373eb3c573Smarks } acevals_t; 1383eb3c573Smarks 1393eb3c573Smarks typedef struct ace_list { 1403eb3c573Smarks acevals_t user_obj; 1413eb3c573Smarks avl_tree_t user; 1423eb3c573Smarks int numusers; 1433eb3c573Smarks acevals_t group_obj; 1443eb3c573Smarks avl_tree_t group; 1453eb3c573Smarks int numgroups; 1463eb3c573Smarks acevals_t other_obj; 1473eb3c573Smarks uint32_t acl_mask; 1483eb3c573Smarks int hasmask; 1493eb3c573Smarks int dfacl_flag; 1503eb3c573Smarks ace_to_aent_state_t state; 1513eb3c573Smarks int seen; /* bitmask of all aclent_t a_type values seen */ 1523eb3c573Smarks } ace_list_t; 153d2443e76Smarks 154fa9e4066Sahrens typedef union { 155fa9e4066Sahrens const char *file; 156fa9e4066Sahrens int fd; 157fa9e4066Sahrens } acl_inp; 158fa9e4066Sahrens 159fa9e4066Sahrens acl_t * 160fa9e4066Sahrens acl_alloc(enum acl_type type) 161fa9e4066Sahrens { 162fa9e4066Sahrens acl_t *aclp; 163fa9e4066Sahrens 164fa9e4066Sahrens aclp = malloc(sizeof (acl_t)); 165fa9e4066Sahrens 166fa9e4066Sahrens if (aclp == NULL) 167fa9e4066Sahrens return (NULL); 168fa9e4066Sahrens 169fa9e4066Sahrens aclp->acl_aclp = NULL; 170fa9e4066Sahrens aclp->acl_cnt = 0; 171fa9e4066Sahrens 172fa9e4066Sahrens switch (type) { 173fa9e4066Sahrens case ACE_T: 174fa9e4066Sahrens aclp->acl_type = ACE_T; 175fa9e4066Sahrens aclp->acl_entry_size = sizeof (ace_t); 176fa9e4066Sahrens break; 177fa9e4066Sahrens case ACLENT_T: 178fa9e4066Sahrens aclp->acl_type = ACLENT_T; 179fa9e4066Sahrens aclp->acl_entry_size = sizeof (aclent_t); 180fa9e4066Sahrens break; 181fa9e4066Sahrens default: 182fa9e4066Sahrens acl_free(aclp); 183fa9e4066Sahrens aclp = NULL; 184fa9e4066Sahrens } 185fa9e4066Sahrens return (aclp); 186fa9e4066Sahrens } 187fa9e4066Sahrens 188fa9e4066Sahrens /* 189fa9e4066Sahrens * Free acl_t structure 190fa9e4066Sahrens */ 191fa9e4066Sahrens void 192fa9e4066Sahrens acl_free(acl_t *aclp) 193fa9e4066Sahrens { 194fa9e4066Sahrens if (aclp == NULL) 195fa9e4066Sahrens return; 196fa9e4066Sahrens 197fa9e4066Sahrens if (aclp->acl_aclp) 198fa9e4066Sahrens free(aclp->acl_aclp); 199fa9e4066Sahrens free(aclp); 200fa9e4066Sahrens } 201fa9e4066Sahrens 202fa9e4066Sahrens /* 203fa9e4066Sahrens * Determine whether a file has a trivial ACL 204fa9e4066Sahrens * returns: 0 = trivial 205fa9e4066Sahrens * 1 = nontrivial 206fa9e4066Sahrens * <0 some other system failure, such as ENOENT or EPERM 207fa9e4066Sahrens */ 208fa9e4066Sahrens int 209fa9e4066Sahrens acl_trivial(const char *filename) 210fa9e4066Sahrens { 211fa9e4066Sahrens int acl_flavor; 212fa9e4066Sahrens int aclcnt; 213fa9e4066Sahrens int cntcmd; 214fa9e4066Sahrens int val = 0; 215fa9e4066Sahrens ace_t *acep; 216fa9e4066Sahrens 217fa9e4066Sahrens acl_flavor = pathconf(filename, _PC_ACL_ENABLED); 218fa9e4066Sahrens 219fa9e4066Sahrens if (acl_flavor == _ACL_ACE_ENABLED) 220fa9e4066Sahrens cntcmd = ACE_GETACLCNT; 221fa9e4066Sahrens else 222fa9e4066Sahrens cntcmd = GETACLCNT; 223fa9e4066Sahrens 224fa9e4066Sahrens aclcnt = acl(filename, cntcmd, 0, NULL); 225fa9e4066Sahrens if (aclcnt > 0) { 226fa9e4066Sahrens if (acl_flavor == _ACL_ACE_ENABLED) { 227fa9e4066Sahrens acep = malloc(sizeof (ace_t) * aclcnt); 228fa9e4066Sahrens if (acep == NULL) 229fa9e4066Sahrens return (-1); 230fa9e4066Sahrens if (acl(filename, ACE_GETACL, 231fa9e4066Sahrens aclcnt, acep) < 0) { 232fa9e4066Sahrens free(acep); 233fa9e4066Sahrens return (-1); 234fa9e4066Sahrens } 235fa9e4066Sahrens 236fa9e4066Sahrens val = ace_trivial(acep, aclcnt); 237fa9e4066Sahrens free(acep); 238d2443e76Smarks 239fa9e4066Sahrens } else if (aclcnt > MIN_ACL_ENTRIES) 240fa9e4066Sahrens val = 1; 241fa9e4066Sahrens } 242fa9e4066Sahrens return (val); 243fa9e4066Sahrens } 244fa9e4066Sahrens 245fa9e4066Sahrens static uint32_t 246fa9e4066Sahrens access_mask_set(int haswriteperm, int hasreadperm, int isowner, int isallow) 247fa9e4066Sahrens { 248fa9e4066Sahrens uint32_t access_mask = 0; 249fa9e4066Sahrens int acl_produce; 250fa9e4066Sahrens int synchronize_set = 0, write_owner_set = 0; 251fa9e4066Sahrens int delete_set = 0, write_attrs_set = 0; 252fa9e4066Sahrens int read_named_set = 0, write_named_set = 0; 253fa9e4066Sahrens 254fa9e4066Sahrens acl_produce = (ACL_SYNCHRONIZE_SET_ALLOW | 255fa9e4066Sahrens ACL_WRITE_ATTRS_OWNER_SET_ALLOW | 256fa9e4066Sahrens ACL_WRITE_ATTRS_WRITER_SET_DENY); 257fa9e4066Sahrens 258fa9e4066Sahrens if (isallow) { 259fa9e4066Sahrens synchronize_set = ACL_SYNCHRONIZE_SET_ALLOW; 260fa9e4066Sahrens write_owner_set = ACL_WRITE_OWNER_SET_ALLOW; 261fa9e4066Sahrens delete_set = ACL_DELETE_SET_ALLOW; 262fa9e4066Sahrens if (hasreadperm) 263fa9e4066Sahrens read_named_set = ACL_READ_NAMED_READER_SET_ALLOW; 264fa9e4066Sahrens if (haswriteperm) 265fa9e4066Sahrens write_named_set = ACL_WRITE_NAMED_WRITER_SET_ALLOW; 266fa9e4066Sahrens if (isowner) 267fa9e4066Sahrens write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_ALLOW; 268fa9e4066Sahrens else if (haswriteperm) 269fa9e4066Sahrens write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_ALLOW; 270fa9e4066Sahrens } else { 271fa9e4066Sahrens 272fa9e4066Sahrens synchronize_set = ACL_SYNCHRONIZE_SET_DENY; 273fa9e4066Sahrens write_owner_set = ACL_WRITE_OWNER_SET_DENY; 274fa9e4066Sahrens delete_set = ACL_DELETE_SET_DENY; 275fa9e4066Sahrens if (hasreadperm) 276fa9e4066Sahrens read_named_set = ACL_READ_NAMED_READER_SET_DENY; 277fa9e4066Sahrens if (haswriteperm) 278fa9e4066Sahrens write_named_set = ACL_WRITE_NAMED_WRITER_SET_DENY; 279fa9e4066Sahrens if (isowner) 280fa9e4066Sahrens write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_DENY; 281fa9e4066Sahrens else if (haswriteperm) 282fa9e4066Sahrens write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_DENY; 283fa9e4066Sahrens else 284fa9e4066Sahrens /* 285fa9e4066Sahrens * If the entity is not the owner and does not 286fa9e4066Sahrens * have write permissions ACE_WRITE_ATTRIBUTES will 287fa9e4066Sahrens * always go in the DENY ACE. 288fa9e4066Sahrens */ 289fa9e4066Sahrens access_mask |= ACE_WRITE_ATTRIBUTES; 290fa9e4066Sahrens } 291fa9e4066Sahrens 292fa9e4066Sahrens if (acl_produce & synchronize_set) 293fa9e4066Sahrens access_mask |= ACE_SYNCHRONIZE; 294fa9e4066Sahrens if (acl_produce & write_owner_set) 295fa9e4066Sahrens access_mask |= ACE_WRITE_OWNER; 296fa9e4066Sahrens if (acl_produce & delete_set) 297fa9e4066Sahrens access_mask |= ACE_DELETE; 298fa9e4066Sahrens if (acl_produce & write_attrs_set) 299fa9e4066Sahrens access_mask |= ACE_WRITE_ATTRIBUTES; 300fa9e4066Sahrens if (acl_produce & read_named_set) 301fa9e4066Sahrens access_mask |= ACE_READ_NAMED_ATTRS; 302fa9e4066Sahrens if (acl_produce & write_named_set) 303fa9e4066Sahrens access_mask |= ACE_WRITE_NAMED_ATTRS; 304fa9e4066Sahrens 305fa9e4066Sahrens return (access_mask); 306fa9e4066Sahrens } 307fa9e4066Sahrens 308fa9e4066Sahrens /* 309fa9e4066Sahrens * Given an mode_t, convert it into an access_mask as used 310fa9e4066Sahrens * by nfsace, assuming aclent_t -> nfsace semantics. 311fa9e4066Sahrens */ 312fa9e4066Sahrens static uint32_t 313fa9e4066Sahrens mode_to_ace_access(mode_t mode, int isdir, int isowner, int isallow) 314fa9e4066Sahrens { 315fa9e4066Sahrens uint32_t access = 0; 316fa9e4066Sahrens int haswriteperm = 0; 317fa9e4066Sahrens int hasreadperm = 0; 318fa9e4066Sahrens 319fa9e4066Sahrens if (isallow) { 320fa9e4066Sahrens haswriteperm = (mode & 02); 321fa9e4066Sahrens hasreadperm = (mode & 04); 322fa9e4066Sahrens } else { 323fa9e4066Sahrens haswriteperm = !(mode & 02); 324fa9e4066Sahrens hasreadperm = !(mode & 04); 325fa9e4066Sahrens } 326fa9e4066Sahrens 327fa9e4066Sahrens /* 328fa9e4066Sahrens * The following call takes care of correctly setting the following 329fa9e4066Sahrens * mask bits in the access_mask: 330fa9e4066Sahrens * ACE_SYNCHRONIZE, ACE_WRITE_OWNER, ACE_DELETE, 331fa9e4066Sahrens * ACE_WRITE_ATTRIBUTES, ACE_WRITE_NAMED_ATTRS, ACE_READ_NAMED_ATTRS 332fa9e4066Sahrens */ 333fa9e4066Sahrens access = access_mask_set(haswriteperm, hasreadperm, isowner, isallow); 334fa9e4066Sahrens 335fa9e4066Sahrens if (isallow) { 336fa9e4066Sahrens access |= ACE_READ_ACL | ACE_READ_ATTRIBUTES; 337fa9e4066Sahrens if (isowner) 338fa9e4066Sahrens access |= ACE_WRITE_ACL; 339fa9e4066Sahrens } else { 340fa9e4066Sahrens if (! isowner) 341fa9e4066Sahrens access |= ACE_WRITE_ACL; 342fa9e4066Sahrens } 343fa9e4066Sahrens 344fa9e4066Sahrens /* read */ 345fa9e4066Sahrens if (mode & 04) { 346fa9e4066Sahrens access |= ACE_READ_DATA; 347fa9e4066Sahrens } 348fa9e4066Sahrens /* write */ 349fa9e4066Sahrens if (mode & 02) { 350fa9e4066Sahrens access |= ACE_WRITE_DATA | 351fa9e4066Sahrens ACE_APPEND_DATA; 352fa9e4066Sahrens if (isdir) 353fa9e4066Sahrens access |= ACE_DELETE_CHILD; 354fa9e4066Sahrens } 355fa9e4066Sahrens /* exec */ 356fa9e4066Sahrens if (mode & 01) { 357fa9e4066Sahrens access |= ACE_EXECUTE; 358fa9e4066Sahrens } 359fa9e4066Sahrens 360fa9e4066Sahrens return (access); 361fa9e4066Sahrens } 362fa9e4066Sahrens 363fa9e4066Sahrens /* 364fa9e4066Sahrens * Given an nfsace (presumably an ALLOW entry), make a 365fa9e4066Sahrens * corresponding DENY entry at the address given. 366fa9e4066Sahrens */ 367fa9e4066Sahrens static void 368fa9e4066Sahrens ace_make_deny(ace_t *allow, ace_t *deny, int isdir, int isowner) 369fa9e4066Sahrens { 370fa9e4066Sahrens (void) memcpy(deny, allow, sizeof (ace_t)); 371fa9e4066Sahrens 372fa9e4066Sahrens deny->a_who = allow->a_who; 373fa9e4066Sahrens 374fa9e4066Sahrens deny->a_type = ACE_ACCESS_DENIED_ACE_TYPE; 375fa9e4066Sahrens deny->a_access_mask ^= ACE_POSIX_SUPPORTED_BITS; 376fa9e4066Sahrens if (isdir) 377fa9e4066Sahrens deny->a_access_mask ^= ACE_DELETE_CHILD; 378fa9e4066Sahrens 379fa9e4066Sahrens deny->a_access_mask &= ~(ACE_SYNCHRONIZE | ACE_WRITE_OWNER | 380fa9e4066Sahrens ACE_DELETE | ACE_WRITE_ATTRIBUTES | ACE_READ_NAMED_ATTRS | 381fa9e4066Sahrens ACE_WRITE_NAMED_ATTRS); 382fa9e4066Sahrens deny->a_access_mask |= access_mask_set((allow->a_access_mask & 383fa9e4066Sahrens ACE_WRITE_DATA), (allow->a_access_mask & ACE_READ_DATA), isowner, 384fa9e4066Sahrens B_FALSE); 385fa9e4066Sahrens } 386fa9e4066Sahrens /* 387fa9e4066Sahrens * Make an initial pass over an array of aclent_t's. Gather 388fa9e4066Sahrens * information such as an ACL_MASK (if any), number of users, 389fa9e4066Sahrens * number of groups, and whether the array needs to be sorted. 390fa9e4066Sahrens */ 391fa9e4066Sahrens static int 392fa9e4066Sahrens ln_aent_preprocess(aclent_t *aclent, int n, 393fa9e4066Sahrens int *hasmask, mode_t *mask, 394fa9e4066Sahrens int *numuser, int *numgroup, int *needsort) 395fa9e4066Sahrens { 396fa9e4066Sahrens int error = 0; 397fa9e4066Sahrens int i; 398fa9e4066Sahrens int curtype = 0; 399fa9e4066Sahrens 400fa9e4066Sahrens *hasmask = 0; 401fa9e4066Sahrens *mask = 07; 402fa9e4066Sahrens *needsort = 0; 403fa9e4066Sahrens *numuser = 0; 404fa9e4066Sahrens *numgroup = 0; 405fa9e4066Sahrens 406fa9e4066Sahrens for (i = 0; i < n; i++) { 407fa9e4066Sahrens if (aclent[i].a_type < curtype) 408fa9e4066Sahrens *needsort = 1; 409fa9e4066Sahrens else if (aclent[i].a_type > curtype) 410fa9e4066Sahrens curtype = aclent[i].a_type; 411fa9e4066Sahrens if (aclent[i].a_type & USER) 412fa9e4066Sahrens (*numuser)++; 413fa9e4066Sahrens if (aclent[i].a_type & (GROUP | GROUP_OBJ)) 414fa9e4066Sahrens (*numgroup)++; 415fa9e4066Sahrens if (aclent[i].a_type & CLASS_OBJ) { 416fa9e4066Sahrens if (*hasmask) { 417fa9e4066Sahrens error = EINVAL; 418fa9e4066Sahrens goto out; 419fa9e4066Sahrens } else { 420fa9e4066Sahrens *hasmask = 1; 421fa9e4066Sahrens *mask = aclent[i].a_perm; 422fa9e4066Sahrens } 423fa9e4066Sahrens } 424fa9e4066Sahrens } 425fa9e4066Sahrens 426fa9e4066Sahrens if ((! *hasmask) && (*numuser + *numgroup > 1)) { 427fa9e4066Sahrens error = EINVAL; 428fa9e4066Sahrens goto out; 429fa9e4066Sahrens } 430fa9e4066Sahrens 431fa9e4066Sahrens out: 432fa9e4066Sahrens return (error); 433fa9e4066Sahrens } 434fa9e4066Sahrens 435fa9e4066Sahrens /* 436fa9e4066Sahrens * Convert an array of aclent_t into an array of nfsace entries, 437fa9e4066Sahrens * following POSIX draft -> nfsv4 conversion semantics as outlined in 438fa9e4066Sahrens * the IETF draft. 439fa9e4066Sahrens */ 440fa9e4066Sahrens static int 441fa9e4066Sahrens ln_aent_to_ace(aclent_t *aclent, int n, ace_t **acepp, int *rescount, int isdir) 442fa9e4066Sahrens { 443fa9e4066Sahrens int error = 0; 444fa9e4066Sahrens mode_t mask; 445fa9e4066Sahrens int numuser, numgroup, needsort; 446fa9e4066Sahrens int resultsize = 0; 447fa9e4066Sahrens int i, groupi = 0, skip; 448fa9e4066Sahrens ace_t *acep, *result = NULL; 449fa9e4066Sahrens int hasmask; 450fa9e4066Sahrens 451fa9e4066Sahrens error = ln_aent_preprocess(aclent, n, &hasmask, &mask, 452fa9e4066Sahrens &numuser, &numgroup, &needsort); 453fa9e4066Sahrens if (error != 0) 454fa9e4066Sahrens goto out; 455fa9e4066Sahrens 456fa9e4066Sahrens /* allow + deny for each aclent */ 457fa9e4066Sahrens resultsize = n * 2; 458fa9e4066Sahrens if (hasmask) { 459fa9e4066Sahrens /* 460fa9e4066Sahrens * stick extra deny on the group_obj and on each 461fa9e4066Sahrens * user|group for the mask (the group_obj was added 462fa9e4066Sahrens * into the count for numgroup) 463fa9e4066Sahrens */ 464fa9e4066Sahrens resultsize += numuser + numgroup; 465fa9e4066Sahrens /* ... and don't count the mask itself */ 466fa9e4066Sahrens resultsize -= 2; 467fa9e4066Sahrens } 468fa9e4066Sahrens 469fa9e4066Sahrens /* sort the source if necessary */ 470fa9e4066Sahrens if (needsort) 471fa9e4066Sahrens ksort((caddr_t)aclent, n, sizeof (aclent_t), cmp2acls); 472fa9e4066Sahrens 473fa9e4066Sahrens result = acep = calloc(1, resultsize * sizeof (ace_t)); 474fa9e4066Sahrens if (result == NULL) 475fa9e4066Sahrens goto out; 476fa9e4066Sahrens 477fa9e4066Sahrens for (i = 0; i < n; i++) { 478fa9e4066Sahrens /* 479fa9e4066Sahrens * don't process CLASS_OBJ (mask); mask was grabbed in 480fa9e4066Sahrens * ln_aent_preprocess() 481fa9e4066Sahrens */ 482fa9e4066Sahrens if (aclent[i].a_type & CLASS_OBJ) 483fa9e4066Sahrens continue; 484fa9e4066Sahrens 485fa9e4066Sahrens /* If we need an ACL_MASK emulator, prepend it now */ 486fa9e4066Sahrens if ((hasmask) && 487fa9e4066Sahrens (aclent[i].a_type & (USER | GROUP | GROUP_OBJ))) { 488fa9e4066Sahrens acep->a_type = ACE_ACCESS_DENIED_ACE_TYPE; 489fa9e4066Sahrens acep->a_flags = 0; 490fa9e4066Sahrens if (aclent[i].a_type & GROUP_OBJ) { 491fa9e4066Sahrens acep->a_who = -1; 492fa9e4066Sahrens acep->a_flags |= 493fa9e4066Sahrens (ACE_IDENTIFIER_GROUP|ACE_GROUP); 494fa9e4066Sahrens } else if (aclent[i].a_type & USER) { 495fa9e4066Sahrens acep->a_who = aclent[i].a_id; 496fa9e4066Sahrens } else { 497fa9e4066Sahrens acep->a_who = aclent[i].a_id; 498fa9e4066Sahrens acep->a_flags |= ACE_IDENTIFIER_GROUP; 499fa9e4066Sahrens } 500fa9e4066Sahrens if (aclent[i].a_type & ACL_DEFAULT) { 501fa9e4066Sahrens acep->a_flags |= ACE_INHERIT_ONLY_ACE | 502fa9e4066Sahrens ACE_FILE_INHERIT_ACE | 503fa9e4066Sahrens ACE_DIRECTORY_INHERIT_ACE; 504fa9e4066Sahrens } 505fa9e4066Sahrens /* 506fa9e4066Sahrens * Set the access mask for the prepended deny 507fa9e4066Sahrens * ace. To do this, we invert the mask (found 508fa9e4066Sahrens * in ln_aent_preprocess()) then convert it to an 509fa9e4066Sahrens * DENY ace access_mask. 510fa9e4066Sahrens */ 511fa9e4066Sahrens acep->a_access_mask = mode_to_ace_access((mask ^ 07), 512fa9e4066Sahrens isdir, 0, 0); 513fa9e4066Sahrens acep += 1; 514fa9e4066Sahrens } 515fa9e4066Sahrens 516fa9e4066Sahrens /* handle a_perm -> access_mask */ 517fa9e4066Sahrens acep->a_access_mask = mode_to_ace_access(aclent[i].a_perm, 518fa9e4066Sahrens isdir, aclent[i].a_type & USER_OBJ, 1); 519fa9e4066Sahrens 520fa9e4066Sahrens /* emulate a default aclent */ 521fa9e4066Sahrens if (aclent[i].a_type & ACL_DEFAULT) { 522fa9e4066Sahrens acep->a_flags |= ACE_INHERIT_ONLY_ACE | 523fa9e4066Sahrens ACE_FILE_INHERIT_ACE | 524fa9e4066Sahrens ACE_DIRECTORY_INHERIT_ACE; 525fa9e4066Sahrens } 526fa9e4066Sahrens 527fa9e4066Sahrens /* 528fa9e4066Sahrens * handle a_perm and a_id 529fa9e4066Sahrens * 530fa9e4066Sahrens * this must be done last, since it involves the 531fa9e4066Sahrens * corresponding deny aces, which are handled 532fa9e4066Sahrens * differently for each different a_type. 533fa9e4066Sahrens */ 534fa9e4066Sahrens if (aclent[i].a_type & USER_OBJ) { 535fa9e4066Sahrens acep->a_who = -1; 536fa9e4066Sahrens acep->a_flags |= ACE_OWNER; 537fa9e4066Sahrens ace_make_deny(acep, acep + 1, isdir, B_TRUE); 538fa9e4066Sahrens acep += 2; 539fa9e4066Sahrens } else if (aclent[i].a_type & USER) { 540fa9e4066Sahrens acep->a_who = aclent[i].a_id; 541fa9e4066Sahrens ace_make_deny(acep, acep + 1, isdir, B_FALSE); 542fa9e4066Sahrens acep += 2; 543fa9e4066Sahrens } else if (aclent[i].a_type & (GROUP_OBJ | GROUP)) { 544fa9e4066Sahrens if (aclent[i].a_type & GROUP_OBJ) { 545fa9e4066Sahrens acep->a_who = -1; 546fa9e4066Sahrens acep->a_flags |= ACE_GROUP; 547fa9e4066Sahrens } else { 548fa9e4066Sahrens acep->a_who = aclent[i].a_id; 549fa9e4066Sahrens } 550fa9e4066Sahrens acep->a_flags |= ACE_IDENTIFIER_GROUP; 551fa9e4066Sahrens /* 552fa9e4066Sahrens * Set the corresponding deny for the group ace. 553fa9e4066Sahrens * 554fa9e4066Sahrens * The deny aces go after all of the groups, unlike 555fa9e4066Sahrens * everything else, where they immediately follow 556fa9e4066Sahrens * the allow ace. 557fa9e4066Sahrens * 558fa9e4066Sahrens * We calculate "skip", the number of slots to 559fa9e4066Sahrens * skip ahead for the deny ace, here. 560fa9e4066Sahrens * 561fa9e4066Sahrens * The pattern is: 562fa9e4066Sahrens * MD1 A1 MD2 A2 MD3 A3 D1 D2 D3 563fa9e4066Sahrens * thus, skip is 564fa9e4066Sahrens * (2 * numgroup) - 1 - groupi 565fa9e4066Sahrens * (2 * numgroup) to account for MD + A 566fa9e4066Sahrens * - 1 to account for the fact that we're on the 567fa9e4066Sahrens * access (A), not the mask (MD) 568fa9e4066Sahrens * - groupi to account for the fact that we have 569fa9e4066Sahrens * passed up groupi number of MD's. 570fa9e4066Sahrens */ 571fa9e4066Sahrens skip = (2 * numgroup) - 1 - groupi; 572fa9e4066Sahrens ace_make_deny(acep, acep + skip, isdir, B_FALSE); 573fa9e4066Sahrens /* 574fa9e4066Sahrens * If we just did the last group, skip acep past 575fa9e4066Sahrens * all of the denies; else, just move ahead one. 576fa9e4066Sahrens */ 577fa9e4066Sahrens if (++groupi >= numgroup) 578fa9e4066Sahrens acep += numgroup + 1; 579fa9e4066Sahrens else 580fa9e4066Sahrens acep += 1; 581fa9e4066Sahrens } else if (aclent[i].a_type & OTHER_OBJ) { 582fa9e4066Sahrens acep->a_who = -1; 583fa9e4066Sahrens acep->a_flags |= ACE_EVERYONE; 584fa9e4066Sahrens ace_make_deny(acep, acep + 1, isdir, B_FALSE); 585fa9e4066Sahrens acep += 2; 586fa9e4066Sahrens } else { 587fa9e4066Sahrens error = EINVAL; 588fa9e4066Sahrens goto out; 589fa9e4066Sahrens } 590fa9e4066Sahrens } 591fa9e4066Sahrens 592fa9e4066Sahrens *acepp = result; 593fa9e4066Sahrens *rescount = resultsize; 594fa9e4066Sahrens 595fa9e4066Sahrens out: 596fa9e4066Sahrens if (error != 0) { 597fa9e4066Sahrens if ((result != NULL) && (resultsize > 0)) { 598fa9e4066Sahrens free(result); 599fa9e4066Sahrens } 600fa9e4066Sahrens } 601fa9e4066Sahrens 602fa9e4066Sahrens return (error); 603fa9e4066Sahrens } 604fa9e4066Sahrens 605fa9e4066Sahrens static int 606fa9e4066Sahrens convert_aent_to_ace(aclent_t *aclentp, int aclcnt, int isdir, 607fa9e4066Sahrens ace_t **retacep, int *retacecnt) 608fa9e4066Sahrens { 609fa9e4066Sahrens ace_t *acep; 610fa9e4066Sahrens ace_t *dfacep; 611fa9e4066Sahrens int acecnt = 0; 612fa9e4066Sahrens int dfacecnt = 0; 613fa9e4066Sahrens int dfaclstart = 0; 614fa9e4066Sahrens int dfaclcnt = 0; 615fa9e4066Sahrens aclent_t *aclp; 616fa9e4066Sahrens int i; 617fa9e4066Sahrens int error; 618fa9e4066Sahrens 619fa9e4066Sahrens ksort((caddr_t)aclentp, aclcnt, sizeof (aclent_t), cmp2acls); 620fa9e4066Sahrens 621fa9e4066Sahrens for (i = 0, aclp = aclentp; i < aclcnt; aclp++, i++) { 622fa9e4066Sahrens if (aclp->a_type & ACL_DEFAULT) 623fa9e4066Sahrens break; 624fa9e4066Sahrens } 625fa9e4066Sahrens 626fa9e4066Sahrens if (i < aclcnt) { 6273eb3c573Smarks dfaclstart = i; 6283eb3c573Smarks dfaclcnt = aclcnt - i; 629fa9e4066Sahrens } 630fa9e4066Sahrens 631fa9e4066Sahrens if (dfaclcnt && isdir == 0) { 632fa9e4066Sahrens return (-1); 633fa9e4066Sahrens } 634fa9e4066Sahrens 635fa9e4066Sahrens error = ln_aent_to_ace(aclentp, i, &acep, &acecnt, isdir); 636fa9e4066Sahrens if (error) 637fa9e4066Sahrens return (-1); 638fa9e4066Sahrens 639fa9e4066Sahrens if (dfaclcnt) { 640fa9e4066Sahrens error = ln_aent_to_ace(&aclentp[dfaclstart], dfaclcnt, 641fa9e4066Sahrens &dfacep, &dfacecnt, isdir); 642fa9e4066Sahrens if (error) { 643fa9e4066Sahrens if (acep) { 644fa9e4066Sahrens free(acep); 645fa9e4066Sahrens } 646fa9e4066Sahrens return (-1); 647fa9e4066Sahrens } 648fa9e4066Sahrens } 649fa9e4066Sahrens 6503eb3c573Smarks if (dfacecnt != 0) { 6513eb3c573Smarks acep = realloc(acep, sizeof (ace_t) * (acecnt + dfacecnt)); 6523eb3c573Smarks if (acep == NULL) 653fa9e4066Sahrens return (-1); 654fa9e4066Sahrens if (dfaclcnt) { 6553eb3c573Smarks (void) memcpy(acep + acecnt, dfacep, 656fa9e4066Sahrens sizeof (ace_t) * dfacecnt); 657fa9e4066Sahrens } 6583eb3c573Smarks } 659fa9e4066Sahrens if (dfaclcnt) 660fa9e4066Sahrens free(dfacep); 661fa9e4066Sahrens 662fa9e4066Sahrens *retacecnt = acecnt + dfacecnt; 6633eb3c573Smarks *retacep = acep; 664fa9e4066Sahrens return (0); 665fa9e4066Sahrens } 666fa9e4066Sahrens 6673eb3c573Smarks static void 6683eb3c573Smarks acevals_init(acevals_t *vals, uid_t key) 6693eb3c573Smarks { 6703eb3c573Smarks bzero(vals, sizeof (*vals)); 6713eb3c573Smarks vals->allowed = ACE_MASK_UNDEFINED; 6723eb3c573Smarks vals->denied = ACE_MASK_UNDEFINED; 6733eb3c573Smarks vals->mask = ACE_MASK_UNDEFINED; 6743eb3c573Smarks vals->key = key; 6753eb3c573Smarks } 6763eb3c573Smarks 6773eb3c573Smarks static void 6783eb3c573Smarks ace_list_init(ace_list_t *al, int dfacl_flag) 6793eb3c573Smarks { 6803eb3c573Smarks acevals_init(&al->user_obj, NULL); 6813eb3c573Smarks acevals_init(&al->group_obj, NULL); 6823eb3c573Smarks acevals_init(&al->other_obj, NULL); 6833eb3c573Smarks al->numusers = 0; 6843eb3c573Smarks al->numgroups = 0; 6853eb3c573Smarks al->acl_mask = 0; 6863eb3c573Smarks al->hasmask = 0; 6873eb3c573Smarks al->state = ace_unused; 6883eb3c573Smarks al->seen = 0; 6893eb3c573Smarks al->dfacl_flag = dfacl_flag; 6903eb3c573Smarks } 6913eb3c573Smarks 6923eb3c573Smarks /* 6933eb3c573Smarks * Find or create an acevals holder for a given id and avl tree. 6943eb3c573Smarks * 6953eb3c573Smarks * Note that only one thread will ever touch these avl trees, so 6963eb3c573Smarks * there is no need for locking. 6973eb3c573Smarks */ 6983eb3c573Smarks static acevals_t * 6993eb3c573Smarks acevals_find(ace_t *ace, avl_tree_t *avl, int *num) 7003eb3c573Smarks { 7013eb3c573Smarks acevals_t key, *rc; 7023eb3c573Smarks avl_index_t where; 7033eb3c573Smarks 7043eb3c573Smarks key.key = ace->a_who; 7053eb3c573Smarks rc = avl_find(avl, &key, &where); 7063eb3c573Smarks if (rc != NULL) 7073eb3c573Smarks return (rc); 7083eb3c573Smarks 7093eb3c573Smarks /* this memory is freed by ln_ace_to_aent()->ace_list_free() */ 7103eb3c573Smarks rc = calloc(1, sizeof (acevals_t)); 7113eb3c573Smarks if (rc == NULL) 7123eb3c573Smarks return (rc); 7133eb3c573Smarks acevals_init(rc, ace->a_who); 7143eb3c573Smarks avl_insert(avl, rc, where); 7153eb3c573Smarks (*num)++; 7163eb3c573Smarks 7173eb3c573Smarks return (rc); 7183eb3c573Smarks } 719fa9e4066Sahrens 720fa9e4066Sahrens static int 7213eb3c573Smarks access_mask_check(ace_t *acep, int mask_bit, int isowner) 7223eb3c573Smarks { 7233eb3c573Smarks int set_deny, err_deny; 7243eb3c573Smarks int set_allow, err_allow; 7253eb3c573Smarks int acl_consume; 7263eb3c573Smarks int haswriteperm, hasreadperm; 7273eb3c573Smarks 7283eb3c573Smarks if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) { 7293eb3c573Smarks haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 0 : 1; 7303eb3c573Smarks hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 0 : 1; 7313eb3c573Smarks } else { 7323eb3c573Smarks haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 1 : 0; 7333eb3c573Smarks hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 1 : 0; 7343eb3c573Smarks } 7353eb3c573Smarks 7363eb3c573Smarks acl_consume = (ACL_SYNCHRONIZE_ERR_DENY | 7373eb3c573Smarks ACL_DELETE_ERR_DENY | 7383eb3c573Smarks ACL_WRITE_OWNER_ERR_DENY | 7393eb3c573Smarks ACL_WRITE_OWNER_ERR_ALLOW | 7403eb3c573Smarks ACL_WRITE_ATTRS_OWNER_SET_ALLOW | 7413eb3c573Smarks ACL_WRITE_ATTRS_OWNER_ERR_DENY | 7423eb3c573Smarks ACL_WRITE_ATTRS_WRITER_SET_DENY | 7433eb3c573Smarks ACL_WRITE_ATTRS_WRITER_ERR_ALLOW | 7443eb3c573Smarks ACL_WRITE_NAMED_WRITER_ERR_DENY | 7453eb3c573Smarks ACL_READ_NAMED_READER_ERR_DENY); 7463eb3c573Smarks 7473eb3c573Smarks if (mask_bit == ACE_SYNCHRONIZE) { 7483eb3c573Smarks set_deny = ACL_SYNCHRONIZE_SET_DENY; 7493eb3c573Smarks err_deny = ACL_SYNCHRONIZE_ERR_DENY; 7503eb3c573Smarks set_allow = ACL_SYNCHRONIZE_SET_ALLOW; 7513eb3c573Smarks err_allow = ACL_SYNCHRONIZE_ERR_ALLOW; 7523eb3c573Smarks } else if (mask_bit == ACE_WRITE_OWNER) { 7533eb3c573Smarks set_deny = ACL_WRITE_OWNER_SET_DENY; 7543eb3c573Smarks err_deny = ACL_WRITE_OWNER_ERR_DENY; 7553eb3c573Smarks set_allow = ACL_WRITE_OWNER_SET_ALLOW; 7563eb3c573Smarks err_allow = ACL_WRITE_OWNER_ERR_ALLOW; 7573eb3c573Smarks } else if (mask_bit == ACE_DELETE) { 7583eb3c573Smarks set_deny = ACL_DELETE_SET_DENY; 7593eb3c573Smarks err_deny = ACL_DELETE_ERR_DENY; 7603eb3c573Smarks set_allow = ACL_DELETE_SET_ALLOW; 7613eb3c573Smarks err_allow = ACL_DELETE_ERR_ALLOW; 7623eb3c573Smarks } else if (mask_bit == ACE_WRITE_ATTRIBUTES) { 7633eb3c573Smarks if (isowner) { 7643eb3c573Smarks set_deny = ACL_WRITE_ATTRS_OWNER_SET_DENY; 7653eb3c573Smarks err_deny = ACL_WRITE_ATTRS_OWNER_ERR_DENY; 7663eb3c573Smarks set_allow = ACL_WRITE_ATTRS_OWNER_SET_ALLOW; 7673eb3c573Smarks err_allow = ACL_WRITE_ATTRS_OWNER_ERR_ALLOW; 7683eb3c573Smarks } else if (haswriteperm) { 7693eb3c573Smarks set_deny = ACL_WRITE_ATTRS_WRITER_SET_DENY; 7703eb3c573Smarks err_deny = ACL_WRITE_ATTRS_WRITER_ERR_DENY; 7713eb3c573Smarks set_allow = ACL_WRITE_ATTRS_WRITER_SET_ALLOW; 7723eb3c573Smarks err_allow = ACL_WRITE_ATTRS_WRITER_ERR_ALLOW; 7733eb3c573Smarks } else { 7743eb3c573Smarks if ((acep->a_access_mask & mask_bit) && 7753eb3c573Smarks (acep->a_type & ACE_ACCESS_ALLOWED_ACE_TYPE)) { 7763eb3c573Smarks return (ENOTSUP); 7773eb3c573Smarks } 7783eb3c573Smarks return (0); 7793eb3c573Smarks } 7803eb3c573Smarks } else if (mask_bit == ACE_READ_NAMED_ATTRS) { 7813eb3c573Smarks if (!hasreadperm) 7823eb3c573Smarks return (0); 7833eb3c573Smarks 7843eb3c573Smarks set_deny = ACL_READ_NAMED_READER_SET_DENY; 7853eb3c573Smarks err_deny = ACL_READ_NAMED_READER_ERR_DENY; 7863eb3c573Smarks set_allow = ACL_READ_NAMED_READER_SET_ALLOW; 7873eb3c573Smarks err_allow = ACL_READ_NAMED_READER_ERR_ALLOW; 7883eb3c573Smarks } else if (mask_bit == ACE_WRITE_NAMED_ATTRS) { 7893eb3c573Smarks if (!haswriteperm) 7903eb3c573Smarks return (0); 7913eb3c573Smarks 7923eb3c573Smarks set_deny = ACL_WRITE_NAMED_WRITER_SET_DENY; 7933eb3c573Smarks err_deny = ACL_WRITE_NAMED_WRITER_ERR_DENY; 7943eb3c573Smarks set_allow = ACL_WRITE_NAMED_WRITER_SET_ALLOW; 7953eb3c573Smarks err_allow = ACL_WRITE_NAMED_WRITER_ERR_ALLOW; 7963eb3c573Smarks } else { 7973eb3c573Smarks return (EINVAL); 7983eb3c573Smarks } 7993eb3c573Smarks 8003eb3c573Smarks if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) { 8013eb3c573Smarks if (acl_consume & set_deny) { 8023eb3c573Smarks if (!(acep->a_access_mask & mask_bit)) { 8033eb3c573Smarks return (ENOTSUP); 8043eb3c573Smarks } 8053eb3c573Smarks } else if (acl_consume & err_deny) { 8063eb3c573Smarks if (acep->a_access_mask & mask_bit) { 8073eb3c573Smarks return (ENOTSUP); 8083eb3c573Smarks } 8093eb3c573Smarks } 8103eb3c573Smarks } else { 8113eb3c573Smarks /* ACE_ACCESS_ALLOWED_ACE_TYPE */ 8123eb3c573Smarks if (acl_consume & set_allow) { 8133eb3c573Smarks if (!(acep->a_access_mask & mask_bit)) { 8143eb3c573Smarks return (ENOTSUP); 8153eb3c573Smarks } 8163eb3c573Smarks } else if (acl_consume & err_allow) { 8173eb3c573Smarks if (acep->a_access_mask & mask_bit) { 8183eb3c573Smarks return (ENOTSUP); 8193eb3c573Smarks } 8203eb3c573Smarks } 8213eb3c573Smarks } 8223eb3c573Smarks return (0); 8233eb3c573Smarks } 8243eb3c573Smarks 8253eb3c573Smarks static int 8263eb3c573Smarks ace_to_aent_legal(ace_t *acep) 8273eb3c573Smarks { 8283eb3c573Smarks int error = 0; 8293eb3c573Smarks int isowner; 8303eb3c573Smarks 8313eb3c573Smarks /* only ALLOW or DENY */ 8323eb3c573Smarks if ((acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE) && 8333eb3c573Smarks (acep->a_type != ACE_ACCESS_DENIED_ACE_TYPE)) { 8343eb3c573Smarks error = ENOTSUP; 8353eb3c573Smarks goto out; 8363eb3c573Smarks } 8373eb3c573Smarks 8383eb3c573Smarks /* check for invalid flags */ 8393eb3c573Smarks if (acep->a_flags & ~(ACE_VALID_FLAG_BITS)) { 8403eb3c573Smarks error = EINVAL; 8413eb3c573Smarks goto out; 8423eb3c573Smarks } 8433eb3c573Smarks 8443eb3c573Smarks /* some flags are illegal */ 8453eb3c573Smarks if (acep->a_flags & (ACE_SUCCESSFUL_ACCESS_ACE_FLAG | 8463eb3c573Smarks ACE_FAILED_ACCESS_ACE_FLAG | 8473eb3c573Smarks ACE_NO_PROPAGATE_INHERIT_ACE)) { 8483eb3c573Smarks error = ENOTSUP; 8493eb3c573Smarks goto out; 8503eb3c573Smarks } 8513eb3c573Smarks 8523eb3c573Smarks /* check for invalid masks */ 8533eb3c573Smarks if (acep->a_access_mask & ~(ACE_VALID_MASK_BITS)) { 8543eb3c573Smarks error = EINVAL; 8553eb3c573Smarks goto out; 8563eb3c573Smarks } 8573eb3c573Smarks 8583eb3c573Smarks if ((acep->a_flags & ACE_OWNER)) { 8593eb3c573Smarks isowner = 1; 8603eb3c573Smarks } else { 8613eb3c573Smarks isowner = 0; 8623eb3c573Smarks } 8633eb3c573Smarks 8643eb3c573Smarks error = access_mask_check(acep, ACE_SYNCHRONIZE, isowner); 8653eb3c573Smarks if (error) 8663eb3c573Smarks goto out; 8673eb3c573Smarks 8683eb3c573Smarks error = access_mask_check(acep, ACE_WRITE_OWNER, isowner); 8693eb3c573Smarks if (error) 8703eb3c573Smarks goto out; 8713eb3c573Smarks 8723eb3c573Smarks error = access_mask_check(acep, ACE_DELETE, isowner); 8733eb3c573Smarks if (error) 8743eb3c573Smarks goto out; 8753eb3c573Smarks 8763eb3c573Smarks error = access_mask_check(acep, ACE_WRITE_ATTRIBUTES, isowner); 8773eb3c573Smarks if (error) 8783eb3c573Smarks goto out; 8793eb3c573Smarks 8803eb3c573Smarks error = access_mask_check(acep, ACE_READ_NAMED_ATTRS, isowner); 8813eb3c573Smarks if (error) 8823eb3c573Smarks goto out; 8833eb3c573Smarks 8843eb3c573Smarks error = access_mask_check(acep, ACE_WRITE_NAMED_ATTRS, isowner); 8853eb3c573Smarks if (error) 8863eb3c573Smarks goto out; 8873eb3c573Smarks 8883eb3c573Smarks /* more detailed checking of masks */ 8893eb3c573Smarks if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) { 8903eb3c573Smarks if (! (acep->a_access_mask & ACE_READ_ATTRIBUTES)) { 8913eb3c573Smarks error = ENOTSUP; 8923eb3c573Smarks goto out; 8933eb3c573Smarks } 8943eb3c573Smarks if ((acep->a_access_mask & ACE_WRITE_DATA) && 8953eb3c573Smarks (! (acep->a_access_mask & ACE_APPEND_DATA))) { 8963eb3c573Smarks error = ENOTSUP; 8973eb3c573Smarks goto out; 8983eb3c573Smarks } 8993eb3c573Smarks if ((! (acep->a_access_mask & ACE_WRITE_DATA)) && 9003eb3c573Smarks (acep->a_access_mask & ACE_APPEND_DATA)) { 9013eb3c573Smarks error = ENOTSUP; 9023eb3c573Smarks goto out; 9033eb3c573Smarks } 9043eb3c573Smarks } 9053eb3c573Smarks 9063eb3c573Smarks /* ACL enforcement */ 9073eb3c573Smarks if ((acep->a_access_mask & ACE_READ_ACL) && 9083eb3c573Smarks (acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE)) { 9093eb3c573Smarks error = ENOTSUP; 9103eb3c573Smarks goto out; 9113eb3c573Smarks } 9123eb3c573Smarks if (acep->a_access_mask & ACE_WRITE_ACL) { 9133eb3c573Smarks if ((acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) && 9143eb3c573Smarks (isowner)) { 9153eb3c573Smarks error = ENOTSUP; 9163eb3c573Smarks goto out; 9173eb3c573Smarks } 9183eb3c573Smarks if ((acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) && 9193eb3c573Smarks (! isowner)) { 9203eb3c573Smarks error = ENOTSUP; 9213eb3c573Smarks goto out; 9223eb3c573Smarks } 9233eb3c573Smarks } 9243eb3c573Smarks 9253eb3c573Smarks out: 9263eb3c573Smarks return (error); 9273eb3c573Smarks } 9283eb3c573Smarks 9293eb3c573Smarks static int 9303eb3c573Smarks ace_mask_to_mode(uint32_t mask, o_mode_t *modep, int isdir) 9313eb3c573Smarks { 9323eb3c573Smarks int error = 0; 9333eb3c573Smarks o_mode_t mode = 0; 9343eb3c573Smarks uint32_t bits, wantbits; 9353eb3c573Smarks 9363eb3c573Smarks /* read */ 9373eb3c573Smarks if (mask & ACE_READ_DATA) 9383eb3c573Smarks mode |= 04; 9393eb3c573Smarks 9403eb3c573Smarks /* write */ 9413eb3c573Smarks wantbits = (ACE_WRITE_DATA | ACE_APPEND_DATA); 9423eb3c573Smarks if (isdir) 9433eb3c573Smarks wantbits |= ACE_DELETE_CHILD; 9443eb3c573Smarks bits = mask & wantbits; 9453eb3c573Smarks if (bits != 0) { 9463eb3c573Smarks if (bits != wantbits) { 9473eb3c573Smarks error = ENOTSUP; 9483eb3c573Smarks goto out; 9493eb3c573Smarks } 9503eb3c573Smarks mode |= 02; 9513eb3c573Smarks } 9523eb3c573Smarks 9533eb3c573Smarks /* exec */ 9543eb3c573Smarks if (mask & ACE_EXECUTE) { 9553eb3c573Smarks mode |= 01; 9563eb3c573Smarks } 9573eb3c573Smarks 9583eb3c573Smarks *modep = mode; 9593eb3c573Smarks 9603eb3c573Smarks out: 9613eb3c573Smarks return (error); 9623eb3c573Smarks } 9633eb3c573Smarks 9643eb3c573Smarks static int 9653eb3c573Smarks ace_allow_to_mode(uint32_t mask, o_mode_t *modep, int isdir) 9663eb3c573Smarks { 9673eb3c573Smarks /* ACE_READ_ACL and ACE_READ_ATTRIBUTES must both be set */ 9683eb3c573Smarks if ((mask & (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) != 9693eb3c573Smarks (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) { 9703eb3c573Smarks return (ENOTSUP); 9713eb3c573Smarks } 9723eb3c573Smarks 9733eb3c573Smarks return (ace_mask_to_mode(mask, modep, isdir)); 9743eb3c573Smarks } 9753eb3c573Smarks 9763eb3c573Smarks static int 9773eb3c573Smarks acevals_to_aent(acevals_t *vals, aclent_t *dest, ace_list_t *list, 9783eb3c573Smarks uid_t owner, gid_t group, int isdir) 9793eb3c573Smarks { 9803eb3c573Smarks int error; 9813eb3c573Smarks uint32_t flips = ACE_POSIX_SUPPORTED_BITS; 9823eb3c573Smarks 9833eb3c573Smarks if (isdir) 9843eb3c573Smarks flips |= ACE_DELETE_CHILD; 9853eb3c573Smarks if (vals->allowed != (vals->denied ^ flips)) { 9863eb3c573Smarks error = ENOTSUP; 9873eb3c573Smarks goto out; 9883eb3c573Smarks } 9893eb3c573Smarks if ((list->hasmask) && (list->acl_mask != vals->mask) && 9903eb3c573Smarks (vals->aent_type & (USER | GROUP | GROUP_OBJ))) { 9913eb3c573Smarks error = ENOTSUP; 9923eb3c573Smarks goto out; 9933eb3c573Smarks } 9943eb3c573Smarks error = ace_allow_to_mode(vals->allowed, &dest->a_perm, isdir); 9953eb3c573Smarks if (error != 0) 9963eb3c573Smarks goto out; 9973eb3c573Smarks dest->a_type = vals->aent_type; 9983eb3c573Smarks if (dest->a_type & (USER | GROUP)) { 9993eb3c573Smarks dest->a_id = vals->key; 10003eb3c573Smarks } else if (dest->a_type & USER_OBJ) { 10013eb3c573Smarks dest->a_id = owner; 10023eb3c573Smarks } else if (dest->a_type & GROUP_OBJ) { 10033eb3c573Smarks dest->a_id = group; 10043eb3c573Smarks } else if (dest->a_type & OTHER_OBJ) { 10053eb3c573Smarks dest->a_id = 0; 10063eb3c573Smarks } else { 10073eb3c573Smarks error = EINVAL; 10083eb3c573Smarks goto out; 10093eb3c573Smarks } 10103eb3c573Smarks 10113eb3c573Smarks out: 10123eb3c573Smarks return (error); 10133eb3c573Smarks } 10143eb3c573Smarks 10153eb3c573Smarks static int 10163eb3c573Smarks ace_list_to_aent(ace_list_t *list, aclent_t **aclentp, int *aclcnt, 10173eb3c573Smarks uid_t owner, gid_t group, int isdir) 10183eb3c573Smarks { 10193eb3c573Smarks int error = 0; 10203eb3c573Smarks aclent_t *aent, *result = NULL; 10213eb3c573Smarks acevals_t *vals; 10223eb3c573Smarks int resultcount; 10233eb3c573Smarks 10243eb3c573Smarks if ((list->seen & (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) != 10253eb3c573Smarks (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) { 10263eb3c573Smarks error = ENOTSUP; 10273eb3c573Smarks goto out; 10283eb3c573Smarks } 10293eb3c573Smarks if ((! list->hasmask) && (list->numusers + list->numgroups > 0)) { 10303eb3c573Smarks error = ENOTSUP; 10313eb3c573Smarks goto out; 10323eb3c573Smarks } 10333eb3c573Smarks 10343eb3c573Smarks resultcount = 3 + list->numusers + list->numgroups; 10353eb3c573Smarks /* 10363eb3c573Smarks * This must be the same condition as below, when we add the CLASS_OBJ 10373eb3c573Smarks * (aka ACL mask) 10383eb3c573Smarks */ 10393eb3c573Smarks if ((list->hasmask) || (! list->dfacl_flag)) 10403eb3c573Smarks resultcount += 1; 10413eb3c573Smarks 10423eb3c573Smarks result = aent = calloc(1, resultcount * sizeof (aclent_t)); 10433eb3c573Smarks 10443eb3c573Smarks if (result == NULL) { 10453eb3c573Smarks error = ENOMEM; 10463eb3c573Smarks goto out; 10473eb3c573Smarks } 10483eb3c573Smarks 10493eb3c573Smarks /* USER_OBJ */ 10503eb3c573Smarks if (!(list->user_obj.aent_type & USER_OBJ)) { 10513eb3c573Smarks error = EINVAL; 10523eb3c573Smarks goto out; 10533eb3c573Smarks } 10543eb3c573Smarks 10553eb3c573Smarks error = acevals_to_aent(&list->user_obj, aent, list, owner, group, 10563eb3c573Smarks isdir); 10573eb3c573Smarks 10583eb3c573Smarks if (error != 0) 10593eb3c573Smarks goto out; 10603eb3c573Smarks ++aent; 10613eb3c573Smarks /* USER */ 10623eb3c573Smarks vals = NULL; 10633eb3c573Smarks for (vals = avl_first(&list->user); vals != NULL; 10643eb3c573Smarks vals = AVL_NEXT(&list->user, vals)) { 10653eb3c573Smarks if (!(vals->aent_type & USER)) { 10663eb3c573Smarks error = EINVAL; 10673eb3c573Smarks goto out; 10683eb3c573Smarks } 10693eb3c573Smarks error = acevals_to_aent(vals, aent, list, owner, group, 10703eb3c573Smarks isdir); 10713eb3c573Smarks if (error != 0) 10723eb3c573Smarks goto out; 10733eb3c573Smarks ++aent; 10743eb3c573Smarks } 10753eb3c573Smarks /* GROUP_OBJ */ 10763eb3c573Smarks if (!(list->group_obj.aent_type & GROUP_OBJ)) { 10773eb3c573Smarks error = EINVAL; 10783eb3c573Smarks goto out; 10793eb3c573Smarks } 10803eb3c573Smarks error = acevals_to_aent(&list->group_obj, aent, list, owner, group, 10813eb3c573Smarks isdir); 10823eb3c573Smarks if (error != 0) 10833eb3c573Smarks goto out; 10843eb3c573Smarks ++aent; 10853eb3c573Smarks /* GROUP */ 10863eb3c573Smarks vals = NULL; 10873eb3c573Smarks for (vals = avl_first(&list->group); vals != NULL; 10883eb3c573Smarks vals = AVL_NEXT(&list->group, vals)) { 10893eb3c573Smarks if (!(vals->aent_type & GROUP)) { 10903eb3c573Smarks error = EINVAL; 10913eb3c573Smarks goto out; 10923eb3c573Smarks } 10933eb3c573Smarks error = acevals_to_aent(vals, aent, list, owner, group, 10943eb3c573Smarks isdir); 10953eb3c573Smarks if (error != 0) 10963eb3c573Smarks goto out; 10973eb3c573Smarks ++aent; 10983eb3c573Smarks } 10993eb3c573Smarks /* 11003eb3c573Smarks * CLASS_OBJ (aka ACL_MASK) 11013eb3c573Smarks * 11023eb3c573Smarks * An ACL_MASK is not fabricated if the ACL is a default ACL. 11033eb3c573Smarks * This is to follow UFS's behavior. 11043eb3c573Smarks */ 11053eb3c573Smarks if ((list->hasmask) || (! list->dfacl_flag)) { 11063eb3c573Smarks if (list->hasmask) { 11073eb3c573Smarks uint32_t flips = ACE_POSIX_SUPPORTED_BITS; 11083eb3c573Smarks if (isdir) 11093eb3c573Smarks flips |= ACE_DELETE_CHILD; 11103eb3c573Smarks error = ace_mask_to_mode(list->acl_mask ^ flips, 11113eb3c573Smarks &aent->a_perm, isdir); 11123eb3c573Smarks if (error != 0) 11133eb3c573Smarks goto out; 11143eb3c573Smarks } else { 11153eb3c573Smarks /* fabricate the ACL_MASK from the group permissions */ 11163eb3c573Smarks error = ace_mask_to_mode(list->group_obj.allowed, 11173eb3c573Smarks &aent->a_perm, isdir); 11183eb3c573Smarks if (error != 0) 11193eb3c573Smarks goto out; 11203eb3c573Smarks } 11213eb3c573Smarks aent->a_id = 0; 11223eb3c573Smarks aent->a_type = CLASS_OBJ | list->dfacl_flag; 11233eb3c573Smarks ++aent; 11243eb3c573Smarks } 11253eb3c573Smarks /* OTHER_OBJ */ 11263eb3c573Smarks if (!(list->other_obj.aent_type & OTHER_OBJ)) { 11273eb3c573Smarks error = EINVAL; 11283eb3c573Smarks goto out; 11293eb3c573Smarks } 11303eb3c573Smarks error = acevals_to_aent(&list->other_obj, aent, list, owner, group, 11313eb3c573Smarks isdir); 11323eb3c573Smarks if (error != 0) 11333eb3c573Smarks goto out; 11343eb3c573Smarks ++aent; 11353eb3c573Smarks 11363eb3c573Smarks *aclentp = result; 11373eb3c573Smarks *aclcnt = resultcount; 11383eb3c573Smarks 11393eb3c573Smarks out: 11403eb3c573Smarks if (error != 0) { 11413eb3c573Smarks if (result != NULL) 11423eb3c573Smarks free(result); 11433eb3c573Smarks } 11443eb3c573Smarks 11453eb3c573Smarks return (error); 11463eb3c573Smarks } 11473eb3c573Smarks 11483eb3c573Smarks /* 11493eb3c573Smarks * free all data associated with an ace_list 11503eb3c573Smarks */ 11513eb3c573Smarks static void 11523eb3c573Smarks ace_list_free(ace_list_t *al) 11533eb3c573Smarks { 11543eb3c573Smarks acevals_t *node; 11553eb3c573Smarks void *cookie; 11563eb3c573Smarks 11573eb3c573Smarks if (al == NULL) 11583eb3c573Smarks return; 11593eb3c573Smarks 11603eb3c573Smarks cookie = NULL; 11613eb3c573Smarks while ((node = avl_destroy_nodes(&al->user, &cookie)) != NULL) 11623eb3c573Smarks free(node); 11633eb3c573Smarks cookie = NULL; 11643eb3c573Smarks while ((node = avl_destroy_nodes(&al->group, &cookie)) != NULL) 11653eb3c573Smarks free(node); 11663eb3c573Smarks 11673eb3c573Smarks avl_destroy(&al->user); 11683eb3c573Smarks avl_destroy(&al->group); 11693eb3c573Smarks 11703eb3c573Smarks /* free the container itself */ 11713eb3c573Smarks free(al); 11723eb3c573Smarks } 11733eb3c573Smarks 11743eb3c573Smarks static int 11753eb3c573Smarks acevals_compare(const void *va, const void *vb) 11763eb3c573Smarks { 11773eb3c573Smarks const acevals_t *a = va, *b = vb; 11783eb3c573Smarks 11793eb3c573Smarks if (a->key == b->key) 11803eb3c573Smarks return (0); 11813eb3c573Smarks 11823eb3c573Smarks if (a->key > b->key) 11833eb3c573Smarks return (1); 11843eb3c573Smarks 11853eb3c573Smarks else 11863eb3c573Smarks return (-1); 11873eb3c573Smarks } 11883eb3c573Smarks 11893eb3c573Smarks /* 11903eb3c573Smarks * Convert a list of ace_t entries to equivalent regular and default 11913eb3c573Smarks * aclent_t lists. Return error (ENOTSUP) when conversion is not possible. 11923eb3c573Smarks */ 11933eb3c573Smarks static int 11943eb3c573Smarks ln_ace_to_aent(ace_t *ace, int n, uid_t owner, gid_t group, 11953eb3c573Smarks aclent_t **aclentp, int *aclcnt, aclent_t **dfaclentp, int *dfaclcnt, 11963eb3c573Smarks int isdir) 11973eb3c573Smarks { 11983eb3c573Smarks int error = 0; 11993eb3c573Smarks ace_t *acep; 12003eb3c573Smarks uint32_t bits; 12013eb3c573Smarks int i; 12023eb3c573Smarks ace_list_t *normacl = NULL, *dfacl = NULL, *acl; 12033eb3c573Smarks acevals_t *vals; 12043eb3c573Smarks 12053eb3c573Smarks *aclentp = NULL; 12063eb3c573Smarks *aclcnt = 0; 12073eb3c573Smarks *dfaclentp = NULL; 12083eb3c573Smarks *dfaclcnt = 0; 12093eb3c573Smarks 12103eb3c573Smarks /* we need at least user_obj, group_obj, and other_obj */ 12113eb3c573Smarks if (n < 6) { 12123eb3c573Smarks error = ENOTSUP; 12133eb3c573Smarks goto out; 12143eb3c573Smarks } 12153eb3c573Smarks if (ace == NULL) { 12163eb3c573Smarks error = EINVAL; 12173eb3c573Smarks goto out; 12183eb3c573Smarks } 12193eb3c573Smarks 12203eb3c573Smarks normacl = calloc(1, sizeof (ace_list_t)); 12213eb3c573Smarks 12223eb3c573Smarks if (normacl == NULL) { 12233eb3c573Smarks error = errno; 12243eb3c573Smarks goto out; 12253eb3c573Smarks } 12263eb3c573Smarks 12273eb3c573Smarks avl_create(&normacl->user, acevals_compare, sizeof (acevals_t), 12283eb3c573Smarks offsetof(acevals_t, avl)); 12293eb3c573Smarks avl_create(&normacl->group, acevals_compare, sizeof (acevals_t), 12303eb3c573Smarks offsetof(acevals_t, avl)); 12313eb3c573Smarks 12323eb3c573Smarks ace_list_init(normacl, 0); 12333eb3c573Smarks 12343eb3c573Smarks dfacl = calloc(1, sizeof (ace_list_t)); 12353eb3c573Smarks if (dfacl == NULL) { 12363eb3c573Smarks error = errno; 12373eb3c573Smarks goto out; 12383eb3c573Smarks } 12393eb3c573Smarks avl_create(&dfacl->user, acevals_compare, sizeof (acevals_t), 12403eb3c573Smarks offsetof(acevals_t, avl)); 12413eb3c573Smarks avl_create(&dfacl->group, acevals_compare, sizeof (acevals_t), 12423eb3c573Smarks offsetof(acevals_t, avl)); 12433eb3c573Smarks ace_list_init(dfacl, ACL_DEFAULT); 12443eb3c573Smarks 12453eb3c573Smarks /* process every ace_t... */ 12463eb3c573Smarks for (i = 0; i < n; i++) { 12473eb3c573Smarks acep = &ace[i]; 12483eb3c573Smarks 12493eb3c573Smarks /* rule out certain cases quickly */ 12503eb3c573Smarks error = ace_to_aent_legal(acep); 12513eb3c573Smarks if (error != 0) 12523eb3c573Smarks goto out; 12533eb3c573Smarks 12543eb3c573Smarks /* 12553eb3c573Smarks * Turn off these bits in order to not have to worry about 12563eb3c573Smarks * them when doing the checks for compliments. 12573eb3c573Smarks */ 12583eb3c573Smarks acep->a_access_mask &= ~(ACE_WRITE_OWNER | ACE_DELETE | 12593eb3c573Smarks ACE_SYNCHRONIZE | ACE_WRITE_ATTRIBUTES | 12603eb3c573Smarks ACE_READ_NAMED_ATTRS | ACE_WRITE_NAMED_ATTRS); 12613eb3c573Smarks 12623eb3c573Smarks /* see if this should be a regular or default acl */ 12633eb3c573Smarks bits = acep->a_flags & 12643eb3c573Smarks (ACE_INHERIT_ONLY_ACE | 12653eb3c573Smarks ACE_FILE_INHERIT_ACE | 12663eb3c573Smarks ACE_DIRECTORY_INHERIT_ACE); 12673eb3c573Smarks if (bits != 0) { 12683eb3c573Smarks /* all or nothing on these inherit bits */ 12693eb3c573Smarks if (bits != (ACE_INHERIT_ONLY_ACE | 12703eb3c573Smarks ACE_FILE_INHERIT_ACE | 12713eb3c573Smarks ACE_DIRECTORY_INHERIT_ACE)) { 12723eb3c573Smarks error = ENOTSUP; 12733eb3c573Smarks goto out; 12743eb3c573Smarks } 12753eb3c573Smarks acl = dfacl; 12763eb3c573Smarks } else { 12773eb3c573Smarks acl = normacl; 12783eb3c573Smarks } 12793eb3c573Smarks 12803eb3c573Smarks if ((acep->a_flags & ACE_OWNER)) { 12813eb3c573Smarks if (acl->state > ace_user_obj) { 12823eb3c573Smarks error = ENOTSUP; 12833eb3c573Smarks goto out; 12843eb3c573Smarks } 12853eb3c573Smarks acl->state = ace_user_obj; 12863eb3c573Smarks acl->seen |= USER_OBJ; 12873eb3c573Smarks vals = &acl->user_obj; 12883eb3c573Smarks vals->aent_type = USER_OBJ | acl->dfacl_flag; 12893eb3c573Smarks } else if ((acep->a_flags & ACE_EVERYONE)) { 12903eb3c573Smarks acl->state = ace_other_obj; 12913eb3c573Smarks acl->seen |= OTHER_OBJ; 12923eb3c573Smarks vals = &acl->other_obj; 12933eb3c573Smarks vals->aent_type = OTHER_OBJ | acl->dfacl_flag; 12943eb3c573Smarks } else if (acep->a_flags & ACE_IDENTIFIER_GROUP) { 12953eb3c573Smarks if (acl->state > ace_group) { 12963eb3c573Smarks error = ENOTSUP; 12973eb3c573Smarks goto out; 12983eb3c573Smarks } 12993eb3c573Smarks if ((acep->a_flags & ACE_GROUP)) { 13003eb3c573Smarks acl->seen |= GROUP_OBJ; 13013eb3c573Smarks vals = &acl->group_obj; 13023eb3c573Smarks vals->aent_type = GROUP_OBJ | acl->dfacl_flag; 13033eb3c573Smarks } else { 13043eb3c573Smarks acl->seen |= GROUP; 13053eb3c573Smarks vals = acevals_find(acep, &acl->group, 13063eb3c573Smarks &acl->numgroups); 13073eb3c573Smarks if (vals == NULL) { 13083eb3c573Smarks error = ENOMEM; 13093eb3c573Smarks goto out; 13103eb3c573Smarks } 13113eb3c573Smarks vals->aent_type = GROUP | acl->dfacl_flag; 13123eb3c573Smarks } 13133eb3c573Smarks acl->state = ace_group; 13143eb3c573Smarks } else { 13153eb3c573Smarks if (acl->state > ace_user) { 13163eb3c573Smarks error = ENOTSUP; 13173eb3c573Smarks goto out; 13183eb3c573Smarks } 13193eb3c573Smarks acl->state = ace_user; 13203eb3c573Smarks acl->seen |= USER; 13213eb3c573Smarks vals = acevals_find(acep, &acl->user, 13223eb3c573Smarks &acl->numusers); 13233eb3c573Smarks if (vals == NULL) { 13243eb3c573Smarks error = ENOMEM; 13253eb3c573Smarks goto out; 13263eb3c573Smarks } 13273eb3c573Smarks vals->aent_type = USER | acl->dfacl_flag; 13283eb3c573Smarks } 13293eb3c573Smarks 13303eb3c573Smarks if (!(acl->state > ace_unused)) { 13313eb3c573Smarks error = EINVAL; 13323eb3c573Smarks goto out; 13333eb3c573Smarks } 13343eb3c573Smarks 13353eb3c573Smarks if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) { 13363eb3c573Smarks /* no more than one allowed per aclent_t */ 13373eb3c573Smarks if (vals->allowed != ACE_MASK_UNDEFINED) { 13383eb3c573Smarks error = ENOTSUP; 13393eb3c573Smarks goto out; 13403eb3c573Smarks } 13413eb3c573Smarks vals->allowed = acep->a_access_mask; 13423eb3c573Smarks } else { 13433eb3c573Smarks /* 13443eb3c573Smarks * it's a DENY; if there was a previous DENY, it 13453eb3c573Smarks * must have been an ACL_MASK. 13463eb3c573Smarks */ 13473eb3c573Smarks if (vals->denied != ACE_MASK_UNDEFINED) { 13483eb3c573Smarks /* ACL_MASK is for USER and GROUP only */ 13493eb3c573Smarks if ((acl->state != ace_user) && 13503eb3c573Smarks (acl->state != ace_group)) { 13513eb3c573Smarks error = ENOTSUP; 13523eb3c573Smarks goto out; 13533eb3c573Smarks } 13543eb3c573Smarks 13553eb3c573Smarks if (! acl->hasmask) { 13563eb3c573Smarks acl->hasmask = 1; 13573eb3c573Smarks acl->acl_mask = vals->denied; 13583eb3c573Smarks /* check for mismatched ACL_MASK emulations */ 13593eb3c573Smarks } else if (acl->acl_mask != vals->denied) { 13603eb3c573Smarks error = ENOTSUP; 13613eb3c573Smarks goto out; 13623eb3c573Smarks } 13633eb3c573Smarks vals->mask = vals->denied; 13643eb3c573Smarks } 13653eb3c573Smarks vals->denied = acep->a_access_mask; 13663eb3c573Smarks } 13673eb3c573Smarks } 13683eb3c573Smarks 13693eb3c573Smarks /* done collating; produce the aclent_t lists */ 13703eb3c573Smarks if (normacl->state != ace_unused) { 13713eb3c573Smarks error = ace_list_to_aent(normacl, aclentp, aclcnt, 13723eb3c573Smarks owner, group, isdir); 13733eb3c573Smarks if (error != 0) { 13743eb3c573Smarks goto out; 13753eb3c573Smarks } 13763eb3c573Smarks } 13773eb3c573Smarks if (dfacl->state != ace_unused) { 13783eb3c573Smarks error = ace_list_to_aent(dfacl, dfaclentp, dfaclcnt, 13793eb3c573Smarks owner, group, isdir); 13803eb3c573Smarks if (error != 0) { 13813eb3c573Smarks goto out; 13823eb3c573Smarks } 13833eb3c573Smarks } 13843eb3c573Smarks 13853eb3c573Smarks out: 13863eb3c573Smarks if (normacl != NULL) 13873eb3c573Smarks ace_list_free(normacl); 13883eb3c573Smarks if (dfacl != NULL) 13893eb3c573Smarks ace_list_free(dfacl); 13903eb3c573Smarks 13913eb3c573Smarks return (error); 13923eb3c573Smarks } 13933eb3c573Smarks 13943eb3c573Smarks static int 13953eb3c573Smarks convert_ace_to_aent(ace_t *acebufp, int acecnt, int isdir, 13963eb3c573Smarks uid_t owner, gid_t group, aclent_t **retaclentp, int *retaclcnt) 13973eb3c573Smarks { 13983eb3c573Smarks int error; 13993eb3c573Smarks aclent_t *aclentp, *dfaclentp; 14003eb3c573Smarks int aclcnt, dfaclcnt; 14013eb3c573Smarks 14023eb3c573Smarks error = ln_ace_to_aent(acebufp, acecnt, owner, group, 14033eb3c573Smarks &aclentp, &aclcnt, &dfaclentp, &dfaclcnt, isdir); 14043eb3c573Smarks 14053eb3c573Smarks if (error) 14063eb3c573Smarks return (error); 14073eb3c573Smarks 14083eb3c573Smarks 14093eb3c573Smarks if (dfaclcnt != 0) { 14103eb3c573Smarks /* 14113eb3c573Smarks * Slap aclentp and dfaclentp into a single array. 14123eb3c573Smarks */ 14133eb3c573Smarks aclentp = realloc(aclentp, (sizeof (aclent_t) * aclcnt) + 14143eb3c573Smarks (sizeof (aclent_t) * dfaclcnt)); 14153eb3c573Smarks if (aclentp != NULL) { 14163eb3c573Smarks (void) memcpy(aclentp + aclcnt, 14173eb3c573Smarks dfaclentp, sizeof (aclent_t) * dfaclcnt); 14183eb3c573Smarks } else { 14193eb3c573Smarks error = -1; 14203eb3c573Smarks } 14213eb3c573Smarks } 14223eb3c573Smarks 14233eb3c573Smarks if (aclentp) { 14243eb3c573Smarks *retaclentp = aclentp; 14253eb3c573Smarks *retaclcnt = aclcnt + dfaclcnt; 14263eb3c573Smarks } 14273eb3c573Smarks 14283eb3c573Smarks if (dfaclentp) 14293eb3c573Smarks free(dfaclentp); 14303eb3c573Smarks 14313eb3c573Smarks return (error); 14323eb3c573Smarks } 14333eb3c573Smarks 14340157963dSmarks static int 1435fa9e4066Sahrens cacl_get(acl_inp inp, int get_flag, int type, acl_t **aclp) 1436fa9e4066Sahrens { 1437fa9e4066Sahrens const char *fname; 1438fa9e4066Sahrens int fd; 1439fa9e4066Sahrens int ace_acl = 0; 1440fa9e4066Sahrens int error; 1441fa9e4066Sahrens int getcmd, cntcmd; 1442fa9e4066Sahrens acl_t *acl_info; 1443fa9e4066Sahrens int save_errno; 1444fa9e4066Sahrens int stat_error; 1445fa9e4066Sahrens struct stat64 statbuf; 1446fa9e4066Sahrens 1447fa9e4066Sahrens *aclp = NULL; 1448fa9e4066Sahrens if (type == ACL_PATH) { 1449fa9e4066Sahrens fname = inp.file; 1450fa9e4066Sahrens ace_acl = pathconf(fname, _PC_ACL_ENABLED); 1451fa9e4066Sahrens } else { 1452fa9e4066Sahrens fd = inp.fd; 1453fa9e4066Sahrens ace_acl = fpathconf(fd, _PC_ACL_ENABLED); 1454fa9e4066Sahrens } 1455fa9e4066Sahrens 1456fa9e4066Sahrens /* 1457fa9e4066Sahrens * if acl's aren't supported then 1458fa9e4066Sahrens * send it through the old GETACL interface 1459fa9e4066Sahrens */ 1460*a222db82Smarks if (ace_acl == 0 || ace_acl == -1) { 1461fa9e4066Sahrens ace_acl = _ACL_ACLENT_ENABLED; 1462fa9e4066Sahrens } 1463fa9e4066Sahrens 1464fa9e4066Sahrens if (ace_acl & _ACL_ACE_ENABLED) { 1465fa9e4066Sahrens cntcmd = ACE_GETACLCNT; 1466fa9e4066Sahrens getcmd = ACE_GETACL; 1467fa9e4066Sahrens acl_info = acl_alloc(ACE_T); 1468fa9e4066Sahrens } else { 1469fa9e4066Sahrens cntcmd = GETACLCNT; 1470fa9e4066Sahrens getcmd = GETACL; 1471fa9e4066Sahrens acl_info = acl_alloc(ACLENT_T); 1472fa9e4066Sahrens } 1473fa9e4066Sahrens 1474fa9e4066Sahrens if (acl_info == NULL) 1475fa9e4066Sahrens return (-1); 1476fa9e4066Sahrens 1477fa9e4066Sahrens if (type == ACL_PATH) { 1478fa9e4066Sahrens acl_info->acl_cnt = acl(fname, cntcmd, 0, NULL); 1479fa9e4066Sahrens } else { 1480fa9e4066Sahrens acl_info->acl_cnt = facl(fd, cntcmd, 0, NULL); 1481fa9e4066Sahrens } 1482fa9e4066Sahrens 1483fa9e4066Sahrens save_errno = errno; 1484fa9e4066Sahrens if (acl_info->acl_cnt < 0) { 1485fa9e4066Sahrens acl_free(acl_info); 1486fa9e4066Sahrens errno = save_errno; 1487fa9e4066Sahrens return (-1); 1488fa9e4066Sahrens } 1489fa9e4066Sahrens 1490fa9e4066Sahrens if (acl_info->acl_cnt == 0) { 1491fa9e4066Sahrens acl_free(acl_info); 1492fa9e4066Sahrens errno = save_errno; 1493fa9e4066Sahrens return (0); 1494fa9e4066Sahrens } 1495fa9e4066Sahrens 1496fa9e4066Sahrens acl_info->acl_aclp = 1497fa9e4066Sahrens malloc(acl_info->acl_cnt * acl_info->acl_entry_size); 1498fa9e4066Sahrens save_errno = errno; 1499fa9e4066Sahrens 1500fa9e4066Sahrens if (acl_info->acl_aclp == NULL) { 1501fa9e4066Sahrens acl_free(acl_info); 1502fa9e4066Sahrens errno = save_errno; 1503fa9e4066Sahrens return (-1); 1504fa9e4066Sahrens } 1505fa9e4066Sahrens 1506fa9e4066Sahrens if (type == ACL_PATH) { 1507fa9e4066Sahrens stat_error = stat64(fname, &statbuf); 1508fa9e4066Sahrens error = acl(fname, getcmd, acl_info->acl_cnt, 1509fa9e4066Sahrens acl_info->acl_aclp); 1510fa9e4066Sahrens } else { 1511fa9e4066Sahrens stat_error = fstat64(fd, &statbuf); 1512fa9e4066Sahrens error = facl(fd, getcmd, acl_info->acl_cnt, 1513fa9e4066Sahrens acl_info->acl_aclp); 1514fa9e4066Sahrens } 1515fa9e4066Sahrens 1516fa9e4066Sahrens save_errno = errno; 1517fa9e4066Sahrens if (error == -1) { 1518fa9e4066Sahrens acl_free(acl_info); 1519fa9e4066Sahrens errno = save_errno; 1520fa9e4066Sahrens return (-1); 1521fa9e4066Sahrens } 1522fa9e4066Sahrens 1523fa9e4066Sahrens 1524fa9e4066Sahrens if (stat_error == 0) { 1525fa9e4066Sahrens acl_info->acl_flags = 1526fa9e4066Sahrens (S_ISDIR(statbuf.st_mode) ? ACL_IS_DIR : 0); 1527fa9e4066Sahrens } else 1528fa9e4066Sahrens acl_info->acl_flags = 0; 1529fa9e4066Sahrens 1530fa9e4066Sahrens switch (acl_info->acl_type) { 1531fa9e4066Sahrens case ACLENT_T: 1532fa9e4066Sahrens if (acl_info->acl_cnt <= MIN_ACL_ENTRIES) 1533fa9e4066Sahrens acl_info->acl_flags |= ACL_IS_TRIVIAL; 1534fa9e4066Sahrens break; 1535fa9e4066Sahrens case ACE_T: 1536fa9e4066Sahrens if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0) 1537fa9e4066Sahrens acl_info->acl_flags |= ACL_IS_TRIVIAL; 1538fa9e4066Sahrens break; 1539fa9e4066Sahrens default: 1540fa9e4066Sahrens errno = EINVAL; 1541fa9e4066Sahrens acl_free(acl_info); 1542fa9e4066Sahrens return (-1); 1543fa9e4066Sahrens } 1544fa9e4066Sahrens 1545fa9e4066Sahrens if ((acl_info->acl_flags & ACL_IS_TRIVIAL) && 1546fa9e4066Sahrens (get_flag & ACL_NO_TRIVIAL)) { 1547fa9e4066Sahrens acl_free(acl_info); 1548fa9e4066Sahrens errno = 0; 1549fa9e4066Sahrens return (0); 1550fa9e4066Sahrens } 1551fa9e4066Sahrens 1552fa9e4066Sahrens *aclp = acl_info; 1553fa9e4066Sahrens return (0); 1554fa9e4066Sahrens } 1555fa9e4066Sahrens 1556fa9e4066Sahrens /* 1557fa9e4066Sahrens * return -1 on failure, otherwise the number of acl 1558fa9e4066Sahrens * entries is returned 1559fa9e4066Sahrens */ 1560fa9e4066Sahrens int 1561fa9e4066Sahrens acl_get(const char *path, int get_flag, acl_t **aclp) 1562fa9e4066Sahrens { 1563fa9e4066Sahrens acl_inp acl_inp; 1564fa9e4066Sahrens acl_inp.file = path; 1565fa9e4066Sahrens 1566fa9e4066Sahrens return (cacl_get(acl_inp, get_flag, ACL_PATH, aclp)); 1567fa9e4066Sahrens } 1568fa9e4066Sahrens 1569fa9e4066Sahrens int 1570fa9e4066Sahrens facl_get(int fd, int get_flag, acl_t **aclp) 1571fa9e4066Sahrens { 1572fa9e4066Sahrens 1573fa9e4066Sahrens acl_inp acl_inp; 1574fa9e4066Sahrens acl_inp.fd = fd; 1575fa9e4066Sahrens 1576fa9e4066Sahrens return (cacl_get(acl_inp, get_flag, ACL_FD, aclp)); 1577fa9e4066Sahrens } 1578fa9e4066Sahrens 15793eb3c573Smarks static int 15803eb3c573Smarks acl_translate(acl_t *aclp, int target_flavor, int isdir, uid_t owner, 15813eb3c573Smarks gid_t group) 15823eb3c573Smarks { 15833eb3c573Smarks int aclcnt; 15843eb3c573Smarks void *acldata; 15853eb3c573Smarks int error; 15863eb3c573Smarks 15873eb3c573Smarks /* 15883eb3c573Smarks * See if we need to translate 15893eb3c573Smarks */ 15903eb3c573Smarks if ((target_flavor == _ACL_ACE_ENABLED && aclp->acl_type == ACE_T) || 15913eb3c573Smarks (target_flavor == _ACL_ACLENT_ENABLED && 15923eb3c573Smarks aclp->acl_type == ACLENT_T)) 15933eb3c573Smarks return (0); 15943eb3c573Smarks 15953eb3c573Smarks if (target_flavor == -1) 15963eb3c573Smarks return (-1); 15973eb3c573Smarks 15983eb3c573Smarks if (target_flavor == _ACL_ACE_ENABLED && 15993eb3c573Smarks aclp->acl_type == ACLENT_T) { 16003eb3c573Smarks error = convert_aent_to_ace(aclp->acl_aclp, 16013eb3c573Smarks aclp->acl_cnt, isdir, (ace_t **)&acldata, &aclcnt); 16023eb3c573Smarks if (error) { 16033eb3c573Smarks errno = error; 16043eb3c573Smarks return (-1); 16053eb3c573Smarks } 16063eb3c573Smarks } else if (target_flavor == _ACL_ACLENT_ENABLED && 16073eb3c573Smarks aclp->acl_type == ACE_T) { 16083eb3c573Smarks error = convert_ace_to_aent(aclp->acl_aclp, aclp->acl_cnt, 16093eb3c573Smarks isdir, owner, group, (aclent_t **)&acldata, &aclcnt); 16103eb3c573Smarks if (error) { 16113eb3c573Smarks errno = error; 16123eb3c573Smarks return (-1); 16133eb3c573Smarks } 16143eb3c573Smarks } else { 16153eb3c573Smarks errno = ENOTSUP; 16163eb3c573Smarks return (-1); 16173eb3c573Smarks } 16183eb3c573Smarks 16193eb3c573Smarks /* 16203eb3c573Smarks * replace old acl with newly translated acl 16213eb3c573Smarks */ 16223eb3c573Smarks free(aclp->acl_aclp); 16233eb3c573Smarks aclp->acl_aclp = acldata; 16243eb3c573Smarks aclp->acl_cnt = aclcnt; 16253eb3c573Smarks aclp->acl_type = (target_flavor == _ACL_ACE_ENABLED) ? ACE_T : ACLENT_T; 16263eb3c573Smarks return (0); 16273eb3c573Smarks } 16283eb3c573Smarks 1629fa9e4066Sahrens /* 1630fa9e4066Sahrens * Set an ACL, translates acl to ace_t when appropriate. 1631fa9e4066Sahrens */ 1632fa9e4066Sahrens static int 1633fa9e4066Sahrens cacl_set(acl_inp *acl_inp, acl_t *aclp, int type) 1634fa9e4066Sahrens { 1635fa9e4066Sahrens int error = 0; 1636fa9e4066Sahrens int acl_flavor_target; 1637fa9e4066Sahrens struct stat64 statbuf; 1638fa9e4066Sahrens int stat_error; 1639fa9e4066Sahrens int isdir; 1640fa9e4066Sahrens 1641fa9e4066Sahrens 1642fa9e4066Sahrens if (type == ACL_PATH) { 1643fa9e4066Sahrens stat_error = stat64(acl_inp->file, &statbuf); 1644fa9e4066Sahrens if (stat_error) 1645fa9e4066Sahrens return (-1); 1646fa9e4066Sahrens acl_flavor_target = pathconf(acl_inp->file, _PC_ACL_ENABLED); 1647fa9e4066Sahrens } else { 1648fa9e4066Sahrens stat_error = fstat64(acl_inp->fd, &statbuf); 1649fa9e4066Sahrens if (stat_error) 1650fa9e4066Sahrens return (-1); 1651fa9e4066Sahrens acl_flavor_target = fpathconf(acl_inp->fd, _PC_ACL_ENABLED); 1652fa9e4066Sahrens } 1653fa9e4066Sahrens 1654*a222db82Smarks /* 1655*a222db82Smarks * If target returns an error or 0 from pathconf call then 1656*a222db82Smarks * fall back to UFS/POSIX Draft interface. 1657*a222db82Smarks * In the case of 0 we will then fail in either acl(2) or 1658*a222db82Smarks * acl_translate(). We could erroneously get 0 back from 1659*a222db82Smarks * a file system that is using fs_pathconf() and not answering 1660*a222db82Smarks * the _PC_ACL_ENABLED question itself. 1661*a222db82Smarks */ 1662*a222db82Smarks if (acl_flavor_target == 0 || acl_flavor_target == -1) 1663*a222db82Smarks acl_flavor_target = _ACL_ACLENT_ENABLED; 1664*a222db82Smarks 1665fa9e4066Sahrens isdir = S_ISDIR(statbuf.st_mode); 1666fa9e4066Sahrens 16673eb3c573Smarks if ((error = acl_translate(aclp, acl_flavor_target, isdir, 16683eb3c573Smarks statbuf.st_uid, statbuf.st_gid)) != 0) { 16693eb3c573Smarks return (error); 1670fa9e4066Sahrens } 1671fa9e4066Sahrens 1672fa9e4066Sahrens if (type == ACL_PATH) { 1673fa9e4066Sahrens error = acl(acl_inp->file, 1674fa9e4066Sahrens (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, 1675fa9e4066Sahrens aclp->acl_cnt, aclp->acl_aclp); 1676fa9e4066Sahrens } else { 1677fa9e4066Sahrens error = facl(acl_inp->fd, 1678fa9e4066Sahrens (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, 1679fa9e4066Sahrens aclp->acl_cnt, aclp->acl_aclp); 1680fa9e4066Sahrens } 1681fa9e4066Sahrens 1682fa9e4066Sahrens return (error); 1683fa9e4066Sahrens } 1684fa9e4066Sahrens 1685fa9e4066Sahrens int 1686fa9e4066Sahrens acl_set(const char *path, acl_t *aclp) 1687fa9e4066Sahrens { 1688fa9e4066Sahrens acl_inp acl_inp; 1689fa9e4066Sahrens 1690fa9e4066Sahrens acl_inp.file = path; 1691fa9e4066Sahrens 1692fa9e4066Sahrens return (cacl_set(&acl_inp, aclp, ACL_PATH)); 1693fa9e4066Sahrens } 1694fa9e4066Sahrens 1695fa9e4066Sahrens int 1696fa9e4066Sahrens facl_set(int fd, acl_t *aclp) 1697fa9e4066Sahrens { 1698fa9e4066Sahrens acl_inp acl_inp; 1699fa9e4066Sahrens 1700fa9e4066Sahrens acl_inp.fd = fd; 1701fa9e4066Sahrens 1702fa9e4066Sahrens return (cacl_set(&acl_inp, aclp, ACL_FD)); 1703fa9e4066Sahrens } 1704fa9e4066Sahrens 1705fa9e4066Sahrens int 1706fa9e4066Sahrens acl_cnt(acl_t *aclp) 1707fa9e4066Sahrens { 1708fa9e4066Sahrens return (aclp->acl_cnt); 1709fa9e4066Sahrens } 1710fa9e4066Sahrens 1711fa9e4066Sahrens int 1712fa9e4066Sahrens acl_type(acl_t *aclp) 1713fa9e4066Sahrens { 1714fa9e4066Sahrens return (aclp->acl_type); 1715fa9e4066Sahrens } 1716fa9e4066Sahrens 1717fa9e4066Sahrens acl_t * 1718fa9e4066Sahrens acl_dup(acl_t *aclp) 1719fa9e4066Sahrens { 1720fa9e4066Sahrens acl_t *newaclp; 1721fa9e4066Sahrens 1722fa9e4066Sahrens newaclp = acl_alloc(aclp->acl_type); 1723fa9e4066Sahrens if (newaclp == NULL) 1724fa9e4066Sahrens return (NULL); 1725fa9e4066Sahrens 1726fa9e4066Sahrens newaclp->acl_aclp = malloc(aclp->acl_entry_size * aclp->acl_cnt); 1727fa9e4066Sahrens if (newaclp->acl_aclp == NULL) { 1728fa9e4066Sahrens acl_free(newaclp); 1729fa9e4066Sahrens return (NULL); 1730fa9e4066Sahrens } 1731fa9e4066Sahrens 1732fa9e4066Sahrens (void) memcpy(newaclp->acl_aclp, 1733fa9e4066Sahrens aclp->acl_aclp, aclp->acl_entry_size * aclp->acl_cnt); 1734fa9e4066Sahrens newaclp->acl_cnt = aclp->acl_cnt; 1735fa9e4066Sahrens 1736fa9e4066Sahrens return (newaclp); 1737fa9e4066Sahrens } 1738fa9e4066Sahrens 1739fa9e4066Sahrens int 1740fa9e4066Sahrens acl_flags(acl_t *aclp) 1741fa9e4066Sahrens { 1742fa9e4066Sahrens return (aclp->acl_flags); 1743fa9e4066Sahrens } 1744fa9e4066Sahrens 1745fa9e4066Sahrens void * 1746fa9e4066Sahrens acl_data(acl_t *aclp) 1747fa9e4066Sahrens { 1748fa9e4066Sahrens return (aclp->acl_aclp); 1749fa9e4066Sahrens } 1750fa9e4066Sahrens 1751fa9e4066Sahrens /* 1752fa9e4066Sahrens * Remove an ACL from a file and create a trivial ACL based 1753fa9e4066Sahrens * off of the mode argument. After acl has been set owner/group 1754fa9e4066Sahrens * are updated to match owner,group arguments 1755fa9e4066Sahrens */ 1756fa9e4066Sahrens int 1757fa9e4066Sahrens acl_strip(const char *file, uid_t owner, gid_t group, mode_t mode) 1758fa9e4066Sahrens { 1759fa9e4066Sahrens int error = 0; 1760fa9e4066Sahrens aclent_t min_acl[MIN_ACL_ENTRIES]; 1761fa9e4066Sahrens ace_t min_ace_acl[6]; /* owner, group, everyone + complement denies */ 1762fa9e4066Sahrens int acl_flavor; 1763fa9e4066Sahrens int aclcnt; 1764fa9e4066Sahrens 1765fa9e4066Sahrens acl_flavor = pathconf(file, _PC_ACL_ENABLED); 1766fa9e4066Sahrens 1767fa9e4066Sahrens /* 1768fa9e4066Sahrens * force it through aclent flavor when file system doesn't 1769fa9e4066Sahrens * understand question 1770fa9e4066Sahrens */ 1771*a222db82Smarks if (acl_flavor == 0 || acl_flavor == -1) 1772fa9e4066Sahrens acl_flavor = _ACL_ACLENT_ENABLED; 1773fa9e4066Sahrens 1774fa9e4066Sahrens if (acl_flavor & _ACL_ACLENT_ENABLED) { 1775fa9e4066Sahrens min_acl[0].a_type = USER_OBJ; 1776fa9e4066Sahrens min_acl[0].a_id = owner; 1777fa9e4066Sahrens min_acl[0].a_perm = ((mode & 0700) >> 6); 1778fa9e4066Sahrens min_acl[1].a_type = GROUP_OBJ; 1779fa9e4066Sahrens min_acl[1].a_id = group; 1780fa9e4066Sahrens min_acl[1].a_perm = ((mode & 0070) >> 3); 1781fa9e4066Sahrens min_acl[2].a_type = CLASS_OBJ; 1782fa9e4066Sahrens min_acl[2].a_id = (uid_t)-1; 1783fa9e4066Sahrens min_acl[2].a_perm = ((mode & 0070) >> 3); 1784fa9e4066Sahrens min_acl[3].a_type = OTHER_OBJ; 1785fa9e4066Sahrens min_acl[3].a_id = (uid_t)-1; 1786fa9e4066Sahrens min_acl[3].a_perm = (mode & 0007); 1787fa9e4066Sahrens aclcnt = 4; 1788fa9e4066Sahrens error = acl(file, SETACL, aclcnt, min_acl); 1789fa9e4066Sahrens } else if (acl_flavor & _ACL_ACE_ENABLED) { 1790fa9e4066Sahrens (void) memcpy(min_ace_acl, trivial_acl, sizeof (ace_t) * 6); 1791fa9e4066Sahrens 1792fa9e4066Sahrens /* 1793fa9e4066Sahrens * Make aces match request mode 1794fa9e4066Sahrens */ 1795fa9e4066Sahrens adjust_ace_pair(&min_ace_acl[0], (mode & 0700) >> 6); 1796fa9e4066Sahrens adjust_ace_pair(&min_ace_acl[2], (mode & 0070) >> 3); 1797fa9e4066Sahrens adjust_ace_pair(&min_ace_acl[4], mode & 0007); 1798fa9e4066Sahrens 1799fa9e4066Sahrens error = acl(file, ACE_SETACL, 6, min_ace_acl); 1800fa9e4066Sahrens } else { 1801fa9e4066Sahrens errno = EINVAL; 1802fa9e4066Sahrens error = 1; 1803fa9e4066Sahrens } 1804fa9e4066Sahrens 1805fa9e4066Sahrens if (error == 0) 1806fa9e4066Sahrens error = chown(file, owner, group); 1807fa9e4066Sahrens return (error); 1808fa9e4066Sahrens } 1809fa9e4066Sahrens 1810fa9e4066Sahrens static int 1811fa9e4066Sahrens ace_match(void *entry1, void *entry2) 1812fa9e4066Sahrens { 1813fa9e4066Sahrens ace_t *p1 = (ace_t *)entry1; 1814fa9e4066Sahrens ace_t *p2 = (ace_t *)entry2; 1815fa9e4066Sahrens ace_t ace1, ace2; 1816fa9e4066Sahrens 1817fa9e4066Sahrens ace1 = *p1; 1818fa9e4066Sahrens ace2 = *p2; 1819fa9e4066Sahrens 1820fa9e4066Sahrens /* 1821fa9e4066Sahrens * Need to fixup who field for abstrations for 1822fa9e4066Sahrens * accurate comparison, since field is undefined. 1823fa9e4066Sahrens */ 1824fa9e4066Sahrens if (ace1.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE)) 1825fa9e4066Sahrens ace1.a_who = -1; 1826fa9e4066Sahrens if (ace2.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE)) 1827fa9e4066Sahrens ace2.a_who = -1; 1828fa9e4066Sahrens return (memcmp(&ace1, &ace2, sizeof (ace_t))); 1829fa9e4066Sahrens } 1830fa9e4066Sahrens 1831fa9e4066Sahrens static int 1832fa9e4066Sahrens aclent_match(void *entry1, void *entry2) 1833fa9e4066Sahrens { 1834fa9e4066Sahrens aclent_t *aclent1 = (aclent_t *)entry1; 1835fa9e4066Sahrens aclent_t *aclent2 = (aclent_t *)entry2; 1836fa9e4066Sahrens 1837fa9e4066Sahrens return (memcmp(aclent1, aclent2, sizeof (aclent_t))); 1838fa9e4066Sahrens } 1839fa9e4066Sahrens 1840fa9e4066Sahrens /* 1841fa9e4066Sahrens * Find acl entries in acl that correspond to removeacl. Search 1842fa9e4066Sahrens * is started from slot. The flag argument indicates whether to 1843fa9e4066Sahrens * remove all matches or just the first match. 1844fa9e4066Sahrens */ 1845fa9e4066Sahrens int 1846fa9e4066Sahrens acl_removeentries(acl_t *acl, acl_t *removeacl, int start_slot, int flag) 1847fa9e4066Sahrens { 1848fa9e4066Sahrens int i, j; 1849fa9e4066Sahrens int match; 1850fa9e4066Sahrens int (*acl_match)(void *acl1, void *acl2); 1851fa9e4066Sahrens void *acl_entry, *remove_entry; 1852fa9e4066Sahrens void *start; 1853fa9e4066Sahrens int found = 0; 1854fa9e4066Sahrens 1855fa9e4066Sahrens if (flag != ACL_REMOVE_ALL && flag != ACL_REMOVE_FIRST) 1856fa9e4066Sahrens flag = ACL_REMOVE_FIRST; 1857fa9e4066Sahrens 1858fa9e4066Sahrens if (acl == NULL || removeacl == NULL) 1859fa9e4066Sahrens return (EACL_NO_ACL_ENTRY); 1860fa9e4066Sahrens 1861fa9e4066Sahrens if (acl->acl_type != removeacl->acl_type) 1862fa9e4066Sahrens return (EACL_DIFF_TYPE); 1863fa9e4066Sahrens 1864fa9e4066Sahrens if (acl->acl_type == ACLENT_T) 1865fa9e4066Sahrens acl_match = aclent_match; 1866fa9e4066Sahrens else 1867fa9e4066Sahrens acl_match = ace_match; 1868fa9e4066Sahrens 1869fa9e4066Sahrens for (i = 0, remove_entry = removeacl->acl_aclp; 1870fa9e4066Sahrens i != removeacl->acl_cnt; i++) { 1871fa9e4066Sahrens 1872fa9e4066Sahrens j = 0; 1873fa9e4066Sahrens acl_entry = (char *)acl->acl_aclp + 1874fa9e4066Sahrens (acl->acl_entry_size * start_slot); 1875fa9e4066Sahrens for (;;) { 1876fa9e4066Sahrens match = acl_match(acl_entry, remove_entry); 1877fa9e4066Sahrens if (match == 0) { 1878fa9e4066Sahrens found++; 1879fa9e4066Sahrens start = (char *)acl_entry + 1880fa9e4066Sahrens acl->acl_entry_size; 1881fa9e4066Sahrens (void) memmove(acl_entry, start, 1882fa9e4066Sahrens acl->acl_entry_size * 1883fa9e4066Sahrens acl->acl_cnt-- - (j + 1)); 1884fa9e4066Sahrens 1885fa9e4066Sahrens if (flag == ACL_REMOVE_FIRST) 1886fa9e4066Sahrens break; 1887fa9e4066Sahrens /* 1888fa9e4066Sahrens * List has changed, restart search from 1889fa9e4066Sahrens * beginning. 1890fa9e4066Sahrens */ 1891fa9e4066Sahrens acl_entry = acl->acl_aclp; 1892fa9e4066Sahrens j = 0; 1893fa9e4066Sahrens continue; 1894fa9e4066Sahrens } 1895fa9e4066Sahrens acl_entry = ((char *)acl_entry + acl->acl_entry_size); 1896fa9e4066Sahrens if (++j >= acl->acl_cnt) { 1897fa9e4066Sahrens break; 1898fa9e4066Sahrens } 1899fa9e4066Sahrens } 1900fa9e4066Sahrens } 1901fa9e4066Sahrens 1902fa9e4066Sahrens return ((found == 0) ? EACL_NO_ACL_ENTRY : 0); 1903fa9e4066Sahrens } 1904fa9e4066Sahrens 1905fa9e4066Sahrens /* 1906fa9e4066Sahrens * Replace entires entries in acl1 with the corresponding entries 1907fa9e4066Sahrens * in newentries. The where argument specifies where to begin 1908fa9e4066Sahrens * the replacement. If the where argument is 1 greater than the 1909fa9e4066Sahrens * number of acl entries in acl1 then they are appended. If the 1910fa9e4066Sahrens * where argument is 2+ greater than the number of acl entries then 1911fa9e4066Sahrens * EACL_INVALID_SLOT is returned. 1912fa9e4066Sahrens */ 1913fa9e4066Sahrens int 1914fa9e4066Sahrens acl_modifyentries(acl_t *acl1, acl_t *newentries, int where) 1915fa9e4066Sahrens { 1916fa9e4066Sahrens 1917fa9e4066Sahrens int slot; 1918fa9e4066Sahrens int slots_needed; 1919fa9e4066Sahrens int slots_left; 1920fa9e4066Sahrens int newsize; 1921fa9e4066Sahrens 1922fa9e4066Sahrens if (acl1 == NULL || newentries == NULL) 1923fa9e4066Sahrens return (EACL_NO_ACL_ENTRY); 1924fa9e4066Sahrens 1925fa9e4066Sahrens if (where < 0 || where >= acl1->acl_cnt) 1926fa9e4066Sahrens return (EACL_INVALID_SLOT); 1927fa9e4066Sahrens 1928fa9e4066Sahrens if (acl1->acl_type != newentries->acl_type) 1929fa9e4066Sahrens return (EACL_DIFF_TYPE); 1930fa9e4066Sahrens 1931fa9e4066Sahrens slot = where; 1932fa9e4066Sahrens 1933fa9e4066Sahrens slots_left = acl1->acl_cnt - slot + 1; 1934fa9e4066Sahrens if (slots_left < newentries->acl_cnt) { 1935fa9e4066Sahrens slots_needed = newentries->acl_cnt - slots_left; 1936fa9e4066Sahrens newsize = (acl1->acl_entry_size * acl1->acl_cnt) + 1937fa9e4066Sahrens (acl1->acl_entry_size * slots_needed); 1938fa9e4066Sahrens acl1->acl_aclp = realloc(acl1->acl_aclp, newsize); 1939fa9e4066Sahrens if (acl1->acl_aclp == NULL) 1940fa9e4066Sahrens return (-1); 1941fa9e4066Sahrens } 1942fa9e4066Sahrens (void) memcpy((char *)acl1->acl_aclp + (acl1->acl_entry_size * slot), 1943fa9e4066Sahrens newentries->acl_aclp, 1944fa9e4066Sahrens newentries->acl_entry_size * newentries->acl_cnt); 1945fa9e4066Sahrens 1946fa9e4066Sahrens /* 1947fa9e4066Sahrens * Did ACL grow? 1948fa9e4066Sahrens */ 1949fa9e4066Sahrens 1950fa9e4066Sahrens if ((slot + newentries->acl_cnt) > acl1->acl_cnt) { 1951fa9e4066Sahrens acl1->acl_cnt = slot + newentries->acl_cnt; 1952fa9e4066Sahrens } 1953fa9e4066Sahrens 1954fa9e4066Sahrens return (0); 1955fa9e4066Sahrens } 1956fa9e4066Sahrens 1957fa9e4066Sahrens /* 1958fa9e4066Sahrens * Add acl2 entries into acl1. The where argument specifies where 1959fa9e4066Sahrens * to add the entries. 1960fa9e4066Sahrens */ 1961fa9e4066Sahrens int 1962fa9e4066Sahrens acl_addentries(acl_t *acl1, acl_t *acl2, int where) 1963fa9e4066Sahrens { 1964fa9e4066Sahrens 1965fa9e4066Sahrens int newsize; 1966fa9e4066Sahrens int len; 1967fa9e4066Sahrens void *start; 1968fa9e4066Sahrens void *to; 1969fa9e4066Sahrens 1970fa9e4066Sahrens if (acl1 == NULL || acl2 == NULL) 1971fa9e4066Sahrens return (EACL_NO_ACL_ENTRY); 1972fa9e4066Sahrens 1973fa9e4066Sahrens if (acl1->acl_type != acl2->acl_type) 1974fa9e4066Sahrens return (EACL_DIFF_TYPE); 1975fa9e4066Sahrens 1976fa9e4066Sahrens /* 1977fa9e4066Sahrens * allow where to specify 1 past last slot for an append operation 1978fa9e4066Sahrens * but anything greater is an error. 1979fa9e4066Sahrens */ 1980fa9e4066Sahrens if (where < 0 || where > acl1->acl_cnt) 1981fa9e4066Sahrens return (EACL_INVALID_SLOT); 1982fa9e4066Sahrens 1983fa9e4066Sahrens newsize = (acl2->acl_entry_size * acl2->acl_cnt) + 1984fa9e4066Sahrens (acl1->acl_entry_size * acl1->acl_cnt); 1985fa9e4066Sahrens acl1->acl_aclp = realloc(acl1->acl_aclp, newsize); 1986fa9e4066Sahrens if (acl1->acl_aclp == NULL) 1987fa9e4066Sahrens return (-1); 1988fa9e4066Sahrens 1989fa9e4066Sahrens /* 1990fa9e4066Sahrens * first push down entries where new ones will be inserted 1991fa9e4066Sahrens */ 1992fa9e4066Sahrens 1993fa9e4066Sahrens to = (void *)((char *)acl1->acl_aclp + 1994fa9e4066Sahrens ((where + acl2->acl_cnt) * acl1->acl_entry_size)); 1995fa9e4066Sahrens 1996fa9e4066Sahrens start = (void *)((char *)acl1->acl_aclp + 1997fa9e4066Sahrens where * acl1->acl_entry_size); 1998fa9e4066Sahrens 1999fa9e4066Sahrens if (where < acl1->acl_cnt) { 2000fa9e4066Sahrens len = (acl1->acl_cnt - where) * acl1->acl_entry_size; 2001fa9e4066Sahrens (void) memmove(to, start, len); 2002fa9e4066Sahrens } 2003fa9e4066Sahrens 2004fa9e4066Sahrens /* 2005fa9e4066Sahrens * now stick in new entries. 2006fa9e4066Sahrens */ 2007fa9e4066Sahrens 2008fa9e4066Sahrens (void) memmove(start, acl2->acl_aclp, 2009fa9e4066Sahrens acl2->acl_cnt * acl2->acl_entry_size); 2010fa9e4066Sahrens 2011fa9e4066Sahrens acl1->acl_cnt += acl2->acl_cnt; 2012fa9e4066Sahrens return (0); 2013fa9e4066Sahrens } 2014fa9e4066Sahrens 2015fa9e4066Sahrens /* 2016fa9e4066Sahrens * return text for an ACL error. 2017fa9e4066Sahrens */ 2018fa9e4066Sahrens char * 2019fa9e4066Sahrens acl_strerror(int errnum) 2020fa9e4066Sahrens { 2021fa9e4066Sahrens switch (errnum) { 2022fa9e4066Sahrens case EACL_GRP_ERROR: 2023fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 20245a5eeccaSmarks "There is more than one group or default group entry")); 2025fa9e4066Sahrens case EACL_USER_ERROR: 2026fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 20275a5eeccaSmarks "There is more than one user or default user entry")); 2028fa9e4066Sahrens case EACL_OTHER_ERROR: 2029fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2030fa9e4066Sahrens "There is more than one other entry")); 2031fa9e4066Sahrens case EACL_CLASS_ERROR: 2032fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2033fa9e4066Sahrens "There is more than one mask entry")); 2034fa9e4066Sahrens case EACL_DUPLICATE_ERROR: 2035fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2036fa9e4066Sahrens "Duplicate user or group entries")); 2037fa9e4066Sahrens case EACL_MISS_ERROR: 2038fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2039fa9e4066Sahrens "Missing user/group owner, other, mask entry")); 2040fa9e4066Sahrens case EACL_MEM_ERROR: 2041fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2042fa9e4066Sahrens "Memory error")); 2043fa9e4066Sahrens case EACL_ENTRY_ERROR: 2044fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2045fa9e4066Sahrens "Unrecognized entry type")); 2046fa9e4066Sahrens case EACL_INHERIT_ERROR: 2047fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2048fa9e4066Sahrens "Invalid inheritance flags")); 2049fa9e4066Sahrens case EACL_FLAGS_ERROR: 2050fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2051fa9e4066Sahrens "Unrecognized entry flags")); 2052fa9e4066Sahrens case EACL_PERM_MASK_ERROR: 2053fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2054fa9e4066Sahrens "Invalid ACL permissions")); 2055fa9e4066Sahrens case EACL_COUNT_ERROR: 2056fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2057fa9e4066Sahrens "Invalid ACL count")); 2058fa9e4066Sahrens case EACL_INVALID_SLOT: 2059fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2060fa9e4066Sahrens "Invalid ACL entry number specified")); 2061fa9e4066Sahrens case EACL_NO_ACL_ENTRY: 2062fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2063fa9e4066Sahrens "ACL entry doesn't exist")); 2064fa9e4066Sahrens case EACL_DIFF_TYPE: 2065fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2066fa9e4066Sahrens "ACL type's are different")); 2067fa9e4066Sahrens case EACL_INVALID_USER_GROUP: 2068fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "Invalid user or group")); 2069fa9e4066Sahrens case EACL_INVALID_STR: 2070fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "ACL string is invalid")); 2071fa9e4066Sahrens case EACL_FIELD_NOT_BLANK: 2072fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "Field expected to be blank")); 2073fa9e4066Sahrens case EACL_INVALID_ACCESS_TYPE: 2074fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "Invalid access type")); 2075fa9e4066Sahrens case EACL_UNKNOWN_DATA: 2076fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "Unrecognized entry")); 2077fa9e4066Sahrens case EACL_MISSING_FIELDS: 2078fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2079fa9e4066Sahrens "ACL specification missing required fields")); 2080fa9e4066Sahrens case EACL_INHERIT_NOTDIR: 2081fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 2082fa9e4066Sahrens "Inheritance flags are only allowed on directories")); 2083fa9e4066Sahrens case -1: 2084fa9e4066Sahrens return (strerror(errno)); 2085fa9e4066Sahrens default: 2086fa9e4066Sahrens errno = EINVAL; 2087fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "Unknown error")); 2088fa9e4066Sahrens } 2089fa9e4066Sahrens } 20905a5eeccaSmarks 20915a5eeccaSmarks extern int yyinteractive; 20925a5eeccaSmarks 20935a5eeccaSmarks /* PRINTFLIKE1 */ 20945a5eeccaSmarks void 20955a5eeccaSmarks acl_error(const char *fmt, ...) 20965a5eeccaSmarks { 20975a5eeccaSmarks va_list va; 20985a5eeccaSmarks 20995a5eeccaSmarks if (yyinteractive == 0) 21005a5eeccaSmarks return; 21015a5eeccaSmarks 21025a5eeccaSmarks va_start(va, fmt); 21035a5eeccaSmarks (void) vfprintf(stderr, fmt, va); 21045a5eeccaSmarks va_end(va); 21055a5eeccaSmarks } 2106