qcopy-acl.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. /* copy-acl.c - copy access control list from one file to another file
  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. /* Copy access control lists from one file to another. If SOURCE_DESC is
  18. a valid file descriptor, use file descriptor operations, else use
  19. filename based operations on SRC_NAME. Likewise for DEST_DESC and
  20. DST_NAME.
  21. If access control lists are not available, fchmod the target file to
  22. MODE. Also sets the non-permission bits of the destination file
  23. (S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set.
  24. Return 0 if successful.
  25. Return -2 and set errno for an error relating to the source file.
  26. Return -1 and set errno for an error relating to the destination file. */
  27. int
  28. qcopy_acl (const char *src_name, int source_desc, const char *dst_name,
  29. int dest_desc, mode_t mode)
  30. {
  31. #if USE_ACL && HAVE_ACL_GET_FILE
  32. /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
  33. /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
  34. # if !HAVE_ACL_TYPE_EXTENDED
  35. /* Linux, FreeBSD, IRIX, Tru64 */
  36. acl_t acl;
  37. int ret;
  38. if (HAVE_ACL_GET_FD && source_desc != -1)
  39. acl = acl_get_fd (source_desc);
  40. else
  41. acl = acl_get_file (src_name, ACL_TYPE_ACCESS);
  42. if (acl == NULL)
  43. {
  44. if (! acl_errno_valid (errno))
  45. return qset_acl (dst_name, dest_desc, mode);
  46. else
  47. return -2;
  48. }
  49. if (HAVE_ACL_SET_FD && dest_desc != -1)
  50. ret = acl_set_fd (dest_desc, acl);
  51. else
  52. ret = acl_set_file (dst_name, ACL_TYPE_ACCESS, acl);
  53. if (ret != 0)
  54. {
  55. int saved_errno = errno;
  56. if (! acl_errno_valid (errno) && !acl_access_nontrivial (acl))
  57. {
  58. acl_free (acl);
  59. return chmod_or_fchmod (dst_name, dest_desc, mode);
  60. }
  61. else
  62. {
  63. acl_free (acl);
  64. chmod_or_fchmod (dst_name, dest_desc, mode);
  65. errno = saved_errno;
  66. return -1;
  67. }
  68. }
  69. else
  70. acl_free (acl);
  71. if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX)))
  72. {
  73. /* We did not call chmod so far, and either the mode and the ACL are
  74. separate or special bits are to be set which don't fit into ACLs. */
  75. if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
  76. return -1;
  77. }
  78. if (S_ISDIR (mode))
  79. {
  80. acl = acl_get_file (src_name, ACL_TYPE_DEFAULT);
  81. if (acl == NULL)
  82. return -2;
  83. if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl))
  84. {
  85. int saved_errno = errno;
  86. acl_free (acl);
  87. errno = saved_errno;
  88. return -1;
  89. }
  90. else
  91. acl_free (acl);
  92. }
  93. return 0;
  94. # else /* HAVE_ACL_TYPE_EXTENDED */
  95. /* Mac OS X */
  96. /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)
  97. and acl_get_file (name, ACL_TYPE_DEFAULT)
  98. always return NULL / EINVAL. You have to use
  99. acl_get_file (name, ACL_TYPE_EXTENDED)
  100. or acl_get_fd (open (name, ...))
  101. to retrieve an ACL.
  102. On the other hand,
  103. acl_set_file (name, ACL_TYPE_ACCESS, acl)
  104. and acl_set_file (name, ACL_TYPE_DEFAULT, acl)
  105. have the same effect as
  106. acl_set_file (name, ACL_TYPE_EXTENDED, acl):
  107. Each of these calls sets the file's ACL. */
  108. acl_t acl;
  109. int ret;
  110. if (HAVE_ACL_GET_FD && source_desc != -1)
  111. acl = acl_get_fd (source_desc);
  112. else
  113. acl = acl_get_file (src_name, ACL_TYPE_EXTENDED);
  114. if (acl == NULL)
  115. {
  116. if (!acl_errno_valid (errno))
  117. return qset_acl (dst_name, dest_desc, mode);
  118. else
  119. return -2;
  120. }
  121. if (HAVE_ACL_SET_FD && dest_desc != -1)
  122. ret = acl_set_fd (dest_desc, acl);
  123. else
  124. ret = acl_set_file (dst_name, ACL_TYPE_EXTENDED, acl);
  125. if (ret != 0)
  126. {
  127. int saved_errno = errno;
  128. if (!acl_errno_valid (saved_errno) && !acl_extended_nontrivial (acl))
  129. {
  130. acl_free (acl);
  131. return chmod_or_fchmod (dst_name, dest_desc, mode);
  132. }
  133. else
  134. {
  135. acl_free (acl);
  136. chmod_or_fchmod (dst_name, dest_desc, mode);
  137. errno = saved_errno;
  138. return -1;
  139. }
  140. }
  141. else
  142. acl_free (acl);
  143. /* Since !MODE_INSIDE_ACL, we have to call chmod explicitly. */
  144. return chmod_or_fchmod (dst_name, dest_desc, mode);
  145. # endif
  146. #elif USE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
  147. /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
  148. of Unixware. The acl() call returns the access and default ACL both
  149. at once. */
  150. # ifdef ACE_GETACL
  151. int ace_count;
  152. ace_t *ace_entries;
  153. # endif
  154. int count;
  155. aclent_t *entries;
  156. int did_chmod;
  157. int saved_errno;
  158. int ret;
  159. # ifdef ACE_GETACL
  160. /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
  161. file systems (whereas the other ones are used in UFS file systems).
  162. There is an API
  163. pathconf (name, _PC_ACL_ENABLED)
  164. fpathconf (desc, _PC_ACL_ENABLED)
  165. that allows to determine which of the two kinds of ACLs is supported
  166. for the given file. But some file systems may implement this call
  167. incorrectly, so better not use it.
  168. When fetching the source ACL, we simply fetch both ACL types.
  169. When setting the destination ACL, we try either ACL types, assuming
  170. that the kernel will translate the ACL from one form to the other.
  171. (See in <http://docs.sun.com/app/docs/doc/819-2241/6n4huc7ia?l=en&a=view>
  172. the description of ENOTSUP.) */
  173. for (;;)
  174. {
  175. ace_count = (source_desc != -1
  176. ? facl (source_desc, ACE_GETACLCNT, 0, NULL)
  177. : acl (src_name, ACE_GETACLCNT, 0, NULL));
  178. if (ace_count < 0)
  179. {
  180. if (errno == ENOSYS || errno == EINVAL)
  181. {
  182. ace_count = 0;
  183. ace_entries = NULL;
  184. break;
  185. }
  186. else
  187. return -2;
  188. }
  189. if (ace_count == 0)
  190. {
  191. ace_entries = NULL;
  192. break;
  193. }
  194. ace_entries = (ace_t *) malloc (ace_count * sizeof (ace_t));
  195. if (ace_entries == NULL)
  196. {
  197. errno = ENOMEM;
  198. return -2;
  199. }
  200. ret = (source_desc != -1
  201. ? facl (source_desc, ACE_GETACL, ace_count, ace_entries)
  202. : acl (src_name, ACE_GETACL, ace_count, ace_entries));
  203. if (ret < 0)
  204. {
  205. free (ace_entries);
  206. if (errno == ENOSYS || errno == EINVAL)
  207. {
  208. ace_count = 0;
  209. ace_entries = NULL;
  210. break;
  211. }
  212. else
  213. return -2;
  214. }
  215. if (ret == ace_count)
  216. break;
  217. /* Huh? The number of ACL entries changed since the last call.
  218. Repeat. */
  219. }
  220. # endif
  221. for (;;)
  222. {
  223. count = (source_desc != -1
  224. ? facl (source_desc, GETACLCNT, 0, NULL)
  225. : acl (src_name, GETACLCNT, 0, NULL));
  226. if (count < 0)
  227. {
  228. if (errno == ENOSYS || errno == ENOTSUP || errno == EOPNOTSUPP)
  229. {
  230. count = 0;
  231. entries = NULL;
  232. break;
  233. }
  234. else
  235. return -2;
  236. }
  237. if (count == 0)
  238. {
  239. entries = NULL;
  240. break;
  241. }
  242. entries = (aclent_t *) malloc (count * sizeof (aclent_t));
  243. if (entries == NULL)
  244. {
  245. errno = ENOMEM;
  246. return -2;
  247. }
  248. if ((source_desc != -1
  249. ? facl (source_desc, GETACL, count, entries)
  250. : acl (src_name, GETACL, count, entries))
  251. == count)
  252. break;
  253. /* Huh? The number of ACL entries changed since the last call.
  254. Repeat. */
  255. }
  256. /* Is there an ACL of either kind? */
  257. # ifdef ACE_GETACL
  258. if (ace_count == 0)
  259. # endif
  260. if (count == 0)
  261. return qset_acl (dst_name, dest_desc, mode);
  262. did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */
  263. saved_errno = 0; /* the first non-ignorable error code */
  264. if (!MODE_INSIDE_ACL)
  265. {
  266. /* On Cygwin, it is necessary to call chmod before acl, because
  267. chmod can change the contents of the ACL (in ways that don't
  268. change the allowed accesses, but still visible). */
  269. if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
  270. saved_errno = errno;
  271. did_chmod = 1;
  272. }
  273. /* If both ace_entries and entries are available, try SETACL before
  274. ACE_SETACL, because SETACL cannot fail with ENOTSUP whereas ACE_SETACL
  275. can. */
  276. if (count > 0)
  277. {
  278. ret = (dest_desc != -1
  279. ? facl (dest_desc, SETACL, count, entries)
  280. : acl (dst_name, SETACL, count, entries));
  281. if (ret < 0 && saved_errno == 0)
  282. {
  283. saved_errno = errno;
  284. if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
  285. && !acl_nontrivial (count, entries))
  286. saved_errno = 0;
  287. }
  288. else
  289. did_chmod = 1;
  290. }
  291. free (entries);
  292. # ifdef ACE_GETACL
  293. if (ace_count > 0)
  294. {
  295. ret = (dest_desc != -1
  296. ? facl (dest_desc, ACE_SETACL, ace_count, ace_entries)
  297. : acl (dst_name, ACE_SETACL, ace_count, ace_entries));
  298. if (ret < 0 && saved_errno == 0)
  299. {
  300. saved_errno = errno;
  301. if ((errno == ENOSYS || errno == EINVAL || errno == ENOTSUP)
  302. && !acl_ace_nontrivial (ace_count, ace_entries))
  303. saved_errno = 0;
  304. }
  305. }
  306. free (ace_entries);
  307. # endif
  308. if (MODE_INSIDE_ACL
  309. && did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0))
  310. {
  311. /* We did not call chmod so far, and either the mode and the ACL are
  312. separate or special bits are to be set which don't fit into ACLs. */
  313. if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
  314. {
  315. if (saved_errno == 0)
  316. saved_errno = errno;
  317. }
  318. }
  319. if (saved_errno)
  320. {
  321. errno = saved_errno;
  322. return -1;
  323. }
  324. return 0;
  325. #elif USE_ACL && HAVE_GETACL /* HP-UX */
  326. struct acl_entry entries[NACLENTRIES];
  327. int count;
  328. # if HAVE_ACLV_H
  329. struct acl aclv_entries[NACLVENTRIES];
  330. int aclv_count;
  331. # endif
  332. int did_chmod;
  333. int saved_errno;
  334. int ret;
  335. count = (source_desc != -1
  336. ? fgetacl (source_desc, NACLENTRIES, entries)
  337. : getacl (src_name, NACLENTRIES, entries));
  338. if (count < 0)
  339. {
  340. if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
  341. count = 0;
  342. else
  343. return -2;
  344. }
  345. else if (count > 0)
  346. {
  347. if (count > NACLENTRIES)
  348. /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */
  349. abort ();
  350. }
  351. # if HAVE_ACLV_H
  352. aclv_count = acl ((char *) src_name, ACL_GET, NACLVENTRIES, aclv_entries);
  353. if (aclv_count < 0)
  354. {
  355. if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
  356. count = 0;
  357. else
  358. return -2;
  359. }
  360. else if (aclv_count > 0)
  361. {
  362. if (aclv_count > NACLVENTRIES)
  363. /* If NACLVENTRIES cannot be trusted, use dynamic memory allocation. */
  364. abort ();
  365. }
  366. # endif
  367. if (count == 0)
  368. # if HAVE_ACLV_H
  369. if (aclv_count == 0)
  370. # endif
  371. return qset_acl (dst_name, dest_desc, mode);
  372. did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */
  373. saved_errno = 0; /* the first non-ignorable error code */
  374. if (count > 0)
  375. {
  376. ret = (dest_desc != -1
  377. ? fsetacl (dest_desc, count, entries)
  378. : setacl (dst_name, count, entries));
  379. if (ret < 0 && saved_errno == 0)
  380. {
  381. saved_errno = errno;
  382. if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
  383. {
  384. struct stat source_statbuf;
  385. if ((source_desc != -1
  386. ? fstat (source_desc, &source_statbuf)
  387. : stat (src_name, &source_statbuf)) == 0)
  388. {
  389. if (!acl_nontrivial (count, entries, &source_statbuf))
  390. saved_errno = 0;
  391. }
  392. else
  393. saved_errno = errno;
  394. }
  395. }
  396. else
  397. did_chmod = 1;
  398. }
  399. # if HAVE_ACLV_H
  400. if (aclv_count > 0)
  401. {
  402. ret = acl ((char *) dst_name, ACL_SET, aclv_count, aclv_entries);
  403. if (ret < 0 && saved_errno == 0)
  404. {
  405. saved_errno = errno;
  406. if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
  407. {
  408. if (!aclv_nontrivial (aclv_count, aclv_entries))
  409. saved_errno = 0;
  410. }
  411. }
  412. else
  413. did_chmod = 1;
  414. }
  415. # endif
  416. if (did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0))
  417. {
  418. /* We did not call chmod so far, and special bits are to be set which
  419. don't fit into ACLs. */
  420. if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
  421. {
  422. if (saved_errno == 0)
  423. saved_errno = errno;
  424. }
  425. }
  426. if (saved_errno)
  427. {
  428. errno = saved_errno;
  429. return -1;
  430. }
  431. return 0;
  432. #elif USE_ACL && HAVE_ACLX_GET && 0 /* AIX */
  433. /* TODO */
  434. #elif USE_ACL && HAVE_STATACL /* older AIX */
  435. union { struct acl a; char room[4096]; } u;
  436. int ret;
  437. if ((source_desc != -1
  438. ? fstatacl (source_desc, STX_NORMAL, &u.a, sizeof (u))
  439. : statacl (src_name, STX_NORMAL, &u.a, sizeof (u)))
  440. < 0)
  441. return -2;
  442. ret = (dest_desc != -1
  443. ? fchacl (dest_desc, &u.a, u.a.acl_len)
  444. : chacl (dst_name, &u.a, u.a.acl_len));
  445. if (ret < 0)
  446. {
  447. int saved_errno = errno;
  448. chmod_or_fchmod (dst_name, dest_desc, mode);
  449. errno = saved_errno;
  450. return -1;
  451. }
  452. /* No need to call chmod_or_fchmod at this point, since the mode bits
  453. S_ISUID, S_ISGID, S_ISVTX are also stored in the ACL. */
  454. return 0;
  455. #elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */
  456. struct acl entries[NACLENTRIES];
  457. int count;
  458. int ret;
  459. count = acl ((char *) src_name, ACL_GET, NACLENTRIES, entries);
  460. if (count < 0)
  461. {
  462. if (0)
  463. count = 0;
  464. else
  465. return -2;
  466. }
  467. else if (count > 0)
  468. {
  469. if (count > NACLENTRIES)
  470. /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */
  471. abort ();
  472. }
  473. if (count == 0)
  474. return qset_acl (dst_name, dest_desc, mode);
  475. ret = acl ((char *) dst_name, ACL_SET, count, entries);
  476. if (ret < 0)
  477. {
  478. int saved_errno = errno;
  479. if (0)
  480. {
  481. if (!acl_nontrivial (count, entries))
  482. return chmod_or_fchmod (dst_name, dest_desc, mode);
  483. }
  484. chmod_or_fchmod (dst_name, dest_desc, mode);
  485. errno = saved_errno;
  486. return -1;
  487. }
  488. if (mode & (S_ISUID | S_ISGID | S_ISVTX))
  489. {
  490. /* We did not call chmod so far, and either the mode and the ACL are
  491. separate or special bits are to be set which don't fit into ACLs. */
  492. return chmod_or_fchmod (dst_name, dest_desc, mode);
  493. }
  494. return 0;
  495. #else
  496. return qset_acl (dst_name, dest_desc, mode);
  497. #endif
  498. }