1 /*- 2 * Copyright (c) 2003-2010 Tim Kientzle 3 * Copyright (c) 2016 Martin Matuska 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "archive_platform.h" 28 __FBSDID("$FreeBSD$"); 29 30 #ifdef HAVE_ERRNO_H 31 #include <errno.h> 32 #endif 33 #ifdef HAVE_LIMITS_H 34 #include <limits.h> 35 #endif 36 #ifdef HAVE_WCHAR_H 37 #include <wchar.h> 38 #endif 39 40 #include "archive_acl_private.h" 41 #include "archive_entry.h" 42 #include "archive_private.h" 43 44 #undef max 45 #define max(a, b) ((a)>(b)?(a):(b)) 46 47 #ifndef HAVE_WMEMCMP 48 /* Good enough for simple equality testing, but not for sorting. */ 49 #define wmemcmp(a,b,i) memcmp((a), (b), (i) * sizeof(wchar_t)) 50 #endif 51 52 static int acl_special(struct archive_acl *acl, 53 int type, int permset, int tag); 54 static struct archive_acl_entry *acl_new_entry(struct archive_acl *acl, 55 int type, int permset, int tag, int id); 56 static int archive_acl_add_entry_len_l(struct archive_acl *acl, 57 int type, int permset, int tag, int id, const char *name, 58 size_t len, struct archive_string_conv *sc); 59 static int archive_acl_text_want_type(struct archive_acl *acl, int flags); 60 static ssize_t archive_acl_text_len(struct archive_acl *acl, int want_type, 61 int flags, int wide, struct archive *a, 62 struct archive_string_conv *sc); 63 static int isint_w(const wchar_t *start, const wchar_t *end, int *result); 64 static int ismode_w(const wchar_t *start, const wchar_t *end, int *result); 65 static int is_nfs4_flags_w(const wchar_t *start, const wchar_t *end, 66 int *result); 67 static int is_nfs4_perms_w(const wchar_t *start, const wchar_t *end, 68 int *result); 69 static void next_field_w(const wchar_t **wp, const wchar_t **start, 70 const wchar_t **end, wchar_t *sep); 71 static void append_entry_w(wchar_t **wp, const wchar_t *prefix, int type, 72 int tag, int flags, const wchar_t *wname, int perm, int id); 73 static void append_id_w(wchar_t **wp, int id); 74 static int isint(const char *start, const char *end, int *result); 75 static int ismode(const char *start, const char *end, int *result); 76 static int is_nfs4_flags(const char *start, const char *end, 77 int *result); 78 static int is_nfs4_perms(const char *start, const char *end, 79 int *result); 80 static void next_field(const char **p, const char **start, 81 const char **end, char *sep); 82 static void append_entry(char **p, const char *prefix, int type, 83 int tag, int flags, const char *name, int perm, int id); 84 static void append_id(char **p, int id); 85 86 static const struct { 87 const int perm; 88 const char c; 89 const wchar_t wc; 90 } nfsv4_acl_perm_map[] = { 91 { ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, 'r', 92 L'r' }, 93 { ARCHIVE_ENTRY_ACL_WRITE_DATA | ARCHIVE_ENTRY_ACL_ADD_FILE, 'w', 94 L'w' }, 95 { ARCHIVE_ENTRY_ACL_EXECUTE, 'x', L'x' }, 96 { ARCHIVE_ENTRY_ACL_APPEND_DATA | ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, 97 'p', L'p' }, 98 { ARCHIVE_ENTRY_ACL_DELETE, 'd', L'd' }, 99 { ARCHIVE_ENTRY_ACL_DELETE_CHILD, 'D', L'D' }, 100 { ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, 'a', L'a' }, 101 { ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, 'A', L'A' }, 102 { ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, 'R', L'R' }, 103 { ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, 'W', L'W' }, 104 { ARCHIVE_ENTRY_ACL_READ_ACL, 'c', L'c' }, 105 { ARCHIVE_ENTRY_ACL_WRITE_ACL, 'C', L'C' }, 106 { ARCHIVE_ENTRY_ACL_WRITE_OWNER, 'o', L'o' }, 107 { ARCHIVE_ENTRY_ACL_SYNCHRONIZE, 's', L's' } 108 }; 109 110 static const int nfsv4_acl_perm_map_size = (int)(sizeof(nfsv4_acl_perm_map) / 111 sizeof(nfsv4_acl_perm_map[0])); 112 113 static const struct { 114 const int perm; 115 const char c; 116 const wchar_t wc; 117 } nfsv4_acl_flag_map[] = { 118 { ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, 'f', L'f' }, 119 { ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, 'd', L'd' }, 120 { ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, 'i', L'i' }, 121 { ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, 'n', L'n' }, 122 { ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, 'S', L'S' }, 123 { ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, 'F', L'F' }, 124 { ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, 'I', L'I' } 125 }; 126 127 static const int nfsv4_acl_flag_map_size = (int)(sizeof(nfsv4_acl_flag_map) / 128 sizeof(nfsv4_acl_flag_map[0])); 129 130 void 131 archive_acl_clear(struct archive_acl *acl) 132 { 133 struct archive_acl_entry *ap; 134 135 while (acl->acl_head != NULL) { 136 ap = acl->acl_head->next; 137 archive_mstring_clean(&acl->acl_head->name); 138 free(acl->acl_head); 139 acl->acl_head = ap; 140 } 141 free(acl->acl_text_w); 142 acl->acl_text_w = NULL; 143 free(acl->acl_text); 144 acl->acl_text = NULL; 145 acl->acl_p = NULL; 146 acl->acl_types = 0; 147 acl->acl_state = 0; /* Not counting. */ 148 } 149 150 void 151 archive_acl_copy(struct archive_acl *dest, struct archive_acl *src) 152 { 153 struct archive_acl_entry *ap, *ap2; 154 155 archive_acl_clear(dest); 156 157 dest->mode = src->mode; 158 ap = src->acl_head; 159 while (ap != NULL) { 160 ap2 = acl_new_entry(dest, 161 ap->type, ap->permset, ap->tag, ap->id); 162 if (ap2 != NULL) 163 archive_mstring_copy(&ap2->name, &ap->name); 164 ap = ap->next; 165 } 166 } 167 168 int 169 archive_acl_add_entry(struct archive_acl *acl, 170 int type, int permset, int tag, int id, const char *name) 171 { 172 struct archive_acl_entry *ap; 173 174 if (acl_special(acl, type, permset, tag) == 0) 175 return ARCHIVE_OK; 176 ap = acl_new_entry(acl, type, permset, tag, id); 177 if (ap == NULL) { 178 /* XXX Error XXX */ 179 return ARCHIVE_FAILED; 180 } 181 if (name != NULL && *name != '\0') 182 archive_mstring_copy_mbs(&ap->name, name); 183 else 184 archive_mstring_clean(&ap->name); 185 return ARCHIVE_OK; 186 } 187 188 int 189 archive_acl_add_entry_w_len(struct archive_acl *acl, 190 int type, int permset, int tag, int id, const wchar_t *name, size_t len) 191 { 192 struct archive_acl_entry *ap; 193 194 if (acl_special(acl, type, permset, tag) == 0) 195 return ARCHIVE_OK; 196 ap = acl_new_entry(acl, type, permset, tag, id); 197 if (ap == NULL) { 198 /* XXX Error XXX */ 199 return ARCHIVE_FAILED; 200 } 201 if (name != NULL && *name != L'\0' && len > 0) 202 archive_mstring_copy_wcs_len(&ap->name, name, len); 203 else 204 archive_mstring_clean(&ap->name); 205 return ARCHIVE_OK; 206 } 207 208 static int 209 archive_acl_add_entry_len_l(struct archive_acl *acl, 210 int type, int permset, int tag, int id, const char *name, size_t len, 211 struct archive_string_conv *sc) 212 { 213 struct archive_acl_entry *ap; 214 int r; 215 216 if (acl_special(acl, type, permset, tag) == 0) 217 return ARCHIVE_OK; 218 ap = acl_new_entry(acl, type, permset, tag, id); 219 if (ap == NULL) { 220 /* XXX Error XXX */ 221 return ARCHIVE_FAILED; 222 } 223 if (name != NULL && *name != '\0' && len > 0) { 224 r = archive_mstring_copy_mbs_len_l(&ap->name, name, len, sc); 225 } else { 226 r = 0; 227 archive_mstring_clean(&ap->name); 228 } 229 if (r == 0) 230 return (ARCHIVE_OK); 231 else if (errno == ENOMEM) 232 return (ARCHIVE_FATAL); 233 else 234 return (ARCHIVE_WARN); 235 } 236 237 /* 238 * If this ACL entry is part of the standard POSIX permissions set, 239 * store the permissions in the stat structure and return zero. 240 */ 241 static int 242 acl_special(struct archive_acl *acl, int type, int permset, int tag) 243 { 244 if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS 245 && ((permset & ~007) == 0)) { 246 switch (tag) { 247 case ARCHIVE_ENTRY_ACL_USER_OBJ: 248 acl->mode &= ~0700; 249 acl->mode |= (permset & 7) << 6; 250 return (0); 251 case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 252 acl->mode &= ~0070; 253 acl->mode |= (permset & 7) << 3; 254 return (0); 255 case ARCHIVE_ENTRY_ACL_OTHER: 256 acl->mode &= ~0007; 257 acl->mode |= permset & 7; 258 return (0); 259 } 260 } 261 return (1); 262 } 263 264 /* 265 * Allocate and populate a new ACL entry with everything but the 266 * name. 267 */ 268 static struct archive_acl_entry * 269 acl_new_entry(struct archive_acl *acl, 270 int type, int permset, int tag, int id) 271 { 272 struct archive_acl_entry *ap, *aq; 273 274 /* Type argument must be a valid NFS4 or POSIX.1e type. 275 * The type must agree with anything already set and 276 * the permset must be compatible. */ 277 if (type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 278 if (acl->acl_types & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 279 return (NULL); 280 } 281 if (permset & 282 ~(ARCHIVE_ENTRY_ACL_PERMS_NFS4 283 | ARCHIVE_ENTRY_ACL_INHERITANCE_NFS4)) { 284 return (NULL); 285 } 286 } else if (type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) { 287 if (acl->acl_types & ~ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) { 288 return (NULL); 289 } 290 if (permset & ~ARCHIVE_ENTRY_ACL_PERMS_POSIX1E) { 291 return (NULL); 292 } 293 } else { 294 return (NULL); 295 } 296 297 /* Verify the tag is valid and compatible with NFS4 or POSIX.1e. */ 298 switch (tag) { 299 case ARCHIVE_ENTRY_ACL_USER: 300 case ARCHIVE_ENTRY_ACL_USER_OBJ: 301 case ARCHIVE_ENTRY_ACL_GROUP: 302 case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 303 /* Tags valid in both NFS4 and POSIX.1e */ 304 break; 305 case ARCHIVE_ENTRY_ACL_MASK: 306 case ARCHIVE_ENTRY_ACL_OTHER: 307 /* Tags valid only in POSIX.1e. */ 308 if (type & ~ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) { 309 return (NULL); 310 } 311 break; 312 case ARCHIVE_ENTRY_ACL_EVERYONE: 313 /* Tags valid only in NFS4. */ 314 if (type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 315 return (NULL); 316 } 317 break; 318 default: 319 /* No other values are valid. */ 320 return (NULL); 321 } 322 323 free(acl->acl_text_w); 324 acl->acl_text_w = NULL; 325 free(acl->acl_text); 326 acl->acl_text = NULL; 327 328 /* 329 * If there's a matching entry already in the list, overwrite it. 330 * NFSv4 entries may be repeated and are not overwritten. 331 * 332 * TODO: compare names of no id is provided (needs more rework) 333 */ 334 ap = acl->acl_head; 335 aq = NULL; 336 while (ap != NULL) { 337 if (((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0) && 338 ap->type == type && ap->tag == tag && ap->id == id) { 339 if (id != -1 || (tag != ARCHIVE_ENTRY_ACL_USER && 340 tag != ARCHIVE_ENTRY_ACL_GROUP)) { 341 ap->permset = permset; 342 return (ap); 343 } 344 } 345 aq = ap; 346 ap = ap->next; 347 } 348 349 /* Add a new entry to the end of the list. */ 350 ap = (struct archive_acl_entry *)calloc(1, sizeof(*ap)); 351 if (ap == NULL) 352 return (NULL); 353 if (aq == NULL) 354 acl->acl_head = ap; 355 else 356 aq->next = ap; 357 ap->type = type; 358 ap->tag = tag; 359 ap->id = id; 360 ap->permset = permset; 361 acl->acl_types |= type; 362 return (ap); 363 } 364 365 /* 366 * Return a count of entries matching "want_type". 367 */ 368 int 369 archive_acl_count(struct archive_acl *acl, int want_type) 370 { 371 int count; 372 struct archive_acl_entry *ap; 373 374 count = 0; 375 ap = acl->acl_head; 376 while (ap != NULL) { 377 if ((ap->type & want_type) != 0) 378 count++; 379 ap = ap->next; 380 } 381 382 if (count > 0 && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)) 383 count += 3; 384 return (count); 385 } 386 387 /* 388 * Return a bitmask of stored ACL types in an ACL list 389 */ 390 int 391 archive_acl_types(struct archive_acl *acl) 392 { 393 return (acl->acl_types); 394 } 395 396 /* 397 * Prepare for reading entries from the ACL data. Returns a count 398 * of entries matching "want_type", or zero if there are no 399 * non-extended ACL entries of that type. 400 */ 401 int 402 archive_acl_reset(struct archive_acl *acl, int want_type) 403 { 404 int count, cutoff; 405 406 count = archive_acl_count(acl, want_type); 407 408 /* 409 * If the only entries are the three standard ones, 410 * then don't return any ACL data. (In this case, 411 * client can just use chmod(2) to set permissions.) 412 */ 413 if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) 414 cutoff = 3; 415 else 416 cutoff = 0; 417 418 if (count > cutoff) 419 acl->acl_state = ARCHIVE_ENTRY_ACL_USER_OBJ; 420 else 421 acl->acl_state = 0; 422 acl->acl_p = acl->acl_head; 423 return (count); 424 } 425 426 427 /* 428 * Return the next ACL entry in the list. Fake entries for the 429 * standard permissions and include them in the returned list. 430 */ 431 int 432 archive_acl_next(struct archive *a, struct archive_acl *acl, int want_type, 433 int *type, int *permset, int *tag, int *id, const char **name) 434 { 435 *name = NULL; 436 *id = -1; 437 438 /* 439 * The acl_state is either zero (no entries available), -1 440 * (reading from list), or an entry type (retrieve that type 441 * from ae_stat.aest_mode). 442 */ 443 if (acl->acl_state == 0) 444 return (ARCHIVE_WARN); 445 446 /* The first three access entries are special. */ 447 if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { 448 switch (acl->acl_state) { 449 case ARCHIVE_ENTRY_ACL_USER_OBJ: 450 *permset = (acl->mode >> 6) & 7; 451 *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 452 *tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 453 acl->acl_state = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 454 return (ARCHIVE_OK); 455 case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 456 *permset = (acl->mode >> 3) & 7; 457 *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 458 *tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 459 acl->acl_state = ARCHIVE_ENTRY_ACL_OTHER; 460 return (ARCHIVE_OK); 461 case ARCHIVE_ENTRY_ACL_OTHER: 462 *permset = acl->mode & 7; 463 *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 464 *tag = ARCHIVE_ENTRY_ACL_OTHER; 465 acl->acl_state = -1; 466 acl->acl_p = acl->acl_head; 467 return (ARCHIVE_OK); 468 default: 469 break; 470 } 471 } 472 473 while (acl->acl_p != NULL && (acl->acl_p->type & want_type) == 0) 474 acl->acl_p = acl->acl_p->next; 475 if (acl->acl_p == NULL) { 476 acl->acl_state = 0; 477 *type = 0; 478 *permset = 0; 479 *tag = 0; 480 *id = -1; 481 *name = NULL; 482 return (ARCHIVE_EOF); /* End of ACL entries. */ 483 } 484 *type = acl->acl_p->type; 485 *permset = acl->acl_p->permset; 486 *tag = acl->acl_p->tag; 487 *id = acl->acl_p->id; 488 if (archive_mstring_get_mbs(a, &acl->acl_p->name, name) != 0) { 489 if (errno == ENOMEM) 490 return (ARCHIVE_FATAL); 491 *name = NULL; 492 } 493 acl->acl_p = acl->acl_p->next; 494 return (ARCHIVE_OK); 495 } 496 497 /* 498 * Determine what type of ACL do we want 499 */ 500 static int 501 archive_acl_text_want_type(struct archive_acl *acl, int flags) 502 { 503 int want_type; 504 505 /* Check if ACL is NFSv4 */ 506 if ((acl->acl_types & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { 507 /* NFSv4 should never mix with POSIX.1e */ 508 if ((acl->acl_types & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) 509 return (0); 510 else 511 return (ARCHIVE_ENTRY_ACL_TYPE_NFS4); 512 } 513 514 /* Now deal with POSIX.1e ACLs */ 515 516 want_type = 0; 517 if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) 518 want_type |= ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 519 if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) 520 want_type |= ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; 521 522 /* By default we want both access and default ACLs */ 523 if (want_type == 0) 524 return (ARCHIVE_ENTRY_ACL_TYPE_POSIX1E); 525 526 return (want_type); 527 } 528 529 /* 530 * Calculate ACL text string length 531 */ 532 static ssize_t 533 archive_acl_text_len(struct archive_acl *acl, int want_type, int flags, 534 int wide, struct archive *a, struct archive_string_conv *sc) { 535 struct archive_acl_entry *ap; 536 const char *name; 537 const wchar_t *wname; 538 int count, idlen, tmp, r; 539 ssize_t length; 540 size_t len; 541 542 count = 0; 543 length = 0; 544 for (ap = acl->acl_head; ap != NULL; ap = ap->next) { 545 if ((ap->type & want_type) == 0) 546 continue; 547 /* 548 * Filemode-mapping ACL entries are stored exclusively in 549 * ap->mode so they should not be in the list 550 */ 551 if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) 552 && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ 553 || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ 554 || ap->tag == ARCHIVE_ENTRY_ACL_OTHER)) 555 continue; 556 count++; 557 if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0 558 && (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) 559 length += 8; /* "default:" */ 560 switch (ap->tag) { 561 case ARCHIVE_ENTRY_ACL_USER_OBJ: 562 if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 563 length += 6; /* "owner@" */ 564 break; 565 } 566 /* FALLTHROUGH */ 567 case ARCHIVE_ENTRY_ACL_USER: 568 case ARCHIVE_ENTRY_ACL_MASK: 569 length += 4; /* "user", "mask" */ 570 break; 571 case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 572 if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 573 length += 6; /* "group@" */ 574 break; 575 } 576 /* FALLTHROUGH */ 577 case ARCHIVE_ENTRY_ACL_GROUP: 578 case ARCHIVE_ENTRY_ACL_OTHER: 579 length += 5; /* "group", "other" */ 580 break; 581 case ARCHIVE_ENTRY_ACL_EVERYONE: 582 length += 9; /* "everyone@" */ 583 break; 584 } 585 length += 1; /* colon after tag */ 586 if (ap->tag == ARCHIVE_ENTRY_ACL_USER || 587 ap->tag == ARCHIVE_ENTRY_ACL_GROUP) { 588 if (wide) { 589 r = archive_mstring_get_wcs(a, &ap->name, 590 &wname); 591 if (r == 0 && wname != NULL) 592 length += wcslen(wname); 593 else if (r < 0 && errno == ENOMEM) 594 return (0); 595 else 596 length += sizeof(uid_t) * 3 + 1; 597 } else { 598 r = archive_mstring_get_mbs_l(&ap->name, &name, 599 &len, sc); 600 if (r != 0) 601 return (0); 602 if (len > 0 && name != NULL) 603 length += len; 604 else 605 length += sizeof(uid_t) * 3 + 1; 606 } 607 length += 1; /* colon after user or group name */ 608 } else if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) 609 length += 1; /* 2nd colon empty user,group or other */ 610 611 if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) != 0) 612 && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) 613 && (ap->tag == ARCHIVE_ENTRY_ACL_OTHER 614 || ap->tag == ARCHIVE_ENTRY_ACL_MASK)) { 615 /* Solaris has no colon after other: and mask: */ 616 length = length - 1; 617 } 618 619 if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 620 /* rwxpdDaARWcCos:fdinSFI:deny */ 621 length += 27; 622 if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DENY) == 0) 623 length += 1; /* allow, alarm, audit */ 624 } else 625 length += 3; /* rwx */ 626 627 if ((ap->tag == ARCHIVE_ENTRY_ACL_USER || 628 ap->tag == ARCHIVE_ENTRY_ACL_GROUP) && 629 (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) != 0) { 630 length += 1; /* colon */ 631 /* ID digit count */ 632 idlen = 1; 633 tmp = ap->id; 634 while (tmp > 9) { 635 tmp = tmp / 10; 636 idlen++; 637 } 638 length += idlen; 639 } 640 length ++; /* entry separator */ 641 } 642 643 /* Add filemode-mapping access entries to the length */ 644 if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { 645 if ((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) != 0) { 646 /* "user::rwx\ngroup::rwx\nother:rwx\n" */ 647 length += 31; 648 } else { 649 /* "user::rwx\ngroup::rwx\nother::rwx\n" */ 650 length += 32; 651 } 652 } else if (count == 0) 653 return (0); 654 655 /* The terminating character is included in count */ 656 return (length); 657 } 658 659 /* 660 * Generate a wide text version of the ACL. The flags parameter controls 661 * the type and style of the generated ACL. 662 */ 663 wchar_t * 664 archive_acl_to_text_w(struct archive_acl *acl, ssize_t *text_len, int flags, 665 struct archive *a) 666 { 667 int count; 668 ssize_t length; 669 size_t len; 670 const wchar_t *wname; 671 const wchar_t *prefix; 672 wchar_t separator; 673 struct archive_acl_entry *ap; 674 int id, r, want_type; 675 wchar_t *wp, *ws; 676 677 want_type = archive_acl_text_want_type(acl, flags); 678 679 /* Both NFSv4 and POSIX.1 types found */ 680 if (want_type == 0) 681 return (NULL); 682 683 if (want_type == ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) 684 flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT; 685 686 length = archive_acl_text_len(acl, want_type, flags, 1, a, NULL); 687 688 if (length == 0) 689 return (NULL); 690 691 if (flags & ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA) 692 separator = L','; 693 else 694 separator = L'\n'; 695 696 /* Now, allocate the string and actually populate it. */ 697 wp = ws = (wchar_t *)malloc(length * sizeof(wchar_t)); 698 if (wp == NULL) { 699 if (errno == ENOMEM) 700 __archive_errx(1, "No memory"); 701 return (NULL); 702 } 703 count = 0; 704 705 if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { 706 append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 707 ARCHIVE_ENTRY_ACL_USER_OBJ, flags, NULL, 708 acl->mode & 0700, -1); 709 *wp++ = separator; 710 append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 711 ARCHIVE_ENTRY_ACL_GROUP_OBJ, flags, NULL, 712 acl->mode & 0070, -1); 713 *wp++ = separator; 714 append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 715 ARCHIVE_ENTRY_ACL_OTHER, flags, NULL, 716 acl->mode & 0007, -1); 717 count += 3; 718 } 719 720 for (ap = acl->acl_head; ap != NULL; ap = ap->next) { 721 if ((ap->type & want_type) == 0) 722 continue; 723 /* 724 * Filemode-mapping ACL entries are stored exclusively in 725 * ap->mode so they should not be in the list 726 */ 727 if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) 728 && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ 729 || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ 730 || ap->tag == ARCHIVE_ENTRY_ACL_OTHER)) 731 continue; 732 if (ap->type == ARCHIVE_ENTRY_ACL_TYPE_DEFAULT && 733 (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0) 734 prefix = L"default:"; 735 else 736 prefix = NULL; 737 r = archive_mstring_get_wcs(a, &ap->name, &wname); 738 if (r == 0) { 739 if (count > 0) 740 *wp++ = separator; 741 if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) 742 id = ap->id; 743 else 744 id = -1; 745 append_entry_w(&wp, prefix, ap->type, ap->tag, flags, 746 wname, ap->permset, id); 747 count++; 748 } else if (r < 0 && errno == ENOMEM) { 749 free(ws); 750 return (NULL); 751 } 752 } 753 754 /* Add terminating character */ 755 *wp++ = L'\0'; 756 757 len = wcslen(ws); 758 759 if ((ssize_t)len > (length - 1)) 760 __archive_errx(1, "Buffer overrun"); 761 762 if (text_len != NULL) 763 *text_len = len; 764 765 return (ws); 766 } 767 768 static void 769 append_id_w(wchar_t **wp, int id) 770 { 771 if (id < 0) 772 id = 0; 773 if (id > 9) 774 append_id_w(wp, id / 10); 775 *(*wp)++ = L"0123456789"[id % 10]; 776 } 777 778 static void 779 append_entry_w(wchar_t **wp, const wchar_t *prefix, int type, 780 int tag, int flags, const wchar_t *wname, int perm, int id) 781 { 782 int i; 783 784 if (prefix != NULL) { 785 wcscpy(*wp, prefix); 786 *wp += wcslen(*wp); 787 } 788 switch (tag) { 789 case ARCHIVE_ENTRY_ACL_USER_OBJ: 790 wname = NULL; 791 id = -1; 792 if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { 793 wcscpy(*wp, L"owner@"); 794 break; 795 } 796 /* FALLTHROUGH */ 797 case ARCHIVE_ENTRY_ACL_USER: 798 wcscpy(*wp, L"user"); 799 break; 800 case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 801 wname = NULL; 802 id = -1; 803 if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { 804 wcscpy(*wp, L"group@"); 805 break; 806 } 807 /* FALLTHROUGH */ 808 case ARCHIVE_ENTRY_ACL_GROUP: 809 wcscpy(*wp, L"group"); 810 break; 811 case ARCHIVE_ENTRY_ACL_MASK: 812 wcscpy(*wp, L"mask"); 813 wname = NULL; 814 id = -1; 815 break; 816 case ARCHIVE_ENTRY_ACL_OTHER: 817 wcscpy(*wp, L"other"); 818 wname = NULL; 819 id = -1; 820 break; 821 case ARCHIVE_ENTRY_ACL_EVERYONE: 822 wcscpy(*wp, L"everyone@"); 823 wname = NULL; 824 id = -1; 825 break; 826 } 827 *wp += wcslen(*wp); 828 *(*wp)++ = L':'; 829 if (((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) || 830 tag == ARCHIVE_ENTRY_ACL_USER || 831 tag == ARCHIVE_ENTRY_ACL_GROUP) { 832 if (wname != NULL) { 833 wcscpy(*wp, wname); 834 *wp += wcslen(*wp); 835 } else if (tag == ARCHIVE_ENTRY_ACL_USER 836 || tag == ARCHIVE_ENTRY_ACL_GROUP) { 837 append_id_w(wp, id); 838 if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0) 839 id = -1; 840 } 841 /* Solaris style has no second colon after other and mask */ 842 if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) == 0) 843 || (tag != ARCHIVE_ENTRY_ACL_OTHER 844 && tag != ARCHIVE_ENTRY_ACL_MASK)) 845 *(*wp)++ = L':'; 846 } 847 if ((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) { 848 /* POSIX.1e ACL perms */ 849 *(*wp)++ = (perm & 0444) ? L'r' : L'-'; 850 *(*wp)++ = (perm & 0222) ? L'w' : L'-'; 851 *(*wp)++ = (perm & 0111) ? L'x' : L'-'; 852 } else { 853 /* NFSv4 ACL perms */ 854 for (i = 0; i < nfsv4_acl_perm_map_size; i++) { 855 if (perm & nfsv4_acl_perm_map[i].perm) 856 *(*wp)++ = nfsv4_acl_perm_map[i].wc; 857 else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0) 858 *(*wp)++ = L'-'; 859 } 860 *(*wp)++ = L':'; 861 for (i = 0; i < nfsv4_acl_flag_map_size; i++) { 862 if (perm & nfsv4_acl_flag_map[i].perm) 863 *(*wp)++ = nfsv4_acl_flag_map[i].wc; 864 else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0) 865 *(*wp)++ = L'-'; 866 } 867 *(*wp)++ = L':'; 868 switch (type) { 869 case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: 870 wcscpy(*wp, L"allow"); 871 break; 872 case ARCHIVE_ENTRY_ACL_TYPE_DENY: 873 wcscpy(*wp, L"deny"); 874 break; 875 case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: 876 wcscpy(*wp, L"audit"); 877 break; 878 case ARCHIVE_ENTRY_ACL_TYPE_ALARM: 879 wcscpy(*wp, L"alarm"); 880 break; 881 default: 882 break; 883 } 884 *wp += wcslen(*wp); 885 } 886 if (id != -1) { 887 *(*wp)++ = L':'; 888 append_id_w(wp, id); 889 } 890 } 891 892 /* 893 * Generate a text version of the ACL. The flags parameter controls 894 * the type and style of the generated ACL. 895 */ 896 char * 897 archive_acl_to_text_l(struct archive_acl *acl, ssize_t *text_len, int flags, 898 struct archive_string_conv *sc) 899 { 900 int count; 901 ssize_t length; 902 size_t len; 903 const char *name; 904 const char *prefix; 905 char separator; 906 struct archive_acl_entry *ap; 907 int id, r, want_type; 908 char *p, *s; 909 910 want_type = archive_acl_text_want_type(acl, flags); 911 912 /* Both NFSv4 and POSIX.1 types found */ 913 if (want_type == 0) 914 return (NULL); 915 916 if (want_type == ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) 917 flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT; 918 919 length = archive_acl_text_len(acl, want_type, flags, 0, NULL, sc); 920 921 if (length == 0) 922 return (NULL); 923 924 if (flags & ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA) 925 separator = ','; 926 else 927 separator = '\n'; 928 929 /* Now, allocate the string and actually populate it. */ 930 p = s = (char *)malloc(length * sizeof(char)); 931 if (p == NULL) { 932 if (errno == ENOMEM) 933 __archive_errx(1, "No memory"); 934 return (NULL); 935 } 936 count = 0; 937 938 if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { 939 append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 940 ARCHIVE_ENTRY_ACL_USER_OBJ, flags, NULL, 941 acl->mode & 0700, -1); 942 *p++ = separator; 943 append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 944 ARCHIVE_ENTRY_ACL_GROUP_OBJ, flags, NULL, 945 acl->mode & 0070, -1); 946 *p++ = separator; 947 append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 948 ARCHIVE_ENTRY_ACL_OTHER, flags, NULL, 949 acl->mode & 0007, -1); 950 count += 3; 951 } 952 953 for (ap = acl->acl_head; ap != NULL; ap = ap->next) { 954 if ((ap->type & want_type) == 0) 955 continue; 956 /* 957 * Filemode-mapping ACL entries are stored exclusively in 958 * ap->mode so they should not be in the list 959 */ 960 if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) 961 && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ 962 || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ 963 || ap->tag == ARCHIVE_ENTRY_ACL_OTHER)) 964 continue; 965 if (ap->type == ARCHIVE_ENTRY_ACL_TYPE_DEFAULT && 966 (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0) 967 prefix = "default:"; 968 else 969 prefix = NULL; 970 r = archive_mstring_get_mbs_l( 971 &ap->name, &name, &len, sc); 972 if (r != 0) { 973 free(s); 974 return (NULL); 975 } 976 if (count > 0) 977 *p++ = separator; 978 if (name == NULL || 979 (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)) { 980 id = ap->id; 981 } else { 982 id = -1; 983 } 984 append_entry(&p, prefix, ap->type, ap->tag, flags, name, 985 ap->permset, id); 986 count++; 987 } 988 989 /* Add terminating character */ 990 *p++ = '\0'; 991 992 len = strlen(s); 993 994 if ((ssize_t)len > (length - 1)) 995 __archive_errx(1, "Buffer overrun"); 996 997 if (text_len != NULL) 998 *text_len = len; 999 1000 return (s); 1001 } 1002 1003 static void 1004 append_id(char **p, int id) 1005 { 1006 if (id < 0) 1007 id = 0; 1008 if (id > 9) 1009 append_id(p, id / 10); 1010 *(*p)++ = "0123456789"[id % 10]; 1011 } 1012 1013 static void 1014 append_entry(char **p, const char *prefix, int type, 1015 int tag, int flags, const char *name, int perm, int id) 1016 { 1017 int i; 1018 1019 if (prefix != NULL) { 1020 strcpy(*p, prefix); 1021 *p += strlen(*p); 1022 } 1023 switch (tag) { 1024 case ARCHIVE_ENTRY_ACL_USER_OBJ: 1025 name = NULL; 1026 id = -1; 1027 if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { 1028 strcpy(*p, "owner@"); 1029 break; 1030 } 1031 /* FALLTHROUGH */ 1032 case ARCHIVE_ENTRY_ACL_USER: 1033 strcpy(*p, "user"); 1034 break; 1035 case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 1036 name = NULL; 1037 id = -1; 1038 if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { 1039 strcpy(*p, "group@"); 1040 break; 1041 } 1042 /* FALLTHROUGH */ 1043 case ARCHIVE_ENTRY_ACL_GROUP: 1044 strcpy(*p, "group"); 1045 break; 1046 case ARCHIVE_ENTRY_ACL_MASK: 1047 strcpy(*p, "mask"); 1048 name = NULL; 1049 id = -1; 1050 break; 1051 case ARCHIVE_ENTRY_ACL_OTHER: 1052 strcpy(*p, "other"); 1053 name = NULL; 1054 id = -1; 1055 break; 1056 case ARCHIVE_ENTRY_ACL_EVERYONE: 1057 strcpy(*p, "everyone@"); 1058 name = NULL; 1059 id = -1; 1060 break; 1061 } 1062 *p += strlen(*p); 1063 *(*p)++ = ':'; 1064 if (((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) || 1065 tag == ARCHIVE_ENTRY_ACL_USER || 1066 tag == ARCHIVE_ENTRY_ACL_GROUP) { 1067 if (name != NULL) { 1068 strcpy(*p, name); 1069 *p += strlen(*p); 1070 } else if (tag == ARCHIVE_ENTRY_ACL_USER 1071 || tag == ARCHIVE_ENTRY_ACL_GROUP) { 1072 append_id(p, id); 1073 if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0) 1074 id = -1; 1075 } 1076 /* Solaris style has no second colon after other and mask */ 1077 if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) == 0) 1078 || (tag != ARCHIVE_ENTRY_ACL_OTHER 1079 && tag != ARCHIVE_ENTRY_ACL_MASK)) 1080 *(*p)++ = ':'; 1081 } 1082 if ((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) { 1083 /* POSIX.1e ACL perms */ 1084 *(*p)++ = (perm & 0444) ? 'r' : '-'; 1085 *(*p)++ = (perm & 0222) ? 'w' : '-'; 1086 *(*p)++ = (perm & 0111) ? 'x' : '-'; 1087 } else { 1088 /* NFSv4 ACL perms */ 1089 for (i = 0; i < nfsv4_acl_perm_map_size; i++) { 1090 if (perm & nfsv4_acl_perm_map[i].perm) 1091 *(*p)++ = nfsv4_acl_perm_map[i].c; 1092 else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0) 1093 *(*p)++ = '-'; 1094 } 1095 *(*p)++ = ':'; 1096 for (i = 0; i < nfsv4_acl_flag_map_size; i++) { 1097 if (perm & nfsv4_acl_flag_map[i].perm) 1098 *(*p)++ = nfsv4_acl_flag_map[i].c; 1099 else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0) 1100 *(*p)++ = '-'; 1101 } 1102 *(*p)++ = ':'; 1103 switch (type) { 1104 case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: 1105 strcpy(*p, "allow"); 1106 break; 1107 case ARCHIVE_ENTRY_ACL_TYPE_DENY: 1108 strcpy(*p, "deny"); 1109 break; 1110 case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: 1111 strcpy(*p, "audit"); 1112 break; 1113 case ARCHIVE_ENTRY_ACL_TYPE_ALARM: 1114 strcpy(*p, "alarm"); 1115 break; 1116 } 1117 *p += strlen(*p); 1118 } 1119 if (id != -1) { 1120 *(*p)++ = ':'; 1121 append_id(p, id); 1122 } 1123 } 1124 1125 /* 1126 * Parse a wide ACL text string. 1127 * 1128 * The want_type argument may be one of the following: 1129 * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - text is a POSIX.1e ACL of type ACCESS 1130 * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - text is a POSIX.1e ACL of type DEFAULT 1131 * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - text is as a NFSv4 ACL 1132 * 1133 * POSIX.1e ACL entries prefixed with "default:" are treated as 1134 * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT unless type is ARCHIVE_ENTRY_ACL_TYPE_NFS4 1135 */ 1136 int 1137 archive_acl_from_text_w(struct archive_acl *acl, const wchar_t *text, 1138 int want_type) 1139 { 1140 struct { 1141 const wchar_t *start; 1142 const wchar_t *end; 1143 } field[6], name; 1144 1145 const wchar_t *s, *st; 1146 1147 int numfields, fields, n, r, sol, ret; 1148 int type, types, tag, permset, id; 1149 size_t len; 1150 wchar_t sep; 1151 1152 ret = ARCHIVE_OK; 1153 types = 0; 1154 1155 switch (want_type) { 1156 case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E: 1157 want_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 1158 __LA_FALLTHROUGH; 1159 case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: 1160 case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: 1161 numfields = 5; 1162 break; 1163 case ARCHIVE_ENTRY_ACL_TYPE_NFS4: 1164 numfields = 6; 1165 break; 1166 default: 1167 return (ARCHIVE_FATAL); 1168 } 1169 1170 while (text != NULL && *text != L'\0') { 1171 /* 1172 * Parse the fields out of the next entry, 1173 * advance 'text' to start of next entry. 1174 */ 1175 fields = 0; 1176 do { 1177 const wchar_t *start, *end; 1178 next_field_w(&text, &start, &end, &sep); 1179 if (fields < numfields) { 1180 field[fields].start = start; 1181 field[fields].end = end; 1182 } 1183 ++fields; 1184 } while (sep == L':'); 1185 1186 /* Set remaining fields to blank. */ 1187 for (n = fields; n < numfields; ++n) 1188 field[n].start = field[n].end = NULL; 1189 1190 if (field[0].start != NULL && *(field[0].start) == L'#') { 1191 /* Comment, skip entry */ 1192 continue; 1193 } 1194 1195 n = 0; 1196 sol = 0; 1197 id = -1; 1198 permset = 0; 1199 name.start = name.end = NULL; 1200 1201 if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 1202 /* POSIX.1e ACLs */ 1203 /* 1204 * Default keyword "default:user::rwx" 1205 * if found, we have one more field 1206 * 1207 * We also support old Solaris extension: 1208 * "defaultuser::rwx" is the default ACL corresponding 1209 * to "user::rwx", etc. valid only for first field 1210 */ 1211 s = field[0].start; 1212 len = field[0].end - field[0].start; 1213 if (*s == L'd' && (len == 1 || (len >= 7 1214 && wmemcmp((s + 1), L"efault", 6) == 0))) { 1215 type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; 1216 if (len > 7) 1217 field[0].start += 7; 1218 else 1219 n = 1; 1220 } else 1221 type = want_type; 1222 1223 /* Check for a numeric ID in field n+1 or n+3. */ 1224 isint_w(field[n + 1].start, field[n + 1].end, &id); 1225 /* Field n+3 is optional. */ 1226 if (id == -1 && fields > n+3) 1227 isint_w(field[n + 3].start, field[n + 3].end, 1228 &id); 1229 1230 tag = 0; 1231 s = field[n].start; 1232 st = field[n].start + 1; 1233 len = field[n].end - field[n].start; 1234 1235 switch (*s) { 1236 case L'u': 1237 if (len == 1 || (len == 4 1238 && wmemcmp(st, L"ser", 3) == 0)) 1239 tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 1240 break; 1241 case L'g': 1242 if (len == 1 || (len == 5 1243 && wmemcmp(st, L"roup", 4) == 0)) 1244 tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 1245 break; 1246 case L'o': 1247 if (len == 1 || (len == 5 1248 && wmemcmp(st, L"ther", 4) == 0)) 1249 tag = ARCHIVE_ENTRY_ACL_OTHER; 1250 break; 1251 case L'm': 1252 if (len == 1 || (len == 4 1253 && wmemcmp(st, L"ask", 3) == 0)) 1254 tag = ARCHIVE_ENTRY_ACL_MASK; 1255 break; 1256 default: 1257 break; 1258 } 1259 1260 switch (tag) { 1261 case ARCHIVE_ENTRY_ACL_OTHER: 1262 case ARCHIVE_ENTRY_ACL_MASK: 1263 if (fields == (n + 2) 1264 && field[n + 1].start < field[n + 1].end 1265 && ismode_w(field[n + 1].start, 1266 field[n + 1].end, &permset)) { 1267 /* This is Solaris-style "other:rwx" */ 1268 sol = 1; 1269 } else if (fields == (n + 3) && 1270 field[n + 1].start < field[n + 1].end) { 1271 /* Invalid mask or other field */ 1272 ret = ARCHIVE_WARN; 1273 continue; 1274 } 1275 break; 1276 case ARCHIVE_ENTRY_ACL_USER_OBJ: 1277 case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 1278 if (id != -1 || 1279 field[n + 1].start < field[n + 1].end) { 1280 name = field[n + 1]; 1281 if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) 1282 tag = ARCHIVE_ENTRY_ACL_USER; 1283 else 1284 tag = ARCHIVE_ENTRY_ACL_GROUP; 1285 } 1286 break; 1287 default: 1288 /* Invalid tag, skip entry */ 1289 ret = ARCHIVE_WARN; 1290 continue; 1291 } 1292 1293 /* 1294 * Without "default:" we expect mode in field 2 1295 * Exception: Solaris other and mask fields 1296 */ 1297 if (permset == 0 && !ismode_w(field[n + 2 - sol].start, 1298 field[n + 2 - sol].end, &permset)) { 1299 /* Invalid mode, skip entry */ 1300 ret = ARCHIVE_WARN; 1301 continue; 1302 } 1303 } else { 1304 /* NFS4 ACLs */ 1305 s = field[0].start; 1306 len = field[0].end - field[0].start; 1307 tag = 0; 1308 1309 switch (len) { 1310 case 4: 1311 if (wmemcmp(s, L"user", 4) == 0) 1312 tag = ARCHIVE_ENTRY_ACL_USER; 1313 break; 1314 case 5: 1315 if (wmemcmp(s, L"group", 5) == 0) 1316 tag = ARCHIVE_ENTRY_ACL_GROUP; 1317 break; 1318 case 6: 1319 if (wmemcmp(s, L"owner@", 6) == 0) 1320 tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 1321 else if (wmemcmp(s, L"group@", len) == 0) 1322 tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 1323 break; 1324 case 9: 1325 if (wmemcmp(s, L"everyone@", 9) == 0) 1326 tag = ARCHIVE_ENTRY_ACL_EVERYONE; 1327 default: 1328 break; 1329 } 1330 1331 if (tag == 0) { 1332 /* Invalid tag, skip entry */ 1333 ret = ARCHIVE_WARN; 1334 continue; 1335 } else if (tag == ARCHIVE_ENTRY_ACL_USER || 1336 tag == ARCHIVE_ENTRY_ACL_GROUP) { 1337 n = 1; 1338 name = field[1]; 1339 isint_w(name.start, name.end, &id); 1340 } else 1341 n = 0; 1342 1343 if (!is_nfs4_perms_w(field[1 + n].start, 1344 field[1 + n].end, &permset)) { 1345 /* Invalid NFSv4 perms, skip entry */ 1346 ret = ARCHIVE_WARN; 1347 continue; 1348 } 1349 if (!is_nfs4_flags_w(field[2 + n].start, 1350 field[2 + n].end, &permset)) { 1351 /* Invalid NFSv4 flags, skip entry */ 1352 ret = ARCHIVE_WARN; 1353 continue; 1354 } 1355 s = field[3 + n].start; 1356 len = field[3 + n].end - field[3 + n].start; 1357 type = 0; 1358 if (len == 4) { 1359 if (wmemcmp(s, L"deny", 4) == 0) 1360 type = ARCHIVE_ENTRY_ACL_TYPE_DENY; 1361 } else if (len == 5) { 1362 if (wmemcmp(s, L"allow", 5) == 0) 1363 type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; 1364 else if (wmemcmp(s, L"audit", 5) == 0) 1365 type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT; 1366 else if (wmemcmp(s, L"alarm", 5) == 0) 1367 type = ARCHIVE_ENTRY_ACL_TYPE_ALARM; 1368 } 1369 if (type == 0) { 1370 /* Invalid entry type, skip entry */ 1371 ret = ARCHIVE_WARN; 1372 continue; 1373 } 1374 isint_w(field[4 + n].start, field[4 + n].end, &id); 1375 } 1376 1377 /* Add entry to the internal list. */ 1378 r = archive_acl_add_entry_w_len(acl, type, permset, 1379 tag, id, name.start, name.end - name.start); 1380 if (r < ARCHIVE_WARN) 1381 return (r); 1382 if (r != ARCHIVE_OK) 1383 ret = ARCHIVE_WARN; 1384 types |= type; 1385 } 1386 1387 /* Reset ACL */ 1388 archive_acl_reset(acl, types); 1389 1390 return (ret); 1391 } 1392 1393 /* 1394 * Parse a string to a positive decimal integer. Returns true if 1395 * the string is non-empty and consists only of decimal digits, 1396 * false otherwise. 1397 */ 1398 static int 1399 isint_w(const wchar_t *start, const wchar_t *end, int *result) 1400 { 1401 int n = 0; 1402 if (start >= end) 1403 return (0); 1404 while (start < end) { 1405 if (*start < '0' || *start > '9') 1406 return (0); 1407 if (n > (INT_MAX / 10) || 1408 (n == INT_MAX / 10 && (*start - '0') > INT_MAX % 10)) { 1409 n = INT_MAX; 1410 } else { 1411 n *= 10; 1412 n += *start - '0'; 1413 } 1414 start++; 1415 } 1416 *result = n; 1417 return (1); 1418 } 1419 1420 /* 1421 * Parse a string as a mode field. Returns true if 1422 * the string is non-empty and consists only of mode characters, 1423 * false otherwise. 1424 */ 1425 static int 1426 ismode_w(const wchar_t *start, const wchar_t *end, int *permset) 1427 { 1428 const wchar_t *p; 1429 1430 if (start >= end) 1431 return (0); 1432 p = start; 1433 *permset = 0; 1434 while (p < end) { 1435 switch (*p++) { 1436 case L'r': case L'R': 1437 *permset |= ARCHIVE_ENTRY_ACL_READ; 1438 break; 1439 case L'w': case L'W': 1440 *permset |= ARCHIVE_ENTRY_ACL_WRITE; 1441 break; 1442 case L'x': case L'X': 1443 *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; 1444 break; 1445 case L'-': 1446 break; 1447 default: 1448 return (0); 1449 } 1450 } 1451 return (1); 1452 } 1453 1454 /* 1455 * Parse a string as a NFS4 ACL permission field. 1456 * Returns true if the string is non-empty and consists only of NFS4 ACL 1457 * permission characters, false otherwise 1458 */ 1459 static int 1460 is_nfs4_perms_w(const wchar_t *start, const wchar_t *end, int *permset) 1461 { 1462 const wchar_t *p = start; 1463 1464 while (p < end) { 1465 switch (*p++) { 1466 case L'r': 1467 *permset |= ARCHIVE_ENTRY_ACL_READ_DATA; 1468 break; 1469 case L'w': 1470 *permset |= ARCHIVE_ENTRY_ACL_WRITE_DATA; 1471 break; 1472 case L'x': 1473 *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; 1474 break; 1475 case L'p': 1476 *permset |= ARCHIVE_ENTRY_ACL_APPEND_DATA; 1477 break; 1478 case L'D': 1479 *permset |= ARCHIVE_ENTRY_ACL_DELETE_CHILD; 1480 break; 1481 case L'd': 1482 *permset |= ARCHIVE_ENTRY_ACL_DELETE; 1483 break; 1484 case L'a': 1485 *permset |= ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES; 1486 break; 1487 case L'A': 1488 *permset |= ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES; 1489 break; 1490 case L'R': 1491 *permset |= ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS; 1492 break; 1493 case L'W': 1494 *permset |= ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS; 1495 break; 1496 case L'c': 1497 *permset |= ARCHIVE_ENTRY_ACL_READ_ACL; 1498 break; 1499 case L'C': 1500 *permset |= ARCHIVE_ENTRY_ACL_WRITE_ACL; 1501 break; 1502 case L'o': 1503 *permset |= ARCHIVE_ENTRY_ACL_WRITE_OWNER; 1504 break; 1505 case L's': 1506 *permset |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE; 1507 break; 1508 case L'-': 1509 break; 1510 default: 1511 return(0); 1512 } 1513 } 1514 return (1); 1515 } 1516 1517 /* 1518 * Parse a string as a NFS4 ACL flags field. 1519 * Returns true if the string is non-empty and consists only of NFS4 ACL 1520 * flag characters, false otherwise 1521 */ 1522 static int 1523 is_nfs4_flags_w(const wchar_t *start, const wchar_t *end, int *permset) 1524 { 1525 const wchar_t *p = start; 1526 1527 while (p < end) { 1528 switch(*p++) { 1529 case L'f': 1530 *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT; 1531 break; 1532 case L'd': 1533 *permset |= ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT; 1534 break; 1535 case L'i': 1536 *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY; 1537 break; 1538 case L'n': 1539 *permset |= 1540 ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT; 1541 break; 1542 case L'S': 1543 *permset |= ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS; 1544 break; 1545 case L'F': 1546 *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS; 1547 break; 1548 case L'I': 1549 *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERITED; 1550 break; 1551 case L'-': 1552 break; 1553 default: 1554 return (0); 1555 } 1556 } 1557 return (1); 1558 } 1559 1560 /* 1561 * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]". *wp is updated 1562 * to point to just after the separator. *start points to the first 1563 * character of the matched text and *end just after the last 1564 * character of the matched identifier. In particular *end - *start 1565 * is the length of the field body, not including leading or trailing 1566 * whitespace. 1567 */ 1568 static void 1569 next_field_w(const wchar_t **wp, const wchar_t **start, 1570 const wchar_t **end, wchar_t *sep) 1571 { 1572 /* Skip leading whitespace to find start of field. */ 1573 while (**wp == L' ' || **wp == L'\t' || **wp == L'\n') { 1574 (*wp)++; 1575 } 1576 *start = *wp; 1577 1578 /* Scan for the separator. */ 1579 while (**wp != L'\0' && **wp != L',' && **wp != L':' && 1580 **wp != L'\n' && **wp != L'#') { 1581 (*wp)++; 1582 } 1583 *sep = **wp; 1584 1585 /* Locate end of field, trim trailing whitespace if necessary */ 1586 if (*wp == *start) { 1587 *end = *wp; 1588 } else { 1589 *end = *wp - 1; 1590 while (**end == L' ' || **end == L'\t' || **end == L'\n') { 1591 (*end)--; 1592 } 1593 (*end)++; 1594 } 1595 1596 /* Handle in-field comments */ 1597 if (*sep == L'#') { 1598 while (**wp != L'\0' && **wp != L',' && **wp != L'\n') { 1599 (*wp)++; 1600 } 1601 *sep = **wp; 1602 } 1603 1604 /* Adjust scanner location. */ 1605 if (**wp != L'\0') 1606 (*wp)++; 1607 } 1608 1609 /* 1610 * Parse an ACL text string. 1611 * 1612 * The want_type argument may be one of the following: 1613 * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - text is a POSIX.1e ACL of type ACCESS 1614 * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - text is a POSIX.1e ACL of type DEFAULT 1615 * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - text is as a NFSv4 ACL 1616 * 1617 * POSIX.1e ACL entries prefixed with "default:" are treated as 1618 * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT unless type is ARCHIVE_ENTRY_ACL_TYPE_NFS4 1619 */ 1620 int 1621 archive_acl_from_text_l(struct archive_acl *acl, const char *text, 1622 int want_type, struct archive_string_conv *sc) 1623 { 1624 struct { 1625 const char *start; 1626 const char *end; 1627 } field[6], name; 1628 1629 const char *s, *st; 1630 int numfields, fields, n, r, sol, ret; 1631 int type, types, tag, permset, id; 1632 size_t len; 1633 char sep; 1634 1635 switch (want_type) { 1636 case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E: 1637 want_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 1638 __LA_FALLTHROUGH; 1639 case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: 1640 case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: 1641 numfields = 5; 1642 break; 1643 case ARCHIVE_ENTRY_ACL_TYPE_NFS4: 1644 numfields = 6; 1645 break; 1646 default: 1647 return (ARCHIVE_FATAL); 1648 } 1649 1650 ret = ARCHIVE_OK; 1651 types = 0; 1652 1653 while (text != NULL && *text != '\0') { 1654 /* 1655 * Parse the fields out of the next entry, 1656 * advance 'text' to start of next entry. 1657 */ 1658 fields = 0; 1659 do { 1660 const char *start, *end; 1661 next_field(&text, &start, &end, &sep); 1662 if (fields < numfields) { 1663 field[fields].start = start; 1664 field[fields].end = end; 1665 } 1666 ++fields; 1667 } while (sep == ':'); 1668 1669 /* Set remaining fields to blank. */ 1670 for (n = fields; n < numfields; ++n) 1671 field[n].start = field[n].end = NULL; 1672 1673 if (field[0].start != NULL && *(field[0].start) == '#') { 1674 /* Comment, skip entry */ 1675 continue; 1676 } 1677 1678 n = 0; 1679 sol = 0; 1680 id = -1; 1681 permset = 0; 1682 name.start = name.end = NULL; 1683 1684 if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 1685 /* POSIX.1e ACLs */ 1686 /* 1687 * Default keyword "default:user::rwx" 1688 * if found, we have one more field 1689 * 1690 * We also support old Solaris extension: 1691 * "defaultuser::rwx" is the default ACL corresponding 1692 * to "user::rwx", etc. valid only for first field 1693 */ 1694 s = field[0].start; 1695 len = field[0].end - field[0].start; 1696 if (*s == 'd' && (len == 1 || (len >= 7 1697 && memcmp((s + 1), "efault", 6) == 0))) { 1698 type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; 1699 if (len > 7) 1700 field[0].start += 7; 1701 else 1702 n = 1; 1703 } else 1704 type = want_type; 1705 1706 /* Check for a numeric ID in field n+1 or n+3. */ 1707 isint(field[n + 1].start, field[n + 1].end, &id); 1708 /* Field n+3 is optional. */ 1709 if (id == -1 && fields > (n + 3)) 1710 isint(field[n + 3].start, field[n + 3].end, 1711 &id); 1712 1713 tag = 0; 1714 s = field[n].start; 1715 st = field[n].start + 1; 1716 len = field[n].end - field[n].start; 1717 1718 if (len == 0) { 1719 ret = ARCHIVE_WARN; 1720 continue; 1721 } 1722 1723 switch (*s) { 1724 case 'u': 1725 if (len == 1 || (len == 4 1726 && memcmp(st, "ser", 3) == 0)) 1727 tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 1728 break; 1729 case 'g': 1730 if (len == 1 || (len == 5 1731 && memcmp(st, "roup", 4) == 0)) 1732 tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 1733 break; 1734 case 'o': 1735 if (len == 1 || (len == 5 1736 && memcmp(st, "ther", 4) == 0)) 1737 tag = ARCHIVE_ENTRY_ACL_OTHER; 1738 break; 1739 case 'm': 1740 if (len == 1 || (len == 4 1741 && memcmp(st, "ask", 3) == 0)) 1742 tag = ARCHIVE_ENTRY_ACL_MASK; 1743 break; 1744 default: 1745 break; 1746 } 1747 1748 switch (tag) { 1749 case ARCHIVE_ENTRY_ACL_OTHER: 1750 case ARCHIVE_ENTRY_ACL_MASK: 1751 if (fields == (n + 2) 1752 && field[n + 1].start < field[n + 1].end 1753 && ismode(field[n + 1].start, 1754 field[n + 1].end, &permset)) { 1755 /* This is Solaris-style "other:rwx" */ 1756 sol = 1; 1757 } else if (fields == (n + 3) && 1758 field[n + 1].start < field[n + 1].end) { 1759 /* Invalid mask or other field */ 1760 ret = ARCHIVE_WARN; 1761 continue; 1762 } 1763 break; 1764 case ARCHIVE_ENTRY_ACL_USER_OBJ: 1765 case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 1766 if (id != -1 || 1767 field[n + 1].start < field[n + 1].end) { 1768 name = field[n + 1]; 1769 if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) 1770 tag = ARCHIVE_ENTRY_ACL_USER; 1771 else 1772 tag = ARCHIVE_ENTRY_ACL_GROUP; 1773 } 1774 break; 1775 default: 1776 /* Invalid tag, skip entry */ 1777 ret = ARCHIVE_WARN; 1778 continue; 1779 } 1780 1781 /* 1782 * Without "default:" we expect mode in field 3 1783 * Exception: Solaris other and mask fields 1784 */ 1785 if (permset == 0 && !ismode(field[n + 2 - sol].start, 1786 field[n + 2 - sol].end, &permset)) { 1787 /* Invalid mode, skip entry */ 1788 ret = ARCHIVE_WARN; 1789 continue; 1790 } 1791 } else { 1792 /* NFS4 ACLs */ 1793 s = field[0].start; 1794 len = field[0].end - field[0].start; 1795 tag = 0; 1796 1797 switch (len) { 1798 case 4: 1799 if (memcmp(s, "user", 4) == 0) 1800 tag = ARCHIVE_ENTRY_ACL_USER; 1801 break; 1802 case 5: 1803 if (memcmp(s, "group", 5) == 0) 1804 tag = ARCHIVE_ENTRY_ACL_GROUP; 1805 break; 1806 case 6: 1807 if (memcmp(s, "owner@", 6) == 0) 1808 tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 1809 else if (memcmp(s, "group@", 6) == 0) 1810 tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 1811 break; 1812 case 9: 1813 if (memcmp(s, "everyone@", 9) == 0) 1814 tag = ARCHIVE_ENTRY_ACL_EVERYONE; 1815 break; 1816 default: 1817 break; 1818 } 1819 1820 if (tag == 0) { 1821 /* Invalid tag, skip entry */ 1822 ret = ARCHIVE_WARN; 1823 continue; 1824 } else if (tag == ARCHIVE_ENTRY_ACL_USER || 1825 tag == ARCHIVE_ENTRY_ACL_GROUP) { 1826 n = 1; 1827 name = field[1]; 1828 isint(name.start, name.end, &id); 1829 } else 1830 n = 0; 1831 1832 if (!is_nfs4_perms(field[1 + n].start, 1833 field[1 + n].end, &permset)) { 1834 /* Invalid NFSv4 perms, skip entry */ 1835 ret = ARCHIVE_WARN; 1836 continue; 1837 } 1838 if (!is_nfs4_flags(field[2 + n].start, 1839 field[2 + n].end, &permset)) { 1840 /* Invalid NFSv4 flags, skip entry */ 1841 ret = ARCHIVE_WARN; 1842 continue; 1843 } 1844 s = field[3 + n].start; 1845 len = field[3 + n].end - field[3 + n].start; 1846 type = 0; 1847 if (len == 4) { 1848 if (memcmp(s, "deny", 4) == 0) 1849 type = ARCHIVE_ENTRY_ACL_TYPE_DENY; 1850 } else if (len == 5) { 1851 if (memcmp(s, "allow", 5) == 0) 1852 type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; 1853 else if (memcmp(s, "audit", 5) == 0) 1854 type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT; 1855 else if (memcmp(s, "alarm", 5) == 0) 1856 type = ARCHIVE_ENTRY_ACL_TYPE_ALARM; 1857 } 1858 if (type == 0) { 1859 /* Invalid entry type, skip entry */ 1860 ret = ARCHIVE_WARN; 1861 continue; 1862 } 1863 isint(field[4 + n].start, field[4 + n].end, 1864 &id); 1865 } 1866 1867 /* Add entry to the internal list. */ 1868 r = archive_acl_add_entry_len_l(acl, type, permset, 1869 tag, id, name.start, name.end - name.start, sc); 1870 if (r < ARCHIVE_WARN) 1871 return (r); 1872 if (r != ARCHIVE_OK) 1873 ret = ARCHIVE_WARN; 1874 types |= type; 1875 } 1876 1877 /* Reset ACL */ 1878 archive_acl_reset(acl, types); 1879 1880 return (ret); 1881 } 1882 1883 /* 1884 * Parse a string to a positive decimal integer. Returns true if 1885 * the string is non-empty and consists only of decimal digits, 1886 * false otherwise. 1887 */ 1888 static int 1889 isint(const char *start, const char *end, int *result) 1890 { 1891 int n = 0; 1892 if (start >= end) 1893 return (0); 1894 while (start < end) { 1895 if (*start < '0' || *start > '9') 1896 return (0); 1897 if (n > (INT_MAX / 10) || 1898 (n == INT_MAX / 10 && (*start - '0') > INT_MAX % 10)) { 1899 n = INT_MAX; 1900 } else { 1901 n *= 10; 1902 n += *start - '0'; 1903 } 1904 start++; 1905 } 1906 *result = n; 1907 return (1); 1908 } 1909 1910 /* 1911 * Parse a string as a mode field. Returns true if 1912 * the string is non-empty and consists only of mode characters, 1913 * false otherwise. 1914 */ 1915 static int 1916 ismode(const char *start, const char *end, int *permset) 1917 { 1918 const char *p; 1919 1920 if (start >= end) 1921 return (0); 1922 p = start; 1923 *permset = 0; 1924 while (p < end) { 1925 switch (*p++) { 1926 case 'r': case 'R': 1927 *permset |= ARCHIVE_ENTRY_ACL_READ; 1928 break; 1929 case 'w': case 'W': 1930 *permset |= ARCHIVE_ENTRY_ACL_WRITE; 1931 break; 1932 case 'x': case 'X': 1933 *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; 1934 break; 1935 case '-': 1936 break; 1937 default: 1938 return (0); 1939 } 1940 } 1941 return (1); 1942 } 1943 1944 /* 1945 * Parse a string as a NFS4 ACL permission field. 1946 * Returns true if the string is non-empty and consists only of NFS4 ACL 1947 * permission characters, false otherwise 1948 */ 1949 static int 1950 is_nfs4_perms(const char *start, const char *end, int *permset) 1951 { 1952 const char *p = start; 1953 1954 while (p < end) { 1955 switch (*p++) { 1956 case 'r': 1957 *permset |= ARCHIVE_ENTRY_ACL_READ_DATA; 1958 break; 1959 case 'w': 1960 *permset |= ARCHIVE_ENTRY_ACL_WRITE_DATA; 1961 break; 1962 case 'x': 1963 *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; 1964 break; 1965 case 'p': 1966 *permset |= ARCHIVE_ENTRY_ACL_APPEND_DATA; 1967 break; 1968 case 'D': 1969 *permset |= ARCHIVE_ENTRY_ACL_DELETE_CHILD; 1970 break; 1971 case 'd': 1972 *permset |= ARCHIVE_ENTRY_ACL_DELETE; 1973 break; 1974 case 'a': 1975 *permset |= ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES; 1976 break; 1977 case 'A': 1978 *permset |= ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES; 1979 break; 1980 case 'R': 1981 *permset |= ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS; 1982 break; 1983 case 'W': 1984 *permset |= ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS; 1985 break; 1986 case 'c': 1987 *permset |= ARCHIVE_ENTRY_ACL_READ_ACL; 1988 break; 1989 case 'C': 1990 *permset |= ARCHIVE_ENTRY_ACL_WRITE_ACL; 1991 break; 1992 case 'o': 1993 *permset |= ARCHIVE_ENTRY_ACL_WRITE_OWNER; 1994 break; 1995 case 's': 1996 *permset |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE; 1997 break; 1998 case '-': 1999 break; 2000 default: 2001 return(0); 2002 } 2003 } 2004 return (1); 2005 } 2006 2007 /* 2008 * Parse a string as a NFS4 ACL flags field. 2009 * Returns true if the string is non-empty and consists only of NFS4 ACL 2010 * flag characters, false otherwise 2011 */ 2012 static int 2013 is_nfs4_flags(const char *start, const char *end, int *permset) 2014 { 2015 const char *p = start; 2016 2017 while (p < end) { 2018 switch(*p++) { 2019 case 'f': 2020 *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT; 2021 break; 2022 case 'd': 2023 *permset |= ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT; 2024 break; 2025 case 'i': 2026 *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY; 2027 break; 2028 case 'n': 2029 *permset |= 2030 ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT; 2031 break; 2032 case 'S': 2033 *permset |= ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS; 2034 break; 2035 case 'F': 2036 *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS; 2037 break; 2038 case 'I': 2039 *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERITED; 2040 break; 2041 case '-': 2042 break; 2043 default: 2044 return (0); 2045 } 2046 } 2047 return (1); 2048 } 2049 2050 /* 2051 * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]". *wp is updated 2052 * to point to just after the separator. *start points to the first 2053 * character of the matched text and *end just after the last 2054 * character of the matched identifier. In particular *end - *start 2055 * is the length of the field body, not including leading or trailing 2056 * whitespace. 2057 */ 2058 static void 2059 next_field(const char **p, const char **start, 2060 const char **end, char *sep) 2061 { 2062 /* Skip leading whitespace to find start of field. */ 2063 while (**p == ' ' || **p == '\t' || **p == '\n') { 2064 (*p)++; 2065 } 2066 *start = *p; 2067 2068 /* Scan for the separator. */ 2069 while (**p != '\0' && **p != ',' && **p != ':' && **p != '\n' && 2070 **p != '#') { 2071 (*p)++; 2072 } 2073 *sep = **p; 2074 2075 /* Locate end of field, trim trailing whitespace if necessary */ 2076 if (*p == *start) { 2077 *end = *p; 2078 } else { 2079 *end = *p - 1; 2080 while (**end == ' ' || **end == '\t' || **end == '\n') { 2081 (*end)--; 2082 } 2083 (*end)++; 2084 } 2085 2086 /* Handle in-field comments */ 2087 if (*sep == '#') { 2088 while (**p != '\0' && **p != ',' && **p != '\n') { 2089 (*p)++; 2090 } 2091 *sep = **p; 2092 } 2093 2094 /* Adjust scanner location. */ 2095 if (**p != '\0') 2096 (*p)++; 2097 } 2098