1 /*
2 * linux/fs/nfs/rpcauth.c
3 *
4 * Generic RPC authentication API.
5 *
6 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
7 */
8
9 #include <linux/types.h>
10 #include <linux/sched.h>
11 #include <linux/malloc.h>
12 #include <linux/errno.h>
13 #include <linux/socket.h>
14 #include <linux/sunrpc/clnt.h>
15 #include <linux/spinlock.h>
16
17 #ifdef RPC_DEBUG
18 # define RPCDBG_FACILITY RPCDBG_AUTH
19 #endif
20
21 #define RPC_MAXFLAVOR 8
22
23 static struct rpc_authops * auth_flavors[RPC_MAXFLAVOR] = {
24 &authnull_ops, /* AUTH_NULL */
25 &authunix_ops, /* AUTH_UNIX */
26 NULL, /* others can be loadable modules */
27 };
28
29 int
30 rpcauth_register(struct rpc_authops *ops)
31 {
32 unsigned int flavor;
33
34 if ((flavor = ops->au_flavor) >= RPC_MAXFLAVOR)
35 return -EINVAL;
36 if (auth_flavors[flavor] != NULL)
37 return -EPERM; /* what else? */
38 auth_flavors[flavor] = ops;
39 return 0;
40 }
41
42 int
43 rpcauth_unregister(struct rpc_authops *ops)
44 {
45 unsigned int flavor;
46
47 if ((flavor = ops->au_flavor) >= RPC_MAXFLAVOR)
48 return -EINVAL;
49 if (auth_flavors[flavor] != ops)
50 return -EPERM; /* what else? */
51 auth_flavors[flavor] = NULL;
52 return 0;
53 }
54
55 struct rpc_auth *
56 rpcauth_create(unsigned int flavor, struct rpc_clnt *clnt)
57 {
58 struct rpc_authops *ops;
59
60 if (flavor >= RPC_MAXFLAVOR || !(ops = auth_flavors[flavor]))
61 return NULL;
62 clnt->cl_auth = ops->create(clnt);
63 return clnt->cl_auth;
64 }
65
66 void
67 rpcauth_destroy(struct rpc_auth *auth)
68 {
69 auth->au_ops->destroy(auth);
70 }
71
72 spinlock_t rpc_credcache_lock = SPIN_LOCK_UNLOCKED;
73
74 /*
75 * Initialize RPC credential cache
76 */
77 void
78 rpcauth_init_credcache(struct rpc_auth *auth)
79 {
80 memset(auth->au_credcache, 0, sizeof(auth->au_credcache));
81 auth->au_nextgc = jiffies + (auth->au_expire >> 1);
82 }
83
84 static inline void
85 rpcauth_crdestroy(struct rpc_auth *auth, struct rpc_cred *cred)
86 {
87 #ifdef RPC_DEBUG
88 if (cred->cr_magic != RPCAUTH_CRED_MAGIC)
89 BUG();
90 cred->cr_magic = 0;
91 #endif
92 if (auth->au_ops->crdestroy)
93 auth->au_ops->crdestroy(cred);
94 else
95 rpc_free(cred);
96 }
97
98 /*
99 * Clear the RPC credential cache
100 */
101 void
102 rpcauth_free_credcache(struct rpc_auth *auth)
103 {
104 struct rpc_cred **q, *cred;
105 void (*destroy)(struct rpc_cred *);
106 int i;
107
108 if (!(destroy = auth->au_ops->crdestroy))
109 destroy = (void (*)(struct rpc_cred *)) rpc_free;
110
111 spin_lock(&rpc_credcache_lock);
112 for (i = 0; i < RPC_CREDCACHE_NR; i++) {
113 q = &auth->au_credcache[i];
114 while ((cred = *q) != NULL) {
115 *q = cred->cr_next;
116 destroy(cred);
117 }
118 }
119 spin_unlock(&rpc_credcache_lock);
120 }
121
122 /*
123 * Remove stale credentials. Avoid sleeping inside the loop.
124 */
125 static void
126 rpcauth_gc_credcache(struct rpc_auth *auth)
127 {
128 struct rpc_cred **q, *cred, *free = NULL;
129 int i;
130
131 dprintk("RPC: gc'ing RPC credentials for auth %p\n", auth);
132 spin_lock(&rpc_credcache_lock);
133 for (i = 0; i < RPC_CREDCACHE_NR; i++) {
134 q = &auth->au_credcache[i];
135 while ((cred = *q) != NULL) {
136 if (!cred->cr_count &&
137 time_before(cred->cr_expire, jiffies)) {
138 *q = cred->cr_next;
139 cred->cr_next = free;
140 free = cred;
141 continue;
142 }
143 q = &cred->cr_next;
144 }
145 }
146 spin_unlock(&rpc_credcache_lock);
147 while ((cred = free) != NULL) {
148 free = cred->cr_next;
149 rpcauth_crdestroy(auth, cred);
150 }
151 auth->au_nextgc = jiffies + auth->au_expire;
152 }
153
154 /*
155 * Insert credential into cache
156 */
157 void
158 rpcauth_insert_credcache(struct rpc_auth *auth, struct rpc_cred *cred)
159 {
160 int nr;
161
162 nr = (cred->cr_uid & RPC_CREDCACHE_MASK);
163 spin_lock(&rpc_credcache_lock);
164 cred->cr_next = auth->au_credcache[nr];
165 auth->au_credcache[nr] = cred;
166 cred->cr_count++;
167 cred->cr_expire = jiffies + auth->au_expire;
168 spin_unlock(&rpc_credcache_lock);
169 }
170
171 /*
172 * Look up a process' credentials in the authentication cache
173 */
174 static struct rpc_cred *
175 rpcauth_lookup_credcache(struct rpc_auth *auth, int taskflags)
176 {
177 struct rpc_cred **q, *cred = NULL;
178 int nr = 0;
179
180 if (!(taskflags & RPC_TASK_ROOTCREDS))
181 nr = current->uid & RPC_CREDCACHE_MASK;
182
183 if (time_before(auth->au_nextgc, jiffies))
184 rpcauth_gc_credcache(auth);
185
186 spin_lock(&rpc_credcache_lock);
187 q = &auth->au_credcache[nr];
188 while ((cred = *q) != NULL) {
189 if (!(cred->cr_flags & RPCAUTH_CRED_DEAD) &&
190 auth->au_ops->crmatch(cred, taskflags)) {
191 *q = cred->cr_next;
192 break;
193 }
194 q = &cred->cr_next;
195 }
196 spin_unlock(&rpc_credcache_lock);
197
198 if (!cred) {
199 cred = auth->au_ops->crcreate(taskflags);
200 #ifdef RPC_DEBUG
201 if (cred)
202 cred->cr_magic = RPCAUTH_CRED_MAGIC;
203 #endif
204 }
205
206 if (cred)
207 rpcauth_insert_credcache(auth, cred);
208
209 return (struct rpc_cred *) cred;
210 }
211
212 /*
213 * Remove cred handle from cache
214 */
215 static void
216 rpcauth_remove_credcache(struct rpc_auth *auth, struct rpc_cred *cred)
217 {
218 struct rpc_cred **q, *cr;
219 int nr;
220
221 nr = (cred->cr_uid & RPC_CREDCACHE_MASK);
222 spin_lock(&rpc_credcache_lock);
223 q = &auth->au_credcache[nr];
224 while ((cr = *q) != NULL) {
225 if (cred == cr) {
226 *q = cred->cr_next;
227 cred->cr_next = NULL;
228 break;
229 }
230 q = &cred->cr_next;
231 }
232 spin_unlock(&rpc_credcache_lock);
233 }
234
235 struct rpc_cred *
236 rpcauth_lookupcred(struct rpc_auth *auth, int taskflags)
237 {
238 dprintk("RPC: looking up %s cred\n",
239 auth->au_ops->au_name);
240 return rpcauth_lookup_credcache(auth, taskflags);
241 }
242
243 struct rpc_cred *
244 rpcauth_bindcred(struct rpc_task *task)
245 {
246 struct rpc_auth *auth = task->tk_auth;
247
248 dprintk("RPC: %4d looking up %s cred\n",
249 task->tk_pid, task->tk_auth->au_ops->au_name);
250 task->tk_msg.rpc_cred = rpcauth_lookup_credcache(auth, task->tk_flags);
251 if (task->tk_msg.rpc_cred == 0)
252 task->tk_status = -ENOMEM;
253 return task->tk_msg.rpc_cred;
254 }
255
256 int
257 rpcauth_matchcred(struct rpc_auth *auth, struct rpc_cred *cred, int taskflags)
258 {
259 dprintk("RPC: matching %s cred %d\n",
260 auth->au_ops->au_name, taskflags);
261 return auth->au_ops->crmatch(cred, taskflags);
262 }
263
264 void
265 rpcauth_holdcred(struct rpc_task *task)
266 {
267 dprintk("RPC: %4d holding %s cred %p\n",
268 task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_msg.rpc_cred);
269 if (task->tk_msg.rpc_cred) {
270 task->tk_msg.rpc_cred->cr_count++;
271 task->tk_msg.rpc_cred->cr_expire = jiffies + task->tk_auth->au_expire;
272 }
273 }
274
275 void
276 rpcauth_releasecred(struct rpc_auth *auth, struct rpc_cred *cred)
277 {
278 if (cred != NULL && cred->cr_count > 0) {
279 cred->cr_count--;
280 if (cred->cr_flags & RPCAUTH_CRED_DEAD) {
281 rpcauth_remove_credcache(auth, cred);
282 if (!cred->cr_count)
283 rpcauth_crdestroy(auth, cred);
284 }
285 }
286 }
287
288 void
289 rpcauth_unbindcred(struct rpc_task *task)
290 {
291 struct rpc_auth *auth = task->tk_auth;
292 struct rpc_cred *cred = task->tk_msg.rpc_cred;
293
294 dprintk("RPC: %4d releasing %s cred %p\n",
295 task->tk_pid, auth->au_ops->au_name, cred);
296
297 rpcauth_releasecred(auth, cred);
298 task->tk_msg.rpc_cred = NULL;
299 }
300
301 u32 *
302 rpcauth_marshcred(struct rpc_task *task, u32 *p)
303 {
304 struct rpc_auth *auth = task->tk_auth;
305
306 dprintk("RPC: %4d marshaling %s cred %p\n",
307 task->tk_pid, auth->au_ops->au_name, task->tk_msg.rpc_cred);
308 return auth->au_ops->crmarshal(task, p,
309 task->tk_flags & RPC_CALL_REALUID);
310 }
311
312 u32 *
313 rpcauth_checkverf(struct rpc_task *task, u32 *p)
314 {
315 struct rpc_auth *auth = task->tk_auth;
316
317 dprintk("RPC: %4d validating %s cred %p\n",
318 task->tk_pid, auth->au_ops->au_name, task->tk_msg.rpc_cred);
319 return auth->au_ops->crvalidate(task, p);
320 }
321
322 int
323 rpcauth_refreshcred(struct rpc_task *task)
324 {
325 struct rpc_auth *auth = task->tk_auth;
326
327 dprintk("RPC: %4d refreshing %s cred %p\n",
328 task->tk_pid, auth->au_ops->au_name, task->tk_msg.rpc_cred);
329 task->tk_status = auth->au_ops->crrefresh(task);
330 return task->tk_status;
331 }
332
333 void
334 rpcauth_invalcred(struct rpc_task *task)
335 {
336 dprintk("RPC: %4d invalidating %s cred %p\n",
337 task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_msg.rpc_cred);
338 if (task->tk_msg.rpc_cred)
339 task->tk_msg.rpc_cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
340 }
341
342 int
343 rpcauth_uptodatecred(struct rpc_task *task)
344 {
345 return !(task->tk_msg.rpc_cred) ||
346 (task->tk_msg.rpc_cred->cr_flags & RPCAUTH_CRED_UPTODATE);
347 }
348
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.