archive_acl.c 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069
  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. case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
  1068. case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
  1069. numfields = 5;
  1070. break;
  1071. case ARCHIVE_ENTRY_ACL_TYPE_NFS4:
  1072. numfields = 6;
  1073. break;
  1074. default:
  1075. return (ARCHIVE_FATAL);
  1076. }
  1077. while (text != NULL && *text != L'\0') {
  1078. /*
  1079. * Parse the fields out of the next entry,
  1080. * advance 'text' to start of next entry.
  1081. */
  1082. fields = 0;
  1083. do {
  1084. const wchar_t *start, *end;
  1085. next_field_w(&text, &start, &end, &sep);
  1086. if (fields < numfields) {
  1087. field[fields].start = start;
  1088. field[fields].end = end;
  1089. }
  1090. ++fields;
  1091. } while (sep == L':');
  1092. /* Set remaining fields to blank. */
  1093. for (n = fields; n < numfields; ++n)
  1094. field[n].start = field[n].end = NULL;
  1095. if (field[0].start != NULL && *(field[0].start) == L'#') {
  1096. /* Comment, skip entry */
  1097. continue;
  1098. }
  1099. n = 0;
  1100. sol = 0;
  1101. id = -1;
  1102. permset = 0;
  1103. name.start = name.end = NULL;
  1104. if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
  1105. /* POSIX.1e ACLs */
  1106. /*
  1107. * Default keyword "default:user::rwx"
  1108. * if found, we have one more field
  1109. *
  1110. * We also support old Solaris extension:
  1111. * "defaultuser::rwx" is the default ACL corresponding
  1112. * to "user::rwx", etc. valid only for first field
  1113. */
  1114. s = field[0].start;
  1115. len = field[0].end - field[0].start;
  1116. if (*s == L'd' && (len == 1 || (len >= 7
  1117. && wmemcmp((s + 1), L"efault", 6) == 0))) {
  1118. type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
  1119. if (len > 7)
  1120. field[0].start += 7;
  1121. else
  1122. n = 1;
  1123. } else
  1124. type = want_type;
  1125. /* Check for a numeric ID in field n+1 or n+3. */
  1126. isint_w(field[n + 1].start, field[n + 1].end, &id);
  1127. /* Field n+3 is optional. */
  1128. if (id == -1 && fields > n+3)
  1129. isint_w(field[n + 3].start, field[n + 3].end,
  1130. &id);
  1131. tag = 0;
  1132. s = field[n].start;
  1133. st = field[n].start + 1;
  1134. len = field[n].end - field[n].start;
  1135. switch (*s) {
  1136. case L'u':
  1137. if (len == 1 || (len == 4
  1138. && wmemcmp(st, L"ser", 3) == 0))
  1139. tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
  1140. break;
  1141. case L'g':
  1142. if (len == 1 || (len == 5
  1143. && wmemcmp(st, L"roup", 4) == 0))
  1144. tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
  1145. break;
  1146. case L'o':
  1147. if (len == 1 || (len == 5
  1148. && wmemcmp(st, L"ther", 4) == 0))
  1149. tag = ARCHIVE_ENTRY_ACL_OTHER;
  1150. break;
  1151. case L'm':
  1152. if (len == 1 || (len == 4
  1153. && wmemcmp(st, L"ask", 3) == 0))
  1154. tag = ARCHIVE_ENTRY_ACL_MASK;
  1155. break;
  1156. default:
  1157. break;
  1158. }
  1159. switch (tag) {
  1160. case ARCHIVE_ENTRY_ACL_OTHER:
  1161. case ARCHIVE_ENTRY_ACL_MASK:
  1162. if (fields == (n + 2)
  1163. && field[n + 1].start < field[n + 1].end
  1164. && ismode_w(field[n + 1].start,
  1165. field[n + 1].end, &permset)) {
  1166. /* This is Solaris-style "other:rwx" */
  1167. sol = 1;
  1168. } else if (fields == (n + 3) &&
  1169. field[n + 1].start < field[n + 1].end) {
  1170. /* Invalid mask or other field */
  1171. ret = ARCHIVE_WARN;
  1172. continue;
  1173. }
  1174. break;
  1175. case ARCHIVE_ENTRY_ACL_USER_OBJ:
  1176. case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
  1177. if (id != -1 ||
  1178. field[n + 1].start < field[n + 1].end) {
  1179. name = field[n + 1];
  1180. if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ)
  1181. tag = ARCHIVE_ENTRY_ACL_USER;
  1182. else
  1183. tag = ARCHIVE_ENTRY_ACL_GROUP;
  1184. }
  1185. break;
  1186. default:
  1187. /* Invalid tag, skip entry */
  1188. ret = ARCHIVE_WARN;
  1189. continue;
  1190. }
  1191. /*
  1192. * Without "default:" we expect mode in field 2
  1193. * Exception: Solaris other and mask fields
  1194. */
  1195. if (permset == 0 && !ismode_w(field[n + 2 - sol].start,
  1196. field[n + 2 - sol].end, &permset)) {
  1197. /* Invalid mode, skip entry */
  1198. ret = ARCHIVE_WARN;
  1199. continue;
  1200. }
  1201. } else {
  1202. /* NFS4 ACLs */
  1203. s = field[0].start;
  1204. len = field[0].end - field[0].start;
  1205. tag = 0;
  1206. switch (len) {
  1207. case 4:
  1208. if (wmemcmp(s, L"user", 4) == 0)
  1209. tag = ARCHIVE_ENTRY_ACL_USER;
  1210. break;
  1211. case 5:
  1212. if (wmemcmp(s, L"group", 5) == 0)
  1213. tag = ARCHIVE_ENTRY_ACL_GROUP;
  1214. break;
  1215. case 6:
  1216. if (wmemcmp(s, L"owner@", 6) == 0)
  1217. tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
  1218. else if (wmemcmp(s, L"group@", len) == 0)
  1219. tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
  1220. break;
  1221. case 9:
  1222. if (wmemcmp(s, L"everyone@", 9) == 0)
  1223. tag = ARCHIVE_ENTRY_ACL_EVERYONE;
  1224. default:
  1225. break;
  1226. }
  1227. if (tag == 0) {
  1228. /* Invalid tag, skip entry */
  1229. ret = ARCHIVE_WARN;
  1230. continue;
  1231. } else if (tag == ARCHIVE_ENTRY_ACL_USER ||
  1232. tag == ARCHIVE_ENTRY_ACL_GROUP) {
  1233. n = 1;
  1234. name = field[1];
  1235. isint_w(name.start, name.end, &id);
  1236. } else
  1237. n = 0;
  1238. if (!is_nfs4_perms_w(field[1 + n].start,
  1239. field[1 + n].end, &permset)) {
  1240. /* Invalid NFSv4 perms, skip entry */
  1241. ret = ARCHIVE_WARN;
  1242. continue;
  1243. }
  1244. if (!is_nfs4_flags_w(field[2 + n].start,
  1245. field[2 + n].end, &permset)) {
  1246. /* Invalid NFSv4 flags, skip entry */
  1247. ret = ARCHIVE_WARN;
  1248. continue;
  1249. }
  1250. s = field[3 + n].start;
  1251. len = field[3 + n].end - field[3 + n].start;
  1252. type = 0;
  1253. if (len == 4) {
  1254. if (wmemcmp(s, L"deny", 4) == 0)
  1255. type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
  1256. } else if (len == 5) {
  1257. if (wmemcmp(s, L"allow", 5) == 0)
  1258. type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
  1259. else if (wmemcmp(s, L"audit", 5) == 0)
  1260. type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT;
  1261. else if (wmemcmp(s, L"alarm", 5) == 0)
  1262. type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
  1263. }
  1264. if (type == 0) {
  1265. /* Invalid entry type, skip entry */
  1266. ret = ARCHIVE_WARN;
  1267. continue;
  1268. }
  1269. isint_w(field[4 + n].start, field[4 + n].end, &id);
  1270. }
  1271. /* Add entry to the internal list. */
  1272. r = archive_acl_add_entry_w_len(acl, type, permset,
  1273. tag, id, name.start, name.end - name.start);
  1274. if (r < ARCHIVE_WARN)
  1275. return (r);
  1276. if (r != ARCHIVE_OK)
  1277. ret = ARCHIVE_WARN;
  1278. types |= type;
  1279. }
  1280. /* Reset ACL */
  1281. archive_acl_reset(acl, types);
  1282. return (ret);
  1283. }
  1284. /*
  1285. * Parse a string to a positive decimal integer. Returns true if
  1286. * the string is non-empty and consists only of decimal digits,
  1287. * false otherwise.
  1288. */
  1289. static int
  1290. isint_w(const wchar_t *start, const wchar_t *end, int *result)
  1291. {
  1292. int n = 0;
  1293. if (start >= end)
  1294. return (0);
  1295. while (start < end) {
  1296. if (*start < '0' || *start > '9')
  1297. return (0);
  1298. if (n > (INT_MAX / 10) ||
  1299. (n == INT_MAX / 10 && (*start - '0') > INT_MAX % 10)) {
  1300. n = INT_MAX;
  1301. } else {
  1302. n *= 10;
  1303. n += *start - '0';
  1304. }
  1305. start++;
  1306. }
  1307. *result = n;
  1308. return (1);
  1309. }
  1310. /*
  1311. * Parse a string as a mode field. Returns true if
  1312. * the string is non-empty and consists only of mode characters,
  1313. * false otherwise.
  1314. */
  1315. static int
  1316. ismode_w(const wchar_t *start, const wchar_t *end, int *permset)
  1317. {
  1318. const wchar_t *p;
  1319. if (start >= end)
  1320. return (0);
  1321. p = start;
  1322. *permset = 0;
  1323. while (p < end) {
  1324. switch (*p++) {
  1325. case L'r': case L'R':
  1326. *permset |= ARCHIVE_ENTRY_ACL_READ;
  1327. break;
  1328. case L'w': case L'W':
  1329. *permset |= ARCHIVE_ENTRY_ACL_WRITE;
  1330. break;
  1331. case L'x': case L'X':
  1332. *permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
  1333. break;
  1334. case L'-':
  1335. break;
  1336. default:
  1337. return (0);
  1338. }
  1339. }
  1340. return (1);
  1341. }
  1342. /*
  1343. * Parse a string as a NFS4 ACL permission field.
  1344. * Returns true if the string is non-empty and consists only of NFS4 ACL
  1345. * permission characters, false otherwise
  1346. */
  1347. static int
  1348. is_nfs4_perms_w(const wchar_t *start, const wchar_t *end, int *permset)
  1349. {
  1350. const wchar_t *p = start;
  1351. while (p < end) {
  1352. switch (*p++) {
  1353. case L'r':
  1354. *permset |= ARCHIVE_ENTRY_ACL_READ_DATA;
  1355. break;
  1356. case L'w':
  1357. *permset |= ARCHIVE_ENTRY_ACL_WRITE_DATA;
  1358. break;
  1359. case L'x':
  1360. *permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
  1361. break;
  1362. case L'p':
  1363. *permset |= ARCHIVE_ENTRY_ACL_APPEND_DATA;
  1364. break;
  1365. case L'D':
  1366. *permset |= ARCHIVE_ENTRY_ACL_DELETE_CHILD;
  1367. break;
  1368. case L'd':
  1369. *permset |= ARCHIVE_ENTRY_ACL_DELETE;
  1370. break;
  1371. case L'a':
  1372. *permset |= ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES;
  1373. break;
  1374. case L'A':
  1375. *permset |= ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES;
  1376. break;
  1377. case L'R':
  1378. *permset |= ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS;
  1379. break;
  1380. case L'W':
  1381. *permset |= ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS;
  1382. break;
  1383. case L'c':
  1384. *permset |= ARCHIVE_ENTRY_ACL_READ_ACL;
  1385. break;
  1386. case L'C':
  1387. *permset |= ARCHIVE_ENTRY_ACL_WRITE_ACL;
  1388. break;
  1389. case L'o':
  1390. *permset |= ARCHIVE_ENTRY_ACL_WRITE_OWNER;
  1391. break;
  1392. case L's':
  1393. *permset |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE;
  1394. break;
  1395. case L'-':
  1396. break;
  1397. default:
  1398. return(0);
  1399. }
  1400. }
  1401. return (1);
  1402. }
  1403. /*
  1404. * Parse a string as a NFS4 ACL flags field.
  1405. * Returns true if the string is non-empty and consists only of NFS4 ACL
  1406. * flag characters, false otherwise
  1407. */
  1408. static int
  1409. is_nfs4_flags_w(const wchar_t *start, const wchar_t *end, int *permset)
  1410. {
  1411. const wchar_t *p = start;
  1412. while (p < end) {
  1413. switch(*p++) {
  1414. case L'f':
  1415. *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT;
  1416. break;
  1417. case L'd':
  1418. *permset |= ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT;
  1419. break;
  1420. case L'i':
  1421. *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY;
  1422. break;
  1423. case L'n':
  1424. *permset |=
  1425. ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT;
  1426. break;
  1427. case L'S':
  1428. *permset |= ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS;
  1429. break;
  1430. case L'F':
  1431. *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS;
  1432. break;
  1433. case L'I':
  1434. *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERITED;
  1435. break;
  1436. case L'-':
  1437. break;
  1438. default:
  1439. return (0);
  1440. }
  1441. }
  1442. return (1);
  1443. }
  1444. /*
  1445. * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]". *wp is updated
  1446. * to point to just after the separator. *start points to the first
  1447. * character of the matched text and *end just after the last
  1448. * character of the matched identifier. In particular *end - *start
  1449. * is the length of the field body, not including leading or trailing
  1450. * whitespace.
  1451. */
  1452. static void
  1453. next_field_w(const wchar_t **wp, const wchar_t **start,
  1454. const wchar_t **end, wchar_t *sep)
  1455. {
  1456. /* Skip leading whitespace to find start of field. */
  1457. while (**wp == L' ' || **wp == L'\t' || **wp == L'\n') {
  1458. (*wp)++;
  1459. }
  1460. *start = *wp;
  1461. /* Scan for the separator. */
  1462. while (**wp != L'\0' && **wp != L',' && **wp != L':' &&
  1463. **wp != L'\n') {
  1464. (*wp)++;
  1465. }
  1466. *sep = **wp;
  1467. /* Trim trailing whitespace to locate end of field. */
  1468. *end = *wp - 1;
  1469. while (**end == L' ' || **end == L'\t' || **end == L'\n') {
  1470. (*end)--;
  1471. }
  1472. (*end)++;
  1473. /* Adjust scanner location. */
  1474. if (**wp != L'\0')
  1475. (*wp)++;
  1476. }
  1477. /*
  1478. * Parse an ACL text string.
  1479. *
  1480. * The want_type argument may be one of the following:
  1481. * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - text is a POSIX.1e ACL of type ACCESS
  1482. * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - text is a POSIX.1e ACL of type DEFAULT
  1483. * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - text is as a NFSv4 ACL
  1484. *
  1485. * POSIX.1e ACL entries prefixed with "default:" are treated as
  1486. * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT unless type is ARCHIVE_ENTRY_ACL_TYPE_NFS4
  1487. */
  1488. int
  1489. archive_acl_from_text_l(struct archive_acl *acl, const char *text,
  1490. int want_type, struct archive_string_conv *sc)
  1491. {
  1492. struct {
  1493. const char *start;
  1494. const char *end;
  1495. } field[6], name;
  1496. const char *s, *st;
  1497. int numfields, fields, n, r, sol, ret;
  1498. int type, types, tag, permset, id;
  1499. size_t len;
  1500. char sep;
  1501. switch (want_type) {
  1502. case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E:
  1503. want_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
  1504. case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
  1505. case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
  1506. numfields = 5;
  1507. break;
  1508. case ARCHIVE_ENTRY_ACL_TYPE_NFS4:
  1509. numfields = 6;
  1510. break;
  1511. default:
  1512. return (ARCHIVE_FATAL);
  1513. }
  1514. ret = ARCHIVE_OK;
  1515. types = 0;
  1516. while (text != NULL && *text != '\0') {
  1517. /*
  1518. * Parse the fields out of the next entry,
  1519. * advance 'text' to start of next entry.
  1520. */
  1521. fields = 0;
  1522. do {
  1523. const char *start, *end;
  1524. next_field(&text, &start, &end, &sep);
  1525. if (fields < numfields) {
  1526. field[fields].start = start;
  1527. field[fields].end = end;
  1528. }
  1529. ++fields;
  1530. } while (sep == ':');
  1531. /* Set remaining fields to blank. */
  1532. for (n = fields; n < numfields; ++n)
  1533. field[n].start = field[n].end = NULL;
  1534. if (field[0].start != NULL && *(field[0].start) == '#') {
  1535. /* Comment, skip entry */
  1536. continue;
  1537. }
  1538. n = 0;
  1539. sol = 0;
  1540. id = -1;
  1541. permset = 0;
  1542. name.start = name.end = NULL;
  1543. if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
  1544. /* POSIX.1e ACLs */
  1545. /*
  1546. * Default keyword "default:user::rwx"
  1547. * if found, we have one more field
  1548. *
  1549. * We also support old Solaris extension:
  1550. * "defaultuser::rwx" is the default ACL corresponding
  1551. * to "user::rwx", etc. valid only for first field
  1552. */
  1553. s = field[0].start;
  1554. len = field[0].end - field[0].start;
  1555. if (*s == 'd' && (len == 1 || (len >= 7
  1556. && memcmp((s + 1), "efault", 6) == 0))) {
  1557. type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
  1558. if (len > 7)
  1559. field[0].start += 7;
  1560. else
  1561. n = 1;
  1562. } else
  1563. type = want_type;
  1564. /* Check for a numeric ID in field n+1 or n+3. */
  1565. isint(field[n + 1].start, field[n + 1].end, &id);
  1566. /* Field n+3 is optional. */
  1567. if (id == -1 && fields > (n + 3))
  1568. isint(field[n + 3].start, field[n + 3].end,
  1569. &id);
  1570. tag = 0;
  1571. s = field[n].start;
  1572. st = field[n].start + 1;
  1573. len = field[n].end - field[n].start;
  1574. switch (*s) {
  1575. case 'u':
  1576. if (len == 1 || (len == 4
  1577. && memcmp(st, "ser", 3) == 0))
  1578. tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
  1579. break;
  1580. case 'g':
  1581. if (len == 1 || (len == 5
  1582. && memcmp(st, "roup", 4) == 0))
  1583. tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
  1584. break;
  1585. case 'o':
  1586. if (len == 1 || (len == 5
  1587. && memcmp(st, "ther", 4) == 0))
  1588. tag = ARCHIVE_ENTRY_ACL_OTHER;
  1589. break;
  1590. case 'm':
  1591. if (len == 1 || (len == 4
  1592. && memcmp(st, "ask", 3) == 0))
  1593. tag = ARCHIVE_ENTRY_ACL_MASK;
  1594. break;
  1595. default:
  1596. break;
  1597. }
  1598. switch (tag) {
  1599. case ARCHIVE_ENTRY_ACL_OTHER:
  1600. case ARCHIVE_ENTRY_ACL_MASK:
  1601. if (fields == (n + 2)
  1602. && field[n + 1].start < field[n + 1].end
  1603. && ismode(field[n + 1].start,
  1604. field[n + 1].end, &permset)) {
  1605. /* This is Solaris-style "other:rwx" */
  1606. sol = 1;
  1607. } else if (fields == (n + 3) &&
  1608. field[n + 1].start < field[n + 1].end) {
  1609. /* Invalid mask or other field */
  1610. ret = ARCHIVE_WARN;
  1611. continue;
  1612. }
  1613. break;
  1614. case ARCHIVE_ENTRY_ACL_USER_OBJ:
  1615. case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
  1616. if (id != -1 ||
  1617. field[n + 1].start < field[n + 1].end) {
  1618. name = field[n + 1];
  1619. if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ)
  1620. tag = ARCHIVE_ENTRY_ACL_USER;
  1621. else
  1622. tag = ARCHIVE_ENTRY_ACL_GROUP;
  1623. }
  1624. break;
  1625. default:
  1626. /* Invalid tag, skip entry */
  1627. ret = ARCHIVE_WARN;
  1628. continue;
  1629. }
  1630. /*
  1631. * Without "default:" we expect mode in field 3
  1632. * Exception: Solaris other and mask fields
  1633. */
  1634. if (permset == 0 && !ismode(field[n + 2 - sol].start,
  1635. field[n + 2 - sol].end, &permset)) {
  1636. /* Invalid mode, skip entry */
  1637. ret = ARCHIVE_WARN;
  1638. continue;
  1639. }
  1640. } else {
  1641. /* NFS4 ACLs */
  1642. s = field[0].start;
  1643. len = field[0].end - field[0].start;
  1644. tag = 0;
  1645. switch (len) {
  1646. case 4:
  1647. if (memcmp(s, "user", 4) == 0)
  1648. tag = ARCHIVE_ENTRY_ACL_USER;
  1649. break;
  1650. case 5:
  1651. if (memcmp(s, "group", 5) == 0)
  1652. tag = ARCHIVE_ENTRY_ACL_GROUP;
  1653. break;
  1654. case 6:
  1655. if (memcmp(s, "owner@", 6) == 0)
  1656. tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
  1657. else if (memcmp(s, "group@", 6) == 0)
  1658. tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
  1659. break;
  1660. case 9:
  1661. if (memcmp(s, "everyone@", 9) == 0)
  1662. tag = ARCHIVE_ENTRY_ACL_EVERYONE;
  1663. break;
  1664. default:
  1665. break;
  1666. }
  1667. if (tag == 0) {
  1668. /* Invalid tag, skip entry */
  1669. ret = ARCHIVE_WARN;
  1670. continue;
  1671. } else if (tag == ARCHIVE_ENTRY_ACL_USER ||
  1672. tag == ARCHIVE_ENTRY_ACL_GROUP) {
  1673. n = 1;
  1674. name = field[1];
  1675. isint(name.start, name.end, &id);
  1676. } else
  1677. n = 0;
  1678. if (!is_nfs4_perms(field[1 + n].start,
  1679. field[1 + n].end, &permset)) {
  1680. /* Invalid NFSv4 perms, skip entry */
  1681. ret = ARCHIVE_WARN;
  1682. continue;
  1683. }
  1684. if (!is_nfs4_flags(field[2 + n].start,
  1685. field[2 + n].end, &permset)) {
  1686. /* Invalid NFSv4 flags, skip entry */
  1687. ret = ARCHIVE_WARN;
  1688. continue;
  1689. }
  1690. s = field[3 + n].start;
  1691. len = field[3 + n].end - field[3 + n].start;
  1692. type = 0;
  1693. if (len == 4) {
  1694. if (memcmp(s, "deny", 4) == 0)
  1695. type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
  1696. } else if (len == 5) {
  1697. if (memcmp(s, "allow", 5) == 0)
  1698. type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
  1699. else if (memcmp(s, "audit", 5) == 0)
  1700. type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT;
  1701. else if (memcmp(s, "alarm", 5) == 0)
  1702. type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
  1703. }
  1704. if (type == 0) {
  1705. /* Invalid entry type, skip entry */
  1706. ret = ARCHIVE_WARN;
  1707. continue;
  1708. }
  1709. isint(field[4 + n].start, field[4 + n].end,
  1710. &id);
  1711. }
  1712. /* Add entry to the internal list. */
  1713. r = archive_acl_add_entry_len_l(acl, type, permset,
  1714. tag, id, name.start, name.end - name.start, sc);
  1715. if (r < ARCHIVE_WARN)
  1716. return (r);
  1717. if (r != ARCHIVE_OK)
  1718. ret = ARCHIVE_WARN;
  1719. types |= type;
  1720. }
  1721. /* Reset ACL */
  1722. archive_acl_reset(acl, types);
  1723. return (ret);
  1724. }
  1725. /*
  1726. * Parse a string to a positive decimal integer. Returns true if
  1727. * the string is non-empty and consists only of decimal digits,
  1728. * false otherwise.
  1729. */
  1730. static int
  1731. isint(const char *start, const char *end, int *result)
  1732. {
  1733. int n = 0;
  1734. if (start >= end)
  1735. return (0);
  1736. while (start < end) {
  1737. if (*start < '0' || *start > '9')
  1738. return (0);
  1739. if (n > (INT_MAX / 10) ||
  1740. (n == INT_MAX / 10 && (*start - '0') > INT_MAX % 10)) {
  1741. n = INT_MAX;
  1742. } else {
  1743. n *= 10;
  1744. n += *start - '0';
  1745. }
  1746. start++;
  1747. }
  1748. *result = n;
  1749. return (1);
  1750. }
  1751. /*
  1752. * Parse a string as a mode field. Returns true if
  1753. * the string is non-empty and consists only of mode characters,
  1754. * false otherwise.
  1755. */
  1756. static int
  1757. ismode(const char *start, const char *end, int *permset)
  1758. {
  1759. const char *p;
  1760. if (start >= end)
  1761. return (0);
  1762. p = start;
  1763. *permset = 0;
  1764. while (p < end) {
  1765. switch (*p++) {
  1766. case 'r': case 'R':
  1767. *permset |= ARCHIVE_ENTRY_ACL_READ;
  1768. break;
  1769. case 'w': case 'W':
  1770. *permset |= ARCHIVE_ENTRY_ACL_WRITE;
  1771. break;
  1772. case 'x': case 'X':
  1773. *permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
  1774. break;
  1775. case '-':
  1776. break;
  1777. default:
  1778. return (0);
  1779. }
  1780. }
  1781. return (1);
  1782. }
  1783. /*
  1784. * Parse a string as a NFS4 ACL permission field.
  1785. * Returns true if the string is non-empty and consists only of NFS4 ACL
  1786. * permission characters, false otherwise
  1787. */
  1788. static int
  1789. is_nfs4_perms(const char *start, const char *end, int *permset)
  1790. {
  1791. const char *p = start;
  1792. while (p < end) {
  1793. switch (*p++) {
  1794. case 'r':
  1795. *permset |= ARCHIVE_ENTRY_ACL_READ_DATA;
  1796. break;
  1797. case 'w':
  1798. *permset |= ARCHIVE_ENTRY_ACL_WRITE_DATA;
  1799. break;
  1800. case 'x':
  1801. *permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
  1802. break;
  1803. case 'p':
  1804. *permset |= ARCHIVE_ENTRY_ACL_APPEND_DATA;
  1805. break;
  1806. case 'D':
  1807. *permset |= ARCHIVE_ENTRY_ACL_DELETE_CHILD;
  1808. break;
  1809. case 'd':
  1810. *permset |= ARCHIVE_ENTRY_ACL_DELETE;
  1811. break;
  1812. case 'a':
  1813. *permset |= ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES;
  1814. break;
  1815. case 'A':
  1816. *permset |= ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES;
  1817. break;
  1818. case 'R':
  1819. *permset |= ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS;
  1820. break;
  1821. case 'W':
  1822. *permset |= ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS;
  1823. break;
  1824. case 'c':
  1825. *permset |= ARCHIVE_ENTRY_ACL_READ_ACL;
  1826. break;
  1827. case 'C':
  1828. *permset |= ARCHIVE_ENTRY_ACL_WRITE_ACL;
  1829. break;
  1830. case 'o':
  1831. *permset |= ARCHIVE_ENTRY_ACL_WRITE_OWNER;
  1832. break;
  1833. case 's':
  1834. *permset |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE;
  1835. break;
  1836. case '-':
  1837. break;
  1838. default:
  1839. return(0);
  1840. }
  1841. }
  1842. return (1);
  1843. }
  1844. /*
  1845. * Parse a string as a NFS4 ACL flags field.
  1846. * Returns true if the string is non-empty and consists only of NFS4 ACL
  1847. * flag characters, false otherwise
  1848. */
  1849. static int
  1850. is_nfs4_flags(const char *start, const char *end, int *permset)
  1851. {
  1852. const char *p = start;
  1853. while (p < end) {
  1854. switch(*p++) {
  1855. case 'f':
  1856. *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT;
  1857. break;
  1858. case 'd':
  1859. *permset |= ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT;
  1860. break;
  1861. case 'i':
  1862. *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY;
  1863. break;
  1864. case 'n':
  1865. *permset |=
  1866. ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT;
  1867. break;
  1868. case 'S':
  1869. *permset |= ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS;
  1870. break;
  1871. case 'F':
  1872. *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS;
  1873. break;
  1874. case 'I':
  1875. *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERITED;
  1876. break;
  1877. case '-':
  1878. break;
  1879. default:
  1880. return (0);
  1881. }
  1882. }
  1883. return (1);
  1884. }
  1885. /*
  1886. * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]". *wp is updated
  1887. * to point to just after the separator. *start points to the first
  1888. * character of the matched text and *end just after the last
  1889. * character of the matched identifier. In particular *end - *start
  1890. * is the length of the field body, not including leading or trailing
  1891. * whitespace.
  1892. */
  1893. static void
  1894. next_field(const char **p, const char **start,
  1895. const char **end, char *sep)
  1896. {
  1897. /* Skip leading whitespace to find start of field. */
  1898. while (**p == ' ' || **p == '\t' || **p == '\n') {
  1899. (*p)++;
  1900. }
  1901. *start = *p;
  1902. /* Scan for the separator. */
  1903. while (**p != '\0' && **p != ',' && **p != ':' && **p != '\n') {
  1904. (*p)++;
  1905. }
  1906. *sep = **p;
  1907. /* Trim trailing whitespace to locate end of field. */
  1908. *end = *p - 1;
  1909. while (**end == ' ' || **end == '\t' || **end == '\n') {
  1910. (*end)--;
  1911. }
  1912. (*end)++;
  1913. /* Adjust scanner location. */
  1914. if (**p != '\0')
  1915. (*p)++;
  1916. }