acl.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. /*
  2. * linux/fs/ext2/acl.c
  3. *
  4. * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
  5. */
  6. #include <linux/init.h>
  7. #include <linux/sched.h>
  8. #include <linux/slab.h>
  9. #include <linux/fs.h>
  10. #include "ext2.h"
  11. #include "xattr.h"
  12. #include "acl.h"
  13. /*
  14. * Convert from filesystem to in-memory representation.
  15. */
  16. static struct posix_acl *
  17. ext2_acl_from_disk(const void *value, size_t size)
  18. {
  19. const char *end = (char *)value + size;
  20. int n, count;
  21. struct posix_acl *acl;
  22. if (!value)
  23. return NULL;
  24. if (size < sizeof(ext2_acl_header))
  25. return ERR_PTR(-EINVAL);
  26. if (((ext2_acl_header *)value)->a_version !=
  27. cpu_to_le32(EXT2_ACL_VERSION))
  28. return ERR_PTR(-EINVAL);
  29. value = (char *)value + sizeof(ext2_acl_header);
  30. count = ext2_acl_count(size);
  31. if (count < 0)
  32. return ERR_PTR(-EINVAL);
  33. if (count == 0)
  34. return NULL;
  35. acl = posix_acl_alloc(count, GFP_KERNEL);
  36. if (!acl)
  37. return ERR_PTR(-ENOMEM);
  38. for (n=0; n < count; n++) {
  39. ext2_acl_entry *entry =
  40. (ext2_acl_entry *)value;
  41. if ((char *)value + sizeof(ext2_acl_entry_short) > end)
  42. goto fail;
  43. acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag);
  44. acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
  45. switch(acl->a_entries[n].e_tag) {
  46. case ACL_USER_OBJ:
  47. case ACL_GROUP_OBJ:
  48. case ACL_MASK:
  49. case ACL_OTHER:
  50. value = (char *)value +
  51. sizeof(ext2_acl_entry_short);
  52. break;
  53. case ACL_USER:
  54. value = (char *)value + sizeof(ext2_acl_entry);
  55. if ((char *)value > end)
  56. goto fail;
  57. acl->a_entries[n].e_uid =
  58. make_kuid(&init_user_ns,
  59. le32_to_cpu(entry->e_id));
  60. break;
  61. case ACL_GROUP:
  62. value = (char *)value + sizeof(ext2_acl_entry);
  63. if ((char *)value > end)
  64. goto fail;
  65. acl->a_entries[n].e_gid =
  66. make_kgid(&init_user_ns,
  67. le32_to_cpu(entry->e_id));
  68. break;
  69. default:
  70. goto fail;
  71. }
  72. }
  73. if (value != end)
  74. goto fail;
  75. return acl;
  76. fail:
  77. posix_acl_release(acl);
  78. return ERR_PTR(-EINVAL);
  79. }
  80. /*
  81. * Convert from in-memory to filesystem representation.
  82. */
  83. static void *
  84. ext2_acl_to_disk(const struct posix_acl *acl, size_t *size)
  85. {
  86. ext2_acl_header *ext_acl;
  87. char *e;
  88. size_t n;
  89. *size = ext2_acl_size(acl->a_count);
  90. ext_acl = kmalloc(sizeof(ext2_acl_header) + acl->a_count *
  91. sizeof(ext2_acl_entry), GFP_KERNEL);
  92. if (!ext_acl)
  93. return ERR_PTR(-ENOMEM);
  94. ext_acl->a_version = cpu_to_le32(EXT2_ACL_VERSION);
  95. e = (char *)ext_acl + sizeof(ext2_acl_header);
  96. for (n=0; n < acl->a_count; n++) {
  97. const struct posix_acl_entry *acl_e = &acl->a_entries[n];
  98. ext2_acl_entry *entry = (ext2_acl_entry *)e;
  99. entry->e_tag = cpu_to_le16(acl_e->e_tag);
  100. entry->e_perm = cpu_to_le16(acl_e->e_perm);
  101. switch(acl_e->e_tag) {
  102. case ACL_USER:
  103. entry->e_id = cpu_to_le32(
  104. from_kuid(&init_user_ns, acl_e->e_uid));
  105. e += sizeof(ext2_acl_entry);
  106. break;
  107. case ACL_GROUP:
  108. entry->e_id = cpu_to_le32(
  109. from_kgid(&init_user_ns, acl_e->e_gid));
  110. e += sizeof(ext2_acl_entry);
  111. break;
  112. case ACL_USER_OBJ:
  113. case ACL_GROUP_OBJ:
  114. case ACL_MASK:
  115. case ACL_OTHER:
  116. e += sizeof(ext2_acl_entry_short);
  117. break;
  118. default:
  119. goto fail;
  120. }
  121. }
  122. return (char *)ext_acl;
  123. fail:
  124. kfree(ext_acl);
  125. return ERR_PTR(-EINVAL);
  126. }
  127. /*
  128. * inode->i_mutex: don't care
  129. */
  130. struct posix_acl *
  131. ext2_get_acl(struct inode *inode, int type)
  132. {
  133. int name_index;
  134. char *value = NULL;
  135. struct posix_acl *acl;
  136. int retval;
  137. switch (type) {
  138. case ACL_TYPE_ACCESS:
  139. name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
  140. break;
  141. case ACL_TYPE_DEFAULT:
  142. name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT;
  143. break;
  144. default:
  145. BUG();
  146. }
  147. retval = ext2_xattr_get(inode, name_index, "", NULL, 0);
  148. if (retval > 0) {
  149. value = kmalloc(retval, GFP_KERNEL);
  150. if (!value)
  151. return ERR_PTR(-ENOMEM);
  152. retval = ext2_xattr_get(inode, name_index, "", value, retval);
  153. }
  154. if (retval > 0)
  155. acl = ext2_acl_from_disk(value, retval);
  156. else if (retval == -ENODATA || retval == -ENOSYS)
  157. acl = NULL;
  158. else
  159. acl = ERR_PTR(retval);
  160. kfree(value);
  161. if (!IS_ERR(acl))
  162. set_cached_acl(inode, type, acl);
  163. return acl;
  164. }
  165. static int
  166. __ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
  167. {
  168. int name_index;
  169. void *value = NULL;
  170. size_t size = 0;
  171. int error;
  172. switch(type) {
  173. case ACL_TYPE_ACCESS:
  174. name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
  175. break;
  176. case ACL_TYPE_DEFAULT:
  177. name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT;
  178. if (!S_ISDIR(inode->i_mode))
  179. return acl ? -EACCES : 0;
  180. break;
  181. default:
  182. return -EINVAL;
  183. }
  184. if (acl) {
  185. value = ext2_acl_to_disk(acl, &size);
  186. if (IS_ERR(value))
  187. return (int)PTR_ERR(value);
  188. }
  189. error = ext2_xattr_set(inode, name_index, "", value, size, 0);
  190. kfree(value);
  191. if (!error)
  192. set_cached_acl(inode, type, acl);
  193. return error;
  194. }
  195. /*
  196. * inode->i_mutex: down
  197. */
  198. int
  199. ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
  200. {
  201. int error;
  202. if (type == ACL_TYPE_ACCESS && acl) {
  203. error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
  204. if (error)
  205. return error;
  206. inode->i_ctime = CURRENT_TIME_SEC;
  207. mark_inode_dirty(inode);
  208. }
  209. return __ext2_set_acl(inode, acl, type);
  210. }
  211. /*
  212. * Initialize the ACLs of a new inode. Called from ext2_new_inode.
  213. *
  214. * dir->i_mutex: down
  215. * inode->i_mutex: up (access to inode is still exclusive)
  216. */
  217. int
  218. ext2_init_acl(struct inode *inode, struct inode *dir)
  219. {
  220. struct posix_acl *default_acl, *acl;
  221. int error;
  222. error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
  223. if (error)
  224. return error;
  225. if (default_acl) {
  226. error = __ext2_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
  227. posix_acl_release(default_acl);
  228. }
  229. if (acl) {
  230. if (!error)
  231. error = __ext2_set_acl(inode, acl, ACL_TYPE_ACCESS);
  232. posix_acl_release(acl);
  233. }
  234. return error;
  235. }