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 *
authloopback_create(void)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
authloopback_init(void * buf,void * cdrarg,int kmflags)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
authloopback_nextverf(AUTH * auth)114 authloopback_nextverf(AUTH *auth)
115 {
116
117 /* no action necessary */
118 }
119
120 static bool_t
authloopback_marshal(AUTH * auth,XDR * xdrs,struct cred * cr)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
authloopback_validate(AUTH * auth,struct opaque_auth * verf)244 authloopback_validate(AUTH *auth, struct opaque_auth *verf)
245 {
246 return (TRUE);
247 }
248
249 /* ARGSUSED */
250 static bool_t
authloopback_refresh(AUTH * auth,struct rpc_msg * msg,cred_t * cr)251 authloopback_refresh(AUTH *auth, struct rpc_msg *msg, cred_t *cr)
252 {
253 return (FALSE);
254 }
255
256 static void
authloopback_destroy(register AUTH * auth)257 authloopback_destroy(register AUTH *auth)
258 {
259 kmem_cache_free(authloopback_cache, auth);
260 }
261