xref: /illumos-gate/usr/src/uts/common/rpc/sec/sec_svc.c (revision 4703203d)
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 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  *  sec_svc.c, Server-side rpc security interface.
31  */
32 #ifdef _KERNEL
33 #include <sys/param.h>
34 #include <sys/types.h>
35 #include <sys/debug.h>
36 #include <sys/systm.h>
37 #include <rpc/types.h>
38 #include <netinet/in.h>
39 #include <rpc/xdr.h>
40 #include <rpc/auth.h>
41 #include <rpc/clnt.h>
42 #include <rpc/rpc_msg.h>
43 #include <sys/tiuser.h>
44 #include <sys/tihdr.h>
45 #include <sys/t_kuser.h>
46 #include <sys/cmn_err.h>
47 #include <rpc/auth_des.h>
48 #include <rpc/auth_sys.h>
49 #include <rpc/rpcsec_gss.h>
50 #include <rpc/svc_auth.h>
51 #include <rpc/svc.h>
52 #else
53 #include <rpc/rpc.h>
54 #endif
55 
56 
57 enum auth_stat _svcauth_null(struct svc_req *, struct rpc_msg *);
58 
59 /*
60  *  NO-OP server wrap/unwrap svc_authany_ops using no-op svc_authany_wrap().
61  */
62 /* ARGSUSED */
63 static int
64 svc_authany_wrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xfunc, caddr_t xwhere)
65 {
66 	return (*xfunc)(xdrs, xwhere);
67 }
68 
69 struct svc_auth_ops svc_authany_ops = {
70 	svc_authany_wrap,
71 	svc_authany_wrap
72 };
73 
74 
75 /*
76  * The call rpc message, msg has been obtained from the wire.  The msg contains
77  * the raw form of credentials and verifiers.  authenticate returns AUTH_OK
78  * if the msg is successfully authenticated.  If AUTH_OK then the routine also
79  * does the following things:
80  * set rqst->rq_xprt->verf to the appropriate response verifier;
81  * sets rqst->rq_client_cred to the "cooked" form of the credentials.
82  *
83  * NB: rqst->rq_cxprt->verf must be pre-alloctaed;
84  * its length is set appropriately.
85  *
86  * The caller still owns and is responsible for msg->u.cmb.cred and
87  * msg->u.cmb.verf.  The authentication system retains ownership of
88  * rqst->rq_client_cred, the cooked credentials.
89  *
90  * There is an assumption that any flavor less than AUTH_NULL is
91  * invalid.
92  */
93 enum auth_stat
94 sec_svc_msg(struct svc_req *rqst, struct rpc_msg *msg, bool_t *no_dispatch)
95 {
96 	int cred_flavor;
97 
98 	rqst->rq_cred = msg->rm_call.cb_cred;
99 	rqst->rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor;
100 	rqst->rq_xprt->xp_verf.oa_length = 0;
101 	/*
102 	 * Init the xp_auth to be no-op for all the flavors.
103 	 * Flavor specific routines will revise this when appropriate.
104 	 */
105 	rqst->rq_xprt->xp_auth.svc_ah_ops = svc_authany_ops;
106 	rqst->rq_xprt->xp_auth.svc_ah_private = NULL;
107 	*no_dispatch = FALSE;
108 
109 	cred_flavor = rqst->rq_cred.oa_flavor;
110 
111 	switch (cred_flavor) {
112 	case AUTH_NULL:
113 		rqst->rq_xprt->xp_cookie = (void *) AUTH_NULL;
114 		return (_svcauth_null(rqst, msg));
115 
116 	case AUTH_UNIX:
117 		rqst->rq_xprt->xp_cookie = (void *) AUTH_UNIX;
118 		return (_svcauth_unix(rqst, msg));
119 
120 	case AUTH_SHORT:
121 		rqst->rq_xprt->xp_cookie = (void *) AUTH_SHORT;
122 		return (_svcauth_short(rqst, msg));
123 
124 	case AUTH_DES:
125 		rqst->rq_xprt->xp_cookie = (void *) AUTH_DES;
126 		return (_svcauth_des(rqst, msg));
127 
128 	case RPCSEC_GSS:
129 		/*
130 		 * RPCSEC_GSS flavor routine takes an additional
131 		 * boolean parameter that gets set to TRUE when
132 		 * the call is not to be dispatched to the server.
133 		 */
134 		return (__svcrpcsec_gss(rqst, msg, no_dispatch));
135 	}
136 	return (AUTH_REJECTEDCRED);
137 }
138 
139 /*
140  *  sec_svc_getcred() gets unix cred of incoming security rpc requests.
141  *  It also returns the prinicipal name and a cookie which is application
142  *  dependent e.g. for nfs, it is the pseudo flavor.
143  *
144  *  return 0 on failure
145  */
146 int
147 sec_svc_getcred(struct svc_req *req, cred_t *cr, caddr_t *principal,
148 	int *secmod)
149 {
150 	struct authunix_parms *aup;
151 	struct authdes_cred *adc;
152 	int flavor, stat;
153 	rpc_gss_rawcred_t *rcred;
154 	rpc_gss_ucred_t	*ucred;
155 	void *cookie;
156 
157 	stat = 1;
158 	flavor = req->rq_cred.oa_flavor;
159 
160 	*principal = NULL;
161 	switch (flavor) {
162 	case AUTH_UNIX:
163 		*secmod = AUTH_UNIX;
164 		aup = (struct authunix_parms *)req->rq_clntcred;
165 		if (crsetugid(cr, aup->aup_uid, aup->aup_gid) != 0 ||
166 		    crsetgroups(cr, aup->aup_len, aup->aup_gids) != 0)
167 			stat = 0;
168 		break;
169 
170 	case AUTH_NONE:
171 		*secmod = AUTH_NONE;
172 		break;
173 
174 	case AUTH_DES:
175 		*secmod = AUTH_DES;
176 		adc = (struct authdes_cred *)req->rq_clntcred;
177 		stat = kauthdes_getucred(adc, cr);
178 		*principal = adc->adc_fullname.name;
179 		break;
180 
181 	case RPCSEC_GSS:
182 		stat = rpc_gss_getcred(req, &rcred, &ucred, &cookie);
183 		*secmod = (int)(uintptr_t)cookie;	/* XX64 */
184 		if (ucred != NULL) {
185 			if (crsetugid(cr, ucred->uid, ucred->gid) != 0 ||
186 			    crsetgroups(cr, ucred->gidlen, ucred->gidlist) != 0)
187 				stat = 0;
188 		} else {
189 			(void) crsetugid(cr, UID_NOBODY, GID_NOBODY);
190 			(void) crsetgroups(cr, 0, NULL);
191 		}
192 		*principal = (caddr_t)rcred->client_principal;
193 		break;
194 
195 	default:
196 		stat = 0;
197 		break;
198 	}
199 
200 	return (stat);
201 }
202 
203 
204 /* ARGSUSED */
205 enum auth_stat
206 _svcauth_null(struct svc_req *rqst, struct rpc_msg *msg)
207 {
208 	return (AUTH_OK);
209 }
210 
211 
212 /*
213  *  Load root principal names from user space to kernel space.
214  *
215  *  flavor - security flavor
216  *  count - number of principal names to be loaded
217  *  proots - address of the array of root names.
218  *		input is the array address in the user space,
219  *		output is the kernel address.
220  *
221  *  return 0 on failure.
222  */
223 int
224 sec_svc_loadrootnames(int flavor, int count, caddr_t **proots, model_t model)
225 {
226 	caddr_t *roots, *oroots, root;
227 	char netname[MAXNETNAMELEN+1];
228 	struct rpc_gss_principal gsstmp, *gssname;
229 	uint_t i, j;
230 	size_t len, allocsz, oallocsz;
231 
232 #ifdef lint
233 	model = model;
234 #endif
235 
236 	/*
237 	 * Get list of names from user space
238 	 */
239 	allocsz = count * sizeof (caddr_t);
240 	oallocsz = count * SIZEOF_PTR(model);
241 
242 	/*
243 	 * And now copy each individual principal name
244 	 */
245 	switch (flavor) {
246 	case AUTH_DES:
247 		roots = kmem_zalloc(allocsz, KM_SLEEP);
248 		oroots = kmem_alloc(oallocsz, KM_SLEEP);
249 
250 		if (copyin(*proots, oroots, oallocsz))
251 			goto done;
252 
253 		for (i = 0; i < count; i++) {
254 			/*
255 			 * copyinstr copies the complete string (including the
256 			 * NULL) and returns the len with the NULL byte
257 			 * included in the calculation as long as the max
258 			 * length is not exceeded.
259 			 */
260 #ifdef _SYSCALL32_IMPL
261 			if (model != DATAMODEL_NATIVE) {
262 				caddr32_t *tmp;
263 
264 				tmp = (caddr32_t *)oroots;
265 				root = (caddr_t)(uintptr_t)tmp[i];
266 			} else
267 #endif
268 				root = oroots[i];
269 			if (copyinstr(root, netname, sizeof (netname), &len)) {
270 				for (j = 0; j < i; j++) {
271 					if (roots[j] != NULL)
272 						kmem_free(roots[j],
273 						    strlen(roots[j]) + 1);
274 				}
275 				goto done;
276 			}
277 			roots[i] = kmem_alloc(len, KM_SLEEP);
278 			bcopy(netname, roots[i], len);
279 		}
280 		kmem_free(oroots, oallocsz);
281 		*proots = roots;
282 		return (1);
283 
284 	case RPCSEC_GSS:
285 		roots = kmem_alloc(allocsz, KM_SLEEP);
286 		oroots = kmem_alloc(oallocsz, KM_SLEEP);
287 
288 		if (copyin(*proots, oroots, oallocsz))
289 			goto done;
290 
291 		for (i = 0; i < count; i++) {
292 #ifdef _SYSCALL32_IMPL
293 			if (model != DATAMODEL_NATIVE) {
294 				caddr32_t *tmp;
295 
296 				tmp = (caddr32_t *)oroots;
297 				root = (caddr_t)(uintptr_t)tmp[i];
298 			} else
299 #endif
300 				root = oroots[i];
301 
302 			if (copyin(root, &gsstmp, sizeof (gsstmp))) {
303 				kmem_free(oroots, oallocsz);
304 				goto gssfreeup;
305 			}
306 			len = sizeof (gsstmp.len) + gsstmp.len;
307 			gssname = kmem_alloc(len, KM_SLEEP);
308 			if (copyin(root, gssname, len)) {
309 				kmem_free(gssname, len);
310 				kmem_free(oroots, oallocsz);
311 				goto gssfreeup;
312 			}
313 			roots[i] = (caddr_t)gssname;
314 		}
315 		kmem_free(oroots, oallocsz);
316 		*proots = roots;
317 		return (1);
318 
319 	default:
320 		return (0);
321 	}
322 
323 gssfreeup:
324 	for (j = 0; j < i; j++) {
325 		if (roots[j] != NULL) {
326 			gssname = (rpc_gss_principal_t)roots[j];
327 			kmem_free(roots[j], gssname->len +
328 			    sizeof (gssname->len));
329 		}
330 	}
331 done:
332 	kmem_free(roots, allocsz);
333 	return (0);
334 }
335 
336 
337 /*
338  * Figure out everything we allocated in a root principal name list in
339  * order to free it up.
340  */
341 void
342 sec_svc_freerootnames(int flavor, int count, caddr_t *proots)
343 {
344 	int i;
345 	rpc_gss_principal_t gssname;
346 
347 	switch (flavor) {
348 	case AUTH_DES:
349 		for (i = 0; i < count; i++)
350 			if (proots[i] != NULL)
351 				kmem_free(proots[i], strlen(proots[i]) + 1);
352 		break;
353 
354 	case RPCSEC_GSS:
355 		for (i = 0; i < count; i++) {
356 			if (proots[i] == NULL)
357 				continue;
358 			gssname = (rpc_gss_principal_t)proots[i];
359 			kmem_free(proots[i], gssname->len + sizeof (int));
360 		}
361 		break;
362 
363 	}
364 	kmem_free(proots, count * sizeof (caddr_t));
365 }
366 
367 /*
368  * Check if the  given principal name is in the root principal list
369  */
370 bool_t
371 sec_svc_inrootlist(int flavor, caddr_t rootname, int count, caddr_t *roots)
372 {
373 	int i, tmp_len;
374 	rpc_gss_principal_t gssp, tmp_gssp;
375 	size_t namelen;
376 
377 	switch (flavor) {
378 	case AUTH_DES:
379 		namelen = strlen(rootname) + 1;
380 		for (i = 0; i < count; i++)
381 			if (bcmp(rootname, roots[i], namelen) == 0)
382 				return (TRUE);
383 		break;
384 
385 	case RPCSEC_GSS:
386 		gssp = (rpc_gss_principal_t)rootname;
387 		namelen = gssp->len;
388 		for (i = 0; i < count; i++) {
389 			tmp_gssp = (rpc_gss_principal_t)roots[i];
390 			tmp_len = tmp_gssp->len;
391 			if ((namelen == tmp_len) &&
392 			    (bcmp(&gssp->name[0],
393 			    &tmp_gssp->name[0], namelen) == 0))
394 				return (TRUE);
395 		}
396 		break;
397 	}
398 	return (FALSE);
399 }
400 
401 /*
402  * Miscellaneout "control" functions manipulating global RPC security
403  * attributes for server applications.
404  */
405 bool_t
406 sec_svc_control(uint_t cmd, void *argp)
407 {
408 	bool_t result = FALSE;		/* be paranoid */
409 
410 	switch (cmd) {
411 	case RPC_SVC_SET_GSS_CALLBACK:
412 		result = rpc_gss_set_callback((rpc_gss_callback_t *)argp);
413 		break;
414 	default:
415 		cmn_err(CE_WARN, "sec_svc_control: bad command (%d)", cmd);
416 		result = FALSE;
417 		break;
418 	}
419 
420 	return (result);
421 }
422