auth_unix.c revision 180064
1177633Sdfr/*	$NetBSD: auth_unix.c,v 1.18 2000/07/06 03:03:30 christos Exp $	*/
2177633Sdfr
3177633Sdfr/*
4177633Sdfr * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5177633Sdfr * unrestricted use provided that this legend is included on all tape
6177633Sdfr * media and as a part of the software program in whole or part.  Users
7177633Sdfr * may copy or modify Sun RPC without charge, but are not authorized
8177633Sdfr * to license or distribute it to anyone else except as part of a product or
9177633Sdfr * program developed by the user.
10177633Sdfr *
11177633Sdfr * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12177633Sdfr * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13177633Sdfr * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14177633Sdfr *
15177633Sdfr * Sun RPC is provided with no support and without any obligation on the
16177633Sdfr * part of Sun Microsystems, Inc. to assist in its use, correction,
17177633Sdfr * modification or enhancement.
18177633Sdfr *
19177633Sdfr * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20177633Sdfr * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21177633Sdfr * OR ANY PART THEREOF.
22177633Sdfr *
23177633Sdfr * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24177633Sdfr * or profits or other special, indirect and consequential damages, even if
25177633Sdfr * Sun has been advised of the possibility of such damages.
26177633Sdfr *
27177633Sdfr * Sun Microsystems, Inc.
28177633Sdfr * 2550 Garcia Avenue
29177633Sdfr * Mountain View, California  94043
30177633Sdfr */
31177633Sdfr
32177633Sdfr#if defined(LIBC_SCCS) && !defined(lint)
33177633Sdfrstatic char *sccsid2 = "@(#)auth_unix.c 1.19 87/08/11 Copyr 1984 Sun Micro";
34177633Sdfrstatic char *sccsid = "@(#)auth_unix.c	2.2 88/08/01 4.0 RPCSRC";
35177633Sdfr#endif
36177633Sdfr#include <sys/cdefs.h>
37177633Sdfr__FBSDID("$FreeBSD: head/sys/rpc/auth_unix.c 180064 2008-06-27 14:35:05Z dfr $");
38177633Sdfr
39177633Sdfr/*
40177633Sdfr * auth_unix.c, Implements UNIX style authentication parameters.
41177633Sdfr *
42177633Sdfr * Copyright (C) 1984, Sun Microsystems, Inc.
43177633Sdfr *
44177633Sdfr * The system is very weak.  The client uses no encryption for it's
45177633Sdfr * credentials and only sends null verifiers.  The server sends backs
46177633Sdfr * null verifiers or optionally a verifier that suggests a new short hand
47177633Sdfr * for the credentials.
48177633Sdfr *
49177633Sdfr */
50177633Sdfr
51177633Sdfr#include <sys/param.h>
52177633Sdfr#include <sys/systm.h>
53180025Sdfr#include <sys/hash.h>
54180025Sdfr#include <sys/kernel.h>
55177633Sdfr#include <sys/lock.h>
56177633Sdfr#include <sys/malloc.h>
57180064Sdfr#include <sys/pcpu.h>
58180025Sdfr#include <sys/sx.h>
59177633Sdfr#include <sys/ucred.h>
60177633Sdfr
61177633Sdfr#include <rpc/types.h>
62177633Sdfr#include <rpc/xdr.h>
63177633Sdfr#include <rpc/auth.h>
64177633Sdfr
65177685Sdfr#include <rpc/rpc_com.h>
66177633Sdfr
67177633Sdfr/* auth_unix.c */
68177633Sdfrstatic void authunix_nextverf (AUTH *);
69177633Sdfrstatic bool_t authunix_marshal (AUTH *, XDR *);
70177633Sdfrstatic bool_t authunix_validate (AUTH *, struct opaque_auth *);
71177633Sdfrstatic bool_t authunix_refresh (AUTH *, void *);
72177633Sdfrstatic void authunix_destroy (AUTH *);
73177633Sdfrstatic void marshal_new_auth (AUTH *);
74177633Sdfr
75177633Sdfrstatic struct auth_ops authunix_ops = {
76177633Sdfr	.ah_nextverf =		authunix_nextverf,
77177633Sdfr	.ah_marshal =		authunix_marshal,
78177633Sdfr	.ah_validate =		authunix_validate,
79177633Sdfr	.ah_refresh =		authunix_refresh,
80177633Sdfr	.ah_destroy =		authunix_destroy
81177633Sdfr};
82177633Sdfr
83177633Sdfr/*
84177633Sdfr * This struct is pointed to by the ah_private field of an auth_handle.
85177633Sdfr */
86177633Sdfrstruct audata {
87180025Sdfr	TAILQ_ENTRY(audata)	au_link;
88180025Sdfr	TAILQ_ENTRY(audata)	au_alllink;
89180025Sdfr	int			au_refs;
90180025Sdfr	struct xucred		au_xcred;
91177633Sdfr	struct opaque_auth	au_origcred;	/* original credentials */
92177633Sdfr	struct opaque_auth	au_shcred;	/* short hand cred */
93177633Sdfr	u_long			au_shfaults;	/* short hand cache faults */
94177633Sdfr	char			au_marshed[MAX_AUTH_BYTES];
95177633Sdfr	u_int			au_mpos;	/* xdr pos at end of marshed */
96180025Sdfr	AUTH			*au_auth;	/* link back to AUTH */
97177633Sdfr};
98180025SdfrTAILQ_HEAD(audata_list, audata);
99177633Sdfr#define	AUTH_PRIVATE(auth)	((struct audata *)auth->ah_private)
100177633Sdfr
101180025Sdfr#define AUTH_UNIX_HASH_SIZE	16
102180025Sdfr#define AUTH_UNIX_MAX		256
103180025Sdfrstatic struct audata_list auth_unix_cache[AUTH_UNIX_HASH_SIZE];
104180025Sdfrstatic struct audata_list auth_unix_all;
105180025Sdfrstatic struct sx auth_unix_lock;
106180025Sdfrstatic int auth_unix_count;
107180025Sdfr
108180025Sdfrstatic void
109180025Sdfrauthunix_init(void *dummy)
110180025Sdfr{
111180025Sdfr	int i;
112180025Sdfr
113180025Sdfr	for (i = 0; i < AUTH_UNIX_HASH_SIZE; i++)
114180025Sdfr		TAILQ_INIT(&auth_unix_cache[i]);
115180025Sdfr	TAILQ_INIT(&auth_unix_all);
116180025Sdfr	sx_init(&auth_unix_lock, "auth_unix_lock");
117180025Sdfr}
118180025SdfrSYSINIT(authunix_init, SI_SUB_KMEM, SI_ORDER_ANY, authunix_init, NULL);
119180025Sdfr
120177633Sdfr/*
121177633Sdfr * Create a unix style authenticator.
122177633Sdfr * Returns an auth handle with the given stuff in it.
123177633Sdfr */
124177633SdfrAUTH *
125177633Sdfrauthunix_create(struct ucred *cred)
126177633Sdfr{
127180025Sdfr	uint32_t h, th;
128177633Sdfr	struct xucred xcr;
129177633Sdfr	char mymem[MAX_AUTH_BYTES];
130177633Sdfr	XDR xdrs;
131177633Sdfr	AUTH *auth;
132180025Sdfr	struct audata *au, *tau;
133177633Sdfr	struct timeval now;
134177633Sdfr	uint32_t time;
135177633Sdfr	int len;
136177633Sdfr
137180025Sdfr	if (auth_unix_count > AUTH_UNIX_MAX) {
138180025Sdfr		while (auth_unix_count > AUTH_UNIX_MAX) {
139180025Sdfr			sx_xlock(&auth_unix_lock);
140180025Sdfr			tau = TAILQ_FIRST(&auth_unix_all);
141180025Sdfr			th = HASHSTEP(HASHINIT, tau->au_xcred.cr_uid)
142180025Sdfr				% AUTH_UNIX_HASH_SIZE;
143180025Sdfr			TAILQ_REMOVE(&auth_unix_cache[th], tau, au_link);
144180025Sdfr			TAILQ_REMOVE(&auth_unix_all, tau, au_alllink);
145180025Sdfr			auth_unix_count--;
146180025Sdfr			sx_xunlock(&auth_unix_lock);
147180025Sdfr			AUTH_DESTROY(tau->au_auth);
148180025Sdfr		}
149180025Sdfr	}
150180025Sdfr
151177633Sdfr	/*
152180025Sdfr	 * Hash the uid to see if we already have an AUTH with this cred.
153180025Sdfr	 */
154180025Sdfr	h = HASHSTEP(HASHINIT, cred->cr_uid) % AUTH_UNIX_HASH_SIZE;
155180025Sdfr	cru2x(cred, &xcr);
156180025Sdfragain:
157180025Sdfr	sx_slock(&auth_unix_lock);
158180025Sdfr	TAILQ_FOREACH(au, &auth_unix_cache[h], au_link) {
159180025Sdfr		if (!memcmp(&xcr, &au->au_xcred, sizeof(xcr))) {
160180025Sdfr			if (sx_try_upgrade(&auth_unix_lock)) {
161180025Sdfr				/*
162180025Sdfr				 * Keep auth_unix_all LRU sorted.
163180025Sdfr				 */
164180025Sdfr				TAILQ_REMOVE(&auth_unix_all, au, au_alllink);
165180025Sdfr				TAILQ_INSERT_TAIL(&auth_unix_all, au,
166180025Sdfr				    au_alllink);
167180025Sdfr				au->au_refs++;
168180025Sdfr				sx_xunlock(&auth_unix_lock);
169180025Sdfr				return (au->au_auth);
170180025Sdfr			} else {
171180025Sdfr				sx_sunlock(&auth_unix_lock);
172180025Sdfr				goto again;
173180025Sdfr			}
174180025Sdfr		}
175180025Sdfr	}
176180025Sdfr
177180025Sdfr	/*
178177633Sdfr	 * Allocate and set up auth handle
179177633Sdfr	 */
180177633Sdfr	au = NULL;
181177633Sdfr	auth = mem_alloc(sizeof(*auth));
182177633Sdfr	au = mem_alloc(sizeof(*au));
183177633Sdfr	auth->ah_ops = &authunix_ops;
184177633Sdfr	auth->ah_private = (caddr_t)au;
185177633Sdfr	auth->ah_verf = au->au_shcred = _null_auth;
186180025Sdfr	au->au_refs = 1;
187180025Sdfr	au->au_xcred = xcr;
188177633Sdfr	au->au_shfaults = 0;
189177633Sdfr	au->au_origcred.oa_base = NULL;
190180025Sdfr	au->au_auth = auth;
191177633Sdfr
192177633Sdfr	getmicrotime(&now);
193177633Sdfr	time = now.tv_sec;
194177633Sdfr
195177633Sdfr	/*
196177633Sdfr	 * Serialize the parameters into origcred
197177633Sdfr	 */
198177633Sdfr	xdrmem_create(&xdrs, mymem, MAX_AUTH_BYTES, XDR_ENCODE);
199177633Sdfr	cru2x(cred, &xcr);
200177633Sdfr	if (! xdr_authunix_parms(&xdrs, &time, &xcr))
201177633Sdfr		panic("authunix_create: failed to encode creds");
202177633Sdfr	au->au_origcred.oa_length = len = XDR_GETPOS(&xdrs);
203177633Sdfr	au->au_origcred.oa_flavor = AUTH_UNIX;
204177633Sdfr	au->au_origcred.oa_base = mem_alloc((u_int) len);
205177633Sdfr	memcpy(au->au_origcred.oa_base, mymem, (size_t)len);
206177633Sdfr
207177633Sdfr	/*
208177633Sdfr	 * set auth handle to reflect new cred.
209177633Sdfr	 */
210177633Sdfr	auth->ah_cred = au->au_origcred;
211177633Sdfr	marshal_new_auth(auth);
212180025Sdfr
213180025Sdfr	if (sx_try_upgrade(&auth_unix_lock)) {
214180025Sdfr		auth_unix_count++;
215180025Sdfr		TAILQ_INSERT_TAIL(&auth_unix_cache[h], au, au_link);
216180025Sdfr		TAILQ_INSERT_TAIL(&auth_unix_all, au, au_alllink);
217180025Sdfr		au->au_refs++;	/* one for the cache, one for user */
218180025Sdfr		sx_xunlock(&auth_unix_lock);
219180025Sdfr		return (auth);
220180025Sdfr	} else {
221180025Sdfr		sx_sunlock(&auth_unix_lock);
222180025Sdfr		AUTH_DESTROY(auth);
223180025Sdfr		goto again;
224177633Sdfr	}
225177633Sdfr}
226177633Sdfr
227177633Sdfr/*
228177633Sdfr * authunix operations
229177633Sdfr */
230177633Sdfr
231177633Sdfr/* ARGSUSED */
232177633Sdfrstatic void
233177633Sdfrauthunix_nextverf(AUTH *auth)
234177633Sdfr{
235177633Sdfr	/* no action necessary */
236177633Sdfr}
237177633Sdfr
238177633Sdfrstatic bool_t
239177633Sdfrauthunix_marshal(AUTH *auth, XDR *xdrs)
240177633Sdfr{
241177633Sdfr	struct audata *au;
242177633Sdfr
243177633Sdfr	au = AUTH_PRIVATE(auth);
244177633Sdfr	return (XDR_PUTBYTES(xdrs, au->au_marshed, au->au_mpos));
245177633Sdfr}
246177633Sdfr
247177633Sdfrstatic bool_t
248177633Sdfrauthunix_validate(AUTH *auth, struct opaque_auth *verf)
249177633Sdfr{
250177633Sdfr	struct audata *au;
251177633Sdfr	XDR xdrs;
252177633Sdfr
253177633Sdfr	if (verf->oa_flavor == AUTH_SHORT) {
254177633Sdfr		au = AUTH_PRIVATE(auth);
255177633Sdfr		xdrmem_create(&xdrs, verf->oa_base, verf->oa_length,
256177633Sdfr		    XDR_DECODE);
257177633Sdfr
258177633Sdfr		if (au->au_shcred.oa_base != NULL) {
259177633Sdfr			mem_free(au->au_shcred.oa_base,
260177633Sdfr			    au->au_shcred.oa_length);
261177633Sdfr			au->au_shcred.oa_base = NULL;
262177633Sdfr		}
263177633Sdfr		if (xdr_opaque_auth(&xdrs, &au->au_shcred)) {
264177633Sdfr			auth->ah_cred = au->au_shcred;
265177633Sdfr		} else {
266177633Sdfr			xdrs.x_op = XDR_FREE;
267177633Sdfr			(void)xdr_opaque_auth(&xdrs, &au->au_shcred);
268177633Sdfr			au->au_shcred.oa_base = NULL;
269177633Sdfr			auth->ah_cred = au->au_origcred;
270177633Sdfr		}
271177633Sdfr		marshal_new_auth(auth);
272177633Sdfr	}
273177633Sdfr	return (TRUE);
274177633Sdfr}
275177633Sdfr
276177633Sdfrstatic bool_t
277177633Sdfrauthunix_refresh(AUTH *auth, void *dummy)
278177633Sdfr{
279177633Sdfr	struct audata *au = AUTH_PRIVATE(auth);
280177633Sdfr	struct xucred xcr;
281177633Sdfr	uint32_t time;
282177633Sdfr	struct timeval now;
283177633Sdfr	XDR xdrs;
284177633Sdfr	int stat;
285177633Sdfr
286177633Sdfr	if (auth->ah_cred.oa_base == au->au_origcred.oa_base) {
287177633Sdfr		/* there is no hope.  Punt */
288177633Sdfr		return (FALSE);
289177633Sdfr	}
290177633Sdfr	au->au_shfaults ++;
291177633Sdfr
292177633Sdfr	/* first deserialize the creds back into a struct ucred */
293177633Sdfr	xdrmem_create(&xdrs, au->au_origcred.oa_base,
294177633Sdfr	    au->au_origcred.oa_length, XDR_DECODE);
295177633Sdfr	stat = xdr_authunix_parms(&xdrs, &time, &xcr);
296177633Sdfr	if (! stat)
297177633Sdfr		goto done;
298177633Sdfr
299177633Sdfr	/* update the time and serialize in place */
300177633Sdfr	getmicrotime(&now);
301177633Sdfr	time = now.tv_sec;
302177633Sdfr	xdrs.x_op = XDR_ENCODE;
303177633Sdfr	XDR_SETPOS(&xdrs, 0);
304177633Sdfr
305177633Sdfr	stat = xdr_authunix_parms(&xdrs, &time, &xcr);
306177633Sdfr	if (! stat)
307177633Sdfr		goto done;
308177633Sdfr	auth->ah_cred = au->au_origcred;
309177633Sdfr	marshal_new_auth(auth);
310177633Sdfrdone:
311177633Sdfr	XDR_DESTROY(&xdrs);
312177633Sdfr	return (stat);
313177633Sdfr}
314177633Sdfr
315177633Sdfrstatic void
316177633Sdfrauthunix_destroy(AUTH *auth)
317177633Sdfr{
318177633Sdfr	struct audata *au;
319180025Sdfr	int refs;
320177633Sdfr
321177633Sdfr	au = AUTH_PRIVATE(auth);
322180025Sdfr
323180025Sdfr	sx_xlock(&auth_unix_lock);
324180025Sdfr	au->au_refs--;
325180025Sdfr	refs = au->au_refs;
326180025Sdfr	sx_xunlock(&auth_unix_lock);
327180025Sdfr
328180025Sdfr	if (refs > 0)
329180025Sdfr		return;
330180025Sdfr
331177633Sdfr	mem_free(au->au_origcred.oa_base, au->au_origcred.oa_length);
332177633Sdfr
333177633Sdfr	if (au->au_shcred.oa_base != NULL)
334177633Sdfr		mem_free(au->au_shcred.oa_base, au->au_shcred.oa_length);
335177633Sdfr
336177633Sdfr	mem_free(auth->ah_private, sizeof(struct audata));
337177633Sdfr
338177633Sdfr	if (auth->ah_verf.oa_base != NULL)
339177633Sdfr		mem_free(auth->ah_verf.oa_base, auth->ah_verf.oa_length);
340177633Sdfr
341177633Sdfr	mem_free(auth, sizeof(*auth));
342177633Sdfr}
343177633Sdfr
344177633Sdfr/*
345177633Sdfr * Marshals (pre-serializes) an auth struct.
346177633Sdfr * sets private data, au_marshed and au_mpos
347177633Sdfr */
348177633Sdfrstatic void
349177633Sdfrmarshal_new_auth(AUTH *auth)
350177633Sdfr{
351177633Sdfr	XDR	xdr_stream;
352177633Sdfr	XDR	*xdrs = &xdr_stream;
353177633Sdfr	struct audata *au;
354177633Sdfr
355177633Sdfr	au = AUTH_PRIVATE(auth);
356177633Sdfr	xdrmem_create(xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE);
357177633Sdfr	if ((! xdr_opaque_auth(xdrs, &(auth->ah_cred))) ||
358177633Sdfr	    (! xdr_opaque_auth(xdrs, &(auth->ah_verf))))
359177633Sdfr		printf("auth_none.c - Fatal marshalling problem");
360177633Sdfr	else
361177633Sdfr		au->au_mpos = XDR_GETPOS(xdrs);
362177633Sdfr	XDR_DESTROY(xdrs);
363177633Sdfr}
364