Branch data Line data Source code
1 : : /*
2 : : * fs/nfs/idmap.c
3 : : *
4 : : * UID and GID to name mapping for clients.
5 : : *
6 : : * Copyright (c) 2002 The Regents of the University of Michigan.
7 : : * All rights reserved.
8 : : *
9 : : * Marius Aamodt Eriksen <marius@umich.edu>
10 : : *
11 : : * Redistribution and use in source and binary forms, with or without
12 : : * modification, are permitted provided that the following conditions
13 : : * are met:
14 : : *
15 : : * 1. Redistributions of source code must retain the above copyright
16 : : * notice, this list of conditions and the following disclaimer.
17 : : * 2. Redistributions in binary form must reproduce the above copyright
18 : : * notice, this list of conditions and the following disclaimer in the
19 : : * documentation and/or other materials provided with the distribution.
20 : : * 3. Neither the name of the University nor the names of its
21 : : * contributors may be used to endorse or promote products derived
22 : : * from this software without specific prior written permission.
23 : : *
24 : : * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
25 : : * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 : : * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 : : * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 : : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 : : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 : : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
31 : : * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 : : * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
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.
35 : : */
36 : : #include <linux/types.h>
37 : : #include <linux/parser.h>
38 : : #include <linux/fs.h>
39 : : #include <net/net_namespace.h>
40 : : #include <linux/sunrpc/rpc_pipe_fs.h>
41 : : #include <linux/nfs_fs.h>
42 : : #include <linux/nfs_fs_sb.h>
43 : : #include <linux/key.h>
44 : : #include <linux/keyctl.h>
45 : : #include <linux/key-type.h>
46 : : #include <keys/user-type.h>
47 : : #include <keys/request_key_auth-type.h>
48 : : #include <linux/module.h>
49 : :
50 : : #include "internal.h"
51 : : #include "netns.h"
52 : : #include "nfs4idmap.h"
53 : : #include "nfs4trace.h"
54 : :
55 : : #define NFS_UINT_MAXLEN 11
56 : :
57 : : static const struct cred *id_resolver_cache;
58 : : static struct key_type key_type_id_resolver_legacy;
59 : :
60 : : struct idmap_legacy_upcalldata {
61 : : struct rpc_pipe_msg pipe_msg;
62 : : struct idmap_msg idmap_msg;
63 : : struct key *authkey;
64 : : struct idmap *idmap;
65 : : };
66 : :
67 : : struct idmap {
68 : : struct rpc_pipe_dir_object idmap_pdo;
69 : : struct rpc_pipe *idmap_pipe;
70 : : struct idmap_legacy_upcalldata *idmap_upcall_data;
71 : : struct mutex idmap_mutex;
72 : : const struct cred *cred;
73 : : };
74 : :
75 : : static struct user_namespace *idmap_userns(const struct idmap *idmap)
76 : : {
77 [ # # # # : 0 : if (idmap && idmap->cred)
# # # # #
# # # # #
# # ]
78 : 0 : return idmap->cred->user_ns;
79 : : return &init_user_ns;
80 : : }
81 : :
82 : : /**
83 : : * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields
84 : : * @fattr: fully initialised struct nfs_fattr
85 : : * @owner_name: owner name string cache
86 : : * @group_name: group name string cache
87 : : */
88 : 0 : void nfs_fattr_init_names(struct nfs_fattr *fattr,
89 : : struct nfs4_string *owner_name,
90 : : struct nfs4_string *group_name)
91 : : {
92 : 0 : fattr->owner_name = owner_name;
93 : 0 : fattr->group_name = group_name;
94 : 0 : }
95 : :
96 : : static void nfs_fattr_free_owner_name(struct nfs_fattr *fattr)
97 : : {
98 : 0 : fattr->valid &= ~NFS_ATTR_FATTR_OWNER_NAME;
99 : 0 : kfree(fattr->owner_name->data);
100 : : }
101 : :
102 : : static void nfs_fattr_free_group_name(struct nfs_fattr *fattr)
103 : : {
104 : 0 : fattr->valid &= ~NFS_ATTR_FATTR_GROUP_NAME;
105 : 0 : kfree(fattr->group_name->data);
106 : : }
107 : :
108 : 0 : static bool nfs_fattr_map_owner_name(struct nfs_server *server, struct nfs_fattr *fattr)
109 : : {
110 : 0 : struct nfs4_string *owner = fattr->owner_name;
111 : : kuid_t uid;
112 : :
113 [ # # ]: 0 : if (!(fattr->valid & NFS_ATTR_FATTR_OWNER_NAME))
114 : : return false;
115 [ # # ]: 0 : if (nfs_map_name_to_uid(server, owner->data, owner->len, &uid) == 0) {
116 : 0 : fattr->uid = uid;
117 : 0 : fattr->valid |= NFS_ATTR_FATTR_OWNER;
118 : : }
119 : : return true;
120 : : }
121 : :
122 : 0 : static bool nfs_fattr_map_group_name(struct nfs_server *server, struct nfs_fattr *fattr)
123 : : {
124 : 0 : struct nfs4_string *group = fattr->group_name;
125 : : kgid_t gid;
126 : :
127 [ # # ]: 0 : if (!(fattr->valid & NFS_ATTR_FATTR_GROUP_NAME))
128 : : return false;
129 [ # # ]: 0 : if (nfs_map_group_to_gid(server, group->data, group->len, &gid) == 0) {
130 : 0 : fattr->gid = gid;
131 : 0 : fattr->valid |= NFS_ATTR_FATTR_GROUP;
132 : : }
133 : : return true;
134 : : }
135 : :
136 : : /**
137 : : * nfs_fattr_free_names - free up the NFSv4 owner and group strings
138 : : * @fattr: a fully initialised nfs_fattr structure
139 : : */
140 : 0 : void nfs_fattr_free_names(struct nfs_fattr *fattr)
141 : : {
142 [ # # ]: 0 : if (fattr->valid & NFS_ATTR_FATTR_OWNER_NAME)
143 : : nfs_fattr_free_owner_name(fattr);
144 [ # # ]: 0 : if (fattr->valid & NFS_ATTR_FATTR_GROUP_NAME)
145 : : nfs_fattr_free_group_name(fattr);
146 : 0 : }
147 : :
148 : : /**
149 : : * nfs_fattr_map_and_free_names - map owner/group strings into uid/gid and free
150 : : * @server: pointer to the filesystem nfs_server structure
151 : : * @fattr: a fully initialised nfs_fattr structure
152 : : *
153 : : * This helper maps the cached NFSv4 owner/group strings in fattr into
154 : : * their numeric uid/gid equivalents, and then frees the cached strings.
155 : : */
156 : 0 : void nfs_fattr_map_and_free_names(struct nfs_server *server, struct nfs_fattr *fattr)
157 : : {
158 [ # # ]: 0 : if (nfs_fattr_map_owner_name(server, fattr))
159 : : nfs_fattr_free_owner_name(fattr);
160 [ # # ]: 0 : if (nfs_fattr_map_group_name(server, fattr))
161 : : nfs_fattr_free_group_name(fattr);
162 : 0 : }
163 : :
164 : 0 : int nfs_map_string_to_numeric(const char *name, size_t namelen, __u32 *res)
165 : : {
166 : : unsigned long val;
167 : : char buf[16];
168 : :
169 [ # # # # ]: 0 : if (memchr(name, '@', namelen) != NULL || namelen >= sizeof(buf))
170 : : return 0;
171 : 0 : memcpy(buf, name, namelen);
172 : 0 : buf[namelen] = '\0';
173 [ # # ]: 0 : if (kstrtoul(buf, 0, &val) != 0)
174 : : return 0;
175 : 0 : *res = val;
176 : 0 : return 1;
177 : : }
178 : : EXPORT_SYMBOL_GPL(nfs_map_string_to_numeric);
179 : :
180 : : static int nfs_map_numeric_to_string(__u32 id, char *buf, size_t buflen)
181 : : {
182 : 0 : return snprintf(buf, buflen, "%u", id);
183 : : }
184 : :
185 : : static struct key_type key_type_id_resolver = {
186 : : .name = "id_resolver",
187 : : .preparse = user_preparse,
188 : : .free_preparse = user_free_preparse,
189 : : .instantiate = generic_key_instantiate,
190 : : .revoke = user_revoke,
191 : : .destroy = user_destroy,
192 : : .describe = user_describe,
193 : : .read = user_read,
194 : : };
195 : :
196 : 207 : int nfs_idmap_init(void)
197 : : {
198 : : struct cred *cred;
199 : : struct key *keyring;
200 : : int ret = 0;
201 : :
202 : 207 : printk(KERN_NOTICE "NFS: Registering the %s key type\n",
203 : : key_type_id_resolver.name);
204 : :
205 : 207 : cred = prepare_kernel_cred(NULL);
206 [ + - ]: 207 : if (!cred)
207 : : return -ENOMEM;
208 : :
209 : 207 : keyring = keyring_alloc(".id_resolver",
210 : 207 : GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
211 : : (KEY_POS_ALL & ~KEY_POS_SETATTR) |
212 : : KEY_USR_VIEW | KEY_USR_READ,
213 : : KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
214 [ - + ]: 207 : if (IS_ERR(keyring)) {
215 : : ret = PTR_ERR(keyring);
216 : 0 : goto failed_put_cred;
217 : : }
218 : :
219 : 207 : ret = register_key_type(&key_type_id_resolver);
220 [ + - ]: 207 : if (ret < 0)
221 : : goto failed_put_key;
222 : :
223 : 207 : ret = register_key_type(&key_type_id_resolver_legacy);
224 [ + - ]: 207 : if (ret < 0)
225 : : goto failed_reg_legacy;
226 : :
227 : 207 : set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
228 : 207 : cred->thread_keyring = keyring;
229 : 207 : cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
230 : 207 : id_resolver_cache = cred;
231 : 207 : return 0;
232 : :
233 : : failed_reg_legacy:
234 : 0 : unregister_key_type(&key_type_id_resolver);
235 : : failed_put_key:
236 : 0 : key_put(keyring);
237 : : failed_put_cred:
238 : 0 : put_cred(cred);
239 : 0 : return ret;
240 : : }
241 : :
242 : 0 : void nfs_idmap_quit(void)
243 : : {
244 : 0 : key_revoke(id_resolver_cache->thread_keyring);
245 : 0 : unregister_key_type(&key_type_id_resolver);
246 : 0 : unregister_key_type(&key_type_id_resolver_legacy);
247 : 0 : put_cred(id_resolver_cache);
248 : 0 : }
249 : :
250 : : /*
251 : : * Assemble the description to pass to request_key()
252 : : * This function will allocate a new string and update dest to point
253 : : * at it. The caller is responsible for freeing dest.
254 : : *
255 : : * On error 0 is returned. Otherwise, the length of dest is returned.
256 : : */
257 : 0 : static ssize_t nfs_idmap_get_desc(const char *name, size_t namelen,
258 : : const char *type, size_t typelen, char **desc)
259 : : {
260 : : char *cp;
261 : 0 : size_t desclen = typelen + namelen + 2;
262 : :
263 : 0 : *desc = kmalloc(desclen, GFP_KERNEL);
264 [ # # ]: 0 : if (!*desc)
265 : : return -ENOMEM;
266 : :
267 : : cp = *desc;
268 : 0 : memcpy(cp, type, typelen);
269 : 0 : cp += typelen;
270 : 0 : *cp++ = ':';
271 : :
272 : 0 : memcpy(cp, name, namelen);
273 : 0 : cp += namelen;
274 : 0 : *cp = '\0';
275 : 0 : return desclen;
276 : : }
277 : :
278 : 0 : static struct key *nfs_idmap_request_key(const char *name, size_t namelen,
279 : : const char *type, struct idmap *idmap)
280 : : {
281 : : char *desc;
282 : : struct key *rkey = ERR_PTR(-EAGAIN);
283 : : ssize_t ret;
284 : :
285 : 0 : ret = nfs_idmap_get_desc(name, namelen, type, strlen(type), &desc);
286 [ # # ]: 0 : if (ret < 0)
287 : 0 : return ERR_PTR(ret);
288 : :
289 [ # # # # ]: 0 : if (!idmap->cred || idmap->cred->user_ns == &init_user_ns)
290 : 0 : rkey = request_key(&key_type_id_resolver, desc, "");
291 [ # # ]: 0 : if (IS_ERR(rkey)) {
292 : 0 : mutex_lock(&idmap->idmap_mutex);
293 : 0 : rkey = request_key_with_auxdata(&key_type_id_resolver_legacy,
294 : : desc, NULL, "", 0, idmap);
295 : 0 : mutex_unlock(&idmap->idmap_mutex);
296 : : }
297 [ # # ]: 0 : if (!IS_ERR(rkey))
298 : 0 : set_bit(KEY_FLAG_ROOT_CAN_INVAL, &rkey->flags);
299 : :
300 : 0 : kfree(desc);
301 : 0 : return rkey;
302 : : }
303 : :
304 : 0 : static ssize_t nfs_idmap_get_key(const char *name, size_t namelen,
305 : : const char *type, void *data,
306 : : size_t data_size, struct idmap *idmap)
307 : : {
308 : : const struct cred *saved_cred;
309 : : struct key *rkey;
310 : : const struct user_key_payload *payload;
311 : : ssize_t ret;
312 : :
313 : 0 : saved_cred = override_creds(id_resolver_cache);
314 : 0 : rkey = nfs_idmap_request_key(name, namelen, type, idmap);
315 : 0 : revert_creds(saved_cred);
316 : :
317 [ # # ]: 0 : if (IS_ERR(rkey)) {
318 : : ret = PTR_ERR(rkey);
319 : 0 : goto out;
320 : : }
321 : :
322 : : rcu_read_lock();
323 : 0 : rkey->perm |= KEY_USR_VIEW;
324 : :
325 : 0 : ret = key_validate(rkey);
326 [ # # ]: 0 : if (ret < 0)
327 : : goto out_up;
328 : :
329 : : payload = user_key_payload_rcu(rkey);
330 [ # # ]: 0 : if (IS_ERR_OR_NULL(payload)) {
331 : : ret = PTR_ERR(payload);
332 : 0 : goto out_up;
333 : : }
334 : :
335 : 0 : ret = payload->datalen;
336 [ # # ]: 0 : if (ret > 0 && ret <= data_size)
337 : 0 : memcpy(data, payload->data, ret);
338 : : else
339 : : ret = -EINVAL;
340 : :
341 : : out_up:
342 : : rcu_read_unlock();
343 : 0 : key_put(rkey);
344 : : out:
345 : 0 : return ret;
346 : : }
347 : :
348 : : /* ID -> Name */
349 : 0 : static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf,
350 : : size_t buflen, struct idmap *idmap)
351 : : {
352 : : char id_str[NFS_UINT_MAXLEN];
353 : : int id_len;
354 : : ssize_t ret;
355 : :
356 : : id_len = nfs_map_numeric_to_string(id, id_str, sizeof(id_str));
357 : 0 : ret = nfs_idmap_get_key(id_str, id_len, type, buf, buflen, idmap);
358 [ # # ]: 0 : if (ret < 0)
359 : : return -EINVAL;
360 : 0 : return ret;
361 : : }
362 : :
363 : : /* Name -> ID */
364 : 0 : static int nfs_idmap_lookup_id(const char *name, size_t namelen, const char *type,
365 : : __u32 *id, struct idmap *idmap)
366 : : {
367 : : char id_str[NFS_UINT_MAXLEN];
368 : : long id_long;
369 : : ssize_t data_size;
370 : : int ret = 0;
371 : :
372 : 0 : data_size = nfs_idmap_get_key(name, namelen, type, id_str, NFS_UINT_MAXLEN, idmap);
373 [ # # ]: 0 : if (data_size <= 0) {
374 : : ret = -EINVAL;
375 : : } else {
376 : : ret = kstrtol(id_str, 10, &id_long);
377 [ # # ]: 0 : if (!ret)
378 : 0 : *id = (__u32)id_long;
379 : : }
380 : 0 : return ret;
381 : : }
382 : :
383 : : /* idmap classic begins here */
384 : :
385 : : enum {
386 : : Opt_find_uid, Opt_find_gid, Opt_find_user, Opt_find_group, Opt_find_err
387 : : };
388 : :
389 : : static const match_table_t nfs_idmap_tokens = {
390 : : { Opt_find_uid, "uid:%s" },
391 : : { Opt_find_gid, "gid:%s" },
392 : : { Opt_find_user, "user:%s" },
393 : : { Opt_find_group, "group:%s" },
394 : : { Opt_find_err, NULL }
395 : : };
396 : :
397 : : static int nfs_idmap_legacy_upcall(struct key *, void *);
398 : : static ssize_t idmap_pipe_downcall(struct file *, const char __user *,
399 : : size_t);
400 : : static void idmap_release_pipe(struct inode *);
401 : : static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *);
402 : :
403 : : static const struct rpc_pipe_ops idmap_upcall_ops = {
404 : : .upcall = rpc_pipe_generic_upcall,
405 : : .downcall = idmap_pipe_downcall,
406 : : .release_pipe = idmap_release_pipe,
407 : : .destroy_msg = idmap_pipe_destroy_msg,
408 : : };
409 : :
410 : : static struct key_type key_type_id_resolver_legacy = {
411 : : .name = "id_legacy",
412 : : .preparse = user_preparse,
413 : : .free_preparse = user_free_preparse,
414 : : .instantiate = generic_key_instantiate,
415 : : .revoke = user_revoke,
416 : : .destroy = user_destroy,
417 : : .describe = user_describe,
418 : : .read = user_read,
419 : : .request_key = nfs_idmap_legacy_upcall,
420 : : };
421 : :
422 : 0 : static void nfs_idmap_pipe_destroy(struct dentry *dir,
423 : : struct rpc_pipe_dir_object *pdo)
424 : : {
425 : 0 : struct idmap *idmap = pdo->pdo_data;
426 : 0 : struct rpc_pipe *pipe = idmap->idmap_pipe;
427 : :
428 [ # # ]: 0 : if (pipe->dentry) {
429 : 0 : rpc_unlink(pipe->dentry);
430 : 0 : pipe->dentry = NULL;
431 : : }
432 : 0 : }
433 : :
434 : 0 : static int nfs_idmap_pipe_create(struct dentry *dir,
435 : : struct rpc_pipe_dir_object *pdo)
436 : : {
437 : 0 : struct idmap *idmap = pdo->pdo_data;
438 : 0 : struct rpc_pipe *pipe = idmap->idmap_pipe;
439 : : struct dentry *dentry;
440 : :
441 : 0 : dentry = rpc_mkpipe_dentry(dir, "idmap", idmap, pipe);
442 [ # # ]: 0 : if (IS_ERR(dentry))
443 : 0 : return PTR_ERR(dentry);
444 : 0 : pipe->dentry = dentry;
445 : 0 : return 0;
446 : : }
447 : :
448 : : static const struct rpc_pipe_dir_object_ops nfs_idmap_pipe_dir_object_ops = {
449 : : .create = nfs_idmap_pipe_create,
450 : : .destroy = nfs_idmap_pipe_destroy,
451 : : };
452 : :
453 : : int
454 : 0 : nfs_idmap_new(struct nfs_client *clp)
455 : : {
456 : : struct idmap *idmap;
457 : : struct rpc_pipe *pipe;
458 : : int error;
459 : :
460 : 0 : idmap = kzalloc(sizeof(*idmap), GFP_KERNEL);
461 [ # # ]: 0 : if (idmap == NULL)
462 : : return -ENOMEM;
463 : :
464 : 0 : mutex_init(&idmap->idmap_mutex);
465 : 0 : idmap->cred = get_cred(clp->cl_rpcclient->cl_cred);
466 : :
467 : 0 : rpc_init_pipe_dir_object(&idmap->idmap_pdo,
468 : : &nfs_idmap_pipe_dir_object_ops,
469 : : idmap);
470 : :
471 : 0 : pipe = rpc_mkpipe_data(&idmap_upcall_ops, 0);
472 [ # # ]: 0 : if (IS_ERR(pipe)) {
473 : : error = PTR_ERR(pipe);
474 : 0 : goto err;
475 : : }
476 : 0 : idmap->idmap_pipe = pipe;
477 : :
478 : 0 : error = rpc_add_pipe_dir_object(clp->cl_net,
479 : 0 : &clp->cl_rpcclient->cl_pipedir_objects,
480 : : &idmap->idmap_pdo);
481 [ # # ]: 0 : if (error)
482 : : goto err_destroy_pipe;
483 : :
484 : 0 : clp->cl_idmap = idmap;
485 : 0 : return 0;
486 : : err_destroy_pipe:
487 : 0 : rpc_destroy_pipe_data(idmap->idmap_pipe);
488 : : err:
489 : 0 : put_cred(idmap->cred);
490 : 0 : kfree(idmap);
491 : 0 : return error;
492 : : }
493 : :
494 : : void
495 : 0 : nfs_idmap_delete(struct nfs_client *clp)
496 : : {
497 : 0 : struct idmap *idmap = clp->cl_idmap;
498 : :
499 [ # # ]: 0 : if (!idmap)
500 : 0 : return;
501 : 0 : clp->cl_idmap = NULL;
502 : 0 : rpc_remove_pipe_dir_object(clp->cl_net,
503 : 0 : &clp->cl_rpcclient->cl_pipedir_objects,
504 : : &idmap->idmap_pdo);
505 : 0 : rpc_destroy_pipe_data(idmap->idmap_pipe);
506 : 0 : put_cred(idmap->cred);
507 : 0 : kfree(idmap);
508 : : }
509 : :
510 : 0 : static int nfs_idmap_prepare_message(char *desc, struct idmap *idmap,
511 : : struct idmap_msg *im,
512 : : struct rpc_pipe_msg *msg)
513 : : {
514 : : substring_t substr;
515 : : int token, ret;
516 : :
517 : 0 : im->im_type = IDMAP_TYPE_GROUP;
518 : 0 : token = match_token(desc, nfs_idmap_tokens, &substr);
519 : :
520 [ # # # # : 0 : switch (token) {
# ]
521 : : case Opt_find_uid:
522 : 0 : im->im_type = IDMAP_TYPE_USER;
523 : : /* Fall through */
524 : : case Opt_find_gid:
525 : 0 : im->im_conv = IDMAP_CONV_NAMETOID;
526 : 0 : ret = match_strlcpy(im->im_name, &substr, IDMAP_NAMESZ);
527 : 0 : break;
528 : :
529 : : case Opt_find_user:
530 : 0 : im->im_type = IDMAP_TYPE_USER;
531 : : /* Fall through */
532 : : case Opt_find_group:
533 : 0 : im->im_conv = IDMAP_CONV_IDTONAME;
534 : 0 : ret = match_int(&substr, &im->im_id);
535 [ # # ]: 0 : if (ret)
536 : : goto out;
537 : : break;
538 : :
539 : : default:
540 : : ret = -EINVAL;
541 : : goto out;
542 : : }
543 : :
544 : 0 : msg->data = im;
545 : 0 : msg->len = sizeof(struct idmap_msg);
546 : :
547 : : out:
548 : 0 : return ret;
549 : : }
550 : :
551 : : static bool
552 : 0 : nfs_idmap_prepare_pipe_upcall(struct idmap *idmap,
553 : : struct idmap_legacy_upcalldata *data)
554 : : {
555 [ # # ]: 0 : if (idmap->idmap_upcall_data != NULL) {
556 [ # # ]: 0 : WARN_ON_ONCE(1);
557 : : return false;
558 : : }
559 : 0 : idmap->idmap_upcall_data = data;
560 : 0 : return true;
561 : : }
562 : :
563 : : static void
564 : 0 : nfs_idmap_complete_pipe_upcall_locked(struct idmap *idmap, int ret)
565 : : {
566 : 0 : struct key *authkey = idmap->idmap_upcall_data->authkey;
567 : :
568 : 0 : kfree(idmap->idmap_upcall_data);
569 : 0 : idmap->idmap_upcall_data = NULL;
570 : 0 : complete_request_key(authkey, ret);
571 : 0 : key_put(authkey);
572 : 0 : }
573 : :
574 : : static void
575 : : nfs_idmap_abort_pipe_upcall(struct idmap *idmap, int ret)
576 : : {
577 [ # # # # : 0 : if (idmap->idmap_upcall_data != NULL)
# # ]
578 : 0 : nfs_idmap_complete_pipe_upcall_locked(idmap, ret);
579 : : }
580 : :
581 : 0 : static int nfs_idmap_legacy_upcall(struct key *authkey, void *aux)
582 : : {
583 : : struct idmap_legacy_upcalldata *data;
584 : : struct request_key_auth *rka = get_request_key_auth(authkey);
585 : : struct rpc_pipe_msg *msg;
586 : : struct idmap_msg *im;
587 : : struct idmap *idmap = (struct idmap *)aux;
588 : 0 : struct key *key = rka->target_key;
589 : : int ret = -ENOKEY;
590 : :
591 [ # # ]: 0 : if (!aux)
592 : : goto out1;
593 : :
594 : : /* msg and im are freed in idmap_pipe_destroy_msg */
595 : : ret = -ENOMEM;
596 : 0 : data = kzalloc(sizeof(*data), GFP_KERNEL);
597 [ # # ]: 0 : if (!data)
598 : : goto out1;
599 : :
600 : 0 : msg = &data->pipe_msg;
601 : 0 : im = &data->idmap_msg;
602 : 0 : data->idmap = idmap;
603 : 0 : data->authkey = key_get(authkey);
604 : :
605 : 0 : ret = nfs_idmap_prepare_message(key->description, idmap, im, msg);
606 [ # # ]: 0 : if (ret < 0)
607 : : goto out2;
608 : :
609 : : ret = -EAGAIN;
610 [ # # ]: 0 : if (!nfs_idmap_prepare_pipe_upcall(idmap, data))
611 : : goto out2;
612 : :
613 : 0 : ret = rpc_queue_upcall(idmap->idmap_pipe, msg);
614 [ # # ]: 0 : if (ret < 0)
615 : : nfs_idmap_abort_pipe_upcall(idmap, ret);
616 : :
617 : 0 : return ret;
618 : : out2:
619 : 0 : kfree(data);
620 : : out1:
621 : 0 : complete_request_key(authkey, ret);
622 : 0 : return ret;
623 : : }
624 : :
625 : : static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data, size_t datalen)
626 : : {
627 : 0 : return key_instantiate_and_link(key, data, datalen,
628 : 0 : id_resolver_cache->thread_keyring,
629 : : authkey);
630 : : }
631 : :
632 : 0 : static int nfs_idmap_read_and_verify_message(struct idmap_msg *im,
633 : : struct idmap_msg *upcall,
634 : : struct key *key, struct key *authkey)
635 : : {
636 : : char id_str[NFS_UINT_MAXLEN];
637 : : size_t len;
638 : : int ret = -ENOKEY;
639 : :
640 : : /* ret = -ENOKEY */
641 [ # # ]: 0 : if (upcall->im_type != im->im_type || upcall->im_conv != im->im_conv)
642 : : goto out;
643 [ # # # ]: 0 : switch (im->im_conv) {
644 : : case IDMAP_CONV_NAMETOID:
645 [ # # ]: 0 : if (strcmp(upcall->im_name, im->im_name) != 0)
646 : : break;
647 : : /* Note: here we store the NUL terminator too */
648 : 0 : len = 1 + nfs_map_numeric_to_string(im->im_id, id_str,
649 : : sizeof(id_str));
650 : : ret = nfs_idmap_instantiate(key, authkey, id_str, len);
651 : 0 : break;
652 : : case IDMAP_CONV_IDTONAME:
653 [ # # ]: 0 : if (upcall->im_id != im->im_id)
654 : : break;
655 : 0 : len = strlen(im->im_name);
656 : : ret = nfs_idmap_instantiate(key, authkey, im->im_name, len);
657 : 0 : break;
658 : : default:
659 : : ret = -EINVAL;
660 : : }
661 : : out:
662 : 0 : return ret;
663 : : }
664 : :
665 : : static ssize_t
666 : 0 : idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
667 : : {
668 : : struct request_key_auth *rka;
669 : : struct rpc_inode *rpci = RPC_I(file_inode(filp));
670 : 0 : struct idmap *idmap = (struct idmap *)rpci->private;
671 : : struct key *authkey;
672 : : struct idmap_msg im;
673 : : size_t namelen_in;
674 : : int ret = -ENOKEY;
675 : :
676 : : /* If instantiation is successful, anyone waiting for key construction
677 : : * will have been woken up and someone else may now have used
678 : : * idmap_key_cons - so after this point we may no longer touch it.
679 : : */
680 [ # # ]: 0 : if (idmap->idmap_upcall_data == NULL)
681 : : goto out_noupcall;
682 : :
683 : 0 : authkey = idmap->idmap_upcall_data->authkey;
684 : : rka = get_request_key_auth(authkey);
685 : :
686 [ # # ]: 0 : if (mlen != sizeof(im)) {
687 : : ret = -ENOSPC;
688 : : goto out;
689 : : }
690 : :
691 [ # # ]: 0 : if (copy_from_user(&im, src, mlen) != 0) {
692 : : ret = -EFAULT;
693 : : goto out;
694 : : }
695 : :
696 [ # # ]: 0 : if (!(im.im_status & IDMAP_STATUS_SUCCESS)) {
697 : : ret = -ENOKEY;
698 : : goto out;
699 : : }
700 : :
701 : 0 : namelen_in = strnlen(im.im_name, IDMAP_NAMESZ);
702 [ # # ]: 0 : if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ) {
703 : : ret = -EINVAL;
704 : : goto out;
705 : : }
706 : :
707 : 0 : ret = nfs_idmap_read_and_verify_message(&im,
708 : 0 : &idmap->idmap_upcall_data->idmap_msg,
709 : : rka->target_key, authkey);
710 [ # # ]: 0 : if (ret >= 0) {
711 : 0 : key_set_timeout(rka->target_key, nfs_idmap_cache_timeout);
712 : 0 : ret = mlen;
713 : : }
714 : :
715 : : out:
716 : 0 : nfs_idmap_complete_pipe_upcall_locked(idmap, ret);
717 : : out_noupcall:
718 : 0 : return ret;
719 : : }
720 : :
721 : : static void
722 : 0 : idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg)
723 : : {
724 : : struct idmap_legacy_upcalldata *data = container_of(msg,
725 : : struct idmap_legacy_upcalldata,
726 : : pipe_msg);
727 : 0 : struct idmap *idmap = data->idmap;
728 : :
729 [ # # ]: 0 : if (msg->errno)
730 : : nfs_idmap_abort_pipe_upcall(idmap, msg->errno);
731 : 0 : }
732 : :
733 : : static void
734 : 0 : idmap_release_pipe(struct inode *inode)
735 : : {
736 : : struct rpc_inode *rpci = RPC_I(inode);
737 : 0 : struct idmap *idmap = (struct idmap *)rpci->private;
738 : :
739 : : nfs_idmap_abort_pipe_upcall(idmap, -EPIPE);
740 : 0 : }
741 : :
742 : 0 : int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, kuid_t *uid)
743 : : {
744 : 0 : struct idmap *idmap = server->nfs_client->cl_idmap;
745 : 0 : __u32 id = -1;
746 : : int ret = 0;
747 : :
748 [ # # ]: 0 : if (!nfs_map_string_to_numeric(name, namelen, &id))
749 : 0 : ret = nfs_idmap_lookup_id(name, namelen, "uid", &id, idmap);
750 [ # # ]: 0 : if (ret == 0) {
751 : 0 : *uid = make_kuid(idmap_userns(idmap), id);
752 [ # # ]: 0 : if (!uid_valid(*uid))
753 : : ret = -ERANGE;
754 : : }
755 : 0 : trace_nfs4_map_name_to_uid(name, namelen, id, ret);
756 : 0 : return ret;
757 : : }
758 : :
759 : 0 : int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, kgid_t *gid)
760 : : {
761 : 0 : struct idmap *idmap = server->nfs_client->cl_idmap;
762 : 0 : __u32 id = -1;
763 : : int ret = 0;
764 : :
765 [ # # ]: 0 : if (!nfs_map_string_to_numeric(name, namelen, &id))
766 : 0 : ret = nfs_idmap_lookup_id(name, namelen, "gid", &id, idmap);
767 [ # # ]: 0 : if (ret == 0) {
768 : 0 : *gid = make_kgid(idmap_userns(idmap), id);
769 [ # # ]: 0 : if (!gid_valid(*gid))
770 : : ret = -ERANGE;
771 : : }
772 : 0 : trace_nfs4_map_group_to_gid(name, namelen, id, ret);
773 : 0 : return ret;
774 : : }
775 : :
776 : 0 : int nfs_map_uid_to_name(const struct nfs_server *server, kuid_t uid, char *buf, size_t buflen)
777 : : {
778 : 0 : struct idmap *idmap = server->nfs_client->cl_idmap;
779 : : int ret = -EINVAL;
780 : : __u32 id;
781 : :
782 : 0 : id = from_kuid_munged(idmap_userns(idmap), uid);
783 [ # # ]: 0 : if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
784 : 0 : ret = nfs_idmap_lookup_name(id, "user", buf, buflen, idmap);
785 [ # # ]: 0 : if (ret < 0)
786 : : ret = nfs_map_numeric_to_string(id, buf, buflen);
787 : 0 : trace_nfs4_map_uid_to_name(buf, ret, id, ret);
788 : 0 : return ret;
789 : : }
790 : 0 : int nfs_map_gid_to_group(const struct nfs_server *server, kgid_t gid, char *buf, size_t buflen)
791 : : {
792 : 0 : struct idmap *idmap = server->nfs_client->cl_idmap;
793 : : int ret = -EINVAL;
794 : : __u32 id;
795 : :
796 : 0 : id = from_kgid_munged(idmap_userns(idmap), gid);
797 [ # # ]: 0 : if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
798 : 0 : ret = nfs_idmap_lookup_name(id, "group", buf, buflen, idmap);
799 [ # # ]: 0 : if (ret < 0)
800 : : ret = nfs_map_numeric_to_string(id, buf, buflen);
801 : 0 : trace_nfs4_map_gid_to_group(buf, ret, id, ret);
802 : 0 : return ret;
803 : : }
|