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