acl.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  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. return acl;
  162. }
  163. static int
  164. __ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
  165. {
  166. int name_index;
  167. void *value = NULL;
  168. size_t size = 0;
  169. int error;
  170. switch(type) {
  171. case ACL_TYPE_ACCESS:
  172. name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
  173. break;
  174. case ACL_TYPE_DEFAULT:
  175. name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT;
  176. if (!S_ISDIR(inode->i_mode))
  177. return acl ? -EACCES : 0;
  178. break;
  179. default:
  180. return -EINVAL;
  181. }
  182. if (acl) {
  183. value = ext2_acl_to_disk(acl, &size);
  184. if (IS_ERR(value))
  185. return (int)PTR_ERR(value);
  186. }
  187. error = ext2_xattr_set(inode, name_index, "", value, size, 0);
  188. kfree(value);
  189. if (!error)
  190. set_cached_acl(inode, type, acl);
  191. return error;
  192. }
  193. /*
  194. * inode->i_mutex: down
  195. */
  196. int
  197. ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
  198. {
  199. int error;
  200. if (type == ACL_TYPE_ACCESS && acl) {
  201. error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
  202. if (error)
  203. return error;
  204. inode->i_ctime = current_time(inode);
  205. mark_inode_dirty(inode);
  206. }
  207. return __ext2_set_acl(inode, acl, type);
  208. }
  209. /*
  210. * Initialize the ACLs of a new inode. Called from ext2_new_inode.
  211. *
  212. * dir->i_mutex: down
  213. * inode->i_mutex: up (access to inode is still exclusive)
  214. */
  215. int
  216. ext2_init_acl(struct inode *inode, struct inode *dir)
  217. {
  218. struct posix_acl *default_acl, *acl;
  219. int error;
  220. error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
  221. if (error)
  222. return error;
  223. if (default_acl) {
  224. error = __ext2_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
  225. posix_acl_release(default_acl);
  226. }
  227. if (acl) {
  228. if (!error)
  229. error = __ext2_set_acl(inode, acl, ACL_TYPE_ACCESS);
  230. posix_acl_release(acl);
  231. }
  232. return error;
  233. }