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 /* 22*8672SRenaud.Manus@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23789Sahrens * Use is subject to license terms. 24789Sahrens */ 25789Sahrens 26789Sahrens 27789Sahrens #include <stdlib.h> 28789Sahrens #include <string.h> 29789Sahrens #include <unistd.h> 30789Sahrens #include <limits.h> 31789Sahrens #include <grp.h> 32789Sahrens #include <pwd.h> 331462Smarks #include <strings.h> 34789Sahrens #include <sys/types.h> 35789Sahrens #include <errno.h> 36789Sahrens #include <sys/stat.h> 371420Smarks #include <sys/varargs.h> 38789Sahrens #include <locale.h> 39789Sahrens #include <aclutils.h> 405331Samw #include <sys/avl.h> 41789Sahrens #include <acl_common.h> 427057Smarks #include <idmap.h> 43789Sahrens 44789Sahrens #define ACL_PATH 0 45789Sahrens #define ACL_FD 1 46789Sahrens 471231Smarks 48789Sahrens typedef union { 49789Sahrens const char *file; 50789Sahrens int fd; 51789Sahrens } acl_inp; 52789Sahrens 53789Sahrens 54789Sahrens /* 55789Sahrens * Determine whether a file has a trivial ACL 56789Sahrens * returns: 0 = trivial 57789Sahrens * 1 = nontrivial 58789Sahrens * <0 some other system failure, such as ENOENT or EPERM 59789Sahrens */ 60789Sahrens int 61789Sahrens acl_trivial(const char *filename) 62789Sahrens { 63789Sahrens int acl_flavor; 64789Sahrens int aclcnt; 65789Sahrens int cntcmd; 66789Sahrens int val = 0; 67789Sahrens ace_t *acep; 68789Sahrens 69789Sahrens acl_flavor = pathconf(filename, _PC_ACL_ENABLED); 70789Sahrens 71789Sahrens if (acl_flavor == _ACL_ACE_ENABLED) 72789Sahrens cntcmd = ACE_GETACLCNT; 73789Sahrens else 74789Sahrens cntcmd = GETACLCNT; 75789Sahrens 76789Sahrens aclcnt = acl(filename, cntcmd, 0, NULL); 77789Sahrens if (aclcnt > 0) { 78789Sahrens if (acl_flavor == _ACL_ACE_ENABLED) { 791231Smarks acep = malloc(sizeof (ace_t) * aclcnt); 801231Smarks if (acep == NULL) 811231Smarks return (-1); 821231Smarks if (acl(filename, ACE_GETACL, 831231Smarks aclcnt, acep) < 0) { 841231Smarks free(acep); 851231Smarks return (-1); 861231Smarks } 87789Sahrens 881231Smarks val = ace_trivial(acep, aclcnt); 891231Smarks free(acep); 901231Smarks 91789Sahrens } else if (aclcnt > MIN_ACL_ENTRIES) 92789Sahrens val = 1; 93789Sahrens } 94789Sahrens return (val); 95789Sahrens } 96789Sahrens 971462Smarks 981477Smarks static int 99789Sahrens cacl_get(acl_inp inp, int get_flag, int type, acl_t **aclp) 100789Sahrens { 101789Sahrens const char *fname; 102789Sahrens int fd; 103789Sahrens int ace_acl = 0; 104789Sahrens int error; 105789Sahrens int getcmd, cntcmd; 106789Sahrens acl_t *acl_info; 107789Sahrens int save_errno; 108789Sahrens int stat_error; 109789Sahrens struct stat64 statbuf; 110789Sahrens 111789Sahrens *aclp = NULL; 112789Sahrens if (type == ACL_PATH) { 113789Sahrens fname = inp.file; 114789Sahrens ace_acl = pathconf(fname, _PC_ACL_ENABLED); 115789Sahrens } else { 116789Sahrens fd = inp.fd; 117789Sahrens ace_acl = fpathconf(fd, _PC_ACL_ENABLED); 118789Sahrens } 119789Sahrens 120789Sahrens /* 121789Sahrens * if acl's aren't supported then 122789Sahrens * send it through the old GETACL interface 123789Sahrens */ 1241666Smarks if (ace_acl == 0 || ace_acl == -1) { 125789Sahrens ace_acl = _ACL_ACLENT_ENABLED; 126789Sahrens } 127789Sahrens 128789Sahrens if (ace_acl & _ACL_ACE_ENABLED) { 129789Sahrens cntcmd = ACE_GETACLCNT; 130789Sahrens getcmd = ACE_GETACL; 131789Sahrens acl_info = acl_alloc(ACE_T); 132789Sahrens } else { 133789Sahrens cntcmd = GETACLCNT; 134789Sahrens getcmd = GETACL; 135789Sahrens acl_info = acl_alloc(ACLENT_T); 136789Sahrens } 137789Sahrens 138789Sahrens if (acl_info == NULL) 139789Sahrens return (-1); 140789Sahrens 141789Sahrens if (type == ACL_PATH) { 142789Sahrens acl_info->acl_cnt = acl(fname, cntcmd, 0, NULL); 143789Sahrens } else { 144789Sahrens acl_info->acl_cnt = facl(fd, cntcmd, 0, NULL); 145789Sahrens } 146789Sahrens 147789Sahrens save_errno = errno; 148789Sahrens if (acl_info->acl_cnt < 0) { 149789Sahrens acl_free(acl_info); 150789Sahrens errno = save_errno; 151789Sahrens return (-1); 152789Sahrens } 153789Sahrens 154789Sahrens if (acl_info->acl_cnt == 0) { 155789Sahrens acl_free(acl_info); 156789Sahrens errno = save_errno; 157789Sahrens return (0); 158789Sahrens } 159789Sahrens 160789Sahrens acl_info->acl_aclp = 161789Sahrens malloc(acl_info->acl_cnt * acl_info->acl_entry_size); 162789Sahrens save_errno = errno; 163789Sahrens 164789Sahrens if (acl_info->acl_aclp == NULL) { 165789Sahrens acl_free(acl_info); 166789Sahrens errno = save_errno; 167789Sahrens return (-1); 168789Sahrens } 169789Sahrens 170789Sahrens if (type == ACL_PATH) { 171789Sahrens stat_error = stat64(fname, &statbuf); 172789Sahrens error = acl(fname, getcmd, acl_info->acl_cnt, 173789Sahrens acl_info->acl_aclp); 174789Sahrens } else { 175789Sahrens stat_error = fstat64(fd, &statbuf); 176789Sahrens error = facl(fd, getcmd, acl_info->acl_cnt, 177789Sahrens acl_info->acl_aclp); 178789Sahrens } 179789Sahrens 180789Sahrens save_errno = errno; 181789Sahrens if (error == -1) { 182789Sahrens acl_free(acl_info); 183789Sahrens errno = save_errno; 184789Sahrens return (-1); 185789Sahrens } 186789Sahrens 187789Sahrens 188789Sahrens if (stat_error == 0) { 189789Sahrens acl_info->acl_flags = 190789Sahrens (S_ISDIR(statbuf.st_mode) ? ACL_IS_DIR : 0); 191789Sahrens } else 192789Sahrens acl_info->acl_flags = 0; 193789Sahrens 194789Sahrens switch (acl_info->acl_type) { 195789Sahrens case ACLENT_T: 196789Sahrens if (acl_info->acl_cnt <= MIN_ACL_ENTRIES) 197789Sahrens acl_info->acl_flags |= ACL_IS_TRIVIAL; 198789Sahrens break; 199789Sahrens case ACE_T: 200789Sahrens if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0) 201789Sahrens acl_info->acl_flags |= ACL_IS_TRIVIAL; 202789Sahrens break; 203789Sahrens default: 204789Sahrens errno = EINVAL; 205789Sahrens acl_free(acl_info); 206789Sahrens return (-1); 207789Sahrens } 208789Sahrens 209789Sahrens if ((acl_info->acl_flags & ACL_IS_TRIVIAL) && 210789Sahrens (get_flag & ACL_NO_TRIVIAL)) { 211789Sahrens acl_free(acl_info); 212789Sahrens errno = 0; 213789Sahrens return (0); 214789Sahrens } 215789Sahrens 216789Sahrens *aclp = acl_info; 217789Sahrens return (0); 218789Sahrens } 219789Sahrens 220789Sahrens /* 221789Sahrens * return -1 on failure, otherwise the number of acl 222789Sahrens * entries is returned 223789Sahrens */ 224789Sahrens int 225789Sahrens acl_get(const char *path, int get_flag, acl_t **aclp) 226789Sahrens { 227789Sahrens acl_inp acl_inp; 228789Sahrens acl_inp.file = path; 229789Sahrens 230789Sahrens return (cacl_get(acl_inp, get_flag, ACL_PATH, aclp)); 231789Sahrens } 232789Sahrens 233789Sahrens int 234789Sahrens facl_get(int fd, int get_flag, acl_t **aclp) 235789Sahrens { 236789Sahrens 237789Sahrens acl_inp acl_inp; 238789Sahrens acl_inp.fd = fd; 239789Sahrens 240789Sahrens return (cacl_get(acl_inp, get_flag, ACL_FD, aclp)); 241789Sahrens } 242789Sahrens 243789Sahrens /* 244789Sahrens * Set an ACL, translates acl to ace_t when appropriate. 245789Sahrens */ 246789Sahrens static int 247789Sahrens cacl_set(acl_inp *acl_inp, acl_t *aclp, int type) 248789Sahrens { 249789Sahrens int error = 0; 250789Sahrens int acl_flavor_target; 251789Sahrens struct stat64 statbuf; 252789Sahrens int stat_error; 253789Sahrens int isdir; 254789Sahrens 255789Sahrens 256789Sahrens if (type == ACL_PATH) { 257789Sahrens stat_error = stat64(acl_inp->file, &statbuf); 258789Sahrens if (stat_error) 259789Sahrens return (-1); 260789Sahrens acl_flavor_target = pathconf(acl_inp->file, _PC_ACL_ENABLED); 261789Sahrens } else { 262789Sahrens stat_error = fstat64(acl_inp->fd, &statbuf); 263789Sahrens if (stat_error) 264789Sahrens return (-1); 265789Sahrens acl_flavor_target = fpathconf(acl_inp->fd, _PC_ACL_ENABLED); 266789Sahrens } 267789Sahrens 2681666Smarks /* 2691666Smarks * If target returns an error or 0 from pathconf call then 2701666Smarks * fall back to UFS/POSIX Draft interface. 2711666Smarks * In the case of 0 we will then fail in either acl(2) or 2721666Smarks * acl_translate(). We could erroneously get 0 back from 2731666Smarks * a file system that is using fs_pathconf() and not answering 2741666Smarks * the _PC_ACL_ENABLED question itself. 2751666Smarks */ 2761666Smarks if (acl_flavor_target == 0 || acl_flavor_target == -1) 2771666Smarks acl_flavor_target = _ACL_ACLENT_ENABLED; 2781666Smarks 279789Sahrens isdir = S_ISDIR(statbuf.st_mode); 280789Sahrens 2811462Smarks if ((error = acl_translate(aclp, acl_flavor_target, isdir, 2821462Smarks statbuf.st_uid, statbuf.st_gid)) != 0) { 2831462Smarks return (error); 284789Sahrens } 285789Sahrens 286789Sahrens if (type == ACL_PATH) { 287789Sahrens error = acl(acl_inp->file, 288789Sahrens (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, 289789Sahrens aclp->acl_cnt, aclp->acl_aclp); 290789Sahrens } else { 291789Sahrens error = facl(acl_inp->fd, 292789Sahrens (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, 293789Sahrens aclp->acl_cnt, aclp->acl_aclp); 294789Sahrens } 295789Sahrens 296789Sahrens return (error); 297789Sahrens } 298789Sahrens 299789Sahrens int 300789Sahrens acl_set(const char *path, acl_t *aclp) 301789Sahrens { 302789Sahrens acl_inp acl_inp; 303789Sahrens 304789Sahrens acl_inp.file = path; 305789Sahrens 306789Sahrens return (cacl_set(&acl_inp, aclp, ACL_PATH)); 307789Sahrens } 308789Sahrens 309789Sahrens int 310789Sahrens facl_set(int fd, acl_t *aclp) 311789Sahrens { 312789Sahrens acl_inp acl_inp; 313789Sahrens 314789Sahrens acl_inp.fd = fd; 315789Sahrens 316789Sahrens return (cacl_set(&acl_inp, aclp, ACL_FD)); 317789Sahrens } 318789Sahrens 319789Sahrens int 320789Sahrens acl_cnt(acl_t *aclp) 321789Sahrens { 322789Sahrens return (aclp->acl_cnt); 323789Sahrens } 324789Sahrens 325789Sahrens int 326789Sahrens acl_type(acl_t *aclp) 327789Sahrens { 328789Sahrens return (aclp->acl_type); 329789Sahrens } 330789Sahrens 331789Sahrens acl_t * 332789Sahrens acl_dup(acl_t *aclp) 333789Sahrens { 334789Sahrens acl_t *newaclp; 335789Sahrens 336789Sahrens newaclp = acl_alloc(aclp->acl_type); 337789Sahrens if (newaclp == NULL) 338789Sahrens return (NULL); 339789Sahrens 340789Sahrens newaclp->acl_aclp = malloc(aclp->acl_entry_size * aclp->acl_cnt); 341789Sahrens if (newaclp->acl_aclp == NULL) { 342789Sahrens acl_free(newaclp); 343789Sahrens return (NULL); 344789Sahrens } 345789Sahrens 346789Sahrens (void) memcpy(newaclp->acl_aclp, 347789Sahrens aclp->acl_aclp, aclp->acl_entry_size * aclp->acl_cnt); 348789Sahrens newaclp->acl_cnt = aclp->acl_cnt; 349789Sahrens 350789Sahrens return (newaclp); 351789Sahrens } 352789Sahrens 353789Sahrens int 354789Sahrens acl_flags(acl_t *aclp) 355789Sahrens { 356789Sahrens return (aclp->acl_flags); 357789Sahrens } 358789Sahrens 359789Sahrens void * 360789Sahrens acl_data(acl_t *aclp) 361789Sahrens { 362789Sahrens return (aclp->acl_aclp); 363789Sahrens } 364789Sahrens 365789Sahrens /* 3661953Smarks * Take an acl array and build an acl_t. 3671953Smarks */ 3681953Smarks acl_t * 3691953Smarks acl_to_aclp(enum acl_type type, void *acl, int count) 3701953Smarks { 3711953Smarks acl_t *aclp; 3721953Smarks 3731953Smarks 3741953Smarks aclp = acl_alloc(type); 3751953Smarks if (aclp == NULL) 3761953Smarks return (aclp); 3771953Smarks 3781953Smarks aclp->acl_aclp = acl; 3791953Smarks aclp->acl_cnt = count; 3801953Smarks 3811953Smarks return (aclp); 3821953Smarks } 3831953Smarks 3841953Smarks /* 385789Sahrens * Remove an ACL from a file and create a trivial ACL based 386789Sahrens * off of the mode argument. After acl has been set owner/group 387789Sahrens * are updated to match owner,group arguments 388789Sahrens */ 389789Sahrens int 390789Sahrens acl_strip(const char *file, uid_t owner, gid_t group, mode_t mode) 391789Sahrens { 392789Sahrens int error = 0; 393789Sahrens aclent_t min_acl[MIN_ACL_ENTRIES]; 394789Sahrens ace_t min_ace_acl[6]; /* owner, group, everyone + complement denies */ 395789Sahrens int acl_flavor; 396789Sahrens int aclcnt; 397789Sahrens 398789Sahrens acl_flavor = pathconf(file, _PC_ACL_ENABLED); 399789Sahrens 400789Sahrens /* 401789Sahrens * force it through aclent flavor when file system doesn't 402789Sahrens * understand question 403789Sahrens */ 4041666Smarks if (acl_flavor == 0 || acl_flavor == -1) 405789Sahrens acl_flavor = _ACL_ACLENT_ENABLED; 406789Sahrens 407789Sahrens if (acl_flavor & _ACL_ACLENT_ENABLED) { 408789Sahrens min_acl[0].a_type = USER_OBJ; 409789Sahrens min_acl[0].a_id = owner; 410789Sahrens min_acl[0].a_perm = ((mode & 0700) >> 6); 411789Sahrens min_acl[1].a_type = GROUP_OBJ; 412789Sahrens min_acl[1].a_id = group; 413789Sahrens min_acl[1].a_perm = ((mode & 0070) >> 3); 414789Sahrens min_acl[2].a_type = CLASS_OBJ; 415789Sahrens min_acl[2].a_id = (uid_t)-1; 416789Sahrens min_acl[2].a_perm = ((mode & 0070) >> 3); 417789Sahrens min_acl[3].a_type = OTHER_OBJ; 418789Sahrens min_acl[3].a_id = (uid_t)-1; 419789Sahrens min_acl[3].a_perm = (mode & 0007); 420789Sahrens aclcnt = 4; 421789Sahrens error = acl(file, SETACL, aclcnt, min_acl); 422789Sahrens } else if (acl_flavor & _ACL_ACE_ENABLED) { 423789Sahrens (void) memcpy(min_ace_acl, trivial_acl, sizeof (ace_t) * 6); 424789Sahrens 425789Sahrens /* 426789Sahrens * Make aces match request mode 427789Sahrens */ 428789Sahrens adjust_ace_pair(&min_ace_acl[0], (mode & 0700) >> 6); 429789Sahrens adjust_ace_pair(&min_ace_acl[2], (mode & 0070) >> 3); 430789Sahrens adjust_ace_pair(&min_ace_acl[4], mode & 0007); 431789Sahrens 432789Sahrens error = acl(file, ACE_SETACL, 6, min_ace_acl); 433789Sahrens } else { 434789Sahrens errno = EINVAL; 435789Sahrens error = 1; 436789Sahrens } 437789Sahrens 438789Sahrens if (error == 0) 439789Sahrens error = chown(file, owner, group); 440789Sahrens return (error); 441789Sahrens } 442789Sahrens 443789Sahrens static int 444789Sahrens ace_match(void *entry1, void *entry2) 445789Sahrens { 446789Sahrens ace_t *p1 = (ace_t *)entry1; 447789Sahrens ace_t *p2 = (ace_t *)entry2; 448789Sahrens ace_t ace1, ace2; 449789Sahrens 450789Sahrens ace1 = *p1; 451789Sahrens ace2 = *p2; 452789Sahrens 453789Sahrens /* 454789Sahrens * Need to fixup who field for abstrations for 455789Sahrens * accurate comparison, since field is undefined. 456789Sahrens */ 457789Sahrens if (ace1.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE)) 4584321Scasper ace1.a_who = (uid_t)-1; 459789Sahrens if (ace2.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE)) 4604321Scasper ace2.a_who = (uid_t)-1; 461789Sahrens return (memcmp(&ace1, &ace2, sizeof (ace_t))); 462789Sahrens } 463789Sahrens 464789Sahrens static int 465789Sahrens aclent_match(void *entry1, void *entry2) 466789Sahrens { 467789Sahrens aclent_t *aclent1 = (aclent_t *)entry1; 468789Sahrens aclent_t *aclent2 = (aclent_t *)entry2; 469789Sahrens 470789Sahrens return (memcmp(aclent1, aclent2, sizeof (aclent_t))); 471789Sahrens } 472789Sahrens 473789Sahrens /* 474789Sahrens * Find acl entries in acl that correspond to removeacl. Search 475789Sahrens * is started from slot. The flag argument indicates whether to 476789Sahrens * remove all matches or just the first match. 477789Sahrens */ 478789Sahrens int 479789Sahrens acl_removeentries(acl_t *acl, acl_t *removeacl, int start_slot, int flag) 480789Sahrens { 481789Sahrens int i, j; 482789Sahrens int match; 483789Sahrens int (*acl_match)(void *acl1, void *acl2); 484789Sahrens void *acl_entry, *remove_entry; 485789Sahrens void *start; 486789Sahrens int found = 0; 487789Sahrens 488789Sahrens if (flag != ACL_REMOVE_ALL && flag != ACL_REMOVE_FIRST) 489789Sahrens flag = ACL_REMOVE_FIRST; 490789Sahrens 491789Sahrens if (acl == NULL || removeacl == NULL) 492789Sahrens return (EACL_NO_ACL_ENTRY); 493789Sahrens 494789Sahrens if (acl->acl_type != removeacl->acl_type) 495789Sahrens return (EACL_DIFF_TYPE); 496789Sahrens 497789Sahrens if (acl->acl_type == ACLENT_T) 498789Sahrens acl_match = aclent_match; 499789Sahrens else 500789Sahrens acl_match = ace_match; 501789Sahrens 502789Sahrens for (i = 0, remove_entry = removeacl->acl_aclp; 503789Sahrens i != removeacl->acl_cnt; i++) { 504789Sahrens 505789Sahrens j = 0; 506789Sahrens acl_entry = (char *)acl->acl_aclp + 507789Sahrens (acl->acl_entry_size * start_slot); 508789Sahrens for (;;) { 509789Sahrens match = acl_match(acl_entry, remove_entry); 510789Sahrens if (match == 0) { 511789Sahrens found++; 512*8672SRenaud.Manus@Sun.COM 513*8672SRenaud.Manus@Sun.COM /* avoid memmove if last entry */ 514*8672SRenaud.Manus@Sun.COM if (acl->acl_cnt == (j + 1)) { 515*8672SRenaud.Manus@Sun.COM acl->acl_cnt--; 516*8672SRenaud.Manus@Sun.COM break; 517*8672SRenaud.Manus@Sun.COM } 518*8672SRenaud.Manus@Sun.COM 519789Sahrens start = (char *)acl_entry + 520789Sahrens acl->acl_entry_size; 521789Sahrens (void) memmove(acl_entry, start, 522789Sahrens acl->acl_entry_size * 523*8672SRenaud.Manus@Sun.COM (acl->acl_cnt-- - (j + 1))); 524789Sahrens 525789Sahrens if (flag == ACL_REMOVE_FIRST) 526789Sahrens break; 527789Sahrens /* 5287057Smarks * List has changed, just continue so this 5297057Smarks * slot gets checked with it's new contents. 530789Sahrens */ 531789Sahrens continue; 532789Sahrens } 533789Sahrens acl_entry = ((char *)acl_entry + acl->acl_entry_size); 534789Sahrens if (++j >= acl->acl_cnt) { 535789Sahrens break; 536789Sahrens } 537789Sahrens } 5387057Smarks remove_entry = (char *)remove_entry + removeacl->acl_entry_size; 539789Sahrens } 540789Sahrens 541789Sahrens return ((found == 0) ? EACL_NO_ACL_ENTRY : 0); 542789Sahrens } 543789Sahrens 544789Sahrens /* 545789Sahrens * Replace entires entries in acl1 with the corresponding entries 546789Sahrens * in newentries. The where argument specifies where to begin 547789Sahrens * the replacement. If the where argument is 1 greater than the 548789Sahrens * number of acl entries in acl1 then they are appended. If the 549789Sahrens * where argument is 2+ greater than the number of acl entries then 550789Sahrens * EACL_INVALID_SLOT is returned. 551789Sahrens */ 552789Sahrens int 553789Sahrens acl_modifyentries(acl_t *acl1, acl_t *newentries, int where) 554789Sahrens { 555789Sahrens 556789Sahrens int slot; 557789Sahrens int slots_needed; 558789Sahrens int slots_left; 559789Sahrens int newsize; 560789Sahrens 561789Sahrens if (acl1 == NULL || newentries == NULL) 562789Sahrens return (EACL_NO_ACL_ENTRY); 563789Sahrens 564789Sahrens if (where < 0 || where >= acl1->acl_cnt) 565789Sahrens return (EACL_INVALID_SLOT); 566789Sahrens 567789Sahrens if (acl1->acl_type != newentries->acl_type) 568789Sahrens return (EACL_DIFF_TYPE); 569789Sahrens 570789Sahrens slot = where; 571789Sahrens 572789Sahrens slots_left = acl1->acl_cnt - slot + 1; 573789Sahrens if (slots_left < newentries->acl_cnt) { 574789Sahrens slots_needed = newentries->acl_cnt - slots_left; 575789Sahrens newsize = (acl1->acl_entry_size * acl1->acl_cnt) + 576789Sahrens (acl1->acl_entry_size * slots_needed); 577789Sahrens acl1->acl_aclp = realloc(acl1->acl_aclp, newsize); 578789Sahrens if (acl1->acl_aclp == NULL) 579789Sahrens return (-1); 580789Sahrens } 581789Sahrens (void) memcpy((char *)acl1->acl_aclp + (acl1->acl_entry_size * slot), 582789Sahrens newentries->acl_aclp, 583789Sahrens newentries->acl_entry_size * newentries->acl_cnt); 584789Sahrens 585789Sahrens /* 586789Sahrens * Did ACL grow? 587789Sahrens */ 588789Sahrens 589789Sahrens if ((slot + newentries->acl_cnt) > acl1->acl_cnt) { 590789Sahrens acl1->acl_cnt = slot + newentries->acl_cnt; 591789Sahrens } 592789Sahrens 593789Sahrens return (0); 594789Sahrens } 595789Sahrens 596789Sahrens /* 597789Sahrens * Add acl2 entries into acl1. The where argument specifies where 598789Sahrens * to add the entries. 599789Sahrens */ 600789Sahrens int 601789Sahrens acl_addentries(acl_t *acl1, acl_t *acl2, int where) 602789Sahrens { 603789Sahrens 604789Sahrens int newsize; 605789Sahrens int len; 606789Sahrens void *start; 607789Sahrens void *to; 608789Sahrens 609789Sahrens if (acl1 == NULL || acl2 == NULL) 610789Sahrens return (EACL_NO_ACL_ENTRY); 611789Sahrens 612789Sahrens if (acl1->acl_type != acl2->acl_type) 613789Sahrens return (EACL_DIFF_TYPE); 614789Sahrens 615789Sahrens /* 616789Sahrens * allow where to specify 1 past last slot for an append operation 617789Sahrens * but anything greater is an error. 618789Sahrens */ 619789Sahrens if (where < 0 || where > acl1->acl_cnt) 620789Sahrens return (EACL_INVALID_SLOT); 621789Sahrens 622789Sahrens newsize = (acl2->acl_entry_size * acl2->acl_cnt) + 623789Sahrens (acl1->acl_entry_size * acl1->acl_cnt); 624789Sahrens acl1->acl_aclp = realloc(acl1->acl_aclp, newsize); 625789Sahrens if (acl1->acl_aclp == NULL) 626789Sahrens return (-1); 627789Sahrens 628789Sahrens /* 629789Sahrens * first push down entries where new ones will be inserted 630789Sahrens */ 631789Sahrens 632789Sahrens to = (void *)((char *)acl1->acl_aclp + 633789Sahrens ((where + acl2->acl_cnt) * acl1->acl_entry_size)); 634789Sahrens 635789Sahrens start = (void *)((char *)acl1->acl_aclp + 636789Sahrens where * acl1->acl_entry_size); 637789Sahrens 638789Sahrens if (where < acl1->acl_cnt) { 639789Sahrens len = (acl1->acl_cnt - where) * acl1->acl_entry_size; 640789Sahrens (void) memmove(to, start, len); 641789Sahrens } 642789Sahrens 643789Sahrens /* 644789Sahrens * now stick in new entries. 645789Sahrens */ 646789Sahrens 647789Sahrens (void) memmove(start, acl2->acl_aclp, 648789Sahrens acl2->acl_cnt * acl2->acl_entry_size); 649789Sahrens 650789Sahrens acl1->acl_cnt += acl2->acl_cnt; 651789Sahrens return (0); 652789Sahrens } 653789Sahrens 654789Sahrens /* 655789Sahrens * return text for an ACL error. 656789Sahrens */ 657789Sahrens char * 658789Sahrens acl_strerror(int errnum) 659789Sahrens { 660789Sahrens switch (errnum) { 661789Sahrens case EACL_GRP_ERROR: 662789Sahrens return (dgettext(TEXT_DOMAIN, 6631420Smarks "There is more than one group or default group entry")); 664789Sahrens case EACL_USER_ERROR: 665789Sahrens return (dgettext(TEXT_DOMAIN, 6661420Smarks "There is more than one user or default user entry")); 667789Sahrens case EACL_OTHER_ERROR: 668789Sahrens return (dgettext(TEXT_DOMAIN, 669789Sahrens "There is more than one other entry")); 670789Sahrens case EACL_CLASS_ERROR: 671789Sahrens return (dgettext(TEXT_DOMAIN, 672789Sahrens "There is more than one mask entry")); 673789Sahrens case EACL_DUPLICATE_ERROR: 674789Sahrens return (dgettext(TEXT_DOMAIN, 675789Sahrens "Duplicate user or group entries")); 676789Sahrens case EACL_MISS_ERROR: 677789Sahrens return (dgettext(TEXT_DOMAIN, 678789Sahrens "Missing user/group owner, other, mask entry")); 679789Sahrens case EACL_MEM_ERROR: 680789Sahrens return (dgettext(TEXT_DOMAIN, 681789Sahrens "Memory error")); 682789Sahrens case EACL_ENTRY_ERROR: 683789Sahrens return (dgettext(TEXT_DOMAIN, 684789Sahrens "Unrecognized entry type")); 685789Sahrens case EACL_INHERIT_ERROR: 686789Sahrens return (dgettext(TEXT_DOMAIN, 687789Sahrens "Invalid inheritance flags")); 688789Sahrens case EACL_FLAGS_ERROR: 689789Sahrens return (dgettext(TEXT_DOMAIN, 690789Sahrens "Unrecognized entry flags")); 691789Sahrens case EACL_PERM_MASK_ERROR: 692789Sahrens return (dgettext(TEXT_DOMAIN, 693789Sahrens "Invalid ACL permissions")); 694789Sahrens case EACL_COUNT_ERROR: 695789Sahrens return (dgettext(TEXT_DOMAIN, 696789Sahrens "Invalid ACL count")); 697789Sahrens case EACL_INVALID_SLOT: 698789Sahrens return (dgettext(TEXT_DOMAIN, 699789Sahrens "Invalid ACL entry number specified")); 700789Sahrens case EACL_NO_ACL_ENTRY: 701789Sahrens return (dgettext(TEXT_DOMAIN, 702789Sahrens "ACL entry doesn't exist")); 703789Sahrens case EACL_DIFF_TYPE: 704789Sahrens return (dgettext(TEXT_DOMAIN, 705789Sahrens "ACL type's are different")); 706789Sahrens case EACL_INVALID_USER_GROUP: 707789Sahrens return (dgettext(TEXT_DOMAIN, "Invalid user or group")); 708789Sahrens case EACL_INVALID_STR: 709789Sahrens return (dgettext(TEXT_DOMAIN, "ACL string is invalid")); 710789Sahrens case EACL_FIELD_NOT_BLANK: 711789Sahrens return (dgettext(TEXT_DOMAIN, "Field expected to be blank")); 712789Sahrens case EACL_INVALID_ACCESS_TYPE: 713789Sahrens return (dgettext(TEXT_DOMAIN, "Invalid access type")); 714789Sahrens case EACL_UNKNOWN_DATA: 715789Sahrens return (dgettext(TEXT_DOMAIN, "Unrecognized entry")); 716789Sahrens case EACL_MISSING_FIELDS: 717789Sahrens return (dgettext(TEXT_DOMAIN, 718789Sahrens "ACL specification missing required fields")); 719789Sahrens case EACL_INHERIT_NOTDIR: 720789Sahrens return (dgettext(TEXT_DOMAIN, 721789Sahrens "Inheritance flags are only allowed on directories")); 722789Sahrens case -1: 723789Sahrens return (strerror(errno)); 724789Sahrens default: 725789Sahrens errno = EINVAL; 726789Sahrens return (dgettext(TEXT_DOMAIN, "Unknown error")); 727789Sahrens } 728789Sahrens } 7291420Smarks 7301420Smarks extern int yyinteractive; 7311420Smarks 7321420Smarks /* PRINTFLIKE1 */ 7331420Smarks void 7341420Smarks acl_error(const char *fmt, ...) 7351420Smarks { 7361420Smarks va_list va; 7371420Smarks 7381420Smarks if (yyinteractive == 0) 7391420Smarks return; 7401420Smarks 7411420Smarks va_start(va, fmt); 7421420Smarks (void) vfprintf(stderr, fmt, va); 7431420Smarks va_end(va); 7441420Smarks } 7457057Smarks 7467057Smarks int 7477057Smarks sid_to_id(char *sid, boolean_t user, uid_t *id) 7487057Smarks { 7497057Smarks idmap_handle_t *idmap_hdl = NULL; 7507057Smarks idmap_get_handle_t *get_hdl = NULL; 7517057Smarks char *rid_start = NULL; 7527057Smarks idmap_stat status; 7537057Smarks char *end; 7547680SMark.Shellenbaum@Sun.COM int error = 1; 7557057Smarks char *domain_start; 7567057Smarks 7577057Smarks if ((domain_start = strchr(sid, '@')) == NULL) { 7587057Smarks idmap_rid_t rid; 7597057Smarks 7607057Smarks if ((rid_start = strrchr(sid, '-')) == NULL) 7617680SMark.Shellenbaum@Sun.COM return (1); 7627057Smarks *rid_start++ = '\0'; 7637057Smarks errno = 0; 7647057Smarks rid = strtoul(rid_start--, &end, 10); 7657057Smarks if (errno == 0 && *end == '\0') { 7667680SMark.Shellenbaum@Sun.COM if (idmap_init(&idmap_hdl) == IDMAP_SUCCESS && 7677680SMark.Shellenbaum@Sun.COM idmap_get_create(idmap_hdl, &get_hdl) == 7687680SMark.Shellenbaum@Sun.COM IDMAP_SUCCESS) { 7697057Smarks if (user) 7707057Smarks error = idmap_get_uidbysid(get_hdl, 7717369SJulian.Pullen@Sun.COM sid, rid, IDMAP_REQ_FLG_USE_CACHE, 7727369SJulian.Pullen@Sun.COM id, &status); 7737057Smarks else 7747057Smarks error = idmap_get_gidbysid(get_hdl, 7757369SJulian.Pullen@Sun.COM sid, rid, IDMAP_REQ_FLG_USE_CACHE, 7767369SJulian.Pullen@Sun.COM id, &status); 7777680SMark.Shellenbaum@Sun.COM if (error == IDMAP_SUCCESS) { 7787680SMark.Shellenbaum@Sun.COM error = idmap_get_mappings(get_hdl); 7797680SMark.Shellenbaum@Sun.COM if (error == IDMAP_SUCCESS && 7807680SMark.Shellenbaum@Sun.COM status != IDMAP_SUCCESS) 7817680SMark.Shellenbaum@Sun.COM error = 1; 7827680SMark.Shellenbaum@Sun.COM else 7837680SMark.Shellenbaum@Sun.COM error = 0; 7847680SMark.Shellenbaum@Sun.COM } 7857680SMark.Shellenbaum@Sun.COM } else { 7867680SMark.Shellenbaum@Sun.COM error = 1; 7877057Smarks } 7887680SMark.Shellenbaum@Sun.COM if (get_hdl) 7897680SMark.Shellenbaum@Sun.COM idmap_get_destroy(get_hdl); 7907680SMark.Shellenbaum@Sun.COM if (idmap_hdl) 7917680SMark.Shellenbaum@Sun.COM (void) idmap_fini(idmap_hdl); 7927057Smarks } else { 7937680SMark.Shellenbaum@Sun.COM error = 1; 7947057Smarks } 7957057Smarks *rid_start = '-'; /* putback character removed earlier */ 7967057Smarks } else { 7977057Smarks char *name = sid; 7987057Smarks *domain_start++ = '\0'; 7997057Smarks 8007057Smarks if (user) 8017369SJulian.Pullen@Sun.COM error = idmap_getuidbywinname(name, domain_start, 8027369SJulian.Pullen@Sun.COM IDMAP_REQ_FLG_USE_CACHE, id); 8037057Smarks else 8047369SJulian.Pullen@Sun.COM error = idmap_getgidbywinname(name, domain_start, 8057369SJulian.Pullen@Sun.COM IDMAP_REQ_FLG_USE_CACHE, id); 8067057Smarks *--domain_start = '@'; 8077680SMark.Shellenbaum@Sun.COM error = (error == IDMAP_SUCCESS) ? 0 : 1; 8087057Smarks } 8097057Smarks 8107057Smarks return (error); 8117057Smarks } 812