162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/net/sunrpc/auth.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Generic RPC client authentication API. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/types.h> 1162306a36Sopenharmony_ci#include <linux/sched.h> 1262306a36Sopenharmony_ci#include <linux/cred.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci#include <linux/errno.h> 1662306a36Sopenharmony_ci#include <linux/hash.h> 1762306a36Sopenharmony_ci#include <linux/sunrpc/clnt.h> 1862306a36Sopenharmony_ci#include <linux/sunrpc/gss_api.h> 1962306a36Sopenharmony_ci#include <linux/spinlock.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <trace/events/sunrpc.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define RPC_CREDCACHE_DEFAULT_HASHBITS (4) 2462306a36Sopenharmony_cistruct rpc_cred_cache { 2562306a36Sopenharmony_ci struct hlist_head *hashtable; 2662306a36Sopenharmony_ci unsigned int hashbits; 2762306a36Sopenharmony_ci spinlock_t lock; 2862306a36Sopenharmony_ci}; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic unsigned int auth_hashbits = RPC_CREDCACHE_DEFAULT_HASHBITS; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic const struct rpc_authops __rcu *auth_flavors[RPC_AUTH_MAXFLAVOR] = { 3362306a36Sopenharmony_ci [RPC_AUTH_NULL] = (const struct rpc_authops __force __rcu *)&authnull_ops, 3462306a36Sopenharmony_ci [RPC_AUTH_UNIX] = (const struct rpc_authops __force __rcu *)&authunix_ops, 3562306a36Sopenharmony_ci [RPC_AUTH_TLS] = (const struct rpc_authops __force __rcu *)&authtls_ops, 3662306a36Sopenharmony_ci}; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic LIST_HEAD(cred_unused); 3962306a36Sopenharmony_cistatic unsigned long number_cred_unused; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic struct cred machine_cred = { 4262306a36Sopenharmony_ci .usage = ATOMIC_INIT(1), 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* 4662306a36Sopenharmony_ci * Return the machine_cred pointer to be used whenever 4762306a36Sopenharmony_ci * the a generic machine credential is needed. 4862306a36Sopenharmony_ci */ 4962306a36Sopenharmony_ciconst struct cred *rpc_machine_cred(void) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci return &machine_cred; 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_machine_cred); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#define MAX_HASHTABLE_BITS (14) 5662306a36Sopenharmony_cistatic int param_set_hashtbl_sz(const char *val, const struct kernel_param *kp) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci unsigned long num; 5962306a36Sopenharmony_ci unsigned int nbits; 6062306a36Sopenharmony_ci int ret; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (!val) 6362306a36Sopenharmony_ci goto out_inval; 6462306a36Sopenharmony_ci ret = kstrtoul(val, 0, &num); 6562306a36Sopenharmony_ci if (ret) 6662306a36Sopenharmony_ci goto out_inval; 6762306a36Sopenharmony_ci nbits = fls(num - 1); 6862306a36Sopenharmony_ci if (nbits > MAX_HASHTABLE_BITS || nbits < 2) 6962306a36Sopenharmony_ci goto out_inval; 7062306a36Sopenharmony_ci *(unsigned int *)kp->arg = nbits; 7162306a36Sopenharmony_ci return 0; 7262306a36Sopenharmony_ciout_inval: 7362306a36Sopenharmony_ci return -EINVAL; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic int param_get_hashtbl_sz(char *buffer, const struct kernel_param *kp) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci unsigned int nbits; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci nbits = *(unsigned int *)kp->arg; 8162306a36Sopenharmony_ci return sprintf(buffer, "%u\n", 1U << nbits); 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci#define param_check_hashtbl_sz(name, p) __param_check(name, p, unsigned int); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic const struct kernel_param_ops param_ops_hashtbl_sz = { 8762306a36Sopenharmony_ci .set = param_set_hashtbl_sz, 8862306a36Sopenharmony_ci .get = param_get_hashtbl_sz, 8962306a36Sopenharmony_ci}; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cimodule_param_named(auth_hashtable_size, auth_hashbits, hashtbl_sz, 0644); 9262306a36Sopenharmony_ciMODULE_PARM_DESC(auth_hashtable_size, "RPC credential cache hashtable size"); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic unsigned long auth_max_cred_cachesize = ULONG_MAX; 9562306a36Sopenharmony_cimodule_param(auth_max_cred_cachesize, ulong, 0644); 9662306a36Sopenharmony_ciMODULE_PARM_DESC(auth_max_cred_cachesize, "RPC credential maximum total cache size"); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic u32 9962306a36Sopenharmony_cipseudoflavor_to_flavor(u32 flavor) { 10062306a36Sopenharmony_ci if (flavor > RPC_AUTH_MAXFLAVOR) 10162306a36Sopenharmony_ci return RPC_AUTH_GSS; 10262306a36Sopenharmony_ci return flavor; 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ciint 10662306a36Sopenharmony_cirpcauth_register(const struct rpc_authops *ops) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci const struct rpc_authops *old; 10962306a36Sopenharmony_ci rpc_authflavor_t flavor; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR) 11262306a36Sopenharmony_ci return -EINVAL; 11362306a36Sopenharmony_ci old = cmpxchg((const struct rpc_authops ** __force)&auth_flavors[flavor], NULL, ops); 11462306a36Sopenharmony_ci if (old == NULL || old == ops) 11562306a36Sopenharmony_ci return 0; 11662306a36Sopenharmony_ci return -EPERM; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpcauth_register); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ciint 12162306a36Sopenharmony_cirpcauth_unregister(const struct rpc_authops *ops) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci const struct rpc_authops *old; 12462306a36Sopenharmony_ci rpc_authflavor_t flavor; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR) 12762306a36Sopenharmony_ci return -EINVAL; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci old = cmpxchg((const struct rpc_authops ** __force)&auth_flavors[flavor], ops, NULL); 13062306a36Sopenharmony_ci if (old == ops || old == NULL) 13162306a36Sopenharmony_ci return 0; 13262306a36Sopenharmony_ci return -EPERM; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpcauth_unregister); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic const struct rpc_authops * 13762306a36Sopenharmony_cirpcauth_get_authops(rpc_authflavor_t flavor) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci const struct rpc_authops *ops; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (flavor >= RPC_AUTH_MAXFLAVOR) 14262306a36Sopenharmony_ci return NULL; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci rcu_read_lock(); 14562306a36Sopenharmony_ci ops = rcu_dereference(auth_flavors[flavor]); 14662306a36Sopenharmony_ci if (ops == NULL) { 14762306a36Sopenharmony_ci rcu_read_unlock(); 14862306a36Sopenharmony_ci request_module("rpc-auth-%u", flavor); 14962306a36Sopenharmony_ci rcu_read_lock(); 15062306a36Sopenharmony_ci ops = rcu_dereference(auth_flavors[flavor]); 15162306a36Sopenharmony_ci if (ops == NULL) 15262306a36Sopenharmony_ci goto out; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci if (!try_module_get(ops->owner)) 15562306a36Sopenharmony_ci ops = NULL; 15662306a36Sopenharmony_ciout: 15762306a36Sopenharmony_ci rcu_read_unlock(); 15862306a36Sopenharmony_ci return ops; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic void 16262306a36Sopenharmony_cirpcauth_put_authops(const struct rpc_authops *ops) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci module_put(ops->owner); 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci/** 16862306a36Sopenharmony_ci * rpcauth_get_pseudoflavor - check if security flavor is supported 16962306a36Sopenharmony_ci * @flavor: a security flavor 17062306a36Sopenharmony_ci * @info: a GSS mech OID, quality of protection, and service value 17162306a36Sopenharmony_ci * 17262306a36Sopenharmony_ci * Verifies that an appropriate kernel module is available or already loaded. 17362306a36Sopenharmony_ci * Returns an equivalent pseudoflavor, or RPC_AUTH_MAXFLAVOR if "flavor" is 17462306a36Sopenharmony_ci * not supported locally. 17562306a36Sopenharmony_ci */ 17662306a36Sopenharmony_cirpc_authflavor_t 17762306a36Sopenharmony_cirpcauth_get_pseudoflavor(rpc_authflavor_t flavor, struct rpcsec_gss_info *info) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci const struct rpc_authops *ops = rpcauth_get_authops(flavor); 18062306a36Sopenharmony_ci rpc_authflavor_t pseudoflavor; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (!ops) 18362306a36Sopenharmony_ci return RPC_AUTH_MAXFLAVOR; 18462306a36Sopenharmony_ci pseudoflavor = flavor; 18562306a36Sopenharmony_ci if (ops->info2flavor != NULL) 18662306a36Sopenharmony_ci pseudoflavor = ops->info2flavor(info); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci rpcauth_put_authops(ops); 18962306a36Sopenharmony_ci return pseudoflavor; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpcauth_get_pseudoflavor); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci/** 19462306a36Sopenharmony_ci * rpcauth_get_gssinfo - find GSS tuple matching a GSS pseudoflavor 19562306a36Sopenharmony_ci * @pseudoflavor: GSS pseudoflavor to match 19662306a36Sopenharmony_ci * @info: rpcsec_gss_info structure to fill in 19762306a36Sopenharmony_ci * 19862306a36Sopenharmony_ci * Returns zero and fills in "info" if pseudoflavor matches a 19962306a36Sopenharmony_ci * supported mechanism. 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_ciint 20262306a36Sopenharmony_cirpcauth_get_gssinfo(rpc_authflavor_t pseudoflavor, struct rpcsec_gss_info *info) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci rpc_authflavor_t flavor = pseudoflavor_to_flavor(pseudoflavor); 20562306a36Sopenharmony_ci const struct rpc_authops *ops; 20662306a36Sopenharmony_ci int result; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci ops = rpcauth_get_authops(flavor); 20962306a36Sopenharmony_ci if (ops == NULL) 21062306a36Sopenharmony_ci return -ENOENT; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci result = -ENOENT; 21362306a36Sopenharmony_ci if (ops->flavor2info != NULL) 21462306a36Sopenharmony_ci result = ops->flavor2info(pseudoflavor, info); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci rpcauth_put_authops(ops); 21762306a36Sopenharmony_ci return result; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpcauth_get_gssinfo); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistruct rpc_auth * 22262306a36Sopenharmony_cirpcauth_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci struct rpc_auth *auth = ERR_PTR(-EINVAL); 22562306a36Sopenharmony_ci const struct rpc_authops *ops; 22662306a36Sopenharmony_ci u32 flavor = pseudoflavor_to_flavor(args->pseudoflavor); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci ops = rpcauth_get_authops(flavor); 22962306a36Sopenharmony_ci if (ops == NULL) 23062306a36Sopenharmony_ci goto out; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci auth = ops->create(args, clnt); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci rpcauth_put_authops(ops); 23562306a36Sopenharmony_ci if (IS_ERR(auth)) 23662306a36Sopenharmony_ci return auth; 23762306a36Sopenharmony_ci if (clnt->cl_auth) 23862306a36Sopenharmony_ci rpcauth_release(clnt->cl_auth); 23962306a36Sopenharmony_ci clnt->cl_auth = auth; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ciout: 24262306a36Sopenharmony_ci return auth; 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpcauth_create); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_civoid 24762306a36Sopenharmony_cirpcauth_release(struct rpc_auth *auth) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci if (!refcount_dec_and_test(&auth->au_count)) 25062306a36Sopenharmony_ci return; 25162306a36Sopenharmony_ci auth->au_ops->destroy(auth); 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic DEFINE_SPINLOCK(rpc_credcache_lock); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci/* 25762306a36Sopenharmony_ci * On success, the caller is responsible for freeing the reference 25862306a36Sopenharmony_ci * held by the hashtable 25962306a36Sopenharmony_ci */ 26062306a36Sopenharmony_cistatic bool 26162306a36Sopenharmony_cirpcauth_unhash_cred_locked(struct rpc_cred *cred) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci if (!test_and_clear_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags)) 26462306a36Sopenharmony_ci return false; 26562306a36Sopenharmony_ci hlist_del_rcu(&cred->cr_hash); 26662306a36Sopenharmony_ci return true; 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic bool 27062306a36Sopenharmony_cirpcauth_unhash_cred(struct rpc_cred *cred) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci spinlock_t *cache_lock; 27362306a36Sopenharmony_ci bool ret; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (!test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags)) 27662306a36Sopenharmony_ci return false; 27762306a36Sopenharmony_ci cache_lock = &cred->cr_auth->au_credcache->lock; 27862306a36Sopenharmony_ci spin_lock(cache_lock); 27962306a36Sopenharmony_ci ret = rpcauth_unhash_cred_locked(cred); 28062306a36Sopenharmony_ci spin_unlock(cache_lock); 28162306a36Sopenharmony_ci return ret; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci/* 28562306a36Sopenharmony_ci * Initialize RPC credential cache 28662306a36Sopenharmony_ci */ 28762306a36Sopenharmony_ciint 28862306a36Sopenharmony_cirpcauth_init_credcache(struct rpc_auth *auth) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci struct rpc_cred_cache *new; 29162306a36Sopenharmony_ci unsigned int hashsize; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci new = kmalloc(sizeof(*new), GFP_KERNEL); 29462306a36Sopenharmony_ci if (!new) 29562306a36Sopenharmony_ci goto out_nocache; 29662306a36Sopenharmony_ci new->hashbits = auth_hashbits; 29762306a36Sopenharmony_ci hashsize = 1U << new->hashbits; 29862306a36Sopenharmony_ci new->hashtable = kcalloc(hashsize, sizeof(new->hashtable[0]), GFP_KERNEL); 29962306a36Sopenharmony_ci if (!new->hashtable) 30062306a36Sopenharmony_ci goto out_nohashtbl; 30162306a36Sopenharmony_ci spin_lock_init(&new->lock); 30262306a36Sopenharmony_ci auth->au_credcache = new; 30362306a36Sopenharmony_ci return 0; 30462306a36Sopenharmony_ciout_nohashtbl: 30562306a36Sopenharmony_ci kfree(new); 30662306a36Sopenharmony_ciout_nocache: 30762306a36Sopenharmony_ci return -ENOMEM; 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpcauth_init_credcache); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cichar * 31262306a36Sopenharmony_cirpcauth_stringify_acceptor(struct rpc_cred *cred) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci if (!cred->cr_ops->crstringify_acceptor) 31562306a36Sopenharmony_ci return NULL; 31662306a36Sopenharmony_ci return cred->cr_ops->crstringify_acceptor(cred); 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpcauth_stringify_acceptor); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci/* 32162306a36Sopenharmony_ci * Destroy a list of credentials 32262306a36Sopenharmony_ci */ 32362306a36Sopenharmony_cistatic inline 32462306a36Sopenharmony_civoid rpcauth_destroy_credlist(struct list_head *head) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci struct rpc_cred *cred; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci while (!list_empty(head)) { 32962306a36Sopenharmony_ci cred = list_entry(head->next, struct rpc_cred, cr_lru); 33062306a36Sopenharmony_ci list_del_init(&cred->cr_lru); 33162306a36Sopenharmony_ci put_rpccred(cred); 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic void 33662306a36Sopenharmony_cirpcauth_lru_add_locked(struct rpc_cred *cred) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci if (!list_empty(&cred->cr_lru)) 33962306a36Sopenharmony_ci return; 34062306a36Sopenharmony_ci number_cred_unused++; 34162306a36Sopenharmony_ci list_add_tail(&cred->cr_lru, &cred_unused); 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic void 34562306a36Sopenharmony_cirpcauth_lru_add(struct rpc_cred *cred) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci if (!list_empty(&cred->cr_lru)) 34862306a36Sopenharmony_ci return; 34962306a36Sopenharmony_ci spin_lock(&rpc_credcache_lock); 35062306a36Sopenharmony_ci rpcauth_lru_add_locked(cred); 35162306a36Sopenharmony_ci spin_unlock(&rpc_credcache_lock); 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic void 35562306a36Sopenharmony_cirpcauth_lru_remove_locked(struct rpc_cred *cred) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci if (list_empty(&cred->cr_lru)) 35862306a36Sopenharmony_ci return; 35962306a36Sopenharmony_ci number_cred_unused--; 36062306a36Sopenharmony_ci list_del_init(&cred->cr_lru); 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic void 36462306a36Sopenharmony_cirpcauth_lru_remove(struct rpc_cred *cred) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci if (list_empty(&cred->cr_lru)) 36762306a36Sopenharmony_ci return; 36862306a36Sopenharmony_ci spin_lock(&rpc_credcache_lock); 36962306a36Sopenharmony_ci rpcauth_lru_remove_locked(cred); 37062306a36Sopenharmony_ci spin_unlock(&rpc_credcache_lock); 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci/* 37462306a36Sopenharmony_ci * Clear the RPC credential cache, and delete those credentials 37562306a36Sopenharmony_ci * that are not referenced. 37662306a36Sopenharmony_ci */ 37762306a36Sopenharmony_civoid 37862306a36Sopenharmony_cirpcauth_clear_credcache(struct rpc_cred_cache *cache) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci LIST_HEAD(free); 38162306a36Sopenharmony_ci struct hlist_head *head; 38262306a36Sopenharmony_ci struct rpc_cred *cred; 38362306a36Sopenharmony_ci unsigned int hashsize = 1U << cache->hashbits; 38462306a36Sopenharmony_ci int i; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci spin_lock(&rpc_credcache_lock); 38762306a36Sopenharmony_ci spin_lock(&cache->lock); 38862306a36Sopenharmony_ci for (i = 0; i < hashsize; i++) { 38962306a36Sopenharmony_ci head = &cache->hashtable[i]; 39062306a36Sopenharmony_ci while (!hlist_empty(head)) { 39162306a36Sopenharmony_ci cred = hlist_entry(head->first, struct rpc_cred, cr_hash); 39262306a36Sopenharmony_ci rpcauth_unhash_cred_locked(cred); 39362306a36Sopenharmony_ci /* Note: We now hold a reference to cred */ 39462306a36Sopenharmony_ci rpcauth_lru_remove_locked(cred); 39562306a36Sopenharmony_ci list_add_tail(&cred->cr_lru, &free); 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci spin_unlock(&cache->lock); 39962306a36Sopenharmony_ci spin_unlock(&rpc_credcache_lock); 40062306a36Sopenharmony_ci rpcauth_destroy_credlist(&free); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci/* 40462306a36Sopenharmony_ci * Destroy the RPC credential cache 40562306a36Sopenharmony_ci */ 40662306a36Sopenharmony_civoid 40762306a36Sopenharmony_cirpcauth_destroy_credcache(struct rpc_auth *auth) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci struct rpc_cred_cache *cache = auth->au_credcache; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (cache) { 41262306a36Sopenharmony_ci auth->au_credcache = NULL; 41362306a36Sopenharmony_ci rpcauth_clear_credcache(cache); 41462306a36Sopenharmony_ci kfree(cache->hashtable); 41562306a36Sopenharmony_ci kfree(cache); 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpcauth_destroy_credcache); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci#define RPC_AUTH_EXPIRY_MORATORIUM (60 * HZ) 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci/* 42462306a36Sopenharmony_ci * Remove stale credentials. Avoid sleeping inside the loop. 42562306a36Sopenharmony_ci */ 42662306a36Sopenharmony_cistatic long 42762306a36Sopenharmony_cirpcauth_prune_expired(struct list_head *free, int nr_to_scan) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci struct rpc_cred *cred, *next; 43062306a36Sopenharmony_ci unsigned long expired = jiffies - RPC_AUTH_EXPIRY_MORATORIUM; 43162306a36Sopenharmony_ci long freed = 0; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci list_for_each_entry_safe(cred, next, &cred_unused, cr_lru) { 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci if (nr_to_scan-- == 0) 43662306a36Sopenharmony_ci break; 43762306a36Sopenharmony_ci if (refcount_read(&cred->cr_count) > 1) { 43862306a36Sopenharmony_ci rpcauth_lru_remove_locked(cred); 43962306a36Sopenharmony_ci continue; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci /* 44262306a36Sopenharmony_ci * Enforce a 60 second garbage collection moratorium 44362306a36Sopenharmony_ci * Note that the cred_unused list must be time-ordered. 44462306a36Sopenharmony_ci */ 44562306a36Sopenharmony_ci if (time_in_range(cred->cr_expire, expired, jiffies)) 44662306a36Sopenharmony_ci continue; 44762306a36Sopenharmony_ci if (!rpcauth_unhash_cred(cred)) 44862306a36Sopenharmony_ci continue; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci rpcauth_lru_remove_locked(cred); 45162306a36Sopenharmony_ci freed++; 45262306a36Sopenharmony_ci list_add_tail(&cred->cr_lru, free); 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci return freed ? freed : SHRINK_STOP; 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistatic unsigned long 45862306a36Sopenharmony_cirpcauth_cache_do_shrink(int nr_to_scan) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci LIST_HEAD(free); 46162306a36Sopenharmony_ci unsigned long freed; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci spin_lock(&rpc_credcache_lock); 46462306a36Sopenharmony_ci freed = rpcauth_prune_expired(&free, nr_to_scan); 46562306a36Sopenharmony_ci spin_unlock(&rpc_credcache_lock); 46662306a36Sopenharmony_ci rpcauth_destroy_credlist(&free); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci return freed; 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci/* 47262306a36Sopenharmony_ci * Run memory cache shrinker. 47362306a36Sopenharmony_ci */ 47462306a36Sopenharmony_cistatic unsigned long 47562306a36Sopenharmony_cirpcauth_cache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci if ((sc->gfp_mask & GFP_KERNEL) != GFP_KERNEL) 47962306a36Sopenharmony_ci return SHRINK_STOP; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci /* nothing left, don't come back */ 48262306a36Sopenharmony_ci if (list_empty(&cred_unused)) 48362306a36Sopenharmony_ci return SHRINK_STOP; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci return rpcauth_cache_do_shrink(sc->nr_to_scan); 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cistatic unsigned long 48962306a36Sopenharmony_cirpcauth_cache_shrink_count(struct shrinker *shrink, struct shrink_control *sc) 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci return number_cred_unused * sysctl_vfs_cache_pressure / 100; 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_cistatic void 49662306a36Sopenharmony_cirpcauth_cache_enforce_limit(void) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci unsigned long diff; 49962306a36Sopenharmony_ci unsigned int nr_to_scan; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci if (number_cred_unused <= auth_max_cred_cachesize) 50262306a36Sopenharmony_ci return; 50362306a36Sopenharmony_ci diff = number_cred_unused - auth_max_cred_cachesize; 50462306a36Sopenharmony_ci nr_to_scan = 100; 50562306a36Sopenharmony_ci if (diff < nr_to_scan) 50662306a36Sopenharmony_ci nr_to_scan = diff; 50762306a36Sopenharmony_ci rpcauth_cache_do_shrink(nr_to_scan); 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci/* 51162306a36Sopenharmony_ci * Look up a process' credentials in the authentication cache 51262306a36Sopenharmony_ci */ 51362306a36Sopenharmony_cistruct rpc_cred * 51462306a36Sopenharmony_cirpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, 51562306a36Sopenharmony_ci int flags, gfp_t gfp) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci LIST_HEAD(free); 51862306a36Sopenharmony_ci struct rpc_cred_cache *cache = auth->au_credcache; 51962306a36Sopenharmony_ci struct rpc_cred *cred = NULL, 52062306a36Sopenharmony_ci *entry, *new; 52162306a36Sopenharmony_ci unsigned int nr; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci nr = auth->au_ops->hash_cred(acred, cache->hashbits); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci rcu_read_lock(); 52662306a36Sopenharmony_ci hlist_for_each_entry_rcu(entry, &cache->hashtable[nr], cr_hash) { 52762306a36Sopenharmony_ci if (!entry->cr_ops->crmatch(acred, entry, flags)) 52862306a36Sopenharmony_ci continue; 52962306a36Sopenharmony_ci cred = get_rpccred(entry); 53062306a36Sopenharmony_ci if (cred) 53162306a36Sopenharmony_ci break; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci rcu_read_unlock(); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci if (cred != NULL) 53662306a36Sopenharmony_ci goto found; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci new = auth->au_ops->crcreate(auth, acred, flags, gfp); 53962306a36Sopenharmony_ci if (IS_ERR(new)) { 54062306a36Sopenharmony_ci cred = new; 54162306a36Sopenharmony_ci goto out; 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci spin_lock(&cache->lock); 54562306a36Sopenharmony_ci hlist_for_each_entry(entry, &cache->hashtable[nr], cr_hash) { 54662306a36Sopenharmony_ci if (!entry->cr_ops->crmatch(acred, entry, flags)) 54762306a36Sopenharmony_ci continue; 54862306a36Sopenharmony_ci cred = get_rpccred(entry); 54962306a36Sopenharmony_ci if (cred) 55062306a36Sopenharmony_ci break; 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci if (cred == NULL) { 55362306a36Sopenharmony_ci cred = new; 55462306a36Sopenharmony_ci set_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags); 55562306a36Sopenharmony_ci refcount_inc(&cred->cr_count); 55662306a36Sopenharmony_ci hlist_add_head_rcu(&cred->cr_hash, &cache->hashtable[nr]); 55762306a36Sopenharmony_ci } else 55862306a36Sopenharmony_ci list_add_tail(&new->cr_lru, &free); 55962306a36Sopenharmony_ci spin_unlock(&cache->lock); 56062306a36Sopenharmony_ci rpcauth_cache_enforce_limit(); 56162306a36Sopenharmony_cifound: 56262306a36Sopenharmony_ci if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) && 56362306a36Sopenharmony_ci cred->cr_ops->cr_init != NULL && 56462306a36Sopenharmony_ci !(flags & RPCAUTH_LOOKUP_NEW)) { 56562306a36Sopenharmony_ci int res = cred->cr_ops->cr_init(auth, cred); 56662306a36Sopenharmony_ci if (res < 0) { 56762306a36Sopenharmony_ci put_rpccred(cred); 56862306a36Sopenharmony_ci cred = ERR_PTR(res); 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci rpcauth_destroy_credlist(&free); 57262306a36Sopenharmony_ciout: 57362306a36Sopenharmony_ci return cred; 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpcauth_lookup_credcache); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_cistruct rpc_cred * 57862306a36Sopenharmony_cirpcauth_lookupcred(struct rpc_auth *auth, int flags) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci struct auth_cred acred; 58162306a36Sopenharmony_ci struct rpc_cred *ret; 58262306a36Sopenharmony_ci const struct cred *cred = current_cred(); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci memset(&acred, 0, sizeof(acred)); 58562306a36Sopenharmony_ci acred.cred = cred; 58662306a36Sopenharmony_ci ret = auth->au_ops->lookup_cred(auth, &acred, flags); 58762306a36Sopenharmony_ci return ret; 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpcauth_lookupcred); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_civoid 59262306a36Sopenharmony_cirpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred, 59362306a36Sopenharmony_ci struct rpc_auth *auth, const struct rpc_credops *ops) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci INIT_HLIST_NODE(&cred->cr_hash); 59662306a36Sopenharmony_ci INIT_LIST_HEAD(&cred->cr_lru); 59762306a36Sopenharmony_ci refcount_set(&cred->cr_count, 1); 59862306a36Sopenharmony_ci cred->cr_auth = auth; 59962306a36Sopenharmony_ci cred->cr_flags = 0; 60062306a36Sopenharmony_ci cred->cr_ops = ops; 60162306a36Sopenharmony_ci cred->cr_expire = jiffies; 60262306a36Sopenharmony_ci cred->cr_cred = get_cred(acred->cred); 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpcauth_init_cred); 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cistatic struct rpc_cred * 60762306a36Sopenharmony_cirpcauth_bind_root_cred(struct rpc_task *task, int lookupflags) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci struct rpc_auth *auth = task->tk_client->cl_auth; 61062306a36Sopenharmony_ci struct auth_cred acred = { 61162306a36Sopenharmony_ci .cred = get_task_cred(&init_task), 61262306a36Sopenharmony_ci }; 61362306a36Sopenharmony_ci struct rpc_cred *ret; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci if (RPC_IS_ASYNC(task)) 61662306a36Sopenharmony_ci lookupflags |= RPCAUTH_LOOKUP_ASYNC; 61762306a36Sopenharmony_ci ret = auth->au_ops->lookup_cred(auth, &acred, lookupflags); 61862306a36Sopenharmony_ci put_cred(acred.cred); 61962306a36Sopenharmony_ci return ret; 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic struct rpc_cred * 62362306a36Sopenharmony_cirpcauth_bind_machine_cred(struct rpc_task *task, int lookupflags) 62462306a36Sopenharmony_ci{ 62562306a36Sopenharmony_ci struct rpc_auth *auth = task->tk_client->cl_auth; 62662306a36Sopenharmony_ci struct auth_cred acred = { 62762306a36Sopenharmony_ci .principal = task->tk_client->cl_principal, 62862306a36Sopenharmony_ci .cred = init_task.cred, 62962306a36Sopenharmony_ci }; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci if (!acred.principal) 63262306a36Sopenharmony_ci return NULL; 63362306a36Sopenharmony_ci if (RPC_IS_ASYNC(task)) 63462306a36Sopenharmony_ci lookupflags |= RPCAUTH_LOOKUP_ASYNC; 63562306a36Sopenharmony_ci return auth->au_ops->lookup_cred(auth, &acred, lookupflags); 63662306a36Sopenharmony_ci} 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cistatic struct rpc_cred * 63962306a36Sopenharmony_cirpcauth_bind_new_cred(struct rpc_task *task, int lookupflags) 64062306a36Sopenharmony_ci{ 64162306a36Sopenharmony_ci struct rpc_auth *auth = task->tk_client->cl_auth; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci return rpcauth_lookupcred(auth, lookupflags); 64462306a36Sopenharmony_ci} 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_cistatic int 64762306a36Sopenharmony_cirpcauth_bindcred(struct rpc_task *task, const struct cred *cred, int flags) 64862306a36Sopenharmony_ci{ 64962306a36Sopenharmony_ci struct rpc_rqst *req = task->tk_rqstp; 65062306a36Sopenharmony_ci struct rpc_cred *new = NULL; 65162306a36Sopenharmony_ci int lookupflags = 0; 65262306a36Sopenharmony_ci struct rpc_auth *auth = task->tk_client->cl_auth; 65362306a36Sopenharmony_ci struct auth_cred acred = { 65462306a36Sopenharmony_ci .cred = cred, 65562306a36Sopenharmony_ci }; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci if (flags & RPC_TASK_ASYNC) 65862306a36Sopenharmony_ci lookupflags |= RPCAUTH_LOOKUP_NEW | RPCAUTH_LOOKUP_ASYNC; 65962306a36Sopenharmony_ci if (task->tk_op_cred) 66062306a36Sopenharmony_ci /* Task must use exactly this rpc_cred */ 66162306a36Sopenharmony_ci new = get_rpccred(task->tk_op_cred); 66262306a36Sopenharmony_ci else if (cred != NULL && cred != &machine_cred) 66362306a36Sopenharmony_ci new = auth->au_ops->lookup_cred(auth, &acred, lookupflags); 66462306a36Sopenharmony_ci else if (cred == &machine_cred) 66562306a36Sopenharmony_ci new = rpcauth_bind_machine_cred(task, lookupflags); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci /* If machine cred couldn't be bound, try a root cred */ 66862306a36Sopenharmony_ci if (new) 66962306a36Sopenharmony_ci ; 67062306a36Sopenharmony_ci else if (cred == &machine_cred) 67162306a36Sopenharmony_ci new = rpcauth_bind_root_cred(task, lookupflags); 67262306a36Sopenharmony_ci else if (flags & RPC_TASK_NULLCREDS) 67362306a36Sopenharmony_ci new = authnull_ops.lookup_cred(NULL, NULL, 0); 67462306a36Sopenharmony_ci else 67562306a36Sopenharmony_ci new = rpcauth_bind_new_cred(task, lookupflags); 67662306a36Sopenharmony_ci if (IS_ERR(new)) 67762306a36Sopenharmony_ci return PTR_ERR(new); 67862306a36Sopenharmony_ci put_rpccred(req->rq_cred); 67962306a36Sopenharmony_ci req->rq_cred = new; 68062306a36Sopenharmony_ci return 0; 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_civoid 68462306a36Sopenharmony_ciput_rpccred(struct rpc_cred *cred) 68562306a36Sopenharmony_ci{ 68662306a36Sopenharmony_ci if (cred == NULL) 68762306a36Sopenharmony_ci return; 68862306a36Sopenharmony_ci rcu_read_lock(); 68962306a36Sopenharmony_ci if (refcount_dec_and_test(&cred->cr_count)) 69062306a36Sopenharmony_ci goto destroy; 69162306a36Sopenharmony_ci if (refcount_read(&cred->cr_count) != 1 || 69262306a36Sopenharmony_ci !test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags)) 69362306a36Sopenharmony_ci goto out; 69462306a36Sopenharmony_ci if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0) { 69562306a36Sopenharmony_ci cred->cr_expire = jiffies; 69662306a36Sopenharmony_ci rpcauth_lru_add(cred); 69762306a36Sopenharmony_ci /* Race breaker */ 69862306a36Sopenharmony_ci if (unlikely(!test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags))) 69962306a36Sopenharmony_ci rpcauth_lru_remove(cred); 70062306a36Sopenharmony_ci } else if (rpcauth_unhash_cred(cred)) { 70162306a36Sopenharmony_ci rpcauth_lru_remove(cred); 70262306a36Sopenharmony_ci if (refcount_dec_and_test(&cred->cr_count)) 70362306a36Sopenharmony_ci goto destroy; 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ciout: 70662306a36Sopenharmony_ci rcu_read_unlock(); 70762306a36Sopenharmony_ci return; 70862306a36Sopenharmony_cidestroy: 70962306a36Sopenharmony_ci rcu_read_unlock(); 71062306a36Sopenharmony_ci cred->cr_ops->crdestroy(cred); 71162306a36Sopenharmony_ci} 71262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(put_rpccred); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci/** 71562306a36Sopenharmony_ci * rpcauth_marshcred - Append RPC credential to end of @xdr 71662306a36Sopenharmony_ci * @task: controlling RPC task 71762306a36Sopenharmony_ci * @xdr: xdr_stream containing initial portion of RPC Call header 71862306a36Sopenharmony_ci * 71962306a36Sopenharmony_ci * On success, an appropriate verifier is added to @xdr, @xdr is 72062306a36Sopenharmony_ci * updated to point past the verifier, and zero is returned. 72162306a36Sopenharmony_ci * Otherwise, @xdr is in an undefined state and a negative errno 72262306a36Sopenharmony_ci * is returned. 72362306a36Sopenharmony_ci */ 72462306a36Sopenharmony_ciint rpcauth_marshcred(struct rpc_task *task, struct xdr_stream *xdr) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci const struct rpc_credops *ops = task->tk_rqstp->rq_cred->cr_ops; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci return ops->crmarshal(task, xdr); 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci/** 73262306a36Sopenharmony_ci * rpcauth_wrap_req_encode - XDR encode the RPC procedure 73362306a36Sopenharmony_ci * @task: controlling RPC task 73462306a36Sopenharmony_ci * @xdr: stream where on-the-wire bytes are to be marshalled 73562306a36Sopenharmony_ci * 73662306a36Sopenharmony_ci * On success, @xdr contains the encoded and wrapped message. 73762306a36Sopenharmony_ci * Otherwise, @xdr is in an undefined state. 73862306a36Sopenharmony_ci */ 73962306a36Sopenharmony_ciint rpcauth_wrap_req_encode(struct rpc_task *task, struct xdr_stream *xdr) 74062306a36Sopenharmony_ci{ 74162306a36Sopenharmony_ci kxdreproc_t encode = task->tk_msg.rpc_proc->p_encode; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci encode(task->tk_rqstp, xdr, task->tk_msg.rpc_argp); 74462306a36Sopenharmony_ci return 0; 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpcauth_wrap_req_encode); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci/** 74962306a36Sopenharmony_ci * rpcauth_wrap_req - XDR encode and wrap the RPC procedure 75062306a36Sopenharmony_ci * @task: controlling RPC task 75162306a36Sopenharmony_ci * @xdr: stream where on-the-wire bytes are to be marshalled 75262306a36Sopenharmony_ci * 75362306a36Sopenharmony_ci * On success, @xdr contains the encoded and wrapped message, 75462306a36Sopenharmony_ci * and zero is returned. Otherwise, @xdr is in an undefined 75562306a36Sopenharmony_ci * state and a negative errno is returned. 75662306a36Sopenharmony_ci */ 75762306a36Sopenharmony_ciint rpcauth_wrap_req(struct rpc_task *task, struct xdr_stream *xdr) 75862306a36Sopenharmony_ci{ 75962306a36Sopenharmony_ci const struct rpc_credops *ops = task->tk_rqstp->rq_cred->cr_ops; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci return ops->crwrap_req(task, xdr); 76262306a36Sopenharmony_ci} 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci/** 76562306a36Sopenharmony_ci * rpcauth_checkverf - Validate verifier in RPC Reply header 76662306a36Sopenharmony_ci * @task: controlling RPC task 76762306a36Sopenharmony_ci * @xdr: xdr_stream containing RPC Reply header 76862306a36Sopenharmony_ci * 76962306a36Sopenharmony_ci * Return values: 77062306a36Sopenharmony_ci * %0: Verifier is valid. @xdr now points past the verifier. 77162306a36Sopenharmony_ci * %-EIO: Verifier is corrupted or message ended early. 77262306a36Sopenharmony_ci * %-EACCES: Verifier is intact but not valid. 77362306a36Sopenharmony_ci * %-EPROTONOSUPPORT: Server does not support the requested auth type. 77462306a36Sopenharmony_ci * 77562306a36Sopenharmony_ci * When a negative errno is returned, @xdr is left in an undefined 77662306a36Sopenharmony_ci * state. 77762306a36Sopenharmony_ci */ 77862306a36Sopenharmony_ciint 77962306a36Sopenharmony_cirpcauth_checkverf(struct rpc_task *task, struct xdr_stream *xdr) 78062306a36Sopenharmony_ci{ 78162306a36Sopenharmony_ci const struct rpc_credops *ops = task->tk_rqstp->rq_cred->cr_ops; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci return ops->crvalidate(task, xdr); 78462306a36Sopenharmony_ci} 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci/** 78762306a36Sopenharmony_ci * rpcauth_unwrap_resp_decode - Invoke XDR decode function 78862306a36Sopenharmony_ci * @task: controlling RPC task 78962306a36Sopenharmony_ci * @xdr: stream where the Reply message resides 79062306a36Sopenharmony_ci * 79162306a36Sopenharmony_ci * Returns zero on success; otherwise a negative errno is returned. 79262306a36Sopenharmony_ci */ 79362306a36Sopenharmony_ciint 79462306a36Sopenharmony_cirpcauth_unwrap_resp_decode(struct rpc_task *task, struct xdr_stream *xdr) 79562306a36Sopenharmony_ci{ 79662306a36Sopenharmony_ci kxdrdproc_t decode = task->tk_msg.rpc_proc->p_decode; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci return decode(task->tk_rqstp, xdr, task->tk_msg.rpc_resp); 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpcauth_unwrap_resp_decode); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci/** 80362306a36Sopenharmony_ci * rpcauth_unwrap_resp - Invoke unwrap and decode function for the cred 80462306a36Sopenharmony_ci * @task: controlling RPC task 80562306a36Sopenharmony_ci * @xdr: stream where the Reply message resides 80662306a36Sopenharmony_ci * 80762306a36Sopenharmony_ci * Returns zero on success; otherwise a negative errno is returned. 80862306a36Sopenharmony_ci */ 80962306a36Sopenharmony_ciint 81062306a36Sopenharmony_cirpcauth_unwrap_resp(struct rpc_task *task, struct xdr_stream *xdr) 81162306a36Sopenharmony_ci{ 81262306a36Sopenharmony_ci const struct rpc_credops *ops = task->tk_rqstp->rq_cred->cr_ops; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci return ops->crunwrap_resp(task, xdr); 81562306a36Sopenharmony_ci} 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_cibool 81862306a36Sopenharmony_cirpcauth_xmit_need_reencode(struct rpc_task *task) 81962306a36Sopenharmony_ci{ 82062306a36Sopenharmony_ci struct rpc_cred *cred = task->tk_rqstp->rq_cred; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci if (!cred || !cred->cr_ops->crneed_reencode) 82362306a36Sopenharmony_ci return false; 82462306a36Sopenharmony_ci return cred->cr_ops->crneed_reencode(task); 82562306a36Sopenharmony_ci} 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ciint 82862306a36Sopenharmony_cirpcauth_refreshcred(struct rpc_task *task) 82962306a36Sopenharmony_ci{ 83062306a36Sopenharmony_ci struct rpc_cred *cred; 83162306a36Sopenharmony_ci int err; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci cred = task->tk_rqstp->rq_cred; 83462306a36Sopenharmony_ci if (cred == NULL) { 83562306a36Sopenharmony_ci err = rpcauth_bindcred(task, task->tk_msg.rpc_cred, task->tk_flags); 83662306a36Sopenharmony_ci if (err < 0) 83762306a36Sopenharmony_ci goto out; 83862306a36Sopenharmony_ci cred = task->tk_rqstp->rq_cred; 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci err = cred->cr_ops->crrefresh(task); 84262306a36Sopenharmony_ciout: 84362306a36Sopenharmony_ci if (err < 0) 84462306a36Sopenharmony_ci task->tk_status = err; 84562306a36Sopenharmony_ci return err; 84662306a36Sopenharmony_ci} 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_civoid 84962306a36Sopenharmony_cirpcauth_invalcred(struct rpc_task *task) 85062306a36Sopenharmony_ci{ 85162306a36Sopenharmony_ci struct rpc_cred *cred = task->tk_rqstp->rq_cred; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci if (cred) 85462306a36Sopenharmony_ci clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); 85562306a36Sopenharmony_ci} 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ciint 85862306a36Sopenharmony_cirpcauth_uptodatecred(struct rpc_task *task) 85962306a36Sopenharmony_ci{ 86062306a36Sopenharmony_ci struct rpc_cred *cred = task->tk_rqstp->rq_cred; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci return cred == NULL || 86362306a36Sopenharmony_ci test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0; 86462306a36Sopenharmony_ci} 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_cistatic struct shrinker rpc_cred_shrinker = { 86762306a36Sopenharmony_ci .count_objects = rpcauth_cache_shrink_count, 86862306a36Sopenharmony_ci .scan_objects = rpcauth_cache_shrink_scan, 86962306a36Sopenharmony_ci .seeks = DEFAULT_SEEKS, 87062306a36Sopenharmony_ci}; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ciint __init rpcauth_init_module(void) 87362306a36Sopenharmony_ci{ 87462306a36Sopenharmony_ci int err; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci err = rpc_init_authunix(); 87762306a36Sopenharmony_ci if (err < 0) 87862306a36Sopenharmony_ci goto out1; 87962306a36Sopenharmony_ci err = register_shrinker(&rpc_cred_shrinker, "sunrpc_cred"); 88062306a36Sopenharmony_ci if (err < 0) 88162306a36Sopenharmony_ci goto out2; 88262306a36Sopenharmony_ci return 0; 88362306a36Sopenharmony_ciout2: 88462306a36Sopenharmony_ci rpc_destroy_authunix(); 88562306a36Sopenharmony_ciout1: 88662306a36Sopenharmony_ci return err; 88762306a36Sopenharmony_ci} 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_civoid rpcauth_remove_module(void) 89062306a36Sopenharmony_ci{ 89162306a36Sopenharmony_ci rpc_destroy_authunix(); 89262306a36Sopenharmony_ci unregister_shrinker(&rpc_cred_shrinker); 89362306a36Sopenharmony_ci} 894