File: /usr/src/linux/net/sunrpc/auth.c

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/slab.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     static 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     /*
85      * Destroy an unreferenced credential
86      */
87     static inline void
88     rpcauth_crdestroy(struct rpc_cred *cred)
89     {
90     #ifdef RPC_DEBUG
91     	if (cred->cr_magic != RPCAUTH_CRED_MAGIC)
92     		BUG();
93     	cred->cr_magic = 0;
94     	if (atomic_read(&cred->cr_count) || cred->cr_auth)
95     		BUG();
96     #endif
97     	cred->cr_ops->crdestroy(cred);
98     }
99     
100     /*
101      * Destroy a list of credentials
102      */
103     static inline
104     void rpcauth_destroy_credlist(struct rpc_cred *head)
105     {
106     	struct rpc_cred *cred;
107     
108     	while ((cred = head) != NULL) {
109     		head = cred->cr_next;
110     		rpcauth_crdestroy(cred);
111     	}
112     }
113     
114     /*
115      * Clear the RPC credential cache, and delete those credentials
116      * that are not referenced.
117      */
118     void
119     rpcauth_free_credcache(struct rpc_auth *auth)
120     {
121     	struct rpc_cred	**q, *cred, *free = NULL;
122     	int		i;
123     
124     	spin_lock(&rpc_credcache_lock);
125     	for (i = 0; i < RPC_CREDCACHE_NR; i++) {
126     		q = &auth->au_credcache[i];
127     		while ((cred = *q) != NULL) {
128     			*q = cred->cr_next;
129     			cred->cr_auth = NULL;
130     			if (atomic_read(&cred->cr_count) == 0) {
131     				cred->cr_next = free;
132     				free = cred;
133     			} else
134     				cred->cr_next = NULL;
135     		}
136     	}
137     	spin_unlock(&rpc_credcache_lock);
138     	rpcauth_destroy_credlist(free);
139     }
140     
141     /*
142      * Remove stale credentials. Avoid sleeping inside the loop.
143      */
144     static void
145     rpcauth_gc_credcache(struct rpc_auth *auth)
146     {
147     	struct rpc_cred	**q, *cred, *free = NULL;
148     	int		i;
149     
150     	dprintk("RPC: gc'ing RPC credentials for auth %p\n", auth);
151     	spin_lock(&rpc_credcache_lock);
152     	for (i = 0; i < RPC_CREDCACHE_NR; i++) {
153     		q = &auth->au_credcache[i];
154     		while ((cred = *q) != NULL) {
155     			if (!atomic_read(&cred->cr_count) &&
156     			    time_before(cred->cr_expire, jiffies)) {
157     				*q = cred->cr_next;
158     				cred->cr_auth = NULL;
159     				cred->cr_next = free;
160     				free = cred;
161     				continue;
162     			}
163     			q = &cred->cr_next;
164     		}
165     	}
166     	spin_unlock(&rpc_credcache_lock);
167     	rpcauth_destroy_credlist(free);
168     	auth->au_nextgc = jiffies + auth->au_expire;
169     }
170     
171     /*
172      * Insert credential into cache
173      */
174     void
175     rpcauth_insert_credcache(struct rpc_auth *auth, struct rpc_cred *cred)
176     {
177     	int		nr;
178     
179     	nr = (cred->cr_uid & RPC_CREDCACHE_MASK);
180     	spin_lock(&rpc_credcache_lock);
181     	cred->cr_next = auth->au_credcache[nr];
182     	auth->au_credcache[nr] = cred;
183     	cred->cr_auth = auth;
184     	get_rpccred(cred);
185     	spin_unlock(&rpc_credcache_lock);
186     }
187     
188     /*
189      * Look up a process' credentials in the authentication cache
190      */
191     static struct rpc_cred *
192     rpcauth_lookup_credcache(struct rpc_auth *auth, int taskflags)
193     {
194     	struct rpc_cred	**q, *cred = NULL;
195     	int		nr = 0;
196     
197     	if (!(taskflags & RPC_TASK_ROOTCREDS))
198     		nr = current->uid & RPC_CREDCACHE_MASK;
199     
200     	if (time_before(auth->au_nextgc, jiffies))
201     		rpcauth_gc_credcache(auth);
202     
203     	spin_lock(&rpc_credcache_lock);
204     	q = &auth->au_credcache[nr];
205     	while ((cred = *q) != NULL) {
206     		if (!(cred->cr_flags & RPCAUTH_CRED_DEAD) &&
207     		    cred->cr_ops->crmatch(cred, taskflags)) {
208     			*q = cred->cr_next;
209     			break;
210     		}
211     		q = &cred->cr_next;
212     	}
213     	spin_unlock(&rpc_credcache_lock);
214     
215     	if (!cred) {
216     		cred = auth->au_ops->crcreate(taskflags);
217     #ifdef RPC_DEBUG
218     		if (cred)
219     			cred->cr_magic = RPCAUTH_CRED_MAGIC;
220     #endif
221     	}
222     
223     	if (cred)
224     		rpcauth_insert_credcache(auth, cred);
225     
226     	return (struct rpc_cred *) cred;
227     }
228     
229     /*
230      * Remove cred handle from cache
231      */
232     static void
233     rpcauth_remove_credcache(struct rpc_cred *cred)
234     {
235     	struct rpc_auth *auth = cred->cr_auth;
236     	struct rpc_cred	**q, *cr;
237     	int		nr;
238     
239     	nr = (cred->cr_uid & RPC_CREDCACHE_MASK);
240     	q = &auth->au_credcache[nr];
241     	while ((cr = *q) != NULL) {
242     		if (cred == cr) {
243     			*q = cred->cr_next;
244     			cred->cr_next = NULL;
245     			cred->cr_auth = NULL;
246     			break;
247     		}
248     		q = &cred->cr_next;
249     	}
250     }
251     
252     struct rpc_cred *
253     rpcauth_lookupcred(struct rpc_auth *auth, int taskflags)
254     {
255     	dprintk("RPC:     looking up %s cred\n",
256     		auth->au_ops->au_name);
257     	return rpcauth_lookup_credcache(auth, taskflags);
258     }
259     
260     struct rpc_cred *
261     rpcauth_bindcred(struct rpc_task *task)
262     {
263     	struct rpc_auth *auth = task->tk_auth;
264     
265     	dprintk("RPC: %4d looking up %s cred\n",
266     		task->tk_pid, task->tk_auth->au_ops->au_name);
267     	task->tk_msg.rpc_cred = rpcauth_lookup_credcache(auth, task->tk_flags);
268     	if (task->tk_msg.rpc_cred == 0)
269     		task->tk_status = -ENOMEM;
270     	return task->tk_msg.rpc_cred;
271     }
272     
273     int
274     rpcauth_matchcred(struct rpc_auth *auth, struct rpc_cred *cred, int taskflags)
275     {
276     	dprintk("RPC:     matching %s cred %d\n",
277     		auth->au_ops->au_name, taskflags);
278     	return cred->cr_ops->crmatch(cred, taskflags);
279     }
280     
281     void
282     rpcauth_holdcred(struct rpc_task *task)
283     {
284     	dprintk("RPC: %4d holding %s cred %p\n",
285     		task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_msg.rpc_cred);
286     	if (task->tk_msg.rpc_cred)
287     		get_rpccred(task->tk_msg.rpc_cred);
288     }
289     
290     void
291     put_rpccred(struct rpc_cred *cred)
292     {
293     	if (!atomic_dec_and_lock(&cred->cr_count, &rpc_credcache_lock))
294     		return;
295     
296     	if (cred->cr_auth && cred->cr_flags & RPCAUTH_CRED_DEAD)
297     		rpcauth_remove_credcache(cred);
298     
299     	if (!cred->cr_auth) {
300     		spin_unlock(&rpc_credcache_lock);
301     		rpcauth_crdestroy(cred);
302     		return;
303     	}
304     	cred->cr_expire = jiffies + cred->cr_auth->au_expire;
305     	spin_unlock(&rpc_credcache_lock);
306     }
307     
308     void
309     rpcauth_unbindcred(struct rpc_task *task)
310     {
311     	struct rpc_auth	*auth = task->tk_auth;
312     	struct rpc_cred	*cred = task->tk_msg.rpc_cred;
313     
314     	dprintk("RPC: %4d releasing %s cred %p\n",
315     		task->tk_pid, auth->au_ops->au_name, cred);
316     
317     	put_rpccred(cred);
318     	task->tk_msg.rpc_cred = NULL;
319     }
320     
321     u32 *
322     rpcauth_marshcred(struct rpc_task *task, u32 *p)
323     {
324     	struct rpc_auth	*auth = task->tk_auth;
325     	struct rpc_cred	*cred = task->tk_msg.rpc_cred;
326     
327     	dprintk("RPC: %4d marshaling %s cred %p\n",
328     		task->tk_pid, auth->au_ops->au_name, cred);
329     	return cred->cr_ops->crmarshal(task, p,
330     				task->tk_flags & RPC_CALL_REALUID);
331     }
332     
333     u32 *
334     rpcauth_checkverf(struct rpc_task *task, u32 *p)
335     {
336     	struct rpc_auth	*auth = task->tk_auth;
337     	struct rpc_cred	*cred = task->tk_msg.rpc_cred;
338     
339     	dprintk("RPC: %4d validating %s cred %p\n",
340     		task->tk_pid, auth->au_ops->au_name, cred);
341     	return cred->cr_ops->crvalidate(task, p);
342     }
343     
344     int
345     rpcauth_refreshcred(struct rpc_task *task)
346     {
347     	struct rpc_auth	*auth = task->tk_auth;
348     	struct rpc_cred	*cred = task->tk_msg.rpc_cred;
349     
350     	dprintk("RPC: %4d refreshing %s cred %p\n",
351     		task->tk_pid, auth->au_ops->au_name, cred);
352     	task->tk_status = cred->cr_ops->crrefresh(task);
353     	return task->tk_status;
354     }
355     
356     void
357     rpcauth_invalcred(struct rpc_task *task)
358     {
359     	dprintk("RPC: %4d invalidating %s cred %p\n",
360     		task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_msg.rpc_cred);
361     	spin_lock(&rpc_credcache_lock);
362     	if (task->tk_msg.rpc_cred)
363     		task->tk_msg.rpc_cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
364     	spin_unlock(&rpc_credcache_lock);
365     }
366     
367     int
368     rpcauth_uptodatecred(struct rpc_task *task)
369     {
370     	int retval;
371     	spin_lock(&rpc_credcache_lock);
372     	retval = !(task->tk_msg.rpc_cred) ||
373     		(task->tk_msg.rpc_cred->cr_flags & RPCAUTH_CRED_UPTODATE);
374     	spin_unlock(&rpc_credcache_lock);
375     	return retval;
376     }
377