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