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 struct rpc_authops * auth_flavors[RPC_AUTH_MAXFLAVOR] = {
22 &authnull_ops, /* AUTH_NULL */
23 &authunix_ops, /* AUTH_UNIX */
24 NULL, /* others can be loadable modules */
28 pseudoflavor_to_flavor(u32 flavor) {
29 if (flavor >= RPC_AUTH_MAXFLAVOR)
35 rpcauth_register(struct rpc_authops *ops)
37 rpc_authflavor_t flavor;
39 if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR)
41 if (auth_flavors[flavor] != NULL)
42 return -EPERM; /* what else? */
43 auth_flavors[flavor] = ops;
48 rpcauth_unregister(struct rpc_authops *ops)
50 rpc_authflavor_t flavor;
52 if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR)
54 if (auth_flavors[flavor] != ops)
55 return -EPERM; /* what else? */
56 auth_flavors[flavor] = NULL;
61 rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt)
63 struct rpc_auth *auth;
64 struct rpc_authops *ops;
65 u32 flavor = pseudoflavor_to_flavor(pseudoflavor);
67 auth = ERR_PTR(-EINVAL);
68 if (flavor >= RPC_AUTH_MAXFLAVOR)
71 /* FIXME - auth_flavors[] really needs an rw lock,
72 * and module refcounting. */
74 if ((ops = auth_flavors[flavor]) == NULL)
75 request_module("rpc-auth-%u", flavor);
77 if ((ops = auth_flavors[flavor]) == NULL)
79 auth = ops->create(clnt, pseudoflavor);
83 rpcauth_destroy(clnt->cl_auth);
91 rpcauth_destroy(struct rpc_auth *auth)
93 if (!atomic_dec_and_test(&auth->au_count))
95 auth->au_ops->destroy(auth);
98 static DEFINE_SPINLOCK(rpc_credcache_lock);
101 * Initialize RPC credential cache
104 rpcauth_init_credcache(struct rpc_auth *auth, unsigned long expire)
106 struct rpc_cred_cache *new;
109 new = kmalloc(sizeof(*new), GFP_KERNEL);
112 for (i = 0; i < RPC_CREDCACHE_NR; i++)
113 INIT_HLIST_HEAD(&new->hashtable[i]);
114 new->expire = expire;
115 new->nextgc = jiffies + (expire >> 1);
116 auth->au_credcache = new;
121 * Destroy a list of credentials
124 void rpcauth_destroy_credlist(struct hlist_head *head)
126 struct rpc_cred *cred;
128 while (!hlist_empty(head)) {
129 cred = hlist_entry(head->first, struct rpc_cred, cr_hash);
130 hlist_del_init(&cred->cr_hash);
136 * Clear the RPC credential cache, and delete those credentials
137 * that are not referenced.
140 rpcauth_clear_credcache(struct rpc_cred_cache *cache)
143 struct hlist_node *pos, *next;
144 struct rpc_cred *cred;
147 spin_lock(&rpc_credcache_lock);
148 for (i = 0; i < RPC_CREDCACHE_NR; i++) {
149 hlist_for_each_safe(pos, next, &cache->hashtable[i]) {
150 cred = hlist_entry(pos, struct rpc_cred, cr_hash);
151 __hlist_del(&cred->cr_hash);
152 hlist_add_head(&cred->cr_hash, &free);
155 spin_unlock(&rpc_credcache_lock);
156 rpcauth_destroy_credlist(&free);
160 * Destroy the RPC credential cache
163 rpcauth_destroy_credcache(struct rpc_auth *auth)
165 struct rpc_cred_cache *cache = auth->au_credcache;
168 auth->au_credcache = NULL;
169 rpcauth_clear_credcache(cache);
175 rpcauth_prune_expired(struct rpc_auth *auth, struct rpc_cred *cred, struct hlist_head *free)
177 if (atomic_read(&cred->cr_count) != 1)
179 if (time_after(jiffies, cred->cr_expire + auth->au_credcache->expire))
180 cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
181 if (!(cred->cr_flags & RPCAUTH_CRED_UPTODATE)) {
182 __hlist_del(&cred->cr_hash);
183 hlist_add_head(&cred->cr_hash, free);
188 * Remove stale credentials. Avoid sleeping inside the loop.
191 rpcauth_gc_credcache(struct rpc_auth *auth, struct hlist_head *free)
193 struct rpc_cred_cache *cache = auth->au_credcache;
194 struct hlist_node *pos, *next;
195 struct rpc_cred *cred;
198 dprintk("RPC: gc'ing RPC credentials for auth %p\n", auth);
199 for (i = 0; i < RPC_CREDCACHE_NR; i++) {
200 hlist_for_each_safe(pos, next, &cache->hashtable[i]) {
201 cred = hlist_entry(pos, struct rpc_cred, cr_hash);
202 rpcauth_prune_expired(auth, cred, free);
205 cache->nextgc = jiffies + cache->expire;
209 * Look up a process' credentials in the authentication cache
212 rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,
215 struct rpc_cred_cache *cache = auth->au_credcache;
217 struct hlist_node *pos, *next;
218 struct rpc_cred *new = NULL,
222 if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS))
223 nr = acred->uid & RPC_CREDCACHE_MASK;
225 spin_lock(&rpc_credcache_lock);
226 if (time_before(cache->nextgc, jiffies))
227 rpcauth_gc_credcache(auth, &free);
228 hlist_for_each_safe(pos, next, &cache->hashtable[nr]) {
229 struct rpc_cred *entry;
230 entry = hlist_entry(pos, struct rpc_cred, cr_hash);
231 if (entry->cr_ops->crmatch(acred, entry, flags)) {
232 hlist_del(&entry->cr_hash);
236 rpcauth_prune_expired(auth, entry, &free);
240 hlist_add_head(&new->cr_hash, &free);
245 hlist_add_head(&cred->cr_hash, &cache->hashtable[nr]);
248 spin_unlock(&rpc_credcache_lock);
250 rpcauth_destroy_credlist(&free);
253 new = auth->au_ops->crcreate(auth, acred, flags);
256 new->cr_magic = RPCAUTH_CRED_MAGIC;
261 } else if ((cred->cr_flags & RPCAUTH_CRED_NEW)
262 && cred->cr_ops->cr_init != NULL
263 && !(flags & RPCAUTH_LOOKUP_NEW)) {
264 int res = cred->cr_ops->cr_init(auth, cred);
271 return (struct rpc_cred *) cred;
275 rpcauth_lookupcred(struct rpc_auth *auth, int flags)
277 struct auth_cred acred = {
278 .uid = current->fsuid,
279 .gid = current->fsgid,
280 .group_info = current->group_info,
282 struct rpc_cred *ret;
284 dprintk("RPC: looking up %s cred\n",
285 auth->au_ops->au_name);
286 get_group_info(acred.group_info);
287 ret = auth->au_ops->lookup_cred(auth, &acred, flags);
288 put_group_info(acred.group_info);
293 rpcauth_bindcred(struct rpc_task *task)
295 struct rpc_auth *auth = task->tk_auth;
296 struct auth_cred acred = {
297 .uid = current->fsuid,
298 .gid = current->fsgid,
299 .group_info = current->group_info,
301 struct rpc_cred *ret;
304 dprintk("RPC: %5u looking up %s cred\n",
305 task->tk_pid, task->tk_auth->au_ops->au_name);
306 get_group_info(acred.group_info);
307 if (task->tk_flags & RPC_TASK_ROOTCREDS)
308 flags |= RPCAUTH_LOOKUP_ROOTCREDS;
309 ret = auth->au_ops->lookup_cred(auth, &acred, flags);
311 task->tk_msg.rpc_cred = ret;
313 task->tk_status = PTR_ERR(ret);
314 put_group_info(acred.group_info);
319 rpcauth_holdcred(struct rpc_task *task)
321 dprintk("RPC: %5u holding %s cred %p\n",
322 task->tk_pid, task->tk_auth->au_ops->au_name,
323 task->tk_msg.rpc_cred);
324 if (task->tk_msg.rpc_cred)
325 get_rpccred(task->tk_msg.rpc_cred);
329 put_rpccred(struct rpc_cred *cred)
331 cred->cr_expire = jiffies;
332 if (!atomic_dec_and_test(&cred->cr_count))
334 cred->cr_ops->crdestroy(cred);
338 rpcauth_unbindcred(struct rpc_task *task)
340 struct rpc_cred *cred = task->tk_msg.rpc_cred;
342 dprintk("RPC: %5u releasing %s cred %p\n",
343 task->tk_pid, task->tk_auth->au_ops->au_name, cred);
346 task->tk_msg.rpc_cred = NULL;
350 rpcauth_marshcred(struct rpc_task *task, __be32 *p)
352 struct rpc_cred *cred = task->tk_msg.rpc_cred;
354 dprintk("RPC: %5u marshaling %s cred %p\n",
355 task->tk_pid, task->tk_auth->au_ops->au_name, cred);
357 return cred->cr_ops->crmarshal(task, p);
361 rpcauth_checkverf(struct rpc_task *task, __be32 *p)
363 struct rpc_cred *cred = task->tk_msg.rpc_cred;
365 dprintk("RPC: %5u validating %s cred %p\n",
366 task->tk_pid, task->tk_auth->au_ops->au_name, cred);
368 return cred->cr_ops->crvalidate(task, p);
372 rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp,
373 __be32 *data, void *obj)
375 struct rpc_cred *cred = task->tk_msg.rpc_cred;
377 dprintk("RPC: %5u using %s cred %p to wrap rpc data\n",
378 task->tk_pid, cred->cr_ops->cr_name, cred);
379 if (cred->cr_ops->crwrap_req)
380 return cred->cr_ops->crwrap_req(task, encode, rqstp, data, obj);
381 /* By default, we encode the arguments normally. */
382 return encode(rqstp, data, obj);
386 rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp,
387 __be32 *data, void *obj)
389 struct rpc_cred *cred = task->tk_msg.rpc_cred;
391 dprintk("RPC: %5u using %s cred %p to unwrap rpc data\n",
392 task->tk_pid, cred->cr_ops->cr_name, cred);
393 if (cred->cr_ops->crunwrap_resp)
394 return cred->cr_ops->crunwrap_resp(task, decode, rqstp,
396 /* By default, we decode the arguments normally. */
397 return decode(rqstp, data, obj);
401 rpcauth_refreshcred(struct rpc_task *task)
403 struct rpc_cred *cred = task->tk_msg.rpc_cred;
406 dprintk("RPC: %5u refreshing %s cred %p\n",
407 task->tk_pid, task->tk_auth->au_ops->au_name, cred);
409 err = cred->cr_ops->crrefresh(task);
411 task->tk_status = err;
416 rpcauth_invalcred(struct rpc_task *task)
418 dprintk("RPC: %5u invalidating %s cred %p\n",
419 task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_msg.rpc_cred);
420 spin_lock(&rpc_credcache_lock);
421 if (task->tk_msg.rpc_cred)
422 task->tk_msg.rpc_cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
423 spin_unlock(&rpc_credcache_lock);
427 rpcauth_uptodatecred(struct rpc_task *task)
429 return !(task->tk_msg.rpc_cred) ||
430 (task->tk_msg.rpc_cred->cr_flags & RPCAUTH_CRED_UPTODATE);