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