1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 51462Smarks * Common Development and Distribution License (the "License"). 61462Smarks * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 21789Sahrens /* 2212164SMark.Shellenbaum@Sun.COM * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23789Sahrens */ 24789Sahrens 25789Sahrens 26789Sahrens #include <stdlib.h> 27789Sahrens #include <string.h> 28789Sahrens #include <unistd.h> 29789Sahrens #include <limits.h> 30789Sahrens #include <grp.h> 31789Sahrens #include <pwd.h> 321462Smarks #include <strings.h> 33789Sahrens #include <sys/types.h> 34789Sahrens #include <errno.h> 35789Sahrens #include <sys/stat.h> 361420Smarks #include <sys/varargs.h> 37789Sahrens #include <locale.h> 38789Sahrens #include <aclutils.h> 395331Samw #include <sys/avl.h> 40789Sahrens #include <acl_common.h> 417057Smarks #include <idmap.h> 42789Sahrens 43789Sahrens #define ACL_PATH 0 44789Sahrens #define ACL_FD 1 45789Sahrens 461231Smarks 47789Sahrens typedef union { 48789Sahrens const char *file; 49789Sahrens int fd; 50789Sahrens } acl_inp; 51789Sahrens 52789Sahrens 53789Sahrens /* 54789Sahrens * Determine whether a file has a trivial ACL 55789Sahrens * returns: 0 = trivial 56789Sahrens * 1 = nontrivial 57789Sahrens * <0 some other system failure, such as ENOENT or EPERM 58789Sahrens */ 59789Sahrens int 60789Sahrens acl_trivial(const char *filename) 61789Sahrens { 62789Sahrens int acl_flavor; 63789Sahrens int aclcnt; 64789Sahrens int cntcmd; 65789Sahrens int val = 0; 66789Sahrens ace_t *acep; 67789Sahrens 68789Sahrens acl_flavor = pathconf(filename, _PC_ACL_ENABLED); 69789Sahrens 70789Sahrens if (acl_flavor == _ACL_ACE_ENABLED) 71789Sahrens cntcmd = ACE_GETACLCNT; 72789Sahrens else 73789Sahrens cntcmd = GETACLCNT; 74789Sahrens 75789Sahrens aclcnt = acl(filename, cntcmd, 0, NULL); 76789Sahrens if (aclcnt > 0) { 77789Sahrens if (acl_flavor == _ACL_ACE_ENABLED) { 781231Smarks acep = malloc(sizeof (ace_t) * aclcnt); 791231Smarks if (acep == NULL) 801231Smarks return (-1); 811231Smarks if (acl(filename, ACE_GETACL, 821231Smarks aclcnt, acep) < 0) { 831231Smarks free(acep); 841231Smarks return (-1); 851231Smarks } 86789Sahrens 871231Smarks val = ace_trivial(acep, aclcnt); 881231Smarks free(acep); 891231Smarks 90789Sahrens } else if (aclcnt > MIN_ACL_ENTRIES) 91789Sahrens val = 1; 92789Sahrens } 93789Sahrens return (val); 94789Sahrens } 95789Sahrens 961462Smarks 971477Smarks static int 98789Sahrens cacl_get(acl_inp inp, int get_flag, int type, acl_t **aclp) 99789Sahrens { 100789Sahrens const char *fname; 101789Sahrens int fd; 102789Sahrens int ace_acl = 0; 103789Sahrens int error; 104789Sahrens int getcmd, cntcmd; 105789Sahrens acl_t *acl_info; 106789Sahrens int save_errno; 107789Sahrens int stat_error; 108789Sahrens struct stat64 statbuf; 109789Sahrens 110789Sahrens *aclp = NULL; 111789Sahrens if (type == ACL_PATH) { 112789Sahrens fname = inp.file; 113789Sahrens ace_acl = pathconf(fname, _PC_ACL_ENABLED); 114789Sahrens } else { 115789Sahrens fd = inp.fd; 116789Sahrens ace_acl = fpathconf(fd, _PC_ACL_ENABLED); 117789Sahrens } 118789Sahrens 119789Sahrens /* 120789Sahrens * if acl's aren't supported then 121789Sahrens * send it through the old GETACL interface 122789Sahrens */ 1231666Smarks if (ace_acl == 0 || ace_acl == -1) { 124789Sahrens ace_acl = _ACL_ACLENT_ENABLED; 125789Sahrens } 126789Sahrens 127789Sahrens if (ace_acl & _ACL_ACE_ENABLED) { 128789Sahrens cntcmd = ACE_GETACLCNT; 129789Sahrens getcmd = ACE_GETACL; 130789Sahrens acl_info = acl_alloc(ACE_T); 131789Sahrens } else { 132789Sahrens cntcmd = GETACLCNT; 133789Sahrens getcmd = GETACL; 134789Sahrens acl_info = acl_alloc(ACLENT_T); 135789Sahrens } 136789Sahrens 137789Sahrens if (acl_info == NULL) 138789Sahrens return (-1); 139789Sahrens 140789Sahrens if (type == ACL_PATH) { 141789Sahrens acl_info->acl_cnt = acl(fname, cntcmd, 0, NULL); 142789Sahrens } else { 143789Sahrens acl_info->acl_cnt = facl(fd, cntcmd, 0, NULL); 144789Sahrens } 145789Sahrens 146789Sahrens save_errno = errno; 147789Sahrens if (acl_info->acl_cnt < 0) { 148789Sahrens acl_free(acl_info); 149789Sahrens errno = save_errno; 150789Sahrens return (-1); 151789Sahrens } 152789Sahrens 153789Sahrens if (acl_info->acl_cnt == 0) { 154789Sahrens acl_free(acl_info); 155789Sahrens errno = save_errno; 156789Sahrens return (0); 157789Sahrens } 158789Sahrens 159789Sahrens acl_info->acl_aclp = 160789Sahrens malloc(acl_info->acl_cnt * acl_info->acl_entry_size); 161789Sahrens save_errno = errno; 162789Sahrens 163789Sahrens if (acl_info->acl_aclp == NULL) { 164789Sahrens acl_free(acl_info); 165789Sahrens errno = save_errno; 166789Sahrens return (-1); 167789Sahrens } 168789Sahrens 169789Sahrens if (type == ACL_PATH) { 170789Sahrens stat_error = stat64(fname, &statbuf); 171789Sahrens error = acl(fname, getcmd, acl_info->acl_cnt, 172789Sahrens acl_info->acl_aclp); 173789Sahrens } else { 174789Sahrens stat_error = fstat64(fd, &statbuf); 175789Sahrens error = facl(fd, getcmd, acl_info->acl_cnt, 176789Sahrens acl_info->acl_aclp); 177789Sahrens } 178789Sahrens 179789Sahrens save_errno = errno; 180789Sahrens if (error == -1) { 181789Sahrens acl_free(acl_info); 182789Sahrens errno = save_errno; 183789Sahrens return (-1); 184789Sahrens } 185789Sahrens 186789Sahrens 187789Sahrens if (stat_error == 0) { 188789Sahrens acl_info->acl_flags = 189789Sahrens (S_ISDIR(statbuf.st_mode) ? ACL_IS_DIR : 0); 190789Sahrens } else 191789Sahrens acl_info->acl_flags = 0; 192789Sahrens 193789Sahrens switch (acl_info->acl_type) { 194789Sahrens case ACLENT_T: 195789Sahrens if (acl_info->acl_cnt <= MIN_ACL_ENTRIES) 196789Sahrens acl_info->acl_flags |= ACL_IS_TRIVIAL; 197789Sahrens break; 198789Sahrens case ACE_T: 199789Sahrens if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0) 200789Sahrens acl_info->acl_flags |= ACL_IS_TRIVIAL; 201789Sahrens break; 202789Sahrens default: 203789Sahrens errno = EINVAL; 204789Sahrens acl_free(acl_info); 205789Sahrens return (-1); 206789Sahrens } 207789Sahrens 208789Sahrens if ((acl_info->acl_flags & ACL_IS_TRIVIAL) && 209789Sahrens (get_flag & ACL_NO_TRIVIAL)) { 210789Sahrens acl_free(acl_info); 211789Sahrens errno = 0; 212789Sahrens return (0); 213789Sahrens } 214789Sahrens 215789Sahrens *aclp = acl_info; 216789Sahrens return (0); 217789Sahrens } 218789Sahrens 219789Sahrens /* 220789Sahrens * return -1 on failure, otherwise the number of acl 221789Sahrens * entries is returned 222789Sahrens */ 223789Sahrens int 224789Sahrens acl_get(const char *path, int get_flag, acl_t **aclp) 225789Sahrens { 226789Sahrens acl_inp acl_inp; 227789Sahrens acl_inp.file = path; 228789Sahrens 229789Sahrens return (cacl_get(acl_inp, get_flag, ACL_PATH, aclp)); 230789Sahrens } 231789Sahrens 232789Sahrens int 233789Sahrens facl_get(int fd, int get_flag, acl_t **aclp) 234789Sahrens { 235789Sahrens 236789Sahrens acl_inp acl_inp; 237789Sahrens acl_inp.fd = fd; 238789Sahrens 239789Sahrens return (cacl_get(acl_inp, get_flag, ACL_FD, aclp)); 240789Sahrens } 241789Sahrens 242789Sahrens /* 243789Sahrens * Set an ACL, translates acl to ace_t when appropriate. 244789Sahrens */ 245789Sahrens static int 246789Sahrens cacl_set(acl_inp *acl_inp, acl_t *aclp, int type) 247789Sahrens { 248789Sahrens int error = 0; 249789Sahrens int acl_flavor_target; 250789Sahrens struct stat64 statbuf; 251789Sahrens int stat_error; 252789Sahrens int isdir; 253789Sahrens 254789Sahrens 255789Sahrens if (type == ACL_PATH) { 256789Sahrens stat_error = stat64(acl_inp->file, &statbuf); 257789Sahrens if (stat_error) 258789Sahrens return (-1); 259789Sahrens acl_flavor_target = pathconf(acl_inp->file, _PC_ACL_ENABLED); 260789Sahrens } else { 261789Sahrens stat_error = fstat64(acl_inp->fd, &statbuf); 262789Sahrens if (stat_error) 263789Sahrens return (-1); 264789Sahrens acl_flavor_target = fpathconf(acl_inp->fd, _PC_ACL_ENABLED); 265789Sahrens } 266789Sahrens 2671666Smarks /* 2681666Smarks * If target returns an error or 0 from pathconf call then 2691666Smarks * fall back to UFS/POSIX Draft interface. 2701666Smarks * In the case of 0 we will then fail in either acl(2) or 2711666Smarks * acl_translate(). We could erroneously get 0 back from 2721666Smarks * a file system that is using fs_pathconf() and not answering 2731666Smarks * the _PC_ACL_ENABLED question itself. 2741666Smarks */ 2751666Smarks if (acl_flavor_target == 0 || acl_flavor_target == -1) 2761666Smarks acl_flavor_target = _ACL_ACLENT_ENABLED; 2771666Smarks 278789Sahrens isdir = S_ISDIR(statbuf.st_mode); 279789Sahrens 2801462Smarks if ((error = acl_translate(aclp, acl_flavor_target, isdir, 2811462Smarks statbuf.st_uid, statbuf.st_gid)) != 0) { 2821462Smarks return (error); 283789Sahrens } 284789Sahrens 285789Sahrens if (type == ACL_PATH) { 286789Sahrens error = acl(acl_inp->file, 287789Sahrens (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, 288789Sahrens aclp->acl_cnt, aclp->acl_aclp); 289789Sahrens } else { 290789Sahrens error = facl(acl_inp->fd, 291789Sahrens (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, 292789Sahrens aclp->acl_cnt, aclp->acl_aclp); 293789Sahrens } 294789Sahrens 295789Sahrens return (error); 296789Sahrens } 297789Sahrens 298789Sahrens int 299789Sahrens acl_set(const char *path, acl_t *aclp) 300789Sahrens { 301789Sahrens acl_inp acl_inp; 302789Sahrens 303789Sahrens acl_inp.file = path; 304789Sahrens 305789Sahrens return (cacl_set(&acl_inp, aclp, ACL_PATH)); 306789Sahrens } 307789Sahrens 308789Sahrens int 309789Sahrens facl_set(int fd, acl_t *aclp) 310789Sahrens { 311789Sahrens acl_inp acl_inp; 312789Sahrens 313789Sahrens acl_inp.fd = fd; 314789Sahrens 315789Sahrens return (cacl_set(&acl_inp, aclp, ACL_FD)); 316789Sahrens } 317789Sahrens 318789Sahrens int 319789Sahrens acl_cnt(acl_t *aclp) 320789Sahrens { 321789Sahrens return (aclp->acl_cnt); 322789Sahrens } 323789Sahrens 324789Sahrens int 325789Sahrens acl_type(acl_t *aclp) 326789Sahrens { 327789Sahrens return (aclp->acl_type); 328789Sahrens } 329789Sahrens 330789Sahrens acl_t * 331789Sahrens acl_dup(acl_t *aclp) 332789Sahrens { 333789Sahrens acl_t *newaclp; 334789Sahrens 335789Sahrens newaclp = acl_alloc(aclp->acl_type); 336789Sahrens if (newaclp == NULL) 337789Sahrens return (NULL); 338789Sahrens 339789Sahrens newaclp->acl_aclp = malloc(aclp->acl_entry_size * aclp->acl_cnt); 340789Sahrens if (newaclp->acl_aclp == NULL) { 341789Sahrens acl_free(newaclp); 342789Sahrens return (NULL); 343789Sahrens } 344789Sahrens 345789Sahrens (void) memcpy(newaclp->acl_aclp, 346789Sahrens aclp->acl_aclp, aclp->acl_entry_size * aclp->acl_cnt); 347789Sahrens newaclp->acl_cnt = aclp->acl_cnt; 348789Sahrens 349789Sahrens return (newaclp); 350789Sahrens } 351789Sahrens 352789Sahrens int 353789Sahrens acl_flags(acl_t *aclp) 354789Sahrens { 355789Sahrens return (aclp->acl_flags); 356789Sahrens } 357789Sahrens 358789Sahrens void * 359789Sahrens acl_data(acl_t *aclp) 360789Sahrens { 361789Sahrens return (aclp->acl_aclp); 362789Sahrens } 363789Sahrens 364789Sahrens /* 3651953Smarks * Take an acl array and build an acl_t. 3661953Smarks */ 3671953Smarks acl_t * 3681953Smarks acl_to_aclp(enum acl_type type, void *acl, int count) 3691953Smarks { 3701953Smarks acl_t *aclp; 3711953Smarks 3721953Smarks 3731953Smarks aclp = acl_alloc(type); 3741953Smarks if (aclp == NULL) 3751953Smarks return (aclp); 3761953Smarks 3771953Smarks aclp->acl_aclp = acl; 3781953Smarks aclp->acl_cnt = count; 3791953Smarks 3801953Smarks return (aclp); 3811953Smarks } 3821953Smarks 3831953Smarks /* 384789Sahrens * Remove an ACL from a file and create a trivial ACL based 385789Sahrens * off of the mode argument. After acl has been set owner/group 386789Sahrens * are updated to match owner,group arguments 387789Sahrens */ 388789Sahrens int 389789Sahrens acl_strip(const char *file, uid_t owner, gid_t group, mode_t mode) 390789Sahrens { 391789Sahrens int error = 0; 392789Sahrens aclent_t min_acl[MIN_ACL_ENTRIES]; 39312164SMark.Shellenbaum@Sun.COM ace_t *min_ace_acl; 394789Sahrens int acl_flavor; 395789Sahrens int aclcnt; 396789Sahrens 397789Sahrens acl_flavor = pathconf(file, _PC_ACL_ENABLED); 398789Sahrens 399789Sahrens /* 400789Sahrens * force it through aclent flavor when file system doesn't 401789Sahrens * understand question 402789Sahrens */ 4031666Smarks if (acl_flavor == 0 || acl_flavor == -1) 404789Sahrens acl_flavor = _ACL_ACLENT_ENABLED; 405789Sahrens 406789Sahrens if (acl_flavor & _ACL_ACLENT_ENABLED) { 407789Sahrens min_acl[0].a_type = USER_OBJ; 408789Sahrens min_acl[0].a_id = owner; 409789Sahrens min_acl[0].a_perm = ((mode & 0700) >> 6); 410789Sahrens min_acl[1].a_type = GROUP_OBJ; 411789Sahrens min_acl[1].a_id = group; 412789Sahrens min_acl[1].a_perm = ((mode & 0070) >> 3); 413789Sahrens min_acl[2].a_type = CLASS_OBJ; 414789Sahrens min_acl[2].a_id = (uid_t)-1; 415789Sahrens min_acl[2].a_perm = ((mode & 0070) >> 3); 416789Sahrens min_acl[3].a_type = OTHER_OBJ; 417789Sahrens min_acl[3].a_id = (uid_t)-1; 418789Sahrens min_acl[3].a_perm = (mode & 0007); 419789Sahrens aclcnt = 4; 420789Sahrens error = acl(file, SETACL, aclcnt, min_acl); 421789Sahrens } else if (acl_flavor & _ACL_ACE_ENABLED) { 42212164SMark.Shellenbaum@Sun.COM if ((error = acl_trivial_create(mode, &min_ace_acl, 42312164SMark.Shellenbaum@Sun.COM &aclcnt)) != 0) 42412164SMark.Shellenbaum@Sun.COM return (error); 42512164SMark.Shellenbaum@Sun.COM error = acl(file, ACE_SETACL, aclcnt, min_ace_acl); 42612164SMark.Shellenbaum@Sun.COM free(min_ace_acl); 427789Sahrens } else { 428789Sahrens errno = EINVAL; 429789Sahrens error = 1; 430789Sahrens } 431789Sahrens 432789Sahrens if (error == 0) 433789Sahrens error = chown(file, owner, group); 434789Sahrens return (error); 435789Sahrens } 436789Sahrens 437789Sahrens static int 438789Sahrens ace_match(void *entry1, void *entry2) 439789Sahrens { 440789Sahrens ace_t *p1 = (ace_t *)entry1; 441789Sahrens ace_t *p2 = (ace_t *)entry2; 442789Sahrens ace_t ace1, ace2; 443789Sahrens 444789Sahrens ace1 = *p1; 445789Sahrens ace2 = *p2; 446789Sahrens 447789Sahrens /* 448789Sahrens * Need to fixup who field for abstrations for 449789Sahrens * accurate comparison, since field is undefined. 450789Sahrens */ 451789Sahrens if (ace1.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE)) 4524321Scasper ace1.a_who = (uid_t)-1; 453789Sahrens if (ace2.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE)) 4544321Scasper ace2.a_who = (uid_t)-1; 455789Sahrens return (memcmp(&ace1, &ace2, sizeof (ace_t))); 456789Sahrens } 457789Sahrens 458789Sahrens static int 459789Sahrens aclent_match(void *entry1, void *entry2) 460789Sahrens { 461789Sahrens aclent_t *aclent1 = (aclent_t *)entry1; 462789Sahrens aclent_t *aclent2 = (aclent_t *)entry2; 463789Sahrens 464789Sahrens return (memcmp(aclent1, aclent2, sizeof (aclent_t))); 465789Sahrens } 466789Sahrens 467789Sahrens /* 468789Sahrens * Find acl entries in acl that correspond to removeacl. Search 469789Sahrens * is started from slot. The flag argument indicates whether to 470789Sahrens * remove all matches or just the first match. 471789Sahrens */ 472789Sahrens int 473789Sahrens acl_removeentries(acl_t *acl, acl_t *removeacl, int start_slot, int flag) 474789Sahrens { 475789Sahrens int i, j; 476789Sahrens int match; 477789Sahrens int (*acl_match)(void *acl1, void *acl2); 478789Sahrens void *acl_entry, *remove_entry; 479789Sahrens void *start; 480789Sahrens int found = 0; 481789Sahrens 482789Sahrens if (flag != ACL_REMOVE_ALL && flag != ACL_REMOVE_FIRST) 483789Sahrens flag = ACL_REMOVE_FIRST; 484789Sahrens 485789Sahrens if (acl == NULL || removeacl == NULL) 486789Sahrens return (EACL_NO_ACL_ENTRY); 487789Sahrens 488789Sahrens if (acl->acl_type != removeacl->acl_type) 489789Sahrens return (EACL_DIFF_TYPE); 490789Sahrens 491789Sahrens if (acl->acl_type == ACLENT_T) 492789Sahrens acl_match = aclent_match; 493789Sahrens else 494789Sahrens acl_match = ace_match; 495789Sahrens 496789Sahrens for (i = 0, remove_entry = removeacl->acl_aclp; 497789Sahrens i != removeacl->acl_cnt; i++) { 498789Sahrens 499789Sahrens j = 0; 500789Sahrens acl_entry = (char *)acl->acl_aclp + 501789Sahrens (acl->acl_entry_size * start_slot); 502789Sahrens for (;;) { 503789Sahrens match = acl_match(acl_entry, remove_entry); 504789Sahrens if (match == 0) { 505789Sahrens found++; 5068672SRenaud.Manus@Sun.COM 5078672SRenaud.Manus@Sun.COM /* avoid memmove if last entry */ 5088672SRenaud.Manus@Sun.COM if (acl->acl_cnt == (j + 1)) { 5098672SRenaud.Manus@Sun.COM acl->acl_cnt--; 5108672SRenaud.Manus@Sun.COM break; 5118672SRenaud.Manus@Sun.COM } 5128672SRenaud.Manus@Sun.COM 513789Sahrens start = (char *)acl_entry + 514789Sahrens acl->acl_entry_size; 515789Sahrens (void) memmove(acl_entry, start, 516789Sahrens acl->acl_entry_size * 5178672SRenaud.Manus@Sun.COM (acl->acl_cnt-- - (j + 1))); 518789Sahrens 519789Sahrens if (flag == ACL_REMOVE_FIRST) 520789Sahrens break; 521789Sahrens /* 5227057Smarks * List has changed, just continue so this 5237057Smarks * slot gets checked with it's new contents. 524789Sahrens */ 525789Sahrens continue; 526789Sahrens } 527789Sahrens acl_entry = ((char *)acl_entry + acl->acl_entry_size); 528789Sahrens if (++j >= acl->acl_cnt) { 529789Sahrens break; 530789Sahrens } 531789Sahrens } 5327057Smarks remove_entry = (char *)remove_entry + removeacl->acl_entry_size; 533789Sahrens } 534789Sahrens 535789Sahrens return ((found == 0) ? EACL_NO_ACL_ENTRY : 0); 536789Sahrens } 537789Sahrens 538789Sahrens /* 539789Sahrens * Replace entires entries in acl1 with the corresponding entries 540789Sahrens * in newentries. The where argument specifies where to begin 541789Sahrens * the replacement. If the where argument is 1 greater than the 542789Sahrens * number of acl entries in acl1 then they are appended. If the 543789Sahrens * where argument is 2+ greater than the number of acl entries then 544789Sahrens * EACL_INVALID_SLOT is returned. 545789Sahrens */ 546789Sahrens int 547789Sahrens acl_modifyentries(acl_t *acl1, acl_t *newentries, int where) 548789Sahrens { 549789Sahrens 550789Sahrens int slot; 551789Sahrens int slots_needed; 552789Sahrens int slots_left; 553789Sahrens int newsize; 554789Sahrens 555789Sahrens if (acl1 == NULL || newentries == NULL) 556789Sahrens return (EACL_NO_ACL_ENTRY); 557789Sahrens 558789Sahrens if (where < 0 || where >= acl1->acl_cnt) 559789Sahrens return (EACL_INVALID_SLOT); 560789Sahrens 561789Sahrens if (acl1->acl_type != newentries->acl_type) 562789Sahrens return (EACL_DIFF_TYPE); 563789Sahrens 564789Sahrens slot = where; 565789Sahrens 566789Sahrens slots_left = acl1->acl_cnt - slot + 1; 567789Sahrens if (slots_left < newentries->acl_cnt) { 568789Sahrens slots_needed = newentries->acl_cnt - slots_left; 569789Sahrens newsize = (acl1->acl_entry_size * acl1->acl_cnt) + 570789Sahrens (acl1->acl_entry_size * slots_needed); 571789Sahrens acl1->acl_aclp = realloc(acl1->acl_aclp, newsize); 572789Sahrens if (acl1->acl_aclp == NULL) 573789Sahrens return (-1); 574789Sahrens } 575789Sahrens (void) memcpy((char *)acl1->acl_aclp + (acl1->acl_entry_size * slot), 576789Sahrens newentries->acl_aclp, 577789Sahrens newentries->acl_entry_size * newentries->acl_cnt); 578789Sahrens 579789Sahrens /* 580789Sahrens * Did ACL grow? 581789Sahrens */ 582789Sahrens 583789Sahrens if ((slot + newentries->acl_cnt) > acl1->acl_cnt) { 584789Sahrens acl1->acl_cnt = slot + newentries->acl_cnt; 585789Sahrens } 586789Sahrens 587789Sahrens return (0); 588789Sahrens } 589789Sahrens 590789Sahrens /* 591789Sahrens * Add acl2 entries into acl1. The where argument specifies where 592789Sahrens * to add the entries. 593789Sahrens */ 594789Sahrens int 595789Sahrens acl_addentries(acl_t *acl1, acl_t *acl2, int where) 596789Sahrens { 597789Sahrens 598789Sahrens int newsize; 599789Sahrens int len; 600789Sahrens void *start; 601789Sahrens void *to; 602789Sahrens 603789Sahrens if (acl1 == NULL || acl2 == NULL) 604789Sahrens return (EACL_NO_ACL_ENTRY); 605789Sahrens 606789Sahrens if (acl1->acl_type != acl2->acl_type) 607789Sahrens return (EACL_DIFF_TYPE); 608789Sahrens 609789Sahrens /* 610789Sahrens * allow where to specify 1 past last slot for an append operation 611789Sahrens * but anything greater is an error. 612789Sahrens */ 613789Sahrens if (where < 0 || where > acl1->acl_cnt) 614789Sahrens return (EACL_INVALID_SLOT); 615789Sahrens 616789Sahrens newsize = (acl2->acl_entry_size * acl2->acl_cnt) + 617789Sahrens (acl1->acl_entry_size * acl1->acl_cnt); 618789Sahrens acl1->acl_aclp = realloc(acl1->acl_aclp, newsize); 619789Sahrens if (acl1->acl_aclp == NULL) 620789Sahrens return (-1); 621789Sahrens 622789Sahrens /* 623789Sahrens * first push down entries where new ones will be inserted 624789Sahrens */ 625789Sahrens 626789Sahrens to = (void *)((char *)acl1->acl_aclp + 627789Sahrens ((where + acl2->acl_cnt) * acl1->acl_entry_size)); 628789Sahrens 629789Sahrens start = (void *)((char *)acl1->acl_aclp + 630789Sahrens where * acl1->acl_entry_size); 631789Sahrens 632789Sahrens if (where < acl1->acl_cnt) { 633789Sahrens len = (acl1->acl_cnt - where) * acl1->acl_entry_size; 634789Sahrens (void) memmove(to, start, len); 635789Sahrens } 636789Sahrens 637789Sahrens /* 638789Sahrens * now stick in new entries. 639789Sahrens */ 640789Sahrens 641789Sahrens (void) memmove(start, acl2->acl_aclp, 642789Sahrens acl2->acl_cnt * acl2->acl_entry_size); 643789Sahrens 644789Sahrens acl1->acl_cnt += acl2->acl_cnt; 645789Sahrens return (0); 646789Sahrens } 647789Sahrens 648789Sahrens /* 649789Sahrens * return text for an ACL error. 650789Sahrens */ 651789Sahrens char * 652789Sahrens acl_strerror(int errnum) 653789Sahrens { 654789Sahrens switch (errnum) { 655789Sahrens case EACL_GRP_ERROR: 656789Sahrens return (dgettext(TEXT_DOMAIN, 6571420Smarks "There is more than one group or default group entry")); 658789Sahrens case EACL_USER_ERROR: 659789Sahrens return (dgettext(TEXT_DOMAIN, 6601420Smarks "There is more than one user or default user entry")); 661789Sahrens case EACL_OTHER_ERROR: 662789Sahrens return (dgettext(TEXT_DOMAIN, 663789Sahrens "There is more than one other entry")); 664789Sahrens case EACL_CLASS_ERROR: 665789Sahrens return (dgettext(TEXT_DOMAIN, 666789Sahrens "There is more than one mask entry")); 667789Sahrens case EACL_DUPLICATE_ERROR: 668789Sahrens return (dgettext(TEXT_DOMAIN, 669789Sahrens "Duplicate user or group entries")); 670789Sahrens case EACL_MISS_ERROR: 671789Sahrens return (dgettext(TEXT_DOMAIN, 672789Sahrens "Missing user/group owner, other, mask entry")); 673789Sahrens case EACL_MEM_ERROR: 674789Sahrens return (dgettext(TEXT_DOMAIN, 675789Sahrens "Memory error")); 676789Sahrens case EACL_ENTRY_ERROR: 677789Sahrens return (dgettext(TEXT_DOMAIN, 678789Sahrens "Unrecognized entry type")); 679789Sahrens case EACL_INHERIT_ERROR: 680789Sahrens return (dgettext(TEXT_DOMAIN, 681789Sahrens "Invalid inheritance flags")); 682789Sahrens case EACL_FLAGS_ERROR: 683789Sahrens return (dgettext(TEXT_DOMAIN, 684789Sahrens "Unrecognized entry flags")); 685789Sahrens case EACL_PERM_MASK_ERROR: 686789Sahrens return (dgettext(TEXT_DOMAIN, 687789Sahrens "Invalid ACL permissions")); 688789Sahrens case EACL_COUNT_ERROR: 689789Sahrens return (dgettext(TEXT_DOMAIN, 690789Sahrens "Invalid ACL count")); 691789Sahrens case EACL_INVALID_SLOT: 692789Sahrens return (dgettext(TEXT_DOMAIN, 693789Sahrens "Invalid ACL entry number specified")); 694789Sahrens case EACL_NO_ACL_ENTRY: 695789Sahrens return (dgettext(TEXT_DOMAIN, 696789Sahrens "ACL entry doesn't exist")); 697789Sahrens case EACL_DIFF_TYPE: 698789Sahrens return (dgettext(TEXT_DOMAIN, 69910228SStephanie.Scheffler@Sun.COM "Different file system ACL types cannot be merged")); 700789Sahrens case EACL_INVALID_USER_GROUP: 701789Sahrens return (dgettext(TEXT_DOMAIN, "Invalid user or group")); 702789Sahrens case EACL_INVALID_STR: 703789Sahrens return (dgettext(TEXT_DOMAIN, "ACL string is invalid")); 704789Sahrens case EACL_FIELD_NOT_BLANK: 705789Sahrens return (dgettext(TEXT_DOMAIN, "Field expected to be blank")); 706789Sahrens case EACL_INVALID_ACCESS_TYPE: 707789Sahrens return (dgettext(TEXT_DOMAIN, "Invalid access type")); 708789Sahrens case EACL_UNKNOWN_DATA: 709789Sahrens return (dgettext(TEXT_DOMAIN, "Unrecognized entry")); 710789Sahrens case EACL_MISSING_FIELDS: 711789Sahrens return (dgettext(TEXT_DOMAIN, 712789Sahrens "ACL specification missing required fields")); 713789Sahrens case EACL_INHERIT_NOTDIR: 714789Sahrens return (dgettext(TEXT_DOMAIN, 715789Sahrens "Inheritance flags are only allowed on directories")); 716789Sahrens case -1: 717789Sahrens return (strerror(errno)); 718789Sahrens default: 719789Sahrens errno = EINVAL; 720789Sahrens return (dgettext(TEXT_DOMAIN, "Unknown error")); 721789Sahrens } 722789Sahrens } 7231420Smarks 7241420Smarks extern int yyinteractive; 7251420Smarks 7261420Smarks /* PRINTFLIKE1 */ 7271420Smarks void 7281420Smarks acl_error(const char *fmt, ...) 7291420Smarks { 7301420Smarks va_list va; 7311420Smarks 7321420Smarks if (yyinteractive == 0) 7331420Smarks return; 7341420Smarks 7351420Smarks va_start(va, fmt); 7361420Smarks (void) vfprintf(stderr, fmt, va); 7371420Smarks va_end(va); 7381420Smarks } 7397057Smarks 7407057Smarks int 7417057Smarks sid_to_id(char *sid, boolean_t user, uid_t *id) 7427057Smarks { 7437057Smarks idmap_get_handle_t *get_hdl = NULL; 7447057Smarks char *rid_start = NULL; 7457057Smarks idmap_stat status; 7467057Smarks char *end; 7477680SMark.Shellenbaum@Sun.COM int error = 1; 7487057Smarks char *domain_start; 7497057Smarks 7507057Smarks if ((domain_start = strchr(sid, '@')) == NULL) { 7517057Smarks idmap_rid_t rid; 7527057Smarks 7537057Smarks if ((rid_start = strrchr(sid, '-')) == NULL) 7547680SMark.Shellenbaum@Sun.COM return (1); 7557057Smarks *rid_start++ = '\0'; 7567057Smarks errno = 0; 7577057Smarks rid = strtoul(rid_start--, &end, 10); 7587057Smarks if (errno == 0 && *end == '\0') { 759*12914SJoyce.McIntosh@Sun.COM if (idmap_get_create(&get_hdl) == 7607680SMark.Shellenbaum@Sun.COM IDMAP_SUCCESS) { 7617057Smarks if (user) 7627057Smarks error = idmap_get_uidbysid(get_hdl, 7637369SJulian.Pullen@Sun.COM sid, rid, IDMAP_REQ_FLG_USE_CACHE, 7647369SJulian.Pullen@Sun.COM id, &status); 7657057Smarks else 7667057Smarks error = idmap_get_gidbysid(get_hdl, 7677369SJulian.Pullen@Sun.COM sid, rid, IDMAP_REQ_FLG_USE_CACHE, 7687369SJulian.Pullen@Sun.COM id, &status); 7697680SMark.Shellenbaum@Sun.COM if (error == IDMAP_SUCCESS) { 7707680SMark.Shellenbaum@Sun.COM error = idmap_get_mappings(get_hdl); 7717680SMark.Shellenbaum@Sun.COM if (error == IDMAP_SUCCESS && 7727680SMark.Shellenbaum@Sun.COM status != IDMAP_SUCCESS) 7737680SMark.Shellenbaum@Sun.COM error = 1; 7747680SMark.Shellenbaum@Sun.COM else 7757680SMark.Shellenbaum@Sun.COM error = 0; 7767680SMark.Shellenbaum@Sun.COM } 7777680SMark.Shellenbaum@Sun.COM } else { 7787680SMark.Shellenbaum@Sun.COM error = 1; 7797057Smarks } 7807680SMark.Shellenbaum@Sun.COM if (get_hdl) 7817680SMark.Shellenbaum@Sun.COM idmap_get_destroy(get_hdl); 7827057Smarks } else { 7837680SMark.Shellenbaum@Sun.COM error = 1; 7847057Smarks } 7857057Smarks *rid_start = '-'; /* putback character removed earlier */ 7867057Smarks } else { 7877057Smarks char *name = sid; 7887057Smarks *domain_start++ = '\0'; 7897057Smarks 7907057Smarks if (user) 7917369SJulian.Pullen@Sun.COM error = idmap_getuidbywinname(name, domain_start, 7927369SJulian.Pullen@Sun.COM IDMAP_REQ_FLG_USE_CACHE, id); 7937057Smarks else 7947369SJulian.Pullen@Sun.COM error = idmap_getgidbywinname(name, domain_start, 7957369SJulian.Pullen@Sun.COM IDMAP_REQ_FLG_USE_CACHE, id); 7967057Smarks *--domain_start = '@'; 7977680SMark.Shellenbaum@Sun.COM error = (error == IDMAP_SUCCESS) ? 0 : 1; 7987057Smarks } 7997057Smarks 8007057Smarks return (error); 8017057Smarks } 802