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