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