2 * linux/net/sunrpc/auth.c
4 * Generic RPC client authentication API.
6 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
9 #include <linux/types.h>
10 #include <linux/sched.h>
11 #include <linux/module.h>
12 #include <linux/slab.h>
13 #include <linux/errno.h>
14 #include <linux/sunrpc/clnt.h>
15 #include <linux/spinlock.h>
18 # define RPCDBG_FACILITY RPCDBG_AUTH
21 static DEFINE_SPINLOCK(rpc_authflavor_lock
);
22 static const struct rpc_authops
*auth_flavors
[RPC_AUTH_MAXFLAVOR
] = {
23 &authnull_ops
, /* AUTH_NULL */
24 &authunix_ops
, /* AUTH_UNIX */
25 NULL
, /* others can be loadable modules */
28 static LIST_HEAD(cred_unused
);
29 static unsigned long number_cred_unused
;
32 pseudoflavor_to_flavor(u32 flavor
) {
33 if (flavor
>= RPC_AUTH_MAXFLAVOR
)
39 rpcauth_register(const struct rpc_authops
*ops
)
41 rpc_authflavor_t flavor
;
44 if ((flavor
= ops
->au_flavor
) >= RPC_AUTH_MAXFLAVOR
)
46 spin_lock(&rpc_authflavor_lock
);
47 if (auth_flavors
[flavor
] == NULL
) {
48 auth_flavors
[flavor
] = ops
;
51 spin_unlock(&rpc_authflavor_lock
);
54 EXPORT_SYMBOL_GPL(rpcauth_register
);
57 rpcauth_unregister(const struct rpc_authops
*ops
)
59 rpc_authflavor_t flavor
;
62 if ((flavor
= ops
->au_flavor
) >= RPC_AUTH_MAXFLAVOR
)
64 spin_lock(&rpc_authflavor_lock
);
65 if (auth_flavors
[flavor
] == ops
) {
66 auth_flavors
[flavor
] = NULL
;
69 spin_unlock(&rpc_authflavor_lock
);
72 EXPORT_SYMBOL_GPL(rpcauth_unregister
);
75 rpcauth_create(rpc_authflavor_t pseudoflavor
, struct rpc_clnt
*clnt
)
77 struct rpc_auth
*auth
;
78 const struct rpc_authops
*ops
;
79 u32 flavor
= pseudoflavor_to_flavor(pseudoflavor
);
81 auth
= ERR_PTR(-EINVAL
);
82 if (flavor
>= RPC_AUTH_MAXFLAVOR
)
86 if ((ops
= auth_flavors
[flavor
]) == NULL
)
87 request_module("rpc-auth-%u", flavor
);
89 spin_lock(&rpc_authflavor_lock
);
90 ops
= auth_flavors
[flavor
];
91 if (ops
== NULL
|| !try_module_get(ops
->owner
)) {
92 spin_unlock(&rpc_authflavor_lock
);
95 spin_unlock(&rpc_authflavor_lock
);
96 auth
= ops
->create(clnt
, pseudoflavor
);
97 module_put(ops
->owner
);
101 rpcauth_release(clnt
->cl_auth
);
102 clnt
->cl_auth
= auth
;
107 EXPORT_SYMBOL_GPL(rpcauth_create
);
110 rpcauth_release(struct rpc_auth
*auth
)
112 if (!atomic_dec_and_test(&auth
->au_count
))
114 auth
->au_ops
->destroy(auth
);
117 static DEFINE_SPINLOCK(rpc_credcache_lock
);
120 rpcauth_unhash_cred_locked(struct rpc_cred
*cred
)
122 hlist_del_rcu(&cred
->cr_hash
);
123 smp_mb__before_clear_bit();
124 clear_bit(RPCAUTH_CRED_HASHED
, &cred
->cr_flags
);
128 rpcauth_unhash_cred(struct rpc_cred
*cred
)
130 spinlock_t
*cache_lock
;
132 cache_lock
= &cred
->cr_auth
->au_credcache
->lock
;
133 spin_lock(cache_lock
);
134 if (atomic_read(&cred
->cr_count
) == 0)
135 rpcauth_unhash_cred_locked(cred
);
136 spin_unlock(cache_lock
);
140 * Initialize RPC credential cache
143 rpcauth_init_credcache(struct rpc_auth
*auth
)
145 struct rpc_cred_cache
*new;
148 new = kmalloc(sizeof(*new), GFP_KERNEL
);
151 for (i
= 0; i
< RPC_CREDCACHE_NR
; i
++)
152 INIT_HLIST_HEAD(&new->hashtable
[i
]);
153 spin_lock_init(&new->lock
);
154 auth
->au_credcache
= new;
157 EXPORT_SYMBOL_GPL(rpcauth_init_credcache
);
160 * Destroy a list of credentials
163 void rpcauth_destroy_credlist(struct list_head
*head
)
165 struct rpc_cred
*cred
;
167 while (!list_empty(head
)) {
168 cred
= list_entry(head
->next
, struct rpc_cred
, cr_lru
);
169 list_del_init(&cred
->cr_lru
);
175 * Clear the RPC credential cache, and delete those credentials
176 * that are not referenced.
179 rpcauth_clear_credcache(struct rpc_cred_cache
*cache
)
182 struct hlist_head
*head
;
183 struct rpc_cred
*cred
;
186 spin_lock(&rpc_credcache_lock
);
187 spin_lock(&cache
->lock
);
188 for (i
= 0; i
< RPC_CREDCACHE_NR
; i
++) {
189 head
= &cache
->hashtable
[i
];
190 while (!hlist_empty(head
)) {
191 cred
= hlist_entry(head
->first
, struct rpc_cred
, cr_hash
);
193 if (!list_empty(&cred
->cr_lru
)) {
194 list_del(&cred
->cr_lru
);
195 number_cred_unused
--;
197 list_add_tail(&cred
->cr_lru
, &free
);
198 rpcauth_unhash_cred_locked(cred
);
201 spin_unlock(&cache
->lock
);
202 spin_unlock(&rpc_credcache_lock
);
203 rpcauth_destroy_credlist(&free
);
207 * Destroy the RPC credential cache
210 rpcauth_destroy_credcache(struct rpc_auth
*auth
)
212 struct rpc_cred_cache
*cache
= auth
->au_credcache
;
215 auth
->au_credcache
= NULL
;
216 rpcauth_clear_credcache(cache
);
220 EXPORT_SYMBOL_GPL(rpcauth_destroy_credcache
);
223 * Remove stale credentials. Avoid sleeping inside the loop.
226 rpcauth_prune_expired(struct list_head
*free
, int nr_to_scan
)
228 spinlock_t
*cache_lock
;
229 struct rpc_cred
*cred
;
231 while (!list_empty(&cred_unused
)) {
232 cred
= list_entry(cred_unused
.next
, struct rpc_cred
, cr_lru
);
233 list_del_init(&cred
->cr_lru
);
234 number_cred_unused
--;
235 if (atomic_read(&cred
->cr_count
) != 0)
237 cache_lock
= &cred
->cr_auth
->au_credcache
->lock
;
238 spin_lock(cache_lock
);
239 if (atomic_read(&cred
->cr_count
) == 0) {
241 list_add_tail(&cred
->cr_lru
, free
);
242 rpcauth_unhash_cred_locked(cred
);
245 spin_unlock(cache_lock
);
253 * Run memory cache shrinker.
256 rpcauth_cache_shrinker(int nr_to_scan
, gfp_t gfp_mask
)
261 if (list_empty(&cred_unused
))
263 spin_lock(&rpc_credcache_lock
);
264 nr_to_scan
= rpcauth_prune_expired(&free
, nr_to_scan
);
265 res
= (number_cred_unused
/ 100) * sysctl_vfs_cache_pressure
;
266 spin_unlock(&rpc_credcache_lock
);
267 rpcauth_destroy_credlist(&free
);
272 * Look up a process' credentials in the authentication cache
275 rpcauth_lookup_credcache(struct rpc_auth
*auth
, struct auth_cred
* acred
,
279 struct rpc_cred_cache
*cache
= auth
->au_credcache
;
280 struct hlist_node
*pos
;
281 struct rpc_cred
*cred
= NULL
,
285 if (!(flags
& RPCAUTH_LOOKUP_ROOTCREDS
))
286 nr
= acred
->uid
& RPC_CREDCACHE_MASK
;
289 hlist_for_each_entry_rcu(entry
, pos
, &cache
->hashtable
[nr
], cr_hash
) {
290 if (!entry
->cr_ops
->crmatch(acred
, entry
, flags
))
292 spin_lock(&cache
->lock
);
293 if (test_bit(RPCAUTH_CRED_HASHED
, &entry
->cr_flags
) == 0) {
294 spin_unlock(&cache
->lock
);
297 cred
= get_rpccred(entry
);
298 spin_unlock(&cache
->lock
);
306 new = auth
->au_ops
->crcreate(auth
, acred
, flags
);
312 spin_lock(&cache
->lock
);
313 hlist_for_each_entry(entry
, pos
, &cache
->hashtable
[nr
], cr_hash
) {
314 if (!entry
->cr_ops
->crmatch(acred
, entry
, flags
))
316 cred
= get_rpccred(entry
);
321 set_bit(RPCAUTH_CRED_HASHED
, &cred
->cr_flags
);
322 hlist_add_head_rcu(&cred
->cr_hash
, &cache
->hashtable
[nr
]);
324 list_add_tail(&new->cr_lru
, &free
);
325 spin_unlock(&cache
->lock
);
327 if (test_bit(RPCAUTH_CRED_NEW
, &cred
->cr_flags
)
328 && cred
->cr_ops
->cr_init
!= NULL
329 && !(flags
& RPCAUTH_LOOKUP_NEW
)) {
330 int res
= cred
->cr_ops
->cr_init(auth
, cred
);
336 rpcauth_destroy_credlist(&free
);
340 EXPORT_SYMBOL_GPL(rpcauth_lookup_credcache
);
343 rpcauth_lookupcred(struct rpc_auth
*auth
, int flags
)
345 struct auth_cred acred
= {
346 .uid
= current
->fsuid
,
347 .gid
= current
->fsgid
,
348 .group_info
= current
->group_info
,
350 struct rpc_cred
*ret
;
352 dprintk("RPC: looking up %s cred\n",
353 auth
->au_ops
->au_name
);
354 get_group_info(acred
.group_info
);
355 ret
= auth
->au_ops
->lookup_cred(auth
, &acred
, flags
);
356 put_group_info(acred
.group_info
);
359 EXPORT_SYMBOL_GPL(rpcauth_lookupcred
);
362 rpcauth_init_cred(struct rpc_cred
*cred
, const struct auth_cred
*acred
,
363 struct rpc_auth
*auth
, const struct rpc_credops
*ops
)
365 INIT_HLIST_NODE(&cred
->cr_hash
);
366 INIT_LIST_HEAD(&cred
->cr_lru
);
367 atomic_set(&cred
->cr_count
, 1);
368 cred
->cr_auth
= auth
;
370 cred
->cr_expire
= jiffies
;
372 cred
->cr_magic
= RPCAUTH_CRED_MAGIC
;
374 cred
->cr_uid
= acred
->uid
;
376 EXPORT_SYMBOL_GPL(rpcauth_init_cred
);
379 rpcauth_bindcred(struct rpc_task
*task
)
381 struct rpc_auth
*auth
= task
->tk_client
->cl_auth
;
382 struct auth_cred acred
= {
383 .uid
= current
->fsuid
,
384 .gid
= current
->fsgid
,
385 .group_info
= current
->group_info
,
387 struct rpc_cred
*ret
;
390 dprintk("RPC: %5u looking up %s cred\n",
391 task
->tk_pid
, task
->tk_client
->cl_auth
->au_ops
->au_name
);
392 get_group_info(acred
.group_info
);
393 if (task
->tk_flags
& RPC_TASK_ROOTCREDS
)
394 flags
|= RPCAUTH_LOOKUP_ROOTCREDS
;
395 ret
= auth
->au_ops
->lookup_cred(auth
, &acred
, flags
);
397 task
->tk_msg
.rpc_cred
= ret
;
399 task
->tk_status
= PTR_ERR(ret
);
400 put_group_info(acred
.group_info
);
405 rpcauth_holdcred(struct rpc_task
*task
)
407 struct rpc_cred
*cred
= task
->tk_msg
.rpc_cred
;
410 dprintk("RPC: %5u holding %s cred %p\n", task
->tk_pid
,
411 cred
->cr_auth
->au_ops
->au_name
, cred
);
416 put_rpccred(struct rpc_cred
*cred
)
418 /* Fast path for unhashed credentials */
419 if (test_bit(RPCAUTH_CRED_HASHED
, &cred
->cr_flags
) != 0)
422 if (!atomic_dec_and_test(&cred
->cr_count
))
426 if (!atomic_dec_and_lock(&cred
->cr_count
, &rpc_credcache_lock
))
428 if (!list_empty(&cred
->cr_lru
)) {
429 number_cred_unused
--;
430 list_del_init(&cred
->cr_lru
);
432 if (test_bit(RPCAUTH_CRED_UPTODATE
, &cred
->cr_flags
) == 0)
433 rpcauth_unhash_cred(cred
);
434 else if (test_bit(RPCAUTH_CRED_HASHED
, &cred
->cr_flags
) != 0) {
435 cred
->cr_expire
= jiffies
;
436 list_add_tail(&cred
->cr_lru
, &cred_unused
);
437 number_cred_unused
++;
438 spin_unlock(&rpc_credcache_lock
);
441 spin_unlock(&rpc_credcache_lock
);
443 cred
->cr_ops
->crdestroy(cred
);
445 EXPORT_SYMBOL_GPL(put_rpccred
);
448 rpcauth_unbindcred(struct rpc_task
*task
)
450 struct rpc_cred
*cred
= task
->tk_msg
.rpc_cred
;
452 dprintk("RPC: %5u releasing %s cred %p\n",
453 task
->tk_pid
, cred
->cr_auth
->au_ops
->au_name
, cred
);
456 task
->tk_msg
.rpc_cred
= NULL
;
460 rpcauth_marshcred(struct rpc_task
*task
, __be32
*p
)
462 struct rpc_cred
*cred
= task
->tk_msg
.rpc_cred
;
464 dprintk("RPC: %5u marshaling %s cred %p\n",
465 task
->tk_pid
, cred
->cr_auth
->au_ops
->au_name
, cred
);
467 return cred
->cr_ops
->crmarshal(task
, p
);
471 rpcauth_checkverf(struct rpc_task
*task
, __be32
*p
)
473 struct rpc_cred
*cred
= task
->tk_msg
.rpc_cred
;
475 dprintk("RPC: %5u validating %s cred %p\n",
476 task
->tk_pid
, cred
->cr_auth
->au_ops
->au_name
, cred
);
478 return cred
->cr_ops
->crvalidate(task
, p
);
482 rpcauth_wrap_req(struct rpc_task
*task
, kxdrproc_t encode
, void *rqstp
,
483 __be32
*data
, void *obj
)
485 struct rpc_cred
*cred
= task
->tk_msg
.rpc_cred
;
487 dprintk("RPC: %5u using %s cred %p to wrap rpc data\n",
488 task
->tk_pid
, cred
->cr_ops
->cr_name
, cred
);
489 if (cred
->cr_ops
->crwrap_req
)
490 return cred
->cr_ops
->crwrap_req(task
, encode
, rqstp
, data
, obj
);
491 /* By default, we encode the arguments normally. */
492 return rpc_call_xdrproc(encode
, rqstp
, data
, obj
);
496 rpcauth_unwrap_resp(struct rpc_task
*task
, kxdrproc_t decode
, void *rqstp
,
497 __be32
*data
, void *obj
)
499 struct rpc_cred
*cred
= task
->tk_msg
.rpc_cred
;
501 dprintk("RPC: %5u using %s cred %p to unwrap rpc data\n",
502 task
->tk_pid
, cred
->cr_ops
->cr_name
, cred
);
503 if (cred
->cr_ops
->crunwrap_resp
)
504 return cred
->cr_ops
->crunwrap_resp(task
, decode
, rqstp
,
506 /* By default, we decode the arguments normally. */
507 return rpc_call_xdrproc(decode
, rqstp
, data
, obj
);
511 rpcauth_refreshcred(struct rpc_task
*task
)
513 struct rpc_cred
*cred
= task
->tk_msg
.rpc_cred
;
516 dprintk("RPC: %5u refreshing %s cred %p\n",
517 task
->tk_pid
, cred
->cr_auth
->au_ops
->au_name
, cred
);
519 err
= cred
->cr_ops
->crrefresh(task
);
521 task
->tk_status
= err
;
526 rpcauth_invalcred(struct rpc_task
*task
)
528 struct rpc_cred
*cred
= task
->tk_msg
.rpc_cred
;
530 dprintk("RPC: %5u invalidating %s cred %p\n",
531 task
->tk_pid
, cred
->cr_auth
->au_ops
->au_name
, cred
);
533 clear_bit(RPCAUTH_CRED_UPTODATE
, &cred
->cr_flags
);
537 rpcauth_uptodatecred(struct rpc_task
*task
)
539 struct rpc_cred
*cred
= task
->tk_msg
.rpc_cred
;
541 return cred
== NULL
||
542 test_bit(RPCAUTH_CRED_UPTODATE
, &cred
->cr_flags
) != 0;
545 static struct shrinker rpc_cred_shrinker
= {
546 .shrink
= rpcauth_cache_shrinker
,
547 .seeks
= DEFAULT_SEEKS
,
550 void __init
rpcauth_init_module(void)
553 register_shrinker(&rpc_cred_shrinker
);
556 void __exit
rpcauth_remove_module(void)
558 unregister_shrinker(&rpc_cred_shrinker
);