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