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