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