PageRenderTime 144ms CodeModel.GetById 24ms app.highlight 109ms RepoModel.GetById 1ms app.codeStats 1ms

/contrib/bind9/lib/dns/spnego.c

https://bitbucket.org/freebsd/freebsd-head/
C | 1800 lines | 1383 code | 212 blank | 205 comment | 256 complexity | 66ace5ca8ee56058029efbe2aa15a53b MD5 | raw file
   1/*
   2 * Copyright (C) 2006-2012  Internet Systems Consortium, Inc. ("ISC")
   3 *
   4 * Permission to use, copy, modify, and/or distribute this software for any
   5 * purpose with or without fee is hereby granted, provided that the above
   6 * copyright notice and this permission notice appear in all copies.
   7 *
   8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
   9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  10 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  14 * PERFORMANCE OF THIS SOFTWARE.
  15 */
  16
  17/* $Id$ */
  18
  19/*! \file
  20 * \brief
  21 * Portable SPNEGO implementation.
  22 *
  23 * This is part of a portable implementation of the SPNEGO protocol
  24 * (RFCs 2478 and 4178).  This implementation uses the RFC 4178 ASN.1
  25 * module but is not a full implementation of the RFC 4178 protocol;
  26 * at the moment, we only support GSS-TSIG with Kerberos
  27 * authentication, so we only need enough of the SPNEGO protocol to
  28 * support that.
  29 *
  30 * The files that make up this portable SPNEGO implementation are:
  31 * \li	spnego.c	(this file)
  32 * \li	spnego.h	(API SPNEGO exports to the rest of lib/dns)
  33 * \li	spnego.asn1	(SPNEGO ASN.1 module)
  34 * \li	spnego_asn1.c	(routines generated from spngo.asn1)
  35 * \li	spnego_asn1.pl	(perl script to generate spnego_asn1.c)
  36 *
  37 * Everything but the functions exported in spnego.h is static, to
  38 * avoid possible conflicts with other libraries (particularly Heimdal,
  39 * since much of this code comes from Heimdal by way of mod_auth_kerb).
  40 *
  41 * spnego_asn1.c is shipped as part of lib/dns because generating it
  42 * requires both Perl and the Heimdal ASN.1 compiler.  See
  43 * spnego_asn1.pl for further details.  We've tried to eliminate all
  44 * compiler warnings from the generated code, but you may see a few
  45 * when using a compiler version we haven't tested yet.
  46 */
  47
  48/*
  49 * Portions of this code were derived from mod_auth_kerb and Heimdal.
  50 * These packages are available from:
  51 *
  52 *   http://modauthkerb.sourceforge.net/
  53 *   http://www.pdc.kth.se/heimdal/
  54 *
  55 * and were released under the following licenses:
  56 *
  57 * ----------------------------------------------------------------
  58 *
  59 * Copyright (c) 2004 Masarykova universita
  60 * (Masaryk University, Brno, Czech Republic)
  61 * All rights reserved.
  62 *
  63 * Redistribution and use in source and binary forms, with or without
  64 * modification, are permitted provided that the following conditions are met:
  65 *
  66 * 1. Redistributions of source code must retain the above copyright notice,
  67 *    this list of conditions and the following disclaimer.
  68 *
  69 * 2. Redistributions in binary form must reproduce the above copyright
  70 *    notice, this list of conditions and the following disclaimer in the
  71 *    documentation and/or other materials provided with the distribution.
  72 *
  73 * 3. Neither the name of the University nor the names of its contributors may
  74 *    be used to endorse or promote products derived from this software
  75 *    without specific prior written permission.
  76 *
  77 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  78 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  79 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  80 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  81 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  82 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  83 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  84 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  85 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  86 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  87 * POSSIBILITY OF SUCH DAMAGE.
  88 *
  89 * ----------------------------------------------------------------
  90 *
  91 * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
  92 * (Royal Institute of Technology, Stockholm, Sweden).
  93 * All rights reserved.
  94 *
  95 * Redistribution and use in source and binary forms, with or without
  96 * modification, are permitted provided that the following conditions
  97 * are met:
  98 *
  99 * 1. Redistributions of source code must retain the above copyright
 100 *    notice, this list of conditions and the following disclaimer.
 101 *
 102 * 2. Redistributions in binary form must reproduce the above copyright
 103 *    notice, this list of conditions and the following disclaimer in the
 104 *    documentation and/or other materials provided with the distribution.
 105 *
 106 * 3. Neither the name of the Institute nor the names of its contributors
 107 *    may be used to endorse or promote products derived from this software
 108 *    without specific prior written permission.
 109 *
 110 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 111 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 112 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 113 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 114 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 115 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 116 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 117 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 118 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 119 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 120 * SUCH DAMAGE.
 121 */
 122
 123/*
 124 * XXXSRA We should omit this file entirely in Makefile.in via autoconf,
 125 * but this will keep it from generating errors until that's written.
 126 */
 127
 128#ifdef GSSAPI
 129
 130/*
 131 * XXXSRA Some of the following files are almost certainly unnecessary,
 132 * but using this list (borrowed from gssapictx.c) gets rid of some
 133 * whacky compilation errors when building with MSVC and should be
 134 * harmless in any case.
 135 */
 136
 137#include <config.h>
 138
 139#include <stdlib.h>
 140#include <errno.h>
 141
 142#include <isc/buffer.h>
 143#include <isc/dir.h>
 144#include <isc/entropy.h>
 145#include <isc/lex.h>
 146#include <isc/mem.h>
 147#include <isc/once.h>
 148#include <isc/random.h>
 149#include <isc/string.h>
 150#include <isc/time.h>
 151#include <isc/util.h>
 152
 153#include <dns/fixedname.h>
 154#include <dns/name.h>
 155#include <dns/rdata.h>
 156#include <dns/rdataclass.h>
 157#include <dns/result.h>
 158#include <dns/types.h>
 159#include <dns/keyvalues.h>
 160#include <dns/log.h>
 161
 162#include <dst/gssapi.h>
 163#include <dst/result.h>
 164
 165#include "dst_internal.h"
 166
 167/*
 168 * The API we export
 169 */
 170#include "spnego.h"
 171
 172/* asn1_err.h */
 173/* Generated from ../../../lib/asn1/asn1_err.et */
 174
 175#ifndef ERROR_TABLE_BASE_asn1
 176/* these may be brought in already via gssapi_krb5.h */
 177typedef enum asn1_error_number {
 178	ASN1_BAD_TIMEFORMAT = 1859794432,
 179	ASN1_MISSING_FIELD = 1859794433,
 180	ASN1_MISPLACED_FIELD = 1859794434,
 181	ASN1_TYPE_MISMATCH = 1859794435,
 182	ASN1_OVERFLOW = 1859794436,
 183	ASN1_OVERRUN = 1859794437,
 184	ASN1_BAD_ID = 1859794438,
 185	ASN1_BAD_LENGTH = 1859794439,
 186	ASN1_BAD_FORMAT = 1859794440,
 187	ASN1_PARSE_ERROR = 1859794441
 188} asn1_error_number;
 189
 190#define ERROR_TABLE_BASE_asn1 1859794432
 191#endif
 192
 193#define __asn1_common_definitions__
 194
 195typedef struct octet_string {
 196	size_t length;
 197	void *data;
 198} octet_string;
 199
 200typedef char *general_string;
 201
 202typedef char *utf8_string;
 203
 204typedef struct oid {
 205	size_t length;
 206	unsigned *components;
 207} oid;
 208
 209/* der.h */
 210
 211typedef enum {
 212	ASN1_C_UNIV = 0, ASN1_C_APPL = 1,
 213	ASN1_C_CONTEXT = 2, ASN1_C_PRIVATE = 3
 214} Der_class;
 215
 216typedef enum {
 217	PRIM = 0, CONS = 1
 218} Der_type;
 219
 220/* Universal tags */
 221
 222enum {
 223	UT_Boolean = 1,
 224	UT_Integer = 2,
 225	UT_BitString = 3,
 226	UT_OctetString = 4,
 227	UT_Null = 5,
 228	UT_OID = 6,
 229	UT_Enumerated = 10,
 230	UT_Sequence = 16,
 231	UT_Set = 17,
 232	UT_PrintableString = 19,
 233	UT_IA5String = 22,
 234	UT_UTCTime = 23,
 235	UT_GeneralizedTime = 24,
 236	UT_VisibleString = 26,
 237	UT_GeneralString = 27
 238};
 239
 240#define ASN1_INDEFINITE 0xdce0deed
 241
 242static int
 243der_get_length(const unsigned char *p, size_t len,
 244	       size_t * val, size_t * size);
 245
 246static int
 247der_get_octet_string(const unsigned char *p, size_t len,
 248		     octet_string * data, size_t * size);
 249static int
 250der_get_oid(const unsigned char *p, size_t len,
 251	    oid * data, size_t * size);
 252static int
 253der_get_tag(const unsigned char *p, size_t len,
 254	    Der_class * class, Der_type * type,
 255	    int *tag, size_t * size);
 256
 257static int
 258der_match_tag(const unsigned char *p, size_t len,
 259	      Der_class class, Der_type type,
 260	      int tag, size_t * size);
 261static int
 262der_match_tag_and_length(const unsigned char *p, size_t len,
 263			 Der_class class, Der_type type, int tag,
 264			 size_t * length_ret, size_t * size);
 265
 266static int
 267decode_oid(const unsigned char *p, size_t len,
 268	   oid * k, size_t * size);
 269
 270static int
 271decode_enumerated(const unsigned char *p, size_t len, void *num, size_t *size);
 272
 273static int
 274decode_octet_string(const unsigned char *, size_t, octet_string *, size_t *);
 275
 276static int
 277der_put_int(unsigned char *p, size_t len, int val, size_t *);
 278
 279static int
 280der_put_length(unsigned char *p, size_t len, size_t val, size_t *);
 281
 282static int
 283der_put_octet_string(unsigned char *p, size_t len,
 284		     const octet_string * data, size_t *);
 285static int
 286der_put_oid(unsigned char *p, size_t len,
 287	    const oid * data, size_t * size);
 288static int
 289der_put_tag(unsigned char *p, size_t len, Der_class class, Der_type type,
 290	    int tag, size_t *);
 291static int
 292der_put_length_and_tag(unsigned char *, size_t, size_t,
 293		       Der_class, Der_type, int, size_t *);
 294
 295static int
 296encode_enumerated(unsigned char *p, size_t len, const void *data, size_t *);
 297
 298static int
 299encode_octet_string(unsigned char *p, size_t len,
 300		    const octet_string * k, size_t *);
 301static int
 302encode_oid(unsigned char *p, size_t len,
 303	   const oid * k, size_t *);
 304
 305static void
 306free_octet_string(octet_string * k);
 307
 308static void
 309free_oid  (oid * k);
 310
 311static size_t
 312length_len(size_t len);
 313
 314static int
 315fix_dce(size_t reallen, size_t * len);
 316
 317/*
 318 * Include stuff generated by the ASN.1 compiler.
 319 */
 320
 321#include "spnego_asn1.c"
 322
 323static unsigned char gss_krb5_mech_oid_bytes[] = {
 324	0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02
 325};
 326
 327static gss_OID_desc gss_krb5_mech_oid_desc = {
 328	sizeof(gss_krb5_mech_oid_bytes),
 329	gss_krb5_mech_oid_bytes
 330};
 331
 332static gss_OID GSS_KRB5_MECH = &gss_krb5_mech_oid_desc;
 333
 334static unsigned char gss_mskrb5_mech_oid_bytes[] = {
 335	0x2a, 0x86, 0x48, 0x82, 0xf7, 0x12, 0x01, 0x02, 0x02
 336};
 337
 338static gss_OID_desc gss_mskrb5_mech_oid_desc = {
 339	sizeof(gss_mskrb5_mech_oid_bytes),
 340	gss_mskrb5_mech_oid_bytes
 341};
 342
 343static gss_OID GSS_MSKRB5_MECH = &gss_mskrb5_mech_oid_desc;
 344
 345static unsigned char gss_spnego_mech_oid_bytes[] = {
 346	0x2b, 0x06, 0x01, 0x05, 0x05, 0x02
 347};
 348
 349static gss_OID_desc gss_spnego_mech_oid_desc = {
 350	sizeof(gss_spnego_mech_oid_bytes),
 351	gss_spnego_mech_oid_bytes
 352};
 353
 354static gss_OID GSS_SPNEGO_MECH = &gss_spnego_mech_oid_desc;
 355
 356/* spnegokrb5_locl.h */
 357
 358static OM_uint32
 359gssapi_spnego_encapsulate(OM_uint32 *,
 360			  unsigned char *,
 361			  size_t,
 362			  gss_buffer_t,
 363			  const gss_OID);
 364
 365static OM_uint32
 366gssapi_spnego_decapsulate(OM_uint32 *,
 367			  gss_buffer_t,
 368			  unsigned char **,
 369			  size_t *,
 370			  const gss_OID);
 371
 372/* mod_auth_kerb.c */
 373
 374static int
 375cmp_gss_type(gss_buffer_t token, gss_OID oid)
 376{
 377	unsigned char *p;
 378	size_t len;
 379
 380	if (token->length == 0U)
 381		return (GSS_S_DEFECTIVE_TOKEN);
 382
 383	p = token->value;
 384	if (*p++ != 0x60)
 385		return (GSS_S_DEFECTIVE_TOKEN);
 386	len = *p++;
 387	if (len & 0x80) {
 388		if ((len & 0x7f) > 4U)
 389			return (GSS_S_DEFECTIVE_TOKEN);
 390		p += len & 0x7f;
 391	}
 392	if (*p++ != 0x06)
 393		return (GSS_S_DEFECTIVE_TOKEN);
 394
 395	if (((OM_uint32) *p++) != oid->length)
 396		return (GSS_S_DEFECTIVE_TOKEN);
 397
 398	return (memcmp(p, oid->elements, oid->length));
 399}
 400
 401/* accept_sec_context.c */
 402/*
 403 * SPNEGO wrapper for Kerberos5 GSS-API kouril@ics.muni.cz, 2003 (mostly
 404 * based on Heimdal code)
 405 */
 406
 407static OM_uint32
 408code_NegTokenArg(OM_uint32 * minor_status,
 409		 const NegTokenResp * resp,
 410		 unsigned char **outbuf,
 411		 size_t * outbuf_size)
 412{
 413	OM_uint32 ret;
 414	u_char *buf;
 415	size_t buf_size, buf_len = 0;
 416
 417	buf_size = 1024;
 418	buf = malloc(buf_size);
 419	if (buf == NULL) {
 420		*minor_status = ENOMEM;
 421		return (GSS_S_FAILURE);
 422	}
 423	do {
 424		ret = encode_NegTokenResp(buf + buf_size - 1,
 425					  buf_size,
 426					  resp, &buf_len);
 427		if (ret == 0) {
 428			size_t tmp;
 429
 430			ret = der_put_length_and_tag(buf + buf_size - buf_len - 1,
 431						     buf_size - buf_len,
 432						     buf_len,
 433						     ASN1_C_CONTEXT,
 434						     CONS,
 435						     1,
 436						     &tmp);
 437			if (ret == 0)
 438				buf_len += tmp;
 439		}
 440		if (ret) {
 441			if (ret == ASN1_OVERFLOW) {
 442				u_char *tmp;
 443
 444				buf_size *= 2;
 445				tmp = realloc(buf, buf_size);
 446				if (tmp == NULL) {
 447					*minor_status = ENOMEM;
 448					free(buf);
 449					return (GSS_S_FAILURE);
 450				}
 451				buf = tmp;
 452			} else {
 453				*minor_status = ret;
 454				free(buf);
 455				return (GSS_S_FAILURE);
 456			}
 457		}
 458	} while (ret == ASN1_OVERFLOW);
 459
 460	*outbuf = malloc(buf_len);
 461	if (*outbuf == NULL) {
 462		*minor_status = ENOMEM;
 463		free(buf);
 464		return (GSS_S_FAILURE);
 465	}
 466	memcpy(*outbuf, buf + buf_size - buf_len, buf_len);
 467	*outbuf_size = buf_len;
 468
 469	free(buf);
 470
 471	return (GSS_S_COMPLETE);
 472}
 473
 474static OM_uint32
 475send_reject(OM_uint32 * minor_status,
 476	    gss_buffer_t output_token)
 477{
 478	NegTokenResp resp;
 479	OM_uint32 ret;
 480
 481	resp.negState = malloc(sizeof(*resp.negState));
 482	if (resp.negState == NULL) {
 483		*minor_status = ENOMEM;
 484		return (GSS_S_FAILURE);
 485	}
 486	*(resp.negState) = reject;
 487
 488	resp.supportedMech = NULL;
 489	resp.responseToken = NULL;
 490	resp.mechListMIC = NULL;
 491
 492	ret = code_NegTokenArg(minor_status, &resp,
 493			       (unsigned char **)&output_token->value,
 494			       &output_token->length);
 495	free_NegTokenResp(&resp);
 496	if (ret)
 497		return (ret);
 498
 499	return (GSS_S_BAD_MECH);
 500}
 501
 502static OM_uint32
 503send_accept(OM_uint32 * minor_status,
 504	    gss_buffer_t output_token,
 505	    gss_buffer_t mech_token,
 506	    const gss_OID pref)
 507{
 508	NegTokenResp resp;
 509	OM_uint32 ret;
 510
 511	memset(&resp, 0, sizeof(resp));
 512	resp.negState = malloc(sizeof(*resp.negState));
 513	if (resp.negState == NULL) {
 514		*minor_status = ENOMEM;
 515		return (GSS_S_FAILURE);
 516	}
 517	*(resp.negState) = accept_completed;
 518
 519	resp.supportedMech = malloc(sizeof(*resp.supportedMech));
 520	if (resp.supportedMech == NULL) {
 521		free_NegTokenResp(&resp);
 522		*minor_status = ENOMEM;
 523		return (GSS_S_FAILURE);
 524	}
 525	ret = der_get_oid(pref->elements,
 526			  pref->length,
 527			  resp.supportedMech,
 528			  NULL);
 529	if (ret) {
 530		free_NegTokenResp(&resp);
 531		*minor_status = ENOMEM;
 532		return (GSS_S_FAILURE);
 533	}
 534	if (mech_token != NULL && mech_token->length != 0U) {
 535		resp.responseToken = malloc(sizeof(*resp.responseToken));
 536		if (resp.responseToken == NULL) {
 537			free_NegTokenResp(&resp);
 538			*minor_status = ENOMEM;
 539			return (GSS_S_FAILURE);
 540		}
 541		resp.responseToken->length = mech_token->length;
 542		resp.responseToken->data = mech_token->value;
 543	}
 544
 545	ret = code_NegTokenArg(minor_status, &resp,
 546			       (unsigned char **)&output_token->value,
 547			       &output_token->length);
 548	if (resp.responseToken != NULL) {
 549		free(resp.responseToken);
 550		resp.responseToken = NULL;
 551	}
 552	free_NegTokenResp(&resp);
 553	if (ret)
 554		return (ret);
 555
 556	return (GSS_S_COMPLETE);
 557}
 558
 559OM_uint32
 560gss_accept_sec_context_spnego(OM_uint32 *minor_status,
 561			      gss_ctx_id_t *context_handle,
 562			      const gss_cred_id_t acceptor_cred_handle,
 563			      const gss_buffer_t input_token_buffer,
 564			      const gss_channel_bindings_t input_chan_bindings,
 565			      gss_name_t *src_name,
 566			      gss_OID *mech_type,
 567			      gss_buffer_t output_token,
 568			      OM_uint32 *ret_flags,
 569			      OM_uint32 *time_rec,
 570			      gss_cred_id_t *delegated_cred_handle)
 571{
 572	NegTokenInit init_token;
 573	OM_uint32 major_status;
 574	OM_uint32 minor_status2;
 575	gss_buffer_desc ibuf, obuf;
 576	gss_buffer_t ot = NULL;
 577	gss_OID pref = GSS_KRB5_MECH;
 578	unsigned char *buf;
 579	size_t buf_size;
 580	size_t len, taglen, ni_len;
 581	int found = 0;
 582	int ret;
 583	unsigned i;
 584
 585	/*
 586	 * Before doing anything else, see whether this is a SPNEGO
 587	 * PDU.  If not, dispatch to the GSSAPI library and get out.
 588	 */
 589
 590	if (cmp_gss_type(input_token_buffer, GSS_SPNEGO_MECH))
 591		return (gss_accept_sec_context(minor_status,
 592					       context_handle,
 593					       acceptor_cred_handle,
 594					       input_token_buffer,
 595					       input_chan_bindings,
 596					       src_name,
 597					       mech_type,
 598					       output_token,
 599					       ret_flags,
 600					       time_rec,
 601					       delegated_cred_handle));
 602
 603	/*
 604	 * If we get here, it's SPNEGO.
 605	 */
 606
 607	memset(&init_token, 0, sizeof(init_token));
 608
 609	ret = gssapi_spnego_decapsulate(minor_status, input_token_buffer,
 610					&buf, &buf_size, GSS_SPNEGO_MECH);
 611	if (ret)
 612		return (ret);
 613
 614	ret = der_match_tag_and_length(buf, buf_size, ASN1_C_CONTEXT, CONS,
 615				       0, &len, &taglen);
 616	if (ret)
 617		return (ret);
 618
 619	ret = decode_NegTokenInit(buf + taglen, len, &init_token, &ni_len);
 620	if (ret) {
 621		*minor_status = EINVAL;	/* XXX */
 622		return (GSS_S_DEFECTIVE_TOKEN);
 623	}
 624
 625	for (i = 0; !found && i < init_token.mechTypes.len; ++i) {
 626		unsigned char mechbuf[17];
 627		size_t mech_len;
 628
 629		ret = der_put_oid(mechbuf + sizeof(mechbuf) - 1,
 630				  sizeof(mechbuf),
 631				  &init_token.mechTypes.val[i],
 632				  &mech_len);
 633		if (ret)
 634			return (GSS_S_DEFECTIVE_TOKEN);
 635		if (mech_len == GSS_KRB5_MECH->length &&
 636		    memcmp(GSS_KRB5_MECH->elements,
 637			   mechbuf + sizeof(mechbuf) - mech_len,
 638			   mech_len) == 0) {
 639			found = 1;
 640			break;
 641		}
 642		if (mech_len == GSS_MSKRB5_MECH->length &&
 643		    memcmp(GSS_MSKRB5_MECH->elements,
 644			   mechbuf + sizeof(mechbuf) - mech_len,
 645			   mech_len) == 0) {
 646			found = 1;
 647			if (i == 0)
 648				pref = GSS_MSKRB5_MECH;
 649			break;
 650		}
 651	}
 652
 653	if (!found)
 654		return (send_reject(minor_status, output_token));
 655
 656	if (i == 0 && init_token.mechToken != NULL) {
 657		ibuf.length = init_token.mechToken->length;
 658		ibuf.value = init_token.mechToken->data;
 659
 660		major_status = gss_accept_sec_context(minor_status,
 661						      context_handle,
 662						      acceptor_cred_handle,
 663						      &ibuf,
 664						      input_chan_bindings,
 665						      src_name,
 666						      mech_type,
 667						      &obuf,
 668						      ret_flags,
 669						      time_rec,
 670						      delegated_cred_handle);
 671		if (GSS_ERROR(major_status)) {
 672			send_reject(&minor_status2, output_token);
 673			return (major_status);
 674		}
 675		ot = &obuf;
 676	}
 677	ret = send_accept(&minor_status2, output_token, ot, pref);
 678	if (ot != NULL && ot->length != 0U)
 679		gss_release_buffer(&minor_status2, ot);
 680
 681	return (ret);
 682}
 683
 684/* decapsulate.c */
 685
 686static OM_uint32
 687gssapi_verify_mech_header(u_char ** str,
 688			  size_t total_len,
 689			  const gss_OID mech)
 690{
 691	size_t len, len_len, mech_len, foo;
 692	int e;
 693	u_char *p = *str;
 694
 695	if (total_len < 1U)
 696		return (GSS_S_DEFECTIVE_TOKEN);
 697	if (*p++ != 0x60)
 698		return (GSS_S_DEFECTIVE_TOKEN);
 699	e = der_get_length(p, total_len - 1, &len, &len_len);
 700	if (e || 1 + len_len + len != total_len)
 701		return (GSS_S_DEFECTIVE_TOKEN);
 702	p += len_len;
 703	if (*p++ != 0x06)
 704		return (GSS_S_DEFECTIVE_TOKEN);
 705	e = der_get_length(p, total_len - 1 - len_len - 1,
 706			   &mech_len, &foo);
 707	if (e)
 708		return (GSS_S_DEFECTIVE_TOKEN);
 709	p += foo;
 710	if (mech_len != mech->length)
 711		return (GSS_S_BAD_MECH);
 712	if (memcmp(p, mech->elements, mech->length) != 0)
 713		return (GSS_S_BAD_MECH);
 714	p += mech_len;
 715	*str = p;
 716	return (GSS_S_COMPLETE);
 717}
 718
 719/*
 720 * Remove the GSS-API wrapping from `in_token' giving `buf and buf_size' Does
 721 * not copy data, so just free `in_token'.
 722 */
 723
 724static OM_uint32
 725gssapi_spnego_decapsulate(OM_uint32 *minor_status,
 726			  gss_buffer_t input_token_buffer,
 727			  unsigned char **buf,
 728			  size_t *buf_len,
 729			  const gss_OID mech)
 730{
 731	u_char *p;
 732	OM_uint32 ret;
 733
 734	p = input_token_buffer->value;
 735	ret = gssapi_verify_mech_header(&p,
 736					input_token_buffer->length,
 737					mech);
 738	if (ret) {
 739		*minor_status = ret;
 740		return (GSS_S_FAILURE);
 741	}
 742	*buf_len = input_token_buffer->length -
 743		(p - (u_char *) input_token_buffer->value);
 744	*buf = p;
 745	return (GSS_S_COMPLETE);
 746}
 747
 748/* der_free.c */
 749
 750static void
 751free_octet_string(octet_string *k)
 752{
 753	free(k->data);
 754	k->data = NULL;
 755}
 756
 757static void
 758free_oid(oid *k)
 759{
 760	free(k->components);
 761	k->components = NULL;
 762}
 763
 764/* der_get.c */
 765
 766/*
 767 * All decoding functions take a pointer `p' to first position in which to
 768 * read, from the left, `len' which means the maximum number of characters we
 769 * are able to read, `ret' were the value will be returned and `size' where
 770 * the number of used bytes is stored. Either 0 or an error code is returned.
 771 */
 772
 773static int
 774der_get_unsigned(const unsigned char *p, size_t len,
 775		 unsigned *ret, size_t *size)
 776{
 777	unsigned val = 0;
 778	size_t oldlen = len;
 779
 780	while (len--)
 781		val = val * 256 + *p++;
 782	*ret = val;
 783	if (size)
 784		*size = oldlen;
 785	return (0);
 786}
 787
 788static int
 789der_get_int(const unsigned char *p, size_t len,
 790	    int *ret, size_t *size)
 791{
 792	int val = 0;
 793	size_t oldlen = len;
 794
 795	if (len > 0U) {
 796		val = (signed char)*p++;
 797		while (--len)
 798			val = val * 256 + *p++;
 799	}
 800	*ret = val;
 801	if (size)
 802		*size = oldlen;
 803	return (0);
 804}
 805
 806static int
 807der_get_length(const unsigned char *p, size_t len,
 808	       size_t *val, size_t *size)
 809{
 810	size_t v;
 811
 812	if (len <= 0U)
 813		return (ASN1_OVERRUN);
 814	--len;
 815	v = *p++;
 816	if (v < 128U) {
 817		*val = v;
 818		if (size)
 819			*size = 1;
 820	} else {
 821		int e;
 822		size_t l;
 823		unsigned tmp;
 824
 825		if (v == 0x80U) {
 826			*val = ASN1_INDEFINITE;
 827			if (size)
 828				*size = 1;
 829			return (0);
 830		}
 831		v &= 0x7F;
 832		if (len < v)
 833			return (ASN1_OVERRUN);
 834		e = der_get_unsigned(p, v, &tmp, &l);
 835		if (e)
 836			return (e);
 837		*val = tmp;
 838		if (size)
 839			*size = l + 1;
 840	}
 841	return (0);
 842}
 843
 844static int
 845der_get_octet_string(const unsigned char *p, size_t len,
 846		     octet_string *data, size_t *size)
 847{
 848	data->length = len;
 849	data->data = malloc(len);
 850	if (data->data == NULL && data->length != 0U)
 851		return (ENOMEM);
 852	memcpy(data->data, p, len);
 853	if (size)
 854		*size = len;
 855	return (0);
 856}
 857
 858static int
 859der_get_oid(const unsigned char *p, size_t len,
 860	    oid *data, size_t *size)
 861{
 862	int n;
 863	size_t oldlen = len;
 864
 865	if (len < 1U)
 866		return (ASN1_OVERRUN);
 867
 868	data->components = malloc(len * sizeof(*data->components));
 869	if (data->components == NULL && len != 0U)
 870		return (ENOMEM);
 871	data->components[0] = (*p) / 40;
 872	data->components[1] = (*p) % 40;
 873	--len;
 874	++p;
 875	for (n = 2; len > 0U; ++n) {
 876		unsigned u = 0;
 877
 878		do {
 879			--len;
 880			u = u * 128 + (*p++ % 128);
 881		} while (len > 0U && p[-1] & 0x80);
 882		data->components[n] = u;
 883	}
 884	if (p[-1] & 0x80) {
 885		free_oid(data);
 886		return (ASN1_OVERRUN);
 887	}
 888	data->length = n;
 889	if (size)
 890		*size = oldlen;
 891	return (0);
 892}
 893
 894static int
 895der_get_tag(const unsigned char *p, size_t len,
 896	    Der_class *class, Der_type *type,
 897	    int *tag, size_t *size)
 898{
 899	if (len < 1U)
 900		return (ASN1_OVERRUN);
 901	*class = (Der_class) (((*p) >> 6) & 0x03);
 902	*type = (Der_type) (((*p) >> 5) & 0x01);
 903	*tag = (*p) & 0x1F;
 904	if (size)
 905		*size = 1;
 906	return (0);
 907}
 908
 909static int
 910der_match_tag(const unsigned char *p, size_t len,
 911	      Der_class class, Der_type type,
 912	      int tag, size_t *size)
 913{
 914	size_t l;
 915	Der_class thisclass;
 916	Der_type thistype;
 917	int thistag;
 918	int e;
 919
 920	e = der_get_tag(p, len, &thisclass, &thistype, &thistag, &l);
 921	if (e)
 922		return (e);
 923	if (class != thisclass || type != thistype)
 924		return (ASN1_BAD_ID);
 925	if (tag > thistag)
 926		return (ASN1_MISPLACED_FIELD);
 927	if (tag < thistag)
 928		return (ASN1_MISSING_FIELD);
 929	if (size)
 930		*size = l;
 931	return (0);
 932}
 933
 934static int
 935der_match_tag_and_length(const unsigned char *p, size_t len,
 936			 Der_class class, Der_type type, int tag,
 937			 size_t *length_ret, size_t *size)
 938{
 939	size_t l, ret = 0;
 940	int e;
 941
 942	e = der_match_tag(p, len, class, type, tag, &l);
 943	if (e)
 944		return (e);
 945	p += l;
 946	len -= l;
 947	ret += l;
 948	e = der_get_length(p, len, length_ret, &l);
 949	if (e)
 950		return (e);
 951	/* p += l; */
 952	len -= l;
 953	POST(len);
 954	ret += l;
 955	if (size)
 956		*size = ret;
 957	return (0);
 958}
 959
 960static int
 961decode_enumerated(const unsigned char *p, size_t len, void *num, size_t *size)
 962{
 963	size_t ret = 0;
 964	size_t l, reallen;
 965	int e;
 966
 967	e = der_match_tag(p, len, ASN1_C_UNIV, PRIM, UT_Enumerated, &l);
 968	if (e)
 969		return (e);
 970	p += l;
 971	len -= l;
 972	ret += l;
 973	e = der_get_length(p, len, &reallen, &l);
 974	if (e)
 975		return (e);
 976	p += l;
 977	len -= l;
 978	ret += l;
 979	e = der_get_int(p, reallen, num, &l);
 980	if (e)
 981		return (e);
 982	p += l;
 983	len -= l;
 984	POST(p); POST(len);
 985	ret += l;
 986	if (size)
 987		*size = ret;
 988	return (0);
 989}
 990
 991static int
 992decode_octet_string(const unsigned char *p, size_t len,
 993		    octet_string *k, size_t *size)
 994{
 995	size_t ret = 0;
 996	size_t l;
 997	int e;
 998	size_t slen;
 999
1000	e = der_match_tag(p, len, ASN1_C_UNIV, PRIM, UT_OctetString, &l);
1001	if (e)
1002		return (e);
1003	p += l;
1004	len -= l;
1005	ret += l;
1006
1007	e = der_get_length(p, len, &slen, &l);
1008	if (e)
1009		return (e);
1010	p += l;
1011	len -= l;
1012	ret += l;
1013	if (len < slen)
1014		return (ASN1_OVERRUN);
1015
1016	e = der_get_octet_string(p, slen, k, &l);
1017	if (e)
1018		return (e);
1019	p += l;
1020	len -= l;
1021	POST(p); POST(len);
1022	ret += l;
1023	if (size)
1024		*size = ret;
1025	return (0);
1026}
1027
1028static int
1029decode_oid(const unsigned char *p, size_t len,
1030	   oid *k, size_t *size)
1031{
1032	size_t ret = 0;
1033	size_t l;
1034	int e;
1035	size_t slen;
1036
1037	e = der_match_tag(p, len, ASN1_C_UNIV, PRIM, UT_OID, &l);
1038	if (e)
1039		return (e);
1040	p += l;
1041	len -= l;
1042	ret += l;
1043
1044	e = der_get_length(p, len, &slen, &l);
1045	if (e)
1046		return (e);
1047	p += l;
1048	len -= l;
1049	ret += l;
1050	if (len < slen)
1051		return (ASN1_OVERRUN);
1052
1053	e = der_get_oid(p, slen, k, &l);
1054	if (e)
1055		return (e);
1056	p += l;
1057	len -= l;
1058	POST(p); POST(len);
1059	ret += l;
1060	if (size)
1061		*size = ret;
1062	return (0);
1063}
1064
1065static int
1066fix_dce(size_t reallen, size_t *len)
1067{
1068	if (reallen == ASN1_INDEFINITE)
1069		return (1);
1070	if (*len < reallen)
1071		return (-1);
1072	*len = reallen;
1073	return (0);
1074}
1075
1076/* der_length.c */
1077
1078static size_t
1079len_unsigned(unsigned val)
1080{
1081	size_t ret = 0;
1082
1083	do {
1084		++ret;
1085		val /= 256;
1086	} while (val);
1087	return (ret);
1088}
1089
1090static size_t
1091length_len(size_t len)
1092{
1093	if (len < 128U)
1094		return (1);
1095	else
1096		return (len_unsigned(len) + 1);
1097}
1098
1099
1100/* der_put.c */
1101
1102/*
1103 * All encoding functions take a pointer `p' to first position in which to
1104 * write, from the right, `len' which means the maximum number of characters
1105 * we are able to write.  The function returns the number of characters
1106 * written in `size' (if non-NULL). The return value is 0 or an error.
1107 */
1108
1109static int
1110der_put_unsigned(unsigned char *p, size_t len, unsigned val, size_t *size)
1111{
1112	unsigned char *base = p;
1113
1114	if (val) {
1115		while (len > 0U && val) {
1116			*p-- = val % 256;
1117			val /= 256;
1118			--len;
1119		}
1120		if (val != 0)
1121			return (ASN1_OVERFLOW);
1122		else {
1123			*size = base - p;
1124			return (0);
1125		}
1126	} else if (len < 1U)
1127		return (ASN1_OVERFLOW);
1128	else {
1129		*p = 0;
1130		*size = 1;
1131		return (0);
1132	}
1133}
1134
1135static int
1136der_put_int(unsigned char *p, size_t len, int val, size_t *size)
1137{
1138	unsigned char *base = p;
1139
1140	if (val >= 0) {
1141		do {
1142			if (len < 1U)
1143				return (ASN1_OVERFLOW);
1144			*p-- = val % 256;
1145			len--;
1146			val /= 256;
1147		} while (val);
1148		if (p[1] >= 128) {
1149			if (len < 1U)
1150				return (ASN1_OVERFLOW);
1151			*p-- = 0;
1152			len--;
1153		}
1154	} else {
1155		val = ~val;
1156		do {
1157			if (len < 1U)
1158				return (ASN1_OVERFLOW);
1159			*p-- = ~(val % 256);
1160			len--;
1161			val /= 256;
1162		} while (val);
1163		if (p[1] < 128) {
1164			if (len < 1U)
1165				return (ASN1_OVERFLOW);
1166			*p-- = 0xff;
1167			len--;
1168		}
1169	}
1170	*size = base - p;
1171	return (0);
1172}
1173
1174static int
1175der_put_length(unsigned char *p, size_t len, size_t val, size_t *size)
1176{
1177	if (len < 1U)
1178		return (ASN1_OVERFLOW);
1179	if (val < 128U) {
1180		*p = val;
1181		*size = 1;
1182		return (0);
1183	} else {
1184		size_t l;
1185		int e;
1186
1187		e = der_put_unsigned(p, len - 1, val, &l);
1188		if (e)
1189			return (e);
1190		p -= l;
1191		*p = 0x80 | l;
1192		*size = l + 1;
1193		return (0);
1194	}
1195}
1196
1197static int
1198der_put_octet_string(unsigned char *p, size_t len,
1199		     const octet_string *data, size_t *size)
1200{
1201	if (len < data->length)
1202		return (ASN1_OVERFLOW);
1203	p -= data->length;
1204	len -= data->length;
1205	POST(len);
1206	memcpy(p + 1, data->data, data->length);
1207	*size = data->length;
1208	return (0);
1209}
1210
1211static int
1212der_put_oid(unsigned char *p, size_t len,
1213	    const oid *data, size_t *size)
1214{
1215	unsigned char *base = p;
1216	int n;
1217
1218	for (n = data->length - 1; n >= 2; --n) {
1219		unsigned	u = data->components[n];
1220
1221		if (len < 1U)
1222			return (ASN1_OVERFLOW);
1223		*p-- = u % 128;
1224		u /= 128;
1225		--len;
1226		while (u > 0) {
1227			if (len < 1U)
1228				return (ASN1_OVERFLOW);
1229			*p-- = 128 + u % 128;
1230			u /= 128;
1231			--len;
1232		}
1233	}
1234	if (len < 1U)
1235		return (ASN1_OVERFLOW);
1236	*p-- = 40 * data->components[0] + data->components[1];
1237	*size = base - p;
1238	return (0);
1239}
1240
1241static int
1242der_put_tag(unsigned char *p, size_t len, Der_class class, Der_type type,
1243	    int tag, size_t *size)
1244{
1245	if (len < 1U)
1246		return (ASN1_OVERFLOW);
1247	*p = (class << 6) | (type << 5) | tag;	/* XXX */
1248	*size = 1;
1249	return (0);
1250}
1251
1252static int
1253der_put_length_and_tag(unsigned char *p, size_t len, size_t len_val,
1254		       Der_class class, Der_type type, int tag, size_t *size)
1255{
1256	size_t ret = 0;
1257	size_t l;
1258	int e;
1259
1260	e = der_put_length(p, len, len_val, &l);
1261	if (e)
1262		return (e);
1263	p -= l;
1264	len -= l;
1265	ret += l;
1266	e = der_put_tag(p, len, class, type, tag, &l);
1267	if (e)
1268		return (e);
1269	p -= l;
1270	len -= l;
1271	POST(p); POST(len);
1272	ret += l;
1273	*size = ret;
1274	return (0);
1275}
1276
1277static int
1278encode_enumerated(unsigned char *p, size_t len, const void *data, size_t *size)
1279{
1280	unsigned num = *(const unsigned *)data;
1281	size_t ret = 0;
1282	size_t l;
1283	int e;
1284
1285	e = der_put_int(p, len, num, &l);
1286	if (e)
1287		return (e);
1288	p -= l;
1289	len -= l;
1290	ret += l;
1291	e = der_put_length_and_tag(p, len, l, ASN1_C_UNIV, PRIM, UT_Enumerated, &l);
1292	if (e)
1293		return (e);
1294	p -= l;
1295	len -= l;
1296	POST(p); POST(len);
1297	ret += l;
1298	*size = ret;
1299	return (0);
1300}
1301
1302static int
1303encode_octet_string(unsigned char *p, size_t len,
1304		    const octet_string *k, size_t *size)
1305{
1306	size_t ret = 0;
1307	size_t l;
1308	int e;
1309
1310	e = der_put_octet_string(p, len, k, &l);
1311	if (e)
1312		return (e);
1313	p -= l;
1314	len -= l;
1315	ret += l;
1316	e = der_put_length_and_tag(p, len, l, ASN1_C_UNIV, PRIM, UT_OctetString, &l);
1317	if (e)
1318		return (e);
1319	p -= l;
1320	len -= l;
1321	POST(p); POST(len);
1322	ret += l;
1323	*size = ret;
1324	return (0);
1325}
1326
1327static int
1328encode_oid(unsigned char *p, size_t len,
1329	   const oid *k, size_t *size)
1330{
1331	size_t ret = 0;
1332	size_t l;
1333	int e;
1334
1335	e = der_put_oid(p, len, k, &l);
1336	if (e)
1337		return (e);
1338	p -= l;
1339	len -= l;
1340	ret += l;
1341	e = der_put_length_and_tag(p, len, l, ASN1_C_UNIV, PRIM, UT_OID, &l);
1342	if (e)
1343		return (e);
1344	p -= l;
1345	len -= l;
1346	POST(p); POST(len);
1347	ret += l;
1348	*size = ret;
1349	return (0);
1350}
1351
1352
1353/* encapsulate.c */
1354
1355static void
1356gssapi_encap_length(size_t data_len,
1357		    size_t *len,
1358		    size_t *total_len,
1359		    const gss_OID mech)
1360{
1361	size_t len_len;
1362
1363	*len = 1 + 1 + mech->length + data_len;
1364
1365	len_len = length_len(*len);
1366
1367	*total_len = 1 + len_len + *len;
1368}
1369
1370static u_char *
1371gssapi_mech_make_header(u_char *p,
1372			size_t len,
1373			const gss_OID mech)
1374{
1375	int e;
1376	size_t len_len, foo;
1377
1378	*p++ = 0x60;
1379	len_len = length_len(len);
1380	e = der_put_length(p + len_len - 1, len_len, len, &foo);
1381	if (e || foo != len_len)
1382		return (NULL);
1383	p += len_len;
1384	*p++ = 0x06;
1385	*p++ = mech->length;
1386	memcpy(p, mech->elements, mech->length);
1387	p += mech->length;
1388	return (p);
1389}
1390
1391/*
1392 * Give it a krb5_data and it will encapsulate with extra GSS-API wrappings.
1393 */
1394
1395static OM_uint32
1396gssapi_spnego_encapsulate(OM_uint32 * minor_status,
1397			  unsigned char *buf,
1398			  size_t buf_size,
1399			  gss_buffer_t output_token,
1400			  const gss_OID mech)
1401{
1402	size_t len, outer_len;
1403	u_char *p;
1404
1405	gssapi_encap_length(buf_size, &len, &outer_len, mech);
1406
1407	output_token->length = outer_len;
1408	output_token->value = malloc(outer_len);
1409	if (output_token->value == NULL) {
1410		*minor_status = ENOMEM;
1411		return (GSS_S_FAILURE);
1412	}
1413	p = gssapi_mech_make_header(output_token->value, len, mech);
1414	if (p == NULL) {
1415		if (output_token->length != 0U)
1416			gss_release_buffer(minor_status, output_token);
1417		return (GSS_S_FAILURE);
1418	}
1419	memcpy(p, buf, buf_size);
1420	return (GSS_S_COMPLETE);
1421}
1422
1423/* init_sec_context.c */
1424/*
1425 * SPNEGO wrapper for Kerberos5 GSS-API kouril@ics.muni.cz, 2003 (mostly
1426 * based on Heimdal code)
1427 */
1428
1429static int
1430add_mech(MechTypeList * mech_list, gss_OID mech)
1431{
1432	MechType *tmp;
1433	int ret;
1434
1435	tmp = realloc(mech_list->val, (mech_list->len + 1) * sizeof(*tmp));
1436	if (tmp == NULL)
1437		return (ENOMEM);
1438	mech_list->val = tmp;
1439
1440	ret = der_get_oid(mech->elements, mech->length,
1441			  &mech_list->val[mech_list->len], NULL);
1442	if (ret)
1443		return (ret);
1444
1445	mech_list->len++;
1446	return (0);
1447}
1448
1449/*
1450 * return the length of the mechanism in token or -1
1451 * (which implies that the token was bad - GSS_S_DEFECTIVE_TOKEN
1452 */
1453
1454static ssize_t
1455gssapi_krb5_get_mech(const u_char *ptr,
1456		     size_t total_len,
1457		     const u_char **mech_ret)
1458{
1459	size_t len, len_len, mech_len, foo;
1460	const u_char *p = ptr;
1461	int e;
1462
1463	if (total_len < 1U)
1464		return (-1);
1465	if (*p++ != 0x60)
1466		return (-1);
1467	e = der_get_length (p, total_len - 1, &len, &len_len);
1468	if (e || 1 + len_len + len != total_len)
1469		return (-1);
1470	p += len_len;
1471	if (*p++ != 0x06)
1472		return (-1);
1473	e = der_get_length (p, total_len - 1 - len_len - 1,
1474			    &mech_len, &foo);
1475	if (e)
1476		return (-1);
1477	p += foo;
1478	*mech_ret = p;
1479	return (mech_len);
1480}
1481
1482static OM_uint32
1483spnego_initial(OM_uint32 *minor_status,
1484	       const gss_cred_id_t initiator_cred_handle,
1485	       gss_ctx_id_t *context_handle,
1486	       const gss_name_t target_name,
1487	       const gss_OID mech_type,
1488	       OM_uint32 req_flags,
1489	       OM_uint32 time_req,
1490	       const gss_channel_bindings_t input_chan_bindings,
1491	       const gss_buffer_t input_token,
1492	       gss_OID *actual_mech_type,
1493	       gss_buffer_t output_token,
1494	       OM_uint32 *ret_flags,
1495	       OM_uint32 *time_rec)
1496{
1497	NegTokenInit token_init;
1498	OM_uint32 major_status, minor_status2;
1499	gss_buffer_desc	krb5_output_token = GSS_C_EMPTY_BUFFER;
1500	unsigned char *buf = NULL;
1501	size_t buf_size;
1502	size_t len;
1503	int ret;
1504
1505	(void)mech_type;
1506
1507	memset(&token_init, 0, sizeof(token_init));
1508
1509	ret = add_mech(&token_init.mechTypes, GSS_KRB5_MECH);
1510	if (ret) {
1511		*minor_status = ret;
1512		ret = GSS_S_FAILURE;
1513		goto end;
1514	}
1515
1516	major_status = gss_init_sec_context(minor_status,
1517					    initiator_cred_handle,
1518					    context_handle,
1519					    target_name,
1520					    GSS_KRB5_MECH,
1521					    req_flags,
1522					    time_req,
1523					    input_chan_bindings,
1524					    input_token,
1525					    actual_mech_type,
1526					    &krb5_output_token,
1527					    ret_flags,
1528					    time_rec);
1529	if (GSS_ERROR(major_status)) {
1530		ret = major_status;
1531		goto end;
1532	}
1533	if (krb5_output_token.length > 0U) {
1534		token_init.mechToken = malloc(sizeof(*token_init.mechToken));
1535		if (token_init.mechToken == NULL) {
1536			*minor_status = ENOMEM;
1537			ret = GSS_S_FAILURE;
1538			goto end;
1539		}
1540		token_init.mechToken->data = krb5_output_token.value;
1541		token_init.mechToken->length = krb5_output_token.length;
1542	}
1543	/*
1544	 * The MS implementation of SPNEGO seems to not like the mechListMIC
1545	 * field, so we omit it (it's optional anyway)
1546	 */
1547
1548	buf_size = 1024;
1549	buf = malloc(buf_size);
1550
1551	do {
1552		ret = encode_NegTokenInit(buf + buf_size - 1,
1553					  buf_size,
1554					  &token_init, &len);
1555		if (ret == 0) {
1556			size_t tmp;
1557
1558			ret = der_put_length_and_tag(buf + buf_size - len - 1,
1559						     buf_size - len,
1560						     len,
1561						     ASN1_C_CONTEXT,
1562						     CONS,
1563						     0,
1564						     &tmp);
1565			if (ret == 0)
1566				len += tmp;
1567		}
1568		if (ret) {
1569			if (ret == ASN1_OVERFLOW) {
1570				u_char *tmp;
1571
1572				buf_size *= 2;
1573				tmp = realloc(buf, buf_size);
1574				if (tmp == NULL) {
1575					*minor_status = ENOMEM;
1576					ret = GSS_S_FAILURE;
1577					goto end;
1578				}
1579				buf = tmp;
1580			} else {
1581				*minor_status = ret;
1582				ret = GSS_S_FAILURE;
1583				goto end;
1584			}
1585		}
1586	} while (ret == ASN1_OVERFLOW);
1587
1588	ret = gssapi_spnego_encapsulate(minor_status,
1589					buf + buf_size - len, len,
1590					output_token, GSS_SPNEGO_MECH);
1591	if (ret == GSS_S_COMPLETE)
1592		ret = major_status;
1593
1594end:
1595	if (token_init.mechToken != NULL) {
1596		free(token_init.mechToken);
1597		token_init.mechToken = NULL;
1598	}
1599	free_NegTokenInit(&token_init);
1600	if (krb5_output_token.length != 0U)
1601		gss_release_buffer(&minor_status2, &krb5_output_token);
1602	if (buf)
1603		free(buf);
1604
1605	return (ret);
1606}
1607
1608static OM_uint32
1609spnego_reply(OM_uint32 *minor_status,
1610	     const gss_cred_id_t initiator_cred_handle,
1611	     gss_ctx_id_t *context_handle,
1612	     const gss_name_t target_name,
1613	     const gss_OID mech_type,
1614	     OM_uint32 req_flags,
1615	     OM_uint32 time_req,
1616	     const gss_channel_bindings_t input_chan_bindings,
1617	     const gss_buffer_t input_token,
1618	     gss_OID *actual_mech_type,
1619	     gss_buffer_t output_token,
1620	     OM_uint32 *ret_flags,
1621	     OM_uint32 *time_rec)
1622{
1623	OM_uint32 ret;
1624	NegTokenResp resp;
1625	unsigned char *buf;
1626	size_t buf_size;
1627	u_char oidbuf[17];
1628	size_t oidlen;
1629	gss_buffer_desc sub_token;
1630	ssize_t mech_len;
1631	const u_char *p;
1632	size_t len, taglen;
1633
1634	(void)mech_type;
1635
1636	output_token->length = 0;
1637	output_token->value  = NULL;
1638
1639	/*
1640	 * SPNEGO doesn't include gss wrapping on SubsequentContextToken
1641	 * like the Kerberos 5 mech does. But lets check for it anyway.
1642	 */
1643
1644	mech_len = gssapi_krb5_get_mech(input_token->value,
1645					input_token->length,
1646					&p);
1647
1648	if (mech_len < 0) {
1649		buf = input_token->value;
1650		buf_size = input_token->length;
1651	} else if ((size_t)mech_len == GSS_KRB5_MECH->length &&
1652		   memcmp(GSS_KRB5_MECH->elements, p, mech_len) == 0)
1653		return (gss_init_sec_context(minor_status,
1654					     initiator_cred_handle,
1655					     context_handle,
1656					     target_name,
1657					     GSS_KRB5_MECH,
1658					     req_flags,
1659					     time_req,
1660					     input_chan_bindings,
1661					     input_token,
1662					     actual_mech_type,
1663					     output_token,
1664					     ret_flags,
1665					     time_rec));
1666	else if ((size_t)mech_len == GSS_SPNEGO_MECH->length &&
1667		 memcmp(GSS_SPNEGO_MECH->elements, p, mech_len) == 0) {
1668		ret = gssapi_spnego_decapsulate(minor_status,
1669						input_token,
1670						&buf,
1671						&buf_size,
1672						GSS_SPNEGO_MECH);
1673		if (ret)
1674			return (ret);
1675	} else
1676		return (GSS_S_BAD_MECH);
1677
1678	ret = der_match_tag_and_length(buf, buf_size,
1679				       ASN1_C_CONTEXT, CONS, 1, &len, &taglen);
1680	if (ret)
1681		return (ret);
1682
1683	if(len > buf_size - taglen)
1684		return (ASN1_OVERRUN);
1685
1686	ret = decode_NegTokenResp(buf + taglen, len, &resp, NULL);
1687	if (ret) {
1688		*minor_status = ENOMEM;
1689		return (GSS_S_FAILURE);
1690	}
1691
1692	if (resp.negState == NULL ||
1693	    *(resp.negState) == reject ||
1694	    resp.supportedMech == NULL) {
1695		free_NegTokenResp(&resp);
1696		return (GSS_S_BAD_MECH);
1697	}
1698
1699	ret = der_put_oid(oidbuf + sizeof(oidbuf) - 1,
1700			  sizeof(oidbuf),
1701			  resp.supportedMech,
1702			  &oidlen);
1703	if (ret || oidlen != GSS_KRB5_MECH->length ||
1704	    memcmp(oidbuf + sizeof(oidbuf) - oidlen,
1705		   GSS_KRB5_MECH->elements,
1706		   oidlen) != 0) {
1707		free_NegTokenResp(&resp);
1708		return GSS_S_BAD_MECH;
1709	}
1710
1711	if (resp.responseToken != NULL) {
1712		sub_token.length = resp.responseToken->length;
1713		sub_token.value  = resp.responseToken->data;
1714	} else {
1715		sub_token.length = 0;
1716		sub_token.value  = NULL;
1717	}
1718
1719	ret = gss_init_sec_context(minor_status,
1720				   initiator_cred_handle,
1721				   context_handle,
1722				   target_name,
1723				   GSS_KRB5_MECH,
1724				   req_flags,
1725				   time_req,
1726				   input_chan_bindings,
1727				   &sub_token,
1728				   actual_mech_type,
1729				   output_token,
1730				   ret_flags,
1731				   time_rec);
1732	if (ret) {
1733		free_NegTokenResp(&resp);
1734		return (ret);
1735	}
1736
1737	/*
1738	 * XXXSRA I don't think this limited implementation ever needs
1739	 * to check the MIC -- our preferred mechanism (Kerberos)
1740	 * authenticates its own messages and is the only mechanism
1741	 * we'll accept, so if the mechanism negotiation completes
1742	 * successfully, we don't need the MIC.  See RFC 4178.
1743	 */
1744
1745	free_NegTokenResp(&resp);
1746	return (ret);
1747}
1748
1749
1750
1751OM_uint32
1752gss_init_sec_context_spnego(OM_uint32 *minor_status,
1753			    const gss_cred_id_t initiator_cred_handle,
1754			    gss_ctx_id_t *context_handle,
1755			    const gss_name_t target_name,
1756			    const gss_OID mech_type,
1757			    OM_uint32 req_flags,
1758			    OM_uint32 time_req,
1759			    const gss_channel_bindings_t input_chan_bindings,
1760			    const gss_buffer_t input_token,
1761			    gss_OID *actual_mech_type,
1762			    gss_buffer_t output_token,
1763			    OM_uint32 *ret_flags,
1764			    OM_uint32 *time_rec)
1765{
1766	/* Dirty trick to suppress compiler warnings */
1767
1768	/* Figure out whether we're starting over or processing a reply */
1769
1770	if (input_token == GSS_C_NO_BUFFER || input_token->length == 0U)
1771		return (spnego_initial(minor_status,
1772				       initiator_cred_handle,
1773				       context_handle,
1774				       target_name,
1775				       mech_type,
1776				       req_flags,
1777				       time_req,
1778				       input_chan_bindings,
1779				       input_token,
1780				       actual_mech_type,
1781				       output_token,
1782				       ret_flags,
1783				       time_rec));
1784	else
1785		return (spnego_reply(minor_status,
1786				     initiator_cred_handle,
1787				     context_handle,
1788				     target_name,
1789				     mech_type,
1790				     req_flags,
1791				     time_req,
1792				     input_chan_bindings,
1793				     input_token,
1794				     actual_mech_type,
1795				     output_token,
1796				     ret_flags,
1797				     time_rec));
1798}
1799
1800#endif /* GSSAPI */