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 /* 224321Scasper * Copyright 2007 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> 41*5331Samw #include <sys/avl.h> 42789Sahrens #include <acl_common.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 /* 521789Sahrens * List has changed, restart search from 522789Sahrens * beginning. 523789Sahrens */ 524789Sahrens acl_entry = acl->acl_aclp; 525789Sahrens j = 0; 526789Sahrens continue; 527789Sahrens } 528789Sahrens acl_entry = ((char *)acl_entry + acl->acl_entry_size); 529789Sahrens if (++j >= acl->acl_cnt) { 530789Sahrens break; 531789Sahrens } 532789Sahrens } 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