generic_acl.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /*
  2. * fs/generic_acl.c
  3. *
  4. * (C) 2005 Andreas Gruenbacher <agruen@suse.de>
  5. *
  6. * This file is released under the GPL.
  7. */
  8. #include <linux/sched.h>
  9. #include <linux/fs.h>
  10. #include <linux/generic_acl.h>
  11. /**
  12. * generic_acl_list - Generic xattr_handler->list() operation
  13. * @ops: Filesystem specific getacl and setacl callbacks
  14. */
  15. size_t
  16. generic_acl_list(struct inode *inode, struct generic_acl_operations *ops,
  17. int type, char *list, size_t list_size)
  18. {
  19. struct posix_acl *acl;
  20. const char *name;
  21. size_t size;
  22. acl = ops->getacl(inode, type);
  23. if (!acl)
  24. return 0;
  25. posix_acl_release(acl);
  26. switch(type) {
  27. case ACL_TYPE_ACCESS:
  28. name = POSIX_ACL_XATTR_ACCESS;
  29. break;
  30. case ACL_TYPE_DEFAULT:
  31. name = POSIX_ACL_XATTR_DEFAULT;
  32. break;
  33. default:
  34. return 0;
  35. }
  36. size = strlen(name) + 1;
  37. if (list && size <= list_size)
  38. memcpy(list, name, size);
  39. return size;
  40. }
  41. /**
  42. * generic_acl_get - Generic xattr_handler->get() operation
  43. * @ops: Filesystem specific getacl and setacl callbacks
  44. */
  45. int
  46. generic_acl_get(struct inode *inode, struct generic_acl_operations *ops,
  47. int type, void *buffer, size_t size)
  48. {
  49. struct posix_acl *acl;
  50. int error;
  51. acl = ops->getacl(inode, type);
  52. if (!acl)
  53. return -ENODATA;
  54. error = posix_acl_to_xattr(acl, buffer, size);
  55. posix_acl_release(acl);
  56. return error;
  57. }
  58. /**
  59. * generic_acl_set - Generic xattr_handler->set() operation
  60. * @ops: Filesystem specific getacl and setacl callbacks
  61. */
  62. int
  63. generic_acl_set(struct inode *inode, struct generic_acl_operations *ops,
  64. int type, const void *value, size_t size)
  65. {
  66. struct posix_acl *acl = NULL;
  67. int error;
  68. if (S_ISLNK(inode->i_mode))
  69. return -EOPNOTSUPP;
  70. if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER))
  71. return -EPERM;
  72. if (value) {
  73. acl = posix_acl_from_xattr(value, size);
  74. if (IS_ERR(acl))
  75. return PTR_ERR(acl);
  76. }
  77. if (acl) {
  78. mode_t mode;
  79. error = posix_acl_valid(acl);
  80. if (error)
  81. goto failed;
  82. switch(type) {
  83. case ACL_TYPE_ACCESS:
  84. mode = inode->i_mode;
  85. error = posix_acl_equiv_mode(acl, &mode);
  86. if (error < 0)
  87. goto failed;
  88. inode->i_mode = mode;
  89. if (error == 0) {
  90. posix_acl_release(acl);
  91. acl = NULL;
  92. }
  93. break;
  94. case ACL_TYPE_DEFAULT:
  95. if (!S_ISDIR(inode->i_mode)) {
  96. error = -EINVAL;
  97. goto failed;
  98. }
  99. break;
  100. }
  101. }
  102. ops->setacl(inode, type, acl);
  103. error = 0;
  104. failed:
  105. posix_acl_release(acl);
  106. return error;
  107. }
  108. /**
  109. * generic_acl_init - Take care of acl inheritance at @inode create time
  110. * @ops: Filesystem specific getacl and setacl callbacks
  111. *
  112. * Files created inside a directory with a default ACL inherit the
  113. * directory's default ACL.
  114. */
  115. int
  116. generic_acl_init(struct inode *inode, struct inode *dir,
  117. struct generic_acl_operations *ops)
  118. {
  119. struct posix_acl *acl = NULL;
  120. mode_t mode = inode->i_mode;
  121. int error;
  122. inode->i_mode = mode & ~current->fs->umask;
  123. if (!S_ISLNK(inode->i_mode))
  124. acl = ops->getacl(dir, ACL_TYPE_DEFAULT);
  125. if (acl) {
  126. struct posix_acl *clone;
  127. if (S_ISDIR(inode->i_mode)) {
  128. clone = posix_acl_clone(acl, GFP_KERNEL);
  129. error = -ENOMEM;
  130. if (!clone)
  131. goto cleanup;
  132. ops->setacl(inode, ACL_TYPE_DEFAULT, clone);
  133. posix_acl_release(clone);
  134. }
  135. clone = posix_acl_clone(acl, GFP_KERNEL);
  136. error = -ENOMEM;
  137. if (!clone)
  138. goto cleanup;
  139. error = posix_acl_create_masq(clone, &mode);
  140. if (error >= 0) {
  141. inode->i_mode = mode;
  142. if (error > 0)
  143. ops->setacl(inode, ACL_TYPE_ACCESS, clone);
  144. }
  145. posix_acl_release(clone);
  146. }
  147. error = 0;
  148. cleanup:
  149. posix_acl_release(acl);
  150. return error;
  151. }
  152. /**
  153. * generic_acl_chmod - change the access acl of @inode upon chmod()
  154. * @ops: FIlesystem specific getacl and setacl callbacks
  155. *
  156. * A chmod also changes the permissions of the owner, group/mask, and
  157. * other ACL entries.
  158. */
  159. int
  160. generic_acl_chmod(struct inode *inode, struct generic_acl_operations *ops)
  161. {
  162. struct posix_acl *acl, *clone;
  163. int error = 0;
  164. if (S_ISLNK(inode->i_mode))
  165. return -EOPNOTSUPP;
  166. acl = ops->getacl(inode, ACL_TYPE_ACCESS);
  167. if (acl) {
  168. clone = posix_acl_clone(acl, GFP_KERNEL);
  169. posix_acl_release(acl);
  170. if (!clone)
  171. return -ENOMEM;
  172. error = posix_acl_chmod_masq(clone, inode->i_mode);
  173. if (!error)
  174. ops->setacl(inode, ACL_TYPE_ACCESS, clone);
  175. posix_acl_release(clone);
  176. }
  177. return error;
  178. }