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