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