]> CyberLeo.Net >> Repos - FreeBSD/releng/9.3.git/blob - contrib/bind9/lib/dns/spnego.c
Fix BIND remote denial of service vulnerability. [SA-15:27]
[FreeBSD/releng/9.3.git] / contrib / bind9 / lib / dns / spnego.c
1 /*
2  * Copyright (C) 2006-2014  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 */
177 typedef 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
195 typedef struct octet_string {
196         size_t length;
197         void *data;
198 } octet_string;
199
200 typedef char *general_string;
201
202 typedef char *utf8_string;
203
204 typedef struct oid {
205         size_t length;
206         unsigned *components;
207 } oid;
208
209 /* der.h */
210
211 typedef enum {
212         ASN1_C_UNIV = 0, ASN1_C_APPL = 1,
213         ASN1_C_CONTEXT = 2, ASN1_C_PRIVATE = 3
214 } Der_class;
215
216 typedef enum {
217         PRIM = 0, CONS = 1
218 } Der_type;
219
220 /* Universal tags */
221
222 enum {
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
242 static int
243 der_get_length(const unsigned char *p, size_t len,
244                size_t * val, size_t * size);
245
246 static int
247 der_get_octet_string(const unsigned char *p, size_t len,
248                      octet_string * data, size_t * size);
249 static int
250 der_get_oid(const unsigned char *p, size_t len,
251             oid * data, size_t * size);
252 static int
253 der_get_tag(const unsigned char *p, size_t len,
254             Der_class * class, Der_type * type,
255             int *tag, size_t * size);
256
257 static int
258 der_match_tag(const unsigned char *p, size_t len,
259               Der_class class, Der_type type,
260               int tag, size_t * size);
261 static int
262 der_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
266 static int
267 decode_oid(const unsigned char *p, size_t len,
268            oid * k, size_t * size);
269
270 static int
271 decode_enumerated(const unsigned char *p, size_t len, void *num, size_t *size);
272
273 static int
274 decode_octet_string(const unsigned char *, size_t, octet_string *, size_t *);
275
276 static int
277 der_put_int(unsigned char *p, size_t len, int val, size_t *);
278
279 static int
280 der_put_length(unsigned char *p, size_t len, size_t val, size_t *);
281
282 static int
283 der_put_octet_string(unsigned char *p, size_t len,
284                      const octet_string * data, size_t *);
285 static int
286 der_put_oid(unsigned char *p, size_t len,
287             const oid * data, size_t * size);
288 static int
289 der_put_tag(unsigned char *p, size_t len, Der_class class, Der_type type,
290             int tag, size_t *);
291 static int
292 der_put_length_and_tag(unsigned char *, size_t, size_t,
293                        Der_class, Der_type, int, size_t *);
294
295 static int
296 encode_enumerated(unsigned char *p, size_t len, const void *data, size_t *);
297
298 static int
299 encode_octet_string(unsigned char *p, size_t len,
300                     const octet_string * k, size_t *);
301 static int
302 encode_oid(unsigned char *p, size_t len,
303            const oid * k, size_t *);
304
305 static void
306 free_octet_string(octet_string * k);
307
308 static void
309 free_oid  (oid * k);
310
311 static size_t
312 length_len(size_t len);
313
314 static int
315 fix_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
323 static unsigned char gss_krb5_mech_oid_bytes[] = {
324         0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02
325 };
326
327 static gss_OID_desc gss_krb5_mech_oid_desc = {
328         sizeof(gss_krb5_mech_oid_bytes),
329         gss_krb5_mech_oid_bytes
330 };
331
332 static gss_OID GSS_KRB5_MECH = &gss_krb5_mech_oid_desc;
333
334 static unsigned char gss_mskrb5_mech_oid_bytes[] = {
335         0x2a, 0x86, 0x48, 0x82, 0xf7, 0x12, 0x01, 0x02, 0x02
336 };
337
338 static gss_OID_desc gss_mskrb5_mech_oid_desc = {
339         sizeof(gss_mskrb5_mech_oid_bytes),
340         gss_mskrb5_mech_oid_bytes
341 };
342
343 static gss_OID GSS_MSKRB5_MECH = &gss_mskrb5_mech_oid_desc;
344
345 static unsigned char gss_spnego_mech_oid_bytes[] = {
346         0x2b, 0x06, 0x01, 0x05, 0x05, 0x02
347 };
348
349 static gss_OID_desc gss_spnego_mech_oid_desc = {
350         sizeof(gss_spnego_mech_oid_bytes),
351         gss_spnego_mech_oid_bytes
352 };
353
354 static gss_OID GSS_SPNEGO_MECH = &gss_spnego_mech_oid_desc;
355
356 /* spnegokrb5_locl.h */
357
358 static OM_uint32
359 gssapi_spnego_encapsulate(OM_uint32 *,
360                           unsigned char *,
361                           size_t,
362                           gss_buffer_t,
363                           const gss_OID);
364
365 static OM_uint32
366 gssapi_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
374 static int
375 cmp_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
407 static OM_uint32
408 code_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         memmove(*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
474 static OM_uint32
475 send_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
502 static OM_uint32
503 send_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
559 OM_uint32
560 gss_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                         free_NegTokenInit(&init_token);
635                         return (GSS_S_DEFECTIVE_TOKEN);
636                 }
637                 if (mech_len == GSS_KRB5_MECH->length &&
638                     memcmp(GSS_KRB5_MECH->elements,
639                            mechbuf + sizeof(mechbuf) - mech_len,
640                            mech_len) == 0) {
641                         found = 1;
642                         break;
643                 }
644                 if (mech_len == GSS_MSKRB5_MECH->length &&
645                     memcmp(GSS_MSKRB5_MECH->elements,
646                            mechbuf + sizeof(mechbuf) - mech_len,
647                            mech_len) == 0) {
648                         found = 1;
649                         if (i == 0)
650                                 pref = GSS_MSKRB5_MECH;
651                         break;
652                 }
653         }
654
655         if (!found) {
656                 free_NegTokenInit(&init_token);
657                 return (send_reject(minor_status, output_token));
658         }
659
660         if (i == 0 && init_token.mechToken != NULL) {
661                 ibuf.length = init_token.mechToken->length;
662                 ibuf.value = init_token.mechToken->data;
663
664                 major_status = gss_accept_sec_context(minor_status,
665                                                       context_handle,
666                                                       acceptor_cred_handle,
667                                                       &ibuf,
668                                                       input_chan_bindings,
669                                                       src_name,
670                                                       mech_type,
671                                                       &obuf,
672                                                       ret_flags,
673                                                       time_rec,
674                                                       delegated_cred_handle);
675                 if (GSS_ERROR(major_status)) {
676                         free_NegTokenInit(&init_token);
677                         send_reject(&minor_status2, output_token);
678                         return (major_status);
679                 }
680                 ot = &obuf;
681         }
682         ret = send_accept(&minor_status2, output_token, ot, pref);
683         free_NegTokenInit(&init_token);
684         if (ot != NULL && ot->length != 0U)
685                 gss_release_buffer(&minor_status2, ot);
686
687         return (ret);
688 }
689
690 /* decapsulate.c */
691
692 static OM_uint32
693 gssapi_verify_mech_header(u_char ** str,
694                           size_t total_len,
695                           const gss_OID mech)
696 {
697         size_t len, len_len, mech_len, foo;
698         int e;
699         u_char *p = *str;
700
701         if (total_len < 1U)
702                 return (GSS_S_DEFECTIVE_TOKEN);
703         if (*p++ != 0x60)
704                 return (GSS_S_DEFECTIVE_TOKEN);
705         e = der_get_length(p, total_len - 1, &len, &len_len);
706         if (e || 1 + len_len + len != total_len)
707                 return (GSS_S_DEFECTIVE_TOKEN);
708         p += len_len;
709         if (*p++ != 0x06)
710                 return (GSS_S_DEFECTIVE_TOKEN);
711         e = der_get_length(p, total_len - 1 - len_len - 1,
712                            &mech_len, &foo);
713         if (e)
714                 return (GSS_S_DEFECTIVE_TOKEN);
715         p += foo;
716         if (mech_len != mech->length)
717                 return (GSS_S_BAD_MECH);
718         if (memcmp(p, mech->elements, mech->length) != 0)
719                 return (GSS_S_BAD_MECH);
720         p += mech_len;
721         *str = p;
722         return (GSS_S_COMPLETE);
723 }
724
725 /*
726  * Remove the GSS-API wrapping from `in_token' giving `buf and buf_size' Does
727  * not copy data, so just free `in_token'.
728  */
729
730 static OM_uint32
731 gssapi_spnego_decapsulate(OM_uint32 *minor_status,
732                           gss_buffer_t input_token_buffer,
733                           unsigned char **buf,
734                           size_t *buf_len,
735                           const gss_OID mech)
736 {
737         u_char *p;
738         OM_uint32 ret;
739
740         p = input_token_buffer->value;
741         ret = gssapi_verify_mech_header(&p,
742                                         input_token_buffer->length,
743                                         mech);
744         if (ret) {
745                 *minor_status = ret;
746                 return (GSS_S_FAILURE);
747         }
748         *buf_len = input_token_buffer->length -
749                 (p - (u_char *) input_token_buffer->value);
750         *buf = p;
751         return (GSS_S_COMPLETE);
752 }
753
754 /* der_free.c */
755
756 static void
757 free_octet_string(octet_string *k)
758 {
759         free(k->data);
760         k->data = NULL;
761 }
762
763 static void
764 free_oid(oid *k)
765 {
766         free(k->components);
767         k->components = NULL;
768 }
769
770 /* der_get.c */
771
772 /*
773  * All decoding functions take a pointer `p' to first position in which to
774  * read, from the left, `len' which means the maximum number of characters we
775  * are able to read, `ret' were the value will be returned and `size' where
776  * the number of used bytes is stored. Either 0 or an error code is returned.
777  */
778
779 static int
780 der_get_unsigned(const unsigned char *p, size_t len,
781                  unsigned *ret, size_t *size)
782 {
783         unsigned val = 0;
784         size_t oldlen = len;
785
786         while (len--)
787                 val = val * 256 + *p++;
788         *ret = val;
789         if (size)
790                 *size = oldlen;
791         return (0);
792 }
793
794 static int
795 der_get_int(const unsigned char *p, size_t len,
796             int *ret, size_t *size)
797 {
798         int val = 0;
799         size_t oldlen = len;
800
801         if (len > 0U) {
802                 val = (signed char)*p++;
803                 while (--len)
804                         val = val * 256 + *p++;
805         }
806         *ret = val;
807         if (size)
808                 *size = oldlen;
809         return (0);
810 }
811
812 static int
813 der_get_length(const unsigned char *p, size_t len,
814                size_t *val, size_t *size)
815 {
816         size_t v;
817
818         if (len <= 0U)
819                 return (ASN1_OVERRUN);
820         --len;
821         v = *p++;
822         if (v < 128U) {
823                 *val = v;
824                 if (size)
825                         *size = 1;
826         } else {
827                 int e;
828                 size_t l;
829                 unsigned tmp;
830
831                 if (v == 0x80U) {
832                         *val = ASN1_INDEFINITE;
833                         if (size)
834                                 *size = 1;
835                         return (0);
836                 }
837                 v &= 0x7F;
838                 if (len < v)
839                         return (ASN1_OVERRUN);
840                 e = der_get_unsigned(p, v, &tmp, &l);
841                 if (e)
842                         return (e);
843                 *val = tmp;
844                 if (size)
845                         *size = l + 1;
846         }
847         return (0);
848 }
849
850 static int
851 der_get_octet_string(const unsigned char *p, size_t len,
852                      octet_string *data, size_t *size)
853 {
854         data->length = len;
855         if (len != 0U) {
856                 data->data = malloc(len);
857                 if (data->data == NULL)
858                         return (ENOMEM);
859                 memmove(data->data, p, len);
860         } else
861                 data->data = NULL;
862         if (size)
863                 *size = len;
864         return (0);
865 }
866
867 static int
868 der_get_oid(const unsigned char *p, size_t len,
869             oid *data, size_t *size)
870 {
871         int n;
872         size_t oldlen = len;
873
874         data->components = NULL;
875         data->length = 0;
876         if (len < 1U)
877                 return (ASN1_OVERRUN);
878
879         data->components = malloc(len * sizeof(*data->components));
880         if (data->components == NULL && len != 0U)
881                 return (ENOMEM);
882         data->components[0] = (*p) / 40;
883         data->components[1] = (*p) % 40;
884         --len;
885         ++p;
886         for (n = 2; len > 0U; ++n) {
887                 unsigned u = 0;
888
889                 do {
890                         --len;
891                         u = u * 128 + (*p++ % 128);
892                 } while (len > 0U && p[-1] & 0x80);
893                 data->components[n] = u;
894         }
895         if (p[-1] & 0x80) {
896                 free_oid(data);
897                 return (ASN1_OVERRUN);
898         }
899         data->length = n;
900         if (size)
901                 *size = oldlen;
902         return (0);
903 }
904
905 static int
906 der_get_tag(const unsigned char *p, size_t len,
907             Der_class *class, Der_type *type,
908             int *tag, size_t *size)
909 {
910         if (len < 1U)
911                 return (ASN1_OVERRUN);
912         *class = (Der_class) (((*p) >> 6) & 0x03);
913         *type = (Der_type) (((*p) >> 5) & 0x01);
914         *tag = (*p) & 0x1F;
915         if (size)
916                 *size = 1;
917         return (0);
918 }
919
920 static int
921 der_match_tag(const unsigned char *p, size_t len,
922               Der_class class, Der_type type,
923               int tag, size_t *size)
924 {
925         size_t l;
926         Der_class thisclass;
927         Der_type thistype;
928         int thistag;
929         int e;
930
931         e = der_get_tag(p, len, &thisclass, &thistype, &thistag, &l);
932         if (e)
933                 return (e);
934         if (class != thisclass || type != thistype)
935                 return (ASN1_BAD_ID);
936         if (tag > thistag)
937                 return (ASN1_MISPLACED_FIELD);
938         if (tag < thistag)
939                 return (ASN1_MISSING_FIELD);
940         if (size)
941                 *size = l;
942         return (0);
943 }
944
945 static int
946 der_match_tag_and_length(const unsigned char *p, size_t len,
947                          Der_class class, Der_type type, int tag,
948                          size_t *length_ret, size_t *size)
949 {
950         size_t l, ret = 0;
951         int e;
952
953         e = der_match_tag(p, len, class, type, tag, &l);
954         if (e)
955                 return (e);
956         p += l;
957         len -= l;
958         ret += l;
959         e = der_get_length(p, len, length_ret, &l);
960         if (e)
961                 return (e);
962         /* p += l; */
963         len -= l;
964         POST(len);
965         ret += l;
966         if (size)
967                 *size = ret;
968         return (0);
969 }
970
971 static int
972 decode_enumerated(const unsigned char *p, size_t len, void *num, size_t *size)
973 {
974         size_t ret = 0;
975         size_t l, reallen;
976         int e;
977
978         e = der_match_tag(p, len, ASN1_C_UNIV, PRIM, UT_Enumerated, &l);
979         if (e)
980                 return (e);
981         p += l;
982         len -= l;
983         ret += l;
984         e = der_get_length(p, len, &reallen, &l);
985         if (e)
986                 return (e);
987         p += l;
988         len -= l;
989         ret += l;
990         e = der_get_int(p, reallen, num, &l);
991         if (e)
992                 return (e);
993         p += l;
994         len -= l;
995         POST(p); POST(len);
996         ret += l;
997         if (size)
998                 *size = ret;
999         return (0);
1000 }
1001
1002 static int
1003 decode_octet_string(const unsigned char *p, size_t len,
1004                     octet_string *k, size_t *size)
1005 {
1006         size_t ret = 0;
1007         size_t l;
1008         int e;
1009         size_t slen;
1010
1011         k->data = NULL;
1012         k->length = 0;
1013
1014         e = der_match_tag(p, len, ASN1_C_UNIV, PRIM, UT_OctetString, &l);
1015         if (e)
1016                 return (e);
1017         p += l;
1018         len -= l;
1019         ret += l;
1020
1021         e = der_get_length(p, len, &slen, &l);
1022         if (e)
1023                 return (e);
1024         p += l;
1025         len -= l;
1026         ret += l;
1027         if (len < slen)
1028                 return (ASN1_OVERRUN);
1029
1030         e = der_get_octet_string(p, slen, k, &l);
1031         if (e)
1032                 return (e);
1033         p += l;
1034         len -= l;
1035         POST(p); POST(len);
1036         ret += l;
1037         if (size)
1038                 *size = ret;
1039         return (0);
1040 }
1041
1042 static int
1043 decode_oid(const unsigned char *p, size_t len,
1044            oid *k, size_t *size)
1045 {
1046         size_t ret = 0;
1047         size_t l;
1048         int e;
1049         size_t slen;
1050
1051         e = der_match_tag(p, len, ASN1_C_UNIV, PRIM, UT_OID, &l);
1052         if (e)
1053                 return (e);
1054         p += l;
1055         len -= l;
1056         ret += l;
1057
1058         e = der_get_length(p, len, &slen, &l);
1059         if (e)
1060                 return (e);
1061         p += l;
1062         len -= l;
1063         ret += l;
1064         if (len < slen)
1065                 return (ASN1_OVERRUN);
1066
1067         e = der_get_oid(p, slen, k, &l);
1068         if (e)
1069                 return (e);
1070         p += l;
1071         len -= l;
1072         POST(p); POST(len);
1073         ret += l;
1074         if (size)
1075                 *size = ret;
1076         return (0);
1077 }
1078
1079 static int
1080 fix_dce(size_t reallen, size_t *len)
1081 {
1082         if (reallen == ASN1_INDEFINITE)
1083                 return (1);
1084         if (*len < reallen)
1085                 return (-1);
1086         *len = reallen;
1087         return (0);
1088 }
1089
1090 /* der_length.c */
1091
1092 static size_t
1093 len_unsigned(unsigned val)
1094 {
1095         size_t ret = 0;
1096
1097         do {
1098                 ++ret;
1099                 val /= 256;
1100         } while (val);
1101         return (ret);
1102 }
1103
1104 static size_t
1105 length_len(size_t len)
1106 {
1107         if (len < 128U)
1108                 return (1);
1109         else
1110                 return (len_unsigned((unsigned int)len) + 1);
1111 }
1112
1113
1114 /* der_put.c */
1115
1116 /*
1117  * All encoding functions take a pointer `p' to first position in which to
1118  * write, from the right, `len' which means the maximum number of characters
1119  * we are able to write.  The function returns the number of characters
1120  * written in `size' (if non-NULL). The return value is 0 or an error.
1121  */
1122
1123 static int
1124 der_put_unsigned(unsigned char *p, size_t len, unsigned val, size_t *size)
1125 {
1126         unsigned char *base = p;
1127
1128         if (val) {
1129                 while (len > 0U && val) {
1130                         *p-- = val % 256;
1131                         val /= 256;
1132                         --len;
1133                 }
1134                 if (val != 0)
1135                         return (ASN1_OVERFLOW);
1136                 else {
1137                         *size = base - p;
1138                         return (0);
1139                 }
1140         } else if (len < 1U)
1141                 return (ASN1_OVERFLOW);
1142         else {
1143                 *p = 0;
1144                 *size = 1;
1145                 return (0);
1146         }
1147 }
1148
1149 static int
1150 der_put_int(unsigned char *p, size_t len, int val, size_t *size)
1151 {
1152         unsigned char *base = p;
1153
1154         if (val >= 0) {
1155                 do {
1156                         if (len < 1U)
1157                                 return (ASN1_OVERFLOW);
1158                         *p-- = val % 256;
1159                         len--;
1160                         val /= 256;
1161                 } while (val);
1162                 if (p[1] >= 128) {
1163                         if (len < 1U)
1164                                 return (ASN1_OVERFLOW);
1165                         *p-- = 0;
1166                         len--;
1167                 }
1168         } else {
1169                 val = ~val;
1170                 do {
1171                         if (len < 1U)
1172                                 return (ASN1_OVERFLOW);
1173                         *p-- = ~(val % 256);
1174                         len--;
1175                         val /= 256;
1176                 } while (val);
1177                 if (p[1] < 128) {
1178                         if (len < 1U)
1179                                 return (ASN1_OVERFLOW);
1180                         *p-- = 0xff;
1181                         len--;
1182                 }
1183         }
1184         *size = base - p;
1185         return (0);
1186 }
1187
1188 static int
1189 der_put_length(unsigned char *p, size_t len, size_t val, size_t *size)
1190 {
1191         if (len < 1U)
1192                 return (ASN1_OVERFLOW);
1193         if (val < 128U) {
1194                 *p = (unsigned char)val;
1195                 *size = 1;
1196                 return (0);
1197         } else {
1198                 size_t l;
1199                 int e;
1200
1201                 e = der_put_unsigned(p, len - 1, (unsigned int)val, &l);
1202                 if (e)
1203                         return (e);
1204                 p -= l;
1205                 *p = 0x80 | (unsigned char)l;
1206                 *size = l + 1;
1207                 return (0);
1208         }
1209 }
1210
1211 static int
1212 der_put_octet_string(unsigned char *p, size_t len,
1213                      const octet_string *data, size_t *size)
1214 {
1215         if (len < data->length)
1216                 return (ASN1_OVERFLOW);
1217         p -= data->length;
1218         len -= data->length;
1219         POST(len);
1220         memmove(p + 1, data->data, data->length);
1221         *size = data->length;
1222         return (0);
1223 }
1224
1225 static int
1226 der_put_oid(unsigned char *p, size_t len,
1227             const oid *data, size_t *size)
1228 {
1229         unsigned char *base = p;
1230         size_t n;
1231
1232         for (n = data->length; n >= 3u; --n) {
1233                 unsigned        u = data->components[n - 1];
1234
1235                 if (len < 1U)
1236                         return (ASN1_OVERFLOW);
1237                 *p-- = u % 128;
1238                 u /= 128;
1239                 --len;
1240                 while (u > 0) {
1241                         if (len < 1U)
1242                                 return (ASN1_OVERFLOW);
1243                         *p-- = 128 + u % 128;
1244                         u /= 128;
1245                         --len;
1246                 }
1247         }
1248         if (len < 1U)
1249                 return (ASN1_OVERFLOW);
1250         *p-- = 40 * data->components[0] + data->components[1];
1251         *size = base - p;
1252         return (0);
1253 }
1254
1255 static int
1256 der_put_tag(unsigned char *p, size_t len, Der_class class, Der_type type,
1257             int tag, size_t *size)
1258 {
1259         if (len < 1U)
1260                 return (ASN1_OVERFLOW);
1261         *p = (class << 6) | (type << 5) | tag;  /* XXX */
1262         *size = 1;
1263         return (0);
1264 }
1265
1266 static int
1267 der_put_length_and_tag(unsigned char *p, size_t len, size_t len_val,
1268                        Der_class class, Der_type type, int tag, size_t *size)
1269 {
1270         size_t ret = 0;
1271         size_t l;
1272         int e;
1273
1274         e = der_put_length(p, len, len_val, &l);
1275         if (e)
1276                 return (e);
1277         p -= l;
1278         len -= l;
1279         ret += l;
1280         e = der_put_tag(p, len, class, type, tag, &l);
1281         if (e)
1282                 return (e);
1283         p -= l;
1284         len -= l;
1285         POST(p); POST(len);
1286         ret += l;
1287         *size = ret;
1288         return (0);
1289 }
1290
1291 static int
1292 encode_enumerated(unsigned char *p, size_t len, const void *data, size_t *size)
1293 {
1294         unsigned num = *(const unsigned *)data;
1295         size_t ret = 0;
1296         size_t l;
1297         int e;
1298
1299         e = der_put_int(p, len, num, &l);
1300         if (e)
1301                 return (e);
1302         p -= l;
1303         len -= l;
1304         ret += l;
1305         e = der_put_length_and_tag(p, len, l, ASN1_C_UNIV, PRIM, UT_Enumerated, &l);
1306         if (e)
1307                 return (e);
1308         p -= l;
1309         len -= l;
1310         POST(p); POST(len);
1311         ret += l;
1312         *size = ret;
1313         return (0);
1314 }
1315
1316 static int
1317 encode_octet_string(unsigned char *p, size_t len,
1318                     const octet_string *k, size_t *size)
1319 {
1320         size_t ret = 0;
1321         size_t l;
1322         int e;
1323
1324         e = der_put_octet_string(p, len, k, &l);
1325         if (e)
1326                 return (e);
1327         p -= l;
1328         len -= l;
1329         ret += l;
1330         e = der_put_length_and_tag(p, len, l, ASN1_C_UNIV, PRIM, UT_OctetString, &l);
1331         if (e)
1332                 return (e);
1333         p -= l;
1334         len -= l;
1335         POST(p); POST(len);
1336         ret += l;
1337         *size = ret;
1338         return (0);
1339 }
1340
1341 static int
1342 encode_oid(unsigned char *p, size_t len,
1343            const oid *k, size_t *size)
1344 {
1345         size_t ret = 0;
1346         size_t l;
1347         int e;
1348
1349         e = der_put_oid(p, len, k, &l);
1350         if (e)
1351                 return (e);
1352         p -= l;
1353         len -= l;
1354         ret += l;
1355         e = der_put_length_and_tag(p, len, l, ASN1_C_UNIV, PRIM, UT_OID, &l);
1356         if (e)
1357                 return (e);
1358         p -= l;
1359         len -= l;
1360         POST(p); POST(len);
1361         ret += l;
1362         *size = ret;
1363         return (0);
1364 }
1365
1366
1367 /* encapsulate.c */
1368
1369 static void
1370 gssapi_encap_length(size_t data_len,
1371                     size_t *len,
1372                     size_t *total_len,
1373                     const gss_OID mech)
1374 {
1375         size_t len_len;
1376
1377         *len = 1 + 1 + mech->length + data_len;
1378
1379         len_len = length_len(*len);
1380
1381         *total_len = 1 + len_len + *len;
1382 }
1383
1384 static u_char *
1385 gssapi_mech_make_header(u_char *p,
1386                         size_t len,
1387                         const gss_OID mech)
1388 {
1389         int e;
1390         size_t len_len, foo;
1391
1392         *p++ = 0x60;
1393         len_len = length_len(len);
1394         e = der_put_length(p + len_len - 1, len_len, len, &foo);
1395         if (e || foo != len_len)
1396                 return (NULL);
1397         p += len_len;
1398         *p++ = 0x06;
1399         *p++ = mech->length;
1400         memmove(p, mech->elements, mech->length);
1401         p += mech->length;
1402         return (p);
1403 }
1404
1405 /*
1406  * Give it a krb5_data and it will encapsulate with extra GSS-API wrappings.
1407  */
1408
1409 static OM_uint32
1410 gssapi_spnego_encapsulate(OM_uint32 * minor_status,
1411                           unsigned char *buf,
1412                           size_t buf_size,
1413                           gss_buffer_t output_token,
1414                           const gss_OID mech)
1415 {
1416         size_t len, outer_len;
1417         u_char *p;
1418
1419         gssapi_encap_length(buf_size, &len, &outer_len, mech);
1420
1421         output_token->length = outer_len;
1422         output_token->value = malloc(outer_len);
1423         if (output_token->value == NULL) {
1424                 *minor_status = ENOMEM;
1425                 return (GSS_S_FAILURE);
1426         }
1427         p = gssapi_mech_make_header(output_token->value, len, mech);
1428         if (p == NULL) {
1429                 if (output_token->length != 0U)
1430                         gss_release_buffer(minor_status, output_token);
1431                 return (GSS_S_FAILURE);
1432         }
1433         memmove(p, buf, buf_size);
1434         return (GSS_S_COMPLETE);
1435 }
1436
1437 /* init_sec_context.c */
1438 /*
1439  * SPNEGO wrapper for Kerberos5 GSS-API kouril@ics.muni.cz, 2003 (mostly
1440  * based on Heimdal code)
1441  */
1442
1443 static int
1444 add_mech(MechTypeList * mech_list, gss_OID mech)
1445 {
1446         MechType *tmp;
1447         int ret;
1448
1449         tmp = realloc(mech_list->val, (mech_list->len + 1) * sizeof(*tmp));
1450         if (tmp == NULL)
1451                 return (ENOMEM);
1452         mech_list->val = tmp;
1453
1454         ret = der_get_oid(mech->elements, mech->length,
1455                           &mech_list->val[mech_list->len], NULL);
1456         if (ret)
1457                 return (ret);
1458
1459         mech_list->len++;
1460         return (0);
1461 }
1462
1463 /*
1464  * return the length of the mechanism in token or -1
1465  * (which implies that the token was bad - GSS_S_DEFECTIVE_TOKEN
1466  */
1467
1468 static ssize_t
1469 gssapi_krb5_get_mech(const u_char *ptr,
1470                      size_t total_len,
1471                      const u_char **mech_ret)
1472 {
1473         size_t len, len_len, mech_len, foo;
1474         const u_char *p = ptr;
1475         int e;
1476
1477         if (total_len < 1U)
1478                 return (-1);
1479         if (*p++ != 0x60)
1480                 return (-1);
1481         e = der_get_length (p, total_len - 1, &len, &len_len);
1482         if (e || 1 + len_len + len != total_len)
1483                 return (-1);
1484         p += len_len;
1485         if (*p++ != 0x06)
1486                 return (-1);
1487         e = der_get_length (p, total_len - 1 - len_len - 1,
1488                             &mech_len, &foo);
1489         if (e)
1490                 return (-1);
1491         p += foo;
1492         *mech_ret = p;
1493         return (mech_len);
1494 }
1495
1496 static OM_uint32
1497 spnego_initial(OM_uint32 *minor_status,
1498                const gss_cred_id_t initiator_cred_handle,
1499                gss_ctx_id_t *context_handle,
1500                const gss_name_t target_name,
1501                const gss_OID mech_type,
1502                OM_uint32 req_flags,
1503                OM_uint32 time_req,
1504                const gss_channel_bindings_t input_chan_bindings,
1505                const gss_buffer_t input_token,
1506                gss_OID *actual_mech_type,
1507                gss_buffer_t output_token,
1508                OM_uint32 *ret_flags,
1509                OM_uint32 *time_rec)
1510 {
1511         NegTokenInit token_init;
1512         OM_uint32 major_status, minor_status2;
1513         gss_buffer_desc krb5_output_token = GSS_C_EMPTY_BUFFER;
1514         unsigned char *buf = NULL;
1515         size_t buf_size;
1516         size_t len;
1517         int ret;
1518
1519         (void)mech_type;
1520
1521         memset(&token_init, 0, sizeof(token_init));
1522
1523         ret = add_mech(&token_init.mechTypes, GSS_KRB5_MECH);
1524         if (ret) {
1525                 *minor_status = ret;
1526                 ret = GSS_S_FAILURE;
1527                 goto end;
1528         }
1529
1530         major_status = gss_init_sec_context(minor_status,
1531                                             initiator_cred_handle,
1532                                             context_handle,
1533                                             target_name,
1534                                             GSS_KRB5_MECH,
1535                                             req_flags,
1536                                             time_req,
1537                                             input_chan_bindings,
1538                                             input_token,
1539                                             actual_mech_type,
1540                                             &krb5_output_token,
1541                                             ret_flags,
1542                                             time_rec);
1543         if (GSS_ERROR(major_status)) {
1544                 ret = major_status;
1545                 goto end;
1546         }
1547         if (krb5_output_token.length > 0U) {
1548                 token_init.mechToken = malloc(sizeof(*token_init.mechToken));
1549                 if (token_init.mechToken == NULL) {
1550                         *minor_status = ENOMEM;
1551                         ret = GSS_S_FAILURE;
1552                         goto end;
1553                 }
1554                 token_init.mechToken->data = krb5_output_token.value;
1555                 token_init.mechToken->length = krb5_output_token.length;
1556         }
1557         /*
1558          * The MS implementation of SPNEGO seems to not like the mechListMIC
1559          * field, so we omit it (it's optional anyway)
1560          */
1561
1562         buf_size = 1024;
1563         buf = malloc(buf_size);
1564         if (buf == NULL) {
1565                 *minor_status = ENOMEM;
1566                 ret = GSS_S_FAILURE;
1567                 goto end;
1568         }
1569
1570         do {
1571                 ret = encode_NegTokenInit(buf + buf_size - 1,
1572                                           buf_size,
1573                                           &token_init, &len);
1574                 if (ret == 0) {
1575                         size_t tmp;
1576
1577                         ret = der_put_length_and_tag(buf + buf_size - len - 1,
1578                                                      buf_size - len,
1579                                                      len,
1580                                                      ASN1_C_CONTEXT,
1581                                                      CONS,
1582                                                      0,
1583                                                      &tmp);
1584                         if (ret == 0)
1585                                 len += tmp;
1586                 }
1587                 if (ret) {
1588                         if (ret == ASN1_OVERFLOW) {
1589                                 u_char *tmp;
1590
1591                                 buf_size *= 2;
1592                                 tmp = realloc(buf, buf_size);
1593                                 if (tmp == NULL) {
1594                                         *minor_status = ENOMEM;
1595                                         ret = GSS_S_FAILURE;
1596                                         goto end;
1597                                 }
1598                                 buf = tmp;
1599                         } else {
1600                                 *minor_status = ret;
1601                                 ret = GSS_S_FAILURE;
1602                                 goto end;
1603                         }
1604                 }
1605         } while (ret == ASN1_OVERFLOW);
1606
1607         ret = gssapi_spnego_encapsulate(minor_status,
1608                                         buf + buf_size - len, len,
1609                                         output_token, GSS_SPNEGO_MECH);
1610         if (ret == GSS_S_COMPLETE)
1611                 ret = major_status;
1612
1613 end:
1614         if (token_init.mechToken != NULL) {
1615                 free(token_init.mechToken);
1616                 token_init.mechToken = NULL;
1617         }
1618         free_NegTokenInit(&token_init);
1619         if (krb5_output_token.length != 0U)
1620                 gss_release_buffer(&minor_status2, &krb5_output_token);
1621         if (buf)
1622                 free(buf);
1623
1624         return (ret);
1625 }
1626
1627 static OM_uint32
1628 spnego_reply(OM_uint32 *minor_status,
1629              const gss_cred_id_t initiator_cred_handle,
1630              gss_ctx_id_t *context_handle,
1631              const gss_name_t target_name,
1632              const gss_OID mech_type,
1633              OM_uint32 req_flags,
1634              OM_uint32 time_req,
1635              const gss_channel_bindings_t input_chan_bindings,
1636              const gss_buffer_t input_token,
1637              gss_OID *actual_mech_type,
1638              gss_buffer_t output_token,
1639              OM_uint32 *ret_flags,
1640              OM_uint32 *time_rec)
1641 {
1642         OM_uint32 ret;
1643         NegTokenResp resp;
1644         unsigned char *buf;
1645         size_t buf_size;
1646         u_char oidbuf[17];
1647         size_t oidlen;
1648         gss_buffer_desc sub_token;
1649         ssize_t mech_len;
1650         const u_char *p;
1651         size_t len, taglen;
1652
1653         (void)mech_type;
1654
1655         output_token->length = 0;
1656         output_token->value  = NULL;
1657
1658         /*
1659          * SPNEGO doesn't include gss wrapping on SubsequentContextToken
1660          * like the Kerberos 5 mech does. But lets check for it anyway.
1661          */
1662
1663         mech_len = gssapi_krb5_get_mech(input_token->value,
1664                                         input_token->length,
1665                                         &p);
1666
1667         if (mech_len < 0) {
1668                 buf = input_token->value;
1669                 buf_size = input_token->length;
1670         } else if ((size_t)mech_len == GSS_KRB5_MECH->length &&
1671                    memcmp(GSS_KRB5_MECH->elements, p, mech_len) == 0)
1672                 return (gss_init_sec_context(minor_status,
1673                                              initiator_cred_handle,
1674                                              context_handle,
1675                                              target_name,
1676                                              GSS_KRB5_MECH,
1677                                              req_flags,
1678                                              time_req,
1679                                              input_chan_bindings,
1680                                              input_token,
1681                                              actual_mech_type,
1682                                              output_token,
1683                                              ret_flags,
1684                                              time_rec));
1685         else if ((size_t)mech_len == GSS_SPNEGO_MECH->length &&
1686                  memcmp(GSS_SPNEGO_MECH->elements, p, mech_len) == 0) {
1687                 ret = gssapi_spnego_decapsulate(minor_status,
1688                                                 input_token,
1689                                                 &buf,
1690                                                 &buf_size,
1691                                                 GSS_SPNEGO_MECH);
1692                 if (ret)
1693                         return (ret);
1694         } else
1695                 return (GSS_S_BAD_MECH);
1696
1697         ret = der_match_tag_and_length(buf, buf_size,
1698                                        ASN1_C_CONTEXT, CONS, 1, &len, &taglen);
1699         if (ret)
1700                 return (ret);
1701
1702         if(len > buf_size - taglen)
1703                 return (ASN1_OVERRUN);
1704
1705         ret = decode_NegTokenResp(buf + taglen, len, &resp, NULL);
1706         if (ret) {
1707                 free_NegTokenResp(&resp);
1708                 *minor_status = ENOMEM;
1709                 return (GSS_S_FAILURE);
1710         }
1711
1712         if (resp.negState == NULL ||
1713             *(resp.negState) == reject ||
1714             resp.supportedMech == NULL) {
1715                 free_NegTokenResp(&resp);
1716                 return (GSS_S_BAD_MECH);
1717         }
1718
1719         ret = der_put_oid(oidbuf + sizeof(oidbuf) - 1,
1720                           sizeof(oidbuf),
1721                           resp.supportedMech,
1722                           &oidlen);
1723         if (ret || oidlen != GSS_KRB5_MECH->length ||
1724             memcmp(oidbuf + sizeof(oidbuf) - oidlen,
1725                    GSS_KRB5_MECH->elements,
1726                    oidlen) != 0) {
1727                 free_NegTokenResp(&resp);
1728                 return GSS_S_BAD_MECH;
1729         }
1730
1731         if (resp.responseToken != NULL) {
1732                 sub_token.length = resp.responseToken->length;
1733                 sub_token.value  = resp.responseToken->data;
1734         } else {
1735                 sub_token.length = 0;
1736                 sub_token.value  = NULL;
1737         }
1738
1739         ret = gss_init_sec_context(minor_status,
1740                                    initiator_cred_handle,
1741                                    context_handle,
1742                                    target_name,
1743                                    GSS_KRB5_MECH,
1744                                    req_flags,
1745                                    time_req,
1746                                    input_chan_bindings,
1747                                    &sub_token,
1748                                    actual_mech_type,
1749                                    output_token,
1750                                    ret_flags,
1751                                    time_rec);
1752         if (ret) {
1753                 free_NegTokenResp(&resp);
1754                 return (ret);
1755         }
1756
1757         /*
1758          * XXXSRA I don't think this limited implementation ever needs
1759          * to check the MIC -- our preferred mechanism (Kerberos)
1760          * authenticates its own messages and is the only mechanism
1761          * we'll accept, so if the mechanism negotiation completes
1762          * successfully, we don't need the MIC.  See RFC 4178.
1763          */
1764
1765         free_NegTokenResp(&resp);
1766         return (ret);
1767 }
1768
1769
1770
1771 OM_uint32
1772 gss_init_sec_context_spnego(OM_uint32 *minor_status,
1773                             const gss_cred_id_t initiator_cred_handle,
1774                             gss_ctx_id_t *context_handle,
1775                             const gss_name_t target_name,
1776                             const gss_OID mech_type,
1777                             OM_uint32 req_flags,
1778                             OM_uint32 time_req,
1779                             const gss_channel_bindings_t input_chan_bindings,
1780                             const gss_buffer_t input_token,
1781                             gss_OID *actual_mech_type,
1782                             gss_buffer_t output_token,
1783                             OM_uint32 *ret_flags,
1784                             OM_uint32 *time_rec)
1785 {
1786         /* Dirty trick to suppress compiler warnings */
1787
1788         /* Figure out whether we're starting over or processing a reply */
1789
1790         if (input_token == GSS_C_NO_BUFFER || input_token->length == 0U)
1791                 return (spnego_initial(minor_status,
1792                                        initiator_cred_handle,
1793                                        context_handle,
1794                                        target_name,
1795                                        mech_type,
1796                                        req_flags,
1797                                        time_req,
1798                                        input_chan_bindings,
1799                                        input_token,
1800                                        actual_mech_type,
1801                                        output_token,
1802                                        ret_flags,
1803                                        time_rec));
1804         else
1805                 return (spnego_reply(minor_status,
1806                                      initiator_cred_handle,
1807                                      context_handle,
1808                                      target_name,
1809                                      mech_type,
1810                                      req_flags,
1811                                      time_req,
1812                                      input_chan_bindings,
1813                                      input_token,
1814                                      actual_mech_type,
1815                                      output_token,
1816                                      ret_flags,
1817                                      time_rec));
1818 }
1819
1820 #endif /* GSSAPI */