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