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