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 buf = hdr; 1101 IXDR_PUT_U_INT32(buf, msg->rm_xid); 1102 IXDR_PUT_ENUM(buf, msg->rm_direction); 1103 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_rpcvers); 1104 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_prog); 1105 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_vers); 1106 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_proc); 1107 oa = &msg->rm_call.cb_cred; 1108 IXDR_PUT_ENUM(buf, oa->oa_flavor); 1109 IXDR_PUT_U_INT32(buf, oa->oa_length); 1110 if (oa->oa_length) { 1111 len = RNDUP(oa->oa_length); 1112 tmp = buf; 1113 buf += len / sizeof (int); 1114 *(buf - 1) = 0; 1115 (void) memcpy((caddr_t)tmp, oa->oa_base, oa->oa_length); 1116 } 1117 len = ((char *)buf) - (char *)hdr; 1118 msg_buf.length = len; 1119 msg_buf.value = (char *)hdr; 1120 oa = &msg->rm_call.cb_verf; 1121 tok_buf.length = oa->oa_length; 1122 tok_buf.value = oa->oa_base; 1123 1124 gssstat = gss_verify(&minor_stat, context, &msg_buf, &tok_buf, 1125 qop_state); 1126 if (gssstat != GSS_S_COMPLETE) 1127 return (FALSE); 1128 return (TRUE); 1129 } 1130 1131 /* 1132 * Set response verifier. This is the checksum of the given number. 1133 * (e.g. sequence number or sequence window) 1134 */ 1135 static bool_t 1136 set_response_verf(rqst, msg, cl, num) 1137 struct svc_req *rqst; 1138 struct rpc_msg *msg; 1139 svc_rpc_gss_data *cl; 1140 uint_t num; 1141 { 1142 OM_uint32 minor; 1143 gss_buffer_desc in_buf, out_buf; 1144 uint_t num_net; 1145 1146 num_net = (uint_t)htonl(num); 1147 in_buf.length = sizeof (num); 1148 in_buf.value = (char *)&num_net; 1149 if (gss_sign(&minor, cl->context, cl->qop, &in_buf, 1150 &out_buf) != GSS_S_COMPLETE) 1151 return (FALSE); 1152 rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS; 1153 rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base; 1154 rqst->rq_xprt->xp_verf.oa_length = out_buf.length; 1155 memcpy(rqst->rq_xprt->xp_verf.oa_base, out_buf.value, 1156 out_buf.length); 1157 (void) gss_release_buffer(&minor, &out_buf); 1158 return (TRUE); 1159 } 1160 1161 /* 1162 * Create client context. 1163 */ 1164 static svc_rpc_gss_data * 1165 create_client() 1166 { 1167 svc_rpc_gss_data *client_data; 1168 static uint_t key = 1; 1169 1170 client_data = (svc_rpc_gss_data *) malloc(sizeof (*client_data)); 1171 if (client_data == NULL) 1172 return (NULL); 1173 memset((char *)client_data, 0, sizeof (*client_data)); 1174 1175 /* 1176 * set up client data structure 1177 */ 1178 client_data->established = FALSE; 1179 client_data->locked = FALSE; 1180 client_data->u_cred_set = FALSE; 1181 client_data->context = GSS_C_NO_CONTEXT; 1182 client_data->expiration = init_lifetime + time(0); 1183 client_data->ref_cnt = 1; 1184 client_data->qop = GSS_C_QOP_DEFAULT; 1185 client_data->done_docallback = FALSE; 1186 client_data->stale = FALSE; 1187 client_data->time_secs_set = 0; 1188 client_data->retrans_data = NULL; 1189 mutex_init(&client_data->clm, USYNC_THREAD, NULL); 1190 /* 1191 * Check totals. If we've hit the limit, we destroy a context 1192 * based on LRU method. 1193 */ 1194 mutex_lock(&ctx_mutex); 1195 if (num_gss_contexts >= max_gss_contexts) { 1196 /* 1197 * now try on LRU basis 1198 */ 1199 drop_lru_client(); 1200 if (num_gss_contexts >= max_gss_contexts) { 1201 mutex_unlock(&ctx_mutex); 1202 free((char *)client_data); 1203 return (NULL); 1204 } 1205 } 1206 1207 /* 1208 * The client context handle is a 32-bit key (unsigned int). 1209 * The key is incremented until there is no duplicate for it. 1210 */ 1211 for (;;) { 1212 client_data->key = key++; 1213 if (find_client(client_data->key) == NULL) { 1214 insert_client(client_data); 1215 /* 1216 * Set cleanup callback if we haven't. 1217 */ 1218 if (!cleanup_cb_set) { 1219 old_cleanup_cb = 1220 (void (*)()) __svc_set_proc_cleanup_cb( 1221 (void *)ctx_cleanup); 1222 cleanup_cb_set = TRUE; 1223 } 1224 mutex_unlock(&ctx_mutex); 1225 return (client_data); 1226 } 1227 } 1228 /*NOTREACHED*/ 1229 } 1230 1231 /* 1232 * Insert client context into hash list and LRU list. 1233 */ 1234 static void 1235 insert_client(client_data) 1236 svc_rpc_gss_data *client_data; 1237 { 1238 svc_rpc_gss_data *cl; 1239 int index = (client_data->key & HASHMASK); 1240 1241 client_data->prev = NULL; 1242 cl = clients[index]; 1243 if ((client_data->next = cl) != NULL) 1244 cl->prev = client_data; 1245 clients[index] = client_data; 1246 1247 client_data->lru_prev = NULL; 1248 if ((client_data->lru_next = lru_first) != NULL) 1249 lru_first->lru_prev = client_data; 1250 else 1251 lru_last = client_data; 1252 lru_first = client_data; 1253 1254 num_gss_contexts++; 1255 } 1256 1257 /* 1258 * Fetch a client, given the client context handle. Move it to the 1259 * top of the LRU list since this is the most recently used context. 1260 */ 1261 static svc_rpc_gss_data * 1262 get_client(ctx_handle) 1263 gss_buffer_t ctx_handle; 1264 { 1265 uint_t key = *(uint_t *)ctx_handle->value; 1266 svc_rpc_gss_data *cl; 1267 1268 mutex_lock(&ctx_mutex); 1269 if ((cl = find_client(key)) != NULL) { 1270 mutex_lock(&cl->clm); 1271 if (cl->stale) { 1272 mutex_unlock(&cl->clm); 1273 mutex_unlock(&ctx_mutex); 1274 return (NULL); 1275 } 1276 cl->ref_cnt++; 1277 mutex_unlock(&cl->clm); 1278 if (cl != lru_first) { 1279 cl->lru_prev->lru_next = cl->lru_next; 1280 if (cl->lru_next != NULL) 1281 cl->lru_next->lru_prev = cl->lru_prev; 1282 else 1283 lru_last = cl->lru_prev; 1284 cl->lru_prev = NULL; 1285 cl->lru_next = lru_first; 1286 lru_first->lru_prev = cl; 1287 lru_first = cl; 1288 } 1289 } 1290 mutex_unlock(&ctx_mutex); 1291 return (cl); 1292 } 1293 1294 /* 1295 * Given the client context handle, find the context corresponding to it. 1296 * Don't change its LRU state since it may not be used. 1297 */ 1298 static svc_rpc_gss_data * 1299 find_client(key) 1300 uint_t key; 1301 { 1302 int index = (key & HASHMASK); 1303 svc_rpc_gss_data *cl; 1304 1305 for (cl = clients[index]; cl != NULL; cl = cl->next) { 1306 if (cl->key == key) 1307 break; 1308 } 1309 return (cl); 1310 } 1311 1312 /* 1313 * Destroy a client context. 1314 */ 1315 static void 1316 destroy_client(client_data) 1317 svc_rpc_gss_data *client_data; 1318 { 1319 OM_uint32 minor; 1320 int index = (client_data->key & HASHMASK); 1321 1322 /* 1323 * remove from hash list 1324 */ 1325 if (client_data->prev == NULL) 1326 clients[index] = client_data->next; 1327 else 1328 client_data->prev->next = client_data->next; 1329 if (client_data->next != NULL) 1330 client_data->next->prev = client_data->prev; 1331 1332 /* 1333 * remove from LRU list 1334 */ 1335 if (client_data->lru_prev == NULL) 1336 lru_first = client_data->lru_next; 1337 else 1338 client_data->lru_prev->lru_next = client_data->lru_next; 1339 if (client_data->lru_next != NULL) 1340 client_data->lru_next->lru_prev = client_data->lru_prev; 1341 else 1342 lru_last = client_data->lru_prev; 1343 1344 /* 1345 * If there is a GSS context, clean up GSS state. 1346 */ 1347 if (client_data->context != GSS_C_NO_CONTEXT) { 1348 (void) gss_delete_sec_context(&minor, &client_data->context, 1349 NULL); 1350 if (client_data->client_name) 1351 (void) gss_release_name(&minor, &client_data->client_name); 1352 if (client_data->raw_cred.client_principal) 1353 free((char *)client_data->raw_cred.client_principal); 1354 if (client_data->u_cred.gidlist != NULL) 1355 free((char *)client_data->u_cred.gidlist); 1356 if (client_data->deleg != GSS_C_NO_CREDENTIAL) 1357 (void) gss_release_cred(&minor, &client_data->deleg); 1358 } 1359 1360 if (client_data->retrans_data != NULL) 1361 retrans_del(client_data); 1362 1363 free(client_data); 1364 num_gss_contexts--; 1365 } 1366 1367 /* 1368 * Check for expired client contexts. 1369 */ 1370 static void 1371 sweep_clients() 1372 { 1373 svc_rpc_gss_data *cl, *next; 1374 int index; 1375 1376 for (index = 0; index < HASHMOD; index++) { 1377 cl = clients[index]; 1378 while (cl) { 1379 next = cl->next; 1380 mutex_lock(&cl->clm); 1381 if ((cl->expiration != GSS_C_INDEFINITE && 1382 cl->expiration <= time(0)) || cl->stale) { 1383 cl->stale = TRUE; 1384 if (cl->ref_cnt == 0) { 1385 mutex_unlock(&cl->clm); 1386 destroy_client(cl); 1387 } else 1388 mutex_unlock(&cl->clm); 1389 } else 1390 mutex_unlock(&cl->clm); 1391 cl = next; 1392 } 1393 } 1394 last_swept = time(0); 1395 } 1396 1397 /* 1398 * Drop the least recently used client context, if possible. 1399 */ 1400 static void 1401 drop_lru_client() 1402 { 1403 mutex_lock(&lru_last->clm); 1404 lru_last->stale = TRUE; 1405 mutex_unlock(&lru_last->clm); 1406 if (lru_last->ref_cnt == 0) 1407 destroy_client(lru_last); 1408 else 1409 sweep_clients(); 1410 } 1411 1412 /* 1413 * find service credentials 1414 * return cred if found, 1415 * other wise, NULL 1416 */ 1417 1418 svc_creds_list_t * 1419 find_svc_cred(char *service_name, uint_t program, uint_t version) { 1420 1421 svc_creds_list_t *sc; 1422 1423 if (!svc_creds_list) 1424 return (NULL); 1425 1426 for (sc = svc_creds_list; sc != NULL; sc = sc->next) { 1427 if (program != sc->program || version != sc->version) 1428 continue; 1429 1430 if (strcmp(service_name, sc->server_name) != 0) 1431 continue; 1432 return (sc); 1433 } 1434 return (NULL); 1435 } 1436 1437 /* 1438 * Set the server principal name. 1439 */ 1440 bool_t 1441 __rpc_gss_set_svc_name(server_name, mech, req_time, program, version) 1442 char *server_name; 1443 char *mech; 1444 OM_uint32 req_time; 1445 uint_t program; 1446 uint_t version; 1447 { 1448 gss_name_t name; 1449 svc_creds_list_t *svc_cred; 1450 gss_OID mechanism; 1451 gss_OID_set_desc oid_set_desc; 1452 gss_OID_set oid_set; 1453 OM_uint32 ret_time; 1454 OM_uint32 major, minor; 1455 gss_buffer_desc name_buf; 1456 1457 if (!__rpc_gss_mech_to_oid(mech, &mechanism)) { 1458 return (FALSE); 1459 } 1460 1461 name_buf.value = server_name; 1462 name_buf.length = strlen(server_name); 1463 major = gss_import_name(&minor, &name_buf, 1464 (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &name); 1465 if (major != GSS_S_COMPLETE) { 1466 return (FALSE); 1467 } 1468 1469 /* Check if there is already an entry in the svc_creds_list. */ 1470 rw_wrlock(&cred_lock); 1471 if (svc_cred = find_svc_cred(server_name, program, version)) { 1472 1473 major = gss_add_cred(&minor, svc_cred->cred, name, 1474 mechanism, GSS_C_ACCEPT, 1475 0, req_time, NULL, 1476 &oid_set, NULL, 1477 &ret_time); 1478 (void) gss_release_name(&minor, &name); 1479 if (major == GSS_S_COMPLETE) { 1480 /* 1481 * Successfully added the mech to the cred handle 1482 * free the existing oid_set in svc_cred 1483 */ 1484 gss_release_oid_set(&minor, &svc_cred->oid_set); 1485 svc_cred->oid_set = oid_set; 1486 rw_unlock(&cred_lock); 1487 return (TRUE); 1488 } else if (major == GSS_S_DUPLICATE_ELEMENT) { 1489 rw_unlock(&cred_lock); 1490 return (TRUE); 1491 } else if (major == GSS_S_CREDENTIALS_EXPIRED) { 1492 if (rpc_gss_refresh_svc_cred(svc_cred)) { 1493 rw_unlock(&cred_lock); 1494 return (TRUE); 1495 } else { 1496 rw_unlock(&cred_lock); 1497 return (FALSE); 1498 } 1499 } else { 1500 rw_unlock(&cred_lock); 1501 return (FALSE); 1502 } 1503 } else { 1504 svc_cred = (svc_creds_list_t *)malloc(sizeof (*svc_cred)); 1505 if (svc_cred == NULL) { 1506 (void) gss_release_name(&minor, &name); 1507 rw_unlock(&cred_lock); 1508 return (FALSE); 1509 } 1510 oid_set_desc.count = 1; 1511 oid_set_desc.elements = mechanism; 1512 major = gss_acquire_cred(&minor, name, req_time, 1513 &oid_set_desc, 1514 GSS_C_ACCEPT, 1515 &svc_cred->cred, 1516 &oid_set, &ret_time); 1517 1518 if (major != GSS_S_COMPLETE) { 1519 (void) gss_release_name(&minor, &name); 1520 free(svc_cred); 1521 rw_unlock(&cred_lock); 1522 return (FALSE); 1523 } 1524 1525 svc_cred->name = name; 1526 svc_cred->program = program; 1527 svc_cred->version = version; 1528 svc_cred->req_time = req_time; 1529 svc_cred->oid_set = oid_set; 1530 svc_cred->server_name = strdup(server_name); 1531 if (svc_cred->server_name == NULL) { 1532 (void) gss_release_name(&minor, &name); 1533 free((char *)svc_cred); 1534 rw_unlock(&cred_lock); 1535 return (FALSE); 1536 } 1537 mutex_init(&svc_cred->refresh_mutex, USYNC_THREAD, NULL); 1538 1539 svc_cred->next = svc_creds_list; 1540 svc_creds_list = svc_cred; 1541 svc_creds_count++; 1542 rw_unlock(&cred_lock); 1543 1544 return (TRUE); 1545 } 1546 } 1547 /* 1548 * Refresh server credentials. 1549 */ 1550 static bool_t 1551 rpc_gss_refresh_svc_cred(svc_cred) 1552 svc_creds_list_t *svc_cred; 1553 { 1554 OM_uint32 major, minor; 1555 gss_OID_set oid_set; 1556 OM_uint32 ret_time; 1557 1558 (void) gss_release_cred(&minor, &svc_cred->cred); 1559 svc_cred->cred = GSS_C_NO_CREDENTIAL; 1560 major = gss_acquire_cred(&minor, svc_cred->name, svc_cred->req_time, 1561 svc_cred->oid_set, GSS_C_ACCEPT, &svc_cred->cred, &oid_set, 1562 &ret_time); 1563 if (major != GSS_S_COMPLETE) { 1564 return (FALSE); 1565 } 1566 gss_release_oid_set(&minor, &svc_cred->oid_set); 1567 svc_cred->oid_set = oid_set; 1568 return (TRUE); 1569 } 1570 1571 /* 1572 * Encrypt the serialized arguments from xdr_func applied to xdr_ptr 1573 * and write the result to xdrs. 1574 */ 1575 static bool_t 1576 svc_rpc_gss_wrap(auth, out_xdrs, xdr_func, xdr_ptr) 1577 SVCAUTH *auth; 1578 XDR *out_xdrs; 1579 bool_t (*xdr_func)(); 1580 caddr_t xdr_ptr; 1581 { 1582 svc_rpc_gss_parms_t *gss_parms = &auth->svc_gss_parms; 1583 1584 /* 1585 * If context is not established, or if neither integrity nor 1586 * privacy service is used, don't wrap - just XDR encode. 1587 * Otherwise, wrap data using service and QOP parameters. 1588 */ 1589 if (!gss_parms->established || 1590 gss_parms->service == rpc_gss_svc_none) 1591 return ((*xdr_func)(out_xdrs, xdr_ptr)); 1592 1593 return (__rpc_gss_wrap_data(gss_parms->service, 1594 (OM_uint32)gss_parms->qop_rcvd, 1595 (gss_ctx_id_t)gss_parms->context, 1596 gss_parms->seq_num, 1597 out_xdrs, xdr_func, xdr_ptr)); 1598 } 1599 1600 /* 1601 * Decrypt the serialized arguments and XDR decode them. 1602 */ 1603 static bool_t 1604 svc_rpc_gss_unwrap(auth, in_xdrs, xdr_func, xdr_ptr) 1605 SVCAUTH *auth; 1606 XDR *in_xdrs; 1607 bool_t (*xdr_func)(); 1608 caddr_t xdr_ptr; 1609 { 1610 svc_rpc_gss_parms_t *gss_parms = &auth->svc_gss_parms; 1611 1612 /* 1613 * If context is not established, or if neither integrity nor 1614 * privacy service is used, don't unwrap - just XDR decode. 1615 * Otherwise, unwrap data. 1616 */ 1617 if (!gss_parms->established || 1618 gss_parms->service == rpc_gss_svc_none) 1619 return ((*xdr_func)(in_xdrs, xdr_ptr)); 1620 1621 return (__rpc_gss_unwrap_data(gss_parms->service, 1622 (gss_ctx_id_t)gss_parms->context, 1623 gss_parms->seq_num, 1624 gss_parms->qop_rcvd, 1625 in_xdrs, xdr_func, xdr_ptr)); 1626 } 1627 1628 int 1629 __rpc_gss_svc_max_data_length(req, max_tp_unit_len) 1630 struct svc_req *req; 1631 int max_tp_unit_len; 1632 { 1633 SVCAUTH *svcauth; 1634 svc_rpc_gss_parms_t *gss_parms; 1635 1636 svcauth = __svc_get_svcauth(req->rq_xprt); 1637 gss_parms = &svcauth->svc_gss_parms; 1638 1639 if (!gss_parms->established || max_tp_unit_len <= 0) 1640 return (0); 1641 1642 return (__find_max_data_length(gss_parms->service, 1643 (gss_ctx_id_t)gss_parms->context, 1644 gss_parms->qop_rcvd, max_tp_unit_len)); 1645 } 1646 1647 /* 1648 * Add retransmit entry to the context cache entry for a new xid. 1649 * If there is already an entry, delete it before adding the new one. 1650 */ 1651 static void retrans_add(client, xid, result) 1652 svc_rpc_gss_data *client; 1653 uint32_t xid; 1654 rpc_gss_init_res *result; 1655 { 1656 retrans_entry *rdata; 1657 1658 if (client->retrans_data && client->retrans_data->xid == xid) 1659 return; 1660 1661 rdata = (retrans_entry *) malloc(sizeof (*rdata)); 1662 if (rdata == NULL) 1663 return; 1664 1665 rdata->xid = xid; 1666 rdata->result = *result; 1667 1668 if (result->token.length != 0) { 1669 GSS_DUP_BUFFER(rdata->result.token, result->token); 1670 } 1671 1672 if (client->retrans_data) 1673 retrans_del(client); 1674 1675 client->retrans_data = rdata; 1676 } 1677 1678 /* 1679 * Delete the retransmit data from the context cache entry. 1680 */ 1681 static void retrans_del(client) 1682 svc_rpc_gss_data *client; 1683 { 1684 retrans_entry *rdata; 1685 OM_uint32 minor_stat; 1686 1687 if (client->retrans_data == NULL) 1688 return; 1689 1690 rdata = client->retrans_data; 1691 if (rdata->result.token.length != 0) { 1692 (void) gss_release_buffer(&minor_stat, &rdata->result.token); 1693 } 1694 1695 free((caddr_t)rdata); 1696 client->retrans_data = NULL; 1697 } 1698