archive_acl.c revision 313570
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 86231200Smmvoid 87231200Smmarchive_acl_clear(struct archive_acl *acl) 88231200Smm{ 89231200Smm struct archive_acl_entry *ap; 90231200Smm 91231200Smm while (acl->acl_head != NULL) { 92231200Smm ap = acl->acl_head->next; 93231200Smm archive_mstring_clean(&acl->acl_head->name); 94231200Smm free(acl->acl_head); 95231200Smm acl->acl_head = ap; 96231200Smm } 97231200Smm if (acl->acl_text_w != NULL) { 98231200Smm free(acl->acl_text_w); 99231200Smm acl->acl_text_w = NULL; 100231200Smm } 101231200Smm if (acl->acl_text != NULL) { 102231200Smm free(acl->acl_text); 103231200Smm acl->acl_text = NULL; 104231200Smm } 105231200Smm acl->acl_p = NULL; 106311041Smm acl->acl_types = 0; 107231200Smm acl->acl_state = 0; /* Not counting. */ 108231200Smm} 109231200Smm 110231200Smmvoid 111231200Smmarchive_acl_copy(struct archive_acl *dest, struct archive_acl *src) 112231200Smm{ 113231200Smm struct archive_acl_entry *ap, *ap2; 114231200Smm 115231200Smm archive_acl_clear(dest); 116231200Smm 117231200Smm dest->mode = src->mode; 118231200Smm ap = src->acl_head; 119231200Smm while (ap != NULL) { 120231200Smm ap2 = acl_new_entry(dest, 121231200Smm ap->type, ap->permset, ap->tag, ap->id); 122231200Smm if (ap2 != NULL) 123231200Smm archive_mstring_copy(&ap2->name, &ap->name); 124231200Smm ap = ap->next; 125231200Smm } 126231200Smm} 127231200Smm 128231200Smmint 129231200Smmarchive_acl_add_entry(struct archive_acl *acl, 130231200Smm int type, int permset, int tag, int id, const char *name) 131231200Smm{ 132231200Smm struct archive_acl_entry *ap; 133231200Smm 134231200Smm if (acl_special(acl, type, permset, tag) == 0) 135231200Smm return ARCHIVE_OK; 136231200Smm ap = acl_new_entry(acl, type, permset, tag, id); 137231200Smm if (ap == NULL) { 138231200Smm /* XXX Error XXX */ 139231200Smm return ARCHIVE_FAILED; 140231200Smm } 141231200Smm if (name != NULL && *name != '\0') 142231200Smm archive_mstring_copy_mbs(&ap->name, name); 143231200Smm else 144231200Smm archive_mstring_clean(&ap->name); 145231200Smm return ARCHIVE_OK; 146231200Smm} 147231200Smm 148231200Smmint 149231200Smmarchive_acl_add_entry_w_len(struct archive_acl *acl, 150231200Smm int type, int permset, int tag, int id, const wchar_t *name, size_t len) 151231200Smm{ 152231200Smm struct archive_acl_entry *ap; 153231200Smm 154231200Smm if (acl_special(acl, type, permset, tag) == 0) 155231200Smm return ARCHIVE_OK; 156231200Smm ap = acl_new_entry(acl, type, permset, tag, id); 157231200Smm if (ap == NULL) { 158231200Smm /* XXX Error XXX */ 159231200Smm return ARCHIVE_FAILED; 160231200Smm } 161231200Smm if (name != NULL && *name != L'\0' && len > 0) 162231200Smm archive_mstring_copy_wcs_len(&ap->name, name, len); 163231200Smm else 164231200Smm archive_mstring_clean(&ap->name); 165231200Smm return ARCHIVE_OK; 166231200Smm} 167231200Smm 168232153Smmstatic int 169231200Smmarchive_acl_add_entry_len_l(struct archive_acl *acl, 170231200Smm int type, int permset, int tag, int id, const char *name, size_t len, 171231200Smm struct archive_string_conv *sc) 172231200Smm{ 173231200Smm struct archive_acl_entry *ap; 174231200Smm int r; 175231200Smm 176231200Smm if (acl_special(acl, type, permset, tag) == 0) 177231200Smm return ARCHIVE_OK; 178231200Smm ap = acl_new_entry(acl, type, permset, tag, id); 179231200Smm if (ap == NULL) { 180231200Smm /* XXX Error XXX */ 181231200Smm return ARCHIVE_FAILED; 182231200Smm } 183231200Smm if (name != NULL && *name != '\0' && len > 0) { 184231200Smm r = archive_mstring_copy_mbs_len_l(&ap->name, name, len, sc); 185231200Smm } else { 186231200Smm r = 0; 187231200Smm archive_mstring_clean(&ap->name); 188231200Smm } 189231200Smm if (r == 0) 190231200Smm return (ARCHIVE_OK); 191231200Smm else if (errno == ENOMEM) 192231200Smm return (ARCHIVE_FATAL); 193231200Smm else 194231200Smm return (ARCHIVE_WARN); 195231200Smm} 196231200Smm 197231200Smm/* 198231200Smm * If this ACL entry is part of the standard POSIX permissions set, 199231200Smm * store the permissions in the stat structure and return zero. 200231200Smm */ 201231200Smmstatic int 202231200Smmacl_special(struct archive_acl *acl, int type, int permset, int tag) 203231200Smm{ 204231200Smm if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS 205231200Smm && ((permset & ~007) == 0)) { 206231200Smm switch (tag) { 207231200Smm case ARCHIVE_ENTRY_ACL_USER_OBJ: 208231200Smm acl->mode &= ~0700; 209231200Smm acl->mode |= (permset & 7) << 6; 210231200Smm return (0); 211231200Smm case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 212231200Smm acl->mode &= ~0070; 213231200Smm acl->mode |= (permset & 7) << 3; 214231200Smm return (0); 215231200Smm case ARCHIVE_ENTRY_ACL_OTHER: 216231200Smm acl->mode &= ~0007; 217231200Smm acl->mode |= permset & 7; 218231200Smm return (0); 219231200Smm } 220231200Smm } 221231200Smm return (1); 222231200Smm} 223231200Smm 224231200Smm/* 225231200Smm * Allocate and populate a new ACL entry with everything but the 226231200Smm * name. 227231200Smm */ 228231200Smmstatic struct archive_acl_entry * 229231200Smmacl_new_entry(struct archive_acl *acl, 230231200Smm int type, int permset, int tag, int id) 231231200Smm{ 232231200Smm struct archive_acl_entry *ap, *aq; 233231200Smm 234231200Smm /* Type argument must be a valid NFS4 or POSIX.1e type. 235231200Smm * The type must agree with anything already set and 236231200Smm * the permset must be compatible. */ 237231200Smm if (type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 238231200Smm if (acl->acl_types & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 239231200Smm return (NULL); 240231200Smm } 241231200Smm if (permset & 242231200Smm ~(ARCHIVE_ENTRY_ACL_PERMS_NFS4 243231200Smm | ARCHIVE_ENTRY_ACL_INHERITANCE_NFS4)) { 244231200Smm return (NULL); 245231200Smm } 246231200Smm } else if (type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) { 247231200Smm if (acl->acl_types & ~ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) { 248231200Smm return (NULL); 249231200Smm } 250231200Smm if (permset & ~ARCHIVE_ENTRY_ACL_PERMS_POSIX1E) { 251231200Smm return (NULL); 252231200Smm } 253231200Smm } else { 254231200Smm return (NULL); 255231200Smm } 256231200Smm 257231200Smm /* Verify the tag is valid and compatible with NFS4 or POSIX.1e. */ 258231200Smm switch (tag) { 259231200Smm case ARCHIVE_ENTRY_ACL_USER: 260231200Smm case ARCHIVE_ENTRY_ACL_USER_OBJ: 261231200Smm case ARCHIVE_ENTRY_ACL_GROUP: 262231200Smm case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 263231200Smm /* Tags valid in both NFS4 and POSIX.1e */ 264231200Smm break; 265231200Smm case ARCHIVE_ENTRY_ACL_MASK: 266231200Smm case ARCHIVE_ENTRY_ACL_OTHER: 267231200Smm /* Tags valid only in POSIX.1e. */ 268231200Smm if (type & ~ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) { 269231200Smm return (NULL); 270231200Smm } 271231200Smm break; 272231200Smm case ARCHIVE_ENTRY_ACL_EVERYONE: 273231200Smm /* Tags valid only in NFS4. */ 274231200Smm if (type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 275231200Smm return (NULL); 276231200Smm } 277231200Smm break; 278231200Smm default: 279231200Smm /* No other values are valid. */ 280231200Smm return (NULL); 281231200Smm } 282231200Smm 283231200Smm if (acl->acl_text_w != NULL) { 284231200Smm free(acl->acl_text_w); 285231200Smm acl->acl_text_w = NULL; 286231200Smm } 287231200Smm if (acl->acl_text != NULL) { 288231200Smm free(acl->acl_text); 289231200Smm acl->acl_text = NULL; 290231200Smm } 291231200Smm 292311041Smm /* 293311041Smm * If there's a matching entry already in the list, overwrite it. 294311041Smm * NFSv4 entries may be repeated and are not overwritten. 295311041Smm * 296311041Smm * TODO: compare names of no id is provided (needs more rework) 297311041Smm */ 298231200Smm ap = acl->acl_head; 299231200Smm aq = NULL; 300231200Smm while (ap != NULL) { 301311041Smm if (((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0) && 302311041Smm ap->type == type && ap->tag == tag && ap->id == id) { 303311041Smm if (id != -1 || (tag != ARCHIVE_ENTRY_ACL_USER && 304311041Smm tag != ARCHIVE_ENTRY_ACL_GROUP)) { 305311041Smm ap->permset = permset; 306311041Smm return (ap); 307311041Smm } 308231200Smm } 309231200Smm aq = ap; 310231200Smm ap = ap->next; 311231200Smm } 312231200Smm 313231200Smm /* Add a new entry to the end of the list. */ 314311041Smm ap = (struct archive_acl_entry *)calloc(1, sizeof(*ap)); 315231200Smm if (ap == NULL) 316231200Smm return (NULL); 317231200Smm if (aq == NULL) 318231200Smm acl->acl_head = ap; 319231200Smm else 320231200Smm aq->next = ap; 321231200Smm ap->type = type; 322231200Smm ap->tag = tag; 323231200Smm ap->id = id; 324231200Smm ap->permset = permset; 325231200Smm acl->acl_types |= type; 326231200Smm return (ap); 327231200Smm} 328231200Smm 329231200Smm/* 330231200Smm * Return a count of entries matching "want_type". 331231200Smm */ 332231200Smmint 333231200Smmarchive_acl_count(struct archive_acl *acl, int want_type) 334231200Smm{ 335231200Smm int count; 336231200Smm struct archive_acl_entry *ap; 337231200Smm 338231200Smm count = 0; 339231200Smm ap = acl->acl_head; 340231200Smm while (ap != NULL) { 341231200Smm if ((ap->type & want_type) != 0) 342231200Smm count++; 343231200Smm ap = ap->next; 344231200Smm } 345231200Smm 346231200Smm if (count > 0 && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)) 347231200Smm count += 3; 348231200Smm return (count); 349231200Smm} 350231200Smm 351231200Smm/* 352313570Smm * Return a bitmask of stored ACL types in an ACL list 353313570Smm */ 354313570Smmint 355313570Smmarchive_acl_types(struct archive_acl *acl) 356313570Smm{ 357313570Smm return (acl->acl_types); 358313570Smm} 359313570Smm 360313570Smm/* 361231200Smm * Prepare for reading entries from the ACL data. Returns a count 362231200Smm * of entries matching "want_type", or zero if there are no 363231200Smm * non-extended ACL entries of that type. 364231200Smm */ 365231200Smmint 366231200Smmarchive_acl_reset(struct archive_acl *acl, int want_type) 367231200Smm{ 368231200Smm int count, cutoff; 369231200Smm 370231200Smm count = archive_acl_count(acl, want_type); 371231200Smm 372231200Smm /* 373231200Smm * If the only entries are the three standard ones, 374231200Smm * then don't return any ACL data. (In this case, 375231200Smm * client can just use chmod(2) to set permissions.) 376231200Smm */ 377231200Smm if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) 378231200Smm cutoff = 3; 379231200Smm else 380231200Smm cutoff = 0; 381231200Smm 382231200Smm if (count > cutoff) 383231200Smm acl->acl_state = ARCHIVE_ENTRY_ACL_USER_OBJ; 384231200Smm else 385231200Smm acl->acl_state = 0; 386231200Smm acl->acl_p = acl->acl_head; 387231200Smm return (count); 388231200Smm} 389231200Smm 390231200Smm 391231200Smm/* 392231200Smm * Return the next ACL entry in the list. Fake entries for the 393231200Smm * standard permissions and include them in the returned list. 394231200Smm */ 395231200Smmint 396313570Smmarchive_acl_next(struct archive *a, struct archive_acl *acl, int want_type, 397313570Smm int *type, int *permset, int *tag, int *id, const char **name) 398231200Smm{ 399231200Smm *name = NULL; 400231200Smm *id = -1; 401231200Smm 402231200Smm /* 403231200Smm * The acl_state is either zero (no entries available), -1 404231200Smm * (reading from list), or an entry type (retrieve that type 405231200Smm * from ae_stat.aest_mode). 406231200Smm */ 407231200Smm if (acl->acl_state == 0) 408231200Smm return (ARCHIVE_WARN); 409231200Smm 410231200Smm /* The first three access entries are special. */ 411231200Smm if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { 412231200Smm switch (acl->acl_state) { 413231200Smm case ARCHIVE_ENTRY_ACL_USER_OBJ: 414231200Smm *permset = (acl->mode >> 6) & 7; 415231200Smm *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 416231200Smm *tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 417231200Smm acl->acl_state = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 418231200Smm return (ARCHIVE_OK); 419231200Smm case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 420231200Smm *permset = (acl->mode >> 3) & 7; 421231200Smm *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 422231200Smm *tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 423231200Smm acl->acl_state = ARCHIVE_ENTRY_ACL_OTHER; 424231200Smm return (ARCHIVE_OK); 425231200Smm case ARCHIVE_ENTRY_ACL_OTHER: 426231200Smm *permset = acl->mode & 7; 427231200Smm *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 428231200Smm *tag = ARCHIVE_ENTRY_ACL_OTHER; 429231200Smm acl->acl_state = -1; 430231200Smm acl->acl_p = acl->acl_head; 431231200Smm return (ARCHIVE_OK); 432231200Smm default: 433231200Smm break; 434231200Smm } 435231200Smm } 436231200Smm 437231200Smm while (acl->acl_p != NULL && (acl->acl_p->type & want_type) == 0) 438231200Smm acl->acl_p = acl->acl_p->next; 439231200Smm if (acl->acl_p == NULL) { 440231200Smm acl->acl_state = 0; 441231200Smm *type = 0; 442231200Smm *permset = 0; 443231200Smm *tag = 0; 444231200Smm *id = -1; 445231200Smm *name = NULL; 446231200Smm return (ARCHIVE_EOF); /* End of ACL entries. */ 447231200Smm } 448231200Smm *type = acl->acl_p->type; 449231200Smm *permset = acl->acl_p->permset; 450231200Smm *tag = acl->acl_p->tag; 451231200Smm *id = acl->acl_p->id; 452238856Smm if (archive_mstring_get_mbs(a, &acl->acl_p->name, name) != 0) { 453238856Smm if (errno == ENOMEM) 454238856Smm return (ARCHIVE_FATAL); 455231200Smm *name = NULL; 456238856Smm } 457231200Smm acl->acl_p = acl->acl_p->next; 458231200Smm return (ARCHIVE_OK); 459231200Smm} 460231200Smm 461231200Smm/* 462313570Smm * Determine what type of ACL do we want 463231200Smm */ 464313570Smmstatic int 465313570Smmarchive_acl_text_want_type(struct archive_acl *acl, int flags) 466231200Smm{ 467313570Smm int want_type; 468231200Smm 469313570Smm /* Check if ACL is NFSv4 */ 470313570Smm if ((acl->acl_types & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { 471313570Smm /* NFSv4 should never mix with POSIX.1e */ 472313570Smm if ((acl->acl_types & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) 473313570Smm return (0); 474313570Smm else 475313570Smm return (ARCHIVE_ENTRY_ACL_TYPE_NFS4); 476231200Smm } 477231200Smm 478313570Smm /* Now deal with POSIX.1e ACLs */ 479313570Smm 480313570Smm want_type = 0; 481313570Smm if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) 482313570Smm want_type |= ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 483313570Smm if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) 484313570Smm want_type |= ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; 485313570Smm 486313570Smm /* By default we want both access and default ACLs */ 487313570Smm if (want_type == 0) 488313570Smm return (ARCHIVE_ENTRY_ACL_TYPE_POSIX1E); 489313570Smm 490313570Smm return (want_type); 491313570Smm} 492313570Smm 493313570Smm/* 494313570Smm * Calculate ACL text string length 495313570Smm */ 496313570Smmstatic ssize_t 497313570Smmarchive_acl_text_len(struct archive_acl *acl, int want_type, int flags, 498313570Smm int wide, struct archive *a, struct archive_string_conv *sc) { 499313570Smm struct archive_acl_entry *ap; 500313570Smm const char *name; 501313570Smm const wchar_t *wname; 502313570Smm int count, idlen, tmp, r; 503313570Smm ssize_t length; 504313570Smm size_t len; 505313570Smm 506231200Smm count = 0; 507231200Smm length = 0; 508313570Smm for (ap = acl->acl_head; ap != NULL; ap = ap->next) { 509313570Smm if ((ap->type & want_type) == 0) 510313570Smm continue; 511313570Smm /* 512313570Smm * Filemode-mapping ACL entries are stored exclusively in 513313570Smm * ap->mode so they should not be in the list 514313570Smm */ 515313570Smm if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) 516313570Smm && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ 517313570Smm || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ 518313570Smm || ap->tag == ARCHIVE_ENTRY_ACL_OTHER)) 519313570Smm continue; 520313570Smm count++; 521313570Smm if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0 522313570Smm && (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) 523313570Smm length += 8; /* "default:" */ 524313570Smm switch (ap->tag) { 525313570Smm case ARCHIVE_ENTRY_ACL_USER_OBJ: 526313570Smm if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 527313570Smm length += 6; /* "owner@" */ 528313570Smm break; 529313570Smm } 530313570Smm /* FALLTHROUGH */ 531313570Smm case ARCHIVE_ENTRY_ACL_USER: 532313570Smm case ARCHIVE_ENTRY_ACL_MASK: 533313570Smm length += 4; /* "user", "mask" */ 534313570Smm break; 535313570Smm case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 536313570Smm if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 537313570Smm length += 6; /* "group@" */ 538313570Smm break; 539313570Smm } 540313570Smm /* FALLTHROUGH */ 541313570Smm case ARCHIVE_ENTRY_ACL_GROUP: 542313570Smm case ARCHIVE_ENTRY_ACL_OTHER: 543313570Smm length += 5; /* "group", "other" */ 544313570Smm break; 545313570Smm case ARCHIVE_ENTRY_ACL_EVERYONE: 546313570Smm length += 9; /* "everyone@" */ 547313570Smm break; 548313570Smm } 549313570Smm length += 1; /* colon after tag */ 550313570Smm if (ap->tag == ARCHIVE_ENTRY_ACL_USER || 551313570Smm ap->tag == ARCHIVE_ENTRY_ACL_GROUP) { 552313570Smm if (wide) { 553313570Smm r = archive_mstring_get_wcs(a, &ap->name, 554313570Smm &wname); 555313570Smm if (r == 0 && wname != NULL) 556313570Smm length += wcslen(wname); 557313570Smm else if (r < 0 && errno == ENOMEM) 558313570Smm return (0); 559313570Smm else 560313570Smm length += sizeof(uid_t) * 3 + 1; 561313570Smm } else { 562313570Smm r = archive_mstring_get_mbs_l(&ap->name, &name, 563313570Smm &len, sc); 564313570Smm if (r != 0) 565313570Smm return (0); 566313570Smm if (len > 0 && name != NULL) 567313570Smm length += len; 568313570Smm else 569313570Smm length += sizeof(uid_t) * 3 + 1; 570313570Smm } 571313570Smm length += 1; /* colon after user or group name */ 572313570Smm } else if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) 573313570Smm length += 1; /* 2nd colon empty user,group or other */ 574313570Smm 575313570Smm if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) != 0) 576313570Smm && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) 577313570Smm && (ap->tag == ARCHIVE_ENTRY_ACL_OTHER 578313570Smm || ap->tag == ARCHIVE_ENTRY_ACL_MASK)) { 579313570Smm /* Solaris has no colon after other: and mask: */ 580313570Smm length = length - 1; 581313570Smm } 582313570Smm 583313570Smm if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 584313570Smm /* rwxpdDaARWcCos:fdinSFI:deny */ 585313570Smm length += 27; 586313570Smm if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DENY) == 0) 587313570Smm length += 1; /* allow, alarm, audit */ 588313570Smm } else 589231200Smm length += 3; /* rwx */ 590313570Smm 591313570Smm if ((ap->tag == ARCHIVE_ENTRY_ACL_USER || 592313570Smm ap->tag == ARCHIVE_ENTRY_ACL_GROUP) && 593313570Smm (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) != 0) { 594231200Smm length += 1; /* colon */ 595313570Smm /* ID digit count */ 596313570Smm idlen = 1; 597313570Smm tmp = ap->id; 598313570Smm while (tmp > 9) { 599313570Smm tmp = tmp / 10; 600313570Smm idlen++; 601313570Smm } 602313570Smm length += idlen; 603231200Smm } 604313570Smm length ++; /* entry separator */ 605231200Smm } 606231200Smm 607313570Smm /* Add filemode-mapping access entries to the length */ 608313570Smm if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { 609313570Smm if ((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) != 0) { 610313570Smm /* "user::rwx\ngroup::rwx\nother:rwx\n" */ 611313570Smm length += 31; 612313570Smm } else { 613313570Smm /* "user::rwx\ngroup::rwx\nother::rwx\n" */ 614313570Smm length += 32; 615313570Smm } 616313570Smm } else if (count == 0) 617313570Smm return (0); 618231200Smm 619313570Smm /* The terminating character is included in count */ 620313570Smm return (length); 621313570Smm} 622313570Smm 623313570Smm/* 624313570Smm * Generate a wide text version of the ACL. The flags parameter controls 625313570Smm * the type and style of the generated ACL. 626313570Smm */ 627313570Smmwchar_t * 628313570Smmarchive_acl_to_text_w(struct archive_acl *acl, ssize_t *text_len, int flags, 629313570Smm struct archive *a) 630313570Smm{ 631313570Smm int count; 632313570Smm ssize_t length; 633313570Smm size_t len; 634313570Smm const wchar_t *wname; 635313570Smm const wchar_t *prefix; 636313570Smm wchar_t separator; 637313570Smm struct archive_acl_entry *ap; 638313570Smm int id, r, want_type; 639313570Smm wchar_t *wp, *ws; 640313570Smm 641313570Smm want_type = archive_acl_text_want_type(acl, flags); 642313570Smm 643313570Smm /* Both NFSv4 and POSIX.1 types found */ 644313570Smm if (want_type == 0) 645231200Smm return (NULL); 646231200Smm 647313570Smm if (want_type == ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) 648313570Smm flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT; 649313570Smm 650313570Smm length = archive_acl_text_len(acl, want_type, flags, 1, a, NULL); 651313570Smm 652313570Smm if (length == 0) 653313570Smm return (NULL); 654313570Smm 655313570Smm if (flags & ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA) 656313570Smm separator = L','; 657313570Smm else 658313570Smm separator = L'\n'; 659313570Smm 660231200Smm /* Now, allocate the string and actually populate it. */ 661313570Smm wp = ws = (wchar_t *)malloc(length * sizeof(wchar_t)); 662313570Smm if (wp == NULL) { 663313570Smm if (errno == ENOMEM) 664313570Smm __archive_errx(1, "No memory"); 665238856Smm return (NULL); 666313570Smm } 667231200Smm count = 0; 668313570Smm 669313570Smm if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { 670313570Smm append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 671313570Smm ARCHIVE_ENTRY_ACL_USER_OBJ, flags, NULL, 672231200Smm acl->mode & 0700, -1); 673313570Smm *wp++ = separator; 674313570Smm append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 675313570Smm ARCHIVE_ENTRY_ACL_GROUP_OBJ, flags, NULL, 676231200Smm acl->mode & 0070, -1); 677313570Smm *wp++ = separator; 678313570Smm append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 679313570Smm ARCHIVE_ENTRY_ACL_OTHER, flags, NULL, 680231200Smm acl->mode & 0007, -1); 681231200Smm count += 3; 682231200Smm } 683231200Smm 684313570Smm for (ap = acl->acl_head; ap != NULL; ap = ap->next) { 685313570Smm if ((ap->type & want_type) == 0) 686313570Smm continue; 687313570Smm /* 688313570Smm * Filemode-mapping ACL entries are stored exclusively in 689313570Smm * ap->mode so they should not be in the list 690313570Smm */ 691313570Smm if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) 692313570Smm && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ 693313570Smm || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ 694313570Smm || ap->tag == ARCHIVE_ENTRY_ACL_OTHER)) 695313570Smm continue; 696313570Smm if (ap->type == ARCHIVE_ENTRY_ACL_TYPE_DEFAULT && 697313570Smm (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0) 698231200Smm prefix = L"default:"; 699231200Smm else 700231200Smm prefix = NULL; 701313570Smm r = archive_mstring_get_wcs(a, &ap->name, &wname); 702313570Smm if (r == 0) { 703313570Smm if (count > 0) 704313570Smm *wp++ = separator; 705313570Smm if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) 706313570Smm id = ap->id; 707313570Smm else 708313570Smm id = -1; 709313570Smm append_entry_w(&wp, prefix, ap->type, ap->tag, flags, 710313570Smm wname, ap->permset, id); 711313570Smm count++; 712313570Smm } else if (r < 0 && errno == ENOMEM) 713313570Smm return (NULL); 714231200Smm } 715231200Smm 716313570Smm /* Add terminating character */ 717313570Smm *wp++ = L'\0'; 718313570Smm 719313570Smm len = wcslen(ws); 720313570Smm 721313570Smm if ((ssize_t)len > (length - 1)) 722313570Smm __archive_errx(1, "Buffer overrun"); 723313570Smm 724313570Smm if (text_len != NULL) 725313570Smm *text_len = len; 726313570Smm 727313570Smm return (ws); 728231200Smm} 729231200Smm 730231200Smmstatic void 731231200Smmappend_id_w(wchar_t **wp, int id) 732231200Smm{ 733231200Smm if (id < 0) 734231200Smm id = 0; 735231200Smm if (id > 9) 736231200Smm append_id_w(wp, id / 10); 737231200Smm *(*wp)++ = L"0123456789"[id % 10]; 738231200Smm} 739231200Smm 740231200Smmstatic void 741313570Smmappend_entry_w(wchar_t **wp, const wchar_t *prefix, int type, 742313570Smm int tag, int flags, const wchar_t *wname, int perm, int id) 743231200Smm{ 744231200Smm if (prefix != NULL) { 745231200Smm wcscpy(*wp, prefix); 746231200Smm *wp += wcslen(*wp); 747231200Smm } 748231200Smm switch (tag) { 749231200Smm case ARCHIVE_ENTRY_ACL_USER_OBJ: 750231200Smm wname = NULL; 751231200Smm id = -1; 752313570Smm if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { 753313570Smm wcscpy(*wp, L"owner@"); 754313570Smm break; 755313570Smm } 756231200Smm /* FALLTHROUGH */ 757231200Smm case ARCHIVE_ENTRY_ACL_USER: 758231200Smm wcscpy(*wp, L"user"); 759231200Smm break; 760231200Smm case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 761231200Smm wname = NULL; 762231200Smm id = -1; 763313570Smm if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { 764313570Smm wcscpy(*wp, L"group@"); 765313570Smm break; 766313570Smm } 767231200Smm /* FALLTHROUGH */ 768231200Smm case ARCHIVE_ENTRY_ACL_GROUP: 769231200Smm wcscpy(*wp, L"group"); 770231200Smm break; 771231200Smm case ARCHIVE_ENTRY_ACL_MASK: 772231200Smm wcscpy(*wp, L"mask"); 773231200Smm wname = NULL; 774231200Smm id = -1; 775231200Smm break; 776231200Smm case ARCHIVE_ENTRY_ACL_OTHER: 777231200Smm wcscpy(*wp, L"other"); 778231200Smm wname = NULL; 779231200Smm id = -1; 780231200Smm break; 781313570Smm case ARCHIVE_ENTRY_ACL_EVERYONE: 782313570Smm wcscpy(*wp, L"everyone@"); 783313570Smm wname = NULL; 784313570Smm id = -1; 785313570Smm break; 786231200Smm } 787231200Smm *wp += wcslen(*wp); 788231200Smm *(*wp)++ = L':'; 789313570Smm if (((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) || 790313570Smm tag == ARCHIVE_ENTRY_ACL_USER || 791313570Smm tag == ARCHIVE_ENTRY_ACL_GROUP) { 792313570Smm if (wname != NULL) { 793313570Smm wcscpy(*wp, wname); 794313570Smm *wp += wcslen(*wp); 795313570Smm } else if (tag == ARCHIVE_ENTRY_ACL_USER 796313570Smm || tag == ARCHIVE_ENTRY_ACL_GROUP) { 797313570Smm append_id_w(wp, id); 798313570Smm if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0) 799313570Smm id = -1; 800313570Smm } 801313570Smm /* Solaris style has no second colon after other and mask */ 802313570Smm if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) == 0) 803313570Smm || (tag != ARCHIVE_ENTRY_ACL_OTHER 804313570Smm && tag != ARCHIVE_ENTRY_ACL_MASK)) 805313570Smm *(*wp)++ = L':'; 806313570Smm } 807313570Smm if ((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) { 808313570Smm /* POSIX.1e ACL perms */ 809313570Smm *(*wp)++ = (perm & 0444) ? L'r' : L'-'; 810313570Smm *(*wp)++ = (perm & 0222) ? L'w' : L'-'; 811313570Smm *(*wp)++ = (perm & 0111) ? L'x' : L'-'; 812313570Smm } else { 813313570Smm /* NFS4 ACL perms */ 814313570Smm *(*wp)++ = (perm & (ARCHIVE_ENTRY_ACL_READ_DATA | 815313570Smm ARCHIVE_ENTRY_ACL_LIST_DIRECTORY)) ? L'r' : L'-'; 816313570Smm *(*wp)++ = (perm & (ARCHIVE_ENTRY_ACL_WRITE_DATA | 817313570Smm ARCHIVE_ENTRY_ACL_ADD_FILE)) ? L'w' : L'-'; 818313570Smm *(*wp)++ = (perm & ARCHIVE_ENTRY_ACL_EXECUTE) ? L'x' : L'-'; 819313570Smm *(*wp)++ = (perm & (ARCHIVE_ENTRY_ACL_APPEND_DATA | 820313570Smm ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY)) ? L'p' : L'-'; 821313570Smm *(*wp)++ = (perm & ARCHIVE_ENTRY_ACL_DELETE) ? L'd' : L'-'; 822313570Smm *(*wp)++ = (perm & 823313570Smm ARCHIVE_ENTRY_ACL_DELETE_CHILD) ? L'D' : L'-'; 824313570Smm *(*wp)++ = (perm & 825313570Smm ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES) ? L'a' : L'-'; 826313570Smm *(*wp)++ = (perm & 827313570Smm ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES) ? L'A' : L'-'; 828313570Smm *(*wp)++ = (perm & 829313570Smm ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS) ? L'R' : L'-'; 830313570Smm *(*wp)++ = (perm & 831313570Smm ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS) ? L'W' : L'-'; 832313570Smm *(*wp)++ = (perm & ARCHIVE_ENTRY_ACL_READ_ACL) ? L'c' : L'-'; 833313570Smm *(*wp)++ = (perm & ARCHIVE_ENTRY_ACL_WRITE_ACL) ? L'C' : L'-'; 834313570Smm *(*wp)++ = (perm & 835313570Smm ARCHIVE_ENTRY_ACL_WRITE_OWNER) ? L'o' : L'-'; 836313570Smm *(*wp)++ = (perm & 837313570Smm ARCHIVE_ENTRY_ACL_SYNCHRONIZE) ? L's' : L'-'; 838313570Smm *(*wp)++ = L':'; 839313570Smm *(*wp)++ = (perm & 840313570Smm ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT) ? L'f' : L'-'; 841313570Smm *(*wp)++ = (perm & 842313570Smm ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT) ? L'd' : L'-'; 843313570Smm *(*wp)++ = (perm & 844313570Smm ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY) ? L'i' : L'-'; 845313570Smm *(*wp)++ = (perm & 846313570Smm ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT) ? L'n' : L'-'; 847313570Smm *(*wp)++ = (perm & 848313570Smm ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS) ? L'S' : L'-'; 849313570Smm *(*wp)++ = (perm & 850313570Smm ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS) ? L'F' : L'-'; 851313570Smm *(*wp)++ = (perm & 852313570Smm ARCHIVE_ENTRY_ACL_ENTRY_INHERITED) ? L'I' : L'-'; 853313570Smm *(*wp)++ = L':'; 854313570Smm switch (type) { 855313570Smm case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: 856313570Smm wcscpy(*wp, L"allow"); 857313570Smm break; 858313570Smm case ARCHIVE_ENTRY_ACL_TYPE_DENY: 859313570Smm wcscpy(*wp, L"deny"); 860313570Smm break; 861313570Smm case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: 862313570Smm wcscpy(*wp, L"audit"); 863313570Smm break; 864313570Smm case ARCHIVE_ENTRY_ACL_TYPE_ALARM: 865313570Smm wcscpy(*wp, L"alarm"); 866313570Smm break; 867313570Smm default: 868313570Smm break; 869313570Smm } 870231200Smm *wp += wcslen(*wp); 871231200Smm } 872231200Smm if (id != -1) { 873231200Smm *(*wp)++ = L':'; 874231200Smm append_id_w(wp, id); 875231200Smm } 876231200Smm} 877231200Smm 878313570Smm/* 879313570Smm * Generate a text version of the ACL. The flags parameter controls 880313570Smm * the type and style of the generated ACL. 881313570Smm */ 882313570Smmchar * 883313570Smmarchive_acl_to_text_l(struct archive_acl *acl, ssize_t *text_len, int flags, 884231200Smm struct archive_string_conv *sc) 885231200Smm{ 886231200Smm int count; 887313570Smm ssize_t length; 888313570Smm size_t len; 889231200Smm const char *name; 890231200Smm const char *prefix; 891231200Smm char separator; 892231200Smm struct archive_acl_entry *ap; 893313570Smm int id, r, want_type; 894313570Smm char *p, *s; 895231200Smm 896313570Smm want_type = archive_acl_text_want_type(acl, flags); 897231200Smm 898313570Smm /* Both NFSv4 and POSIX.1 types found */ 899313570Smm if (want_type == 0) 900313570Smm return (NULL); 901231200Smm 902313570Smm if (want_type == ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) 903313570Smm flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT; 904231200Smm 905313570Smm length = archive_acl_text_len(acl, want_type, flags, 0, NULL, sc); 906231200Smm 907313570Smm if (length == 0) 908313570Smm return (NULL); 909313570Smm 910313570Smm if (flags & ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA) 911313570Smm separator = ','; 912313570Smm else 913313570Smm separator = '\n'; 914313570Smm 915231200Smm /* Now, allocate the string and actually populate it. */ 916313570Smm p = s = (char *)malloc(length * sizeof(char)); 917313570Smm if (p == NULL) { 918313570Smm if (errno == ENOMEM) 919313570Smm __archive_errx(1, "No memory"); 920313570Smm return (NULL); 921313570Smm } 922231200Smm count = 0; 923313570Smm 924313570Smm if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { 925313570Smm append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 926313570Smm ARCHIVE_ENTRY_ACL_USER_OBJ, flags, NULL, 927231200Smm acl->mode & 0700, -1); 928313570Smm *p++ = separator; 929313570Smm append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 930313570Smm ARCHIVE_ENTRY_ACL_GROUP_OBJ, flags, NULL, 931231200Smm acl->mode & 0070, -1); 932313570Smm *p++ = separator; 933313570Smm append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 934313570Smm ARCHIVE_ENTRY_ACL_OTHER, flags, NULL, 935231200Smm acl->mode & 0007, -1); 936231200Smm count += 3; 937231200Smm } 938231200Smm 939313570Smm for (ap = acl->acl_head; ap != NULL; ap = ap->next) { 940313570Smm if ((ap->type & want_type) == 0) 941313570Smm continue; 942313570Smm /* 943313570Smm * Filemode-mapping ACL entries are stored exclusively in 944313570Smm * ap->mode so they should not be in the list 945313570Smm */ 946313570Smm if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) 947313570Smm && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ 948313570Smm || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ 949313570Smm || ap->tag == ARCHIVE_ENTRY_ACL_OTHER)) 950313570Smm continue; 951313570Smm if (ap->type == ARCHIVE_ENTRY_ACL_TYPE_DEFAULT && 952313570Smm (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0) 953231200Smm prefix = "default:"; 954231200Smm else 955231200Smm prefix = NULL; 956313570Smm r = archive_mstring_get_mbs_l( 957313570Smm &ap->name, &name, &len, sc); 958313570Smm if (r != 0) 959313570Smm return (NULL); 960313570Smm if (count > 0) 961313570Smm *p++ = separator; 962313570Smm if (name == NULL || 963313570Smm (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)) { 964313570Smm id = ap->id; 965313570Smm } else { 966313570Smm id = -1; 967231200Smm } 968313570Smm append_entry(&p, prefix, ap->type, ap->tag, flags, name, 969313570Smm ap->permset, id); 970313570Smm count++; 971231200Smm } 972231200Smm 973313570Smm /* Add terminating character */ 974313570Smm *p++ = '\0'; 975313570Smm 976313570Smm len = strlen(s); 977313570Smm 978313570Smm if ((ssize_t)len > (length - 1)) 979313570Smm __archive_errx(1, "Buffer overrun"); 980313570Smm 981313570Smm if (text_len != NULL) 982313570Smm *text_len = len; 983313570Smm 984313570Smm return (s); 985231200Smm} 986231200Smm 987231200Smmstatic void 988231200Smmappend_id(char **p, int id) 989231200Smm{ 990231200Smm if (id < 0) 991231200Smm id = 0; 992231200Smm if (id > 9) 993231200Smm append_id(p, id / 10); 994231200Smm *(*p)++ = "0123456789"[id % 10]; 995231200Smm} 996231200Smm 997231200Smmstatic void 998313570Smmappend_entry(char **p, const char *prefix, int type, 999313570Smm int tag, int flags, const char *name, int perm, int id) 1000231200Smm{ 1001231200Smm if (prefix != NULL) { 1002231200Smm strcpy(*p, prefix); 1003231200Smm *p += strlen(*p); 1004231200Smm } 1005231200Smm switch (tag) { 1006231200Smm case ARCHIVE_ENTRY_ACL_USER_OBJ: 1007231200Smm name = NULL; 1008231200Smm id = -1; 1009313570Smm if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { 1010313570Smm strcpy(*p, "owner@"); 1011313570Smm break; 1012313570Smm } 1013231200Smm /* FALLTHROUGH */ 1014231200Smm case ARCHIVE_ENTRY_ACL_USER: 1015231200Smm strcpy(*p, "user"); 1016231200Smm break; 1017231200Smm case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 1018231200Smm name = NULL; 1019231200Smm id = -1; 1020313570Smm if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { 1021313570Smm strcpy(*p, "group@"); 1022313570Smm break; 1023313570Smm } 1024231200Smm /* FALLTHROUGH */ 1025231200Smm case ARCHIVE_ENTRY_ACL_GROUP: 1026231200Smm strcpy(*p, "group"); 1027231200Smm break; 1028231200Smm case ARCHIVE_ENTRY_ACL_MASK: 1029231200Smm strcpy(*p, "mask"); 1030231200Smm name = NULL; 1031231200Smm id = -1; 1032231200Smm break; 1033231200Smm case ARCHIVE_ENTRY_ACL_OTHER: 1034231200Smm strcpy(*p, "other"); 1035231200Smm name = NULL; 1036231200Smm id = -1; 1037231200Smm break; 1038313570Smm case ARCHIVE_ENTRY_ACL_EVERYONE: 1039313570Smm strcpy(*p, "everyone@"); 1040313570Smm name = NULL; 1041313570Smm id = -1; 1042313570Smm break; 1043231200Smm } 1044231200Smm *p += strlen(*p); 1045231200Smm *(*p)++ = ':'; 1046313570Smm if (((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) || 1047313570Smm tag == ARCHIVE_ENTRY_ACL_USER || 1048313570Smm tag == ARCHIVE_ENTRY_ACL_GROUP) { 1049313570Smm if (name != NULL) { 1050313570Smm strcpy(*p, name); 1051313570Smm *p += strlen(*p); 1052313570Smm } else if (tag == ARCHIVE_ENTRY_ACL_USER 1053313570Smm || tag == ARCHIVE_ENTRY_ACL_GROUP) { 1054313570Smm append_id(p, id); 1055313570Smm if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0) 1056313570Smm id = -1; 1057313570Smm } 1058313570Smm /* Solaris style has no second colon after other and mask */ 1059313570Smm if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) == 0) 1060313570Smm || (tag != ARCHIVE_ENTRY_ACL_OTHER 1061313570Smm && tag != ARCHIVE_ENTRY_ACL_MASK)) 1062313570Smm *(*p)++ = ':'; 1063313570Smm } 1064313570Smm if ((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) { 1065313570Smm /* POSIX.1e ACL perms */ 1066313570Smm *(*p)++ = (perm & 0444) ? 'r' : '-'; 1067313570Smm *(*p)++ = (perm & 0222) ? 'w' : '-'; 1068313570Smm *(*p)++ = (perm & 0111) ? 'x' : '-'; 1069313570Smm } else { 1070313570Smm /* NFS4 ACL perms */ 1071313570Smm *(*p)++ = (perm & (ARCHIVE_ENTRY_ACL_READ_DATA | 1072313570Smm ARCHIVE_ENTRY_ACL_LIST_DIRECTORY)) ? 'r' : '-'; 1073313570Smm *(*p)++ = (perm & (ARCHIVE_ENTRY_ACL_WRITE_DATA | 1074313570Smm ARCHIVE_ENTRY_ACL_ADD_FILE)) ? 'w' : '-'; 1075313570Smm *(*p)++ = (perm & (ARCHIVE_ENTRY_ACL_EXECUTE)) ? 'x' : '-'; 1076313570Smm *(*p)++ = (perm & (ARCHIVE_ENTRY_ACL_APPEND_DATA | 1077313570Smm ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY)) ? 'p' : '-'; 1078313570Smm *(*p)++ = (perm & ARCHIVE_ENTRY_ACL_DELETE) ? 'd' : '-'; 1079313570Smm *(*p)++ = (perm & ARCHIVE_ENTRY_ACL_DELETE_CHILD) ? 'D' : '-'; 1080313570Smm *(*p)++ = (perm & 1081313570Smm ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES) ? 'a' : '-'; 1082313570Smm *(*p)++ = (perm & 1083313570Smm ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES) ? 'A' : '-'; 1084313570Smm *(*p)++ = (perm & 1085313570Smm ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS) ? 'R' : '-'; 1086313570Smm *(*p)++ = (perm & 1087313570Smm ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS) ? 'W' : '-'; 1088313570Smm *(*p)++ = (perm & 1089313570Smm ARCHIVE_ENTRY_ACL_READ_ACL) ? 'c' : '-'; 1090313570Smm *(*p)++ = (perm & 1091313570Smm ARCHIVE_ENTRY_ACL_WRITE_ACL) ? 'C' : '-'; 1092313570Smm *(*p)++ = (perm & 1093313570Smm ARCHIVE_ENTRY_ACL_WRITE_OWNER) ? 'o' : '-'; 1094313570Smm *(*p)++ = (perm & 1095313570Smm ARCHIVE_ENTRY_ACL_SYNCHRONIZE) ? 's' : '-'; 1096313570Smm *(*p)++ = ':'; 1097313570Smm *(*p)++ = (perm & 1098313570Smm ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT) ? 'f' : '-'; 1099313570Smm *(*p)++ = (perm & 1100313570Smm ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT) ? 'd' : '-'; 1101313570Smm *(*p)++ = (perm & 1102313570Smm ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY) ? 'i' : '-'; 1103313570Smm *(*p)++ = (perm & 1104313570Smm ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT) ? 'n' : '-'; 1105313570Smm *(*p)++ = (perm & 1106313570Smm ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS) ? 'S' : '-'; 1107313570Smm *(*p)++ = (perm & 1108313570Smm ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS) ? 'F' : '-'; 1109313570Smm *(*p)++ = (perm & 1110313570Smm ARCHIVE_ENTRY_ACL_ENTRY_INHERITED) ? 'I' : '-'; 1111313570Smm *(*p)++ = ':'; 1112313570Smm switch (type) { 1113313570Smm case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: 1114313570Smm strcpy(*p, "allow"); 1115313570Smm break; 1116313570Smm case ARCHIVE_ENTRY_ACL_TYPE_DENY: 1117313570Smm strcpy(*p, "deny"); 1118313570Smm break; 1119313570Smm case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: 1120313570Smm strcpy(*p, "audit"); 1121313570Smm break; 1122313570Smm case ARCHIVE_ENTRY_ACL_TYPE_ALARM: 1123313570Smm strcpy(*p, "alarm"); 1124313570Smm break; 1125313570Smm } 1126231200Smm *p += strlen(*p); 1127231200Smm } 1128231200Smm if (id != -1) { 1129231200Smm *(*p)++ = ':'; 1130231200Smm append_id(p, id); 1131231200Smm } 1132231200Smm} 1133231200Smm 1134231200Smm/* 1135313570Smm * Parse a wide ACL text string. 1136313570Smm * 1137313570Smm * The want_type argument may be one of the following: 1138313570Smm * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - text is a POSIX.1e ACL of type ACCESS 1139313570Smm * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - text is a POSIX.1e ACL of type DEFAULT 1140313570Smm * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - text is as a NFSv4 ACL 1141313570Smm * 1142313570Smm * POSIX.1e ACL entries prefixed with "default:" are treated as 1143313570Smm * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT unless type is ARCHIVE_ENTRY_ACL_TYPE_NFS4 1144231200Smm */ 1145231200Smmint 1146313570Smmarchive_acl_from_text_w(struct archive_acl *acl, const wchar_t *text, 1147313570Smm int want_type) 1148231200Smm{ 1149231200Smm struct { 1150231200Smm const wchar_t *start; 1151231200Smm const wchar_t *end; 1152313570Smm } field[6], name; 1153231200Smm 1154313570Smm const wchar_t *s, *st; 1155313570Smm 1156313570Smm int numfields, fields, n, r, sol, ret; 1157313570Smm int type, types, tag, permset, id; 1158313570Smm size_t len; 1159231200Smm wchar_t sep; 1160231200Smm 1161313570Smm ret = ARCHIVE_OK; 1162313570Smm types = 0; 1163313570Smm 1164313570Smm switch (want_type) { 1165313570Smm case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E: 1166313570Smm want_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 1167313570Smm case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: 1168313570Smm case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: 1169313570Smm numfields = 5; 1170313570Smm break; 1171313570Smm case ARCHIVE_ENTRY_ACL_TYPE_NFS4: 1172313570Smm numfields = 6; 1173313570Smm break; 1174313570Smm default: 1175313570Smm return (ARCHIVE_FATAL); 1176313570Smm } 1177313570Smm 1178313570Smm while (text != NULL && *text != L'\0') { 1179231200Smm /* 1180231200Smm * Parse the fields out of the next entry, 1181231200Smm * advance 'text' to start of next entry. 1182231200Smm */ 1183231200Smm fields = 0; 1184231200Smm do { 1185231200Smm const wchar_t *start, *end; 1186231200Smm next_field_w(&text, &start, &end, &sep); 1187313570Smm if (fields < numfields) { 1188231200Smm field[fields].start = start; 1189231200Smm field[fields].end = end; 1190231200Smm } 1191231200Smm ++fields; 1192231200Smm } while (sep == L':'); 1193231200Smm 1194231200Smm /* Set remaining fields to blank. */ 1195313570Smm for (n = fields; n < numfields; ++n) 1196231200Smm field[n].start = field[n].end = NULL; 1197231200Smm 1198313570Smm if (field[0].start != NULL && *(field[0].start) == L'#') { 1199313570Smm /* Comment, skip entry */ 1200313570Smm continue; 1201313570Smm } 1202313570Smm 1203313570Smm n = 0; 1204313570Smm sol = 0; 1205231200Smm id = -1; 1206313570Smm permset = 0; 1207313570Smm name.start = name.end = NULL; 1208231200Smm 1209313570Smm if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 1210313570Smm /* POSIX.1e ACLs */ 1211313570Smm /* 1212313570Smm * Default keyword "default:user::rwx" 1213313570Smm * if found, we have one more field 1214313570Smm * 1215313570Smm * We also support old Solaris extension: 1216313570Smm * "defaultuser::rwx" is the default ACL corresponding 1217313570Smm * to "user::rwx", etc. valid only for first field 1218313570Smm */ 1219313570Smm s = field[0].start; 1220313570Smm len = field[0].end - field[0].start; 1221313570Smm if (*s == L'd' && (len == 1 || (len >= 7 1222313570Smm && wmemcmp((s + 1), L"efault", 6) == 0))) { 1223313570Smm type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; 1224313570Smm if (len > 7) 1225313570Smm field[0].start += 7; 1226313570Smm else 1227313570Smm n = 1; 1228313570Smm } else 1229313570Smm type = want_type; 1230231200Smm 1231313570Smm /* Check for a numeric ID in field n+1 or n+3. */ 1232313570Smm isint_w(field[n + 1].start, field[n + 1].end, &id); 1233313570Smm /* Field n+3 is optional. */ 1234313570Smm if (id == -1 && fields > n+3) 1235313570Smm isint_w(field[n + 3].start, field[n + 3].end, 1236313570Smm &id); 1237313570Smm 1238313570Smm tag = 0; 1239313570Smm s = field[n].start; 1240313570Smm st = field[n].start + 1; 1241313570Smm len = field[n].end - field[n].start; 1242313570Smm 1243313570Smm switch (*s) { 1244313570Smm case L'u': 1245313570Smm if (len == 1 || (len == 4 1246313570Smm && wmemcmp(st, L"ser", 3) == 0)) 1247313570Smm tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 1248313570Smm break; 1249313570Smm case L'g': 1250313570Smm if (len == 1 || (len == 5 1251313570Smm && wmemcmp(st, L"roup", 4) == 0)) 1252313570Smm tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 1253313570Smm break; 1254313570Smm case L'o': 1255313570Smm if (len == 1 || (len == 5 1256313570Smm && wmemcmp(st, L"ther", 4) == 0)) 1257313570Smm tag = ARCHIVE_ENTRY_ACL_OTHER; 1258313570Smm break; 1259313570Smm case L'm': 1260313570Smm if (len == 1 || (len == 4 1261313570Smm && wmemcmp(st, L"ask", 3) == 0)) 1262313570Smm tag = ARCHIVE_ENTRY_ACL_MASK; 1263313570Smm break; 1264313570Smm default: 1265313570Smm break; 1266313570Smm } 1267313570Smm 1268313570Smm switch (tag) { 1269313570Smm case ARCHIVE_ENTRY_ACL_OTHER: 1270313570Smm case ARCHIVE_ENTRY_ACL_MASK: 1271313570Smm if (fields == (n + 2) 1272313570Smm && field[n + 1].start < field[n + 1].end 1273313570Smm && ismode_w(field[n + 1].start, 1274313570Smm field[n + 1].end, &permset)) { 1275313570Smm /* This is Solaris-style "other:rwx" */ 1276313570Smm sol = 1; 1277313570Smm } else if (fields == (n + 3) && 1278313570Smm field[n + 1].start < field[n + 1].end) { 1279313570Smm /* Invalid mask or other field */ 1280313570Smm ret = ARCHIVE_WARN; 1281313570Smm continue; 1282313570Smm } 1283313570Smm break; 1284313570Smm case ARCHIVE_ENTRY_ACL_USER_OBJ: 1285313570Smm case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 1286313570Smm if (id != -1 || 1287313570Smm field[n + 1].start < field[n + 1].end) { 1288313570Smm name = field[n + 1]; 1289313570Smm if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) 1290313570Smm tag = ARCHIVE_ENTRY_ACL_USER; 1291313570Smm else 1292313570Smm tag = ARCHIVE_ENTRY_ACL_GROUP; 1293313570Smm } 1294313570Smm break; 1295313570Smm default: 1296313570Smm /* Invalid tag, skip entry */ 1297313570Smm ret = ARCHIVE_WARN; 1298313570Smm continue; 1299313570Smm } 1300313570Smm 1301313570Smm /* 1302313570Smm * Without "default:" we expect mode in field 2 1303313570Smm * Exception: Solaris other and mask fields 1304313570Smm */ 1305313570Smm if (permset == 0 && !ismode_w(field[n + 2 - sol].start, 1306313570Smm field[n + 2 - sol].end, &permset)) { 1307313570Smm /* Invalid mode, skip entry */ 1308313570Smm ret = ARCHIVE_WARN; 1309313570Smm continue; 1310313570Smm } 1311313570Smm } else { 1312313570Smm /* NFS4 ACLs */ 1313313570Smm s = field[0].start; 1314313570Smm len = field[0].end - field[0].start; 1315313570Smm tag = 0; 1316313570Smm 1317313570Smm switch (len) { 1318313570Smm case 4: 1319313570Smm if (wmemcmp(s, L"user", 4) == 0) 1320313570Smm tag = ARCHIVE_ENTRY_ACL_USER; 1321313570Smm break; 1322313570Smm case 5: 1323313570Smm if (wmemcmp(s, L"group", 5) == 0) 1324313570Smm tag = ARCHIVE_ENTRY_ACL_GROUP; 1325313570Smm break; 1326313570Smm case 6: 1327313570Smm if (wmemcmp(s, L"owner@", 6) == 0) 1328313570Smm tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 1329313570Smm else if (wmemcmp(s, L"group@", len) == 0) 1330313570Smm tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 1331313570Smm break; 1332313570Smm case 9: 1333313570Smm if (wmemcmp(s, L"everyone@", 9) == 0) 1334313570Smm tag = ARCHIVE_ENTRY_ACL_EVERYONE; 1335313570Smm default: 1336313570Smm break; 1337313570Smm } 1338313570Smm 1339313570Smm if (tag == 0) { 1340313570Smm /* Invalid tag, skip entry */ 1341313570Smm ret = ARCHIVE_WARN; 1342313570Smm continue; 1343313570Smm } else if (tag == ARCHIVE_ENTRY_ACL_USER || 1344313570Smm tag == ARCHIVE_ENTRY_ACL_GROUP) { 1345313570Smm n = 1; 1346231200Smm name = field[1]; 1347313570Smm isint_w(name.start, name.end, &id); 1348231200Smm } else 1349313570Smm n = 0; 1350231200Smm 1351313570Smm if (!is_nfs4_perms_w(field[1 + n].start, 1352313570Smm field[1 + n].end, &permset)) { 1353313570Smm /* Invalid NFSv4 perms, skip entry */ 1354313570Smm ret = ARCHIVE_WARN; 1355313570Smm continue; 1356313570Smm } 1357313570Smm if (!is_nfs4_flags_w(field[2 + n].start, 1358313570Smm field[2 + n].end, &permset)) { 1359313570Smm /* Invalid NFSv4 flags, skip entry */ 1360313570Smm ret = ARCHIVE_WARN; 1361313570Smm continue; 1362313570Smm } 1363313570Smm s = field[3 + n].start; 1364313570Smm len = field[3 + n].end - field[3 + n].start; 1365313570Smm type = 0; 1366313570Smm if (len == 4) { 1367313570Smm if (wmemcmp(s, L"deny", 4) == 0) 1368313570Smm type = ARCHIVE_ENTRY_ACL_TYPE_DENY; 1369313570Smm } else if (len == 5) { 1370313570Smm if (wmemcmp(s, L"allow", 5) == 0) 1371313570Smm type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; 1372313570Smm else if (wmemcmp(s, L"audit", 5) == 0) 1373313570Smm type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT; 1374313570Smm else if (wmemcmp(s, L"alarm", 5) == 0) 1375313570Smm type = ARCHIVE_ENTRY_ACL_TYPE_ALARM; 1376313570Smm } 1377313570Smm if (type == 0) { 1378313570Smm /* Invalid entry type, skip entry */ 1379313570Smm ret = ARCHIVE_WARN; 1380313570Smm continue; 1381313570Smm } 1382313570Smm isint_w(field[4 + n].start, field[4 + n].end, &id); 1383313570Smm } 1384313570Smm 1385231200Smm /* Add entry to the internal list. */ 1386313570Smm r = archive_acl_add_entry_w_len(acl, type, permset, 1387231200Smm tag, id, name.start, name.end - name.start); 1388313570Smm if (r < ARCHIVE_WARN) 1389313570Smm return (r); 1390313570Smm if (r != ARCHIVE_OK) 1391313570Smm ret = ARCHIVE_WARN; 1392313570Smm types |= type; 1393231200Smm } 1394313570Smm 1395313570Smm /* Reset ACL */ 1396313570Smm archive_acl_reset(acl, types); 1397313570Smm 1398313570Smm return (ret); 1399231200Smm} 1400231200Smm 1401231200Smm/* 1402231200Smm * Parse a string to a positive decimal integer. Returns true if 1403231200Smm * the string is non-empty and consists only of decimal digits, 1404231200Smm * false otherwise. 1405231200Smm */ 1406231200Smmstatic int 1407231200Smmisint_w(const wchar_t *start, const wchar_t *end, int *result) 1408231200Smm{ 1409231200Smm int n = 0; 1410231200Smm if (start >= end) 1411231200Smm return (0); 1412231200Smm while (start < end) { 1413231200Smm if (*start < '0' || *start > '9') 1414231200Smm return (0); 1415231200Smm if (n > (INT_MAX / 10) || 1416231200Smm (n == INT_MAX / 10 && (*start - '0') > INT_MAX % 10)) { 1417231200Smm n = INT_MAX; 1418231200Smm } else { 1419231200Smm n *= 10; 1420231200Smm n += *start - '0'; 1421231200Smm } 1422231200Smm start++; 1423231200Smm } 1424231200Smm *result = n; 1425231200Smm return (1); 1426231200Smm} 1427231200Smm 1428231200Smm/* 1429231200Smm * Parse a string as a mode field. Returns true if 1430231200Smm * the string is non-empty and consists only of mode characters, 1431231200Smm * false otherwise. 1432231200Smm */ 1433231200Smmstatic int 1434231200Smmismode_w(const wchar_t *start, const wchar_t *end, int *permset) 1435231200Smm{ 1436231200Smm const wchar_t *p; 1437231200Smm 1438231200Smm if (start >= end) 1439231200Smm return (0); 1440231200Smm p = start; 1441231200Smm *permset = 0; 1442231200Smm while (p < end) { 1443231200Smm switch (*p++) { 1444313570Smm case L'r': case L'R': 1445231200Smm *permset |= ARCHIVE_ENTRY_ACL_READ; 1446231200Smm break; 1447313570Smm case L'w': case L'W': 1448231200Smm *permset |= ARCHIVE_ENTRY_ACL_WRITE; 1449231200Smm break; 1450313570Smm case L'x': case L'X': 1451231200Smm *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; 1452231200Smm break; 1453313570Smm case L'-': 1454231200Smm break; 1455231200Smm default: 1456231200Smm return (0); 1457231200Smm } 1458231200Smm } 1459231200Smm return (1); 1460231200Smm} 1461231200Smm 1462231200Smm/* 1463313570Smm * Parse a string as a NFS4 ACL permission field. 1464313570Smm * Returns true if the string is non-empty and consists only of NFS4 ACL 1465313570Smm * permission characters, false otherwise 1466313570Smm */ 1467313570Smmstatic int 1468313570Smmis_nfs4_perms_w(const wchar_t *start, const wchar_t *end, int *permset) 1469313570Smm{ 1470313570Smm const wchar_t *p; 1471313570Smm 1472313570Smm if (start >= end) 1473313570Smm return (0); 1474313570Smm p = start; 1475313570Smm while (p < end) { 1476313570Smm switch (*p++) { 1477313570Smm case L'r': 1478313570Smm *permset |= ARCHIVE_ENTRY_ACL_READ_DATA; 1479313570Smm break; 1480313570Smm case L'w': 1481313570Smm *permset |= ARCHIVE_ENTRY_ACL_WRITE_DATA; 1482313570Smm break; 1483313570Smm case L'x': 1484313570Smm *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; 1485313570Smm break; 1486313570Smm case L'p': 1487313570Smm *permset |= ARCHIVE_ENTRY_ACL_APPEND_DATA; 1488313570Smm break; 1489313570Smm case L'D': 1490313570Smm *permset |= ARCHIVE_ENTRY_ACL_DELETE_CHILD; 1491313570Smm break; 1492313570Smm case L'd': 1493313570Smm *permset |= ARCHIVE_ENTRY_ACL_DELETE; 1494313570Smm break; 1495313570Smm case L'a': 1496313570Smm *permset |= ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES; 1497313570Smm break; 1498313570Smm case L'A': 1499313570Smm *permset |= ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES; 1500313570Smm break; 1501313570Smm case L'R': 1502313570Smm *permset |= ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS; 1503313570Smm break; 1504313570Smm case L'W': 1505313570Smm *permset |= ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS; 1506313570Smm break; 1507313570Smm case L'c': 1508313570Smm *permset |= ARCHIVE_ENTRY_ACL_READ_ACL; 1509313570Smm break; 1510313570Smm case L'C': 1511313570Smm *permset |= ARCHIVE_ENTRY_ACL_WRITE_ACL; 1512313570Smm break; 1513313570Smm case L'o': 1514313570Smm *permset |= ARCHIVE_ENTRY_ACL_WRITE_OWNER; 1515313570Smm break; 1516313570Smm case L's': 1517313570Smm *permset |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE; 1518313570Smm break; 1519313570Smm case L'-': 1520313570Smm break; 1521313570Smm default: 1522313570Smm return(0); 1523313570Smm } 1524313570Smm } 1525313570Smm return (1); 1526313570Smm} 1527313570Smm 1528313570Smm/* 1529313570Smm * Parse a string as a NFS4 ACL flags field. 1530313570Smm * Returns true if the string is non-empty and consists only of NFS4 ACL 1531313570Smm * flag characters, false otherwise 1532313570Smm */ 1533313570Smmstatic int 1534313570Smmis_nfs4_flags_w(const wchar_t *start, const wchar_t *end, int *permset) 1535313570Smm{ 1536313570Smm const wchar_t *p; 1537313570Smm 1538313570Smm if (start >= end) 1539313570Smm return (0); 1540313570Smm p = start; 1541313570Smm while (p < end) { 1542313570Smm switch(*p++) { 1543313570Smm case L'f': 1544313570Smm *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT; 1545313570Smm break; 1546313570Smm case L'd': 1547313570Smm *permset |= ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT; 1548313570Smm break; 1549313570Smm case L'i': 1550313570Smm *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY; 1551313570Smm break; 1552313570Smm case L'n': 1553313570Smm *permset |= 1554313570Smm ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT; 1555313570Smm break; 1556313570Smm case L'S': 1557313570Smm *permset |= ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS; 1558313570Smm break; 1559313570Smm case L'F': 1560313570Smm *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS; 1561313570Smm break; 1562313570Smm case L'I': 1563313570Smm *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERITED; 1564313570Smm break; 1565313570Smm case L'-': 1566313570Smm break; 1567313570Smm default: 1568313570Smm return (0); 1569313570Smm } 1570313570Smm } 1571313570Smm return (1); 1572313570Smm} 1573313570Smm 1574313570Smm/* 1575231200Smm * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]". *wp is updated 1576231200Smm * to point to just after the separator. *start points to the first 1577231200Smm * character of the matched text and *end just after the last 1578231200Smm * character of the matched identifier. In particular *end - *start 1579231200Smm * is the length of the field body, not including leading or trailing 1580231200Smm * whitespace. 1581231200Smm */ 1582231200Smmstatic void 1583231200Smmnext_field_w(const wchar_t **wp, const wchar_t **start, 1584231200Smm const wchar_t **end, wchar_t *sep) 1585231200Smm{ 1586231200Smm /* Skip leading whitespace to find start of field. */ 1587231200Smm while (**wp == L' ' || **wp == L'\t' || **wp == L'\n') { 1588231200Smm (*wp)++; 1589231200Smm } 1590231200Smm *start = *wp; 1591231200Smm 1592231200Smm /* Scan for the separator. */ 1593231200Smm while (**wp != L'\0' && **wp != L',' && **wp != L':' && 1594231200Smm **wp != L'\n') { 1595231200Smm (*wp)++; 1596231200Smm } 1597231200Smm *sep = **wp; 1598231200Smm 1599231200Smm /* Trim trailing whitespace to locate end of field. */ 1600231200Smm *end = *wp - 1; 1601231200Smm while (**end == L' ' || **end == L'\t' || **end == L'\n') { 1602231200Smm (*end)--; 1603231200Smm } 1604231200Smm (*end)++; 1605231200Smm 1606231200Smm /* Adjust scanner location. */ 1607231200Smm if (**wp != L'\0') 1608231200Smm (*wp)++; 1609231200Smm} 1610231200Smm 1611231200Smm/* 1612313570Smm * Parse an ACL text string. 1613313570Smm * 1614313570Smm * The want_type argument may be one of the following: 1615313570Smm * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - text is a POSIX.1e ACL of type ACCESS 1616313570Smm * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - text is a POSIX.1e ACL of type DEFAULT 1617313570Smm * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - text is as a NFSv4 ACL 1618313570Smm * 1619313570Smm * POSIX.1e ACL entries prefixed with "default:" are treated as 1620313570Smm * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT unless type is ARCHIVE_ENTRY_ACL_TYPE_NFS4 1621231200Smm */ 1622231200Smmint 1623313570Smmarchive_acl_from_text_l(struct archive_acl *acl, const char *text, 1624313570Smm int want_type, struct archive_string_conv *sc) 1625231200Smm{ 1626231200Smm struct { 1627231200Smm const char *start; 1628231200Smm const char *end; 1629313570Smm } field[6], name; 1630231200Smm 1631313570Smm const char *s, *st; 1632313570Smm int numfields, fields, n, r, sol, ret; 1633313570Smm int type, types, tag, permset, id; 1634313570Smm size_t len; 1635231200Smm char sep; 1636231200Smm 1637313570Smm switch (want_type) { 1638313570Smm case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E: 1639313570Smm want_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 1640313570Smm case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: 1641313570Smm case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: 1642313570Smm numfields = 5; 1643313570Smm break; 1644313570Smm case ARCHIVE_ENTRY_ACL_TYPE_NFS4: 1645313570Smm numfields = 6; 1646313570Smm break; 1647313570Smm default: 1648313570Smm return (ARCHIVE_FATAL); 1649313570Smm } 1650313570Smm 1651313570Smm ret = ARCHIVE_OK; 1652313570Smm types = 0; 1653313570Smm 1654231200Smm while (text != NULL && *text != '\0') { 1655231200Smm /* 1656231200Smm * Parse the fields out of the next entry, 1657231200Smm * advance 'text' to start of next entry. 1658231200Smm */ 1659231200Smm fields = 0; 1660231200Smm do { 1661231200Smm const char *start, *end; 1662231200Smm next_field(&text, &start, &end, &sep); 1663313570Smm if (fields < numfields) { 1664231200Smm field[fields].start = start; 1665231200Smm field[fields].end = end; 1666231200Smm } 1667231200Smm ++fields; 1668231200Smm } while (sep == ':'); 1669231200Smm 1670231200Smm /* Set remaining fields to blank. */ 1671313570Smm for (n = fields; n < numfields; ++n) 1672231200Smm field[n].start = field[n].end = NULL; 1673231200Smm 1674313570Smm if (field[0].start != NULL && *(field[0].start) == '#') { 1675313570Smm /* Comment, skip entry */ 1676313570Smm continue; 1677313570Smm } 1678313570Smm 1679313570Smm n = 0; 1680313570Smm sol = 0; 1681231200Smm id = -1; 1682313570Smm permset = 0; 1683313570Smm name.start = name.end = NULL; 1684231200Smm 1685313570Smm if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 1686313570Smm /* POSIX.1e ACLs */ 1687313570Smm /* 1688313570Smm * Default keyword "default:user::rwx" 1689313570Smm * if found, we have one more field 1690313570Smm * 1691313570Smm * We also support old Solaris extension: 1692313570Smm * "defaultuser::rwx" is the default ACL corresponding 1693313570Smm * to "user::rwx", etc. valid only for first field 1694313570Smm */ 1695313570Smm s = field[0].start; 1696313570Smm len = field[0].end - field[0].start; 1697313570Smm if (*s == 'd' && (len == 1 || (len >= 7 1698313570Smm && memcmp((s + 1), "efault", 6) == 0))) { 1699313570Smm type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; 1700313570Smm if (len > 7) 1701313570Smm field[0].start += 7; 1702313570Smm else 1703313570Smm n = 1; 1704313570Smm } else 1705313570Smm type = want_type; 1706231200Smm 1707313570Smm /* Check for a numeric ID in field n+1 or n+3. */ 1708313570Smm isint(field[n + 1].start, field[n + 1].end, &id); 1709313570Smm /* Field n+3 is optional. */ 1710313570Smm if (id == -1 && fields > (n + 3)) 1711313570Smm isint(field[n + 3].start, field[n + 3].end, 1712313570Smm &id); 1713313570Smm 1714313570Smm tag = 0; 1715313570Smm s = field[n].start; 1716313570Smm st = field[n].start + 1; 1717313570Smm len = field[n].end - field[n].start; 1718313570Smm 1719313570Smm switch (*s) { 1720313570Smm case 'u': 1721313570Smm if (len == 1 || (len == 4 1722313570Smm && memcmp(st, "ser", 3) == 0)) 1723313570Smm tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 1724313570Smm break; 1725313570Smm case 'g': 1726313570Smm if (len == 1 || (len == 5 1727313570Smm && memcmp(st, "roup", 4) == 0)) 1728313570Smm tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 1729313570Smm break; 1730313570Smm case 'o': 1731313570Smm if (len == 1 || (len == 5 1732313570Smm && memcmp(st, "ther", 4) == 0)) 1733313570Smm tag = ARCHIVE_ENTRY_ACL_OTHER; 1734313570Smm break; 1735313570Smm case 'm': 1736313570Smm if (len == 1 || (len == 4 1737313570Smm && memcmp(st, "ask", 3) == 0)) 1738313570Smm tag = ARCHIVE_ENTRY_ACL_MASK; 1739313570Smm break; 1740313570Smm default: 1741313570Smm break; 1742313570Smm } 1743313570Smm 1744313570Smm switch (tag) { 1745313570Smm case ARCHIVE_ENTRY_ACL_OTHER: 1746313570Smm case ARCHIVE_ENTRY_ACL_MASK: 1747313570Smm if (fields == (n + 2) 1748313570Smm && field[n + 1].start < field[n + 1].end 1749313570Smm && ismode(field[n + 1].start, 1750313570Smm field[n + 1].end, &permset)) { 1751313570Smm /* This is Solaris-style "other:rwx" */ 1752313570Smm sol = 1; 1753313570Smm } else if (fields == (n + 3) && 1754313570Smm field[n + 1].start < field[n + 1].end) { 1755313570Smm /* Invalid mask or other field */ 1756313570Smm ret = ARCHIVE_WARN; 1757313570Smm continue; 1758313570Smm } 1759313570Smm break; 1760313570Smm case ARCHIVE_ENTRY_ACL_USER_OBJ: 1761313570Smm case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 1762313570Smm if (id != -1 || 1763313570Smm field[n + 1].start < field[n + 1].end) { 1764313570Smm name = field[n + 1]; 1765313570Smm if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) 1766313570Smm tag = ARCHIVE_ENTRY_ACL_USER; 1767313570Smm else 1768313570Smm tag = ARCHIVE_ENTRY_ACL_GROUP; 1769313570Smm } 1770313570Smm break; 1771313570Smm default: 1772313570Smm /* Invalid tag, skip entry */ 1773313570Smm ret = ARCHIVE_WARN; 1774313570Smm continue; 1775313570Smm } 1776313570Smm 1777313570Smm /* 1778313570Smm * Without "default:" we expect mode in field 3 1779313570Smm * Exception: Solaris other and mask fields 1780313570Smm */ 1781313570Smm if (permset == 0 && !ismode(field[n + 2 - sol].start, 1782313570Smm field[n + 2 - sol].end, &permset)) { 1783313570Smm /* Invalid mode, skip entry */ 1784313570Smm ret = ARCHIVE_WARN; 1785313570Smm continue; 1786313570Smm } 1787313570Smm } else { 1788313570Smm /* NFS4 ACLs */ 1789313570Smm s = field[0].start; 1790313570Smm len = field[0].end - field[0].start; 1791313570Smm tag = 0; 1792313570Smm 1793313570Smm switch (len) { 1794313570Smm case 4: 1795313570Smm if (memcmp(s, "user", 4) == 0) 1796313570Smm tag = ARCHIVE_ENTRY_ACL_USER; 1797313570Smm break; 1798313570Smm case 5: 1799313570Smm if (memcmp(s, "group", 5) == 0) 1800313570Smm tag = ARCHIVE_ENTRY_ACL_GROUP; 1801313570Smm break; 1802313570Smm case 6: 1803313570Smm if (memcmp(s, "owner@", 6) == 0) 1804313570Smm tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 1805313570Smm else if (memcmp(s, "group@", 6) == 0) 1806313570Smm tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 1807313570Smm break; 1808313570Smm case 9: 1809313570Smm if (memcmp(s, "everyone@", 9) == 0) 1810313570Smm tag = ARCHIVE_ENTRY_ACL_EVERYONE; 1811313570Smm break; 1812313570Smm default: 1813313570Smm break; 1814313570Smm } 1815313570Smm 1816313570Smm if (tag == 0) { 1817313570Smm /* Invalid tag, skip entry */ 1818313570Smm ret = ARCHIVE_WARN; 1819313570Smm continue; 1820313570Smm } else if (tag == ARCHIVE_ENTRY_ACL_USER || 1821313570Smm tag == ARCHIVE_ENTRY_ACL_GROUP) { 1822313570Smm n = 1; 1823231200Smm name = field[1]; 1824313570Smm isint(name.start, name.end, &id); 1825231200Smm } else 1826313570Smm n = 0; 1827231200Smm 1828313570Smm if (!is_nfs4_perms(field[1 + n].start, 1829313570Smm field[1 + n].end, &permset)) { 1830313570Smm /* Invalid NFSv4 perms, skip entry */ 1831313570Smm ret = ARCHIVE_WARN; 1832313570Smm continue; 1833313570Smm } 1834313570Smm if (!is_nfs4_flags(field[2 + n].start, 1835313570Smm field[2 + n].end, &permset)) { 1836313570Smm /* Invalid NFSv4 flags, skip entry */ 1837313570Smm ret = ARCHIVE_WARN; 1838313570Smm continue; 1839313570Smm } 1840313570Smm s = field[3 + n].start; 1841313570Smm len = field[3 + n].end - field[3 + n].start; 1842313570Smm type = 0; 1843313570Smm if (len == 4) { 1844313570Smm if (memcmp(s, "deny", 4) == 0) 1845313570Smm type = ARCHIVE_ENTRY_ACL_TYPE_DENY; 1846313570Smm } else if (len == 5) { 1847313570Smm if (memcmp(s, "allow", 5) == 0) 1848313570Smm type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; 1849313570Smm else if (memcmp(s, "audit", 5) == 0) 1850313570Smm type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT; 1851313570Smm else if (memcmp(s, "alarm", 5) == 0) 1852313570Smm type = ARCHIVE_ENTRY_ACL_TYPE_ALARM; 1853313570Smm } 1854313570Smm if (type == 0) { 1855313570Smm /* Invalid entry type, skip entry */ 1856313570Smm ret = ARCHIVE_WARN; 1857313570Smm continue; 1858313570Smm } 1859313570Smm isint(field[4 + n].start, field[4 + n].end, 1860313570Smm &id); 1861313570Smm } 1862313570Smm 1863231200Smm /* Add entry to the internal list. */ 1864231200Smm r = archive_acl_add_entry_len_l(acl, type, permset, 1865231200Smm tag, id, name.start, name.end - name.start, sc); 1866231200Smm if (r < ARCHIVE_WARN) 1867231200Smm return (r); 1868231200Smm if (r != ARCHIVE_OK) 1869231200Smm ret = ARCHIVE_WARN; 1870313570Smm types |= type; 1871231200Smm } 1872313570Smm 1873313570Smm /* Reset ACL */ 1874313570Smm archive_acl_reset(acl, types); 1875313570Smm 1876231200Smm return (ret); 1877231200Smm} 1878231200Smm 1879231200Smm/* 1880231200Smm * Parse a string to a positive decimal integer. Returns true if 1881231200Smm * the string is non-empty and consists only of decimal digits, 1882231200Smm * false otherwise. 1883231200Smm */ 1884231200Smmstatic int 1885231200Smmisint(const char *start, const char *end, int *result) 1886231200Smm{ 1887231200Smm int n = 0; 1888231200Smm if (start >= end) 1889231200Smm return (0); 1890231200Smm while (start < end) { 1891231200Smm if (*start < '0' || *start > '9') 1892231200Smm return (0); 1893231200Smm if (n > (INT_MAX / 10) || 1894231200Smm (n == INT_MAX / 10 && (*start - '0') > INT_MAX % 10)) { 1895231200Smm n = INT_MAX; 1896231200Smm } else { 1897231200Smm n *= 10; 1898231200Smm n += *start - '0'; 1899231200Smm } 1900231200Smm start++; 1901231200Smm } 1902231200Smm *result = n; 1903231200Smm return (1); 1904231200Smm} 1905231200Smm 1906231200Smm/* 1907231200Smm * Parse a string as a mode field. Returns true if 1908231200Smm * the string is non-empty and consists only of mode characters, 1909231200Smm * false otherwise. 1910231200Smm */ 1911231200Smmstatic int 1912231200Smmismode(const char *start, const char *end, int *permset) 1913231200Smm{ 1914231200Smm const char *p; 1915231200Smm 1916231200Smm if (start >= end) 1917231200Smm return (0); 1918231200Smm p = start; 1919231200Smm *permset = 0; 1920231200Smm while (p < end) { 1921231200Smm switch (*p++) { 1922231200Smm case 'r': case 'R': 1923231200Smm *permset |= ARCHIVE_ENTRY_ACL_READ; 1924231200Smm break; 1925231200Smm case 'w': case 'W': 1926231200Smm *permset |= ARCHIVE_ENTRY_ACL_WRITE; 1927231200Smm break; 1928231200Smm case 'x': case 'X': 1929231200Smm *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; 1930231200Smm break; 1931231200Smm case '-': 1932231200Smm break; 1933231200Smm default: 1934231200Smm return (0); 1935231200Smm } 1936231200Smm } 1937231200Smm return (1); 1938231200Smm} 1939231200Smm 1940231200Smm/* 1941313570Smm * Parse a string as a NFS4 ACL permission field. 1942313570Smm * Returns true if the string is non-empty and consists only of NFS4 ACL 1943313570Smm * permission characters, false otherwise 1944313570Smm */ 1945313570Smmstatic int 1946313570Smmis_nfs4_perms(const char *start, const char *end, int *permset) 1947313570Smm{ 1948313570Smm const char *p; 1949313570Smm 1950313570Smm if (start >= end) 1951313570Smm return (0); 1952313570Smm p = start; 1953313570Smm while (p < end) { 1954313570Smm switch (*p++) { 1955313570Smm case 'r': 1956313570Smm *permset |= ARCHIVE_ENTRY_ACL_READ_DATA; 1957313570Smm break; 1958313570Smm case 'w': 1959313570Smm *permset |= ARCHIVE_ENTRY_ACL_WRITE_DATA; 1960313570Smm break; 1961313570Smm case 'x': 1962313570Smm *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; 1963313570Smm break; 1964313570Smm case 'p': 1965313570Smm *permset |= ARCHIVE_ENTRY_ACL_APPEND_DATA; 1966313570Smm break; 1967313570Smm case 'D': 1968313570Smm *permset |= ARCHIVE_ENTRY_ACL_DELETE_CHILD; 1969313570Smm break; 1970313570Smm case 'd': 1971313570Smm *permset |= ARCHIVE_ENTRY_ACL_DELETE; 1972313570Smm break; 1973313570Smm case 'a': 1974313570Smm *permset |= ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES; 1975313570Smm break; 1976313570Smm case 'A': 1977313570Smm *permset |= ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES; 1978313570Smm break; 1979313570Smm case 'R': 1980313570Smm *permset |= ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS; 1981313570Smm break; 1982313570Smm case 'W': 1983313570Smm *permset |= ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS; 1984313570Smm break; 1985313570Smm case 'c': 1986313570Smm *permset |= ARCHIVE_ENTRY_ACL_READ_ACL; 1987313570Smm break; 1988313570Smm case 'C': 1989313570Smm *permset |= ARCHIVE_ENTRY_ACL_WRITE_ACL; 1990313570Smm break; 1991313570Smm case 'o': 1992313570Smm *permset |= ARCHIVE_ENTRY_ACL_WRITE_OWNER; 1993313570Smm break; 1994313570Smm case 's': 1995313570Smm *permset |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE; 1996313570Smm break; 1997313570Smm case '-': 1998313570Smm break; 1999313570Smm default: 2000313570Smm return(0); 2001313570Smm } 2002313570Smm } 2003313570Smm return (1); 2004313570Smm} 2005313570Smm 2006313570Smm/* 2007313570Smm * Parse a string as a NFS4 ACL flags field. 2008313570Smm * Returns true if the string is non-empty and consists only of NFS4 ACL 2009313570Smm * flag characters, false otherwise 2010313570Smm */ 2011313570Smmstatic int 2012313570Smmis_nfs4_flags(const char *start, const char *end, int *permset) 2013313570Smm{ 2014313570Smm const char *p; 2015313570Smm 2016313570Smm if (start >= end) 2017313570Smm return (0); 2018313570Smm p = start; 2019313570Smm while (p < end) { 2020313570Smm switch(*p++) { 2021313570Smm case 'f': 2022313570Smm *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT; 2023313570Smm break; 2024313570Smm case 'd': 2025313570Smm *permset |= ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT; 2026313570Smm break; 2027313570Smm case 'i': 2028313570Smm *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY; 2029313570Smm break; 2030313570Smm case 'n': 2031313570Smm *permset |= 2032313570Smm ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT; 2033313570Smm break; 2034313570Smm case 'S': 2035313570Smm *permset |= ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS; 2036313570Smm break; 2037313570Smm case 'F': 2038313570Smm *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS; 2039313570Smm break; 2040313570Smm case 'I': 2041313570Smm *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERITED; 2042313570Smm break; 2043313570Smm case '-': 2044313570Smm break; 2045313570Smm default: 2046313570Smm return (0); 2047313570Smm } 2048313570Smm } 2049313570Smm return (1); 2050313570Smm} 2051313570Smm 2052313570Smm/* 2053231200Smm * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]". *wp is updated 2054231200Smm * to point to just after the separator. *start points to the first 2055231200Smm * character of the matched text and *end just after the last 2056231200Smm * character of the matched identifier. In particular *end - *start 2057231200Smm * is the length of the field body, not including leading or trailing 2058231200Smm * whitespace. 2059231200Smm */ 2060231200Smmstatic void 2061231200Smmnext_field(const char **p, const char **start, 2062231200Smm const char **end, char *sep) 2063231200Smm{ 2064231200Smm /* Skip leading whitespace to find start of field. */ 2065231200Smm while (**p == ' ' || **p == '\t' || **p == '\n') { 2066231200Smm (*p)++; 2067231200Smm } 2068231200Smm *start = *p; 2069231200Smm 2070231200Smm /* Scan for the separator. */ 2071231200Smm while (**p != '\0' && **p != ',' && **p != ':' && **p != '\n') { 2072231200Smm (*p)++; 2073231200Smm } 2074231200Smm *sep = **p; 2075231200Smm 2076231200Smm /* Trim trailing whitespace to locate end of field. */ 2077231200Smm *end = *p - 1; 2078231200Smm while (**end == ' ' || **end == '\t' || **end == '\n') { 2079231200Smm (*end)--; 2080231200Smm } 2081231200Smm (*end)++; 2082231200Smm 2083231200Smm /* Adjust scanner location. */ 2084231200Smm if (**p != '\0') 2085231200Smm (*p)++; 2086231200Smm} 2087