acl.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. /*
  2. * linux/fs/ext3/acl.c
  3. *
  4. * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
  5. */
  6. #include "ext3.h"
  7. #include "xattr.h"
  8. #include "acl.h"
  9. /*
  10. * Convert from filesystem to in-memory representation.
  11. */
  12. static struct posix_acl *
  13. ext3_acl_from_disk(const void *value, size_t size)
  14. {
  15. const char *end = (char *)value + size;
  16. int n, count;
  17. struct posix_acl *acl;
  18. if (!value)
  19. return NULL;
  20. if (size < sizeof(ext3_acl_header))
  21. return ERR_PTR(-EINVAL);
  22. if (((ext3_acl_header *)value)->a_version !=
  23. cpu_to_le32(EXT3_ACL_VERSION))
  24. return ERR_PTR(-EINVAL);
  25. value = (char *)value + sizeof(ext3_acl_header);
  26. count = ext3_acl_count(size);
  27. if (count < 0)
  28. return ERR_PTR(-EINVAL);
  29. if (count == 0)
  30. return NULL;
  31. acl = posix_acl_alloc(count, GFP_NOFS);
  32. if (!acl)
  33. return ERR_PTR(-ENOMEM);
  34. for (n=0; n < count; n++) {
  35. ext3_acl_entry *entry =
  36. (ext3_acl_entry *)value;
  37. if ((char *)value + sizeof(ext3_acl_entry_short) > end)
  38. goto fail;
  39. acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag);
  40. acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
  41. switch(acl->a_entries[n].e_tag) {
  42. case ACL_USER_OBJ:
  43. case ACL_GROUP_OBJ:
  44. case ACL_MASK:
  45. case ACL_OTHER:
  46. value = (char *)value +
  47. sizeof(ext3_acl_entry_short);
  48. break;
  49. case ACL_USER:
  50. value = (char *)value + sizeof(ext3_acl_entry);
  51. if ((char *)value > end)
  52. goto fail;
  53. acl->a_entries[n].e_uid =
  54. make_kuid(&init_user_ns,
  55. le32_to_cpu(entry->e_id));
  56. break;
  57. case ACL_GROUP:
  58. value = (char *)value + sizeof(ext3_acl_entry);
  59. if ((char *)value > end)
  60. goto fail;
  61. acl->a_entries[n].e_gid =
  62. make_kgid(&init_user_ns,
  63. le32_to_cpu(entry->e_id));
  64. break;
  65. default:
  66. goto fail;
  67. }
  68. }
  69. if (value != end)
  70. goto fail;
  71. return acl;
  72. fail:
  73. posix_acl_release(acl);
  74. return ERR_PTR(-EINVAL);
  75. }
  76. /*
  77. * Convert from in-memory to filesystem representation.
  78. */
  79. static void *
  80. ext3_acl_to_disk(const struct posix_acl *acl, size_t *size)
  81. {
  82. ext3_acl_header *ext_acl;
  83. char *e;
  84. size_t n;
  85. *size = ext3_acl_size(acl->a_count);
  86. ext_acl = kmalloc(sizeof(ext3_acl_header) + acl->a_count *
  87. sizeof(ext3_acl_entry), GFP_NOFS);
  88. if (!ext_acl)
  89. return ERR_PTR(-ENOMEM);
  90. ext_acl->a_version = cpu_to_le32(EXT3_ACL_VERSION);
  91. e = (char *)ext_acl + sizeof(ext3_acl_header);
  92. for (n=0; n < acl->a_count; n++) {
  93. const struct posix_acl_entry *acl_e = &acl->a_entries[n];
  94. ext3_acl_entry *entry = (ext3_acl_entry *)e;
  95. entry->e_tag = cpu_to_le16(acl_e->e_tag);
  96. entry->e_perm = cpu_to_le16(acl_e->e_perm);
  97. switch(acl_e->e_tag) {
  98. case ACL_USER:
  99. entry->e_id = cpu_to_le32(
  100. from_kuid(&init_user_ns, acl_e->e_uid));
  101. e += sizeof(ext3_acl_entry);
  102. break;
  103. case ACL_GROUP:
  104. entry->e_id = cpu_to_le32(
  105. from_kgid(&init_user_ns, acl_e->e_gid));
  106. e += sizeof(ext3_acl_entry);
  107. break;
  108. case ACL_USER_OBJ:
  109. case ACL_GROUP_OBJ:
  110. case ACL_MASK:
  111. case ACL_OTHER:
  112. e += sizeof(ext3_acl_entry_short);
  113. break;
  114. default:
  115. goto fail;
  116. }
  117. }
  118. return (char *)ext_acl;
  119. fail:
  120. kfree(ext_acl);
  121. return ERR_PTR(-EINVAL);
  122. }
  123. /*
  124. * Inode operation get_posix_acl().
  125. *
  126. * inode->i_mutex: don't care
  127. */
  128. struct posix_acl *
  129. ext3_get_acl(struct inode *inode, int type)
  130. {
  131. int name_index;
  132. char *value = NULL;
  133. struct posix_acl *acl;
  134. int retval;
  135. if (!test_opt(inode->i_sb, POSIX_ACL))
  136. return NULL;
  137. acl = get_cached_acl(inode, type);
  138. if (acl != ACL_NOT_CACHED)
  139. return acl;
  140. switch (type) {
  141. case ACL_TYPE_ACCESS:
  142. name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS;
  143. break;
  144. case ACL_TYPE_DEFAULT:
  145. name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT;
  146. break;
  147. default:
  148. BUG();
  149. }
  150. retval = ext3_xattr_get(inode, name_index, "", NULL, 0);
  151. if (retval > 0) {
  152. value = kmalloc(retval, GFP_NOFS);
  153. if (!value)
  154. return ERR_PTR(-ENOMEM);
  155. retval = ext3_xattr_get(inode, name_index, "", value, retval);
  156. }
  157. if (retval > 0)
  158. acl = ext3_acl_from_disk(value, retval);
  159. else if (retval == -ENODATA || retval == -ENOSYS)
  160. acl = NULL;
  161. else
  162. acl = ERR_PTR(retval);
  163. kfree(value);
  164. if (!IS_ERR(acl))
  165. set_cached_acl(inode, type, acl);
  166. return acl;
  167. }
  168. /*
  169. * Set the access or default ACL of an inode.
  170. *
  171. * inode->i_mutex: down unless called from ext3_new_inode
  172. */
  173. static int
  174. ext3_set_acl(handle_t *handle, struct inode *inode, int type,
  175. struct posix_acl *acl)
  176. {
  177. int name_index;
  178. void *value = NULL;
  179. size_t size = 0;
  180. int error;
  181. if (S_ISLNK(inode->i_mode))
  182. return -EOPNOTSUPP;
  183. switch(type) {
  184. case ACL_TYPE_ACCESS:
  185. name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS;
  186. if (acl) {
  187. error = posix_acl_equiv_mode(acl, &inode->i_mode);
  188. if (error < 0)
  189. return error;
  190. else {
  191. inode->i_ctime = CURRENT_TIME_SEC;
  192. ext3_mark_inode_dirty(handle, inode);
  193. if (error == 0)
  194. acl = NULL;
  195. }
  196. }
  197. break;
  198. case ACL_TYPE_DEFAULT:
  199. name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT;
  200. if (!S_ISDIR(inode->i_mode))
  201. return acl ? -EACCES : 0;
  202. break;
  203. default:
  204. return -EINVAL;
  205. }
  206. if (acl) {
  207. value = ext3_acl_to_disk(acl, &size);
  208. if (IS_ERR(value))
  209. return (int)PTR_ERR(value);
  210. }
  211. error = ext3_xattr_set_handle(handle, inode, name_index, "",
  212. value, size, 0);
  213. kfree(value);
  214. if (!error)
  215. set_cached_acl(inode, type, acl);
  216. return error;
  217. }
  218. /*
  219. * Initialize the ACLs of a new inode. Called from ext3_new_inode.
  220. *
  221. * dir->i_mutex: down
  222. * inode->i_mutex: up (access to inode is still exclusive)
  223. */
  224. int
  225. ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
  226. {
  227. struct posix_acl *acl = NULL;
  228. int error = 0;
  229. if (!S_ISLNK(inode->i_mode)) {
  230. if (test_opt(dir->i_sb, POSIX_ACL)) {
  231. acl = ext3_get_acl(dir, ACL_TYPE_DEFAULT);
  232. if (IS_ERR(acl))
  233. return PTR_ERR(acl);
  234. }
  235. if (!acl)
  236. inode->i_mode &= ~current_umask();
  237. }
  238. if (test_opt(inode->i_sb, POSIX_ACL) && acl) {
  239. if (S_ISDIR(inode->i_mode)) {
  240. error = ext3_set_acl(handle, inode,
  241. ACL_TYPE_DEFAULT, acl);
  242. if (error)
  243. goto cleanup;
  244. }
  245. error = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
  246. if (error < 0)
  247. return error;
  248. if (error > 0) {
  249. /* This is an extended ACL */
  250. error = ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, acl);
  251. }
  252. }
  253. cleanup:
  254. posix_acl_release(acl);
  255. return error;
  256. }
  257. /*
  258. * Does chmod for an inode that may have an Access Control List. The
  259. * inode->i_mode field must be updated to the desired value by the caller
  260. * before calling this function.
  261. * Returns 0 on success, or a negative error number.
  262. *
  263. * We change the ACL rather than storing some ACL entries in the file
  264. * mode permission bits (which would be more efficient), because that
  265. * would break once additional permissions (like ACL_APPEND, ACL_DELETE
  266. * for directories) are added. There are no more bits available in the
  267. * file mode.
  268. *
  269. * inode->i_mutex: down
  270. */
  271. int
  272. ext3_acl_chmod(struct inode *inode)
  273. {
  274. struct posix_acl *acl;
  275. handle_t *handle;
  276. int retries = 0;
  277. int error;
  278. if (S_ISLNK(inode->i_mode))
  279. return -EOPNOTSUPP;
  280. if (!test_opt(inode->i_sb, POSIX_ACL))
  281. return 0;
  282. acl = ext3_get_acl(inode, ACL_TYPE_ACCESS);
  283. if (IS_ERR(acl) || !acl)
  284. return PTR_ERR(acl);
  285. error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
  286. if (error)
  287. return error;
  288. retry:
  289. handle = ext3_journal_start(inode,
  290. EXT3_DATA_TRANS_BLOCKS(inode->i_sb));
  291. if (IS_ERR(handle)) {
  292. error = PTR_ERR(handle);
  293. ext3_std_error(inode->i_sb, error);
  294. goto out;
  295. }
  296. error = ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, acl);
  297. ext3_journal_stop(handle);
  298. if (error == -ENOSPC &&
  299. ext3_should_retry_alloc(inode->i_sb, &retries))
  300. goto retry;
  301. out:
  302. posix_acl_release(acl);
  303. return error;
  304. }
  305. /*
  306. * Extended attribute handlers
  307. */
  308. static size_t
  309. ext3_xattr_list_acl_access(struct dentry *dentry, char *list, size_t list_len,
  310. const char *name, size_t name_len, int type)
  311. {
  312. const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);
  313. if (!test_opt(dentry->d_sb, POSIX_ACL))
  314. return 0;
  315. if (list && size <= list_len)
  316. memcpy(list, POSIX_ACL_XATTR_ACCESS, size);
  317. return size;
  318. }
  319. static size_t
  320. ext3_xattr_list_acl_default(struct dentry *dentry, char *list, size_t list_len,
  321. const char *name, size_t name_len, int type)
  322. {
  323. const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);
  324. if (!test_opt(dentry->d_sb, POSIX_ACL))
  325. return 0;
  326. if (list && size <= list_len)
  327. memcpy(list, POSIX_ACL_XATTR_DEFAULT, size);
  328. return size;
  329. }
  330. static int
  331. ext3_xattr_get_acl(struct dentry *dentry, const char *name, void *buffer,
  332. size_t size, int type)
  333. {
  334. struct posix_acl *acl;
  335. int error;
  336. if (strcmp(name, "") != 0)
  337. return -EINVAL;
  338. if (!test_opt(dentry->d_sb, POSIX_ACL))
  339. return -EOPNOTSUPP;
  340. acl = ext3_get_acl(dentry->d_inode, type);
  341. if (IS_ERR(acl))
  342. return PTR_ERR(acl);
  343. if (acl == NULL)
  344. return -ENODATA;
  345. error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
  346. posix_acl_release(acl);
  347. return error;
  348. }
  349. static int
  350. ext3_xattr_set_acl(struct dentry *dentry, const char *name, const void *value,
  351. size_t size, int flags, int type)
  352. {
  353. struct inode *inode = dentry->d_inode;
  354. handle_t *handle;
  355. struct posix_acl *acl;
  356. int error, retries = 0;
  357. if (strcmp(name, "") != 0)
  358. return -EINVAL;
  359. if (!test_opt(inode->i_sb, POSIX_ACL))
  360. return -EOPNOTSUPP;
  361. if (!inode_owner_or_capable(inode))
  362. return -EPERM;
  363. if (value) {
  364. acl = posix_acl_from_xattr(&init_user_ns, value, size);
  365. if (IS_ERR(acl))
  366. return PTR_ERR(acl);
  367. else if (acl) {
  368. error = posix_acl_valid(acl);
  369. if (error)
  370. goto release_and_out;
  371. }
  372. } else
  373. acl = NULL;
  374. retry:
  375. handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb));
  376. if (IS_ERR(handle))
  377. return PTR_ERR(handle);
  378. error = ext3_set_acl(handle, inode, type, acl);
  379. ext3_journal_stop(handle);
  380. if (error == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries))
  381. goto retry;
  382. release_and_out:
  383. posix_acl_release(acl);
  384. return error;
  385. }
  386. const struct xattr_handler ext3_xattr_acl_access_handler = {
  387. .prefix = POSIX_ACL_XATTR_ACCESS,
  388. .flags = ACL_TYPE_ACCESS,
  389. .list = ext3_xattr_list_acl_access,
  390. .get = ext3_xattr_get_acl,
  391. .set = ext3_xattr_set_acl,
  392. };
  393. const struct xattr_handler ext3_xattr_acl_default_handler = {
  394. .prefix = POSIX_ACL_XATTR_DEFAULT,
  395. .flags = ACL_TYPE_DEFAULT,
  396. .list = ext3_xattr_list_acl_default,
  397. .get = ext3_xattr_get_acl,
  398. .set = ext3_xattr_set_acl,
  399. };