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