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