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 /* 2227dd1e87SMark Shellenbaum * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23*a3c49ce1SAlbert Lee * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 24fa9e4066Sahrens */ 25fa9e4066Sahrens 26fa9e4066Sahrens 27fa9e4066Sahrens #include <stdlib.h> 28fa9e4066Sahrens #include <string.h> 29fa9e4066Sahrens #include <unistd.h> 30fa9e4066Sahrens #include <limits.h> 31fa9e4066Sahrens #include <grp.h> 32fa9e4066Sahrens #include <pwd.h> 333eb3c573Smarks #include <strings.h> 34fa9e4066Sahrens #include <sys/types.h> 35fa9e4066Sahrens #include <errno.h> 36fa9e4066Sahrens #include <sys/stat.h> 375a5eeccaSmarks #include <sys/varargs.h> 38fa9e4066Sahrens #include <locale.h> 39fa9e4066Sahrens #include <aclutils.h> 403eb3c573Smarks #include <sys/avl.h> 41da6c28aaSamw #include <acl_common.h> 42b249c65cSmarks #include <idmap.h> 43fa9e4066Sahrens 44fa9e4066Sahrens #define ACL_PATH 0 45fa9e4066Sahrens #define ACL_FD 1 46fa9e4066Sahrens 47d2443e76Smarks 48fa9e4066Sahrens typedef union { 49fa9e4066Sahrens const char *file; 50fa9e4066Sahrens int fd; 51fa9e4066Sahrens } acl_inp; 52fa9e4066Sahrens 53fa9e4066Sahrens 54fa9e4066Sahrens /* 55fa9e4066Sahrens * Determine whether a file has a trivial ACL 56fa9e4066Sahrens * returns: 0 = trivial 57fa9e4066Sahrens * 1 = nontrivial 58fa9e4066Sahrens * <0 some other system failure, such as ENOENT or EPERM 59fa9e4066Sahrens */ 60fa9e4066Sahrens int 61fa9e4066Sahrens acl_trivial(const char *filename) 62fa9e4066Sahrens { 63fa9e4066Sahrens int acl_flavor; 64fa9e4066Sahrens int aclcnt; 65fa9e4066Sahrens int cntcmd; 66fa9e4066Sahrens int val = 0; 67fa9e4066Sahrens ace_t *acep; 68fa9e4066Sahrens 69fa9e4066Sahrens acl_flavor = pathconf(filename, _PC_ACL_ENABLED); 70fa9e4066Sahrens 71fa9e4066Sahrens if (acl_flavor == _ACL_ACE_ENABLED) 72fa9e4066Sahrens cntcmd = ACE_GETACLCNT; 73fa9e4066Sahrens else 74fa9e4066Sahrens cntcmd = GETACLCNT; 75fa9e4066Sahrens 76fa9e4066Sahrens aclcnt = acl(filename, cntcmd, 0, NULL); 77fa9e4066Sahrens if (aclcnt > 0) { 78fa9e4066Sahrens if (acl_flavor == _ACL_ACE_ENABLED) { 79fa9e4066Sahrens acep = malloc(sizeof (ace_t) * aclcnt); 80fa9e4066Sahrens if (acep == NULL) 81fa9e4066Sahrens return (-1); 82fa9e4066Sahrens if (acl(filename, ACE_GETACL, 83fa9e4066Sahrens aclcnt, acep) < 0) { 84fa9e4066Sahrens free(acep); 85fa9e4066Sahrens return (-1); 86fa9e4066Sahrens } 87fa9e4066Sahrens 88fa9e4066Sahrens val = ace_trivial(acep, aclcnt); 89fa9e4066Sahrens free(acep); 90d2443e76Smarks 91fa9e4066Sahrens } else if (aclcnt > MIN_ACL_ENTRIES) 92fa9e4066Sahrens val = 1; 93fa9e4066Sahrens } 94fa9e4066Sahrens return (val); 95fa9e4066Sahrens } 96fa9e4066Sahrens 973eb3c573Smarks 980157963dSmarks static int 99fa9e4066Sahrens cacl_get(acl_inp inp, int get_flag, int type, acl_t **aclp) 100fa9e4066Sahrens { 101fa9e4066Sahrens const char *fname; 102fa9e4066Sahrens int fd; 103fa9e4066Sahrens int ace_acl = 0; 104fa9e4066Sahrens int error; 105fa9e4066Sahrens int getcmd, cntcmd; 106fa9e4066Sahrens acl_t *acl_info; 107fa9e4066Sahrens int save_errno; 108fa9e4066Sahrens int stat_error; 109fa9e4066Sahrens struct stat64 statbuf; 110fa9e4066Sahrens 111fa9e4066Sahrens *aclp = NULL; 112fa9e4066Sahrens if (type == ACL_PATH) { 113fa9e4066Sahrens fname = inp.file; 114fa9e4066Sahrens ace_acl = pathconf(fname, _PC_ACL_ENABLED); 115fa9e4066Sahrens } else { 116fa9e4066Sahrens fd = inp.fd; 117fa9e4066Sahrens ace_acl = fpathconf(fd, _PC_ACL_ENABLED); 118fa9e4066Sahrens } 119fa9e4066Sahrens 120fa9e4066Sahrens /* 121fa9e4066Sahrens * if acl's aren't supported then 122fa9e4066Sahrens * send it through the old GETACL interface 123fa9e4066Sahrens */ 124a222db82Smarks if (ace_acl == 0 || ace_acl == -1) { 125fa9e4066Sahrens ace_acl = _ACL_ACLENT_ENABLED; 126fa9e4066Sahrens } 127fa9e4066Sahrens 128fa9e4066Sahrens if (ace_acl & _ACL_ACE_ENABLED) { 129fa9e4066Sahrens cntcmd = ACE_GETACLCNT; 130fa9e4066Sahrens getcmd = ACE_GETACL; 131fa9e4066Sahrens acl_info = acl_alloc(ACE_T); 132fa9e4066Sahrens } else { 133fa9e4066Sahrens cntcmd = GETACLCNT; 134fa9e4066Sahrens getcmd = GETACL; 135fa9e4066Sahrens acl_info = acl_alloc(ACLENT_T); 136fa9e4066Sahrens } 137fa9e4066Sahrens 138fa9e4066Sahrens if (acl_info == NULL) 139fa9e4066Sahrens return (-1); 140fa9e4066Sahrens 141fa9e4066Sahrens if (type == ACL_PATH) { 142fa9e4066Sahrens acl_info->acl_cnt = acl(fname, cntcmd, 0, NULL); 143fa9e4066Sahrens } else { 144fa9e4066Sahrens acl_info->acl_cnt = facl(fd, cntcmd, 0, NULL); 145fa9e4066Sahrens } 146fa9e4066Sahrens 147fa9e4066Sahrens save_errno = errno; 148fa9e4066Sahrens if (acl_info->acl_cnt < 0) { 149fa9e4066Sahrens acl_free(acl_info); 150fa9e4066Sahrens errno = save_errno; 151fa9e4066Sahrens return (-1); 152fa9e4066Sahrens } 153fa9e4066Sahrens 154fa9e4066Sahrens if (acl_info->acl_cnt == 0) { 155fa9e4066Sahrens acl_free(acl_info); 156fa9e4066Sahrens errno = save_errno; 157fa9e4066Sahrens return (0); 158fa9e4066Sahrens } 159fa9e4066Sahrens 160fa9e4066Sahrens acl_info->acl_aclp = 161fa9e4066Sahrens malloc(acl_info->acl_cnt * acl_info->acl_entry_size); 162fa9e4066Sahrens save_errno = errno; 163fa9e4066Sahrens 164fa9e4066Sahrens if (acl_info->acl_aclp == NULL) { 165fa9e4066Sahrens acl_free(acl_info); 166fa9e4066Sahrens errno = save_errno; 167fa9e4066Sahrens return (-1); 168fa9e4066Sahrens } 169fa9e4066Sahrens 170fa9e4066Sahrens if (type == ACL_PATH) { 171fa9e4066Sahrens stat_error = stat64(fname, &statbuf); 172fa9e4066Sahrens error = acl(fname, getcmd, acl_info->acl_cnt, 173fa9e4066Sahrens acl_info->acl_aclp); 174fa9e4066Sahrens } else { 175fa9e4066Sahrens stat_error = fstat64(fd, &statbuf); 176fa9e4066Sahrens error = facl(fd, getcmd, acl_info->acl_cnt, 177fa9e4066Sahrens acl_info->acl_aclp); 178fa9e4066Sahrens } 179fa9e4066Sahrens 180fa9e4066Sahrens save_errno = errno; 181fa9e4066Sahrens if (error == -1) { 182fa9e4066Sahrens acl_free(acl_info); 183fa9e4066Sahrens errno = save_errno; 184fa9e4066Sahrens return (-1); 185fa9e4066Sahrens } 186fa9e4066Sahrens 187fa9e4066Sahrens 188fa9e4066Sahrens if (stat_error == 0) { 189fa9e4066Sahrens acl_info->acl_flags = 190fa9e4066Sahrens (S_ISDIR(statbuf.st_mode) ? ACL_IS_DIR : 0); 191fa9e4066Sahrens } else 192fa9e4066Sahrens acl_info->acl_flags = 0; 193fa9e4066Sahrens 194fa9e4066Sahrens switch (acl_info->acl_type) { 195fa9e4066Sahrens case ACLENT_T: 196fa9e4066Sahrens if (acl_info->acl_cnt <= MIN_ACL_ENTRIES) 197fa9e4066Sahrens acl_info->acl_flags |= ACL_IS_TRIVIAL; 198fa9e4066Sahrens break; 199fa9e4066Sahrens case ACE_T: 200fa9e4066Sahrens if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0) 201fa9e4066Sahrens acl_info->acl_flags |= ACL_IS_TRIVIAL; 202fa9e4066Sahrens break; 203fa9e4066Sahrens default: 204fa9e4066Sahrens errno = EINVAL; 205fa9e4066Sahrens acl_free(acl_info); 206fa9e4066Sahrens return (-1); 207fa9e4066Sahrens } 208fa9e4066Sahrens 209fa9e4066Sahrens if ((acl_info->acl_flags & ACL_IS_TRIVIAL) && 210fa9e4066Sahrens (get_flag & ACL_NO_TRIVIAL)) { 211fa9e4066Sahrens acl_free(acl_info); 212fa9e4066Sahrens errno = 0; 213fa9e4066Sahrens return (0); 214fa9e4066Sahrens } 215fa9e4066Sahrens 216fa9e4066Sahrens *aclp = acl_info; 217fa9e4066Sahrens return (0); 218fa9e4066Sahrens } 219fa9e4066Sahrens 220fa9e4066Sahrens /* 221fa9e4066Sahrens * return -1 on failure, otherwise the number of acl 222fa9e4066Sahrens * entries is returned 223fa9e4066Sahrens */ 224fa9e4066Sahrens int 225fa9e4066Sahrens acl_get(const char *path, int get_flag, acl_t **aclp) 226fa9e4066Sahrens { 227fa9e4066Sahrens acl_inp acl_inp; 228fa9e4066Sahrens acl_inp.file = path; 229fa9e4066Sahrens 230fa9e4066Sahrens return (cacl_get(acl_inp, get_flag, ACL_PATH, aclp)); 231fa9e4066Sahrens } 232fa9e4066Sahrens 233fa9e4066Sahrens int 234fa9e4066Sahrens facl_get(int fd, int get_flag, acl_t **aclp) 235fa9e4066Sahrens { 236fa9e4066Sahrens 237fa9e4066Sahrens acl_inp acl_inp; 238fa9e4066Sahrens acl_inp.fd = fd; 239fa9e4066Sahrens 240fa9e4066Sahrens return (cacl_get(acl_inp, get_flag, ACL_FD, aclp)); 241fa9e4066Sahrens } 242fa9e4066Sahrens 243fa9e4066Sahrens /* 244fa9e4066Sahrens * Set an ACL, translates acl to ace_t when appropriate. 245fa9e4066Sahrens */ 246fa9e4066Sahrens static int 247fa9e4066Sahrens cacl_set(acl_inp *acl_inp, acl_t *aclp, int type) 248fa9e4066Sahrens { 249fa9e4066Sahrens int error = 0; 250fa9e4066Sahrens int acl_flavor_target; 251fa9e4066Sahrens struct stat64 statbuf; 252fa9e4066Sahrens int stat_error; 253fa9e4066Sahrens int isdir; 254fa9e4066Sahrens 255fa9e4066Sahrens 256fa9e4066Sahrens if (type == ACL_PATH) { 257fa9e4066Sahrens stat_error = stat64(acl_inp->file, &statbuf); 258fa9e4066Sahrens if (stat_error) 259fa9e4066Sahrens return (-1); 260fa9e4066Sahrens acl_flavor_target = pathconf(acl_inp->file, _PC_ACL_ENABLED); 261fa9e4066Sahrens } else { 262fa9e4066Sahrens stat_error = fstat64(acl_inp->fd, &statbuf); 263fa9e4066Sahrens if (stat_error) 264fa9e4066Sahrens return (-1); 265fa9e4066Sahrens acl_flavor_target = fpathconf(acl_inp->fd, _PC_ACL_ENABLED); 266fa9e4066Sahrens } 267fa9e4066Sahrens 268a222db82Smarks /* 269a222db82Smarks * If target returns an error or 0 from pathconf call then 270a222db82Smarks * fall back to UFS/POSIX Draft interface. 271a222db82Smarks * In the case of 0 we will then fail in either acl(2) or 272a222db82Smarks * acl_translate(). We could erroneously get 0 back from 273a222db82Smarks * a file system that is using fs_pathconf() and not answering 274a222db82Smarks * the _PC_ACL_ENABLED question itself. 275a222db82Smarks */ 276a222db82Smarks if (acl_flavor_target == 0 || acl_flavor_target == -1) 277a222db82Smarks acl_flavor_target = _ACL_ACLENT_ENABLED; 278a222db82Smarks 279fa9e4066Sahrens isdir = S_ISDIR(statbuf.st_mode); 280fa9e4066Sahrens 2813eb3c573Smarks if ((error = acl_translate(aclp, acl_flavor_target, isdir, 2823eb3c573Smarks statbuf.st_uid, statbuf.st_gid)) != 0) { 2833eb3c573Smarks return (error); 284fa9e4066Sahrens } 285fa9e4066Sahrens 286fa9e4066Sahrens if (type == ACL_PATH) { 287fa9e4066Sahrens error = acl(acl_inp->file, 288fa9e4066Sahrens (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, 289fa9e4066Sahrens aclp->acl_cnt, aclp->acl_aclp); 290fa9e4066Sahrens } else { 291fa9e4066Sahrens error = facl(acl_inp->fd, 292fa9e4066Sahrens (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, 293fa9e4066Sahrens aclp->acl_cnt, aclp->acl_aclp); 294fa9e4066Sahrens } 295fa9e4066Sahrens 296fa9e4066Sahrens return (error); 297fa9e4066Sahrens } 298fa9e4066Sahrens 299fa9e4066Sahrens int 300fa9e4066Sahrens acl_set(const char *path, acl_t *aclp) 301fa9e4066Sahrens { 302fa9e4066Sahrens acl_inp acl_inp; 303fa9e4066Sahrens 304fa9e4066Sahrens acl_inp.file = path; 305fa9e4066Sahrens 306fa9e4066Sahrens return (cacl_set(&acl_inp, aclp, ACL_PATH)); 307fa9e4066Sahrens } 308fa9e4066Sahrens 309fa9e4066Sahrens int 310fa9e4066Sahrens facl_set(int fd, acl_t *aclp) 311fa9e4066Sahrens { 312fa9e4066Sahrens acl_inp acl_inp; 313fa9e4066Sahrens 314fa9e4066Sahrens acl_inp.fd = fd; 315fa9e4066Sahrens 316fa9e4066Sahrens return (cacl_set(&acl_inp, aclp, ACL_FD)); 317fa9e4066Sahrens } 318fa9e4066Sahrens 319fa9e4066Sahrens int 320fa9e4066Sahrens acl_cnt(acl_t *aclp) 321fa9e4066Sahrens { 322fa9e4066Sahrens return (aclp->acl_cnt); 323fa9e4066Sahrens } 324fa9e4066Sahrens 325fa9e4066Sahrens int 326fa9e4066Sahrens acl_type(acl_t *aclp) 327fa9e4066Sahrens { 328fa9e4066Sahrens return (aclp->acl_type); 329fa9e4066Sahrens } 330fa9e4066Sahrens 331fa9e4066Sahrens acl_t * 332fa9e4066Sahrens acl_dup(acl_t *aclp) 333fa9e4066Sahrens { 334fa9e4066Sahrens acl_t *newaclp; 335fa9e4066Sahrens 336fa9e4066Sahrens newaclp = acl_alloc(aclp->acl_type); 337fa9e4066Sahrens if (newaclp == NULL) 338fa9e4066Sahrens return (NULL); 339fa9e4066Sahrens 340fa9e4066Sahrens newaclp->acl_aclp = malloc(aclp->acl_entry_size * aclp->acl_cnt); 341fa9e4066Sahrens if (newaclp->acl_aclp == NULL) { 342fa9e4066Sahrens acl_free(newaclp); 343fa9e4066Sahrens return (NULL); 344fa9e4066Sahrens } 345fa9e4066Sahrens 346fa9e4066Sahrens (void) memcpy(newaclp->acl_aclp, 347fa9e4066Sahrens aclp->acl_aclp, aclp->acl_entry_size * aclp->acl_cnt); 348fa9e4066Sahrens newaclp->acl_cnt = aclp->acl_cnt; 349fa9e4066Sahrens 350fa9e4066Sahrens return (newaclp); 351fa9e4066Sahrens } 352fa9e4066Sahrens 353fa9e4066Sahrens int 354fa9e4066Sahrens acl_flags(acl_t *aclp) 355fa9e4066Sahrens { 356fa9e4066Sahrens return (aclp->acl_flags); 357fa9e4066Sahrens } 358fa9e4066Sahrens 359fa9e4066Sahrens void * 360fa9e4066Sahrens acl_data(acl_t *aclp) 361fa9e4066Sahrens { 362fa9e4066Sahrens return (aclp->acl_aclp); 363fa9e4066Sahrens } 364fa9e4066Sahrens 365fa9e4066Sahrens /* 36649f0e518Smarks * Take an acl array and build an acl_t. 36749f0e518Smarks */ 36849f0e518Smarks acl_t * 36949f0e518Smarks acl_to_aclp(enum acl_type type, void *acl, int count) 37049f0e518Smarks { 37149f0e518Smarks acl_t *aclp; 37249f0e518Smarks 37349f0e518Smarks 37449f0e518Smarks aclp = acl_alloc(type); 37549f0e518Smarks if (aclp == NULL) 37649f0e518Smarks return (aclp); 37749f0e518Smarks 37849f0e518Smarks aclp->acl_aclp = acl; 37949f0e518Smarks aclp->acl_cnt = count; 38049f0e518Smarks 38149f0e518Smarks return (aclp); 38249f0e518Smarks } 38349f0e518Smarks 38449f0e518Smarks /* 385fa9e4066Sahrens * Remove an ACL from a file and create a trivial ACL based 386fa9e4066Sahrens * off of the mode argument. After acl has been set owner/group 387fa9e4066Sahrens * are updated to match owner,group arguments 388fa9e4066Sahrens */ 389fa9e4066Sahrens int 390fa9e4066Sahrens acl_strip(const char *file, uid_t owner, gid_t group, mode_t mode) 391fa9e4066Sahrens { 392fa9e4066Sahrens int error = 0; 393fa9e4066Sahrens aclent_t min_acl[MIN_ACL_ENTRIES]; 39427dd1e87SMark Shellenbaum ace_t *min_ace_acl; 395fa9e4066Sahrens int acl_flavor; 396fa9e4066Sahrens int aclcnt; 397*a3c49ce1SAlbert Lee struct stat64 statbuf; 398fa9e4066Sahrens 399fa9e4066Sahrens acl_flavor = pathconf(file, _PC_ACL_ENABLED); 400fa9e4066Sahrens 401*a3c49ce1SAlbert Lee if (stat64(file, &statbuf) != 0) { 402*a3c49ce1SAlbert Lee error = 1; 403*a3c49ce1SAlbert Lee return (error); 404*a3c49ce1SAlbert Lee } 405*a3c49ce1SAlbert Lee 406fa9e4066Sahrens /* 407fa9e4066Sahrens * force it through aclent flavor when file system doesn't 408fa9e4066Sahrens * understand question 409fa9e4066Sahrens */ 410a222db82Smarks if (acl_flavor == 0 || acl_flavor == -1) 411fa9e4066Sahrens acl_flavor = _ACL_ACLENT_ENABLED; 412fa9e4066Sahrens 413fa9e4066Sahrens if (acl_flavor & _ACL_ACLENT_ENABLED) { 414fa9e4066Sahrens min_acl[0].a_type = USER_OBJ; 415fa9e4066Sahrens min_acl[0].a_id = owner; 416fa9e4066Sahrens min_acl[0].a_perm = ((mode & 0700) >> 6); 417fa9e4066Sahrens min_acl[1].a_type = GROUP_OBJ; 418fa9e4066Sahrens min_acl[1].a_id = group; 419fa9e4066Sahrens min_acl[1].a_perm = ((mode & 0070) >> 3); 420fa9e4066Sahrens min_acl[2].a_type = CLASS_OBJ; 421fa9e4066Sahrens min_acl[2].a_id = (uid_t)-1; 422fa9e4066Sahrens min_acl[2].a_perm = ((mode & 0070) >> 3); 423fa9e4066Sahrens min_acl[3].a_type = OTHER_OBJ; 424fa9e4066Sahrens min_acl[3].a_id = (uid_t)-1; 425fa9e4066Sahrens min_acl[3].a_perm = (mode & 0007); 426fa9e4066Sahrens aclcnt = 4; 427fa9e4066Sahrens error = acl(file, SETACL, aclcnt, min_acl); 428fa9e4066Sahrens } else if (acl_flavor & _ACL_ACE_ENABLED) { 429*a3c49ce1SAlbert Lee if ((error = acl_trivial_create(mode, S_ISDIR(statbuf.st_mode), 430*a3c49ce1SAlbert Lee &min_ace_acl, &aclcnt)) != 0) 43127dd1e87SMark Shellenbaum return (error); 43227dd1e87SMark Shellenbaum error = acl(file, ACE_SETACL, aclcnt, min_ace_acl); 43327dd1e87SMark Shellenbaum free(min_ace_acl); 434fa9e4066Sahrens } else { 435fa9e4066Sahrens errno = EINVAL; 436fa9e4066Sahrens error = 1; 437fa9e4066Sahrens } 438fa9e4066Sahrens 439fa9e4066Sahrens if (error == 0) 440fa9e4066Sahrens error = chown(file, owner, group); 441fa9e4066Sahrens return (error); 442fa9e4066Sahrens } 443fa9e4066Sahrens 444fa9e4066Sahrens static int 445fa9e4066Sahrens ace_match(void *entry1, void *entry2) 446fa9e4066Sahrens { 447fa9e4066Sahrens ace_t *p1 = (ace_t *)entry1; 448fa9e4066Sahrens ace_t *p2 = (ace_t *)entry2; 449fa9e4066Sahrens ace_t ace1, ace2; 450fa9e4066Sahrens 451fa9e4066Sahrens ace1 = *p1; 452fa9e4066Sahrens ace2 = *p2; 453fa9e4066Sahrens 454fa9e4066Sahrens /* 455fa9e4066Sahrens * Need to fixup who field for abstrations for 456fa9e4066Sahrens * accurate comparison, since field is undefined. 457fa9e4066Sahrens */ 458fa9e4066Sahrens if (ace1.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE)) 459f48205beScasper ace1.a_who = (uid_t)-1; 460fa9e4066Sahrens if (ace2.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE)) 461f48205beScasper ace2.a_who = (uid_t)-1; 462fa9e4066Sahrens return (memcmp(&ace1, &ace2, sizeof (ace_t))); 463fa9e4066Sahrens } 464fa9e4066Sahrens 465fa9e4066Sahrens static int 466fa9e4066Sahrens aclent_match(void *entry1, void *entry2) 467fa9e4066Sahrens { 468fa9e4066Sahrens aclent_t *aclent1 = (aclent_t *)entry1; 469fa9e4066Sahrens aclent_t *aclent2 = (aclent_t *)entry2; 470fa9e4066Sahrens 471fa9e4066Sahrens return (memcmp(aclent1, aclent2, sizeof (aclent_t))); 472fa9e4066Sahrens } 473fa9e4066Sahrens 474fa9e4066Sahrens /* 475fa9e4066Sahrens * Find acl entries in acl that correspond to removeacl. Search 476fa9e4066Sahrens * is started from slot. The flag argument indicates whether to 477fa9e4066Sahrens * remove all matches or just the first match. 478fa9e4066Sahrens */ 479fa9e4066Sahrens int 480fa9e4066Sahrens acl_removeentries(acl_t *acl, acl_t *removeacl, int start_slot, int flag) 481fa9e4066Sahrens { 482fa9e4066Sahrens int i, j; 483fa9e4066Sahrens int match; 484fa9e4066Sahrens int (*acl_match)(void *acl1, void *acl2); 485fa9e4066Sahrens void *acl_entry, *remove_entry; 486fa9e4066Sahrens void *start; 487fa9e4066Sahrens int found = 0; 488fa9e4066Sahrens 489fa9e4066Sahrens if (flag != ACL_REMOVE_ALL && flag != ACL_REMOVE_FIRST) 490fa9e4066Sahrens flag = ACL_REMOVE_FIRST; 491fa9e4066Sahrens 492fa9e4066Sahrens if (acl == NULL || removeacl == NULL) 493fa9e4066Sahrens return (EACL_NO_ACL_ENTRY); 494fa9e4066Sahrens 495fa9e4066Sahrens if (acl->acl_type != removeacl->acl_type) 496fa9e4066Sahrens return (EACL_DIFF_TYPE); 497fa9e4066Sahrens 498fa9e4066Sahrens if (acl->acl_type == ACLENT_T) 499fa9e4066Sahrens acl_match = aclent_match; 500fa9e4066Sahrens else 501fa9e4066Sahrens acl_match = ace_match; 502fa9e4066Sahrens 503fa9e4066Sahrens for (i = 0, remove_entry = removeacl->acl_aclp; 504fa9e4066Sahrens i != removeacl->acl_cnt; i++) { 505fa9e4066Sahrens 506fa9e4066Sahrens j = 0; 507fa9e4066Sahrens acl_entry = (char *)acl->acl_aclp + 508fa9e4066Sahrens (acl->acl_entry_size * start_slot); 509fa9e4066Sahrens for (;;) { 510fa9e4066Sahrens match = acl_match(acl_entry, remove_entry); 511fa9e4066Sahrens if (match == 0) { 512fa9e4066Sahrens found++; 51357841ad7SRenaud Manus 51457841ad7SRenaud Manus /* avoid memmove if last entry */ 51557841ad7SRenaud Manus if (acl->acl_cnt == (j + 1)) { 51657841ad7SRenaud Manus acl->acl_cnt--; 51757841ad7SRenaud Manus break; 51857841ad7SRenaud Manus } 51957841ad7SRenaud Manus 520fa9e4066Sahrens start = (char *)acl_entry + 521fa9e4066Sahrens acl->acl_entry_size; 522fa9e4066Sahrens (void) memmove(acl_entry, start, 523fa9e4066Sahrens acl->acl_entry_size * 52457841ad7SRenaud Manus (acl->acl_cnt-- - (j + 1))); 525fa9e4066Sahrens 526fa9e4066Sahrens if (flag == ACL_REMOVE_FIRST) 527fa9e4066Sahrens break; 528fa9e4066Sahrens /* 529b249c65cSmarks * List has changed, just continue so this 530b249c65cSmarks * slot gets checked with it's new contents. 531fa9e4066Sahrens */ 532fa9e4066Sahrens continue; 533fa9e4066Sahrens } 534fa9e4066Sahrens acl_entry = ((char *)acl_entry + acl->acl_entry_size); 535fa9e4066Sahrens if (++j >= acl->acl_cnt) { 536fa9e4066Sahrens break; 537fa9e4066Sahrens } 538fa9e4066Sahrens } 539b249c65cSmarks remove_entry = (char *)remove_entry + removeacl->acl_entry_size; 540fa9e4066Sahrens } 541fa9e4066Sahrens 542fa9e4066Sahrens return ((found == 0) ? EACL_NO_ACL_ENTRY : 0); 543fa9e4066Sahrens } 544fa9e4066Sahrens 545fa9e4066Sahrens /* 546fa9e4066Sahrens * Replace entires entries in acl1 with the corresponding entries 547fa9e4066Sahrens * in newentries. The where argument specifies where to begin 548fa9e4066Sahrens * the replacement. If the where argument is 1 greater than the 549fa9e4066Sahrens * number of acl entries in acl1 then they are appended. If the 550fa9e4066Sahrens * where argument is 2+ greater than the number of acl entries then 551fa9e4066Sahrens * EACL_INVALID_SLOT is returned. 552fa9e4066Sahrens */ 553fa9e4066Sahrens int 554fa9e4066Sahrens acl_modifyentries(acl_t *acl1, acl_t *newentries, int where) 555fa9e4066Sahrens { 556fa9e4066Sahrens 557fa9e4066Sahrens int slot; 558fa9e4066Sahrens int slots_needed; 559fa9e4066Sahrens int slots_left; 560fa9e4066Sahrens int newsize; 561fa9e4066Sahrens 562fa9e4066Sahrens if (acl1 == NULL || newentries == NULL) 563fa9e4066Sahrens return (EACL_NO_ACL_ENTRY); 564fa9e4066Sahrens 565fa9e4066Sahrens if (where < 0 || where >= acl1->acl_cnt) 566fa9e4066Sahrens return (EACL_INVALID_SLOT); 567fa9e4066Sahrens 568fa9e4066Sahrens if (acl1->acl_type != newentries->acl_type) 569fa9e4066Sahrens return (EACL_DIFF_TYPE); 570fa9e4066Sahrens 571fa9e4066Sahrens slot = where; 572fa9e4066Sahrens 573fa9e4066Sahrens slots_left = acl1->acl_cnt - slot + 1; 574fa9e4066Sahrens if (slots_left < newentries->acl_cnt) { 575fa9e4066Sahrens slots_needed = newentries->acl_cnt - slots_left; 576fa9e4066Sahrens newsize = (acl1->acl_entry_size * acl1->acl_cnt) + 577fa9e4066Sahrens (acl1->acl_entry_size * slots_needed); 578fa9e4066Sahrens acl1->acl_aclp = realloc(acl1->acl_aclp, newsize); 579fa9e4066Sahrens if (acl1->acl_aclp == NULL) 580fa9e4066Sahrens return (-1); 581fa9e4066Sahrens } 582fa9e4066Sahrens (void) memcpy((char *)acl1->acl_aclp + (acl1->acl_entry_size * slot), 583fa9e4066Sahrens newentries->acl_aclp, 584fa9e4066Sahrens newentries->acl_entry_size * newentries->acl_cnt); 585fa9e4066Sahrens 586fa9e4066Sahrens /* 587fa9e4066Sahrens * Did ACL grow? 588fa9e4066Sahrens */ 589fa9e4066Sahrens 590fa9e4066Sahrens if ((slot + newentries->acl_cnt) > acl1->acl_cnt) { 591fa9e4066Sahrens acl1->acl_cnt = slot + newentries->acl_cnt; 592fa9e4066Sahrens } 593fa9e4066Sahrens 594fa9e4066Sahrens return (0); 595fa9e4066Sahrens } 596fa9e4066Sahrens 597fa9e4066Sahrens /* 598fa9e4066Sahrens * Add acl2 entries into acl1. The where argument specifies where 599fa9e4066Sahrens * to add the entries. 600fa9e4066Sahrens */ 601fa9e4066Sahrens int 602fa9e4066Sahrens acl_addentries(acl_t *acl1, acl_t *acl2, int where) 603fa9e4066Sahrens { 604fa9e4066Sahrens 605fa9e4066Sahrens int newsize; 606fa9e4066Sahrens int len; 607fa9e4066Sahrens void *start; 608fa9e4066Sahrens void *to; 609fa9e4066Sahrens 610fa9e4066Sahrens if (acl1 == NULL || acl2 == NULL) 611fa9e4066Sahrens return (EACL_NO_ACL_ENTRY); 612fa9e4066Sahrens 613fa9e4066Sahrens if (acl1->acl_type != acl2->acl_type) 614fa9e4066Sahrens return (EACL_DIFF_TYPE); 615fa9e4066Sahrens 616fa9e4066Sahrens /* 617fa9e4066Sahrens * allow where to specify 1 past last slot for an append operation 618fa9e4066Sahrens * but anything greater is an error. 619fa9e4066Sahrens */ 620fa9e4066Sahrens if (where < 0 || where > acl1->acl_cnt) 621fa9e4066Sahrens return (EACL_INVALID_SLOT); 622fa9e4066Sahrens 623fa9e4066Sahrens newsize = (acl2->acl_entry_size * acl2->acl_cnt) + 624fa9e4066Sahrens (acl1->acl_entry_size * acl1->acl_cnt); 625fa9e4066Sahrens acl1->acl_aclp = realloc(acl1->acl_aclp, newsize); 626fa9e4066Sahrens if (acl1->acl_aclp == NULL) 627fa9e4066Sahrens return (-1); 628fa9e4066Sahrens 629fa9e4066Sahrens /* 630fa9e4066Sahrens * first push down entries where new ones will be inserted 631fa9e4066Sahrens */ 632fa9e4066Sahrens 633fa9e4066Sahrens to = (void *)((char *)acl1->acl_aclp + 634fa9e4066Sahrens ((where + acl2->acl_cnt) * acl1->acl_entry_size)); 635fa9e4066Sahrens 636fa9e4066Sahrens start = (void *)((char *)acl1->acl_aclp + 637fa9e4066Sahrens where * acl1->acl_entry_size); 638fa9e4066Sahrens 639fa9e4066Sahrens if (where < acl1->acl_cnt) { 640fa9e4066Sahrens len = (acl1->acl_cnt - where) * acl1->acl_entry_size; 641fa9e4066Sahrens (void) memmove(to, start, len); 642fa9e4066Sahrens } 643fa9e4066Sahrens 644fa9e4066Sahrens /* 645fa9e4066Sahrens * now stick in new entries. 646fa9e4066Sahrens */ 647fa9e4066Sahrens 648fa9e4066Sahrens (void) memmove(start, acl2->acl_aclp, 649fa9e4066Sahrens acl2->acl_cnt * acl2->acl_entry_size); 650fa9e4066Sahrens 651fa9e4066Sahrens acl1->acl_cnt += acl2->acl_cnt; 652fa9e4066Sahrens return (0); 653fa9e4066Sahrens } 654fa9e4066Sahrens 655fa9e4066Sahrens /* 656fa9e4066Sahrens * return text for an ACL error. 657fa9e4066Sahrens */ 658fa9e4066Sahrens char * 659fa9e4066Sahrens acl_strerror(int errnum) 660fa9e4066Sahrens { 661fa9e4066Sahrens switch (errnum) { 662fa9e4066Sahrens case EACL_GRP_ERROR: 663fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 6645a5eeccaSmarks "There is more than one group or default group entry")); 665fa9e4066Sahrens case EACL_USER_ERROR: 666fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 6675a5eeccaSmarks "There is more than one user or default user entry")); 668fa9e4066Sahrens case EACL_OTHER_ERROR: 669fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 670fa9e4066Sahrens "There is more than one other entry")); 671fa9e4066Sahrens case EACL_CLASS_ERROR: 672fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 673fa9e4066Sahrens "There is more than one mask entry")); 674fa9e4066Sahrens case EACL_DUPLICATE_ERROR: 675fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 676fa9e4066Sahrens "Duplicate user or group entries")); 677fa9e4066Sahrens case EACL_MISS_ERROR: 678fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 679fa9e4066Sahrens "Missing user/group owner, other, mask entry")); 680fa9e4066Sahrens case EACL_MEM_ERROR: 681fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 682fa9e4066Sahrens "Memory error")); 683fa9e4066Sahrens case EACL_ENTRY_ERROR: 684fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 685fa9e4066Sahrens "Unrecognized entry type")); 686fa9e4066Sahrens case EACL_INHERIT_ERROR: 687fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 688fa9e4066Sahrens "Invalid inheritance flags")); 689fa9e4066Sahrens case EACL_FLAGS_ERROR: 690fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 691fa9e4066Sahrens "Unrecognized entry flags")); 692fa9e4066Sahrens case EACL_PERM_MASK_ERROR: 693fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 694fa9e4066Sahrens "Invalid ACL permissions")); 695fa9e4066Sahrens case EACL_COUNT_ERROR: 696fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 697fa9e4066Sahrens "Invalid ACL count")); 698fa9e4066Sahrens case EACL_INVALID_SLOT: 699fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 700fa9e4066Sahrens "Invalid ACL entry number specified")); 701fa9e4066Sahrens case EACL_NO_ACL_ENTRY: 702fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 703fa9e4066Sahrens "ACL entry doesn't exist")); 704fa9e4066Sahrens case EACL_DIFF_TYPE: 705fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 7062269545aSstephanie scheffler "Different file system ACL types cannot be merged")); 707fa9e4066Sahrens case EACL_INVALID_USER_GROUP: 708fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "Invalid user or group")); 709fa9e4066Sahrens case EACL_INVALID_STR: 710fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "ACL string is invalid")); 711fa9e4066Sahrens case EACL_FIELD_NOT_BLANK: 712fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "Field expected to be blank")); 713fa9e4066Sahrens case EACL_INVALID_ACCESS_TYPE: 714fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "Invalid access type")); 715fa9e4066Sahrens case EACL_UNKNOWN_DATA: 716fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "Unrecognized entry")); 717fa9e4066Sahrens case EACL_MISSING_FIELDS: 718fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 719fa9e4066Sahrens "ACL specification missing required fields")); 720fa9e4066Sahrens case EACL_INHERIT_NOTDIR: 721fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, 722fa9e4066Sahrens "Inheritance flags are only allowed on directories")); 723fa9e4066Sahrens case -1: 724fa9e4066Sahrens return (strerror(errno)); 725fa9e4066Sahrens default: 726fa9e4066Sahrens errno = EINVAL; 727fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "Unknown error")); 728fa9e4066Sahrens } 729fa9e4066Sahrens } 7305a5eeccaSmarks 7315a5eeccaSmarks extern int yyinteractive; 7325a5eeccaSmarks 7335a5eeccaSmarks /* PRINTFLIKE1 */ 7345a5eeccaSmarks void 7355a5eeccaSmarks acl_error(const char *fmt, ...) 7365a5eeccaSmarks { 7375a5eeccaSmarks va_list va; 7385a5eeccaSmarks 7395a5eeccaSmarks if (yyinteractive == 0) 7405a5eeccaSmarks return; 7415a5eeccaSmarks 7425a5eeccaSmarks va_start(va, fmt); 7435a5eeccaSmarks (void) vfprintf(stderr, fmt, va); 7445a5eeccaSmarks va_end(va); 7455a5eeccaSmarks } 746b249c65cSmarks 747b249c65cSmarks int 748b249c65cSmarks sid_to_id(char *sid, boolean_t user, uid_t *id) 749b249c65cSmarks { 750b249c65cSmarks idmap_get_handle_t *get_hdl = NULL; 751b249c65cSmarks char *rid_start = NULL; 752b249c65cSmarks idmap_stat status; 753b249c65cSmarks char *end; 754909c9a9fSMark Shellenbaum int error = 1; 755b249c65cSmarks char *domain_start; 756b249c65cSmarks 757b249c65cSmarks if ((domain_start = strchr(sid, '@')) == NULL) { 758b249c65cSmarks idmap_rid_t rid; 759b249c65cSmarks 760b249c65cSmarks if ((rid_start = strrchr(sid, '-')) == NULL) 761909c9a9fSMark Shellenbaum return (1); 762b249c65cSmarks *rid_start++ = '\0'; 763b249c65cSmarks errno = 0; 764b249c65cSmarks rid = strtoul(rid_start--, &end, 10); 765b249c65cSmarks if (errno == 0 && *end == '\0') { 7661fdeec65Sjoyce mcintosh if (idmap_get_create(&get_hdl) == 767909c9a9fSMark Shellenbaum IDMAP_SUCCESS) { 768b249c65cSmarks if (user) 769b249c65cSmarks error = idmap_get_uidbysid(get_hdl, 7703ee87bcaSJulian Pullen sid, rid, IDMAP_REQ_FLG_USE_CACHE, 7713ee87bcaSJulian Pullen id, &status); 772b249c65cSmarks else 773b249c65cSmarks error = idmap_get_gidbysid(get_hdl, 7743ee87bcaSJulian Pullen sid, rid, IDMAP_REQ_FLG_USE_CACHE, 7753ee87bcaSJulian Pullen id, &status); 776909c9a9fSMark Shellenbaum if (error == IDMAP_SUCCESS) { 777909c9a9fSMark Shellenbaum error = idmap_get_mappings(get_hdl); 778909c9a9fSMark Shellenbaum if (error == IDMAP_SUCCESS && 779909c9a9fSMark Shellenbaum status != IDMAP_SUCCESS) 780909c9a9fSMark Shellenbaum error = 1; 781909c9a9fSMark Shellenbaum else 782909c9a9fSMark Shellenbaum error = 0; 783b249c65cSmarks } 784b249c65cSmarks } else { 785909c9a9fSMark Shellenbaum error = 1; 786b249c65cSmarks } 787b249c65cSmarks if (get_hdl) 788b249c65cSmarks idmap_get_destroy(get_hdl); 789909c9a9fSMark Shellenbaum } else { 790909c9a9fSMark Shellenbaum error = 1; 791909c9a9fSMark Shellenbaum } 792b249c65cSmarks *rid_start = '-'; /* putback character removed earlier */ 793b249c65cSmarks } else { 794b249c65cSmarks char *name = sid; 795b249c65cSmarks *domain_start++ = '\0'; 796b249c65cSmarks 797b249c65cSmarks if (user) 7983ee87bcaSJulian Pullen error = idmap_getuidbywinname(name, domain_start, 7993ee87bcaSJulian Pullen IDMAP_REQ_FLG_USE_CACHE, id); 800b249c65cSmarks else 8013ee87bcaSJulian Pullen error = idmap_getgidbywinname(name, domain_start, 8023ee87bcaSJulian Pullen IDMAP_REQ_FLG_USE_CACHE, id); 803b249c65cSmarks *--domain_start = '@'; 804909c9a9fSMark Shellenbaum error = (error == IDMAP_SUCCESS) ? 0 : 1; 805b249c65cSmarks } 806b249c65cSmarks 807b249c65cSmarks return (error); 808b249c65cSmarks } 809