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