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*7057Smarks * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23789Sahrens * Use is subject to license terms. 24789Sahrens */ 25789Sahrens 26789Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 27789Sahrens 28789Sahrens #include <stdlib.h> 29789Sahrens #include <string.h> 30789Sahrens #include <unistd.h> 31789Sahrens #include <limits.h> 32789Sahrens #include <grp.h> 33789Sahrens #include <pwd.h> 341462Smarks #include <strings.h> 35789Sahrens #include <sys/types.h> 36789Sahrens #include <errno.h> 37789Sahrens #include <sys/stat.h> 381420Smarks #include <sys/varargs.h> 39789Sahrens #include <locale.h> 40789Sahrens #include <aclutils.h> 415331Samw #include <sys/avl.h> 42789Sahrens #include <acl_common.h> 43*7057Smarks #include <idmap.h> 44789Sahrens 45789Sahrens #define ACL_PATH 0 46789Sahrens #define ACL_FD 1 47789Sahrens 481231Smarks 49789Sahrens typedef union { 50789Sahrens const char *file; 51789Sahrens int fd; 52789Sahrens } acl_inp; 53789Sahrens 54789Sahrens 55789Sahrens /* 56789Sahrens * Determine whether a file has a trivial ACL 57789Sahrens * returns: 0 = trivial 58789Sahrens * 1 = nontrivial 59789Sahrens * <0 some other system failure, such as ENOENT or EPERM 60789Sahrens */ 61789Sahrens int 62789Sahrens acl_trivial(const char *filename) 63789Sahrens { 64789Sahrens int acl_flavor; 65789Sahrens int aclcnt; 66789Sahrens int cntcmd; 67789Sahrens int val = 0; 68789Sahrens ace_t *acep; 69789Sahrens 70789Sahrens acl_flavor = pathconf(filename, _PC_ACL_ENABLED); 71789Sahrens 72789Sahrens if (acl_flavor == _ACL_ACE_ENABLED) 73789Sahrens cntcmd = ACE_GETACLCNT; 74789Sahrens else 75789Sahrens cntcmd = GETACLCNT; 76789Sahrens 77789Sahrens aclcnt = acl(filename, cntcmd, 0, NULL); 78789Sahrens if (aclcnt > 0) { 79789Sahrens if (acl_flavor == _ACL_ACE_ENABLED) { 801231Smarks acep = malloc(sizeof (ace_t) * aclcnt); 811231Smarks if (acep == NULL) 821231Smarks return (-1); 831231Smarks if (acl(filename, ACE_GETACL, 841231Smarks aclcnt, acep) < 0) { 851231Smarks free(acep); 861231Smarks return (-1); 871231Smarks } 88789Sahrens 891231Smarks val = ace_trivial(acep, aclcnt); 901231Smarks free(acep); 911231Smarks 92789Sahrens } else if (aclcnt > MIN_ACL_ENTRIES) 93789Sahrens val = 1; 94789Sahrens } 95789Sahrens return (val); 96789Sahrens } 97789Sahrens 981462Smarks 991477Smarks static int 100789Sahrens cacl_get(acl_inp inp, int get_flag, int type, acl_t **aclp) 101789Sahrens { 102789Sahrens const char *fname; 103789Sahrens int fd; 104789Sahrens int ace_acl = 0; 105789Sahrens int error; 106789Sahrens int getcmd, cntcmd; 107789Sahrens acl_t *acl_info; 108789Sahrens int save_errno; 109789Sahrens int stat_error; 110789Sahrens struct stat64 statbuf; 111789Sahrens 112789Sahrens *aclp = NULL; 113789Sahrens if (type == ACL_PATH) { 114789Sahrens fname = inp.file; 115789Sahrens ace_acl = pathconf(fname, _PC_ACL_ENABLED); 116789Sahrens } else { 117789Sahrens fd = inp.fd; 118789Sahrens ace_acl = fpathconf(fd, _PC_ACL_ENABLED); 119789Sahrens } 120789Sahrens 121789Sahrens /* 122789Sahrens * if acl's aren't supported then 123789Sahrens * send it through the old GETACL interface 124789Sahrens */ 1251666Smarks if (ace_acl == 0 || ace_acl == -1) { 126789Sahrens ace_acl = _ACL_ACLENT_ENABLED; 127789Sahrens } 128789Sahrens 129789Sahrens if (ace_acl & _ACL_ACE_ENABLED) { 130789Sahrens cntcmd = ACE_GETACLCNT; 131789Sahrens getcmd = ACE_GETACL; 132789Sahrens acl_info = acl_alloc(ACE_T); 133789Sahrens } else { 134789Sahrens cntcmd = GETACLCNT; 135789Sahrens getcmd = GETACL; 136789Sahrens acl_info = acl_alloc(ACLENT_T); 137789Sahrens } 138789Sahrens 139789Sahrens if (acl_info == NULL) 140789Sahrens return (-1); 141789Sahrens 142789Sahrens if (type == ACL_PATH) { 143789Sahrens acl_info->acl_cnt = acl(fname, cntcmd, 0, NULL); 144789Sahrens } else { 145789Sahrens acl_info->acl_cnt = facl(fd, cntcmd, 0, NULL); 146789Sahrens } 147789Sahrens 148789Sahrens save_errno = errno; 149789Sahrens if (acl_info->acl_cnt < 0) { 150789Sahrens acl_free(acl_info); 151789Sahrens errno = save_errno; 152789Sahrens return (-1); 153789Sahrens } 154789Sahrens 155789Sahrens if (acl_info->acl_cnt == 0) { 156789Sahrens acl_free(acl_info); 157789Sahrens errno = save_errno; 158789Sahrens return (0); 159789Sahrens } 160789Sahrens 161789Sahrens acl_info->acl_aclp = 162789Sahrens malloc(acl_info->acl_cnt * acl_info->acl_entry_size); 163789Sahrens save_errno = errno; 164789Sahrens 165789Sahrens if (acl_info->acl_aclp == NULL) { 166789Sahrens acl_free(acl_info); 167789Sahrens errno = save_errno; 168789Sahrens return (-1); 169789Sahrens } 170789Sahrens 171789Sahrens if (type == ACL_PATH) { 172789Sahrens stat_error = stat64(fname, &statbuf); 173789Sahrens error = acl(fname, getcmd, acl_info->acl_cnt, 174789Sahrens acl_info->acl_aclp); 175789Sahrens } else { 176789Sahrens stat_error = fstat64(fd, &statbuf); 177789Sahrens error = facl(fd, getcmd, acl_info->acl_cnt, 178789Sahrens acl_info->acl_aclp); 179789Sahrens } 180789Sahrens 181789Sahrens save_errno = errno; 182789Sahrens if (error == -1) { 183789Sahrens acl_free(acl_info); 184789Sahrens errno = save_errno; 185789Sahrens return (-1); 186789Sahrens } 187789Sahrens 188789Sahrens 189789Sahrens if (stat_error == 0) { 190789Sahrens acl_info->acl_flags = 191789Sahrens (S_ISDIR(statbuf.st_mode) ? ACL_IS_DIR : 0); 192789Sahrens } else 193789Sahrens acl_info->acl_flags = 0; 194789Sahrens 195789Sahrens switch (acl_info->acl_type) { 196789Sahrens case ACLENT_T: 197789Sahrens if (acl_info->acl_cnt <= MIN_ACL_ENTRIES) 198789Sahrens acl_info->acl_flags |= ACL_IS_TRIVIAL; 199789Sahrens break; 200789Sahrens case ACE_T: 201789Sahrens if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0) 202789Sahrens acl_info->acl_flags |= ACL_IS_TRIVIAL; 203789Sahrens break; 204789Sahrens default: 205789Sahrens errno = EINVAL; 206789Sahrens acl_free(acl_info); 207789Sahrens return (-1); 208789Sahrens } 209789Sahrens 210789Sahrens if ((acl_info->acl_flags & ACL_IS_TRIVIAL) && 211789Sahrens (get_flag & ACL_NO_TRIVIAL)) { 212789Sahrens acl_free(acl_info); 213789Sahrens errno = 0; 214789Sahrens return (0); 215789Sahrens } 216789Sahrens 217789Sahrens *aclp = acl_info; 218789Sahrens return (0); 219789Sahrens } 220789Sahrens 221789Sahrens /* 222789Sahrens * return -1 on failure, otherwise the number of acl 223789Sahrens * entries is returned 224789Sahrens */ 225789Sahrens int 226789Sahrens acl_get(const char *path, int get_flag, acl_t **aclp) 227789Sahrens { 228789Sahrens acl_inp acl_inp; 229789Sahrens acl_inp.file = path; 230789Sahrens 231789Sahrens return (cacl_get(acl_inp, get_flag, ACL_PATH, aclp)); 232789Sahrens } 233789Sahrens 234789Sahrens int 235789Sahrens facl_get(int fd, int get_flag, acl_t **aclp) 236789Sahrens { 237789Sahrens 238789Sahrens acl_inp acl_inp; 239789Sahrens acl_inp.fd = fd; 240789Sahrens 241789Sahrens return (cacl_get(acl_inp, get_flag, ACL_FD, aclp)); 242789Sahrens } 243789Sahrens 244789Sahrens /* 245789Sahrens * Set an ACL, translates acl to ace_t when appropriate. 246789Sahrens */ 247789Sahrens static int 248789Sahrens cacl_set(acl_inp *acl_inp, acl_t *aclp, int type) 249789Sahrens { 250789Sahrens int error = 0; 251789Sahrens int acl_flavor_target; 252789Sahrens struct stat64 statbuf; 253789Sahrens int stat_error; 254789Sahrens int isdir; 255789Sahrens 256789Sahrens 257789Sahrens if (type == ACL_PATH) { 258789Sahrens stat_error = stat64(acl_inp->file, &statbuf); 259789Sahrens if (stat_error) 260789Sahrens return (-1); 261789Sahrens acl_flavor_target = pathconf(acl_inp->file, _PC_ACL_ENABLED); 262789Sahrens } else { 263789Sahrens stat_error = fstat64(acl_inp->fd, &statbuf); 264789Sahrens if (stat_error) 265789Sahrens return (-1); 266789Sahrens acl_flavor_target = fpathconf(acl_inp->fd, _PC_ACL_ENABLED); 267789Sahrens } 268789Sahrens 2691666Smarks /* 2701666Smarks * If target returns an error or 0 from pathconf call then 2711666Smarks * fall back to UFS/POSIX Draft interface. 2721666Smarks * In the case of 0 we will then fail in either acl(2) or 2731666Smarks * acl_translate(). We could erroneously get 0 back from 2741666Smarks * a file system that is using fs_pathconf() and not answering 2751666Smarks * the _PC_ACL_ENABLED question itself. 2761666Smarks */ 2771666Smarks if (acl_flavor_target == 0 || acl_flavor_target == -1) 2781666Smarks acl_flavor_target = _ACL_ACLENT_ENABLED; 2791666Smarks 280789Sahrens isdir = S_ISDIR(statbuf.st_mode); 281789Sahrens 2821462Smarks if ((error = acl_translate(aclp, acl_flavor_target, isdir, 2831462Smarks statbuf.st_uid, statbuf.st_gid)) != 0) { 2841462Smarks return (error); 285789Sahrens } 286789Sahrens 287789Sahrens if (type == ACL_PATH) { 288789Sahrens error = acl(acl_inp->file, 289789Sahrens (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, 290789Sahrens aclp->acl_cnt, aclp->acl_aclp); 291789Sahrens } else { 292789Sahrens error = facl(acl_inp->fd, 293789Sahrens (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, 294789Sahrens aclp->acl_cnt, aclp->acl_aclp); 295789Sahrens } 296789Sahrens 297789Sahrens return (error); 298789Sahrens } 299789Sahrens 300789Sahrens int 301789Sahrens acl_set(const char *path, acl_t *aclp) 302789Sahrens { 303789Sahrens acl_inp acl_inp; 304789Sahrens 305789Sahrens acl_inp.file = path; 306789Sahrens 307789Sahrens return (cacl_set(&acl_inp, aclp, ACL_PATH)); 308789Sahrens } 309789Sahrens 310789Sahrens int 311789Sahrens facl_set(int fd, acl_t *aclp) 312789Sahrens { 313789Sahrens acl_inp acl_inp; 314789Sahrens 315789Sahrens acl_inp.fd = fd; 316789Sahrens 317789Sahrens return (cacl_set(&acl_inp, aclp, ACL_FD)); 318789Sahrens } 319789Sahrens 320789Sahrens int 321789Sahrens acl_cnt(acl_t *aclp) 322789Sahrens { 323789Sahrens return (aclp->acl_cnt); 324789Sahrens } 325789Sahrens 326789Sahrens int 327789Sahrens acl_type(acl_t *aclp) 328789Sahrens { 329789Sahrens return (aclp->acl_type); 330789Sahrens } 331789Sahrens 332789Sahrens acl_t * 333789Sahrens acl_dup(acl_t *aclp) 334789Sahrens { 335789Sahrens acl_t *newaclp; 336789Sahrens 337789Sahrens newaclp = acl_alloc(aclp->acl_type); 338789Sahrens if (newaclp == NULL) 339789Sahrens return (NULL); 340789Sahrens 341789Sahrens newaclp->acl_aclp = malloc(aclp->acl_entry_size * aclp->acl_cnt); 342789Sahrens if (newaclp->acl_aclp == NULL) { 343789Sahrens acl_free(newaclp); 344789Sahrens return (NULL); 345789Sahrens } 346789Sahrens 347789Sahrens (void) memcpy(newaclp->acl_aclp, 348789Sahrens aclp->acl_aclp, aclp->acl_entry_size * aclp->acl_cnt); 349789Sahrens newaclp->acl_cnt = aclp->acl_cnt; 350789Sahrens 351789Sahrens return (newaclp); 352789Sahrens } 353789Sahrens 354789Sahrens int 355789Sahrens acl_flags(acl_t *aclp) 356789Sahrens { 357789Sahrens return (aclp->acl_flags); 358789Sahrens } 359789Sahrens 360789Sahrens void * 361789Sahrens acl_data(acl_t *aclp) 362789Sahrens { 363789Sahrens return (aclp->acl_aclp); 364789Sahrens } 365789Sahrens 366789Sahrens /* 3671953Smarks * Take an acl array and build an acl_t. 3681953Smarks */ 3691953Smarks acl_t * 3701953Smarks acl_to_aclp(enum acl_type type, void *acl, int count) 3711953Smarks { 3721953Smarks acl_t *aclp; 3731953Smarks 3741953Smarks 3751953Smarks aclp = acl_alloc(type); 3761953Smarks if (aclp == NULL) 3771953Smarks return (aclp); 3781953Smarks 3791953Smarks aclp->acl_aclp = acl; 3801953Smarks aclp->acl_cnt = count; 3811953Smarks 3821953Smarks return (aclp); 3831953Smarks } 3841953Smarks 3851953Smarks /* 386789Sahrens * Remove an ACL from a file and create a trivial ACL based 387789Sahrens * off of the mode argument. After acl has been set owner/group 388789Sahrens * are updated to match owner,group arguments 389789Sahrens */ 390789Sahrens int 391789Sahrens acl_strip(const char *file, uid_t owner, gid_t group, mode_t mode) 392789Sahrens { 393789Sahrens int error = 0; 394789Sahrens aclent_t min_acl[MIN_ACL_ENTRIES]; 395789Sahrens ace_t min_ace_acl[6]; /* owner, group, everyone + complement denies */ 396789Sahrens int acl_flavor; 397789Sahrens int aclcnt; 398789Sahrens 399789Sahrens acl_flavor = pathconf(file, _PC_ACL_ENABLED); 400789Sahrens 401789Sahrens /* 402789Sahrens * force it through aclent flavor when file system doesn't 403789Sahrens * understand question 404789Sahrens */ 4051666Smarks if (acl_flavor == 0 || acl_flavor == -1) 406789Sahrens acl_flavor = _ACL_ACLENT_ENABLED; 407789Sahrens 408789Sahrens if (acl_flavor & _ACL_ACLENT_ENABLED) { 409789Sahrens min_acl[0].a_type = USER_OBJ; 410789Sahrens min_acl[0].a_id = owner; 411789Sahrens min_acl[0].a_perm = ((mode & 0700) >> 6); 412789Sahrens min_acl[1].a_type = GROUP_OBJ; 413789Sahrens min_acl[1].a_id = group; 414789Sahrens min_acl[1].a_perm = ((mode & 0070) >> 3); 415789Sahrens min_acl[2].a_type = CLASS_OBJ; 416789Sahrens min_acl[2].a_id = (uid_t)-1; 417789Sahrens min_acl[2].a_perm = ((mode & 0070) >> 3); 418789Sahrens min_acl[3].a_type = OTHER_OBJ; 419789Sahrens min_acl[3].a_id = (uid_t)-1; 420789Sahrens min_acl[3].a_perm = (mode & 0007); 421789Sahrens aclcnt = 4; 422789Sahrens error = acl(file, SETACL, aclcnt, min_acl); 423789Sahrens } else if (acl_flavor & _ACL_ACE_ENABLED) { 424789Sahrens (void) memcpy(min_ace_acl, trivial_acl, sizeof (ace_t) * 6); 425789Sahrens 426789Sahrens /* 427789Sahrens * Make aces match request mode 428789Sahrens */ 429789Sahrens adjust_ace_pair(&min_ace_acl[0], (mode & 0700) >> 6); 430789Sahrens adjust_ace_pair(&min_ace_acl[2], (mode & 0070) >> 3); 431789Sahrens adjust_ace_pair(&min_ace_acl[4], mode & 0007); 432789Sahrens 433789Sahrens error = acl(file, ACE_SETACL, 6, min_ace_acl); 434789Sahrens } else { 435789Sahrens errno = EINVAL; 436789Sahrens error = 1; 437789Sahrens } 438789Sahrens 439789Sahrens if (error == 0) 440789Sahrens error = chown(file, owner, group); 441789Sahrens return (error); 442789Sahrens } 443789Sahrens 444789Sahrens static int 445789Sahrens ace_match(void *entry1, void *entry2) 446789Sahrens { 447789Sahrens ace_t *p1 = (ace_t *)entry1; 448789Sahrens ace_t *p2 = (ace_t *)entry2; 449789Sahrens ace_t ace1, ace2; 450789Sahrens 451789Sahrens ace1 = *p1; 452789Sahrens ace2 = *p2; 453789Sahrens 454789Sahrens /* 455789Sahrens * Need to fixup who field for abstrations for 456789Sahrens * accurate comparison, since field is undefined. 457789Sahrens */ 458789Sahrens if (ace1.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE)) 4594321Scasper ace1.a_who = (uid_t)-1; 460789Sahrens if (ace2.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE)) 4614321Scasper ace2.a_who = (uid_t)-1; 462789Sahrens return (memcmp(&ace1, &ace2, sizeof (ace_t))); 463789Sahrens } 464789Sahrens 465789Sahrens static int 466789Sahrens aclent_match(void *entry1, void *entry2) 467789Sahrens { 468789Sahrens aclent_t *aclent1 = (aclent_t *)entry1; 469789Sahrens aclent_t *aclent2 = (aclent_t *)entry2; 470789Sahrens 471789Sahrens return (memcmp(aclent1, aclent2, sizeof (aclent_t))); 472789Sahrens } 473789Sahrens 474789Sahrens /* 475789Sahrens * Find acl entries in acl that correspond to removeacl. Search 476789Sahrens * is started from slot. The flag argument indicates whether to 477789Sahrens * remove all matches or just the first match. 478789Sahrens */ 479789Sahrens int 480789Sahrens acl_removeentries(acl_t *acl, acl_t *removeacl, int start_slot, int flag) 481789Sahrens { 482789Sahrens int i, j; 483789Sahrens int match; 484789Sahrens int (*acl_match)(void *acl1, void *acl2); 485789Sahrens void *acl_entry, *remove_entry; 486789Sahrens void *start; 487789Sahrens int found = 0; 488789Sahrens 489789Sahrens if (flag != ACL_REMOVE_ALL && flag != ACL_REMOVE_FIRST) 490789Sahrens flag = ACL_REMOVE_FIRST; 491789Sahrens 492789Sahrens if (acl == NULL || removeacl == NULL) 493789Sahrens return (EACL_NO_ACL_ENTRY); 494789Sahrens 495789Sahrens if (acl->acl_type != removeacl->acl_type) 496789Sahrens return (EACL_DIFF_TYPE); 497789Sahrens 498789Sahrens if (acl->acl_type == ACLENT_T) 499789Sahrens acl_match = aclent_match; 500789Sahrens else 501789Sahrens acl_match = ace_match; 502789Sahrens 503789Sahrens for (i = 0, remove_entry = removeacl->acl_aclp; 504789Sahrens i != removeacl->acl_cnt; i++) { 505789Sahrens 506789Sahrens j = 0; 507789Sahrens acl_entry = (char *)acl->acl_aclp + 508789Sahrens (acl->acl_entry_size * start_slot); 509789Sahrens for (;;) { 510789Sahrens match = acl_match(acl_entry, remove_entry); 511789Sahrens if (match == 0) { 512789Sahrens found++; 513789Sahrens start = (char *)acl_entry + 514789Sahrens acl->acl_entry_size; 515789Sahrens (void) memmove(acl_entry, start, 516789Sahrens acl->acl_entry_size * 517789Sahrens acl->acl_cnt-- - (j + 1)); 518789Sahrens 519789Sahrens if (flag == ACL_REMOVE_FIRST) 520789Sahrens break; 521789Sahrens /* 522*7057Smarks * List has changed, just continue so this 523*7057Smarks * 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 } 532*7057Smarks 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, 699789Sahrens "ACL type's are different")); 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 } 739*7057Smarks 740*7057Smarks int 741*7057Smarks sid_to_id(char *sid, boolean_t user, uid_t *id) 742*7057Smarks { 743*7057Smarks idmap_handle_t *idmap_hdl = NULL; 744*7057Smarks idmap_get_handle_t *get_hdl = NULL; 745*7057Smarks char *rid_start = NULL; 746*7057Smarks idmap_stat status; 747*7057Smarks char *end; 748*7057Smarks int error = 0; 749*7057Smarks char *domain_start; 750*7057Smarks 751*7057Smarks 752*7057Smarks if ((domain_start = strchr(sid, '@')) == NULL) { 753*7057Smarks idmap_rid_t rid; 754*7057Smarks 755*7057Smarks if ((rid_start = strrchr(sid, '-')) == NULL) 756*7057Smarks return (-1); 757*7057Smarks *rid_start++ = '\0'; 758*7057Smarks errno = 0; 759*7057Smarks rid = strtoul(rid_start--, &end, 10); 760*7057Smarks if (errno == 0 && *end == '\0') { 761*7057Smarks if (idmap_init(&idmap_hdl) == 0 && 762*7057Smarks idmap_get_create(idmap_hdl, &get_hdl) == 0) { 763*7057Smarks if (user) 764*7057Smarks error = idmap_get_uidbysid(get_hdl, 765*7057Smarks sid, rid, 0, id, &status); 766*7057Smarks else 767*7057Smarks error = idmap_get_gidbysid(get_hdl, 768*7057Smarks sid, rid, 0, id, &status); 769*7057Smarks } 770*7057Smarks } else { 771*7057Smarks error = -1; 772*7057Smarks } 773*7057Smarks if (error == 0) { 774*7057Smarks error = idmap_get_mappings(get_hdl); 775*7057Smarks if (error == 0 && status != 0) 776*7057Smarks error = -1; 777*7057Smarks } 778*7057Smarks if (get_hdl) 779*7057Smarks idmap_get_destroy(get_hdl); 780*7057Smarks if (idmap_hdl) 781*7057Smarks (void) idmap_fini(idmap_hdl); 782*7057Smarks *rid_start = '-'; /* putback character removed earlier */ 783*7057Smarks } else { 784*7057Smarks char *name = sid; 785*7057Smarks *domain_start++ = '\0'; 786*7057Smarks 787*7057Smarks if (user) 788*7057Smarks error = idmap_getuidbywinname(name, domain_start, id); 789*7057Smarks else 790*7057Smarks error = idmap_getgidbywinname(name, domain_start, id); 791*7057Smarks *--domain_start = '@'; 792*7057Smarks } 793*7057Smarks 794*7057Smarks return (error); 795*7057Smarks } 796