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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1995-2003 Sun Microsystems, Inc. 24 * All rights reserved. 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 ret = AUTH_BADCRED; 604 goto error; 605 } 606 607 xdrmem_create(&xdrs, cred->oa_base, cred->oa_length, XDR_DECODE); 608 609 memset((char *)&creds, 0, sizeof (creds)); 610 if (!__xdr_rpc_gss_creds(&xdrs, &creds)) { 611 XDR_DESTROY(&xdrs); 612 ret = AUTH_BADCRED; 613 goto error; 614 } 615 XDR_DESTROY(&xdrs); 616 617 /* 618 * If this is a control message and proc is GSSAPI_INIT, then 619 * create a client handle for this client. Otherwise, look up 620 * the existing handle. 621 */ 622 if (creds.gss_proc == RPCSEC_GSS_INIT) { 623 if (creds.ctx_handle.length != 0) { 624 ret = AUTH_BADCRED; 625 goto error; 626 } 627 if ((client_data = create_client()) == NULL) { 628 ret = AUTH_FAILED; 629 goto error; 630 } 631 } else { 632 /* 633 * Only verify values for service parameter when proc 634 * not RPCSEC_GSS_INIT or RPCSEC_GSS_CONTINUE_INIT. 635 * RFC2203 says contents for sequence and service args 636 * are undefined for creation procs. 637 * 638 * Note: only need to check for *CONTINUE_INIT here because 639 * if() clause already checked for RPCSEC_GSS_INIT 640 */ 641 if (creds.gss_proc != RPCSEC_GSS_CONTINUE_INIT) { 642 switch (creds.service) { 643 case rpc_gss_svc_none: 644 case rpc_gss_svc_integrity: 645 case rpc_gss_svc_privacy: 646 break; 647 default: 648 ret = AUTH_BADCRED; 649 goto error; 650 } 651 } 652 if (creds.ctx_handle.length == 0) { 653 ret = AUTH_BADCRED; 654 goto error; 655 } 656 if ((client_data = get_client(&creds.ctx_handle)) == NULL) { 657 ret = RPCSEC_GSS_NOCRED; 658 goto error; 659 } 660 } 661 662 /* 663 * lock the client data until it's safe; if it's already stale, 664 * no more processing is possible 665 */ 666 mutex_lock(&client_data->clm); 667 if (client_data->stale) { 668 ret = RPCSEC_GSS_NOCRED; 669 goto error2; 670 } 671 672 /* 673 * Any response we send will use ctx_handle, so set it now; 674 * also set seq_window since this won't change. 675 */ 676 call_res.ctx_handle.length = sizeof (client_data->key); 677 call_res.ctx_handle.value = (char *)&client_data->key; 678 call_res.seq_window = SEQ_WIN; 679 680 /* 681 * Set the appropriate wrap/unwrap routine for RPCSEC_GSS. 682 */ 683 svcauth = __svc_get_svcauth(rqst->rq_xprt); 684 svcauth->svc_ah_ops = svc_rpc_gss_ops; 685 svcauth->svc_ah_private = (caddr_t)client_data; 686 687 /* 688 * Keep copy of parameters we'll need for response, for the 689 * sake of reentrancy (we don't want to look in the context 690 * data because when we are sending a response, another 691 * request may have come in. 692 */ 693 gss_parms = &svcauth->svc_gss_parms; 694 gss_parms->established = client_data->established; 695 gss_parms->service = creds.service; 696 gss_parms->qop_rcvd = (uint_t)client_data->qop; 697 gss_parms->context = (void *)client_data->context; 698 gss_parms->seq_num = creds.seq_num; 699 700 if (!client_data->established) { 701 if (creds.gss_proc == RPCSEC_GSS_DATA) { 702 ret = RPCSEC_GSS_FAILED; 703 client_data->stale = TRUE; 704 goto error2; 705 } 706 707 /* 708 * If the context is not established, then only GSSAPI_INIT 709 * and _CONTINUE requests are valid. 710 */ 711 if (creds.gss_proc != RPCSEC_GSS_INIT && creds.gss_proc != 712 RPCSEC_GSS_CONTINUE_INIT) { 713 ret = RPCSEC_GSS_FAILED; 714 client_data->stale = TRUE; 715 goto error2; 716 } 717 718 /* 719 * call is for us, deserialize arguments 720 */ 721 memset(&call_arg, 0, sizeof (call_arg)); 722 if (!svc_getargs(rqst->rq_xprt, __xdr_rpc_gss_init_arg, 723 (caddr_t)&call_arg)) { 724 ret = RPCSEC_GSS_FAILED; 725 client_data->stale = TRUE; 726 goto error2; 727 } 728 729 gssstat = GSS_S_FAILURE; 730 minor_stat = 0; 731 rw_rdlock(&cred_lock); 732 /* 733 * set next sc to point to the server cred 734 * if the client_data contains server_creds 735 */ 736 for (sc = svc_creds_list; sc != NULL; sc = sc->next) { 737 if (rqst->rq_prog != sc->program || 738 rqst->rq_vers != sc->version) 739 continue; 740 741 mutex_lock(&sc->refresh_mutex); 742 gssstat = gss_accept_sec_context(&minor_stat, 743 &client_data->context, 744 sc->cred, 745 &call_arg, 746 GSS_C_NO_CHANNEL_BINDINGS, 747 &client_data->client_name, 748 &mech_type, 749 &output_token, 750 &ret_flags, 751 &time_rec, 752 NULL); 753 754 if (gssstat == GSS_S_CREDENTIALS_EXPIRED) { 755 if (rpc_gss_refresh_svc_cred(sc)) { 756 gssstat = gss_accept_sec_context( 757 &minor_stat, 758 &client_data->context, 759 sc->cred, 760 &call_arg, 761 GSS_C_NO_CHANNEL_BINDINGS, 762 &client_data->client_name, 763 &mech_type, 764 &output_token, 765 &ret_flags, 766 &time_rec, 767 NULL); 768 mutex_unlock(&sc->refresh_mutex); 769 770 } else { 771 mutex_unlock(&sc->refresh_mutex); 772 gssstat = GSS_S_NO_CRED; 773 break; 774 } 775 776 } else 777 mutex_unlock(&sc->refresh_mutex); 778 779 if (gssstat == GSS_S_COMPLETE) { 780 /* 781 * Server_creds was right - set it. Also 782 * set the raw and unix credentials at this 783 * point. This saves a lot of computation 784 * later when credentials are retrieved. 785 */ 786 /* 787 * XXX server_creds will prob be stale 788 * after rpc_gss_refresh_svc_cred(), but 789 * it appears not to ever be referenced 790 * anyways. 791 */ 792 mutex_lock(&sc->refresh_mutex); 793 client_data->server_creds = sc->cred; 794 client_data->raw_cred.version = creds.version; 795 client_data->raw_cred.service = creds.service; 796 client_data->raw_cred.svc_principal = 797 sc->server_name; 798 mutex_unlock(&sc->refresh_mutex); 799 800 if ((client_data->raw_cred.mechanism 801 = __rpc_gss_oid_to_mech(mech_type)) 802 == NULL) { 803 gssstat = GSS_S_FAILURE; 804 (void) gss_release_buffer(&minor_stat, 805 &output_token); 806 } else if (!set_client_principal(client_data-> 807 client_name, &client_data-> 808 raw_cred.client_principal)) { 809 gssstat = GSS_S_FAILURE; 810 (void) gss_release_buffer(&minor_stat, 811 &output_token); 812 } 813 break; 814 } 815 816 if (gssstat == GSS_S_CONTINUE_NEEDED) { 817 /* 818 * XXX server_creds will prob be stale 819 * after rpc_gss_refresh_svc_cred(), but 820 * it appears not to ever be referenced 821 * anyways. 822 */ 823 mutex_lock(&sc->refresh_mutex); 824 client_data->server_creds = sc->cred; 825 mutex_unlock(&sc->refresh_mutex); 826 break; 827 } 828 829 } 830 rw_unlock(&cred_lock); 831 832 call_res.gss_major = gssstat; 833 call_res.gss_minor = minor_stat; 834 835 xdr_free(__xdr_rpc_gss_init_arg, (caddr_t)&call_arg); 836 837 if (gssstat != GSS_S_COMPLETE && 838 gssstat != GSS_S_CONTINUE_NEEDED) { 839 /* 840 * We have a failure - send response and delete 841 * the context. Don't dispatch. Set ctx_handle 842 * to NULL and seq_window to 0. 843 */ 844 call_res.ctx_handle.length = 0; 845 call_res.ctx_handle.value = NULL; 846 call_res.seq_window = 0; 847 848 svc_sendreply(rqst->rq_xprt, __xdr_rpc_gss_init_res, 849 (caddr_t)&call_res); 850 *no_dispatch = TRUE; 851 ret = AUTH_OK; 852 client_data->stale = TRUE; 853 goto error2; 854 } 855 856 /* 857 * This step succeeded. Send a response, along with 858 * a token if there's one. Don't dispatch. 859 */ 860 if (output_token.length != 0) { 861 GSS_COPY_BUFFER(call_res.token, output_token); 862 } 863 864 /* 865 * set response verifier: checksum of SEQ_WIN 866 */ 867 if (gssstat == GSS_S_COMPLETE) { 868 if (!set_response_verf(rqst, msg, client_data, 869 (uint_t)SEQ_WIN)) { 870 ret = RPCSEC_GSS_FAILED; 871 client_data->stale = TRUE; 872 (void) gss_release_buffer(&minor_stat, 873 &output_token); 874 goto error2; 875 } 876 } 877 878 svc_sendreply(rqst->rq_xprt, __xdr_rpc_gss_init_res, 879 (caddr_t)&call_res); 880 /* 881 * Cache last response in case it is lost and the client 882 * retries on an established context. 883 */ 884 (void) retrans_add(client_data, msg->rm_xid, &call_res); 885 *no_dispatch = TRUE; 886 (void) gss_release_buffer(&minor_stat, &output_token); 887 888 /* 889 * If appropriate, set established to TRUE *after* sending 890 * response (otherwise, the client will receive the final 891 * token encrypted) 892 */ 893 if (gssstat == GSS_S_COMPLETE) { 894 /* 895 * Context is established. Set expiry time for 896 * context (the minimum of time_rec and max_lifetime). 897 */ 898 client_data->seq_num = 1; 899 if (time_rec == GSS_C_INDEFINITE) { 900 if (max_lifetime != GSS_C_INDEFINITE) 901 client_data->expiration = 902 max_lifetime + time(0); 903 else 904 client_data->expiration = 905 GSS_C_INDEFINITE; 906 } else if (max_lifetime == GSS_C_INDEFINITE || 907 max_lifetime > time_rec) 908 client_data->expiration = time_rec + time(0); 909 else 910 client_data->expiration = max_lifetime + 911 time(0); 912 client_data->established = TRUE; 913 } 914 915 } else { 916 if ((creds.gss_proc != RPCSEC_GSS_DATA) && 917 (creds.gss_proc != RPCSEC_GSS_DESTROY)) { 918 919 switch (creds.gss_proc) { 920 921 case RPCSEC_GSS_CONTINUE_INIT: 922 /* 923 * This is an established context. Continue to 924 * satisfy retried continue init requests out of 925 * the retransmit cache. Throw away any that don't 926 * have a matching xid or the cach is empty. 927 * Delete the retransmit cache once the client sends 928 * a data request. 929 */ 930 if (client_data->retrans_data && 931 (client_data->retrans_data->xid == msg->rm_xid)) { 932 933 retrans_result = &client_data->retrans_data->result; 934 if (set_response_verf(rqst, msg, client_data, 935 (uint_t)retrans_result->seq_window)) { 936 937 gss_parms->established = FALSE; 938 svc_sendreply(rqst->rq_xprt, 939 __xdr_rpc_gss_init_res, 940 (caddr_t)retrans_result); 941 *no_dispatch = TRUE; 942 goto success; 943 } 944 } 945 /* fall thru to default */ 946 947 default: 948 syslog(LOG_ERR, "_svcrpcsec_gss: non-data request " 949 "on an established context"); 950 ret = AUTH_FAILED; 951 goto error2; 952 } 953 } 954 955 /* 956 * Once the context is established and there is no more 957 * retransmission of last continue init request, it is safe 958 * to delete the retransmit cache entry. 959 */ 960 if (client_data->retrans_data) 961 retrans_del(client_data); 962 963 /* 964 * Context is already established. Check verifier, and 965 * note parameters we will need for response in gss_parms. 966 */ 967 if (!check_verf(msg, client_data->context, 968 &gss_parms->qop_rcvd)) { 969 ret = RPCSEC_GSS_NOCRED; 970 goto error2; 971 } 972 /* 973 * Check and invoke callback if necessary. 974 */ 975 if (!client_data->done_docallback) { 976 client_data->done_docallback = TRUE; 977 client_data->qop = gss_parms->qop_rcvd; 978 client_data->raw_cred.qop = __rpc_gss_num_to_qop( 979 client_data->raw_cred.mechanism, 980 gss_parms->qop_rcvd); 981 client_data->raw_cred.service = creds.service; 982 if (!do_callback(rqst, client_data)) { 983 ret = AUTH_FAILED; 984 client_data->stale = TRUE; 985 goto error2; 986 } 987 } 988 989 /* 990 * If the context was locked, make sure that the client 991 * has not changed QOP. 992 */ 993 if (client_data->locked && 994 gss_parms->qop_rcvd != client_data->qop) { 995 ret = AUTH_BADVERF; 996 goto error2; 997 } 998 999 /* 1000 * Validate sequence number. 1001 */ 1002 if (!check_seq(client_data, creds.seq_num, 1003 &client_data->stale)) { 1004 if (client_data->stale) 1005 ret = RPCSEC_GSS_FAILED; 1006 else { 1007 /* 1008 * Operational error, drop packet silently. 1009 * The client will recover after timing out, 1010 * assuming this is a client error and not 1011 * a relpay attack. Don't dispatch. 1012 */ 1013 ret = AUTH_OK; 1014 *no_dispatch = TRUE; 1015 } 1016 goto error2; 1017 } 1018 1019 /* 1020 * set response verifier 1021 */ 1022 if (!set_response_verf(rqst, msg, client_data, creds.seq_num)) { 1023 ret = RPCSEC_GSS_FAILED; 1024 client_data->stale = TRUE; 1025 goto error2; 1026 } 1027 1028 /* 1029 * If this is a control message RPCSEC_GSS_DESTROY, process 1030 * the call; otherwise, return AUTH_OK so it will be 1031 * dispatched to the application server. 1032 */ 1033 if (creds.gss_proc == RPCSEC_GSS_DESTROY) { 1034 svc_sendreply(rqst->rq_xprt, xdr_void, NULL); 1035 *no_dispatch = TRUE; 1036 client_data->stale = TRUE; 1037 1038 } else { 1039 /* 1040 * This should be an RPCSEC_GSS_DATA request. 1041 * If context is locked, make sure that the client 1042 * has not changed the security service. 1043 */ 1044 if (client_data->locked && 1045 client_data->raw_cred.service != creds.service) { 1046 ret = AUTH_FAILED; 1047 goto error2; 1048 } 1049 1050 /* 1051 * Set client credentials to raw credential 1052 * structure in context. This is okay, since 1053 * this will not change during the lifetime of 1054 * the context (so it's MT safe). 1055 */ 1056 rqst->rq_clntcred = (char *)&client_data->raw_cred; 1057 } 1058 } 1059 1060 success: 1061 /* 1062 * Success. 1063 */ 1064 if (creds.ctx_handle.length != 0) 1065 xdr_free(__xdr_rpc_gss_creds, (caddr_t)&creds); 1066 mutex_unlock(&client_data->clm); 1067 return (AUTH_OK); 1068 error2: 1069 mutex_unlock(&client_data->clm); 1070 error: 1071 /* 1072 * Failure. 1073 */ 1074 if (creds.ctx_handle.length != 0) 1075 xdr_free(__xdr_rpc_gss_creds, (caddr_t)&creds); 1076 return (ret); 1077 } 1078 1079 /* 1080 * Check verifier. The verifier is the checksum of the RPC header 1081 * upto and including the credentials field. 1082 */ 1083 static bool_t 1084 check_verf(msg, context, qop_state) 1085 struct rpc_msg *msg; 1086 gss_ctx_id_t context; 1087 int *qop_state; 1088 { 1089 int *buf, *tmp; 1090 int hdr[32]; 1091 struct opaque_auth *oa; 1092 int len; 1093 gss_buffer_desc msg_buf; 1094 gss_buffer_desc tok_buf; 1095 OM_uint32 gssstat, minor_stat; 1096 1097 /* 1098 * We have to reconstruct the RPC header from the previously 1099 * parsed information, since we haven't kept the header intact. 1100 */ 1101 buf = hdr; 1102 IXDR_PUT_U_INT32(buf, msg->rm_xid); 1103 IXDR_PUT_ENUM(buf, msg->rm_direction); 1104 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_rpcvers); 1105 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_prog); 1106 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_vers); 1107 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_proc); 1108 oa = &msg->rm_call.cb_cred; 1109 IXDR_PUT_ENUM(buf, oa->oa_flavor); 1110 IXDR_PUT_U_INT32(buf, oa->oa_length); 1111 if (oa->oa_length) { 1112 len = RNDUP(oa->oa_length); 1113 tmp = buf; 1114 buf += len / sizeof (int); 1115 *(buf - 1) = 0; 1116 (void) memcpy((caddr_t)tmp, oa->oa_base, oa->oa_length); 1117 } 1118 len = ((char *)buf) - (char *)hdr; 1119 msg_buf.length = len; 1120 msg_buf.value = (char *)hdr; 1121 oa = &msg->rm_call.cb_verf; 1122 tok_buf.length = oa->oa_length; 1123 tok_buf.value = oa->oa_base; 1124 1125 gssstat = gss_verify(&minor_stat, context, &msg_buf, &tok_buf, 1126 qop_state); 1127 if (gssstat != GSS_S_COMPLETE) 1128 return (FALSE); 1129 return (TRUE); 1130 } 1131 1132 /* 1133 * Set response verifier. This is the checksum of the given number. 1134 * (e.g. sequence number or sequence window) 1135 */ 1136 static bool_t 1137 set_response_verf(rqst, msg, cl, num) 1138 struct svc_req *rqst; 1139 struct rpc_msg *msg; 1140 svc_rpc_gss_data *cl; 1141 uint_t num; 1142 { 1143 OM_uint32 minor; 1144 gss_buffer_desc in_buf, out_buf; 1145 uint_t num_net; 1146 1147 num_net = (uint_t)htonl(num); 1148 in_buf.length = sizeof (num); 1149 in_buf.value = (char *)&num_net; 1150 if (gss_sign(&minor, cl->context, cl->qop, &in_buf, 1151 &out_buf) != GSS_S_COMPLETE) 1152 return (FALSE); 1153 rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS; 1154 rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base; 1155 rqst->rq_xprt->xp_verf.oa_length = out_buf.length; 1156 memcpy(rqst->rq_xprt->xp_verf.oa_base, out_buf.value, 1157 out_buf.length); 1158 (void) gss_release_buffer(&minor, &out_buf); 1159 return (TRUE); 1160 } 1161 1162 /* 1163 * Create client context. 1164 */ 1165 static svc_rpc_gss_data * 1166 create_client() 1167 { 1168 svc_rpc_gss_data *client_data; 1169 static uint_t key = 1; 1170 1171 client_data = (svc_rpc_gss_data *) malloc(sizeof (*client_data)); 1172 if (client_data == NULL) 1173 return (NULL); 1174 memset((char *)client_data, 0, sizeof (*client_data)); 1175 1176 /* 1177 * set up client data structure 1178 */ 1179 client_data->established = FALSE; 1180 client_data->locked = FALSE; 1181 client_data->u_cred_set = FALSE; 1182 client_data->context = GSS_C_NO_CONTEXT; 1183 client_data->expiration = init_lifetime + time(0); 1184 client_data->ref_cnt = 1; 1185 client_data->qop = GSS_C_QOP_DEFAULT; 1186 client_data->done_docallback = FALSE; 1187 client_data->stale = FALSE; 1188 client_data->time_secs_set = 0; 1189 client_data->retrans_data = NULL; 1190 mutex_init(&client_data->clm, USYNC_THREAD, NULL); 1191 /* 1192 * Check totals. If we've hit the limit, we destroy a context 1193 * based on LRU method. 1194 */ 1195 mutex_lock(&ctx_mutex); 1196 if (num_gss_contexts >= max_gss_contexts) { 1197 /* 1198 * now try on LRU basis 1199 */ 1200 drop_lru_client(); 1201 if (num_gss_contexts >= max_gss_contexts) { 1202 mutex_unlock(&ctx_mutex); 1203 free((char *)client_data); 1204 return (NULL); 1205 } 1206 } 1207 1208 /* 1209 * The client context handle is a 32-bit key (unsigned int). 1210 * The key is incremented until there is no duplicate for it. 1211 */ 1212 for (;;) { 1213 client_data->key = key++; 1214 if (find_client(client_data->key) == NULL) { 1215 insert_client(client_data); 1216 /* 1217 * Set cleanup callback if we haven't. 1218 */ 1219 if (!cleanup_cb_set) { 1220 old_cleanup_cb = 1221 (void (*)()) __svc_set_proc_cleanup_cb( 1222 (void *)ctx_cleanup); 1223 cleanup_cb_set = TRUE; 1224 } 1225 mutex_unlock(&ctx_mutex); 1226 return (client_data); 1227 } 1228 } 1229 /*NOTREACHED*/ 1230 } 1231 1232 /* 1233 * Insert client context into hash list and LRU list. 1234 */ 1235 static void 1236 insert_client(client_data) 1237 svc_rpc_gss_data *client_data; 1238 { 1239 svc_rpc_gss_data *cl; 1240 int index = (client_data->key & HASHMASK); 1241 1242 client_data->prev = NULL; 1243 cl = clients[index]; 1244 if ((client_data->next = cl) != NULL) 1245 cl->prev = client_data; 1246 clients[index] = client_data; 1247 1248 client_data->lru_prev = NULL; 1249 if ((client_data->lru_next = lru_first) != NULL) 1250 lru_first->lru_prev = client_data; 1251 else 1252 lru_last = client_data; 1253 lru_first = client_data; 1254 1255 num_gss_contexts++; 1256 } 1257 1258 /* 1259 * Fetch a client, given the client context handle. Move it to the 1260 * top of the LRU list since this is the most recently used context. 1261 */ 1262 static svc_rpc_gss_data * 1263 get_client(ctx_handle) 1264 gss_buffer_t ctx_handle; 1265 { 1266 uint_t key = *(uint_t *)ctx_handle->value; 1267 svc_rpc_gss_data *cl; 1268 1269 mutex_lock(&ctx_mutex); 1270 if ((cl = find_client(key)) != NULL) { 1271 mutex_lock(&cl->clm); 1272 if (cl->stale) { 1273 mutex_unlock(&cl->clm); 1274 mutex_unlock(&ctx_mutex); 1275 return (NULL); 1276 } 1277 cl->ref_cnt++; 1278 mutex_unlock(&cl->clm); 1279 if (cl != lru_first) { 1280 cl->lru_prev->lru_next = cl->lru_next; 1281 if (cl->lru_next != NULL) 1282 cl->lru_next->lru_prev = cl->lru_prev; 1283 else 1284 lru_last = cl->lru_prev; 1285 cl->lru_prev = NULL; 1286 cl->lru_next = lru_first; 1287 lru_first->lru_prev = cl; 1288 lru_first = cl; 1289 } 1290 } 1291 mutex_unlock(&ctx_mutex); 1292 return (cl); 1293 } 1294 1295 /* 1296 * Given the client context handle, find the context corresponding to it. 1297 * Don't change its LRU state since it may not be used. 1298 */ 1299 static svc_rpc_gss_data * 1300 find_client(key) 1301 uint_t key; 1302 { 1303 int index = (key & HASHMASK); 1304 svc_rpc_gss_data *cl; 1305 1306 for (cl = clients[index]; cl != NULL; cl = cl->next) { 1307 if (cl->key == key) 1308 break; 1309 } 1310 return (cl); 1311 } 1312 1313 /* 1314 * Destroy a client context. 1315 */ 1316 static void 1317 destroy_client(client_data) 1318 svc_rpc_gss_data *client_data; 1319 { 1320 OM_uint32 minor; 1321 int index = (client_data->key & HASHMASK); 1322 1323 /* 1324 * remove from hash list 1325 */ 1326 if (client_data->prev == NULL) 1327 clients[index] = client_data->next; 1328 else 1329 client_data->prev->next = client_data->next; 1330 if (client_data->next != NULL) 1331 client_data->next->prev = client_data->prev; 1332 1333 /* 1334 * remove from LRU list 1335 */ 1336 if (client_data->lru_prev == NULL) 1337 lru_first = client_data->lru_next; 1338 else 1339 client_data->lru_prev->lru_next = client_data->lru_next; 1340 if (client_data->lru_next != NULL) 1341 client_data->lru_next->lru_prev = client_data->lru_prev; 1342 else 1343 lru_last = client_data->lru_prev; 1344 1345 /* 1346 * If there is a GSS context, clean up GSS state. 1347 */ 1348 if (client_data->context != GSS_C_NO_CONTEXT) { 1349 (void) gss_delete_sec_context(&minor, &client_data->context, 1350 NULL); 1351 if (client_data->client_name) 1352 (void) gss_release_name(&minor, &client_data->client_name); 1353 if (client_data->raw_cred.client_principal) 1354 free((char *)client_data->raw_cred.client_principal); 1355 if (client_data->u_cred.gidlist != NULL) 1356 free((char *)client_data->u_cred.gidlist); 1357 if (client_data->deleg != GSS_C_NO_CREDENTIAL) 1358 (void) gss_release_cred(&minor, &client_data->deleg); 1359 } 1360 1361 if (client_data->retrans_data != NULL) 1362 retrans_del(client_data); 1363 1364 free(client_data); 1365 num_gss_contexts--; 1366 } 1367 1368 /* 1369 * Check for expired client contexts. 1370 */ 1371 static void 1372 sweep_clients() 1373 { 1374 svc_rpc_gss_data *cl, *next; 1375 int index; 1376 1377 for (index = 0; index < HASHMOD; index++) { 1378 cl = clients[index]; 1379 while (cl) { 1380 next = cl->next; 1381 mutex_lock(&cl->clm); 1382 if ((cl->expiration != GSS_C_INDEFINITE && 1383 cl->expiration <= time(0)) || cl->stale) { 1384 cl->stale = TRUE; 1385 if (cl->ref_cnt == 0) { 1386 mutex_unlock(&cl->clm); 1387 destroy_client(cl); 1388 } else 1389 mutex_unlock(&cl->clm); 1390 } else 1391 mutex_unlock(&cl->clm); 1392 cl = next; 1393 } 1394 } 1395 last_swept = time(0); 1396 } 1397 1398 /* 1399 * Drop the least recently used client context, if possible. 1400 */ 1401 static void 1402 drop_lru_client() 1403 { 1404 mutex_lock(&lru_last->clm); 1405 lru_last->stale = TRUE; 1406 mutex_unlock(&lru_last->clm); 1407 if (lru_last->ref_cnt == 0) 1408 destroy_client(lru_last); 1409 else 1410 sweep_clients(); 1411 } 1412 1413 /* 1414 * find service credentials 1415 * return cred if found, 1416 * other wise, NULL 1417 */ 1418 1419 svc_creds_list_t * 1420 find_svc_cred(char *service_name, uint_t program, uint_t version) { 1421 1422 svc_creds_list_t *sc; 1423 1424 if (!svc_creds_list) 1425 return (NULL); 1426 1427 for (sc = svc_creds_list; sc != NULL; sc = sc->next) { 1428 if (program != sc->program || version != sc->version) 1429 continue; 1430 1431 if (strcmp(service_name, sc->server_name) != 0) 1432 continue; 1433 return (sc); 1434 } 1435 return (NULL); 1436 } 1437 1438 /* 1439 * Set the server principal name. 1440 */ 1441 bool_t 1442 __rpc_gss_set_svc_name(server_name, mech, req_time, program, version) 1443 char *server_name; 1444 char *mech; 1445 OM_uint32 req_time; 1446 uint_t program; 1447 uint_t version; 1448 { 1449 gss_name_t name; 1450 svc_creds_list_t *svc_cred; 1451 gss_OID mechanism; 1452 gss_OID_set_desc oid_set_desc; 1453 gss_OID_set oid_set; 1454 OM_uint32 ret_time; 1455 OM_uint32 major, minor; 1456 gss_buffer_desc name_buf; 1457 1458 if (!__rpc_gss_mech_to_oid(mech, &mechanism)) { 1459 return (FALSE); 1460 } 1461 1462 name_buf.value = server_name; 1463 name_buf.length = strlen(server_name); 1464 major = gss_import_name(&minor, &name_buf, 1465 (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &name); 1466 if (major != GSS_S_COMPLETE) { 1467 return (FALSE); 1468 } 1469 1470 /* Check if there is already an entry in the svc_creds_list. */ 1471 rw_wrlock(&cred_lock); 1472 if (svc_cred = find_svc_cred(server_name, program, version)) { 1473 1474 major = gss_add_cred(&minor, svc_cred->cred, name, 1475 mechanism, GSS_C_ACCEPT, 1476 0, req_time, NULL, 1477 &oid_set, NULL, 1478 &ret_time); 1479 (void) gss_release_name(&minor, &name); 1480 if (major == GSS_S_COMPLETE) { 1481 /* 1482 * Successfully added the mech to the cred handle 1483 * free the existing oid_set in svc_cred 1484 */ 1485 gss_release_oid_set(&minor, &svc_cred->oid_set); 1486 svc_cred->oid_set = oid_set; 1487 rw_unlock(&cred_lock); 1488 return (TRUE); 1489 } else if (major == GSS_S_DUPLICATE_ELEMENT) { 1490 rw_unlock(&cred_lock); 1491 return (TRUE); 1492 } else if (major == GSS_S_CREDENTIALS_EXPIRED) { 1493 if (rpc_gss_refresh_svc_cred(svc_cred)) { 1494 rw_unlock(&cred_lock); 1495 return (TRUE); 1496 } else { 1497 rw_unlock(&cred_lock); 1498 return (FALSE); 1499 } 1500 } else { 1501 rw_unlock(&cred_lock); 1502 return (FALSE); 1503 } 1504 } else { 1505 svc_cred = (svc_creds_list_t *)malloc(sizeof (*svc_cred)); 1506 if (svc_cred == NULL) { 1507 (void) gss_release_name(&minor, &name); 1508 rw_unlock(&cred_lock); 1509 return (FALSE); 1510 } 1511 oid_set_desc.count = 1; 1512 oid_set_desc.elements = mechanism; 1513 major = gss_acquire_cred(&minor, name, req_time, 1514 &oid_set_desc, 1515 GSS_C_ACCEPT, 1516 &svc_cred->cred, 1517 &oid_set, &ret_time); 1518 1519 if (major != GSS_S_COMPLETE) { 1520 (void) gss_release_name(&minor, &name); 1521 free(svc_cred); 1522 rw_unlock(&cred_lock); 1523 return (FALSE); 1524 } 1525 1526 svc_cred->name = name; 1527 svc_cred->program = program; 1528 svc_cred->version = version; 1529 svc_cred->req_time = req_time; 1530 svc_cred->oid_set = oid_set; 1531 svc_cred->server_name = strdup(server_name); 1532 if (svc_cred->server_name == NULL) { 1533 (void) gss_release_name(&minor, &name); 1534 free((char *)svc_cred); 1535 rw_unlock(&cred_lock); 1536 return (FALSE); 1537 } 1538 mutex_init(&svc_cred->refresh_mutex, USYNC_THREAD, NULL); 1539 1540 svc_cred->next = svc_creds_list; 1541 svc_creds_list = svc_cred; 1542 svc_creds_count++; 1543 rw_unlock(&cred_lock); 1544 1545 return (TRUE); 1546 } 1547 } 1548 /* 1549 * Refresh server credentials. 1550 */ 1551 static bool_t 1552 rpc_gss_refresh_svc_cred(svc_cred) 1553 svc_creds_list_t *svc_cred; 1554 { 1555 OM_uint32 major, minor; 1556 gss_OID_set oid_set; 1557 OM_uint32 ret_time; 1558 1559 (void) gss_release_cred(&minor, &svc_cred->cred); 1560 svc_cred->cred = GSS_C_NO_CREDENTIAL; 1561 major = gss_acquire_cred(&minor, svc_cred->name, svc_cred->req_time, 1562 svc_cred->oid_set, GSS_C_ACCEPT, &svc_cred->cred, &oid_set, 1563 &ret_time); 1564 if (major != GSS_S_COMPLETE) { 1565 return (FALSE); 1566 } 1567 gss_release_oid_set(&minor, &svc_cred->oid_set); 1568 svc_cred->oid_set = oid_set; 1569 return (TRUE); 1570 } 1571 1572 /* 1573 * Encrypt the serialized arguments from xdr_func applied to xdr_ptr 1574 * and write the result to xdrs. 1575 */ 1576 static bool_t 1577 svc_rpc_gss_wrap(auth, out_xdrs, xdr_func, xdr_ptr) 1578 SVCAUTH *auth; 1579 XDR *out_xdrs; 1580 bool_t (*xdr_func)(); 1581 caddr_t xdr_ptr; 1582 { 1583 svc_rpc_gss_parms_t *gss_parms = &auth->svc_gss_parms; 1584 1585 /* 1586 * If context is not established, or if neither integrity nor 1587 * privacy service is used, don't wrap - just XDR encode. 1588 * Otherwise, wrap data using service and QOP parameters. 1589 */ 1590 if (!gss_parms->established || 1591 gss_parms->service == rpc_gss_svc_none) 1592 return ((*xdr_func)(out_xdrs, xdr_ptr)); 1593 1594 return (__rpc_gss_wrap_data(gss_parms->service, 1595 (OM_uint32)gss_parms->qop_rcvd, 1596 (gss_ctx_id_t)gss_parms->context, 1597 gss_parms->seq_num, 1598 out_xdrs, xdr_func, xdr_ptr)); 1599 } 1600 1601 /* 1602 * Decrypt the serialized arguments and XDR decode them. 1603 */ 1604 static bool_t 1605 svc_rpc_gss_unwrap(auth, in_xdrs, xdr_func, xdr_ptr) 1606 SVCAUTH *auth; 1607 XDR *in_xdrs; 1608 bool_t (*xdr_func)(); 1609 caddr_t xdr_ptr; 1610 { 1611 svc_rpc_gss_parms_t *gss_parms = &auth->svc_gss_parms; 1612 1613 /* 1614 * If context is not established, or if neither integrity nor 1615 * privacy service is used, don't unwrap - just XDR decode. 1616 * Otherwise, unwrap data. 1617 */ 1618 if (!gss_parms->established || 1619 gss_parms->service == rpc_gss_svc_none) 1620 return ((*xdr_func)(in_xdrs, xdr_ptr)); 1621 1622 return (__rpc_gss_unwrap_data(gss_parms->service, 1623 (gss_ctx_id_t)gss_parms->context, 1624 gss_parms->seq_num, 1625 gss_parms->qop_rcvd, 1626 in_xdrs, xdr_func, xdr_ptr)); 1627 } 1628 1629 int 1630 __rpc_gss_svc_max_data_length(req, max_tp_unit_len) 1631 struct svc_req *req; 1632 int max_tp_unit_len; 1633 { 1634 SVCAUTH *svcauth; 1635 svc_rpc_gss_parms_t *gss_parms; 1636 1637 svcauth = __svc_get_svcauth(req->rq_xprt); 1638 gss_parms = &svcauth->svc_gss_parms; 1639 1640 if (!gss_parms->established || max_tp_unit_len <= 0) 1641 return (0); 1642 1643 return (__find_max_data_length(gss_parms->service, 1644 (gss_ctx_id_t)gss_parms->context, 1645 gss_parms->qop_rcvd, max_tp_unit_len)); 1646 } 1647 1648 /* 1649 * Add retransmit entry to the context cache entry for a new xid. 1650 * If there is already an entry, delete it before adding the new one. 1651 */ 1652 static void retrans_add(client, xid, result) 1653 svc_rpc_gss_data *client; 1654 uint32_t xid; 1655 rpc_gss_init_res *result; 1656 { 1657 retrans_entry *rdata; 1658 1659 if (client->retrans_data && client->retrans_data->xid == xid) 1660 return; 1661 1662 rdata = (retrans_entry *) malloc(sizeof (*rdata)); 1663 if (rdata == NULL) 1664 return; 1665 1666 rdata->xid = xid; 1667 rdata->result = *result; 1668 1669 if (result->token.length != 0) { 1670 GSS_DUP_BUFFER(rdata->result.token, result->token); 1671 } 1672 1673 if (client->retrans_data) 1674 retrans_del(client); 1675 1676 client->retrans_data = rdata; 1677 } 1678 1679 /* 1680 * Delete the retransmit data from the context cache entry. 1681 */ 1682 static void retrans_del(client) 1683 svc_rpc_gss_data *client; 1684 { 1685 retrans_entry *rdata; 1686 OM_uint32 minor_stat; 1687 1688 if (client->retrans_data == NULL) 1689 return; 1690 1691 rdata = client->retrans_data; 1692 if (rdata->result.token.length != 0) { 1693 (void) gss_release_buffer(&minor_stat, &rdata->result.token); 1694 } 1695 1696 free((caddr_t)rdata); 1697 client->retrans_data = NULL; 1698 } 1699