xref: /illumos-gate/usr/src/uts/common/rpc/sec/auth_loopb.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
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  */
64 static void	authloopback_nextverf(AUTH *);
65 static bool_t	authloopback_marshal(AUTH *, XDR *, struct cred *);
66 static bool_t	authloopback_validate(AUTH *, struct opaque_auth *);
67 static bool_t	authloopback_refresh(AUTH *, struct rpc_msg *, cred_t *);
68 static void	authloopback_destroy(AUTH *);
69 
70 static 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  */
84 AUTH *
85 authloopback_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 */
97 int
98 authloopback_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 */
113 static void
114 authloopback_nextverf(AUTH *auth)
115 {
116 
117 	/* no action necessary */
118 }
119 
120 static bool_t
121 authloopback_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 
235 done:
236 	XDR_DESTROY(&xdrm);
237 	kmem_free(sercred, MAX_AUTH_BYTES);
238 
239 	return (ret);
240 }
241 
242 /* ARGSUSED */
243 static bool_t
244 authloopback_validate(AUTH *auth, struct opaque_auth *verf)
245 {
246 	return (TRUE);
247 }
248 
249 /* ARGSUSED */
250 static bool_t
251 authloopback_refresh(AUTH *auth, struct rpc_msg *msg, cred_t *cr)
252 {
253 	return (FALSE);
254 }
255 
256 static void
257 authloopback_destroy(register AUTH *auth)
258 {
259 	kmem_cache_free(authloopback_cache, auth);
260 }
261