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 1222 oa = &msg->rm_call.cb_cred; 1223 if (oa->oa_length > MAX_AUTH_BYTES) 1224 return (FALSE); 1225 1226 /* 8 XDR units from the IXDR macro calls. */ 1227 if (sizeof (hdr) < (8 * BYTES_PER_XDR_UNIT + 1228 RNDUP(oa->oa_length))) 1229 return (FALSE); 1230 buf = (int *)hdr; 1231 IXDR_PUT_U_INT32(buf, msg->rm_xid); 1232 IXDR_PUT_ENUM(buf, msg->rm_direction); 1233 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_rpcvers); 1234 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_prog); 1235 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_vers); 1236 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_proc); 1237 IXDR_PUT_ENUM(buf, oa->oa_flavor); 1238 IXDR_PUT_U_INT32(buf, oa->oa_length); 1239 if (oa->oa_length) { 1240 len = RNDUP(oa->oa_length); 1241 tmp = buf; 1242 buf += len / sizeof (int); 1243 *(buf - 1) = 0; 1244 (void) bcopy(oa->oa_base, (caddr_t)tmp, oa->oa_length); 1245 } 1246 len = ((char *)buf) - hdr; 1247 msg_buf.length = len; 1248 msg_buf.value = hdr; 1249 oa = &msg->rm_call.cb_verf; 1250 tok_buf.length = oa->oa_length; 1251 tok_buf.value = oa->oa_base; 1252 1253 gssstat = kgss_verify(&minor_stat, context, &msg_buf, &tok_buf, 1254 qop_state); 1255 if (gssstat != GSS_S_COMPLETE) { 1256 RPCGSS_LOG(1, "check_verf: kgss_verify status 0x%x\n", gssstat); 1257 1258 RPCGSS_LOG(4, "check_verf: msg_buf length %d\n", len); 1259 RPCGSS_LOG(4, "check_verf: msg_buf value 0x%x\n", *(int *)hdr); 1260 RPCGSS_LOG(4, "check_verf: tok_buf length %ld\n", 1261 tok_buf.length); 1262 RPCGSS_LOG(4, "check_verf: tok_buf value 0x%p\n", 1263 (void *)oa->oa_base); 1264 RPCGSS_LOG(4, "check_verf: context 0x%p\n", (void *)context); 1265 1266 return (FALSE); 1267 } 1268 return (TRUE); 1269 } 1270 1271 /* 1272 * Set response verifier. This is the checksum of the given number. 1273 * (e.g. sequence number or sequence window) 1274 */ 1275 static bool_t 1276 set_response_verf(rqst, msg, cl, num) 1277 struct svc_req *rqst; 1278 struct rpc_msg *msg; 1279 svc_rpc_gss_data *cl; 1280 uint_t num; 1281 { 1282 OM_uint32 minor; 1283 gss_buffer_desc in_buf, out_buf; 1284 uint_t num_net; 1285 1286 num_net = (uint_t)htonl(num); 1287 in_buf.length = sizeof (num); 1288 in_buf.value = (char *)&num_net; 1289 /* XXX uid ? */ 1290 if ((kgss_sign(&minor, cl->context, cl->qop, &in_buf, 1291 &out_buf)) != GSS_S_COMPLETE) 1292 return (FALSE); 1293 1294 rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS; 1295 rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base; 1296 rqst->rq_xprt->xp_verf.oa_length = out_buf.length; 1297 bcopy(out_buf.value, rqst->rq_xprt->xp_verf.oa_base, out_buf.length); 1298 (void) gss_release_buffer(&minor, &out_buf); 1299 return (TRUE); 1300 } 1301 1302 /* 1303 * Create client context. 1304 */ 1305 static svc_rpc_gss_data * 1306 create_client() 1307 { 1308 svc_rpc_gss_data *client_data; 1309 static uint_t key = 1; 1310 1311 client_data = (svc_rpc_gss_data *) kmem_cache_alloc(svc_data_handle, 1312 KM_SLEEP); 1313 if (client_data == NULL) 1314 return (NULL); 1315 1316 /* 1317 * set up client data structure 1318 */ 1319 client_data->next = NULL; 1320 client_data->prev = NULL; 1321 client_data->lru_next = NULL; 1322 client_data->lru_prev = NULL; 1323 client_data->client_name.length = 0; 1324 client_data->client_name.value = NULL; 1325 client_data->seq_num = 0; 1326 bzero(client_data->seq_bits, sizeof (client_data->seq_bits)); 1327 client_data->key = 0; 1328 client_data->cookie = NULL; 1329 bzero(&client_data->u_cred, sizeof (client_data->u_cred)); 1330 client_data->established = FALSE; 1331 client_data->locked = FALSE; 1332 client_data->u_cred_set = 0; 1333 client_data->context = GSS_C_NO_CONTEXT; 1334 client_data->expiration = GSS_C_INDEFINITE; 1335 client_data->deleg = GSS_C_NO_CREDENTIAL; 1336 client_data->ref_cnt = 1; 1337 client_data->last_ref_time = gethrestime_sec(); 1338 client_data->qop = GSS_C_QOP_DEFAULT; 1339 client_data->done_docallback = FALSE; 1340 client_data->stale = FALSE; 1341 client_data->retrans_data = NULL; 1342 bzero(&client_data->raw_cred, sizeof (client_data->raw_cred)); 1343 1344 /* 1345 * The client context handle is a 32-bit key (unsigned int). 1346 * The key is incremented until there is no duplicate for it. 1347 */ 1348 1349 svc_rpc_gss_cache_stats.total_entries_allocated++; 1350 mutex_enter(&ctx_mutex); 1351 for (;;) { 1352 client_data->key = key++; 1353 if (find_client(client_data->key) == NULL) { 1354 insert_client(client_data); 1355 mutex_exit(&ctx_mutex); 1356 return (client_data); 1357 } 1358 } 1359 /*NOTREACHED*/ 1360 } 1361 1362 /* 1363 * Insert client context into hash list and LRU list. 1364 */ 1365 static void 1366 insert_client(client_data) 1367 svc_rpc_gss_data *client_data; 1368 { 1369 svc_rpc_gss_data *cl; 1370 int index = HASH(client_data->key); 1371 1372 ASSERT(mutex_owned(&ctx_mutex)); 1373 1374 client_data->prev = NULL; 1375 cl = clients[index]; 1376 if ((client_data->next = cl) != NULL) 1377 cl->prev = client_data; 1378 clients[index] = client_data; 1379 1380 client_data->lru_prev = NULL; 1381 if ((client_data->lru_next = lru_first) != NULL) 1382 lru_first->lru_prev = client_data; 1383 else 1384 lru_last = client_data; 1385 lru_first = client_data; 1386 1387 num_gss_contexts++; 1388 } 1389 1390 /* 1391 * Fetch a client, given the client context handle. Move it to the 1392 * top of the LRU list since this is the most recently used context. 1393 */ 1394 static svc_rpc_gss_data * 1395 get_client(ctx_handle) 1396 gss_buffer_t ctx_handle; 1397 { 1398 uint_t key = *(uint_t *)ctx_handle->value; 1399 svc_rpc_gss_data *cl; 1400 1401 mutex_enter(&ctx_mutex); 1402 if ((cl = find_client(key)) != NULL) { 1403 mutex_enter(&cl->clm); 1404 if (cl->stale) { 1405 if (cl->ref_cnt == 0) { 1406 mutex_exit(&cl->clm); 1407 destroy_client(cl); 1408 } else { 1409 mutex_exit(&cl->clm); 1410 } 1411 mutex_exit(&ctx_mutex); 1412 return (NULL); 1413 } 1414 cl->ref_cnt++; 1415 cl->last_ref_time = gethrestime_sec(); 1416 mutex_exit(&cl->clm); 1417 if (cl != lru_first) { 1418 cl->lru_prev->lru_next = cl->lru_next; 1419 if (cl->lru_next != NULL) 1420 cl->lru_next->lru_prev = cl->lru_prev; 1421 else 1422 lru_last = cl->lru_prev; 1423 cl->lru_prev = NULL; 1424 cl->lru_next = lru_first; 1425 lru_first->lru_prev = cl; 1426 lru_first = cl; 1427 } 1428 } 1429 mutex_exit(&ctx_mutex); 1430 return (cl); 1431 } 1432 1433 /* 1434 * Given the client context handle, find the context corresponding to it. 1435 * Don't change its LRU state since it may not be used. 1436 */ 1437 static svc_rpc_gss_data * 1438 find_client(key) 1439 uint_t key; 1440 { 1441 int index = HASH(key); 1442 svc_rpc_gss_data *cl = NULL; 1443 1444 ASSERT(mutex_owned(&ctx_mutex)); 1445 1446 for (cl = clients[index]; cl != NULL; cl = cl->next) { 1447 if (cl->key == key) 1448 break; 1449 } 1450 return (cl); 1451 } 1452 1453 /* 1454 * Destroy a client context. 1455 */ 1456 static void 1457 destroy_client(client_data) 1458 svc_rpc_gss_data *client_data; 1459 { 1460 OM_uint32 minor; 1461 int index = HASH(client_data->key); 1462 1463 ASSERT(mutex_owned(&ctx_mutex)); 1464 1465 /* 1466 * remove from hash list 1467 */ 1468 if (client_data->prev == NULL) 1469 clients[index] = client_data->next; 1470 else 1471 client_data->prev->next = client_data->next; 1472 if (client_data->next != NULL) 1473 client_data->next->prev = client_data->prev; 1474 1475 /* 1476 * remove from LRU list 1477 */ 1478 if (client_data->lru_prev == NULL) 1479 lru_first = client_data->lru_next; 1480 else 1481 client_data->lru_prev->lru_next = client_data->lru_next; 1482 if (client_data->lru_next != NULL) 1483 client_data->lru_next->lru_prev = client_data->lru_prev; 1484 else 1485 lru_last = client_data->lru_prev; 1486 1487 /* 1488 * If there is a GSS context, clean up GSS state. 1489 */ 1490 if (client_data->context != GSS_C_NO_CONTEXT) { 1491 (void) kgss_delete_sec_context(&minor, &client_data->context, 1492 NULL); 1493 1494 common_client_data_free(client_data); 1495 1496 if (client_data->deleg != GSS_C_NO_CREDENTIAL) { 1497 (void) kgss_release_cred(&minor, &client_data->deleg, 1498 crgetuid(CRED())); 1499 } 1500 } 1501 1502 if (client_data->u_cred.gidlist != NULL) { 1503 kmem_free((char *)client_data->u_cred.gidlist, 1504 client_data->u_cred.gidlen * sizeof (gid_t)); 1505 client_data->u_cred.gidlist = NULL; 1506 } 1507 if (client_data->retrans_data != NULL) 1508 retrans_del(client_data); 1509 1510 kmem_cache_free(svc_data_handle, client_data); 1511 num_gss_contexts--; 1512 } 1513 1514 /* 1515 * Check for expired and stale client contexts. 1516 */ 1517 static void 1518 sweep_clients(bool_t from_reclaim) 1519 { 1520 svc_rpc_gss_data *cl, *next; 1521 time_t last_reference_needed; 1522 time_t now = gethrestime_sec(); 1523 1524 ASSERT(mutex_owned(&ctx_mutex)); 1525 1526 last_reference_needed = now - (from_reclaim ? 1527 svc_rpc_gss_active_delta : 1528 svc_rpc_gss_inactive_delta); 1529 1530 cl = lru_last; 1531 while (cl) { 1532 /* 1533 * We assume here that any manipulation of the LRU pointers 1534 * and hash bucket pointers are only done when holding the 1535 * ctx_mutex. 1536 */ 1537 next = cl->lru_prev; 1538 1539 mutex_enter(&cl->clm); 1540 1541 if ((cl->expiration != GSS_C_INDEFINITE && 1542 cl->expiration <= now) || cl->stale || 1543 cl->last_ref_time <= last_reference_needed) { 1544 1545 if ((cl->expiration != GSS_C_INDEFINITE && 1546 cl->expiration <= now) || cl->stale || 1547 (cl->last_ref_time <= last_reference_needed && 1548 cl->ref_cnt == 0)) { 1549 1550 cl->stale = TRUE; 1551 1552 if (cl->ref_cnt == 0) { 1553 mutex_exit(&cl->clm); 1554 if (from_reclaim) 1555 svc_rpc_gss_cache_stats. 1556 no_returned_by_reclaim++; 1557 destroy_client(cl); 1558 } else 1559 mutex_exit(&cl->clm); 1560 } else 1561 mutex_exit(&cl->clm); 1562 } else 1563 mutex_exit(&cl->clm); 1564 1565 cl = next; 1566 } 1567 1568 last_swept = gethrestime_sec(); 1569 } 1570 1571 /* 1572 * Encrypt the serialized arguments from xdr_func applied to xdr_ptr 1573 * and write the result to xdrs. 1574 */ 1575 static bool_t 1576 svc_rpc_gss_wrap(auth, out_xdrs, xdr_func, xdr_ptr) 1577 SVCAUTH *auth; 1578 XDR *out_xdrs; 1579 bool_t (*xdr_func)(); 1580 caddr_t xdr_ptr; 1581 { 1582 svc_rpc_gss_parms_t *gss_parms = SVCAUTH_GSSPARMS(auth); 1583 1584 /* 1585 * If context is not established, or if neither integrity nor 1586 * privacy service is used, don't wrap - just XDR encode. 1587 * Otherwise, wrap data using service and QOP parameters. 1588 */ 1589 if (!gss_parms->established || 1590 gss_parms->service == rpc_gss_svc_none) 1591 return ((*xdr_func)(out_xdrs, xdr_ptr)); 1592 1593 return (__rpc_gss_wrap_data(gss_parms->service, 1594 (OM_uint32)gss_parms->qop_rcvd, 1595 (gss_ctx_id_t)gss_parms->context, 1596 gss_parms->seq_num, 1597 out_xdrs, xdr_func, xdr_ptr)); 1598 } 1599 1600 /* 1601 * Decrypt the serialized arguments and XDR decode them. 1602 */ 1603 static bool_t 1604 svc_rpc_gss_unwrap(auth, in_xdrs, xdr_func, xdr_ptr) 1605 SVCAUTH *auth; 1606 XDR *in_xdrs; 1607 bool_t (*xdr_func)(); 1608 caddr_t xdr_ptr; 1609 { 1610 svc_rpc_gss_parms_t *gss_parms = SVCAUTH_GSSPARMS(auth); 1611 1612 /* 1613 * If context is not established, or if neither integrity nor 1614 * privacy service is used, don't unwrap - just XDR decode. 1615 * Otherwise, unwrap data. 1616 */ 1617 if (!gss_parms->established || 1618 gss_parms->service == rpc_gss_svc_none) 1619 return ((*xdr_func)(in_xdrs, xdr_ptr)); 1620 1621 return (__rpc_gss_unwrap_data(gss_parms->service, 1622 (gss_ctx_id_t)gss_parms->context, 1623 gss_parms->seq_num, 1624 gss_parms->qop_rcvd, 1625 in_xdrs, xdr_func, xdr_ptr)); 1626 } 1627 1628 1629 /* ARGSUSED */ 1630 int 1631 rpc_gss_svc_max_data_length(struct svc_req *req, int max_tp_unit_len) 1632 { 1633 return (0); 1634 } 1635 1636 /* 1637 * Add retransmit entry to the context cache entry for a new xid. 1638 * If there is already an entry, delete it before adding the new one. 1639 */ 1640 static void retrans_add(client, xid, result) 1641 svc_rpc_gss_data *client; 1642 uint32_t xid; 1643 rpc_gss_init_res *result; 1644 { 1645 retrans_entry *rdata; 1646 1647 if (client->retrans_data && client->retrans_data->xid == xid) 1648 return; 1649 1650 rdata = kmem_zalloc(sizeof (*rdata), KM_SLEEP); 1651 1652 if (rdata == NULL) 1653 return; 1654 1655 rdata->xid = xid; 1656 rdata->result = *result; 1657 1658 if (result->token.length != 0) { 1659 GSS_DUP_BUFFER(rdata->result.token, result->token); 1660 } 1661 1662 if (client->retrans_data) 1663 retrans_del(client); 1664 1665 client->retrans_data = rdata; 1666 } 1667 1668 /* 1669 * Delete the retransmit data from the context cache entry. 1670 */ 1671 static void retrans_del(client) 1672 svc_rpc_gss_data *client; 1673 { 1674 retrans_entry *rdata; 1675 OM_uint32 minor_stat; 1676 1677 if (client->retrans_data == NULL) 1678 return; 1679 1680 rdata = client->retrans_data; 1681 if (rdata->result.token.length != 0) { 1682 (void) gss_release_buffer(&minor_stat, &rdata->result.token); 1683 } 1684 1685 kmem_free((caddr_t)rdata, sizeof (*rdata)); 1686 client->retrans_data = NULL; 1687 } 1688 1689 /* 1690 * This function frees the following fields of svc_rpc_gss_data: 1691 * client_name, raw_cred.client_principal, raw_cred.mechanism. 1692 */ 1693 static void 1694 common_client_data_free(svc_rpc_gss_data *client_data) 1695 { 1696 if (client_data->client_name.length > 0) { 1697 (void) gss_release_buffer(NULL, &client_data->client_name); 1698 } 1699 1700 if (client_data->raw_cred.client_principal) { 1701 kmem_free((caddr_t)client_data->raw_cred.client_principal, 1702 client_data->raw_cred.client_principal->len + 1703 sizeof (int)); 1704 client_data->raw_cred.client_principal = NULL; 1705 } 1706 1707 /* 1708 * In the user GSS-API library, mechanism (mech_type returned 1709 * by gss_accept_sec_context) is static storage, however 1710 * since all the work is done for gss_accept_sec_context under 1711 * gssd, what is returned in the kernel, is a copy from the oid 1712 * obtained under from gssd, so need to free it when destroying 1713 * the client data. 1714 */ 1715 1716 if (client_data->raw_cred.mechanism) { 1717 kgss_free_oid(client_data->raw_cred.mechanism); 1718 client_data->raw_cred.mechanism = NULL; 1719 } 1720 } 1721