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