blob: 04534ea537c8fd15082a2c5b23b02472f9175c3b [file] [log] [blame]
Thomas Gleixner457c8992019-05-19 13:08:55 +01001// SPDX-License-Identifier: GPL-2.0-only
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * linux/net/sunrpc/auth.c
4 *
5 * Generic RPC client authentication API.
6 *
7 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
8 */
9
10#include <linux/types.h>
11#include <linux/sched.h>
Ingo Molnar5b825c32017-02-02 17:54:15 +010012#include <linux/cred.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/module.h>
14#include <linux/slab.h>
15#include <linux/errno.h>
Trond Myklebust25337fd2008-03-12 14:40:14 -040016#include <linux/hash.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/sunrpc/clnt.h>
Chuck Lever6a1a1e32012-07-11 16:31:08 -040018#include <linux/sunrpc/gss_api.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <linux/spinlock.h>
20
Chuck Levera0584ee2019-02-11 11:24:58 -050021#include <trace/events/sunrpc.h>
22
Trond Myklebust241269b2010-07-31 14:29:08 -040023#define RPC_CREDCACHE_DEFAULT_HASHBITS (4)
24struct rpc_cred_cache {
25 struct hlist_head *hashtable;
26 unsigned int hashbits;
27 spinlock_t lock;
28};
29
30static unsigned int auth_hashbits = RPC_CREDCACHE_DEFAULT_HASHBITS;
31
Trond Myklebust4e4c3be2018-09-27 13:12:44 -040032static const struct rpc_authops __rcu *auth_flavors[RPC_AUTH_MAXFLAVOR] = {
33 [RPC_AUTH_NULL] = (const struct rpc_authops __force __rcu *)&authnull_ops,
34 [RPC_AUTH_UNIX] = (const struct rpc_authops __force __rcu *)&authunix_ops,
Chuck Lever12072652023-06-07 09:58:04 -040035 [RPC_AUTH_TLS] = (const struct rpc_authops __force __rcu *)&authtls_ops,
Linus Torvalds1da177e2005-04-16 15:20:36 -070036};
37
Trond Myklebuste092bdc2007-06-23 19:45:36 -040038static LIST_HEAD(cred_unused);
Trond Myklebustf5c21872007-06-25 17:11:20 -040039static unsigned long number_cred_unused;
Trond Myklebuste092bdc2007-06-23 19:45:36 -040040
NeilBrowna52458b2018-12-03 11:30:31 +110041static struct cred machine_cred = {
42 .usage = ATOMIC_INIT(1),
NeilBrown5e169232018-12-03 11:30:30 +110043};
44
45/*
46 * Return the machine_cred pointer to be used whenever
47 * the a generic machine credential is needed.
48 */
NeilBrowna52458b2018-12-03 11:30:31 +110049const struct cred *rpc_machine_cred(void)
NeilBrown5e169232018-12-03 11:30:30 +110050{
51 return &machine_cred;
52}
53EXPORT_SYMBOL_GPL(rpc_machine_cred);
54
Miquel van Smoorenburgdb5fe262010-09-12 19:55:26 -040055#define MAX_HASHTABLE_BITS (14)
Stephen Rothwell8e4e15d2010-08-04 12:11:22 +100056static int param_set_hashtbl_sz(const char *val, const struct kernel_param *kp)
Trond Myklebust241269b2010-07-31 14:29:08 -040057{
58 unsigned long num;
59 unsigned int nbits;
60 int ret;
61
62 if (!val)
63 goto out_inval;
Daniel Walter00cfaa92014-06-21 13:06:38 +010064 ret = kstrtoul(val, 0, &num);
Dan Carpenter1a54c0c2018-07-12 15:30:08 +030065 if (ret)
Trond Myklebust241269b2010-07-31 14:29:08 -040066 goto out_inval;
Frank Sorenson34ae6852016-06-27 15:17:19 -040067 nbits = fls(num - 1);
Trond Myklebust241269b2010-07-31 14:29:08 -040068 if (nbits > MAX_HASHTABLE_BITS || nbits < 2)
69 goto out_inval;
70 *(unsigned int *)kp->arg = nbits;
71 return 0;
72out_inval:
73 return -EINVAL;
74}
75
Stephen Rothwell8e4e15d2010-08-04 12:11:22 +100076static int param_get_hashtbl_sz(char *buffer, const struct kernel_param *kp)
Trond Myklebust241269b2010-07-31 14:29:08 -040077{
78 unsigned int nbits;
79
80 nbits = *(unsigned int *)kp->arg;
Xiongfeng Wang2ac3ddc2020-05-08 09:33:00 +080081 return sprintf(buffer, "%u\n", 1U << nbits);
Trond Myklebust241269b2010-07-31 14:29:08 -040082}
83
84#define param_check_hashtbl_sz(name, p) __param_check(name, p, unsigned int);
85
Luis R. Rodriguez9c278472015-05-27 11:09:38 +093086static const struct kernel_param_ops param_ops_hashtbl_sz = {
Stephen Rothwell8e4e15d2010-08-04 12:11:22 +100087 .set = param_set_hashtbl_sz,
88 .get = param_get_hashtbl_sz,
89};
90
Trond Myklebust241269b2010-07-31 14:29:08 -040091module_param_named(auth_hashtable_size, auth_hashbits, hashtbl_sz, 0644);
92MODULE_PARM_DESC(auth_hashtable_size, "RPC credential cache hashtable size");
93
Trond Myklebustbae67462014-07-21 13:32:42 -040094static unsigned long auth_max_cred_cachesize = ULONG_MAX;
95module_param(auth_max_cred_cachesize, ulong, 0644);
96MODULE_PARM_DESC(auth_max_cred_cachesize, "RPC credential maximum total cache size");
97
Linus Torvalds1da177e2005-04-16 15:20:36 -070098static u32
99pseudoflavor_to_flavor(u32 flavor) {
Chuck Lever1c74a242013-03-22 12:53:08 -0400100 if (flavor > RPC_AUTH_MAXFLAVOR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 return RPC_AUTH_GSS;
102 return flavor;
103}
104
105int
Trond Myklebustf1c0a8612007-06-23 20:17:58 -0400106rpcauth_register(const struct rpc_authops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107{
Trond Myklebust4e4c3be2018-09-27 13:12:44 -0400108 const struct rpc_authops *old;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 rpc_authflavor_t flavor;
110
111 if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR)
112 return -EINVAL;
Trond Myklebust4e4c3be2018-09-27 13:12:44 -0400113 old = cmpxchg((const struct rpc_authops ** __force)&auth_flavors[flavor], NULL, ops);
114 if (old == NULL || old == ops)
115 return 0;
116 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117}
Trond Myklebuste8914c62007-07-14 15:39:59 -0400118EXPORT_SYMBOL_GPL(rpcauth_register);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119
120int
Trond Myklebustf1c0a8612007-06-23 20:17:58 -0400121rpcauth_unregister(const struct rpc_authops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122{
Trond Myklebust4e4c3be2018-09-27 13:12:44 -0400123 const struct rpc_authops *old;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 rpc_authflavor_t flavor;
125
126 if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR)
127 return -EINVAL;
Trond Myklebust4e4c3be2018-09-27 13:12:44 -0400128
129 old = cmpxchg((const struct rpc_authops ** __force)&auth_flavors[flavor], ops, NULL);
130 if (old == ops || old == NULL)
131 return 0;
132 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133}
Trond Myklebuste8914c62007-07-14 15:39:59 -0400134EXPORT_SYMBOL_GPL(rpcauth_unregister);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135
Trond Myklebust4e4c3be2018-09-27 13:12:44 -0400136static const struct rpc_authops *
137rpcauth_get_authops(rpc_authflavor_t flavor)
138{
139 const struct rpc_authops *ops;
140
141 if (flavor >= RPC_AUTH_MAXFLAVOR)
142 return NULL;
143
144 rcu_read_lock();
145 ops = rcu_dereference(auth_flavors[flavor]);
146 if (ops == NULL) {
147 rcu_read_unlock();
148 request_module("rpc-auth-%u", flavor);
149 rcu_read_lock();
150 ops = rcu_dereference(auth_flavors[flavor]);
151 if (ops == NULL)
152 goto out;
153 }
154 if (!try_module_get(ops->owner))
155 ops = NULL;
156out:
157 rcu_read_unlock();
158 return ops;
159}
160
161static void
162rpcauth_put_authops(const struct rpc_authops *ops)
163{
164 module_put(ops->owner);
165}
166
Chuck Lever6a1a1e32012-07-11 16:31:08 -0400167/**
Chuck Lever9568c5e2013-03-16 15:54:43 -0400168 * rpcauth_get_pseudoflavor - check if security flavor is supported
169 * @flavor: a security flavor
170 * @info: a GSS mech OID, quality of protection, and service value
171 *
172 * Verifies that an appropriate kernel module is available or already loaded.
173 * Returns an equivalent pseudoflavor, or RPC_AUTH_MAXFLAVOR if "flavor" is
174 * not supported locally.
175 */
176rpc_authflavor_t
177rpcauth_get_pseudoflavor(rpc_authflavor_t flavor, struct rpcsec_gss_info *info)
178{
Trond Myklebust4e4c3be2018-09-27 13:12:44 -0400179 const struct rpc_authops *ops = rpcauth_get_authops(flavor);
Chuck Lever9568c5e2013-03-16 15:54:43 -0400180 rpc_authflavor_t pseudoflavor;
181
Trond Myklebust4e4c3be2018-09-27 13:12:44 -0400182 if (!ops)
Chuck Lever9568c5e2013-03-16 15:54:43 -0400183 return RPC_AUTH_MAXFLAVOR;
Chuck Lever9568c5e2013-03-16 15:54:43 -0400184 pseudoflavor = flavor;
185 if (ops->info2flavor != NULL)
186 pseudoflavor = ops->info2flavor(info);
187
Trond Myklebust4e4c3be2018-09-27 13:12:44 -0400188 rpcauth_put_authops(ops);
Chuck Lever9568c5e2013-03-16 15:54:43 -0400189 return pseudoflavor;
190}
191EXPORT_SYMBOL_GPL(rpcauth_get_pseudoflavor);
192
193/**
Chuck Levera77c8062013-03-16 15:55:10 -0400194 * rpcauth_get_gssinfo - find GSS tuple matching a GSS pseudoflavor
195 * @pseudoflavor: GSS pseudoflavor to match
196 * @info: rpcsec_gss_info structure to fill in
197 *
198 * Returns zero and fills in "info" if pseudoflavor matches a
199 * supported mechanism.
200 */
201int
202rpcauth_get_gssinfo(rpc_authflavor_t pseudoflavor, struct rpcsec_gss_info *info)
203{
204 rpc_authflavor_t flavor = pseudoflavor_to_flavor(pseudoflavor);
205 const struct rpc_authops *ops;
206 int result;
207
Trond Myklebust4e4c3be2018-09-27 13:12:44 -0400208 ops = rpcauth_get_authops(flavor);
Chuck Levera77c8062013-03-16 15:55:10 -0400209 if (ops == NULL)
Chuck Levera77c8062013-03-16 15:55:10 -0400210 return -ENOENT;
Chuck Levera77c8062013-03-16 15:55:10 -0400211
212 result = -ENOENT;
213 if (ops->flavor2info != NULL)
214 result = ops->flavor2info(pseudoflavor, info);
215
Trond Myklebust4e4c3be2018-09-27 13:12:44 -0400216 rpcauth_put_authops(ops);
Chuck Levera77c8062013-03-16 15:55:10 -0400217 return result;
218}
219EXPORT_SYMBOL_GPL(rpcauth_get_gssinfo);
220
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221struct rpc_auth *
Sargun Dhillon82b98ca2018-07-05 16:48:50 +0000222rpcauth_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223{
Trond Myklebust4e4c3be2018-09-27 13:12:44 -0400224 struct rpc_auth *auth = ERR_PTR(-EINVAL);
Trond Myklebustf1c0a8612007-06-23 20:17:58 -0400225 const struct rpc_authops *ops;
Trond Myklebust4e4c3be2018-09-27 13:12:44 -0400226 u32 flavor = pseudoflavor_to_flavor(args->pseudoflavor);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227
Trond Myklebust4e4c3be2018-09-27 13:12:44 -0400228 ops = rpcauth_get_authops(flavor);
229 if (ops == NULL)
Olaf Kirchf344f6d2006-03-20 13:44:08 -0500230 goto out;
231
Trond Myklebustc2190662013-08-26 19:23:04 -0400232 auth = ops->create(args, clnt);
Trond Myklebust4e4c3be2018-09-27 13:12:44 -0400233
234 rpcauth_put_authops(ops);
J. Bruce Fields6a192752005-06-22 17:16:23 +0000235 if (IS_ERR(auth))
236 return auth;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 if (clnt->cl_auth)
Trond Myklebustde7a8ce2007-06-23 10:46:47 -0400238 rpcauth_release(clnt->cl_auth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 clnt->cl_auth = auth;
Olaf Kirchf344f6d2006-03-20 13:44:08 -0500240
241out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 return auth;
243}
Trond Myklebuste8914c62007-07-14 15:39:59 -0400244EXPORT_SYMBOL_GPL(rpcauth_create);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
246void
Trond Myklebustde7a8ce2007-06-23 10:46:47 -0400247rpcauth_release(struct rpc_auth *auth)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248{
Trond Myklebust331bc712018-10-14 10:40:29 -0400249 if (!refcount_dec_and_test(&auth->au_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 return;
251 auth->au_ops->destroy(auth);
252}
253
254static DEFINE_SPINLOCK(rpc_credcache_lock);
255
Trond Myklebust95cd6232018-10-11 16:11:09 -0400256/*
257 * On success, the caller is responsible for freeing the reference
258 * held by the hashtable
259 */
260static bool
Trond Myklebust31be5bf2007-06-24 15:55:26 -0400261rpcauth_unhash_cred_locked(struct rpc_cred *cred)
262{
Trond Myklebust95cd6232018-10-11 16:11:09 -0400263 if (!test_and_clear_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags))
264 return false;
Trond Myklebust31be5bf2007-06-24 15:55:26 -0400265 hlist_del_rcu(&cred->cr_hash);
Trond Myklebust95cd6232018-10-11 16:11:09 -0400266 return true;
Trond Myklebust31be5bf2007-06-24 15:55:26 -0400267}
268
Trond Myklebust95cd6232018-10-11 16:11:09 -0400269static bool
Trond Myklebust9499b432007-06-24 15:57:57 -0400270rpcauth_unhash_cred(struct rpc_cred *cred)
271{
272 spinlock_t *cache_lock;
Trond Myklebust95cd6232018-10-11 16:11:09 -0400273 bool ret;
Trond Myklebust9499b432007-06-24 15:57:57 -0400274
Trond Myklebust95cd6232018-10-11 16:11:09 -0400275 if (!test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags))
276 return false;
Trond Myklebust9499b432007-06-24 15:57:57 -0400277 cache_lock = &cred->cr_auth->au_credcache->lock;
278 spin_lock(cache_lock);
Trond Myklebust95cd6232018-10-11 16:11:09 -0400279 ret = rpcauth_unhash_cred_locked(cred);
Trond Myklebust9499b432007-06-24 15:57:57 -0400280 spin_unlock(cache_lock);
Trond Myklebustf0380f32009-12-03 08:10:17 -0500281 return ret;
Trond Myklebust9499b432007-06-24 15:57:57 -0400282}
283
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284/*
285 * Initialize RPC credential cache
286 */
287int
Trond Myklebustf5c21872007-06-25 17:11:20 -0400288rpcauth_init_credcache(struct rpc_auth *auth)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289{
290 struct rpc_cred_cache *new;
Trond Myklebust988664a2010-07-31 14:29:07 -0400291 unsigned int hashsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
Kris Katterjohn8b3a7002006-01-11 15:56:43 -0800293 new = kmalloc(sizeof(*new), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 if (!new)
Trond Myklebust241269b2010-07-31 14:29:08 -0400295 goto out_nocache;
296 new->hashbits = auth_hashbits;
Trond Myklebust988664a2010-07-31 14:29:07 -0400297 hashsize = 1U << new->hashbits;
Trond Myklebust241269b2010-07-31 14:29:08 -0400298 new->hashtable = kcalloc(hashsize, sizeof(new->hashtable[0]), GFP_KERNEL);
299 if (!new->hashtable)
300 goto out_nohashtbl;
Trond Myklebust9499b432007-06-24 15:57:57 -0400301 spin_lock_init(&new->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 auth->au_credcache = new;
303 return 0;
Trond Myklebust241269b2010-07-31 14:29:08 -0400304out_nohashtbl:
305 kfree(new);
306out_nocache:
307 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308}
Trond Myklebuste8914c62007-07-14 15:39:59 -0400309EXPORT_SYMBOL_GPL(rpcauth_init_credcache);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
Jeff Laytona0337d12014-06-21 20:52:16 -0400311char *
312rpcauth_stringify_acceptor(struct rpc_cred *cred)
313{
314 if (!cred->cr_ops->crstringify_acceptor)
315 return NULL;
316 return cred->cr_ops->crstringify_acceptor(cred);
317}
318EXPORT_SYMBOL_GPL(rpcauth_stringify_acceptor);
319
Andy Adamson4de6caa2013-08-14 11:59:15 -0400320/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 * Destroy a list of credentials
322 */
323static inline
Trond Myklebuste092bdc2007-06-23 19:45:36 -0400324void rpcauth_destroy_credlist(struct list_head *head)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325{
326 struct rpc_cred *cred;
327
Trond Myklebuste092bdc2007-06-23 19:45:36 -0400328 while (!list_empty(head)) {
329 cred = list_entry(head->next, struct rpc_cred, cr_lru);
330 list_del_init(&cred->cr_lru);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 put_rpccred(cred);
332 }
333}
334
Trond Myklebust95cd6232018-10-11 16:11:09 -0400335static void
336rpcauth_lru_add_locked(struct rpc_cred *cred)
337{
338 if (!list_empty(&cred->cr_lru))
339 return;
340 number_cred_unused++;
341 list_add_tail(&cred->cr_lru, &cred_unused);
342}
343
344static void
345rpcauth_lru_add(struct rpc_cred *cred)
346{
347 if (!list_empty(&cred->cr_lru))
348 return;
349 spin_lock(&rpc_credcache_lock);
350 rpcauth_lru_add_locked(cred);
351 spin_unlock(&rpc_credcache_lock);
352}
353
354static void
355rpcauth_lru_remove_locked(struct rpc_cred *cred)
356{
357 if (list_empty(&cred->cr_lru))
358 return;
359 number_cred_unused--;
360 list_del_init(&cred->cr_lru);
361}
362
363static void
364rpcauth_lru_remove(struct rpc_cred *cred)
365{
366 if (list_empty(&cred->cr_lru))
367 return;
368 spin_lock(&rpc_credcache_lock);
369 rpcauth_lru_remove_locked(cred);
370 spin_unlock(&rpc_credcache_lock);
371}
372
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373/*
374 * Clear the RPC credential cache, and delete those credentials
375 * that are not referenced.
376 */
377void
Trond Myklebust3ab9bb72007-06-09 15:41:42 -0400378rpcauth_clear_credcache(struct rpc_cred_cache *cache)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379{
Trond Myklebuste092bdc2007-06-23 19:45:36 -0400380 LIST_HEAD(free);
381 struct hlist_head *head;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 struct rpc_cred *cred;
Trond Myklebust988664a2010-07-31 14:29:07 -0400383 unsigned int hashsize = 1U << cache->hashbits;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 int i;
385
386 spin_lock(&rpc_credcache_lock);
Trond Myklebust9499b432007-06-24 15:57:57 -0400387 spin_lock(&cache->lock);
Trond Myklebust988664a2010-07-31 14:29:07 -0400388 for (i = 0; i < hashsize; i++) {
Trond Myklebuste092bdc2007-06-23 19:45:36 -0400389 head = &cache->hashtable[i];
390 while (!hlist_empty(head)) {
391 cred = hlist_entry(head->first, struct rpc_cred, cr_hash);
Trond Myklebust31be5bf2007-06-24 15:55:26 -0400392 rpcauth_unhash_cred_locked(cred);
Trond Myklebust95cd6232018-10-11 16:11:09 -0400393 /* Note: We now hold a reference to cred */
394 rpcauth_lru_remove_locked(cred);
395 list_add_tail(&cred->cr_lru, &free);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 }
397 }
Trond Myklebust9499b432007-06-24 15:57:57 -0400398 spin_unlock(&cache->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 spin_unlock(&rpc_credcache_lock);
400 rpcauth_destroy_credlist(&free);
401}
402
Trond Myklebust3ab9bb72007-06-09 15:41:42 -0400403/*
404 * Destroy the RPC credential cache
405 */
406void
407rpcauth_destroy_credcache(struct rpc_auth *auth)
408{
409 struct rpc_cred_cache *cache = auth->au_credcache;
410
411 if (cache) {
412 auth->au_credcache = NULL;
413 rpcauth_clear_credcache(cache);
Trond Myklebust241269b2010-07-31 14:29:08 -0400414 kfree(cache->hashtable);
Trond Myklebust3ab9bb72007-06-09 15:41:42 -0400415 kfree(cache);
416 }
417}
Trond Myklebuste8914c62007-07-14 15:39:59 -0400418EXPORT_SYMBOL_GPL(rpcauth_destroy_credcache);
Trond Myklebust3ab9bb72007-06-09 15:41:42 -0400419
Trond Myklebustd2b83142008-04-14 18:13:37 -0400420
421#define RPC_AUTH_EXPIRY_MORATORIUM (60 * HZ)
422
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423/*
424 * Remove stale credentials. Avoid sleeping inside the loop.
425 */
Dave Chinner70534a72013-08-28 10:18:14 +1000426static long
Trond Myklebustf5c21872007-06-25 17:11:20 -0400427rpcauth_prune_expired(struct list_head *free, int nr_to_scan)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428{
Trond Myklebusteac0d182008-10-28 15:21:41 -0400429 struct rpc_cred *cred, *next;
Trond Myklebustd2b83142008-04-14 18:13:37 -0400430 unsigned long expired = jiffies - RPC_AUTH_EXPIRY_MORATORIUM;
Dave Chinner70534a72013-08-28 10:18:14 +1000431 long freed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
Trond Myklebusteac0d182008-10-28 15:21:41 -0400433 list_for_each_entry_safe(cred, next, &cred_unused, cr_lru) {
434
Trond Myklebust20673402010-05-13 12:51:06 -0400435 if (nr_to_scan-- == 0)
436 break;
Trond Myklebust79b18182018-10-14 10:34:31 -0400437 if (refcount_read(&cred->cr_count) > 1) {
Trond Myklebust95cd6232018-10-11 16:11:09 -0400438 rpcauth_lru_remove_locked(cred);
439 continue;
440 }
Trond Myklebust93a05e62010-05-13 12:51:06 -0400441 /*
442 * Enforce a 60 second garbage collection moratorium
443 * Note that the cred_unused list must be time-ordered.
444 */
Dan Alonif1bafa72022-07-04 15:56:57 +0300445 if (time_in_range(cred->cr_expire, expired, jiffies))
Trond Myklebust95cd6232018-10-11 16:11:09 -0400446 continue;
447 if (!rpcauth_unhash_cred(cred))
Trond Myklebuste092bdc2007-06-23 19:45:36 -0400448 continue;
Trond Myklebusteac0d182008-10-28 15:21:41 -0400449
Trond Myklebust95cd6232018-10-11 16:11:09 -0400450 rpcauth_lru_remove_locked(cred);
451 freed++;
452 list_add_tail(&cred->cr_lru, free);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 }
Trond Myklebust95cd6232018-10-11 16:11:09 -0400454 return freed ? freed : SHRINK_STOP;
Trond Myklebuste092bdc2007-06-23 19:45:36 -0400455}
456
Trond Myklebustbae67462014-07-21 13:32:42 -0400457static unsigned long
458rpcauth_cache_do_shrink(int nr_to_scan)
459{
460 LIST_HEAD(free);
461 unsigned long freed;
462
463 spin_lock(&rpc_credcache_lock);
464 freed = rpcauth_prune_expired(&free, nr_to_scan);
465 spin_unlock(&rpc_credcache_lock);
466 rpcauth_destroy_credlist(&free);
467
468 return freed;
469}
470
Trond Myklebuste092bdc2007-06-23 19:45:36 -0400471/*
Trond Myklebustf5c21872007-06-25 17:11:20 -0400472 * Run memory cache shrinker.
Trond Myklebuste092bdc2007-06-23 19:45:36 -0400473 */
Dave Chinner70534a72013-08-28 10:18:14 +1000474static unsigned long
475rpcauth_cache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
476
Trond Myklebuste092bdc2007-06-23 19:45:36 -0400477{
Dave Chinner70534a72013-08-28 10:18:14 +1000478 if ((sc->gfp_mask & GFP_KERNEL) != GFP_KERNEL)
479 return SHRINK_STOP;
480
481 /* nothing left, don't come back */
Trond Myklebustf5c21872007-06-25 17:11:20 -0400482 if (list_empty(&cred_unused))
Dave Chinner70534a72013-08-28 10:18:14 +1000483 return SHRINK_STOP;
484
Trond Myklebustbae67462014-07-21 13:32:42 -0400485 return rpcauth_cache_do_shrink(sc->nr_to_scan);
Dave Chinner70534a72013-08-28 10:18:14 +1000486}
487
488static unsigned long
489rpcauth_cache_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
490
491{
NeilBrown4c3ffd02017-01-06 14:19:58 +1100492 return number_cred_unused * sysctl_vfs_cache_pressure / 100;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493}
494
Trond Myklebustbae67462014-07-21 13:32:42 -0400495static void
496rpcauth_cache_enforce_limit(void)
497{
498 unsigned long diff;
499 unsigned int nr_to_scan;
500
501 if (number_cred_unused <= auth_max_cred_cachesize)
502 return;
503 diff = number_cred_unused - auth_max_cred_cachesize;
504 nr_to_scan = 100;
505 if (diff < nr_to_scan)
506 nr_to_scan = diff;
507 rpcauth_cache_do_shrink(nr_to_scan);
508}
509
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510/*
511 * Look up a process' credentials in the authentication cache
512 */
513struct rpc_cred *
514rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,
Jeff Layton3c6e0bc2016-04-21 20:51:54 -0400515 int flags, gfp_t gfp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516{
Trond Myklebuste092bdc2007-06-23 19:45:36 -0400517 LIST_HEAD(free);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 struct rpc_cred_cache *cache = auth->au_credcache;
Trond Myklebust31be5bf2007-06-24 15:55:26 -0400519 struct rpc_cred *cred = NULL,
520 *entry, *new;
Trond Myklebust25337fd2008-03-12 14:40:14 -0400521 unsigned int nr;
522
Frank Sorenson66cbd4b2016-09-29 10:44:41 -0500523 nr = auth->au_ops->hash_cred(acred, cache->hashbits);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
Trond Myklebust31be5bf2007-06-24 15:55:26 -0400525 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800526 hlist_for_each_entry_rcu(entry, &cache->hashtable[nr], cr_hash) {
Trond Myklebust31be5bf2007-06-24 15:55:26 -0400527 if (!entry->cr_ops->crmatch(acred, entry, flags))
528 continue;
Trond Myklebust31be5bf2007-06-24 15:55:26 -0400529 cred = get_rpccred(entry);
Trond Myklebust07d02a62018-10-12 13:28:26 -0400530 if (cred)
531 break;
Trond Myklebust31be5bf2007-06-24 15:55:26 -0400532 }
533 rcu_read_unlock();
534
Trond Myklebust9499b432007-06-24 15:57:57 -0400535 if (cred != NULL)
Trond Myklebust31be5bf2007-06-24 15:55:26 -0400536 goto found;
Trond Myklebust31be5bf2007-06-24 15:55:26 -0400537
Jeff Layton3c6e0bc2016-04-21 20:51:54 -0400538 new = auth->au_ops->crcreate(auth, acred, flags, gfp);
Trond Myklebust31be5bf2007-06-24 15:55:26 -0400539 if (IS_ERR(new)) {
540 cred = new;
541 goto out;
542 }
543
Trond Myklebust9499b432007-06-24 15:57:57 -0400544 spin_lock(&cache->lock);
Sasha Levinb67bfe02013-02-27 17:06:00 -0800545 hlist_for_each_entry(entry, &cache->hashtable[nr], cr_hash) {
Trond Myklebuste092bdc2007-06-23 19:45:36 -0400546 if (!entry->cr_ops->crmatch(acred, entry, flags))
547 continue;
548 cred = get_rpccred(entry);
Trond Myklebust07d02a62018-10-12 13:28:26 -0400549 if (cred)
550 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 }
Trond Myklebust31be5bf2007-06-24 15:55:26 -0400552 if (cred == NULL) {
Trond Myklebust5fe47552007-06-23 19:55:31 -0400553 cred = new;
Trond Myklebust31be5bf2007-06-24 15:55:26 -0400554 set_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags);
Trond Myklebust79b18182018-10-14 10:34:31 -0400555 refcount_inc(&cred->cr_count);
Trond Myklebust31be5bf2007-06-24 15:55:26 -0400556 hlist_add_head_rcu(&cred->cr_hash, &cache->hashtable[nr]);
557 } else
558 list_add_tail(&new->cr_lru, &free);
Trond Myklebust9499b432007-06-24 15:57:57 -0400559 spin_unlock(&cache->lock);
Trond Myklebustbae67462014-07-21 13:32:42 -0400560 rpcauth_cache_enforce_limit();
Trond Myklebust31be5bf2007-06-24 15:55:26 -0400561found:
Joe Perchesf64f9e72009-11-29 16:55:45 -0800562 if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) &&
563 cred->cr_ops->cr_init != NULL &&
564 !(flags & RPCAUTH_LOOKUP_NEW)) {
Trond Myklebustfba3bad2006-02-01 12:19:27 -0500565 int res = cred->cr_ops->cr_init(auth, cred);
566 if (res < 0) {
567 put_rpccred(cred);
568 cred = ERR_PTR(res);
569 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 }
Trond Myklebust31be5bf2007-06-24 15:55:26 -0400571 rpcauth_destroy_credlist(&free);
572out:
573 return cred;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574}
Trond Myklebuste8914c62007-07-14 15:39:59 -0400575EXPORT_SYMBOL_GPL(rpcauth_lookup_credcache);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576
577struct rpc_cred *
Trond Myklebust8a317762006-02-01 12:18:36 -0500578rpcauth_lookupcred(struct rpc_auth *auth, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579{
David Howells86a264a2008-11-14 10:39:18 +1100580 struct auth_cred acred;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 struct rpc_cred *ret;
David Howells86a264a2008-11-14 10:39:18 +1100582 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583
David Howells86a264a2008-11-14 10:39:18 +1100584 memset(&acred, 0, sizeof(acred));
NeilBrown97f68c6b2018-12-03 11:30:30 +1100585 acred.cred = cred;
Trond Myklebust8a317762006-02-01 12:18:36 -0500586 ret = auth->au_ops->lookup_cred(auth, &acred, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 return ret;
588}
Andy Adamson66b06862014-06-12 15:02:32 -0400589EXPORT_SYMBOL_GPL(rpcauth_lookupcred);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
Trond Myklebust5fe47552007-06-23 19:55:31 -0400591void
592rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred,
593 struct rpc_auth *auth, const struct rpc_credops *ops)
594{
595 INIT_HLIST_NODE(&cred->cr_hash);
Trond Myklebuste092bdc2007-06-23 19:45:36 -0400596 INIT_LIST_HEAD(&cred->cr_lru);
Trond Myklebust79b18182018-10-14 10:34:31 -0400597 refcount_set(&cred->cr_count, 1);
Trond Myklebust5fe47552007-06-23 19:55:31 -0400598 cred->cr_auth = auth;
NeilBrown2edd8d72018-12-03 11:30:31 +1100599 cred->cr_flags = 0;
Trond Myklebust5fe47552007-06-23 19:55:31 -0400600 cred->cr_ops = ops;
601 cred->cr_expire = jiffies;
NeilBrown97f68c6b2018-12-03 11:30:30 +1100602 cred->cr_cred = get_cred(acred->cred);
Trond Myklebust5fe47552007-06-23 19:55:31 -0400603}
Trond Myklebuste8914c62007-07-14 15:39:59 -0400604EXPORT_SYMBOL_GPL(rpcauth_init_cred);
Trond Myklebust5fe47552007-06-23 19:55:31 -0400605
Trond Myklebust8572b8e2010-07-31 14:29:08 -0400606static struct rpc_cred *
Trond Myklebust5d351752009-09-15 13:32:13 -0400607rpcauth_bind_root_cred(struct rpc_task *task, int lookupflags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608{
Trond Myklebust1be27f32007-06-27 14:29:04 -0400609 struct rpc_auth *auth = task->tk_client->cl_auth;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 struct auth_cred acred = {
NeilBrown97f68c6b2018-12-03 11:30:30 +1100611 .cred = get_task_cred(&init_task),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 };
NeilBrown97f68c6b2018-12-03 11:30:30 +1100613 struct rpc_cred *ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614
NeilBrowna41b05e2022-03-07 10:41:44 +1100615 if (RPC_IS_ASYNC(task))
616 lookupflags |= RPCAUTH_LOOKUP_ASYNC;
NeilBrown97f68c6b2018-12-03 11:30:30 +1100617 ret = auth->au_ops->lookup_cred(auth, &acred, lookupflags);
618 put_cred(acred.cred);
619 return ret;
Trond Myklebustaf093832008-03-12 12:12:16 -0400620}
621
Trond Myklebust8572b8e2010-07-31 14:29:08 -0400622static struct rpc_cred *
NeilBrown5e169232018-12-03 11:30:30 +1100623rpcauth_bind_machine_cred(struct rpc_task *task, int lookupflags)
624{
625 struct rpc_auth *auth = task->tk_client->cl_auth;
626 struct auth_cred acred = {
627 .principal = task->tk_client->cl_principal,
628 .cred = init_task.cred,
629 };
630
631 if (!acred.principal)
632 return NULL;
NeilBrowna41b05e2022-03-07 10:41:44 +1100633 if (RPC_IS_ASYNC(task))
634 lookupflags |= RPCAUTH_LOOKUP_ASYNC;
NeilBrown5e169232018-12-03 11:30:30 +1100635 return auth->au_ops->lookup_cred(auth, &acred, lookupflags);
636}
637
638static struct rpc_cred *
Trond Myklebust5d351752009-09-15 13:32:13 -0400639rpcauth_bind_new_cred(struct rpc_task *task, int lookupflags)
Trond Myklebustaf093832008-03-12 12:12:16 -0400640{
641 struct rpc_auth *auth = task->tk_client->cl_auth;
Trond Myklebustaf093832008-03-12 12:12:16 -0400642
Trond Myklebust8572b8e2010-07-31 14:29:08 -0400643 return rpcauth_lookupcred(auth, lookupflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644}
645
Trond Myklebusta17c2152010-07-31 14:29:08 -0400646static int
NeilBrowna52458b2018-12-03 11:30:31 +1100647rpcauth_bindcred(struct rpc_task *task, const struct cred *cred, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648{
Trond Myklebusta17c2152010-07-31 14:29:08 -0400649 struct rpc_rqst *req = task->tk_rqstp;
NeilBrown5e169232018-12-03 11:30:30 +1100650 struct rpc_cred *new = NULL;
Trond Myklebust5d351752009-09-15 13:32:13 -0400651 int lookupflags = 0;
NeilBrowna52458b2018-12-03 11:30:31 +1100652 struct rpc_auth *auth = task->tk_client->cl_auth;
653 struct auth_cred acred = {
654 .cred = cred,
655 };
Trond Myklebust5d351752009-09-15 13:32:13 -0400656
657 if (flags & RPC_TASK_ASYNC)
NeilBrowna41b05e2022-03-07 10:41:44 +1100658 lookupflags |= RPCAUTH_LOOKUP_NEW | RPCAUTH_LOOKUP_ASYNC;
NeilBrown1de7eea2018-12-03 11:30:30 +1100659 if (task->tk_op_cred)
660 /* Task must use exactly this rpc_cred */
NeilBrownd6efccd2018-12-03 11:30:31 +1100661 new = get_rpccred(task->tk_op_cred);
NeilBrown1de7eea2018-12-03 11:30:30 +1100662 else if (cred != NULL && cred != &machine_cred)
NeilBrowna52458b2018-12-03 11:30:31 +1100663 new = auth->au_ops->lookup_cred(auth, &acred, lookupflags);
NeilBrown5e169232018-12-03 11:30:30 +1100664 else if (cred == &machine_cred)
665 new = rpcauth_bind_machine_cred(task, lookupflags);
666
667 /* If machine cred couldn't be bound, try a root cred */
668 if (new)
669 ;
NeilBrown89c2be82022-03-07 10:41:44 +1100670 else if (cred == &machine_cred)
Trond Myklebust8572b8e2010-07-31 14:29:08 -0400671 new = rpcauth_bind_root_cred(task, lookupflags);
NeilBrowna68a72e2018-12-03 11:30:30 +1100672 else if (flags & RPC_TASK_NULLCREDS)
673 new = authnull_ops.lookup_cred(NULL, NULL, 0);
Trond Myklebust4ccda2c2008-03-12 16:20:55 -0400674 else
Trond Myklebust8572b8e2010-07-31 14:29:08 -0400675 new = rpcauth_bind_new_cred(task, lookupflags);
676 if (IS_ERR(new))
677 return PTR_ERR(new);
Trond Myklebust9a8f6b52016-05-16 17:42:42 -0400678 put_rpccred(req->rq_cred);
Trond Myklebusta17c2152010-07-31 14:29:08 -0400679 req->rq_cred = new;
Trond Myklebust8572b8e2010-07-31 14:29:08 -0400680 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681}
682
683void
684put_rpccred(struct rpc_cred *cred)
685{
Trond Myklebust9a8f6b52016-05-16 17:42:42 -0400686 if (cred == NULL)
687 return;
Trond Myklebust95cd6232018-10-11 16:11:09 -0400688 rcu_read_lock();
Trond Myklebust79b18182018-10-14 10:34:31 -0400689 if (refcount_dec_and_test(&cred->cr_count))
Trond Myklebust95cd6232018-10-11 16:11:09 -0400690 goto destroy;
Trond Myklebust79b18182018-10-14 10:34:31 -0400691 if (refcount_read(&cred->cr_count) != 1 ||
Trond Myklebust95cd6232018-10-11 16:11:09 -0400692 !test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags))
693 goto out;
694 if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0) {
695 cred->cr_expire = jiffies;
696 rpcauth_lru_add(cred);
697 /* Race breaker */
698 if (unlikely(!test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags)))
699 rpcauth_lru_remove(cred);
700 } else if (rpcauth_unhash_cred(cred)) {
701 rpcauth_lru_remove(cred);
Trond Myklebust79b18182018-10-14 10:34:31 -0400702 if (refcount_dec_and_test(&cred->cr_count))
Trond Myklebust95cd6232018-10-11 16:11:09 -0400703 goto destroy;
Trond Myklebustf0380f32009-12-03 08:10:17 -0500704 }
Trond Myklebust95cd6232018-10-11 16:11:09 -0400705out:
706 rcu_read_unlock();
Trond Myklebustf0380f32009-12-03 08:10:17 -0500707 return;
Trond Myklebust95cd6232018-10-11 16:11:09 -0400708destroy:
709 rcu_read_unlock();
710 cred->cr_ops->crdestroy(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711}
Trond Myklebuste8914c62007-07-14 15:39:59 -0400712EXPORT_SYMBOL_GPL(put_rpccred);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
Chuck Levere8680a22019-02-11 11:24:48 -0500714/**
715 * rpcauth_marshcred - Append RPC credential to end of @xdr
716 * @task: controlling RPC task
717 * @xdr: xdr_stream containing initial portion of RPC Call header
718 *
719 * On success, an appropriate verifier is added to @xdr, @xdr is
720 * updated to point past the verifier, and zero is returned.
721 * Otherwise, @xdr is in an undefined state and a negative errno
722 * is returned.
723 */
724int rpcauth_marshcred(struct rpc_task *task, struct xdr_stream *xdr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725{
Chuck Levere8680a22019-02-11 11:24:48 -0500726 const struct rpc_credops *ops = task->tk_rqstp->rq_cred->cr_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727
Chuck Levere8680a22019-02-11 11:24:48 -0500728 return ops->crmarshal(task, xdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729}
730
Chuck Levere8680a22019-02-11 11:24:48 -0500731/**
732 * rpcauth_wrap_req_encode - XDR encode the RPC procedure
733 * @task: controlling RPC task
734 * @xdr: stream where on-the-wire bytes are to be marshalled
735 *
736 * On success, @xdr contains the encoded and wrapped message.
737 * Otherwise, @xdr is in an undefined state.
738 */
739int rpcauth_wrap_req_encode(struct rpc_task *task, struct xdr_stream *xdr)
Chuck Lever9f06c712010-12-14 14:59:18 +0000740{
Chuck Levere8680a22019-02-11 11:24:48 -0500741 kxdreproc_t encode = task->tk_msg.rpc_proc->p_encode;
Chuck Lever9f06c712010-12-14 14:59:18 +0000742
Chuck Levere8680a22019-02-11 11:24:48 -0500743 encode(task->tk_rqstp, xdr, task->tk_msg.rpc_argp);
Chuck Lever9f06c712010-12-14 14:59:18 +0000744 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745}
Chuck Levere8680a22019-02-11 11:24:48 -0500746EXPORT_SYMBOL_GPL(rpcauth_wrap_req_encode);
747
748/**
749 * rpcauth_wrap_req - XDR encode and wrap the RPC procedure
750 * @task: controlling RPC task
751 * @xdr: stream where on-the-wire bytes are to be marshalled
752 *
753 * On success, @xdr contains the encoded and wrapped message,
754 * and zero is returned. Otherwise, @xdr is in an undefined
755 * state and a negative errno is returned.
756 */
757int rpcauth_wrap_req(struct rpc_task *task, struct xdr_stream *xdr)
758{
759 const struct rpc_credops *ops = task->tk_rqstp->rq_cred->cr_ops;
760
761 return ops->crwrap_req(task, xdr);
762}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763
Chuck Levera0584ee2019-02-11 11:24:58 -0500764/**
765 * rpcauth_checkverf - Validate verifier in RPC Reply header
766 * @task: controlling RPC task
767 * @xdr: xdr_stream containing RPC Reply header
768 *
Chuck Lever5623ecf2023-09-06 16:05:26 -0400769 * Return values:
770 * %0: Verifier is valid. @xdr now points past the verifier.
771 * %-EIO: Verifier is corrupted or message ended early.
772 * %-EACCES: Verifier is intact but not valid.
773 * %-EPROTONOSUPPORT: Server does not support the requested auth type.
774 *
775 * When a negative errno is returned, @xdr is left in an undefined
776 * state.
Chuck Levera0584ee2019-02-11 11:24:58 -0500777 */
778int
779rpcauth_checkverf(struct rpc_task *task, struct xdr_stream *xdr)
Chuck Leverbf269552010-12-14 14:59:29 +0000780{
Chuck Levera0584ee2019-02-11 11:24:58 -0500781 const struct rpc_credops *ops = task->tk_rqstp->rq_cred->cr_ops;
Chuck Leverbf269552010-12-14 14:59:29 +0000782
Chuck Levera0584ee2019-02-11 11:24:58 -0500783 return ops->crvalidate(task, xdr);
Chuck Leverbf269552010-12-14 14:59:29 +0000784}
785
Chuck Levera0584ee2019-02-11 11:24:58 -0500786/**
787 * rpcauth_unwrap_resp_decode - Invoke XDR decode function
788 * @task: controlling RPC task
789 * @xdr: stream where the Reply message resides
790 *
791 * Returns zero on success; otherwise a negative errno is returned.
792 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793int
Chuck Levera0584ee2019-02-11 11:24:58 -0500794rpcauth_unwrap_resp_decode(struct rpc_task *task, struct xdr_stream *xdr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795{
Chuck Levera0584ee2019-02-11 11:24:58 -0500796 kxdrdproc_t decode = task->tk_msg.rpc_proc->p_decode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
Chuck Levera0584ee2019-02-11 11:24:58 -0500798 return decode(task->tk_rqstp, xdr, task->tk_msg.rpc_resp);
799}
800EXPORT_SYMBOL_GPL(rpcauth_unwrap_resp_decode);
801
802/**
803 * rpcauth_unwrap_resp - Invoke unwrap and decode function for the cred
804 * @task: controlling RPC task
805 * @xdr: stream where the Reply message resides
806 *
807 * Returns zero on success; otherwise a negative errno is returned.
808 */
809int
810rpcauth_unwrap_resp(struct rpc_task *task, struct xdr_stream *xdr)
811{
812 const struct rpc_credops *ops = task->tk_rqstp->rq_cred->cr_ops;
813
814 return ops->crunwrap_resp(task, xdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815}
816
Trond Myklebust3021a5bb2018-08-14 13:50:21 -0400817bool
818rpcauth_xmit_need_reencode(struct rpc_task *task)
819{
820 struct rpc_cred *cred = task->tk_rqstp->rq_cred;
821
822 if (!cred || !cred->cr_ops->crneed_reencode)
823 return false;
824 return cred->cr_ops->crneed_reencode(task);
825}
826
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827int
828rpcauth_refreshcred(struct rpc_task *task)
829{
Trond Myklebust9a84d382010-10-24 18:00:46 -0400830 struct rpc_cred *cred;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 int err;
832
Trond Myklebusta17c2152010-07-31 14:29:08 -0400833 cred = task->tk_rqstp->rq_cred;
834 if (cred == NULL) {
835 err = rpcauth_bindcred(task, task->tk_msg.rpc_cred, task->tk_flags);
836 if (err < 0)
837 goto out;
838 cred = task->tk_rqstp->rq_cred;
Joe Perchesf81c6222011-06-03 11:51:19 +0000839 }
Chuck Lever0bbacc42005-11-01 16:53:32 -0500840
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 err = cred->cr_ops->crrefresh(task);
Trond Myklebusta17c2152010-07-31 14:29:08 -0400842out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 if (err < 0)
844 task->tk_status = err;
845 return err;
846}
847
848void
849rpcauth_invalcred(struct rpc_task *task)
850{
Trond Myklebusta17c2152010-07-31 14:29:08 -0400851 struct rpc_cred *cred = task->tk_rqstp->rq_cred;
Trond Myklebustfc432dd2007-06-25 10:15:15 -0400852
Trond Myklebustfc432dd2007-06-25 10:15:15 -0400853 if (cred)
854 clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855}
856
857int
858rpcauth_uptodatecred(struct rpc_task *task)
859{
Trond Myklebusta17c2152010-07-31 14:29:08 -0400860 struct rpc_cred *cred = task->tk_rqstp->rq_cred;
Trond Myklebustfc432dd2007-06-25 10:15:15 -0400861
862 return cred == NULL ||
863 test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864}
Trond Myklebustf5c21872007-06-25 17:11:20 -0400865
Qi Zhengabe0c262023-09-11 17:44:17 +0800866static struct shrinker *rpc_cred_shrinker;
Trond Myklebustf5c21872007-06-25 17:11:20 -0400867
Trond Myklebust5d8d9a42010-07-31 14:29:07 -0400868int __init rpcauth_init_module(void)
Trond Myklebustf5c21872007-06-25 17:11:20 -0400869{
Trond Myklebust5d8d9a42010-07-31 14:29:07 -0400870 int err;
871
872 err = rpc_init_authunix();
873 if (err < 0)
874 goto out1;
Qi Zhengabe0c262023-09-11 17:44:17 +0800875 rpc_cred_shrinker = shrinker_alloc(0, "sunrpc_cred");
876 if (!rpc_cred_shrinker) {
877 err = -ENOMEM;
NeilBrown89a4f752018-12-03 11:30:31 +1100878 goto out2;
Qi Zhengabe0c262023-09-11 17:44:17 +0800879 }
880
881 rpc_cred_shrinker->count_objects = rpcauth_cache_shrink_count;
882 rpc_cred_shrinker->scan_objects = rpcauth_cache_shrink_scan;
883
884 shrinker_register(rpc_cred_shrinker);
885
Trond Myklebust5d8d9a42010-07-31 14:29:07 -0400886 return 0;
887out2:
888 rpc_destroy_authunix();
889out1:
890 return err;
Trond Myklebustf5c21872007-06-25 17:11:20 -0400891}
892
Stephen Rothwellc135e842010-09-29 14:16:57 +1000893void rpcauth_remove_module(void)
Trond Myklebustf5c21872007-06-25 17:11:20 -0400894{
Trond Myklebust5d8d9a42010-07-31 14:29:07 -0400895 rpc_destroy_authunix();
Qi Zhengabe0c262023-09-11 17:44:17 +0800896 shrinker_free(rpc_cred_shrinker);
Trond Myklebustf5c21872007-06-25 17:11:20 -0400897}