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]
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.
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>
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>
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().
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
= {
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
93 sec_svc_msg(struct svc_req
*rqst
, struct rpc_msg
*msg
, bool_t
*no_dispatch
)
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
) {
112 rqst
->rq_xprt
->xp_cookie
= (void *) AUTH_NULL
;
113 return (_svcauth_null(rqst
, msg
));
116 rqst
->rq_xprt
->xp_cookie
= (void *) AUTH_UNIX
;
117 return (_svcauth_unix(rqst
, msg
));
120 rqst
->rq_xprt
->xp_cookie
= (void *) AUTH_SHORT
;
121 return (_svcauth_short(rqst
, msg
));
124 rqst
->rq_xprt
->xp_cookie
= (void *) AUTH_DES
;
125 return (_svcauth_des(rqst
, msg
));
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
,
149 struct authunix_parms
*aup
;
150 struct authdes_cred
*adc
;
152 rpc_gss_rawcred_t
*rcred
;
153 rpc_gss_ucred_t
*ucred
;
157 flavor
= req
->rq_cred
.oa_flavor
;
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
);
176 adc
= (struct authdes_cred
*)req
->rq_clntcred
;
177 stat
= kauthdes_getucred(adc
, cr
);
178 *principal
= adc
->adc_fullname
.name
;
182 stat
= rpc_gss_getcred(req
, &rcred
, &ucred
, &cookie
);
183 *secmod
= (int)(uintptr_t)cookie
; /* XX64 */
185 if (crsetugid(cr
, ucred
->uid
, ucred
->gid
) != 0 ||
186 crsetgroups(cr
, ucred
->gidlen
, ucred
->gidlist
) != 0)
189 (void) crsetugid(cr
, UID_NOBODY
, GID_NOBODY
);
190 (void) crsetgroups(cr
, 0, NULL
);
192 *principal
= (caddr_t
)rcred
->client_principal
;
206 _svcauth_null(struct svc_req
*rqst
, struct rpc_msg
*msg
)
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
;
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
244 roots
= kmem_zalloc(allocsz
, KM_SLEEP
);
245 oroots
= kmem_alloc(oallocsz
, KM_SLEEP
);
247 if (copyin(*proots
, oroots
, oallocsz
))
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
) {
261 tmp
= (caddr32_t
*)oroots
;
262 root
= (caddr_t
)(uintptr_t)tmp
[i
];
266 if (copyinstr(root
, netname
, sizeof (netname
), &len
)) {
267 for (j
= 0; j
< i
; j
++) {
268 if (roots
[j
] != NULL
)
270 strlen(roots
[j
]) + 1);
274 roots
[i
] = kmem_alloc(len
, KM_SLEEP
);
275 bcopy(netname
, roots
[i
], len
);
277 kmem_free(oroots
, oallocsz
);
282 roots
= kmem_alloc(allocsz
, KM_SLEEP
);
283 oroots
= kmem_alloc(oallocsz
, KM_SLEEP
);
285 if (copyin(*proots
, oroots
, oallocsz
))
288 for (i
= 0; i
< count
; i
++) {
289 #ifdef _SYSCALL32_IMPL
290 if (model
!= DATAMODEL_NATIVE
) {
293 tmp
= (caddr32_t
*)oroots
;
294 root
= (caddr_t
)(uintptr_t)tmp
[i
];
299 if (copyin(root
, &gsstmp
, sizeof (gsstmp
))) {
300 kmem_free(oroots
, oallocsz
);
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
);
310 roots
[i
] = (caddr_t
)gssname
;
312 kmem_free(oroots
, oallocsz
);
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
));
329 kmem_free(roots
, allocsz
);
335 * Figure out everything we allocated in a root principal name list in
336 * order to free it up.
339 sec_svc_freerootnames(int flavor
, int count
, caddr_t
*proots
)
342 rpc_gss_principal_t gssname
;
346 for (i
= 0; i
< count
; i
++)
347 if (proots
[i
] != NULL
)
348 kmem_free(proots
[i
], strlen(proots
[i
]) + 1);
352 for (i
= 0; i
< count
; i
++) {
353 if (proots
[i
] == NULL
)
355 gssname
= (rpc_gss_principal_t
)proots
[i
];
356 kmem_free(proots
[i
], gssname
->len
+ sizeof (int));
361 kmem_free(proots
, count
* sizeof (caddr_t
));
365 * Check if the given principal name is in the root principal list
368 sec_svc_inrootlist(int flavor
, caddr_t rootname
, int count
, caddr_t
*roots
)
371 rpc_gss_principal_t gssp
, tmp_gssp
;
376 namelen
= strlen(rootname
) + 1;
377 for (i
= 0; i
< count
; i
++)
378 if (bcmp(rootname
, roots
[i
], namelen
) == 0)
383 gssp
= (rpc_gss_principal_t
)rootname
;
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))
399 * Miscellaneout "control" functions manipulating global RPC security
400 * attributes for server applications.
403 sec_svc_control(uint_t cmd
, void *argp
)
405 bool_t result
= FALSE
; /* be paranoid */
408 case RPC_SVC_SET_GSS_CALLBACK
:
409 result
= rpc_gss_set_callback((rpc_gss_callback_t
*)argp
);
412 cmn_err(CE_WARN
, "sec_svc_control: bad command (%d)", cmd
);