get-permissions.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /* Get 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 <string.h>
  16. #include "acl.h"
  17. #include "acl-internal.h"
  18. /* Read the permissions of a file into CTX. If DESC is a valid file descriptor,
  19. use file descriptor operations, else use filename based operations on NAME.
  20. MODE is the file mode obtained from a previous stat call.
  21. Return 0 if successful. Return -1 and set errno upon failure. */
  22. int
  23. get_permissions (const char *name, int desc, mode_t mode,
  24. struct permission_context *ctx)
  25. {
  26. memset (ctx, 0, sizeof *ctx);
  27. ctx->mode = mode;
  28. #if USE_ACL && HAVE_ACL_GET_FILE
  29. /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
  30. /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
  31. # if !HAVE_ACL_TYPE_EXTENDED
  32. /* Linux, FreeBSD, IRIX, Tru64 */
  33. if (HAVE_ACL_GET_FD && desc != -1)
  34. ctx->acl = acl_get_fd (desc);
  35. else
  36. ctx->acl = acl_get_file (name, ACL_TYPE_ACCESS);
  37. if (ctx->acl == NULL)
  38. return acl_errno_valid (errno) ? -1 : 0;
  39. /* With POSIX ACLs, a file cannot have "no" acl; a file without
  40. extended permissions has a "minimal" acl which is equivalent to the
  41. file mode. */
  42. if (S_ISDIR (mode))
  43. {
  44. ctx->default_acl = acl_get_file (name, ACL_TYPE_DEFAULT);
  45. if (ctx->default_acl == NULL)
  46. return -1;
  47. }
  48. # if HAVE_ACL_TYPE_NFS4 /* FreeBSD */
  49. /* TODO (see set_permissions). */
  50. # endif
  51. # else /* HAVE_ACL_TYPE_EXTENDED */
  52. /* Mac OS X */
  53. /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)
  54. and acl_get_file (name, ACL_TYPE_DEFAULT)
  55. always return NULL / EINVAL. You have to use
  56. acl_get_file (name, ACL_TYPE_EXTENDED)
  57. or acl_get_fd (open (name, ...))
  58. to retrieve an ACL.
  59. On the other hand,
  60. acl_set_file (name, ACL_TYPE_ACCESS, acl)
  61. and acl_set_file (name, ACL_TYPE_DEFAULT, acl)
  62. have the same effect as
  63. acl_set_file (name, ACL_TYPE_EXTENDED, acl):
  64. Each of these calls sets the file's ACL. */
  65. if (HAVE_ACL_GET_FD && desc != -1)
  66. ctx->acl = acl_get_fd (desc);
  67. else
  68. ctx->acl = acl_get_file (name, ACL_TYPE_EXTENDED);
  69. if (ctx->acl == NULL)
  70. return acl_errno_valid (errno) ? -1 : 0;
  71. # endif
  72. #elif USE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
  73. /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
  74. of Unixware. The acl() call returns the access and default ACL both
  75. at once. */
  76. # ifdef ACE_GETACL
  77. /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
  78. file systems (whereas the other ones are used in UFS file systems).
  79. There is an API
  80. pathconf (name, _PC_ACL_ENABLED)
  81. fpathconf (desc, _PC_ACL_ENABLED)
  82. that allows to determine which of the two kinds of ACLs is supported
  83. for the given file. But some file systems may implement this call
  84. incorrectly, so better not use it.
  85. When fetching the source ACL, we simply fetch both ACL types.
  86. When setting the destination ACL, we try either ACL types, assuming
  87. that the kernel will translate the ACL from one form to the other.
  88. (See in <http://docs.sun.com/app/docs/doc/819-2241/6n4huc7ia?l=en&a=view>
  89. the description of ENOTSUP.) */
  90. for (;;)
  91. {
  92. int ret;
  93. if (desc != -1)
  94. ret = facl (desc, ACE_GETACLCNT, 0, NULL);
  95. else
  96. ret = acl (name, ACE_GETACLCNT, 0, NULL);
  97. if (ret < 0)
  98. {
  99. if (errno == ENOSYS || errno == EINVAL)
  100. ret = 0;
  101. else
  102. return -1;
  103. }
  104. ctx->ace_count = ret;
  105. if (ctx->ace_count == 0)
  106. break;
  107. ctx->ace_entries = (ace_t *) malloc (ctx->ace_count * sizeof (ace_t));
  108. if (ctx->ace_entries == NULL)
  109. {
  110. errno = ENOMEM;
  111. return -1;
  112. }
  113. if (desc != -1)
  114. ret = facl (desc, ACE_GETACL, ctx->ace_count, ctx->ace_entries);
  115. else
  116. ret = acl (name, ACE_GETACL, ctx->ace_count, ctx->ace_entries);
  117. if (ret < 0)
  118. {
  119. if (errno == ENOSYS || errno == EINVAL)
  120. {
  121. free (ctx->ace_entries);
  122. ctx->ace_entries = NULL;
  123. ctx->ace_count = 0;
  124. break;
  125. }
  126. else
  127. return -1;
  128. }
  129. if (ret <= ctx->ace_count)
  130. {
  131. ctx->ace_count = ret;
  132. break;
  133. }
  134. /* Huh? The number of ACL entries has increased since the last call.
  135. Repeat. */
  136. free (ctx->ace_entries);
  137. ctx->ace_entries = NULL;
  138. }
  139. # endif
  140. for (;;)
  141. {
  142. int ret;
  143. if (desc != -1)
  144. ret = facl (desc, GETACLCNT, 0, NULL);
  145. else
  146. ret = acl (name, GETACLCNT, 0, NULL);
  147. if (ret < 0)
  148. {
  149. if (errno == ENOSYS || errno == ENOTSUP || errno == EOPNOTSUPP)
  150. ret = 0;
  151. else
  152. return -1;
  153. }
  154. ctx->count = ret;
  155. if (ctx->count == 0)
  156. break;
  157. ctx->entries = (aclent_t *) malloc (ctx->count * sizeof (aclent_t));
  158. if (ctx->entries == NULL)
  159. {
  160. errno = ENOMEM;
  161. return -1;
  162. }
  163. if (desc != -1)
  164. ret = facl (desc, GETACL, ctx->count, ctx->entries);
  165. else
  166. ret = acl (name, GETACL, ctx->count, ctx->entries);
  167. if (ret < 0)
  168. {
  169. if (errno == ENOSYS || errno == ENOTSUP || errno == EOPNOTSUPP)
  170. {
  171. free (ctx->entries);
  172. ctx->entries = NULL;
  173. ctx->count = 0;
  174. break;
  175. }
  176. else
  177. return -1;
  178. }
  179. if (ret <= ctx->count)
  180. {
  181. ctx->count = ret;
  182. break;
  183. }
  184. /* Huh? The number of ACL entries has increased since the last call.
  185. Repeat. */
  186. free (ctx->entries);
  187. ctx->entries = NULL;
  188. }
  189. #elif USE_ACL && HAVE_GETACL /* HP-UX */
  190. {
  191. int ret;
  192. if (desc != -1)
  193. ret = fgetacl (desc, NACLENTRIES, ctx->entries);
  194. else
  195. ret = getacl (name, NACLENTRIES, ctx->entries);
  196. if (ret < 0)
  197. {
  198. if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
  199. ret = 0;
  200. else
  201. return -1;
  202. }
  203. else if (ret > NACLENTRIES)
  204. /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */
  205. abort ();
  206. ctx->count = ret;
  207. # if HAVE_ACLV_H
  208. ret = acl ((char *) name, ACL_GET, NACLVENTRIES, ctx->aclv_entries);
  209. if (ret < 0)
  210. {
  211. if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
  212. ret = 0;
  213. else
  214. return -2;
  215. }
  216. else if (ret > NACLVENTRIES)
  217. /* If NACLVENTRIES cannot be trusted, use dynamic memory allocation. */
  218. abort ();
  219. ctx->aclv_count = ret;
  220. # endif
  221. }
  222. #elif USE_ACL && HAVE_ACLX_GET && ACL_AIX_WIP /* AIX */
  223. /* TODO (see set_permissions). */
  224. #elif USE_ACL && HAVE_STATACL /* older AIX */
  225. {
  226. int ret;
  227. if (desc != -1)
  228. ret = fstatacl (desc, STX_NORMAL, &ctx->u.a, sizeof ctx->u);
  229. else
  230. ret = statacl ((char *) name, STX_NORMAL, &ctx->u.a, sizeof ctx->u);
  231. if (ret == 0)
  232. ctx->have_u = true;
  233. }
  234. #elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */
  235. {
  236. int ret = acl ((char *) name, ACL_GET, NACLENTRIES, ctx->entries);
  237. if (ret < 0)
  238. return -1;
  239. else if (ret > NACLENTRIES)
  240. /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */
  241. abort ();
  242. ctx->count = ret;
  243. }
  244. #endif
  245. return 0;
  246. }