auth.c 17.1 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
 * linux/net/sunrpc/auth.c
 *
 * Generic RPC client authentication API.
 *
 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
 */

#include <linux/types.h>
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/errno.h>
14
#include <linux/hash.h>
L
Linus Torvalds 已提交
15
#include <linux/sunrpc/clnt.h>
C
Chuck Lever 已提交
16
#include <linux/sunrpc/gss_api.h>
L
Linus Torvalds 已提交
17 18 19 20 21 22
#include <linux/spinlock.h>

#ifdef RPC_DEBUG
# define RPCDBG_FACILITY	RPCDBG_AUTH
#endif

23 24 25 26 27 28 29 30 31
#define RPC_CREDCACHE_DEFAULT_HASHBITS	(4)
struct rpc_cred_cache {
	struct hlist_head	*hashtable;
	unsigned int		hashbits;
	spinlock_t		lock;
};

static unsigned int auth_hashbits = RPC_CREDCACHE_DEFAULT_HASHBITS;

32
static DEFINE_SPINLOCK(rpc_authflavor_lock);
33
static const struct rpc_authops *auth_flavors[RPC_AUTH_MAXFLAVOR] = {
L
Linus Torvalds 已提交
34 35 36 37 38
	&authnull_ops,		/* AUTH_NULL */
	&authunix_ops,		/* AUTH_UNIX */
	NULL,			/* others can be loadable modules */
};

39
static LIST_HEAD(cred_unused);
40
static unsigned long number_cred_unused;
41

42
#define MAX_HASHTABLE_BITS (14)
43
static int param_set_hashtbl_sz(const char *val, const struct kernel_param *kp)
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
{
	unsigned long num;
	unsigned int nbits;
	int ret;

	if (!val)
		goto out_inval;
	ret = strict_strtoul(val, 0, &num);
	if (ret == -EINVAL)
		goto out_inval;
	nbits = fls(num);
	if (num > (1U << nbits))
		nbits++;
	if (nbits > MAX_HASHTABLE_BITS || nbits < 2)
		goto out_inval;
	*(unsigned int *)kp->arg = nbits;
	return 0;
out_inval:
	return -EINVAL;
}

65
static int param_get_hashtbl_sz(char *buffer, const struct kernel_param *kp)
66 67 68 69 70 71 72 73 74
{
	unsigned int nbits;

	nbits = *(unsigned int *)kp->arg;
	return sprintf(buffer, "%u", 1U << nbits);
}

#define param_check_hashtbl_sz(name, p) __param_check(name, p, unsigned int);

75 76 77 78 79
static struct kernel_param_ops param_ops_hashtbl_sz = {
	.set = param_set_hashtbl_sz,
	.get = param_get_hashtbl_sz,
};

80 81 82
module_param_named(auth_hashtable_size, auth_hashbits, hashtbl_sz, 0644);
MODULE_PARM_DESC(auth_hashtable_size, "RPC credential cache hashtable size");

L
Linus Torvalds 已提交
83 84 85 86 87 88 89 90
static u32
pseudoflavor_to_flavor(u32 flavor) {
	if (flavor >= RPC_AUTH_MAXFLAVOR)
		return RPC_AUTH_GSS;
	return flavor;
}

int
91
rpcauth_register(const struct rpc_authops *ops)
L
Linus Torvalds 已提交
92 93
{
	rpc_authflavor_t flavor;
94
	int ret = -EPERM;
L
Linus Torvalds 已提交
95 96 97

	if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR)
		return -EINVAL;
98 99 100 101 102 103 104
	spin_lock(&rpc_authflavor_lock);
	if (auth_flavors[flavor] == NULL) {
		auth_flavors[flavor] = ops;
		ret = 0;
	}
	spin_unlock(&rpc_authflavor_lock);
	return ret;
L
Linus Torvalds 已提交
105
}
106
EXPORT_SYMBOL_GPL(rpcauth_register);
L
Linus Torvalds 已提交
107 108

int
109
rpcauth_unregister(const struct rpc_authops *ops)
L
Linus Torvalds 已提交
110 111
{
	rpc_authflavor_t flavor;
112
	int ret = -EPERM;
L
Linus Torvalds 已提交
113 114 115

	if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR)
		return -EINVAL;
116 117 118 119 120 121 122
	spin_lock(&rpc_authflavor_lock);
	if (auth_flavors[flavor] == ops) {
		auth_flavors[flavor] = NULL;
		ret = 0;
	}
	spin_unlock(&rpc_authflavor_lock);
	return ret;
L
Linus Torvalds 已提交
123
}
124
EXPORT_SYMBOL_GPL(rpcauth_unregister);
L
Linus Torvalds 已提交
125

C
Chuck Lever 已提交
126 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 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
/**
 * rpcauth_list_flavors - discover registered flavors and pseudoflavors
 * @array: array to fill in
 * @size: size of "array"
 *
 * Returns the number of array items filled in, or a negative errno.
 *
 * The returned array is not sorted by any policy.  Callers should not
 * rely on the order of the items in the returned array.
 */
int
rpcauth_list_flavors(rpc_authflavor_t *array, int size)
{
	rpc_authflavor_t flavor;
	int result = 0;

	spin_lock(&rpc_authflavor_lock);
	for (flavor = 0; flavor < RPC_AUTH_MAXFLAVOR; flavor++) {
		const struct rpc_authops *ops = auth_flavors[flavor];
		rpc_authflavor_t pseudos[4];
		int i, len;

		if (result >= size) {
			result = -ENOMEM;
			break;
		}

		if (ops == NULL)
			continue;
		if (ops->list_pseudoflavors == NULL) {
			array[result++] = ops->au_flavor;
			continue;
		}
		len = ops->list_pseudoflavors(pseudos, ARRAY_SIZE(pseudos));
		if (len < 0) {
			result = len;
			break;
		}
		for (i = 0; i < len; i++) {
			if (result >= size) {
				result = -ENOMEM;
				break;
			}
			array[result++] = pseudos[i];
		}
	}
	spin_unlock(&rpc_authflavor_lock);

	dprintk("RPC:       %s returns %d\n", __func__, result);
	return result;
}
EXPORT_SYMBOL_GPL(rpcauth_list_flavors);

L
Linus Torvalds 已提交
179 180 181 182
struct rpc_auth *
rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt)
{
	struct rpc_auth		*auth;
183
	const struct rpc_authops *ops;
L
Linus Torvalds 已提交
184 185
	u32			flavor = pseudoflavor_to_flavor(pseudoflavor);

186 187 188 189 190 191
	auth = ERR_PTR(-EINVAL);
	if (flavor >= RPC_AUTH_MAXFLAVOR)
		goto out;

	if ((ops = auth_flavors[flavor]) == NULL)
		request_module("rpc-auth-%u", flavor);
192 193 194 195
	spin_lock(&rpc_authflavor_lock);
	ops = auth_flavors[flavor];
	if (ops == NULL || !try_module_get(ops->owner)) {
		spin_unlock(&rpc_authflavor_lock);
196
		goto out;
197 198
	}
	spin_unlock(&rpc_authflavor_lock);
L
Linus Torvalds 已提交
199
	auth = ops->create(clnt, pseudoflavor);
200
	module_put(ops->owner);
201 202
	if (IS_ERR(auth))
		return auth;
L
Linus Torvalds 已提交
203
	if (clnt->cl_auth)
204
		rpcauth_release(clnt->cl_auth);
L
Linus Torvalds 已提交
205
	clnt->cl_auth = auth;
206 207

out:
L
Linus Torvalds 已提交
208 209
	return auth;
}
210
EXPORT_SYMBOL_GPL(rpcauth_create);
L
Linus Torvalds 已提交
211 212

void
213
rpcauth_release(struct rpc_auth *auth)
L
Linus Torvalds 已提交
214 215 216 217 218 219 220 221
{
	if (!atomic_dec_and_test(&auth->au_count))
		return;
	auth->au_ops->destroy(auth);
}

static DEFINE_SPINLOCK(rpc_credcache_lock);

222 223 224 225 226 227 228 229
static void
rpcauth_unhash_cred_locked(struct rpc_cred *cred)
{
	hlist_del_rcu(&cred->cr_hash);
	smp_mb__before_clear_bit();
	clear_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags);
}

230
static int
231 232 233
rpcauth_unhash_cred(struct rpc_cred *cred)
{
	spinlock_t *cache_lock;
234
	int ret;
235 236 237

	cache_lock = &cred->cr_auth->au_credcache->lock;
	spin_lock(cache_lock);
238 239
	ret = atomic_read(&cred->cr_count) == 0;
	if (ret)
240 241
		rpcauth_unhash_cred_locked(cred);
	spin_unlock(cache_lock);
242
	return ret;
243 244
}

L
Linus Torvalds 已提交
245 246 247 248
/*
 * Initialize RPC credential cache
 */
int
249
rpcauth_init_credcache(struct rpc_auth *auth)
L
Linus Torvalds 已提交
250 251
{
	struct rpc_cred_cache *new;
252
	unsigned int hashsize;
L
Linus Torvalds 已提交
253

254
	new = kmalloc(sizeof(*new), GFP_KERNEL);
L
Linus Torvalds 已提交
255
	if (!new)
256 257
		goto out_nocache;
	new->hashbits = auth_hashbits;
258
	hashsize = 1U << new->hashbits;
259 260 261
	new->hashtable = kcalloc(hashsize, sizeof(new->hashtable[0]), GFP_KERNEL);
	if (!new->hashtable)
		goto out_nohashtbl;
262
	spin_lock_init(&new->lock);
L
Linus Torvalds 已提交
263 264
	auth->au_credcache = new;
	return 0;
265 266 267 268
out_nohashtbl:
	kfree(new);
out_nocache:
	return -ENOMEM;
L
Linus Torvalds 已提交
269
}
270
EXPORT_SYMBOL_GPL(rpcauth_init_credcache);
L
Linus Torvalds 已提交
271 272 273 274 275

/*
 * Destroy a list of credentials
 */
static inline
276
void rpcauth_destroy_credlist(struct list_head *head)
L
Linus Torvalds 已提交
277 278 279
{
	struct rpc_cred *cred;

280 281 282
	while (!list_empty(head)) {
		cred = list_entry(head->next, struct rpc_cred, cr_lru);
		list_del_init(&cred->cr_lru);
L
Linus Torvalds 已提交
283 284 285 286 287 288 289 290 291
		put_rpccred(cred);
	}
}

/*
 * Clear the RPC credential cache, and delete those credentials
 * that are not referenced.
 */
void
292
rpcauth_clear_credcache(struct rpc_cred_cache *cache)
L
Linus Torvalds 已提交
293
{
294 295
	LIST_HEAD(free);
	struct hlist_head *head;
L
Linus Torvalds 已提交
296
	struct rpc_cred	*cred;
297
	unsigned int hashsize = 1U << cache->hashbits;
L
Linus Torvalds 已提交
298 299 300
	int		i;

	spin_lock(&rpc_credcache_lock);
301
	spin_lock(&cache->lock);
302
	for (i = 0; i < hashsize; i++) {
303 304 305 306
		head = &cache->hashtable[i];
		while (!hlist_empty(head)) {
			cred = hlist_entry(head->first, struct rpc_cred, cr_hash);
			get_rpccred(cred);
307 308 309 310 311
			if (!list_empty(&cred->cr_lru)) {
				list_del(&cred->cr_lru);
				number_cred_unused--;
			}
			list_add_tail(&cred->cr_lru, &free);
312
			rpcauth_unhash_cred_locked(cred);
L
Linus Torvalds 已提交
313 314
		}
	}
315
	spin_unlock(&cache->lock);
L
Linus Torvalds 已提交
316 317 318 319
	spin_unlock(&rpc_credcache_lock);
	rpcauth_destroy_credlist(&free);
}

320 321 322 323 324 325 326 327 328 329 330
/*
 * Destroy the RPC credential cache
 */
void
rpcauth_destroy_credcache(struct rpc_auth *auth)
{
	struct rpc_cred_cache *cache = auth->au_credcache;

	if (cache) {
		auth->au_credcache = NULL;
		rpcauth_clear_credcache(cache);
331
		kfree(cache->hashtable);
332 333 334
		kfree(cache);
	}
}
335
EXPORT_SYMBOL_GPL(rpcauth_destroy_credcache);
336

337 338 339

#define RPC_AUTH_EXPIRY_MORATORIUM (60 * HZ)

340 341 342
/*
 * Remove stale credentials. Avoid sleeping inside the loop.
 */
343 344
static int
rpcauth_prune_expired(struct list_head *free, int nr_to_scan)
L
Linus Torvalds 已提交
345
{
346
	spinlock_t *cache_lock;
347
	struct rpc_cred *cred, *next;
348
	unsigned long expired = jiffies - RPC_AUTH_EXPIRY_MORATORIUM;
349

350 351
	list_for_each_entry_safe(cred, next, &cred_unused, cr_lru) {

352 353
		if (nr_to_scan-- == 0)
			break;
354 355 356 357
		/*
		 * Enforce a 60 second garbage collection moratorium
		 * Note that the cred_unused list must be time-ordered.
		 */
358
		if (time_in_range(cred->cr_expire, expired, jiffies) &&
359
		    test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0)
360
			return 0;
361

362
		list_del_init(&cred->cr_lru);
363
		number_cred_unused--;
364 365
		if (atomic_read(&cred->cr_count) != 0)
			continue;
366

367 368 369 370 371 372 373 374
		cache_lock = &cred->cr_auth->au_credcache->lock;
		spin_lock(cache_lock);
		if (atomic_read(&cred->cr_count) == 0) {
			get_rpccred(cred);
			list_add_tail(&cred->cr_lru, free);
			rpcauth_unhash_cred_locked(cred);
		}
		spin_unlock(cache_lock);
L
Linus Torvalds 已提交
375
	}
376
	return (number_cred_unused / 100) * sysctl_vfs_cache_pressure;
L
Linus Torvalds 已提交
377 378 379
}

/*
380
 * Run memory cache shrinker.
L
Linus Torvalds 已提交
381
 */
382
static int
383
rpcauth_cache_shrinker(struct shrinker *shrink, struct shrink_control *sc)
L
Linus Torvalds 已提交
384
{
385 386
	LIST_HEAD(free);
	int res;
387 388
	int nr_to_scan = sc->nr_to_scan;
	gfp_t gfp_mask = sc->gfp_mask;
389

390 391
	if ((gfp_mask & GFP_KERNEL) != GFP_KERNEL)
		return (nr_to_scan == 0) ? 0 : -1;
392 393
	if (list_empty(&cred_unused))
		return 0;
394
	spin_lock(&rpc_credcache_lock);
395
	res = rpcauth_prune_expired(&free, nr_to_scan);
396
	spin_unlock(&rpc_credcache_lock);
397 398
	rpcauth_destroy_credlist(&free);
	return res;
L
Linus Torvalds 已提交
399 400 401 402 403 404 405
}

/*
 * Look up a process' credentials in the authentication cache
 */
struct rpc_cred *
rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,
406
		int flags)
L
Linus Torvalds 已提交
407
{
408
	LIST_HEAD(free);
L
Linus Torvalds 已提交
409
	struct rpc_cred_cache *cache = auth->au_credcache;
410
	struct hlist_node *pos;
411 412
	struct rpc_cred	*cred = NULL,
			*entry, *new;
413 414
	unsigned int nr;

415
	nr = hash_long(acred->uid, cache->hashbits);
L
Linus Torvalds 已提交
416

417 418
	rcu_read_lock();
	hlist_for_each_entry_rcu(entry, pos, &cache->hashtable[nr], cr_hash) {
419 420
		if (!entry->cr_ops->crmatch(acred, entry, flags))
			continue;
421
		spin_lock(&cache->lock);
422
		if (test_bit(RPCAUTH_CRED_HASHED, &entry->cr_flags) == 0) {
423
			spin_unlock(&cache->lock);
424 425
			continue;
		}
426
		cred = get_rpccred(entry);
427
		spin_unlock(&cache->lock);
428
		break;
L
Linus Torvalds 已提交
429
	}
430 431
	rcu_read_unlock();

432
	if (cred != NULL)
433
		goto found;
L
Linus Torvalds 已提交
434

435 436 437 438 439
	new = auth->au_ops->crcreate(auth, acred, flags);
	if (IS_ERR(new)) {
		cred = new;
		goto out;
	}
L
Linus Torvalds 已提交
440

441
	spin_lock(&cache->lock);
442 443 444 445 446 447 448
	hlist_for_each_entry(entry, pos, &cache->hashtable[nr], cr_hash) {
		if (!entry->cr_ops->crmatch(acred, entry, flags))
			continue;
		cred = get_rpccred(entry);
		break;
	}
	if (cred == NULL) {
449
		cred = new;
450 451 452 453
		set_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags);
		hlist_add_head_rcu(&cred->cr_hash, &cache->hashtable[nr]);
	} else
		list_add_tail(&new->cr_lru, &free);
454
	spin_unlock(&cache->lock);
455
found:
456 457 458
	if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) &&
	    cred->cr_ops->cr_init != NULL &&
	    !(flags & RPCAUTH_LOOKUP_NEW)) {
459 460 461 462 463
		int res = cred->cr_ops->cr_init(auth, cred);
		if (res < 0) {
			put_rpccred(cred);
			cred = ERR_PTR(res);
		}
L
Linus Torvalds 已提交
464
	}
465 466 467
	rpcauth_destroy_credlist(&free);
out:
	return cred;
L
Linus Torvalds 已提交
468
}
469
EXPORT_SYMBOL_GPL(rpcauth_lookup_credcache);
L
Linus Torvalds 已提交
470 471

struct rpc_cred *
472
rpcauth_lookupcred(struct rpc_auth *auth, int flags)
L
Linus Torvalds 已提交
473
{
474
	struct auth_cred acred;
L
Linus Torvalds 已提交
475
	struct rpc_cred *ret;
476
	const struct cred *cred = current_cred();
L
Linus Torvalds 已提交
477

478
	dprintk("RPC:       looking up %s cred\n",
L
Linus Torvalds 已提交
479
		auth->au_ops->au_name);
480 481 482 483 484 485

	memset(&acred, 0, sizeof(acred));
	acred.uid = cred->fsuid;
	acred.gid = cred->fsgid;
	acred.group_info = get_group_info(((struct cred *)cred)->group_info);

486
	ret = auth->au_ops->lookup_cred(auth, &acred, flags);
L
Linus Torvalds 已提交
487 488 489 490
	put_group_info(acred.group_info);
	return ret;
}

491 492 493 494 495
void
rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred,
		  struct rpc_auth *auth, const struct rpc_credops *ops)
{
	INIT_HLIST_NODE(&cred->cr_hash);
496
	INIT_LIST_HEAD(&cred->cr_lru);
497 498 499 500 501 502 503 504 505
	atomic_set(&cred->cr_count, 1);
	cred->cr_auth = auth;
	cred->cr_ops = ops;
	cred->cr_expire = jiffies;
#ifdef RPC_DEBUG
	cred->cr_magic = RPCAUTH_CRED_MAGIC;
#endif
	cred->cr_uid = acred->uid;
}
506
EXPORT_SYMBOL_GPL(rpcauth_init_cred);
507

508
struct rpc_cred *
509
rpcauth_generic_bind_cred(struct rpc_task *task, struct rpc_cred *cred, int lookupflags)
510 511 512
{
	dprintk("RPC: %5u holding %s cred %p\n", task->tk_pid,
			cred->cr_auth->au_ops->au_name, cred);
513
	return get_rpccred(cred);
514
}
515
EXPORT_SYMBOL_GPL(rpcauth_generic_bind_cred);
516

517
static struct rpc_cred *
518
rpcauth_bind_root_cred(struct rpc_task *task, int lookupflags)
L
Linus Torvalds 已提交
519
{
520
	struct rpc_auth *auth = task->tk_client->cl_auth;
L
Linus Torvalds 已提交
521
	struct auth_cred acred = {
522 523
		.uid = 0,
		.gid = 0,
L
Linus Torvalds 已提交
524 525
	};

526
	dprintk("RPC: %5u looking up %s cred\n",
527
		task->tk_pid, task->tk_client->cl_auth->au_ops->au_name);
528
	return auth->au_ops->lookup_cred(auth, &acred, lookupflags);
529 530
}

531
static struct rpc_cred *
532
rpcauth_bind_new_cred(struct rpc_task *task, int lookupflags)
533 534 535 536 537
{
	struct rpc_auth *auth = task->tk_client->cl_auth;

	dprintk("RPC: %5u looking up %s cred\n",
		task->tk_pid, auth->au_ops->au_name);
538
	return rpcauth_lookupcred(auth, lookupflags);
L
Linus Torvalds 已提交
539 540
}

541
static int
542
rpcauth_bindcred(struct rpc_task *task, struct rpc_cred *cred, int flags)
L
Linus Torvalds 已提交
543
{
544
	struct rpc_rqst *req = task->tk_rqstp;
545
	struct rpc_cred *new;
546 547 548 549
	int lookupflags = 0;

	if (flags & RPC_TASK_ASYNC)
		lookupflags |= RPCAUTH_LOOKUP_NEW;
550
	if (cred != NULL)
551
		new = cred->cr_ops->crbind(task, cred, lookupflags);
552
	else if (flags & RPC_TASK_ROOTCREDS)
553
		new = rpcauth_bind_root_cred(task, lookupflags);
554
	else
555 556 557
		new = rpcauth_bind_new_cred(task, lookupflags);
	if (IS_ERR(new))
		return PTR_ERR(new);
558 559 560
	if (req->rq_cred != NULL)
		put_rpccred(req->rq_cred);
	req->rq_cred = new;
561
	return 0;
L
Linus Torvalds 已提交
562 563 564 565 566
}

void
put_rpccred(struct rpc_cred *cred)
{
567
	/* Fast path for unhashed credentials */
568 569 570
	if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) == 0) {
		if (atomic_dec_and_test(&cred->cr_count))
			cred->cr_ops->crdestroy(cred);
L
Linus Torvalds 已提交
571
		return;
572 573
	}

574 575
	if (!atomic_dec_and_lock(&cred->cr_count, &rpc_credcache_lock))
		return;
576 577
	if (!list_empty(&cred->cr_lru)) {
		number_cred_unused--;
578
		list_del_init(&cred->cr_lru);
579
	}
580
	if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) {
581 582 583 584 585 586 587 588 589 590
		if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0) {
			cred->cr_expire = jiffies;
			list_add_tail(&cred->cr_lru, &cred_unused);
			number_cred_unused++;
			goto out_nodestroy;
		}
		if (!rpcauth_unhash_cred(cred)) {
			/* We were hashed and someone looked us up... */
			goto out_nodestroy;
		}
591 592
	}
	spin_unlock(&rpc_credcache_lock);
L
Linus Torvalds 已提交
593
	cred->cr_ops->crdestroy(cred);
594 595 596
	return;
out_nodestroy:
	spin_unlock(&rpc_credcache_lock);
L
Linus Torvalds 已提交
597
}
598
EXPORT_SYMBOL_GPL(put_rpccred);
L
Linus Torvalds 已提交
599

600 601
__be32 *
rpcauth_marshcred(struct rpc_task *task, __be32 *p)
L
Linus Torvalds 已提交
602
{
603
	struct rpc_cred	*cred = task->tk_rqstp->rq_cred;
L
Linus Torvalds 已提交
604

605
	dprintk("RPC: %5u marshaling %s cred %p\n",
606
		task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
607

L
Linus Torvalds 已提交
608 609 610
	return cred->cr_ops->crmarshal(task, p);
}

611 612
__be32 *
rpcauth_checkverf(struct rpc_task *task, __be32 *p)
L
Linus Torvalds 已提交
613
{
614
	struct rpc_cred	*cred = task->tk_rqstp->rq_cred;
L
Linus Torvalds 已提交
615

616
	dprintk("RPC: %5u validating %s cred %p\n",
617
		task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
618

L
Linus Torvalds 已提交
619 620 621
	return cred->cr_ops->crvalidate(task, p);
}

622 623 624 625 626 627 628 629 630
static void rpcauth_wrap_req_encode(kxdreproc_t encode, struct rpc_rqst *rqstp,
				   __be32 *data, void *obj)
{
	struct xdr_stream xdr;

	xdr_init_encode(&xdr, &rqstp->rq_snd_buf, data);
	encode(rqstp, &xdr, obj);
}

L
Linus Torvalds 已提交
631
int
632
rpcauth_wrap_req(struct rpc_task *task, kxdreproc_t encode, void *rqstp,
633
		__be32 *data, void *obj)
L
Linus Torvalds 已提交
634
{
635
	struct rpc_cred *cred = task->tk_rqstp->rq_cred;
L
Linus Torvalds 已提交
636

637
	dprintk("RPC: %5u using %s cred %p to wrap rpc data\n",
L
Linus Torvalds 已提交
638 639 640 641
			task->tk_pid, cred->cr_ops->cr_name, cred);
	if (cred->cr_ops->crwrap_req)
		return cred->cr_ops->crwrap_req(task, encode, rqstp, data, obj);
	/* By default, we encode the arguments normally. */
642 643
	rpcauth_wrap_req_encode(encode, rqstp, data, obj);
	return 0;
L
Linus Torvalds 已提交
644 645
}

646 647 648 649 650 651 652 653 654 655
static int
rpcauth_unwrap_req_decode(kxdrdproc_t decode, struct rpc_rqst *rqstp,
			  __be32 *data, void *obj)
{
	struct xdr_stream xdr;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, data);
	return decode(rqstp, &xdr, obj);
}

L
Linus Torvalds 已提交
656
int
657
rpcauth_unwrap_resp(struct rpc_task *task, kxdrdproc_t decode, void *rqstp,
658
		__be32 *data, void *obj)
L
Linus Torvalds 已提交
659
{
660
	struct rpc_cred *cred = task->tk_rqstp->rq_cred;
L
Linus Torvalds 已提交
661

662
	dprintk("RPC: %5u using %s cred %p to unwrap rpc data\n",
L
Linus Torvalds 已提交
663 664 665 666 667
			task->tk_pid, cred->cr_ops->cr_name, cred);
	if (cred->cr_ops->crunwrap_resp)
		return cred->cr_ops->crunwrap_resp(task, decode, rqstp,
						   data, obj);
	/* By default, we decode the arguments normally. */
668
	return rpcauth_unwrap_req_decode(decode, rqstp, data, obj);
L
Linus Torvalds 已提交
669 670 671 672 673
}

int
rpcauth_refreshcred(struct rpc_task *task)
{
674
	struct rpc_cred	*cred;
L
Linus Torvalds 已提交
675 676
	int err;

677 678 679 680 681 682
	cred = task->tk_rqstp->rq_cred;
	if (cred == NULL) {
		err = rpcauth_bindcred(task, task->tk_msg.rpc_cred, task->tk_flags);
		if (err < 0)
			goto out;
		cred = task->tk_rqstp->rq_cred;
J
Joe Perches 已提交
683
	}
684
	dprintk("RPC: %5u refreshing %s cred %p\n",
685
		task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
686

L
Linus Torvalds 已提交
687
	err = cred->cr_ops->crrefresh(task);
688
out:
L
Linus Torvalds 已提交
689 690 691 692 693 694 695 696
	if (err < 0)
		task->tk_status = err;
	return err;
}

void
rpcauth_invalcred(struct rpc_task *task)
{
697
	struct rpc_cred *cred = task->tk_rqstp->rq_cred;
698

699
	dprintk("RPC: %5u invalidating %s cred %p\n",
700
		task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
701 702
	if (cred)
		clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
L
Linus Torvalds 已提交
703 704 705 706 707
}

int
rpcauth_uptodatecred(struct rpc_task *task)
{
708
	struct rpc_cred *cred = task->tk_rqstp->rq_cred;
709 710 711

	return cred == NULL ||
		test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0;
L
Linus Torvalds 已提交
712
}
713

714 715 716 717
static struct shrinker rpc_cred_shrinker = {
	.shrink = rpcauth_cache_shrinker,
	.seeks = DEFAULT_SEEKS,
};
718

719
int __init rpcauth_init_module(void)
720
{
721 722 723 724 725 726 727 728
	int err;

	err = rpc_init_authunix();
	if (err < 0)
		goto out1;
	err = rpc_init_generic_auth();
	if (err < 0)
		goto out2;
729
	register_shrinker(&rpc_cred_shrinker);
730 731 732 733 734
	return 0;
out2:
	rpc_destroy_authunix();
out1:
	return err;
735 736
}

737
void rpcauth_remove_module(void)
738
{
739 740
	rpc_destroy_authunix();
	rpc_destroy_generic_auth();
741
	unregister_shrinker(&rpc_cred_shrinker);
742
}