archive_acl.c 51 KB

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