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