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 rpc_gss_options_ret_t options; 197 198 if (rpc_gss_count > RPC_GSS_MAX) { 199 while (rpc_gss_count > RPC_GSS_MAX) { 200 sx_xlock(&rpc_gss_lock); 201 tgd = TAILQ_FIRST(&rpc_gss_all); 202 th = tgd->gd_hash; 203 TAILQ_REMOVE(&rpc_gss_cache[th], tgd, gd_link); 204 TAILQ_REMOVE(&rpc_gss_all, tgd, gd_alllink); 205 rpc_gss_count--; 206 sx_xunlock(&rpc_gss_lock); 207 AUTH_DESTROY(tgd->gd_auth); 208 } 209 } 210 211 /* 212 * See if we already have an AUTH which matches. 213 */ 214 h = rpc_gss_hash(principal, mech_oid, cred, service); 215 216 again: 217 sx_slock(&rpc_gss_lock); 218 TAILQ_FOREACH(gd, &rpc_gss_cache[h], gd_link) { 219 if (gd->gd_ucred->cr_uid == cred->cr_uid 220 && !strcmp(gd->gd_principal, principal) 221 && gd->gd_mech == mech_oid 222 && gd->gd_cred.gc_svc == service) { 223 refcount_acquire(&gd->gd_refs); 224 if (sx_try_upgrade(&rpc_gss_lock)) { 225 /* 226 * Keep rpc_gss_all LRU sorted. 227 */ 228 TAILQ_REMOVE(&rpc_gss_all, gd, gd_alllink); 229 TAILQ_INSERT_TAIL(&rpc_gss_all, gd, 230 gd_alllink); 231 sx_xunlock(&rpc_gss_lock); 232 } else { 233 sx_sunlock(&rpc_gss_lock); 234 } 235 236 /* 237 * If the state != ESTABLISHED, try and initialize 238 * the authenticator again. This will happen if the 239 * user's credentials have expired. It may succeed now, 240 * if they have done a kinit or similar. 241 */ 242 if (gd->gd_state != RPCSEC_GSS_ESTABLISHED) { 243 memset(&options, 0, sizeof (options)); 244 (void) rpc_gss_init(gd->gd_auth, &options); 245 } 246 return (gd->gd_auth); 247 } 248 } 249 sx_sunlock(&rpc_gss_lock); 250 251 /* 252 * We missed in the cache - create a new association. 253 */ 254 auth = rpc_gss_seccreate_int(clnt, cred, principal, mech_oid, service, 255 GSS_C_QOP_DEFAULT, NULL, NULL); 256 if (!auth) 257 return (NULL); 258 259 gd = AUTH_PRIVATE(auth); 260 gd->gd_hash = h; 261 262 sx_xlock(&rpc_gss_lock); 263 TAILQ_FOREACH(tgd, &rpc_gss_cache[h], gd_link) { 264 if (tgd->gd_ucred->cr_uid == cred->cr_uid 265 && !strcmp(tgd->gd_principal, principal) 266 && tgd->gd_mech == mech_oid 267 && tgd->gd_cred.gc_svc == service) { 268 /* 269 * We lost a race to create the AUTH that 270 * matches this cred. 271 */ 272 sx_xunlock(&rpc_gss_lock); 273 AUTH_DESTROY(auth); 274 goto again; 275 } 276 } 277 278 rpc_gss_count++; 279 TAILQ_INSERT_TAIL(&rpc_gss_cache[h], gd, gd_link); 280 TAILQ_INSERT_TAIL(&rpc_gss_all, gd, gd_alllink); 281 refcount_acquire(&gd->gd_refs); /* one for the cache, one for user */ 282 sx_xunlock(&rpc_gss_lock); 283 284 return (auth); 285 } 286 287 void 288 rpc_gss_secpurge(CLIENT *clnt) 289 { 290 uint32_t h; 291 struct rpc_gss_data *gd, *tgd; 292 293 TAILQ_FOREACH_SAFE(gd, &rpc_gss_all, gd_alllink, tgd) { 294 if (gd->gd_clnt == clnt) { 295 sx_xlock(&rpc_gss_lock); 296 h = gd->gd_hash; 297 TAILQ_REMOVE(&rpc_gss_cache[h], gd, gd_link); 298 TAILQ_REMOVE(&rpc_gss_all, gd, gd_alllink); 299 rpc_gss_count--; 300 sx_xunlock(&rpc_gss_lock); 301 AUTH_DESTROY(gd->gd_auth); 302 } 303 } 304 } 305 306 AUTH * 307 rpc_gss_seccreate(CLIENT *clnt, struct ucred *cred, const char *principal, 308 const char *mechanism, rpc_gss_service_t service, const char *qop, 309 rpc_gss_options_req_t *options_req, rpc_gss_options_ret_t *options_ret) 310 { 311 gss_OID oid; 312 u_int qop_num; 313 314 /* 315 * Bail out now if we don't know this mechanism. 316 */ 317 if (!rpc_gss_mech_to_oid(mechanism, &oid)) 318 return (NULL); 319 320 if (qop) { 321 if (!rpc_gss_qop_to_num(qop, mechanism, &qop_num)) 322 return (NULL); 323 } else { 324 qop_num = GSS_C_QOP_DEFAULT; 325 } 326 327 return (rpc_gss_seccreate_int(clnt, cred, principal, oid, service, 328 qop_num, options_req, options_ret)); 329 } 330 331 static AUTH * 332 rpc_gss_seccreate_int(CLIENT *clnt, struct ucred *cred, const char *principal, 333 gss_OID mech_oid, rpc_gss_service_t service, u_int qop_num, 334 rpc_gss_options_req_t *options_req, rpc_gss_options_ret_t *options_ret) 335 { 336 AUTH *auth; 337 rpc_gss_options_ret_t options; 338 struct rpc_gss_data *gd; 339 340 /* 341 * If the caller doesn't want the options, point at local 342 * storage to simplify the code below. 343 */ 344 if (!options_ret) 345 options_ret = &options; 346 347 /* 348 * Default service is integrity. 349 */ 350 if (service == rpc_gss_svc_default) 351 service = rpc_gss_svc_integrity; 352 353 memset(options_ret, 0, sizeof(*options_ret)); 354 355 rpc_gss_log_debug("in rpc_gss_seccreate()"); 356 357 memset(&rpc_createerr, 0, sizeof(rpc_createerr)); 358 359 auth = mem_alloc(sizeof(*auth)); 360 if (auth == NULL) { 361 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 362 rpc_createerr.cf_error.re_errno = ENOMEM; 363 return (NULL); 364 } 365 gd = mem_alloc(sizeof(*gd)); 366 if (gd == NULL) { 367 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 368 rpc_createerr.cf_error.re_errno = ENOMEM; 369 mem_free(auth, sizeof(*auth)); 370 return (NULL); 371 } 372 373 auth->ah_ops = &rpc_gss_ops; 374 auth->ah_private = (caddr_t) gd; 375 auth->ah_cred.oa_flavor = RPCSEC_GSS; 376 377 refcount_init(&gd->gd_refs, 1); 378 mtx_init(&gd->gd_lock, "gd->gd_lock", NULL, MTX_DEF); 379 gd->gd_auth = auth; 380 gd->gd_ucred = crdup(cred); 381 gd->gd_principal = strdup(principal, M_RPC); 382 383 384 if (options_req) { 385 gd->gd_options = *options_req; 386 } else { 387 gd->gd_options.req_flags = GSS_C_MUTUAL_FLAG; 388 gd->gd_options.time_req = 0; 389 gd->gd_options.my_cred = GSS_C_NO_CREDENTIAL; 390 gd->gd_options.input_channel_bindings = NULL; 391 } 392 CLNT_ACQUIRE(clnt); 393 gd->gd_clnt = clnt; 394 gd->gd_ctx = GSS_C_NO_CONTEXT; 395 gd->gd_mech = mech_oid; 396 gd->gd_qop = qop_num; 397 398 gd->gd_cred.gc_version = RPCSEC_GSS_VERSION; 399 gd->gd_cred.gc_proc = RPCSEC_GSS_INIT; 400 gd->gd_cred.gc_seq = 0; 401 gd->gd_cred.gc_svc = service; 402 LIST_INIT(&gd->gd_reqs); 403 404 if (!rpc_gss_init(auth, options_ret)) { 405 goto bad; 406 } 407 408 return (auth); 409 410 bad: 411 AUTH_DESTROY(auth); 412 return (NULL); 413 } 414 415 bool_t 416 rpc_gss_set_defaults(AUTH *auth, rpc_gss_service_t service, const char *qop) 417 { 418 struct rpc_gss_data *gd; 419 u_int qop_num; 420 const char *mechanism; 421 422 gd = AUTH_PRIVATE(auth); 423 if (!rpc_gss_oid_to_mech(gd->gd_mech, &mechanism)) { 424 return (FALSE); 425 } 426 427 if (qop) { 428 if (!rpc_gss_qop_to_num(qop, mechanism, &qop_num)) { 429 return (FALSE); 430 } 431 } else { 432 qop_num = GSS_C_QOP_DEFAULT; 433 } 434 435 gd->gd_cred.gc_svc = service; 436 gd->gd_qop = qop_num; 437 return (TRUE); 438 } 439 440 static void 441 rpc_gss_purge_xid(struct rpc_gss_data *gd, uint32_t xid) 442 { 443 struct rpc_pending_request *pr, *npr; 444 struct rpc_pending_request_list reqs; 445 446 LIST_INIT(&reqs); 447 mtx_lock(&gd->gd_lock); 448 LIST_FOREACH_SAFE(pr, &gd->gd_reqs, pr_link, npr) { 449 if (pr->pr_xid == xid) { 450 LIST_REMOVE(pr, pr_link); 451 LIST_INSERT_HEAD(&reqs, pr, pr_link); 452 } 453 } 454 455 mtx_unlock(&gd->gd_lock); 456 457 LIST_FOREACH_SAFE(pr, &reqs, pr_link, npr) { 458 mem_free(pr, sizeof(*pr)); 459 } 460 } 461 462 static uint32_t 463 rpc_gss_alloc_seq(struct rpc_gss_data *gd) 464 { 465 uint32_t seq; 466 467 mtx_lock(&gd->gd_lock); 468 seq = gd->gd_seq; 469 gd->gd_seq++; 470 mtx_unlock(&gd->gd_lock); 471 472 return (seq); 473 } 474 475 static void 476 rpc_gss_nextverf(__unused AUTH *auth) 477 { 478 479 /* not used */ 480 } 481 482 static bool_t 483 rpc_gss_marshal(AUTH *auth, uint32_t xid, XDR *xdrs, struct mbuf *args) 484 { 485 struct rpc_gss_data *gd; 486 struct rpc_pending_request *pr; 487 uint32_t seq; 488 XDR tmpxdrs; 489 struct rpc_gss_cred gsscred; 490 char credbuf[MAX_AUTH_BYTES]; 491 struct opaque_auth creds, verf; 492 gss_buffer_desc rpcbuf, checksum; 493 OM_uint32 maj_stat, min_stat; 494 bool_t xdr_stat; 495 496 rpc_gss_log_debug("in rpc_gss_marshal()"); 497 498 gd = AUTH_PRIVATE(auth); 499 500 gsscred = gd->gd_cred; 501 seq = rpc_gss_alloc_seq(gd); 502 gsscred.gc_seq = seq; 503 504 xdrmem_create(&tmpxdrs, credbuf, sizeof(credbuf), XDR_ENCODE); 505 if (!xdr_rpc_gss_cred(&tmpxdrs, &gsscred)) { 506 XDR_DESTROY(&tmpxdrs); 507 _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM); 508 return (FALSE); 509 } 510 creds.oa_flavor = RPCSEC_GSS; 511 creds.oa_base = credbuf; 512 creds.oa_length = XDR_GETPOS(&tmpxdrs); 513 XDR_DESTROY(&tmpxdrs); 514 515 xdr_opaque_auth(xdrs, &creds); 516 517 if (gd->gd_cred.gc_proc == RPCSEC_GSS_INIT || 518 gd->gd_cred.gc_proc == RPCSEC_GSS_CONTINUE_INIT) { 519 if (!xdr_opaque_auth(xdrs, &_null_auth)) { 520 _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM); 521 return (FALSE); 522 } 523 xdrmbuf_append(xdrs, args); 524 return (TRUE); 525 } else { 526 /* 527 * Keep track of this XID + seq pair so that we can do 528 * the matching gss_verify_mic in AUTH_VALIDATE. 529 */ 530 pr = mem_alloc(sizeof(struct rpc_pending_request)); 531 mtx_lock(&gd->gd_lock); 532 pr->pr_xid = xid; 533 pr->pr_seq = seq; 534 LIST_INSERT_HEAD(&gd->gd_reqs, pr, pr_link); 535 mtx_unlock(&gd->gd_lock); 536 537 /* 538 * Checksum serialized RPC header, up to and including 539 * credential. For the in-kernel environment, we 540 * assume that our XDR stream is on a contiguous 541 * memory buffer (e.g. an mbuf). 542 */ 543 rpcbuf.length = XDR_GETPOS(xdrs); 544 XDR_SETPOS(xdrs, 0); 545 rpcbuf.value = XDR_INLINE(xdrs, rpcbuf.length); 546 547 maj_stat = gss_get_mic(&min_stat, gd->gd_ctx, gd->gd_qop, 548 &rpcbuf, &checksum); 549 550 if (maj_stat != GSS_S_COMPLETE) { 551 rpc_gss_log_status("gss_get_mic", gd->gd_mech, 552 maj_stat, min_stat); 553 if (maj_stat == GSS_S_CONTEXT_EXPIRED) { 554 rpc_gss_destroy_context(auth, TRUE); 555 } 556 _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, EPERM); 557 return (FALSE); 558 } 559 560 verf.oa_flavor = RPCSEC_GSS; 561 verf.oa_base = checksum.value; 562 verf.oa_length = checksum.length; 563 564 xdr_stat = xdr_opaque_auth(xdrs, &verf); 565 gss_release_buffer(&min_stat, &checksum); 566 if (!xdr_stat) { 567 _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM); 568 return (FALSE); 569 } 570 if (gd->gd_state != RPCSEC_GSS_ESTABLISHED || 571 gd->gd_cred.gc_svc == rpc_gss_svc_none) { 572 xdrmbuf_append(xdrs, args); 573 return (TRUE); 574 } else { 575 if (!xdr_rpc_gss_wrap_data(&args, 576 gd->gd_ctx, gd->gd_qop, gd->gd_cred.gc_svc, 577 seq)) 578 return (FALSE); 579 xdrmbuf_append(xdrs, args); 580 return (TRUE); 581 } 582 } 583 584 return (TRUE); 585 } 586 587 static bool_t 588 rpc_gss_validate(AUTH *auth, uint32_t xid, struct opaque_auth *verf, 589 struct mbuf **resultsp) 590 { 591 struct rpc_gss_data *gd; 592 struct rpc_pending_request *pr, *npr; 593 struct rpc_pending_request_list reqs; 594 gss_qop_t qop_state; 595 uint32_t num, seq; 596 gss_buffer_desc signbuf, checksum; 597 OM_uint32 maj_stat, min_stat; 598 599 rpc_gss_log_debug("in rpc_gss_validate()"); 600 601 gd = AUTH_PRIVATE(auth); 602 603 /* 604 * The client will call us with a NULL verf when it gives up 605 * on an XID. 606 */ 607 if (!verf) { 608 rpc_gss_purge_xid(gd, xid); 609 return (TRUE); 610 } 611 612 if (gd->gd_state == RPCSEC_GSS_CONTEXT) { 613 /* 614 * Save the on the wire verifier to validate last INIT 615 * phase packet after decode if the major status is 616 * GSS_S_COMPLETE. 617 */ 618 if (gd->gd_verf.value) 619 xdr_free((xdrproc_t) xdr_gss_buffer_desc, 620 (char *) &gd->gd_verf); 621 gd->gd_verf.value = mem_alloc(verf->oa_length); 622 if (gd->gd_verf.value == NULL) { 623 printf("gss_validate: out of memory\n"); 624 _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM); 625 m_freem(*resultsp); 626 *resultsp = NULL; 627 return (FALSE); 628 } 629 memcpy(gd->gd_verf.value, verf->oa_base, verf->oa_length); 630 gd->gd_verf.length = verf->oa_length; 631 632 return (TRUE); 633 } 634 635 /* 636 * We need to check the verifier against all the requests 637 * we've send for this XID - for unreliable protocols, we 638 * retransmit with the same XID but different sequence 639 * number. We temporarily take this set of requests out of the 640 * list so that we can work through the list without having to 641 * hold the lock. 642 */ 643 mtx_lock(&gd->gd_lock); 644 LIST_INIT(&reqs); 645 LIST_FOREACH_SAFE(pr, &gd->gd_reqs, pr_link, npr) { 646 if (pr->pr_xid == xid) { 647 LIST_REMOVE(pr, pr_link); 648 LIST_INSERT_HEAD(&reqs, pr, pr_link); 649 } 650 } 651 mtx_unlock(&gd->gd_lock); 652 LIST_FOREACH(pr, &reqs, pr_link) { 653 if (pr->pr_xid == xid) { 654 seq = pr->pr_seq; 655 num = htonl(seq); 656 signbuf.value = # 657 signbuf.length = sizeof(num); 658 659 checksum.value = verf->oa_base; 660 checksum.length = verf->oa_length; 661 662 maj_stat = gss_verify_mic(&min_stat, gd->gd_ctx, 663 &signbuf, &checksum, &qop_state); 664 if (maj_stat != GSS_S_COMPLETE 665 || qop_state != gd->gd_qop) { 666 continue; 667 } 668 if (maj_stat == GSS_S_CONTEXT_EXPIRED) { 669 rpc_gss_destroy_context(auth, TRUE); 670 break; 671 } 672 //rpc_gss_purge_reqs(gd, seq); 673 LIST_FOREACH_SAFE(pr, &reqs, pr_link, npr) 674 mem_free(pr, sizeof(*pr)); 675 676 if (gd->gd_cred.gc_svc == rpc_gss_svc_none) { 677 return (TRUE); 678 } else { 679 if (!xdr_rpc_gss_unwrap_data(resultsp, 680 gd->gd_ctx, gd->gd_qop, 681 gd->gd_cred.gc_svc, seq)) { 682 return (FALSE); 683 } 684 } 685 return (TRUE); 686 } 687 } 688 689 /* 690 * We didn't match - put back any entries for this XID so that 691 * a future call to validate can retry. 692 */ 693 mtx_lock(&gd->gd_lock); 694 LIST_FOREACH_SAFE(pr, &reqs, pr_link, npr) { 695 LIST_REMOVE(pr, pr_link); 696 LIST_INSERT_HEAD(&gd->gd_reqs, pr, pr_link); 697 } 698 mtx_unlock(&gd->gd_lock); 699 700 /* 701 * Nothing matches - give up. 702 */ 703 _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, EPERM); 704 m_freem(*resultsp); 705 *resultsp = NULL; 706 return (FALSE); 707 } 708 709 static bool_t 710 rpc_gss_init(AUTH *auth, rpc_gss_options_ret_t *options_ret) 711 { 712 struct thread *td = curthread; 713 struct ucred *crsave; 714 struct rpc_gss_data *gd; 715 struct rpc_gss_init_res gr; 716 gss_buffer_desc principal_desc; 717 gss_buffer_desc *recv_tokenp, recv_token, send_token; 718 gss_name_t name; 719 OM_uint32 maj_stat, min_stat, call_stat; 720 const char *mech; 721 struct rpc_callextra ext; 722 723 rpc_gss_log_debug("in rpc_gss_refresh()"); 724 725 gd = AUTH_PRIVATE(auth); 726 727 mtx_lock(&gd->gd_lock); 728 /* 729 * If the context isn't in START state, someone else is 730 * refreshing - we wait till they are done. If they fail, they 731 * will put the state back to START and we can try (most 732 * likely to also fail). 733 */ 734 while (gd->gd_state != RPCSEC_GSS_START 735 && gd->gd_state != RPCSEC_GSS_ESTABLISHED) { 736 msleep(gd, &gd->gd_lock, 0, "gssstate", 0); 737 } 738 if (gd->gd_state == RPCSEC_GSS_ESTABLISHED) { 739 mtx_unlock(&gd->gd_lock); 740 return (TRUE); 741 } 742 gd->gd_state = RPCSEC_GSS_CONTEXT; 743 mtx_unlock(&gd->gd_lock); 744 745 gd->gd_cred.gc_proc = RPCSEC_GSS_INIT; 746 gd->gd_cred.gc_seq = 0; 747 748 principal_desc.value = (void *)gd->gd_principal; 749 principal_desc.length = strlen(gd->gd_principal); 750 maj_stat = gss_import_name(&min_stat, &principal_desc, 751 GSS_C_NT_HOSTBASED_SERVICE, &name); 752 if (maj_stat != GSS_S_COMPLETE) { 753 options_ret->major_status = maj_stat; 754 options_ret->minor_status = min_stat; 755 goto out; 756 } 757 758 /* GSS context establishment loop. */ 759 memset(&recv_token, 0, sizeof(recv_token)); 760 memset(&gr, 0, sizeof(gr)); 761 memset(options_ret, 0, sizeof(*options_ret)); 762 options_ret->major_status = GSS_S_FAILURE; 763 recv_tokenp = GSS_C_NO_BUFFER; 764 765 for (;;) { 766 crsave = td->td_ucred; 767 td->td_ucred = gd->gd_ucred; 768 maj_stat = gss_init_sec_context(&min_stat, 769 gd->gd_options.my_cred, 770 &gd->gd_ctx, 771 name, 772 gd->gd_mech, 773 gd->gd_options.req_flags, 774 gd->gd_options.time_req, 775 gd->gd_options.input_channel_bindings, 776 recv_tokenp, 777 &gd->gd_mech, /* used mech */ 778 &send_token, 779 &options_ret->ret_flags, 780 &options_ret->time_req); 781 td->td_ucred = crsave; 782 783 /* 784 * Free the token which we got from the server (if 785 * any). Remember that this was allocated by XDR, not 786 * GSS-API. 787 */ 788 if (recv_tokenp != GSS_C_NO_BUFFER) { 789 xdr_free((xdrproc_t) xdr_gss_buffer_desc, 790 (char *) &recv_token); 791 recv_tokenp = GSS_C_NO_BUFFER; 792 } 793 if (gd->gd_mech && rpc_gss_oid_to_mech(gd->gd_mech, &mech)) { 794 strlcpy(options_ret->actual_mechanism, 795 mech, 796 sizeof(options_ret->actual_mechanism)); 797 } 798 if (maj_stat != GSS_S_COMPLETE && 799 maj_stat != GSS_S_CONTINUE_NEEDED) { 800 rpc_gss_log_status("gss_init_sec_context", gd->gd_mech, 801 maj_stat, min_stat); 802 options_ret->major_status = maj_stat; 803 options_ret->minor_status = min_stat; 804 break; 805 } 806 if (send_token.length != 0) { 807 memset(&gr, 0, sizeof(gr)); 808 809 bzero(&ext, sizeof(ext)); 810 ext.rc_auth = auth; 811 call_stat = CLNT_CALL_EXT(gd->gd_clnt, &ext, NULLPROC, 812 (xdrproc_t)xdr_gss_buffer_desc, 813 &send_token, 814 (xdrproc_t)xdr_rpc_gss_init_res, 815 (caddr_t)&gr, AUTH_TIMEOUT); 816 817 gss_release_buffer(&min_stat, &send_token); 818 819 if (call_stat != RPC_SUCCESS) 820 break; 821 822 if (gr.gr_major != GSS_S_COMPLETE && 823 gr.gr_major != GSS_S_CONTINUE_NEEDED) { 824 rpc_gss_log_status("server reply", gd->gd_mech, 825 gr.gr_major, gr.gr_minor); 826 options_ret->major_status = gr.gr_major; 827 options_ret->minor_status = gr.gr_minor; 828 break; 829 } 830 831 /* 832 * Save the server's gr_handle value, freeing 833 * what we have already (remember that this 834 * was allocated by XDR, not GSS-API). 835 */ 836 if (gr.gr_handle.length != 0) { 837 xdr_free((xdrproc_t) xdr_gss_buffer_desc, 838 (char *) &gd->gd_cred.gc_handle); 839 gd->gd_cred.gc_handle = gr.gr_handle; 840 } 841 842 /* 843 * Save the server's token as well. 844 */ 845 if (gr.gr_token.length != 0) { 846 recv_token = gr.gr_token; 847 recv_tokenp = &recv_token; 848 } 849 850 /* 851 * Since we have copied out all the bits of gr 852 * which XDR allocated for us, we don't need 853 * to free it. 854 */ 855 gd->gd_cred.gc_proc = RPCSEC_GSS_CONTINUE_INIT; 856 } 857 858 if (maj_stat == GSS_S_COMPLETE) { 859 gss_buffer_desc bufin; 860 u_int seq, qop_state = 0; 861 862 /* 863 * gss header verifier, 864 * usually checked in gss_validate 865 */ 866 seq = htonl(gr.gr_win); 867 bufin.value = (unsigned char *)&seq; 868 bufin.length = sizeof(seq); 869 870 maj_stat = gss_verify_mic(&min_stat, gd->gd_ctx, 871 &bufin, &gd->gd_verf, &qop_state); 872 873 if (maj_stat != GSS_S_COMPLETE || 874 qop_state != gd->gd_qop) { 875 rpc_gss_log_status("gss_verify_mic", gd->gd_mech, 876 maj_stat, min_stat); 877 if (maj_stat == GSS_S_CONTEXT_EXPIRED) { 878 rpc_gss_destroy_context(auth, TRUE); 879 } 880 _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, 881 EPERM); 882 options_ret->major_status = maj_stat; 883 options_ret->minor_status = min_stat; 884 break; 885 } 886 887 options_ret->major_status = GSS_S_COMPLETE; 888 options_ret->minor_status = 0; 889 options_ret->rpcsec_version = gd->gd_cred.gc_version; 890 options_ret->gss_context = gd->gd_ctx; 891 892 gd->gd_cred.gc_proc = RPCSEC_GSS_DATA; 893 gd->gd_seq = 1; 894 gd->gd_win = gr.gr_win; 895 break; 896 } 897 } 898 899 gss_release_name(&min_stat, &name); 900 xdr_free((xdrproc_t) xdr_gss_buffer_desc, 901 (char *) &gd->gd_verf); 902 903 out: 904 /* End context negotiation loop. */ 905 if (gd->gd_cred.gc_proc != RPCSEC_GSS_DATA) { 906 rpc_createerr.cf_stat = RPC_AUTHERROR; 907 _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, EPERM); 908 if (gd->gd_ctx) { 909 gss_delete_sec_context(&min_stat, &gd->gd_ctx, 910 GSS_C_NO_BUFFER); 911 } 912 mtx_lock(&gd->gd_lock); 913 gd->gd_state = RPCSEC_GSS_START; 914 wakeup(gd); 915 mtx_unlock(&gd->gd_lock); 916 return (FALSE); 917 } 918 919 mtx_lock(&gd->gd_lock); 920 gd->gd_state = RPCSEC_GSS_ESTABLISHED; 921 wakeup(gd); 922 mtx_unlock(&gd->gd_lock); 923 924 return (TRUE); 925 } 926 927 static bool_t 928 rpc_gss_refresh(AUTH *auth, void *msg) 929 { 930 struct rpc_msg *reply = (struct rpc_msg *) msg; 931 rpc_gss_options_ret_t options; 932 struct rpc_gss_data *gd; 933 934 gd = AUTH_PRIVATE(auth); 935 936 /* 937 * If the context is in DESTROYING state, then just return, since 938 * there is no point in refreshing the credentials. 939 */ 940 mtx_lock(&gd->gd_lock); 941 if (gd->gd_state == RPCSEC_GSS_DESTROYING) { 942 mtx_unlock(&gd->gd_lock); 943 return (FALSE); 944 } 945 mtx_unlock(&gd->gd_lock); 946 947 /* 948 * If the error was RPCSEC_GSS_CREDPROBLEM of 949 * RPCSEC_GSS_CTXPROBLEM we start again from scratch. All 950 * other errors are fatal. 951 */ 952 if (reply->rm_reply.rp_stat == MSG_DENIED 953 && reply->rm_reply.rp_rjct.rj_stat == AUTH_ERROR 954 && (reply->rm_reply.rp_rjct.rj_why == RPCSEC_GSS_CREDPROBLEM 955 || reply->rm_reply.rp_rjct.rj_why == RPCSEC_GSS_CTXPROBLEM)) { 956 rpc_gss_destroy_context(auth, FALSE); 957 memset(&options, 0, sizeof(options)); 958 return (rpc_gss_init(auth, &options)); 959 } 960 961 return (FALSE); 962 } 963 964 static void 965 rpc_gss_destroy_context(AUTH *auth, bool_t send_destroy) 966 { 967 struct rpc_gss_data *gd; 968 struct rpc_pending_request *pr; 969 OM_uint32 min_stat; 970 struct rpc_callextra ext; 971 972 rpc_gss_log_debug("in rpc_gss_destroy_context()"); 973 974 gd = AUTH_PRIVATE(auth); 975 976 mtx_lock(&gd->gd_lock); 977 /* 978 * If the context isn't in ESTABISHED state, someone else is 979 * destroying/refreshing - we wait till they are done. 980 */ 981 if (gd->gd_state != RPCSEC_GSS_ESTABLISHED) { 982 while (gd->gd_state != RPCSEC_GSS_START 983 && gd->gd_state != RPCSEC_GSS_ESTABLISHED) 984 msleep(gd, &gd->gd_lock, 0, "gssstate", 0); 985 mtx_unlock(&gd->gd_lock); 986 return; 987 } 988 gd->gd_state = RPCSEC_GSS_DESTROYING; 989 mtx_unlock(&gd->gd_lock); 990 991 if (send_destroy) { 992 gd->gd_cred.gc_proc = RPCSEC_GSS_DESTROY; 993 bzero(&ext, sizeof(ext)); 994 ext.rc_auth = auth; 995 CLNT_CALL_EXT(gd->gd_clnt, &ext, NULLPROC, 996 (xdrproc_t)xdr_void, NULL, 997 (xdrproc_t)xdr_void, NULL, AUTH_TIMEOUT); 998 } 999 1000 while ((pr = LIST_FIRST(&gd->gd_reqs)) != NULL) { 1001 LIST_REMOVE(pr, pr_link); 1002 mem_free(pr, sizeof(*pr)); 1003 } 1004 1005 /* 1006 * Free the context token. Remember that this was 1007 * allocated by XDR, not GSS-API. 1008 */ 1009 xdr_free((xdrproc_t) xdr_gss_buffer_desc, 1010 (char *) &gd->gd_cred.gc_handle); 1011 gd->gd_cred.gc_handle.length = 0; 1012 1013 if (gd->gd_ctx != GSS_C_NO_CONTEXT) 1014 gss_delete_sec_context(&min_stat, &gd->gd_ctx, NULL); 1015 1016 mtx_lock(&gd->gd_lock); 1017 gd->gd_state = RPCSEC_GSS_START; 1018 wakeup(gd); 1019 mtx_unlock(&gd->gd_lock); 1020 } 1021 1022 static void 1023 rpc_gss_destroy(AUTH *auth) 1024 { 1025 struct rpc_gss_data *gd; 1026 1027 rpc_gss_log_debug("in rpc_gss_destroy()"); 1028 1029 gd = AUTH_PRIVATE(auth); 1030 1031 if (!refcount_release(&gd->gd_refs)) 1032 return; 1033 1034 rpc_gss_destroy_context(auth, TRUE); 1035 1036 CLNT_RELEASE(gd->gd_clnt); 1037 crfree(gd->gd_ucred); 1038 free(gd->gd_principal, M_RPC); 1039 if (gd->gd_verf.value) 1040 xdr_free((xdrproc_t) xdr_gss_buffer_desc, 1041 (char *) &gd->gd_verf); 1042 mtx_destroy(&gd->gd_lock); 1043 1044 mem_free(gd, sizeof(*gd)); 1045 mem_free(auth, sizeof(*auth)); 1046 } 1047 1048 int 1049 rpc_gss_max_data_length(AUTH *auth, int max_tp_unit_len) 1050 { 1051 struct rpc_gss_data *gd; 1052 int want_conf; 1053 OM_uint32 max; 1054 OM_uint32 maj_stat, min_stat; 1055 int result; 1056 1057 gd = AUTH_PRIVATE(auth); 1058 1059 switch (gd->gd_cred.gc_svc) { 1060 case rpc_gss_svc_none: 1061 return (max_tp_unit_len); 1062 break; 1063 1064 case rpc_gss_svc_default: 1065 case rpc_gss_svc_integrity: 1066 want_conf = FALSE; 1067 break; 1068 1069 case rpc_gss_svc_privacy: 1070 want_conf = TRUE; 1071 break; 1072 1073 default: 1074 return (0); 1075 } 1076 1077 maj_stat = gss_wrap_size_limit(&min_stat, gd->gd_ctx, want_conf, 1078 gd->gd_qop, max_tp_unit_len, &max); 1079 1080 if (maj_stat == GSS_S_COMPLETE) { 1081 result = (int) max; 1082 if (result < 0) 1083 result = 0; 1084 return (result); 1085 } else { 1086 rpc_gss_log_status("gss_wrap_size_limit", gd->gd_mech, 1087 maj_stat, min_stat); 1088 return (0); 1089 } 1090 } 1091