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