set-permissions.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847
  1. /* Set permissions of a file. -*- coding: utf-8 -*-
  2. Copyright (C) 2002-2003, 2005-2015 Free Software Foundation, Inc.
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 3 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */
  14. #include <config.h>
  15. #include "acl.h"
  16. #include "acl-internal.h"
  17. #if USE_ACL
  18. # if ! defined HAVE_ACL_FROM_MODE && defined HAVE_ACL_FROM_TEXT /* FreeBSD, IRIX, Tru64 */
  19. # if HAVE_ACL_GET_FILE && !HAVE_ACL_TYPE_EXTENDED
  20. static acl_t
  21. acl_from_mode (mode_t mode)
  22. {
  23. # if HAVE_ACL_FREE_TEXT /* Tru64 */
  24. char acl_text[] = "u::---,g::---,o::---,";
  25. # else /* FreeBSD, IRIX */
  26. char acl_text[] = "u::---,g::---,o::---";
  27. # endif
  28. if (mode & S_IRUSR) acl_text[ 3] = 'r';
  29. if (mode & S_IWUSR) acl_text[ 4] = 'w';
  30. if (mode & S_IXUSR) acl_text[ 5] = 'x';
  31. if (mode & S_IRGRP) acl_text[10] = 'r';
  32. if (mode & S_IWGRP) acl_text[11] = 'w';
  33. if (mode & S_IXGRP) acl_text[12] = 'x';
  34. if (mode & S_IROTH) acl_text[17] = 'r';
  35. if (mode & S_IWOTH) acl_text[18] = 'w';
  36. if (mode & S_IXOTH) acl_text[19] = 'x';
  37. return acl_from_text (acl_text);
  38. }
  39. # endif
  40. # endif
  41. # if HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
  42. static int
  43. set_acls_from_mode (const char *name, int desc, mode_t mode, bool *must_chmod)
  44. {
  45. # ifdef ACE_GETACL
  46. /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
  47. file systems (whereas the other ones are used in UFS file systems). */
  48. /* The flags in the ace_t structure changed in a binary incompatible way
  49. when ACL_NO_TRIVIAL etc. were introduced in <sys/acl.h> version 1.15.
  50. How to distinguish the two conventions at runtime?
  51. We fetch the existing ACL. In the old convention, usually three ACEs have
  52. a_flags = ACE_OWNER / ACE_GROUP / ACE_OTHER, in the range 0x0100..0x0400.
  53. In the new convention, these values are not used. */
  54. int convention;
  55. {
  56. /* Initially, try to read the entries into a stack-allocated buffer.
  57. Use malloc if it does not fit. */
  58. enum
  59. {
  60. alloc_init = 4000 / sizeof (ace_t), /* >= 3 */
  61. alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (ace_t))
  62. };
  63. ace_t buf[alloc_init];
  64. size_t alloc = alloc_init;
  65. ace_t *entries = buf;
  66. ace_t *malloced = NULL;
  67. int count;
  68. for (;;)
  69. {
  70. count = (desc != -1
  71. ? facl (desc, ACE_GETACL, alloc, entries)
  72. : acl (name, ACE_GETACL, alloc, entries));
  73. if (count < 0 && errno == ENOSPC)
  74. {
  75. /* Increase the size of the buffer. */
  76. free (malloced);
  77. if (alloc > alloc_max / 2)
  78. {
  79. errno = ENOMEM;
  80. return -1;
  81. }
  82. alloc = 2 * alloc; /* <= alloc_max */
  83. entries = malloced = (ace_t *) malloc (alloc * sizeof (ace_t));
  84. if (entries == NULL)
  85. {
  86. errno = ENOMEM;
  87. return -1;
  88. }
  89. continue;
  90. }
  91. break;
  92. }
  93. if (count <= 0)
  94. convention = -1;
  95. else
  96. {
  97. int i;
  98. convention = 0;
  99. for (i = 0; i < count; i++)
  100. if (entries[i].a_flags & (OLD_ACE_OWNER | OLD_ACE_GROUP | OLD_ACE_OTHER))
  101. {
  102. convention = 1;
  103. break;
  104. }
  105. }
  106. free (malloced);
  107. }
  108. if (convention >= 0)
  109. {
  110. ace_t entries[6];
  111. int count;
  112. int ret;
  113. if (convention)
  114. {
  115. /* Running on Solaris 10. */
  116. entries[0].a_type = OLD_ALLOW;
  117. entries[0].a_flags = OLD_ACE_OWNER;
  118. entries[0].a_who = 0; /* irrelevant */
  119. entries[0].a_access_mask = (mode >> 6) & 7;
  120. entries[1].a_type = OLD_ALLOW;
  121. entries[1].a_flags = OLD_ACE_GROUP;
  122. entries[1].a_who = 0; /* irrelevant */
  123. entries[1].a_access_mask = (mode >> 3) & 7;
  124. entries[2].a_type = OLD_ALLOW;
  125. entries[2].a_flags = OLD_ACE_OTHER;
  126. entries[2].a_who = 0;
  127. entries[2].a_access_mask = mode & 7;
  128. count = 3;
  129. }
  130. else
  131. {
  132. /* Running on Solaris 10 (newer version) or Solaris 11.
  133. The details here were found through "/bin/ls -lvd somefiles". */
  134. entries[0].a_type = NEW_ACE_ACCESS_DENIED_ACE_TYPE;
  135. entries[0].a_flags = NEW_ACE_OWNER;
  136. entries[0].a_who = 0; /* irrelevant */
  137. entries[0].a_access_mask = 0;
  138. entries[1].a_type = NEW_ACE_ACCESS_ALLOWED_ACE_TYPE;
  139. entries[1].a_flags = NEW_ACE_OWNER;
  140. entries[1].a_who = 0; /* irrelevant */
  141. entries[1].a_access_mask = NEW_ACE_WRITE_NAMED_ATTRS
  142. | NEW_ACE_WRITE_ATTRIBUTES
  143. | NEW_ACE_WRITE_ACL
  144. | NEW_ACE_WRITE_OWNER;
  145. if (mode & 0400)
  146. entries[1].a_access_mask |= NEW_ACE_READ_DATA;
  147. else
  148. entries[0].a_access_mask |= NEW_ACE_READ_DATA;
  149. if (mode & 0200)
  150. entries[1].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
  151. else
  152. entries[0].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
  153. if (mode & 0100)
  154. entries[1].a_access_mask |= NEW_ACE_EXECUTE;
  155. else
  156. entries[0].a_access_mask |= NEW_ACE_EXECUTE;
  157. entries[2].a_type = NEW_ACE_ACCESS_DENIED_ACE_TYPE;
  158. entries[2].a_flags = NEW_ACE_GROUP | NEW_ACE_IDENTIFIER_GROUP;
  159. entries[2].a_who = 0; /* irrelevant */
  160. entries[2].a_access_mask = 0;
  161. entries[3].a_type = NEW_ACE_ACCESS_ALLOWED_ACE_TYPE;
  162. entries[3].a_flags = NEW_ACE_GROUP | NEW_ACE_IDENTIFIER_GROUP;
  163. entries[3].a_who = 0; /* irrelevant */
  164. entries[3].a_access_mask = 0;
  165. if (mode & 0040)
  166. entries[3].a_access_mask |= NEW_ACE_READ_DATA;
  167. else
  168. entries[2].a_access_mask |= NEW_ACE_READ_DATA;
  169. if (mode & 0020)
  170. entries[3].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
  171. else
  172. entries[2].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
  173. if (mode & 0010)
  174. entries[3].a_access_mask |= NEW_ACE_EXECUTE;
  175. else
  176. entries[2].a_access_mask |= NEW_ACE_EXECUTE;
  177. entries[4].a_type = NEW_ACE_ACCESS_DENIED_ACE_TYPE;
  178. entries[4].a_flags = NEW_ACE_EVERYONE;
  179. entries[4].a_who = 0;
  180. entries[4].a_access_mask = NEW_ACE_WRITE_NAMED_ATTRS
  181. | NEW_ACE_WRITE_ATTRIBUTES
  182. | NEW_ACE_WRITE_ACL
  183. | NEW_ACE_WRITE_OWNER;
  184. entries[5].a_type = NEW_ACE_ACCESS_ALLOWED_ACE_TYPE;
  185. entries[5].a_flags = NEW_ACE_EVERYONE;
  186. entries[5].a_who = 0;
  187. entries[5].a_access_mask = NEW_ACE_READ_NAMED_ATTRS
  188. | NEW_ACE_READ_ATTRIBUTES
  189. | NEW_ACE_READ_ACL
  190. | NEW_ACE_SYNCHRONIZE;
  191. if (mode & 0004)
  192. entries[5].a_access_mask |= NEW_ACE_READ_DATA;
  193. else
  194. entries[4].a_access_mask |= NEW_ACE_READ_DATA;
  195. if (mode & 0002)
  196. entries[5].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
  197. else
  198. entries[4].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
  199. if (mode & 0001)
  200. entries[5].a_access_mask |= NEW_ACE_EXECUTE;
  201. else
  202. entries[4].a_access_mask |= NEW_ACE_EXECUTE;
  203. count = 6;
  204. }
  205. if (desc != -1)
  206. ret = facl (desc, ACE_SETACL, count, entries);
  207. else
  208. ret = acl (name, ACE_SETACL, count, entries);
  209. if (ret < 0 && errno != EINVAL && errno != ENOTSUP)
  210. {
  211. if (errno == ENOSYS)
  212. {
  213. *must_chmod = true;
  214. return 0;
  215. }
  216. return -1;
  217. }
  218. if (ret == 0)
  219. return 0;
  220. }
  221. # endif
  222. {
  223. aclent_t entries[3];
  224. int ret;
  225. entries[0].a_type = USER_OBJ;
  226. entries[0].a_id = 0; /* irrelevant */
  227. entries[0].a_perm = (mode >> 6) & 7;
  228. entries[1].a_type = GROUP_OBJ;
  229. entries[1].a_id = 0; /* irrelevant */
  230. entries[1].a_perm = (mode >> 3) & 7;
  231. entries[2].a_type = OTHER_OBJ;
  232. entries[2].a_id = 0;
  233. entries[2].a_perm = mode & 7;
  234. if (desc != -1)
  235. ret = facl (desc, SETACL,
  236. sizeof (entries) / sizeof (aclent_t), entries);
  237. else
  238. ret = acl (name, SETACL,
  239. sizeof (entries) / sizeof (aclent_t), entries);
  240. if (ret < 0)
  241. {
  242. if (errno == ENOSYS || errno == EOPNOTSUPP)
  243. {
  244. *must_chmod = true;
  245. return 0;
  246. }
  247. return -1;
  248. }
  249. }
  250. }
  251. # elif HAVE_GETACL /* HP-UX */
  252. static int
  253. context_acl_from_mode (struct permission_context *ctx, const char *name, int desc)
  254. {
  255. struct stat statbuf;
  256. int ret;
  257. if (desc != -1)
  258. ret = fstat (desc, &statbuf);
  259. else
  260. ret = stat (name, &statbuf);
  261. if (ret < 0)
  262. return -1;
  263. ctx->entries[0].uid = statbuf.st_uid;
  264. ctx->entries[0].gid = ACL_NSGROUP;
  265. ctx->entries[0].mode = (ctx->mode >> 6) & 7;
  266. ctx->entries[1].uid = ACL_NSUSER;
  267. ctx->entries[1].gid = statbuf.st_gid;
  268. ctx->entries[1].mode = (ctx->mode >> 3) & 7;
  269. ctx->entries[2].uid = ACL_NSUSER;
  270. ctx->entries[2].gid = ACL_NSGROUP;
  271. ctx->entries[2].mode = ctx->mode & 7;
  272. ctx->count = 3;
  273. return 0;
  274. }
  275. # if HAVE_ACLV_H /* HP-UX >= 11.11 */
  276. static int
  277. context_aclv_from_mode (struct permission_context *ctx)
  278. {
  279. int ret;
  280. ctx->aclv_entries[0].a_type = USER_OBJ;
  281. ctx->aclv_entries[0].a_id = 0; /* irrelevant */
  282. ctx->aclv_entries[0].a_perm = (ctx->mode >> 6) & 7;
  283. ctx->aclv_entries[1].a_type = GROUP_OBJ;
  284. ctx->aclv_entries[1].a_id = 0; /* irrelevant */
  285. ctx->aclv_entries[1].a_perm = (ctx->mode >> 3) & 7;
  286. ctx->aclv_entries[2].a_type = CLASS_OBJ;
  287. ctx->aclv_entries[2].a_id = 0;
  288. ctx->aclv_entries[2].a_perm = (ctx->mode >> 3) & 7;
  289. ctx->aclv_entries[3].a_type = OTHER_OBJ;
  290. ctx->aclv_entries[3].a_id = 0;
  291. ctx->aclv_entries[3].a_perm = ctx->mode & 7;
  292. ctx->aclv_count = 4;
  293. ret = aclsort (ctx->aclv_count, 1, ctx->aclv_entries);
  294. if (ret > 0)
  295. abort ();
  296. return ret;
  297. }
  298. # endif
  299. # elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */
  300. static int
  301. set_acls_from_mode (const char *name, int desc, mode_t mode, bool *must_chmod)
  302. {
  303. acl_type_list_t types;
  304. size_t types_size = sizeof (types);
  305. acl_type_t type;
  306. if (aclx_gettypes (name, &types, &types_size) < 0
  307. || types.num_entries == 0)
  308. {
  309. *must_chmod = true;
  310. return 0;
  311. }
  312. /* XXX Do we need to clear all types of ACLs for the given file, or is it
  313. sufficient to clear the first one? */
  314. type = types.entries[0];
  315. if (type.u64 == ACL_AIXC)
  316. {
  317. union { struct acl a; char room[128]; } u;
  318. int ret;
  319. u.a.acl_len = (char *) &u.a.acl_ext[0] - (char *) &u.a; /* no entries */
  320. u.a.acl_mode = mode & ~(S_IXACL | 0777);
  321. u.a.u_access = (mode >> 6) & 7;
  322. u.a.g_access = (mode >> 3) & 7;
  323. u.a.o_access = mode & 7;
  324. if (desc != -1)
  325. ret = aclx_fput (desc, SET_ACL | SET_MODE_S_BITS,
  326. type, &u.a, u.a.acl_len, mode);
  327. else
  328. ret = aclx_put (name, SET_ACL | SET_MODE_S_BITS,
  329. type, &u.a, u.a.acl_len, mode);
  330. if (!(ret < 0 && errno == ENOSYS))
  331. return ret;
  332. }
  333. else if (type.u64 == ACL_NFS4)
  334. {
  335. union { nfs4_acl_int_t a; char room[128]; } u;
  336. nfs4_ace_int_t *ace;
  337. int ret;
  338. u.a.aclVersion = NFS4_ACL_INT_STRUCT_VERSION;
  339. u.a.aclEntryN = 0;
  340. ace = &u.a.aclEntry[0];
  341. {
  342. ace->flags = ACE4_ID_SPECIAL;
  343. ace->aceWho.special_whoid = ACE4_WHO_OWNER;
  344. ace->aceType = ACE4_ACCESS_ALLOWED_ACE_TYPE;
  345. ace->aceFlags = 0;
  346. ace->aceMask =
  347. (mode & 0400 ? ACE4_READ_DATA | ACE4_LIST_DIRECTORY : 0)
  348. | (mode & 0200
  349. ? ACE4_WRITE_DATA | ACE4_ADD_FILE | ACE4_APPEND_DATA
  350. | ACE4_ADD_SUBDIRECTORY
  351. : 0)
  352. | (mode & 0100 ? ACE4_EXECUTE : 0);
  353. ace->aceWhoString[0] = '\0';
  354. ace->entryLen = (char *) &ace->aceWhoString[4] - (char *) ace;
  355. ace = (nfs4_ace_int_t *) (char *) &ace->aceWhoString[4];
  356. u.a.aclEntryN++;
  357. }
  358. {
  359. ace->flags = ACE4_ID_SPECIAL;
  360. ace->aceWho.special_whoid = ACE4_WHO_GROUP;
  361. ace->aceType = ACE4_ACCESS_ALLOWED_ACE_TYPE;
  362. ace->aceFlags = 0;
  363. ace->aceMask =
  364. (mode & 0040 ? ACE4_READ_DATA | ACE4_LIST_DIRECTORY : 0)
  365. | (mode & 0020
  366. ? ACE4_WRITE_DATA | ACE4_ADD_FILE | ACE4_APPEND_DATA
  367. | ACE4_ADD_SUBDIRECTORY
  368. : 0)
  369. | (mode & 0010 ? ACE4_EXECUTE : 0);
  370. ace->aceWhoString[0] = '\0';
  371. ace->entryLen = (char *) &ace->aceWhoString[4] - (char *) ace;
  372. ace = (nfs4_ace_int_t *) (char *) &ace->aceWhoString[4];
  373. u.a.aclEntryN++;
  374. }
  375. {
  376. ace->flags = ACE4_ID_SPECIAL;
  377. ace->aceWho.special_whoid = ACE4_WHO_EVERYONE;
  378. ace->aceType = ACE4_ACCESS_ALLOWED_ACE_TYPE;
  379. ace->aceFlags = 0;
  380. ace->aceMask =
  381. (mode & 0004 ? ACE4_READ_DATA | ACE4_LIST_DIRECTORY : 0)
  382. | (mode & 0002
  383. ? ACE4_WRITE_DATA | ACE4_ADD_FILE | ACE4_APPEND_DATA
  384. | ACE4_ADD_SUBDIRECTORY
  385. : 0)
  386. | (mode & 0001 ? ACE4_EXECUTE : 0);
  387. ace->aceWhoString[0] = '\0';
  388. ace->entryLen = (char *) &ace->aceWhoString[4] - (char *) ace;
  389. ace = (nfs4_ace_int_t *) (char *) &ace->aceWhoString[4];
  390. u.a.aclEntryN++;
  391. }
  392. u.a.aclLength = (char *) ace - (char *) &u.a;
  393. if (desc != -1)
  394. ret = aclx_fput (desc, SET_ACL | SET_MODE_S_BITS,
  395. type, &u.a, u.a.aclLength, mode);
  396. else
  397. ret = aclx_put (name, SET_ACL | SET_MODE_S_BITS,
  398. type, &u.a, u.a.aclLength, mode);
  399. if (!(ret < 0 && errno == ENOSYS))
  400. return ret;
  401. }
  402. *must_chmod = true;
  403. return 0;
  404. }
  405. # elif HAVE_STATACL /* older AIX */
  406. static int
  407. context_acl_from_mode (struct permission_context *ctx)
  408. {
  409. ctx->u.a.acl_len = (char *) &ctx->u.a.acl_ext[0] - (char *) &ctx->u.a; /* no entries */
  410. ctx->u.a.acl_mode = ctx->mode & ~(S_IXACL | 0777);
  411. ctx->u.a.u_access = (ctx->mode >> 6) & 7;
  412. ctx->u.a.g_access = (ctx->mode >> 3) & 7;
  413. ctx->u.a.o_access = ctx->mode & 7;
  414. ctx->have_u = true;
  415. return 0;
  416. }
  417. # elif HAVE_ACLSORT /* NonStop Kernel */
  418. static int
  419. context_acl_from_mode (struct permission_context *ctx)
  420. {
  421. int ret;
  422. ctx->entries[0].a_type = USER_OBJ;
  423. ctx->entries[0].a_id = 0; /* irrelevant */
  424. ctx->entries[0].a_perm = (ctx->mode >> 6) & 7;
  425. ctx->entries[1].a_type = GROUP_OBJ;
  426. ctx->entries[1].a_id = 0; /* irrelevant */
  427. ctx->entries[1].a_perm = (ctx->mode >> 3) & 7;
  428. ctx->entries[2].a_type = CLASS_OBJ;
  429. ctx->entries[2].a_id = 0;
  430. ctx->entries[2].a_perm = (ctx->mode >> 3) & 7;
  431. ctx->entries[3].a_type = OTHER_OBJ;
  432. ctx->entries[3].a_id = 0;
  433. ctx->entries[3].a_perm = ctx->mode & 7;
  434. ctx->count = 4;
  435. ret = aclsort (ctx->count, 1, entries);
  436. if (ret > 0)
  437. abort ();
  438. return ret;
  439. }
  440. # endif
  441. static int
  442. set_acls (struct permission_context *ctx, const char *name, int desc,
  443. int from_mode, bool *must_chmod, bool *acls_set)
  444. {
  445. int ret = 0;
  446. # if HAVE_ACL_GET_FILE
  447. /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
  448. /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
  449. # if !HAVE_ACL_TYPE_EXTENDED
  450. /* Linux, FreeBSD, IRIX, Tru64 */
  451. # ifndef HAVE_ACL_FROM_TEXT
  452. # error Must have acl_from_text (see POSIX 1003.1e draft 17).
  453. # endif
  454. # ifndef HAVE_ACL_DELETE_DEF_FILE
  455. # error Must have acl_delete_def_file (see POSIX 1003.1e draft 17).
  456. # endif
  457. if (! ctx->acls_not_supported)
  458. {
  459. if (ret == 0 && from_mode)
  460. {
  461. if (ctx->acl)
  462. acl_free (ctx->acl);
  463. ctx->acl = acl_from_mode (ctx->mode);
  464. if (ctx->acl == NULL)
  465. ret = -1;
  466. }
  467. if (ret == 0 && ctx->acl)
  468. {
  469. if (HAVE_ACL_SET_FD && desc != -1)
  470. ret = acl_set_fd (desc, ctx->acl);
  471. else
  472. ret = acl_set_file (name, ACL_TYPE_ACCESS, ctx->acl);
  473. if (ret != 0)
  474. {
  475. if (! acl_errno_valid (errno))
  476. {
  477. ctx->acls_not_supported = true;
  478. if (from_mode || acl_access_nontrivial (ctx->acl) == 0)
  479. ret = 0;
  480. }
  481. }
  482. else
  483. {
  484. *acls_set = true;
  485. if (S_ISDIR(ctx->mode))
  486. {
  487. if (! from_mode && ctx->default_acl &&
  488. acl_default_nontrivial (ctx->default_acl))
  489. ret = acl_set_file (name, ACL_TYPE_DEFAULT,
  490. ctx->default_acl);
  491. else
  492. ret = acl_delete_def_file (name);
  493. }
  494. }
  495. }
  496. }
  497. # if HAVE_ACL_TYPE_NFS4 /* FreeBSD */
  498. /* File systems either support POSIX ACLs (for example, ufs) or NFS4 ACLs
  499. (for example, zfs). */
  500. /* TODO: Implement setting ACLs once get_permissions() reads them. */
  501. # endif
  502. # else /* HAVE_ACL_TYPE_EXTENDED */
  503. /* Mac OS X */
  504. /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)
  505. and acl_get_file (name, ACL_TYPE_DEFAULT)
  506. always return NULL / EINVAL. You have to use
  507. acl_get_file (name, ACL_TYPE_EXTENDED)
  508. or acl_get_fd (open (name, ...))
  509. to retrieve an ACL.
  510. On the other hand,
  511. acl_set_file (name, ACL_TYPE_ACCESS, acl)
  512. and acl_set_file (name, ACL_TYPE_DEFAULT, acl)
  513. have the same effect as
  514. acl_set_file (name, ACL_TYPE_EXTENDED, acl):
  515. Each of these calls sets the file's ACL. */
  516. if (ctx->acl == NULL)
  517. {
  518. acl_t acl;
  519. /* Remove ACLs if the file has ACLs. */
  520. if (HAVE_ACL_GET_FD && desc != -1)
  521. acl = acl_get_fd (desc);
  522. else
  523. acl = acl_get_file (name, ACL_TYPE_EXTENDED);
  524. if (acl)
  525. {
  526. acl_free (acl);
  527. acl = acl_init (0);
  528. if (acl)
  529. {
  530. if (HAVE_ACL_SET_FD && desc != -1)
  531. ret = acl_set_fd (desc, acl);
  532. else
  533. ret = acl_set_file (name, ACL_TYPE_EXTENDED, acl);
  534. acl_free (acl);
  535. }
  536. else
  537. ret = -1;
  538. }
  539. }
  540. else
  541. {
  542. if (HAVE_ACL_SET_FD && desc != -1)
  543. ret = acl_set_fd (desc, ctx->acl);
  544. else
  545. ret = acl_set_file (name, ACL_TYPE_EXTENDED, ctx->acl);
  546. if (ret != 0)
  547. {
  548. if (! acl_errno_valid (errno)
  549. && ! acl_extended_nontrivial (ctx->acl))
  550. ret = 0;
  551. }
  552. }
  553. *acls_set = true;
  554. # endif
  555. # elif defined GETACL /* Solaris, Cygwin, not HP-UX */
  556. /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
  557. of Unixware. The acl() call returns the access and default ACL both
  558. at once. */
  559. /* If both ace_entries and entries are available, try SETACL before
  560. ACE_SETACL, because SETACL cannot fail with ENOTSUP whereas ACE_SETACL
  561. can. */
  562. if (from_mode)
  563. return set_acls_from_mode (name, desc, ctx->mode, must_chmod);
  564. if (ret == 0 && ctx->count)
  565. {
  566. if (desc != -1)
  567. ret = facl (desc, SETACL, ctx->count, ctx->entries);
  568. else
  569. ret = acl (name, SETACL, ctx->count, ctx->entries);
  570. if (ret < 0)
  571. {
  572. if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
  573. && acl_nontrivial (ctx->count, ctx->entries) == 0)
  574. ret = 0;
  575. }
  576. else
  577. *acls_set = true;
  578. }
  579. # ifdef ACE_GETACL
  580. if (ret == 0 && ctx->ace_count)
  581. {
  582. if (desc != -1)
  583. ret = facl (desc, ACE_SETACL, ctx->ace_count, ctx->ace_entries);
  584. else
  585. ret = acl (name, ACE_SETACL, ctx->ace_count, ctx->ace_entries);
  586. if (ret < 0)
  587. {
  588. if ((errno == ENOSYS || errno == EINVAL || errno == ENOTSUP)
  589. && acl_ace_nontrivial (ctx->ace_count, ctx->ace_entries) == 0)
  590. ret = 0;
  591. }
  592. else
  593. *acls_set = true;
  594. }
  595. # endif
  596. # elif HAVE_GETACL /* HP-UX */
  597. if (from_mode)
  598. ret = context_acl_from_mode (ctx, name, desc);
  599. if (ret == 0 && ctx->count > 0)
  600. {
  601. if (desc != -1)
  602. ret = fsetacl (desc, ctx->count, ctx->entries);
  603. else
  604. ret = setacl (name, ctx->count, ctx->entries);
  605. if (ret < 0)
  606. {
  607. if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
  608. && (from_mode || !acl_nontrivial (ctx->count, ctx->entries)))
  609. ret = 0;
  610. }
  611. else
  612. *acls_set = true;
  613. }
  614. # if HAVE_ACLV_H
  615. if (from_mode)
  616. ret = context_aclv_from_mode (ctx);
  617. if (ret == 0 && ctx->aclv_count > 0)
  618. {
  619. ret = acl ((char *) name, ACL_SET, ctx->aclv_count, ctx->aclv_entries);
  620. if (ret < 0)
  621. {
  622. if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
  623. && (from_mode || !aclv_nontrivial (ctx->aclv_count, ctx->aclv_entries)))
  624. ret = 0;
  625. }
  626. else
  627. *acls_set = true;
  628. }
  629. # endif
  630. # elif HAVE_ACLX_GET && ACL_AIX_WIP /* AIX */
  631. /* TODO: Implement setting ACLs once get_permissions() reads them. */
  632. if (from_mode)
  633. ret = set_acls_from_mode (name, desc, mode, must_chmod);
  634. # elif HAVE_STATACL /* older AIX */
  635. if (from_mode)
  636. ret = context_acl_from_mode (ctx);
  637. if (ret == 0 && ctx->have_u)
  638. {
  639. if (desc != -1)
  640. ret = fchacl (desc, &ctx->u.a, ctx->u.a.acl_len);
  641. else
  642. ret = chacl ((char *) name, &ctx->u.a, ctx->u.a.acl_len);
  643. if (ret < 0)
  644. {
  645. if (errno == ENOSYS && from_mode)
  646. ret = 0;
  647. }
  648. else
  649. *acls_set = true;
  650. }
  651. # elif HAVE_ACLSORT /* NonStop Kernel */
  652. if (from_mode)
  653. ret = context_acl_from_mode (ctx);
  654. if (ret == 0 && ctx->count)
  655. {
  656. ret = acl ((char *) name, ACL_SET, ctx->count, ctx->entries);
  657. if (ret != 0)
  658. {
  659. if (!acl_nontrivial (ctx->count, ctx->entries))
  660. ret = 0;
  661. }
  662. else
  663. *acls_set = true;
  664. }
  665. # else /* No ACLs */
  666. /* Nothing to do. */
  667. # endif
  668. return ret;
  669. }
  670. #endif
  671. /* If DESC is a valid file descriptor use fchmod to change the
  672. file's mode to MODE on systems that have fchmod. On systems
  673. that don't have fchmod and if DESC is invalid, use chmod on
  674. NAME instead.
  675. Return 0 if successful. Return -1 and set errno upon failure. */
  676. int
  677. chmod_or_fchmod (const char *name, int desc, mode_t mode)
  678. {
  679. if (HAVE_FCHMOD && desc != -1)
  680. return fchmod (desc, mode);
  681. else
  682. return chmod (name, mode);
  683. }
  684. /* Set the permissions in CTX on a file. If DESC is a valid file descriptor,
  685. use file descriptor operations, else use filename based operations on NAME.
  686. If access control lists are not available, fchmod the target file to the
  687. mode in CTX. Also sets the non-permission bits of the destination file
  688. (S_ISUID, S_ISGID, S_ISVTX) to those from the mode in CTX if any are set.
  689. Return 0 if successful. Return -1 and set errno upon failure. */
  690. int
  691. set_permissions (struct permission_context *ctx, const char *name, int desc)
  692. {
  693. bool acls_set _GL_UNUSED = false;
  694. bool early_chmod;
  695. bool must_chmod = false;
  696. int ret = 0;
  697. #if USE_ACL
  698. # if HAVE_STATACL
  699. /* older AIX */
  700. /* There is no need to call chmod_or_fchmod, since the mode
  701. bits S_ISUID, S_ISGID, S_ISVTX are also stored in the ACL. */
  702. early_chmod = false;
  703. # else
  704. /* All other platforms */
  705. /* On Cygwin, it is necessary to call chmod before acl, because
  706. chmod can change the contents of the ACL (in ways that don't
  707. change the allowed accesses, but still visible). */
  708. early_chmod = (! MODE_INSIDE_ACL || (ctx->mode & (S_ISUID | S_ISGID | S_ISVTX)));
  709. # endif
  710. #else
  711. /* No ACLs */
  712. early_chmod = true;
  713. #endif
  714. if (early_chmod)
  715. {
  716. ret = chmod_or_fchmod (name, desc, ctx->mode);
  717. if (ret != 0)
  718. return -1;
  719. }
  720. #if USE_ACL
  721. ret = set_acls (ctx, name, desc, false, &must_chmod, &acls_set);
  722. if (! acls_set)
  723. {
  724. int saved_errno = ret ? errno : 0;
  725. /* If we can't set an acl which we expect to be able to set, try setting
  726. the permissions to ctx->mode. Due to possible inherited permissions,
  727. we cannot simply chmod. */
  728. ret = set_acls (ctx, name, desc, true, &must_chmod, &acls_set);
  729. if (! acls_set)
  730. must_chmod = true;
  731. if (saved_errno)
  732. {
  733. errno = saved_errno;
  734. ret = -1;
  735. }
  736. }
  737. #endif
  738. if (must_chmod && ! early_chmod)
  739. {
  740. int saved_errno = ret ? errno : 0;
  741. ret = chmod_or_fchmod (name, desc, ctx->mode);
  742. if (saved_errno)
  743. {
  744. errno = saved_errno;
  745. ret = -1;
  746. }
  747. }
  748. return ret;
  749. }