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