archive_acl.c 51 KB

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