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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Copyright (c) 2018, Joyent, Inc. 28 * Copyright 2021 Tintri by DDN, Inc. All rights reserved. 29 */ 30 31 /* 32 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. 33 * 34 * $Header: 35 * /afs/gza.com/product/secure/rel-eng/src/1.1/rpc/RCS/auth_gssapi.c,v 36 * 1.14 1995/03/22 22:07:55 jik Exp $ 37 */ 38 39 #include <sys/systm.h> 40 #include <sys/types.h> 41 #include <gssapi/gssapi.h> 42 #include <rpc/rpc.h> 43 #include <rpc/rpcsec_defs.h> 44 #include <sys/debug.h> 45 #include <sys/cmn_err.h> 46 #include <sys/ddi.h> 47 48 static void rpc_gss_nextverf(); 49 static bool_t rpc_gss_marshall(); 50 static bool_t rpc_gss_validate(); 51 static bool_t rpc_gss_refresh(); 52 static void rpc_gss_destroy(); 53 #if 0 54 static void rpc_gss_destroy_pvt(); 55 #endif 56 static void rpc_gss_free_pvt(); 57 static int rpc_gss_seccreate_pvt(); 58 static bool_t rpc_gss_wrap(); 59 static bool_t rpc_gss_unwrap(); 60 static bool_t validate_seqwin(); 61 62 63 #ifdef DEBUG 64 #include <sys/promif.h> 65 #endif 66 67 static struct auth_ops rpc_gss_ops = { 68 rpc_gss_nextverf, 69 rpc_gss_marshall, 70 rpc_gss_validate, 71 rpc_gss_refresh, 72 rpc_gss_destroy, 73 rpc_gss_wrap, 74 rpc_gss_unwrap, 75 }; 76 77 /* 78 * Private data for RPCSEC_GSS. 79 */ 80 typedef struct _rpc_gss_data { 81 bool_t established; /* TRUE when established */ 82 CLIENT *clnt; /* associated client handle */ 83 int version; /* RPCSEC version */ 84 gss_ctx_id_t context; /* GSS context id */ 85 gss_buffer_desc ctx_handle; /* RPCSEC GSS context handle */ 86 uint_t seq_num; /* last sequence number rcvd */ 87 gss_cred_id_t my_cred; /* caller's GSS credentials */ 88 OM_uint32 qop; /* requested QOP */ 89 rpc_gss_service_t service; /* requested service */ 90 uint_t gss_proc; /* GSS control procedure */ 91 gss_name_t target_name; /* target server */ 92 int req_flags; /* GSS request bits */ 93 gss_OID mech_type; /* GSS mechanism */ 94 OM_uint32 time_req; /* requested cred lifetime */ 95 bool_t invalid; /* can't use this any more */ 96 OM_uint32 seq_window; /* server sequence window */ 97 struct opaque_auth *verifier; /* rpc reply verifier saved for */ 98 /* validating the sequence window */ 99 gss_channel_bindings_t icb; 100 } rpc_gss_data; 101 #define AUTH_PRIVATE(auth) ((rpc_gss_data *)auth->ah_private) 102 103 #define INTERRUPT_OK 1 /* allow interrupt */ 104 105 /* 106 * RPCSEC_GSS auth cache definitions. 107 */ 108 109 /* The table size must be a power of two. */ 110 #define GSSAUTH_TABLESIZE 16 111 #define HASH(keynum, uid_num) \ 112 ((((intptr_t)(keynum)) ^ ((int)uid_num)) & (GSSAUTH_TABLESIZE - 1)) 113 114 /* 115 * gss auth cache entry. 116 */ 117 typedef struct ga_cache_entry { 118 void *cache_key; 119 uid_t uid; 120 zoneid_t zoneid; 121 bool_t in_use; 122 time_t ref_time; /* the time referenced previously */ 123 time_t ctx_expired_time; /* when the context will be expired */ 124 AUTH *auth; 125 struct ga_cache_entry *next; 126 } *ga_cache_list; 127 128 struct ga_cache_entry *ga_cache_table[GSSAUTH_TABLESIZE]; 129 static krwlock_t ga_cache_table_lock; 130 static struct kmem_cache *ga_cache_handle; 131 static void gssauth_cache_reclaim(void *); 132 133 static void gssauth_zone_fini(zoneid_t, void *); 134 static zone_key_t gssauth_zone_key; 135 136 int ga_cache_hit; 137 int ga_cache_miss; 138 int ga_cache_reclaim; 139 140 #define NOT_DEAD(ptr) ASSERT((((intptr_t)(ptr)) != 0xdeadbeef)) 141 142 void 143 gssauth_init(void) 144 { 145 /* 146 * Initialize gss auth cache table lock 147 */ 148 rw_init(&ga_cache_table_lock, NULL, RW_DEFAULT, NULL); 149 150 /* 151 * Allocate gss auth cache handle 152 */ 153 ga_cache_handle = kmem_cache_create("ga_cache_handle", 154 sizeof (struct ga_cache_entry), 0, NULL, NULL, 155 gssauth_cache_reclaim, NULL, NULL, 0); 156 zone_key_create(&gssauth_zone_key, NULL, NULL, gssauth_zone_fini); 157 } 158 159 /* 160 * Destroy the structures previously initialized in gssauth_init() 161 * This routine is called by _init() if mod_install() failed. 162 */ 163 void 164 gssauth_fini(void) 165 { 166 (void) zone_key_delete(gssauth_zone_key); 167 kmem_cache_destroy(ga_cache_handle); 168 rw_destroy(&ga_cache_table_lock); 169 } 170 171 /* 172 * This is a cleanup routine to release cached entries when a zone is being 173 * destroyed. The code is also used when kmem calls us to free up memory, at 174 * which point ``zoneid'' will be ALL_ZONES. We don't honor the cache timeout 175 * when the zone is going away, since the zoneid (and all associated cached 176 * entries) are invalid. 177 */ 178 time_t rpc_gss_cache_time = 60 * 60; 179 180 /* ARGSUSED */ 181 static void 182 gssauth_zone_fini(zoneid_t zoneid, void *unused) 183 { 184 struct ga_cache_entry *p, *prev, *next; 185 int i; 186 time_t now; 187 188 rw_enter(&ga_cache_table_lock, RW_WRITER); 189 190 for (i = 0; i < GSSAUTH_TABLESIZE; i++) { 191 prev = NULL; 192 for (p = ga_cache_table[i]; p; p = next) { 193 NOT_DEAD(p->next); 194 next = p->next; 195 NOT_DEAD(next); 196 if (zoneid == ALL_ZONES) { /* kmem callback */ 197 /* 198 * Free entries that have not been 199 * used for rpc_gss_cache_time seconds. 200 */ 201 now = gethrestime_sec(); 202 if ((p->ref_time + rpc_gss_cache_time > 203 now) || p->in_use) { 204 if ((p->ref_time + rpc_gss_cache_time <= 205 now) && p->in_use) { 206 RPCGSS_LOG0(2, "gssauth_cache_" 207 "reclaim: in_use\n"); 208 } 209 prev = p; 210 continue; 211 } 212 } else { 213 if (p->zoneid != zoneid) { 214 prev = p; 215 continue; 216 } 217 ASSERT(!p->in_use); 218 } 219 220 RPCGSS_LOG(2, "gssauth_cache_reclaim: destroy auth " 221 "%p\n", (void *)p->auth); 222 rpc_gss_destroy(p->auth); 223 kmem_cache_free(ga_cache_handle, (void *)p); 224 if (prev == NULL) { 225 ga_cache_table[i] = next; 226 } else { 227 NOT_DEAD(prev->next); 228 prev->next = next; 229 } 230 } 231 } 232 233 rw_exit(&ga_cache_table_lock); 234 235 } 236 237 /* 238 * Called by the kernel memory allocator when 239 * memory is low. Free unused cache entries. 240 * If that's not enough, the VM system will 241 * call again for some more. 242 */ 243 /*ARGSUSED*/ 244 static void 245 gssauth_cache_reclaim(void *cdrarg) 246 { 247 gssauth_zone_fini(ALL_ZONES, NULL); 248 } 249 250 #define NOT_NULL(ptr) ASSERT(ptr) 251 #define IS_ALIGNED(ptr) ASSERT((((intptr_t)(ptr)) & 3) == 0) 252 253 /* 254 * Get the client gss security service handle. 255 * If it is in the cache table, get it, otherwise, create 256 * a new one by calling rpc_gss_seccreate(). 257 */ 258 int 259 rpc_gss_secget(CLIENT *clnt, 260 char *principal, 261 rpc_gss_OID mechanism, 262 rpc_gss_service_t service_type, 263 uint_t qop, 264 rpc_gss_options_req_t *options_req, 265 rpc_gss_options_ret_t *options_ret, 266 void *cache_key, 267 cred_t *cr, 268 AUTH **retauth) 269 { 270 struct ga_cache_entry **head, *current, *new, *prev; 271 AUTH *auth = NULL; 272 rpc_gss_data *ap; 273 rpc_gss_options_ret_t opt_ret; 274 int status = 0; 275 uid_t uid = crgetuid(cr); 276 zoneid_t zoneid = getzoneid(); 277 278 if (retauth == NULL) 279 return (EINVAL); 280 *retauth = NULL; 281 282 NOT_NULL(cr); 283 IS_ALIGNED(cr); 284 #ifdef DEBUG 285 if (HASH(cache_key, uid) < 0) { 286 prom_printf("cache_key %p, cr %p\n", cache_key, (void *)cr); 287 } 288 #endif 289 290 /* 291 * Get a valid gss auth handle from the cache table. 292 * If auth in cache is invalid and not in use, destroy it. 293 */ 294 prev = NULL; 295 rw_enter(&ga_cache_table_lock, RW_WRITER); 296 297 ASSERT(HASH(cache_key, uid) >= 0); 298 head = &ga_cache_table[HASH(cache_key, uid)]; 299 NOT_NULL(head); 300 IS_ALIGNED(head); 301 302 for (current = *head; current; current = current->next) { 303 NOT_NULL(current); 304 IS_ALIGNED(current); 305 if ((cache_key == current->cache_key) && 306 (uid == current->uid) && (zoneid == current->zoneid) && 307 !current->in_use) { 308 current->in_use = TRUE; 309 current->ref_time = gethrestime_sec(); 310 ap = AUTH_PRIVATE(current->auth); 311 ap->clnt = clnt; 312 ga_cache_hit++; 313 if (ap->invalid || 314 ((current->ctx_expired_time != GSS_C_INDEFINITE) && 315 (gethrestime_sec() >= 316 current->ctx_expired_time))) { 317 RPCGSS_LOG0(1, "NOTICE: rpc_gss_secget: time to " 318 "refresh the auth\n"); 319 if (prev == NULL) { 320 *head = current->next; 321 } else { 322 prev->next = current->next; 323 } 324 rpc_gss_destroy(current->auth); 325 kmem_cache_free(ga_cache_handle, (void *) current); 326 auth = NULL; 327 } else { 328 auth = current->auth; 329 } 330 break; 331 } else { 332 prev = current; 333 } 334 } 335 rw_exit(&ga_cache_table_lock); 336 337 /* 338 * If no valid gss auth handle can be found in the cache, create 339 * a new one. 340 */ 341 if (!auth) { 342 ga_cache_miss++; 343 if (options_ret == NULL) 344 options_ret = &opt_ret; 345 346 status = rpc_gss_seccreate(clnt, principal, mechanism, 347 service_type, qop, options_req, options_ret, cr, &auth); 348 if (status == 0) { 349 RPCGSS_LOG(2, "rpc_gss_secget: new auth %p\n", 350 (void *)auth); 351 new = kmem_cache_alloc(ga_cache_handle, KM_NOSLEEP); 352 IS_ALIGNED(new); 353 NOT_DEAD(new); 354 if (new) { 355 new->cache_key = cache_key; 356 new->uid = uid; 357 new->zoneid = zoneid; 358 new->in_use = TRUE; 359 new->ref_time = gethrestime_sec(); 360 if (options_ret->time_ret != GSS_C_INDEFINITE) { 361 new->ctx_expired_time = new->ref_time + 362 options_ret->time_ret; 363 } else { 364 new->ctx_expired_time = GSS_C_INDEFINITE; 365 } 366 new->auth = auth; 367 rw_enter(&ga_cache_table_lock, RW_WRITER); 368 NOT_DEAD(*head); 369 NOT_DEAD(new->next); 370 new->next = *head; 371 *head = new; 372 rw_exit(&ga_cache_table_lock); 373 } 374 /* done with opt_ret */ 375 if (options_ret == &opt_ret) { 376 kgss_free_oid((gss_OID) opt_ret.actual_mechanism); 377 } 378 } 379 } 380 381 *retauth = auth; 382 return (status); 383 } 384 385 386 387 /* 388 * rpc_gss_secfree will destroy a rpcsec_gss context only if 389 * the auth handle is not in the cache table. 390 */ 391 void 392 rpc_gss_secfree(AUTH *auth) 393 { 394 struct ga_cache_entry *next, *cur; 395 int i; 396 397 /* 398 * Check the cache table to find the auth. 399 * Marked it unused. 400 */ 401 rw_enter(&ga_cache_table_lock, RW_WRITER); 402 for (i = 0; i < GSSAUTH_TABLESIZE; i++) { 403 for (cur = ga_cache_table[i]; cur; cur = next) { 404 NOT_DEAD(cur); 405 next = cur->next; 406 NOT_DEAD(next); 407 if (cur->auth == auth) { 408 ASSERT(cur->in_use == TRUE); 409 cur->in_use = FALSE; 410 rw_exit(&ga_cache_table_lock); 411 return; 412 } 413 } 414 } 415 rw_exit(&ga_cache_table_lock); 416 RPCGSS_LOG(2, "rpc_gss_secfree: destroy auth %p\n", (void *)auth); 417 rpc_gss_destroy(auth); 418 } 419 420 421 /* 422 * Create a gss security service context. 423 */ 424 int 425 rpc_gss_seccreate(CLIENT *clnt, 426 char *principal, /* target service@server */ 427 rpc_gss_OID mechanism, /* security mechanism */ 428 rpc_gss_service_t service_type, /* security service */ 429 uint_t qop, /* requested QOP */ 430 rpc_gss_options_req_t *options_req, /* requested options */ 431 rpc_gss_options_ret_t *options_ret, /* returned options */ 432 cred_t *cr, /* client's unix cred */ 433 AUTH **retauth) /* auth handle */ 434 { 435 OM_uint32 gssstat; 436 OM_uint32 minor_stat; 437 gss_name_t target_name; 438 int ret_flags; 439 OM_uint32 time_rec; 440 gss_buffer_desc input_name; 441 AUTH *auth = NULL; 442 rpc_gss_data *ap = NULL; 443 int error; 444 445 /* 446 * convert name to GSS internal type 447 */ 448 input_name.value = principal; 449 input_name.length = strlen(principal); 450 451 if (options_ret != NULL) { 452 options_ret->major_status = 0; 453 options_ret->minor_status = 0; 454 } 455 456 gssstat = gss_import_name(&minor_stat, &input_name, 457 (gss_OID)GSS_C_NT_HOSTBASED_SERVICE, &target_name); 458 459 if (gssstat != GSS_S_COMPLETE) { 460 RPCGSS_LOG0(1, 461 "rpc_gss_seccreate: unable to import gss name\n"); 462 if (options_ret != NULL) { 463 options_ret->major_status = gssstat; 464 options_ret->minor_status = minor_stat; 465 } 466 return (ENOMEM); 467 } 468 469 /* 470 * Create AUTH handle. Save the necessary interface information 471 * so that the client can refresh the handle later if needed. 472 */ 473 if ((auth = (AUTH *) kmem_alloc(sizeof (*auth), KM_SLEEP)) != NULL) 474 ap = (rpc_gss_data *) kmem_alloc(sizeof (*ap), KM_SLEEP); 475 if (auth == NULL || ap == NULL) { 476 RPCGSS_LOG0(1, "rpc_gss_seccreate: out of memory\n"); 477 if (auth != NULL) 478 kmem_free((char *)auth, sizeof (*auth)); 479 (void) gss_release_name(&minor_stat, &target_name); 480 return (ENOMEM); 481 } 482 483 bzero((char *)ap, sizeof (*ap)); 484 ap->clnt = clnt; 485 ap->version = RPCSEC_GSS_VERSION; 486 if (options_req != NULL) { 487 ap->my_cred = options_req->my_cred; 488 ap->req_flags = options_req->req_flags; 489 ap->time_req = options_req->time_req; 490 ap->icb = options_req->input_channel_bindings; 491 } else { 492 ap->my_cred = GSS_C_NO_CREDENTIAL; 493 ap->req_flags = GSS_C_MUTUAL_FLAG; 494 ap->time_req = 0; 495 ap->icb = GSS_C_NO_CHANNEL_BINDINGS; 496 } 497 if ((ap->service = service_type) == rpc_gss_svc_default) 498 ap->service = rpc_gss_svc_integrity; 499 ap->qop = qop; 500 ap->target_name = target_name; 501 502 /* 503 * Now invoke the real interface that sets up the context from 504 * the information stashed away in the private data. 505 */ 506 if (error = rpc_gss_seccreate_pvt(&gssstat, &minor_stat, auth, ap, 507 mechanism, &ap->mech_type, &ret_flags, &time_rec, cr, 0)) { 508 if (ap->target_name) { 509 (void) gss_release_name(&minor_stat, &ap->target_name); 510 } 511 if (options_ret != NULL) { 512 options_ret->major_status = gssstat; 513 options_ret->minor_status = minor_stat; 514 } 515 kmem_free((char *)ap, sizeof (*ap)); 516 kmem_free((char *)auth, sizeof (*auth)); 517 RPCGSS_LOG(1, "rpc_gss_seccreate: init context failed" 518 " errno=%d\n", error); 519 return (error); 520 } 521 522 /* 523 * Make sure that the requested service is supported. In all 524 * cases, integrity service must be available. 525 */ 526 if ((ap->service == rpc_gss_svc_privacy && 527 !(ret_flags & GSS_C_CONF_FLAG)) || 528 !(ret_flags & GSS_C_INTEG_FLAG)) { 529 rpc_gss_destroy(auth); 530 RPCGSS_LOG0(1, "rpc_gss_seccreate: service not supported\n"); 531 return (EPROTONOSUPPORT); 532 } 533 534 /* 535 * return option values if requested 536 */ 537 if (options_ret != NULL) { 538 options_ret->major_status = gssstat; 539 options_ret->minor_status = minor_stat; 540 options_ret->rpcsec_version = ap->version; 541 options_ret->ret_flags = ret_flags; 542 options_ret->time_ret = time_rec; 543 options_ret->gss_context = ap->context; 544 /* 545 * Caller's responsibility to free this. 546 */ 547 NOT_NULL(ap->mech_type); 548 __rpc_gss_dup_oid(ap->mech_type, 549 (gss_OID *)&options_ret->actual_mechanism); 550 } 551 552 *retauth = auth; 553 return (0); 554 } 555 556 /* 557 * Private interface to create a context. This is the interface 558 * that's invoked when the context has to be refreshed. 559 */ 560 static int 561 rpc_gss_seccreate_pvt(gssstat, minor_stat, auth, ap, desired_mech_type, 562 actual_mech_type, ret_flags, time_rec, cr, isrefresh) 563 OM_uint32 *gssstat; 564 OM_uint32 *minor_stat; 565 AUTH *auth; 566 rpc_gss_data *ap; 567 gss_OID desired_mech_type; 568 gss_OID *actual_mech_type; 569 int *ret_flags; 570 OM_uint32 *time_rec; 571 cred_t *cr; 572 int isrefresh; 573 { 574 CLIENT *clnt = ap->clnt; 575 AUTH *save_auth; 576 enum clnt_stat callstat; 577 rpc_gss_init_arg call_arg; 578 rpc_gss_init_res call_res; 579 gss_buffer_desc *input_token_p, input_token, process_token; 580 int free_results = 0; 581 k_sigset_t smask; 582 int error = 0; 583 584 /* 585 * (re)initialize AUTH handle and private data. 586 */ 587 bzero((char *)auth, sizeof (*auth)); 588 auth->ah_ops = &rpc_gss_ops; 589 auth->ah_private = (caddr_t)ap; 590 auth->ah_cred.oa_flavor = RPCSEC_GSS; 591 592 ap->established = FALSE; 593 ap->ctx_handle.length = 0; 594 ap->ctx_handle.value = NULL; 595 ap->context = NULL; 596 ap->seq_num = 0; 597 ap->gss_proc = RPCSEC_GSS_INIT; 598 599 /* 600 * should not change clnt->cl_auth at this time, so save 601 * old handle 602 */ 603 save_auth = clnt->cl_auth; 604 clnt->cl_auth = auth; 605 606 /* 607 * set state for starting context setup 608 */ 609 bzero((char *)&call_arg, sizeof (call_arg)); 610 input_token_p = GSS_C_NO_BUFFER; 611 612 next_token: 613 *gssstat = kgss_init_sec_context(minor_stat, 614 ap->my_cred, 615 &ap->context, 616 ap->target_name, 617 desired_mech_type, 618 ap->req_flags, 619 ap->time_req, 620 NULL, 621 input_token_p, 622 actual_mech_type, 623 &call_arg, 624 ret_flags, 625 time_rec, 626 crgetuid(cr)); 627 628 if (input_token_p != GSS_C_NO_BUFFER) { 629 OM_uint32 minor_stat2; 630 631 (void) gss_release_buffer(&minor_stat2, input_token_p); 632 input_token_p = GSS_C_NO_BUFFER; 633 } 634 635 if (*gssstat != GSS_S_COMPLETE && *gssstat != GSS_S_CONTINUE_NEEDED) { 636 rpc_gss_display_status(*gssstat, *minor_stat, 637 desired_mech_type, crgetuid(cr), 638 "rpcsec_gss_secreate_pvt:gss_init_sec_context"); 639 error = EACCES; 640 goto cleanup; 641 } 642 643 /* 644 * if we got a token, pass it on 645 */ 646 if (call_arg.length != 0) { 647 struct timeval timeout = {30, 0}; 648 int rpcsec_retry = isrefresh ? 649 RPCSEC_GSS_REFRESH_ATTEMPTS : 1; 650 uint32_t oldxid; 651 uint32_t zeroxid = 0; 652 653 bzero((char *)&call_res, sizeof (call_res)); 654 655 (void) CLNT_CONTROL(clnt, CLGET_XID, (char *)&oldxid); 656 (void) CLNT_CONTROL(clnt, CLSET_XID, (char *)&zeroxid); 657 658 659 while (rpcsec_retry > 0) { 660 struct rpc_err rpcerr; 661 662 sigintr(&smask, INTERRUPT_OK); 663 664 callstat = clnt_call(clnt, NULLPROC, 665 __xdr_rpc_gss_init_arg, (caddr_t)&call_arg, 666 __xdr_rpc_gss_init_res, (caddr_t)&call_res, 667 timeout); 668 669 sigunintr(&smask); 670 671 if (callstat == RPC_SUCCESS) { 672 error = 0; 673 if (isrefresh && 674 call_res.gss_major == GSS_S_FAILURE) { 675 676 clock_t one_sec = drv_usectohz(1000000); 677 678 rpcsec_retry--; 679 680 /* 681 * Pause a little and try again. 682 */ 683 684 if (clnt->cl_nosignal == TRUE) { 685 delay(one_sec); 686 } else { 687 if (delay_sig(one_sec)) { 688 error = EINTR; 689 break; 690 } 691 } 692 continue; 693 } 694 break; 695 } 696 697 if (callstat == RPC_TIMEDOUT) { 698 error = ETIMEDOUT; 699 break; 700 } 701 702 if (callstat == RPC_XPRTFAILED) { 703 error = ECONNRESET; 704 break; 705 } 706 707 if (callstat == RPC_INTR) { 708 error = EINTR; 709 break; 710 } 711 712 if (callstat == RPC_INPROGRESS) { 713 continue; 714 } 715 716 clnt_geterr(clnt, &rpcerr); 717 error = rpcerr.re_errno; 718 break; 719 } 720 721 (void) CLNT_CONTROL(clnt, CLSET_XID, (char *)&oldxid); 722 723 (void) gss_release_buffer(minor_stat, &call_arg); 724 725 if (callstat != RPC_SUCCESS) { 726 RPCGSS_LOG(1, 727 "rpc_gss_seccreate_pvt: clnt_call failed %d\n", 728 callstat); 729 goto cleanup; 730 } 731 732 /* 733 * we have results - note that these need to be freed 734 */ 735 free_results = 1; 736 737 if ((call_res.gss_major != GSS_S_COMPLETE) && 738 (call_res.gss_major != GSS_S_CONTINUE_NEEDED)) { 739 RPCGSS_LOG1(1, "rpc_gss_seccreate_pvt: " 740 "call_res gss_major %x, gss_minor %x\n", 741 call_res.gss_major, call_res.gss_minor); 742 error = EACCES; 743 goto cleanup; 744 } 745 746 ap->gss_proc = RPCSEC_GSS_CONTINUE_INIT; 747 748 /* 749 * check for ctx_handle 750 */ 751 if (ap->ctx_handle.length == 0) { 752 if (call_res.ctx_handle.length == 0) { 753 RPCGSS_LOG0(1, "rpc_gss_seccreate_pvt: zero " 754 "length handle in response\n"); 755 error = EACCES; 756 goto cleanup; 757 } 758 GSS_DUP_BUFFER(ap->ctx_handle, 759 call_res.ctx_handle); 760 } else if (!GSS_BUFFERS_EQUAL(ap->ctx_handle, 761 call_res.ctx_handle)) { 762 RPCGSS_LOG0(1, 763 "rpc_gss_seccreate_pvt: ctx_handle not the same\n"); 764 error = EACCES; 765 goto cleanup; 766 } 767 768 /* 769 * check for token 770 */ 771 if (call_res.token.length != 0) { 772 if (*gssstat == GSS_S_COMPLETE) { 773 RPCGSS_LOG0(1, "rpc_gss_seccreate_pvt: non " 774 "zero length token in response, but " 775 "gsstat == GSS_S_COMPLETE\n"); 776 error = EACCES; 777 goto cleanup; 778 } 779 GSS_DUP_BUFFER(input_token, call_res.token); 780 input_token_p = &input_token; 781 782 } else if (*gssstat != GSS_S_COMPLETE) { 783 RPCGSS_LOG0(1, "rpc_gss_seccreate_pvt:zero length " 784 "token in response, but " 785 "gsstat != GSS_S_COMPLETE\n"); 786 error = EACCES; 787 goto cleanup; 788 } 789 790 /* save the sequence window value; validate later */ 791 ap->seq_window = call_res.seq_window; 792 xdr_free(__xdr_rpc_gss_init_res, (caddr_t)&call_res); 793 free_results = 0; 794 } 795 796 /* 797 * results were okay.. continue if necessary 798 */ 799 if (*gssstat == GSS_S_CONTINUE_NEEDED) { 800 goto next_token; 801 } 802 803 /* 804 * Context is established. Now use kgss_export_sec_context and 805 * kgss_import_sec_context to transfer the context from the user 806 * land to kernel if the mechanism specific kernel module is 807 * available. 808 */ 809 *gssstat = kgss_export_sec_context(minor_stat, ap->context, 810 &process_token); 811 if (*gssstat == GSS_S_NAME_NOT_MN) { 812 RPCGSS_LOG(2, "rpc_gss_seccreate_pvt: export_sec_context " 813 "Kernel Module unavailable gssstat = 0x%x\n", 814 *gssstat); 815 goto done; 816 } else if (*gssstat != GSS_S_COMPLETE) { 817 (void) rpc_gss_display_status(*gssstat, *minor_stat, 818 isrefresh ? GSS_C_NULL_OID : *actual_mech_type, 819 crgetuid(cr), 820 "rpcsec_gss_secreate_pvt:gss_export_sec_context"); 821 (void) kgss_delete_sec_context(minor_stat, 822 &ap->context, NULL); 823 error = EACCES; 824 goto cleanup; 825 } else if (process_token.length == 0) { 826 RPCGSS_LOG0(1, "rpc_gss_seccreate_pvt:zero length " 827 "token in response for export_sec_context, but " 828 "gsstat == GSS_S_COMPLETE\n"); 829 (void) kgss_delete_sec_context(minor_stat, 830 &ap->context, NULL); 831 error = EACCES; 832 goto cleanup; 833 } else 834 *gssstat = kgss_import_sec_context(minor_stat, &process_token, 835 ap->context); 836 837 if (*gssstat == GSS_S_COMPLETE) { 838 (void) gss_release_buffer(minor_stat, &process_token); 839 } else { 840 rpc_gss_display_status(*gssstat, *minor_stat, 841 desired_mech_type, crgetuid(cr), 842 "rpcsec_gss_secreate_pvt:gss_import_sec_context"); 843 (void) kgss_delete_sec_context(minor_stat, 844 &ap->context, NULL); 845 (void) gss_release_buffer(minor_stat, &process_token); 846 error = EACCES; 847 goto cleanup; 848 } 849 850 done: 851 /* 852 * Validate the sequence window - RFC 2203 section 5.2.3.1 853 */ 854 if (!validate_seqwin(ap)) { 855 error = EACCES; 856 goto cleanup; 857 } 858 859 /* 860 * Done! Security context creation is successful. 861 * Ready for exchanging data. 862 */ 863 ap->established = TRUE; 864 ap->seq_num = 1; 865 ap->gss_proc = RPCSEC_GSS_DATA; 866 ap->invalid = FALSE; 867 868 clnt->cl_auth = save_auth; /* restore cl_auth */ 869 870 return (0); 871 872 cleanup: 873 if (free_results) 874 xdr_free(__xdr_rpc_gss_init_res, (caddr_t)&call_res); 875 clnt->cl_auth = save_auth; /* restore cl_auth */ 876 877 /* 878 * If need to retry for AUTH_REFRESH, do not cleanup the 879 * auth private data. 880 */ 881 if (isrefresh && (error == ETIMEDOUT || error == ECONNRESET)) { 882 return (error); 883 } 884 885 if (ap->context != NULL) { 886 rpc_gss_free_pvt(auth); 887 } 888 889 return (error? error : EACCES); 890 } 891 892 /* 893 * Marshall credentials. 894 */ 895 static bool_t 896 marshall_creds(ap, xdrs, cred_buf_len) 897 rpc_gss_data *ap; 898 XDR *xdrs; 899 uint_t cred_buf_len; 900 { 901 rpc_gss_creds ag_creds; 902 char *cred_buf; 903 struct opaque_auth creds; 904 XDR cred_xdrs; 905 906 ag_creds.version = ap->version; 907 ag_creds.gss_proc = ap->gss_proc; 908 ag_creds.seq_num = ap->seq_num; 909 ag_creds.service = ap->service; 910 911 /* 912 * If context has not been set up yet, use NULL handle. 913 */ 914 if (ap->ctx_handle.length > 0) 915 ag_creds.ctx_handle = ap->ctx_handle; 916 else { 917 ag_creds.ctx_handle.length = 0; 918 ag_creds.ctx_handle.value = NULL; 919 } 920 921 cred_buf = kmem_alloc(cred_buf_len, KM_SLEEP); 922 xdrmem_create(&cred_xdrs, (caddr_t)cred_buf, cred_buf_len, 923 XDR_ENCODE); 924 if (!__xdr_rpc_gss_creds(&cred_xdrs, &ag_creds)) { 925 kmem_free(cred_buf, MAX_AUTH_BYTES); 926 XDR_DESTROY(&cred_xdrs); 927 return (FALSE); 928 } 929 930 creds.oa_flavor = RPCSEC_GSS; 931 creds.oa_base = cred_buf; 932 creds.oa_length = xdr_getpos(&cred_xdrs); 933 XDR_DESTROY(&cred_xdrs); 934 935 if (!xdr_opaque_auth(xdrs, &creds)) { 936 kmem_free(cred_buf, cred_buf_len); 937 return (FALSE); 938 } 939 940 kmem_free(cred_buf, cred_buf_len); 941 return (TRUE); 942 } 943 944 /* 945 * Marshall verifier. The verifier is the checksum of the RPC header 946 * up to and including the credential field. The XDR handle that's 947 * passed in has the header up to and including the credential field 948 * encoded. A pointer to the transmit buffer is also passed in. 949 */ 950 static bool_t 951 marshall_verf(ap, xdrs, buf) 952 rpc_gss_data *ap; 953 XDR *xdrs; /* send XDR */ 954 char *buf; /* pointer of send buffer */ 955 { 956 struct opaque_auth verf; 957 OM_uint32 major, minor; 958 gss_buffer_desc in_buf, out_buf; 959 bool_t ret = FALSE; 960 961 /* 962 * If context is not established yet, use NULL verifier. 963 */ 964 if (!ap->established) { 965 verf.oa_flavor = AUTH_NONE; 966 verf.oa_base = NULL; 967 verf.oa_length = 0; 968 return (xdr_opaque_auth(xdrs, &verf)); 969 } 970 971 verf.oa_flavor = RPCSEC_GSS; 972 in_buf.length = xdr_getpos(xdrs); 973 in_buf.value = buf; 974 if ((major = kgss_sign(&minor, ap->context, ap->qop, &in_buf, 975 &out_buf)) != GSS_S_COMPLETE) { 976 if (major == GSS_S_CONTEXT_EXPIRED) { 977 ap->invalid = TRUE; 978 } 979 RPCGSS_LOG1(1, 980 "marshall_verf: kgss_sign failed GSS Major %x Minor %x\n", 981 major, minor); 982 return (FALSE); 983 } 984 verf.oa_base = out_buf.value; 985 verf.oa_length = out_buf.length; 986 ret = xdr_opaque_auth(xdrs, &verf); 987 (void) gss_release_buffer(&minor, &out_buf); 988 989 return (ret); 990 } 991 992 /* 993 * Validate sequence window upon a successful RPCSEC_GSS INIT session. 994 * The sequence window sent back by the server should be verifiable by 995 * the verifier which is a checksum of the sequence window. 996 */ 997 static bool_t 998 validate_seqwin(rpc_gss_data *ap) 999 { 1000 uint_t seq_win_net; 1001 OM_uint32 major = 0, minor = 0; 1002 gss_buffer_desc msg_buf, tok_buf; 1003 int qop_state = 0; 1004 1005 ASSERT(ap->verifier); 1006 ASSERT(ap->context); 1007 seq_win_net = (uint_t)htonl(ap->seq_window); 1008 msg_buf.length = sizeof (seq_win_net); 1009 msg_buf.value = (char *)&seq_win_net; 1010 tok_buf.length = ap->verifier->oa_length; 1011 tok_buf.value = ap->verifier->oa_base; 1012 major = kgss_verify(&minor, ap->context, &msg_buf, &tok_buf, 1013 &qop_state); 1014 1015 if (major != GSS_S_COMPLETE) { 1016 RPCGSS_LOG1(1, 1017 "validate_seqwin: kgss_verify failed GSS Major " 1018 "%x Minor %x\n", major, minor); 1019 RPCGSS_LOG1(1, "seq_window %d, verf len %d ", ap->seq_window, 1020 ap->verifier->oa_length); 1021 return (FALSE); 1022 } 1023 return (TRUE); 1024 } 1025 1026 /* 1027 * Validate RPC response verifier from server. The response verifier 1028 * is the checksum of the request sequence number. 1029 */ 1030 static bool_t 1031 rpc_gss_validate(auth, verf) 1032 AUTH *auth; 1033 struct opaque_auth *verf; 1034 { 1035 rpc_gss_data *ap = AUTH_PRIVATE(auth); 1036 uint_t seq_num_net; 1037 OM_uint32 major, minor; 1038 gss_buffer_desc msg_buf, tok_buf; 1039 int qop_state; 1040 1041 /* 1042 * If context is not established yet, save the verifier for 1043 * validating the sequence window later at the end of context 1044 * creation session. 1045 */ 1046 if (!ap->established) { 1047 if (ap->verifier == NULL) { 1048 ap->verifier = kmem_zalloc(sizeof (struct opaque_auth), 1049 KM_SLEEP); 1050 if (verf->oa_length > 0) 1051 ap->verifier->oa_base = kmem_zalloc(verf->oa_length, 1052 KM_SLEEP); 1053 } else { 1054 if (ap->verifier->oa_length > 0) 1055 kmem_free(ap->verifier->oa_base, ap->verifier->oa_length); 1056 if (verf->oa_length > 0) 1057 ap->verifier->oa_base = kmem_zalloc(verf->oa_length, 1058 KM_SLEEP); 1059 } 1060 ap->verifier->oa_length = verf->oa_length; 1061 bcopy(verf->oa_base, ap->verifier->oa_base, verf->oa_length); 1062 return (TRUE); 1063 } 1064 1065 seq_num_net = (uint_t)htonl(ap->seq_num); 1066 msg_buf.length = sizeof (seq_num_net); 1067 msg_buf.value = (char *)&seq_num_net; 1068 tok_buf.length = verf->oa_length; 1069 tok_buf.value = verf->oa_base; 1070 major = kgss_verify(&minor, ap->context, &msg_buf, &tok_buf, 1071 &qop_state); 1072 if (major != GSS_S_COMPLETE) { 1073 RPCGSS_LOG1(1, 1074 "rpc_gss_validate: kgss_verify failed GSS Major %x Minor %x\n", 1075 major, minor); 1076 return (FALSE); 1077 } 1078 return (TRUE); 1079 } 1080 1081 /* 1082 * Refresh client context. This is necessary sometimes because the 1083 * server will ocassionally destroy contexts based on LRU method, or 1084 * because of expired credentials. 1085 */ 1086 static bool_t 1087 rpc_gss_refresh(auth, msg, cr) 1088 AUTH *auth; 1089 struct rpc_msg *msg; 1090 cred_t *cr; 1091 { 1092 rpc_gss_data *ap = AUTH_PRIVATE(auth); 1093 gss_ctx_id_t ctx_sav = NULL; 1094 gss_buffer_desc ctx_hdle_sav = {0, NULL}; 1095 uint_t sn_sav, proc_sav; 1096 bool_t est_sav; 1097 OM_uint32 gssstat, minor_stat; 1098 int error; 1099 1100 /* 1101 * The context needs to be recreated only when the error status 1102 * returned from the server is one of the following: 1103 * RPCSEC_GSS_NOCRED and RPCSEC_GSS_FAILED 1104 * The existing context should not be destroyed unless the above 1105 * error status codes are received or if the context has not 1106 * been set up. 1107 */ 1108 1109 if (msg->rjcted_rply.rj_why == RPCSEC_GSS_NOCRED || 1110 msg->rjcted_rply.rj_why == RPCSEC_GSS_FAILED || 1111 !ap->established) { 1112 /* 1113 * Destroy the context if necessary. Use the same memory 1114 * for the new context since we've already passed a pointer 1115 * to it to the user. 1116 */ 1117 if (ap->context != NULL) { 1118 ctx_sav = ap->context; 1119 ap->context = NULL; 1120 } 1121 if (ap->ctx_handle.length != 0) { 1122 ctx_hdle_sav.length = ap->ctx_handle.length; 1123 ctx_hdle_sav.value = ap->ctx_handle.value; 1124 ap->ctx_handle.length = 0; 1125 ap->ctx_handle.value = NULL; 1126 } 1127 1128 /* 1129 * If the context was not already established, don't try to 1130 * recreate it. 1131 */ 1132 if (!ap->established) { 1133 ap->invalid = TRUE; 1134 RPCGSS_LOG0(1, 1135 "rpc_gss_refresh: context was not established\n"); 1136 error = EINVAL; 1137 goto out; 1138 } 1139 1140 est_sav = ap->established; 1141 sn_sav = ap->seq_num; 1142 proc_sav = ap->gss_proc; 1143 1144 /* 1145 * Recreate context. 1146 */ 1147 error = rpc_gss_seccreate_pvt(&gssstat, &minor_stat, auth, 1148 ap, ap->mech_type, (gss_OID *)NULL, (int *)NULL, 1149 (OM_uint32 *)NULL, cr, 1); 1150 1151 switch (error) { 1152 case 0: 1153 RPCGSS_LOG(1, 1154 "rpc_gss_refresh: auth %p refreshed\n", (void *)auth); 1155 goto out; 1156 1157 case ETIMEDOUT: 1158 case ECONNRESET: 1159 RPCGSS_LOG0(1, "rpc_gss_refresh: try again\n"); 1160 1161 if (ap->context != NULL) { 1162 (void) kgss_delete_sec_context(&minor_stat, 1163 &ap->context, NULL); 1164 } 1165 if (ap->ctx_handle.length != 0) { 1166 (void) gss_release_buffer(&minor_stat, 1167 &ap->ctx_handle); 1168 } 1169 1170 /* 1171 * Restore the original value for the caller to 1172 * try again later. 1173 */ 1174 ap->context = ctx_sav; 1175 ap->ctx_handle.length = ctx_hdle_sav.length; 1176 ap->ctx_handle.value = ctx_hdle_sav.value; 1177 ap->established = est_sav; 1178 ap->seq_num = sn_sav; 1179 ap->gss_proc = proc_sav; 1180 1181 return (FALSE); 1182 1183 default: 1184 ap->invalid = TRUE; 1185 RPCGSS_LOG(1, "rpc_gss_refresh: can't refresh this " 1186 "auth, error=%d\n", error); 1187 goto out; 1188 } 1189 } 1190 RPCGSS_LOG0(1, "rpc_gss_refresh: don't refresh"); 1191 return (FALSE); 1192 1193 out: 1194 if (ctx_sav != NULL) { 1195 (void) kgss_delete_sec_context(&minor_stat, 1196 &ctx_sav, NULL); 1197 } 1198 if (ctx_hdle_sav.length != 0) { 1199 (void) gss_release_buffer(&minor_stat, &ctx_hdle_sav); 1200 } 1201 1202 return (error == 0); 1203 } 1204 1205 /* 1206 * Destroy a context. 1207 */ 1208 static void 1209 rpc_gss_destroy(auth) 1210 AUTH *auth; 1211 { 1212 rpc_gss_data *ap = AUTH_PRIVATE(auth); 1213 1214 /* 1215 * XXX Currently, we do not ping the server (rpc_gss_destroy_pvt) 1216 * to destroy the context in the server cache. 1217 * We assume there is a good LRU/aging mechanism for the 1218 * context cache on the server side. 1219 */ 1220 rpc_gss_free_pvt(auth); 1221 kmem_free((char *)ap, sizeof (*ap)); 1222 kmem_free(auth, sizeof (*auth)); 1223 } 1224 1225 /* 1226 * Private interface to free memory allocated in the rpcsec_gss private 1227 * data structure (rpc_gss_data). 1228 */ 1229 static void 1230 rpc_gss_free_pvt(auth) 1231 AUTH *auth; 1232 { 1233 OM_uint32 minor_stat; 1234 rpc_gss_data *ap = AUTH_PRIVATE(auth); 1235 1236 if (ap->ctx_handle.length != 0) { 1237 (void) gss_release_buffer(&minor_stat, &ap->ctx_handle); 1238 ap->ctx_handle.length = 0; 1239 ap->ctx_handle.value = NULL; 1240 } 1241 1242 /* 1243 * Destroy local GSS context. 1244 */ 1245 if (ap->context != NULL) { 1246 (void) kgss_delete_sec_context(&minor_stat, &ap->context, NULL); 1247 ap->context = NULL; 1248 } 1249 1250 /* 1251 * Looks like we need to release default credentials if we use it. 1252 * Non-default creds need to be released by user. 1253 */ 1254 if (ap->my_cred == GSS_C_NO_CREDENTIAL) 1255 (void) kgss_release_cred(&minor_stat, &ap->my_cred, 1256 crgetuid(CRED())); 1257 1258 /* 1259 * Release any internal name structures. 1260 */ 1261 if (ap->target_name != NULL) { 1262 (void) gss_release_name(&minor_stat, &ap->target_name); 1263 ap->target_name = NULL; 1264 } 1265 1266 /* 1267 * Free mech_type oid structure. 1268 */ 1269 if (ap->mech_type != NULL) { 1270 kgss_free_oid(ap->mech_type); 1271 ap->mech_type = NULL; 1272 } 1273 1274 /* 1275 * Free the verifier saved for sequence window checking. 1276 */ 1277 if (ap->verifier != NULL) { 1278 if (ap->verifier->oa_length > 0) { 1279 kmem_free(ap->verifier->oa_base, ap->verifier->oa_length); 1280 } 1281 kmem_free(ap->verifier, sizeof (struct opaque_auth)); 1282 ap->verifier = NULL; 1283 } 1284 } 1285 1286 #if 0 1287 /* 1288 * XXX this function is not used right now. 1289 * There is a client handle issue needs to be resolved. 1290 * 1291 * This is a private interface which will destroy a context 1292 * without freeing up the memory used by it. We need to do this when 1293 * a refresh fails, for example, so the user will still have a handle. 1294 */ 1295 static void 1296 rpc_gss_destroy_pvt(auth) 1297 AUTH *auth; 1298 { 1299 struct timeval timeout; 1300 rpc_gss_data *ap = AUTH_PRIVATE(auth); 1301 1302 /* 1303 * If we have a server context id, inform server that we are 1304 * destroying the context. 1305 */ 1306 if (ap->ctx_handle.length != 0) { 1307 uint32_t oldxid; 1308 uint32_t zeroxid = 0; 1309 1310 ap->gss_proc = RPCSEC_GSS_DESTROY; 1311 timeout.tv_sec = 10; 1312 timeout.tv_usec = 0; 1313 (void) CLNT_CONTROL(ap->clnt, CLGET_XID, (char *)&oldxid); 1314 (void) CLNT_CONTROL(ap->clnt, CLSET_XID, (char *)&zeroxid); 1315 (void) clnt_call(ap->clnt, NULLPROC, xdr_void, NULL, 1316 xdr_void, NULL, timeout); 1317 (void) CLNT_CONTROL(ap->clnt, CLSET_XID, (char *)&oldxid); 1318 } 1319 1320 rpc_gss_free_pvt(auth); 1321 } 1322 #endif 1323 1324 /* 1325 * Wrap client side data. The encoded header is passed in through 1326 * buf and buflen. The header is up to but not including the 1327 * credential field. 1328 */ 1329 bool_t 1330 rpc_gss_wrap(auth, buf, buflen, out_xdrs, xdr_func, xdr_ptr) 1331 AUTH *auth; 1332 char *buf; /* encoded header */ 1333 /* has been changed to u_int in the user land */ 1334 uint_t buflen; /* encoded header length */ 1335 XDR *out_xdrs; 1336 xdrproc_t xdr_func; 1337 caddr_t xdr_ptr; 1338 { 1339 rpc_gss_data *ap = AUTH_PRIVATE(auth); 1340 XDR xdrs; 1341 char *tmp_buf; 1342 uint_t xdr_buf_len, cred_buf_len; 1343 1344 /* 1345 * Here is how MAX_SIGNED_LEN is estimated. 1346 * Signing a 48 bytes buffer using des_cbc_md5 would end up with 1347 * a buffer length 33 (padded data + 16 bytes of seq_num/checksum). 1348 * Current known max seq_num/checksum size is 24 bytes. 1349 * 88 is derived from RNDUP(33+(24-16)) * 2. 1350 */ 1351 #define MAX_SIGNED_LEN 88 1352 1353 /* 1354 * Reject an invalid context. 1355 */ 1356 if (ap->invalid) { 1357 RPCGSS_LOG0(1, "rpc_gss_wrap: reject an invalid context\n"); 1358 return (FALSE); 1359 } 1360 1361 /* 1362 * If context is established, bump up sequence number. 1363 */ 1364 if (ap->established) 1365 ap->seq_num++; 1366 1367 /* 1368 * Create the header in a temporary XDR context and buffer 1369 * before putting it out. 1370 */ 1371 cred_buf_len = RNDUP(sizeof (ap->version) + sizeof (ap->gss_proc) + 1372 sizeof (ap->seq_num) + sizeof (ap->service) + 1373 sizeof (ap->ctx_handle) + ap->ctx_handle.length); 1374 1375 xdr_buf_len = buflen + cred_buf_len + sizeof (struct opaque_auth) + 1376 MAX_SIGNED_LEN; 1377 tmp_buf = kmem_alloc(xdr_buf_len, KM_SLEEP); 1378 xdrmem_create(&xdrs, tmp_buf, xdr_buf_len, XDR_ENCODE); 1379 if (!XDR_PUTBYTES(&xdrs, buf, buflen)) { 1380 kmem_free(tmp_buf, xdr_buf_len); 1381 RPCGSS_LOG0(1, "rpc_gss_wrap: xdr putbytes failed\n"); 1382 return (FALSE); 1383 } 1384 1385 /* 1386 * create cred field 1387 */ 1388 if (!marshall_creds(ap, &xdrs, cred_buf_len)) { 1389 kmem_free(tmp_buf, xdr_buf_len); 1390 RPCGSS_LOG0(1, "rpc_gss_wrap: marshall_creds failed\n"); 1391 return (FALSE); 1392 } 1393 1394 /* 1395 * create verifier 1396 */ 1397 if (!marshall_verf(ap, &xdrs, tmp_buf)) { 1398 kmem_free(tmp_buf, xdr_buf_len); 1399 RPCGSS_LOG0(1, "rpc_gss_wrap: marshall_verf failed\n"); 1400 return (FALSE); 1401 } 1402 1403 /* 1404 * write out header and destroy temp structures 1405 */ 1406 if (!XDR_PUTBYTES(out_xdrs, tmp_buf, XDR_GETPOS(&xdrs))) { 1407 kmem_free(tmp_buf, xdr_buf_len); 1408 RPCGSS_LOG0(1, "rpc_gss_wrap: write out header failed\n"); 1409 return (FALSE); 1410 } 1411 XDR_DESTROY(&xdrs); 1412 kmem_free(tmp_buf, xdr_buf_len); 1413 1414 /* 1415 * If context is not established, or if neither integrity 1416 * nor privacy is used, just XDR encode data. 1417 */ 1418 if (!ap->established || ap->service == rpc_gss_svc_none) { 1419 return ((*xdr_func)(out_xdrs, xdr_ptr)); 1420 } 1421 1422 return (__rpc_gss_wrap_data(ap->service, ap->qop, ap->context, 1423 ap->seq_num, out_xdrs, xdr_func, xdr_ptr)); 1424 } 1425 1426 /* 1427 * Unwrap received data. 1428 */ 1429 bool_t 1430 rpc_gss_unwrap(auth, in_xdrs, xdr_func, xdr_ptr) 1431 AUTH *auth; 1432 XDR *in_xdrs; 1433 bool_t (*xdr_func)(); 1434 caddr_t xdr_ptr; 1435 { 1436 rpc_gss_data *ap = AUTH_PRIVATE(auth); 1437 1438 /* 1439 * If context is not established, of if neither integrity 1440 * nor privacy is used, just XDR encode data. 1441 */ 1442 if (!ap->established || ap->service == rpc_gss_svc_none) 1443 return ((*xdr_func)(in_xdrs, xdr_ptr)); 1444 1445 return (__rpc_gss_unwrap_data(ap->service, 1446 ap->context, 1447 ap->seq_num, 1448 ap->qop, 1449 in_xdrs, xdr_func, xdr_ptr)); 1450 } 1451 1452 /* 1453 * Revoke an GSSAPI based security credentials 1454 * from the cache table. 1455 */ 1456 int 1457 rpc_gss_revauth(uid_t uid, rpc_gss_OID mech) 1458 { 1459 struct ga_cache_entry *next, *prev, *cur; 1460 rpc_gss_data *ap; 1461 zoneid_t zoneid = getzoneid(); 1462 int i; 1463 1464 /* 1465 * Check the cache table against the uid and the 1466 * mechanism type. 1467 */ 1468 rw_enter(&ga_cache_table_lock, RW_WRITER); 1469 for (i = 0; i < GSSAUTH_TABLESIZE; i++) { 1470 prev = NULL; 1471 for (cur = ga_cache_table[i]; cur; cur = next) { 1472 NOT_DEAD(cur); 1473 next = cur->next; 1474 NOT_DEAD(next); 1475 ap = AUTH_PRIVATE(cur->auth); 1476 if (__rpc_gss_oids_equal(ap->mech_type, 1477 (gss_OID) mech) && (cur->uid == uid) && 1478 (cur->zoneid == zoneid)) { 1479 if (cur->in_use) { 1480 RPCGSS_LOG(2, "rpc_gss_revauth:invalid " 1481 "auth %p\n", (void *)cur->auth); 1482 ap->invalid = TRUE; 1483 } else { 1484 RPCGSS_LOG(2, "rpc_gss_revauth:destroy " 1485 "auth %p\n", (void *)cur->auth); 1486 rpc_gss_destroy(cur->auth); 1487 kmem_cache_free(ga_cache_handle, 1488 (void *)cur); 1489 } 1490 if (prev == NULL) { 1491 ga_cache_table[i] = next; 1492 } else { 1493 prev->next = next; 1494 NOT_DEAD(prev->next); 1495 } 1496 } else { 1497 prev = cur; 1498 } 1499 } 1500 } 1501 rw_exit(&ga_cache_table_lock); 1502 1503 return (0); 1504 } 1505 1506 1507 /* 1508 * Delete all the entries indexed by the cache_key. 1509 * 1510 * For example, the cache_key used for NFS is the address of the 1511 * security entry for each mount point. When the file system is unmounted, 1512 * all the cache entries indexed by this key should be deleted. 1513 */ 1514 void 1515 rpc_gss_secpurge(void *cache_key) 1516 { 1517 struct ga_cache_entry *next, *prev, *cur; 1518 int i; 1519 1520 /* 1521 * Check the cache table against the cache_key. 1522 */ 1523 rw_enter(&ga_cache_table_lock, RW_WRITER); 1524 for (i = 0; i < GSSAUTH_TABLESIZE; i++) { 1525 prev = NULL; 1526 for (cur = ga_cache_table[i]; cur; cur = next) { 1527 NOT_DEAD(cur); 1528 next = cur->next; 1529 NOT_DEAD(next); 1530 if (cache_key == cur->cache_key) { 1531 RPCGSS_LOG(2, "rpc_gss_secpurge: destroy auth " 1532 "%p\n", (void *)cur->auth); 1533 if (cur->in_use == FALSE) 1534 rpc_gss_destroy(cur->auth); 1535 kmem_cache_free(ga_cache_handle, (void *)cur); 1536 if (prev == NULL) { 1537 ga_cache_table[i] = next; 1538 } else { 1539 NOT_DEAD(prev->next); 1540 prev->next = next; 1541 } 1542 } else { 1543 prev = cur; 1544 } 1545 } 1546 } 1547 rw_exit(&ga_cache_table_lock); 1548 } 1549 1550 /* 1551 * Function: rpc_gss_nextverf. Not used. 1552 */ 1553 static void 1554 rpc_gss_nextverf() 1555 { 1556 } 1557 1558 /* 1559 * Function: rpc_gss_marshall - no op routine. 1560 * rpc_gss_wrap() is doing the marshalling. 1561 */ 1562 /*ARGSUSED*/ 1563 static bool_t 1564 rpc_gss_marshall(auth, xdrs) 1565 AUTH *auth; 1566 XDR *xdrs; 1567 { 1568 return (TRUE); 1569 } 1570 1571 /* 1572 * Set service defaults. 1573 * Not supported yet. 1574 */ 1575 /* ARGSUSED */ 1576 bool_t 1577 rpc_gss_set_defaults(auth, service, qop) 1578 AUTH *auth; 1579 rpc_gss_service_t service; 1580 uint_t qop; 1581 { 1582 return (FALSE); 1583 } 1584 1585 /* ARGSUSED */ 1586 int 1587 rpc_gss_max_data_length(AUTH *rpcgss_handle, int max_tp_unit_len) 1588 { 1589 return (0); 1590 } 1591 1592 rpc_gss_service_t 1593 rpc_gss_get_service_type(AUTH *auth) 1594 { 1595 rpc_gss_data *ap = AUTH_PRIVATE(auth); 1596 1597 return (ap->service); 1598 } 1599