Import 2.3.5
[davej-history.git] / net / sunrpc / auth.c
blob7c966779b464751c5b80433bb4ba639f7d9c88c6
1 /*
2 * linux/fs/nfs/rpcauth.c
4 * Generic RPC authentication API.
6 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
8 * Modified May 1999, Horst von Brand <vonbrand@sleipnir.valparaiso.cl>
9 */
11 #include <linux/types.h>
12 #include <linux/string.h>
13 #include <linux/sched.h>
14 #include <linux/malloc.h>
15 #include <linux/errno.h>
16 #include <linux/socket.h>
17 #include <linux/sunrpc/clnt.h>
19 #ifdef RPC_DEBUG
20 # define RPCDBG_FACILITY RPCDBG_AUTH
21 #endif
23 #define RPC_MAXFLAVOR 8
25 static struct rpc_authops * auth_flavors[RPC_MAXFLAVOR] = {
26 &authnull_ops, /* AUTH_NULL */
27 &authunix_ops, /* AUTH_UNIX */
28 NULL, /* others can be loadable modules */
31 int
32 rpcauth_register(struct rpc_authops *ops)
34 unsigned int flavor;
36 if ((flavor = ops->au_flavor) >= RPC_MAXFLAVOR)
37 return -EINVAL;
38 if (auth_flavors[flavor] != NULL)
39 return -EPERM; /* what else? */
40 auth_flavors[flavor] = ops;
41 return 0;
44 int
45 rpcauth_unregister(struct rpc_authops *ops)
47 unsigned int flavor;
49 if ((flavor = ops->au_flavor) >= RPC_MAXFLAVOR)
50 return -EINVAL;
51 if (auth_flavors[flavor] != ops)
52 return -EPERM; /* what else? */
53 auth_flavors[flavor] = NULL;
54 return 0;
57 struct rpc_auth *
58 rpcauth_create(unsigned int flavor, struct rpc_clnt *clnt)
60 struct rpc_authops *ops;
62 if (flavor >= RPC_MAXFLAVOR || !(ops = auth_flavors[flavor]))
63 return NULL;
64 clnt->cl_auth = ops->create(clnt);
65 return clnt->cl_auth;
68 void
69 rpcauth_destroy(struct rpc_auth *auth)
71 auth->au_ops->destroy(auth);
75 * Initialize RPC credential cache
77 void
78 rpcauth_init_credcache(struct rpc_auth *auth)
80 memset(auth->au_credcache, 0, sizeof(auth->au_credcache));
81 auth->au_nextgc = jiffies + (auth->au_expire >> 1);
85 * Clear the RPC credential cache
87 void
88 rpcauth_free_credcache(struct rpc_auth *auth)
90 struct rpc_cred **q, *cred;
91 void (*destroy)(struct rpc_cred *);
92 int i;
94 if (!(destroy = auth->au_ops->crdestroy))
95 destroy = (void (*)(struct rpc_cred *)) rpc_free;
97 for (i = 0; i < RPC_CREDCACHE_NR; i++) {
98 q = &auth->au_credcache[i];
99 while ((cred = *q) != NULL) {
100 *q = cred->cr_next;
101 destroy(cred);
107 * Remove stale credentials. Avoid sleeping inside the loop.
109 static void
110 rpcauth_gc_credcache(struct rpc_auth *auth)
112 struct rpc_cred **q, *cred, *free = NULL;
113 int i, safe = 0;
115 dprintk("RPC: gc'ing RPC credentials for auth %p\n", auth);
116 for (i = 0; i < RPC_CREDCACHE_NR; i++) {
117 q = &auth->au_credcache[i];
118 while ((cred = *q) != NULL) {
119 if (++safe > 500) {
120 printk("RPC: rpcauth_gc_credcache looping!\n");
121 break;
123 if (!cred->cr_count && time_before(cred->cr_expire, jiffies)) {
124 *q = cred->cr_next;
125 cred->cr_next = free;
126 free = cred;
127 continue;
129 q = &cred->cr_next;
132 while ((cred = free) != NULL) {
133 free = cred->cr_next;
134 rpc_free(cred);
136 auth->au_nextgc = jiffies + auth->au_expire;
140 * Insert credential into cache
142 inline void
143 rpcauth_insert_credcache(struct rpc_auth *auth, struct rpc_cred *cred)
145 int nr;
147 nr = (cred->cr_uid % RPC_CREDCACHE_NR);
148 cred->cr_next = auth->au_credcache[nr];
149 auth->au_credcache[nr] = cred;
150 cred->cr_expire = jiffies + auth->au_expire;
151 cred->cr_count++;
155 * Look up a process' credentials in the authentication cache
157 static struct rpc_cred *
158 rpcauth_lookup_credcache(struct rpc_task *task)
160 struct rpc_auth *auth = task->tk_auth;
161 struct rpc_cred **q, *cred = NULL;
162 int nr;
164 nr = RPC_DO_ROOTOVERRIDE(task)? 0 : (current->uid % RPC_CREDCACHE_NR);
166 if (time_before(auth->au_nextgc, jiffies))
167 rpcauth_gc_credcache(auth);
169 q = &auth->au_credcache[nr];
170 while ((cred = *q) != NULL) {
171 if (auth->au_ops->crmatch(task, cred)) {
172 *q = cred->cr_next;
173 break;
175 q = &cred->cr_next;
178 if (!cred)
179 cred = auth->au_ops->crcreate(task);
181 if (cred)
182 rpcauth_insert_credcache(auth, cred);
184 return (struct rpc_cred *) cred;
188 * Remove cred handle from cache
190 static inline void
191 rpcauth_remove_credcache(struct rpc_auth *auth, struct rpc_cred *cred)
193 struct rpc_cred **q, *cr;
194 int nr;
196 nr = (cred->cr_uid % RPC_CREDCACHE_NR);
197 q = &auth->au_credcache[nr];
198 while ((cr = *q) != NULL) {
199 if (cred == cr) {
200 *q = cred->cr_next;
201 return;
203 q = &cred->cr_next;
207 struct rpc_cred *
208 rpcauth_lookupcred(struct rpc_task *task)
210 dprintk("RPC: %4d looking up %s cred\n",
211 task->tk_pid, task->tk_auth->au_ops->au_name);
212 return task->tk_cred = rpcauth_lookup_credcache(task);
216 rpcauth_matchcred(struct rpc_task *task, struct rpc_cred *cred)
218 struct rpc_auth *auth = task->tk_auth;
220 dprintk("RPC: %4d matching %s cred %p\n",
221 task->tk_pid, auth->au_ops->au_name, task->tk_cred);
222 return auth->au_ops->crmatch(task, cred);
225 void
226 rpcauth_holdcred(struct rpc_task *task)
228 dprintk("RPC: %4d holding %s cred %p\n",
229 task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_cred);
230 if (task->tk_cred)
231 task->tk_cred->cr_count++;
234 void
235 rpcauth_releasecred(struct rpc_task *task)
237 struct rpc_auth *auth = task->tk_auth;
238 struct rpc_cred *cred;
240 dprintk("RPC: %4d releasing %s cred %p\n",
241 task->tk_pid, auth->au_ops->au_name, task->tk_cred);
242 if ((cred = task->tk_cred) != NULL) {
243 cred->cr_count--;
244 if (cred->cr_flags & RPCAUTH_CRED_DEAD) {
245 rpcauth_remove_credcache(auth, cred);
246 if (!cred->cr_count)
247 auth->au_ops->crdestroy(cred);
249 task->tk_cred = NULL;
253 u32 *
254 rpcauth_marshcred(struct rpc_task *task, u32 *p)
256 struct rpc_auth *auth = task->tk_auth;
258 dprintk("RPC: %4d marshaling %s cred %p\n",
259 task->tk_pid, auth->au_ops->au_name, task->tk_cred);
260 return auth->au_ops->crmarshal(task, p,
261 task->tk_flags & RPC_CALL_REALUID);
264 u32 *
265 rpcauth_checkverf(struct rpc_task *task, u32 *p)
267 struct rpc_auth *auth = task->tk_auth;
269 dprintk("RPC: %4d validating %s cred %p\n",
270 task->tk_pid, auth->au_ops->au_name, task->tk_cred);
271 return auth->au_ops->crvalidate(task, p);
275 rpcauth_refreshcred(struct rpc_task *task)
277 struct rpc_auth *auth = task->tk_auth;
279 dprintk("RPC: %4d refreshing %s cred %p\n",
280 task->tk_pid, auth->au_ops->au_name, task->tk_cred);
281 task->tk_status = auth->au_ops->crrefresh(task);
282 return task->tk_status;
285 void
286 rpcauth_invalcred(struct rpc_task *task)
288 dprintk("RPC: %4d invalidating %s cred %p\n",
289 task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_cred);
290 if (task->tk_cred)
291 task->tk_cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
295 rpcauth_uptodatecred(struct rpc_task *task)
297 return !(task->tk_cred) ||
298 (task->tk_cred->cr_flags & RPCAUTH_CRED_UPTODATE);