1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * linux/net/sunrpc/auth.c 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Generic RPC client authentication API. 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> 81da177e4SLinus Torvalds */ 91da177e4SLinus Torvalds 101da177e4SLinus Torvalds #include <linux/types.h> 111da177e4SLinus Torvalds #include <linux/sched.h> 125b825c3aSIngo Molnar #include <linux/cred.h> 131da177e4SLinus Torvalds #include <linux/module.h> 141da177e4SLinus Torvalds #include <linux/slab.h> 151da177e4SLinus Torvalds #include <linux/errno.h> 1625337fdcSTrond Myklebust #include <linux/hash.h> 171da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h> 186a1a1e34SChuck Lever #include <linux/sunrpc/gss_api.h> 191da177e4SLinus Torvalds #include <linux/spinlock.h> 201da177e4SLinus Torvalds 21a0584ee9SChuck Lever #include <trace/events/sunrpc.h> 22a0584ee9SChuck Lever 23241269bdSTrond Myklebust #define RPC_CREDCACHE_DEFAULT_HASHBITS (4) 24241269bdSTrond Myklebust struct rpc_cred_cache { 25241269bdSTrond Myklebust struct hlist_head *hashtable; 26241269bdSTrond Myklebust unsigned int hashbits; 27241269bdSTrond Myklebust spinlock_t lock; 28241269bdSTrond Myklebust }; 29241269bdSTrond Myklebust 30241269bdSTrond Myklebust static unsigned int auth_hashbits = RPC_CREDCACHE_DEFAULT_HASHBITS; 31241269bdSTrond Myklebust 324e4c3befSTrond Myklebust static const struct rpc_authops __rcu *auth_flavors[RPC_AUTH_MAXFLAVOR] = { 334e4c3befSTrond Myklebust [RPC_AUTH_NULL] = (const struct rpc_authops __force __rcu *)&authnull_ops, 344e4c3befSTrond Myklebust [RPC_AUTH_UNIX] = (const struct rpc_authops __force __rcu *)&authunix_ops, 351da177e4SLinus Torvalds NULL, /* others can be loadable modules */ 361da177e4SLinus Torvalds }; 371da177e4SLinus Torvalds 38e092bdcdSTrond Myklebust static LIST_HEAD(cred_unused); 39f5c2187cSTrond Myklebust static unsigned long number_cred_unused; 40e092bdcdSTrond Myklebust 41a52458b4SNeilBrown static struct cred machine_cred = { 42a52458b4SNeilBrown .usage = ATOMIC_INIT(1), 43e7f45099SSantosh kumar pradhan #ifdef CONFIG_DEBUG_CREDENTIALS 44e7f45099SSantosh kumar pradhan .magic = CRED_MAGIC, 45e7f45099SSantosh kumar pradhan #endif 465e16923bSNeilBrown }; 475e16923bSNeilBrown 485e16923bSNeilBrown /* 495e16923bSNeilBrown * Return the machine_cred pointer to be used whenever 505e16923bSNeilBrown * the a generic machine credential is needed. 515e16923bSNeilBrown */ 52a52458b4SNeilBrown const struct cred *rpc_machine_cred(void) 535e16923bSNeilBrown { 545e16923bSNeilBrown return &machine_cred; 555e16923bSNeilBrown } 565e16923bSNeilBrown EXPORT_SYMBOL_GPL(rpc_machine_cred); 575e16923bSNeilBrown 58db5fe265SMiquel van Smoorenburg #define MAX_HASHTABLE_BITS (14) 598e4e15d4SStephen Rothwell static int param_set_hashtbl_sz(const char *val, const struct kernel_param *kp) 60241269bdSTrond Myklebust { 61241269bdSTrond Myklebust unsigned long num; 62241269bdSTrond Myklebust unsigned int nbits; 63241269bdSTrond Myklebust int ret; 64241269bdSTrond Myklebust 65241269bdSTrond Myklebust if (!val) 66241269bdSTrond Myklebust goto out_inval; 6700cfaa94SDaniel Walter ret = kstrtoul(val, 0, &num); 681a54c0cfSDan Carpenter if (ret) 69241269bdSTrond Myklebust goto out_inval; 7034ae685cSFrank Sorenson nbits = fls(num - 1); 71241269bdSTrond Myklebust if (nbits > MAX_HASHTABLE_BITS || nbits < 2) 72241269bdSTrond Myklebust goto out_inval; 73241269bdSTrond Myklebust *(unsigned int *)kp->arg = nbits; 74241269bdSTrond Myklebust return 0; 75241269bdSTrond Myklebust out_inval: 76241269bdSTrond Myklebust return -EINVAL; 77241269bdSTrond Myklebust } 78241269bdSTrond Myklebust 798e4e15d4SStephen Rothwell static int param_get_hashtbl_sz(char *buffer, const struct kernel_param *kp) 80241269bdSTrond Myklebust { 81241269bdSTrond Myklebust unsigned int nbits; 82241269bdSTrond Myklebust 83241269bdSTrond Myklebust nbits = *(unsigned int *)kp->arg; 842ac3ddc7SXiongfeng Wang return sprintf(buffer, "%u\n", 1U << nbits); 85241269bdSTrond Myklebust } 86241269bdSTrond Myklebust 87241269bdSTrond Myklebust #define param_check_hashtbl_sz(name, p) __param_check(name, p, unsigned int); 88241269bdSTrond Myklebust 899c27847dSLuis R. Rodriguez static const struct kernel_param_ops param_ops_hashtbl_sz = { 908e4e15d4SStephen Rothwell .set = param_set_hashtbl_sz, 918e4e15d4SStephen Rothwell .get = param_get_hashtbl_sz, 928e4e15d4SStephen Rothwell }; 938e4e15d4SStephen Rothwell 94241269bdSTrond Myklebust module_param_named(auth_hashtable_size, auth_hashbits, hashtbl_sz, 0644); 95241269bdSTrond Myklebust MODULE_PARM_DESC(auth_hashtable_size, "RPC credential cache hashtable size"); 96241269bdSTrond Myklebust 97bae6746fSTrond Myklebust static unsigned long auth_max_cred_cachesize = ULONG_MAX; 98bae6746fSTrond Myklebust module_param(auth_max_cred_cachesize, ulong, 0644); 99bae6746fSTrond Myklebust MODULE_PARM_DESC(auth_max_cred_cachesize, "RPC credential maximum total cache size"); 100bae6746fSTrond Myklebust 1011da177e4SLinus Torvalds static u32 1021da177e4SLinus Torvalds pseudoflavor_to_flavor(u32 flavor) { 1031c74a244SChuck Lever if (flavor > RPC_AUTH_MAXFLAVOR) 1041da177e4SLinus Torvalds return RPC_AUTH_GSS; 1051da177e4SLinus Torvalds return flavor; 1061da177e4SLinus Torvalds } 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds int 109f1c0a861STrond Myklebust rpcauth_register(const struct rpc_authops *ops) 1101da177e4SLinus Torvalds { 1114e4c3befSTrond Myklebust const struct rpc_authops *old; 1121da177e4SLinus Torvalds rpc_authflavor_t flavor; 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR) 1151da177e4SLinus Torvalds return -EINVAL; 1164e4c3befSTrond Myklebust old = cmpxchg((const struct rpc_authops ** __force)&auth_flavors[flavor], NULL, ops); 1174e4c3befSTrond Myklebust if (old == NULL || old == ops) 1184e4c3befSTrond Myklebust return 0; 1194e4c3befSTrond Myklebust return -EPERM; 1201da177e4SLinus Torvalds } 121e8914c65STrond Myklebust EXPORT_SYMBOL_GPL(rpcauth_register); 1221da177e4SLinus Torvalds 1231da177e4SLinus Torvalds int 124f1c0a861STrond Myklebust rpcauth_unregister(const struct rpc_authops *ops) 1251da177e4SLinus Torvalds { 1264e4c3befSTrond Myklebust const struct rpc_authops *old; 1271da177e4SLinus Torvalds rpc_authflavor_t flavor; 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR) 1301da177e4SLinus Torvalds return -EINVAL; 1314e4c3befSTrond Myklebust 1324e4c3befSTrond Myklebust old = cmpxchg((const struct rpc_authops ** __force)&auth_flavors[flavor], ops, NULL); 1334e4c3befSTrond Myklebust if (old == ops || old == NULL) 1344e4c3befSTrond Myklebust return 0; 1354e4c3befSTrond Myklebust return -EPERM; 1361da177e4SLinus Torvalds } 137e8914c65STrond Myklebust EXPORT_SYMBOL_GPL(rpcauth_unregister); 1381da177e4SLinus Torvalds 1394e4c3befSTrond Myklebust static const struct rpc_authops * 1404e4c3befSTrond Myklebust rpcauth_get_authops(rpc_authflavor_t flavor) 1414e4c3befSTrond Myklebust { 1424e4c3befSTrond Myklebust const struct rpc_authops *ops; 1434e4c3befSTrond Myklebust 1444e4c3befSTrond Myklebust if (flavor >= RPC_AUTH_MAXFLAVOR) 1454e4c3befSTrond Myklebust return NULL; 1464e4c3befSTrond Myklebust 1474e4c3befSTrond Myklebust rcu_read_lock(); 1484e4c3befSTrond Myklebust ops = rcu_dereference(auth_flavors[flavor]); 1494e4c3befSTrond Myklebust if (ops == NULL) { 1504e4c3befSTrond Myklebust rcu_read_unlock(); 1514e4c3befSTrond Myklebust request_module("rpc-auth-%u", flavor); 1524e4c3befSTrond Myklebust rcu_read_lock(); 1534e4c3befSTrond Myklebust ops = rcu_dereference(auth_flavors[flavor]); 1544e4c3befSTrond Myklebust if (ops == NULL) 1554e4c3befSTrond Myklebust goto out; 1564e4c3befSTrond Myklebust } 1574e4c3befSTrond Myklebust if (!try_module_get(ops->owner)) 1584e4c3befSTrond Myklebust ops = NULL; 1594e4c3befSTrond Myklebust out: 1604e4c3befSTrond Myklebust rcu_read_unlock(); 1614e4c3befSTrond Myklebust return ops; 1624e4c3befSTrond Myklebust } 1634e4c3befSTrond Myklebust 1644e4c3befSTrond Myklebust static void 1654e4c3befSTrond Myklebust rpcauth_put_authops(const struct rpc_authops *ops) 1664e4c3befSTrond Myklebust { 1674e4c3befSTrond Myklebust module_put(ops->owner); 1684e4c3befSTrond Myklebust } 1694e4c3befSTrond Myklebust 1706a1a1e34SChuck Lever /** 1719568c5e9SChuck Lever * rpcauth_get_pseudoflavor - check if security flavor is supported 1729568c5e9SChuck Lever * @flavor: a security flavor 1739568c5e9SChuck Lever * @info: a GSS mech OID, quality of protection, and service value 1749568c5e9SChuck Lever * 1759568c5e9SChuck Lever * Verifies that an appropriate kernel module is available or already loaded. 1769568c5e9SChuck Lever * Returns an equivalent pseudoflavor, or RPC_AUTH_MAXFLAVOR if "flavor" is 1779568c5e9SChuck Lever * not supported locally. 1789568c5e9SChuck Lever */ 1799568c5e9SChuck Lever rpc_authflavor_t 1809568c5e9SChuck Lever rpcauth_get_pseudoflavor(rpc_authflavor_t flavor, struct rpcsec_gss_info *info) 1819568c5e9SChuck Lever { 1824e4c3befSTrond Myklebust const struct rpc_authops *ops = rpcauth_get_authops(flavor); 1839568c5e9SChuck Lever rpc_authflavor_t pseudoflavor; 1849568c5e9SChuck Lever 1854e4c3befSTrond Myklebust if (!ops) 1869568c5e9SChuck Lever return RPC_AUTH_MAXFLAVOR; 1879568c5e9SChuck Lever pseudoflavor = flavor; 1889568c5e9SChuck Lever if (ops->info2flavor != NULL) 1899568c5e9SChuck Lever pseudoflavor = ops->info2flavor(info); 1909568c5e9SChuck Lever 1914e4c3befSTrond Myklebust rpcauth_put_authops(ops); 1929568c5e9SChuck Lever return pseudoflavor; 1939568c5e9SChuck Lever } 1949568c5e9SChuck Lever EXPORT_SYMBOL_GPL(rpcauth_get_pseudoflavor); 1959568c5e9SChuck Lever 1969568c5e9SChuck Lever /** 197a77c806fSChuck Lever * rpcauth_get_gssinfo - find GSS tuple matching a GSS pseudoflavor 198a77c806fSChuck Lever * @pseudoflavor: GSS pseudoflavor to match 199a77c806fSChuck Lever * @info: rpcsec_gss_info structure to fill in 200a77c806fSChuck Lever * 201a77c806fSChuck Lever * Returns zero and fills in "info" if pseudoflavor matches a 202a77c806fSChuck Lever * supported mechanism. 203a77c806fSChuck Lever */ 204a77c806fSChuck Lever int 205a77c806fSChuck Lever rpcauth_get_gssinfo(rpc_authflavor_t pseudoflavor, struct rpcsec_gss_info *info) 206a77c806fSChuck Lever { 207a77c806fSChuck Lever rpc_authflavor_t flavor = pseudoflavor_to_flavor(pseudoflavor); 208a77c806fSChuck Lever const struct rpc_authops *ops; 209a77c806fSChuck Lever int result; 210a77c806fSChuck Lever 2114e4c3befSTrond Myklebust ops = rpcauth_get_authops(flavor); 212a77c806fSChuck Lever if (ops == NULL) 213a77c806fSChuck Lever return -ENOENT; 214a77c806fSChuck Lever 215a77c806fSChuck Lever result = -ENOENT; 216a77c806fSChuck Lever if (ops->flavor2info != NULL) 217a77c806fSChuck Lever result = ops->flavor2info(pseudoflavor, info); 218a77c806fSChuck Lever 2194e4c3befSTrond Myklebust rpcauth_put_authops(ops); 220a77c806fSChuck Lever return result; 221a77c806fSChuck Lever } 222a77c806fSChuck Lever EXPORT_SYMBOL_GPL(rpcauth_get_gssinfo); 223a77c806fSChuck Lever 2241da177e4SLinus Torvalds struct rpc_auth * 22582b98ca5SSargun Dhillon rpcauth_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt) 2261da177e4SLinus Torvalds { 2274e4c3befSTrond Myklebust struct rpc_auth *auth = ERR_PTR(-EINVAL); 228f1c0a861STrond Myklebust const struct rpc_authops *ops; 229c2190661STrond Myklebust u32 flavor = pseudoflavor_to_flavor(args->pseudoflavor); 2301da177e4SLinus Torvalds 2314e4c3befSTrond Myklebust ops = rpcauth_get_authops(flavor); 2324e4c3befSTrond Myklebust if (ops == NULL) 233f344f6dfSOlaf Kirch goto out; 234f344f6dfSOlaf Kirch 235c2190661STrond Myklebust auth = ops->create(args, clnt); 2364e4c3befSTrond Myklebust 2374e4c3befSTrond Myklebust rpcauth_put_authops(ops); 2386a19275aSJ. Bruce Fields if (IS_ERR(auth)) 2396a19275aSJ. Bruce Fields return auth; 2401da177e4SLinus Torvalds if (clnt->cl_auth) 241de7a8ce3STrond Myklebust rpcauth_release(clnt->cl_auth); 2421da177e4SLinus Torvalds clnt->cl_auth = auth; 243f344f6dfSOlaf Kirch 244f344f6dfSOlaf Kirch out: 2451da177e4SLinus Torvalds return auth; 2461da177e4SLinus Torvalds } 247e8914c65STrond Myklebust EXPORT_SYMBOL_GPL(rpcauth_create); 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds void 250de7a8ce3STrond Myklebust rpcauth_release(struct rpc_auth *auth) 2511da177e4SLinus Torvalds { 252331bc71cSTrond Myklebust if (!refcount_dec_and_test(&auth->au_count)) 2531da177e4SLinus Torvalds return; 2541da177e4SLinus Torvalds auth->au_ops->destroy(auth); 2551da177e4SLinus Torvalds } 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds static DEFINE_SPINLOCK(rpc_credcache_lock); 2581da177e4SLinus Torvalds 25995cd6232STrond Myklebust /* 26095cd6232STrond Myklebust * On success, the caller is responsible for freeing the reference 26195cd6232STrond Myklebust * held by the hashtable 26295cd6232STrond Myklebust */ 26395cd6232STrond Myklebust static bool 26431be5bf1STrond Myklebust rpcauth_unhash_cred_locked(struct rpc_cred *cred) 26531be5bf1STrond Myklebust { 26695cd6232STrond Myklebust if (!test_and_clear_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags)) 26795cd6232STrond Myklebust return false; 26831be5bf1STrond Myklebust hlist_del_rcu(&cred->cr_hash); 26995cd6232STrond Myklebust return true; 27031be5bf1STrond Myklebust } 27131be5bf1STrond Myklebust 27295cd6232STrond Myklebust static bool 2739499b434STrond Myklebust rpcauth_unhash_cred(struct rpc_cred *cred) 2749499b434STrond Myklebust { 2759499b434STrond Myklebust spinlock_t *cache_lock; 27695cd6232STrond Myklebust bool ret; 2779499b434STrond Myklebust 27895cd6232STrond Myklebust if (!test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags)) 27995cd6232STrond Myklebust return false; 2809499b434STrond Myklebust cache_lock = &cred->cr_auth->au_credcache->lock; 2819499b434STrond Myklebust spin_lock(cache_lock); 28295cd6232STrond Myklebust ret = rpcauth_unhash_cred_locked(cred); 2839499b434STrond Myklebust spin_unlock(cache_lock); 284f0380f3dSTrond Myklebust return ret; 2859499b434STrond Myklebust } 2869499b434STrond Myklebust 2871da177e4SLinus Torvalds /* 2881da177e4SLinus Torvalds * Initialize RPC credential cache 2891da177e4SLinus Torvalds */ 2901da177e4SLinus Torvalds int 291f5c2187cSTrond Myklebust rpcauth_init_credcache(struct rpc_auth *auth) 2921da177e4SLinus Torvalds { 2931da177e4SLinus Torvalds struct rpc_cred_cache *new; 294988664a0STrond Myklebust unsigned int hashsize; 2951da177e4SLinus Torvalds 2968b3a7005SKris Katterjohn new = kmalloc(sizeof(*new), GFP_KERNEL); 2971da177e4SLinus Torvalds if (!new) 298241269bdSTrond Myklebust goto out_nocache; 299241269bdSTrond Myklebust new->hashbits = auth_hashbits; 300988664a0STrond Myklebust hashsize = 1U << new->hashbits; 301241269bdSTrond Myklebust new->hashtable = kcalloc(hashsize, sizeof(new->hashtable[0]), GFP_KERNEL); 302241269bdSTrond Myklebust if (!new->hashtable) 303241269bdSTrond Myklebust goto out_nohashtbl; 3049499b434STrond Myklebust spin_lock_init(&new->lock); 3051da177e4SLinus Torvalds auth->au_credcache = new; 3061da177e4SLinus Torvalds return 0; 307241269bdSTrond Myklebust out_nohashtbl: 308241269bdSTrond Myklebust kfree(new); 309241269bdSTrond Myklebust out_nocache: 310241269bdSTrond Myklebust return -ENOMEM; 3111da177e4SLinus Torvalds } 312e8914c65STrond Myklebust EXPORT_SYMBOL_GPL(rpcauth_init_credcache); 3131da177e4SLinus Torvalds 314a0337d1dSJeff Layton char * 315a0337d1dSJeff Layton rpcauth_stringify_acceptor(struct rpc_cred *cred) 316a0337d1dSJeff Layton { 317a0337d1dSJeff Layton if (!cred->cr_ops->crstringify_acceptor) 318a0337d1dSJeff Layton return NULL; 319a0337d1dSJeff Layton return cred->cr_ops->crstringify_acceptor(cred); 320a0337d1dSJeff Layton } 321a0337d1dSJeff Layton EXPORT_SYMBOL_GPL(rpcauth_stringify_acceptor); 322a0337d1dSJeff Layton 3234de6caa2SAndy Adamson /* 3241da177e4SLinus Torvalds * Destroy a list of credentials 3251da177e4SLinus Torvalds */ 3261da177e4SLinus Torvalds static inline 327e092bdcdSTrond Myklebust void rpcauth_destroy_credlist(struct list_head *head) 3281da177e4SLinus Torvalds { 3291da177e4SLinus Torvalds struct rpc_cred *cred; 3301da177e4SLinus Torvalds 331e092bdcdSTrond Myklebust while (!list_empty(head)) { 332e092bdcdSTrond Myklebust cred = list_entry(head->next, struct rpc_cred, cr_lru); 333e092bdcdSTrond Myklebust list_del_init(&cred->cr_lru); 3341da177e4SLinus Torvalds put_rpccred(cred); 3351da177e4SLinus Torvalds } 3361da177e4SLinus Torvalds } 3371da177e4SLinus Torvalds 33895cd6232STrond Myklebust static void 33995cd6232STrond Myklebust rpcauth_lru_add_locked(struct rpc_cred *cred) 34095cd6232STrond Myklebust { 34195cd6232STrond Myklebust if (!list_empty(&cred->cr_lru)) 34295cd6232STrond Myklebust return; 34395cd6232STrond Myklebust number_cred_unused++; 34495cd6232STrond Myklebust list_add_tail(&cred->cr_lru, &cred_unused); 34595cd6232STrond Myklebust } 34695cd6232STrond Myklebust 34795cd6232STrond Myklebust static void 34895cd6232STrond Myklebust rpcauth_lru_add(struct rpc_cred *cred) 34995cd6232STrond Myklebust { 35095cd6232STrond Myklebust if (!list_empty(&cred->cr_lru)) 35195cd6232STrond Myklebust return; 35295cd6232STrond Myklebust spin_lock(&rpc_credcache_lock); 35395cd6232STrond Myklebust rpcauth_lru_add_locked(cred); 35495cd6232STrond Myklebust spin_unlock(&rpc_credcache_lock); 35595cd6232STrond Myklebust } 35695cd6232STrond Myklebust 35795cd6232STrond Myklebust static void 35895cd6232STrond Myklebust rpcauth_lru_remove_locked(struct rpc_cred *cred) 35995cd6232STrond Myklebust { 36095cd6232STrond Myklebust if (list_empty(&cred->cr_lru)) 36195cd6232STrond Myklebust return; 36295cd6232STrond Myklebust number_cred_unused--; 36395cd6232STrond Myklebust list_del_init(&cred->cr_lru); 36495cd6232STrond Myklebust } 36595cd6232STrond Myklebust 36695cd6232STrond Myklebust static void 36795cd6232STrond Myklebust rpcauth_lru_remove(struct rpc_cred *cred) 36895cd6232STrond Myklebust { 36995cd6232STrond Myklebust if (list_empty(&cred->cr_lru)) 37095cd6232STrond Myklebust return; 37195cd6232STrond Myklebust spin_lock(&rpc_credcache_lock); 37295cd6232STrond Myklebust rpcauth_lru_remove_locked(cred); 37395cd6232STrond Myklebust spin_unlock(&rpc_credcache_lock); 37495cd6232STrond Myklebust } 37595cd6232STrond Myklebust 3761da177e4SLinus Torvalds /* 3771da177e4SLinus Torvalds * Clear the RPC credential cache, and delete those credentials 3781da177e4SLinus Torvalds * that are not referenced. 3791da177e4SLinus Torvalds */ 3801da177e4SLinus Torvalds void 3813ab9bb72STrond Myklebust rpcauth_clear_credcache(struct rpc_cred_cache *cache) 3821da177e4SLinus Torvalds { 383e092bdcdSTrond Myklebust LIST_HEAD(free); 384e092bdcdSTrond Myklebust struct hlist_head *head; 3851da177e4SLinus Torvalds struct rpc_cred *cred; 386988664a0STrond Myklebust unsigned int hashsize = 1U << cache->hashbits; 3871da177e4SLinus Torvalds int i; 3881da177e4SLinus Torvalds 3891da177e4SLinus Torvalds spin_lock(&rpc_credcache_lock); 3909499b434STrond Myklebust spin_lock(&cache->lock); 391988664a0STrond Myklebust for (i = 0; i < hashsize; i++) { 392e092bdcdSTrond Myklebust head = &cache->hashtable[i]; 393e092bdcdSTrond Myklebust while (!hlist_empty(head)) { 394e092bdcdSTrond Myklebust cred = hlist_entry(head->first, struct rpc_cred, cr_hash); 39531be5bf1STrond Myklebust rpcauth_unhash_cred_locked(cred); 39695cd6232STrond Myklebust /* Note: We now hold a reference to cred */ 39795cd6232STrond Myklebust rpcauth_lru_remove_locked(cred); 39895cd6232STrond Myklebust list_add_tail(&cred->cr_lru, &free); 3991da177e4SLinus Torvalds } 4001da177e4SLinus Torvalds } 4019499b434STrond Myklebust spin_unlock(&cache->lock); 4021da177e4SLinus Torvalds spin_unlock(&rpc_credcache_lock); 4031da177e4SLinus Torvalds rpcauth_destroy_credlist(&free); 4041da177e4SLinus Torvalds } 4051da177e4SLinus Torvalds 4063ab9bb72STrond Myklebust /* 4073ab9bb72STrond Myklebust * Destroy the RPC credential cache 4083ab9bb72STrond Myklebust */ 4093ab9bb72STrond Myklebust void 4103ab9bb72STrond Myklebust rpcauth_destroy_credcache(struct rpc_auth *auth) 4113ab9bb72STrond Myklebust { 4123ab9bb72STrond Myklebust struct rpc_cred_cache *cache = auth->au_credcache; 4133ab9bb72STrond Myklebust 4143ab9bb72STrond Myklebust if (cache) { 4153ab9bb72STrond Myklebust auth->au_credcache = NULL; 4163ab9bb72STrond Myklebust rpcauth_clear_credcache(cache); 417241269bdSTrond Myklebust kfree(cache->hashtable); 4183ab9bb72STrond Myklebust kfree(cache); 4193ab9bb72STrond Myklebust } 4203ab9bb72STrond Myklebust } 421e8914c65STrond Myklebust EXPORT_SYMBOL_GPL(rpcauth_destroy_credcache); 4223ab9bb72STrond Myklebust 423d2b83141STrond Myklebust 424d2b83141STrond Myklebust #define RPC_AUTH_EXPIRY_MORATORIUM (60 * HZ) 425d2b83141STrond Myklebust 4261da177e4SLinus Torvalds /* 4271da177e4SLinus Torvalds * Remove stale credentials. Avoid sleeping inside the loop. 4281da177e4SLinus Torvalds */ 42970534a73SDave Chinner static long 430f5c2187cSTrond Myklebust rpcauth_prune_expired(struct list_head *free, int nr_to_scan) 4311da177e4SLinus Torvalds { 432eac0d18dSTrond Myklebust struct rpc_cred *cred, *next; 433d2b83141STrond Myklebust unsigned long expired = jiffies - RPC_AUTH_EXPIRY_MORATORIUM; 43470534a73SDave Chinner long freed = 0; 4351da177e4SLinus Torvalds 436eac0d18dSTrond Myklebust list_for_each_entry_safe(cred, next, &cred_unused, cr_lru) { 437eac0d18dSTrond Myklebust 43820673406STrond Myklebust if (nr_to_scan-- == 0) 43920673406STrond Myklebust break; 44079b18181STrond Myklebust if (refcount_read(&cred->cr_count) > 1) { 44195cd6232STrond Myklebust rpcauth_lru_remove_locked(cred); 44295cd6232STrond Myklebust continue; 44395cd6232STrond Myklebust } 44493a05e65STrond Myklebust /* 44593a05e65STrond Myklebust * Enforce a 60 second garbage collection moratorium 44693a05e65STrond Myklebust * Note that the cred_unused list must be time-ordered. 44793a05e65STrond Myklebust */ 44895cd6232STrond Myklebust if (!time_in_range(cred->cr_expire, expired, jiffies)) 44995cd6232STrond Myklebust continue; 45095cd6232STrond Myklebust if (!rpcauth_unhash_cred(cred)) 451e092bdcdSTrond Myklebust continue; 452eac0d18dSTrond Myklebust 45395cd6232STrond Myklebust rpcauth_lru_remove_locked(cred); 45495cd6232STrond Myklebust freed++; 455e092bdcdSTrond Myklebust list_add_tail(&cred->cr_lru, free); 4561da177e4SLinus Torvalds } 45795cd6232STrond Myklebust return freed ? freed : SHRINK_STOP; 4581da177e4SLinus Torvalds } 459e092bdcdSTrond Myklebust 460bae6746fSTrond Myklebust static unsigned long 461bae6746fSTrond Myklebust rpcauth_cache_do_shrink(int nr_to_scan) 462bae6746fSTrond Myklebust { 463bae6746fSTrond Myklebust LIST_HEAD(free); 464bae6746fSTrond Myklebust unsigned long freed; 465bae6746fSTrond Myklebust 466bae6746fSTrond Myklebust spin_lock(&rpc_credcache_lock); 467bae6746fSTrond Myklebust freed = rpcauth_prune_expired(&free, nr_to_scan); 468bae6746fSTrond Myklebust spin_unlock(&rpc_credcache_lock); 469bae6746fSTrond Myklebust rpcauth_destroy_credlist(&free); 470bae6746fSTrond Myklebust 471bae6746fSTrond Myklebust return freed; 472bae6746fSTrond Myklebust } 473bae6746fSTrond Myklebust 474e092bdcdSTrond Myklebust /* 475f5c2187cSTrond Myklebust * Run memory cache shrinker. 476e092bdcdSTrond Myklebust */ 47770534a73SDave Chinner static unsigned long 47870534a73SDave Chinner rpcauth_cache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) 47970534a73SDave Chinner 480e092bdcdSTrond Myklebust { 48170534a73SDave Chinner if ((sc->gfp_mask & GFP_KERNEL) != GFP_KERNEL) 48270534a73SDave Chinner return SHRINK_STOP; 48370534a73SDave Chinner 48470534a73SDave Chinner /* nothing left, don't come back */ 485f5c2187cSTrond Myklebust if (list_empty(&cred_unused)) 48670534a73SDave Chinner return SHRINK_STOP; 48770534a73SDave Chinner 488bae6746fSTrond Myklebust return rpcauth_cache_do_shrink(sc->nr_to_scan); 48970534a73SDave Chinner } 49070534a73SDave Chinner 49170534a73SDave Chinner static unsigned long 49270534a73SDave Chinner rpcauth_cache_shrink_count(struct shrinker *shrink, struct shrink_control *sc) 49370534a73SDave Chinner 49470534a73SDave Chinner { 4954c3ffd05SNeilBrown return number_cred_unused * sysctl_vfs_cache_pressure / 100; 4961da177e4SLinus Torvalds } 4971da177e4SLinus Torvalds 498bae6746fSTrond Myklebust static void 499bae6746fSTrond Myklebust rpcauth_cache_enforce_limit(void) 500bae6746fSTrond Myklebust { 501bae6746fSTrond Myklebust unsigned long diff; 502bae6746fSTrond Myklebust unsigned int nr_to_scan; 503bae6746fSTrond Myklebust 504bae6746fSTrond Myklebust if (number_cred_unused <= auth_max_cred_cachesize) 505bae6746fSTrond Myklebust return; 506bae6746fSTrond Myklebust diff = number_cred_unused - auth_max_cred_cachesize; 507bae6746fSTrond Myklebust nr_to_scan = 100; 508bae6746fSTrond Myklebust if (diff < nr_to_scan) 509bae6746fSTrond Myklebust nr_to_scan = diff; 510bae6746fSTrond Myklebust rpcauth_cache_do_shrink(nr_to_scan); 511bae6746fSTrond Myklebust } 512bae6746fSTrond Myklebust 5131da177e4SLinus Torvalds /* 5141da177e4SLinus Torvalds * Look up a process' credentials in the authentication cache 5151da177e4SLinus Torvalds */ 5161da177e4SLinus Torvalds struct rpc_cred * 5171da177e4SLinus Torvalds rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, 5183c6e0bc8SJeff Layton int flags, gfp_t gfp) 5191da177e4SLinus Torvalds { 520e092bdcdSTrond Myklebust LIST_HEAD(free); 5211da177e4SLinus Torvalds struct rpc_cred_cache *cache = auth->au_credcache; 52231be5bf1STrond Myklebust struct rpc_cred *cred = NULL, 52331be5bf1STrond Myklebust *entry, *new; 52425337fdcSTrond Myklebust unsigned int nr; 52525337fdcSTrond Myklebust 52666cbd4baSFrank Sorenson nr = auth->au_ops->hash_cred(acred, cache->hashbits); 5271da177e4SLinus Torvalds 52831be5bf1STrond Myklebust rcu_read_lock(); 529b67bfe0dSSasha Levin hlist_for_each_entry_rcu(entry, &cache->hashtable[nr], cr_hash) { 53031be5bf1STrond Myklebust if (!entry->cr_ops->crmatch(acred, entry, flags)) 53131be5bf1STrond Myklebust continue; 53231be5bf1STrond Myklebust cred = get_rpccred(entry); 53307d02a67STrond Myklebust if (cred) 53431be5bf1STrond Myklebust break; 53531be5bf1STrond Myklebust } 53631be5bf1STrond Myklebust rcu_read_unlock(); 53731be5bf1STrond Myklebust 5389499b434STrond Myklebust if (cred != NULL) 53931be5bf1STrond Myklebust goto found; 54031be5bf1STrond Myklebust 5413c6e0bc8SJeff Layton new = auth->au_ops->crcreate(auth, acred, flags, gfp); 54231be5bf1STrond Myklebust if (IS_ERR(new)) { 54331be5bf1STrond Myklebust cred = new; 54431be5bf1STrond Myklebust goto out; 54531be5bf1STrond Myklebust } 54631be5bf1STrond Myklebust 5479499b434STrond Myklebust spin_lock(&cache->lock); 548b67bfe0dSSasha Levin hlist_for_each_entry(entry, &cache->hashtable[nr], cr_hash) { 549e092bdcdSTrond Myklebust if (!entry->cr_ops->crmatch(acred, entry, flags)) 550e092bdcdSTrond Myklebust continue; 551e092bdcdSTrond Myklebust cred = get_rpccred(entry); 55207d02a67STrond Myklebust if (cred) 5531da177e4SLinus Torvalds break; 5541da177e4SLinus Torvalds } 55531be5bf1STrond Myklebust if (cred == NULL) { 55631be5bf1STrond Myklebust cred = new; 55731be5bf1STrond Myklebust set_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags); 55879b18181STrond Myklebust refcount_inc(&cred->cr_count); 55931be5bf1STrond Myklebust hlist_add_head_rcu(&cred->cr_hash, &cache->hashtable[nr]); 56031be5bf1STrond Myklebust } else 561e092bdcdSTrond Myklebust list_add_tail(&new->cr_lru, &free); 5629499b434STrond Myklebust spin_unlock(&cache->lock); 563bae6746fSTrond Myklebust rpcauth_cache_enforce_limit(); 56431be5bf1STrond Myklebust found: 565f64f9e71SJoe Perches if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) && 566f64f9e71SJoe Perches cred->cr_ops->cr_init != NULL && 567f64f9e71SJoe Perches !(flags & RPCAUTH_LOOKUP_NEW)) { 568fba3bad4STrond Myklebust int res = cred->cr_ops->cr_init(auth, cred); 569fba3bad4STrond Myklebust if (res < 0) { 570fba3bad4STrond Myklebust put_rpccred(cred); 571fba3bad4STrond Myklebust cred = ERR_PTR(res); 572fba3bad4STrond Myklebust } 5731da177e4SLinus Torvalds } 57431be5bf1STrond Myklebust rpcauth_destroy_credlist(&free); 57531be5bf1STrond Myklebust out: 57631be5bf1STrond Myklebust return cred; 5771da177e4SLinus Torvalds } 578e8914c65STrond Myklebust EXPORT_SYMBOL_GPL(rpcauth_lookup_credcache); 5791da177e4SLinus Torvalds 5801da177e4SLinus Torvalds struct rpc_cred * 5818a317760STrond Myklebust rpcauth_lookupcred(struct rpc_auth *auth, int flags) 5821da177e4SLinus Torvalds { 58386a264abSDavid Howells struct auth_cred acred; 5841da177e4SLinus Torvalds struct rpc_cred *ret; 58586a264abSDavid Howells const struct cred *cred = current_cred(); 5861da177e4SLinus Torvalds 58786a264abSDavid Howells memset(&acred, 0, sizeof(acred)); 58897f68c6bSNeilBrown acred.cred = cred; 5898a317760STrond Myklebust ret = auth->au_ops->lookup_cred(auth, &acred, flags); 5901da177e4SLinus Torvalds return ret; 5911da177e4SLinus Torvalds } 59266b06860SAndy Adamson EXPORT_SYMBOL_GPL(rpcauth_lookupcred); 5931da177e4SLinus Torvalds 5945fe4755eSTrond Myklebust void 5955fe4755eSTrond Myklebust rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred, 5965fe4755eSTrond Myklebust struct rpc_auth *auth, const struct rpc_credops *ops) 5975fe4755eSTrond Myklebust { 5985fe4755eSTrond Myklebust INIT_HLIST_NODE(&cred->cr_hash); 599e092bdcdSTrond Myklebust INIT_LIST_HEAD(&cred->cr_lru); 60079b18181STrond Myklebust refcount_set(&cred->cr_count, 1); 6015fe4755eSTrond Myklebust cred->cr_auth = auth; 6022edd8d74SNeilBrown cred->cr_flags = 0; 6035fe4755eSTrond Myklebust cred->cr_ops = ops; 6045fe4755eSTrond Myklebust cred->cr_expire = jiffies; 60597f68c6bSNeilBrown cred->cr_cred = get_cred(acred->cred); 6065fe4755eSTrond Myklebust } 607e8914c65STrond Myklebust EXPORT_SYMBOL_GPL(rpcauth_init_cred); 6085fe4755eSTrond Myklebust 6098572b8e2STrond Myklebust static struct rpc_cred * 6105d351754STrond Myklebust rpcauth_bind_root_cred(struct rpc_task *task, int lookupflags) 6111da177e4SLinus Torvalds { 6121be27f36STrond Myklebust struct rpc_auth *auth = task->tk_client->cl_auth; 6131da177e4SLinus Torvalds struct auth_cred acred = { 61497f68c6bSNeilBrown .cred = get_task_cred(&init_task), 6151da177e4SLinus Torvalds }; 61697f68c6bSNeilBrown struct rpc_cred *ret; 6171da177e4SLinus Torvalds 618a41b05edSNeilBrown if (RPC_IS_ASYNC(task)) 619a41b05edSNeilBrown lookupflags |= RPCAUTH_LOOKUP_ASYNC; 62097f68c6bSNeilBrown ret = auth->au_ops->lookup_cred(auth, &acred, lookupflags); 62197f68c6bSNeilBrown put_cred(acred.cred); 62297f68c6bSNeilBrown return ret; 623af093835STrond Myklebust } 624af093835STrond Myklebust 6258572b8e2STrond Myklebust static struct rpc_cred * 6265e16923bSNeilBrown rpcauth_bind_machine_cred(struct rpc_task *task, int lookupflags) 6275e16923bSNeilBrown { 6285e16923bSNeilBrown struct rpc_auth *auth = task->tk_client->cl_auth; 6295e16923bSNeilBrown struct auth_cred acred = { 6305e16923bSNeilBrown .principal = task->tk_client->cl_principal, 6315e16923bSNeilBrown .cred = init_task.cred, 6325e16923bSNeilBrown }; 6335e16923bSNeilBrown 6345e16923bSNeilBrown if (!acred.principal) 6355e16923bSNeilBrown return NULL; 636a41b05edSNeilBrown if (RPC_IS_ASYNC(task)) 637a41b05edSNeilBrown lookupflags |= RPCAUTH_LOOKUP_ASYNC; 6385e16923bSNeilBrown return auth->au_ops->lookup_cred(auth, &acred, lookupflags); 6395e16923bSNeilBrown } 6405e16923bSNeilBrown 6415e16923bSNeilBrown static struct rpc_cred * 6425d351754STrond Myklebust rpcauth_bind_new_cred(struct rpc_task *task, int lookupflags) 643af093835STrond Myklebust { 644af093835STrond Myklebust struct rpc_auth *auth = task->tk_client->cl_auth; 645af093835STrond Myklebust 6468572b8e2STrond Myklebust return rpcauth_lookupcred(auth, lookupflags); 6471da177e4SLinus Torvalds } 6481da177e4SLinus Torvalds 649a17c2153STrond Myklebust static int 650a52458b4SNeilBrown rpcauth_bindcred(struct rpc_task *task, const struct cred *cred, int flags) 6511da177e4SLinus Torvalds { 652a17c2153STrond Myklebust struct rpc_rqst *req = task->tk_rqstp; 6535e16923bSNeilBrown struct rpc_cred *new = NULL; 6545d351754STrond Myklebust int lookupflags = 0; 655a52458b4SNeilBrown struct rpc_auth *auth = task->tk_client->cl_auth; 656a52458b4SNeilBrown struct auth_cred acred = { 657a52458b4SNeilBrown .cred = cred, 658a52458b4SNeilBrown }; 6595d351754STrond Myklebust 6605d351754STrond Myklebust if (flags & RPC_TASK_ASYNC) 661a41b05edSNeilBrown lookupflags |= RPCAUTH_LOOKUP_NEW | RPCAUTH_LOOKUP_ASYNC; 6621de7eea9SNeilBrown if (task->tk_op_cred) 6631de7eea9SNeilBrown /* Task must use exactly this rpc_cred */ 664d6efccd9SNeilBrown new = get_rpccred(task->tk_op_cred); 6651de7eea9SNeilBrown else if (cred != NULL && cred != &machine_cred) 666a52458b4SNeilBrown new = auth->au_ops->lookup_cred(auth, &acred, lookupflags); 6675e16923bSNeilBrown else if (cred == &machine_cred) 6685e16923bSNeilBrown new = rpcauth_bind_machine_cred(task, lookupflags); 6695e16923bSNeilBrown 6705e16923bSNeilBrown /* If machine cred couldn't be bound, try a root cred */ 6715e16923bSNeilBrown if (new) 6725e16923bSNeilBrown ; 673*89c2be8aSNeilBrown else if (cred == &machine_cred) 6748572b8e2STrond Myklebust new = rpcauth_bind_root_cred(task, lookupflags); 675a68a72e1SNeilBrown else if (flags & RPC_TASK_NULLCREDS) 676a68a72e1SNeilBrown new = authnull_ops.lookup_cred(NULL, NULL, 0); 6774ccda2cdSTrond Myklebust else 6788572b8e2STrond Myklebust new = rpcauth_bind_new_cred(task, lookupflags); 6798572b8e2STrond Myklebust if (IS_ERR(new)) 6808572b8e2STrond Myklebust return PTR_ERR(new); 681a17c2153STrond Myklebust put_rpccred(req->rq_cred); 682a17c2153STrond Myklebust req->rq_cred = new; 6838572b8e2STrond Myklebust return 0; 6841da177e4SLinus Torvalds } 6851da177e4SLinus Torvalds 6861da177e4SLinus Torvalds void 6871da177e4SLinus Torvalds put_rpccred(struct rpc_cred *cred) 6881da177e4SLinus Torvalds { 6899a8f6b5eSTrond Myklebust if (cred == NULL) 6909a8f6b5eSTrond Myklebust return; 69195cd6232STrond Myklebust rcu_read_lock(); 69279b18181STrond Myklebust if (refcount_dec_and_test(&cred->cr_count)) 69395cd6232STrond Myklebust goto destroy; 69479b18181STrond Myklebust if (refcount_read(&cred->cr_count) != 1 || 69595cd6232STrond Myklebust !test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags)) 69695cd6232STrond Myklebust goto out; 697f0380f3dSTrond Myklebust if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0) { 698e092bdcdSTrond Myklebust cred->cr_expire = jiffies; 69995cd6232STrond Myklebust rpcauth_lru_add(cred); 70095cd6232STrond Myklebust /* Race breaker */ 70195cd6232STrond Myklebust if (unlikely(!test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags))) 70295cd6232STrond Myklebust rpcauth_lru_remove(cred); 70395cd6232STrond Myklebust } else if (rpcauth_unhash_cred(cred)) { 70495cd6232STrond Myklebust rpcauth_lru_remove(cred); 70579b18181STrond Myklebust if (refcount_dec_and_test(&cred->cr_count)) 70695cd6232STrond Myklebust goto destroy; 707f0380f3dSTrond Myklebust } 70895cd6232STrond Myklebust out: 70995cd6232STrond Myklebust rcu_read_unlock(); 710f0380f3dSTrond Myklebust return; 71195cd6232STrond Myklebust destroy: 71295cd6232STrond Myklebust rcu_read_unlock(); 71395cd6232STrond Myklebust cred->cr_ops->crdestroy(cred); 7141da177e4SLinus Torvalds } 715e8914c65STrond Myklebust EXPORT_SYMBOL_GPL(put_rpccred); 7161da177e4SLinus Torvalds 717e8680a24SChuck Lever /** 718e8680a24SChuck Lever * rpcauth_marshcred - Append RPC credential to end of @xdr 719e8680a24SChuck Lever * @task: controlling RPC task 720e8680a24SChuck Lever * @xdr: xdr_stream containing initial portion of RPC Call header 721e8680a24SChuck Lever * 722e8680a24SChuck Lever * On success, an appropriate verifier is added to @xdr, @xdr is 723e8680a24SChuck Lever * updated to point past the verifier, and zero is returned. 724e8680a24SChuck Lever * Otherwise, @xdr is in an undefined state and a negative errno 725e8680a24SChuck Lever * is returned. 726e8680a24SChuck Lever */ 727e8680a24SChuck Lever int rpcauth_marshcred(struct rpc_task *task, struct xdr_stream *xdr) 7281da177e4SLinus Torvalds { 729e8680a24SChuck Lever const struct rpc_credops *ops = task->tk_rqstp->rq_cred->cr_ops; 7301da177e4SLinus Torvalds 731e8680a24SChuck Lever return ops->crmarshal(task, xdr); 7321da177e4SLinus Torvalds } 7331da177e4SLinus Torvalds 734e8680a24SChuck Lever /** 735e8680a24SChuck Lever * rpcauth_wrap_req_encode - XDR encode the RPC procedure 736e8680a24SChuck Lever * @task: controlling RPC task 737e8680a24SChuck Lever * @xdr: stream where on-the-wire bytes are to be marshalled 738e8680a24SChuck Lever * 739e8680a24SChuck Lever * On success, @xdr contains the encoded and wrapped message. 740e8680a24SChuck Lever * Otherwise, @xdr is in an undefined state. 741e8680a24SChuck Lever */ 742e8680a24SChuck Lever int rpcauth_wrap_req_encode(struct rpc_task *task, struct xdr_stream *xdr) 7439f06c719SChuck Lever { 744e8680a24SChuck Lever kxdreproc_t encode = task->tk_msg.rpc_proc->p_encode; 7459f06c719SChuck Lever 746e8680a24SChuck Lever encode(task->tk_rqstp, xdr, task->tk_msg.rpc_argp); 7479f06c719SChuck Lever return 0; 7481da177e4SLinus Torvalds } 749e8680a24SChuck Lever EXPORT_SYMBOL_GPL(rpcauth_wrap_req_encode); 750e8680a24SChuck Lever 751e8680a24SChuck Lever /** 752e8680a24SChuck Lever * rpcauth_wrap_req - XDR encode and wrap the RPC procedure 753e8680a24SChuck Lever * @task: controlling RPC task 754e8680a24SChuck Lever * @xdr: stream where on-the-wire bytes are to be marshalled 755e8680a24SChuck Lever * 756e8680a24SChuck Lever * On success, @xdr contains the encoded and wrapped message, 757e8680a24SChuck Lever * and zero is returned. Otherwise, @xdr is in an undefined 758e8680a24SChuck Lever * state and a negative errno is returned. 759e8680a24SChuck Lever */ 760e8680a24SChuck Lever int rpcauth_wrap_req(struct rpc_task *task, struct xdr_stream *xdr) 761e8680a24SChuck Lever { 762e8680a24SChuck Lever const struct rpc_credops *ops = task->tk_rqstp->rq_cred->cr_ops; 763e8680a24SChuck Lever 764e8680a24SChuck Lever return ops->crwrap_req(task, xdr); 765e8680a24SChuck Lever } 7661da177e4SLinus Torvalds 767a0584ee9SChuck Lever /** 768a0584ee9SChuck Lever * rpcauth_checkverf - Validate verifier in RPC Reply header 769a0584ee9SChuck Lever * @task: controlling RPC task 770a0584ee9SChuck Lever * @xdr: xdr_stream containing RPC Reply header 771a0584ee9SChuck Lever * 772a0584ee9SChuck Lever * On success, @xdr is updated to point past the verifier and 773a0584ee9SChuck Lever * zero is returned. Otherwise, @xdr is in an undefined state 774a0584ee9SChuck Lever * and a negative errno is returned. 775a0584ee9SChuck Lever */ 776a0584ee9SChuck Lever int 777a0584ee9SChuck Lever rpcauth_checkverf(struct rpc_task *task, struct xdr_stream *xdr) 778bf269551SChuck Lever { 779a0584ee9SChuck Lever const struct rpc_credops *ops = task->tk_rqstp->rq_cred->cr_ops; 780bf269551SChuck Lever 781a0584ee9SChuck Lever return ops->crvalidate(task, xdr); 782bf269551SChuck Lever } 783bf269551SChuck Lever 784a0584ee9SChuck Lever /** 785a0584ee9SChuck Lever * rpcauth_unwrap_resp_decode - Invoke XDR decode function 786a0584ee9SChuck Lever * @task: controlling RPC task 787a0584ee9SChuck Lever * @xdr: stream where the Reply message resides 788a0584ee9SChuck Lever * 789a0584ee9SChuck Lever * Returns zero on success; otherwise a negative errno is returned. 790a0584ee9SChuck Lever */ 7911da177e4SLinus Torvalds int 792a0584ee9SChuck Lever rpcauth_unwrap_resp_decode(struct rpc_task *task, struct xdr_stream *xdr) 7931da177e4SLinus Torvalds { 794a0584ee9SChuck Lever kxdrdproc_t decode = task->tk_msg.rpc_proc->p_decode; 7951da177e4SLinus Torvalds 796a0584ee9SChuck Lever return decode(task->tk_rqstp, xdr, task->tk_msg.rpc_resp); 797a0584ee9SChuck Lever } 798a0584ee9SChuck Lever EXPORT_SYMBOL_GPL(rpcauth_unwrap_resp_decode); 799a0584ee9SChuck Lever 800a0584ee9SChuck Lever /** 801a0584ee9SChuck Lever * rpcauth_unwrap_resp - Invoke unwrap and decode function for the cred 802a0584ee9SChuck Lever * @task: controlling RPC task 803a0584ee9SChuck Lever * @xdr: stream where the Reply message resides 804a0584ee9SChuck Lever * 805a0584ee9SChuck Lever * Returns zero on success; otherwise a negative errno is returned. 806a0584ee9SChuck Lever */ 807a0584ee9SChuck Lever int 808a0584ee9SChuck Lever rpcauth_unwrap_resp(struct rpc_task *task, struct xdr_stream *xdr) 809a0584ee9SChuck Lever { 810a0584ee9SChuck Lever const struct rpc_credops *ops = task->tk_rqstp->rq_cred->cr_ops; 811a0584ee9SChuck Lever 812a0584ee9SChuck Lever return ops->crunwrap_resp(task, xdr); 8131da177e4SLinus Torvalds } 8141da177e4SLinus Torvalds 8153021a5bbSTrond Myklebust bool 8163021a5bbSTrond Myklebust rpcauth_xmit_need_reencode(struct rpc_task *task) 8173021a5bbSTrond Myklebust { 8183021a5bbSTrond Myklebust struct rpc_cred *cred = task->tk_rqstp->rq_cred; 8193021a5bbSTrond Myklebust 8203021a5bbSTrond Myklebust if (!cred || !cred->cr_ops->crneed_reencode) 8213021a5bbSTrond Myklebust return false; 8223021a5bbSTrond Myklebust return cred->cr_ops->crneed_reencode(task); 8233021a5bbSTrond Myklebust } 8243021a5bbSTrond Myklebust 8251da177e4SLinus Torvalds int 8261da177e4SLinus Torvalds rpcauth_refreshcred(struct rpc_task *task) 8271da177e4SLinus Torvalds { 8289a84d380STrond Myklebust struct rpc_cred *cred; 8291da177e4SLinus Torvalds int err; 8301da177e4SLinus Torvalds 831a17c2153STrond Myklebust cred = task->tk_rqstp->rq_cred; 832a17c2153STrond Myklebust if (cred == NULL) { 833a17c2153STrond Myklebust err = rpcauth_bindcred(task, task->tk_msg.rpc_cred, task->tk_flags); 834a17c2153STrond Myklebust if (err < 0) 835a17c2153STrond Myklebust goto out; 836a17c2153STrond Myklebust cred = task->tk_rqstp->rq_cred; 837f81c6224SJoe Perches } 8380bbacc40SChuck Lever 8391da177e4SLinus Torvalds err = cred->cr_ops->crrefresh(task); 840a17c2153STrond Myklebust out: 8411da177e4SLinus Torvalds if (err < 0) 8421da177e4SLinus Torvalds task->tk_status = err; 8431da177e4SLinus Torvalds return err; 8441da177e4SLinus Torvalds } 8451da177e4SLinus Torvalds 8461da177e4SLinus Torvalds void 8471da177e4SLinus Torvalds rpcauth_invalcred(struct rpc_task *task) 8481da177e4SLinus Torvalds { 849a17c2153STrond Myklebust struct rpc_cred *cred = task->tk_rqstp->rq_cred; 850fc432dd9STrond Myklebust 851fc432dd9STrond Myklebust if (cred) 852fc432dd9STrond Myklebust clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); 8531da177e4SLinus Torvalds } 8541da177e4SLinus Torvalds 8551da177e4SLinus Torvalds int 8561da177e4SLinus Torvalds rpcauth_uptodatecred(struct rpc_task *task) 8571da177e4SLinus Torvalds { 858a17c2153STrond Myklebust struct rpc_cred *cred = task->tk_rqstp->rq_cred; 859fc432dd9STrond Myklebust 860fc432dd9STrond Myklebust return cred == NULL || 861fc432dd9STrond Myklebust test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0; 8621da177e4SLinus Torvalds } 863f5c2187cSTrond Myklebust 8648e1f936bSRusty Russell static struct shrinker rpc_cred_shrinker = { 86570534a73SDave Chinner .count_objects = rpcauth_cache_shrink_count, 86670534a73SDave Chinner .scan_objects = rpcauth_cache_shrink_scan, 8678e1f936bSRusty Russell .seeks = DEFAULT_SEEKS, 8688e1f936bSRusty Russell }; 869f5c2187cSTrond Myklebust 8705d8d9a4dSTrond Myklebust int __init rpcauth_init_module(void) 871f5c2187cSTrond Myklebust { 8725d8d9a4dSTrond Myklebust int err; 8735d8d9a4dSTrond Myklebust 8745d8d9a4dSTrond Myklebust err = rpc_init_authunix(); 8755d8d9a4dSTrond Myklebust if (err < 0) 8765d8d9a4dSTrond Myklebust goto out1; 8772864486bSKinglong Mee err = register_shrinker(&rpc_cred_shrinker); 8782864486bSKinglong Mee if (err < 0) 87989a4f758SNeilBrown goto out2; 8805d8d9a4dSTrond Myklebust return 0; 8815d8d9a4dSTrond Myklebust out2: 8825d8d9a4dSTrond Myklebust rpc_destroy_authunix(); 8835d8d9a4dSTrond Myklebust out1: 8845d8d9a4dSTrond Myklebust return err; 885f5c2187cSTrond Myklebust } 886f5c2187cSTrond Myklebust 887c135e84aSStephen Rothwell void rpcauth_remove_module(void) 888f5c2187cSTrond Myklebust { 8895d8d9a4dSTrond Myklebust rpc_destroy_authunix(); 8908e1f936bSRusty Russell unregister_shrinker(&rpc_cred_shrinker); 891f5c2187cSTrond Myklebust } 892