nfs4idmap.c 20.1 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
/*
 * fs/nfs/idmap.c
 *
 *  UID and GID to name mapping for clients.
 *
 *  Copyright (c) 2002 The Regents of the University of Michigan.
 *  All rights reserved.
 *
 *  Marius Aamodt Eriksen <marius@umich.edu>
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. Neither the name of the University nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
36
#include <linux/types.h>
37 38 39 40
#include <linux/parser.h>
#include <linux/fs.h>
#include <net/net_namespace.h>
#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 45 46
#include <linux/keyctl.h>
#include <linux/key-type.h>
#include <keys/user-type.h>
47
#include <keys/request_key_auth-type.h>
48
#include <linux/module.h>
49
#include <linux/user_namespace.h>
50

51
#include "internal.h"
52
#include "netns.h"
53
#include "nfs4idmap.h"
54
#include "nfs4trace.h"
55 56 57

#define NFS_UINT_MAXLEN 11

58 59
static const struct cred *id_resolver_cache;
static struct key_type key_type_id_resolver_legacy;
60

61 62 63
struct idmap_legacy_upcalldata {
	struct rpc_pipe_msg pipe_msg;
	struct idmap_msg idmap_msg;
64
	struct key	*authkey;
65 66 67
	struct idmap *idmap;
};

68
struct idmap {
69
	struct rpc_pipe_dir_object idmap_pdo;
70 71 72
	struct rpc_pipe		*idmap_pipe;
	struct idmap_legacy_upcalldata *idmap_upcall_data;
	struct mutex		idmap_mutex;
73
	struct user_namespace	*user_ns;
74 75
};

76 77
static struct user_namespace *idmap_userns(const struct idmap *idmap)
{
78 79
	if (idmap && idmap->user_ns)
		return idmap->user_ns;
80 81 82
	return &init_user_ns;
}

83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
/**
 * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields
 * @fattr: fully initialised struct nfs_fattr
 * @owner_name: owner name string cache
 * @group_name: group name string cache
 */
void nfs_fattr_init_names(struct nfs_fattr *fattr,
		struct nfs4_string *owner_name,
		struct nfs4_string *group_name)
{
	fattr->owner_name = owner_name;
	fattr->group_name = group_name;
}

static void nfs_fattr_free_owner_name(struct nfs_fattr *fattr)
{
	fattr->valid &= ~NFS_ATTR_FATTR_OWNER_NAME;
	kfree(fattr->owner_name->data);
}

static void nfs_fattr_free_group_name(struct nfs_fattr *fattr)
{
	fattr->valid &= ~NFS_ATTR_FATTR_GROUP_NAME;
	kfree(fattr->group_name->data);
}

static bool nfs_fattr_map_owner_name(struct nfs_server *server, struct nfs_fattr *fattr)
{
	struct nfs4_string *owner = fattr->owner_name;
112
	kuid_t uid;
113 114 115 116 117 118 119 120 121 122 123 124 125

	if (!(fattr->valid & NFS_ATTR_FATTR_OWNER_NAME))
		return false;
	if (nfs_map_name_to_uid(server, owner->data, owner->len, &uid) == 0) {
		fattr->uid = uid;
		fattr->valid |= NFS_ATTR_FATTR_OWNER;
	}
	return true;
}

static bool nfs_fattr_map_group_name(struct nfs_server *server, struct nfs_fattr *fattr)
{
	struct nfs4_string *group = fattr->group_name;
126
	kgid_t gid;
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163

	if (!(fattr->valid & NFS_ATTR_FATTR_GROUP_NAME))
		return false;
	if (nfs_map_group_to_gid(server, group->data, group->len, &gid) == 0) {
		fattr->gid = gid;
		fattr->valid |= NFS_ATTR_FATTR_GROUP;
	}
	return true;
}

/**
 * nfs_fattr_free_names - free up the NFSv4 owner and group strings
 * @fattr: a fully initialised nfs_fattr structure
 */
void nfs_fattr_free_names(struct nfs_fattr *fattr)
{
	if (fattr->valid & NFS_ATTR_FATTR_OWNER_NAME)
		nfs_fattr_free_owner_name(fattr);
	if (fattr->valid & NFS_ATTR_FATTR_GROUP_NAME)
		nfs_fattr_free_group_name(fattr);
}

/**
 * nfs_fattr_map_and_free_names - map owner/group strings into uid/gid and free
 * @server: pointer to the filesystem nfs_server structure
 * @fattr: a fully initialised nfs_fattr structure
 *
 * This helper maps the cached NFSv4 owner/group strings in fattr into
 * their numeric uid/gid equivalents, and then frees the cached strings.
 */
void nfs_fattr_map_and_free_names(struct nfs_server *server, struct nfs_fattr *fattr)
{
	if (nfs_fattr_map_owner_name(server, fattr))
		nfs_fattr_free_owner_name(fattr);
	if (nfs_fattr_map_group_name(server, fattr))
		nfs_fattr_free_group_name(fattr);
}
164

165
int nfs_map_string_to_numeric(const char *name, size_t namelen, __u32 *res)
166 167 168 169 170 171 172 173
{
	unsigned long val;
	char buf[16];

	if (memchr(name, '@', namelen) != NULL || namelen >= sizeof(buf))
		return 0;
	memcpy(buf, name, namelen);
	buf[namelen] = '\0';
174
	if (kstrtoul(buf, 0, &val) != 0)
175 176 177 178
		return 0;
	*res = val;
	return 1;
}
179
EXPORT_SYMBOL_GPL(nfs_map_string_to_numeric);
L
Linus Torvalds 已提交
180

181 182 183 184 185
static int nfs_map_numeric_to_string(__u32 id, char *buf, size_t buflen)
{
	return snprintf(buf, buflen, "%u", id);
}

186
static struct key_type key_type_id_resolver = {
B
Bryan Schumaker 已提交
187
	.name		= "id_resolver",
D
David Howells 已提交
188 189 190
	.preparse	= user_preparse,
	.free_preparse	= user_free_preparse,
	.instantiate	= generic_key_instantiate,
B
Bryan Schumaker 已提交
191 192 193 194 195 196
	.revoke		= user_revoke,
	.destroy	= user_destroy,
	.describe	= user_describe,
	.read		= user_read,
};

197
int nfs_idmap_init(void)
B
Bryan Schumaker 已提交
198 199 200 201 202
{
	struct cred *cred;
	struct key *keyring;
	int ret = 0;

203 204
	printk(KERN_NOTICE "NFS: Registering the %s key type\n",
		key_type_id_resolver.name);
B
Bryan Schumaker 已提交
205 206 207 208 209

	cred = prepare_kernel_cred(NULL);
	if (!cred)
		return -ENOMEM;

210 211
	keyring = keyring_alloc(".id_resolver",
				GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
212 213
				(KEY_POS_ALL & ~KEY_POS_SETATTR) |
				KEY_USR_VIEW | KEY_USR_READ,
214
				KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
B
Bryan Schumaker 已提交
215 216 217 218 219 220 221 222 223
	if (IS_ERR(keyring)) {
		ret = PTR_ERR(keyring);
		goto failed_put_cred;
	}

	ret = register_key_type(&key_type_id_resolver);
	if (ret < 0)
		goto failed_put_key;

224 225 226 227
	ret = register_key_type(&key_type_id_resolver_legacy);
	if (ret < 0)
		goto failed_reg_legacy;

228
	set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
B
Bryan Schumaker 已提交
229 230 231 232 233
	cred->thread_keyring = keyring;
	cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
	id_resolver_cache = cred;
	return 0;

234 235
failed_reg_legacy:
	unregister_key_type(&key_type_id_resolver);
B
Bryan Schumaker 已提交
236 237 238 239 240 241 242
failed_put_key:
	key_put(keyring);
failed_put_cred:
	put_cred(cred);
	return ret;
}

243
void nfs_idmap_quit(void)
B
Bryan Schumaker 已提交
244 245 246
{
	key_revoke(id_resolver_cache->thread_keyring);
	unregister_key_type(&key_type_id_resolver);
247
	unregister_key_type(&key_type_id_resolver_legacy);
B
Bryan Schumaker 已提交
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
	put_cred(id_resolver_cache);
}

/*
 * Assemble the description to pass to request_key()
 * This function will allocate a new string and update dest to point
 * at it.  The caller is responsible for freeing dest.
 *
 * On error 0 is returned.  Otherwise, the length of dest is returned.
 */
static ssize_t nfs_idmap_get_desc(const char *name, size_t namelen,
				const char *type, size_t typelen, char **desc)
{
	char *cp;
	size_t desclen = typelen + namelen + 2;

	*desc = kmalloc(desclen, GFP_KERNEL);
D
Dan Carpenter 已提交
265
	if (!*desc)
B
Bryan Schumaker 已提交
266 267 268 269 270 271 272 273 274 275 276 277 278
		return -ENOMEM;

	cp = *desc;
	memcpy(cp, type, typelen);
	cp += typelen;
	*cp++ = ':';

	memcpy(cp, name, namelen);
	cp += namelen;
	*cp = '\0';
	return desclen;
}

279 280
static struct key *nfs_idmap_request_key(const char *name, size_t namelen,
					 const char *type, struct idmap *idmap)
B
Bryan Schumaker 已提交
281 282
{
	char *desc;
283
	struct key *rkey = ERR_PTR(-EAGAIN);
B
Bryan Schumaker 已提交
284 285 286
	ssize_t ret;

	ret = nfs_idmap_get_desc(name, namelen, type, strlen(type), &desc);
287
	if (ret < 0)
288 289
		return ERR_PTR(ret);

290
	if (!idmap->user_ns || idmap->user_ns == &init_user_ns)
291
		rkey = request_key(&key_type_id_resolver, desc, "");
292 293 294
	if (IS_ERR(rkey)) {
		mutex_lock(&idmap->idmap_mutex);
		rkey = request_key_with_auxdata(&key_type_id_resolver_legacy,
295
						desc, NULL, "", 0, idmap);
296 297
		mutex_unlock(&idmap->idmap_mutex);
	}
298 299
	if (!IS_ERR(rkey))
		set_bit(KEY_FLAG_ROOT_CAN_INVAL, &rkey->flags);
300 301 302 303 304 305 306 307 308 309 310

	kfree(desc);
	return rkey;
}

static ssize_t nfs_idmap_get_key(const char *name, size_t namelen,
				 const char *type, void *data,
				 size_t data_size, struct idmap *idmap)
{
	const struct cred *saved_cred;
	struct key *rkey;
311
	const struct user_key_payload *payload;
312
	ssize_t ret;
B
Bryan Schumaker 已提交
313 314

	saved_cred = override_creds(id_resolver_cache);
315
	rkey = nfs_idmap_request_key(name, namelen, type, idmap);
B
Bryan Schumaker 已提交
316
	revert_creds(saved_cred);
317

B
Bryan Schumaker 已提交
318 319 320 321 322 323
	if (IS_ERR(rkey)) {
		ret = PTR_ERR(rkey);
		goto out;
	}

	rcu_read_lock();
324 325
	rkey->perm |= KEY_USR_VIEW;

B
Bryan Schumaker 已提交
326 327 328 329
	ret = key_validate(rkey);
	if (ret < 0)
		goto out_up;

330
	payload = user_key_payload_rcu(rkey);
B
Bryan Schumaker 已提交
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
	if (IS_ERR_OR_NULL(payload)) {
		ret = PTR_ERR(payload);
		goto out_up;
	}

	ret = payload->datalen;
	if (ret > 0 && ret <= data_size)
		memcpy(data, payload->data, ret);
	else
		ret = -EINVAL;

out_up:
	rcu_read_unlock();
	key_put(rkey);
out:
	return ret;
}

/* ID -> Name */
350 351
static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf,
				     size_t buflen, struct idmap *idmap)
B
Bryan Schumaker 已提交
352 353 354 355 356
{
	char id_str[NFS_UINT_MAXLEN];
	int id_len;
	ssize_t ret;

357
	id_len = nfs_map_numeric_to_string(id, id_str, sizeof(id_str));
358
	ret = nfs_idmap_get_key(id_str, id_len, type, buf, buflen, idmap);
B
Bryan Schumaker 已提交
359 360 361 362 363 364
	if (ret < 0)
		return -EINVAL;
	return ret;
}

/* Name -> ID */
365 366
static int nfs_idmap_lookup_id(const char *name, size_t namelen, const char *type,
			       __u32 *id, struct idmap *idmap)
B
Bryan Schumaker 已提交
367 368 369 370 371 372
{
	char id_str[NFS_UINT_MAXLEN];
	long id_long;
	ssize_t data_size;
	int ret = 0;

373
	data_size = nfs_idmap_get_key(name, namelen, type, id_str, NFS_UINT_MAXLEN, idmap);
B
Bryan Schumaker 已提交
374 375 376
	if (data_size <= 0) {
		ret = -EINVAL;
	} else {
377
		ret = kstrtol(id_str, 10, &id_long);
378 379
		if (!ret)
			*id = (__u32)id_long;
B
Bryan Schumaker 已提交
380 381 382 383
	}
	return ret;
}

384
/* idmap classic begins here */
385

386 387
enum {
	Opt_find_uid, Opt_find_gid, Opt_find_user, Opt_find_group, Opt_find_err
L
Linus Torvalds 已提交
388 389
};

390 391 392 393 394 395
static const match_table_t nfs_idmap_tokens = {
	{ Opt_find_uid, "uid:%s" },
	{ Opt_find_gid, "gid:%s" },
	{ Opt_find_user, "user:%s" },
	{ Opt_find_group, "group:%s" },
	{ Opt_find_err, NULL }
L
Linus Torvalds 已提交
396 397
};

398
static int nfs_idmap_legacy_upcall(struct key *, void *);
C
Chuck Lever 已提交
399 400
static ssize_t idmap_pipe_downcall(struct file *, const char __user *,
				   size_t);
401
static void idmap_release_pipe(struct inode *);
C
Chuck Lever 已提交
402
static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *);
L
Linus Torvalds 已提交
403

404
static const struct rpc_pipe_ops idmap_upcall_ops = {
405
	.upcall		= rpc_pipe_generic_upcall,
C
Chuck Lever 已提交
406
	.downcall	= idmap_pipe_downcall,
407
	.release_pipe	= idmap_release_pipe,
C
Chuck Lever 已提交
408
	.destroy_msg	= idmap_pipe_destroy_msg,
L
Linus Torvalds 已提交
409 410
};

411
static struct key_type key_type_id_resolver_legacy = {
412
	.name		= "id_legacy",
D
David Howells 已提交
413 414 415
	.preparse	= user_preparse,
	.free_preparse	= user_free_preparse,
	.instantiate	= generic_key_instantiate,
416 417 418 419 420 421 422
	.revoke		= user_revoke,
	.destroy	= user_destroy,
	.describe	= user_describe,
	.read		= user_read,
	.request_key	= nfs_idmap_legacy_upcall,
};

423 424
static void nfs_idmap_pipe_destroy(struct dentry *dir,
		struct rpc_pipe_dir_object *pdo)
425
{
426 427 428
	struct idmap *idmap = pdo->pdo_data;
	struct rpc_pipe *pipe = idmap->idmap_pipe;

429
	if (pipe->dentry) {
430
		rpc_unlink(pipe->dentry);
431 432
		pipe->dentry = NULL;
	}
433 434
}

435 436
static int nfs_idmap_pipe_create(struct dentry *dir,
		struct rpc_pipe_dir_object *pdo)
437
{
438 439
	struct idmap *idmap = pdo->pdo_data;
	struct rpc_pipe *pipe = idmap->idmap_pipe;
440 441 442 443 444 445 446 447 448
	struct dentry *dentry;

	dentry = rpc_mkpipe_dentry(dir, "idmap", idmap, pipe);
	if (IS_ERR(dentry))
		return PTR_ERR(dentry);
	pipe->dentry = dentry;
	return 0;
}

449 450 451 452
static const struct rpc_pipe_dir_object_ops nfs_idmap_pipe_dir_object_ops = {
	.create = nfs_idmap_pipe_create,
	.destroy = nfs_idmap_pipe_destroy,
};
453

454
int
455
nfs_idmap_new(struct nfs_client *clp)
L
Linus Torvalds 已提交
456 457
{
	struct idmap *idmap;
458
	struct rpc_pipe *pipe;
459
	int error;
L
Linus Torvalds 已提交
460

C
Chuck Lever 已提交
461 462 463
	idmap = kzalloc(sizeof(*idmap), GFP_KERNEL);
	if (idmap == NULL)
		return -ENOMEM;
L
Linus Torvalds 已提交
464

465
	mutex_init(&idmap->idmap_mutex);
466
	idmap->user_ns = get_user_ns(clp->cl_rpcclient->cl_cred->user_ns);
467

468 469 470 471
	rpc_init_pipe_dir_object(&idmap->idmap_pdo,
			&nfs_idmap_pipe_dir_object_ops,
			idmap);

472 473 474
	pipe = rpc_mkpipe_data(&idmap_upcall_ops, 0);
	if (IS_ERR(pipe)) {
		error = PTR_ERR(pipe);
475
		goto err;
476 477
	}
	idmap->idmap_pipe = pipe;
L
Linus Torvalds 已提交
478

479 480 481 482 483 484
	error = rpc_add_pipe_dir_object(clp->cl_net,
			&clp->cl_rpcclient->cl_pipedir_objects,
			&idmap->idmap_pdo);
	if (error)
		goto err_destroy_pipe;

L
Linus Torvalds 已提交
485
	clp->cl_idmap = idmap;
486
	return 0;
487 488 489
err_destroy_pipe:
	rpc_destroy_pipe_data(idmap->idmap_pipe);
err:
A
Alexey Gladkov 已提交
490
	put_user_ns(idmap->user_ns);
491 492
	kfree(idmap);
	return error;
L
Linus Torvalds 已提交
493 494 495
}

void
496
nfs_idmap_delete(struct nfs_client *clp)
L
Linus Torvalds 已提交
497 498 499 500 501 502
{
	struct idmap *idmap = clp->cl_idmap;

	if (!idmap)
		return;
	clp->cl_idmap = NULL;
503 504 505 506
	rpc_remove_pipe_dir_object(clp->cl_net,
			&clp->cl_rpcclient->cl_pipedir_objects,
			&idmap->idmap_pdo);
	rpc_destroy_pipe_data(idmap->idmap_pipe);
507
	put_user_ns(idmap->user_ns);
L
Linus Torvalds 已提交
508 509 510
	kfree(idmap);
}

511 512
static int nfs_idmap_prepare_message(char *desc, struct idmap *idmap,
				     struct idmap_msg *im,
513
				     struct rpc_pipe_msg *msg)
L
Linus Torvalds 已提交
514
{
515 516
	substring_t substr;
	int token, ret;
L
Linus Torvalds 已提交
517

518 519
	im->im_type = IDMAP_TYPE_GROUP;
	token = match_token(desc, nfs_idmap_tokens, &substr);
L
Linus Torvalds 已提交
520

521 522 523
	switch (token) {
	case Opt_find_uid:
		im->im_type = IDMAP_TYPE_USER;
524
		fallthrough;
525 526 527 528
	case Opt_find_gid:
		im->im_conv = IDMAP_CONV_NAMETOID;
		ret = match_strlcpy(im->im_name, &substr, IDMAP_NAMESZ);
		break;
L
Linus Torvalds 已提交
529

530 531
	case Opt_find_user:
		im->im_type = IDMAP_TYPE_USER;
532
		fallthrough;
533 534 535
	case Opt_find_group:
		im->im_conv = IDMAP_CONV_IDTONAME;
		ret = match_int(&substr, &im->im_id);
536 537
		if (ret)
			goto out;
538
		break;
L
Linus Torvalds 已提交
539

540 541
	default:
		ret = -EINVAL;
L
Linus Torvalds 已提交
542 543 544
		goto out;
	}

545 546
	msg->data = im;
	msg->len  = sizeof(struct idmap_msg);
L
Linus Torvalds 已提交
547

548
out:
C
Chuck Lever 已提交
549
	return ret;
L
Linus Torvalds 已提交
550 551
}

552 553
static bool
nfs_idmap_prepare_pipe_upcall(struct idmap *idmap,
554
		struct idmap_legacy_upcalldata *data)
555
{
556
	if (idmap->idmap_upcall_data != NULL) {
557 558 559
		WARN_ON_ONCE(1);
		return false;
	}
560
	idmap->idmap_upcall_data = data;
561 562 563
	return true;
}

564 565
static void nfs_idmap_complete_pipe_upcall(struct idmap_legacy_upcalldata *data,
					   int ret)
566
{
567 568 569
	complete_request_key(data->authkey, ret);
	key_put(data->authkey);
	kfree(data);
570 571
}

572 573 574
static void nfs_idmap_abort_pipe_upcall(struct idmap *idmap,
					struct idmap_legacy_upcalldata *data,
					int ret)
575
{
576 577
	if (cmpxchg(&idmap->idmap_upcall_data, data, NULL) == data)
		nfs_idmap_complete_pipe_upcall(data, ret);
578 579
}

580
static int nfs_idmap_legacy_upcall(struct key *authkey, void *aux)
L
Linus Torvalds 已提交
581
{
582
	struct idmap_legacy_upcalldata *data;
583
	struct request_key_auth *rka = get_request_key_auth(authkey);
584
	struct rpc_pipe_msg *msg;
L
Linus Torvalds 已提交
585
	struct idmap_msg *im;
586
	struct idmap *idmap = (struct idmap *)aux;
587
	struct key *key = rka->target_key;
588 589 590 591
	int ret = -ENOKEY;

	if (!aux)
		goto out1;
L
Linus Torvalds 已提交
592

593
	/* msg and im are freed in idmap_pipe_destroy_msg */
594
	ret = -ENOMEM;
595
	data = kzalloc(sizeof(*data), GFP_KERNEL);
596
	if (!data)
597
		goto out1;
L
Linus Torvalds 已提交
598

599 600 601
	msg = &data->pipe_msg;
	im = &data->idmap_msg;
	data->idmap = idmap;
602
	data->authkey = key_get(authkey);
603 604

	ret = nfs_idmap_prepare_message(key->description, idmap, im, msg);
605 606
	if (ret < 0)
		goto out2;
L
Linus Torvalds 已提交
607

608
	ret = -EAGAIN;
609
	if (!nfs_idmap_prepare_pipe_upcall(idmap, data))
610
		goto out2;
L
Linus Torvalds 已提交
611

612 613
	ret = rpc_queue_upcall(idmap->idmap_pipe, msg);
	if (ret < 0)
614
		nfs_idmap_abort_pipe_upcall(idmap, data, ret);
L
Linus Torvalds 已提交
615

616
	return ret;
617
out2:
618
	kfree(data);
619
out1:
620
	complete_request_key(authkey, ret);
C
Chuck Lever 已提交
621
	return ret;
L
Linus Torvalds 已提交
622 623
}

624
static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data, size_t datalen)
L
Linus Torvalds 已提交
625
{
626
	return key_instantiate_and_link(key, data, datalen,
627 628 629
					id_resolver_cache->thread_keyring,
					authkey);
}
L
Linus Torvalds 已提交
630

631 632 633
static int nfs_idmap_read_and_verify_message(struct idmap_msg *im,
		struct idmap_msg *upcall,
		struct key *key, struct key *authkey)
634 635
{
	char id_str[NFS_UINT_MAXLEN];
636
	size_t len;
637
	int ret = -ENOKEY;
L
Linus Torvalds 已提交
638

639 640 641
	/* ret = -ENOKEY */
	if (upcall->im_type != im->im_type || upcall->im_conv != im->im_conv)
		goto out;
642 643
	switch (im->im_conv) {
	case IDMAP_CONV_NAMETOID:
644 645
		if (strcmp(upcall->im_name, im->im_name) != 0)
			break;
646
		/* Note: here we store the NUL terminator too */
647 648
		len = 1 + nfs_map_numeric_to_string(im->im_id, id_str,
						    sizeof(id_str));
649
		ret = nfs_idmap_instantiate(key, authkey, id_str, len);
650 651
		break;
	case IDMAP_CONV_IDTONAME:
652 653
		if (upcall->im_id != im->im_id)
			break;
654 655
		len = strlen(im->im_name);
		ret = nfs_idmap_instantiate(key, authkey, im->im_name, len);
656
		break;
657 658
	default:
		ret = -EINVAL;
L
Linus Torvalds 已提交
659
	}
660
out:
L
Linus Torvalds 已提交
661 662 663 664 665 666
	return ret;
}

static ssize_t
idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
{
667
	struct request_key_auth *rka;
A
Al Viro 已提交
668
	struct rpc_inode *rpci = RPC_I(file_inode(filp));
L
Linus Torvalds 已提交
669
	struct idmap *idmap = (struct idmap *)rpci->private;
670
	struct idmap_legacy_upcalldata *data;
671
	struct key *authkey;
672
	struct idmap_msg im;
673
	size_t namelen_in;
674
	int ret = -ENOKEY;
L
Linus Torvalds 已提交
675

676 677 678 679
	/* If instantiation is successful, anyone waiting for key construction
	 * will have been woken up and someone else may now have used
	 * idmap_key_cons - so after this point we may no longer touch it.
	 */
680 681
	data = xchg(&idmap->idmap_upcall_data, NULL);
	if (data == NULL)
682
		goto out_noupcall;
683

684
	authkey = data->authkey;
685
	rka = get_request_key_auth(authkey);
686

687 688
	if (mlen != sizeof(im)) {
		ret = -ENOSPC;
L
Linus Torvalds 已提交
689 690 691
		goto out;
	}

692 693
	if (copy_from_user(&im, src, mlen) != 0) {
		ret = -EFAULT;
L
Linus Torvalds 已提交
694
		goto out;
695
	}
L
Linus Torvalds 已提交
696

697
	if (!(im.im_status & IDMAP_STATUS_SUCCESS)) {
698 699
		ret = -ENOKEY;
		goto out;
L
Linus Torvalds 已提交
700 701
	}

702 703 704
	namelen_in = strnlen(im.im_name, IDMAP_NAMESZ);
	if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ) {
		ret = -EINVAL;
L
Linus Torvalds 已提交
705
		goto out;
706
	}
L
Linus Torvalds 已提交
707

708 709
	ret = nfs_idmap_read_and_verify_message(&im, &data->idmap_msg,
						rka->target_key, authkey);
710
	if (ret >= 0) {
711
		key_set_timeout(rka->target_key, nfs_idmap_cache_timeout);
712 713 714
		ret = mlen;
	}

L
Linus Torvalds 已提交
715
out:
716
	nfs_idmap_complete_pipe_upcall(data, ret);
717
out_noupcall:
L
Linus Torvalds 已提交
718 719 720
	return ret;
}

A
Adrian Bunk 已提交
721
static void
L
Linus Torvalds 已提交
722 723
idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg)
{
724 725 726 727
	struct idmap_legacy_upcalldata *data = container_of(msg,
			struct idmap_legacy_upcalldata,
			pipe_msg);
	struct idmap *idmap = data->idmap;
728 729

	if (msg->errno)
730
		nfs_idmap_abort_pipe_upcall(idmap, data, msg->errno);
731 732 733 734 735 736 737
}

static void
idmap_release_pipe(struct inode *inode)
{
	struct rpc_inode *rpci = RPC_I(inode);
	struct idmap *idmap = (struct idmap *)rpci->private;
738
	struct idmap_legacy_upcalldata *data;
739

740 741 742
	data = xchg(&idmap->idmap_upcall_data, NULL);
	if (data)
		nfs_idmap_complete_pipe_upcall(data, -EPIPE);
L
Linus Torvalds 已提交
743 744
}

745
int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, kuid_t *uid)
L
Linus Torvalds 已提交
746
{
747
	struct idmap *idmap = server->nfs_client->cl_idmap;
748 749
	__u32 id = -1;
	int ret = 0;
L
Linus Torvalds 已提交
750

751 752 753
	if (!nfs_map_string_to_numeric(name, namelen, &id))
		ret = nfs_idmap_lookup_id(name, namelen, "uid", &id, idmap);
	if (ret == 0) {
754
		*uid = make_kuid(idmap_userns(idmap), id);
755 756 757
		if (!uid_valid(*uid))
			ret = -ERANGE;
	}
758
	trace_nfs4_map_name_to_uid(name, namelen, id, ret);
759
	return ret;
L
Linus Torvalds 已提交
760 761
}

762
int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, kgid_t *gid)
L
Linus Torvalds 已提交
763
{
764
	struct idmap *idmap = server->nfs_client->cl_idmap;
765 766
	__u32 id = -1;
	int ret = 0;
L
Linus Torvalds 已提交
767

768 769 770
	if (!nfs_map_string_to_numeric(name, namelen, &id))
		ret = nfs_idmap_lookup_id(name, namelen, "gid", &id, idmap);
	if (ret == 0) {
771
		*gid = make_kgid(idmap_userns(idmap), id);
772 773 774
		if (!gid_valid(*gid))
			ret = -ERANGE;
	}
775
	trace_nfs4_map_group_to_gid(name, namelen, id, ret);
776
	return ret;
L
Linus Torvalds 已提交
777 778
}

779
int nfs_map_uid_to_name(const struct nfs_server *server, kuid_t uid, char *buf, size_t buflen)
L
Linus Torvalds 已提交
780
{
781
	struct idmap *idmap = server->nfs_client->cl_idmap;
782
	int ret = -EINVAL;
783
	__u32 id;
L
Linus Torvalds 已提交
784

785
	id = from_kuid_munged(idmap_userns(idmap), uid);
786
	if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
787
		ret = nfs_idmap_lookup_name(id, "user", buf, buflen, idmap);
788
	if (ret < 0)
789
		ret = nfs_map_numeric_to_string(id, buf, buflen);
790
	trace_nfs4_map_uid_to_name(buf, ret, id, ret);
791
	return ret;
L
Linus Torvalds 已提交
792
}
793
int nfs_map_gid_to_group(const struct nfs_server *server, kgid_t gid, char *buf, size_t buflen)
L
Linus Torvalds 已提交
794
{
795
	struct idmap *idmap = server->nfs_client->cl_idmap;
796
	int ret = -EINVAL;
797
	__u32 id;
L
Linus Torvalds 已提交
798

799
	id = from_kgid_munged(idmap_userns(idmap), gid);
800
	if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
801
		ret = nfs_idmap_lookup_name(id, "group", buf, buflen, idmap);
802
	if (ret < 0)
803
		ret = nfs_map_numeric_to_string(id, buf, buflen);
804
	trace_nfs4_map_gid_to_group(buf, ret, id, ret);
805
	return ret;
L
Linus Torvalds 已提交
806
}