16c95142eSMartin Matuska /*- 26c95142eSMartin Matuska * Copyright (c) 2003-2010 Tim Kientzle 3e9ed7ea4SMartin Matuska * Copyright (c) 2016 Martin Matuska 46c95142eSMartin Matuska * All rights reserved. 56c95142eSMartin Matuska * 66c95142eSMartin Matuska * Redistribution and use in source and binary forms, with or without 76c95142eSMartin Matuska * modification, are permitted provided that the following conditions 86c95142eSMartin Matuska * are met: 96c95142eSMartin Matuska * 1. Redistributions of source code must retain the above copyright 106c95142eSMartin Matuska * notice, this list of conditions and the following disclaimer. 116c95142eSMartin Matuska * 2. Redistributions in binary form must reproduce the above copyright 126c95142eSMartin Matuska * notice, this list of conditions and the following disclaimer in the 136c95142eSMartin Matuska * documentation and/or other materials provided with the distribution. 146c95142eSMartin Matuska * 156c95142eSMartin Matuska * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 166c95142eSMartin Matuska * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 176c95142eSMartin Matuska * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 186c95142eSMartin Matuska * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 196c95142eSMartin Matuska * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 206c95142eSMartin Matuska * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 216c95142eSMartin Matuska * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 226c95142eSMartin Matuska * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 236c95142eSMartin Matuska * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 246c95142eSMartin Matuska * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 256c95142eSMartin Matuska */ 266c95142eSMartin Matuska 276c95142eSMartin Matuska #include "archive_platform.h" 286c95142eSMartin Matuska 296c95142eSMartin Matuska #ifdef HAVE_ERRNO_H 306c95142eSMartin Matuska #include <errno.h> 316c95142eSMartin Matuska #endif 326c95142eSMartin Matuska #ifdef HAVE_LIMITS_H 336c95142eSMartin Matuska #include <limits.h> 346c95142eSMartin Matuska #endif 356c95142eSMartin Matuska #ifdef HAVE_WCHAR_H 366c95142eSMartin Matuska #include <wchar.h> 376c95142eSMartin Matuska #endif 386c95142eSMartin Matuska 396c95142eSMartin Matuska #include "archive_acl_private.h" 406c95142eSMartin Matuska #include "archive_entry.h" 416c95142eSMartin Matuska #include "archive_private.h" 426c95142eSMartin Matuska 436c95142eSMartin Matuska #undef max 446c95142eSMartin Matuska #define max(a, b) ((a)>(b)?(a):(b)) 456c95142eSMartin Matuska 466c95142eSMartin Matuska #ifndef HAVE_WMEMCMP 476c95142eSMartin Matuska /* Good enough for simple equality testing, but not for sorting. */ 486c95142eSMartin Matuska #define wmemcmp(a,b,i) memcmp((a), (b), (i) * sizeof(wchar_t)) 496c95142eSMartin Matuska #endif 506c95142eSMartin Matuska 516c95142eSMartin Matuska static int acl_special(struct archive_acl *acl, 526c95142eSMartin Matuska int type, int permset, int tag); 536c95142eSMartin Matuska static struct archive_acl_entry *acl_new_entry(struct archive_acl *acl, 546c95142eSMartin Matuska int type, int permset, int tag, int id); 556c95142eSMartin Matuska static int archive_acl_add_entry_len_l(struct archive_acl *acl, 566c95142eSMartin Matuska int type, int permset, int tag, int id, const char *name, 576c95142eSMartin Matuska size_t len, struct archive_string_conv *sc); 58e9ed7ea4SMartin Matuska static int archive_acl_text_want_type(struct archive_acl *acl, int flags); 59*bd66c1b4SMartin Matuska static size_t archive_acl_text_len(struct archive_acl *acl, int want_type, 60e9ed7ea4SMartin Matuska int flags, int wide, struct archive *a, 61e9ed7ea4SMartin Matuska struct archive_string_conv *sc); 626c95142eSMartin Matuska static int isint_w(const wchar_t *start, const wchar_t *end, int *result); 636c95142eSMartin Matuska static int ismode_w(const wchar_t *start, const wchar_t *end, int *result); 64e9ed7ea4SMartin Matuska static int is_nfs4_flags_w(const wchar_t *start, const wchar_t *end, 65e9ed7ea4SMartin Matuska int *result); 66e9ed7ea4SMartin Matuska static int is_nfs4_perms_w(const wchar_t *start, const wchar_t *end, 67e9ed7ea4SMartin Matuska int *result); 686c95142eSMartin Matuska static void next_field_w(const wchar_t **wp, const wchar_t **start, 696c95142eSMartin Matuska const wchar_t **end, wchar_t *sep); 70e9ed7ea4SMartin Matuska static void append_entry_w(wchar_t **wp, const wchar_t *prefix, int type, 71e9ed7ea4SMartin Matuska int tag, int flags, const wchar_t *wname, int perm, int id); 726c95142eSMartin Matuska static void append_id_w(wchar_t **wp, int id); 736c95142eSMartin Matuska static int isint(const char *start, const char *end, int *result); 746c95142eSMartin Matuska static int ismode(const char *start, const char *end, int *result); 75e9ed7ea4SMartin Matuska static int is_nfs4_flags(const char *start, const char *end, 76e9ed7ea4SMartin Matuska int *result); 77e9ed7ea4SMartin Matuska static int is_nfs4_perms(const char *start, const char *end, 78e9ed7ea4SMartin Matuska int *result); 79*bd66c1b4SMartin Matuska static void next_field(const char **p, size_t *l, const char **start, 806c95142eSMartin Matuska const char **end, char *sep); 81e9ed7ea4SMartin Matuska static void append_entry(char **p, const char *prefix, int type, 82e9ed7ea4SMartin Matuska int tag, int flags, const char *name, int perm, int id); 836c95142eSMartin Matuska static void append_id(char **p, int id); 846c95142eSMartin Matuska 855d6770bdSMartin Matuska static const struct { 865d6770bdSMartin Matuska const int perm; 875d6770bdSMartin Matuska const char c; 885d6770bdSMartin Matuska const wchar_t wc; 895d6770bdSMartin Matuska } nfsv4_acl_perm_map[] = { 905d6770bdSMartin Matuska { ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, 'r', 915d6770bdSMartin Matuska L'r' }, 925d6770bdSMartin Matuska { ARCHIVE_ENTRY_ACL_WRITE_DATA | ARCHIVE_ENTRY_ACL_ADD_FILE, 'w', 935d6770bdSMartin Matuska L'w' }, 945d6770bdSMartin Matuska { ARCHIVE_ENTRY_ACL_EXECUTE, 'x', L'x' }, 955d6770bdSMartin Matuska { ARCHIVE_ENTRY_ACL_APPEND_DATA | ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, 965d6770bdSMartin Matuska 'p', L'p' }, 975d6770bdSMartin Matuska { ARCHIVE_ENTRY_ACL_DELETE, 'd', L'd' }, 985d6770bdSMartin Matuska { ARCHIVE_ENTRY_ACL_DELETE_CHILD, 'D', L'D' }, 995d6770bdSMartin Matuska { ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, 'a', L'a' }, 1005d6770bdSMartin Matuska { ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, 'A', L'A' }, 1015d6770bdSMartin Matuska { ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, 'R', L'R' }, 1025d6770bdSMartin Matuska { ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, 'W', L'W' }, 1035d6770bdSMartin Matuska { ARCHIVE_ENTRY_ACL_READ_ACL, 'c', L'c' }, 1045d6770bdSMartin Matuska { ARCHIVE_ENTRY_ACL_WRITE_ACL, 'C', L'C' }, 1055d6770bdSMartin Matuska { ARCHIVE_ENTRY_ACL_WRITE_OWNER, 'o', L'o' }, 1065d6770bdSMartin Matuska { ARCHIVE_ENTRY_ACL_SYNCHRONIZE, 's', L's' } 1075d6770bdSMartin Matuska }; 1085d6770bdSMartin Matuska 1095d6770bdSMartin Matuska static const int nfsv4_acl_perm_map_size = (int)(sizeof(nfsv4_acl_perm_map) / 1105d6770bdSMartin Matuska sizeof(nfsv4_acl_perm_map[0])); 1115d6770bdSMartin Matuska 1125d6770bdSMartin Matuska static const struct { 1135d6770bdSMartin Matuska const int perm; 1145d6770bdSMartin Matuska const char c; 1155d6770bdSMartin Matuska const wchar_t wc; 1165d6770bdSMartin Matuska } nfsv4_acl_flag_map[] = { 1175d6770bdSMartin Matuska { ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, 'f', L'f' }, 1185d6770bdSMartin Matuska { ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, 'd', L'd' }, 1195d6770bdSMartin Matuska { ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, 'i', L'i' }, 1205d6770bdSMartin Matuska { ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, 'n', L'n' }, 1215d6770bdSMartin Matuska { ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, 'S', L'S' }, 1225d6770bdSMartin Matuska { ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, 'F', L'F' }, 1235d6770bdSMartin Matuska { ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, 'I', L'I' } 1245d6770bdSMartin Matuska }; 1255d6770bdSMartin Matuska 1265d6770bdSMartin Matuska static const int nfsv4_acl_flag_map_size = (int)(sizeof(nfsv4_acl_flag_map) / 1275d6770bdSMartin Matuska sizeof(nfsv4_acl_flag_map[0])); 1285d6770bdSMartin Matuska 1296c95142eSMartin Matuska void 1306c95142eSMartin Matuska archive_acl_clear(struct archive_acl *acl) 1316c95142eSMartin Matuska { 1326c95142eSMartin Matuska struct archive_acl_entry *ap; 1336c95142eSMartin Matuska 1346c95142eSMartin Matuska while (acl->acl_head != NULL) { 1356c95142eSMartin Matuska ap = acl->acl_head->next; 1366c95142eSMartin Matuska archive_mstring_clean(&acl->acl_head->name); 1376c95142eSMartin Matuska free(acl->acl_head); 1386c95142eSMartin Matuska acl->acl_head = ap; 1396c95142eSMartin Matuska } 1406c95142eSMartin Matuska free(acl->acl_text_w); 1416c95142eSMartin Matuska acl->acl_text_w = NULL; 1426c95142eSMartin Matuska free(acl->acl_text); 1436c95142eSMartin Matuska acl->acl_text = NULL; 1446c95142eSMartin Matuska acl->acl_p = NULL; 145d5d08d29SMartin Matuska acl->acl_types = 0; 1466c95142eSMartin Matuska acl->acl_state = 0; /* Not counting. */ 1476c95142eSMartin Matuska } 1486c95142eSMartin Matuska 1496c95142eSMartin Matuska void 1506c95142eSMartin Matuska archive_acl_copy(struct archive_acl *dest, struct archive_acl *src) 1516c95142eSMartin Matuska { 1526c95142eSMartin Matuska struct archive_acl_entry *ap, *ap2; 1536c95142eSMartin Matuska 1546c95142eSMartin Matuska archive_acl_clear(dest); 1556c95142eSMartin Matuska 1566c95142eSMartin Matuska dest->mode = src->mode; 1576c95142eSMartin Matuska ap = src->acl_head; 1586c95142eSMartin Matuska while (ap != NULL) { 1596c95142eSMartin Matuska ap2 = acl_new_entry(dest, 1606c95142eSMartin Matuska ap->type, ap->permset, ap->tag, ap->id); 1616c95142eSMartin Matuska if (ap2 != NULL) 1626c95142eSMartin Matuska archive_mstring_copy(&ap2->name, &ap->name); 1636c95142eSMartin Matuska ap = ap->next; 1646c95142eSMartin Matuska } 1656c95142eSMartin Matuska } 1666c95142eSMartin Matuska 1676c95142eSMartin Matuska int 1686c95142eSMartin Matuska archive_acl_add_entry(struct archive_acl *acl, 1696c95142eSMartin Matuska int type, int permset, int tag, int id, const char *name) 1706c95142eSMartin Matuska { 1716c95142eSMartin Matuska struct archive_acl_entry *ap; 1726c95142eSMartin Matuska 1736c95142eSMartin Matuska if (acl_special(acl, type, permset, tag) == 0) 1746c95142eSMartin Matuska return ARCHIVE_OK; 1756c95142eSMartin Matuska ap = acl_new_entry(acl, type, permset, tag, id); 1766c95142eSMartin Matuska if (ap == NULL) { 1776c95142eSMartin Matuska /* XXX Error XXX */ 1786c95142eSMartin Matuska return ARCHIVE_FAILED; 1796c95142eSMartin Matuska } 1806c95142eSMartin Matuska if (name != NULL && *name != '\0') 1816c95142eSMartin Matuska archive_mstring_copy_mbs(&ap->name, name); 1826c95142eSMartin Matuska else 1836c95142eSMartin Matuska archive_mstring_clean(&ap->name); 1846c95142eSMartin Matuska return ARCHIVE_OK; 1856c95142eSMartin Matuska } 1866c95142eSMartin Matuska 1876c95142eSMartin Matuska int 1886c95142eSMartin Matuska archive_acl_add_entry_w_len(struct archive_acl *acl, 1896c95142eSMartin Matuska int type, int permset, int tag, int id, const wchar_t *name, size_t len) 1906c95142eSMartin Matuska { 1916c95142eSMartin Matuska struct archive_acl_entry *ap; 1926c95142eSMartin Matuska 1936c95142eSMartin Matuska if (acl_special(acl, type, permset, tag) == 0) 1946c95142eSMartin Matuska return ARCHIVE_OK; 1956c95142eSMartin Matuska ap = acl_new_entry(acl, type, permset, tag, id); 1966c95142eSMartin Matuska if (ap == NULL) { 1976c95142eSMartin Matuska /* XXX Error XXX */ 1986c95142eSMartin Matuska return ARCHIVE_FAILED; 1996c95142eSMartin Matuska } 2006c95142eSMartin Matuska if (name != NULL && *name != L'\0' && len > 0) 2016c95142eSMartin Matuska archive_mstring_copy_wcs_len(&ap->name, name, len); 2026c95142eSMartin Matuska else 2036c95142eSMartin Matuska archive_mstring_clean(&ap->name); 2046c95142eSMartin Matuska return ARCHIVE_OK; 2056c95142eSMartin Matuska } 2066c95142eSMartin Matuska 2076c95142eSMartin Matuska static int 2086c95142eSMartin Matuska archive_acl_add_entry_len_l(struct archive_acl *acl, 2096c95142eSMartin Matuska int type, int permset, int tag, int id, const char *name, size_t len, 2106c95142eSMartin Matuska struct archive_string_conv *sc) 2116c95142eSMartin Matuska { 2126c95142eSMartin Matuska struct archive_acl_entry *ap; 2136c95142eSMartin Matuska int r; 2146c95142eSMartin Matuska 2156c95142eSMartin Matuska if (acl_special(acl, type, permset, tag) == 0) 2166c95142eSMartin Matuska return ARCHIVE_OK; 2176c95142eSMartin Matuska ap = acl_new_entry(acl, type, permset, tag, id); 2186c95142eSMartin Matuska if (ap == NULL) { 2196c95142eSMartin Matuska /* XXX Error XXX */ 2206c95142eSMartin Matuska return ARCHIVE_FAILED; 2216c95142eSMartin Matuska } 2226c95142eSMartin Matuska if (name != NULL && *name != '\0' && len > 0) { 2236c95142eSMartin Matuska r = archive_mstring_copy_mbs_len_l(&ap->name, name, len, sc); 2246c95142eSMartin Matuska } else { 2256c95142eSMartin Matuska r = 0; 2266c95142eSMartin Matuska archive_mstring_clean(&ap->name); 2276c95142eSMartin Matuska } 2286c95142eSMartin Matuska if (r == 0) 2296c95142eSMartin Matuska return (ARCHIVE_OK); 2306c95142eSMartin Matuska else if (errno == ENOMEM) 2316c95142eSMartin Matuska return (ARCHIVE_FATAL); 2326c95142eSMartin Matuska else 2336c95142eSMartin Matuska return (ARCHIVE_WARN); 2346c95142eSMartin Matuska } 2356c95142eSMartin Matuska 2366c95142eSMartin Matuska /* 2376c95142eSMartin Matuska * If this ACL entry is part of the standard POSIX permissions set, 2386c95142eSMartin Matuska * store the permissions in the stat structure and return zero. 2396c95142eSMartin Matuska */ 2406c95142eSMartin Matuska static int 2416c95142eSMartin Matuska acl_special(struct archive_acl *acl, int type, int permset, int tag) 2426c95142eSMartin Matuska { 2436c95142eSMartin Matuska if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS 2446c95142eSMartin Matuska && ((permset & ~007) == 0)) { 2456c95142eSMartin Matuska switch (tag) { 2466c95142eSMartin Matuska case ARCHIVE_ENTRY_ACL_USER_OBJ: 2476c95142eSMartin Matuska acl->mode &= ~0700; 2486c95142eSMartin Matuska acl->mode |= (permset & 7) << 6; 2496c95142eSMartin Matuska return (0); 2506c95142eSMartin Matuska case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 2516c95142eSMartin Matuska acl->mode &= ~0070; 2526c95142eSMartin Matuska acl->mode |= (permset & 7) << 3; 2536c95142eSMartin Matuska return (0); 2546c95142eSMartin Matuska case ARCHIVE_ENTRY_ACL_OTHER: 2556c95142eSMartin Matuska acl->mode &= ~0007; 2566c95142eSMartin Matuska acl->mode |= permset & 7; 2576c95142eSMartin Matuska return (0); 2586c95142eSMartin Matuska } 2596c95142eSMartin Matuska } 2606c95142eSMartin Matuska return (1); 2616c95142eSMartin Matuska } 2626c95142eSMartin Matuska 2636c95142eSMartin Matuska /* 2646c95142eSMartin Matuska * Allocate and populate a new ACL entry with everything but the 2656c95142eSMartin Matuska * name. 2666c95142eSMartin Matuska */ 2676c95142eSMartin Matuska static struct archive_acl_entry * 2686c95142eSMartin Matuska acl_new_entry(struct archive_acl *acl, 2696c95142eSMartin Matuska int type, int permset, int tag, int id) 2706c95142eSMartin Matuska { 2716c95142eSMartin Matuska struct archive_acl_entry *ap, *aq; 2726c95142eSMartin Matuska 2736c95142eSMartin Matuska /* Type argument must be a valid NFS4 or POSIX.1e type. 2746c95142eSMartin Matuska * The type must agree with anything already set and 2756c95142eSMartin Matuska * the permset must be compatible. */ 2766c95142eSMartin Matuska if (type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 2776c95142eSMartin Matuska if (acl->acl_types & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 2786c95142eSMartin Matuska return (NULL); 2796c95142eSMartin Matuska } 2806c95142eSMartin Matuska if (permset & 2816c95142eSMartin Matuska ~(ARCHIVE_ENTRY_ACL_PERMS_NFS4 2826c95142eSMartin Matuska | ARCHIVE_ENTRY_ACL_INHERITANCE_NFS4)) { 2836c95142eSMartin Matuska return (NULL); 2846c95142eSMartin Matuska } 2856c95142eSMartin Matuska } else if (type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) { 2866c95142eSMartin Matuska if (acl->acl_types & ~ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) { 2876c95142eSMartin Matuska return (NULL); 2886c95142eSMartin Matuska } 2896c95142eSMartin Matuska if (permset & ~ARCHIVE_ENTRY_ACL_PERMS_POSIX1E) { 2906c95142eSMartin Matuska return (NULL); 2916c95142eSMartin Matuska } 2926c95142eSMartin Matuska } else { 2936c95142eSMartin Matuska return (NULL); 2946c95142eSMartin Matuska } 2956c95142eSMartin Matuska 2966c95142eSMartin Matuska /* Verify the tag is valid and compatible with NFS4 or POSIX.1e. */ 2976c95142eSMartin Matuska switch (tag) { 2986c95142eSMartin Matuska case ARCHIVE_ENTRY_ACL_USER: 2996c95142eSMartin Matuska case ARCHIVE_ENTRY_ACL_USER_OBJ: 3006c95142eSMartin Matuska case ARCHIVE_ENTRY_ACL_GROUP: 3016c95142eSMartin Matuska case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 3026c95142eSMartin Matuska /* Tags valid in both NFS4 and POSIX.1e */ 3036c95142eSMartin Matuska break; 3046c95142eSMartin Matuska case ARCHIVE_ENTRY_ACL_MASK: 3056c95142eSMartin Matuska case ARCHIVE_ENTRY_ACL_OTHER: 3066c95142eSMartin Matuska /* Tags valid only in POSIX.1e. */ 3076c95142eSMartin Matuska if (type & ~ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) { 3086c95142eSMartin Matuska return (NULL); 3096c95142eSMartin Matuska } 3106c95142eSMartin Matuska break; 3116c95142eSMartin Matuska case ARCHIVE_ENTRY_ACL_EVERYONE: 3126c95142eSMartin Matuska /* Tags valid only in NFS4. */ 3136c95142eSMartin Matuska if (type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 3146c95142eSMartin Matuska return (NULL); 3156c95142eSMartin Matuska } 3166c95142eSMartin Matuska break; 3176c95142eSMartin Matuska default: 3186c95142eSMartin Matuska /* No other values are valid. */ 3196c95142eSMartin Matuska return (NULL); 3206c95142eSMartin Matuska } 3216c95142eSMartin Matuska 3226c95142eSMartin Matuska free(acl->acl_text_w); 3236c95142eSMartin Matuska acl->acl_text_w = NULL; 3246c95142eSMartin Matuska free(acl->acl_text); 3256c95142eSMartin Matuska acl->acl_text = NULL; 3266c95142eSMartin Matuska 3276a414569SMartin Matuska /* 3286a414569SMartin Matuska * If there's a matching entry already in the list, overwrite it. 3296a414569SMartin Matuska * NFSv4 entries may be repeated and are not overwritten. 3306a414569SMartin Matuska * 3316a414569SMartin Matuska * TODO: compare names of no id is provided (needs more rework) 3326a414569SMartin Matuska */ 3336c95142eSMartin Matuska ap = acl->acl_head; 3346c95142eSMartin Matuska aq = NULL; 3356c95142eSMartin Matuska while (ap != NULL) { 3366a414569SMartin Matuska if (((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0) && 3376a414569SMartin Matuska ap->type == type && ap->tag == tag && ap->id == id) { 338d5d08d29SMartin Matuska if (id != -1 || (tag != ARCHIVE_ENTRY_ACL_USER && 339d5d08d29SMartin Matuska tag != ARCHIVE_ENTRY_ACL_GROUP)) { 3406c95142eSMartin Matuska ap->permset = permset; 3416c95142eSMartin Matuska return (ap); 3426c95142eSMartin Matuska } 343d5d08d29SMartin Matuska } 3446c95142eSMartin Matuska aq = ap; 3456c95142eSMartin Matuska ap = ap->next; 3466c95142eSMartin Matuska } 3476c95142eSMartin Matuska 3486c95142eSMartin Matuska /* Add a new entry to the end of the list. */ 349*bd66c1b4SMartin Matuska ap = calloc(1, sizeof(*ap)); 3506c95142eSMartin Matuska if (ap == NULL) 3516c95142eSMartin Matuska return (NULL); 3526c95142eSMartin Matuska if (aq == NULL) 3536c95142eSMartin Matuska acl->acl_head = ap; 3546c95142eSMartin Matuska else 3556c95142eSMartin Matuska aq->next = ap; 3566c95142eSMartin Matuska ap->type = type; 3576c95142eSMartin Matuska ap->tag = tag; 3586c95142eSMartin Matuska ap->id = id; 3596c95142eSMartin Matuska ap->permset = permset; 3606c95142eSMartin Matuska acl->acl_types |= type; 3616c95142eSMartin Matuska return (ap); 3626c95142eSMartin Matuska } 3636c95142eSMartin Matuska 3646c95142eSMartin Matuska /* 3656c95142eSMartin Matuska * Return a count of entries matching "want_type". 3666c95142eSMartin Matuska */ 3676c95142eSMartin Matuska int 3686c95142eSMartin Matuska archive_acl_count(struct archive_acl *acl, int want_type) 3696c95142eSMartin Matuska { 3706c95142eSMartin Matuska int count; 3716c95142eSMartin Matuska struct archive_acl_entry *ap; 3726c95142eSMartin Matuska 3736c95142eSMartin Matuska count = 0; 3746c95142eSMartin Matuska ap = acl->acl_head; 3756c95142eSMartin Matuska while (ap != NULL) { 3766c95142eSMartin Matuska if ((ap->type & want_type) != 0) 3776c95142eSMartin Matuska count++; 3786c95142eSMartin Matuska ap = ap->next; 3796c95142eSMartin Matuska } 3806c95142eSMartin Matuska 3816c95142eSMartin Matuska if (count > 0 && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)) 3826c95142eSMartin Matuska count += 3; 3836c95142eSMartin Matuska return (count); 3846c95142eSMartin Matuska } 3856c95142eSMartin Matuska 3866c95142eSMartin Matuska /* 3879f3de9e2SMartin Matuska * Return a bitmask of stored ACL types in an ACL list 3889f3de9e2SMartin Matuska */ 3899f3de9e2SMartin Matuska int 3909f3de9e2SMartin Matuska archive_acl_types(struct archive_acl *acl) 3919f3de9e2SMartin Matuska { 3929f3de9e2SMartin Matuska return (acl->acl_types); 3939f3de9e2SMartin Matuska } 3949f3de9e2SMartin Matuska 3959f3de9e2SMartin Matuska /* 3966c95142eSMartin Matuska * Prepare for reading entries from the ACL data. Returns a count 3976c95142eSMartin Matuska * of entries matching "want_type", or zero if there are no 3986c95142eSMartin Matuska * non-extended ACL entries of that type. 3996c95142eSMartin Matuska */ 4006c95142eSMartin Matuska int 4016c95142eSMartin Matuska archive_acl_reset(struct archive_acl *acl, int want_type) 4026c95142eSMartin Matuska { 4036c95142eSMartin Matuska int count, cutoff; 4046c95142eSMartin Matuska 4056c95142eSMartin Matuska count = archive_acl_count(acl, want_type); 4066c95142eSMartin Matuska 4076c95142eSMartin Matuska /* 4086c95142eSMartin Matuska * If the only entries are the three standard ones, 4096c95142eSMartin Matuska * then don't return any ACL data. (In this case, 4106c95142eSMartin Matuska * client can just use chmod(2) to set permissions.) 4116c95142eSMartin Matuska */ 4126c95142eSMartin Matuska if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) 4136c95142eSMartin Matuska cutoff = 3; 4146c95142eSMartin Matuska else 4156c95142eSMartin Matuska cutoff = 0; 4166c95142eSMartin Matuska 4176c95142eSMartin Matuska if (count > cutoff) 4186c95142eSMartin Matuska acl->acl_state = ARCHIVE_ENTRY_ACL_USER_OBJ; 4196c95142eSMartin Matuska else 4206c95142eSMartin Matuska acl->acl_state = 0; 4216c95142eSMartin Matuska acl->acl_p = acl->acl_head; 4226c95142eSMartin Matuska return (count); 4236c95142eSMartin Matuska } 4246c95142eSMartin Matuska 4256c95142eSMartin Matuska 4266c95142eSMartin Matuska /* 4276c95142eSMartin Matuska * Return the next ACL entry in the list. Fake entries for the 4286c95142eSMartin Matuska * standard permissions and include them in the returned list. 4296c95142eSMartin Matuska */ 4306c95142eSMartin Matuska int 431e9ed7ea4SMartin Matuska archive_acl_next(struct archive *a, struct archive_acl *acl, int want_type, 432e9ed7ea4SMartin Matuska int *type, int *permset, int *tag, int *id, const char **name) 4336c95142eSMartin Matuska { 4346c95142eSMartin Matuska *name = NULL; 4356c95142eSMartin Matuska *id = -1; 4366c95142eSMartin Matuska 4376c95142eSMartin Matuska /* 4386c95142eSMartin Matuska * The acl_state is either zero (no entries available), -1 4396c95142eSMartin Matuska * (reading from list), or an entry type (retrieve that type 4406c95142eSMartin Matuska * from ae_stat.aest_mode). 4416c95142eSMartin Matuska */ 4426c95142eSMartin Matuska if (acl->acl_state == 0) 4436c95142eSMartin Matuska return (ARCHIVE_WARN); 4446c95142eSMartin Matuska 4456c95142eSMartin Matuska /* The first three access entries are special. */ 4466c95142eSMartin Matuska if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { 4476c95142eSMartin Matuska switch (acl->acl_state) { 4486c95142eSMartin Matuska case ARCHIVE_ENTRY_ACL_USER_OBJ: 4496c95142eSMartin Matuska *permset = (acl->mode >> 6) & 7; 4506c95142eSMartin Matuska *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 4516c95142eSMartin Matuska *tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 4526c95142eSMartin Matuska acl->acl_state = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 4536c95142eSMartin Matuska return (ARCHIVE_OK); 4546c95142eSMartin Matuska case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 4556c95142eSMartin Matuska *permset = (acl->mode >> 3) & 7; 4566c95142eSMartin Matuska *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 4576c95142eSMartin Matuska *tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 4586c95142eSMartin Matuska acl->acl_state = ARCHIVE_ENTRY_ACL_OTHER; 4596c95142eSMartin Matuska return (ARCHIVE_OK); 4606c95142eSMartin Matuska case ARCHIVE_ENTRY_ACL_OTHER: 4616c95142eSMartin Matuska *permset = acl->mode & 7; 4626c95142eSMartin Matuska *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 4636c95142eSMartin Matuska *tag = ARCHIVE_ENTRY_ACL_OTHER; 4646c95142eSMartin Matuska acl->acl_state = -1; 4656c95142eSMartin Matuska acl->acl_p = acl->acl_head; 4666c95142eSMartin Matuska return (ARCHIVE_OK); 4676c95142eSMartin Matuska default: 4686c95142eSMartin Matuska break; 4696c95142eSMartin Matuska } 4706c95142eSMartin Matuska } 4716c95142eSMartin Matuska 4726c95142eSMartin Matuska while (acl->acl_p != NULL && (acl->acl_p->type & want_type) == 0) 4736c95142eSMartin Matuska acl->acl_p = acl->acl_p->next; 4746c95142eSMartin Matuska if (acl->acl_p == NULL) { 4756c95142eSMartin Matuska acl->acl_state = 0; 4766c95142eSMartin Matuska *type = 0; 4776c95142eSMartin Matuska *permset = 0; 4786c95142eSMartin Matuska *tag = 0; 4796c95142eSMartin Matuska *id = -1; 4806c95142eSMartin Matuska *name = NULL; 4816c95142eSMartin Matuska return (ARCHIVE_EOF); /* End of ACL entries. */ 4826c95142eSMartin Matuska } 4836c95142eSMartin Matuska *type = acl->acl_p->type; 4846c95142eSMartin Matuska *permset = acl->acl_p->permset; 4856c95142eSMartin Matuska *tag = acl->acl_p->tag; 4866c95142eSMartin Matuska *id = acl->acl_p->id; 487fd082e96SMartin Matuska if (archive_mstring_get_mbs(a, &acl->acl_p->name, name) != 0) { 488fd082e96SMartin Matuska if (errno == ENOMEM) 489fd082e96SMartin Matuska return (ARCHIVE_FATAL); 4906c95142eSMartin Matuska *name = NULL; 491fd082e96SMartin Matuska } 4926c95142eSMartin Matuska acl->acl_p = acl->acl_p->next; 4936c95142eSMartin Matuska return (ARCHIVE_OK); 4946c95142eSMartin Matuska } 4956c95142eSMartin Matuska 4966c95142eSMartin Matuska /* 497e9ed7ea4SMartin Matuska * Determine what type of ACL do we want 4986c95142eSMartin Matuska */ 499e9ed7ea4SMartin Matuska static int 500e9ed7ea4SMartin Matuska archive_acl_text_want_type(struct archive_acl *acl, int flags) 501e9ed7ea4SMartin Matuska { 502e9ed7ea4SMartin Matuska int want_type; 503e9ed7ea4SMartin Matuska 504e9ed7ea4SMartin Matuska /* Check if ACL is NFSv4 */ 505e9ed7ea4SMartin Matuska if ((acl->acl_types & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { 506e9ed7ea4SMartin Matuska /* NFSv4 should never mix with POSIX.1e */ 507e9ed7ea4SMartin Matuska if ((acl->acl_types & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) 508e9ed7ea4SMartin Matuska return (0); 509e9ed7ea4SMartin Matuska else 510e9ed7ea4SMartin Matuska return (ARCHIVE_ENTRY_ACL_TYPE_NFS4); 511e9ed7ea4SMartin Matuska } 512e9ed7ea4SMartin Matuska 513e9ed7ea4SMartin Matuska /* Now deal with POSIX.1e ACLs */ 514e9ed7ea4SMartin Matuska 515e9ed7ea4SMartin Matuska want_type = 0; 516e9ed7ea4SMartin Matuska if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) 517e9ed7ea4SMartin Matuska want_type |= ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 518e9ed7ea4SMartin Matuska if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) 519e9ed7ea4SMartin Matuska want_type |= ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; 520e9ed7ea4SMartin Matuska 521e9ed7ea4SMartin Matuska /* By default we want both access and default ACLs */ 522e9ed7ea4SMartin Matuska if (want_type == 0) 523e9ed7ea4SMartin Matuska return (ARCHIVE_ENTRY_ACL_TYPE_POSIX1E); 524e9ed7ea4SMartin Matuska 525e9ed7ea4SMartin Matuska return (want_type); 526e9ed7ea4SMartin Matuska } 527e9ed7ea4SMartin Matuska 528e9ed7ea4SMartin Matuska /* 529e9ed7ea4SMartin Matuska * Calculate ACL text string length 530e9ed7ea4SMartin Matuska */ 531*bd66c1b4SMartin Matuska static size_t 532e9ed7ea4SMartin Matuska archive_acl_text_len(struct archive_acl *acl, int want_type, int flags, 533e9ed7ea4SMartin Matuska int wide, struct archive *a, struct archive_string_conv *sc) { 534e9ed7ea4SMartin Matuska struct archive_acl_entry *ap; 535e9ed7ea4SMartin Matuska const char *name; 536e9ed7ea4SMartin Matuska const wchar_t *wname; 537e9ed7ea4SMartin Matuska int count, idlen, tmp, r; 538*bd66c1b4SMartin Matuska size_t length; 539e9ed7ea4SMartin Matuska size_t len; 540e9ed7ea4SMartin Matuska 541e9ed7ea4SMartin Matuska count = 0; 542e9ed7ea4SMartin Matuska length = 0; 543e9ed7ea4SMartin Matuska for (ap = acl->acl_head; ap != NULL; ap = ap->next) { 544e9ed7ea4SMartin Matuska if ((ap->type & want_type) == 0) 545e9ed7ea4SMartin Matuska continue; 546e9ed7ea4SMartin Matuska /* 547e9ed7ea4SMartin Matuska * Filemode-mapping ACL entries are stored exclusively in 548e9ed7ea4SMartin Matuska * ap->mode so they should not be in the list 549e9ed7ea4SMartin Matuska */ 550e9ed7ea4SMartin Matuska if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) 551e9ed7ea4SMartin Matuska && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ 552e9ed7ea4SMartin Matuska || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ 553e9ed7ea4SMartin Matuska || ap->tag == ARCHIVE_ENTRY_ACL_OTHER)) 554e9ed7ea4SMartin Matuska continue; 555e9ed7ea4SMartin Matuska count++; 556e9ed7ea4SMartin Matuska if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0 557e9ed7ea4SMartin Matuska && (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) 558e9ed7ea4SMartin Matuska length += 8; /* "default:" */ 559e9ed7ea4SMartin Matuska switch (ap->tag) { 560e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_USER_OBJ: 561e9ed7ea4SMartin Matuska if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 562e9ed7ea4SMartin Matuska length += 6; /* "owner@" */ 563e9ed7ea4SMartin Matuska break; 564e9ed7ea4SMartin Matuska } 565e9ed7ea4SMartin Matuska /* FALLTHROUGH */ 566e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_USER: 567e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_MASK: 568e9ed7ea4SMartin Matuska length += 4; /* "user", "mask" */ 569e9ed7ea4SMartin Matuska break; 570e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 571e9ed7ea4SMartin Matuska if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 572e9ed7ea4SMartin Matuska length += 6; /* "group@" */ 573e9ed7ea4SMartin Matuska break; 574e9ed7ea4SMartin Matuska } 575e9ed7ea4SMartin Matuska /* FALLTHROUGH */ 576e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_GROUP: 577e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_OTHER: 578e9ed7ea4SMartin Matuska length += 5; /* "group", "other" */ 579e9ed7ea4SMartin Matuska break; 580e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_EVERYONE: 581e9ed7ea4SMartin Matuska length += 9; /* "everyone@" */ 582e9ed7ea4SMartin Matuska break; 583e9ed7ea4SMartin Matuska } 584e9ed7ea4SMartin Matuska length += 1; /* colon after tag */ 585e9ed7ea4SMartin Matuska if (ap->tag == ARCHIVE_ENTRY_ACL_USER || 586e9ed7ea4SMartin Matuska ap->tag == ARCHIVE_ENTRY_ACL_GROUP) { 587e9ed7ea4SMartin Matuska if (wide) { 588e9ed7ea4SMartin Matuska r = archive_mstring_get_wcs(a, &ap->name, 589e9ed7ea4SMartin Matuska &wname); 590e9ed7ea4SMartin Matuska if (r == 0 && wname != NULL) 591e9ed7ea4SMartin Matuska length += wcslen(wname); 592e9ed7ea4SMartin Matuska else if (r < 0 && errno == ENOMEM) 593e9ed7ea4SMartin Matuska return (0); 594e9ed7ea4SMartin Matuska else 595e9ed7ea4SMartin Matuska length += sizeof(uid_t) * 3 + 1; 596e9ed7ea4SMartin Matuska } else { 597c3afd20fSMartin Matuska r = archive_mstring_get_mbs_l(a, &ap->name, &name, 598e9ed7ea4SMartin Matuska &len, sc); 599e9ed7ea4SMartin Matuska if (r != 0) 600e9ed7ea4SMartin Matuska return (0); 601e9ed7ea4SMartin Matuska if (len > 0 && name != NULL) 602e9ed7ea4SMartin Matuska length += len; 603e9ed7ea4SMartin Matuska else 604e9ed7ea4SMartin Matuska length += sizeof(uid_t) * 3 + 1; 605e9ed7ea4SMartin Matuska } 606e9ed7ea4SMartin Matuska length += 1; /* colon after user or group name */ 607e9ed7ea4SMartin Matuska } else if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) 608e9ed7ea4SMartin Matuska length += 1; /* 2nd colon empty user,group or other */ 609e9ed7ea4SMartin Matuska 610e9ed7ea4SMartin Matuska if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) != 0) 611e9ed7ea4SMartin Matuska && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) 612e9ed7ea4SMartin Matuska && (ap->tag == ARCHIVE_ENTRY_ACL_OTHER 613e9ed7ea4SMartin Matuska || ap->tag == ARCHIVE_ENTRY_ACL_MASK)) { 614e9ed7ea4SMartin Matuska /* Solaris has no colon after other: and mask: */ 615e9ed7ea4SMartin Matuska length = length - 1; 616e9ed7ea4SMartin Matuska } 617e9ed7ea4SMartin Matuska 618e9ed7ea4SMartin Matuska if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 619e9ed7ea4SMartin Matuska /* rwxpdDaARWcCos:fdinSFI:deny */ 620e9ed7ea4SMartin Matuska length += 27; 621e9ed7ea4SMartin Matuska if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DENY) == 0) 622e9ed7ea4SMartin Matuska length += 1; /* allow, alarm, audit */ 623e9ed7ea4SMartin Matuska } else 624e9ed7ea4SMartin Matuska length += 3; /* rwx */ 625e9ed7ea4SMartin Matuska 626e9ed7ea4SMartin Matuska if ((ap->tag == ARCHIVE_ENTRY_ACL_USER || 627e9ed7ea4SMartin Matuska ap->tag == ARCHIVE_ENTRY_ACL_GROUP) && 628e9ed7ea4SMartin Matuska (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) != 0) { 629e9ed7ea4SMartin Matuska length += 1; /* colon */ 630e9ed7ea4SMartin Matuska /* ID digit count */ 631e9ed7ea4SMartin Matuska idlen = 1; 632e9ed7ea4SMartin Matuska tmp = ap->id; 633e9ed7ea4SMartin Matuska while (tmp > 9) { 634e9ed7ea4SMartin Matuska tmp = tmp / 10; 635e9ed7ea4SMartin Matuska idlen++; 636e9ed7ea4SMartin Matuska } 637e9ed7ea4SMartin Matuska length += idlen; 638e9ed7ea4SMartin Matuska } 639e9ed7ea4SMartin Matuska length ++; /* entry separator */ 640e9ed7ea4SMartin Matuska } 641e9ed7ea4SMartin Matuska 642e9ed7ea4SMartin Matuska /* Add filemode-mapping access entries to the length */ 643e9ed7ea4SMartin Matuska if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { 644e9ed7ea4SMartin Matuska if ((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) != 0) { 645e9ed7ea4SMartin Matuska /* "user::rwx\ngroup::rwx\nother:rwx\n" */ 646e9ed7ea4SMartin Matuska length += 31; 647e9ed7ea4SMartin Matuska } else { 648e9ed7ea4SMartin Matuska /* "user::rwx\ngroup::rwx\nother::rwx\n" */ 649e9ed7ea4SMartin Matuska length += 32; 650e9ed7ea4SMartin Matuska } 651e9ed7ea4SMartin Matuska } else if (count == 0) 652e9ed7ea4SMartin Matuska return (0); 653e9ed7ea4SMartin Matuska 654e9ed7ea4SMartin Matuska /* The terminating character is included in count */ 655e9ed7ea4SMartin Matuska return (length); 656e9ed7ea4SMartin Matuska } 657e9ed7ea4SMartin Matuska 658e9ed7ea4SMartin Matuska /* 659e9ed7ea4SMartin Matuska * Generate a wide text version of the ACL. The flags parameter controls 660e9ed7ea4SMartin Matuska * the type and style of the generated ACL. 661e9ed7ea4SMartin Matuska */ 662e9ed7ea4SMartin Matuska wchar_t * 663e9ed7ea4SMartin Matuska archive_acl_to_text_w(struct archive_acl *acl, ssize_t *text_len, int flags, 664e9ed7ea4SMartin Matuska struct archive *a) 6656c95142eSMartin Matuska { 6666c95142eSMartin Matuska int count; 667*bd66c1b4SMartin Matuska size_t length; 668e9ed7ea4SMartin Matuska size_t len; 6696c95142eSMartin Matuska const wchar_t *wname; 6706c95142eSMartin Matuska const wchar_t *prefix; 6716c95142eSMartin Matuska wchar_t separator; 6726c95142eSMartin Matuska struct archive_acl_entry *ap; 673e9ed7ea4SMartin Matuska int id, r, want_type; 674e9ed7ea4SMartin Matuska wchar_t *wp, *ws; 6756c95142eSMartin Matuska 676e9ed7ea4SMartin Matuska want_type = archive_acl_text_want_type(acl, flags); 6776c95142eSMartin Matuska 678e9ed7ea4SMartin Matuska /* Both NFSv4 and POSIX.1 types found */ 679e9ed7ea4SMartin Matuska if (want_type == 0) 680e9ed7ea4SMartin Matuska return (NULL); 681e9ed7ea4SMartin Matuska 682e9ed7ea4SMartin Matuska if (want_type == ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) 683e9ed7ea4SMartin Matuska flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT; 684e9ed7ea4SMartin Matuska 685e9ed7ea4SMartin Matuska length = archive_acl_text_len(acl, want_type, flags, 1, a, NULL); 686e9ed7ea4SMartin Matuska 687e9ed7ea4SMartin Matuska if (length == 0) 688e9ed7ea4SMartin Matuska return (NULL); 689e9ed7ea4SMartin Matuska 690e9ed7ea4SMartin Matuska if (flags & ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA) 6916c95142eSMartin Matuska separator = L','; 6926c95142eSMartin Matuska else 693e9ed7ea4SMartin Matuska separator = L'\n'; 694c438d384SMartin Matuska 6956c95142eSMartin Matuska /* Now, allocate the string and actually populate it. */ 696*bd66c1b4SMartin Matuska wp = ws = malloc(length * sizeof(*wp)); 697e9ed7ea4SMartin Matuska if (wp == NULL) { 698e9ed7ea4SMartin Matuska if (errno == ENOMEM) 699e9ed7ea4SMartin Matuska __archive_errx(1, "No memory"); 700fd082e96SMartin Matuska return (NULL); 701e9ed7ea4SMartin Matuska } 7026c95142eSMartin Matuska count = 0; 703e9ed7ea4SMartin Matuska 704e9ed7ea4SMartin Matuska if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { 705e9ed7ea4SMartin Matuska append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 706e9ed7ea4SMartin Matuska ARCHIVE_ENTRY_ACL_USER_OBJ, flags, NULL, 707c438d384SMartin Matuska acl->mode & 0700, -1); 708e9ed7ea4SMartin Matuska *wp++ = separator; 709e9ed7ea4SMartin Matuska append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 710e9ed7ea4SMartin Matuska ARCHIVE_ENTRY_ACL_GROUP_OBJ, flags, NULL, 711c438d384SMartin Matuska acl->mode & 0070, -1); 712e9ed7ea4SMartin Matuska *wp++ = separator; 713e9ed7ea4SMartin Matuska append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 714e9ed7ea4SMartin Matuska ARCHIVE_ENTRY_ACL_OTHER, flags, NULL, 715c438d384SMartin Matuska acl->mode & 0007, -1); 716c4676089SMartin Matuska count += 3; 7176c95142eSMartin Matuska } 7186c95142eSMartin Matuska 719e9ed7ea4SMartin Matuska for (ap = acl->acl_head; ap != NULL; ap = ap->next) { 720e9ed7ea4SMartin Matuska if ((ap->type & want_type) == 0) 721e9ed7ea4SMartin Matuska continue; 722e9ed7ea4SMartin Matuska /* 723e9ed7ea4SMartin Matuska * Filemode-mapping ACL entries are stored exclusively in 724e9ed7ea4SMartin Matuska * ap->mode so they should not be in the list 725e9ed7ea4SMartin Matuska */ 726e9ed7ea4SMartin Matuska if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) 727e9ed7ea4SMartin Matuska && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ 728e9ed7ea4SMartin Matuska || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ 729e9ed7ea4SMartin Matuska || ap->tag == ARCHIVE_ENTRY_ACL_OTHER)) 730e9ed7ea4SMartin Matuska continue; 731e9ed7ea4SMartin Matuska if (ap->type == ARCHIVE_ENTRY_ACL_TYPE_DEFAULT && 732e9ed7ea4SMartin Matuska (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0) 7336c95142eSMartin Matuska prefix = L"default:"; 7346c95142eSMartin Matuska else 7356c95142eSMartin Matuska prefix = NULL; 736fd082e96SMartin Matuska r = archive_mstring_get_wcs(a, &ap->name, &wname); 737fd082e96SMartin Matuska if (r == 0) { 7386c95142eSMartin Matuska if (count > 0) 7396c95142eSMartin Matuska *wp++ = separator; 7406c95142eSMartin Matuska if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) 7416c95142eSMartin Matuska id = ap->id; 7426c95142eSMartin Matuska else 7436c95142eSMartin Matuska id = -1; 744e9ed7ea4SMartin Matuska append_entry_w(&wp, prefix, ap->type, ap->tag, flags, 745c438d384SMartin Matuska wname, ap->permset, id); 7466c95142eSMartin Matuska count++; 747276f481dSMartin Matuska } else if (r < 0 && errno == ENOMEM) { 748276f481dSMartin Matuska free(ws); 749fd082e96SMartin Matuska return (NULL); 7506c95142eSMartin Matuska } 751276f481dSMartin Matuska } 7526c95142eSMartin Matuska 753e9ed7ea4SMartin Matuska /* Add terminating character */ 754e9ed7ea4SMartin Matuska *wp++ = L'\0'; 7556c95142eSMartin Matuska 756e9ed7ea4SMartin Matuska len = wcslen(ws); 757e9ed7ea4SMartin Matuska 758*bd66c1b4SMartin Matuska if (len > length - 1) 759e9ed7ea4SMartin Matuska __archive_errx(1, "Buffer overrun"); 760e9ed7ea4SMartin Matuska 761e9ed7ea4SMartin Matuska if (text_len != NULL) 762e9ed7ea4SMartin Matuska *text_len = len; 763e9ed7ea4SMartin Matuska 764e9ed7ea4SMartin Matuska return (ws); 765e9ed7ea4SMartin Matuska } 7666c95142eSMartin Matuska 7676c95142eSMartin Matuska static void 7686c95142eSMartin Matuska append_id_w(wchar_t **wp, int id) 7696c95142eSMartin Matuska { 7706c95142eSMartin Matuska if (id < 0) 7716c95142eSMartin Matuska id = 0; 7726c95142eSMartin Matuska if (id > 9) 7736c95142eSMartin Matuska append_id_w(wp, id / 10); 7746c95142eSMartin Matuska *(*wp)++ = L"0123456789"[id % 10]; 7756c95142eSMartin Matuska } 7766c95142eSMartin Matuska 7776c95142eSMartin Matuska static void 778e9ed7ea4SMartin Matuska append_entry_w(wchar_t **wp, const wchar_t *prefix, int type, 779e9ed7ea4SMartin Matuska int tag, int flags, const wchar_t *wname, int perm, int id) 7806c95142eSMartin Matuska { 7815d6770bdSMartin Matuska int i; 7825d6770bdSMartin Matuska 7836c95142eSMartin Matuska if (prefix != NULL) { 7846c95142eSMartin Matuska wcscpy(*wp, prefix); 7856c95142eSMartin Matuska *wp += wcslen(*wp); 7866c95142eSMartin Matuska } 7876c95142eSMartin Matuska switch (tag) { 7886c95142eSMartin Matuska case ARCHIVE_ENTRY_ACL_USER_OBJ: 7896c95142eSMartin Matuska wname = NULL; 7906c95142eSMartin Matuska id = -1; 791e9ed7ea4SMartin Matuska if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { 792e9ed7ea4SMartin Matuska wcscpy(*wp, L"owner@"); 793e9ed7ea4SMartin Matuska break; 794e9ed7ea4SMartin Matuska } 7956c95142eSMartin Matuska /* FALLTHROUGH */ 7966c95142eSMartin Matuska case ARCHIVE_ENTRY_ACL_USER: 7976c95142eSMartin Matuska wcscpy(*wp, L"user"); 7986c95142eSMartin Matuska break; 7996c95142eSMartin Matuska case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 8006c95142eSMartin Matuska wname = NULL; 8016c95142eSMartin Matuska id = -1; 802e9ed7ea4SMartin Matuska if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { 803e9ed7ea4SMartin Matuska wcscpy(*wp, L"group@"); 804e9ed7ea4SMartin Matuska break; 805e9ed7ea4SMartin Matuska } 8066c95142eSMartin Matuska /* FALLTHROUGH */ 8076c95142eSMartin Matuska case ARCHIVE_ENTRY_ACL_GROUP: 8086c95142eSMartin Matuska wcscpy(*wp, L"group"); 8096c95142eSMartin Matuska break; 8106c95142eSMartin Matuska case ARCHIVE_ENTRY_ACL_MASK: 8116c95142eSMartin Matuska wcscpy(*wp, L"mask"); 8126c95142eSMartin Matuska wname = NULL; 8136c95142eSMartin Matuska id = -1; 8146c95142eSMartin Matuska break; 8156c95142eSMartin Matuska case ARCHIVE_ENTRY_ACL_OTHER: 8166c95142eSMartin Matuska wcscpy(*wp, L"other"); 8176c95142eSMartin Matuska wname = NULL; 8186c95142eSMartin Matuska id = -1; 8196c95142eSMartin Matuska break; 820e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_EVERYONE: 821e9ed7ea4SMartin Matuska wcscpy(*wp, L"everyone@"); 822e9ed7ea4SMartin Matuska wname = NULL; 823e9ed7ea4SMartin Matuska id = -1; 824e9ed7ea4SMartin Matuska break; 8256c95142eSMartin Matuska } 8266c95142eSMartin Matuska *wp += wcslen(*wp); 8276c95142eSMartin Matuska *(*wp)++ = L':'; 828e9ed7ea4SMartin Matuska if (((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) || 829e9ed7ea4SMartin Matuska tag == ARCHIVE_ENTRY_ACL_USER || 830e9ed7ea4SMartin Matuska tag == ARCHIVE_ENTRY_ACL_GROUP) { 8316c95142eSMartin Matuska if (wname != NULL) { 8326c95142eSMartin Matuska wcscpy(*wp, wname); 8336c95142eSMartin Matuska *wp += wcslen(*wp); 8346c95142eSMartin Matuska } else if (tag == ARCHIVE_ENTRY_ACL_USER 8356c95142eSMartin Matuska || tag == ARCHIVE_ENTRY_ACL_GROUP) { 8366c95142eSMartin Matuska append_id_w(wp, id); 8372dbf8c4aSMartin Matuska if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0) 8386c95142eSMartin Matuska id = -1; 8396c95142eSMartin Matuska } 840e9ed7ea4SMartin Matuska /* Solaris style has no second colon after other and mask */ 841e9ed7ea4SMartin Matuska if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) == 0) 842e9ed7ea4SMartin Matuska || (tag != ARCHIVE_ENTRY_ACL_OTHER 843e9ed7ea4SMartin Matuska && tag != ARCHIVE_ENTRY_ACL_MASK)) 8446c95142eSMartin Matuska *(*wp)++ = L':'; 845e9ed7ea4SMartin Matuska } 846e9ed7ea4SMartin Matuska if ((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) { 847e9ed7ea4SMartin Matuska /* POSIX.1e ACL perms */ 848c438d384SMartin Matuska *(*wp)++ = (perm & 0444) ? L'r' : L'-'; 849c438d384SMartin Matuska *(*wp)++ = (perm & 0222) ? L'w' : L'-'; 850c438d384SMartin Matuska *(*wp)++ = (perm & 0111) ? L'x' : L'-'; 851e9ed7ea4SMartin Matuska } else { 8525d6770bdSMartin Matuska /* NFSv4 ACL perms */ 8535d6770bdSMartin Matuska for (i = 0; i < nfsv4_acl_perm_map_size; i++) { 8545d6770bdSMartin Matuska if (perm & nfsv4_acl_perm_map[i].perm) 8555d6770bdSMartin Matuska *(*wp)++ = nfsv4_acl_perm_map[i].wc; 8565d6770bdSMartin Matuska else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0) 8575d6770bdSMartin Matuska *(*wp)++ = L'-'; 8585d6770bdSMartin Matuska } 859e9ed7ea4SMartin Matuska *(*wp)++ = L':'; 8605d6770bdSMartin Matuska for (i = 0; i < nfsv4_acl_flag_map_size; i++) { 8615d6770bdSMartin Matuska if (perm & nfsv4_acl_flag_map[i].perm) 8625d6770bdSMartin Matuska *(*wp)++ = nfsv4_acl_flag_map[i].wc; 8635d6770bdSMartin Matuska else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0) 8645d6770bdSMartin Matuska *(*wp)++ = L'-'; 8655d6770bdSMartin Matuska } 866e9ed7ea4SMartin Matuska *(*wp)++ = L':'; 867e9ed7ea4SMartin Matuska switch (type) { 868e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: 869e9ed7ea4SMartin Matuska wcscpy(*wp, L"allow"); 870e9ed7ea4SMartin Matuska break; 871e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_TYPE_DENY: 872e9ed7ea4SMartin Matuska wcscpy(*wp, L"deny"); 873e9ed7ea4SMartin Matuska break; 874e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: 875e9ed7ea4SMartin Matuska wcscpy(*wp, L"audit"); 876e9ed7ea4SMartin Matuska break; 877e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_TYPE_ALARM: 878e9ed7ea4SMartin Matuska wcscpy(*wp, L"alarm"); 879e9ed7ea4SMartin Matuska break; 880e9ed7ea4SMartin Matuska default: 881e9ed7ea4SMartin Matuska break; 882e9ed7ea4SMartin Matuska } 883e9ed7ea4SMartin Matuska *wp += wcslen(*wp); 884e9ed7ea4SMartin Matuska } 8856c95142eSMartin Matuska if (id != -1) { 8866c95142eSMartin Matuska *(*wp)++ = L':'; 8876c95142eSMartin Matuska append_id_w(wp, id); 8886c95142eSMartin Matuska } 8896c95142eSMartin Matuska } 8906c95142eSMartin Matuska 891e9ed7ea4SMartin Matuska /* 892e9ed7ea4SMartin Matuska * Generate a text version of the ACL. The flags parameter controls 893e9ed7ea4SMartin Matuska * the type and style of the generated ACL. 894e9ed7ea4SMartin Matuska */ 895e9ed7ea4SMartin Matuska char * 896e9ed7ea4SMartin Matuska archive_acl_to_text_l(struct archive_acl *acl, ssize_t *text_len, int flags, 8976c95142eSMartin Matuska struct archive_string_conv *sc) 8986c95142eSMartin Matuska { 8996c95142eSMartin Matuska int count; 900*bd66c1b4SMartin Matuska size_t length; 901e9ed7ea4SMartin Matuska size_t len; 9026c95142eSMartin Matuska const char *name; 9036c95142eSMartin Matuska const char *prefix; 9046c95142eSMartin Matuska char separator; 9056c95142eSMartin Matuska struct archive_acl_entry *ap; 906e9ed7ea4SMartin Matuska int id, r, want_type; 907e9ed7ea4SMartin Matuska char *p, *s; 9086c95142eSMartin Matuska 909e9ed7ea4SMartin Matuska want_type = archive_acl_text_want_type(acl, flags); 9106c95142eSMartin Matuska 911e9ed7ea4SMartin Matuska /* Both NFSv4 and POSIX.1 types found */ 912e9ed7ea4SMartin Matuska if (want_type == 0) 913e9ed7ea4SMartin Matuska return (NULL); 914e9ed7ea4SMartin Matuska 915e9ed7ea4SMartin Matuska if (want_type == ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) 916e9ed7ea4SMartin Matuska flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT; 917e9ed7ea4SMartin Matuska 918e9ed7ea4SMartin Matuska length = archive_acl_text_len(acl, want_type, flags, 0, NULL, sc); 919e9ed7ea4SMartin Matuska 920e9ed7ea4SMartin Matuska if (length == 0) 921e9ed7ea4SMartin Matuska return (NULL); 922e9ed7ea4SMartin Matuska 923e9ed7ea4SMartin Matuska if (flags & ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA) 9246c95142eSMartin Matuska separator = ','; 9256c95142eSMartin Matuska else 926e9ed7ea4SMartin Matuska separator = '\n'; 927c438d384SMartin Matuska 9286c95142eSMartin Matuska /* Now, allocate the string and actually populate it. */ 929*bd66c1b4SMartin Matuska p = s = malloc(length * sizeof(*p)); 930e9ed7ea4SMartin Matuska if (p == NULL) { 931e9ed7ea4SMartin Matuska if (errno == ENOMEM) 932e9ed7ea4SMartin Matuska __archive_errx(1, "No memory"); 933e9ed7ea4SMartin Matuska return (NULL); 934e9ed7ea4SMartin Matuska } 9356c95142eSMartin Matuska count = 0; 936e9ed7ea4SMartin Matuska 937e9ed7ea4SMartin Matuska if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { 938e9ed7ea4SMartin Matuska append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 939e9ed7ea4SMartin Matuska ARCHIVE_ENTRY_ACL_USER_OBJ, flags, NULL, 940c438d384SMartin Matuska acl->mode & 0700, -1); 941e9ed7ea4SMartin Matuska *p++ = separator; 942e9ed7ea4SMartin Matuska append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 943e9ed7ea4SMartin Matuska ARCHIVE_ENTRY_ACL_GROUP_OBJ, flags, NULL, 944c438d384SMartin Matuska acl->mode & 0070, -1); 945e9ed7ea4SMartin Matuska *p++ = separator; 946e9ed7ea4SMartin Matuska append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 947e9ed7ea4SMartin Matuska ARCHIVE_ENTRY_ACL_OTHER, flags, NULL, 948c438d384SMartin Matuska acl->mode & 0007, -1); 9496c95142eSMartin Matuska count += 3; 950e9ed7ea4SMartin Matuska } 9516c95142eSMartin Matuska 9526c95142eSMartin Matuska for (ap = acl->acl_head; ap != NULL; ap = ap->next) { 953e9ed7ea4SMartin Matuska if ((ap->type & want_type) == 0) 9546c95142eSMartin Matuska continue; 955e9ed7ea4SMartin Matuska /* 956e9ed7ea4SMartin Matuska * Filemode-mapping ACL entries are stored exclusively in 957e9ed7ea4SMartin Matuska * ap->mode so they should not be in the list 958e9ed7ea4SMartin Matuska */ 959e9ed7ea4SMartin Matuska if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) 960e9ed7ea4SMartin Matuska && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ 961e9ed7ea4SMartin Matuska || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ 962e9ed7ea4SMartin Matuska || ap->tag == ARCHIVE_ENTRY_ACL_OTHER)) 963e9ed7ea4SMartin Matuska continue; 964e9ed7ea4SMartin Matuska if (ap->type == ARCHIVE_ENTRY_ACL_TYPE_DEFAULT && 965e9ed7ea4SMartin Matuska (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0) 966e9ed7ea4SMartin Matuska prefix = "default:"; 967e9ed7ea4SMartin Matuska else 968e9ed7ea4SMartin Matuska prefix = NULL; 9696c95142eSMartin Matuska r = archive_mstring_get_mbs_l( 970c3afd20fSMartin Matuska NULL, &ap->name, &name, &len, sc); 971276f481dSMartin Matuska if (r != 0) { 972276f481dSMartin Matuska free(s); 973e9ed7ea4SMartin Matuska return (NULL); 974276f481dSMartin Matuska } 975e9ed7ea4SMartin Matuska if (count > 0) 9766c95142eSMartin Matuska *p++ = separator; 977e9ed7ea4SMartin Matuska if (name == NULL || 978e9ed7ea4SMartin Matuska (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)) { 9796c95142eSMartin Matuska id = ap->id; 98047af42f8SMartin Matuska } else { 9816c95142eSMartin Matuska id = -1; 98247af42f8SMartin Matuska } 983e9ed7ea4SMartin Matuska append_entry(&p, prefix, ap->type, ap->tag, flags, name, 9846c95142eSMartin Matuska ap->permset, id); 9856c95142eSMartin Matuska count++; 9866c95142eSMartin Matuska } 9876c95142eSMartin Matuska 988e9ed7ea4SMartin Matuska /* Add terminating character */ 989e9ed7ea4SMartin Matuska *p++ = '\0'; 9906c95142eSMartin Matuska 991e9ed7ea4SMartin Matuska len = strlen(s); 9926c95142eSMartin Matuska 993*bd66c1b4SMartin Matuska if (len > length - 1) 994e9ed7ea4SMartin Matuska __archive_errx(1, "Buffer overrun"); 995e9ed7ea4SMartin Matuska 996e9ed7ea4SMartin Matuska if (text_len != NULL) 997e9ed7ea4SMartin Matuska *text_len = len; 998e9ed7ea4SMartin Matuska 999e9ed7ea4SMartin Matuska return (s); 10006c95142eSMartin Matuska } 10016c95142eSMartin Matuska 10026c95142eSMartin Matuska static void 10036c95142eSMartin Matuska append_id(char **p, int id) 10046c95142eSMartin Matuska { 10056c95142eSMartin Matuska if (id < 0) 10066c95142eSMartin Matuska id = 0; 10076c95142eSMartin Matuska if (id > 9) 10086c95142eSMartin Matuska append_id(p, id / 10); 10096c95142eSMartin Matuska *(*p)++ = "0123456789"[id % 10]; 10106c95142eSMartin Matuska } 10116c95142eSMartin Matuska 10126c95142eSMartin Matuska static void 1013e9ed7ea4SMartin Matuska append_entry(char **p, const char *prefix, int type, 1014e9ed7ea4SMartin Matuska int tag, int flags, const char *name, int perm, int id) 10156c95142eSMartin Matuska { 10165d6770bdSMartin Matuska int i; 10175d6770bdSMartin Matuska 10186c95142eSMartin Matuska if (prefix != NULL) { 10196c95142eSMartin Matuska strcpy(*p, prefix); 10206c95142eSMartin Matuska *p += strlen(*p); 10216c95142eSMartin Matuska } 10226c95142eSMartin Matuska switch (tag) { 10236c95142eSMartin Matuska case ARCHIVE_ENTRY_ACL_USER_OBJ: 10246c95142eSMartin Matuska name = NULL; 10256c95142eSMartin Matuska id = -1; 1026e9ed7ea4SMartin Matuska if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { 1027e9ed7ea4SMartin Matuska strcpy(*p, "owner@"); 1028e9ed7ea4SMartin Matuska break; 1029e9ed7ea4SMartin Matuska } 10306c95142eSMartin Matuska /* FALLTHROUGH */ 10316c95142eSMartin Matuska case ARCHIVE_ENTRY_ACL_USER: 10326c95142eSMartin Matuska strcpy(*p, "user"); 10336c95142eSMartin Matuska break; 10346c95142eSMartin Matuska case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 10356c95142eSMartin Matuska name = NULL; 10366c95142eSMartin Matuska id = -1; 1037e9ed7ea4SMartin Matuska if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { 1038e9ed7ea4SMartin Matuska strcpy(*p, "group@"); 1039e9ed7ea4SMartin Matuska break; 1040e9ed7ea4SMartin Matuska } 10416c95142eSMartin Matuska /* FALLTHROUGH */ 10426c95142eSMartin Matuska case ARCHIVE_ENTRY_ACL_GROUP: 10436c95142eSMartin Matuska strcpy(*p, "group"); 10446c95142eSMartin Matuska break; 10456c95142eSMartin Matuska case ARCHIVE_ENTRY_ACL_MASK: 10466c95142eSMartin Matuska strcpy(*p, "mask"); 10476c95142eSMartin Matuska name = NULL; 10486c95142eSMartin Matuska id = -1; 10496c95142eSMartin Matuska break; 10506c95142eSMartin Matuska case ARCHIVE_ENTRY_ACL_OTHER: 10516c95142eSMartin Matuska strcpy(*p, "other"); 10526c95142eSMartin Matuska name = NULL; 10536c95142eSMartin Matuska id = -1; 10546c95142eSMartin Matuska break; 1055e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_EVERYONE: 1056e9ed7ea4SMartin Matuska strcpy(*p, "everyone@"); 1057e9ed7ea4SMartin Matuska name = NULL; 1058e9ed7ea4SMartin Matuska id = -1; 1059e9ed7ea4SMartin Matuska break; 10606c95142eSMartin Matuska } 10616c95142eSMartin Matuska *p += strlen(*p); 10626c95142eSMartin Matuska *(*p)++ = ':'; 1063e9ed7ea4SMartin Matuska if (((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) || 1064e9ed7ea4SMartin Matuska tag == ARCHIVE_ENTRY_ACL_USER || 1065e9ed7ea4SMartin Matuska tag == ARCHIVE_ENTRY_ACL_GROUP) { 10666c95142eSMartin Matuska if (name != NULL) { 10676c95142eSMartin Matuska strcpy(*p, name); 10686c95142eSMartin Matuska *p += strlen(*p); 10696c95142eSMartin Matuska } else if (tag == ARCHIVE_ENTRY_ACL_USER 10706c95142eSMartin Matuska || tag == ARCHIVE_ENTRY_ACL_GROUP) { 10716c95142eSMartin Matuska append_id(p, id); 10722dbf8c4aSMartin Matuska if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0) 10736c95142eSMartin Matuska id = -1; 10746c95142eSMartin Matuska } 1075e9ed7ea4SMartin Matuska /* Solaris style has no second colon after other and mask */ 1076e9ed7ea4SMartin Matuska if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) == 0) 1077e9ed7ea4SMartin Matuska || (tag != ARCHIVE_ENTRY_ACL_OTHER 1078e9ed7ea4SMartin Matuska && tag != ARCHIVE_ENTRY_ACL_MASK)) 10796c95142eSMartin Matuska *(*p)++ = ':'; 1080e9ed7ea4SMartin Matuska } 1081e9ed7ea4SMartin Matuska if ((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) { 1082e9ed7ea4SMartin Matuska /* POSIX.1e ACL perms */ 1083c438d384SMartin Matuska *(*p)++ = (perm & 0444) ? 'r' : '-'; 1084c438d384SMartin Matuska *(*p)++ = (perm & 0222) ? 'w' : '-'; 1085c438d384SMartin Matuska *(*p)++ = (perm & 0111) ? 'x' : '-'; 1086e9ed7ea4SMartin Matuska } else { 10875d6770bdSMartin Matuska /* NFSv4 ACL perms */ 10885d6770bdSMartin Matuska for (i = 0; i < nfsv4_acl_perm_map_size; i++) { 10895d6770bdSMartin Matuska if (perm & nfsv4_acl_perm_map[i].perm) 10905d6770bdSMartin Matuska *(*p)++ = nfsv4_acl_perm_map[i].c; 10915d6770bdSMartin Matuska else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0) 10925d6770bdSMartin Matuska *(*p)++ = '-'; 10935d6770bdSMartin Matuska } 1094e9ed7ea4SMartin Matuska *(*p)++ = ':'; 10955d6770bdSMartin Matuska for (i = 0; i < nfsv4_acl_flag_map_size; i++) { 10965d6770bdSMartin Matuska if (perm & nfsv4_acl_flag_map[i].perm) 10975d6770bdSMartin Matuska *(*p)++ = nfsv4_acl_flag_map[i].c; 10985d6770bdSMartin Matuska else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0) 10995d6770bdSMartin Matuska *(*p)++ = '-'; 11005d6770bdSMartin Matuska } 1101e9ed7ea4SMartin Matuska *(*p)++ = ':'; 1102e9ed7ea4SMartin Matuska switch (type) { 1103e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: 1104e9ed7ea4SMartin Matuska strcpy(*p, "allow"); 1105e9ed7ea4SMartin Matuska break; 1106e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_TYPE_DENY: 1107e9ed7ea4SMartin Matuska strcpy(*p, "deny"); 1108e9ed7ea4SMartin Matuska break; 1109e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: 1110e9ed7ea4SMartin Matuska strcpy(*p, "audit"); 1111e9ed7ea4SMartin Matuska break; 1112e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_TYPE_ALARM: 1113e9ed7ea4SMartin Matuska strcpy(*p, "alarm"); 1114e9ed7ea4SMartin Matuska break; 1115e9ed7ea4SMartin Matuska } 1116e9ed7ea4SMartin Matuska *p += strlen(*p); 1117e9ed7ea4SMartin Matuska } 11186c95142eSMartin Matuska if (id != -1) { 11196c95142eSMartin Matuska *(*p)++ = ':'; 11206c95142eSMartin Matuska append_id(p, id); 11216c95142eSMartin Matuska } 11226c95142eSMartin Matuska } 11236c95142eSMartin Matuska 11246c95142eSMartin Matuska /* 1125e9ed7ea4SMartin Matuska * Parse a wide ACL text string. 1126e9ed7ea4SMartin Matuska * 1127e9ed7ea4SMartin Matuska * The want_type argument may be one of the following: 1128e9ed7ea4SMartin Matuska * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - text is a POSIX.1e ACL of type ACCESS 1129e9ed7ea4SMartin Matuska * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - text is a POSIX.1e ACL of type DEFAULT 1130e9ed7ea4SMartin Matuska * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - text is as a NFSv4 ACL 1131e9ed7ea4SMartin Matuska * 1132e9ed7ea4SMartin Matuska * POSIX.1e ACL entries prefixed with "default:" are treated as 1133e9ed7ea4SMartin Matuska * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT unless type is ARCHIVE_ENTRY_ACL_TYPE_NFS4 11346c95142eSMartin Matuska */ 11356c95142eSMartin Matuska int 1136e9ed7ea4SMartin Matuska archive_acl_from_text_w(struct archive_acl *acl, const wchar_t *text, 1137e9ed7ea4SMartin Matuska int want_type) 11386c95142eSMartin Matuska { 11396c95142eSMartin Matuska struct { 11406c95142eSMartin Matuska const wchar_t *start; 11416c95142eSMartin Matuska const wchar_t *end; 1142e9ed7ea4SMartin Matuska } field[6], name; 11436c95142eSMartin Matuska 1144e9ed7ea4SMartin Matuska const wchar_t *s, *st; 1145e9ed7ea4SMartin Matuska 11469f3de9e2SMartin Matuska int numfields, fields, n, r, sol, ret; 1147e9ed7ea4SMartin Matuska int type, types, tag, permset, id; 1148e9ed7ea4SMartin Matuska size_t len; 11496c95142eSMartin Matuska wchar_t sep; 11506c95142eSMartin Matuska 1151e9ed7ea4SMartin Matuska ret = ARCHIVE_OK; 1152e9ed7ea4SMartin Matuska types = 0; 1153e9ed7ea4SMartin Matuska 1154e9ed7ea4SMartin Matuska switch (want_type) { 1155e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E: 1156e9ed7ea4SMartin Matuska want_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 1157a2a3407cSMartin Matuska __LA_FALLTHROUGH; 1158e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: 1159e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: 1160e9ed7ea4SMartin Matuska numfields = 5; 1161e9ed7ea4SMartin Matuska break; 1162e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_TYPE_NFS4: 1163e9ed7ea4SMartin Matuska numfields = 6; 1164e9ed7ea4SMartin Matuska break; 1165e9ed7ea4SMartin Matuska default: 1166e9ed7ea4SMartin Matuska return (ARCHIVE_FATAL); 1167e9ed7ea4SMartin Matuska } 1168e9ed7ea4SMartin Matuska 11696c95142eSMartin Matuska while (text != NULL && *text != L'\0') { 11706c95142eSMartin Matuska /* 11716c95142eSMartin Matuska * Parse the fields out of the next entry, 11726c95142eSMartin Matuska * advance 'text' to start of next entry. 11736c95142eSMartin Matuska */ 11746c95142eSMartin Matuska fields = 0; 11756c95142eSMartin Matuska do { 11766c95142eSMartin Matuska const wchar_t *start, *end; 11776c95142eSMartin Matuska next_field_w(&text, &start, &end, &sep); 1178e9ed7ea4SMartin Matuska if (fields < numfields) { 11796c95142eSMartin Matuska field[fields].start = start; 11806c95142eSMartin Matuska field[fields].end = end; 11816c95142eSMartin Matuska } 11826c95142eSMartin Matuska ++fields; 11836c95142eSMartin Matuska } while (sep == L':'); 11846c95142eSMartin Matuska 11856c95142eSMartin Matuska /* Set remaining fields to blank. */ 1186e9ed7ea4SMartin Matuska for (n = fields; n < numfields; ++n) 11876c95142eSMartin Matuska field[n].start = field[n].end = NULL; 11886c95142eSMartin Matuska 1189e9ed7ea4SMartin Matuska if (field[0].start != NULL && *(field[0].start) == L'#') { 1190e9ed7ea4SMartin Matuska /* Comment, skip entry */ 1191e9ed7ea4SMartin Matuska continue; 1192e9ed7ea4SMartin Matuska } 1193e9ed7ea4SMartin Matuska 1194e9ed7ea4SMartin Matuska n = 0; 11959f3de9e2SMartin Matuska sol = 0; 11966c95142eSMartin Matuska id = -1; 1197e9ed7ea4SMartin Matuska permset = 0; 11986c95142eSMartin Matuska name.start = name.end = NULL; 1199e9ed7ea4SMartin Matuska 1200e9ed7ea4SMartin Matuska if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 1201e9ed7ea4SMartin Matuska /* POSIX.1e ACLs */ 1202e9ed7ea4SMartin Matuska /* 1203e9ed7ea4SMartin Matuska * Default keyword "default:user::rwx" 1204e9ed7ea4SMartin Matuska * if found, we have one more field 1205e9ed7ea4SMartin Matuska * 1206e9ed7ea4SMartin Matuska * We also support old Solaris extension: 1207e9ed7ea4SMartin Matuska * "defaultuser::rwx" is the default ACL corresponding 1208e9ed7ea4SMartin Matuska * to "user::rwx", etc. valid only for first field 1209e9ed7ea4SMartin Matuska */ 1210e9ed7ea4SMartin Matuska s = field[0].start; 1211e9ed7ea4SMartin Matuska len = field[0].end - field[0].start; 1212e9ed7ea4SMartin Matuska if (*s == L'd' && (len == 1 || (len >= 7 1213e9ed7ea4SMartin Matuska && wmemcmp((s + 1), L"efault", 6) == 0))) { 1214e9ed7ea4SMartin Matuska type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; 1215e9ed7ea4SMartin Matuska if (len > 7) 1216e9ed7ea4SMartin Matuska field[0].start += 7; 1217e9ed7ea4SMartin Matuska else 1218e9ed7ea4SMartin Matuska n = 1; 12196c95142eSMartin Matuska } else 1220e9ed7ea4SMartin Matuska type = want_type; 1221e9ed7ea4SMartin Matuska 1222e9ed7ea4SMartin Matuska /* Check for a numeric ID in field n+1 or n+3. */ 1223e9ed7ea4SMartin Matuska isint_w(field[n + 1].start, field[n + 1].end, &id); 1224e9ed7ea4SMartin Matuska /* Field n+3 is optional. */ 1225e9ed7ea4SMartin Matuska if (id == -1 && fields > n+3) 1226e9ed7ea4SMartin Matuska isint_w(field[n + 3].start, field[n + 3].end, 1227e9ed7ea4SMartin Matuska &id); 1228e9ed7ea4SMartin Matuska 1229e9ed7ea4SMartin Matuska tag = 0; 1230e9ed7ea4SMartin Matuska s = field[n].start; 1231e9ed7ea4SMartin Matuska st = field[n].start + 1; 1232e9ed7ea4SMartin Matuska len = field[n].end - field[n].start; 1233e9ed7ea4SMartin Matuska 1234e9ed7ea4SMartin Matuska switch (*s) { 1235e9ed7ea4SMartin Matuska case L'u': 1236e9ed7ea4SMartin Matuska if (len == 1 || (len == 4 1237e9ed7ea4SMartin Matuska && wmemcmp(st, L"ser", 3) == 0)) 12386c95142eSMartin Matuska tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 1239e9ed7ea4SMartin Matuska break; 1240e9ed7ea4SMartin Matuska case L'g': 1241e9ed7ea4SMartin Matuska if (len == 1 || (len == 5 1242e9ed7ea4SMartin Matuska && wmemcmp(st, L"roup", 4) == 0)) 1243e9ed7ea4SMartin Matuska tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 1244e9ed7ea4SMartin Matuska break; 1245e9ed7ea4SMartin Matuska case L'o': 1246e9ed7ea4SMartin Matuska if (len == 1 || (len == 5 1247e9ed7ea4SMartin Matuska && wmemcmp(st, L"ther", 4) == 0)) 1248e9ed7ea4SMartin Matuska tag = ARCHIVE_ENTRY_ACL_OTHER; 1249e9ed7ea4SMartin Matuska break; 1250e9ed7ea4SMartin Matuska case L'm': 1251e9ed7ea4SMartin Matuska if (len == 1 || (len == 4 1252e9ed7ea4SMartin Matuska && wmemcmp(st, L"ask", 3) == 0)) 1253e9ed7ea4SMartin Matuska tag = ARCHIVE_ENTRY_ACL_MASK; 1254e9ed7ea4SMartin Matuska break; 1255e9ed7ea4SMartin Matuska default: 1256e9ed7ea4SMartin Matuska break; 1257e9ed7ea4SMartin Matuska } 1258e9ed7ea4SMartin Matuska 1259e9ed7ea4SMartin Matuska switch (tag) { 1260e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_OTHER: 1261e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_MASK: 1262e9ed7ea4SMartin Matuska if (fields == (n + 2) 1263e9ed7ea4SMartin Matuska && field[n + 1].start < field[n + 1].end 1264e9ed7ea4SMartin Matuska && ismode_w(field[n + 1].start, 1265e9ed7ea4SMartin Matuska field[n + 1].end, &permset)) { 1266e9ed7ea4SMartin Matuska /* This is Solaris-style "other:rwx" */ 12679f3de9e2SMartin Matuska sol = 1; 1268e9ed7ea4SMartin Matuska } else if (fields == (n + 3) && 1269e9ed7ea4SMartin Matuska field[n + 1].start < field[n + 1].end) { 1270e9ed7ea4SMartin Matuska /* Invalid mask or other field */ 1271e9ed7ea4SMartin Matuska ret = ARCHIVE_WARN; 1272e9ed7ea4SMartin Matuska continue; 1273e9ed7ea4SMartin Matuska } 1274e9ed7ea4SMartin Matuska break; 1275e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_USER_OBJ: 1276e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 1277e9ed7ea4SMartin Matuska if (id != -1 || 1278e9ed7ea4SMartin Matuska field[n + 1].start < field[n + 1].end) { 1279e9ed7ea4SMartin Matuska name = field[n + 1]; 1280e9ed7ea4SMartin Matuska if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) 1281e9ed7ea4SMartin Matuska tag = ARCHIVE_ENTRY_ACL_USER; 1282e9ed7ea4SMartin Matuska else 12836c95142eSMartin Matuska tag = ARCHIVE_ENTRY_ACL_GROUP; 1284e9ed7ea4SMartin Matuska } 1285e9ed7ea4SMartin Matuska break; 1286e9ed7ea4SMartin Matuska default: 1287e9ed7ea4SMartin Matuska /* Invalid tag, skip entry */ 1288e9ed7ea4SMartin Matuska ret = ARCHIVE_WARN; 1289e9ed7ea4SMartin Matuska continue; 1290e9ed7ea4SMartin Matuska } 1291e9ed7ea4SMartin Matuska 12929f3de9e2SMartin Matuska /* 12939f3de9e2SMartin Matuska * Without "default:" we expect mode in field 2 12949f3de9e2SMartin Matuska * Exception: Solaris other and mask fields 12959f3de9e2SMartin Matuska */ 12969f3de9e2SMartin Matuska if (permset == 0 && !ismode_w(field[n + 2 - sol].start, 12979f3de9e2SMartin Matuska field[n + 2 - sol].end, &permset)) { 1298e9ed7ea4SMartin Matuska /* Invalid mode, skip entry */ 1299e9ed7ea4SMartin Matuska ret = ARCHIVE_WARN; 1300e9ed7ea4SMartin Matuska continue; 1301e9ed7ea4SMartin Matuska } 1302e9ed7ea4SMartin Matuska } else { 1303e9ed7ea4SMartin Matuska /* NFS4 ACLs */ 1304e9ed7ea4SMartin Matuska s = field[0].start; 1305e9ed7ea4SMartin Matuska len = field[0].end - field[0].start; 1306e9ed7ea4SMartin Matuska tag = 0; 1307e9ed7ea4SMartin Matuska 1308e9ed7ea4SMartin Matuska switch (len) { 1309e9ed7ea4SMartin Matuska case 4: 1310e9ed7ea4SMartin Matuska if (wmemcmp(s, L"user", 4) == 0) 1311e9ed7ea4SMartin Matuska tag = ARCHIVE_ENTRY_ACL_USER; 1312e9ed7ea4SMartin Matuska break; 1313e9ed7ea4SMartin Matuska case 5: 1314e9ed7ea4SMartin Matuska if (wmemcmp(s, L"group", 5) == 0) 1315e9ed7ea4SMartin Matuska tag = ARCHIVE_ENTRY_ACL_GROUP; 1316e9ed7ea4SMartin Matuska break; 1317e9ed7ea4SMartin Matuska case 6: 1318e9ed7ea4SMartin Matuska if (wmemcmp(s, L"owner@", 6) == 0) 1319e9ed7ea4SMartin Matuska tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 1320e9ed7ea4SMartin Matuska else if (wmemcmp(s, L"group@", len) == 0) 1321e9ed7ea4SMartin Matuska tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 1322e9ed7ea4SMartin Matuska break; 1323e9ed7ea4SMartin Matuska case 9: 1324e9ed7ea4SMartin Matuska if (wmemcmp(s, L"everyone@", 9) == 0) 1325e9ed7ea4SMartin Matuska tag = ARCHIVE_ENTRY_ACL_EVERYONE; 1326e9ed7ea4SMartin Matuska default: 1327e9ed7ea4SMartin Matuska break; 1328e9ed7ea4SMartin Matuska } 1329e9ed7ea4SMartin Matuska 1330e9ed7ea4SMartin Matuska if (tag == 0) { 1331e9ed7ea4SMartin Matuska /* Invalid tag, skip entry */ 1332e9ed7ea4SMartin Matuska ret = ARCHIVE_WARN; 1333e9ed7ea4SMartin Matuska continue; 1334e9ed7ea4SMartin Matuska } else if (tag == ARCHIVE_ENTRY_ACL_USER || 1335e9ed7ea4SMartin Matuska tag == ARCHIVE_ENTRY_ACL_GROUP) { 1336e9ed7ea4SMartin Matuska n = 1; 13376c95142eSMartin Matuska name = field[1]; 13382dbf8c4aSMartin Matuska isint_w(name.start, name.end, &id); 13396c95142eSMartin Matuska } else 1340e9ed7ea4SMartin Matuska n = 0; 1341e9ed7ea4SMartin Matuska 1342e9ed7ea4SMartin Matuska if (!is_nfs4_perms_w(field[1 + n].start, 1343e9ed7ea4SMartin Matuska field[1 + n].end, &permset)) { 1344e9ed7ea4SMartin Matuska /* Invalid NFSv4 perms, skip entry */ 1345e9ed7ea4SMartin Matuska ret = ARCHIVE_WARN; 1346e9ed7ea4SMartin Matuska continue; 1347e9ed7ea4SMartin Matuska } 1348e9ed7ea4SMartin Matuska if (!is_nfs4_flags_w(field[2 + n].start, 1349e9ed7ea4SMartin Matuska field[2 + n].end, &permset)) { 1350e9ed7ea4SMartin Matuska /* Invalid NFSv4 flags, skip entry */ 1351e9ed7ea4SMartin Matuska ret = ARCHIVE_WARN; 1352e9ed7ea4SMartin Matuska continue; 1353e9ed7ea4SMartin Matuska } 1354e9ed7ea4SMartin Matuska s = field[3 + n].start; 1355e9ed7ea4SMartin Matuska len = field[3 + n].end - field[3 + n].start; 1356e9ed7ea4SMartin Matuska type = 0; 1357e9ed7ea4SMartin Matuska if (len == 4) { 1358e9ed7ea4SMartin Matuska if (wmemcmp(s, L"deny", 4) == 0) 1359e9ed7ea4SMartin Matuska type = ARCHIVE_ENTRY_ACL_TYPE_DENY; 1360e9ed7ea4SMartin Matuska } else if (len == 5) { 1361e9ed7ea4SMartin Matuska if (wmemcmp(s, L"allow", 5) == 0) 1362e9ed7ea4SMartin Matuska type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; 1363e9ed7ea4SMartin Matuska else if (wmemcmp(s, L"audit", 5) == 0) 1364e9ed7ea4SMartin Matuska type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT; 1365e9ed7ea4SMartin Matuska else if (wmemcmp(s, L"alarm", 5) == 0) 1366e9ed7ea4SMartin Matuska type = ARCHIVE_ENTRY_ACL_TYPE_ALARM; 1367e9ed7ea4SMartin Matuska } 1368e9ed7ea4SMartin Matuska if (type == 0) { 1369e9ed7ea4SMartin Matuska /* Invalid entry type, skip entry */ 1370e9ed7ea4SMartin Matuska ret = ARCHIVE_WARN; 1371e9ed7ea4SMartin Matuska continue; 1372e9ed7ea4SMartin Matuska } 1373e9ed7ea4SMartin Matuska isint_w(field[4 + n].start, field[4 + n].end, &id); 1374e9ed7ea4SMartin Matuska } 13756c95142eSMartin Matuska 13766c95142eSMartin Matuska /* Add entry to the internal list. */ 1377e9ed7ea4SMartin Matuska r = archive_acl_add_entry_w_len(acl, type, permset, 13786c95142eSMartin Matuska tag, id, name.start, name.end - name.start); 1379e9ed7ea4SMartin Matuska if (r < ARCHIVE_WARN) 1380e9ed7ea4SMartin Matuska return (r); 1381e9ed7ea4SMartin Matuska if (r != ARCHIVE_OK) 1382e9ed7ea4SMartin Matuska ret = ARCHIVE_WARN; 1383e9ed7ea4SMartin Matuska types |= type; 13846c95142eSMartin Matuska } 1385e9ed7ea4SMartin Matuska 1386e9ed7ea4SMartin Matuska /* Reset ACL */ 1387e9ed7ea4SMartin Matuska archive_acl_reset(acl, types); 1388e9ed7ea4SMartin Matuska 1389e9ed7ea4SMartin Matuska return (ret); 13906c95142eSMartin Matuska } 13916c95142eSMartin Matuska 13926c95142eSMartin Matuska /* 13936c95142eSMartin Matuska * Parse a string to a positive decimal integer. Returns true if 13946c95142eSMartin Matuska * the string is non-empty and consists only of decimal digits, 13956c95142eSMartin Matuska * false otherwise. 13966c95142eSMartin Matuska */ 13976c95142eSMartin Matuska static int 13986c95142eSMartin Matuska isint_w(const wchar_t *start, const wchar_t *end, int *result) 13996c95142eSMartin Matuska { 14006c95142eSMartin Matuska int n = 0; 14016c95142eSMartin Matuska if (start >= end) 14026c95142eSMartin Matuska return (0); 14036c95142eSMartin Matuska while (start < end) { 1404c3afd20fSMartin Matuska if (*start < L'0' || *start > L'9') 14056c95142eSMartin Matuska return (0); 14066c95142eSMartin Matuska if (n > (INT_MAX / 10) || 1407c3afd20fSMartin Matuska (n == INT_MAX / 10 && (*start - L'0') > INT_MAX % 10)) { 14086c95142eSMartin Matuska n = INT_MAX; 14096c95142eSMartin Matuska } else { 14106c95142eSMartin Matuska n *= 10; 1411c3afd20fSMartin Matuska n += *start - L'0'; 14126c95142eSMartin Matuska } 14136c95142eSMartin Matuska start++; 14146c95142eSMartin Matuska } 14156c95142eSMartin Matuska *result = n; 14166c95142eSMartin Matuska return (1); 14176c95142eSMartin Matuska } 14186c95142eSMartin Matuska 14196c95142eSMartin Matuska /* 14206c95142eSMartin Matuska * Parse a string as a mode field. Returns true if 14216c95142eSMartin Matuska * the string is non-empty and consists only of mode characters, 14226c95142eSMartin Matuska * false otherwise. 14236c95142eSMartin Matuska */ 14246c95142eSMartin Matuska static int 14256c95142eSMartin Matuska ismode_w(const wchar_t *start, const wchar_t *end, int *permset) 14266c95142eSMartin Matuska { 14276c95142eSMartin Matuska const wchar_t *p; 14286c95142eSMartin Matuska 14296c95142eSMartin Matuska if (start >= end) 14306c95142eSMartin Matuska return (0); 14316c95142eSMartin Matuska p = start; 14326c95142eSMartin Matuska *permset = 0; 14336c95142eSMartin Matuska while (p < end) { 14346c95142eSMartin Matuska switch (*p++) { 1435e9ed7ea4SMartin Matuska case L'r': case L'R': 14366c95142eSMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_READ; 14376c95142eSMartin Matuska break; 1438e9ed7ea4SMartin Matuska case L'w': case L'W': 14396c95142eSMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_WRITE; 14406c95142eSMartin Matuska break; 1441e9ed7ea4SMartin Matuska case L'x': case L'X': 14426c95142eSMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; 14436c95142eSMartin Matuska break; 1444e9ed7ea4SMartin Matuska case L'-': 1445e9ed7ea4SMartin Matuska break; 1446e9ed7ea4SMartin Matuska default: 1447e9ed7ea4SMartin Matuska return (0); 1448e9ed7ea4SMartin Matuska } 1449e9ed7ea4SMartin Matuska } 1450e9ed7ea4SMartin Matuska return (1); 1451e9ed7ea4SMartin Matuska } 1452e9ed7ea4SMartin Matuska 1453e9ed7ea4SMartin Matuska /* 1454e9ed7ea4SMartin Matuska * Parse a string as a NFS4 ACL permission field. 1455e9ed7ea4SMartin Matuska * Returns true if the string is non-empty and consists only of NFS4 ACL 1456e9ed7ea4SMartin Matuska * permission characters, false otherwise 1457e9ed7ea4SMartin Matuska */ 1458e9ed7ea4SMartin Matuska static int 1459e9ed7ea4SMartin Matuska is_nfs4_perms_w(const wchar_t *start, const wchar_t *end, int *permset) 1460e9ed7ea4SMartin Matuska { 14615d6770bdSMartin Matuska const wchar_t *p = start; 1462e9ed7ea4SMartin Matuska 1463e9ed7ea4SMartin Matuska while (p < end) { 1464e9ed7ea4SMartin Matuska switch (*p++) { 1465e9ed7ea4SMartin Matuska case L'r': 1466e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_READ_DATA; 1467e9ed7ea4SMartin Matuska break; 1468e9ed7ea4SMartin Matuska case L'w': 1469e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_WRITE_DATA; 1470e9ed7ea4SMartin Matuska break; 1471e9ed7ea4SMartin Matuska case L'x': 1472e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; 1473e9ed7ea4SMartin Matuska break; 1474e9ed7ea4SMartin Matuska case L'p': 1475e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_APPEND_DATA; 1476e9ed7ea4SMartin Matuska break; 1477e9ed7ea4SMartin Matuska case L'D': 1478e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_DELETE_CHILD; 1479e9ed7ea4SMartin Matuska break; 1480e9ed7ea4SMartin Matuska case L'd': 1481e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_DELETE; 1482e9ed7ea4SMartin Matuska break; 1483e9ed7ea4SMartin Matuska case L'a': 1484e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES; 1485e9ed7ea4SMartin Matuska break; 1486e9ed7ea4SMartin Matuska case L'A': 1487e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES; 1488e9ed7ea4SMartin Matuska break; 1489e9ed7ea4SMartin Matuska case L'R': 1490e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS; 1491e9ed7ea4SMartin Matuska break; 1492e9ed7ea4SMartin Matuska case L'W': 1493e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS; 1494e9ed7ea4SMartin Matuska break; 1495e9ed7ea4SMartin Matuska case L'c': 1496e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_READ_ACL; 1497e9ed7ea4SMartin Matuska break; 1498e9ed7ea4SMartin Matuska case L'C': 1499e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_WRITE_ACL; 1500e9ed7ea4SMartin Matuska break; 1501e9ed7ea4SMartin Matuska case L'o': 1502e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_WRITE_OWNER; 1503e9ed7ea4SMartin Matuska break; 1504e9ed7ea4SMartin Matuska case L's': 1505e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE; 1506e9ed7ea4SMartin Matuska break; 1507e9ed7ea4SMartin Matuska case L'-': 1508e9ed7ea4SMartin Matuska break; 1509e9ed7ea4SMartin Matuska default: 1510e9ed7ea4SMartin Matuska return(0); 1511e9ed7ea4SMartin Matuska } 1512e9ed7ea4SMartin Matuska } 1513e9ed7ea4SMartin Matuska return (1); 1514e9ed7ea4SMartin Matuska } 1515e9ed7ea4SMartin Matuska 1516e9ed7ea4SMartin Matuska /* 1517e9ed7ea4SMartin Matuska * Parse a string as a NFS4 ACL flags field. 1518e9ed7ea4SMartin Matuska * Returns true if the string is non-empty and consists only of NFS4 ACL 1519e9ed7ea4SMartin Matuska * flag characters, false otherwise 1520e9ed7ea4SMartin Matuska */ 1521e9ed7ea4SMartin Matuska static int 1522e9ed7ea4SMartin Matuska is_nfs4_flags_w(const wchar_t *start, const wchar_t *end, int *permset) 1523e9ed7ea4SMartin Matuska { 15245d6770bdSMartin Matuska const wchar_t *p = start; 1525e9ed7ea4SMartin Matuska 1526e9ed7ea4SMartin Matuska while (p < end) { 1527e9ed7ea4SMartin Matuska switch(*p++) { 1528e9ed7ea4SMartin Matuska case L'f': 1529e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT; 1530e9ed7ea4SMartin Matuska break; 1531e9ed7ea4SMartin Matuska case L'd': 1532e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT; 1533e9ed7ea4SMartin Matuska break; 1534e9ed7ea4SMartin Matuska case L'i': 1535e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY; 1536e9ed7ea4SMartin Matuska break; 1537e9ed7ea4SMartin Matuska case L'n': 1538e9ed7ea4SMartin Matuska *permset |= 1539e9ed7ea4SMartin Matuska ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT; 1540e9ed7ea4SMartin Matuska break; 1541e9ed7ea4SMartin Matuska case L'S': 1542e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS; 1543e9ed7ea4SMartin Matuska break; 1544e9ed7ea4SMartin Matuska case L'F': 1545e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS; 1546e9ed7ea4SMartin Matuska break; 1547e9ed7ea4SMartin Matuska case L'I': 1548e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERITED; 1549e9ed7ea4SMartin Matuska break; 1550e9ed7ea4SMartin Matuska case L'-': 15516c95142eSMartin Matuska break; 15526c95142eSMartin Matuska default: 15536c95142eSMartin Matuska return (0); 15546c95142eSMartin Matuska } 15556c95142eSMartin Matuska } 15566c95142eSMartin Matuska return (1); 15576c95142eSMartin Matuska } 15586c95142eSMartin Matuska 15596c95142eSMartin Matuska /* 15606c95142eSMartin Matuska * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]". *wp is updated 15616c95142eSMartin Matuska * to point to just after the separator. *start points to the first 15626c95142eSMartin Matuska * character of the matched text and *end just after the last 15636c95142eSMartin Matuska * character of the matched identifier. In particular *end - *start 15646c95142eSMartin Matuska * is the length of the field body, not including leading or trailing 15656c95142eSMartin Matuska * whitespace. 15666c95142eSMartin Matuska */ 15676c95142eSMartin Matuska static void 15686c95142eSMartin Matuska next_field_w(const wchar_t **wp, const wchar_t **start, 15696c95142eSMartin Matuska const wchar_t **end, wchar_t *sep) 15706c95142eSMartin Matuska { 15716c95142eSMartin Matuska /* Skip leading whitespace to find start of field. */ 15726c95142eSMartin Matuska while (**wp == L' ' || **wp == L'\t' || **wp == L'\n') { 15736c95142eSMartin Matuska (*wp)++; 15746c95142eSMartin Matuska } 15756c95142eSMartin Matuska *start = *wp; 15766c95142eSMartin Matuska 15776c95142eSMartin Matuska /* Scan for the separator. */ 15786c95142eSMartin Matuska while (**wp != L'\0' && **wp != L',' && **wp != L':' && 15797d69e4cdSMartin Matuska **wp != L'\n' && **wp != L'#') { 15806c95142eSMartin Matuska (*wp)++; 15816c95142eSMartin Matuska } 15826c95142eSMartin Matuska *sep = **wp; 15836c95142eSMartin Matuska 15847d69e4cdSMartin Matuska /* Locate end of field, trim trailing whitespace if necessary */ 15857d69e4cdSMartin Matuska if (*wp == *start) { 15867d69e4cdSMartin Matuska *end = *wp; 15877d69e4cdSMartin Matuska } else { 15886c95142eSMartin Matuska *end = *wp - 1; 15896c95142eSMartin Matuska while (**end == L' ' || **end == L'\t' || **end == L'\n') { 15906c95142eSMartin Matuska (*end)--; 15916c95142eSMartin Matuska } 15926c95142eSMartin Matuska (*end)++; 15937d69e4cdSMartin Matuska } 15947d69e4cdSMartin Matuska 15957d69e4cdSMartin Matuska /* Handle in-field comments */ 15967d69e4cdSMartin Matuska if (*sep == L'#') { 15977d69e4cdSMartin Matuska while (**wp != L'\0' && **wp != L',' && **wp != L'\n') { 15987d69e4cdSMartin Matuska (*wp)++; 15997d69e4cdSMartin Matuska } 16007d69e4cdSMartin Matuska *sep = **wp; 16017d69e4cdSMartin Matuska } 16026c95142eSMartin Matuska 16036c95142eSMartin Matuska /* Adjust scanner location. */ 16046c95142eSMartin Matuska if (**wp != L'\0') 16056c95142eSMartin Matuska (*wp)++; 16066c95142eSMartin Matuska } 16076c95142eSMartin Matuska 16086c95142eSMartin Matuska /* 1609e9ed7ea4SMartin Matuska * Parse an ACL text string. 1610e9ed7ea4SMartin Matuska * 1611e9ed7ea4SMartin Matuska * The want_type argument may be one of the following: 1612e9ed7ea4SMartin Matuska * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - text is a POSIX.1e ACL of type ACCESS 1613e9ed7ea4SMartin Matuska * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - text is a POSIX.1e ACL of type DEFAULT 1614e9ed7ea4SMartin Matuska * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - text is as a NFSv4 ACL 1615e9ed7ea4SMartin Matuska * 1616e9ed7ea4SMartin Matuska * POSIX.1e ACL entries prefixed with "default:" are treated as 1617e9ed7ea4SMartin Matuska * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT unless type is ARCHIVE_ENTRY_ACL_TYPE_NFS4 16186c95142eSMartin Matuska */ 16196c95142eSMartin Matuska int 1620e9ed7ea4SMartin Matuska archive_acl_from_text_l(struct archive_acl *acl, const char *text, 1621e9ed7ea4SMartin Matuska int want_type, struct archive_string_conv *sc) 16226c95142eSMartin Matuska { 1623*bd66c1b4SMartin Matuska return archive_acl_from_text_nl(acl, text, strlen(text), want_type, sc); 1624*bd66c1b4SMartin Matuska } 1625*bd66c1b4SMartin Matuska 1626*bd66c1b4SMartin Matuska int 1627*bd66c1b4SMartin Matuska archive_acl_from_text_nl(struct archive_acl *acl, const char *text, 1628*bd66c1b4SMartin Matuska size_t length, int want_type, struct archive_string_conv *sc) 1629*bd66c1b4SMartin Matuska { 16306c95142eSMartin Matuska struct { 16316c95142eSMartin Matuska const char *start; 16326c95142eSMartin Matuska const char *end; 1633e9ed7ea4SMartin Matuska } field[6], name; 16346c95142eSMartin Matuska 1635e9ed7ea4SMartin Matuska const char *s, *st; 16369f3de9e2SMartin Matuska int numfields, fields, n, r, sol, ret; 1637e9ed7ea4SMartin Matuska int type, types, tag, permset, id; 1638e9ed7ea4SMartin Matuska size_t len; 16396c95142eSMartin Matuska char sep; 16406c95142eSMartin Matuska 1641e9ed7ea4SMartin Matuska switch (want_type) { 1642e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E: 1643e9ed7ea4SMartin Matuska want_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 1644a2a3407cSMartin Matuska __LA_FALLTHROUGH; 1645e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: 1646e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: 1647e9ed7ea4SMartin Matuska numfields = 5; 1648e9ed7ea4SMartin Matuska break; 1649e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_TYPE_NFS4: 1650e9ed7ea4SMartin Matuska numfields = 6; 1651e9ed7ea4SMartin Matuska break; 1652e9ed7ea4SMartin Matuska default: 1653e9ed7ea4SMartin Matuska return (ARCHIVE_FATAL); 1654e9ed7ea4SMartin Matuska } 1655e9ed7ea4SMartin Matuska 1656e9ed7ea4SMartin Matuska ret = ARCHIVE_OK; 1657e9ed7ea4SMartin Matuska types = 0; 1658e9ed7ea4SMartin Matuska 1659*bd66c1b4SMartin Matuska while (text != NULL && length > 0 && *text != '\0') { 16606c95142eSMartin Matuska /* 16616c95142eSMartin Matuska * Parse the fields out of the next entry, 16626c95142eSMartin Matuska * advance 'text' to start of next entry. 16636c95142eSMartin Matuska */ 16646c95142eSMartin Matuska fields = 0; 16656c95142eSMartin Matuska do { 16666c95142eSMartin Matuska const char *start, *end; 1667*bd66c1b4SMartin Matuska next_field(&text, &length, &start, &end, &sep); 1668e9ed7ea4SMartin Matuska if (fields < numfields) { 16696c95142eSMartin Matuska field[fields].start = start; 16706c95142eSMartin Matuska field[fields].end = end; 16716c95142eSMartin Matuska } 16726c95142eSMartin Matuska ++fields; 16736c95142eSMartin Matuska } while (sep == ':'); 16746c95142eSMartin Matuska 16756c95142eSMartin Matuska /* Set remaining fields to blank. */ 1676e9ed7ea4SMartin Matuska for (n = fields; n < numfields; ++n) 16776c95142eSMartin Matuska field[n].start = field[n].end = NULL; 16786c95142eSMartin Matuska 1679e9ed7ea4SMartin Matuska if (field[0].start != NULL && *(field[0].start) == '#') { 1680e9ed7ea4SMartin Matuska /* Comment, skip entry */ 1681e9ed7ea4SMartin Matuska continue; 1682e9ed7ea4SMartin Matuska } 1683e9ed7ea4SMartin Matuska 1684e9ed7ea4SMartin Matuska n = 0; 16859f3de9e2SMartin Matuska sol = 0; 16866c95142eSMartin Matuska id = -1; 1687e9ed7ea4SMartin Matuska permset = 0; 16886c95142eSMartin Matuska name.start = name.end = NULL; 1689e9ed7ea4SMartin Matuska 1690e9ed7ea4SMartin Matuska if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 1691e9ed7ea4SMartin Matuska /* POSIX.1e ACLs */ 1692e9ed7ea4SMartin Matuska /* 1693e9ed7ea4SMartin Matuska * Default keyword "default:user::rwx" 1694e9ed7ea4SMartin Matuska * if found, we have one more field 1695e9ed7ea4SMartin Matuska * 1696e9ed7ea4SMartin Matuska * We also support old Solaris extension: 1697e9ed7ea4SMartin Matuska * "defaultuser::rwx" is the default ACL corresponding 1698e9ed7ea4SMartin Matuska * to "user::rwx", etc. valid only for first field 1699e9ed7ea4SMartin Matuska */ 1700e9ed7ea4SMartin Matuska s = field[0].start; 1701e9ed7ea4SMartin Matuska len = field[0].end - field[0].start; 1702e9ed7ea4SMartin Matuska if (*s == 'd' && (len == 1 || (len >= 7 1703e9ed7ea4SMartin Matuska && memcmp((s + 1), "efault", 6) == 0))) { 1704e9ed7ea4SMartin Matuska type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; 1705e9ed7ea4SMartin Matuska if (len > 7) 1706e9ed7ea4SMartin Matuska field[0].start += 7; 1707e9ed7ea4SMartin Matuska else 1708e9ed7ea4SMartin Matuska n = 1; 17096c95142eSMartin Matuska } else 1710e9ed7ea4SMartin Matuska type = want_type; 1711e9ed7ea4SMartin Matuska 1712e9ed7ea4SMartin Matuska /* Check for a numeric ID in field n+1 or n+3. */ 1713e9ed7ea4SMartin Matuska isint(field[n + 1].start, field[n + 1].end, &id); 1714e9ed7ea4SMartin Matuska /* Field n+3 is optional. */ 1715e9ed7ea4SMartin Matuska if (id == -1 && fields > (n + 3)) 1716e9ed7ea4SMartin Matuska isint(field[n + 3].start, field[n + 3].end, 1717e9ed7ea4SMartin Matuska &id); 1718e9ed7ea4SMartin Matuska 1719e9ed7ea4SMartin Matuska tag = 0; 1720e9ed7ea4SMartin Matuska s = field[n].start; 1721e9ed7ea4SMartin Matuska st = field[n].start + 1; 1722e9ed7ea4SMartin Matuska len = field[n].end - field[n].start; 1723e9ed7ea4SMartin Matuska 172498bf66e6SMartin Matuska if (len == 0) { 172598bf66e6SMartin Matuska ret = ARCHIVE_WARN; 172698bf66e6SMartin Matuska continue; 172798bf66e6SMartin Matuska } 172898bf66e6SMartin Matuska 1729e9ed7ea4SMartin Matuska switch (*s) { 1730e9ed7ea4SMartin Matuska case 'u': 1731e9ed7ea4SMartin Matuska if (len == 1 || (len == 4 1732e9ed7ea4SMartin Matuska && memcmp(st, "ser", 3) == 0)) 17336c95142eSMartin Matuska tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 1734e9ed7ea4SMartin Matuska break; 1735e9ed7ea4SMartin Matuska case 'g': 1736e9ed7ea4SMartin Matuska if (len == 1 || (len == 5 1737e9ed7ea4SMartin Matuska && memcmp(st, "roup", 4) == 0)) 1738e9ed7ea4SMartin Matuska tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 1739e9ed7ea4SMartin Matuska break; 1740e9ed7ea4SMartin Matuska case 'o': 1741e9ed7ea4SMartin Matuska if (len == 1 || (len == 5 1742e9ed7ea4SMartin Matuska && memcmp(st, "ther", 4) == 0)) 1743e9ed7ea4SMartin Matuska tag = ARCHIVE_ENTRY_ACL_OTHER; 1744e9ed7ea4SMartin Matuska break; 1745e9ed7ea4SMartin Matuska case 'm': 1746e9ed7ea4SMartin Matuska if (len == 1 || (len == 4 1747e9ed7ea4SMartin Matuska && memcmp(st, "ask", 3) == 0)) 1748e9ed7ea4SMartin Matuska tag = ARCHIVE_ENTRY_ACL_MASK; 1749e9ed7ea4SMartin Matuska break; 1750e9ed7ea4SMartin Matuska default: 1751e9ed7ea4SMartin Matuska break; 1752e9ed7ea4SMartin Matuska } 1753e9ed7ea4SMartin Matuska 1754e9ed7ea4SMartin Matuska switch (tag) { 1755e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_OTHER: 1756e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_MASK: 1757e9ed7ea4SMartin Matuska if (fields == (n + 2) 1758e9ed7ea4SMartin Matuska && field[n + 1].start < field[n + 1].end 1759e9ed7ea4SMartin Matuska && ismode(field[n + 1].start, 1760e9ed7ea4SMartin Matuska field[n + 1].end, &permset)) { 1761e9ed7ea4SMartin Matuska /* This is Solaris-style "other:rwx" */ 17629f3de9e2SMartin Matuska sol = 1; 1763e9ed7ea4SMartin Matuska } else if (fields == (n + 3) && 1764e9ed7ea4SMartin Matuska field[n + 1].start < field[n + 1].end) { 1765e9ed7ea4SMartin Matuska /* Invalid mask or other field */ 1766e9ed7ea4SMartin Matuska ret = ARCHIVE_WARN; 1767e9ed7ea4SMartin Matuska continue; 1768e9ed7ea4SMartin Matuska } 1769e9ed7ea4SMartin Matuska break; 1770e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_USER_OBJ: 1771e9ed7ea4SMartin Matuska case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 1772e9ed7ea4SMartin Matuska if (id != -1 || 1773e9ed7ea4SMartin Matuska field[n + 1].start < field[n + 1].end) { 1774e9ed7ea4SMartin Matuska name = field[n + 1]; 1775e9ed7ea4SMartin Matuska if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) 1776e9ed7ea4SMartin Matuska tag = ARCHIVE_ENTRY_ACL_USER; 1777e9ed7ea4SMartin Matuska else 17786c95142eSMartin Matuska tag = ARCHIVE_ENTRY_ACL_GROUP; 1779e9ed7ea4SMartin Matuska } 1780e9ed7ea4SMartin Matuska break; 1781e9ed7ea4SMartin Matuska default: 1782e9ed7ea4SMartin Matuska /* Invalid tag, skip entry */ 1783e9ed7ea4SMartin Matuska ret = ARCHIVE_WARN; 1784e9ed7ea4SMartin Matuska continue; 1785e9ed7ea4SMartin Matuska } 1786e9ed7ea4SMartin Matuska 17879f3de9e2SMartin Matuska /* 17889f3de9e2SMartin Matuska * Without "default:" we expect mode in field 3 17899f3de9e2SMartin Matuska * Exception: Solaris other and mask fields 17909f3de9e2SMartin Matuska */ 17919f3de9e2SMartin Matuska if (permset == 0 && !ismode(field[n + 2 - sol].start, 17929f3de9e2SMartin Matuska field[n + 2 - sol].end, &permset)) { 1793e9ed7ea4SMartin Matuska /* Invalid mode, skip entry */ 1794e9ed7ea4SMartin Matuska ret = ARCHIVE_WARN; 1795e9ed7ea4SMartin Matuska continue; 1796e9ed7ea4SMartin Matuska } 1797e9ed7ea4SMartin Matuska } else { 1798e9ed7ea4SMartin Matuska /* NFS4 ACLs */ 1799e9ed7ea4SMartin Matuska s = field[0].start; 1800e9ed7ea4SMartin Matuska len = field[0].end - field[0].start; 1801e9ed7ea4SMartin Matuska tag = 0; 1802e9ed7ea4SMartin Matuska 1803e9ed7ea4SMartin Matuska switch (len) { 1804e9ed7ea4SMartin Matuska case 4: 1805e9ed7ea4SMartin Matuska if (memcmp(s, "user", 4) == 0) 1806e9ed7ea4SMartin Matuska tag = ARCHIVE_ENTRY_ACL_USER; 1807e9ed7ea4SMartin Matuska break; 1808e9ed7ea4SMartin Matuska case 5: 1809e9ed7ea4SMartin Matuska if (memcmp(s, "group", 5) == 0) 1810e9ed7ea4SMartin Matuska tag = ARCHIVE_ENTRY_ACL_GROUP; 1811e9ed7ea4SMartin Matuska break; 1812e9ed7ea4SMartin Matuska case 6: 1813e9ed7ea4SMartin Matuska if (memcmp(s, "owner@", 6) == 0) 1814e9ed7ea4SMartin Matuska tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 1815e9ed7ea4SMartin Matuska else if (memcmp(s, "group@", 6) == 0) 1816e9ed7ea4SMartin Matuska tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 1817e9ed7ea4SMartin Matuska break; 1818e9ed7ea4SMartin Matuska case 9: 1819e9ed7ea4SMartin Matuska if (memcmp(s, "everyone@", 9) == 0) 1820e9ed7ea4SMartin Matuska tag = ARCHIVE_ENTRY_ACL_EVERYONE; 1821e9ed7ea4SMartin Matuska break; 1822e9ed7ea4SMartin Matuska default: 1823e9ed7ea4SMartin Matuska break; 1824e9ed7ea4SMartin Matuska } 1825e9ed7ea4SMartin Matuska 1826e9ed7ea4SMartin Matuska if (tag == 0) { 1827e9ed7ea4SMartin Matuska /* Invalid tag, skip entry */ 1828e9ed7ea4SMartin Matuska ret = ARCHIVE_WARN; 1829e9ed7ea4SMartin Matuska continue; 1830e9ed7ea4SMartin Matuska } else if (tag == ARCHIVE_ENTRY_ACL_USER || 1831e9ed7ea4SMartin Matuska tag == ARCHIVE_ENTRY_ACL_GROUP) { 1832e9ed7ea4SMartin Matuska n = 1; 18336c95142eSMartin Matuska name = field[1]; 18342dbf8c4aSMartin Matuska isint(name.start, name.end, &id); 18356c95142eSMartin Matuska } else 1836e9ed7ea4SMartin Matuska n = 0; 1837e9ed7ea4SMartin Matuska 1838e9ed7ea4SMartin Matuska if (!is_nfs4_perms(field[1 + n].start, 1839e9ed7ea4SMartin Matuska field[1 + n].end, &permset)) { 1840e9ed7ea4SMartin Matuska /* Invalid NFSv4 perms, skip entry */ 1841e9ed7ea4SMartin Matuska ret = ARCHIVE_WARN; 1842e9ed7ea4SMartin Matuska continue; 1843e9ed7ea4SMartin Matuska } 1844e9ed7ea4SMartin Matuska if (!is_nfs4_flags(field[2 + n].start, 1845e9ed7ea4SMartin Matuska field[2 + n].end, &permset)) { 1846e9ed7ea4SMartin Matuska /* Invalid NFSv4 flags, skip entry */ 1847e9ed7ea4SMartin Matuska ret = ARCHIVE_WARN; 1848e9ed7ea4SMartin Matuska continue; 1849e9ed7ea4SMartin Matuska } 1850e9ed7ea4SMartin Matuska s = field[3 + n].start; 1851e9ed7ea4SMartin Matuska len = field[3 + n].end - field[3 + n].start; 1852e9ed7ea4SMartin Matuska type = 0; 1853e9ed7ea4SMartin Matuska if (len == 4) { 1854e9ed7ea4SMartin Matuska if (memcmp(s, "deny", 4) == 0) 1855e9ed7ea4SMartin Matuska type = ARCHIVE_ENTRY_ACL_TYPE_DENY; 1856e9ed7ea4SMartin Matuska } else if (len == 5) { 1857e9ed7ea4SMartin Matuska if (memcmp(s, "allow", 5) == 0) 1858e9ed7ea4SMartin Matuska type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; 1859e9ed7ea4SMartin Matuska else if (memcmp(s, "audit", 5) == 0) 1860e9ed7ea4SMartin Matuska type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT; 1861e9ed7ea4SMartin Matuska else if (memcmp(s, "alarm", 5) == 0) 1862e9ed7ea4SMartin Matuska type = ARCHIVE_ENTRY_ACL_TYPE_ALARM; 1863e9ed7ea4SMartin Matuska } 1864e9ed7ea4SMartin Matuska if (type == 0) { 1865e9ed7ea4SMartin Matuska /* Invalid entry type, skip entry */ 1866e9ed7ea4SMartin Matuska ret = ARCHIVE_WARN; 1867e9ed7ea4SMartin Matuska continue; 1868e9ed7ea4SMartin Matuska } 1869e9ed7ea4SMartin Matuska isint(field[4 + n].start, field[4 + n].end, 1870e9ed7ea4SMartin Matuska &id); 1871e9ed7ea4SMartin Matuska } 18726c95142eSMartin Matuska 18736c95142eSMartin Matuska /* Add entry to the internal list. */ 18746c95142eSMartin Matuska r = archive_acl_add_entry_len_l(acl, type, permset, 18756c95142eSMartin Matuska tag, id, name.start, name.end - name.start, sc); 18766c95142eSMartin Matuska if (r < ARCHIVE_WARN) 18776c95142eSMartin Matuska return (r); 18786c95142eSMartin Matuska if (r != ARCHIVE_OK) 18796c95142eSMartin Matuska ret = ARCHIVE_WARN; 1880e9ed7ea4SMartin Matuska types |= type; 18816c95142eSMartin Matuska } 1882e9ed7ea4SMartin Matuska 1883e9ed7ea4SMartin Matuska /* Reset ACL */ 1884e9ed7ea4SMartin Matuska archive_acl_reset(acl, types); 1885e9ed7ea4SMartin Matuska 18866c95142eSMartin Matuska return (ret); 18876c95142eSMartin Matuska } 18886c95142eSMartin Matuska 18896c95142eSMartin Matuska /* 18906c95142eSMartin Matuska * Parse a string to a positive decimal integer. Returns true if 18916c95142eSMartin Matuska * the string is non-empty and consists only of decimal digits, 18926c95142eSMartin Matuska * false otherwise. 18936c95142eSMartin Matuska */ 18946c95142eSMartin Matuska static int 18956c95142eSMartin Matuska isint(const char *start, const char *end, int *result) 18966c95142eSMartin Matuska { 18976c95142eSMartin Matuska int n = 0; 18986c95142eSMartin Matuska if (start >= end) 18996c95142eSMartin Matuska return (0); 19006c95142eSMartin Matuska while (start < end) { 19016c95142eSMartin Matuska if (*start < '0' || *start > '9') 19026c95142eSMartin Matuska return (0); 19036c95142eSMartin Matuska if (n > (INT_MAX / 10) || 19046c95142eSMartin Matuska (n == INT_MAX / 10 && (*start - '0') > INT_MAX % 10)) { 19056c95142eSMartin Matuska n = INT_MAX; 19066c95142eSMartin Matuska } else { 19076c95142eSMartin Matuska n *= 10; 19086c95142eSMartin Matuska n += *start - '0'; 19096c95142eSMartin Matuska } 19106c95142eSMartin Matuska start++; 19116c95142eSMartin Matuska } 19126c95142eSMartin Matuska *result = n; 19136c95142eSMartin Matuska return (1); 19146c95142eSMartin Matuska } 19156c95142eSMartin Matuska 19166c95142eSMartin Matuska /* 19176c95142eSMartin Matuska * Parse a string as a mode field. Returns true if 19186c95142eSMartin Matuska * the string is non-empty and consists only of mode characters, 19196c95142eSMartin Matuska * false otherwise. 19206c95142eSMartin Matuska */ 19216c95142eSMartin Matuska static int 19226c95142eSMartin Matuska ismode(const char *start, const char *end, int *permset) 19236c95142eSMartin Matuska { 19246c95142eSMartin Matuska const char *p; 19256c95142eSMartin Matuska 19266c95142eSMartin Matuska if (start >= end) 19276c95142eSMartin Matuska return (0); 19286c95142eSMartin Matuska p = start; 19296c95142eSMartin Matuska *permset = 0; 19306c95142eSMartin Matuska while (p < end) { 19316c95142eSMartin Matuska switch (*p++) { 19326c95142eSMartin Matuska case 'r': case 'R': 19336c95142eSMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_READ; 19346c95142eSMartin Matuska break; 19356c95142eSMartin Matuska case 'w': case 'W': 19366c95142eSMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_WRITE; 19376c95142eSMartin Matuska break; 19386c95142eSMartin Matuska case 'x': case 'X': 19396c95142eSMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; 19406c95142eSMartin Matuska break; 19416c95142eSMartin Matuska case '-': 19426c95142eSMartin Matuska break; 19436c95142eSMartin Matuska default: 19446c95142eSMartin Matuska return (0); 19456c95142eSMartin Matuska } 19466c95142eSMartin Matuska } 19476c95142eSMartin Matuska return (1); 19486c95142eSMartin Matuska } 19496c95142eSMartin Matuska 19506c95142eSMartin Matuska /* 1951e9ed7ea4SMartin Matuska * Parse a string as a NFS4 ACL permission field. 1952e9ed7ea4SMartin Matuska * Returns true if the string is non-empty and consists only of NFS4 ACL 1953e9ed7ea4SMartin Matuska * permission characters, false otherwise 1954e9ed7ea4SMartin Matuska */ 1955e9ed7ea4SMartin Matuska static int 1956e9ed7ea4SMartin Matuska is_nfs4_perms(const char *start, const char *end, int *permset) 1957e9ed7ea4SMartin Matuska { 19585d6770bdSMartin Matuska const char *p = start; 1959e9ed7ea4SMartin Matuska 1960e9ed7ea4SMartin Matuska while (p < end) { 1961e9ed7ea4SMartin Matuska switch (*p++) { 1962e9ed7ea4SMartin Matuska case 'r': 1963e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_READ_DATA; 1964e9ed7ea4SMartin Matuska break; 1965e9ed7ea4SMartin Matuska case 'w': 1966e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_WRITE_DATA; 1967e9ed7ea4SMartin Matuska break; 1968e9ed7ea4SMartin Matuska case 'x': 1969e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; 1970e9ed7ea4SMartin Matuska break; 1971e9ed7ea4SMartin Matuska case 'p': 1972e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_APPEND_DATA; 1973e9ed7ea4SMartin Matuska break; 1974e9ed7ea4SMartin Matuska case 'D': 1975e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_DELETE_CHILD; 1976e9ed7ea4SMartin Matuska break; 1977e9ed7ea4SMartin Matuska case 'd': 1978e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_DELETE; 1979e9ed7ea4SMartin Matuska break; 1980e9ed7ea4SMartin Matuska case 'a': 1981e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES; 1982e9ed7ea4SMartin Matuska break; 1983e9ed7ea4SMartin Matuska case 'A': 1984e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES; 1985e9ed7ea4SMartin Matuska break; 1986e9ed7ea4SMartin Matuska case 'R': 1987e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS; 1988e9ed7ea4SMartin Matuska break; 1989e9ed7ea4SMartin Matuska case 'W': 1990e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS; 1991e9ed7ea4SMartin Matuska break; 1992e9ed7ea4SMartin Matuska case 'c': 1993e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_READ_ACL; 1994e9ed7ea4SMartin Matuska break; 1995e9ed7ea4SMartin Matuska case 'C': 1996e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_WRITE_ACL; 1997e9ed7ea4SMartin Matuska break; 1998e9ed7ea4SMartin Matuska case 'o': 1999e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_WRITE_OWNER; 2000e9ed7ea4SMartin Matuska break; 2001e9ed7ea4SMartin Matuska case 's': 2002e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE; 2003e9ed7ea4SMartin Matuska break; 2004e9ed7ea4SMartin Matuska case '-': 2005e9ed7ea4SMartin Matuska break; 2006e9ed7ea4SMartin Matuska default: 2007e9ed7ea4SMartin Matuska return(0); 2008e9ed7ea4SMartin Matuska } 2009e9ed7ea4SMartin Matuska } 2010e9ed7ea4SMartin Matuska return (1); 2011e9ed7ea4SMartin Matuska } 2012e9ed7ea4SMartin Matuska 2013e9ed7ea4SMartin Matuska /* 2014e9ed7ea4SMartin Matuska * Parse a string as a NFS4 ACL flags field. 2015e9ed7ea4SMartin Matuska * Returns true if the string is non-empty and consists only of NFS4 ACL 2016e9ed7ea4SMartin Matuska * flag characters, false otherwise 2017e9ed7ea4SMartin Matuska */ 2018e9ed7ea4SMartin Matuska static int 2019e9ed7ea4SMartin Matuska is_nfs4_flags(const char *start, const char *end, int *permset) 2020e9ed7ea4SMartin Matuska { 20215d6770bdSMartin Matuska const char *p = start; 2022e9ed7ea4SMartin Matuska 2023e9ed7ea4SMartin Matuska while (p < end) { 2024e9ed7ea4SMartin Matuska switch(*p++) { 2025e9ed7ea4SMartin Matuska case 'f': 2026e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT; 2027e9ed7ea4SMartin Matuska break; 2028e9ed7ea4SMartin Matuska case 'd': 2029e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT; 2030e9ed7ea4SMartin Matuska break; 2031e9ed7ea4SMartin Matuska case 'i': 2032e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY; 2033e9ed7ea4SMartin Matuska break; 2034e9ed7ea4SMartin Matuska case 'n': 2035e9ed7ea4SMartin Matuska *permset |= 2036e9ed7ea4SMartin Matuska ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT; 2037e9ed7ea4SMartin Matuska break; 2038e9ed7ea4SMartin Matuska case 'S': 2039e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS; 2040e9ed7ea4SMartin Matuska break; 2041e9ed7ea4SMartin Matuska case 'F': 2042e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS; 2043e9ed7ea4SMartin Matuska break; 2044e9ed7ea4SMartin Matuska case 'I': 2045e9ed7ea4SMartin Matuska *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERITED; 2046e9ed7ea4SMartin Matuska break; 2047e9ed7ea4SMartin Matuska case '-': 2048e9ed7ea4SMartin Matuska break; 2049e9ed7ea4SMartin Matuska default: 2050e9ed7ea4SMartin Matuska return (0); 2051e9ed7ea4SMartin Matuska } 2052e9ed7ea4SMartin Matuska } 2053e9ed7ea4SMartin Matuska return (1); 2054e9ed7ea4SMartin Matuska } 2055e9ed7ea4SMartin Matuska 2056e9ed7ea4SMartin Matuska /* 2057*bd66c1b4SMartin Matuska * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]". *p is updated 20586c95142eSMartin Matuska * to point to just after the separator. *start points to the first 20596c95142eSMartin Matuska * character of the matched text and *end just after the last 20606c95142eSMartin Matuska * character of the matched identifier. In particular *end - *start 20616c95142eSMartin Matuska * is the length of the field body, not including leading or trailing 20626c95142eSMartin Matuska * whitespace. 20636c95142eSMartin Matuska */ 20646c95142eSMartin Matuska static void 2065*bd66c1b4SMartin Matuska next_field(const char **p, size_t *l, const char **start, 20666c95142eSMartin Matuska const char **end, char *sep) 20676c95142eSMartin Matuska { 20686c95142eSMartin Matuska /* Skip leading whitespace to find start of field. */ 2069*bd66c1b4SMartin Matuska while (*l > 0 && (**p == ' ' || **p == '\t' || **p == '\n')) { 20706c95142eSMartin Matuska (*p)++; 2071*bd66c1b4SMartin Matuska (*l)--; 20726c95142eSMartin Matuska } 20736c95142eSMartin Matuska *start = *p; 20746c95142eSMartin Matuska 2075*bd66c1b4SMartin Matuska /* Locate end of field, trim trailing whitespace if necessary */ 2076*bd66c1b4SMartin Matuska while (*l > 0 && **p != ' ' && **p != '\t' && **p != '\n' && **p != ',' && **p != ':' && **p != '#') { 20776c95142eSMartin Matuska (*p)++; 2078*bd66c1b4SMartin Matuska (*l)--; 2079*bd66c1b4SMartin Matuska } 2080*bd66c1b4SMartin Matuska *end = *p; 2081*bd66c1b4SMartin Matuska 2082*bd66c1b4SMartin Matuska /* Scan for the separator. */ 2083*bd66c1b4SMartin Matuska while (*l > 0 && **p != ',' && **p != ':' && **p != '\n' && **p != '#') { 2084*bd66c1b4SMartin Matuska (*p)++; 2085*bd66c1b4SMartin Matuska (*l)--; 20866c95142eSMartin Matuska } 20876c95142eSMartin Matuska *sep = **p; 20886c95142eSMartin Matuska 20897d69e4cdSMartin Matuska /* Handle in-field comments */ 20907d69e4cdSMartin Matuska if (*sep == '#') { 2091*bd66c1b4SMartin Matuska while (*l > 0 && **p != ',' && **p != '\n') { 20927d69e4cdSMartin Matuska (*p)++; 2093*bd66c1b4SMartin Matuska (*l)--; 20947d69e4cdSMartin Matuska } 20957d69e4cdSMartin Matuska *sep = **p; 20967d69e4cdSMartin Matuska } 20976c95142eSMartin Matuska 2098*bd66c1b4SMartin Matuska /* Skip separator. */ 2099*bd66c1b4SMartin Matuska if (*l > 0) { 21006c95142eSMartin Matuska (*p)++; 2101*bd66c1b4SMartin Matuska (*l)--; 2102*bd66c1b4SMartin Matuska } 21036c95142eSMartin Matuska } 2104