Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / rpc / sec / sec_svc.c
blob81c9896bdef6768de738f0babdf837626232d4ca
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 * sec_svc.c, Server-side rpc security interface.
31 #ifdef _KERNEL
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/debug.h>
35 #include <sys/systm.h>
36 #include <rpc/types.h>
37 #include <netinet/in.h>
38 #include <rpc/xdr.h>
39 #include <rpc/auth.h>
40 #include <rpc/clnt.h>
41 #include <rpc/rpc_msg.h>
42 #include <sys/tiuser.h>
43 #include <sys/tihdr.h>
44 #include <sys/t_kuser.h>
45 #include <sys/cmn_err.h>
46 #include <rpc/auth_des.h>
47 #include <rpc/auth_sys.h>
48 #include <rpc/rpcsec_gss.h>
49 #include <rpc/svc_auth.h>
50 #include <rpc/svc.h>
51 #else
52 #include <rpc/rpc.h>
53 #endif
56 enum auth_stat _svcauth_null(struct svc_req *, struct rpc_msg *);
59 * NO-OP server wrap/unwrap svc_authany_ops using no-op svc_authany_wrap().
61 /* ARGSUSED */
62 static int
63 svc_authany_wrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xfunc, caddr_t xwhere)
65 return (*xfunc)(xdrs, xwhere);
68 struct svc_auth_ops svc_authany_ops = {
69 svc_authany_wrap,
70 svc_authany_wrap
75 * The call rpc message, msg has been obtained from the wire. The msg contains
76 * the raw form of credentials and verifiers. authenticate returns AUTH_OK
77 * if the msg is successfully authenticated. If AUTH_OK then the routine also
78 * does the following things:
79 * set rqst->rq_xprt->verf to the appropriate response verifier;
80 * sets rqst->rq_client_cred to the "cooked" form of the credentials.
82 * NB: rqst->rq_cxprt->verf must be pre-alloctaed;
83 * its length is set appropriately.
85 * The caller still owns and is responsible for msg->u.cmb.cred and
86 * msg->u.cmb.verf. The authentication system retains ownership of
87 * rqst->rq_client_cred, the cooked credentials.
89 * There is an assumption that any flavor less than AUTH_NULL is
90 * invalid.
92 enum auth_stat
93 sec_svc_msg(struct svc_req *rqst, struct rpc_msg *msg, bool_t *no_dispatch)
95 int cred_flavor;
97 rqst->rq_cred = msg->rm_call.cb_cred;
98 rqst->rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor;
99 rqst->rq_xprt->xp_verf.oa_length = 0;
101 * Init the xp_auth to be no-op for all the flavors.
102 * Flavor specific routines will revise this when appropriate.
104 rqst->rq_xprt->xp_auth.svc_ah_ops = svc_authany_ops;
105 rqst->rq_xprt->xp_auth.svc_ah_private = NULL;
106 *no_dispatch = FALSE;
108 cred_flavor = rqst->rq_cred.oa_flavor;
110 switch (cred_flavor) {
111 case AUTH_NULL:
112 rqst->rq_xprt->xp_cookie = (void *) AUTH_NULL;
113 return (_svcauth_null(rqst, msg));
115 case AUTH_UNIX:
116 rqst->rq_xprt->xp_cookie = (void *) AUTH_UNIX;
117 return (_svcauth_unix(rqst, msg));
119 case AUTH_SHORT:
120 rqst->rq_xprt->xp_cookie = (void *) AUTH_SHORT;
121 return (_svcauth_short(rqst, msg));
123 case AUTH_DES:
124 rqst->rq_xprt->xp_cookie = (void *) AUTH_DES;
125 return (_svcauth_des(rqst, msg));
127 case RPCSEC_GSS:
129 * RPCSEC_GSS flavor routine takes an additional
130 * boolean parameter that gets set to TRUE when
131 * the call is not to be dispatched to the server.
133 return (__svcrpcsec_gss(rqst, msg, no_dispatch));
135 return (AUTH_REJECTEDCRED);
139 * sec_svc_getcred() gets unix cred of incoming security rpc requests.
140 * It also returns the prinicipal name and a cookie which is application
141 * dependent e.g. for nfs, it is the pseudo flavor.
143 * return 0 on failure
146 sec_svc_getcred(struct svc_req *req, cred_t *cr, caddr_t *principal,
147 int *secmod)
149 struct authunix_parms *aup;
150 struct authdes_cred *adc;
151 int flavor, stat;
152 rpc_gss_rawcred_t *rcred;
153 rpc_gss_ucred_t *ucred;
154 void *cookie;
156 stat = 1;
157 flavor = req->rq_cred.oa_flavor;
159 *principal = NULL;
160 switch (flavor) {
161 case AUTH_UNIX:
162 *secmod = AUTH_UNIX;
163 aup = (struct authunix_parms *)req->rq_clntcred;
164 if (crsetugid(cr, aup->aup_uid, aup->aup_gid) != 0)
165 (void) crsetugid(cr, UID_NOBODY, GID_NOBODY);
166 if (crsetgroups(cr, aup->aup_len, aup->aup_gids) != 0)
167 (void) crsetgroups(cr, 0, NULL);
168 break;
170 case AUTH_NONE:
171 *secmod = AUTH_NONE;
172 break;
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;
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);
192 *principal = (caddr_t)rcred->client_principal;
193 break;
195 default:
196 stat = 0;
197 break;
200 return (stat);
204 /* ARGSUSED */
205 enum auth_stat
206 _svcauth_null(struct svc_req *rqst, struct rpc_msg *msg)
208 return (AUTH_OK);
213 * Load root principal names from user space to kernel space.
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.
221 * return 0 on failure.
224 sec_svc_loadrootnames(int flavor, int count, caddr_t **proots, model_t model)
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;
234 * Get list of names from user space
236 allocsz = count * sizeof (caddr_t);
237 oallocsz = count * SIZEOF_PTR(model);
240 * And now copy each individual principal name
242 switch (flavor) {
243 case AUTH_DES:
244 roots = kmem_zalloc(allocsz, KM_SLEEP);
245 oroots = kmem_alloc(oallocsz, KM_SLEEP);
247 if (copyin(*proots, oroots, oallocsz))
248 goto done;
250 for (i = 0; i < count; i++) {
252 * copyinstr copies the complete string (including the
253 * NULL) and returns the len with the NULL byte
254 * included in the calculation as long as the max
255 * length is not exceeded.
257 #ifdef _SYSCALL32_IMPL
258 if (model != DATAMODEL_NATIVE) {
259 caddr32_t *tmp;
261 tmp = (caddr32_t *)oroots;
262 root = (caddr_t)(uintptr_t)tmp[i];
263 } else
264 #endif
265 root = oroots[i];
266 if (copyinstr(root, netname, sizeof (netname), &len)) {
267 for (j = 0; j < i; j++) {
268 if (roots[j] != NULL)
269 kmem_free(roots[j],
270 strlen(roots[j]) + 1);
272 goto done;
274 roots[i] = kmem_alloc(len, KM_SLEEP);
275 bcopy(netname, roots[i], len);
277 kmem_free(oroots, oallocsz);
278 *proots = roots;
279 return (1);
281 case RPCSEC_GSS:
282 roots = kmem_alloc(allocsz, KM_SLEEP);
283 oroots = kmem_alloc(oallocsz, KM_SLEEP);
285 if (copyin(*proots, oroots, oallocsz))
286 goto done;
288 for (i = 0; i < count; i++) {
289 #ifdef _SYSCALL32_IMPL
290 if (model != DATAMODEL_NATIVE) {
291 caddr32_t *tmp;
293 tmp = (caddr32_t *)oroots;
294 root = (caddr_t)(uintptr_t)tmp[i];
295 } else
296 #endif
297 root = oroots[i];
299 if (copyin(root, &gsstmp, sizeof (gsstmp))) {
300 kmem_free(oroots, oallocsz);
301 goto gssfreeup;
303 len = sizeof (gsstmp.len) + gsstmp.len;
304 gssname = kmem_alloc(len, KM_SLEEP);
305 if (copyin(root, gssname, len)) {
306 kmem_free(gssname, len);
307 kmem_free(oroots, oallocsz);
308 goto gssfreeup;
310 roots[i] = (caddr_t)gssname;
312 kmem_free(oroots, oallocsz);
313 *proots = roots;
314 return (1);
316 default:
317 return (0);
320 gssfreeup:
321 for (j = 0; j < i; j++) {
322 if (roots[j] != NULL) {
323 gssname = (rpc_gss_principal_t)roots[j];
324 kmem_free(roots[j], gssname->len +
325 sizeof (gssname->len));
328 done:
329 kmem_free(roots, allocsz);
330 return (0);
335 * Figure out everything we allocated in a root principal name list in
336 * order to free it up.
338 void
339 sec_svc_freerootnames(int flavor, int count, caddr_t *proots)
341 int i;
342 rpc_gss_principal_t gssname;
344 switch (flavor) {
345 case AUTH_DES:
346 for (i = 0; i < count; i++)
347 if (proots[i] != NULL)
348 kmem_free(proots[i], strlen(proots[i]) + 1);
349 break;
351 case RPCSEC_GSS:
352 for (i = 0; i < count; i++) {
353 if (proots[i] == NULL)
354 continue;
355 gssname = (rpc_gss_principal_t)proots[i];
356 kmem_free(proots[i], gssname->len + sizeof (int));
358 break;
361 kmem_free(proots, count * sizeof (caddr_t));
365 * Check if the given principal name is in the root principal list
367 bool_t
368 sec_svc_inrootlist(int flavor, caddr_t rootname, int count, caddr_t *roots)
370 int i, tmp_len;
371 rpc_gss_principal_t gssp, tmp_gssp;
372 size_t namelen;
374 switch (flavor) {
375 case AUTH_DES:
376 namelen = strlen(rootname) + 1;
377 for (i = 0; i < count; i++)
378 if (bcmp(rootname, roots[i], namelen) == 0)
379 return (TRUE);
380 break;
382 case RPCSEC_GSS:
383 gssp = (rpc_gss_principal_t)rootname;
384 namelen = gssp->len;
385 for (i = 0; i < count; i++) {
386 tmp_gssp = (rpc_gss_principal_t)roots[i];
387 tmp_len = tmp_gssp->len;
388 if ((namelen == tmp_len) &&
389 (bcmp(&gssp->name[0],
390 &tmp_gssp->name[0], namelen) == 0))
391 return (TRUE);
393 break;
395 return (FALSE);
399 * Miscellaneout "control" functions manipulating global RPC security
400 * attributes for server applications.
402 bool_t
403 sec_svc_control(uint_t cmd, void *argp)
405 bool_t result = FALSE; /* be paranoid */
407 switch (cmd) {
408 case RPC_SVC_SET_GSS_CALLBACK:
409 result = rpc_gss_set_callback((rpc_gss_callback_t *)argp);
410 break;
411 default:
412 cmn_err(CE_WARN, "sec_svc_control: bad command (%d)", cmd);
413 result = FALSE;
414 break;
417 return (result);