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