archive_acl.c revision 339005
1231200Smm/*- 2231200Smm * Copyright (c) 2003-2010 Tim Kientzle 3313570Smm * Copyright (c) 2016 Martin Matuska 4231200Smm * All rights reserved. 5231200Smm * 6231200Smm * Redistribution and use in source and binary forms, with or without 7231200Smm * modification, are permitted provided that the following conditions 8231200Smm * are met: 9231200Smm * 1. Redistributions of source code must retain the above copyright 10231200Smm * notice, this list of conditions and the following disclaimer. 11231200Smm * 2. Redistributions in binary form must reproduce the above copyright 12231200Smm * notice, this list of conditions and the following disclaimer in the 13231200Smm * documentation and/or other materials provided with the distribution. 14231200Smm * 15231200Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16231200Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17231200Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18231200Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19231200Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20231200Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21231200Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22231200Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23231200Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24231200Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25231200Smm */ 26231200Smm 27231200Smm#include "archive_platform.h" 28231200Smm__FBSDID("$FreeBSD$"); 29231200Smm 30231200Smm#ifdef HAVE_ERRNO_H 31231200Smm#include <errno.h> 32231200Smm#endif 33231200Smm#ifdef HAVE_LIMITS_H 34231200Smm#include <limits.h> 35231200Smm#endif 36231200Smm#ifdef HAVE_WCHAR_H 37231200Smm#include <wchar.h> 38231200Smm#endif 39231200Smm 40231200Smm#include "archive_acl_private.h" 41231200Smm#include "archive_entry.h" 42231200Smm#include "archive_private.h" 43231200Smm 44231200Smm#undef max 45231200Smm#define max(a, b) ((a)>(b)?(a):(b)) 46231200Smm 47231200Smm#ifndef HAVE_WMEMCMP 48231200Smm/* Good enough for simple equality testing, but not for sorting. */ 49231200Smm#define wmemcmp(a,b,i) memcmp((a), (b), (i) * sizeof(wchar_t)) 50231200Smm#endif 51231200Smm 52231200Smmstatic int acl_special(struct archive_acl *acl, 53231200Smm int type, int permset, int tag); 54231200Smmstatic struct archive_acl_entry *acl_new_entry(struct archive_acl *acl, 55231200Smm int type, int permset, int tag, int id); 56232153Smmstatic int archive_acl_add_entry_len_l(struct archive_acl *acl, 57232153Smm int type, int permset, int tag, int id, const char *name, 58232153Smm size_t len, struct archive_string_conv *sc); 59313570Smmstatic int archive_acl_text_want_type(struct archive_acl *acl, int flags); 60313570Smmstatic ssize_t archive_acl_text_len(struct archive_acl *acl, int want_type, 61313570Smm int flags, int wide, struct archive *a, 62313570Smm struct archive_string_conv *sc); 63231200Smmstatic int isint_w(const wchar_t *start, const wchar_t *end, int *result); 64231200Smmstatic int ismode_w(const wchar_t *start, const wchar_t *end, int *result); 65313570Smmstatic int is_nfs4_flags_w(const wchar_t *start, const wchar_t *end, 66313570Smm int *result); 67313570Smmstatic int is_nfs4_perms_w(const wchar_t *start, const wchar_t *end, 68313570Smm int *result); 69231200Smmstatic void next_field_w(const wchar_t **wp, const wchar_t **start, 70231200Smm const wchar_t **end, wchar_t *sep); 71313570Smmstatic void append_entry_w(wchar_t **wp, const wchar_t *prefix, int type, 72313570Smm int tag, int flags, const wchar_t *wname, int perm, int id); 73231200Smmstatic void append_id_w(wchar_t **wp, int id); 74231200Smmstatic int isint(const char *start, const char *end, int *result); 75231200Smmstatic int ismode(const char *start, const char *end, int *result); 76313570Smmstatic int is_nfs4_flags(const char *start, const char *end, 77313570Smm int *result); 78313570Smmstatic int is_nfs4_perms(const char *start, const char *end, 79313570Smm int *result); 80231200Smmstatic void next_field(const char **p, const char **start, 81231200Smm const char **end, char *sep); 82313570Smmstatic void append_entry(char **p, const char *prefix, int type, 83313570Smm int tag, int flags, const char *name, int perm, int id); 84231200Smmstatic void append_id(char **p, int id); 85231200Smm 86313926Smmstatic const struct { 87313926Smm const int perm; 88313926Smm const char c; 89313926Smm const wchar_t wc; 90313926Smm} nfsv4_acl_perm_map[] = { 91313926Smm { ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, 'r', 92313926Smm L'r' }, 93313926Smm { ARCHIVE_ENTRY_ACL_WRITE_DATA | ARCHIVE_ENTRY_ACL_ADD_FILE, 'w', 94313926Smm L'w' }, 95313926Smm { ARCHIVE_ENTRY_ACL_EXECUTE, 'x', L'x' }, 96313926Smm { ARCHIVE_ENTRY_ACL_APPEND_DATA | ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, 97313926Smm 'p', L'p' }, 98313926Smm { ARCHIVE_ENTRY_ACL_DELETE, 'd', L'd' }, 99313926Smm { ARCHIVE_ENTRY_ACL_DELETE_CHILD, 'D', L'D' }, 100313926Smm { ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, 'a', L'a' }, 101313926Smm { ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, 'A', L'A' }, 102313926Smm { ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, 'R', L'R' }, 103313926Smm { ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, 'W', L'W' }, 104313926Smm { ARCHIVE_ENTRY_ACL_READ_ACL, 'c', L'c' }, 105313926Smm { ARCHIVE_ENTRY_ACL_WRITE_ACL, 'C', L'C' }, 106313926Smm { ARCHIVE_ENTRY_ACL_WRITE_OWNER, 'o', L'o' }, 107313926Smm { ARCHIVE_ENTRY_ACL_SYNCHRONIZE, 's', L's' } 108313926Smm}; 109313926Smm 110313926Smmstatic const int nfsv4_acl_perm_map_size = (int)(sizeof(nfsv4_acl_perm_map) / 111313926Smm sizeof(nfsv4_acl_perm_map[0])); 112313926Smm 113313926Smmstatic const struct { 114313926Smm const int perm; 115313926Smm const char c; 116313926Smm const wchar_t wc; 117313926Smm} nfsv4_acl_flag_map[] = { 118313926Smm { ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, 'f', L'f' }, 119313926Smm { ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, 'd', L'd' }, 120313926Smm { ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, 'i', L'i' }, 121313926Smm { ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, 'n', L'n' }, 122313926Smm { ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, 'S', L'S' }, 123313926Smm { ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, 'F', L'F' }, 124313926Smm { ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, 'I', L'I' } 125313926Smm}; 126313926Smm 127313926Smmstatic const int nfsv4_acl_flag_map_size = (int)(sizeof(nfsv4_acl_flag_map) / 128313926Smm sizeof(nfsv4_acl_flag_map[0])); 129313926Smm 130231200Smmvoid 131231200Smmarchive_acl_clear(struct archive_acl *acl) 132231200Smm{ 133231200Smm struct archive_acl_entry *ap; 134231200Smm 135231200Smm while (acl->acl_head != NULL) { 136231200Smm ap = acl->acl_head->next; 137231200Smm archive_mstring_clean(&acl->acl_head->name); 138231200Smm free(acl->acl_head); 139231200Smm acl->acl_head = ap; 140231200Smm } 141231200Smm if (acl->acl_text_w != NULL) { 142231200Smm free(acl->acl_text_w); 143231200Smm acl->acl_text_w = NULL; 144231200Smm } 145231200Smm if (acl->acl_text != NULL) { 146231200Smm free(acl->acl_text); 147231200Smm acl->acl_text = NULL; 148231200Smm } 149231200Smm acl->acl_p = NULL; 150311041Smm acl->acl_types = 0; 151231200Smm acl->acl_state = 0; /* Not counting. */ 152231200Smm} 153231200Smm 154231200Smmvoid 155231200Smmarchive_acl_copy(struct archive_acl *dest, struct archive_acl *src) 156231200Smm{ 157231200Smm struct archive_acl_entry *ap, *ap2; 158231200Smm 159231200Smm archive_acl_clear(dest); 160231200Smm 161231200Smm dest->mode = src->mode; 162231200Smm ap = src->acl_head; 163231200Smm while (ap != NULL) { 164231200Smm ap2 = acl_new_entry(dest, 165231200Smm ap->type, ap->permset, ap->tag, ap->id); 166231200Smm if (ap2 != NULL) 167231200Smm archive_mstring_copy(&ap2->name, &ap->name); 168231200Smm ap = ap->next; 169231200Smm } 170231200Smm} 171231200Smm 172231200Smmint 173231200Smmarchive_acl_add_entry(struct archive_acl *acl, 174231200Smm int type, int permset, int tag, int id, const char *name) 175231200Smm{ 176231200Smm struct archive_acl_entry *ap; 177231200Smm 178231200Smm if (acl_special(acl, type, permset, tag) == 0) 179231200Smm return ARCHIVE_OK; 180231200Smm ap = acl_new_entry(acl, type, permset, tag, id); 181231200Smm if (ap == NULL) { 182231200Smm /* XXX Error XXX */ 183231200Smm return ARCHIVE_FAILED; 184231200Smm } 185231200Smm if (name != NULL && *name != '\0') 186231200Smm archive_mstring_copy_mbs(&ap->name, name); 187231200Smm else 188231200Smm archive_mstring_clean(&ap->name); 189231200Smm return ARCHIVE_OK; 190231200Smm} 191231200Smm 192231200Smmint 193231200Smmarchive_acl_add_entry_w_len(struct archive_acl *acl, 194231200Smm int type, int permset, int tag, int id, const wchar_t *name, size_t len) 195231200Smm{ 196231200Smm struct archive_acl_entry *ap; 197231200Smm 198231200Smm if (acl_special(acl, type, permset, tag) == 0) 199231200Smm return ARCHIVE_OK; 200231200Smm ap = acl_new_entry(acl, type, permset, tag, id); 201231200Smm if (ap == NULL) { 202231200Smm /* XXX Error XXX */ 203231200Smm return ARCHIVE_FAILED; 204231200Smm } 205231200Smm if (name != NULL && *name != L'\0' && len > 0) 206231200Smm archive_mstring_copy_wcs_len(&ap->name, name, len); 207231200Smm else 208231200Smm archive_mstring_clean(&ap->name); 209231200Smm return ARCHIVE_OK; 210231200Smm} 211231200Smm 212232153Smmstatic int 213231200Smmarchive_acl_add_entry_len_l(struct archive_acl *acl, 214231200Smm int type, int permset, int tag, int id, const char *name, size_t len, 215231200Smm struct archive_string_conv *sc) 216231200Smm{ 217231200Smm struct archive_acl_entry *ap; 218231200Smm int r; 219231200Smm 220231200Smm if (acl_special(acl, type, permset, tag) == 0) 221231200Smm return ARCHIVE_OK; 222231200Smm ap = acl_new_entry(acl, type, permset, tag, id); 223231200Smm if (ap == NULL) { 224231200Smm /* XXX Error XXX */ 225231200Smm return ARCHIVE_FAILED; 226231200Smm } 227231200Smm if (name != NULL && *name != '\0' && len > 0) { 228231200Smm r = archive_mstring_copy_mbs_len_l(&ap->name, name, len, sc); 229231200Smm } else { 230231200Smm r = 0; 231231200Smm archive_mstring_clean(&ap->name); 232231200Smm } 233231200Smm if (r == 0) 234231200Smm return (ARCHIVE_OK); 235231200Smm else if (errno == ENOMEM) 236231200Smm return (ARCHIVE_FATAL); 237231200Smm else 238231200Smm return (ARCHIVE_WARN); 239231200Smm} 240231200Smm 241231200Smm/* 242231200Smm * If this ACL entry is part of the standard POSIX permissions set, 243231200Smm * store the permissions in the stat structure and return zero. 244231200Smm */ 245231200Smmstatic int 246231200Smmacl_special(struct archive_acl *acl, int type, int permset, int tag) 247231200Smm{ 248231200Smm if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS 249231200Smm && ((permset & ~007) == 0)) { 250231200Smm switch (tag) { 251231200Smm case ARCHIVE_ENTRY_ACL_USER_OBJ: 252231200Smm acl->mode &= ~0700; 253231200Smm acl->mode |= (permset & 7) << 6; 254231200Smm return (0); 255231200Smm case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 256231200Smm acl->mode &= ~0070; 257231200Smm acl->mode |= (permset & 7) << 3; 258231200Smm return (0); 259231200Smm case ARCHIVE_ENTRY_ACL_OTHER: 260231200Smm acl->mode &= ~0007; 261231200Smm acl->mode |= permset & 7; 262231200Smm return (0); 263231200Smm } 264231200Smm } 265231200Smm return (1); 266231200Smm} 267231200Smm 268231200Smm/* 269231200Smm * Allocate and populate a new ACL entry with everything but the 270231200Smm * name. 271231200Smm */ 272231200Smmstatic struct archive_acl_entry * 273231200Smmacl_new_entry(struct archive_acl *acl, 274231200Smm int type, int permset, int tag, int id) 275231200Smm{ 276231200Smm struct archive_acl_entry *ap, *aq; 277231200Smm 278231200Smm /* Type argument must be a valid NFS4 or POSIX.1e type. 279231200Smm * The type must agree with anything already set and 280231200Smm * the permset must be compatible. */ 281231200Smm if (type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 282231200Smm if (acl->acl_types & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 283231200Smm return (NULL); 284231200Smm } 285231200Smm if (permset & 286231200Smm ~(ARCHIVE_ENTRY_ACL_PERMS_NFS4 287231200Smm | ARCHIVE_ENTRY_ACL_INHERITANCE_NFS4)) { 288231200Smm return (NULL); 289231200Smm } 290231200Smm } else if (type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) { 291231200Smm if (acl->acl_types & ~ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) { 292231200Smm return (NULL); 293231200Smm } 294231200Smm if (permset & ~ARCHIVE_ENTRY_ACL_PERMS_POSIX1E) { 295231200Smm return (NULL); 296231200Smm } 297231200Smm } else { 298231200Smm return (NULL); 299231200Smm } 300231200Smm 301231200Smm /* Verify the tag is valid and compatible with NFS4 or POSIX.1e. */ 302231200Smm switch (tag) { 303231200Smm case ARCHIVE_ENTRY_ACL_USER: 304231200Smm case ARCHIVE_ENTRY_ACL_USER_OBJ: 305231200Smm case ARCHIVE_ENTRY_ACL_GROUP: 306231200Smm case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 307231200Smm /* Tags valid in both NFS4 and POSIX.1e */ 308231200Smm break; 309231200Smm case ARCHIVE_ENTRY_ACL_MASK: 310231200Smm case ARCHIVE_ENTRY_ACL_OTHER: 311231200Smm /* Tags valid only in POSIX.1e. */ 312231200Smm if (type & ~ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) { 313231200Smm return (NULL); 314231200Smm } 315231200Smm break; 316231200Smm case ARCHIVE_ENTRY_ACL_EVERYONE: 317231200Smm /* Tags valid only in NFS4. */ 318231200Smm if (type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 319231200Smm return (NULL); 320231200Smm } 321231200Smm break; 322231200Smm default: 323231200Smm /* No other values are valid. */ 324231200Smm return (NULL); 325231200Smm } 326231200Smm 327231200Smm if (acl->acl_text_w != NULL) { 328231200Smm free(acl->acl_text_w); 329231200Smm acl->acl_text_w = NULL; 330231200Smm } 331231200Smm if (acl->acl_text != NULL) { 332231200Smm free(acl->acl_text); 333231200Smm acl->acl_text = NULL; 334231200Smm } 335231200Smm 336311041Smm /* 337311041Smm * If there's a matching entry already in the list, overwrite it. 338311041Smm * NFSv4 entries may be repeated and are not overwritten. 339311041Smm * 340311041Smm * TODO: compare names of no id is provided (needs more rework) 341311041Smm */ 342231200Smm ap = acl->acl_head; 343231200Smm aq = NULL; 344231200Smm while (ap != NULL) { 345311041Smm if (((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0) && 346311041Smm ap->type == type && ap->tag == tag && ap->id == id) { 347311041Smm if (id != -1 || (tag != ARCHIVE_ENTRY_ACL_USER && 348311041Smm tag != ARCHIVE_ENTRY_ACL_GROUP)) { 349311041Smm ap->permset = permset; 350311041Smm return (ap); 351311041Smm } 352231200Smm } 353231200Smm aq = ap; 354231200Smm ap = ap->next; 355231200Smm } 356231200Smm 357231200Smm /* Add a new entry to the end of the list. */ 358311041Smm ap = (struct archive_acl_entry *)calloc(1, sizeof(*ap)); 359231200Smm if (ap == NULL) 360231200Smm return (NULL); 361231200Smm if (aq == NULL) 362231200Smm acl->acl_head = ap; 363231200Smm else 364231200Smm aq->next = ap; 365231200Smm ap->type = type; 366231200Smm ap->tag = tag; 367231200Smm ap->id = id; 368231200Smm ap->permset = permset; 369231200Smm acl->acl_types |= type; 370231200Smm return (ap); 371231200Smm} 372231200Smm 373231200Smm/* 374231200Smm * Return a count of entries matching "want_type". 375231200Smm */ 376231200Smmint 377231200Smmarchive_acl_count(struct archive_acl *acl, int want_type) 378231200Smm{ 379231200Smm int count; 380231200Smm struct archive_acl_entry *ap; 381231200Smm 382231200Smm count = 0; 383231200Smm ap = acl->acl_head; 384231200Smm while (ap != NULL) { 385231200Smm if ((ap->type & want_type) != 0) 386231200Smm count++; 387231200Smm ap = ap->next; 388231200Smm } 389231200Smm 390231200Smm if (count > 0 && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)) 391231200Smm count += 3; 392231200Smm return (count); 393231200Smm} 394231200Smm 395231200Smm/* 396313570Smm * Return a bitmask of stored ACL types in an ACL list 397313570Smm */ 398313570Smmint 399313570Smmarchive_acl_types(struct archive_acl *acl) 400313570Smm{ 401313570Smm return (acl->acl_types); 402313570Smm} 403313570Smm 404313570Smm/* 405231200Smm * Prepare for reading entries from the ACL data. Returns a count 406231200Smm * of entries matching "want_type", or zero if there are no 407231200Smm * non-extended ACL entries of that type. 408231200Smm */ 409231200Smmint 410231200Smmarchive_acl_reset(struct archive_acl *acl, int want_type) 411231200Smm{ 412231200Smm int count, cutoff; 413231200Smm 414231200Smm count = archive_acl_count(acl, want_type); 415231200Smm 416231200Smm /* 417231200Smm * If the only entries are the three standard ones, 418231200Smm * then don't return any ACL data. (In this case, 419231200Smm * client can just use chmod(2) to set permissions.) 420231200Smm */ 421231200Smm if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) 422231200Smm cutoff = 3; 423231200Smm else 424231200Smm cutoff = 0; 425231200Smm 426231200Smm if (count > cutoff) 427231200Smm acl->acl_state = ARCHIVE_ENTRY_ACL_USER_OBJ; 428231200Smm else 429231200Smm acl->acl_state = 0; 430231200Smm acl->acl_p = acl->acl_head; 431231200Smm return (count); 432231200Smm} 433231200Smm 434231200Smm 435231200Smm/* 436231200Smm * Return the next ACL entry in the list. Fake entries for the 437231200Smm * standard permissions and include them in the returned list. 438231200Smm */ 439231200Smmint 440313570Smmarchive_acl_next(struct archive *a, struct archive_acl *acl, int want_type, 441313570Smm int *type, int *permset, int *tag, int *id, const char **name) 442231200Smm{ 443231200Smm *name = NULL; 444231200Smm *id = -1; 445231200Smm 446231200Smm /* 447231200Smm * The acl_state is either zero (no entries available), -1 448231200Smm * (reading from list), or an entry type (retrieve that type 449231200Smm * from ae_stat.aest_mode). 450231200Smm */ 451231200Smm if (acl->acl_state == 0) 452231200Smm return (ARCHIVE_WARN); 453231200Smm 454231200Smm /* The first three access entries are special. */ 455231200Smm if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { 456231200Smm switch (acl->acl_state) { 457231200Smm case ARCHIVE_ENTRY_ACL_USER_OBJ: 458231200Smm *permset = (acl->mode >> 6) & 7; 459231200Smm *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 460231200Smm *tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 461231200Smm acl->acl_state = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 462231200Smm return (ARCHIVE_OK); 463231200Smm case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 464231200Smm *permset = (acl->mode >> 3) & 7; 465231200Smm *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 466231200Smm *tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 467231200Smm acl->acl_state = ARCHIVE_ENTRY_ACL_OTHER; 468231200Smm return (ARCHIVE_OK); 469231200Smm case ARCHIVE_ENTRY_ACL_OTHER: 470231200Smm *permset = acl->mode & 7; 471231200Smm *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 472231200Smm *tag = ARCHIVE_ENTRY_ACL_OTHER; 473231200Smm acl->acl_state = -1; 474231200Smm acl->acl_p = acl->acl_head; 475231200Smm return (ARCHIVE_OK); 476231200Smm default: 477231200Smm break; 478231200Smm } 479231200Smm } 480231200Smm 481231200Smm while (acl->acl_p != NULL && (acl->acl_p->type & want_type) == 0) 482231200Smm acl->acl_p = acl->acl_p->next; 483231200Smm if (acl->acl_p == NULL) { 484231200Smm acl->acl_state = 0; 485231200Smm *type = 0; 486231200Smm *permset = 0; 487231200Smm *tag = 0; 488231200Smm *id = -1; 489231200Smm *name = NULL; 490231200Smm return (ARCHIVE_EOF); /* End of ACL entries. */ 491231200Smm } 492231200Smm *type = acl->acl_p->type; 493231200Smm *permset = acl->acl_p->permset; 494231200Smm *tag = acl->acl_p->tag; 495231200Smm *id = acl->acl_p->id; 496238856Smm if (archive_mstring_get_mbs(a, &acl->acl_p->name, name) != 0) { 497238856Smm if (errno == ENOMEM) 498238856Smm return (ARCHIVE_FATAL); 499231200Smm *name = NULL; 500238856Smm } 501231200Smm acl->acl_p = acl->acl_p->next; 502231200Smm return (ARCHIVE_OK); 503231200Smm} 504231200Smm 505231200Smm/* 506313570Smm * Determine what type of ACL do we want 507231200Smm */ 508313570Smmstatic int 509313570Smmarchive_acl_text_want_type(struct archive_acl *acl, int flags) 510231200Smm{ 511313570Smm int want_type; 512231200Smm 513313570Smm /* Check if ACL is NFSv4 */ 514313570Smm if ((acl->acl_types & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { 515313570Smm /* NFSv4 should never mix with POSIX.1e */ 516313570Smm if ((acl->acl_types & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) 517313570Smm return (0); 518313570Smm else 519313570Smm return (ARCHIVE_ENTRY_ACL_TYPE_NFS4); 520231200Smm } 521231200Smm 522313570Smm /* Now deal with POSIX.1e ACLs */ 523313570Smm 524313570Smm want_type = 0; 525313570Smm if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) 526313570Smm want_type |= ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 527313570Smm if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) 528313570Smm want_type |= ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; 529313570Smm 530313570Smm /* By default we want both access and default ACLs */ 531313570Smm if (want_type == 0) 532313570Smm return (ARCHIVE_ENTRY_ACL_TYPE_POSIX1E); 533313570Smm 534313570Smm return (want_type); 535313570Smm} 536313570Smm 537313570Smm/* 538313570Smm * Calculate ACL text string length 539313570Smm */ 540313570Smmstatic ssize_t 541313570Smmarchive_acl_text_len(struct archive_acl *acl, int want_type, int flags, 542313570Smm int wide, struct archive *a, struct archive_string_conv *sc) { 543313570Smm struct archive_acl_entry *ap; 544313570Smm const char *name; 545313570Smm const wchar_t *wname; 546313570Smm int count, idlen, tmp, r; 547313570Smm ssize_t length; 548313570Smm size_t len; 549313570Smm 550231200Smm count = 0; 551231200Smm length = 0; 552313570Smm for (ap = acl->acl_head; ap != NULL; ap = ap->next) { 553313570Smm if ((ap->type & want_type) == 0) 554313570Smm continue; 555313570Smm /* 556313570Smm * Filemode-mapping ACL entries are stored exclusively in 557313570Smm * ap->mode so they should not be in the list 558313570Smm */ 559313570Smm if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) 560313570Smm && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ 561313570Smm || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ 562313570Smm || ap->tag == ARCHIVE_ENTRY_ACL_OTHER)) 563313570Smm continue; 564313570Smm count++; 565313570Smm if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0 566313570Smm && (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) 567313570Smm length += 8; /* "default:" */ 568313570Smm switch (ap->tag) { 569313570Smm case ARCHIVE_ENTRY_ACL_USER_OBJ: 570313570Smm if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 571313570Smm length += 6; /* "owner@" */ 572313570Smm break; 573313570Smm } 574313570Smm /* FALLTHROUGH */ 575313570Smm case ARCHIVE_ENTRY_ACL_USER: 576313570Smm case ARCHIVE_ENTRY_ACL_MASK: 577313570Smm length += 4; /* "user", "mask" */ 578313570Smm break; 579313570Smm case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 580313570Smm if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 581313570Smm length += 6; /* "group@" */ 582313570Smm break; 583313570Smm } 584313570Smm /* FALLTHROUGH */ 585313570Smm case ARCHIVE_ENTRY_ACL_GROUP: 586313570Smm case ARCHIVE_ENTRY_ACL_OTHER: 587313570Smm length += 5; /* "group", "other" */ 588313570Smm break; 589313570Smm case ARCHIVE_ENTRY_ACL_EVERYONE: 590313570Smm length += 9; /* "everyone@" */ 591313570Smm break; 592313570Smm } 593313570Smm length += 1; /* colon after tag */ 594313570Smm if (ap->tag == ARCHIVE_ENTRY_ACL_USER || 595313570Smm ap->tag == ARCHIVE_ENTRY_ACL_GROUP) { 596313570Smm if (wide) { 597313570Smm r = archive_mstring_get_wcs(a, &ap->name, 598313570Smm &wname); 599313570Smm if (r == 0 && wname != NULL) 600313570Smm length += wcslen(wname); 601313570Smm else if (r < 0 && errno == ENOMEM) 602313570Smm return (0); 603313570Smm else 604313570Smm length += sizeof(uid_t) * 3 + 1; 605313570Smm } else { 606313570Smm r = archive_mstring_get_mbs_l(&ap->name, &name, 607313570Smm &len, sc); 608313570Smm if (r != 0) 609313570Smm return (0); 610313570Smm if (len > 0 && name != NULL) 611313570Smm length += len; 612313570Smm else 613313570Smm length += sizeof(uid_t) * 3 + 1; 614313570Smm } 615313570Smm length += 1; /* colon after user or group name */ 616313570Smm } else if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) 617313570Smm length += 1; /* 2nd colon empty user,group or other */ 618313570Smm 619313570Smm if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) != 0) 620313570Smm && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) 621313570Smm && (ap->tag == ARCHIVE_ENTRY_ACL_OTHER 622313570Smm || ap->tag == ARCHIVE_ENTRY_ACL_MASK)) { 623313570Smm /* Solaris has no colon after other: and mask: */ 624313570Smm length = length - 1; 625313570Smm } 626313570Smm 627313570Smm if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 628313570Smm /* rwxpdDaARWcCos:fdinSFI:deny */ 629313570Smm length += 27; 630313570Smm if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DENY) == 0) 631313570Smm length += 1; /* allow, alarm, audit */ 632313570Smm } else 633231200Smm length += 3; /* rwx */ 634313570Smm 635313570Smm if ((ap->tag == ARCHIVE_ENTRY_ACL_USER || 636313570Smm ap->tag == ARCHIVE_ENTRY_ACL_GROUP) && 637313570Smm (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) != 0) { 638231200Smm length += 1; /* colon */ 639313570Smm /* ID digit count */ 640313570Smm idlen = 1; 641313570Smm tmp = ap->id; 642313570Smm while (tmp > 9) { 643313570Smm tmp = tmp / 10; 644313570Smm idlen++; 645313570Smm } 646313570Smm length += idlen; 647231200Smm } 648313570Smm length ++; /* entry separator */ 649231200Smm } 650231200Smm 651313570Smm /* Add filemode-mapping access entries to the length */ 652313570Smm if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { 653313570Smm if ((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) != 0) { 654313570Smm /* "user::rwx\ngroup::rwx\nother:rwx\n" */ 655313570Smm length += 31; 656313570Smm } else { 657313570Smm /* "user::rwx\ngroup::rwx\nother::rwx\n" */ 658313570Smm length += 32; 659313570Smm } 660313570Smm } else if (count == 0) 661313570Smm return (0); 662231200Smm 663313570Smm /* The terminating character is included in count */ 664313570Smm return (length); 665313570Smm} 666313570Smm 667313570Smm/* 668313570Smm * Generate a wide text version of the ACL. The flags parameter controls 669313570Smm * the type and style of the generated ACL. 670313570Smm */ 671313570Smmwchar_t * 672313570Smmarchive_acl_to_text_w(struct archive_acl *acl, ssize_t *text_len, int flags, 673313570Smm struct archive *a) 674313570Smm{ 675313570Smm int count; 676313570Smm ssize_t length; 677313570Smm size_t len; 678313570Smm const wchar_t *wname; 679313570Smm const wchar_t *prefix; 680313570Smm wchar_t separator; 681313570Smm struct archive_acl_entry *ap; 682313570Smm int id, r, want_type; 683313570Smm wchar_t *wp, *ws; 684313570Smm 685313570Smm want_type = archive_acl_text_want_type(acl, flags); 686313570Smm 687313570Smm /* Both NFSv4 and POSIX.1 types found */ 688313570Smm if (want_type == 0) 689231200Smm return (NULL); 690231200Smm 691313570Smm if (want_type == ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) 692313570Smm flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT; 693313570Smm 694313570Smm length = archive_acl_text_len(acl, want_type, flags, 1, a, NULL); 695313570Smm 696313570Smm if (length == 0) 697313570Smm return (NULL); 698313570Smm 699313570Smm if (flags & ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA) 700313570Smm separator = L','; 701313570Smm else 702313570Smm separator = L'\n'; 703313570Smm 704231200Smm /* Now, allocate the string and actually populate it. */ 705313570Smm wp = ws = (wchar_t *)malloc(length * sizeof(wchar_t)); 706313570Smm if (wp == NULL) { 707313570Smm if (errno == ENOMEM) 708313570Smm __archive_errx(1, "No memory"); 709238856Smm return (NULL); 710313570Smm } 711231200Smm count = 0; 712313570Smm 713313570Smm if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { 714313570Smm append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 715313570Smm ARCHIVE_ENTRY_ACL_USER_OBJ, flags, NULL, 716231200Smm acl->mode & 0700, -1); 717313570Smm *wp++ = separator; 718313570Smm append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 719313570Smm ARCHIVE_ENTRY_ACL_GROUP_OBJ, flags, NULL, 720231200Smm acl->mode & 0070, -1); 721313570Smm *wp++ = separator; 722313570Smm append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 723313570Smm ARCHIVE_ENTRY_ACL_OTHER, flags, NULL, 724231200Smm acl->mode & 0007, -1); 725231200Smm count += 3; 726231200Smm } 727231200Smm 728313570Smm for (ap = acl->acl_head; ap != NULL; ap = ap->next) { 729313570Smm if ((ap->type & want_type) == 0) 730313570Smm continue; 731313570Smm /* 732313570Smm * Filemode-mapping ACL entries are stored exclusively in 733313570Smm * ap->mode so they should not be in the list 734313570Smm */ 735313570Smm if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) 736313570Smm && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ 737313570Smm || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ 738313570Smm || ap->tag == ARCHIVE_ENTRY_ACL_OTHER)) 739313570Smm continue; 740313570Smm if (ap->type == ARCHIVE_ENTRY_ACL_TYPE_DEFAULT && 741313570Smm (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0) 742231200Smm prefix = L"default:"; 743231200Smm else 744231200Smm prefix = NULL; 745313570Smm r = archive_mstring_get_wcs(a, &ap->name, &wname); 746313570Smm if (r == 0) { 747313570Smm if (count > 0) 748313570Smm *wp++ = separator; 749313570Smm if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) 750313570Smm id = ap->id; 751313570Smm else 752313570Smm id = -1; 753313570Smm append_entry_w(&wp, prefix, ap->type, ap->tag, flags, 754313570Smm wname, ap->permset, id); 755313570Smm count++; 756313570Smm } else if (r < 0 && errno == ENOMEM) 757313570Smm return (NULL); 758231200Smm } 759231200Smm 760313570Smm /* Add terminating character */ 761313570Smm *wp++ = L'\0'; 762313570Smm 763313570Smm len = wcslen(ws); 764313570Smm 765313570Smm if ((ssize_t)len > (length - 1)) 766313570Smm __archive_errx(1, "Buffer overrun"); 767313570Smm 768313570Smm if (text_len != NULL) 769313570Smm *text_len = len; 770313570Smm 771313570Smm return (ws); 772231200Smm} 773231200Smm 774231200Smmstatic void 775231200Smmappend_id_w(wchar_t **wp, int id) 776231200Smm{ 777231200Smm if (id < 0) 778231200Smm id = 0; 779231200Smm if (id > 9) 780231200Smm append_id_w(wp, id / 10); 781231200Smm *(*wp)++ = L"0123456789"[id % 10]; 782231200Smm} 783231200Smm 784231200Smmstatic void 785313570Smmappend_entry_w(wchar_t **wp, const wchar_t *prefix, int type, 786313570Smm int tag, int flags, const wchar_t *wname, int perm, int id) 787231200Smm{ 788313926Smm int i; 789313926Smm 790231200Smm if (prefix != NULL) { 791231200Smm wcscpy(*wp, prefix); 792231200Smm *wp += wcslen(*wp); 793231200Smm } 794231200Smm switch (tag) { 795231200Smm case ARCHIVE_ENTRY_ACL_USER_OBJ: 796231200Smm wname = NULL; 797231200Smm id = -1; 798313570Smm if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { 799313570Smm wcscpy(*wp, L"owner@"); 800313570Smm break; 801313570Smm } 802231200Smm /* FALLTHROUGH */ 803231200Smm case ARCHIVE_ENTRY_ACL_USER: 804231200Smm wcscpy(*wp, L"user"); 805231200Smm break; 806231200Smm case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 807231200Smm wname = NULL; 808231200Smm id = -1; 809313570Smm if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { 810313570Smm wcscpy(*wp, L"group@"); 811313570Smm break; 812313570Smm } 813231200Smm /* FALLTHROUGH */ 814231200Smm case ARCHIVE_ENTRY_ACL_GROUP: 815231200Smm wcscpy(*wp, L"group"); 816231200Smm break; 817231200Smm case ARCHIVE_ENTRY_ACL_MASK: 818231200Smm wcscpy(*wp, L"mask"); 819231200Smm wname = NULL; 820231200Smm id = -1; 821231200Smm break; 822231200Smm case ARCHIVE_ENTRY_ACL_OTHER: 823231200Smm wcscpy(*wp, L"other"); 824231200Smm wname = NULL; 825231200Smm id = -1; 826231200Smm break; 827313570Smm case ARCHIVE_ENTRY_ACL_EVERYONE: 828313570Smm wcscpy(*wp, L"everyone@"); 829313570Smm wname = NULL; 830313570Smm id = -1; 831313570Smm break; 832231200Smm } 833231200Smm *wp += wcslen(*wp); 834231200Smm *(*wp)++ = L':'; 835313570Smm if (((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) || 836313570Smm tag == ARCHIVE_ENTRY_ACL_USER || 837313570Smm tag == ARCHIVE_ENTRY_ACL_GROUP) { 838313570Smm if (wname != NULL) { 839313570Smm wcscpy(*wp, wname); 840313570Smm *wp += wcslen(*wp); 841313570Smm } else if (tag == ARCHIVE_ENTRY_ACL_USER 842313570Smm || tag == ARCHIVE_ENTRY_ACL_GROUP) { 843313570Smm append_id_w(wp, id); 844313570Smm if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0) 845313570Smm id = -1; 846313570Smm } 847313570Smm /* Solaris style has no second colon after other and mask */ 848313570Smm if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) == 0) 849313570Smm || (tag != ARCHIVE_ENTRY_ACL_OTHER 850313570Smm && tag != ARCHIVE_ENTRY_ACL_MASK)) 851313570Smm *(*wp)++ = L':'; 852313570Smm } 853313570Smm if ((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) { 854313570Smm /* POSIX.1e ACL perms */ 855313570Smm *(*wp)++ = (perm & 0444) ? L'r' : L'-'; 856313570Smm *(*wp)++ = (perm & 0222) ? L'w' : L'-'; 857313570Smm *(*wp)++ = (perm & 0111) ? L'x' : L'-'; 858313570Smm } else { 859313926Smm /* NFSv4 ACL perms */ 860313926Smm for (i = 0; i < nfsv4_acl_perm_map_size; i++) { 861313926Smm if (perm & nfsv4_acl_perm_map[i].perm) 862313926Smm *(*wp)++ = nfsv4_acl_perm_map[i].wc; 863313926Smm else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0) 864313926Smm *(*wp)++ = L'-'; 865313926Smm } 866313570Smm *(*wp)++ = L':'; 867313926Smm for (i = 0; i < nfsv4_acl_flag_map_size; i++) { 868313926Smm if (perm & nfsv4_acl_flag_map[i].perm) 869313926Smm *(*wp)++ = nfsv4_acl_flag_map[i].wc; 870313926Smm else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0) 871313926Smm *(*wp)++ = L'-'; 872313926Smm } 873313570Smm *(*wp)++ = L':'; 874313570Smm switch (type) { 875313570Smm case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: 876313570Smm wcscpy(*wp, L"allow"); 877313570Smm break; 878313570Smm case ARCHIVE_ENTRY_ACL_TYPE_DENY: 879313570Smm wcscpy(*wp, L"deny"); 880313570Smm break; 881313570Smm case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: 882313570Smm wcscpy(*wp, L"audit"); 883313570Smm break; 884313570Smm case ARCHIVE_ENTRY_ACL_TYPE_ALARM: 885313570Smm wcscpy(*wp, L"alarm"); 886313570Smm break; 887313570Smm default: 888313570Smm break; 889313570Smm } 890231200Smm *wp += wcslen(*wp); 891231200Smm } 892231200Smm if (id != -1) { 893231200Smm *(*wp)++ = L':'; 894231200Smm append_id_w(wp, id); 895231200Smm } 896231200Smm} 897231200Smm 898313570Smm/* 899313570Smm * Generate a text version of the ACL. The flags parameter controls 900313570Smm * the type and style of the generated ACL. 901313570Smm */ 902313570Smmchar * 903313570Smmarchive_acl_to_text_l(struct archive_acl *acl, ssize_t *text_len, int flags, 904231200Smm struct archive_string_conv *sc) 905231200Smm{ 906231200Smm int count; 907313570Smm ssize_t length; 908313570Smm size_t len; 909231200Smm const char *name; 910231200Smm const char *prefix; 911231200Smm char separator; 912231200Smm struct archive_acl_entry *ap; 913313570Smm int id, r, want_type; 914313570Smm char *p, *s; 915231200Smm 916313570Smm want_type = archive_acl_text_want_type(acl, flags); 917231200Smm 918313570Smm /* Both NFSv4 and POSIX.1 types found */ 919313570Smm if (want_type == 0) 920313570Smm return (NULL); 921231200Smm 922313570Smm if (want_type == ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) 923313570Smm flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT; 924231200Smm 925313570Smm length = archive_acl_text_len(acl, want_type, flags, 0, NULL, sc); 926231200Smm 927313570Smm if (length == 0) 928313570Smm return (NULL); 929313570Smm 930313570Smm if (flags & ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA) 931313570Smm separator = ','; 932313570Smm else 933313570Smm separator = '\n'; 934313570Smm 935231200Smm /* Now, allocate the string and actually populate it. */ 936313570Smm p = s = (char *)malloc(length * sizeof(char)); 937313570Smm if (p == NULL) { 938313570Smm if (errno == ENOMEM) 939313570Smm __archive_errx(1, "No memory"); 940313570Smm return (NULL); 941313570Smm } 942231200Smm count = 0; 943313570Smm 944313570Smm if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { 945313570Smm append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 946313570Smm ARCHIVE_ENTRY_ACL_USER_OBJ, flags, NULL, 947231200Smm acl->mode & 0700, -1); 948313570Smm *p++ = separator; 949313570Smm append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 950313570Smm ARCHIVE_ENTRY_ACL_GROUP_OBJ, flags, NULL, 951231200Smm acl->mode & 0070, -1); 952313570Smm *p++ = separator; 953313570Smm append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 954313570Smm ARCHIVE_ENTRY_ACL_OTHER, flags, NULL, 955231200Smm acl->mode & 0007, -1); 956231200Smm count += 3; 957231200Smm } 958231200Smm 959313570Smm for (ap = acl->acl_head; ap != NULL; ap = ap->next) { 960313570Smm if ((ap->type & want_type) == 0) 961313570Smm continue; 962313570Smm /* 963313570Smm * Filemode-mapping ACL entries are stored exclusively in 964313570Smm * ap->mode so they should not be in the list 965313570Smm */ 966313570Smm if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) 967313570Smm && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ 968313570Smm || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ 969313570Smm || ap->tag == ARCHIVE_ENTRY_ACL_OTHER)) 970313570Smm continue; 971313570Smm if (ap->type == ARCHIVE_ENTRY_ACL_TYPE_DEFAULT && 972313570Smm (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0) 973231200Smm prefix = "default:"; 974231200Smm else 975231200Smm prefix = NULL; 976313570Smm r = archive_mstring_get_mbs_l( 977313570Smm &ap->name, &name, &len, sc); 978313570Smm if (r != 0) 979313570Smm return (NULL); 980313570Smm if (count > 0) 981313570Smm *p++ = separator; 982313570Smm if (name == NULL || 983313570Smm (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)) { 984313570Smm id = ap->id; 985313570Smm } else { 986313570Smm id = -1; 987231200Smm } 988313570Smm append_entry(&p, prefix, ap->type, ap->tag, flags, name, 989313570Smm ap->permset, id); 990313570Smm count++; 991231200Smm } 992231200Smm 993313570Smm /* Add terminating character */ 994313570Smm *p++ = '\0'; 995313570Smm 996313570Smm len = strlen(s); 997313570Smm 998313570Smm if ((ssize_t)len > (length - 1)) 999313570Smm __archive_errx(1, "Buffer overrun"); 1000313570Smm 1001313570Smm if (text_len != NULL) 1002313570Smm *text_len = len; 1003313570Smm 1004313570Smm return (s); 1005231200Smm} 1006231200Smm 1007231200Smmstatic void 1008231200Smmappend_id(char **p, int id) 1009231200Smm{ 1010231200Smm if (id < 0) 1011231200Smm id = 0; 1012231200Smm if (id > 9) 1013231200Smm append_id(p, id / 10); 1014231200Smm *(*p)++ = "0123456789"[id % 10]; 1015231200Smm} 1016231200Smm 1017231200Smmstatic void 1018313570Smmappend_entry(char **p, const char *prefix, int type, 1019313570Smm int tag, int flags, const char *name, int perm, int id) 1020231200Smm{ 1021313926Smm int i; 1022313926Smm 1023231200Smm if (prefix != NULL) { 1024231200Smm strcpy(*p, prefix); 1025231200Smm *p += strlen(*p); 1026231200Smm } 1027231200Smm switch (tag) { 1028231200Smm case ARCHIVE_ENTRY_ACL_USER_OBJ: 1029231200Smm name = NULL; 1030231200Smm id = -1; 1031313570Smm if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { 1032313570Smm strcpy(*p, "owner@"); 1033313570Smm break; 1034313570Smm } 1035231200Smm /* FALLTHROUGH */ 1036231200Smm case ARCHIVE_ENTRY_ACL_USER: 1037231200Smm strcpy(*p, "user"); 1038231200Smm break; 1039231200Smm case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 1040231200Smm name = NULL; 1041231200Smm id = -1; 1042313570Smm if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { 1043313570Smm strcpy(*p, "group@"); 1044313570Smm break; 1045313570Smm } 1046231200Smm /* FALLTHROUGH */ 1047231200Smm case ARCHIVE_ENTRY_ACL_GROUP: 1048231200Smm strcpy(*p, "group"); 1049231200Smm break; 1050231200Smm case ARCHIVE_ENTRY_ACL_MASK: 1051231200Smm strcpy(*p, "mask"); 1052231200Smm name = NULL; 1053231200Smm id = -1; 1054231200Smm break; 1055231200Smm case ARCHIVE_ENTRY_ACL_OTHER: 1056231200Smm strcpy(*p, "other"); 1057231200Smm name = NULL; 1058231200Smm id = -1; 1059231200Smm break; 1060313570Smm case ARCHIVE_ENTRY_ACL_EVERYONE: 1061313570Smm strcpy(*p, "everyone@"); 1062313570Smm name = NULL; 1063313570Smm id = -1; 1064313570Smm break; 1065231200Smm } 1066231200Smm *p += strlen(*p); 1067231200Smm *(*p)++ = ':'; 1068313570Smm if (((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) || 1069313570Smm tag == ARCHIVE_ENTRY_ACL_USER || 1070313570Smm tag == ARCHIVE_ENTRY_ACL_GROUP) { 1071313570Smm if (name != NULL) { 1072313570Smm strcpy(*p, name); 1073313570Smm *p += strlen(*p); 1074313570Smm } else if (tag == ARCHIVE_ENTRY_ACL_USER 1075313570Smm || tag == ARCHIVE_ENTRY_ACL_GROUP) { 1076313570Smm append_id(p, id); 1077313570Smm if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0) 1078313570Smm id = -1; 1079313570Smm } 1080313570Smm /* Solaris style has no second colon after other and mask */ 1081313570Smm if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) == 0) 1082313570Smm || (tag != ARCHIVE_ENTRY_ACL_OTHER 1083313570Smm && tag != ARCHIVE_ENTRY_ACL_MASK)) 1084313570Smm *(*p)++ = ':'; 1085313570Smm } 1086313570Smm if ((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) { 1087313570Smm /* POSIX.1e ACL perms */ 1088313570Smm *(*p)++ = (perm & 0444) ? 'r' : '-'; 1089313570Smm *(*p)++ = (perm & 0222) ? 'w' : '-'; 1090313570Smm *(*p)++ = (perm & 0111) ? 'x' : '-'; 1091313570Smm } else { 1092313926Smm /* NFSv4 ACL perms */ 1093313926Smm for (i = 0; i < nfsv4_acl_perm_map_size; i++) { 1094313926Smm if (perm & nfsv4_acl_perm_map[i].perm) 1095313926Smm *(*p)++ = nfsv4_acl_perm_map[i].c; 1096313926Smm else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0) 1097313926Smm *(*p)++ = '-'; 1098313926Smm } 1099313570Smm *(*p)++ = ':'; 1100313926Smm for (i = 0; i < nfsv4_acl_flag_map_size; i++) { 1101313926Smm if (perm & nfsv4_acl_flag_map[i].perm) 1102313926Smm *(*p)++ = nfsv4_acl_flag_map[i].c; 1103313926Smm else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0) 1104313926Smm *(*p)++ = '-'; 1105313926Smm } 1106313570Smm *(*p)++ = ':'; 1107313570Smm switch (type) { 1108313570Smm case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: 1109313570Smm strcpy(*p, "allow"); 1110313570Smm break; 1111313570Smm case ARCHIVE_ENTRY_ACL_TYPE_DENY: 1112313570Smm strcpy(*p, "deny"); 1113313570Smm break; 1114313570Smm case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: 1115313570Smm strcpy(*p, "audit"); 1116313570Smm break; 1117313570Smm case ARCHIVE_ENTRY_ACL_TYPE_ALARM: 1118313570Smm strcpy(*p, "alarm"); 1119313570Smm break; 1120313570Smm } 1121231200Smm *p += strlen(*p); 1122231200Smm } 1123231200Smm if (id != -1) { 1124231200Smm *(*p)++ = ':'; 1125231200Smm append_id(p, id); 1126231200Smm } 1127231200Smm} 1128231200Smm 1129231200Smm/* 1130313570Smm * Parse a wide ACL text string. 1131313570Smm * 1132313570Smm * The want_type argument may be one of the following: 1133313570Smm * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - text is a POSIX.1e ACL of type ACCESS 1134313570Smm * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - text is a POSIX.1e ACL of type DEFAULT 1135313570Smm * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - text is as a NFSv4 ACL 1136313570Smm * 1137313570Smm * POSIX.1e ACL entries prefixed with "default:" are treated as 1138313570Smm * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT unless type is ARCHIVE_ENTRY_ACL_TYPE_NFS4 1139231200Smm */ 1140231200Smmint 1141313570Smmarchive_acl_from_text_w(struct archive_acl *acl, const wchar_t *text, 1142313570Smm int want_type) 1143231200Smm{ 1144231200Smm struct { 1145231200Smm const wchar_t *start; 1146231200Smm const wchar_t *end; 1147313570Smm } field[6], name; 1148231200Smm 1149313570Smm const wchar_t *s, *st; 1150313570Smm 1151313570Smm int numfields, fields, n, r, sol, ret; 1152313570Smm int type, types, tag, permset, id; 1153313570Smm size_t len; 1154231200Smm wchar_t sep; 1155231200Smm 1156313570Smm ret = ARCHIVE_OK; 1157313570Smm types = 0; 1158313570Smm 1159313570Smm switch (want_type) { 1160313570Smm case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E: 1161313570Smm want_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 1162328827Smm __LA_FALLTHROUGH; 1163313570Smm case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: 1164313570Smm case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: 1165313570Smm numfields = 5; 1166313570Smm break; 1167313570Smm case ARCHIVE_ENTRY_ACL_TYPE_NFS4: 1168313570Smm numfields = 6; 1169313570Smm break; 1170313570Smm default: 1171313570Smm return (ARCHIVE_FATAL); 1172313570Smm } 1173313570Smm 1174313570Smm while (text != NULL && *text != L'\0') { 1175231200Smm /* 1176231200Smm * Parse the fields out of the next entry, 1177231200Smm * advance 'text' to start of next entry. 1178231200Smm */ 1179231200Smm fields = 0; 1180231200Smm do { 1181231200Smm const wchar_t *start, *end; 1182231200Smm next_field_w(&text, &start, &end, &sep); 1183313570Smm if (fields < numfields) { 1184231200Smm field[fields].start = start; 1185231200Smm field[fields].end = end; 1186231200Smm } 1187231200Smm ++fields; 1188231200Smm } while (sep == L':'); 1189231200Smm 1190231200Smm /* Set remaining fields to blank. */ 1191313570Smm for (n = fields; n < numfields; ++n) 1192231200Smm field[n].start = field[n].end = NULL; 1193231200Smm 1194313570Smm if (field[0].start != NULL && *(field[0].start) == L'#') { 1195313570Smm /* Comment, skip entry */ 1196313570Smm continue; 1197313570Smm } 1198313570Smm 1199313570Smm n = 0; 1200313570Smm sol = 0; 1201231200Smm id = -1; 1202313570Smm permset = 0; 1203313570Smm name.start = name.end = NULL; 1204231200Smm 1205313570Smm if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 1206313570Smm /* POSIX.1e ACLs */ 1207313570Smm /* 1208313570Smm * Default keyword "default:user::rwx" 1209313570Smm * if found, we have one more field 1210313570Smm * 1211313570Smm * We also support old Solaris extension: 1212313570Smm * "defaultuser::rwx" is the default ACL corresponding 1213313570Smm * to "user::rwx", etc. valid only for first field 1214313570Smm */ 1215313570Smm s = field[0].start; 1216313570Smm len = field[0].end - field[0].start; 1217313570Smm if (*s == L'd' && (len == 1 || (len >= 7 1218313570Smm && wmemcmp((s + 1), L"efault", 6) == 0))) { 1219313570Smm type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; 1220313570Smm if (len > 7) 1221313570Smm field[0].start += 7; 1222313570Smm else 1223313570Smm n = 1; 1224313570Smm } else 1225313570Smm type = want_type; 1226231200Smm 1227313570Smm /* Check for a numeric ID in field n+1 or n+3. */ 1228313570Smm isint_w(field[n + 1].start, field[n + 1].end, &id); 1229313570Smm /* Field n+3 is optional. */ 1230313570Smm if (id == -1 && fields > n+3) 1231313570Smm isint_w(field[n + 3].start, field[n + 3].end, 1232313570Smm &id); 1233313570Smm 1234313570Smm tag = 0; 1235313570Smm s = field[n].start; 1236313570Smm st = field[n].start + 1; 1237313570Smm len = field[n].end - field[n].start; 1238313570Smm 1239313570Smm switch (*s) { 1240313570Smm case L'u': 1241313570Smm if (len == 1 || (len == 4 1242313570Smm && wmemcmp(st, L"ser", 3) == 0)) 1243313570Smm tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 1244313570Smm break; 1245313570Smm case L'g': 1246313570Smm if (len == 1 || (len == 5 1247313570Smm && wmemcmp(st, L"roup", 4) == 0)) 1248313570Smm tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 1249313570Smm break; 1250313570Smm case L'o': 1251313570Smm if (len == 1 || (len == 5 1252313570Smm && wmemcmp(st, L"ther", 4) == 0)) 1253313570Smm tag = ARCHIVE_ENTRY_ACL_OTHER; 1254313570Smm break; 1255313570Smm case L'm': 1256313570Smm if (len == 1 || (len == 4 1257313570Smm && wmemcmp(st, L"ask", 3) == 0)) 1258313570Smm tag = ARCHIVE_ENTRY_ACL_MASK; 1259313570Smm break; 1260313570Smm default: 1261313570Smm break; 1262313570Smm } 1263313570Smm 1264313570Smm switch (tag) { 1265313570Smm case ARCHIVE_ENTRY_ACL_OTHER: 1266313570Smm case ARCHIVE_ENTRY_ACL_MASK: 1267313570Smm if (fields == (n + 2) 1268313570Smm && field[n + 1].start < field[n + 1].end 1269313570Smm && ismode_w(field[n + 1].start, 1270313570Smm field[n + 1].end, &permset)) { 1271313570Smm /* This is Solaris-style "other:rwx" */ 1272313570Smm sol = 1; 1273313570Smm } else if (fields == (n + 3) && 1274313570Smm field[n + 1].start < field[n + 1].end) { 1275313570Smm /* Invalid mask or other field */ 1276313570Smm ret = ARCHIVE_WARN; 1277313570Smm continue; 1278313570Smm } 1279313570Smm break; 1280313570Smm case ARCHIVE_ENTRY_ACL_USER_OBJ: 1281313570Smm case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 1282313570Smm if (id != -1 || 1283313570Smm field[n + 1].start < field[n + 1].end) { 1284313570Smm name = field[n + 1]; 1285313570Smm if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) 1286313570Smm tag = ARCHIVE_ENTRY_ACL_USER; 1287313570Smm else 1288313570Smm tag = ARCHIVE_ENTRY_ACL_GROUP; 1289313570Smm } 1290313570Smm break; 1291313570Smm default: 1292313570Smm /* Invalid tag, skip entry */ 1293313570Smm ret = ARCHIVE_WARN; 1294313570Smm continue; 1295313570Smm } 1296313570Smm 1297313570Smm /* 1298313570Smm * Without "default:" we expect mode in field 2 1299313570Smm * Exception: Solaris other and mask fields 1300313570Smm */ 1301313570Smm if (permset == 0 && !ismode_w(field[n + 2 - sol].start, 1302313570Smm field[n + 2 - sol].end, &permset)) { 1303313570Smm /* Invalid mode, skip entry */ 1304313570Smm ret = ARCHIVE_WARN; 1305313570Smm continue; 1306313570Smm } 1307313570Smm } else { 1308313570Smm /* NFS4 ACLs */ 1309313570Smm s = field[0].start; 1310313570Smm len = field[0].end - field[0].start; 1311313570Smm tag = 0; 1312313570Smm 1313313570Smm switch (len) { 1314313570Smm case 4: 1315313570Smm if (wmemcmp(s, L"user", 4) == 0) 1316313570Smm tag = ARCHIVE_ENTRY_ACL_USER; 1317313570Smm break; 1318313570Smm case 5: 1319313570Smm if (wmemcmp(s, L"group", 5) == 0) 1320313570Smm tag = ARCHIVE_ENTRY_ACL_GROUP; 1321313570Smm break; 1322313570Smm case 6: 1323313570Smm if (wmemcmp(s, L"owner@", 6) == 0) 1324313570Smm tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 1325313570Smm else if (wmemcmp(s, L"group@", len) == 0) 1326313570Smm tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 1327313570Smm break; 1328313570Smm case 9: 1329313570Smm if (wmemcmp(s, L"everyone@", 9) == 0) 1330313570Smm tag = ARCHIVE_ENTRY_ACL_EVERYONE; 1331313570Smm default: 1332313570Smm break; 1333313570Smm } 1334313570Smm 1335313570Smm if (tag == 0) { 1336313570Smm /* Invalid tag, skip entry */ 1337313570Smm ret = ARCHIVE_WARN; 1338313570Smm continue; 1339313570Smm } else if (tag == ARCHIVE_ENTRY_ACL_USER || 1340313570Smm tag == ARCHIVE_ENTRY_ACL_GROUP) { 1341313570Smm n = 1; 1342231200Smm name = field[1]; 1343313570Smm isint_w(name.start, name.end, &id); 1344231200Smm } else 1345313570Smm n = 0; 1346231200Smm 1347313570Smm if (!is_nfs4_perms_w(field[1 + n].start, 1348313570Smm field[1 + n].end, &permset)) { 1349313570Smm /* Invalid NFSv4 perms, skip entry */ 1350313570Smm ret = ARCHIVE_WARN; 1351313570Smm continue; 1352313570Smm } 1353313570Smm if (!is_nfs4_flags_w(field[2 + n].start, 1354313570Smm field[2 + n].end, &permset)) { 1355313570Smm /* Invalid NFSv4 flags, skip entry */ 1356313570Smm ret = ARCHIVE_WARN; 1357313570Smm continue; 1358313570Smm } 1359313570Smm s = field[3 + n].start; 1360313570Smm len = field[3 + n].end - field[3 + n].start; 1361313570Smm type = 0; 1362313570Smm if (len == 4) { 1363313570Smm if (wmemcmp(s, L"deny", 4) == 0) 1364313570Smm type = ARCHIVE_ENTRY_ACL_TYPE_DENY; 1365313570Smm } else if (len == 5) { 1366313570Smm if (wmemcmp(s, L"allow", 5) == 0) 1367313570Smm type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; 1368313570Smm else if (wmemcmp(s, L"audit", 5) == 0) 1369313570Smm type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT; 1370313570Smm else if (wmemcmp(s, L"alarm", 5) == 0) 1371313570Smm type = ARCHIVE_ENTRY_ACL_TYPE_ALARM; 1372313570Smm } 1373313570Smm if (type == 0) { 1374313570Smm /* Invalid entry type, skip entry */ 1375313570Smm ret = ARCHIVE_WARN; 1376313570Smm continue; 1377313570Smm } 1378313570Smm isint_w(field[4 + n].start, field[4 + n].end, &id); 1379313570Smm } 1380313570Smm 1381231200Smm /* Add entry to the internal list. */ 1382313570Smm r = archive_acl_add_entry_w_len(acl, type, permset, 1383231200Smm tag, id, name.start, name.end - name.start); 1384313570Smm if (r < ARCHIVE_WARN) 1385313570Smm return (r); 1386313570Smm if (r != ARCHIVE_OK) 1387313570Smm ret = ARCHIVE_WARN; 1388313570Smm types |= type; 1389231200Smm } 1390313570Smm 1391313570Smm /* Reset ACL */ 1392313570Smm archive_acl_reset(acl, types); 1393313570Smm 1394313570Smm return (ret); 1395231200Smm} 1396231200Smm 1397231200Smm/* 1398231200Smm * Parse a string to a positive decimal integer. Returns true if 1399231200Smm * the string is non-empty and consists only of decimal digits, 1400231200Smm * false otherwise. 1401231200Smm */ 1402231200Smmstatic int 1403231200Smmisint_w(const wchar_t *start, const wchar_t *end, int *result) 1404231200Smm{ 1405231200Smm int n = 0; 1406231200Smm if (start >= end) 1407231200Smm return (0); 1408231200Smm while (start < end) { 1409231200Smm if (*start < '0' || *start > '9') 1410231200Smm return (0); 1411231200Smm if (n > (INT_MAX / 10) || 1412231200Smm (n == INT_MAX / 10 && (*start - '0') > INT_MAX % 10)) { 1413231200Smm n = INT_MAX; 1414231200Smm } else { 1415231200Smm n *= 10; 1416231200Smm n += *start - '0'; 1417231200Smm } 1418231200Smm start++; 1419231200Smm } 1420231200Smm *result = n; 1421231200Smm return (1); 1422231200Smm} 1423231200Smm 1424231200Smm/* 1425231200Smm * Parse a string as a mode field. Returns true if 1426231200Smm * the string is non-empty and consists only of mode characters, 1427231200Smm * false otherwise. 1428231200Smm */ 1429231200Smmstatic int 1430231200Smmismode_w(const wchar_t *start, const wchar_t *end, int *permset) 1431231200Smm{ 1432231200Smm const wchar_t *p; 1433231200Smm 1434231200Smm if (start >= end) 1435231200Smm return (0); 1436231200Smm p = start; 1437231200Smm *permset = 0; 1438231200Smm while (p < end) { 1439231200Smm switch (*p++) { 1440313570Smm case L'r': case L'R': 1441231200Smm *permset |= ARCHIVE_ENTRY_ACL_READ; 1442231200Smm break; 1443313570Smm case L'w': case L'W': 1444231200Smm *permset |= ARCHIVE_ENTRY_ACL_WRITE; 1445231200Smm break; 1446313570Smm case L'x': case L'X': 1447231200Smm *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; 1448231200Smm break; 1449313570Smm case L'-': 1450231200Smm break; 1451231200Smm default: 1452231200Smm return (0); 1453231200Smm } 1454231200Smm } 1455231200Smm return (1); 1456231200Smm} 1457231200Smm 1458231200Smm/* 1459313570Smm * Parse a string as a NFS4 ACL permission field. 1460313570Smm * Returns true if the string is non-empty and consists only of NFS4 ACL 1461313570Smm * permission characters, false otherwise 1462313570Smm */ 1463313570Smmstatic int 1464313570Smmis_nfs4_perms_w(const wchar_t *start, const wchar_t *end, int *permset) 1465313570Smm{ 1466313926Smm const wchar_t *p = start; 1467313570Smm 1468313570Smm while (p < end) { 1469313570Smm switch (*p++) { 1470313570Smm case L'r': 1471313570Smm *permset |= ARCHIVE_ENTRY_ACL_READ_DATA; 1472313570Smm break; 1473313570Smm case L'w': 1474313570Smm *permset |= ARCHIVE_ENTRY_ACL_WRITE_DATA; 1475313570Smm break; 1476313570Smm case L'x': 1477313570Smm *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; 1478313570Smm break; 1479313570Smm case L'p': 1480313570Smm *permset |= ARCHIVE_ENTRY_ACL_APPEND_DATA; 1481313570Smm break; 1482313570Smm case L'D': 1483313570Smm *permset |= ARCHIVE_ENTRY_ACL_DELETE_CHILD; 1484313570Smm break; 1485313570Smm case L'd': 1486313570Smm *permset |= ARCHIVE_ENTRY_ACL_DELETE; 1487313570Smm break; 1488313570Smm case L'a': 1489313570Smm *permset |= ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES; 1490313570Smm break; 1491313570Smm case L'A': 1492313570Smm *permset |= ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES; 1493313570Smm break; 1494313570Smm case L'R': 1495313570Smm *permset |= ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS; 1496313570Smm break; 1497313570Smm case L'W': 1498313570Smm *permset |= ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS; 1499313570Smm break; 1500313570Smm case L'c': 1501313570Smm *permset |= ARCHIVE_ENTRY_ACL_READ_ACL; 1502313570Smm break; 1503313570Smm case L'C': 1504313570Smm *permset |= ARCHIVE_ENTRY_ACL_WRITE_ACL; 1505313570Smm break; 1506313570Smm case L'o': 1507313570Smm *permset |= ARCHIVE_ENTRY_ACL_WRITE_OWNER; 1508313570Smm break; 1509313570Smm case L's': 1510313570Smm *permset |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE; 1511313570Smm break; 1512313570Smm case L'-': 1513313570Smm break; 1514313570Smm default: 1515313570Smm return(0); 1516313570Smm } 1517313570Smm } 1518313570Smm return (1); 1519313570Smm} 1520313570Smm 1521313570Smm/* 1522313570Smm * Parse a string as a NFS4 ACL flags field. 1523313570Smm * Returns true if the string is non-empty and consists only of NFS4 ACL 1524313570Smm * flag characters, false otherwise 1525313570Smm */ 1526313570Smmstatic int 1527313570Smmis_nfs4_flags_w(const wchar_t *start, const wchar_t *end, int *permset) 1528313570Smm{ 1529313926Smm const wchar_t *p = start; 1530313570Smm 1531313570Smm while (p < end) { 1532313570Smm switch(*p++) { 1533313570Smm case L'f': 1534313570Smm *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT; 1535313570Smm break; 1536313570Smm case L'd': 1537313570Smm *permset |= ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT; 1538313570Smm break; 1539313570Smm case L'i': 1540313570Smm *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY; 1541313570Smm break; 1542313570Smm case L'n': 1543313570Smm *permset |= 1544313570Smm ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT; 1545313570Smm break; 1546313570Smm case L'S': 1547313570Smm *permset |= ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS; 1548313570Smm break; 1549313570Smm case L'F': 1550313570Smm *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS; 1551313570Smm break; 1552313570Smm case L'I': 1553313570Smm *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERITED; 1554313570Smm break; 1555313570Smm case L'-': 1556313570Smm break; 1557313570Smm default: 1558313570Smm return (0); 1559313570Smm } 1560313570Smm } 1561313570Smm return (1); 1562313570Smm} 1563313570Smm 1564313570Smm/* 1565231200Smm * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]". *wp is updated 1566231200Smm * to point to just after the separator. *start points to the first 1567231200Smm * character of the matched text and *end just after the last 1568231200Smm * character of the matched identifier. In particular *end - *start 1569231200Smm * is the length of the field body, not including leading or trailing 1570231200Smm * whitespace. 1571231200Smm */ 1572231200Smmstatic void 1573231200Smmnext_field_w(const wchar_t **wp, const wchar_t **start, 1574231200Smm const wchar_t **end, wchar_t *sep) 1575231200Smm{ 1576231200Smm /* Skip leading whitespace to find start of field. */ 1577231200Smm while (**wp == L' ' || **wp == L'\t' || **wp == L'\n') { 1578231200Smm (*wp)++; 1579231200Smm } 1580231200Smm *start = *wp; 1581231200Smm 1582231200Smm /* Scan for the separator. */ 1583231200Smm while (**wp != L'\0' && **wp != L',' && **wp != L':' && 1584231200Smm **wp != L'\n') { 1585231200Smm (*wp)++; 1586231200Smm } 1587231200Smm *sep = **wp; 1588231200Smm 1589231200Smm /* Trim trailing whitespace to locate end of field. */ 1590231200Smm *end = *wp - 1; 1591231200Smm while (**end == L' ' || **end == L'\t' || **end == L'\n') { 1592231200Smm (*end)--; 1593231200Smm } 1594231200Smm (*end)++; 1595231200Smm 1596231200Smm /* Adjust scanner location. */ 1597231200Smm if (**wp != L'\0') 1598231200Smm (*wp)++; 1599231200Smm} 1600231200Smm 1601231200Smm/* 1602313570Smm * Parse an ACL text string. 1603313570Smm * 1604313570Smm * The want_type argument may be one of the following: 1605313570Smm * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - text is a POSIX.1e ACL of type ACCESS 1606313570Smm * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - text is a POSIX.1e ACL of type DEFAULT 1607313570Smm * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - text is as a NFSv4 ACL 1608313570Smm * 1609313570Smm * POSIX.1e ACL entries prefixed with "default:" are treated as 1610313570Smm * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT unless type is ARCHIVE_ENTRY_ACL_TYPE_NFS4 1611231200Smm */ 1612231200Smmint 1613313570Smmarchive_acl_from_text_l(struct archive_acl *acl, const char *text, 1614313570Smm int want_type, struct archive_string_conv *sc) 1615231200Smm{ 1616231200Smm struct { 1617231200Smm const char *start; 1618231200Smm const char *end; 1619313570Smm } field[6], name; 1620231200Smm 1621313570Smm const char *s, *st; 1622313570Smm int numfields, fields, n, r, sol, ret; 1623313570Smm int type, types, tag, permset, id; 1624313570Smm size_t len; 1625231200Smm char sep; 1626231200Smm 1627313570Smm switch (want_type) { 1628313570Smm case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E: 1629313570Smm want_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 1630328827Smm __LA_FALLTHROUGH; 1631313570Smm case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: 1632313570Smm case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: 1633313570Smm numfields = 5; 1634313570Smm break; 1635313570Smm case ARCHIVE_ENTRY_ACL_TYPE_NFS4: 1636313570Smm numfields = 6; 1637313570Smm break; 1638313570Smm default: 1639313570Smm return (ARCHIVE_FATAL); 1640313570Smm } 1641313570Smm 1642313570Smm ret = ARCHIVE_OK; 1643313570Smm types = 0; 1644313570Smm 1645231200Smm while (text != NULL && *text != '\0') { 1646231200Smm /* 1647231200Smm * Parse the fields out of the next entry, 1648231200Smm * advance 'text' to start of next entry. 1649231200Smm */ 1650231200Smm fields = 0; 1651231200Smm do { 1652231200Smm const char *start, *end; 1653231200Smm next_field(&text, &start, &end, &sep); 1654313570Smm if (fields < numfields) { 1655231200Smm field[fields].start = start; 1656231200Smm field[fields].end = end; 1657231200Smm } 1658231200Smm ++fields; 1659231200Smm } while (sep == ':'); 1660231200Smm 1661231200Smm /* Set remaining fields to blank. */ 1662313570Smm for (n = fields; n < numfields; ++n) 1663231200Smm field[n].start = field[n].end = NULL; 1664231200Smm 1665313570Smm if (field[0].start != NULL && *(field[0].start) == '#') { 1666313570Smm /* Comment, skip entry */ 1667313570Smm continue; 1668313570Smm } 1669313570Smm 1670313570Smm n = 0; 1671313570Smm sol = 0; 1672231200Smm id = -1; 1673313570Smm permset = 0; 1674313570Smm name.start = name.end = NULL; 1675231200Smm 1676313570Smm if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 1677313570Smm /* POSIX.1e ACLs */ 1678313570Smm /* 1679313570Smm * Default keyword "default:user::rwx" 1680313570Smm * if found, we have one more field 1681313570Smm * 1682313570Smm * We also support old Solaris extension: 1683313570Smm * "defaultuser::rwx" is the default ACL corresponding 1684313570Smm * to "user::rwx", etc. valid only for first field 1685313570Smm */ 1686313570Smm s = field[0].start; 1687313570Smm len = field[0].end - field[0].start; 1688313570Smm if (*s == 'd' && (len == 1 || (len >= 7 1689313570Smm && memcmp((s + 1), "efault", 6) == 0))) { 1690313570Smm type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; 1691313570Smm if (len > 7) 1692313570Smm field[0].start += 7; 1693313570Smm else 1694313570Smm n = 1; 1695313570Smm } else 1696313570Smm type = want_type; 1697231200Smm 1698313570Smm /* Check for a numeric ID in field n+1 or n+3. */ 1699313570Smm isint(field[n + 1].start, field[n + 1].end, &id); 1700313570Smm /* Field n+3 is optional. */ 1701313570Smm if (id == -1 && fields > (n + 3)) 1702313570Smm isint(field[n + 3].start, field[n + 3].end, 1703313570Smm &id); 1704313570Smm 1705313570Smm tag = 0; 1706313570Smm s = field[n].start; 1707313570Smm st = field[n].start + 1; 1708313570Smm len = field[n].end - field[n].start; 1709313570Smm 1710313570Smm switch (*s) { 1711313570Smm case 'u': 1712313570Smm if (len == 1 || (len == 4 1713313570Smm && memcmp(st, "ser", 3) == 0)) 1714313570Smm tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 1715313570Smm break; 1716313570Smm case 'g': 1717313570Smm if (len == 1 || (len == 5 1718313570Smm && memcmp(st, "roup", 4) == 0)) 1719313570Smm tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 1720313570Smm break; 1721313570Smm case 'o': 1722313570Smm if (len == 1 || (len == 5 1723313570Smm && memcmp(st, "ther", 4) == 0)) 1724313570Smm tag = ARCHIVE_ENTRY_ACL_OTHER; 1725313570Smm break; 1726313570Smm case 'm': 1727313570Smm if (len == 1 || (len == 4 1728313570Smm && memcmp(st, "ask", 3) == 0)) 1729313570Smm tag = ARCHIVE_ENTRY_ACL_MASK; 1730313570Smm break; 1731313570Smm default: 1732313570Smm break; 1733313570Smm } 1734313570Smm 1735313570Smm switch (tag) { 1736313570Smm case ARCHIVE_ENTRY_ACL_OTHER: 1737313570Smm case ARCHIVE_ENTRY_ACL_MASK: 1738313570Smm if (fields == (n + 2) 1739313570Smm && field[n + 1].start < field[n + 1].end 1740313570Smm && ismode(field[n + 1].start, 1741313570Smm field[n + 1].end, &permset)) { 1742313570Smm /* This is Solaris-style "other:rwx" */ 1743313570Smm sol = 1; 1744313570Smm } else if (fields == (n + 3) && 1745313570Smm field[n + 1].start < field[n + 1].end) { 1746313570Smm /* Invalid mask or other field */ 1747313570Smm ret = ARCHIVE_WARN; 1748313570Smm continue; 1749313570Smm } 1750313570Smm break; 1751313570Smm case ARCHIVE_ENTRY_ACL_USER_OBJ: 1752313570Smm case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 1753313570Smm if (id != -1 || 1754313570Smm field[n + 1].start < field[n + 1].end) { 1755313570Smm name = field[n + 1]; 1756313570Smm if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) 1757313570Smm tag = ARCHIVE_ENTRY_ACL_USER; 1758313570Smm else 1759313570Smm tag = ARCHIVE_ENTRY_ACL_GROUP; 1760313570Smm } 1761313570Smm break; 1762313570Smm default: 1763313570Smm /* Invalid tag, skip entry */ 1764313570Smm ret = ARCHIVE_WARN; 1765313570Smm continue; 1766313570Smm } 1767313570Smm 1768313570Smm /* 1769313570Smm * Without "default:" we expect mode in field 3 1770313570Smm * Exception: Solaris other and mask fields 1771313570Smm */ 1772313570Smm if (permset == 0 && !ismode(field[n + 2 - sol].start, 1773313570Smm field[n + 2 - sol].end, &permset)) { 1774313570Smm /* Invalid mode, skip entry */ 1775313570Smm ret = ARCHIVE_WARN; 1776313570Smm continue; 1777313570Smm } 1778313570Smm } else { 1779313570Smm /* NFS4 ACLs */ 1780313570Smm s = field[0].start; 1781313570Smm len = field[0].end - field[0].start; 1782313570Smm tag = 0; 1783313570Smm 1784313570Smm switch (len) { 1785313570Smm case 4: 1786313570Smm if (memcmp(s, "user", 4) == 0) 1787313570Smm tag = ARCHIVE_ENTRY_ACL_USER; 1788313570Smm break; 1789313570Smm case 5: 1790313570Smm if (memcmp(s, "group", 5) == 0) 1791313570Smm tag = ARCHIVE_ENTRY_ACL_GROUP; 1792313570Smm break; 1793313570Smm case 6: 1794313570Smm if (memcmp(s, "owner@", 6) == 0) 1795313570Smm tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 1796313570Smm else if (memcmp(s, "group@", 6) == 0) 1797313570Smm tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 1798313570Smm break; 1799313570Smm case 9: 1800313570Smm if (memcmp(s, "everyone@", 9) == 0) 1801313570Smm tag = ARCHIVE_ENTRY_ACL_EVERYONE; 1802313570Smm break; 1803313570Smm default: 1804313570Smm break; 1805313570Smm } 1806313570Smm 1807313570Smm if (tag == 0) { 1808313570Smm /* Invalid tag, skip entry */ 1809313570Smm ret = ARCHIVE_WARN; 1810313570Smm continue; 1811313570Smm } else if (tag == ARCHIVE_ENTRY_ACL_USER || 1812313570Smm tag == ARCHIVE_ENTRY_ACL_GROUP) { 1813313570Smm n = 1; 1814231200Smm name = field[1]; 1815313570Smm isint(name.start, name.end, &id); 1816231200Smm } else 1817313570Smm n = 0; 1818231200Smm 1819313570Smm if (!is_nfs4_perms(field[1 + n].start, 1820313570Smm field[1 + n].end, &permset)) { 1821313570Smm /* Invalid NFSv4 perms, skip entry */ 1822313570Smm ret = ARCHIVE_WARN; 1823313570Smm continue; 1824313570Smm } 1825313570Smm if (!is_nfs4_flags(field[2 + n].start, 1826313570Smm field[2 + n].end, &permset)) { 1827313570Smm /* Invalid NFSv4 flags, skip entry */ 1828313570Smm ret = ARCHIVE_WARN; 1829313570Smm continue; 1830313570Smm } 1831313570Smm s = field[3 + n].start; 1832313570Smm len = field[3 + n].end - field[3 + n].start; 1833313570Smm type = 0; 1834313570Smm if (len == 4) { 1835313570Smm if (memcmp(s, "deny", 4) == 0) 1836313570Smm type = ARCHIVE_ENTRY_ACL_TYPE_DENY; 1837313570Smm } else if (len == 5) { 1838313570Smm if (memcmp(s, "allow", 5) == 0) 1839313570Smm type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; 1840313570Smm else if (memcmp(s, "audit", 5) == 0) 1841313570Smm type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT; 1842313570Smm else if (memcmp(s, "alarm", 5) == 0) 1843313570Smm type = ARCHIVE_ENTRY_ACL_TYPE_ALARM; 1844313570Smm } 1845313570Smm if (type == 0) { 1846313570Smm /* Invalid entry type, skip entry */ 1847313570Smm ret = ARCHIVE_WARN; 1848313570Smm continue; 1849313570Smm } 1850313570Smm isint(field[4 + n].start, field[4 + n].end, 1851313570Smm &id); 1852313570Smm } 1853313570Smm 1854231200Smm /* Add entry to the internal list. */ 1855231200Smm r = archive_acl_add_entry_len_l(acl, type, permset, 1856231200Smm tag, id, name.start, name.end - name.start, sc); 1857231200Smm if (r < ARCHIVE_WARN) 1858231200Smm return (r); 1859231200Smm if (r != ARCHIVE_OK) 1860231200Smm ret = ARCHIVE_WARN; 1861313570Smm types |= type; 1862231200Smm } 1863313570Smm 1864313570Smm /* Reset ACL */ 1865313570Smm archive_acl_reset(acl, types); 1866313570Smm 1867231200Smm return (ret); 1868231200Smm} 1869231200Smm 1870231200Smm/* 1871231200Smm * Parse a string to a positive decimal integer. Returns true if 1872231200Smm * the string is non-empty and consists only of decimal digits, 1873231200Smm * false otherwise. 1874231200Smm */ 1875231200Smmstatic int 1876231200Smmisint(const char *start, const char *end, int *result) 1877231200Smm{ 1878231200Smm int n = 0; 1879231200Smm if (start >= end) 1880231200Smm return (0); 1881231200Smm while (start < end) { 1882231200Smm if (*start < '0' || *start > '9') 1883231200Smm return (0); 1884231200Smm if (n > (INT_MAX / 10) || 1885231200Smm (n == INT_MAX / 10 && (*start - '0') > INT_MAX % 10)) { 1886231200Smm n = INT_MAX; 1887231200Smm } else { 1888231200Smm n *= 10; 1889231200Smm n += *start - '0'; 1890231200Smm } 1891231200Smm start++; 1892231200Smm } 1893231200Smm *result = n; 1894231200Smm return (1); 1895231200Smm} 1896231200Smm 1897231200Smm/* 1898231200Smm * Parse a string as a mode field. Returns true if 1899231200Smm * the string is non-empty and consists only of mode characters, 1900231200Smm * false otherwise. 1901231200Smm */ 1902231200Smmstatic int 1903231200Smmismode(const char *start, const char *end, int *permset) 1904231200Smm{ 1905231200Smm const char *p; 1906231200Smm 1907231200Smm if (start >= end) 1908231200Smm return (0); 1909231200Smm p = start; 1910231200Smm *permset = 0; 1911231200Smm while (p < end) { 1912231200Smm switch (*p++) { 1913231200Smm case 'r': case 'R': 1914231200Smm *permset |= ARCHIVE_ENTRY_ACL_READ; 1915231200Smm break; 1916231200Smm case 'w': case 'W': 1917231200Smm *permset |= ARCHIVE_ENTRY_ACL_WRITE; 1918231200Smm break; 1919231200Smm case 'x': case 'X': 1920231200Smm *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; 1921231200Smm break; 1922231200Smm case '-': 1923231200Smm break; 1924231200Smm default: 1925231200Smm return (0); 1926231200Smm } 1927231200Smm } 1928231200Smm return (1); 1929231200Smm} 1930231200Smm 1931231200Smm/* 1932313570Smm * Parse a string as a NFS4 ACL permission field. 1933313570Smm * Returns true if the string is non-empty and consists only of NFS4 ACL 1934313570Smm * permission characters, false otherwise 1935313570Smm */ 1936313570Smmstatic int 1937313570Smmis_nfs4_perms(const char *start, const char *end, int *permset) 1938313570Smm{ 1939313926Smm const char *p = start; 1940313570Smm 1941313570Smm while (p < end) { 1942313570Smm switch (*p++) { 1943313570Smm case 'r': 1944313570Smm *permset |= ARCHIVE_ENTRY_ACL_READ_DATA; 1945313570Smm break; 1946313570Smm case 'w': 1947313570Smm *permset |= ARCHIVE_ENTRY_ACL_WRITE_DATA; 1948313570Smm break; 1949313570Smm case 'x': 1950313570Smm *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; 1951313570Smm break; 1952313570Smm case 'p': 1953313570Smm *permset |= ARCHIVE_ENTRY_ACL_APPEND_DATA; 1954313570Smm break; 1955313570Smm case 'D': 1956313570Smm *permset |= ARCHIVE_ENTRY_ACL_DELETE_CHILD; 1957313570Smm break; 1958313570Smm case 'd': 1959313570Smm *permset |= ARCHIVE_ENTRY_ACL_DELETE; 1960313570Smm break; 1961313570Smm case 'a': 1962313570Smm *permset |= ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES; 1963313570Smm break; 1964313570Smm case 'A': 1965313570Smm *permset |= ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES; 1966313570Smm break; 1967313570Smm case 'R': 1968313570Smm *permset |= ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS; 1969313570Smm break; 1970313570Smm case 'W': 1971313570Smm *permset |= ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS; 1972313570Smm break; 1973313570Smm case 'c': 1974313570Smm *permset |= ARCHIVE_ENTRY_ACL_READ_ACL; 1975313570Smm break; 1976313570Smm case 'C': 1977313570Smm *permset |= ARCHIVE_ENTRY_ACL_WRITE_ACL; 1978313570Smm break; 1979313570Smm case 'o': 1980313570Smm *permset |= ARCHIVE_ENTRY_ACL_WRITE_OWNER; 1981313570Smm break; 1982313570Smm case 's': 1983313570Smm *permset |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE; 1984313570Smm break; 1985313570Smm case '-': 1986313570Smm break; 1987313570Smm default: 1988313570Smm return(0); 1989313570Smm } 1990313570Smm } 1991313570Smm return (1); 1992313570Smm} 1993313570Smm 1994313570Smm/* 1995313570Smm * Parse a string as a NFS4 ACL flags field. 1996313570Smm * Returns true if the string is non-empty and consists only of NFS4 ACL 1997313570Smm * flag characters, false otherwise 1998313570Smm */ 1999313570Smmstatic int 2000313570Smmis_nfs4_flags(const char *start, const char *end, int *permset) 2001313570Smm{ 2002313926Smm const char *p = start; 2003313570Smm 2004313570Smm while (p < end) { 2005313570Smm switch(*p++) { 2006313570Smm case 'f': 2007313570Smm *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT; 2008313570Smm break; 2009313570Smm case 'd': 2010313570Smm *permset |= ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT; 2011313570Smm break; 2012313570Smm case 'i': 2013313570Smm *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY; 2014313570Smm break; 2015313570Smm case 'n': 2016313570Smm *permset |= 2017313570Smm ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT; 2018313570Smm break; 2019313570Smm case 'S': 2020313570Smm *permset |= ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS; 2021313570Smm break; 2022313570Smm case 'F': 2023313570Smm *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS; 2024313570Smm break; 2025313570Smm case 'I': 2026313570Smm *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERITED; 2027313570Smm break; 2028313570Smm case '-': 2029313570Smm break; 2030313570Smm default: 2031313570Smm return (0); 2032313570Smm } 2033313570Smm } 2034313570Smm return (1); 2035313570Smm} 2036313570Smm 2037313570Smm/* 2038231200Smm * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]". *wp is updated 2039231200Smm * to point to just after the separator. *start points to the first 2040231200Smm * character of the matched text and *end just after the last 2041231200Smm * character of the matched identifier. In particular *end - *start 2042231200Smm * is the length of the field body, not including leading or trailing 2043231200Smm * whitespace. 2044231200Smm */ 2045231200Smmstatic void 2046231200Smmnext_field(const char **p, const char **start, 2047231200Smm const char **end, char *sep) 2048231200Smm{ 2049231200Smm /* Skip leading whitespace to find start of field. */ 2050231200Smm while (**p == ' ' || **p == '\t' || **p == '\n') { 2051231200Smm (*p)++; 2052231200Smm } 2053231200Smm *start = *p; 2054231200Smm 2055231200Smm /* Scan for the separator. */ 2056231200Smm while (**p != '\0' && **p != ',' && **p != ':' && **p != '\n') { 2057231200Smm (*p)++; 2058231200Smm } 2059231200Smm *sep = **p; 2060231200Smm 2061339005Smm /* If the field is only whitespace, bail out now. */ 2062339005Smm if (**p == '\0') { 2063339005Smm *end = *p; 2064339005Smm return; 2065339005Smm } 2066339005Smm 2067231200Smm /* Trim trailing whitespace to locate end of field. */ 2068231200Smm *end = *p - 1; 2069231200Smm while (**end == ' ' || **end == '\t' || **end == '\n') { 2070231200Smm (*end)--; 2071231200Smm } 2072231200Smm (*end)++; 2073231200Smm 2074231200Smm /* Adjust scanner location. */ 2075231200Smm if (**p != '\0') 2076231200Smm (*p)++; 2077231200Smm} 2078