1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28/*	  All Rights Reserved  	*/
29
30/*
31 * Portions of this source code were derived from Berkeley 4.3 BSD
32 * under license from the Regents of the University of California.
33 */
34
35/*
36 * auth_loopb.c, implements UNIX style authentication parameters in the
37 * kernel.  Interfaces with svc_auth_loopback on the server.  See
38 * auth_loopb.c for the user level implementation of the loopback auth.
39 *
40 */
41
42#include <sys/param.h>
43#include <sys/time.h>
44#include <sys/types.h>
45#include <sys/systm.h>
46#include <sys/user.h>
47#include <sys/proc.h>
48#include <sys/utsname.h>
49#include <sys/cred.h>
50#include <sys/kmem.h>
51#include <sys/sysmacros.h>
52#include <sys/cmn_err.h>
53
54#include <rpc/types.h>
55#include <rpc/xdr.h>
56#include <rpc/auth.h>
57#include <rpc/auth_unix.h>
58#include <rpc/clnt.h>
59#include <rpc/rpc_msg.h>
60
61/*
62 * Unix authenticator operations vector
63 */
64static void	authloopback_nextverf(AUTH *);
65static bool_t	authloopback_marshal(AUTH *, XDR *, struct cred *);
66static bool_t	authloopback_validate(AUTH *, struct opaque_auth *);
67static bool_t	authloopback_refresh(AUTH *, struct rpc_msg *, cred_t *);
68static void	authloopback_destroy(AUTH *);
69
70static struct auth_ops authloopback_ops = {
71	authloopback_nextverf,
72	authloopback_marshal,
73	authloopback_validate,
74	authloopback_refresh,
75	authloopback_destroy,
76	authany_wrap,
77	authany_unwrap
78};
79
80/*
81 * Create a kernel unix style authenticator.
82 * Returns an auth handle.
83 */
84AUTH *
85authloopback_create(void)
86{
87	/*
88	 * Allocate and set up auth handle
89	 */
90	return (kmem_cache_alloc(authloopback_cache, KM_SLEEP));
91}
92
93/*
94 *  The constructor of the authloopback_cache.
95 */
96/* ARGSUSED */
97int
98authloopback_init(void *buf, void *cdrarg, int kmflags)
99{
100	AUTH *auth = (AUTH *)buf;
101
102	auth->ah_ops = &authloopback_ops;
103	auth->ah_cred.oa_flavor = AUTH_LOOPBACK;
104	auth->ah_verf = _null_auth;
105
106	return (0);
107}
108
109/*
110 * authloopback operations
111 */
112/* ARGSUSED */
113static void
114authloopback_nextverf(AUTH *auth)
115{
116
117	/* no action necessary */
118}
119
120static bool_t
121authloopback_marshal(AUTH *auth, XDR *xdrs, struct cred *cr)
122{
123	char *sercred;
124	XDR xdrm;
125	bool_t ret;
126	uint32_t gidlen, credsize, namelen, rounded_namelen;
127	int32_t *ptr;
128	char *nodename = uts_nodename();
129	uint32_t maxgidlen;
130	uint_t startpos;
131
132	ASSERT(xdrs->x_op == XDR_ENCODE);
133	ASSERT(auth->ah_cred.oa_flavor == AUTH_LOOPBACK);
134	ASSERT(auth->ah_verf.oa_flavor == AUTH_NONE);
135	ASSERT(auth->ah_verf.oa_length == 0);
136
137	/*
138	 * First we try a fast path to get through
139	 * this very common operation.
140	 */
141	namelen = (uint32_t)strlen(nodename);
142	if (namelen > MAX_MACHINE_NAME)
143		return (FALSE);
144	rounded_namelen = RNDUP(namelen);
145
146	/*
147	 * NFIELDS is a number of the following fields we are going to encode:
148	 *   - stamp
149	 *   - strlen(machinename)
150	 *   - uid
151	 *   - gid
152	 *   - the number of gids
153	 */
154#define	NFIELDS	5
155	CTASSERT(NFIELDS * BYTES_PER_XDR_UNIT + RNDUP(MAX_MACHINE_NAME) <=
156	    MAX_AUTH_BYTES);
157	maxgidlen = (MAX_AUTH_BYTES - NFIELDS * BYTES_PER_XDR_UNIT -
158	    rounded_namelen) / BYTES_PER_XDR_UNIT;
159
160	gidlen = crgetngroups(cr);
161	if (gidlen > maxgidlen)
162		return (FALSE);
163
164	credsize = NFIELDS * BYTES_PER_XDR_UNIT + rounded_namelen +
165	    gidlen * BYTES_PER_XDR_UNIT;
166	ASSERT(credsize <= MAX_AUTH_BYTES);
167#undef	NFIELDS
168
169	/*
170	 * We need to marshal both cred and verf parts of the rpc_msg body
171	 * (call_body).  For the cred part we need to inline the auth_flavor
172	 * and the opaque auth body size.  Then we inline the credsize bytes of
173	 * the opaque auth body for the cred part.  Finally we add the
174	 * AUTH_NONE verifier (its auth_flavor and the opaque auth body size).
175	 */
176	ptr = XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT + credsize +
177	    2 * BYTES_PER_XDR_UNIT);
178	if (ptr != NULL) {
179		/*
180		 * We can do the fast path.
181		 */
182		const gid_t *gp = crgetgroups(cr);
183
184		IXDR_PUT_U_INT32(ptr, AUTH_LOOPBACK);	/* cred flavor */
185		IXDR_PUT_U_INT32(ptr, credsize);	/* cred len */
186
187		IXDR_PUT_INT32(ptr, gethrestime_sec());
188		IXDR_PUT_U_INT32(ptr, namelen);
189		bcopy(nodename, ptr, namelen);
190		if ((rounded_namelen - namelen) > 0)
191			bzero((char *)ptr + namelen, rounded_namelen - namelen);
192		ptr += rounded_namelen / BYTES_PER_XDR_UNIT;
193		IXDR_PUT_U_INT32(ptr, crgetuid(cr));
194		IXDR_PUT_U_INT32(ptr, crgetgid(cr));
195		IXDR_PUT_U_INT32(ptr, gidlen);
196		while (gidlen-- > 0)
197			IXDR_PUT_U_INT32(ptr, *gp++);
198
199		IXDR_PUT_U_INT32(ptr, AUTH_NONE);	/* verf flavor */
200		IXDR_PUT_U_INT32(ptr, 0);		/* verf len */
201
202		return (TRUE);
203	}
204
205	sercred = kmem_alloc(MAX_AUTH_BYTES, KM_SLEEP);
206
207	/*
208	 * Serialize the auth body data into sercred.
209	 */
210	xdrmem_create(&xdrm, sercred, MAX_AUTH_BYTES, XDR_ENCODE);
211	startpos = XDR_GETPOS(&xdrm);
212	if (!xdr_authloopback(&xdrm, cr)) {
213		printf("authloopback_marshal: xdr_authloopback failed\n");
214		ret = FALSE;
215		goto done;
216	}
217
218	/*
219	 * Make opaque auth credentials to point at the serialized auth body
220	 * data.
221	 */
222	auth->ah_cred.oa_base = sercred;
223	auth->ah_cred.oa_length = XDR_GETPOS(&xdrm) - startpos;
224	ASSERT(auth->ah_cred.oa_length <= MAX_AUTH_BYTES);
225
226	/*
227	 * serialize credentials and verifier (null)
228	 */
229	if ((xdr_opaque_auth(xdrs, &(auth->ah_cred))) &&
230	    (xdr_opaque_auth(xdrs, &(auth->ah_verf))))
231		ret = TRUE;
232	else
233		ret = FALSE;
234
235done:
236	XDR_DESTROY(&xdrm);
237	kmem_free(sercred, MAX_AUTH_BYTES);
238
239	return (ret);
240}
241
242/* ARGSUSED */
243static bool_t
244authloopback_validate(AUTH *auth, struct opaque_auth *verf)
245{
246	return (TRUE);
247}
248
249/* ARGSUSED */
250static bool_t
251authloopback_refresh(AUTH *auth, struct rpc_msg *msg, cred_t *cr)
252{
253	return (FALSE);
254}
255
256static void
257authloopback_destroy(register AUTH *auth)
258{
259	kmem_cache_free(authloopback_cache, auth);
260}
261