1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. 31 * 32 * $Id: svc_auth_gssapi.c,v 1.19 1994/10/27 12:38:51 jik Exp $ 33 */ 34 35 /* 36 * Server side handling of RPCSEC_GSS flavor. 37 */ 38 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <strings.h> 42 #include <sys/stat.h> 43 #include <sys/time.h> 44 #include <gssapi/gssapi.h> 45 #include <gssapi/gssapi_ext.h> 46 #include <rpc/rpc.h> 47 #include <rpc/rpcsec_defs.h> 48 #include <sys/file.h> 49 #include <fcntl.h> 50 #include <pwd.h> 51 #include <stdio.h> 52 #include <syslog.h> 53 54 /* 55 * Sequence window definitions. 56 */ 57 #define SEQ_ARR_SIZE 4 58 #define SEQ_WIN (SEQ_ARR_SIZE*32) 59 #define SEQ_HI_BIT 0x80000000 60 #define SEQ_LO_BIT 1 61 #define DIV_BY_32 5 62 #define SEQ_MASK 0x1f 63 #define SEQ_MAX 0x80000000 64 65 66 /* cache retransmit data */ 67 typedef struct _retrans_entry { 68 uint32_t xid; 69 rpc_gss_init_res result; 70 struct _retrans_entry *next, *prev; 71 } retrans_entry; 72 73 /* 74 * Server side RPCSEC_GSS context information. 75 */ 76 typedef struct _svc_rpc_gss_data { 77 struct _svc_rpc_gss_data *next, *prev; 78 struct _svc_rpc_gss_data *lru_next, *lru_prev; 79 bool_t established; 80 gss_ctx_id_t context; 81 gss_name_t client_name; 82 gss_cred_id_t server_creds; 83 uint_t expiration; 84 uint_t seq_num; 85 uint_t seq_bits[SEQ_ARR_SIZE]; 86 uint_t key; 87 OM_uint32 qop; 88 bool_t done_docallback; 89 bool_t locked; 90 rpc_gss_rawcred_t raw_cred; 91 rpc_gss_ucred_t u_cred; 92 bool_t u_cred_set; 93 void *cookie; 94 gss_cred_id_t deleg; 95 mutex_t clm; 96 int ref_cnt; 97 bool_t stale; 98 time_t time_secs_set; 99 retrans_entry *retrans_data; 100 } svc_rpc_gss_data; 101 102 /* 103 * Data structures used for LRU based context management. 104 */ 105 #define HASHMOD 256 106 #define HASHMASK 255 107 108 static svc_rpc_gss_data *clients[HASHMOD]; 109 static svc_rpc_gss_data *lru_first, *lru_last; 110 static int num_gss_contexts = 0; 111 static int max_gss_contexts = 128; 112 static int sweep_interval = 10; 113 static int last_swept = 0; 114 static uint_t max_lifetime = GSS_C_INDEFINITE; 115 static int init_lifetime = 300; 116 static uint_t gid_timeout = 43200; /* 43200 secs = 12 hours */ 117 118 /* 119 * lock used with context/lru variables 120 */ 121 static mutex_t ctx_mutex = DEFAULTMUTEX; 122 123 /* 124 * server credential management data and structures 125 */ 126 typedef struct svc_creds_list_s { 127 struct svc_creds_list_s *next; 128 gss_cred_id_t cred; 129 gss_name_t name; 130 rpcprog_t program; 131 rpcvers_t version; 132 gss_OID_set oid_set; 133 OM_uint32 req_time; 134 char *server_name; 135 mutex_t refresh_mutex; 136 } svc_creds_list_t; 137 138 139 static svc_creds_list_t *svc_creds_list; 140 static int svc_creds_count = 0; 141 142 /* 143 * lock used with server credential variables list 144 * 145 * server cred list locking guidelines: 146 * - Writer's lock holder has exclusive access to the list 147 * - Reader's lock holder(s) must also lock (refresh_mutex) each node 148 * before accessing that node's elements (ie. cred) 149 */ 150 static rwlock_t cred_lock = DEFAULTRWLOCK; 151 152 /* 153 * server callback list 154 */ 155 typedef struct cblist_s { 156 struct cblist_s *next; 157 rpc_gss_callback_t cb; 158 } cblist_t; 159 160 cblist_t *cblist = NULL; 161 162 /* 163 * lock used with callback variables 164 */ 165 static mutex_t cb_mutex = DEFAULTMUTEX; 166 167 /* 168 * forward declarations 169 */ 170 static bool_t svc_rpc_gss_wrap(); 171 static bool_t svc_rpc_gss_unwrap(); 172 static svc_rpc_gss_data *create_client(); 173 static svc_rpc_gss_data *get_client(); 174 static svc_rpc_gss_data *find_client(); 175 static void destroy_client(); 176 static void sweep_clients(); 177 static void drop_lru_client(); 178 static void insert_client(); 179 static bool_t check_verf(); 180 static bool_t rpc_gss_refresh_svc_cred(); 181 static bool_t set_response_verf(); 182 static void retrans_add(svc_rpc_gss_data *, uint32_t, 183 rpc_gss_init_res *); 184 static void retrans_del(struct _svc_rpc_gss_data *); 185 186 187 /* 188 * server side wrap/unwrap routines 189 */ 190 struct svc_auth_ops svc_rpc_gss_ops = { 191 svc_rpc_gss_wrap, 192 svc_rpc_gss_unwrap, 193 }; 194 195 /* 196 * Fetch server side authentication structure. 197 */ 198 extern SVCAUTH *__svc_get_svcauth(); 199 200 /* 201 * Cleanup routine for destroying context, called after service 202 * procedure is executed, for MT safeness. 203 */ 204 extern void *__svc_set_proc_cleanup_cb(); 205 static void (*old_cleanup_cb)() = NULL; 206 static bool_t cleanup_cb_set = FALSE; 207 208 static void 209 ctx_cleanup(xprt) 210 SVCXPRT *xprt; 211 { 212 svc_rpc_gss_data *cl; 213 SVCAUTH *svcauth; 214 215 if (old_cleanup_cb != NULL) 216 (*old_cleanup_cb)(xprt); 217 218 /* 219 * First check if current context needs to be cleaned up. 220 */ 221 svcauth = __svc_get_svcauth(xprt); 222 /*LINTED*/ 223 if ((cl = (svc_rpc_gss_data *)svcauth->svc_ah_private) != NULL) { 224 mutex_lock(&cl->clm); 225 if (--cl->ref_cnt == 0 && cl->stale) { 226 mutex_unlock(&cl->clm); 227 mutex_lock(&ctx_mutex); 228 destroy_client(cl); 229 mutex_unlock(&ctx_mutex); 230 } else 231 mutex_unlock(&cl->clm); 232 } 233 234 /* 235 * Check for other expired contexts. 236 */ 237 if ((time(0) - last_swept) > sweep_interval) { 238 mutex_lock(&ctx_mutex); 239 /* 240 * Check again, in case some other thread got in. 241 */ 242 if ((time(0) - last_swept) > sweep_interval) 243 sweep_clients(); 244 mutex_unlock(&ctx_mutex); 245 } 246 } 247 248 /* 249 * Set server parameters. 250 */ 251 void 252 __rpc_gss_set_server_parms(init_cred_lifetime, max_cred_lifetime, cache_size) 253 int init_cred_lifetime; 254 int max_cred_lifetime; 255 int cache_size; 256 { 257 /* 258 * Ignore parameters unless greater than zero. 259 */ 260 mutex_lock(&ctx_mutex); 261 if (cache_size > 0) 262 max_gss_contexts = cache_size; 263 if (max_cred_lifetime > 0) 264 max_lifetime = (uint_t)max_cred_lifetime; 265 if (init_cred_lifetime > 0) 266 init_lifetime = init_cred_lifetime; 267 mutex_unlock(&ctx_mutex); 268 } 269 270 /* 271 * Shift the array arr of length arrlen right by nbits bits. 272 */ 273 static void 274 shift_bits(arr, arrlen, nbits) 275 uint_t *arr; 276 int arrlen; 277 int nbits; 278 { 279 int i, j; 280 uint_t lo, hi; 281 282 /* 283 * If the number of bits to be shifted exceeds SEQ_WIN, just 284 * zero out the array. 285 */ 286 if (nbits < SEQ_WIN) { 287 for (i = 0; i < nbits; i++) { 288 hi = 0; 289 for (j = 0; j < arrlen; j++) { 290 lo = arr[j] & SEQ_LO_BIT; 291 arr[j] >>= 1; 292 if (hi) 293 arr[j] |= SEQ_HI_BIT; 294 hi = lo; 295 } 296 } 297 } else { 298 for (j = 0; j < arrlen; j++) 299 arr[j] = 0; 300 } 301 } 302 303 /* 304 * Check that the received sequence number seq_num is valid. 305 */ 306 static bool_t 307 check_seq(cl, seq_num, kill_context) 308 svc_rpc_gss_data *cl; 309 uint_t seq_num; 310 bool_t *kill_context; 311 { 312 int i, j; 313 uint_t bit; 314 315 /* 316 * If it exceeds the maximum, kill context. 317 */ 318 if (seq_num >= SEQ_MAX) { 319 *kill_context = TRUE; 320 return (FALSE); 321 } 322 323 /* 324 * If greater than the last seen sequence number, just shift 325 * the sequence window so that it starts at the new sequence 326 * number and extends downwards by SEQ_WIN. 327 */ 328 if (seq_num > cl->seq_num) { 329 shift_bits(cl->seq_bits, SEQ_ARR_SIZE, seq_num - cl->seq_num); 330 cl->seq_bits[0] |= SEQ_HI_BIT; 331 cl->seq_num = seq_num; 332 return (TRUE); 333 } 334 335 /* 336 * If it is outside the sequence window, return failure. 337 */ 338 i = cl->seq_num - seq_num; 339 if (i >= SEQ_WIN) 340 return (FALSE); 341 342 /* 343 * If within sequence window, set the bit corresponding to it 344 * if not already seen; if already seen, return failure. 345 */ 346 j = SEQ_MASK - (i & SEQ_MASK); 347 bit = j > 0 ? (1 << j) : 1; 348 i >>= DIV_BY_32; 349 if (cl->seq_bits[i] & bit) 350 return (FALSE); 351 cl->seq_bits[i] |= bit; 352 return (TRUE); 353 } 354 355 /* 356 * Convert a name in gss exported type to rpc_gss_principal_t type. 357 */ 358 static bool_t 359 __rpc_gss_make_principal(principal, name) 360 rpc_gss_principal_t *principal; 361 gss_buffer_desc *name; 362 { 363 int plen; 364 char *s; 365 366 plen = RNDUP(name->length) + sizeof (int); 367 (*principal) = (rpc_gss_principal_t)malloc(plen); 368 if ((*principal) == NULL) 369 return (FALSE); 370 bzero((caddr_t)(*principal), plen); 371 (*principal)->len = RNDUP(name->length); 372 s = (*principal)->name; 373 memcpy(s, name->value, name->length); 374 return (TRUE); 375 } 376 377 /* 378 * Convert a name in internal form to the exported type. 379 */ 380 static bool_t 381 set_client_principal(g_name, r_name) 382 gss_name_t g_name; 383 rpc_gss_principal_t *r_name; 384 { 385 gss_buffer_desc name; 386 OM_uint32 major, minor; 387 bool_t ret = FALSE; 388 389 major = gss_export_name(&minor, g_name, &name); 390 if (major != GSS_S_COMPLETE) 391 return (FALSE); 392 ret = __rpc_gss_make_principal(r_name, &name); 393 (void) gss_release_buffer(&minor, &name); 394 return (ret); 395 } 396 397 /* 398 * Set server callback. 399 */ 400 bool_t 401 __rpc_gss_set_callback(cb) 402 rpc_gss_callback_t *cb; 403 { 404 cblist_t *cbl; 405 406 if (cb->callback == NULL) 407 return (FALSE); 408 if ((cbl = (cblist_t *)malloc(sizeof (*cbl))) == NULL) 409 return (FALSE); 410 cbl->cb = *cb; 411 mutex_lock(&cb_mutex); 412 cbl->next = cblist; 413 cblist = cbl; 414 mutex_unlock(&cb_mutex); 415 return (TRUE); 416 } 417 418 /* 419 * Locate callback (if specified) and call server. Release any 420 * delegated credentials unless passed to server and the server 421 * accepts the context. If a callback is not specified, accept 422 * the incoming context. 423 */ 424 static bool_t 425 do_callback(req, client_data) 426 struct svc_req *req; 427 svc_rpc_gss_data *client_data; 428 { 429 cblist_t *cbl; 430 bool_t ret = TRUE, found = FALSE; 431 rpc_gss_lock_t lock; 432 OM_uint32 minor; 433 434 mutex_lock(&cb_mutex); 435 for (cbl = cblist; cbl != NULL; cbl = cbl->next) { 436 if (req->rq_prog != cbl->cb.program || 437 req->rq_vers != cbl->cb.version) 438 continue; 439 found = TRUE; 440 lock.locked = FALSE; 441 lock.raw_cred = &client_data->raw_cred; 442 ret = (*cbl->cb.callback)(req, client_data->deleg, 443 client_data->context, &lock, &client_data->cookie); 444 if (ret) { 445 client_data->locked = lock.locked; 446 client_data->deleg = GSS_C_NO_CREDENTIAL; 447 } 448 break; 449 } 450 if (!found) { 451 if (client_data->deleg != GSS_C_NO_CREDENTIAL) { 452 (void) gss_release_cred(&minor, &client_data->deleg); 453 client_data->deleg = GSS_C_NO_CREDENTIAL; 454 } 455 } 456 mutex_unlock(&cb_mutex); 457 return (ret); 458 } 459 460 /* 461 * Return caller credentials. 462 */ 463 bool_t 464 __rpc_gss_getcred(req, rcred, ucred, cookie) 465 struct svc_req *req; 466 rpc_gss_rawcred_t **rcred; 467 rpc_gss_ucred_t **ucred; 468 void **cookie; 469 { 470 SVCAUTH *svcauth; 471 svc_rpc_gss_data *client_data; 472 svc_rpc_gss_parms_t *gss_parms; 473 gss_OID oid; 474 OM_uint32 status; 475 int len = 0; 476 struct timeval now; 477 478 svcauth = __svc_get_svcauth(req->rq_xprt); 479 /*LINTED*/ 480 client_data = (svc_rpc_gss_data *)svcauth->svc_ah_private; 481 gss_parms = &svcauth->svc_gss_parms; 482 483 mutex_lock(&client_data->clm); 484 485 if (rcred != NULL) { 486 svcauth->raw_cred = client_data->raw_cred; 487 svcauth->raw_cred.service = gss_parms->service; 488 svcauth->raw_cred.qop = __rpc_gss_num_to_qop( 489 svcauth->raw_cred.mechanism, gss_parms->qop_rcvd); 490 *rcred = &svcauth->raw_cred; 491 } 492 if (ucred != NULL) { 493 if (!client_data->u_cred_set) { 494 /* 495 * Double check making sure ucred is not set 496 * after acquiring the lock. 497 */ 498 if (!client_data->u_cred_set) { 499 if (!__rpc_gss_mech_to_oid( 500 (*rcred)->mechanism, &oid)) { 501 fprintf(stderr, dgettext(TEXT_DOMAIN, 502 "mech_to_oid failed in getcred.\n")); 503 *ucred = NULL; 504 } else { 505 status = gsscred_name_to_unix_cred( 506 client_data->client_name, oid, 507 &client_data->u_cred.uid, 508 &client_data->u_cred.gid, 509 &client_data->u_cred.gidlist, 510 &len); 511 if (status == GSS_S_COMPLETE) { 512 client_data->u_cred_set = TRUE; 513 client_data->u_cred.gidlen = 514 (short)len; 515 gettimeofday(&now, 516 (struct timezone *)NULL); 517 client_data->time_secs_set = 518 now.tv_sec; 519 *ucred = &client_data->u_cred; 520 } else 521 *ucred = NULL; 522 } 523 } 524 } else { 525 /* 526 * gid's already set; 527 * check if they have expired. 528 */ 529 gettimeofday(&now, (struct timezone *)NULL); 530 if ((now.tv_sec - client_data->time_secs_set) 531 > gid_timeout) { 532 /* Refresh gid's */ 533 status = gss_get_group_info( 534 client_data->u_cred.uid, 535 &client_data->u_cred.gid, 536 &client_data->u_cred.gidlist, 537 &len); 538 if (status == GSS_S_COMPLETE) { 539 client_data->u_cred.gidlen = 540 (short)len; 541 gettimeofday(&now, 542 (struct timezone *)NULL); 543 client_data->time_secs_set = now.tv_sec; 544 *ucred = &client_data->u_cred; 545 } else { 546 client_data->u_cred_set = FALSE; 547 *ucred = NULL; 548 } 549 } 550 else 551 *ucred = &client_data->u_cred; 552 } 553 } 554 if (cookie != NULL) 555 *cookie = client_data->cookie; 556 557 mutex_unlock(&client_data->clm); 558 559 return (TRUE); 560 } 561 562 /* 563 * Server side authentication for RPCSEC_GSS. 564 */ 565 566 enum auth_stat 567 __svcrpcsec_gss(rqst, msg, no_dispatch) 568 struct svc_req *rqst; 569 struct rpc_msg *msg; 570 bool_t *no_dispatch; 571 { 572 XDR xdrs; 573 rpc_gss_creds creds; 574 rpc_gss_init_arg call_arg; 575 rpc_gss_init_res call_res, *retrans_result; 576 gss_buffer_desc output_token; 577 OM_uint32 gssstat, minor_stat, time_rec, ret_flags; 578 struct opaque_auth *cred; 579 svc_rpc_gss_data *client_data; 580 int ret; 581 svc_creds_list_t *sc; 582 SVCAUTH *svcauth; 583 svc_rpc_gss_parms_t *gss_parms; 584 gss_OID mech_type = GSS_C_NULL_OID; 585 586 /* 587 * Initialize response verifier to NULL verifier. If 588 * necessary, this will be changed later. 589 */ 590 rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NONE; 591 rqst->rq_xprt->xp_verf.oa_base = NULL; 592 rqst->rq_xprt->xp_verf.oa_length = 0; 593 /* 594 * Need to null out results to start with. 595 */ 596 memset((char *)&call_res, 0, sizeof (call_res)); 597 598 /* 599 * Pull out and check credential and verifier. 600 */ 601 cred = &msg->rm_call.cb_cred; 602 if (cred->oa_length == 0) { 603 return (AUTH_BADCRED); 604 } 605 606 xdrmem_create(&xdrs, cred->oa_base, cred->oa_length, XDR_DECODE); 607 608 memset((char *)&creds, 0, sizeof (creds)); 609 if (!__xdr_rpc_gss_creds(&xdrs, &creds)) { 610 XDR_DESTROY(&xdrs); 611 ret = AUTH_BADCRED; 612 goto error; 613 } 614 XDR_DESTROY(&xdrs); 615 616 /* 617 * If this is a control message and proc is GSSAPI_INIT, then 618 * create a client handle for this client. Otherwise, look up 619 * the existing handle. 620 */ 621 if (creds.gss_proc == RPCSEC_GSS_INIT) { 622 if (creds.ctx_handle.length != 0) { 623 ret = AUTH_BADCRED; 624 goto error; 625 } 626 if ((client_data = create_client()) == NULL) { 627 ret = AUTH_FAILED; 628 goto error; 629 } 630 } else { 631 /* 632 * Only verify values for service parameter when proc 633 * not RPCSEC_GSS_INIT or RPCSEC_GSS_CONTINUE_INIT. 634 * RFC2203 says contents for sequence and service args 635 * are undefined for creation procs. 636 * 637 * Note: only need to check for *CONTINUE_INIT here because 638 * if() clause already checked for RPCSEC_GSS_INIT 639 */ 640 if (creds.gss_proc != RPCSEC_GSS_CONTINUE_INIT) { 641 switch (creds.service) { 642 case rpc_gss_svc_none: 643 case rpc_gss_svc_integrity: 644 case rpc_gss_svc_privacy: 645 break; 646 default: 647 ret = AUTH_BADCRED; 648 goto error; 649 } 650 } 651 if (creds.ctx_handle.length == 0) { 652 ret = AUTH_BADCRED; 653 goto error; 654 } 655 if ((client_data = get_client(&creds.ctx_handle)) == NULL) { 656 ret = RPCSEC_GSS_NOCRED; 657 goto error; 658 } 659 } 660 661 /* 662 * lock the client data until it's safe; if it's already stale, 663 * no more processing is possible 664 */ 665 mutex_lock(&client_data->clm); 666 if (client_data->stale) { 667 ret = RPCSEC_GSS_NOCRED; 668 goto error2; 669 } 670 671 /* 672 * Any response we send will use ctx_handle, so set it now; 673 * also set seq_window since this won't change. 674 */ 675 call_res.ctx_handle.length = sizeof (client_data->key); 676 call_res.ctx_handle.value = (char *)&client_data->key; 677 call_res.seq_window = SEQ_WIN; 678 679 /* 680 * Set the appropriate wrap/unwrap routine for RPCSEC_GSS. 681 */ 682 svcauth = __svc_get_svcauth(rqst->rq_xprt); 683 svcauth->svc_ah_ops = svc_rpc_gss_ops; 684 svcauth->svc_ah_private = (caddr_t)client_data; 685 686 /* 687 * Keep copy of parameters we'll need for response, for the 688 * sake of reentrancy (we don't want to look in the context 689 * data because when we are sending a response, another 690 * request may have come in. 691 */ 692 gss_parms = &svcauth->svc_gss_parms; 693 gss_parms->established = client_data->established; 694 gss_parms->service = creds.service; 695 gss_parms->qop_rcvd = (uint_t)client_data->qop; 696 gss_parms->context = (void *)client_data->context; 697 gss_parms->seq_num = creds.seq_num; 698 699 if (!client_data->established) { 700 if (creds.gss_proc == RPCSEC_GSS_DATA) { 701 ret = RPCSEC_GSS_FAILED; 702 client_data->stale = TRUE; 703 goto error2; 704 } 705 706 /* 707 * If the context is not established, then only GSSAPI_INIT 708 * and _CONTINUE requests are valid. 709 */ 710 if (creds.gss_proc != RPCSEC_GSS_INIT && creds.gss_proc != 711 RPCSEC_GSS_CONTINUE_INIT) { 712 ret = RPCSEC_GSS_FAILED; 713 client_data->stale = TRUE; 714 goto error2; 715 } 716 717 /* 718 * call is for us, deserialize arguments 719 */ 720 memset(&call_arg, 0, sizeof (call_arg)); 721 if (!svc_getargs(rqst->rq_xprt, __xdr_rpc_gss_init_arg, 722 (caddr_t)&call_arg)) { 723 ret = RPCSEC_GSS_FAILED; 724 client_data->stale = TRUE; 725 goto error2; 726 } 727 728 gssstat = GSS_S_FAILURE; 729 minor_stat = 0; 730 rw_rdlock(&cred_lock); 731 /* 732 * set next sc to point to the server cred 733 * if the client_data contains server_creds 734 */ 735 for (sc = svc_creds_list; sc != NULL; sc = sc->next) { 736 if (rqst->rq_prog != sc->program || 737 rqst->rq_vers != sc->version) 738 continue; 739 740 mutex_lock(&sc->refresh_mutex); 741 gssstat = gss_accept_sec_context(&minor_stat, 742 &client_data->context, 743 sc->cred, 744 &call_arg, 745 GSS_C_NO_CHANNEL_BINDINGS, 746 &client_data->client_name, 747 &mech_type, 748 &output_token, 749 &ret_flags, 750 &time_rec, 751 NULL); 752 753 if (gssstat == GSS_S_CREDENTIALS_EXPIRED) { 754 if (rpc_gss_refresh_svc_cred(sc)) { 755 gssstat = gss_accept_sec_context( 756 &minor_stat, 757 &client_data->context, 758 sc->cred, 759 &call_arg, 760 GSS_C_NO_CHANNEL_BINDINGS, 761 &client_data->client_name, 762 &mech_type, 763 &output_token, 764 &ret_flags, 765 &time_rec, 766 NULL); 767 mutex_unlock(&sc->refresh_mutex); 768 769 } else { 770 mutex_unlock(&sc->refresh_mutex); 771 gssstat = GSS_S_NO_CRED; 772 break; 773 } 774 775 } else 776 mutex_unlock(&sc->refresh_mutex); 777 778 if (gssstat == GSS_S_COMPLETE) { 779 /* 780 * Server_creds was right - set it. Also 781 * set the raw and unix credentials at this 782 * point. This saves a lot of computation 783 * later when credentials are retrieved. 784 */ 785 /* 786 * XXX server_creds will prob be stale 787 * after rpc_gss_refresh_svc_cred(), but 788 * it appears not to ever be referenced 789 * anyways. 790 */ 791 mutex_lock(&sc->refresh_mutex); 792 client_data->server_creds = sc->cred; 793 client_data->raw_cred.version = creds.version; 794 client_data->raw_cred.service = creds.service; 795 client_data->raw_cred.svc_principal = 796 sc->server_name; 797 mutex_unlock(&sc->refresh_mutex); 798 799 if ((client_data->raw_cred.mechanism 800 = __rpc_gss_oid_to_mech(mech_type)) 801 == NULL) { 802 gssstat = GSS_S_FAILURE; 803 (void) gss_release_buffer(&minor_stat, 804 &output_token); 805 } else if (!set_client_principal(client_data-> 806 client_name, &client_data-> 807 raw_cred.client_principal)) { 808 gssstat = GSS_S_FAILURE; 809 (void) gss_release_buffer(&minor_stat, 810 &output_token); 811 } 812 break; 813 } 814 815 if (gssstat == GSS_S_CONTINUE_NEEDED) { 816 /* 817 * XXX server_creds will prob be stale 818 * after rpc_gss_refresh_svc_cred(), but 819 * it appears not to ever be referenced 820 * anyways. 821 */ 822 mutex_lock(&sc->refresh_mutex); 823 client_data->server_creds = sc->cred; 824 mutex_unlock(&sc->refresh_mutex); 825 break; 826 } 827 828 } 829 rw_unlock(&cred_lock); 830 831 call_res.gss_major = gssstat; 832 call_res.gss_minor = minor_stat; 833 834 xdr_free(__xdr_rpc_gss_init_arg, (caddr_t)&call_arg); 835 836 if (gssstat != GSS_S_COMPLETE && 837 gssstat != GSS_S_CONTINUE_NEEDED) { 838 /* 839 * We have a failure - send response and delete 840 * the context. Don't dispatch. Set ctx_handle 841 * to NULL and seq_window to 0. 842 */ 843 call_res.ctx_handle.length = 0; 844 call_res.ctx_handle.value = NULL; 845 call_res.seq_window = 0; 846 847 svc_sendreply(rqst->rq_xprt, __xdr_rpc_gss_init_res, 848 (caddr_t)&call_res); 849 *no_dispatch = TRUE; 850 ret = AUTH_OK; 851 client_data->stale = TRUE; 852 goto error2; 853 } 854 855 /* 856 * This step succeeded. Send a response, along with 857 * a token if there's one. Don't dispatch. 858 */ 859 if (output_token.length != 0) { 860 GSS_COPY_BUFFER(call_res.token, output_token); 861 } 862 863 /* 864 * set response verifier: checksum of SEQ_WIN 865 */ 866 if (gssstat == GSS_S_COMPLETE) { 867 if (!set_response_verf(rqst, msg, client_data, 868 (uint_t)SEQ_WIN)) { 869 ret = RPCSEC_GSS_FAILED; 870 client_data->stale = TRUE; 871 (void) gss_release_buffer(&minor_stat, 872 &output_token); 873 goto error2; 874 } 875 } 876 877 svc_sendreply(rqst->rq_xprt, __xdr_rpc_gss_init_res, 878 (caddr_t)&call_res); 879 /* 880 * Cache last response in case it is lost and the client 881 * retries on an established context. 882 */ 883 (void) retrans_add(client_data, msg->rm_xid, &call_res); 884 *no_dispatch = TRUE; 885 (void) gss_release_buffer(&minor_stat, &output_token); 886 887 /* 888 * If appropriate, set established to TRUE *after* sending 889 * response (otherwise, the client will receive the final 890 * token encrypted) 891 */ 892 if (gssstat == GSS_S_COMPLETE) { 893 /* 894 * Context is established. Set expiry time for 895 * context (the minimum of time_rec and max_lifetime). 896 */ 897 client_data->seq_num = 1; 898 if (time_rec == GSS_C_INDEFINITE) { 899 if (max_lifetime != GSS_C_INDEFINITE) 900 client_data->expiration = 901 max_lifetime + time(0); 902 else 903 client_data->expiration = 904 GSS_C_INDEFINITE; 905 } else if (max_lifetime == GSS_C_INDEFINITE || 906 max_lifetime > time_rec) 907 client_data->expiration = time_rec + time(0); 908 else 909 client_data->expiration = max_lifetime + 910 time(0); 911 client_data->established = TRUE; 912 } 913 914 } else { 915 if ((creds.gss_proc != RPCSEC_GSS_DATA) && 916 (creds.gss_proc != RPCSEC_GSS_DESTROY)) { 917 918 switch (creds.gss_proc) { 919 920 case RPCSEC_GSS_CONTINUE_INIT: 921 /* 922 * This is an established context. Continue to 923 * satisfy retried continue init requests out of 924 * the retransmit cache. Throw away any that don't 925 * have a matching xid or the cach is empty. 926 * Delete the retransmit cache once the client sends 927 * a data request. 928 */ 929 if (client_data->retrans_data && 930 (client_data->retrans_data->xid == msg->rm_xid)) { 931 932 retrans_result = &client_data->retrans_data->result; 933 if (set_response_verf(rqst, msg, client_data, 934 (uint_t)retrans_result->seq_window)) { 935 936 gss_parms->established = FALSE; 937 svc_sendreply(rqst->rq_xprt, 938 __xdr_rpc_gss_init_res, 939 (caddr_t)retrans_result); 940 *no_dispatch = TRUE; 941 goto success; 942 } 943 } 944 /* fall thru to default */ 945 946 default: 947 syslog(LOG_ERR, "_svcrpcsec_gss: non-data request " 948 "on an established context"); 949 ret = AUTH_FAILED; 950 goto error2; 951 } 952 } 953 954 /* 955 * Once the context is established and there is no more 956 * retransmission of last continue init request, it is safe 957 * to delete the retransmit cache entry. 958 */ 959 if (client_data->retrans_data) 960 retrans_del(client_data); 961 962 /* 963 * Context is already established. Check verifier, and 964 * note parameters we will need for response in gss_parms. 965 */ 966 if (!check_verf(msg, client_data->context, 967 &gss_parms->qop_rcvd)) { 968 ret = RPCSEC_GSS_NOCRED; 969 goto error2; 970 } 971 /* 972 * Check and invoke callback if necessary. 973 */ 974 if (!client_data->done_docallback) { 975 client_data->done_docallback = TRUE; 976 client_data->qop = gss_parms->qop_rcvd; 977 client_data->raw_cred.qop = __rpc_gss_num_to_qop( 978 client_data->raw_cred.mechanism, 979 gss_parms->qop_rcvd); 980 client_data->raw_cred.service = creds.service; 981 if (!do_callback(rqst, client_data)) { 982 ret = AUTH_FAILED; 983 client_data->stale = TRUE; 984 goto error2; 985 } 986 } 987 988 /* 989 * If the context was locked, make sure that the client 990 * has not changed QOP. 991 */ 992 if (client_data->locked && 993 gss_parms->qop_rcvd != client_data->qop) { 994 ret = AUTH_BADVERF; 995 goto error2; 996 } 997 998 /* 999 * Validate sequence number. 1000 */ 1001 if (!check_seq(client_data, creds.seq_num, 1002 &client_data->stale)) { 1003 if (client_data->stale) 1004 ret = RPCSEC_GSS_FAILED; 1005 else { 1006 /* 1007 * Operational error, drop packet silently. 1008 * The client will recover after timing out, 1009 * assuming this is a client error and not 1010 * a relpay attack. Don't dispatch. 1011 */ 1012 ret = AUTH_OK; 1013 *no_dispatch = TRUE; 1014 } 1015 goto error2; 1016 } 1017 1018 /* 1019 * set response verifier 1020 */ 1021 if (!set_response_verf(rqst, msg, client_data, creds.seq_num)) { 1022 ret = RPCSEC_GSS_FAILED; 1023 client_data->stale = TRUE; 1024 goto error2; 1025 } 1026 1027 /* 1028 * If this is a control message RPCSEC_GSS_DESTROY, process 1029 * the call; otherwise, return AUTH_OK so it will be 1030 * dispatched to the application server. 1031 */ 1032 if (creds.gss_proc == RPCSEC_GSS_DESTROY) { 1033 svc_sendreply(rqst->rq_xprt, xdr_void, NULL); 1034 *no_dispatch = TRUE; 1035 client_data->stale = TRUE; 1036 1037 } else { 1038 /* 1039 * This should be an RPCSEC_GSS_DATA request. 1040 * If context is locked, make sure that the client 1041 * has not changed the security service. 1042 */ 1043 if (client_data->locked && 1044 client_data->raw_cred.service != creds.service) { 1045 ret = AUTH_FAILED; 1046 goto error2; 1047 } 1048 1049 /* 1050 * Set client credentials to raw credential 1051 * structure in context. This is okay, since 1052 * this will not change during the lifetime of 1053 * the context (so it's MT safe). 1054 */ 1055 rqst->rq_clntcred = (char *)&client_data->raw_cred; 1056 } 1057 } 1058 1059 success: 1060 /* 1061 * Success. 1062 */ 1063 if (creds.ctx_handle.length != 0) 1064 xdr_free(__xdr_rpc_gss_creds, (caddr_t)&creds); 1065 mutex_unlock(&client_data->clm); 1066 return (AUTH_OK); 1067 error2: 1068 mutex_unlock(&client_data->clm); 1069 error: 1070 /* 1071 * Failure. 1072 */ 1073 if (creds.ctx_handle.length != 0) 1074 xdr_free(__xdr_rpc_gss_creds, (caddr_t)&creds); 1075 return (ret); 1076 } 1077 1078 /* 1079 * Check verifier. The verifier is the checksum of the RPC header 1080 * upto and including the credentials field. 1081 */ 1082 static bool_t 1083 check_verf(msg, context, qop_state) 1084 struct rpc_msg *msg; 1085 gss_ctx_id_t context; 1086 int *qop_state; 1087 { 1088 int *buf, *tmp; 1089 int hdr[32]; 1090 struct opaque_auth *oa; 1091 int len; 1092 gss_buffer_desc msg_buf; 1093 gss_buffer_desc tok_buf; 1094 OM_uint32 gssstat, minor_stat; 1095 1096 /* 1097 * We have to reconstruct the RPC header from the previously 1098 * parsed information, since we haven't kept the header intact. 1099 */ 1100 1101 oa = &msg->rm_call.cb_cred; 1102 if (oa->oa_length > MAX_AUTH_BYTES) 1103 return (FALSE); 1104 1105 /* 8 XDR units from the IXDR macro calls. */ 1106 if (sizeof (hdr) < (8 * BYTES_PER_XDR_UNIT + 1107 RNDUP(oa->oa_length))) 1108 return (FALSE); 1109 buf = hdr; 1110 1111 IXDR_PUT_U_INT32(buf, msg->rm_xid); 1112 IXDR_PUT_ENUM(buf, msg->rm_direction); 1113 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_rpcvers); 1114 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_prog); 1115 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_vers); 1116 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_proc); 1117 IXDR_PUT_ENUM(buf, oa->oa_flavor); 1118 IXDR_PUT_U_INT32(buf, oa->oa_length); 1119 if (oa->oa_length) { 1120 len = RNDUP(oa->oa_length); 1121 tmp = buf; 1122 buf += len / sizeof (int); 1123 *(buf - 1) = 0; 1124 (void) memcpy((caddr_t)tmp, oa->oa_base, oa->oa_length); 1125 } 1126 len = ((char *)buf) - (char *)hdr; 1127 msg_buf.length = len; 1128 msg_buf.value = (char *)hdr; 1129 oa = &msg->rm_call.cb_verf; 1130 tok_buf.length = oa->oa_length; 1131 tok_buf.value = oa->oa_base; 1132 1133 gssstat = gss_verify(&minor_stat, context, &msg_buf, &tok_buf, 1134 qop_state); 1135 if (gssstat != GSS_S_COMPLETE) 1136 return (FALSE); 1137 return (TRUE); 1138 } 1139 1140 /* 1141 * Set response verifier. This is the checksum of the given number. 1142 * (e.g. sequence number or sequence window) 1143 */ 1144 static bool_t 1145 set_response_verf(rqst, msg, cl, num) 1146 struct svc_req *rqst; 1147 struct rpc_msg *msg; 1148 svc_rpc_gss_data *cl; 1149 uint_t num; 1150 { 1151 OM_uint32 minor; 1152 gss_buffer_desc in_buf, out_buf; 1153 uint_t num_net; 1154 1155 num_net = (uint_t)htonl(num); 1156 in_buf.length = sizeof (num); 1157 in_buf.value = (char *)&num_net; 1158 if (gss_sign(&minor, cl->context, cl->qop, &in_buf, 1159 &out_buf) != GSS_S_COMPLETE) 1160 return (FALSE); 1161 rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS; 1162 rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base; 1163 rqst->rq_xprt->xp_verf.oa_length = out_buf.length; 1164 memcpy(rqst->rq_xprt->xp_verf.oa_base, out_buf.value, 1165 out_buf.length); 1166 (void) gss_release_buffer(&minor, &out_buf); 1167 return (TRUE); 1168 } 1169 1170 /* 1171 * Create client context. 1172 */ 1173 static svc_rpc_gss_data * 1174 create_client() 1175 { 1176 svc_rpc_gss_data *client_data; 1177 static uint_t key = 1; 1178 1179 client_data = (svc_rpc_gss_data *) malloc(sizeof (*client_data)); 1180 if (client_data == NULL) 1181 return (NULL); 1182 memset((char *)client_data, 0, sizeof (*client_data)); 1183 1184 /* 1185 * set up client data structure 1186 */ 1187 client_data->established = FALSE; 1188 client_data->locked = FALSE; 1189 client_data->u_cred_set = FALSE; 1190 client_data->context = GSS_C_NO_CONTEXT; 1191 client_data->expiration = init_lifetime + time(0); 1192 client_data->ref_cnt = 1; 1193 client_data->qop = GSS_C_QOP_DEFAULT; 1194 client_data->done_docallback = FALSE; 1195 client_data->stale = FALSE; 1196 client_data->time_secs_set = 0; 1197 client_data->retrans_data = NULL; 1198 mutex_init(&client_data->clm, USYNC_THREAD, NULL); 1199 /* 1200 * Check totals. If we've hit the limit, we destroy a context 1201 * based on LRU method. 1202 */ 1203 mutex_lock(&ctx_mutex); 1204 if (num_gss_contexts >= max_gss_contexts) { 1205 /* 1206 * now try on LRU basis 1207 */ 1208 drop_lru_client(); 1209 if (num_gss_contexts >= max_gss_contexts) { 1210 mutex_unlock(&ctx_mutex); 1211 free((char *)client_data); 1212 return (NULL); 1213 } 1214 } 1215 1216 /* 1217 * The client context handle is a 32-bit key (unsigned int). 1218 * The key is incremented until there is no duplicate for it. 1219 */ 1220 for (;;) { 1221 client_data->key = key++; 1222 if (find_client(client_data->key) == NULL) { 1223 insert_client(client_data); 1224 /* 1225 * Set cleanup callback if we haven't. 1226 */ 1227 if (!cleanup_cb_set) { 1228 old_cleanup_cb = 1229 (void (*)()) __svc_set_proc_cleanup_cb( 1230 (void *)ctx_cleanup); 1231 cleanup_cb_set = TRUE; 1232 } 1233 mutex_unlock(&ctx_mutex); 1234 return (client_data); 1235 } 1236 } 1237 /*NOTREACHED*/ 1238 } 1239 1240 /* 1241 * Insert client context into hash list and LRU list. 1242 */ 1243 static void 1244 insert_client(client_data) 1245 svc_rpc_gss_data *client_data; 1246 { 1247 svc_rpc_gss_data *cl; 1248 int index = (client_data->key & HASHMASK); 1249 1250 client_data->prev = NULL; 1251 cl = clients[index]; 1252 if ((client_data->next = cl) != NULL) 1253 cl->prev = client_data; 1254 clients[index] = client_data; 1255 1256 client_data->lru_prev = NULL; 1257 if ((client_data->lru_next = lru_first) != NULL) 1258 lru_first->lru_prev = client_data; 1259 else 1260 lru_last = client_data; 1261 lru_first = client_data; 1262 1263 num_gss_contexts++; 1264 } 1265 1266 /* 1267 * Fetch a client, given the client context handle. Move it to the 1268 * top of the LRU list since this is the most recently used context. 1269 */ 1270 static svc_rpc_gss_data * 1271 get_client(ctx_handle) 1272 gss_buffer_t ctx_handle; 1273 { 1274 uint_t key = *(uint_t *)ctx_handle->value; 1275 svc_rpc_gss_data *cl; 1276 1277 mutex_lock(&ctx_mutex); 1278 if ((cl = find_client(key)) != NULL) { 1279 mutex_lock(&cl->clm); 1280 if (cl->stale) { 1281 mutex_unlock(&cl->clm); 1282 mutex_unlock(&ctx_mutex); 1283 return (NULL); 1284 } 1285 cl->ref_cnt++; 1286 mutex_unlock(&cl->clm); 1287 if (cl != lru_first) { 1288 cl->lru_prev->lru_next = cl->lru_next; 1289 if (cl->lru_next != NULL) 1290 cl->lru_next->lru_prev = cl->lru_prev; 1291 else 1292 lru_last = cl->lru_prev; 1293 cl->lru_prev = NULL; 1294 cl->lru_next = lru_first; 1295 lru_first->lru_prev = cl; 1296 lru_first = cl; 1297 } 1298 } 1299 mutex_unlock(&ctx_mutex); 1300 return (cl); 1301 } 1302 1303 /* 1304 * Given the client context handle, find the context corresponding to it. 1305 * Don't change its LRU state since it may not be used. 1306 */ 1307 static svc_rpc_gss_data * 1308 find_client(key) 1309 uint_t key; 1310 { 1311 int index = (key & HASHMASK); 1312 svc_rpc_gss_data *cl; 1313 1314 for (cl = clients[index]; cl != NULL; cl = cl->next) { 1315 if (cl->key == key) 1316 break; 1317 } 1318 return (cl); 1319 } 1320 1321 /* 1322 * Destroy a client context. 1323 */ 1324 static void 1325 destroy_client(client_data) 1326 svc_rpc_gss_data *client_data; 1327 { 1328 OM_uint32 minor; 1329 int index = (client_data->key & HASHMASK); 1330 1331 /* 1332 * remove from hash list 1333 */ 1334 if (client_data->prev == NULL) 1335 clients[index] = client_data->next; 1336 else 1337 client_data->prev->next = client_data->next; 1338 if (client_data->next != NULL) 1339 client_data->next->prev = client_data->prev; 1340 1341 /* 1342 * remove from LRU list 1343 */ 1344 if (client_data->lru_prev == NULL) 1345 lru_first = client_data->lru_next; 1346 else 1347 client_data->lru_prev->lru_next = client_data->lru_next; 1348 if (client_data->lru_next != NULL) 1349 client_data->lru_next->lru_prev = client_data->lru_prev; 1350 else 1351 lru_last = client_data->lru_prev; 1352 1353 /* 1354 * If there is a GSS context, clean up GSS state. 1355 */ 1356 if (client_data->context != GSS_C_NO_CONTEXT) { 1357 (void) gss_delete_sec_context(&minor, &client_data->context, 1358 NULL); 1359 if (client_data->client_name) 1360 (void) gss_release_name(&minor, &client_data->client_name); 1361 if (client_data->raw_cred.client_principal) 1362 free((char *)client_data->raw_cred.client_principal); 1363 if (client_data->u_cred.gidlist != NULL) 1364 free((char *)client_data->u_cred.gidlist); 1365 if (client_data->deleg != GSS_C_NO_CREDENTIAL) 1366 (void) gss_release_cred(&minor, &client_data->deleg); 1367 } 1368 1369 if (client_data->retrans_data != NULL) 1370 retrans_del(client_data); 1371 1372 free(client_data); 1373 num_gss_contexts--; 1374 } 1375 1376 /* 1377 * Check for expired client contexts. 1378 */ 1379 static void 1380 sweep_clients() 1381 { 1382 svc_rpc_gss_data *cl, *next; 1383 int index; 1384 1385 for (index = 0; index < HASHMOD; index++) { 1386 cl = clients[index]; 1387 while (cl) { 1388 next = cl->next; 1389 mutex_lock(&cl->clm); 1390 if ((cl->expiration != GSS_C_INDEFINITE && 1391 cl->expiration <= time(0)) || cl->stale) { 1392 cl->stale = TRUE; 1393 if (cl->ref_cnt == 0) { 1394 mutex_unlock(&cl->clm); 1395 destroy_client(cl); 1396 } else 1397 mutex_unlock(&cl->clm); 1398 } else 1399 mutex_unlock(&cl->clm); 1400 cl = next; 1401 } 1402 } 1403 last_swept = time(0); 1404 } 1405 1406 /* 1407 * Drop the least recently used client context, if possible. 1408 */ 1409 static void 1410 drop_lru_client() 1411 { 1412 mutex_lock(&lru_last->clm); 1413 lru_last->stale = TRUE; 1414 mutex_unlock(&lru_last->clm); 1415 if (lru_last->ref_cnt == 0) 1416 destroy_client(lru_last); 1417 else 1418 sweep_clients(); 1419 } 1420 1421 /* 1422 * find service credentials 1423 * return cred if found, 1424 * other wise, NULL 1425 */ 1426 1427 svc_creds_list_t * 1428 find_svc_cred(char *service_name, uint_t program, uint_t version) { 1429 1430 svc_creds_list_t *sc; 1431 1432 if (!svc_creds_list) 1433 return (NULL); 1434 1435 for (sc = svc_creds_list; sc != NULL; sc = sc->next) { 1436 if (program != sc->program || version != sc->version) 1437 continue; 1438 1439 if (strcmp(service_name, sc->server_name) != 0) 1440 continue; 1441 return (sc); 1442 } 1443 return (NULL); 1444 } 1445 1446 /* 1447 * Set the server principal name. 1448 */ 1449 bool_t 1450 __rpc_gss_set_svc_name(server_name, mech, req_time, program, version) 1451 char *server_name; 1452 char *mech; 1453 OM_uint32 req_time; 1454 uint_t program; 1455 uint_t version; 1456 { 1457 gss_name_t name; 1458 svc_creds_list_t *svc_cred; 1459 gss_OID mechanism; 1460 gss_OID_set_desc oid_set_desc; 1461 gss_OID_set oid_set; 1462 OM_uint32 ret_time; 1463 OM_uint32 major, minor; 1464 gss_buffer_desc name_buf; 1465 1466 if (!__rpc_gss_mech_to_oid(mech, &mechanism)) { 1467 return (FALSE); 1468 } 1469 1470 name_buf.value = server_name; 1471 name_buf.length = strlen(server_name); 1472 major = gss_import_name(&minor, &name_buf, 1473 (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &name); 1474 if (major != GSS_S_COMPLETE) { 1475 return (FALSE); 1476 } 1477 1478 /* Check if there is already an entry in the svc_creds_list. */ 1479 rw_wrlock(&cred_lock); 1480 if (svc_cred = find_svc_cred(server_name, program, version)) { 1481 1482 major = gss_add_cred(&minor, svc_cred->cred, name, 1483 mechanism, GSS_C_ACCEPT, 1484 0, req_time, NULL, 1485 &oid_set, NULL, 1486 &ret_time); 1487 (void) gss_release_name(&minor, &name); 1488 if (major == GSS_S_COMPLETE) { 1489 /* 1490 * Successfully added the mech to the cred handle 1491 * free the existing oid_set in svc_cred 1492 */ 1493 gss_release_oid_set(&minor, &svc_cred->oid_set); 1494 svc_cred->oid_set = oid_set; 1495 rw_unlock(&cred_lock); 1496 return (TRUE); 1497 } else if (major == GSS_S_DUPLICATE_ELEMENT) { 1498 rw_unlock(&cred_lock); 1499 return (TRUE); 1500 } else if (major == GSS_S_CREDENTIALS_EXPIRED) { 1501 if (rpc_gss_refresh_svc_cred(svc_cred)) { 1502 rw_unlock(&cred_lock); 1503 return (TRUE); 1504 } else { 1505 rw_unlock(&cred_lock); 1506 return (FALSE); 1507 } 1508 } else { 1509 rw_unlock(&cred_lock); 1510 return (FALSE); 1511 } 1512 } else { 1513 svc_cred = (svc_creds_list_t *)malloc(sizeof (*svc_cred)); 1514 if (svc_cred == NULL) { 1515 (void) gss_release_name(&minor, &name); 1516 rw_unlock(&cred_lock); 1517 return (FALSE); 1518 } 1519 oid_set_desc.count = 1; 1520 oid_set_desc.elements = mechanism; 1521 major = gss_acquire_cred(&minor, name, req_time, 1522 &oid_set_desc, 1523 GSS_C_ACCEPT, 1524 &svc_cred->cred, 1525 &oid_set, &ret_time); 1526 1527 if (major != GSS_S_COMPLETE) { 1528 (void) gss_release_name(&minor, &name); 1529 free(svc_cred); 1530 rw_unlock(&cred_lock); 1531 return (FALSE); 1532 } 1533 1534 svc_cred->name = name; 1535 svc_cred->program = program; 1536 svc_cred->version = version; 1537 svc_cred->req_time = req_time; 1538 svc_cred->oid_set = oid_set; 1539 svc_cred->server_name = strdup(server_name); 1540 if (svc_cred->server_name == NULL) { 1541 (void) gss_release_name(&minor, &name); 1542 free((char *)svc_cred); 1543 rw_unlock(&cred_lock); 1544 return (FALSE); 1545 } 1546 mutex_init(&svc_cred->refresh_mutex, USYNC_THREAD, NULL); 1547 1548 svc_cred->next = svc_creds_list; 1549 svc_creds_list = svc_cred; 1550 svc_creds_count++; 1551 rw_unlock(&cred_lock); 1552 1553 return (TRUE); 1554 } 1555 } 1556 /* 1557 * Refresh server credentials. 1558 */ 1559 static bool_t 1560 rpc_gss_refresh_svc_cred(svc_cred) 1561 svc_creds_list_t *svc_cred; 1562 { 1563 OM_uint32 major, minor; 1564 gss_OID_set oid_set; 1565 OM_uint32 ret_time; 1566 1567 (void) gss_release_cred(&minor, &svc_cred->cred); 1568 svc_cred->cred = GSS_C_NO_CREDENTIAL; 1569 major = gss_acquire_cred(&minor, svc_cred->name, svc_cred->req_time, 1570 svc_cred->oid_set, GSS_C_ACCEPT, &svc_cred->cred, &oid_set, 1571 &ret_time); 1572 if (major != GSS_S_COMPLETE) { 1573 return (FALSE); 1574 } 1575 gss_release_oid_set(&minor, &svc_cred->oid_set); 1576 svc_cred->oid_set = oid_set; 1577 return (TRUE); 1578 } 1579 1580 /* 1581 * Encrypt the serialized arguments from xdr_func applied to xdr_ptr 1582 * and write the result to xdrs. 1583 */ 1584 static bool_t 1585 svc_rpc_gss_wrap(auth, out_xdrs, xdr_func, xdr_ptr) 1586 SVCAUTH *auth; 1587 XDR *out_xdrs; 1588 bool_t (*xdr_func)(); 1589 caddr_t xdr_ptr; 1590 { 1591 svc_rpc_gss_parms_t *gss_parms = &auth->svc_gss_parms; 1592 1593 /* 1594 * If context is not established, or if neither integrity nor 1595 * privacy service is used, don't wrap - just XDR encode. 1596 * Otherwise, wrap data using service and QOP parameters. 1597 */ 1598 if (!gss_parms->established || 1599 gss_parms->service == rpc_gss_svc_none) 1600 return ((*xdr_func)(out_xdrs, xdr_ptr)); 1601 1602 return (__rpc_gss_wrap_data(gss_parms->service, 1603 (OM_uint32)gss_parms->qop_rcvd, 1604 (gss_ctx_id_t)gss_parms->context, 1605 gss_parms->seq_num, 1606 out_xdrs, xdr_func, xdr_ptr)); 1607 } 1608 1609 /* 1610 * Decrypt the serialized arguments and XDR decode them. 1611 */ 1612 static bool_t 1613 svc_rpc_gss_unwrap(auth, in_xdrs, xdr_func, xdr_ptr) 1614 SVCAUTH *auth; 1615 XDR *in_xdrs; 1616 bool_t (*xdr_func)(); 1617 caddr_t xdr_ptr; 1618 { 1619 svc_rpc_gss_parms_t *gss_parms = &auth->svc_gss_parms; 1620 1621 /* 1622 * If context is not established, or if neither integrity nor 1623 * privacy service is used, don't unwrap - just XDR decode. 1624 * Otherwise, unwrap data. 1625 */ 1626 if (!gss_parms->established || 1627 gss_parms->service == rpc_gss_svc_none) 1628 return ((*xdr_func)(in_xdrs, xdr_ptr)); 1629 1630 return (__rpc_gss_unwrap_data(gss_parms->service, 1631 (gss_ctx_id_t)gss_parms->context, 1632 gss_parms->seq_num, 1633 gss_parms->qop_rcvd, 1634 in_xdrs, xdr_func, xdr_ptr)); 1635 } 1636 1637 int 1638 __rpc_gss_svc_max_data_length(req, max_tp_unit_len) 1639 struct svc_req *req; 1640 int max_tp_unit_len; 1641 { 1642 SVCAUTH *svcauth; 1643 svc_rpc_gss_parms_t *gss_parms; 1644 1645 svcauth = __svc_get_svcauth(req->rq_xprt); 1646 gss_parms = &svcauth->svc_gss_parms; 1647 1648 if (!gss_parms->established || max_tp_unit_len <= 0) 1649 return (0); 1650 1651 return (__find_max_data_length(gss_parms->service, 1652 (gss_ctx_id_t)gss_parms->context, 1653 gss_parms->qop_rcvd, max_tp_unit_len)); 1654 } 1655 1656 /* 1657 * Add retransmit entry to the context cache entry for a new xid. 1658 * If there is already an entry, delete it before adding the new one. 1659 */ 1660 static void retrans_add(client, xid, result) 1661 svc_rpc_gss_data *client; 1662 uint32_t xid; 1663 rpc_gss_init_res *result; 1664 { 1665 retrans_entry *rdata; 1666 1667 if (client->retrans_data && client->retrans_data->xid == xid) 1668 return; 1669 1670 rdata = (retrans_entry *) malloc(sizeof (*rdata)); 1671 if (rdata == NULL) 1672 return; 1673 1674 rdata->xid = xid; 1675 rdata->result = *result; 1676 1677 if (result->token.length != 0) { 1678 GSS_DUP_BUFFER(rdata->result.token, result->token); 1679 } 1680 1681 if (client->retrans_data) 1682 retrans_del(client); 1683 1684 client->retrans_data = rdata; 1685 } 1686 1687 /* 1688 * Delete the retransmit data from the context cache entry. 1689 */ 1690 static void retrans_del(client) 1691 svc_rpc_gss_data *client; 1692 { 1693 retrans_entry *rdata; 1694 OM_uint32 minor_stat; 1695 1696 if (client->retrans_data == NULL) 1697 return; 1698 1699 rdata = client->retrans_data; 1700 if (rdata->result.token.length != 0) { 1701 (void) gss_release_buffer(&minor_stat, &rdata->result.token); 1702 } 1703 1704 free((caddr_t)rdata); 1705 client->retrans_data = NULL; 1706 } 1707