auth_unix.c revision 180064
1/*	$NetBSD: auth_unix.c,v 1.18 2000/07/06 03:03:30 christos Exp $	*/
2
3/*
4 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5 * unrestricted use provided that this legend is included on all tape
6 * media and as a part of the software program in whole or part.  Users
7 * may copy or modify Sun RPC without charge, but are not authorized
8 * to license or distribute it to anyone else except as part of a product or
9 * program developed by the user.
10 *
11 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14 *
15 * Sun RPC is provided with no support and without any obligation on the
16 * part of Sun Microsystems, Inc. to assist in its use, correction,
17 * modification or enhancement.
18 *
19 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21 * OR ANY PART THEREOF.
22 *
23 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24 * or profits or other special, indirect and consequential damages, even if
25 * Sun has been advised of the possibility of such damages.
26 *
27 * Sun Microsystems, Inc.
28 * 2550 Garcia Avenue
29 * Mountain View, California  94043
30 */
31
32#if defined(LIBC_SCCS) && !defined(lint)
33static char *sccsid2 = "@(#)auth_unix.c 1.19 87/08/11 Copyr 1984 Sun Micro";
34static char *sccsid = "@(#)auth_unix.c	2.2 88/08/01 4.0 RPCSRC";
35#endif
36#include <sys/cdefs.h>
37__FBSDID("$FreeBSD: head/sys/rpc/auth_unix.c 180064 2008-06-27 14:35:05Z dfr $");
38
39/*
40 * auth_unix.c, Implements UNIX style authentication parameters.
41 *
42 * Copyright (C) 1984, Sun Microsystems, Inc.
43 *
44 * The system is very weak.  The client uses no encryption for it's
45 * credentials and only sends null verifiers.  The server sends backs
46 * null verifiers or optionally a verifier that suggests a new short hand
47 * for the credentials.
48 *
49 */
50
51#include <sys/param.h>
52#include <sys/systm.h>
53#include <sys/hash.h>
54#include <sys/kernel.h>
55#include <sys/lock.h>
56#include <sys/malloc.h>
57#include <sys/pcpu.h>
58#include <sys/sx.h>
59#include <sys/ucred.h>
60
61#include <rpc/types.h>
62#include <rpc/xdr.h>
63#include <rpc/auth.h>
64
65#include <rpc/rpc_com.h>
66
67/* auth_unix.c */
68static void authunix_nextverf (AUTH *);
69static bool_t authunix_marshal (AUTH *, XDR *);
70static bool_t authunix_validate (AUTH *, struct opaque_auth *);
71static bool_t authunix_refresh (AUTH *, void *);
72static void authunix_destroy (AUTH *);
73static void marshal_new_auth (AUTH *);
74
75static struct auth_ops authunix_ops = {
76	.ah_nextverf =		authunix_nextverf,
77	.ah_marshal =		authunix_marshal,
78	.ah_validate =		authunix_validate,
79	.ah_refresh =		authunix_refresh,
80	.ah_destroy =		authunix_destroy
81};
82
83/*
84 * This struct is pointed to by the ah_private field of an auth_handle.
85 */
86struct audata {
87	TAILQ_ENTRY(audata)	au_link;
88	TAILQ_ENTRY(audata)	au_alllink;
89	int			au_refs;
90	struct xucred		au_xcred;
91	struct opaque_auth	au_origcred;	/* original credentials */
92	struct opaque_auth	au_shcred;	/* short hand cred */
93	u_long			au_shfaults;	/* short hand cache faults */
94	char			au_marshed[MAX_AUTH_BYTES];
95	u_int			au_mpos;	/* xdr pos at end of marshed */
96	AUTH			*au_auth;	/* link back to AUTH */
97};
98TAILQ_HEAD(audata_list, audata);
99#define	AUTH_PRIVATE(auth)	((struct audata *)auth->ah_private)
100
101#define AUTH_UNIX_HASH_SIZE	16
102#define AUTH_UNIX_MAX		256
103static struct audata_list auth_unix_cache[AUTH_UNIX_HASH_SIZE];
104static struct audata_list auth_unix_all;
105static struct sx auth_unix_lock;
106static int auth_unix_count;
107
108static void
109authunix_init(void *dummy)
110{
111	int i;
112
113	for (i = 0; i < AUTH_UNIX_HASH_SIZE; i++)
114		TAILQ_INIT(&auth_unix_cache[i]);
115	TAILQ_INIT(&auth_unix_all);
116	sx_init(&auth_unix_lock, "auth_unix_lock");
117}
118SYSINIT(authunix_init, SI_SUB_KMEM, SI_ORDER_ANY, authunix_init, NULL);
119
120/*
121 * Create a unix style authenticator.
122 * Returns an auth handle with the given stuff in it.
123 */
124AUTH *
125authunix_create(struct ucred *cred)
126{
127	uint32_t h, th;
128	struct xucred xcr;
129	char mymem[MAX_AUTH_BYTES];
130	XDR xdrs;
131	AUTH *auth;
132	struct audata *au, *tau;
133	struct timeval now;
134	uint32_t time;
135	int len;
136
137	if (auth_unix_count > AUTH_UNIX_MAX) {
138		while (auth_unix_count > AUTH_UNIX_MAX) {
139			sx_xlock(&auth_unix_lock);
140			tau = TAILQ_FIRST(&auth_unix_all);
141			th = HASHSTEP(HASHINIT, tau->au_xcred.cr_uid)
142				% AUTH_UNIX_HASH_SIZE;
143			TAILQ_REMOVE(&auth_unix_cache[th], tau, au_link);
144			TAILQ_REMOVE(&auth_unix_all, tau, au_alllink);
145			auth_unix_count--;
146			sx_xunlock(&auth_unix_lock);
147			AUTH_DESTROY(tau->au_auth);
148		}
149	}
150
151	/*
152	 * Hash the uid to see if we already have an AUTH with this cred.
153	 */
154	h = HASHSTEP(HASHINIT, cred->cr_uid) % AUTH_UNIX_HASH_SIZE;
155	cru2x(cred, &xcr);
156again:
157	sx_slock(&auth_unix_lock);
158	TAILQ_FOREACH(au, &auth_unix_cache[h], au_link) {
159		if (!memcmp(&xcr, &au->au_xcred, sizeof(xcr))) {
160			if (sx_try_upgrade(&auth_unix_lock)) {
161				/*
162				 * Keep auth_unix_all LRU sorted.
163				 */
164				TAILQ_REMOVE(&auth_unix_all, au, au_alllink);
165				TAILQ_INSERT_TAIL(&auth_unix_all, au,
166				    au_alllink);
167				au->au_refs++;
168				sx_xunlock(&auth_unix_lock);
169				return (au->au_auth);
170			} else {
171				sx_sunlock(&auth_unix_lock);
172				goto again;
173			}
174		}
175	}
176
177	/*
178	 * Allocate and set up auth handle
179	 */
180	au = NULL;
181	auth = mem_alloc(sizeof(*auth));
182	au = mem_alloc(sizeof(*au));
183	auth->ah_ops = &authunix_ops;
184	auth->ah_private = (caddr_t)au;
185	auth->ah_verf = au->au_shcred = _null_auth;
186	au->au_refs = 1;
187	au->au_xcred = xcr;
188	au->au_shfaults = 0;
189	au->au_origcred.oa_base = NULL;
190	au->au_auth = auth;
191
192	getmicrotime(&now);
193	time = now.tv_sec;
194
195	/*
196	 * Serialize the parameters into origcred
197	 */
198	xdrmem_create(&xdrs, mymem, MAX_AUTH_BYTES, XDR_ENCODE);
199	cru2x(cred, &xcr);
200	if (! xdr_authunix_parms(&xdrs, &time, &xcr))
201		panic("authunix_create: failed to encode creds");
202	au->au_origcred.oa_length = len = XDR_GETPOS(&xdrs);
203	au->au_origcred.oa_flavor = AUTH_UNIX;
204	au->au_origcred.oa_base = mem_alloc((u_int) len);
205	memcpy(au->au_origcred.oa_base, mymem, (size_t)len);
206
207	/*
208	 * set auth handle to reflect new cred.
209	 */
210	auth->ah_cred = au->au_origcred;
211	marshal_new_auth(auth);
212
213	if (sx_try_upgrade(&auth_unix_lock)) {
214		auth_unix_count++;
215		TAILQ_INSERT_TAIL(&auth_unix_cache[h], au, au_link);
216		TAILQ_INSERT_TAIL(&auth_unix_all, au, au_alllink);
217		au->au_refs++;	/* one for the cache, one for user */
218		sx_xunlock(&auth_unix_lock);
219		return (auth);
220	} else {
221		sx_sunlock(&auth_unix_lock);
222		AUTH_DESTROY(auth);
223		goto again;
224	}
225}
226
227/*
228 * authunix operations
229 */
230
231/* ARGSUSED */
232static void
233authunix_nextverf(AUTH *auth)
234{
235	/* no action necessary */
236}
237
238static bool_t
239authunix_marshal(AUTH *auth, XDR *xdrs)
240{
241	struct audata *au;
242
243	au = AUTH_PRIVATE(auth);
244	return (XDR_PUTBYTES(xdrs, au->au_marshed, au->au_mpos));
245}
246
247static bool_t
248authunix_validate(AUTH *auth, struct opaque_auth *verf)
249{
250	struct audata *au;
251	XDR xdrs;
252
253	if (verf->oa_flavor == AUTH_SHORT) {
254		au = AUTH_PRIVATE(auth);
255		xdrmem_create(&xdrs, verf->oa_base, verf->oa_length,
256		    XDR_DECODE);
257
258		if (au->au_shcred.oa_base != NULL) {
259			mem_free(au->au_shcred.oa_base,
260			    au->au_shcred.oa_length);
261			au->au_shcred.oa_base = NULL;
262		}
263		if (xdr_opaque_auth(&xdrs, &au->au_shcred)) {
264			auth->ah_cred = au->au_shcred;
265		} else {
266			xdrs.x_op = XDR_FREE;
267			(void)xdr_opaque_auth(&xdrs, &au->au_shcred);
268			au->au_shcred.oa_base = NULL;
269			auth->ah_cred = au->au_origcred;
270		}
271		marshal_new_auth(auth);
272	}
273	return (TRUE);
274}
275
276static bool_t
277authunix_refresh(AUTH *auth, void *dummy)
278{
279	struct audata *au = AUTH_PRIVATE(auth);
280	struct xucred xcr;
281	uint32_t time;
282	struct timeval now;
283	XDR xdrs;
284	int stat;
285
286	if (auth->ah_cred.oa_base == au->au_origcred.oa_base) {
287		/* there is no hope.  Punt */
288		return (FALSE);
289	}
290	au->au_shfaults ++;
291
292	/* first deserialize the creds back into a struct ucred */
293	xdrmem_create(&xdrs, au->au_origcred.oa_base,
294	    au->au_origcred.oa_length, XDR_DECODE);
295	stat = xdr_authunix_parms(&xdrs, &time, &xcr);
296	if (! stat)
297		goto done;
298
299	/* update the time and serialize in place */
300	getmicrotime(&now);
301	time = now.tv_sec;
302	xdrs.x_op = XDR_ENCODE;
303	XDR_SETPOS(&xdrs, 0);
304
305	stat = xdr_authunix_parms(&xdrs, &time, &xcr);
306	if (! stat)
307		goto done;
308	auth->ah_cred = au->au_origcred;
309	marshal_new_auth(auth);
310done:
311	XDR_DESTROY(&xdrs);
312	return (stat);
313}
314
315static void
316authunix_destroy(AUTH *auth)
317{
318	struct audata *au;
319	int refs;
320
321	au = AUTH_PRIVATE(auth);
322
323	sx_xlock(&auth_unix_lock);
324	au->au_refs--;
325	refs = au->au_refs;
326	sx_xunlock(&auth_unix_lock);
327
328	if (refs > 0)
329		return;
330
331	mem_free(au->au_origcred.oa_base, au->au_origcred.oa_length);
332
333	if (au->au_shcred.oa_base != NULL)
334		mem_free(au->au_shcred.oa_base, au->au_shcred.oa_length);
335
336	mem_free(auth->ah_private, sizeof(struct audata));
337
338	if (auth->ah_verf.oa_base != NULL)
339		mem_free(auth->ah_verf.oa_base, auth->ah_verf.oa_length);
340
341	mem_free(auth, sizeof(*auth));
342}
343
344/*
345 * Marshals (pre-serializes) an auth struct.
346 * sets private data, au_marshed and au_mpos
347 */
348static void
349marshal_new_auth(AUTH *auth)
350{
351	XDR	xdr_stream;
352	XDR	*xdrs = &xdr_stream;
353	struct audata *au;
354
355	au = AUTH_PRIVATE(auth);
356	xdrmem_create(xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE);
357	if ((! xdr_opaque_auth(xdrs, &(auth->ah_cred))) ||
358	    (! xdr_opaque_auth(xdrs, &(auth->ah_verf))))
359		printf("auth_none.c - Fatal marshalling problem");
360	else
361		au->au_mpos = XDR_GETPOS(xdrs);
362	XDR_DESTROY(xdrs);
363}
364