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 /* 227057Smarks * Copyright 2008 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++; 512789Sahrens start = (char *)acl_entry + 513789Sahrens acl->acl_entry_size; 514789Sahrens (void) memmove(acl_entry, start, 515789Sahrens acl->acl_entry_size * 516789Sahrens acl->acl_cnt-- - (j + 1)); 517789Sahrens 518789Sahrens if (flag == ACL_REMOVE_FIRST) 519789Sahrens break; 520789Sahrens /* 5217057Smarks * List has changed, just continue so this 5227057Smarks * slot gets checked with it's new contents. 523789Sahrens */ 524789Sahrens continue; 525789Sahrens } 526789Sahrens acl_entry = ((char *)acl_entry + acl->acl_entry_size); 527789Sahrens if (++j >= acl->acl_cnt) { 528789Sahrens break; 529789Sahrens } 530789Sahrens } 5317057Smarks remove_entry = (char *)remove_entry + removeacl->acl_entry_size; 532789Sahrens } 533789Sahrens 534789Sahrens return ((found == 0) ? EACL_NO_ACL_ENTRY : 0); 535789Sahrens } 536789Sahrens 537789Sahrens /* 538789Sahrens * Replace entires entries in acl1 with the corresponding entries 539789Sahrens * in newentries. The where argument specifies where to begin 540789Sahrens * the replacement. If the where argument is 1 greater than the 541789Sahrens * number of acl entries in acl1 then they are appended. If the 542789Sahrens * where argument is 2+ greater than the number of acl entries then 543789Sahrens * EACL_INVALID_SLOT is returned. 544789Sahrens */ 545789Sahrens int 546789Sahrens acl_modifyentries(acl_t *acl1, acl_t *newentries, int where) 547789Sahrens { 548789Sahrens 549789Sahrens int slot; 550789Sahrens int slots_needed; 551789Sahrens int slots_left; 552789Sahrens int newsize; 553789Sahrens 554789Sahrens if (acl1 == NULL || newentries == NULL) 555789Sahrens return (EACL_NO_ACL_ENTRY); 556789Sahrens 557789Sahrens if (where < 0 || where >= acl1->acl_cnt) 558789Sahrens return (EACL_INVALID_SLOT); 559789Sahrens 560789Sahrens if (acl1->acl_type != newentries->acl_type) 561789Sahrens return (EACL_DIFF_TYPE); 562789Sahrens 563789Sahrens slot = where; 564789Sahrens 565789Sahrens slots_left = acl1->acl_cnt - slot + 1; 566789Sahrens if (slots_left < newentries->acl_cnt) { 567789Sahrens slots_needed = newentries->acl_cnt - slots_left; 568789Sahrens newsize = (acl1->acl_entry_size * acl1->acl_cnt) + 569789Sahrens (acl1->acl_entry_size * slots_needed); 570789Sahrens acl1->acl_aclp = realloc(acl1->acl_aclp, newsize); 571789Sahrens if (acl1->acl_aclp == NULL) 572789Sahrens return (-1); 573789Sahrens } 574789Sahrens (void) memcpy((char *)acl1->acl_aclp + (acl1->acl_entry_size * slot), 575789Sahrens newentries->acl_aclp, 576789Sahrens newentries->acl_entry_size * newentries->acl_cnt); 577789Sahrens 578789Sahrens /* 579789Sahrens * Did ACL grow? 580789Sahrens */ 581789Sahrens 582789Sahrens if ((slot + newentries->acl_cnt) > acl1->acl_cnt) { 583789Sahrens acl1->acl_cnt = slot + newentries->acl_cnt; 584789Sahrens } 585789Sahrens 586789Sahrens return (0); 587789Sahrens } 588789Sahrens 589789Sahrens /* 590789Sahrens * Add acl2 entries into acl1. The where argument specifies where 591789Sahrens * to add the entries. 592789Sahrens */ 593789Sahrens int 594789Sahrens acl_addentries(acl_t *acl1, acl_t *acl2, int where) 595789Sahrens { 596789Sahrens 597789Sahrens int newsize; 598789Sahrens int len; 599789Sahrens void *start; 600789Sahrens void *to; 601789Sahrens 602789Sahrens if (acl1 == NULL || acl2 == NULL) 603789Sahrens return (EACL_NO_ACL_ENTRY); 604789Sahrens 605789Sahrens if (acl1->acl_type != acl2->acl_type) 606789Sahrens return (EACL_DIFF_TYPE); 607789Sahrens 608789Sahrens /* 609789Sahrens * allow where to specify 1 past last slot for an append operation 610789Sahrens * but anything greater is an error. 611789Sahrens */ 612789Sahrens if (where < 0 || where > acl1->acl_cnt) 613789Sahrens return (EACL_INVALID_SLOT); 614789Sahrens 615789Sahrens newsize = (acl2->acl_entry_size * acl2->acl_cnt) + 616789Sahrens (acl1->acl_entry_size * acl1->acl_cnt); 617789Sahrens acl1->acl_aclp = realloc(acl1->acl_aclp, newsize); 618789Sahrens if (acl1->acl_aclp == NULL) 619789Sahrens return (-1); 620789Sahrens 621789Sahrens /* 622789Sahrens * first push down entries where new ones will be inserted 623789Sahrens */ 624789Sahrens 625789Sahrens to = (void *)((char *)acl1->acl_aclp + 626789Sahrens ((where + acl2->acl_cnt) * acl1->acl_entry_size)); 627789Sahrens 628789Sahrens start = (void *)((char *)acl1->acl_aclp + 629789Sahrens where * acl1->acl_entry_size); 630789Sahrens 631789Sahrens if (where < acl1->acl_cnt) { 632789Sahrens len = (acl1->acl_cnt - where) * acl1->acl_entry_size; 633789Sahrens (void) memmove(to, start, len); 634789Sahrens } 635789Sahrens 636789Sahrens /* 637789Sahrens * now stick in new entries. 638789Sahrens */ 639789Sahrens 640789Sahrens (void) memmove(start, acl2->acl_aclp, 641789Sahrens acl2->acl_cnt * acl2->acl_entry_size); 642789Sahrens 643789Sahrens acl1->acl_cnt += acl2->acl_cnt; 644789Sahrens return (0); 645789Sahrens } 646789Sahrens 647789Sahrens /* 648789Sahrens * return text for an ACL error. 649789Sahrens */ 650789Sahrens char * 651789Sahrens acl_strerror(int errnum) 652789Sahrens { 653789Sahrens switch (errnum) { 654789Sahrens case EACL_GRP_ERROR: 655789Sahrens return (dgettext(TEXT_DOMAIN, 6561420Smarks "There is more than one group or default group entry")); 657789Sahrens case EACL_USER_ERROR: 658789Sahrens return (dgettext(TEXT_DOMAIN, 6591420Smarks "There is more than one user or default user entry")); 660789Sahrens case EACL_OTHER_ERROR: 661789Sahrens return (dgettext(TEXT_DOMAIN, 662789Sahrens "There is more than one other entry")); 663789Sahrens case EACL_CLASS_ERROR: 664789Sahrens return (dgettext(TEXT_DOMAIN, 665789Sahrens "There is more than one mask entry")); 666789Sahrens case EACL_DUPLICATE_ERROR: 667789Sahrens return (dgettext(TEXT_DOMAIN, 668789Sahrens "Duplicate user or group entries")); 669789Sahrens case EACL_MISS_ERROR: 670789Sahrens return (dgettext(TEXT_DOMAIN, 671789Sahrens "Missing user/group owner, other, mask entry")); 672789Sahrens case EACL_MEM_ERROR: 673789Sahrens return (dgettext(TEXT_DOMAIN, 674789Sahrens "Memory error")); 675789Sahrens case EACL_ENTRY_ERROR: 676789Sahrens return (dgettext(TEXT_DOMAIN, 677789Sahrens "Unrecognized entry type")); 678789Sahrens case EACL_INHERIT_ERROR: 679789Sahrens return (dgettext(TEXT_DOMAIN, 680789Sahrens "Invalid inheritance flags")); 681789Sahrens case EACL_FLAGS_ERROR: 682789Sahrens return (dgettext(TEXT_DOMAIN, 683789Sahrens "Unrecognized entry flags")); 684789Sahrens case EACL_PERM_MASK_ERROR: 685789Sahrens return (dgettext(TEXT_DOMAIN, 686789Sahrens "Invalid ACL permissions")); 687789Sahrens case EACL_COUNT_ERROR: 688789Sahrens return (dgettext(TEXT_DOMAIN, 689789Sahrens "Invalid ACL count")); 690789Sahrens case EACL_INVALID_SLOT: 691789Sahrens return (dgettext(TEXT_DOMAIN, 692789Sahrens "Invalid ACL entry number specified")); 693789Sahrens case EACL_NO_ACL_ENTRY: 694789Sahrens return (dgettext(TEXT_DOMAIN, 695789Sahrens "ACL entry doesn't exist")); 696789Sahrens case EACL_DIFF_TYPE: 697789Sahrens return (dgettext(TEXT_DOMAIN, 698789Sahrens "ACL type's are different")); 699789Sahrens case EACL_INVALID_USER_GROUP: 700789Sahrens return (dgettext(TEXT_DOMAIN, "Invalid user or group")); 701789Sahrens case EACL_INVALID_STR: 702789Sahrens return (dgettext(TEXT_DOMAIN, "ACL string is invalid")); 703789Sahrens case EACL_FIELD_NOT_BLANK: 704789Sahrens return (dgettext(TEXT_DOMAIN, "Field expected to be blank")); 705789Sahrens case EACL_INVALID_ACCESS_TYPE: 706789Sahrens return (dgettext(TEXT_DOMAIN, "Invalid access type")); 707789Sahrens case EACL_UNKNOWN_DATA: 708789Sahrens return (dgettext(TEXT_DOMAIN, "Unrecognized entry")); 709789Sahrens case EACL_MISSING_FIELDS: 710789Sahrens return (dgettext(TEXT_DOMAIN, 711789Sahrens "ACL specification missing required fields")); 712789Sahrens case EACL_INHERIT_NOTDIR: 713789Sahrens return (dgettext(TEXT_DOMAIN, 714789Sahrens "Inheritance flags are only allowed on directories")); 715789Sahrens case -1: 716789Sahrens return (strerror(errno)); 717789Sahrens default: 718789Sahrens errno = EINVAL; 719789Sahrens return (dgettext(TEXT_DOMAIN, "Unknown error")); 720789Sahrens } 721789Sahrens } 7221420Smarks 7231420Smarks extern int yyinteractive; 7241420Smarks 7251420Smarks /* PRINTFLIKE1 */ 7261420Smarks void 7271420Smarks acl_error(const char *fmt, ...) 7281420Smarks { 7291420Smarks va_list va; 7301420Smarks 7311420Smarks if (yyinteractive == 0) 7321420Smarks return; 7331420Smarks 7341420Smarks va_start(va, fmt); 7351420Smarks (void) vfprintf(stderr, fmt, va); 7361420Smarks va_end(va); 7371420Smarks } 7387057Smarks 7397057Smarks int 7407057Smarks sid_to_id(char *sid, boolean_t user, uid_t *id) 7417057Smarks { 7427057Smarks idmap_handle_t *idmap_hdl = NULL; 7437057Smarks idmap_get_handle_t *get_hdl = NULL; 7447057Smarks char *rid_start = NULL; 7457057Smarks idmap_stat status; 7467057Smarks char *end; 747*7680SMark.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) 754*7680SMark.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*7680SMark.Shellenbaum@Sun.COM if (idmap_init(&idmap_hdl) == IDMAP_SUCCESS && 760*7680SMark.Shellenbaum@Sun.COM idmap_get_create(idmap_hdl, &get_hdl) == 761*7680SMark.Shellenbaum@Sun.COM IDMAP_SUCCESS) { 7627057Smarks if (user) 7637057Smarks error = idmap_get_uidbysid(get_hdl, 7647369SJulian.Pullen@Sun.COM sid, rid, IDMAP_REQ_FLG_USE_CACHE, 7657369SJulian.Pullen@Sun.COM id, &status); 7667057Smarks else 7677057Smarks error = idmap_get_gidbysid(get_hdl, 7687369SJulian.Pullen@Sun.COM sid, rid, IDMAP_REQ_FLG_USE_CACHE, 7697369SJulian.Pullen@Sun.COM id, &status); 770*7680SMark.Shellenbaum@Sun.COM if (error == IDMAP_SUCCESS) { 771*7680SMark.Shellenbaum@Sun.COM error = idmap_get_mappings(get_hdl); 772*7680SMark.Shellenbaum@Sun.COM if (error == IDMAP_SUCCESS && 773*7680SMark.Shellenbaum@Sun.COM status != IDMAP_SUCCESS) 774*7680SMark.Shellenbaum@Sun.COM error = 1; 775*7680SMark.Shellenbaum@Sun.COM else 776*7680SMark.Shellenbaum@Sun.COM error = 0; 777*7680SMark.Shellenbaum@Sun.COM } 778*7680SMark.Shellenbaum@Sun.COM } else { 779*7680SMark.Shellenbaum@Sun.COM error = 1; 7807057Smarks } 781*7680SMark.Shellenbaum@Sun.COM if (get_hdl) 782*7680SMark.Shellenbaum@Sun.COM idmap_get_destroy(get_hdl); 783*7680SMark.Shellenbaum@Sun.COM if (idmap_hdl) 784*7680SMark.Shellenbaum@Sun.COM (void) idmap_fini(idmap_hdl); 7857057Smarks } else { 786*7680SMark.Shellenbaum@Sun.COM error = 1; 7877057Smarks } 7887057Smarks *rid_start = '-'; /* putback character removed earlier */ 7897057Smarks } else { 7907057Smarks char *name = sid; 7917057Smarks *domain_start++ = '\0'; 7927057Smarks 7937057Smarks if (user) 7947369SJulian.Pullen@Sun.COM error = idmap_getuidbywinname(name, domain_start, 7957369SJulian.Pullen@Sun.COM IDMAP_REQ_FLG_USE_CACHE, id); 7967057Smarks else 7977369SJulian.Pullen@Sun.COM error = idmap_getgidbywinname(name, domain_start, 7987369SJulian.Pullen@Sun.COM IDMAP_REQ_FLG_USE_CACHE, id); 7997057Smarks *--domain_start = '@'; 800*7680SMark.Shellenbaum@Sun.COM error = (error == IDMAP_SUCCESS) ? 0 : 1; 8017057Smarks } 8027057Smarks 8037057Smarks return (error); 8047057Smarks } 805