1/*	$NetBSD: gssapi.c,v 1.4 2006/09/09 16:22:09 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
75static void
76gssapi_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 */
108static int
109gssapi_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
121static int
122gssapi_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
134vchar_t *
135gssapi_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
153static int
154gssapi_get_default_name(struct ph1handle *iph1, int remote, gss_name_t *service)
155{
156	char name[NI_MAXHOST];
157	struct sockaddr *sa;
158	char* buf = NULL;
159	gss_buffer_desc name_token;
160	OM_uint32 min_stat, maj_stat;
161
162	sa = remote ? iph1->remote : iph1->local;
163
164	if (getnameinfo(sa, sysdep_sa_len(sa), name, NI_MAXHOST, NULL, 0, 0) != 0)
165		return -1;
166
167	name_token.length = asprintf(&buf, "%s@%s", GSSAPI_DEF_NAME, name);
168	name_token.value = buf;
169
170	maj_stat = gss_import_name(&min_stat, &name_token,
171	    GSS_C_NT_HOSTBASED_SERVICE, service);
172	if (GSS_ERROR(maj_stat)) {
173		gssapi_error(min_stat, LOCATION, "import name\n");
174		maj_stat = gss_release_buffer(&min_stat, &name_token);
175		if (GSS_ERROR(maj_stat))
176			gssapi_error(min_stat, LOCATION, "release name_token");
177		return -1;
178	}
179	maj_stat = gss_release_buffer(&min_stat, &name_token);
180	if (GSS_ERROR(maj_stat))
181		gssapi_error(min_stat, LOCATION, "release name_token");
182
183	return 0;
184}
185
186static int
187gssapi_init(struct ph1handle *iph1)
188{
189	struct gssapi_ph1_state *gps;
190	gss_buffer_desc id_token, cred_token;
191	gss_buffer_t cred = &cred_token;
192	gss_name_t princ, canon_princ;
193	OM_uint32 maj_stat, min_stat;
194
195	gps = racoon_calloc(1, sizeof (struct gssapi_ph1_state));
196	if (gps == NULL) {
197		plog(LLV_ERROR, LOCATION, NULL, "racoon_calloc failed\n");
198		return -1;
199	}
200	gps->gss_context = GSS_C_NO_CONTEXT;
201	gps->gss_cred = GSS_C_NO_CREDENTIAL;
202
203	gssapi_set_state(iph1, gps);
204
205	if (iph1->rmconf->proposal->gssid != NULL) {
206		id_token.length = iph1->rmconf->proposal->gssid->l;
207		id_token.value = iph1->rmconf->proposal->gssid->v;
208		maj_stat = gss_import_name(&min_stat, &id_token, GSS_C_NO_OID,
209		    &princ);
210		if (GSS_ERROR(maj_stat)) {
211			gssapi_error(min_stat, LOCATION, "import name\n");
212			gssapi_free_state(iph1);
213			return -1;
214		}
215	} else
216		gssapi_get_default_name(iph1, 0, &princ);
217
218	maj_stat = gss_canonicalize_name(&min_stat, princ, GSS_C_NO_OID,
219	    &canon_princ);
220	if (GSS_ERROR(maj_stat)) {
221		gssapi_error(min_stat, LOCATION, "canonicalize name\n");
222		maj_stat = gss_release_name(&min_stat, &princ);
223		if (GSS_ERROR(maj_stat))
224			gssapi_error(min_stat, LOCATION, "release princ\n");
225		gssapi_free_state(iph1);
226		return -1;
227	}
228	maj_stat = gss_release_name(&min_stat, &princ);
229	if (GSS_ERROR(maj_stat))
230		gssapi_error(min_stat, LOCATION, "release princ\n");
231
232	maj_stat = gss_export_name(&min_stat, canon_princ, cred);
233	if (GSS_ERROR(maj_stat)) {
234		gssapi_error(min_stat, LOCATION, "export name\n");
235		maj_stat = gss_release_name(&min_stat, &canon_princ);
236		if (GSS_ERROR(maj_stat))
237			gssapi_error(min_stat, LOCATION,
238			    "release canon_princ\n");
239		gssapi_free_state(iph1);
240		return -1;
241	}
242
243#if 0
244	/*
245	 * XXXJRT Did this debug message ever work?  This is a GSS name
246	 * blob at this point.
247	 */
248	plog(LLV_DEBUG, LOCATION, NULL, "will try to acquire '%.*s' creds\n",
249	    cred->length, cred->value);
250#endif
251
252	maj_stat = gss_release_buffer(&min_stat, cred);
253	if (GSS_ERROR(maj_stat))
254		gssapi_error(min_stat, LOCATION, "release cred buffer\n");
255
256	maj_stat = gss_acquire_cred(&min_stat, canon_princ, GSS_C_INDEFINITE,
257	    GSS_C_NO_OID_SET, GSS_C_BOTH, &gps->gss_cred, NULL, NULL);
258	if (GSS_ERROR(maj_stat)) {
259		gssapi_error(min_stat, LOCATION, "acquire cred\n");
260		maj_stat = gss_release_name(&min_stat, &canon_princ);
261		if (GSS_ERROR(maj_stat))
262			gssapi_error(min_stat, LOCATION,
263			    "release canon_princ\n");
264		gssapi_free_state(iph1);
265		return -1;
266	}
267	maj_stat = gss_release_name(&min_stat, &canon_princ);
268	if (GSS_ERROR(maj_stat))
269		gssapi_error(min_stat, LOCATION, "release canon_princ\n");
270
271	return 0;
272}
273
274int
275gssapi_get_itoken(struct ph1handle *iph1, int *lenp)
276{
277	struct gssapi_ph1_state *gps;
278	gss_buffer_desc empty, name_token;
279	gss_buffer_t itoken, rtoken, dummy;
280	OM_uint32 maj_stat, min_stat;
281	gss_name_t partner;
282
283	if (gssapi_get_state(iph1) == NULL && gssapi_init(iph1) < 0)
284		return -1;
285
286	gps = gssapi_get_state(iph1);
287
288	empty.length = 0;
289	empty.value = NULL;
290	dummy = &empty;
291
292	if (iph1->approval != NULL && iph1->approval->gssid != NULL) {
293		plog(LLV_DEBUG, LOCATION, NULL,
294		    "using provided service '%.*s'\n",
295		    (int)iph1->approval->gssid->l, iph1->approval->gssid->v);
296		name_token.length = iph1->approval->gssid->l;
297		name_token.value = iph1->approval->gssid->v;
298		maj_stat = gss_import_name(&min_stat, &name_token,
299		    GSS_C_NO_OID, &partner);
300		if (GSS_ERROR(maj_stat)) {
301			gssapi_error(min_stat, LOCATION, "import of %.*s\n",
302			    name_token.length, name_token.value);
303			return -1;
304		}
305	} else
306		if (gssapi_get_default_name(iph1, 1, &partner) < 0)
307			return -1;
308
309	rtoken = gps->gsscnt_p == 0 ? dummy : &gps->gss_p[gps->gsscnt_p - 1];
310	itoken = &gps->gss[gps->gsscnt];
311
312	gps->gss_status = gss_init_sec_context(&min_stat, gps->gss_cred,
313	    &gps->gss_context, partner, GSS_C_NO_OID,
314	    GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG |
315		GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG,
316	    0, GSS_C_NO_CHANNEL_BINDINGS, rtoken, NULL,
317	    itoken, NULL, NULL);
318
319	if (GSS_ERROR(gps->gss_status)) {
320		gssapi_error(min_stat, LOCATION, "init_sec_context\n");
321		maj_stat = gss_release_name(&min_stat, &partner);
322		if (GSS_ERROR(maj_stat))
323			gssapi_error(min_stat, LOCATION, "release name\n");
324		return -1;
325	}
326	maj_stat = gss_release_name(&min_stat, &partner);
327	if (GSS_ERROR(maj_stat))
328		gssapi_error(min_stat, LOCATION, "release name\n");
329
330	plog(LLV_DEBUG, LOCATION, NULL, "gss_init_sec_context status %x\n",
331	    gps->gss_status);
332
333	if (lenp)
334		*lenp = itoken->length;
335
336	if (itoken->length != 0)
337		gps->gsscnt++;
338
339	return 0;
340}
341
342/*
343 * Call gss_accept_context, with token just read from the wire.
344 */
345int
346gssapi_get_rtoken(struct ph1handle *iph1, int *lenp)
347{
348	struct gssapi_ph1_state *gps;
349	gss_buffer_desc name_token;
350	gss_buffer_t itoken, rtoken;
351	OM_uint32 min_stat, maj_stat;
352	gss_name_t client_name;
353
354	if (gssapi_get_state(iph1) == NULL && gssapi_init(iph1) < 0)
355		return -1;
356
357	gps = gssapi_get_state(iph1);
358
359	rtoken = &gps->gss_p[gps->gsscnt_p - 1];
360	itoken = &gps->gss[gps->gsscnt];
361
362	gps->gss_status = gss_accept_sec_context(&min_stat, &gps->gss_context,
363	    gps->gss_cred, rtoken, GSS_C_NO_CHANNEL_BINDINGS, &client_name,
364	    NULL, itoken, NULL, NULL, NULL);
365
366	if (GSS_ERROR(gps->gss_status)) {
367		gssapi_error(min_stat, LOCATION, "accept_sec_context\n");
368		return -1;
369	}
370
371	maj_stat = gss_display_name(&min_stat, client_name, &name_token, NULL);
372	if (GSS_ERROR(maj_stat)) {
373		gssapi_error(min_stat, LOCATION, "gss_display_name\n");
374		maj_stat = gss_release_name(&min_stat, &client_name);
375		if (GSS_ERROR(maj_stat))
376			gssapi_error(min_stat, LOCATION,
377			    "release client_name\n");
378		return -1;
379	}
380	maj_stat = gss_release_name(&min_stat, &client_name);
381	if (GSS_ERROR(maj_stat))
382		gssapi_error(min_stat, LOCATION, "release client_name\n");
383
384	plog(LLV_DEBUG, LOCATION, NULL,
385		"gss_accept_sec_context: other side is %s\n",
386		(char *)name_token.value);
387	maj_stat = gss_release_buffer(&min_stat, &name_token);
388	if (GSS_ERROR(maj_stat))
389		gssapi_error(min_stat, LOCATION, "release name buffer\n");
390
391	if (itoken->length != 0)
392		gps->gsscnt++;
393
394	if (lenp)
395		*lenp = itoken->length;
396
397	return 0;
398}
399
400int
401gssapi_save_received_token(struct ph1handle *iph1, vchar_t *token)
402{
403	struct gssapi_ph1_state *gps;
404	gss_buffer_t gsstoken;
405	int ret;
406
407	if (gssapi_get_state(iph1) == NULL && gssapi_init(iph1) < 0)
408		return -1;
409
410	gps = gssapi_get_state(iph1);
411
412	gsstoken = &gps->gss_p[gps->gsscnt_p];
413
414	ret = gssapi_vm2gssbuf(token, gsstoken);
415	if (ret < 0)
416		return ret;
417	gps->gsscnt_p++;
418
419	return 0;
420}
421
422int
423gssapi_get_token_to_send(struct ph1handle *iph1, vchar_t **token)
424{
425	struct gssapi_ph1_state *gps;
426	gss_buffer_t gsstoken;
427	int ret;
428
429	gps = gssapi_get_state(iph1);
430	if (gps == NULL) {
431		plog(LLV_ERROR, LOCATION, NULL,
432		    "gssapi not yet initialized?\n");
433		return -1;
434	}
435	gsstoken = &gps->gss[gps->gsscnt - 1];
436	ret = gssapi_gss2vmbuf(gsstoken, token);
437	if (ret < 0)
438		return ret;
439
440	return 0;
441}
442
443int
444gssapi_get_itokens(struct ph1handle *iph1, vchar_t **tokens)
445{
446	struct gssapi_ph1_state *gps;
447	int len, i;
448	vchar_t *toks;
449	char *p;
450
451	gps = gssapi_get_state(iph1);
452	if (gps == NULL) {
453		plog(LLV_ERROR, LOCATION, NULL,
454		    "gssapi not yet initialized?\n");
455		return -1;
456	}
457
458	for (i = len = 0; i < gps->gsscnt; i++)
459		len += gps->gss[i].length;
460
461	toks = vmalloc(len);
462	if (toks == 0)
463		return -1;
464	p = (char *)toks->v;
465	for (i = 0; i < gps->gsscnt; i++) {
466		memcpy(p, gps->gss[i].value, gps->gss[i].length);
467		p += gps->gss[i].length;
468	}
469
470	*tokens = toks;
471
472	plog(LLV_DEBUG, LOCATION, NULL,
473		"%d itokens of length %zu\n", gps->gsscnt, (*tokens)->l);
474
475	return 0;
476}
477
478int
479gssapi_get_rtokens(struct ph1handle *iph1, vchar_t **tokens)
480{
481	struct gssapi_ph1_state *gps;
482	int len, i;
483	vchar_t *toks;
484	char *p;
485
486	gps = gssapi_get_state(iph1);
487	if (gps == NULL) {
488		plog(LLV_ERROR, LOCATION, NULL,
489		    "gssapi not yet initialized?\n");
490		return -1;
491	}
492
493	if (gssapi_more_tokens(iph1)) {
494		plog(LLV_ERROR, LOCATION, NULL,
495		    "gssapi roundtrips not complete\n");
496		return -1;
497	}
498
499	for (i = len = 0; i < gps->gsscnt_p; i++)
500		len += gps->gss_p[i].length;
501
502	toks = vmalloc(len);
503	if (toks == 0)
504		return -1;
505	p = (char *)toks->v;
506	for (i = 0; i < gps->gsscnt_p; i++) {
507		memcpy(p, gps->gss_p[i].value, gps->gss_p[i].length);
508		p += gps->gss_p[i].length;
509	}
510
511	*tokens = toks;
512
513	return 0;
514}
515
516vchar_t *
517gssapi_wraphash(struct ph1handle *iph1)
518{
519	struct gssapi_ph1_state *gps;
520	OM_uint32 maj_stat, min_stat;
521	gss_buffer_desc hash_in_buf, hash_out_buf;
522	gss_buffer_t hash_in = &hash_in_buf, hash_out = &hash_out_buf;
523	vchar_t *outbuf;
524
525	gps = gssapi_get_state(iph1);
526	if (gps == NULL) {
527		plog(LLV_ERROR, LOCATION, NULL,
528		    "gssapi not yet initialized?\n");
529		return NULL;
530	}
531
532	if (gssapi_more_tokens(iph1)) {
533		plog(LLV_ERROR, LOCATION, NULL,
534		    "gssapi roundtrips not complete\n");
535		return NULL;
536	}
537
538	if (gssapi_vm2gssbuf(iph1->hash, hash_in) < 0) {
539		plog(LLV_ERROR, LOCATION, NULL, "vm2gssbuf failed\n");
540		return NULL;
541	}
542
543	maj_stat = gss_wrap(&min_stat, gps->gss_context, 1, GSS_C_QOP_DEFAULT,
544	    hash_in, NULL, hash_out);
545	if (GSS_ERROR(maj_stat)) {
546		gssapi_error(min_stat, LOCATION, "wrapping hash value\n");
547		maj_stat = gss_release_buffer(&min_stat, hash_in);
548		if (GSS_ERROR(maj_stat))
549			gssapi_error(min_stat, LOCATION,
550			    "release hash_in buffer\n");
551		return NULL;
552	}
553
554	plog(LLV_DEBUG, LOCATION, NULL, "wrapped HASH, ilen %zu olen %zu\n",
555	    hash_in->length, hash_out->length);
556
557	maj_stat = gss_release_buffer(&min_stat, hash_in);
558	if (GSS_ERROR(maj_stat))
559		gssapi_error(min_stat, LOCATION, "release hash_in buffer\n");
560
561	if (gssapi_gss2vmbuf(hash_out, &outbuf) < 0) {
562		plog(LLV_ERROR, LOCATION, NULL, "gss2vmbuf failed\n");
563		maj_stat = gss_release_buffer(&min_stat, hash_out);
564		if (GSS_ERROR(maj_stat))
565			gssapi_error(min_stat, LOCATION,
566			    "release hash_out buffer\n");
567		return NULL;
568	}
569	maj_stat = gss_release_buffer(&min_stat, hash_out);
570	if (GSS_ERROR(maj_stat))
571		gssapi_error(min_stat, LOCATION, "release hash_out buffer\n");
572
573	return outbuf;
574}
575
576vchar_t *
577gssapi_unwraphash(struct ph1handle *iph1)
578{
579	struct gssapi_ph1_state *gps;
580	OM_uint32 maj_stat, min_stat;
581	gss_buffer_desc hashbuf, hash_outbuf;
582	gss_buffer_t hash_in = &hashbuf, hash_out = &hash_outbuf;
583	vchar_t *outbuf;
584
585	gps = gssapi_get_state(iph1);
586	if (gps == NULL) {
587		plog(LLV_ERROR, LOCATION, NULL,
588		    "gssapi not yet initialized?\n");
589		return NULL;
590	}
591
592
593	hashbuf.length = ntohs(iph1->pl_hash->h.len) - sizeof(*iph1->pl_hash);
594	hashbuf.value = (char *)(iph1->pl_hash + 1);
595
596	plog(LLV_DEBUG, LOCATION, NULL, "unwrapping HASH of len %zu\n",
597	    hashbuf.length);
598
599	maj_stat = gss_unwrap(&min_stat, gps->gss_context, hash_in, hash_out,
600	    NULL, NULL);
601	if (GSS_ERROR(maj_stat)) {
602		gssapi_error(min_stat, LOCATION, "unwrapping hash value\n");
603		return NULL;
604	}
605
606	if (gssapi_gss2vmbuf(hash_out, &outbuf) < 0) {
607		plog(LLV_ERROR, LOCATION, NULL, "gss2vmbuf failed\n");
608		maj_stat = gss_release_buffer(&min_stat, hash_out);
609		if (GSS_ERROR(maj_stat))
610			gssapi_error(min_stat, LOCATION,
611			    "release hash_out buffer\n");
612		return NULL;
613	}
614	maj_stat = gss_release_buffer(&min_stat, hash_out);
615	if (GSS_ERROR(maj_stat))
616		gssapi_error(min_stat, LOCATION, "release hash_out buffer\n");
617
618	return outbuf;
619}
620
621void
622gssapi_set_id_sent(struct ph1handle *iph1)
623{
624	struct gssapi_ph1_state *gps;
625
626	gps = gssapi_get_state(iph1);
627
628	gps->gss_flags |= GSSFLAG_ID_SENT;
629}
630
631int
632gssapi_id_sent(struct ph1handle *iph1)
633{
634	struct gssapi_ph1_state *gps;
635
636	gps = gssapi_get_state(iph1);
637
638	return (gps->gss_flags & GSSFLAG_ID_SENT) != 0;
639}
640
641void
642gssapi_set_id_rcvd(struct ph1handle *iph1)
643{
644	struct gssapi_ph1_state *gps;
645
646	gps = gssapi_get_state(iph1);
647
648	gps->gss_flags |= GSSFLAG_ID_RCVD;
649}
650
651int
652gssapi_id_rcvd(struct ph1handle *iph1)
653{
654	struct gssapi_ph1_state *gps;
655
656	gps = gssapi_get_state(iph1);
657
658	return (gps->gss_flags & GSSFLAG_ID_RCVD) != 0;
659}
660
661void
662gssapi_free_state(struct ph1handle *iph1)
663{
664	struct gssapi_ph1_state *gps;
665	OM_uint32 maj_stat, min_stat;
666
667	gps = gssapi_get_state(iph1);
668
669	if (gps == NULL)
670		return;
671
672	gssapi_set_state(iph1, NULL);
673
674	if (gps->gss_cred != GSS_C_NO_CREDENTIAL) {
675		maj_stat = gss_release_cred(&min_stat, &gps->gss_cred);
676		if (GSS_ERROR(maj_stat))
677			gssapi_error(min_stat, LOCATION,
678			    "releasing credentials\n");
679	}
680	racoon_free(gps);
681}
682
683vchar_t *
684gssapi_get_id(struct ph1handle *iph1)
685{
686	gss_buffer_desc id_buffer;
687	gss_buffer_t id = &id_buffer;
688	gss_name_t defname, canon_name;
689	OM_uint32 min_stat, maj_stat;
690	vchar_t *vmbuf;
691
692	if (iph1->rmconf->proposal->gssid != NULL)
693		return (vdup(iph1->rmconf->proposal->gssid));
694
695	if (gssapi_get_default_name(iph1, 0, &defname) < 0)
696		return NULL;
697
698	maj_stat = gss_canonicalize_name(&min_stat, defname, GSS_C_NO_OID,
699	    &canon_name);
700	if (GSS_ERROR(maj_stat)) {
701		gssapi_error(min_stat, LOCATION, "canonicalize name\n");
702		maj_stat = gss_release_name(&min_stat, &defname);
703		if (GSS_ERROR(maj_stat))
704			gssapi_error(min_stat, LOCATION,
705			    "release default name\n");
706		return NULL;
707	}
708	maj_stat = gss_release_name(&min_stat, &defname);
709	if (GSS_ERROR(maj_stat))
710		gssapi_error(min_stat, LOCATION, "release default name\n");
711
712	maj_stat = gss_export_name(&min_stat, canon_name, id);
713	if (GSS_ERROR(maj_stat)) {
714		gssapi_error(min_stat, LOCATION, "export name\n");
715		maj_stat = gss_release_name(&min_stat, &canon_name);
716		if (GSS_ERROR(maj_stat))
717			gssapi_error(min_stat, LOCATION,
718			    "release canonical name\n");
719		return NULL;
720	}
721	maj_stat = gss_release_name(&min_stat, &canon_name);
722	if (GSS_ERROR(maj_stat))
723		gssapi_error(min_stat, LOCATION, "release canonical name\n");
724
725#if 0
726	/*
727	 * XXXJRT Did this debug message ever work?  This is a GSS name
728	 * blob at this point.
729	 */
730	plog(LLV_DEBUG, LOCATION, NULL, "will try to acquire '%.*s' creds\n",
731	    id->length, id->value);
732#endif
733
734	if (gssapi_gss2vmbuf(id, &vmbuf) < 0) {
735		plog(LLV_ERROR, LOCATION, NULL, "gss2vmbuf failed\n");
736		maj_stat = gss_release_buffer(&min_stat, id);
737		if (GSS_ERROR(maj_stat))
738			gssapi_error(min_stat, LOCATION, "release id buffer\n");
739		return NULL;
740	}
741	maj_stat = gss_release_buffer(&min_stat, id);
742	if (GSS_ERROR(maj_stat))
743		gssapi_error(min_stat, LOCATION, "release id buffer\n");
744
745	return vmbuf;
746}
747#else
748int __gssapi_dUmMy;
749#endif
750