diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /fs/nfs/idmap.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'fs/nfs/idmap.c')
-rw-r--r-- | fs/nfs/idmap.c | 283 |
1 files changed, 272 insertions, 11 deletions
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 21a84d45916f..79664a1025af 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
@@ -33,11 +33,257 @@ | |||
33 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 33 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
34 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 34 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
35 | */ | 35 | */ |
36 | #include <linux/types.h> | ||
37 | #include <linux/string.h> | ||
38 | #include <linux/kernel.h> | ||
39 | |||
40 | static int nfs_map_string_to_numeric(const char *name, size_t namelen, __u32 *res) | ||
41 | { | ||
42 | unsigned long val; | ||
43 | char buf[16]; | ||
44 | |||
45 | if (memchr(name, '@', namelen) != NULL || namelen >= sizeof(buf)) | ||
46 | return 0; | ||
47 | memcpy(buf, name, namelen); | ||
48 | buf[namelen] = '\0'; | ||
49 | if (strict_strtoul(buf, 0, &val) != 0) | ||
50 | return 0; | ||
51 | *res = val; | ||
52 | return 1; | ||
53 | } | ||
54 | |||
55 | static int nfs_map_numeric_to_string(__u32 id, char *buf, size_t buflen) | ||
56 | { | ||
57 | return snprintf(buf, buflen, "%u", id); | ||
58 | } | ||
59 | |||
60 | #ifdef CONFIG_NFS_USE_NEW_IDMAPPER | ||
61 | |||
62 | #include <linux/slab.h> | ||
63 | #include <linux/cred.h> | ||
64 | #include <linux/sunrpc/sched.h> | ||
65 | #include <linux/nfs4.h> | ||
66 | #include <linux/nfs_fs_sb.h> | ||
67 | #include <linux/nfs_idmap.h> | ||
68 | #include <linux/keyctl.h> | ||
69 | #include <linux/key-type.h> | ||
70 | #include <linux/rcupdate.h> | ||
71 | #include <linux/err.h> | ||
72 | |||
73 | #include <keys/user-type.h> | ||
74 | |||
75 | #define NFS_UINT_MAXLEN 11 | ||
76 | |||
77 | const struct cred *id_resolver_cache; | ||
78 | |||
79 | struct key_type key_type_id_resolver = { | ||
80 | .name = "id_resolver", | ||
81 | .instantiate = user_instantiate, | ||
82 | .match = user_match, | ||
83 | .revoke = user_revoke, | ||
84 | .destroy = user_destroy, | ||
85 | .describe = user_describe, | ||
86 | .read = user_read, | ||
87 | }; | ||
88 | |||
89 | int nfs_idmap_init(void) | ||
90 | { | ||
91 | struct cred *cred; | ||
92 | struct key *keyring; | ||
93 | int ret = 0; | ||
94 | |||
95 | printk(KERN_NOTICE "Registering the %s key type\n", key_type_id_resolver.name); | ||
96 | |||
97 | cred = prepare_kernel_cred(NULL); | ||
98 | if (!cred) | ||
99 | return -ENOMEM; | ||
100 | |||
101 | keyring = key_alloc(&key_type_keyring, ".id_resolver", 0, 0, cred, | ||
102 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | | ||
103 | KEY_USR_VIEW | KEY_USR_READ, | ||
104 | KEY_ALLOC_NOT_IN_QUOTA); | ||
105 | if (IS_ERR(keyring)) { | ||
106 | ret = PTR_ERR(keyring); | ||
107 | goto failed_put_cred; | ||
108 | } | ||
109 | |||
110 | ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL); | ||
111 | if (ret < 0) | ||
112 | goto failed_put_key; | ||
113 | |||
114 | ret = register_key_type(&key_type_id_resolver); | ||
115 | if (ret < 0) | ||
116 | goto failed_put_key; | ||
117 | |||
118 | cred->thread_keyring = keyring; | ||
119 | cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; | ||
120 | id_resolver_cache = cred; | ||
121 | return 0; | ||
122 | |||
123 | failed_put_key: | ||
124 | key_put(keyring); | ||
125 | failed_put_cred: | ||
126 | put_cred(cred); | ||
127 | return ret; | ||
128 | } | ||
129 | |||
130 | void nfs_idmap_quit(void) | ||
131 | { | ||
132 | key_revoke(id_resolver_cache->thread_keyring); | ||
133 | unregister_key_type(&key_type_id_resolver); | ||
134 | put_cred(id_resolver_cache); | ||
135 | } | ||
136 | |||
137 | /* | ||
138 | * Assemble the description to pass to request_key() | ||
139 | * This function will allocate a new string and update dest to point | ||
140 | * at it. The caller is responsible for freeing dest. | ||
141 | * | ||
142 | * On error 0 is returned. Otherwise, the length of dest is returned. | ||
143 | */ | ||
144 | static ssize_t nfs_idmap_get_desc(const char *name, size_t namelen, | ||
145 | const char *type, size_t typelen, char **desc) | ||
146 | { | ||
147 | char *cp; | ||
148 | size_t desclen = typelen + namelen + 2; | ||
149 | |||
150 | *desc = kmalloc(desclen, GFP_KERNEL); | ||
151 | if (!*desc) | ||
152 | return -ENOMEM; | ||
153 | |||
154 | cp = *desc; | ||
155 | memcpy(cp, type, typelen); | ||
156 | cp += typelen; | ||
157 | *cp++ = ':'; | ||
158 | |||
159 | memcpy(cp, name, namelen); | ||
160 | cp += namelen; | ||
161 | *cp = '\0'; | ||
162 | return desclen; | ||
163 | } | ||
164 | |||
165 | static ssize_t nfs_idmap_request_key(const char *name, size_t namelen, | ||
166 | const char *type, void *data, size_t data_size) | ||
167 | { | ||
168 | const struct cred *saved_cred; | ||
169 | struct key *rkey; | ||
170 | char *desc; | ||
171 | struct user_key_payload *payload; | ||
172 | ssize_t ret; | ||
173 | |||
174 | ret = nfs_idmap_get_desc(name, namelen, type, strlen(type), &desc); | ||
175 | if (ret <= 0) | ||
176 | goto out; | ||
177 | |||
178 | saved_cred = override_creds(id_resolver_cache); | ||
179 | rkey = request_key(&key_type_id_resolver, desc, ""); | ||
180 | revert_creds(saved_cred); | ||
181 | kfree(desc); | ||
182 | if (IS_ERR(rkey)) { | ||
183 | ret = PTR_ERR(rkey); | ||
184 | goto out; | ||
185 | } | ||
186 | |||
187 | rcu_read_lock(); | ||
188 | rkey->perm |= KEY_USR_VIEW; | ||
189 | |||
190 | ret = key_validate(rkey); | ||
191 | if (ret < 0) | ||
192 | goto out_up; | ||
193 | |||
194 | payload = rcu_dereference(rkey->payload.data); | ||
195 | if (IS_ERR_OR_NULL(payload)) { | ||
196 | ret = PTR_ERR(payload); | ||
197 | goto out_up; | ||
198 | } | ||
199 | |||
200 | ret = payload->datalen; | ||
201 | if (ret > 0 && ret <= data_size) | ||
202 | memcpy(data, payload->data, ret); | ||
203 | else | ||
204 | ret = -EINVAL; | ||
205 | |||
206 | out_up: | ||
207 | rcu_read_unlock(); | ||
208 | key_put(rkey); | ||
209 | out: | ||
210 | return ret; | ||
211 | } | ||
212 | |||
213 | |||
214 | /* ID -> Name */ | ||
215 | static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf, size_t buflen) | ||
216 | { | ||
217 | char id_str[NFS_UINT_MAXLEN]; | ||
218 | int id_len; | ||
219 | ssize_t ret; | ||
220 | |||
221 | id_len = snprintf(id_str, sizeof(id_str), "%u", id); | ||
222 | ret = nfs_idmap_request_key(id_str, id_len, type, buf, buflen); | ||
223 | if (ret < 0) | ||
224 | return -EINVAL; | ||
225 | return ret; | ||
226 | } | ||
227 | |||
228 | /* Name -> ID */ | ||
229 | static int nfs_idmap_lookup_id(const char *name, size_t namelen, | ||
230 | const char *type, __u32 *id) | ||
231 | { | ||
232 | char id_str[NFS_UINT_MAXLEN]; | ||
233 | long id_long; | ||
234 | ssize_t data_size; | ||
235 | int ret = 0; | ||
236 | |||
237 | data_size = nfs_idmap_request_key(name, namelen, type, id_str, NFS_UINT_MAXLEN); | ||
238 | if (data_size <= 0) { | ||
239 | ret = -EINVAL; | ||
240 | } else { | ||
241 | ret = strict_strtol(id_str, 10, &id_long); | ||
242 | *id = (__u32)id_long; | ||
243 | } | ||
244 | return ret; | ||
245 | } | ||
246 | |||
247 | int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) | ||
248 | { | ||
249 | if (nfs_map_string_to_numeric(name, namelen, uid)) | ||
250 | return 0; | ||
251 | return nfs_idmap_lookup_id(name, namelen, "uid", uid); | ||
252 | } | ||
253 | |||
254 | int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *gid) | ||
255 | { | ||
256 | if (nfs_map_string_to_numeric(name, namelen, gid)) | ||
257 | return 0; | ||
258 | return nfs_idmap_lookup_id(name, namelen, "gid", gid); | ||
259 | } | ||
260 | |||
261 | int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen) | ||
262 | { | ||
263 | int ret = -EINVAL; | ||
264 | |||
265 | if (!(server->caps & NFS_CAP_UIDGID_NOMAP)) | ||
266 | ret = nfs_idmap_lookup_name(uid, "user", buf, buflen); | ||
267 | if (ret < 0) | ||
268 | ret = nfs_map_numeric_to_string(uid, buf, buflen); | ||
269 | return ret; | ||
270 | } | ||
271 | int nfs_map_gid_to_group(const struct nfs_server *server, __u32 gid, char *buf, size_t buflen) | ||
272 | { | ||
273 | int ret = -EINVAL; | ||
274 | |||
275 | if (!(server->caps & NFS_CAP_UIDGID_NOMAP)) | ||
276 | ret = nfs_idmap_lookup_name(gid, "group", buf, buflen); | ||
277 | if (ret < 0) | ||
278 | ret = nfs_map_numeric_to_string(gid, buf, buflen); | ||
279 | return ret; | ||
280 | } | ||
281 | |||
282 | #else /* CONFIG_NFS_USE_NEW_IDMAPPER not defined */ | ||
36 | 283 | ||
37 | #include <linux/module.h> | 284 | #include <linux/module.h> |
38 | #include <linux/mutex.h> | 285 | #include <linux/mutex.h> |
39 | #include <linux/init.h> | 286 | #include <linux/init.h> |
40 | #include <linux/types.h> | ||
41 | #include <linux/slab.h> | 287 | #include <linux/slab.h> |
42 | #include <linux/socket.h> | 288 | #include <linux/socket.h> |
43 | #include <linux/in.h> | 289 | #include <linux/in.h> |
@@ -489,30 +735,45 @@ static unsigned int fnvhash32(const void *buf, size_t buflen) | |||
489 | return hash; | 735 | return hash; |
490 | } | 736 | } |
491 | 737 | ||
492 | int nfs_map_name_to_uid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid) | 738 | int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) |
493 | { | 739 | { |
494 | struct idmap *idmap = clp->cl_idmap; | 740 | struct idmap *idmap = server->nfs_client->cl_idmap; |
495 | 741 | ||
742 | if (nfs_map_string_to_numeric(name, namelen, uid)) | ||
743 | return 0; | ||
496 | return nfs_idmap_id(idmap, &idmap->idmap_user_hash, name, namelen, uid); | 744 | return nfs_idmap_id(idmap, &idmap->idmap_user_hash, name, namelen, uid); |
497 | } | 745 | } |
498 | 746 | ||
499 | int nfs_map_group_to_gid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid) | 747 | int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) |
500 | { | 748 | { |
501 | struct idmap *idmap = clp->cl_idmap; | 749 | struct idmap *idmap = server->nfs_client->cl_idmap; |
502 | 750 | ||
751 | if (nfs_map_string_to_numeric(name, namelen, uid)) | ||
752 | return 0; | ||
503 | return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid); | 753 | return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid); |
504 | } | 754 | } |
505 | 755 | ||
506 | int nfs_map_uid_to_name(struct nfs_client *clp, __u32 uid, char *buf) | 756 | int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen) |
507 | { | 757 | { |
508 | struct idmap *idmap = clp->cl_idmap; | 758 | struct idmap *idmap = server->nfs_client->cl_idmap; |
759 | int ret = -EINVAL; | ||
509 | 760 | ||
510 | return nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf); | 761 | if (!(server->caps & NFS_CAP_UIDGID_NOMAP)) |
762 | ret = nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf); | ||
763 | if (ret < 0) | ||
764 | ret = nfs_map_numeric_to_string(uid, buf, buflen); | ||
765 | return ret; | ||
511 | } | 766 | } |
512 | int nfs_map_gid_to_group(struct nfs_client *clp, __u32 uid, char *buf) | 767 | int nfs_map_gid_to_group(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen) |
513 | { | 768 | { |
514 | struct idmap *idmap = clp->cl_idmap; | 769 | struct idmap *idmap = server->nfs_client->cl_idmap; |
770 | int ret = -EINVAL; | ||
515 | 771 | ||
516 | return nfs_idmap_name(idmap, &idmap->idmap_group_hash, uid, buf); | 772 | if (!(server->caps & NFS_CAP_UIDGID_NOMAP)) |
773 | ret = nfs_idmap_name(idmap, &idmap->idmap_group_hash, uid, buf); | ||
774 | if (ret < 0) | ||
775 | ret = nfs_map_numeric_to_string(uid, buf, buflen); | ||
776 | return ret; | ||
517 | } | 777 | } |
518 | 778 | ||
779 | #endif /* CONFIG_NFS_USE_NEW_IDMAPPER */ | ||