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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. 28 * 29 * $Id: svc_auth_gssapi.c,v 1.19 1994/10/27 12:38:51 jik Exp $ 30 */ 31 32 /* 33 * Server side handling of RPCSEC_GSS flavor. 34 */ 35 36 #include <sys/systm.h> 37 #include <sys/kstat.h> 38 #include <sys/cmn_err.h> 39 #include <sys/debug.h> 40 #include <sys/types.h> 41 #include <sys/time.h> 42 #include <gssapi/gssapi.h> 43 #include <gssapi/gssapi_ext.h> 44 #include <rpc/rpc.h> 45 #include <rpc/rpcsec_defs.h> 46 #include <sys/sunddi.h> 47 #include <sys/atomic.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 /* taskq(9F) */ 226 typedef struct svcrpcsec_gss_taskq_arg { 227 SVCXPRT *rq_xprt; 228 rpc_gss_init_arg *rpc_call_arg; 229 struct rpc_msg *msg; 230 svc_rpc_gss_data *client_data; 231 uint_t cr_version; 232 rpc_gss_service_t cr_service; 233 } svcrpcsec_gss_taskq_arg_t; 234 235 /* gssd is single threaded, so 1 thread for the taskq is probably good/ok */ 236 int rpcsec_gss_init_taskq_nthreads = 1; 237 static ddi_taskq_t *svcrpcsec_gss_init_taskq = NULL; 238 239 extern struct rpc_msg *rpc_msg_dup(struct rpc_msg *); 240 extern void rpc_msg_free(struct rpc_msg **, int); 241 242 /* 243 * from svc_clts.c: 244 * Transport private data. 245 * Kept in xprt->xp_p2buf. 246 */ 247 struct udp_data { 248 mblk_t *ud_resp; /* buffer for response */ 249 mblk_t *ud_inmp; /* mblk chain of request */ 250 }; 251 252 /*ARGSUSED*/ 253 static int 254 svc_gss_data_create(void *buf, void *pdata, int kmflag) 255 { 256 svc_rpc_gss_data *client_data = (svc_rpc_gss_data *)buf; 257 258 mutex_init(&client_data->clm, NULL, MUTEX_DEFAULT, NULL); 259 260 return (0); 261 } 262 263 /*ARGSUSED*/ 264 static void 265 svc_gss_data_destroy(void *buf, void *pdata) 266 { 267 svc_rpc_gss_data *client_data = (svc_rpc_gss_data *)buf; 268 269 mutex_destroy(&client_data->clm); 270 } 271 272 273 /*ARGSUSED*/ 274 static void 275 svc_gss_data_reclaim(void *pdata) 276 { 277 mutex_enter(&ctx_mutex); 278 279 svc_rpc_gss_cache_stats.no_reclaims++; 280 sweep_clients(TRUE); 281 282 mutex_exit(&ctx_mutex); 283 } 284 285 /* 286 * Init stuff on the server side. 287 */ 288 void 289 svc_gss_init() 290 { 291 mutex_init(&cb_mutex, NULL, MUTEX_DEFAULT, NULL); 292 mutex_init(&ctx_mutex, NULL, MUTEX_DEFAULT, NULL); 293 rw_init(&cred_lock, NULL, RW_DEFAULT, NULL); 294 clients = (svc_rpc_gss_data **) 295 kmem_zalloc(svc_rpc_gss_hashmod * sizeof (svc_rpc_gss_data *), 296 KM_SLEEP); 297 svc_data_handle = kmem_cache_create("rpc_gss_data_cache", 298 sizeof (svc_rpc_gss_data), 0, 299 svc_gss_data_create, 300 svc_gss_data_destroy, 301 svc_gss_data_reclaim, 302 NULL, NULL, 0); 303 304 if (svcrpcsec_gss_init_taskq == NULL) { 305 svcrpcsec_gss_init_taskq = ddi_taskq_create(NULL, 306 "rpcsec_gss_init_taskq", rpcsec_gss_init_taskq_nthreads, 307 TASKQ_DEFAULTPRI, 0); 308 if (svcrpcsec_gss_init_taskq == NULL) 309 cmn_err(CE_NOTE, 310 "svc_gss_init: ddi_taskq_create failed"); 311 } 312 } 313 314 /* 315 * Destroy structures allocated in svc_gss_init(). 316 * This routine is called by _init() if mod_install() failed. 317 */ 318 void 319 svc_gss_fini() 320 { 321 mutex_destroy(&cb_mutex); 322 mutex_destroy(&ctx_mutex); 323 rw_destroy(&cred_lock); 324 kmem_free(clients, svc_rpc_gss_hashmod * sizeof (svc_rpc_gss_data *)); 325 kmem_cache_destroy(svc_data_handle); 326 } 327 328 /* 329 * Cleanup routine for destroying context, called after service 330 * procedure is executed. Actually we just decrement the reference count 331 * associated with this context. If the reference count is zero and the 332 * context is marked as stale, we would then destroy the context. Additionally, 333 * we check if its been longer than sweep_interval since the last sweep_clients 334 * was run, and if so run sweep_clients to free all stale contexts with zero 335 * reference counts or contexts that are old. (Haven't been access in 336 * svc_rpc_inactive_delta seconds). 337 */ 338 void 339 rpc_gss_cleanup(SVCXPRT *clone_xprt) 340 { 341 svc_rpc_gss_data *cl; 342 SVCAUTH *svcauth; 343 344 /* 345 * First check if current context needs to be cleaned up. 346 * There might be other threads stale this client data 347 * in between. 348 */ 349 svcauth = &clone_xprt->xp_auth; 350 mutex_enter(&ctx_mutex); 351 if ((cl = (svc_rpc_gss_data *)svcauth->svc_ah_private) != NULL) { 352 mutex_enter(&cl->clm); 353 ASSERT(cl->ref_cnt > 0); 354 if (--cl->ref_cnt == 0 && cl->stale) { 355 mutex_exit(&cl->clm); 356 destroy_client(cl); 357 svcauth->svc_ah_private = NULL; 358 } else 359 mutex_exit(&cl->clm); 360 } 361 362 /* 363 * Check for other expired contexts. 364 */ 365 if ((gethrestime_sec() - last_swept) > sweep_interval) 366 sweep_clients(FALSE); 367 368 mutex_exit(&ctx_mutex); 369 } 370 371 /* 372 * Shift the array arr of length arrlen right by nbits bits. 373 */ 374 static void 375 shift_bits(arr, arrlen, nbits) 376 uint_t *arr; 377 int arrlen; 378 int nbits; 379 { 380 int i, j; 381 uint_t lo, hi; 382 383 /* 384 * If the number of bits to be shifted exceeds SEQ_WIN, just 385 * zero out the array. 386 */ 387 if (nbits < SEQ_WIN) { 388 for (i = 0; i < nbits; i++) { 389 hi = 0; 390 for (j = 0; j < arrlen; j++) { 391 lo = arr[j] & SEQ_LO_BIT; 392 arr[j] >>= 1; 393 if (hi) 394 arr[j] |= SEQ_HI_BIT; 395 hi = lo; 396 } 397 } 398 } else { 399 for (j = 0; j < arrlen; j++) 400 arr[j] = 0; 401 } 402 } 403 404 /* 405 * Check that the received sequence number seq_num is valid. 406 */ 407 static bool_t 408 check_seq(cl, seq_num, kill_context) 409 svc_rpc_gss_data *cl; 410 uint_t seq_num; 411 bool_t *kill_context; 412 { 413 int i, j; 414 uint_t bit; 415 416 /* 417 * If it exceeds the maximum, kill context. 418 */ 419 if (seq_num >= SEQ_MAX) { 420 *kill_context = TRUE; 421 RPCGSS_LOG0(4, "check_seq: seq_num not valid\n"); 422 return (FALSE); 423 } 424 425 /* 426 * If greater than the last seen sequence number, just shift 427 * the sequence window so that it starts at the new sequence 428 * number and extends downwards by SEQ_WIN. 429 */ 430 if (seq_num > cl->seq_num) { 431 (void) shift_bits(cl->seq_bits, SEQ_ARR_SIZE, 432 (int)(seq_num - cl->seq_num)); 433 cl->seq_bits[0] |= SEQ_HI_BIT; 434 cl->seq_num = seq_num; 435 return (TRUE); 436 } 437 438 /* 439 * If it is outside the sequence window, return failure. 440 */ 441 i = cl->seq_num - seq_num; 442 if (i >= SEQ_WIN) { 443 RPCGSS_LOG0(4, "check_seq: seq_num is outside the window\n"); 444 return (FALSE); 445 } 446 447 /* 448 * If within sequence window, set the bit corresponding to it 449 * if not already seen; if already seen, return failure. 450 */ 451 j = SEQ_MASK - (i & SEQ_MASK); 452 bit = j > 0 ? (1 << j) : 1; 453 i >>= DIV_BY_32; 454 if (cl->seq_bits[i] & bit) { 455 RPCGSS_LOG0(4, "check_seq: sequence number already seen\n"); 456 return (FALSE); 457 } 458 cl->seq_bits[i] |= bit; 459 return (TRUE); 460 } 461 462 /* 463 * Set server callback. 464 */ 465 bool_t 466 rpc_gss_set_callback(cb) 467 rpc_gss_callback_t *cb; 468 { 469 rpc_gss_cblist_t *cbl, *tmp; 470 471 if (cb->callback == NULL) { 472 RPCGSS_LOG0(1, "rpc_gss_set_callback: no callback to set\n"); 473 return (FALSE); 474 } 475 476 /* check if there is already an entry in the rpc_gss_cblist. */ 477 mutex_enter(&cb_mutex); 478 if (rpc_gss_cblist) { 479 for (tmp = rpc_gss_cblist; tmp != NULL; tmp = tmp->next) { 480 if ((tmp->cb.callback == cb->callback) && 481 (tmp->cb.version == cb->version) && 482 (tmp->cb.program == cb->program)) { 483 mutex_exit(&cb_mutex); 484 return (TRUE); 485 } 486 } 487 } 488 489 /* Not in rpc_gss_cblist. Create a new entry. */ 490 if ((cbl = (rpc_gss_cblist_t *)kmem_alloc(sizeof (*cbl), KM_SLEEP)) 491 == NULL) { 492 mutex_exit(&cb_mutex); 493 return (FALSE); 494 } 495 cbl->cb = *cb; 496 cbl->next = rpc_gss_cblist; 497 rpc_gss_cblist = cbl; 498 mutex_exit(&cb_mutex); 499 return (TRUE); 500 } 501 502 /* 503 * Locate callback (if specified) and call server. Release any 504 * delegated credentials unless passed to server and the server 505 * accepts the context. If a callback is not specified, accept 506 * the incoming context. 507 */ 508 static bool_t 509 do_callback(req, client_data) 510 struct svc_req *req; 511 svc_rpc_gss_data *client_data; 512 { 513 rpc_gss_cblist_t *cbl; 514 bool_t ret = TRUE, found = FALSE; 515 rpc_gss_lock_t lock; 516 OM_uint32 minor; 517 mutex_enter(&cb_mutex); 518 for (cbl = rpc_gss_cblist; cbl != NULL; cbl = cbl->next) { 519 if (req->rq_prog != cbl->cb.program || 520 req->rq_vers != cbl->cb.version) 521 continue; 522 found = TRUE; 523 lock.locked = FALSE; 524 lock.raw_cred = &client_data->raw_cred; 525 ret = (*cbl->cb.callback)(req, client_data->deleg, 526 client_data->context, &lock, &client_data->cookie); 527 req->rq_xprt->xp_cookie = client_data->cookie; 528 529 if (ret) { 530 client_data->locked = lock.locked; 531 client_data->deleg = GSS_C_NO_CREDENTIAL; 532 } 533 break; 534 } 535 if (!found) { 536 if (client_data->deleg != GSS_C_NO_CREDENTIAL) { 537 (void) kgss_release_cred(&minor, &client_data->deleg, 538 crgetuid(CRED())); 539 client_data->deleg = GSS_C_NO_CREDENTIAL; 540 } 541 } 542 mutex_exit(&cb_mutex); 543 return (ret); 544 } 545 546 /* 547 * Get caller credentials. 548 */ 549 bool_t 550 rpc_gss_getcred(req, rcred, ucred, cookie) 551 struct svc_req *req; 552 rpc_gss_rawcred_t **rcred; 553 rpc_gss_ucred_t **ucred; 554 void **cookie; 555 { 556 SVCAUTH *svcauth; 557 svc_rpc_gss_data *client_data; 558 int gssstat, gidlen; 559 560 svcauth = &req->rq_xprt->xp_auth; 561 client_data = (svc_rpc_gss_data *)svcauth->svc_ah_private; 562 563 mutex_enter(&client_data->clm); 564 565 if (rcred != NULL) { 566 svcauth->raw_cred = client_data->raw_cred; 567 *rcred = &svcauth->raw_cred; 568 } 569 if (ucred != NULL) { 570 *ucred = &client_data->u_cred; 571 572 if (client_data->u_cred_set == 0 || 573 client_data->u_cred_set < gethrestime_sec()) { 574 if (client_data->u_cred_set == 0) { 575 if ((gssstat = kgsscred_expname_to_unix_cred( 576 &client_data->client_name, 577 &client_data->u_cred.uid, 578 &client_data->u_cred.gid, 579 &client_data->u_cred.gidlist, 580 &gidlen, crgetuid(CRED()))) != GSS_S_COMPLETE) { 581 RPCGSS_LOG(1, "rpc_gss_getcred: " 582 "kgsscred_expname_to_unix_cred failed %x\n", 583 gssstat); 584 *ucred = NULL; 585 } else { 586 client_data->u_cred.gidlen = (short)gidlen; 587 client_data->u_cred_set = 588 gethrestime_sec() + svc_rpcgss_gid_timeout; 589 } 590 } else if (client_data->u_cred_set < gethrestime_sec()) { 591 if ((gssstat = kgss_get_group_info( 592 client_data->u_cred.uid, 593 &client_data->u_cred.gid, 594 &client_data->u_cred.gidlist, 595 &gidlen, crgetuid(CRED()))) != GSS_S_COMPLETE) { 596 RPCGSS_LOG(1, "rpc_gss_getcred: " 597 "kgss_get_group_info failed %x\n", 598 gssstat); 599 *ucred = NULL; 600 } else { 601 client_data->u_cred.gidlen = (short)gidlen; 602 client_data->u_cred_set = 603 gethrestime_sec() + svc_rpcgss_gid_timeout; 604 } 605 } 606 } 607 } 608 609 if (cookie != NULL) 610 *cookie = client_data->cookie; 611 req->rq_xprt->xp_cookie = client_data->cookie; 612 613 mutex_exit(&client_data->clm); 614 615 return (TRUE); 616 } 617 618 /* 619 * Transfer the context data from the user land to the kernel. 620 */ 621 bool_t transfer_sec_context(svc_rpc_gss_data *client_data) { 622 623 gss_buffer_desc process_token; 624 OM_uint32 gssstat, minor; 625 626 /* 627 * Call kgss_export_sec_context 628 * if an error is returned log a message 629 * go to error handling 630 * Otherwise call kgss_import_sec_context to 631 * convert the token into a context 632 */ 633 gssstat = kgss_export_sec_context(&minor, client_data->context, 634 &process_token); 635 /* 636 * if export_sec_context returns an error we delete the 637 * context just to be safe. 638 */ 639 if (gssstat == GSS_S_NAME_NOT_MN) { 640 RPCGSS_LOG0(4, "svc_rpcsec_gss: export sec context " 641 "Kernel mod unavailable\n"); 642 643 } else if (gssstat != GSS_S_COMPLETE) { 644 RPCGSS_LOG(1, "svc_rpcsec_gss: export sec context failed " 645 " gssstat = 0x%x\n", gssstat); 646 (void) gss_release_buffer(&minor, &process_token); 647 (void) kgss_delete_sec_context(&minor, &client_data->context, 648 NULL); 649 return (FALSE); 650 651 } else if (process_token.length == 0) { 652 RPCGSS_LOG0(1, "svc_rpcsec_gss:zero length token in response " 653 "for export_sec_context, but " 654 "gsstat == GSS_S_COMPLETE\n"); 655 (void) kgss_delete_sec_context(&minor, &client_data->context, 656 NULL); 657 return (FALSE); 658 659 } else { 660 gssstat = kgss_import_sec_context(&minor, &process_token, 661 client_data->context); 662 if (gssstat != GSS_S_COMPLETE) { 663 RPCGSS_LOG(1, "svc_rpcsec_gss: import sec context " 664 " failed gssstat = 0x%x\n", gssstat); 665 (void) kgss_delete_sec_context(&minor, 666 &client_data->context, NULL); 667 (void) gss_release_buffer(&minor, &process_token); 668 return (FALSE); 669 } 670 671 RPCGSS_LOG0(4, "gss_import_sec_context successful\n"); 672 (void) gss_release_buffer(&minor, &process_token); 673 } 674 675 return (TRUE); 676 } 677 678 /* 679 * do_gss_accept is called from a taskq and does all the work for a 680 * RPCSEC_GSS_INIT call (mostly calling kgss_accept_sec_context()). 681 */ 682 static enum auth_stat 683 do_gss_accept( 684 SVCXPRT *xprt, 685 rpc_gss_init_arg *call_arg, 686 struct rpc_msg *msg, 687 svc_rpc_gss_data *client_data, 688 uint_t cr_version, 689 rpc_gss_service_t cr_service) 690 { 691 rpc_gss_init_res call_res; 692 gss_buffer_desc output_token; 693 OM_uint32 gssstat, minor, minor_stat, time_rec; 694 int ret_flags, ret; 695 gss_OID mech_type = GSS_C_NULL_OID; 696 int free_mech_type = 1; 697 struct svc_req r, *rqst; 698 699 rqst = &r; 700 rqst->rq_xprt = xprt; 701 702 /* 703 * Initialize output_token. 704 */ 705 output_token.length = 0; 706 output_token.value = NULL; 707 708 bzero((char *)&call_res, sizeof (call_res)); 709 710 mutex_enter(&client_data->clm); 711 if (client_data->stale) { 712 ret = RPCSEC_GSS_NOCRED; 713 RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n"); 714 goto error2; 715 } 716 717 /* 718 * Any response we send will use ctx_handle, so set it now; 719 * also set seq_window since this won't change. 720 */ 721 call_res.ctx_handle.length = sizeof (client_data->key); 722 call_res.ctx_handle.value = (char *)&client_data->key; 723 call_res.seq_window = SEQ_WIN; 724 725 gssstat = GSS_S_FAILURE; 726 minor = 0; 727 minor_stat = 0; 728 rw_enter(&cred_lock, RW_READER); 729 730 if (client_data->client_name.length) { 731 (void) gss_release_buffer(&minor, 732 &client_data->client_name); 733 } 734 gssstat = kgss_accept_sec_context(&minor_stat, 735 &client_data->context, 736 GSS_C_NO_CREDENTIAL, 737 call_arg, 738 GSS_C_NO_CHANNEL_BINDINGS, 739 &client_data->client_name, 740 &mech_type, 741 &output_token, 742 &ret_flags, 743 &time_rec, 744 NULL, /* don't need a delegated cred back */ 745 crgetuid(CRED())); 746 747 RPCGSS_LOG(4, "gssstat 0x%x \n", gssstat); 748 749 if (gssstat == GSS_S_COMPLETE) { 750 /* 751 * Set the raw and unix credentials at this 752 * point. This saves a lot of computation 753 * later when credentials are retrieved. 754 */ 755 client_data->raw_cred.version = cr_version; 756 client_data->raw_cred.service = cr_service; 757 758 if (client_data->raw_cred.mechanism) { 759 kgss_free_oid(client_data->raw_cred.mechanism); 760 client_data->raw_cred.mechanism = NULL; 761 } 762 client_data->raw_cred.mechanism = (rpc_gss_OID) mech_type; 763 /* 764 * client_data is now responsible for freeing 765 * the data of 'mech_type'. 766 */ 767 free_mech_type = 0; 768 769 if (client_data->raw_cred.client_principal) { 770 kmem_free((caddr_t)client_data->\ 771 raw_cred.client_principal, 772 client_data->raw_cred.\ 773 client_principal->len + sizeof (int)); 774 client_data->raw_cred.client_principal = NULL; 775 } 776 777 /* 778 * The client_name returned from 779 * kgss_accept_sec_context() is in an 780 * exported flat format. 781 */ 782 if (! __rpc_gss_make_principal( 783 &client_data->raw_cred.client_principal, 784 &client_data->client_name)) { 785 RPCGSS_LOG0(1, "_svcrpcsec_gss: " 786 "make principal failed\n"); 787 gssstat = GSS_S_FAILURE; 788 (void) gss_release_buffer(&minor_stat, &output_token); 789 } 790 } 791 792 rw_exit(&cred_lock); 793 794 call_res.gss_major = gssstat; 795 call_res.gss_minor = minor_stat; 796 797 if (gssstat != GSS_S_COMPLETE && 798 gssstat != GSS_S_CONTINUE_NEEDED) { 799 call_res.ctx_handle.length = 0; 800 call_res.ctx_handle.value = NULL; 801 call_res.seq_window = 0; 802 rpc_gss_display_status(gssstat, minor_stat, mech_type, 803 crgetuid(CRED()), 804 "_svc_rpcsec_gss gss_accept_sec_context"); 805 (void) svc_sendreply(rqst->rq_xprt, 806 __xdr_rpc_gss_init_res, (caddr_t)&call_res); 807 client_data->stale = TRUE; 808 ret = AUTH_OK; 809 goto error2; 810 } 811 812 /* 813 * If appropriate, set established to TRUE *after* sending 814 * response (otherwise, the client will receive the final 815 * token encrypted) 816 */ 817 if (gssstat == GSS_S_COMPLETE) { 818 /* 819 * Context is established. Set expiration time 820 * for the context. 821 */ 822 client_data->seq_num = 1; 823 if ((time_rec == GSS_C_INDEFINITE) || (time_rec == 0)) { 824 client_data->expiration = GSS_C_INDEFINITE; 825 } else { 826 client_data->expiration = 827 time_rec + gethrestime_sec(); 828 } 829 830 if (!transfer_sec_context(client_data)) { 831 ret = RPCSEC_GSS_FAILED; 832 client_data->stale = TRUE; 833 RPCGSS_LOG0(1, 834 "_svc_rpcsec_gss: transfer sec context failed\n"); 835 goto error2; 836 } 837 838 client_data->established = TRUE; 839 } 840 841 /* 842 * This step succeeded. Send a response, along with 843 * a token if there's one. Don't dispatch. 844 */ 845 846 if (output_token.length != 0) 847 GSS_COPY_BUFFER(call_res.token, output_token); 848 849 /* 850 * If GSS_S_COMPLETE: set response verifier to 851 * checksum of SEQ_WIN 852 */ 853 if (gssstat == GSS_S_COMPLETE) { 854 if (!set_response_verf(rqst, msg, client_data, 855 (uint_t)SEQ_WIN)) { 856 ret = RPCSEC_GSS_FAILED; 857 client_data->stale = TRUE; 858 RPCGSS_LOG0(1, 859 "_svc_rpcsec_gss:set response verifier failed\n"); 860 goto error2; 861 } 862 } 863 864 if (!svc_sendreply(rqst->rq_xprt, __xdr_rpc_gss_init_res, 865 (caddr_t)&call_res)) { 866 ret = RPCSEC_GSS_FAILED; 867 client_data->stale = TRUE; 868 RPCGSS_LOG0(1, "_svc_rpcsec_gss:send reply failed\n"); 869 goto error2; 870 } 871 872 /* 873 * Cache last response in case it is lost and the client 874 * retries on an established context. 875 */ 876 (void) retrans_add(client_data, msg->rm_xid, &call_res); 877 ASSERT(client_data->ref_cnt > 0); 878 client_data->ref_cnt--; 879 mutex_exit(&client_data->clm); 880 881 (void) gss_release_buffer(&minor_stat, &output_token); 882 883 return (AUTH_OK); 884 885 error2: 886 ASSERT(client_data->ref_cnt > 0); 887 client_data->ref_cnt--; 888 mutex_exit(&client_data->clm); 889 (void) gss_release_buffer(&minor_stat, &output_token); 890 if (free_mech_type && mech_type) 891 kgss_free_oid(mech_type); 892 893 return (ret); 894 } 895 896 static void 897 svcrpcsec_gss_taskq_func(void *svcrpcsecgss_taskq_arg) 898 { 899 enum auth_stat retval; 900 svcrpcsec_gss_taskq_arg_t *arg = svcrpcsecgss_taskq_arg; 901 902 retval = do_gss_accept(arg->rq_xprt, arg->rpc_call_arg, arg->msg, 903 arg->client_data, arg->cr_version, arg->cr_service); 904 if (retval != AUTH_OK) { 905 cmn_err(CE_NOTE, 906 "svcrpcsec_gss_taskq_func: do_gss_accept fail 0x%x", 907 retval); 908 } 909 rpc_msg_free(&arg->msg, MAX_AUTH_BYTES); 910 svc_clone_unlink(arg->rq_xprt); 911 svc_clone_free(arg->rq_xprt); 912 xdr_free(__xdr_rpc_gss_init_arg, (caddr_t)arg->rpc_call_arg); 913 kmem_free(arg->rpc_call_arg, sizeof (*arg->rpc_call_arg)); 914 915 kmem_free(arg, sizeof (*arg)); 916 } 917 918 static enum auth_stat 919 rpcsec_gss_init( 920 struct svc_req *rqst, 921 struct rpc_msg *msg, 922 rpc_gss_creds creds, 923 bool_t *no_dispatch, 924 svc_rpc_gss_data *c_d) /* client data, can be NULL */ 925 { 926 svc_rpc_gss_data *client_data; 927 int ret; 928 svcrpcsec_gss_taskq_arg_t *arg; 929 930 if (creds.ctx_handle.length != 0) { 931 RPCGSS_LOG0(1, "_svcrpcsec_gss: ctx_handle not null\n"); 932 ret = AUTH_BADCRED; 933 return (ret); 934 } 935 936 client_data = c_d ? c_d : create_client(); 937 if (client_data == NULL) { 938 RPCGSS_LOG0(1, 939 "_svcrpcsec_gss: can't create a new cache entry\n"); 940 ret = AUTH_FAILED; 941 return (ret); 942 } 943 944 mutex_enter(&client_data->clm); 945 if (client_data->stale) { 946 ret = RPCSEC_GSS_NOCRED; 947 RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n"); 948 goto error2; 949 } 950 951 /* 952 * kgss_accept_sec_context()/gssd(1M) can be overly time 953 * consuming so let's queue it and return asap. 954 * 955 * taskq func must free arg. 956 */ 957 arg = kmem_alloc(sizeof (*arg), KM_SLEEP); 958 959 /* taskq func must free rpc_call_arg & deserialized arguments */ 960 arg->rpc_call_arg = kmem_alloc(sizeof (*arg->rpc_call_arg), KM_SLEEP); 961 962 /* deserialize arguments */ 963 bzero(arg->rpc_call_arg, sizeof (*arg->rpc_call_arg)); 964 if (!SVC_GETARGS(rqst->rq_xprt, __xdr_rpc_gss_init_arg, 965 (caddr_t)arg->rpc_call_arg)) { 966 ret = RPCSEC_GSS_FAILED; 967 client_data->stale = TRUE; 968 goto error2; 969 } 970 971 /* get a xprt clone for taskq thread, taskq func must free it */ 972 arg->rq_xprt = svc_clone_init(); 973 svc_clone_link(rqst->rq_xprt->xp_master, arg->rq_xprt); 974 arg->rq_xprt->xp_xid = rqst->rq_xprt->xp_xid; 975 976 /* UDP uses the incoming mblk for the response, so dup it. */ 977 /* Note this probably should be done by svc_clone_link(). */ 978 if (rqst->rq_xprt->xp_type == T_CLTS) { 979 struct udp_data *ud_src = 980 (struct udp_data *)rqst->rq_xprt->xp_p2buf; 981 struct udp_data *ud_dst = 982 (struct udp_data *)arg->rq_xprt->xp_p2buf; 983 if (ud_src->ud_resp) { 984 ud_dst->ud_resp = dupb(ud_src->ud_resp); 985 } 986 } 987 988 /* set the appropriate wrap/unwrap routine for RPCSEC_GSS */ 989 arg->rq_xprt->xp_auth.svc_ah_ops = svc_rpc_gss_ops; 990 arg->rq_xprt->xp_auth.svc_ah_private = (caddr_t)client_data; 991 992 /* get a dup of rpc msg for taskq thread */ 993 arg->msg = rpc_msg_dup(msg); /* taskq func must free msg dup */ 994 995 arg->client_data = client_data; 996 arg->cr_version = creds.version; 997 arg->cr_service = creds.service; 998 999 /* should be ok to hold clm lock as taskq will have new thread(s) */ 1000 ret = ddi_taskq_dispatch(svcrpcsec_gss_init_taskq, 1001 svcrpcsec_gss_taskq_func, arg, DDI_SLEEP); 1002 if (ret == DDI_FAILURE) { 1003 cmn_err(CE_NOTE, "rpcsec_gss_init: taskq dispatch fail"); 1004 ret = RPCSEC_GSS_FAILED; 1005 rpc_msg_free(&arg->msg, MAX_AUTH_BYTES); 1006 svc_clone_unlink(arg->rq_xprt); 1007 svc_clone_free(arg->rq_xprt); 1008 kmem_free(arg, sizeof (*arg)); 1009 goto error2; 1010 } 1011 1012 mutex_exit(&client_data->clm); 1013 *no_dispatch = TRUE; 1014 return (AUTH_OK); 1015 1016 error2: 1017 ASSERT(client_data->ref_cnt > 0); 1018 client_data->ref_cnt--; 1019 mutex_exit(&client_data->clm); 1020 cmn_err(CE_NOTE, "rpcsec_gss_init: error 0x%x", ret); 1021 return (ret); 1022 } 1023 1024 static enum auth_stat 1025 rpcsec_gss_continue_init( 1026 struct svc_req *rqst, 1027 struct rpc_msg *msg, 1028 rpc_gss_creds creds, 1029 bool_t *no_dispatch) 1030 { 1031 int ret; 1032 svc_rpc_gss_data *client_data; 1033 svc_rpc_gss_parms_t *gss_parms; 1034 rpc_gss_init_res *retrans_result; 1035 1036 if (creds.ctx_handle.length == 0) { 1037 RPCGSS_LOG0(1, "_svcrpcsec_gss: no ctx_handle\n"); 1038 ret = AUTH_BADCRED; 1039 return (ret); 1040 } 1041 if ((client_data = get_client(&creds.ctx_handle)) == NULL) { 1042 ret = RPCSEC_GSS_NOCRED; 1043 RPCGSS_LOG0(1, "_svcrpcsec_gss: no security context\n"); 1044 return (ret); 1045 } 1046 1047 mutex_enter(&client_data->clm); 1048 if (client_data->stale) { 1049 ret = RPCSEC_GSS_NOCRED; 1050 RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n"); 1051 goto error2; 1052 } 1053 1054 /* 1055 * If context not established, go thru INIT code but with 1056 * this client handle. 1057 */ 1058 if (!client_data->established) { 1059 mutex_exit(&client_data->clm); 1060 return (rpcsec_gss_init(rqst, msg, creds, no_dispatch, 1061 client_data)); 1062 } 1063 1064 /* 1065 * Set the appropriate wrap/unwrap routine for RPCSEC_GSS. 1066 */ 1067 rqst->rq_xprt->xp_auth.svc_ah_ops = svc_rpc_gss_ops; 1068 rqst->rq_xprt->xp_auth.svc_ah_private = (caddr_t)client_data; 1069 1070 /* 1071 * Keep copy of parameters we'll need for response, for the 1072 * sake of reentrancy (we don't want to look in the context 1073 * data because when we are sending a response, another 1074 * request may have come in). 1075 */ 1076 gss_parms = &rqst->rq_xprt->xp_auth.svc_gss_parms; 1077 gss_parms->established = client_data->established; 1078 gss_parms->service = creds.service; 1079 gss_parms->qop_rcvd = (uint_t)client_data->qop; 1080 gss_parms->context = (void *)client_data->context; 1081 gss_parms->seq_num = creds.seq_num; 1082 1083 /* 1084 * This is an established context. Continue to 1085 * satisfy retried continue init requests out of 1086 * the retransmit cache. Throw away any that don't 1087 * have a matching xid or the cach is empty. 1088 * Delete the retransmit cache once the client sends 1089 * a data request. 1090 */ 1091 if (client_data->retrans_data && 1092 (client_data->retrans_data->xid == msg->rm_xid)) { 1093 retrans_result = &client_data->retrans_data->result; 1094 if (set_response_verf(rqst, msg, client_data, 1095 (uint_t)retrans_result->seq_window)) { 1096 gss_parms->established = FALSE; 1097 (void) svc_sendreply(rqst->rq_xprt, 1098 __xdr_rpc_gss_init_res, (caddr_t)retrans_result); 1099 *no_dispatch = TRUE; 1100 ASSERT(client_data->ref_cnt > 0); 1101 client_data->ref_cnt--; 1102 } 1103 } 1104 mutex_exit(&client_data->clm); 1105 1106 return (AUTH_OK); 1107 1108 error2: 1109 ASSERT(client_data->ref_cnt > 0); 1110 client_data->ref_cnt--; 1111 mutex_exit(&client_data->clm); 1112 return (ret); 1113 } 1114 1115 static enum auth_stat 1116 rpcsec_gss_data( 1117 struct svc_req *rqst, 1118 struct rpc_msg *msg, 1119 rpc_gss_creds creds, 1120 bool_t *no_dispatch) 1121 { 1122 int ret; 1123 svc_rpc_gss_parms_t *gss_parms; 1124 svc_rpc_gss_data *client_data; 1125 1126 switch (creds.service) { 1127 case rpc_gss_svc_none: 1128 case rpc_gss_svc_integrity: 1129 case rpc_gss_svc_privacy: 1130 break; 1131 default: 1132 cmn_err(CE_NOTE, "__svcrpcsec_gss: unknown service type=0x%x", 1133 creds.service); 1134 RPCGSS_LOG(1, "_svcrpcsec_gss: unknown service type: 0x%x\n", 1135 creds.service); 1136 ret = AUTH_BADCRED; 1137 return (ret); 1138 } 1139 1140 if (creds.ctx_handle.length == 0) { 1141 RPCGSS_LOG0(1, "_svcrpcsec_gss: no ctx_handle\n"); 1142 ret = AUTH_BADCRED; 1143 return (ret); 1144 } 1145 if ((client_data = get_client(&creds.ctx_handle)) == NULL) { 1146 ret = RPCSEC_GSS_NOCRED; 1147 RPCGSS_LOG0(1, "_svcrpcsec_gss: no security context\n"); 1148 return (ret); 1149 } 1150 1151 1152 mutex_enter(&client_data->clm); 1153 if (!client_data->established) { 1154 ret = AUTH_FAILED; 1155 goto error2; 1156 } 1157 if (client_data->stale) { 1158 ret = RPCSEC_GSS_NOCRED; 1159 RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n"); 1160 goto error2; 1161 } 1162 1163 /* 1164 * Once the context is established and there is no more 1165 * retransmission of last continue init request, it is safe 1166 * to delete the retransmit cache entry. 1167 */ 1168 if (client_data->retrans_data) 1169 retrans_del(client_data); 1170 1171 /* 1172 * Set the appropriate wrap/unwrap routine for RPCSEC_GSS. 1173 */ 1174 rqst->rq_xprt->xp_auth.svc_ah_ops = svc_rpc_gss_ops; 1175 rqst->rq_xprt->xp_auth.svc_ah_private = (caddr_t)client_data; 1176 1177 /* 1178 * Keep copy of parameters we'll need for response, for the 1179 * sake of reentrancy (we don't want to look in the context 1180 * data because when we are sending a response, another 1181 * request may have come in). 1182 */ 1183 gss_parms = &rqst->rq_xprt->xp_auth.svc_gss_parms; 1184 gss_parms->established = client_data->established; 1185 gss_parms->service = creds.service; 1186 gss_parms->qop_rcvd = (uint_t)client_data->qop; 1187 gss_parms->context = (void *)client_data->context; 1188 gss_parms->seq_num = creds.seq_num; 1189 1190 /* 1191 * Context is already established. Check verifier, and 1192 * note parameters we will need for response in gss_parms. 1193 */ 1194 if (!check_verf(msg, client_data->context, 1195 (int *)&gss_parms->qop_rcvd, client_data->u_cred.uid)) { 1196 ret = RPCSEC_GSS_NOCRED; 1197 RPCGSS_LOG0(1, "_svcrpcsec_gss: check verf failed\n"); 1198 goto error2; 1199 } 1200 1201 /* 1202 * Check and invoke callback if necessary. 1203 */ 1204 if (!client_data->done_docallback) { 1205 client_data->done_docallback = TRUE; 1206 client_data->qop = gss_parms->qop_rcvd; 1207 client_data->raw_cred.qop = gss_parms->qop_rcvd; 1208 client_data->raw_cred.service = creds.service; 1209 if (!do_callback(rqst, client_data)) { 1210 ret = AUTH_FAILED; 1211 RPCGSS_LOG0(1, "_svc_rpcsec_gss:callback failed\n"); 1212 goto error2; 1213 } 1214 } 1215 1216 /* 1217 * If the context was locked, make sure that the client 1218 * has not changed QOP. 1219 */ 1220 if (client_data->locked && gss_parms->qop_rcvd != client_data->qop) { 1221 ret = AUTH_BADVERF; 1222 RPCGSS_LOG0(1, "_svcrpcsec_gss: can not change qop\n"); 1223 goto error2; 1224 } 1225 1226 /* 1227 * Validate sequence number. 1228 */ 1229 if (!check_seq(client_data, creds.seq_num, &client_data->stale)) { 1230 if (client_data->stale) { 1231 ret = RPCSEC_GSS_FAILED; 1232 RPCGSS_LOG0(1, 1233 "_svc_rpcsec_gss:check seq failed\n"); 1234 } else { 1235 RPCGSS_LOG0(4, "_svc_rpcsec_gss:check seq " 1236 "failed on good context. Ignoring " 1237 "request\n"); 1238 /* 1239 * Operational error, drop packet silently. 1240 * The client will recover after timing out, 1241 * assuming this is a client error and not 1242 * a relpay attack. Don't dispatch. 1243 */ 1244 ret = AUTH_OK; 1245 *no_dispatch = TRUE; 1246 } 1247 goto error2; 1248 } 1249 1250 /* 1251 * set response verifier 1252 */ 1253 if (!set_response_verf(rqst, msg, client_data, creds.seq_num)) { 1254 ret = RPCSEC_GSS_FAILED; 1255 client_data->stale = TRUE; 1256 RPCGSS_LOG0(1, 1257 "_svc_rpcsec_gss:set response verifier failed\n"); 1258 goto error2; 1259 } 1260 1261 /* 1262 * If context is locked, make sure that the client 1263 * has not changed the security service. 1264 */ 1265 if (client_data->locked && 1266 client_data->raw_cred.service != creds.service) { 1267 RPCGSS_LOG0(1, "_svc_rpcsec_gss: " 1268 "security service changed.\n"); 1269 ret = AUTH_FAILED; 1270 goto error2; 1271 } 1272 1273 /* 1274 * Set client credentials to raw credential 1275 * structure in context. This is okay, since 1276 * this will not change during the lifetime of 1277 * the context (so it's MT safe). 1278 */ 1279 rqst->rq_clntcred = (char *)&client_data->raw_cred; 1280 1281 mutex_exit(&client_data->clm); 1282 return (AUTH_OK); 1283 1284 error2: 1285 ASSERT(client_data->ref_cnt > 0); 1286 client_data->ref_cnt--; 1287 mutex_exit(&client_data->clm); 1288 return (ret); 1289 } 1290 1291 /* 1292 * Note we don't have a client yet to use this routine and test it. 1293 */ 1294 static enum auth_stat 1295 rpcsec_gss_destroy( 1296 struct svc_req *rqst, 1297 rpc_gss_creds creds, 1298 bool_t *no_dispatch) 1299 { 1300 svc_rpc_gss_data *client_data; 1301 int ret; 1302 1303 if (creds.ctx_handle.length == 0) { 1304 RPCGSS_LOG0(1, "_svcrpcsec_gss: no ctx_handle\n"); 1305 ret = AUTH_BADCRED; 1306 return (ret); 1307 } 1308 if ((client_data = get_client(&creds.ctx_handle)) == NULL) { 1309 ret = RPCSEC_GSS_NOCRED; 1310 RPCGSS_LOG0(1, "_svcrpcsec_gss: no security context\n"); 1311 return (ret); 1312 } 1313 1314 mutex_enter(&client_data->clm); 1315 if (!client_data->established) { 1316 ret = AUTH_FAILED; 1317 goto error2; 1318 } 1319 if (client_data->stale) { 1320 ret = RPCSEC_GSS_NOCRED; 1321 RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n"); 1322 goto error2; 1323 } 1324 1325 (void) svc_sendreply(rqst->rq_xprt, xdr_void, NULL); 1326 *no_dispatch = TRUE; 1327 ASSERT(client_data->ref_cnt > 0); 1328 client_data->ref_cnt--; 1329 client_data->stale = TRUE; 1330 mutex_exit(&client_data->clm); 1331 return (AUTH_OK); 1332 1333 error2: 1334 ASSERT(client_data->ref_cnt > 0); 1335 client_data->ref_cnt--; 1336 client_data->stale = TRUE; 1337 mutex_exit(&client_data->clm); 1338 return (ret); 1339 } 1340 1341 /* 1342 * Server side authentication for RPCSEC_GSS. 1343 */ 1344 enum auth_stat 1345 __svcrpcsec_gss( 1346 struct svc_req *rqst, 1347 struct rpc_msg *msg, 1348 bool_t *no_dispatch) 1349 { 1350 XDR xdrs; 1351 rpc_gss_creds creds; 1352 struct opaque_auth *cred; 1353 int ret; 1354 1355 *no_dispatch = FALSE; 1356 1357 /* 1358 * Initialize response verifier to NULL verifier. If 1359 * necessary, this will be changed later. 1360 */ 1361 rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NONE; 1362 rqst->rq_xprt->xp_verf.oa_base = NULL; 1363 rqst->rq_xprt->xp_verf.oa_length = 0; 1364 1365 /* 1366 * Pull out and check credential and verifier. 1367 */ 1368 cred = &msg->rm_call.cb_cred; 1369 1370 if (cred->oa_length == 0) { 1371 RPCGSS_LOG0(1, "_svcrpcsec_gss: zero length cred\n"); 1372 return (AUTH_BADCRED); 1373 } 1374 1375 xdrmem_create(&xdrs, cred->oa_base, cred->oa_length, XDR_DECODE); 1376 bzero((char *)&creds, sizeof (creds)); 1377 if (!__xdr_rpc_gss_creds(&xdrs, &creds)) { 1378 XDR_DESTROY(&xdrs); 1379 RPCGSS_LOG0(1, "_svcrpcsec_gss: can't decode creds\n"); 1380 ret = AUTH_BADCRED; 1381 return (AUTH_BADCRED); 1382 } 1383 XDR_DESTROY(&xdrs); 1384 1385 switch (creds.gss_proc) { 1386 case RPCSEC_GSS_INIT: 1387 ret = rpcsec_gss_init(rqst, msg, creds, no_dispatch, NULL); 1388 break; 1389 case RPCSEC_GSS_CONTINUE_INIT: 1390 ret = rpcsec_gss_continue_init(rqst, msg, creds, no_dispatch); 1391 break; 1392 case RPCSEC_GSS_DATA: 1393 ret = rpcsec_gss_data(rqst, msg, creds, no_dispatch); 1394 break; 1395 case RPCSEC_GSS_DESTROY: 1396 ret = rpcsec_gss_destroy(rqst, creds, no_dispatch); 1397 break; 1398 default: 1399 cmn_err(CE_NOTE, "__svcrpcsec_gss: bad proc=%d", 1400 creds.gss_proc); 1401 ret = AUTH_BADCRED; 1402 } 1403 1404 if (creds.ctx_handle.length != 0) 1405 xdr_free(__xdr_rpc_gss_creds, (caddr_t)&creds); 1406 return (ret); 1407 } 1408 1409 /* 1410 * Check verifier. The verifier is the checksum of the RPC header 1411 * upto and including the credentials field. 1412 */ 1413 1414 /* ARGSUSED */ 1415 static bool_t 1416 check_verf(struct rpc_msg *msg, gss_ctx_id_t context, int *qop_state, uid_t uid) 1417 { 1418 int *buf, *tmp; 1419 char hdr[128]; 1420 struct opaque_auth *oa; 1421 int len; 1422 gss_buffer_desc msg_buf; 1423 gss_buffer_desc tok_buf; 1424 OM_uint32 gssstat, minor_stat; 1425 1426 /* 1427 * We have to reconstruct the RPC header from the previously 1428 * parsed information, since we haven't kept the header intact. 1429 */ 1430 1431 oa = &msg->rm_call.cb_cred; 1432 if (oa->oa_length > MAX_AUTH_BYTES) 1433 return (FALSE); 1434 1435 /* 8 XDR units from the IXDR macro calls. */ 1436 if (sizeof (hdr) < (8 * BYTES_PER_XDR_UNIT + 1437 RNDUP(oa->oa_length))) 1438 return (FALSE); 1439 buf = (int *)hdr; 1440 IXDR_PUT_U_INT32(buf, msg->rm_xid); 1441 IXDR_PUT_ENUM(buf, msg->rm_direction); 1442 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_rpcvers); 1443 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_prog); 1444 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_vers); 1445 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_proc); 1446 IXDR_PUT_ENUM(buf, oa->oa_flavor); 1447 IXDR_PUT_U_INT32(buf, oa->oa_length); 1448 if (oa->oa_length) { 1449 len = RNDUP(oa->oa_length); 1450 tmp = buf; 1451 buf += len / sizeof (int); 1452 *(buf - 1) = 0; 1453 (void) bcopy(oa->oa_base, (caddr_t)tmp, oa->oa_length); 1454 } 1455 len = ((char *)buf) - hdr; 1456 msg_buf.length = len; 1457 msg_buf.value = hdr; 1458 oa = &msg->rm_call.cb_verf; 1459 tok_buf.length = oa->oa_length; 1460 tok_buf.value = oa->oa_base; 1461 1462 gssstat = kgss_verify(&minor_stat, context, &msg_buf, &tok_buf, 1463 qop_state); 1464 if (gssstat != GSS_S_COMPLETE) { 1465 RPCGSS_LOG(1, "check_verf: kgss_verify status 0x%x\n", gssstat); 1466 1467 RPCGSS_LOG(4, "check_verf: msg_buf length %d\n", len); 1468 RPCGSS_LOG(4, "check_verf: msg_buf value 0x%x\n", *(int *)hdr); 1469 RPCGSS_LOG(4, "check_verf: tok_buf length %ld\n", 1470 tok_buf.length); 1471 RPCGSS_LOG(4, "check_verf: tok_buf value 0x%p\n", 1472 (void *)oa->oa_base); 1473 RPCGSS_LOG(4, "check_verf: context 0x%p\n", (void *)context); 1474 1475 return (FALSE); 1476 } 1477 return (TRUE); 1478 } 1479 1480 1481 /* 1482 * Set response verifier. This is the checksum of the given number. 1483 * (e.g. sequence number or sequence window) 1484 */ 1485 static bool_t 1486 set_response_verf(rqst, msg, cl, num) 1487 struct svc_req *rqst; 1488 struct rpc_msg *msg; 1489 svc_rpc_gss_data *cl; 1490 uint_t num; 1491 { 1492 OM_uint32 minor; 1493 gss_buffer_desc in_buf, out_buf; 1494 uint_t num_net; 1495 1496 num_net = (uint_t)htonl(num); 1497 in_buf.length = sizeof (num); 1498 in_buf.value = (char *)&num_net; 1499 /* XXX uid ? */ 1500 1501 if ((kgss_sign(&minor, cl->context, cl->qop, &in_buf, 1502 &out_buf)) != GSS_S_COMPLETE) 1503 return (FALSE); 1504 1505 rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS; 1506 rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base; 1507 rqst->rq_xprt->xp_verf.oa_length = out_buf.length; 1508 bcopy(out_buf.value, rqst->rq_xprt->xp_verf.oa_base, out_buf.length); 1509 (void) gss_release_buffer(&minor, &out_buf); 1510 return (TRUE); 1511 } 1512 1513 /* 1514 * Create client context. 1515 */ 1516 static svc_rpc_gss_data * 1517 create_client() 1518 { 1519 svc_rpc_gss_data *client_data; 1520 static uint_t key = 1; 1521 1522 client_data = (svc_rpc_gss_data *) kmem_cache_alloc(svc_data_handle, 1523 KM_SLEEP); 1524 if (client_data == NULL) 1525 return (NULL); 1526 1527 /* 1528 * set up client data structure 1529 */ 1530 client_data->next = NULL; 1531 client_data->prev = NULL; 1532 client_data->lru_next = NULL; 1533 client_data->lru_prev = NULL; 1534 client_data->client_name.length = 0; 1535 client_data->client_name.value = NULL; 1536 client_data->seq_num = 0; 1537 bzero(client_data->seq_bits, sizeof (client_data->seq_bits)); 1538 client_data->key = 0; 1539 client_data->cookie = NULL; 1540 bzero(&client_data->u_cred, sizeof (client_data->u_cred)); 1541 client_data->established = FALSE; 1542 client_data->locked = FALSE; 1543 client_data->u_cred_set = 0; 1544 client_data->context = GSS_C_NO_CONTEXT; 1545 client_data->expiration = GSS_C_INDEFINITE; 1546 client_data->deleg = GSS_C_NO_CREDENTIAL; 1547 client_data->ref_cnt = 1; 1548 client_data->last_ref_time = gethrestime_sec(); 1549 client_data->qop = GSS_C_QOP_DEFAULT; 1550 client_data->done_docallback = FALSE; 1551 client_data->stale = FALSE; 1552 client_data->retrans_data = NULL; 1553 bzero(&client_data->raw_cred, sizeof (client_data->raw_cred)); 1554 1555 /* 1556 * The client context handle is a 32-bit key (unsigned int). 1557 * The key is incremented until there is no duplicate for it. 1558 */ 1559 1560 svc_rpc_gss_cache_stats.total_entries_allocated++; 1561 mutex_enter(&ctx_mutex); 1562 for (;;) { 1563 client_data->key = key++; 1564 if (find_client(client_data->key) == NULL) { 1565 insert_client(client_data); 1566 mutex_exit(&ctx_mutex); 1567 return (client_data); 1568 } 1569 } 1570 /*NOTREACHED*/ 1571 } 1572 1573 /* 1574 * Insert client context into hash list and LRU list. 1575 */ 1576 static void 1577 insert_client(client_data) 1578 svc_rpc_gss_data *client_data; 1579 { 1580 svc_rpc_gss_data *cl; 1581 int index = HASH(client_data->key); 1582 1583 ASSERT(mutex_owned(&ctx_mutex)); 1584 1585 client_data->prev = NULL; 1586 cl = clients[index]; 1587 if ((client_data->next = cl) != NULL) 1588 cl->prev = client_data; 1589 clients[index] = client_data; 1590 1591 client_data->lru_prev = NULL; 1592 if ((client_data->lru_next = lru_first) != NULL) 1593 lru_first->lru_prev = client_data; 1594 else 1595 lru_last = client_data; 1596 lru_first = client_data; 1597 1598 num_gss_contexts++; 1599 } 1600 1601 /* 1602 * Fetch a client, given the client context handle. Move it to the 1603 * top of the LRU list since this is the most recently used context. 1604 */ 1605 static svc_rpc_gss_data * 1606 get_client(ctx_handle) 1607 gss_buffer_t ctx_handle; 1608 { 1609 uint_t key = *(uint_t *)ctx_handle->value; 1610 svc_rpc_gss_data *cl; 1611 1612 mutex_enter(&ctx_mutex); 1613 if ((cl = find_client(key)) != NULL) { 1614 mutex_enter(&cl->clm); 1615 if (cl->stale) { 1616 if (cl->ref_cnt == 0) { 1617 mutex_exit(&cl->clm); 1618 destroy_client(cl); 1619 } else { 1620 mutex_exit(&cl->clm); 1621 } 1622 mutex_exit(&ctx_mutex); 1623 return (NULL); 1624 } 1625 cl->ref_cnt++; 1626 cl->last_ref_time = gethrestime_sec(); 1627 mutex_exit(&cl->clm); 1628 if (cl != lru_first) { 1629 cl->lru_prev->lru_next = cl->lru_next; 1630 if (cl->lru_next != NULL) 1631 cl->lru_next->lru_prev = cl->lru_prev; 1632 else 1633 lru_last = cl->lru_prev; 1634 cl->lru_prev = NULL; 1635 cl->lru_next = lru_first; 1636 lru_first->lru_prev = cl; 1637 lru_first = cl; 1638 } 1639 } 1640 mutex_exit(&ctx_mutex); 1641 return (cl); 1642 } 1643 1644 /* 1645 * Given the client context handle, find the context corresponding to it. 1646 * Don't change its LRU state since it may not be used. 1647 */ 1648 static svc_rpc_gss_data * 1649 find_client(key) 1650 uint_t key; 1651 { 1652 int index = HASH(key); 1653 svc_rpc_gss_data *cl = NULL; 1654 1655 ASSERT(mutex_owned(&ctx_mutex)); 1656 1657 for (cl = clients[index]; cl != NULL; cl = cl->next) { 1658 if (cl->key == key) 1659 break; 1660 } 1661 return (cl); 1662 } 1663 1664 /* 1665 * Destroy a client context. 1666 */ 1667 static void 1668 destroy_client(client_data) 1669 svc_rpc_gss_data *client_data; 1670 { 1671 OM_uint32 minor; 1672 int index = HASH(client_data->key); 1673 1674 ASSERT(mutex_owned(&ctx_mutex)); 1675 1676 /* 1677 * remove from hash list 1678 */ 1679 if (client_data->prev == NULL) 1680 clients[index] = client_data->next; 1681 else 1682 client_data->prev->next = client_data->next; 1683 if (client_data->next != NULL) 1684 client_data->next->prev = client_data->prev; 1685 1686 /* 1687 * remove from LRU list 1688 */ 1689 if (client_data->lru_prev == NULL) 1690 lru_first = client_data->lru_next; 1691 else 1692 client_data->lru_prev->lru_next = client_data->lru_next; 1693 if (client_data->lru_next != NULL) 1694 client_data->lru_next->lru_prev = client_data->lru_prev; 1695 else 1696 lru_last = client_data->lru_prev; 1697 1698 /* 1699 * If there is a GSS context, clean up GSS state. 1700 */ 1701 if (client_data->context != GSS_C_NO_CONTEXT) { 1702 (void) kgss_delete_sec_context(&minor, &client_data->context, 1703 NULL); 1704 1705 common_client_data_free(client_data); 1706 1707 if (client_data->deleg != GSS_C_NO_CREDENTIAL) { 1708 (void) kgss_release_cred(&minor, &client_data->deleg, 1709 crgetuid(CRED())); 1710 } 1711 } 1712 1713 if (client_data->u_cred.gidlist != NULL) { 1714 kmem_free((char *)client_data->u_cred.gidlist, 1715 client_data->u_cred.gidlen * sizeof (gid_t)); 1716 client_data->u_cred.gidlist = NULL; 1717 } 1718 if (client_data->retrans_data != NULL) 1719 retrans_del(client_data); 1720 1721 kmem_cache_free(svc_data_handle, client_data); 1722 num_gss_contexts--; 1723 } 1724 1725 /* 1726 * Check for expired and stale client contexts. 1727 */ 1728 static void 1729 sweep_clients(bool_t from_reclaim) 1730 { 1731 svc_rpc_gss_data *cl, *next; 1732 time_t last_reference_needed; 1733 time_t now = gethrestime_sec(); 1734 1735 ASSERT(mutex_owned(&ctx_mutex)); 1736 1737 last_reference_needed = now - (from_reclaim ? 1738 svc_rpc_gss_active_delta : svc_rpc_gss_inactive_delta); 1739 1740 cl = lru_last; 1741 while (cl) { 1742 /* 1743 * We assume here that any manipulation of the LRU pointers 1744 * and hash bucket pointers are only done when holding the 1745 * ctx_mutex. 1746 */ 1747 next = cl->lru_prev; 1748 1749 mutex_enter(&cl->clm); 1750 1751 if ((cl->expiration != GSS_C_INDEFINITE && 1752 cl->expiration <= now) || cl->stale || 1753 cl->last_ref_time <= last_reference_needed) { 1754 1755 if ((cl->expiration != GSS_C_INDEFINITE && 1756 cl->expiration <= now) || cl->stale || 1757 (cl->last_ref_time <= last_reference_needed && 1758 cl->ref_cnt == 0)) { 1759 1760 cl->stale = TRUE; 1761 1762 if (cl->ref_cnt == 0) { 1763 mutex_exit(&cl->clm); 1764 if (from_reclaim) 1765 svc_rpc_gss_cache_stats. 1766 no_returned_by_reclaim++; 1767 destroy_client(cl); 1768 } else 1769 mutex_exit(&cl->clm); 1770 } else 1771 mutex_exit(&cl->clm); 1772 } else 1773 mutex_exit(&cl->clm); 1774 1775 cl = next; 1776 } 1777 1778 last_swept = gethrestime_sec(); 1779 } 1780 1781 /* 1782 * Encrypt the serialized arguments from xdr_func applied to xdr_ptr 1783 * and write the result to xdrs. 1784 */ 1785 static bool_t 1786 svc_rpc_gss_wrap(auth, out_xdrs, xdr_func, xdr_ptr) 1787 SVCAUTH *auth; 1788 XDR *out_xdrs; 1789 bool_t (*xdr_func)(); 1790 caddr_t xdr_ptr; 1791 { 1792 svc_rpc_gss_parms_t *gss_parms = SVCAUTH_GSSPARMS(auth); 1793 bool_t ret; 1794 1795 /* 1796 * If context is not established, or if neither integrity nor 1797 * privacy service is used, don't wrap - just XDR encode. 1798 * Otherwise, wrap data using service and QOP parameters. 1799 */ 1800 if (!gss_parms->established || 1801 gss_parms->service == rpc_gss_svc_none) 1802 return ((*xdr_func)(out_xdrs, xdr_ptr)); 1803 1804 ret = __rpc_gss_wrap_data(gss_parms->service, 1805 (OM_uint32)gss_parms->qop_rcvd, 1806 (gss_ctx_id_t)gss_parms->context, 1807 gss_parms->seq_num, 1808 out_xdrs, xdr_func, xdr_ptr); 1809 return (ret); 1810 } 1811 1812 /* 1813 * Decrypt the serialized arguments and XDR decode them. 1814 */ 1815 static bool_t 1816 svc_rpc_gss_unwrap(auth, in_xdrs, xdr_func, xdr_ptr) 1817 SVCAUTH *auth; 1818 XDR *in_xdrs; 1819 bool_t (*xdr_func)(); 1820 caddr_t xdr_ptr; 1821 { 1822 svc_rpc_gss_parms_t *gss_parms = SVCAUTH_GSSPARMS(auth); 1823 1824 /* 1825 * If context is not established, or if neither integrity nor 1826 * privacy service is used, don't unwrap - just XDR decode. 1827 * Otherwise, unwrap data. 1828 */ 1829 if (!gss_parms->established || 1830 gss_parms->service == rpc_gss_svc_none) 1831 return ((*xdr_func)(in_xdrs, xdr_ptr)); 1832 1833 return (__rpc_gss_unwrap_data(gss_parms->service, 1834 (gss_ctx_id_t)gss_parms->context, 1835 gss_parms->seq_num, 1836 gss_parms->qop_rcvd, 1837 in_xdrs, xdr_func, xdr_ptr)); 1838 } 1839 1840 1841 /* ARGSUSED */ 1842 int 1843 rpc_gss_svc_max_data_length(struct svc_req *req, int max_tp_unit_len) 1844 { 1845 return (0); 1846 } 1847 1848 /* 1849 * Add retransmit entry to the context cache entry for a new xid. 1850 * If there is already an entry, delete it before adding the new one. 1851 */ 1852 static void retrans_add(client, xid, result) 1853 svc_rpc_gss_data *client; 1854 uint32_t xid; 1855 rpc_gss_init_res *result; 1856 { 1857 retrans_entry *rdata; 1858 1859 if (client->retrans_data && client->retrans_data->xid == xid) 1860 return; 1861 1862 rdata = kmem_zalloc(sizeof (*rdata), KM_SLEEP); 1863 1864 if (rdata == NULL) 1865 return; 1866 1867 rdata->xid = xid; 1868 rdata->result = *result; 1869 1870 if (result->token.length != 0) { 1871 GSS_DUP_BUFFER(rdata->result.token, result->token); 1872 } 1873 1874 if (client->retrans_data) 1875 retrans_del(client); 1876 1877 client->retrans_data = rdata; 1878 } 1879 1880 /* 1881 * Delete the retransmit data from the context cache entry. 1882 */ 1883 static void retrans_del(client) 1884 svc_rpc_gss_data *client; 1885 { 1886 retrans_entry *rdata; 1887 OM_uint32 minor_stat; 1888 1889 if (client->retrans_data == NULL) 1890 return; 1891 1892 rdata = client->retrans_data; 1893 if (rdata->result.token.length != 0) { 1894 (void) gss_release_buffer(&minor_stat, &rdata->result.token); 1895 } 1896 1897 kmem_free((caddr_t)rdata, sizeof (*rdata)); 1898 client->retrans_data = NULL; 1899 } 1900 1901 /* 1902 * This function frees the following fields of svc_rpc_gss_data: 1903 * client_name, raw_cred.client_principal, raw_cred.mechanism. 1904 */ 1905 static void 1906 common_client_data_free(svc_rpc_gss_data *client_data) 1907 { 1908 if (client_data->client_name.length > 0) { 1909 (void) gss_release_buffer(NULL, &client_data->client_name); 1910 } 1911 1912 if (client_data->raw_cred.client_principal) { 1913 kmem_free((caddr_t)client_data->raw_cred.client_principal, 1914 client_data->raw_cred.client_principal->len + 1915 sizeof (int)); 1916 client_data->raw_cred.client_principal = NULL; 1917 } 1918 1919 /* 1920 * In the user GSS-API library, mechanism (mech_type returned 1921 * by gss_accept_sec_context) is static storage, however 1922 * since all the work is done for gss_accept_sec_context under 1923 * gssd, what is returned in the kernel, is a copy from the oid 1924 * obtained under from gssd, so need to free it when destroying 1925 * the client data. 1926 */ 1927 1928 if (client_data->raw_cred.mechanism) { 1929 kgss_free_oid(client_data->raw_cred.mechanism); 1930 client_data->raw_cred.mechanism = NULL; 1931 } 1932 } 1933