xref: /netbsd-src/crypto/dist/ipsec-tools/src/racoon/gssapi.c (revision e5548b402ae4c44fb816de42c7bba9581ce23ef5)
1 /*	$NetBSD: gssapi.c,v 1.3 2005/11/21 14:20:29 manu Exp $	*/
2 
3 /*	$KAME: gssapi.c,v 1.19 2001/04/03 15:51:55 thorpej Exp $	*/
4 
5 /*
6  * Copyright 2000 Wasabi Systems, Inc.
7  * All rights reserved.
8  *
9  * This software was written by Frank van der Linden of Wasabi Systems
10  * for Zembu Labs, Inc. http://www.zembu.com/
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. The name of Wasabi Systems, Inc. may not be used to endorse
21  *    or promote products derived from this software without specific prior
22  *    written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
28  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  */
36 
37 #include "config.h"
38 
39 #ifdef HAVE_GSSAPI
40 
41 #include <sys/types.h>
42 #include <sys/queue.h>
43 #include <sys/socket.h>
44 #include <netdb.h>
45 #include <unistd.h>
46 
47 #include <stdlib.h>
48 #include <string.h>
49 #include <errno.h>
50 
51 #include "var.h"
52 #include "misc.h"
53 #include "vmbuf.h"
54 #include "plog.h"
55 #include "sockmisc.h"
56 #include "schedule.h"
57 #include "debug.h"
58 
59 #include "localconf.h"
60 #include "remoteconf.h"
61 #include "isakmp_var.h"
62 #include "isakmp.h"
63 #include "oakley.h"
64 #include "handler.h"
65 #include "ipsec_doi.h"
66 #include "crypto_openssl.h"
67 #include "pfkey.h"
68 #include "isakmp_ident.h"
69 #include "isakmp_inf.h"
70 #include "vendorid.h"
71 #include "gcmalloc.h"
72 
73 #include "gssapi.h"
74 
75 static void
76 gssapi_error(OM_uint32 status_code, const char *where,
77 	     const char *fmt, ...)
78 {
79 	OM_uint32 message_context, maj_stat, min_stat;
80 	gss_buffer_desc status_string;
81 	va_list ap;
82 
83 	va_start(ap, fmt);
84 	plogv(LLV_ERROR, where, NULL, fmt, ap);
85 	va_end(ap);
86 
87 	message_context = 0;
88 
89 	do {
90 		maj_stat = gss_display_status(&min_stat, status_code,
91 		    GSS_C_MECH_CODE, GSS_C_NO_OID, &message_context,
92 		    &status_string);
93 		if (GSS_ERROR(maj_stat))
94 			plog(LLV_ERROR, LOCATION, NULL,
95 			    "UNABLE TO GET GSSAPI ERROR CODE\n");
96 		else {
97 			plog(LLV_ERROR, where, NULL,
98 			    "%s\n", (char *)status_string.value);
99 			gss_release_buffer(&min_stat, &status_string);
100 		}
101 	} while (message_context != 0);
102 }
103 
104 /*
105  * vmbufs and gss_buffer_descs are really just the same on NetBSD, but
106  * this is to be portable.
107  */
108 static int
109 gssapi_vm2gssbuf(vchar_t *vmbuf, gss_buffer_t gsstoken)
110 {
111 
112 	gsstoken->value = racoon_malloc(vmbuf->l);
113 	if (gsstoken->value == NULL)
114 		return -1;
115 	memcpy(gsstoken->value, vmbuf->v, vmbuf->l);
116 	gsstoken->length = vmbuf->l;
117 
118 	return 0;
119 }
120 
121 static int
122 gssapi_gss2vmbuf(gss_buffer_t gsstoken, vchar_t **vmbuf)
123 {
124 
125 	*vmbuf = vmalloc(gsstoken->length);
126 	if (*vmbuf == NULL)
127 		return -1;
128 	memcpy((*vmbuf)->v, gsstoken->value, gsstoken->length);
129 	(*vmbuf)->l = gsstoken->length;
130 
131 	return 0;
132 }
133 
134 vchar_t *
135 gssapi_get_default_gss_id(void)
136 {
137 	char name[NI_MAXHOST];
138 	vchar_t *gssid;
139 
140 	if (gethostname(name, sizeof(name)) != 0) {
141 		plog(LLV_ERROR, LOCATION, NULL, "gethostname failed: %s\n",
142 		    strerror(errno));
143 		return (NULL);
144 	}
145 	name[sizeof(name) - 1] = '\0';
146 
147 	gssid = racoon_malloc(sizeof(*gssid));
148 	gssid->l = asprintf(&gssid->v, "%s/%s", GSSAPI_DEF_NAME, name);
149 
150 	return (gssid);
151 }
152 
153 static int
154 gssapi_get_default_name(struct ph1handle *iph1, int remote, gss_name_t *service)
155 {
156 	char name[NI_MAXHOST];
157 	struct sockaddr *sa;
158 	gss_buffer_desc name_token;
159 	OM_uint32 min_stat, maj_stat;
160 
161 	sa = remote ? iph1->remote : iph1->local;
162 
163 	if (getnameinfo(sa, sysdep_sa_len(sa), name, NI_MAXHOST, NULL, 0, 0) != 0)
164 		return -1;
165 
166 	name_token.length = asprintf((char **)&name_token.value,
167 	    "%s@%s", GSSAPI_DEF_NAME, name);
168 	maj_stat = gss_import_name(&min_stat, &name_token,
169 	    GSS_C_NT_HOSTBASED_SERVICE, service);
170 	if (GSS_ERROR(maj_stat)) {
171 		gssapi_error(min_stat, LOCATION, "import name\n");
172 		maj_stat = gss_release_buffer(&min_stat, &name_token);
173 		if (GSS_ERROR(maj_stat))
174 			gssapi_error(min_stat, LOCATION, "release name_token");
175 		return -1;
176 	}
177 	maj_stat = gss_release_buffer(&min_stat, &name_token);
178 	if (GSS_ERROR(maj_stat))
179 		gssapi_error(min_stat, LOCATION, "release name_token");
180 
181 	return 0;
182 }
183 
184 static int
185 gssapi_init(struct ph1handle *iph1)
186 {
187 	struct gssapi_ph1_state *gps;
188 	gss_buffer_desc id_token, cred_token;
189 	gss_buffer_t cred = &cred_token;
190 	gss_name_t princ, canon_princ;
191 	OM_uint32 maj_stat, min_stat;
192 
193 	gps = racoon_calloc(1, sizeof (struct gssapi_ph1_state));
194 	if (gps == NULL) {
195 		plog(LLV_ERROR, LOCATION, NULL, "racoon_calloc failed\n");
196 		return -1;
197 	}
198 	gps->gss_context = GSS_C_NO_CONTEXT;
199 	gps->gss_cred = GSS_C_NO_CREDENTIAL;
200 
201 	gssapi_set_state(iph1, gps);
202 
203 	if (iph1->rmconf->proposal->gssid != NULL) {
204 		id_token.length = iph1->rmconf->proposal->gssid->l;
205 		id_token.value = iph1->rmconf->proposal->gssid->v;
206 		maj_stat = gss_import_name(&min_stat, &id_token, GSS_C_NO_OID,
207 		    &princ);
208 		if (GSS_ERROR(maj_stat)) {
209 			gssapi_error(min_stat, LOCATION, "import name\n");
210 			gssapi_free_state(iph1);
211 			return -1;
212 		}
213 	} else
214 		gssapi_get_default_name(iph1, 0, &princ);
215 
216 	maj_stat = gss_canonicalize_name(&min_stat, princ, GSS_C_NO_OID,
217 	    &canon_princ);
218 	if (GSS_ERROR(maj_stat)) {
219 		gssapi_error(min_stat, LOCATION, "canonicalize name\n");
220 		maj_stat = gss_release_name(&min_stat, &princ);
221 		if (GSS_ERROR(maj_stat))
222 			gssapi_error(min_stat, LOCATION, "release princ\n");
223 		gssapi_free_state(iph1);
224 		return -1;
225 	}
226 	maj_stat = gss_release_name(&min_stat, &princ);
227 	if (GSS_ERROR(maj_stat))
228 		gssapi_error(min_stat, LOCATION, "release princ\n");
229 
230 	maj_stat = gss_export_name(&min_stat, canon_princ, cred);
231 	if (GSS_ERROR(maj_stat)) {
232 		gssapi_error(min_stat, LOCATION, "export name\n");
233 		maj_stat = gss_release_name(&min_stat, &canon_princ);
234 		if (GSS_ERROR(maj_stat))
235 			gssapi_error(min_stat, LOCATION,
236 			    "release canon_princ\n");
237 		gssapi_free_state(iph1);
238 		return -1;
239 	}
240 
241 #if 0
242 	/*
243 	 * XXXJRT Did this debug message ever work?  This is a GSS name
244 	 * blob at this point.
245 	 */
246 	plog(LLV_DEBUG, LOCATION, NULL, "will try to acquire '%.*s' creds\n",
247 	    cred->length, cred->value);
248 #endif
249 
250 	maj_stat = gss_release_buffer(&min_stat, cred);
251 	if (GSS_ERROR(maj_stat))
252 		gssapi_error(min_stat, LOCATION, "release cred buffer\n");
253 
254 	maj_stat = gss_acquire_cred(&min_stat, canon_princ, GSS_C_INDEFINITE,
255 	    GSS_C_NO_OID_SET, GSS_C_BOTH, &gps->gss_cred, NULL, NULL);
256 	if (GSS_ERROR(maj_stat)) {
257 		gssapi_error(min_stat, LOCATION, "acquire cred\n");
258 		maj_stat = gss_release_name(&min_stat, &canon_princ);
259 		if (GSS_ERROR(maj_stat))
260 			gssapi_error(min_stat, LOCATION,
261 			    "release canon_princ\n");
262 		gssapi_free_state(iph1);
263 		return -1;
264 	}
265 	maj_stat = gss_release_name(&min_stat, &canon_princ);
266 	if (GSS_ERROR(maj_stat))
267 		gssapi_error(min_stat, LOCATION, "release canon_princ\n");
268 
269 	return 0;
270 }
271 
272 int
273 gssapi_get_itoken(struct ph1handle *iph1, int *lenp)
274 {
275 	struct gssapi_ph1_state *gps;
276 	gss_buffer_desc empty, name_token;
277 	gss_buffer_t itoken, rtoken, dummy;
278 	OM_uint32 maj_stat, min_stat;
279 	gss_name_t partner;
280 
281 	if (gssapi_get_state(iph1) == NULL && gssapi_init(iph1) < 0)
282 		return -1;
283 
284 	gps = gssapi_get_state(iph1);
285 
286 	empty.length = 0;
287 	empty.value = NULL;
288 	dummy = &empty;
289 
290 	if (iph1->approval != NULL && iph1->approval->gssid != NULL) {
291 		plog(LLV_DEBUG, LOCATION, NULL,
292 		    "using provided service '%.*s'\n",
293 		    iph1->approval->gssid->l, iph1->approval->gssid->v);
294 		name_token.length = iph1->approval->gssid->l;
295 		name_token.value = iph1->approval->gssid->v;
296 		maj_stat = gss_import_name(&min_stat, &name_token,
297 		    GSS_C_NO_OID, &partner);
298 		if (GSS_ERROR(maj_stat)) {
299 			gssapi_error(min_stat, LOCATION, "import of %.*s\n",
300 			    name_token.length, name_token.value);
301 			return -1;
302 		}
303 	} else
304 		if (gssapi_get_default_name(iph1, 1, &partner) < 0)
305 			return -1;
306 
307 	rtoken = gps->gsscnt_p == 0 ? dummy : &gps->gss_p[gps->gsscnt_p - 1];
308 	itoken = &gps->gss[gps->gsscnt];
309 
310 	gps->gss_status = gss_init_sec_context(&min_stat, gps->gss_cred,
311 	    &gps->gss_context, partner, GSS_C_NO_OID,
312 	    GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG |
313 		GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG,
314 	    0, GSS_C_NO_CHANNEL_BINDINGS, rtoken, NULL,
315 	    itoken, NULL, NULL);
316 
317 	if (GSS_ERROR(gps->gss_status)) {
318 		gssapi_error(min_stat, LOCATION, "init_sec_context\n");
319 		maj_stat = gss_release_name(&min_stat, &partner);
320 		if (GSS_ERROR(maj_stat))
321 			gssapi_error(min_stat, LOCATION, "release name\n");
322 		return -1;
323 	}
324 	maj_stat = gss_release_name(&min_stat, &partner);
325 	if (GSS_ERROR(maj_stat))
326 		gssapi_error(min_stat, LOCATION, "release name\n");
327 
328 	plog(LLV_DEBUG, LOCATION, NULL, "gss_init_sec_context status %x\n",
329 	    gps->gss_status);
330 
331 	if (lenp)
332 		*lenp = itoken->length;
333 
334 	if (itoken->length != 0)
335 		gps->gsscnt++;
336 
337 	return 0;
338 }
339 
340 /*
341  * Call gss_accept_context, with token just read from the wire.
342  */
343 int
344 gssapi_get_rtoken(struct ph1handle *iph1, int *lenp)
345 {
346 	struct gssapi_ph1_state *gps;
347 	gss_buffer_desc name_token;
348 	gss_buffer_t itoken, rtoken;
349 	OM_uint32 min_stat, maj_stat;
350 	gss_name_t client_name;
351 
352 	if (gssapi_get_state(iph1) == NULL && gssapi_init(iph1) < 0)
353 		return -1;
354 
355 	gps = gssapi_get_state(iph1);
356 
357 	rtoken = &gps->gss_p[gps->gsscnt_p - 1];
358 	itoken = &gps->gss[gps->gsscnt];
359 
360 	gps->gss_status = gss_accept_sec_context(&min_stat, &gps->gss_context,
361 	    gps->gss_cred, rtoken, GSS_C_NO_CHANNEL_BINDINGS, &client_name,
362 	    NULL, itoken, NULL, NULL, NULL);
363 
364 	if (GSS_ERROR(gps->gss_status)) {
365 		gssapi_error(min_stat, LOCATION, "accept_sec_context\n");
366 		return -1;
367 	}
368 
369 	maj_stat = gss_display_name(&min_stat, client_name, &name_token, NULL);
370 	if (GSS_ERROR(maj_stat)) {
371 		gssapi_error(min_stat, LOCATION, "gss_display_name\n");
372 		maj_stat = gss_release_name(&min_stat, &client_name);
373 		if (GSS_ERROR(maj_stat))
374 			gssapi_error(min_stat, LOCATION,
375 			    "release client_name\n");
376 		return -1;
377 	}
378 	maj_stat = gss_release_name(&min_stat, &client_name);
379 	if (GSS_ERROR(maj_stat))
380 		gssapi_error(min_stat, LOCATION, "release client_name\n");
381 
382 	plog(LLV_DEBUG, LOCATION, NULL,
383 		"gss_accept_sec_context: other side is %s\n",
384 		(char *)name_token.value);
385 	maj_stat = gss_release_buffer(&min_stat, &name_token);
386 	if (GSS_ERROR(maj_stat))
387 		gssapi_error(min_stat, LOCATION, "release name buffer\n");
388 
389 	if (itoken->length != 0)
390 		gps->gsscnt++;
391 
392 	if (lenp)
393 		*lenp = itoken->length;
394 
395 	return 0;
396 }
397 
398 int
399 gssapi_save_received_token(struct ph1handle *iph1, vchar_t *token)
400 {
401 	struct gssapi_ph1_state *gps;
402 	gss_buffer_t gsstoken;
403 	int ret;
404 
405 	if (gssapi_get_state(iph1) == NULL && gssapi_init(iph1) < 0)
406 		return -1;
407 
408 	gps = gssapi_get_state(iph1);
409 
410 	gsstoken = &gps->gss_p[gps->gsscnt_p];
411 
412 	ret = gssapi_vm2gssbuf(token, gsstoken);
413 	if (ret < 0)
414 		return ret;
415 	gps->gsscnt_p++;
416 
417 	return 0;
418 }
419 
420 int
421 gssapi_get_token_to_send(struct ph1handle *iph1, vchar_t **token)
422 {
423 	struct gssapi_ph1_state *gps;
424 	gss_buffer_t gsstoken;
425 	int ret;
426 
427 	gps = gssapi_get_state(iph1);
428 	if (gps == NULL) {
429 		plog(LLV_ERROR, LOCATION, NULL,
430 		    "gssapi not yet initialized?\n");
431 		return -1;
432 	}
433 	gsstoken = &gps->gss[gps->gsscnt - 1];
434 	ret = gssapi_gss2vmbuf(gsstoken, token);
435 	if (ret < 0)
436 		return ret;
437 
438 	return 0;
439 }
440 
441 int
442 gssapi_get_itokens(struct ph1handle *iph1, vchar_t **tokens)
443 {
444 	struct gssapi_ph1_state *gps;
445 	int len, i;
446 	vchar_t *toks;
447 	char *p;
448 
449 	gps = gssapi_get_state(iph1);
450 	if (gps == NULL) {
451 		plog(LLV_ERROR, LOCATION, NULL,
452 		    "gssapi not yet initialized?\n");
453 		return -1;
454 	}
455 
456 	for (i = len = 0; i < gps->gsscnt; i++)
457 		len += gps->gss[i].length;
458 
459 	toks = vmalloc(len);
460 	if (toks == 0)
461 		return -1;
462 	p = (char *)toks->v;
463 	for (i = 0; i < gps->gsscnt; i++) {
464 		memcpy(p, gps->gss[i].value, gps->gss[i].length);
465 		p += gps->gss[i].length;
466 	}
467 
468 	*tokens = toks;
469 
470 	plog(LLV_DEBUG, LOCATION, NULL,
471 		"%d itokens of length %d\n", gps->gsscnt, (*tokens)->l);
472 
473 	return 0;
474 }
475 
476 int
477 gssapi_get_rtokens(struct ph1handle *iph1, vchar_t **tokens)
478 {
479 	struct gssapi_ph1_state *gps;
480 	int len, i;
481 	vchar_t *toks;
482 	char *p;
483 
484 	gps = gssapi_get_state(iph1);
485 	if (gps == NULL) {
486 		plog(LLV_ERROR, LOCATION, NULL,
487 		    "gssapi not yet initialized?\n");
488 		return -1;
489 	}
490 
491 	if (gssapi_more_tokens(iph1)) {
492 		plog(LLV_ERROR, LOCATION, NULL,
493 		    "gssapi roundtrips not complete\n");
494 		return -1;
495 	}
496 
497 	for (i = len = 0; i < gps->gsscnt_p; i++)
498 		len += gps->gss_p[i].length;
499 
500 	toks = vmalloc(len);
501 	if (toks == 0)
502 		return -1;
503 	p = (char *)toks->v;
504 	for (i = 0; i < gps->gsscnt_p; i++) {
505 		memcpy(p, gps->gss_p[i].value, gps->gss_p[i].length);
506 		p += gps->gss_p[i].length;
507 	}
508 
509 	*tokens = toks;
510 
511 	return 0;
512 }
513 
514 vchar_t *
515 gssapi_wraphash(struct ph1handle *iph1)
516 {
517 	struct gssapi_ph1_state *gps;
518 	OM_uint32 maj_stat, min_stat;
519 	gss_buffer_desc hash_in_buf, hash_out_buf;
520 	gss_buffer_t hash_in = &hash_in_buf, hash_out = &hash_out_buf;
521 	vchar_t *outbuf;
522 
523 	gps = gssapi_get_state(iph1);
524 	if (gps == NULL) {
525 		plog(LLV_ERROR, LOCATION, NULL,
526 		    "gssapi not yet initialized?\n");
527 		return NULL;
528 	}
529 
530 	if (gssapi_more_tokens(iph1)) {
531 		plog(LLV_ERROR, LOCATION, NULL,
532 		    "gssapi roundtrips not complete\n");
533 		return NULL;
534 	}
535 
536 	if (gssapi_vm2gssbuf(iph1->hash, hash_in) < 0) {
537 		plog(LLV_ERROR, LOCATION, NULL, "vm2gssbuf failed\n");
538 		return NULL;
539 	}
540 
541 	maj_stat = gss_wrap(&min_stat, gps->gss_context, 1, GSS_C_QOP_DEFAULT,
542 	    hash_in, NULL, hash_out);
543 	if (GSS_ERROR(maj_stat)) {
544 		gssapi_error(min_stat, LOCATION, "wrapping hash value\n");
545 		maj_stat = gss_release_buffer(&min_stat, hash_in);
546 		if (GSS_ERROR(maj_stat))
547 			gssapi_error(min_stat, LOCATION,
548 			    "release hash_in buffer\n");
549 		return NULL;
550 	}
551 
552 	plog(LLV_DEBUG, LOCATION, NULL, "wrapped HASH, ilen %d olen %d\n",
553 	    hash_in->length, hash_out->length);
554 
555 	maj_stat = gss_release_buffer(&min_stat, hash_in);
556 	if (GSS_ERROR(maj_stat))
557 		gssapi_error(min_stat, LOCATION, "release hash_in buffer\n");
558 
559 	if (gssapi_gss2vmbuf(hash_out, &outbuf) < 0) {
560 		plog(LLV_ERROR, LOCATION, NULL, "gss2vmbuf failed\n");
561 		maj_stat = gss_release_buffer(&min_stat, hash_out);
562 		if (GSS_ERROR(maj_stat))
563 			gssapi_error(min_stat, LOCATION,
564 			    "release hash_out buffer\n");
565 		return NULL;
566 	}
567 	maj_stat = gss_release_buffer(&min_stat, hash_out);
568 	if (GSS_ERROR(maj_stat))
569 		gssapi_error(min_stat, LOCATION, "release hash_out buffer\n");
570 
571 	return outbuf;
572 }
573 
574 vchar_t *
575 gssapi_unwraphash(struct ph1handle *iph1)
576 {
577 	struct gssapi_ph1_state *gps;
578 	OM_uint32 maj_stat, min_stat;
579 	gss_buffer_desc hashbuf, hash_outbuf;
580 	gss_buffer_t hash_in = &hashbuf, hash_out = &hash_outbuf;
581 	vchar_t *outbuf;
582 
583 	gps = gssapi_get_state(iph1);
584 	if (gps == NULL) {
585 		plog(LLV_ERROR, LOCATION, NULL,
586 		    "gssapi not yet initialized?\n");
587 		return NULL;
588 	}
589 
590 
591 	hashbuf.length = ntohs(iph1->pl_hash->h.len) - sizeof(*iph1->pl_hash);
592 	hashbuf.value = (char *)(iph1->pl_hash + 1);
593 
594 	plog(LLV_DEBUG, LOCATION, NULL, "unwrapping HASH of len %d\n",
595 	    hashbuf.length);
596 
597 	maj_stat = gss_unwrap(&min_stat, gps->gss_context, hash_in, hash_out,
598 	    NULL, NULL);
599 	if (GSS_ERROR(maj_stat)) {
600 		gssapi_error(min_stat, LOCATION, "unwrapping hash value\n");
601 		return NULL;
602 	}
603 
604 	if (gssapi_gss2vmbuf(hash_out, &outbuf) < 0) {
605 		plog(LLV_ERROR, LOCATION, NULL, "gss2vmbuf failed\n");
606 		maj_stat = gss_release_buffer(&min_stat, hash_out);
607 		if (GSS_ERROR(maj_stat))
608 			gssapi_error(min_stat, LOCATION,
609 			    "release hash_out buffer\n");
610 		return NULL;
611 	}
612 	maj_stat = gss_release_buffer(&min_stat, hash_out);
613 	if (GSS_ERROR(maj_stat))
614 		gssapi_error(min_stat, LOCATION, "release hash_out buffer\n");
615 
616 	return outbuf;
617 }
618 
619 void
620 gssapi_set_id_sent(struct ph1handle *iph1)
621 {
622 	struct gssapi_ph1_state *gps;
623 
624 	gps = gssapi_get_state(iph1);
625 
626 	gps->gss_flags |= GSSFLAG_ID_SENT;
627 }
628 
629 int
630 gssapi_id_sent(struct ph1handle *iph1)
631 {
632 	struct gssapi_ph1_state *gps;
633 
634 	gps = gssapi_get_state(iph1);
635 
636 	return (gps->gss_flags & GSSFLAG_ID_SENT) != 0;
637 }
638 
639 void
640 gssapi_set_id_rcvd(struct ph1handle *iph1)
641 {
642 	struct gssapi_ph1_state *gps;
643 
644 	gps = gssapi_get_state(iph1);
645 
646 	gps->gss_flags |= GSSFLAG_ID_RCVD;
647 }
648 
649 int
650 gssapi_id_rcvd(struct ph1handle *iph1)
651 {
652 	struct gssapi_ph1_state *gps;
653 
654 	gps = gssapi_get_state(iph1);
655 
656 	return (gps->gss_flags & GSSFLAG_ID_RCVD) != 0;
657 }
658 
659 void
660 gssapi_free_state(struct ph1handle *iph1)
661 {
662 	struct gssapi_ph1_state *gps;
663 	OM_uint32 maj_stat, min_stat;
664 
665 	gps = gssapi_get_state(iph1);
666 
667 	if (gps == NULL)
668 		return;
669 
670 	gssapi_set_state(iph1, NULL);
671 
672 	if (gps->gss_cred != GSS_C_NO_CREDENTIAL) {
673 		maj_stat = gss_release_cred(&min_stat, &gps->gss_cred);
674 		if (GSS_ERROR(maj_stat))
675 			gssapi_error(min_stat, LOCATION,
676 			    "releasing credentials\n");
677 	}
678 	racoon_free(gps);
679 }
680 
681 vchar_t *
682 gssapi_get_id(struct ph1handle *iph1)
683 {
684 	gss_buffer_desc id_buffer;
685 	gss_buffer_t id = &id_buffer;
686 	gss_name_t defname, canon_name;
687 	OM_uint32 min_stat, maj_stat;
688 	vchar_t *vmbuf;
689 
690 	if (iph1->rmconf->proposal->gssid != NULL)
691 		return (vdup(iph1->rmconf->proposal->gssid));
692 
693 	if (gssapi_get_default_name(iph1, 0, &defname) < 0)
694 		return NULL;
695 
696 	maj_stat = gss_canonicalize_name(&min_stat, defname, GSS_C_NO_OID,
697 	    &canon_name);
698 	if (GSS_ERROR(maj_stat)) {
699 		gssapi_error(min_stat, LOCATION, "canonicalize name\n");
700 		maj_stat = gss_release_name(&min_stat, &defname);
701 		if (GSS_ERROR(maj_stat))
702 			gssapi_error(min_stat, LOCATION,
703 			    "release default name\n");
704 		return NULL;
705 	}
706 	maj_stat = gss_release_name(&min_stat, &defname);
707 	if (GSS_ERROR(maj_stat))
708 		gssapi_error(min_stat, LOCATION, "release default name\n");
709 
710 	maj_stat = gss_export_name(&min_stat, canon_name, id);
711 	if (GSS_ERROR(maj_stat)) {
712 		gssapi_error(min_stat, LOCATION, "export name\n");
713 		maj_stat = gss_release_name(&min_stat, &canon_name);
714 		if (GSS_ERROR(maj_stat))
715 			gssapi_error(min_stat, LOCATION,
716 			    "release canonical name\n");
717 		return NULL;
718 	}
719 	maj_stat = gss_release_name(&min_stat, &canon_name);
720 	if (GSS_ERROR(maj_stat))
721 		gssapi_error(min_stat, LOCATION, "release canonical name\n");
722 
723 #if 0
724 	/*
725 	 * XXXJRT Did this debug message ever work?  This is a GSS name
726 	 * blob at this point.
727 	 */
728 	plog(LLV_DEBUG, LOCATION, NULL, "will try to acquire '%.*s' creds\n",
729 	    id->length, id->value);
730 #endif
731 
732 	if (gssapi_gss2vmbuf(id, &vmbuf) < 0) {
733 		plog(LLV_ERROR, LOCATION, NULL, "gss2vmbuf failed\n");
734 		maj_stat = gss_release_buffer(&min_stat, id);
735 		if (GSS_ERROR(maj_stat))
736 			gssapi_error(min_stat, LOCATION, "release id buffer\n");
737 		return NULL;
738 	}
739 	maj_stat = gss_release_buffer(&min_stat, id);
740 	if (GSS_ERROR(maj_stat))
741 		gssapi_error(min_stat, LOCATION, "release id buffer\n");
742 
743 	return vmbuf;
744 }
745 #else
746 int __gssapi_dUmMy;
747 #endif
748