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