1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 2008 Doug Rabson 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 /* 29 auth_gss.c 30 31 RPCSEC_GSS client routines. 32 33 Copyright (c) 2000 The Regents of the University of Michigan. 34 All rights reserved. 35 36 Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>. 37 All rights reserved, all wrongs reversed. 38 39 Redistribution and use in source and binary forms, with or without 40 modification, are permitted provided that the following conditions 41 are met: 42 43 1. Redistributions of source code must retain the above copyright 44 notice, this list of conditions and the following disclaimer. 45 2. Redistributions in binary form must reproduce the above copyright 46 notice, this list of conditions and the following disclaimer in the 47 documentation and/or other materials provided with the distribution. 48 3. Neither the name of the University nor the names of its 49 contributors may be used to endorse or promote products derived 50 from this software without specific prior written permission. 51 52 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 53 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 54 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 55 DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 57 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 58 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 59 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 60 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 61 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 62 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 63 64 $Id: auth_gss.c,v 1.32 2002/01/15 15:43:00 andros Exp $ 65 */ 66 67 #include <sys/param.h> 68 #include <sys/systm.h> 69 #include <sys/hash.h> 70 #include <sys/jail.h> 71 #include <sys/kernel.h> 72 #include <sys/kobj.h> 73 #include <sys/lock.h> 74 #include <sys/malloc.h> 75 #include <sys/mbuf.h> 76 #include <sys/mutex.h> 77 #include <sys/proc.h> 78 #include <sys/refcount.h> 79 #include <sys/sx.h> 80 #include <sys/ucred.h> 81 82 #include <rpc/rpc.h> 83 #include <rpc/rpcsec_gss.h> 84 85 #include <kgssapi/krb5/kcrypto.h> 86 87 #include "rpcsec_gss_int.h" 88 89 static void rpc_gss_nextverf(AUTH*); 90 static bool_t rpc_gss_marshal(AUTH *, uint32_t, XDR *, struct mbuf *); 91 static bool_t rpc_gss_init(AUTH *auth, rpc_gss_options_ret_t *options_ret); 92 static bool_t rpc_gss_refresh(AUTH *, void *); 93 static bool_t rpc_gss_validate(AUTH *, uint32_t, struct opaque_auth *, 94 struct mbuf **); 95 static void rpc_gss_destroy(AUTH *); 96 static void rpc_gss_destroy_context(AUTH *, bool_t); 97 98 static const struct auth_ops rpc_gss_ops = { 99 .ah_nextverf = rpc_gss_nextverf, 100 .ah_marshal = rpc_gss_marshal, 101 .ah_validate = rpc_gss_validate, 102 .ah_refresh = rpc_gss_refresh, 103 .ah_destroy = rpc_gss_destroy, 104 }; 105 106 enum rpcsec_gss_state { 107 RPCSEC_GSS_START, 108 RPCSEC_GSS_CONTEXT, 109 RPCSEC_GSS_ESTABLISHED, 110 RPCSEC_GSS_DESTROYING 111 }; 112 113 struct rpc_pending_request { 114 uint32_t pr_xid; /* XID of rpc */ 115 uint32_t pr_seq; /* matching GSS seq */ 116 LIST_ENTRY(rpc_pending_request) pr_link; 117 }; 118 LIST_HEAD(rpc_pending_request_list, rpc_pending_request); 119 120 struct rpc_gss_data { 121 volatile u_int gd_refs; /* number of current users */ 122 struct mtx gd_lock; 123 uint32_t gd_hash; 124 AUTH *gd_auth; /* link back to AUTH */ 125 struct ucred *gd_ucred; /* matching local cred */ 126 char *gd_principal; /* server principal name */ 127 char *gd_clntprincipal; /* client principal name */ 128 rpc_gss_options_req_t gd_options; /* GSS context options */ 129 enum rpcsec_gss_state gd_state; /* connection state */ 130 gss_buffer_desc gd_verf; /* save GSS_S_COMPLETE 131 * NULL RPC verfier to 132 * process at end of 133 * context negotiation */ 134 CLIENT *gd_clnt; /* client handle */ 135 gss_OID gd_mech; /* mechanism to use */ 136 gss_qop_t gd_qop; /* quality of protection */ 137 gss_ctx_id_t gd_ctx; /* context id */ 138 struct rpc_gss_cred gd_cred; /* client credentials */ 139 uint32_t gd_seq; /* next sequence number */ 140 u_int gd_win; /* sequence window */ 141 struct rpc_pending_request_list gd_reqs; 142 TAILQ_ENTRY(rpc_gss_data) gd_link; 143 TAILQ_ENTRY(rpc_gss_data) gd_alllink; 144 }; 145 TAILQ_HEAD(rpc_gss_data_list, rpc_gss_data); 146 147 #define AUTH_PRIVATE(auth) ((struct rpc_gss_data *)auth->ah_private) 148 149 static struct timeval AUTH_TIMEOUT = { 25, 0 }; 150 151 #define RPC_GSS_HASH_SIZE 11 152 #define RPC_GSS_MAX 256 153 static struct rpc_gss_data_list rpc_gss_cache[RPC_GSS_HASH_SIZE]; 154 static struct rpc_gss_data_list rpc_gss_all; 155 static struct sx rpc_gss_lock; 156 static int rpc_gss_count; 157 158 static AUTH *rpc_gss_seccreate_int(CLIENT *, struct ucred *, const char *, 159 const char *, gss_OID, rpc_gss_service_t, u_int, rpc_gss_options_req_t *, 160 rpc_gss_options_ret_t *); 161 162 static void 163 rpc_gss_hashinit(void *dummy) 164 { 165 int i; 166 167 for (i = 0; i < RPC_GSS_HASH_SIZE; i++) 168 TAILQ_INIT(&rpc_gss_cache[i]); 169 TAILQ_INIT(&rpc_gss_all); 170 sx_init(&rpc_gss_lock, "rpc_gss_lock"); 171 } 172 SYSINIT(rpc_gss_hashinit, SI_SUB_KMEM, SI_ORDER_ANY, rpc_gss_hashinit, NULL); 173 174 static uint32_t 175 rpc_gss_hash(const char *principal, gss_OID mech, 176 struct ucred *cred, rpc_gss_service_t service) 177 { 178 uint32_t h; 179 180 h = HASHSTEP(HASHINIT, cred->cr_uid); 181 h = hash32_str(principal, h); 182 h = hash32_buf(mech->elements, mech->length, h); 183 h = HASHSTEP(h, (int) service); 184 185 return (h % RPC_GSS_HASH_SIZE); 186 } 187 188 /* 189 * Simplified interface to create a security association for the 190 * current thread's * ucred. 191 */ 192 AUTH * 193 rpc_gss_secfind(CLIENT *clnt, struct ucred *cred, const char *principal, 194 gss_OID mech_oid, rpc_gss_service_t service) 195 { 196 uint32_t h, th; 197 AUTH *auth; 198 struct rpc_gss_data *gd, *tgd; 199 rpc_gss_options_ret_t options; 200 201 if (rpc_gss_count > RPC_GSS_MAX) { 202 while (rpc_gss_count > RPC_GSS_MAX) { 203 sx_xlock(&rpc_gss_lock); 204 tgd = TAILQ_FIRST(&rpc_gss_all); 205 th = tgd->gd_hash; 206 TAILQ_REMOVE(&rpc_gss_cache[th], tgd, gd_link); 207 TAILQ_REMOVE(&rpc_gss_all, tgd, gd_alllink); 208 rpc_gss_count--; 209 sx_xunlock(&rpc_gss_lock); 210 AUTH_DESTROY(tgd->gd_auth); 211 } 212 } 213 214 /* 215 * See if we already have an AUTH which matches. 216 */ 217 h = rpc_gss_hash(principal, mech_oid, cred, service); 218 219 again: 220 sx_slock(&rpc_gss_lock); 221 TAILQ_FOREACH(gd, &rpc_gss_cache[h], gd_link) { 222 if (gd->gd_ucred->cr_uid == cred->cr_uid 223 && !strcmp(gd->gd_principal, principal) 224 && gd->gd_mech == mech_oid 225 && gd->gd_cred.gc_svc == service) { 226 refcount_acquire(&gd->gd_refs); 227 if (sx_try_upgrade(&rpc_gss_lock)) { 228 /* 229 * Keep rpc_gss_all LRU sorted. 230 */ 231 TAILQ_REMOVE(&rpc_gss_all, gd, gd_alllink); 232 TAILQ_INSERT_TAIL(&rpc_gss_all, gd, 233 gd_alllink); 234 sx_xunlock(&rpc_gss_lock); 235 } else { 236 sx_sunlock(&rpc_gss_lock); 237 } 238 239 /* 240 * If the state != ESTABLISHED, try and initialize 241 * the authenticator again. This will happen if the 242 * user's credentials have expired. It may succeed now, 243 * if they have done a kinit or similar. 244 */ 245 if (gd->gd_state != RPCSEC_GSS_ESTABLISHED) { 246 memset(&options, 0, sizeof (options)); 247 (void) rpc_gss_init(gd->gd_auth, &options); 248 } 249 return (gd->gd_auth); 250 } 251 } 252 sx_sunlock(&rpc_gss_lock); 253 254 /* 255 * We missed in the cache - create a new association. 256 */ 257 auth = rpc_gss_seccreate_int(clnt, cred, NULL, principal, mech_oid, 258 service, GSS_C_QOP_DEFAULT, NULL, NULL); 259 if (!auth) 260 return (NULL); 261 262 gd = AUTH_PRIVATE(auth); 263 gd->gd_hash = h; 264 265 sx_xlock(&rpc_gss_lock); 266 TAILQ_FOREACH(tgd, &rpc_gss_cache[h], gd_link) { 267 if (tgd->gd_ucred->cr_uid == cred->cr_uid 268 && !strcmp(tgd->gd_principal, principal) 269 && tgd->gd_mech == mech_oid 270 && tgd->gd_cred.gc_svc == service) { 271 /* 272 * We lost a race to create the AUTH that 273 * matches this cred. 274 */ 275 sx_xunlock(&rpc_gss_lock); 276 AUTH_DESTROY(auth); 277 goto again; 278 } 279 } 280 281 rpc_gss_count++; 282 TAILQ_INSERT_TAIL(&rpc_gss_cache[h], gd, gd_link); 283 TAILQ_INSERT_TAIL(&rpc_gss_all, gd, gd_alllink); 284 refcount_acquire(&gd->gd_refs); /* one for the cache, one for user */ 285 sx_xunlock(&rpc_gss_lock); 286 287 return (auth); 288 } 289 290 void 291 rpc_gss_secpurge(CLIENT *clnt) 292 { 293 uint32_t h; 294 struct rpc_gss_data *gd, *tgd; 295 296 TAILQ_FOREACH_SAFE(gd, &rpc_gss_all, gd_alllink, tgd) { 297 if (gd->gd_clnt == clnt) { 298 sx_xlock(&rpc_gss_lock); 299 h = gd->gd_hash; 300 TAILQ_REMOVE(&rpc_gss_cache[h], gd, gd_link); 301 TAILQ_REMOVE(&rpc_gss_all, gd, gd_alllink); 302 rpc_gss_count--; 303 sx_xunlock(&rpc_gss_lock); 304 AUTH_DESTROY(gd->gd_auth); 305 } 306 } 307 } 308 309 AUTH * 310 rpc_gss_seccreate(CLIENT *clnt, struct ucred *cred, const char *clnt_principal, 311 const char *principal, const char *mechanism, rpc_gss_service_t service, 312 const char *qop, rpc_gss_options_req_t *options_req, 313 rpc_gss_options_ret_t *options_ret) 314 { 315 gss_OID oid; 316 u_int qop_num; 317 318 /* 319 * Bail out now if we don't know this mechanism. 320 */ 321 if (!rpc_gss_mech_to_oid(mechanism, &oid)) 322 return (NULL); 323 324 if (qop) { 325 if (!rpc_gss_qop_to_num(qop, mechanism, &qop_num)) 326 return (NULL); 327 } else { 328 qop_num = GSS_C_QOP_DEFAULT; 329 } 330 331 return (rpc_gss_seccreate_int(clnt, cred, clnt_principal, principal, 332 oid, service, qop_num, options_req, options_ret)); 333 } 334 335 void 336 rpc_gss_refresh_auth(AUTH *auth) 337 { 338 struct rpc_gss_data *gd; 339 rpc_gss_options_ret_t options; 340 341 gd = AUTH_PRIVATE(auth); 342 /* 343 * If the state != ESTABLISHED, try and initialize 344 * the authenticator again. This will happen if the 345 * user's credentials have expired. It may succeed now, 346 * if they have done a kinit or similar. 347 */ 348 if (gd->gd_state != RPCSEC_GSS_ESTABLISHED) { 349 memset(&options, 0, sizeof (options)); 350 (void) rpc_gss_init(auth, &options); 351 } 352 } 353 354 static AUTH * 355 rpc_gss_seccreate_int(CLIENT *clnt, struct ucred *cred, 356 const char *clnt_principal, const char *principal, gss_OID mech_oid, 357 rpc_gss_service_t service, u_int qop_num, 358 rpc_gss_options_req_t *options_req, rpc_gss_options_ret_t *options_ret) 359 { 360 AUTH *auth; 361 rpc_gss_options_ret_t options; 362 struct rpc_gss_data *gd; 363 364 /* 365 * If the caller doesn't want the options, point at local 366 * storage to simplify the code below. 367 */ 368 if (!options_ret) 369 options_ret = &options; 370 371 /* 372 * Default service is integrity. 373 */ 374 if (service == rpc_gss_svc_default) 375 service = rpc_gss_svc_integrity; 376 377 memset(options_ret, 0, sizeof(*options_ret)); 378 379 rpc_gss_log_debug("in rpc_gss_seccreate()"); 380 381 memset(&rpc_createerr, 0, sizeof(rpc_createerr)); 382 383 auth = mem_alloc(sizeof(*auth)); 384 if (auth == NULL) { 385 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 386 rpc_createerr.cf_error.re_errno = ENOMEM; 387 return (NULL); 388 } 389 gd = mem_alloc(sizeof(*gd)); 390 if (gd == NULL) { 391 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 392 rpc_createerr.cf_error.re_errno = ENOMEM; 393 mem_free(auth, sizeof(*auth)); 394 return (NULL); 395 } 396 397 auth->ah_ops = &rpc_gss_ops; 398 auth->ah_private = (caddr_t) gd; 399 auth->ah_cred.oa_flavor = RPCSEC_GSS; 400 401 refcount_init(&gd->gd_refs, 1); 402 mtx_init(&gd->gd_lock, "gd->gd_lock", NULL, MTX_DEF); 403 gd->gd_auth = auth; 404 gd->gd_ucred = crdup(cred); 405 gd->gd_principal = strdup(principal, M_RPC); 406 if (clnt_principal != NULL) 407 gd->gd_clntprincipal = strdup(clnt_principal, M_RPC); 408 else 409 gd->gd_clntprincipal = NULL; 410 411 412 if (options_req) { 413 gd->gd_options = *options_req; 414 } else { 415 gd->gd_options.req_flags = GSS_C_MUTUAL_FLAG; 416 gd->gd_options.time_req = 0; 417 gd->gd_options.my_cred = GSS_C_NO_CREDENTIAL; 418 gd->gd_options.input_channel_bindings = NULL; 419 } 420 CLNT_ACQUIRE(clnt); 421 gd->gd_clnt = clnt; 422 gd->gd_ctx = GSS_C_NO_CONTEXT; 423 gd->gd_mech = mech_oid; 424 gd->gd_qop = qop_num; 425 426 gd->gd_cred.gc_version = RPCSEC_GSS_VERSION; 427 gd->gd_cred.gc_proc = RPCSEC_GSS_INIT; 428 gd->gd_cred.gc_seq = 0; 429 gd->gd_cred.gc_svc = service; 430 LIST_INIT(&gd->gd_reqs); 431 432 if (!rpc_gss_init(auth, options_ret)) { 433 goto bad; 434 } 435 436 return (auth); 437 438 bad: 439 AUTH_DESTROY(auth); 440 return (NULL); 441 } 442 443 bool_t 444 rpc_gss_set_defaults(AUTH *auth, rpc_gss_service_t service, const char *qop) 445 { 446 struct rpc_gss_data *gd; 447 u_int qop_num; 448 const char *mechanism; 449 450 gd = AUTH_PRIVATE(auth); 451 if (!rpc_gss_oid_to_mech(gd->gd_mech, &mechanism)) { 452 return (FALSE); 453 } 454 455 if (qop) { 456 if (!rpc_gss_qop_to_num(qop, mechanism, &qop_num)) { 457 return (FALSE); 458 } 459 } else { 460 qop_num = GSS_C_QOP_DEFAULT; 461 } 462 463 gd->gd_cred.gc_svc = service; 464 gd->gd_qop = qop_num; 465 return (TRUE); 466 } 467 468 static void 469 rpc_gss_purge_xid(struct rpc_gss_data *gd, uint32_t xid) 470 { 471 struct rpc_pending_request *pr, *npr; 472 struct rpc_pending_request_list reqs; 473 474 LIST_INIT(&reqs); 475 mtx_lock(&gd->gd_lock); 476 LIST_FOREACH_SAFE(pr, &gd->gd_reqs, pr_link, npr) { 477 if (pr->pr_xid == xid) { 478 LIST_REMOVE(pr, pr_link); 479 LIST_INSERT_HEAD(&reqs, pr, pr_link); 480 } 481 } 482 483 mtx_unlock(&gd->gd_lock); 484 485 LIST_FOREACH_SAFE(pr, &reqs, pr_link, npr) { 486 mem_free(pr, sizeof(*pr)); 487 } 488 } 489 490 static uint32_t 491 rpc_gss_alloc_seq(struct rpc_gss_data *gd) 492 { 493 uint32_t seq; 494 495 mtx_lock(&gd->gd_lock); 496 seq = gd->gd_seq; 497 gd->gd_seq++; 498 mtx_unlock(&gd->gd_lock); 499 500 return (seq); 501 } 502 503 static void 504 rpc_gss_nextverf(__unused AUTH *auth) 505 { 506 507 /* not used */ 508 } 509 510 static bool_t 511 rpc_gss_marshal(AUTH *auth, uint32_t xid, XDR *xdrs, struct mbuf *args) 512 { 513 struct rpc_gss_data *gd; 514 struct rpc_pending_request *pr; 515 uint32_t seq; 516 XDR tmpxdrs; 517 struct rpc_gss_cred gsscred; 518 char credbuf[MAX_AUTH_BYTES]; 519 struct opaque_auth creds, verf; 520 gss_buffer_desc rpcbuf, checksum; 521 OM_uint32 maj_stat, min_stat; 522 bool_t xdr_stat; 523 524 rpc_gss_log_debug("in rpc_gss_marshal()"); 525 526 gd = AUTH_PRIVATE(auth); 527 528 gsscred = gd->gd_cred; 529 seq = rpc_gss_alloc_seq(gd); 530 gsscred.gc_seq = seq; 531 532 xdrmem_create(&tmpxdrs, credbuf, sizeof(credbuf), XDR_ENCODE); 533 if (!xdr_rpc_gss_cred(&tmpxdrs, &gsscred)) { 534 XDR_DESTROY(&tmpxdrs); 535 _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM); 536 return (FALSE); 537 } 538 creds.oa_flavor = RPCSEC_GSS; 539 creds.oa_base = credbuf; 540 creds.oa_length = XDR_GETPOS(&tmpxdrs); 541 XDR_DESTROY(&tmpxdrs); 542 543 xdr_opaque_auth(xdrs, &creds); 544 545 if (gd->gd_cred.gc_proc == RPCSEC_GSS_INIT || 546 gd->gd_cred.gc_proc == RPCSEC_GSS_CONTINUE_INIT) { 547 if (!xdr_opaque_auth(xdrs, &_null_auth)) { 548 _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM); 549 return (FALSE); 550 } 551 return (xdr_putmbuf(xdrs, args)); 552 } else { 553 /* 554 * Keep track of this XID + seq pair so that we can do 555 * the matching gss_verify_mic in AUTH_VALIDATE. 556 */ 557 pr = mem_alloc(sizeof(struct rpc_pending_request)); 558 mtx_lock(&gd->gd_lock); 559 pr->pr_xid = xid; 560 pr->pr_seq = seq; 561 LIST_INSERT_HEAD(&gd->gd_reqs, pr, pr_link); 562 mtx_unlock(&gd->gd_lock); 563 564 /* 565 * Checksum serialized RPC header, up to and including 566 * credential. For the in-kernel environment, we 567 * assume that our XDR stream is on a contiguous 568 * memory buffer (e.g. an mbuf). 569 */ 570 rpcbuf.length = XDR_GETPOS(xdrs); 571 XDR_SETPOS(xdrs, 0); 572 rpcbuf.value = XDR_INLINE(xdrs, rpcbuf.length); 573 574 maj_stat = gss_get_mic(&min_stat, gd->gd_ctx, gd->gd_qop, 575 &rpcbuf, &checksum); 576 577 if (maj_stat != GSS_S_COMPLETE) { 578 rpc_gss_log_status("gss_get_mic", gd->gd_mech, 579 maj_stat, min_stat); 580 if (maj_stat == GSS_S_CONTEXT_EXPIRED) { 581 rpc_gss_destroy_context(auth, TRUE); 582 } 583 _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, EPERM); 584 return (FALSE); 585 } 586 587 verf.oa_flavor = RPCSEC_GSS; 588 verf.oa_base = checksum.value; 589 verf.oa_length = checksum.length; 590 591 xdr_stat = xdr_opaque_auth(xdrs, &verf); 592 gss_release_buffer(&min_stat, &checksum); 593 if (!xdr_stat) { 594 _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM); 595 return (FALSE); 596 } 597 if (gd->gd_state != RPCSEC_GSS_ESTABLISHED || 598 gd->gd_cred.gc_svc == rpc_gss_svc_none) { 599 return (xdr_putmbuf(xdrs, args)); 600 } else { 601 if (!xdr_rpc_gss_wrap_data(&args, 602 gd->gd_ctx, gd->gd_qop, gd->gd_cred.gc_svc, 603 seq)) 604 return (FALSE); 605 return (xdr_putmbuf(xdrs, args)); 606 } 607 } 608 609 return (TRUE); 610 } 611 612 static bool_t 613 rpc_gss_validate(AUTH *auth, uint32_t xid, struct opaque_auth *verf, 614 struct mbuf **resultsp) 615 { 616 struct rpc_gss_data *gd; 617 struct rpc_pending_request *pr, *npr; 618 struct rpc_pending_request_list reqs; 619 gss_qop_t qop_state; 620 uint32_t num, seq; 621 gss_buffer_desc signbuf, checksum; 622 OM_uint32 maj_stat, min_stat; 623 624 rpc_gss_log_debug("in rpc_gss_validate()"); 625 626 gd = AUTH_PRIVATE(auth); 627 628 /* 629 * The client will call us with a NULL verf when it gives up 630 * on an XID. 631 */ 632 if (!verf) { 633 rpc_gss_purge_xid(gd, xid); 634 return (TRUE); 635 } 636 637 if (gd->gd_state == RPCSEC_GSS_CONTEXT) { 638 /* 639 * Save the on the wire verifier to validate last INIT 640 * phase packet after decode if the major status is 641 * GSS_S_COMPLETE. 642 */ 643 if (gd->gd_verf.value) 644 xdr_free((xdrproc_t) xdr_gss_buffer_desc, 645 (char *) &gd->gd_verf); 646 gd->gd_verf.value = mem_alloc(verf->oa_length); 647 if (gd->gd_verf.value == NULL) { 648 printf("gss_validate: out of memory\n"); 649 _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM); 650 m_freem(*resultsp); 651 *resultsp = NULL; 652 return (FALSE); 653 } 654 memcpy(gd->gd_verf.value, verf->oa_base, verf->oa_length); 655 gd->gd_verf.length = verf->oa_length; 656 657 return (TRUE); 658 } 659 660 /* 661 * We need to check the verifier against all the requests 662 * we've send for this XID - for unreliable protocols, we 663 * retransmit with the same XID but different sequence 664 * number. We temporarily take this set of requests out of the 665 * list so that we can work through the list without having to 666 * hold the lock. 667 */ 668 mtx_lock(&gd->gd_lock); 669 LIST_INIT(&reqs); 670 LIST_FOREACH_SAFE(pr, &gd->gd_reqs, pr_link, npr) { 671 if (pr->pr_xid == xid) { 672 LIST_REMOVE(pr, pr_link); 673 LIST_INSERT_HEAD(&reqs, pr, pr_link); 674 } 675 } 676 mtx_unlock(&gd->gd_lock); 677 LIST_FOREACH(pr, &reqs, pr_link) { 678 if (pr->pr_xid == xid) { 679 seq = pr->pr_seq; 680 num = htonl(seq); 681 signbuf.value = # 682 signbuf.length = sizeof(num); 683 684 checksum.value = verf->oa_base; 685 checksum.length = verf->oa_length; 686 687 maj_stat = gss_verify_mic(&min_stat, gd->gd_ctx, 688 &signbuf, &checksum, &qop_state); 689 if (maj_stat != GSS_S_COMPLETE 690 || qop_state != gd->gd_qop) { 691 continue; 692 } 693 if (maj_stat == GSS_S_CONTEXT_EXPIRED) { 694 rpc_gss_destroy_context(auth, TRUE); 695 break; 696 } 697 //rpc_gss_purge_reqs(gd, seq); 698 LIST_FOREACH_SAFE(pr, &reqs, pr_link, npr) 699 mem_free(pr, sizeof(*pr)); 700 701 if (gd->gd_cred.gc_svc == rpc_gss_svc_none) { 702 return (TRUE); 703 } else { 704 if (!xdr_rpc_gss_unwrap_data(resultsp, 705 gd->gd_ctx, gd->gd_qop, 706 gd->gd_cred.gc_svc, seq)) { 707 return (FALSE); 708 } 709 } 710 return (TRUE); 711 } 712 } 713 714 /* 715 * We didn't match - put back any entries for this XID so that 716 * a future call to validate can retry. 717 */ 718 mtx_lock(&gd->gd_lock); 719 LIST_FOREACH_SAFE(pr, &reqs, pr_link, npr) { 720 LIST_REMOVE(pr, pr_link); 721 LIST_INSERT_HEAD(&gd->gd_reqs, pr, pr_link); 722 } 723 mtx_unlock(&gd->gd_lock); 724 725 /* 726 * Nothing matches - give up. 727 */ 728 _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, EPERM); 729 m_freem(*resultsp); 730 *resultsp = NULL; 731 return (FALSE); 732 } 733 734 static bool_t 735 rpc_gss_init(AUTH *auth, rpc_gss_options_ret_t *options_ret) 736 { 737 struct thread *td = curthread; 738 struct ucred *crsave; 739 struct rpc_gss_data *gd; 740 struct rpc_gss_init_res gr; 741 gss_buffer_desc principal_desc; 742 gss_buffer_desc *recv_tokenp, recv_token, send_token; 743 gss_name_t name; 744 OM_uint32 maj_stat, min_stat, call_stat; 745 const char *mech; 746 struct rpc_callextra ext; 747 gss_OID mech_oid; 748 gss_OID_set mechlist; 749 static enum krb_imp my_krb_imp = KRBIMP_UNKNOWN; 750 751 rpc_gss_log_debug("in rpc_gss_refresh()"); 752 753 gd = AUTH_PRIVATE(auth); 754 755 mtx_lock(&gd->gd_lock); 756 /* 757 * If the context isn't in START state, someone else is 758 * refreshing - we wait till they are done. If they fail, they 759 * will put the state back to START and we can try (most 760 * likely to also fail). 761 */ 762 while (gd->gd_state != RPCSEC_GSS_START 763 && gd->gd_state != RPCSEC_GSS_ESTABLISHED) { 764 msleep(gd, &gd->gd_lock, 0, "gssstate", 0); 765 } 766 if (gd->gd_state == RPCSEC_GSS_ESTABLISHED) { 767 mtx_unlock(&gd->gd_lock); 768 return (TRUE); 769 } 770 gd->gd_state = RPCSEC_GSS_CONTEXT; 771 mtx_unlock(&gd->gd_lock); 772 773 gd->gd_cred.gc_proc = RPCSEC_GSS_INIT; 774 gd->gd_cred.gc_seq = 0; 775 776 /* 777 * XXX Threads from inside jails can get here via calls 778 * to clnt_vc_call()->AUTH_REFRESH()->rpc_gss_refresh() 779 * but the NFS mount is always done outside of the 780 * jails in vnet0. Since the thread credentials won't 781 * necessarily have cr_prison == vnet0 and this function 782 * has no access to the socket, using vnet0 seems the 783 * only option. This is broken if NFS mounts are enabled 784 * within vnet prisons. 785 */ 786 KGSS_CURVNET_SET_QUIET(vnet0); 787 /* 788 * For KerberosV, if there is a client principal name, that implies 789 * that this is a host based initiator credential in the default 790 * keytab file. For this case, it is necessary to do a 791 * gss_acquire_cred(). When this is done, the gssd daemon will 792 * do the equivalent of "kinit -k" to put a TGT for the name in 793 * the credential cache file for the gssd daemon. 794 */ 795 if (gd->gd_clntprincipal != NULL && 796 rpc_gss_mech_to_oid("kerberosv5", &mech_oid) && 797 gd->gd_mech == mech_oid) { 798 /* Get rid of any old credential. */ 799 if (gd->gd_options.my_cred != GSS_C_NO_CREDENTIAL) { 800 gss_release_cred(&min_stat, &gd->gd_options.my_cred); 801 gd->gd_options.my_cred = GSS_C_NO_CREDENTIAL; 802 } 803 804 /* 805 * The mechanism must be set to KerberosV for acquisition 806 * of credentials to work reliably. 807 */ 808 maj_stat = gss_create_empty_oid_set(&min_stat, &mechlist); 809 if (maj_stat != GSS_S_COMPLETE) { 810 options_ret->major_status = maj_stat; 811 options_ret->minor_status = min_stat; 812 goto out; 813 } 814 maj_stat = gss_add_oid_set_member(&min_stat, gd->gd_mech, 815 &mechlist); 816 if (maj_stat != GSS_S_COMPLETE) { 817 options_ret->major_status = maj_stat; 818 options_ret->minor_status = min_stat; 819 gss_release_oid_set(&min_stat, &mechlist); 820 goto out; 821 } 822 823 principal_desc.value = (void *)gd->gd_clntprincipal; 824 principal_desc.length = strlen(gd->gd_clntprincipal); 825 maj_stat = gss_import_name(&min_stat, &principal_desc, 826 GSS_C_NT_HOSTBASED_SERVICE, &name); 827 if (maj_stat != GSS_S_COMPLETE) { 828 options_ret->major_status = maj_stat; 829 options_ret->minor_status = min_stat; 830 gss_release_oid_set(&min_stat, &mechlist); 831 goto out; 832 } 833 /* Acquire the credentials. */ 834 maj_stat = gss_acquire_cred(&min_stat, name, 0, 835 mechlist, GSS_C_INITIATE, 836 &gd->gd_options.my_cred, NULL, NULL); 837 gss_release_name(&min_stat, &name); 838 gss_release_oid_set(&min_stat, &mechlist); 839 if (maj_stat != GSS_S_COMPLETE) { 840 options_ret->major_status = maj_stat; 841 options_ret->minor_status = min_stat; 842 goto out; 843 } 844 } 845 846 principal_desc.value = (void *)gd->gd_principal; 847 principal_desc.length = strlen(gd->gd_principal); 848 maj_stat = gss_import_name(&min_stat, &principal_desc, 849 GSS_C_NT_HOSTBASED_SERVICE, &name); 850 if (maj_stat != GSS_S_COMPLETE) { 851 options_ret->major_status = maj_stat; 852 options_ret->minor_status = min_stat; 853 goto out; 854 } 855 856 if (my_krb_imp == KRBIMP_UNKNOWN) { 857 maj_stat = gss_supports_lucid(&min_stat, NULL); 858 if (maj_stat == GSS_S_COMPLETE) 859 my_krb_imp = KRBIMP_MIT; 860 else 861 my_krb_imp = KRBIMP_HEIMDALV1; 862 } 863 864 /* GSS context establishment loop. */ 865 memset(&recv_token, 0, sizeof(recv_token)); 866 memset(&gr, 0, sizeof(gr)); 867 memset(options_ret, 0, sizeof(*options_ret)); 868 options_ret->major_status = GSS_S_FAILURE; 869 recv_tokenp = GSS_C_NO_BUFFER; 870 871 for (;;) { 872 crsave = td->td_ucred; 873 td->td_ucred = gd->gd_ucred; 874 if (my_krb_imp == KRBIMP_MIT) 875 maj_stat = gss_init_sec_context_lucid_v1(&min_stat, 876 gd->gd_options.my_cred, 877 &gd->gd_ctx, 878 name, 879 gd->gd_mech, 880 gd->gd_options.req_flags, 881 gd->gd_options.time_req, 882 gd->gd_options.input_channel_bindings, 883 recv_tokenp, 884 &gd->gd_mech, /* used mech */ 885 &send_token, 886 &options_ret->ret_flags, 887 &options_ret->time_req); 888 else 889 maj_stat = gss_init_sec_context(&min_stat, 890 gd->gd_options.my_cred, 891 &gd->gd_ctx, 892 name, 893 gd->gd_mech, 894 gd->gd_options.req_flags, 895 gd->gd_options.time_req, 896 gd->gd_options.input_channel_bindings, 897 recv_tokenp, 898 &gd->gd_mech, /* used mech */ 899 &send_token, 900 &options_ret->ret_flags, 901 &options_ret->time_req); 902 td->td_ucred = crsave; 903 904 /* 905 * Free the token which we got from the server (if 906 * any). Remember that this was allocated by XDR, not 907 * GSS-API. 908 */ 909 if (recv_tokenp != GSS_C_NO_BUFFER) { 910 xdr_free((xdrproc_t) xdr_gss_buffer_desc, 911 (char *) &recv_token); 912 recv_tokenp = GSS_C_NO_BUFFER; 913 } 914 if (gd->gd_mech && rpc_gss_oid_to_mech(gd->gd_mech, &mech)) { 915 strlcpy(options_ret->actual_mechanism, 916 mech, 917 sizeof(options_ret->actual_mechanism)); 918 } 919 if (maj_stat != GSS_S_COMPLETE && 920 maj_stat != GSS_S_CONTINUE_NEEDED) { 921 rpc_gss_log_status("gss_init_sec_context", gd->gd_mech, 922 maj_stat, min_stat); 923 options_ret->major_status = maj_stat; 924 options_ret->minor_status = min_stat; 925 break; 926 } 927 if (send_token.length != 0) { 928 memset(&gr, 0, sizeof(gr)); 929 930 bzero(&ext, sizeof(ext)); 931 ext.rc_auth = auth; 932 call_stat = CLNT_CALL_EXT(gd->gd_clnt, &ext, NULLPROC, 933 (xdrproc_t)xdr_gss_buffer_desc, 934 &send_token, 935 (xdrproc_t)xdr_rpc_gss_init_res, 936 (caddr_t)&gr, AUTH_TIMEOUT); 937 938 gss_release_buffer(&min_stat, &send_token); 939 940 if (call_stat != RPC_SUCCESS) 941 break; 942 943 if (gr.gr_major != GSS_S_COMPLETE && 944 gr.gr_major != GSS_S_CONTINUE_NEEDED) { 945 rpc_gss_log_status("server reply", gd->gd_mech, 946 gr.gr_major, gr.gr_minor); 947 options_ret->major_status = gr.gr_major; 948 options_ret->minor_status = gr.gr_minor; 949 break; 950 } 951 952 /* 953 * Save the server's gr_handle value, freeing 954 * what we have already (remember that this 955 * was allocated by XDR, not GSS-API). 956 */ 957 if (gr.gr_handle.length != 0) { 958 xdr_free((xdrproc_t) xdr_gss_buffer_desc, 959 (char *) &gd->gd_cred.gc_handle); 960 gd->gd_cred.gc_handle = gr.gr_handle; 961 } 962 963 /* 964 * Save the server's token as well. 965 */ 966 if (gr.gr_token.length != 0) { 967 recv_token = gr.gr_token; 968 recv_tokenp = &recv_token; 969 } 970 971 /* 972 * Since we have copied out all the bits of gr 973 * which XDR allocated for us, we don't need 974 * to free it. 975 */ 976 gd->gd_cred.gc_proc = RPCSEC_GSS_CONTINUE_INIT; 977 } 978 979 if (maj_stat == GSS_S_COMPLETE) { 980 gss_buffer_desc bufin; 981 u_int seq, qop_state = 0; 982 983 /* 984 * gss header verifier, 985 * usually checked in gss_validate 986 */ 987 seq = htonl(gr.gr_win); 988 bufin.value = (unsigned char *)&seq; 989 bufin.length = sizeof(seq); 990 991 maj_stat = gss_verify_mic(&min_stat, gd->gd_ctx, 992 &bufin, &gd->gd_verf, &qop_state); 993 994 if (maj_stat != GSS_S_COMPLETE || 995 qop_state != gd->gd_qop) { 996 rpc_gss_log_status("gss_verify_mic", gd->gd_mech, 997 maj_stat, min_stat); 998 if (maj_stat == GSS_S_CONTEXT_EXPIRED) { 999 rpc_gss_destroy_context(auth, TRUE); 1000 } 1001 _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, 1002 EPERM); 1003 options_ret->major_status = maj_stat; 1004 options_ret->minor_status = min_stat; 1005 break; 1006 } 1007 1008 options_ret->major_status = GSS_S_COMPLETE; 1009 options_ret->minor_status = 0; 1010 options_ret->rpcsec_version = gd->gd_cred.gc_version; 1011 options_ret->gss_context = gd->gd_ctx; 1012 1013 gd->gd_cred.gc_proc = RPCSEC_GSS_DATA; 1014 gd->gd_seq = 1; 1015 gd->gd_win = gr.gr_win; 1016 break; 1017 } 1018 } 1019 1020 gss_release_name(&min_stat, &name); 1021 xdr_free((xdrproc_t) xdr_gss_buffer_desc, 1022 (char *) &gd->gd_verf); 1023 1024 out: 1025 /* End context negotiation loop. */ 1026 if (gd->gd_cred.gc_proc != RPCSEC_GSS_DATA) { 1027 rpc_createerr.cf_stat = RPC_AUTHERROR; 1028 _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, EPERM); 1029 if (gd->gd_ctx) { 1030 gss_delete_sec_context(&min_stat, &gd->gd_ctx, 1031 GSS_C_NO_BUFFER); 1032 } 1033 KGSS_CURVNET_RESTORE(); 1034 mtx_lock(&gd->gd_lock); 1035 gd->gd_state = RPCSEC_GSS_START; 1036 wakeup(gd); 1037 mtx_unlock(&gd->gd_lock); 1038 return (FALSE); 1039 } 1040 KGSS_CURVNET_RESTORE(); 1041 1042 mtx_lock(&gd->gd_lock); 1043 gd->gd_state = RPCSEC_GSS_ESTABLISHED; 1044 wakeup(gd); 1045 mtx_unlock(&gd->gd_lock); 1046 1047 return (TRUE); 1048 } 1049 1050 static bool_t 1051 rpc_gss_refresh(AUTH *auth, void *msg) 1052 { 1053 struct rpc_msg *reply = (struct rpc_msg *) msg; 1054 rpc_gss_options_ret_t options; 1055 struct rpc_gss_data *gd; 1056 1057 gd = AUTH_PRIVATE(auth); 1058 1059 /* 1060 * If the context is in DESTROYING state, then just return, since 1061 * there is no point in refreshing the credentials. 1062 */ 1063 mtx_lock(&gd->gd_lock); 1064 if (gd->gd_state == RPCSEC_GSS_DESTROYING) { 1065 mtx_unlock(&gd->gd_lock); 1066 return (FALSE); 1067 } 1068 mtx_unlock(&gd->gd_lock); 1069 1070 /* 1071 * If the error was RPCSEC_GSS_CREDPROBLEM of 1072 * RPCSEC_GSS_CTXPROBLEM we start again from scratch. All 1073 * other errors are fatal. 1074 */ 1075 if (reply->rm_reply.rp_stat == MSG_DENIED 1076 && reply->rm_reply.rp_rjct.rj_stat == AUTH_ERROR 1077 && (reply->rm_reply.rp_rjct.rj_why == RPCSEC_GSS_CREDPROBLEM 1078 || reply->rm_reply.rp_rjct.rj_why == RPCSEC_GSS_CTXPROBLEM)) { 1079 rpc_gss_destroy_context(auth, FALSE); 1080 memset(&options, 0, sizeof(options)); 1081 return (rpc_gss_init(auth, &options)); 1082 } 1083 1084 return (FALSE); 1085 } 1086 1087 static void 1088 rpc_gss_destroy_context(AUTH *auth, bool_t send_destroy) 1089 { 1090 struct rpc_gss_data *gd; 1091 struct rpc_pending_request *pr; 1092 OM_uint32 min_stat; 1093 struct rpc_callextra ext; 1094 1095 rpc_gss_log_debug("in rpc_gss_destroy_context()"); 1096 1097 gd = AUTH_PRIVATE(auth); 1098 1099 mtx_lock(&gd->gd_lock); 1100 /* 1101 * If the context isn't in ESTABISHED state, someone else is 1102 * destroying/refreshing - we wait till they are done. 1103 */ 1104 if (gd->gd_state != RPCSEC_GSS_ESTABLISHED) { 1105 while (gd->gd_state != RPCSEC_GSS_START 1106 && gd->gd_state != RPCSEC_GSS_ESTABLISHED) 1107 msleep(gd, &gd->gd_lock, 0, "gssstate", 0); 1108 mtx_unlock(&gd->gd_lock); 1109 return; 1110 } 1111 gd->gd_state = RPCSEC_GSS_DESTROYING; 1112 mtx_unlock(&gd->gd_lock); 1113 1114 if (send_destroy) { 1115 gd->gd_cred.gc_proc = RPCSEC_GSS_DESTROY; 1116 bzero(&ext, sizeof(ext)); 1117 ext.rc_auth = auth; 1118 CLNT_CALL_EXT(gd->gd_clnt, &ext, NULLPROC, 1119 (xdrproc_t)xdr_void, NULL, 1120 (xdrproc_t)xdr_void, NULL, AUTH_TIMEOUT); 1121 } 1122 1123 while ((pr = LIST_FIRST(&gd->gd_reqs)) != NULL) { 1124 LIST_REMOVE(pr, pr_link); 1125 mem_free(pr, sizeof(*pr)); 1126 } 1127 1128 /* 1129 * Free the context token. Remember that this was 1130 * allocated by XDR, not GSS-API. 1131 */ 1132 xdr_free((xdrproc_t) xdr_gss_buffer_desc, 1133 (char *) &gd->gd_cred.gc_handle); 1134 gd->gd_cred.gc_handle.length = 0; 1135 1136 if (gd->gd_ctx != GSS_C_NO_CONTEXT) 1137 gss_delete_sec_context(&min_stat, &gd->gd_ctx, NULL); 1138 1139 mtx_lock(&gd->gd_lock); 1140 gd->gd_state = RPCSEC_GSS_START; 1141 wakeup(gd); 1142 mtx_unlock(&gd->gd_lock); 1143 } 1144 1145 static void 1146 rpc_gss_destroy(AUTH *auth) 1147 { 1148 struct rpc_gss_data *gd; 1149 1150 rpc_gss_log_debug("in rpc_gss_destroy()"); 1151 1152 gd = AUTH_PRIVATE(auth); 1153 1154 if (!refcount_release(&gd->gd_refs)) 1155 return; 1156 1157 rpc_gss_destroy_context(auth, TRUE); 1158 1159 CLNT_RELEASE(gd->gd_clnt); 1160 crfree(gd->gd_ucred); 1161 free(gd->gd_principal, M_RPC); 1162 if (gd->gd_clntprincipal != NULL) 1163 free(gd->gd_clntprincipal, M_RPC); 1164 if (gd->gd_verf.value) 1165 xdr_free((xdrproc_t) xdr_gss_buffer_desc, 1166 (char *) &gd->gd_verf); 1167 mtx_destroy(&gd->gd_lock); 1168 1169 mem_free(gd, sizeof(*gd)); 1170 mem_free(auth, sizeof(*auth)); 1171 } 1172 1173 int 1174 rpc_gss_max_data_length(AUTH *auth, int max_tp_unit_len) 1175 { 1176 struct rpc_gss_data *gd; 1177 int want_conf; 1178 OM_uint32 max; 1179 OM_uint32 maj_stat, min_stat; 1180 int result; 1181 1182 gd = AUTH_PRIVATE(auth); 1183 1184 switch (gd->gd_cred.gc_svc) { 1185 case rpc_gss_svc_none: 1186 return (max_tp_unit_len); 1187 break; 1188 1189 case rpc_gss_svc_default: 1190 case rpc_gss_svc_integrity: 1191 want_conf = FALSE; 1192 break; 1193 1194 case rpc_gss_svc_privacy: 1195 want_conf = TRUE; 1196 break; 1197 1198 default: 1199 return (0); 1200 } 1201 1202 maj_stat = gss_wrap_size_limit(&min_stat, gd->gd_ctx, want_conf, 1203 gd->gd_qop, max_tp_unit_len, &max); 1204 1205 if (maj_stat == GSS_S_COMPLETE) { 1206 result = (int) max; 1207 if (result < 0) 1208 result = 0; 1209 return (result); 1210 } else { 1211 rpc_gss_log_status("gss_wrap_size_limit", gd->gd_mech, 1212 maj_stat, min_stat); 1213 return (0); 1214 } 1215 } 1216