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