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