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