Replace the spnego dissector with an asn2eth generated one.
authoretxrab <etxrab@f5534014-38df-0310-8fa8-9805f1628bb7>
Thu, 15 Sep 2005 05:38:37 +0000 (05:38 +0000)
committeretxrab <etxrab@f5534014-38df-0310-8fa8-9805f1628bb7>
Thu, 15 Sep 2005 05:38:37 +0000 (05:38 +0000)
git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@15810 f5534014-38df-0310-8fa8-9805f1628bb7

asn1/spnego/Makefile.nmake [new file with mode: 0644]
asn1/spnego/packet-spnego-template.c [new file with mode: 0644]
asn1/spnego/packet-spnego-template.h [new file with mode: 0644]
asn1/spnego/spnego.asn [new file with mode: 0644]
asn1/spnego/spnego.cnf [new file with mode: 0644]
epan/dissectors/packet-spnego.c
epan/dissectors/packet-spnego.h [new file with mode: 0644]

diff --git a/asn1/spnego/Makefile.nmake b/asn1/spnego/Makefile.nmake
new file mode 100644 (file)
index 0000000..392f95f
--- /dev/null
@@ -0,0 +1,42 @@
+## Use: $(MAKE) /$(MAKEFLAGS) -f makefile.nmake
+#
+# $Id$
+
+include ../../config.nmake
+
+UNIX2DOS=$(PERL) ../../tools/unix2dos.pl
+
+PROTOCOL_NAME=spnego
+DISSECTOR_FILES=packet-$(PROTOCOL_NAME).c packet-$(PROTOCOL_NAME).h
+
+all: generate_dissector
+
+generate_dissector: $(DISSECTOR_FILES)
+
+$(DISSECTOR_FILES): ../../tools/asn2eth.py spnego.asn packet-spnego-template.c packet-spnego-template.h spnego.cnf
+!IFDEF PYTHON
+       $(PYTHON) ../../tools/asn2eth.py -X -b -e -p $(PROTOCOL_NAME) -c spnego.cnf -s packet-spnego-template spnego.asn
+!ELSE
+       @echo Error: You need Python to use asn2eth.py
+       @exit 1
+!ENDIF
+
+clean:
+       rm -f parsetab.py $(DISSECTOR_FILES)
+
+# Fix EOL in generated dissectors. Cygwin's python generates files with 
+# mixed EOL styles, which can't be commited to the SVN repository.
+# Stuff included from template and "cnf" files has "\r\n" on windows, while 
+# the generated stuff has "\n".
+
+fix_eol: generate_dissector
+       move packet-$(PROTOCOL_NAME).c packet-$(PROTOCOL_NAME).c.tmp
+       move packet-$(PROTOCOL_NAME).h packet-$(PROTOCOL_NAME).h.tmp
+       $(UNIX2DOS) < packet-$(PROTOCOL_NAME).c.tmp > packet-$(PROTOCOL_NAME).c
+       $(UNIX2DOS) < packet-$(PROTOCOL_NAME).h.tmp > packet-$(PROTOCOL_NAME).h
+       del /f packet-$(PROTOCOL_NAME).c.tmp packet-$(PROTOCOL_NAME).h.tmp
+
+copy_files: generate_dissector fix_eol
+       xcopy packet-$(PROTOCOL_NAME).c ..\..\epan\dissectors /d
+       xcopy packet-$(PROTOCOL_NAME).h ..\..\epan\dissectors /d
+
diff --git a/asn1/spnego/packet-spnego-template.c b/asn1/spnego/packet-spnego-template.c
new file mode 100644 (file)
index 0000000..d5ea031
--- /dev/null
@@ -0,0 +1,1074 @@
+/* packet-spnego.c
+ * Routines for the simple and protected GSS-API negotiation mechanism
+ * as described in RFC 2478.
+ * Copyright 2002, Tim Potter <tpot@samba.org>
+ * Copyright 2002, Richard Sharpe <rsharpe@ns.aus.com>
+ * Copyright 2003, Richard Sharpe <rsharpe@richardsharpe.com>
+ * Copyright 2005, Ronnie Sahlberg (krb decryption)
+ * Copyright 2005, Anders Broman (converted to asn2eth generated dissector)
+ *
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/* The heimdal code for decryption of GSSAPI wrappers using heimdal comes from
+   Heimdal 1.6 and has been modified for ethereal's requirements.
+*/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <glib.h>
+#include <epan/packet.h>
+#include "packet-dcerpc.h"
+#include "packet-gssapi.h"
+#include "packet-kerberos.h"
+#include <epan/crypt-rc4.h>
+#include <epan/conversation.h>
+#include <epan/emem.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "packet-ber.h"
+
+
+#define PNAME  "Simple Protected Negotiation"
+#define PSNAME "SPNEGO"
+#define PFNAME "spnego"
+
+/* Initialize the protocol and registered fields */
+static int proto_spnego = -1;
+static int proto_spnego_krb5 = -1;
+
+
+static int hf_spnego = -1;
+static int hf_spnego_wraptoken = -1;
+static int hf_spnego_krb5_oid;
+static int hf_spnego_krb5 = -1;
+static int hf_spnego_krb5_tok_id = -1;
+static int hf_spnego_krb5_sgn_alg = -1;
+static int hf_spnego_krb5_seal_alg = -1;
+static int hf_spnego_krb5_snd_seq = -1;
+static int hf_spnego_krb5_sgn_cksum = -1;
+static int hf_spnego_krb5_confounder = -1;
+
+#include "packet-spnego-hf.c"
+
+/* Global variables */
+gchar MechType_oid[MAX_OID_STR_LEN];
+gssapi_oid_value *next_level_value;
+gboolean saw_mechanism = FALSE;
+
+
+/* Initialize the subtree pointers */
+static gint ett_spnego;
+static gint ett_spnego_wraptoken;
+static gint ett_spnego_krb5 = -1;
+
+#include "packet-spnego-ett.c"
+
+static dissector_handle_t data_handle;
+
+static dissector_handle_t
+
+gssapi_dissector_handle(gssapi_oid_value *next_level_value) {
+       if (next_level_value == NULL) {
+               return NULL;
+       }
+       return next_level_value->handle;
+}
+
+
+#include "packet-spnego-fn.c"
+/*
+ * This is the SPNEGO KRB5 dissector. It is not true KRB5, but some ASN.1
+ * wrapped blob with an OID, USHORT token ID, and a Ticket, that is also 
+ * ASN.1 wrapped by the looks of it. It conforms to RFC1964.
+ */ 
+
+#define KRB_TOKEN_AP_REQ               0x0001
+#define KRB_TOKEN_AP_REP               0x0002
+#define KRB_TOKEN_AP_ERR               0x0003
+#define KRB_TOKEN_GETMIC               0x0101
+#define KRB_TOKEN_WRAP                 0x0102
+#define KRB_TOKEN_DELETE_SEC_CONTEXT   0x0201
+
+static const value_string spnego_krb5_tok_id_vals[] = {
+  { KRB_TOKEN_AP_REQ,             "KRB5_AP_REQ"},
+  { KRB_TOKEN_AP_REP,             "KRB5_AP_REP"},
+  { KRB_TOKEN_AP_ERR,             "KRB5_ERROR"},
+  { KRB_TOKEN_GETMIC,             "KRB5_GSS_GetMIC" },
+  { KRB_TOKEN_WRAP,               "KRB5_GSS_Wrap" },
+  { KRB_TOKEN_DELETE_SEC_CONTEXT, "KRB5_GSS_Delete_sec_context" },
+  { 0, NULL}
+};
+
+#define KRB_SGN_ALG_DES_MAC_MD5        0x0000
+#define KRB_SGN_ALG_MD2_5      0x0001
+#define KRB_SGN_ALG_DES_MAC    0x0002
+#define KRB_SGN_ALG_HMAC       0x0011
+
+static const value_string spnego_krb5_sgn_alg_vals[] = {
+  { KRB_SGN_ALG_DES_MAC_MD5, "DES MAC MD5"},
+  { KRB_SGN_ALG_MD2_5,       "MD2.5"},
+  { KRB_SGN_ALG_DES_MAC,     "DES MAC"},
+  { KRB_SGN_ALG_HMAC,        "HMAC"},
+  { 0, NULL}
+};
+
+#define KRB_SEAL_ALG_DES_CBC   0x0000
+#define KRB_SEAL_ALG_RC4       0x0010
+#define KRB_SEAL_ALG_NONE      0xffff
+
+static const value_string spnego_krb5_seal_alg_vals[] = {
+  { KRB_SEAL_ALG_DES_CBC, "DES CBC"},
+  { KRB_SEAL_ALG_RC4,     "RC4"},
+  { KRB_SEAL_ALG_NONE,    "None"},
+  { 0, NULL}
+};
+
+/*
+ * XXX - is this for SPNEGO or just GSS-API?
+ * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
+ * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
+ * than designating SPNEGO as the mechanism, offering Kerberos V5, and
+ * getting it accepted.
+ */
+static int
+dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
+static int
+dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint16 token_id);
+
+static void
+dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+       proto_item *item;
+       proto_tree *subtree;
+       int offset = 0;
+       guint16 token_id;
+       gchar oid[MAX_OID_STR_LEN];
+       gssapi_oid_value *value;
+       tvbuff_t *krb5_tvb;
+       gint8 class;
+       gboolean pc, ind = 0;
+       gint32 tag;
+       guint32 len;
+
+
+       item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, offset, 
+                                  -1, FALSE);
+
+       subtree = proto_item_add_subtree(item, ett_spnego_krb5);
+
+       /*
+        * The KRB5 blob conforms to RFC1964:
+        * [APPLICATION 0] {
+        *   OID,
+        *   USHORT (0x0001 == AP-REQ, 0x0002 == AP-REP, 0x0003 == ERROR),
+        *   OCTET STRING } 
+         *
+         * However, for some protocols, the KRB5 blob starts at the SHORT
+        * and has no DER encoded header etc.
+        *
+        * It appears that for some other protocols the KRB5 blob is just
+        * a Kerberos message, with no [APPLICATION 0] header, no OID,
+        * and no USHORT.
+        *
+        * So:
+        *
+        *      If we see an [APPLICATION 0] HEADER, we show the OID and
+        *      the USHORT, and then dissect the rest as a Kerberos message.
+        *
+        *      If we see an [APPLICATION 14] or [APPLICATION 15] header,
+        *      we assume it's an AP-REQ or AP-REP message, and dissect
+        *      it all as a Kerberos message.
+        *
+        *      Otherwise, we show the USHORT, and then dissect the rest
+        *      as a Kerberos message.
+        */
+
+       /*
+        * Get the first header ...
+        */
+       offset = dissect_ber_identifier(pinfo, subtree, tvb, offset, &class, &pc, &tag);
+       offset = dissect_ber_length(pinfo, subtree, tvb, offset, &len, &ind);
+
+       if (class == BER_CLASS_APP && pc == 1) {
+           /*
+            * [APPLICATION <tag>]
+            */
+           switch (tag) {
+
+           case 0:
+               /*
+                * [APPLICATION 0]
+                */
+
+               /* Next, the OID */
+               offset=dissect_ber_object_identifier(FALSE, pinfo, subtree, tvb, offset, hf_spnego_krb5_oid, oid);
+
+               value = gssapi_lookup_oid_str(oid);
+
+               token_id = tvb_get_letohs(tvb, offset);
+               proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
+                                   token_id);
+
+               offset += 2;
+
+               break;
+
+           case 14:    /* [APPLICATION 14] */
+           case 15:    /* [APPLICATION 15] */
+               /*
+                * No token ID - just dissect as a Kerberos message and
+                * return.
+                */
+               offset = dissect_kerberos_main(tvb, pinfo, subtree, FALSE, NULL);
+               return;
+
+           default:
+               proto_tree_add_text(subtree, tvb, offset, 0,
+                       "Unknown header (class=%d, pc=%d, tag=%d)",
+                       class, pc, tag);
+               goto done;
+           }
+       } else {
+           /* Next, the token ID ... */
+
+           token_id = tvb_get_letohs(tvb, offset);
+           proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
+                               token_id);
+
+           offset += 2;
+       }
+
+       switch (token_id) {
+
+       case KRB_TOKEN_AP_REQ:
+       case KRB_TOKEN_AP_REP:
+       case KRB_TOKEN_AP_ERR:
+         krb5_tvb = tvb_new_subset(tvb, offset, -1, -1); 
+         offset = dissect_kerberos_main(krb5_tvb, pinfo, subtree, FALSE, NULL);
+         break;
+
+       case KRB_TOKEN_GETMIC:
+         offset = dissect_spnego_krb5_getmic_base(tvb, offset, pinfo, subtree); 
+         break;
+
+       case KRB_TOKEN_WRAP:
+          offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id);
+         break;
+
+       case KRB_TOKEN_DELETE_SEC_CONTEXT:
+
+         break;
+
+       default:
+
+         break;
+       }
+
+ done:
+       return;
+}
+
+#ifdef HAVE_KERBEROS
+#include <epan/crypt-md5.h>
+
+#ifndef KEYTYPE_ARCFOUR_56
+# define KEYTYPE_ARCFOUR_56 24
+#endif
+/* XXX - We should probably do a configure-time check for this instead */
+#ifndef KRB5_KU_USAGE_SEAL
+# define KRB5_KU_USAGE_SEAL 22
+#endif
+
+static int
+arcfour_mic_key(void *key_data, size_t key_size, int key_type,
+               void *cksum_data, size_t cksum_size,
+               void *key6_data)
+{
+    guint8 k5_data[16];
+    guint8 T[4];
+
+    memset(T, 0, 4);
+
+    if (key_type == KEYTYPE_ARCFOUR_56) {
+       guint8 L40[14] = "fortybits";
+
+       memcpy(L40 + 10, T, sizeof(T));
+       md5_hmac(
+                L40, 14,  
+                key_data,
+                key_size, 
+               k5_data);
+       memset(&k5_data[7], 0xAB, 9);
+    } else {
+       md5_hmac(
+                T, 4,  
+                key_data,
+                key_size,
+               k5_data);
+    }
+
+    md5_hmac(
+       cksum_data, cksum_size,  
+       k5_data,
+       16, 
+       key6_data);
+
+    return 0;
+}
+
+static int
+usage2arcfour(int usage)
+{
+    switch (usage) {
+    case 3: /*KRB5_KU_AS_REP_ENC_PART 3 */
+    case 9: /*KRB5_KU_TGS_REP_ENC_PART_SUB_KEY 9 */
+       return 8;
+    case 22: /*KRB5_KU_USAGE_SEAL 22 */
+       return 13;
+    case 23: /*KRB5_KU_USAGE_SIGN 23 */
+        return 15;
+    case 24: /*KRB5_KU_USAGE_SEQ 24 */
+       return 0;
+    default :
+       return 0;
+    }
+}
+
+static int
+arcfour_mic_cksum(guint8 *key_data, int key_length,
+                 unsigned usage,
+                 u_char sgn_cksum[8],
+                 const void *v1, size_t l1,
+                 const void *v2, size_t l2,
+                 const void *v3, size_t l3)
+{
+    const guint8 signature[] = "signaturekey";
+    guint8 ksign_c[16];
+    unsigned char t[4];
+    md5_state_t ms;
+    unsigned char digest[16];
+    int rc4_usage;
+    guint8 cksum[16];
+    
+    rc4_usage=usage2arcfour(usage);
+    md5_hmac(signature, sizeof(signature), 
+               key_data, key_length, 
+               ksign_c);
+    md5_init(&ms);
+    t[0] = (rc4_usage >>  0) & 0xFF;
+    t[1] = (rc4_usage >>  8) & 0xFF;
+    t[2] = (rc4_usage >> 16) & 0xFF;
+    t[3] = (rc4_usage >> 24) & 0xFF;
+    md5_append(&ms, t, 4);
+    md5_append(&ms, v1, l1);
+    md5_append(&ms, v2, l2);
+    md5_append(&ms, v3, l3);
+    md5_finish(&ms, digest);
+    md5_hmac(digest, 16, ksign_c, 16, cksum);
+
+    memcpy(sgn_cksum, cksum, 8);
+
+    return 0;
+}
+
+/*
+ * Verify padding of a gss wrapped message and return its length.
+ */
+static int
+gssapi_verify_pad(unsigned char *wrapped_data, int wrapped_length, 
+                  size_t datalen,
+                  size_t *padlen)
+{
+    unsigned char *pad;
+    size_t padlength;
+    int i;
+
+    pad = wrapped_data + wrapped_length - 1;
+    padlength = *pad;
+
+    if (padlength > datalen)
+       return 1;
+
+    for (i = padlength; i > 0 && *pad == padlength; i--, pad--)
+       ;
+    if (i != 0)
+       return 2;
+
+    *padlen = padlength;
+
+    return 0;
+}
+
+static int
+decrypt_arcfour(packet_info *pinfo,
+        guint8 *input_message_buffer,
+        guint8 *output_message_buffer,
+        guint8 *key_value, int key_size, int key_type)
+{
+    guint8 Klocaldata[16];
+    int ret;
+    gint32 seq_number;
+    size_t datalen;
+    guint8 k6_data[16], SND_SEQ[8], Confounder[8];
+    guint8 cksum_data[8];
+    int cmp;
+    int conf_flag;
+    size_t padlen = 0;
+
+    datalen = tvb_length(pinfo->gssapi_encrypted_tvb);
+
+    if(tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 4)==0x1000){
+       conf_flag=1;
+    } else if (tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 4)==0xffff){
+       conf_flag=0;
+    } else {
+       return -3;
+    }
+
+    if(tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 6)!=0xffff){
+       return -4;
+    }
+
+    ret = arcfour_mic_key(key_value, key_size, key_type,
+                         (void *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
+                         8, /* SGN_CKSUM */
+                         k6_data);
+    if (ret) {
+       return -5;
+    }
+
+    {
+       rc4_state_struct rc4_state;
+       
+       crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
+       memcpy(SND_SEQ, (unsigned char *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 8, 8), 8);
+       crypt_rc4(&rc4_state, SND_SEQ, 8);
+
+       memset(k6_data, 0, sizeof(k6_data));
+    }
+
+    seq_number=g_ntohl(*((guint32 *)SND_SEQ));
+
+    cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4);
+    if(cmp){
+       cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4);
+    }
+
+    if (cmp != 0) {
+       return -6;
+    }
+
+    {
+       int i;
+
+       for (i = 0; i < 16; i++)
+           Klocaldata[i] = ((u_char *)key_value)[i] ^ 0xF0;
+    }
+    ret = arcfour_mic_key(Klocaldata,sizeof(Klocaldata),key_type,
+                         SND_SEQ, 4,
+                         k6_data);
+    memset(Klocaldata, 0, sizeof(Klocaldata));
+    if (ret) {
+       return -7;
+    }
+
+    if(conf_flag) {
+       rc4_state_struct rc4_state;
+
+       crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
+       memcpy(Confounder, (unsigned char *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 24, 8), 8);
+       crypt_rc4(&rc4_state, Confounder, 8);
+       memcpy(output_message_buffer, input_message_buffer, datalen);
+       crypt_rc4(&rc4_state, output_message_buffer, datalen);
+    } else {
+       memcpy(Confounder, 
+               tvb_get_ptr(pinfo->gssapi_wrap_tvb, 24, 8), 
+               8); /* Confounder */
+       memcpy(output_message_buffer, 
+               input_message_buffer, 
+               datalen);
+    }
+    memset(k6_data, 0, sizeof(k6_data));
+
+    /* only normal (i.e. non DCE style  wrapping use padding ? */
+    if(pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_NORMAL){
+       ret = gssapi_verify_pad(output_message_buffer,datalen,datalen, &padlen);
+       if (ret) {
+           return -9;
+       }
+       datalen -= padlen;
+    }
+
+    /* dont know what the checksum looks like for dce style gssapi */
+    if(pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_NORMAL){
+       ret = arcfour_mic_cksum(key_value, key_size,
+                           KRB5_KU_USAGE_SEAL,
+                           cksum_data, 
+                           tvb_get_ptr(pinfo->gssapi_wrap_tvb, 0, 8), 8,
+                           Confounder, sizeof(Confounder),
+                           output_message_buffer, 
+                           datalen + padlen);
+       if (ret) {
+           return -10;
+       }
+
+       cmp = memcmp(cksum_data, 
+           tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
+           8); /* SGN_CKSUM */
+       if (cmp) {
+           return -11;
+       }
+    }
+
+    return datalen;
+}
+
+
+
+#if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
+
+static void
+decrypt_gssapi_krb_arcfour_wrap(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int keytype)
+{
+       int ret;
+       enc_key_t *ek;
+       int length;
+       const guint8 *original_data;
+
+       static int omb_index=0;
+       static guint8 *omb_arr[4]={NULL,NULL,NULL,NULL};
+       static guint8 *cryptocopy=NULL; /* workaround for pre-0.6.1 heimdal bug */
+       guint8 *output_message_buffer;
+
+       omb_index++;
+       if(omb_index>=4){
+               omb_index=0;
+       }
+       output_message_buffer=omb_arr[omb_index];
+
+
+       length=tvb_length(pinfo->gssapi_encrypted_tvb);
+       original_data=tvb_get_ptr(pinfo->gssapi_encrypted_tvb, 0, length);
+
+       /* dont do anything if we are not attempting to decrypt data */
+/*
+       if(!krb_decrypt){
+               return;
+       }
+*/
+       /* XXX we should only do this for first time, then store somewhere */
+       /* XXX We also need to re-read the keytab when the preference changes */
+
+       cryptocopy=ep_alloc(length);
+       if(output_message_buffer){
+               g_free(output_message_buffer);
+               output_message_buffer=NULL;
+       }
+       output_message_buffer=g_malloc(length);
+
+       for(ek=enc_key_list;ek;ek=ek->next){
+               /* shortcircuit and bail out if enctypes are not matching */
+               if(ek->keytype!=keytype){
+                       continue;
+               }
+
+               /* pre-0.6.1 versions of Heimdal would sometimes change
+                 the cryptotext data even when the decryption failed.
+                 This would obviously not work since we iterate over the
+                 keys. So just give it a copy of the crypto data instead.
+                 This has been seen for RC4-HMAC blobs.
+               */
+               memcpy(cryptocopy, original_data, length);
+               ret=decrypt_arcfour(pinfo,
+                               cryptocopy,
+                               output_message_buffer,
+                               ek->keyvalue,
+                               ek->keylength,
+                               ek->keytype
+                                           );
+               if (ret >= 0) {
+                       proto_tree_add_text(tree, NULL, 0, 0, "[Decrypted using: %s]", ek->key_origin);
+                       pinfo->gssapi_decrypted_tvb=tvb_new_real_data(
+                               output_message_buffer,
+                               ret, ret);
+                       tvb_set_child_real_data_tvbuff(tvb, pinfo->gssapi_decrypted_tvb);
+                       add_new_data_source(pinfo, pinfo->gssapi_decrypted_tvb, "Decrypted GSS-Krb5");
+                       return;
+               }
+       }
+       return;
+}
+#endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
+
+
+#endif
+
+/*
+ * XXX - This is for GSSAPI Wrap tokens ...
+ */
+static int
+dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo
+#ifndef HAVE_KERBEROS
+       _U_
+#endif
+    , proto_tree *tree, guint16 token_id
+#ifndef HAVE_KERBEROS
+       _U_
+#endif
+    )
+{
+       guint16 sgn_alg, seal_alg;
+#ifdef HAVE_KERBEROS
+       int start_offset=offset;
+#endif
+
+       /*
+        * The KRB5 blob conforms to RFC1964:
+        *   USHORT (0x0102 == GSS_Wrap)
+        *   and so on } 
+        */
+
+       /* Now, the sign and seal algorithms ... */
+
+       sgn_alg = tvb_get_letohs(tvb, offset);
+       proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
+                           sgn_alg);
+
+       offset += 2;
+
+       seal_alg = tvb_get_letohs(tvb, offset);
+       proto_tree_add_uint(tree, hf_spnego_krb5_seal_alg, tvb, offset, 2,
+                           seal_alg);
+
+       offset += 2;
+
+       /* Skip the filler */
+
+       offset += 2;
+
+       /* Encrypted sequence number */
+
+       proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
+                           TRUE);
+
+       offset += 8;
+
+       /* Checksum of plaintext padded data */
+
+       proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
+                           TRUE);
+
+       offset += 8;
+
+       /*
+        * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
+        * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
+        * extra 8 bytes of "Random confounder" after the checksum.
+        * It certainly confounds code expecting all Kerberos 5
+        * GSS_Wrap() tokens to look the same....
+        */
+       if (sgn_alg == KRB_SGN_ALG_HMAC) {
+         proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
+                             TRUE);
+         offset += 8;
+       }
+
+       /* Is the data encrypted? */
+       pinfo->gssapi_data_encrypted=(seal_alg!=KRB_SEAL_ALG_NONE);
+
+#ifdef HAVE_KERBEROS
+#define GSS_ARCFOUR_WRAP_TOKEN_SIZE 32
+       if(pinfo->decrypt_gssapi_tvb){
+               /* if the caller did not provide a tvb, then we just use
+                  whatever is left of our current tvb.
+               */
+               if(!pinfo->gssapi_encrypted_tvb){
+                       int len;
+                       len=tvb_reported_length_remaining(tvb,offset);
+                       if(len>tvb_length_remaining(tvb, offset)){
+                               /* no point in trying to decrypt, 
+                                  we dont have the full pdu.
+                               */
+                               return offset;
+                       }
+                       pinfo->gssapi_encrypted_tvb = tvb_new_subset(
+                                       tvb, offset, len, len);
+               }
+                       
+               /* if this is KRB5 wrapped rc4-hmac */
+               if((token_id==KRB_TOKEN_WRAP)
+                &&(sgn_alg==KRB_SGN_ALG_HMAC)
+                &&(seal_alg==KRB_SEAL_ALG_RC4)){
+                       /* do we need to create a tvb for the wrapper
+                          as well ?
+                       */
+                       if(!pinfo->gssapi_wrap_tvb){
+                               pinfo->gssapi_wrap_tvb = tvb_new_subset(
+                                       tvb, start_offset-2,
+                                       GSS_ARCFOUR_WRAP_TOKEN_SIZE,
+                                       GSS_ARCFOUR_WRAP_TOKEN_SIZE);
+                       }
+#if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
+                       decrypt_gssapi_krb_arcfour_wrap(tree,
+                               pinfo,
+                               tvb,
+                               23 /* rc4-hmac */);
+#endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
+               }
+       }       
+#endif
+       /*
+        * Return the offset past the checksum, so that we know where
+        * the data we're wrapped around starts.  Also, set the length
+        * of our top-level item to that offset, so it doesn't cover
+        * the data we're wrapped around.
+        * 
+        * Note that for DCERPC the GSSAPI blobs comes after the data it wraps,
+        * not before.
+        */
+       return offset;
+}
+
+/*
+ * XXX - This is for GSSAPI GetMIC tokens ...
+ */
+static int
+dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
+{
+       guint16 sgn_alg;
+
+       /*
+        * The KRB5 blob conforms to RFC1964:
+        *   USHORT (0x0101 == GSS_GetMIC)
+        *   and so on } 
+        */
+
+       /* Now, the sign algorithm ... */
+
+       sgn_alg = tvb_get_letohs(tvb, offset);
+       proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
+                           sgn_alg);
+
+       offset += 2;
+
+       /* Skip the filler */
+
+       offset += 4;
+
+       /* Encrypted sequence number */
+
+       proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
+                           TRUE);
+
+       offset += 8;
+
+       /* Checksum of plaintext padded data */
+
+       proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
+                           TRUE);
+
+       offset += 8;
+
+       /*
+        * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
+        * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
+        * extra 8 bytes of "Random confounder" after the checksum.
+        * It certainly confounds code expecting all Kerberos 5
+        * GSS_Wrap() tokens to look the same....
+        */
+       if (sgn_alg == KRB_SGN_ALG_HMAC) {
+         proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
+                             TRUE);
+
+         offset += 8;
+       }
+
+       /*
+        * Return the offset past the checksum, so that we know where
+        * the data we're wrapped around starts.  Also, set the length
+        * of our top-level item to that offset, so it doesn't cover
+        * the data we're wrapped around.
+        */
+
+       return offset;
+}
+
+/*
+ * XXX - is this for SPNEGO or just GSS-API?
+ * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
+ * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
+ * than designating SPNEGO as the mechanism, offering Kerberos V5, and
+ * getting it accepted.
+ */
+static int
+dissect_spnego_krb5_wrap(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
+{
+       proto_item *item;
+       proto_tree *subtree;
+       int offset = 0;
+       guint16 token_id;
+
+       item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, 0, -1, FALSE);
+
+       subtree = proto_item_add_subtree(item, ett_spnego_krb5);
+
+       /*
+        * The KRB5 blob conforms to RFC1964:
+        *   USHORT (0x0102 == GSS_Wrap)
+        *   and so on } 
+        */
+
+       /* First, the token ID ... */
+
+       token_id = tvb_get_letohs(tvb, offset);
+       proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
+                           token_id);
+
+       offset += 2;
+
+        offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id);
+
+        /*
+        * Return the offset past the checksum, so that we know where
+        * the data we're wrapped around starts.  Also, set the length
+        * of our top-level item to that offset, so it doesn't cover
+        * the data we're wrapped around.
+        */
+       proto_item_set_len(item, offset);
+       return offset;
+}
+
+/* Spnego stuff from here */
+
+static int
+dissect_spnego_wrap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+       proto_item *item;
+       proto_tree *subtree;
+
+       int offset = 0;
+
+
+       /*
+        * We need this later, so lets get it now ...
+        * It has to be per-frame as there can be more than one GSS-API
+        * negotiation in a conversation.
+        */
+
+
+       item = proto_tree_add_item(tree, hf_spnego, tvb, offset, 
+                                  -1, FALSE);
+
+       subtree = proto_item_add_subtree(item, ett_spnego);
+       /*
+        * The TVB contains a [0] header and a sequence that consists of an
+        * object ID and a blob containing the data ...
+        * XXX - is this RFC 2743's "Mechanism-Independent Token Format",
+        * with the "optional" "use in non-initial tokens" being chosen.
+        * ASN1 code addet to spnego.asn to handle this.
+        */
+
+       offset = dissect_spnego_InitialContextToken(FALSE, tvb, offset, pinfo , subtree, -1);
+
+       return offset;
+}
+
+
+static void
+dissect_spnego(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
+{
+       proto_item *item;
+       proto_tree *subtree;
+       int offset = 0;
+       conversation_t *conversation;
+
+       /*
+        * We need this later, so lets get it now ...
+        * It has to be per-frame as there can be more than one GSS-API
+        * negotiation in a conversation.
+        */
+
+       next_level_value = p_get_proto_data(pinfo->fd, proto_spnego);
+       if (!next_level_value && !pinfo->fd->flags.visited) {
+           /*
+            * No handle attached to this frame, but it's the first
+            * pass, so it'd be attached to the conversation.
+            * If we have a conversation, try to get the handle,
+            * and if we get one, attach it to the frame.
+            */
+           conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
+                                            pinfo->ptype, pinfo->srcport,
+                                            pinfo->destport, 0);
+
+           if (conversation) {
+               next_level_value = conversation_get_proto_data(conversation, 
+                                                              proto_spnego);
+               if (next_level_value)
+                   p_add_proto_data(pinfo->fd, proto_spnego, next_level_value);
+           }
+       }
+
+       item = proto_tree_add_item(parent_tree, hf_spnego, tvb, offset, 
+                                  -1, FALSE);
+
+       subtree = proto_item_add_subtree(item, ett_spnego);
+
+       /*
+        * The TVB contains a [0] header and a sequence that consists of an
+        * object ID and a blob containing the data ...
+        * Actually, it contains, according to RFC2478:
+     * NegotiationToken ::= CHOICE {
+        *          negTokenInit [0] NegTokenInit,
+        *          negTokenTarg [1] NegTokenTarg }
+        * NegTokenInit ::= SEQUENCE {
+        *          mechTypes [0] MechTypeList OPTIONAL,
+        *          reqFlags [1] ContextFlags OPTIONAL,
+        *          mechToken [2] OCTET STRING OPTIONAL,
+        *          mechListMIC [3] OCTET STRING OPTIONAL }
+     * NegTokenTarg ::= SEQUENCE {
+        *          negResult [0] ENUMERATED {
+        *              accept_completed (0),
+        *              accept_incomplete (1),
+        *              reject (2) } OPTIONAL,
+     *          supportedMech [1] MechType OPTIONAL,
+     *          responseToken [2] OCTET STRING OPTIONAL,
+     *          mechListMIC [3] OCTET STRING OPTIONAL }
+     *
+        * Windows typically includes mechTypes and mechListMic ('NONE'
+        * in the case of NTLMSSP only).
+     * It seems to duplicate the responseToken into the mechListMic field
+     * as well. Naughty, naughty.
+     *
+        */
+       offset = dissect_spnego_NegotiationToken(FALSE, tvb, offset, pinfo, subtree, -1);
+
+}
+
+/*--- proto_register_spnego -------------------------------------------*/
+void proto_register_spnego(void) {
+
+  /* List of fields */
+  static hf_register_info hf[] = {
+               { &hf_spnego,
+                 { "SPNEGO", "spnego", FT_NONE, BASE_NONE, NULL, 0x0,
+                   "SPNEGO", HFILL }},
+         { &hf_spnego_wraptoken,
+                 { "wrapToken", "spnego.wraptoken",
+                   FT_NONE, BASE_NONE, NULL, 0x0, "SPNEGO wrapToken",
+                   HFILL}},
+               { &hf_spnego_krb5,
+                 { "krb5_blob", "spnego.krb5.blob", FT_BYTES,
+                   BASE_NONE, NULL, 0, "krb5_blob", HFILL }},
+               {&hf_spnego_krb5_oid,
+               {"KRB5 OID", "spnego.krb5_oid", FT_STRING, 
+                       BASE_NONE, NULL, 0, "KRB5 OID", HFILL }},
+               { &hf_spnego_krb5_tok_id,
+                 { "krb5_tok_id", "spnego.krb5.tok_id", FT_UINT16, BASE_HEX,
+                   VALS(spnego_krb5_tok_id_vals), 0, "KRB5 Token Id", HFILL}},
+               { &hf_spnego_krb5_sgn_alg,
+                 { "krb5_sgn_alg", "spnego.krb5.sgn_alg", FT_UINT16, BASE_HEX,
+                   VALS(spnego_krb5_sgn_alg_vals), 0, "KRB5 Signing Algorithm", HFILL}},
+               { &hf_spnego_krb5_seal_alg,
+                 { "krb5_seal_alg", "spnego.krb5.seal_alg", FT_UINT16, BASE_HEX,
+                   VALS(spnego_krb5_seal_alg_vals), 0, "KRB5 Sealing Algorithm", HFILL}},
+               { &hf_spnego_krb5_snd_seq,
+                 { "krb5_snd_seq", "spnego.krb5.snd_seq", FT_BYTES, BASE_NONE,
+                   NULL, 0, "KRB5 Encrypted Sequence Number", HFILL}},
+               { &hf_spnego_krb5_sgn_cksum,
+                 { "krb5_sgn_cksum", "spnego.krb5.sgn_cksum", FT_BYTES, BASE_NONE,
+                   NULL, 0, "KRB5 Data Checksum", HFILL}},
+               { &hf_spnego_krb5_confounder,
+                 { "krb5_confounder", "spnego.krb5.confounder", FT_BYTES, BASE_NONE,
+                   NULL, 0, "KRB5 Confounder", HFILL}},
+
+#include "packet-spnego-hfarr.c"
+  };
+
+  /* List of subtrees */
+  static gint *ett[] = {
+               &ett_spnego,
+               &ett_spnego_wraptoken,
+               &ett_spnego_krb5,
+
+#include "packet-spnego-ettarr.c"
+  };
+
+  /* Register protocol */
+  proto_spnego = proto_register_protocol(PNAME, PSNAME, PFNAME);
+
+       proto_spnego_krb5 = proto_register_protocol("SPNEGO-KRB5",
+                                                   "SPNEGO-KRB5",
+                                                   "spnego-krb5");
+  /* Register fields and subtrees */
+  proto_register_field_array(proto_spnego, hf, array_length(hf));
+  proto_register_subtree_array(ett, array_length(ett));
+
+}
+
+
+/*--- proto_reg_handoff_spnego ---------------------------------------*/
+void proto_reg_handoff_spnego(void) {
+
+       dissector_handle_t spnego_handle, spnego_wrap_handle;
+       dissector_handle_t spnego_krb5_handle, spnego_krb5_wrap_handle;
+
+       /* Register protocol with GSS-API module */
+
+       spnego_handle = create_dissector_handle(dissect_spnego, proto_spnego);
+       spnego_wrap_handle = new_create_dissector_handle(dissect_spnego_wrap,
+                                                        proto_spnego);
+       gssapi_init_oid("1.3.6.1.5.5.2", proto_spnego, ett_spnego,
+           spnego_handle, spnego_wrap_handle,
+           "SPNEGO - Simple Protected Negotiation");
+
+       /* Register both the one MS created and the real one */
+       /*
+        * Thanks to Jean-Baptiste Marchand and Richard B Ward, the
+        * mystery of the MS KRB5 OID is cleared up. It was due to a library
+        * that did not handle OID components greater than 16 bits, and was
+        * fixed in Win2K SP2 as well as WinXP.
+        * See the archive of <ietf-krb-wg@anl.gov> for the thread topic
+        * SPNEGO implementation issues. 3-Dec-2002.
+        */
+       spnego_krb5_handle = create_dissector_handle(dissect_spnego_krb5,
+                                                    proto_spnego_krb5);
+       spnego_krb5_wrap_handle = new_create_dissector_handle(dissect_spnego_krb5_wrap,
+                                                             proto_spnego_krb5);
+       gssapi_init_oid("1.2.840.48018.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
+                       spnego_krb5_handle, spnego_krb5_wrap_handle,
+                       "MS KRB5 - Microsoft Kerberos 5");
+       gssapi_init_oid("1.2.840.113554.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
+                       spnego_krb5_handle, spnego_krb5_wrap_handle,
+                       "KRB5 - Kerberos 5");
+       gssapi_init_oid("1.2.840.113554.1.2.2.3", proto_spnego_krb5, ett_spnego_krb5,
+                       spnego_krb5_handle, spnego_krb5_wrap_handle,
+                       "KRB5 - Kerberos 5 - User to User");
+
+       /*
+        * Find the data handle for some calls
+        */
+       data_handle = find_dissector("data");
+
+}
diff --git a/asn1/spnego/packet-spnego-template.h b/asn1/spnego/packet-spnego-template.h
new file mode 100644 (file)
index 0000000..8b8130f
--- /dev/null
@@ -0,0 +1,30 @@
+/* packet-spnego.h
+ * Routines for spnego packet dissection
+ *
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef PACKET_SPNEGO_H
+#define PACKET_SPNEGO_H
+
+/*#include "packet-spnego-exp.h"*/
+
+#endif  /* PACKET_spnego_H */
diff --git a/asn1/spnego/spnego.asn b/asn1/spnego/spnego.asn
new file mode 100644 (file)
index 0000000..8813fea
--- /dev/null
@@ -0,0 +1,85 @@
+Spnego {iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) snego(2)}
+-- (1.3.6.1.5.5.2)
+DEFINITIONS ::=
+
+BEGIN
+
+MechType::= OBJECT IDENTIFIER
+
+NegotiationToken ::= CHOICE {
+                              negTokenInit  [0]  NegTokenInit,
+                              negTokenTarg  [1]  NegTokenTarg }
+
+MechTypeList ::= SEQUENCE OF MechType
+
+NegTokenInit ::= SEQUENCE {
+                            mechTypes       [0] MechTypeList  OPTIONAL,
+                            reqFlags        [1] ContextFlags  OPTIONAL,
+                            mechToken       [2] OCTET STRING  OPTIONAL,
+                            mechListMIC     [3] OCTET STRING  OPTIONAL
+                         }
+
+ContextFlags ::= BIT STRING {
+        delegFlag       (0),
+        mutualFlag      (1),
+        replayFlag      (2),
+        sequenceFlag    (3),
+        anonFlag        (4),
+        confFlag        (5),
+        integFlag       (6)
+}
+
+NegTokenTarg ::= SEQUENCE {
+    negResult      [0] ENUMERATED {
+                            accept-completed    (0),
+                            accept-incomplete   (1),
+                            reject              (2) }          OPTIONAL,
+    supportedMech  [1] MechType                                OPTIONAL,
+    responseToken  [2] OCTET STRING                            OPTIONAL,
+    mechListMIC    [3] OCTET STRING                            OPTIONAL
+}
+
+--GSS-API DEFINITIONS ::= 
+--BEGIN 
+--MechType ::= OBJECT IDENTIFIER 
+-- data structure definitions 
+-- callers must be able to distinguish among 
+-- InitialContextToken, SubsequentContextToken, 
+-- PerMsgToken, and SealedMessage data elements 
+-- based on the usage in which they occur 
+InitialContextToken ::= 
+       -- option indication (delegation, etc.) indicated within 
+       -- mechanism-specific token 
+[APPLICATION 0] IMPLICIT SEQUENCE { 
+       thisMech MechType, 
+       innerContextToken InnerContextToken 
+       --      DEFINED BY thisMech 
+       -- contents mechanism-specific 
+       -- ASN.1 structure not required
+        } 
+
+-- SubsequentContextToken ::= InnerContextToken
+
+InnerContextToken ::= ANY
+-- interpretation based on predecessor InitialContextToken 
+-- ASN.1 structure not required 
+
+-- PerMsgToken ::= 
+-- as emitted by GSS_GetMIC and processed by GSS_VerifyMIC 
+-- ASN.1 structure not required 
+--     InnerMsgToken
+
+-- InnerMsgToken ::= ANY
+
+-- SealedMessage ::= 
+-- as emitted by GSS_Wrap and processed by GSS_Unwrap 
+-- includes internal, mechanism-defined indicator 
+-- of whether or not encrypted 
+-- ASN.1 structure not required 
+--     SealedUserData 
+       
+-- SealedUserData ::= ANY 
+
+-- END GSS-API DEFINITIONS
+
+END
\ No newline at end of file
diff --git a/asn1/spnego/spnego.cnf b/asn1/spnego/spnego.cnf
new file mode 100644 (file)
index 0000000..476e4ce
--- /dev/null
@@ -0,0 +1,128 @@
+# spnego.cnf
+# spnego conformation file
+
+# $Id$
+
+#.EXPORTS
+
+#.PDU
+
+#.NO_EMIT
+
+#.TYPE_RENAME
+
+#.FIELD_RENAME
+
+#.FN_PARS MechType
+
+       VAL_PTR = MechType_oid
+
+#.FN_BODY MechType
+
+       gssapi_oid_value *value;
+
+%(DEFAULT_BODY)s
+
+         value = gssapi_lookup_oid_str(MechType_oid);
+
+         /*
+          * Tell our caller the first mechanism we see, so that if
+          * this is a negTokenInit with a mechToken, it can interpret
+          * the mechToken according to the first mechType.  (There
+          * might not have been any indication of the mechType
+          * in prior frames, so we can't necessarily use the
+          * mechanism from the conversation; i.e., a negTokenInit
+          * can contain the initial security token for the desired
+          * mechanism of the initiator - that's the first mechanism
+          * in the list.)
+          */
+         if (!saw_mechanism) {
+           if (value)
+             next_level_value = value;
+           saw_mechanism = TRUE;
+         }
+
+#.FN_BODY InnerContextToken
+
+       conversation_t *conversation;
+       gssapi_oid_value *next_level_value;
+       proto_item *item;
+       proto_tree *subtree;
+       tvbuff_t *token_tvb;
+       int len;
+
+       next_level_value = p_get_proto_data(pinfo->fd, proto_spnego);
+       if (!next_level_value && !pinfo->fd->flags.visited) {
+           /*
+            * No handle attached to this frame, but it's the first
+            * pass, so it'd be attached to the conversation.
+            * If we have a conversation, try to get the handle,
+            * and if we get one, attach it to the frame.
+            */
+           conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
+                                            pinfo->ptype, pinfo->srcport,
+                                            pinfo->destport, 0);
+
+           if (conversation) {
+               next_level_value = conversation_get_proto_data(conversation, 
+                                                              proto_spnego);
+               if (next_level_value)
+                   p_add_proto_data(pinfo->fd, proto_spnego, next_level_value);
+           }
+       }
+
+       next_level_value = gssapi_lookup_oid_str(MechType_oid);
+       /*
+        * Now dissect the GSS_Wrap token; it's assumed to be in the
+        * rest of the tvbuff.
+        */
+       item = proto_tree_add_item(tree, hf_spnego_wraptoken, tvb, offset, 
+                                  -1, FALSE); 
+
+       subtree = proto_item_add_subtree(item, ett_spnego_wraptoken);
+
+       /*
+        * Now, we should be able to dispatch after creating a new TVB.
+        * The subdissector must return the length of the part of the
+        * token it dissected, so we can return the length of the part
+        * we (and it) dissected.
+        */
+
+       token_tvb = tvb_new_subset(tvb, offset, -1, -1);
+       if (next_level_value->wrap_handle) {
+         len = call_dissector(next_level_value->wrap_handle, token_tvb, pinfo, subtree);
+         if (len == 0)
+           offset = tvb_length(tvb);
+         else
+           offset = offset + len;
+       } else
+         
+         offset = tvb_length(tvb);
+
+
+#.FN_HDR MechTypeList
+
+
+       saw_mechanism = FALSE;
+
+#.FN_PARS NegTokenInit/mechToken
+
+       VAL_PTR = &mechToken_tvb
+
+#.FN_BODY NegTokenInit/mechToken
+
+       tvbuff_t *mechToken_tvb;
+
+
+%(DEFAULT_BODY)s       
+
+
+       /*
+        * Now, we should be able to dispatch after creating a new TVB.
+        */
+
+       if (next_level_value)
+          call_dissector(gssapi_dissector_handle(next_level_value), mechToken_tvb, pinfo, tree);
+
+
+#.END
index abf57e61125b37bb1028058f25d08915e087d403..00ec3f5fcefed6f652b78d96b51879635abc4759 100644 (file)
@@ -1,3 +1,10 @@
+/* Do not modify this file.                                                   */
+/* It is created automatically by the ASN.1 to Ethereal dissector compiler    */
+/* .\packet-spnego.c                                                          */
+/* ../../tools/asn2eth.py -X -b -e -p spnego -c spnego.cnf -s packet-spnego-template spnego.asn */
+
+/* Input file: packet-spnego-template.c */
+
 /* packet-spnego.c
  * Routines for the simple and protected GSS-API negotiation mechanism
  * as described in RFC 2478.
@@ -5,6 +12,7 @@
  * Copyright 2002, Richard Sharpe <rsharpe@ns.aus.com>
  * Copyright 2003, Richard Sharpe <rsharpe@richardsharpe.com>
  * Copyright 2005, Ronnie Sahlberg (krb decryption)
+ * Copyright 2005, Anders Broman (converted to asn2eth generated dissector)
  *
  * $Id$
  *
 /* The heimdal code for decryption of GSSAPI wrappers using heimdal comes from
    Heimdal 1.6 and has been modified for ethereal's requirements.
 */
+
 #ifdef HAVE_CONFIG_H
 # include "config.h"
 #endif
 
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
-#include <string.h>
 #include <glib.h>
 #include <epan/packet.h>
-
-#include <epan/asn1.h>
-#include "packet-ber.h"
 #include "packet-dcerpc.h"
 #include "packet-gssapi.h"
 #include "packet-kerberos.h"
 #include <epan/conversation.h>
 #include <epan/emem.h>
 
-#define SPNEGO_negTokenInit 0
-#define SPNEGO_negTokenTarg 1
-#define SPNEGO_mechTypes 0
-#define SPNEGO_reqFlags 1
-#define SPNEGO_mechToken 2
-#define SPNEGO_mechListMIC 3
-#define SPNEGO_negResult 0
-#define SPNEGO_supportedMech 1
-#define SPNEGO_responseToken 2
-#define SPNEGO_negResult_accept_completed 0
-#define SPNEGO_negResult_accept_incomplete 1
-#define SPNEGO_negResult_accept_reject 2
+#include <stdio.h>
+#include <string.h>
+
+#include "packet-ber.h"
+
 
+#define PNAME  "Simple Protected Negotiation"
+#define PSNAME "SPNEGO"
+#define PFNAME "spnego"
+
+/* Initialize the protocol and registered fields */
 static int proto_spnego = -1;
 static int proto_spnego_krb5 = -1;
 
+
 static int hf_spnego = -1;
-static int hf_spnego_mech = -1;
-static int hf_spnego_supportedMech = -1;
-static int hf_spnego_krb5_oid = -1;
-static int hf_spnego_this_mech = -1;
-static int hf_spnego_negtokeninit = -1;
-static int hf_spnego_negtokentarg = -1;
-static int hf_spnego_mechtype = -1;
-static int hf_spnego_mechtoken = -1;
-static int hf_spnego_negtokentarg_negresult = -1;
-static int hf_spnego_mechlistmic = -1;
-static int hf_spnego_responsetoken = -1;
-static int hf_spnego_reqflags = -1;
 static int hf_spnego_wraptoken = -1;
+static int hf_spnego_krb5_oid;
 static int hf_spnego_krb5 = -1;
 static int hf_spnego_krb5_tok_id = -1;
 static int hf_spnego_krb5_sgn_alg = -1;
@@ -87,100 +76,375 @@ static int hf_spnego_krb5_seal_alg = -1;
 static int hf_spnego_krb5_snd_seq = -1;
 static int hf_spnego_krb5_sgn_cksum = -1;
 static int hf_spnego_krb5_confounder = -1;
-static int hf_gssapi_reqflags_deleg = -1;
-static int hf_gssapi_reqflags_mutual = -1;
-static int hf_gssapi_reqflags_replay = -1;
-static int hf_gssapi_reqflags_sequence = -1;
-static int hf_gssapi_reqflags_anon = -1;
-static int hf_gssapi_reqflags_conf = -1;
-static int hf_gssapi_reqflags_integ = -1;
-
-static gint ett_spnego = -1;
-static gint ett_spnego_negtokeninit = -1;
-static gint ett_spnego_negtokentarg = -1;
-static gint ett_spnego_mechtype = -1;
-static gint ett_spnego_mechtoken = -1;
-static gint ett_spnego_mechlistmic = -1;
-static gint ett_spnego_responsetoken = -1;
-static gint ett_spnego_wraptoken = -1;
+
+
+/*--- Included file: packet-spnego-hf.c ---*/
+
+static int hf_spnego_negTokenInit = -1;           /* NegTokenInit */
+static int hf_spnego_negTokenTarg = -1;           /* NegTokenTarg */
+static int hf_spnego_MechTypeList_item = -1;      /* MechType */
+static int hf_spnego_mechTypes = -1;              /* MechTypeList */
+static int hf_spnego_reqFlags = -1;               /* ContextFlags */
+static int hf_spnego_mechToken = -1;              /* T_mechToken */
+static int hf_spnego_mechListMIC = -1;            /* OCTET_STRING */
+static int hf_spnego_negResult = -1;              /* T_negResult */
+static int hf_spnego_supportedMech = -1;          /* MechType */
+static int hf_spnego_responseToken = -1;          /* OCTET_STRING */
+static int hf_spnego_thisMech = -1;               /* MechType */
+static int hf_spnego_innerContextToken = -1;      /* InnerContextToken */
+/* named bits */
+static int hf_spnego_ContextFlags_delegFlag = -1;
+static int hf_spnego_ContextFlags_mutualFlag = -1;
+static int hf_spnego_ContextFlags_replayFlag = -1;
+static int hf_spnego_ContextFlags_sequenceFlag = -1;
+static int hf_spnego_ContextFlags_anonFlag = -1;
+static int hf_spnego_ContextFlags_confFlag = -1;
+static int hf_spnego_ContextFlags_integFlag = -1;
+
+/*--- End of included file: packet-spnego-hf.c ---*/
+
+
+/* Global variables */
+gchar MechType_oid[MAX_OID_STR_LEN];
+gssapi_oid_value *next_level_value;
+gboolean saw_mechanism = FALSE;
+
+
+/* Initialize the subtree pointers */
+static gint ett_spnego;
+static gint ett_spnego_wraptoken;
 static gint ett_spnego_krb5 = -1;
-static gint ett_spnego_reqflags = -1;
 
-static const value_string spnego_negResult_vals[] = {
-  { SPNEGO_negResult_accept_completed,   "Accept Completed" },
-  { SPNEGO_negResult_accept_incomplete,  "Accept Incomplete" },
-  { SPNEGO_negResult_accept_reject,      "Accept Reject"},
-  { 0, NULL}
-};
 
-/*
- * These should be in the GSSAPI dissector ... XXX
- */
+/*--- Included file: packet-spnego-ett.c ---*/
+
+static gint ett_spnego_NegotiationToken = -1;
+static gint ett_spnego_MechTypeList = -1;
+static gint ett_spnego_NegTokenInit = -1;
+static gint ett_spnego_ContextFlags = -1;
+static gint ett_spnego_NegTokenTarg = -1;
+static gint ett_spnego_InitialContextToken = -1;
+
+/*--- End of included file: packet-spnego-ett.c ---*/
+
+
+static dissector_handle_t data_handle;
+
+static dissector_handle_t
+
+gssapi_dissector_handle(gssapi_oid_value *next_level_value) {
+       if (next_level_value == NULL) {
+               return NULL;
+       }
+       return next_level_value->handle;
+}
+
+
+
+/*--- Included file: packet-spnego-fn.c ---*/
+
+/*--- Fields for imported types ---*/
+
+
+
+
+static int
+dissect_spnego_MechType(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
+
+       gssapi_oid_value *value;
+
+  offset = dissect_ber_object_identifier(implicit_tag, pinfo, tree, tvb, offset, hf_index,
+                                            MechType_oid);
+
+
+         value = gssapi_lookup_oid_str(MechType_oid);
+
+         /*
+          * Tell our caller the first mechanism we see, so that if
+          * this is a negTokenInit with a mechToken, it can interpret
+          * the mechToken according to the first mechType.  (There
+          * might not have been any indication of the mechType
+          * in prior frames, so we can't necessarily use the
+          * mechanism from the conversation; i.e., a negTokenInit
+          * can contain the initial security token for the desired
+          * mechanism of the initiator - that's the first mechanism
+          * in the list.)
+          */
+         if (!saw_mechanism) {
+           if (value)
+             next_level_value = value;
+           saw_mechanism = TRUE;
+         }
 
-static const true_false_string tfs_reqflags_deleg = {
-  "Delegation Requested",
-  "Delegation NOT Requested"
+
+  return offset;
+}
+static int dissect_MechTypeList_item(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
+  return dissect_spnego_MechType(FALSE, tvb, offset, pinfo, tree, hf_spnego_MechTypeList_item);
+}
+static int dissect_supportedMech(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
+  return dissect_spnego_MechType(FALSE, tvb, offset, pinfo, tree, hf_spnego_supportedMech);
+}
+static int dissect_thisMech(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
+  return dissect_spnego_MechType(FALSE, tvb, offset, pinfo, tree, hf_spnego_thisMech);
+}
+
+
+static const ber_sequence_t MechTypeList_sequence_of[1] = {
+  { BER_CLASS_UNI, BER_UNI_TAG_OID, BER_FLAGS_NOOWNTAG, dissect_MechTypeList_item },
 };
 
-static const true_false_string tfs_reqflags_mutual = {
-  "Mutual Authentication Requested",
-  "Mutual Authentication NOT Requested"
+static int
+dissect_spnego_MechTypeList(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
+
+
+       saw_mechanism = FALSE;
+
+  offset = dissect_ber_sequence_of(implicit_tag, pinfo, tree, tvb, offset,
+                                      MechTypeList_sequence_of, hf_index, ett_spnego_MechTypeList);
+
+  return offset;
+}
+static int dissect_mechTypes(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
+  return dissect_spnego_MechTypeList(FALSE, tvb, offset, pinfo, tree, hf_spnego_mechTypes);
+}
+
+
+static const asn_namedbit ContextFlags_bits[] = {
+  {  0, &hf_spnego_ContextFlags_delegFlag, -1, -1, "delegFlag", NULL },
+  {  1, &hf_spnego_ContextFlags_mutualFlag, -1, -1, "mutualFlag", NULL },
+  {  2, &hf_spnego_ContextFlags_replayFlag, -1, -1, "replayFlag", NULL },
+  {  3, &hf_spnego_ContextFlags_sequenceFlag, -1, -1, "sequenceFlag", NULL },
+  {  4, &hf_spnego_ContextFlags_anonFlag, -1, -1, "anonFlag", NULL },
+  {  5, &hf_spnego_ContextFlags_confFlag, -1, -1, "confFlag", NULL },
+  {  6, &hf_spnego_ContextFlags_integFlag, -1, -1, "integFlag", NULL },
+  { 0, NULL, 0, 0, NULL, NULL }
 };
 
-static const true_false_string tfs_reqflags_replay = {
-  "Replay Detection Requested",
-  "Replay Detection NOT Requested"
+static int
+dissect_spnego_ContextFlags(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
+  offset = dissect_ber_bitstring(implicit_tag, pinfo, tree, tvb, offset,
+                                    ContextFlags_bits, hf_index, ett_spnego_ContextFlags,
+                                    NULL);
+
+  return offset;
+}
+static int dissect_reqFlags(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
+  return dissect_spnego_ContextFlags(FALSE, tvb, offset, pinfo, tree, hf_spnego_reqFlags);
+}
+
+
+
+static int
+dissect_spnego_T_mechToken(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
+
+       tvbuff_t *mechToken_tvb;
+
+
+  offset = dissect_ber_octet_string(implicit_tag, pinfo, tree, tvb, offset, hf_index,
+                                       &mechToken_tvb);
+       
+
+
+       /*
+        * Now, we should be able to dispatch after creating a new TVB.
+        */
+
+       if (next_level_value)
+          call_dissector(gssapi_dissector_handle(next_level_value), mechToken_tvb, pinfo, tree);
+
+
+
+  return offset;
+}
+static int dissect_mechToken(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
+  return dissect_spnego_T_mechToken(FALSE, tvb, offset, pinfo, tree, hf_spnego_mechToken);
+}
+
+
+
+static int
+dissect_spnego_OCTET_STRING(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
+  offset = dissect_ber_octet_string(implicit_tag, pinfo, tree, tvb, offset, hf_index,
+                                       NULL);
+
+  return offset;
+}
+static int dissect_mechListMIC(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
+  return dissect_spnego_OCTET_STRING(FALSE, tvb, offset, pinfo, tree, hf_spnego_mechListMIC);
+}
+static int dissect_responseToken(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
+  return dissect_spnego_OCTET_STRING(FALSE, tvb, offset, pinfo, tree, hf_spnego_responseToken);
+}
+
+
+static const ber_sequence_t NegTokenInit_sequence[] = {
+  { BER_CLASS_CON, 0, BER_FLAGS_OPTIONAL, dissect_mechTypes },
+  { BER_CLASS_CON, 1, BER_FLAGS_OPTIONAL, dissect_reqFlags },
+  { BER_CLASS_CON, 2, BER_FLAGS_OPTIONAL, dissect_mechToken },
+  { BER_CLASS_CON, 3, BER_FLAGS_OPTIONAL, dissect_mechListMIC },
+  { 0, 0, 0, NULL }
 };
 
-static const true_false_string tfs_reqflags_sequence = {
-  "Out-of-sequence Detection Requested",
-  "Out-of-sequence Detection NOT Requested"
+static int
+dissect_spnego_NegTokenInit(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
+  offset = dissect_ber_sequence(implicit_tag, pinfo, tree, tvb, offset,
+                                   NegTokenInit_sequence, hf_index, ett_spnego_NegTokenInit);
+
+  return offset;
+}
+static int dissect_negTokenInit(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
+  return dissect_spnego_NegTokenInit(FALSE, tvb, offset, pinfo, tree, hf_spnego_negTokenInit);
+}
+
+
+static const value_string spnego_T_negResult_vals[] = {
+  {   0, "accept-completed" },
+  {   1, "accept-incomplete" },
+  {   2, "reject" },
+  { 0, NULL }
 };
 
-static const true_false_string tfs_reqflags_anon = {
-  "Anonymous Authentication Requested",
-  "Anonymous Authentication NOT Requested"
+
+static int
+dissect_spnego_T_negResult(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
+  offset = dissect_ber_integer(implicit_tag, pinfo, tree, tvb, offset, hf_index,
+                                  NULL);
+
+  return offset;
+}
+static int dissect_negResult(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
+  return dissect_spnego_T_negResult(FALSE, tvb, offset, pinfo, tree, hf_spnego_negResult);
+}
+
+
+static const ber_sequence_t NegTokenTarg_sequence[] = {
+  { BER_CLASS_CON, 0, BER_FLAGS_OPTIONAL, dissect_negResult },
+  { BER_CLASS_CON, 1, BER_FLAGS_OPTIONAL, dissect_supportedMech },
+  { BER_CLASS_CON, 2, BER_FLAGS_OPTIONAL, dissect_responseToken },
+  { BER_CLASS_CON, 3, BER_FLAGS_OPTIONAL, dissect_mechListMIC },
+  { 0, 0, 0, NULL }
 };
 
-static const true_false_string tfs_reqflags_conf = {
-  "Per-message Confidentiality Requested",
-  "Per-message Confidentiality NOT Requested"
+static int
+dissect_spnego_NegTokenTarg(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
+  offset = dissect_ber_sequence(implicit_tag, pinfo, tree, tvb, offset,
+                                   NegTokenTarg_sequence, hf_index, ett_spnego_NegTokenTarg);
+
+  return offset;
+}
+static int dissect_negTokenTarg(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
+  return dissect_spnego_NegTokenTarg(FALSE, tvb, offset, pinfo, tree, hf_spnego_negTokenTarg);
+}
+
+
+static const value_string spnego_NegotiationToken_vals[] = {
+  {   0, "negTokenInit" },
+  {   1, "negTokenTarg" },
+  { 0, NULL }
 };
 
-static const true_false_string tfs_reqflags_integ = {
-  "Per-message Integrity Requested",
-  "Per-message Integrity NOT Requested"
+static const ber_choice_t NegotiationToken_choice[] = {
+  {   0, BER_CLASS_CON, 0, 0, dissect_negTokenInit },
+  {   1, BER_CLASS_CON, 1, 0, dissect_negTokenTarg },
+  { 0, 0, 0, 0, NULL }
 };
 
+static int
+dissect_spnego_NegotiationToken(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
+  offset = dissect_ber_choice(pinfo, tree, tvb, offset,
+                                 NegotiationToken_choice, hf_index, ett_spnego_NegotiationToken,
+                                 NULL);
 
-/* Display an ASN1 parse error.  Taken from packet-snmp.c */
+  return offset;
+}
 
-static dissector_handle_t data_handle;
 
-static dissector_handle_t
-gssapi_dissector_handle(gssapi_oid_value *next_level_value) {
-       if (next_level_value == NULL) {
-               return NULL;
+
+static int
+dissect_spnego_InnerContextToken(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
+
+       conversation_t *conversation;
+       gssapi_oid_value *next_level_value;
+       proto_item *item;
+       proto_tree *subtree;
+       tvbuff_t *token_tvb;
+       int len;
+
+       next_level_value = p_get_proto_data(pinfo->fd, proto_spnego);
+       if (!next_level_value && !pinfo->fd->flags.visited) {
+           /*
+            * No handle attached to this frame, but it's the first
+            * pass, so it'd be attached to the conversation.
+            * If we have a conversation, try to get the handle,
+            * and if we get one, attach it to the frame.
+            */
+           conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
+                                            pinfo->ptype, pinfo->srcport,
+                                            pinfo->destport, 0);
+
+           if (conversation) {
+               next_level_value = conversation_get_proto_data(conversation, 
+                                                              proto_spnego);
+               if (next_level_value)
+                   p_add_proto_data(pinfo->fd, proto_spnego, next_level_value);
+           }
        }
-       return next_level_value->handle;
+
+       next_level_value = gssapi_lookup_oid_str(MechType_oid);
+       /*
+        * Now dissect the GSS_Wrap token; it's assumed to be in the
+        * rest of the tvbuff.
+        */
+       item = proto_tree_add_item(tree, hf_spnego_wraptoken, tvb, offset, 
+                                  -1, FALSE); 
+
+       subtree = proto_item_add_subtree(item, ett_spnego_wraptoken);
+
+       /*
+        * Now, we should be able to dispatch after creating a new TVB.
+        * The subdissector must return the length of the part of the
+        * token it dissected, so we can return the length of the part
+        * we (and it) dissected.
+        */
+
+       token_tvb = tvb_new_subset(tvb, offset, -1, -1);
+       if (next_level_value->wrap_handle) {
+         len = call_dissector(next_level_value->wrap_handle, token_tvb, pinfo, subtree);
+         if (len == 0)
+           offset = tvb_length(tvb);
+         else
+           offset = offset + len;
+       } else
+         
+         offset = tvb_length(tvb);
+
+
+
+  return offset;
+}
+static int dissect_innerContextToken(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
+  return dissect_spnego_InnerContextToken(FALSE, tvb, offset, pinfo, tree, hf_spnego_innerContextToken);
 }
 
-static void
-dissect_parse_error(tvbuff_t *tvb, int offset, packet_info *pinfo,
-                   proto_tree *tree, const char *field_name, int ret)
-{
-       const char *errstr;
 
-       errstr = asn1_err_to_str(ret);
+static const ber_sequence_t InitialContextToken_sequence[] = {
+  { BER_CLASS_UNI, BER_UNI_TAG_OID, BER_FLAGS_NOOWNTAG, dissect_thisMech },
+  { BER_CLASS_ANY, 0, BER_FLAGS_NOOWNTAG, dissect_innerContextToken },
+  { 0, 0, 0, NULL }
+};
 
-       if (tree != NULL) {
-               proto_tree_add_text(tree, tvb, offset, 0,
-                   "ERROR: Couldn't parse %s: %s", field_name, errstr);
-               call_dissector(data_handle,
-                   tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
-       }
+static int
+dissect_spnego_InitialContextToken(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
+  offset = dissect_ber_sequence(implicit_tag, pinfo, tree, tvb, offset,
+                                   InitialContextToken_sequence, hf_index, ett_spnego_InitialContextToken);
+
+  return offset;
 }
 
+
+/*--- End of included file: packet-spnego-fn.c ---*/
+
 /*
  * This is the SPNEGO KRB5 dissector. It is not true KRB5, but some ASN.1
  * wrapped blob with an OID, USHORT token ID, and a Ticket, that is also 
@@ -245,14 +509,16 @@ dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
        proto_item *item;
        proto_tree *subtree;
-       int ret, offset = 0;
-       ASN1_SCK hnd;
-       gboolean def;
-       guint len1, cls, con, tag;
+       int offset = 0;
        guint16 token_id;
        gchar oid[MAX_OID_STR_LEN];
        gssapi_oid_value *value;
        tvbuff_t *krb5_tvb;
+       gint8 class;
+       gboolean pc, ind = 0;
+       gint32 tag;
+       guint32 len;
+
 
        item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, offset, 
                                   -1, FALSE);
@@ -286,21 +552,13 @@ dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
         *      as a Kerberos message.
         */
 
-       asn1_open(&hnd, tvb, offset);
-
        /*
         * Get the first header ...
         */
+       offset = dissect_ber_identifier(pinfo, subtree, tvb, offset, &class, &pc, &tag);
+       offset = dissect_ber_length(pinfo, subtree, tvb, offset, &len, &ind);
 
-       ret = asn1_header_decode(&hnd, &cls, &con, &tag, &def, &len1);
-
-       if (ret != ASN1_ERR_NOERROR) {
-               dissect_parse_error(tvb, offset, pinfo, subtree,
-                                   "SPNEGO KRB5 Header", ret);
-               goto done;
-       }
-
-       if (cls == ASN1_APL && con == ASN1_CON) {
+       if (class == BER_CLASS_APP && pc == 1) {
            /*
             * [APPLICATION <tag>]
             */
@@ -311,12 +569,8 @@ dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                 * [APPLICATION 0]
                 */
 
-               offset = hnd.offset;
-
                /* Next, the OID */
                offset=dissect_ber_object_identifier(FALSE, pinfo, subtree, tvb, offset, hf_spnego_krb5_oid, oid);
-               hnd.offset = offset;
-
 
                value = gssapi_lookup_oid_str(oid);
 
@@ -324,8 +578,6 @@ dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
                                    token_id);
 
-               hnd.offset += 2;
-
                offset += 2;
 
                break;
@@ -341,8 +593,8 @@ dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 
            default:
                proto_tree_add_text(subtree, tvb, offset, 0,
-                       "Unknown header (cls=%d, con=%d, tag=%d)",
-                       cls, con, tag);
+                       "Unknown header (class=%d, pc=%d, tag=%d)",
+                       class, pc, tag);
                goto done;
            }
        } else {
@@ -352,8 +604,6 @@ dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
            proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
                                token_id);
 
-           hnd.offset += 2;
-
            offset += 2;
        }
 
@@ -960,662 +1210,46 @@ dissect_spnego_krb5_wrap(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree
 /* Spnego stuff from here */
 
 static int
-dissect_spnego_mechTypes(tvbuff_t *tvb, int offset, packet_info *pinfo,
-                        proto_tree *tree,
-                        gssapi_oid_value **next_level_value_p)
+dissect_spnego_wrap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
-       proto_item *item = NULL;
-       proto_tree *subtree = NULL;
-       gboolean saw_mechanism = FALSE;
-       int start_offset, start_oid_offset, end_oid_offset;
-       gint8 class;
-       gboolean pc, ind_field;
-       gint32 tag;
-       guint32 len1;
-       gchar oid[MAX_OID_STR_LEN];
+       proto_item *item;
+       proto_tree *subtree;
+
+       int offset = 0;
+
 
-       start_offset=offset;
        /*
-        * MechTypeList ::= SEQUENCE OF MechType
+        * We need this later, so lets get it now ...
+        * It has to be per-frame as there can be more than one GSS-API
+        * negotiation in a conversation.
         */
-       offset = get_ber_identifier(tvb, offset, &class, &pc, &tag);
-       offset = get_ber_length(tree, tvb, offset, &len1, &ind_field);
-
-       if (!(class == BER_CLASS_UNI && pc && tag == BER_UNI_TAG_SEQUENCE)) {
-         proto_tree_add_text(
-                             tree, tvb, offset, 0,
-                             "Unknown header (class=%d, pc=%d, tag=%d)",
-                             class, pc, tag);
-         goto done;
-       }
 
-       item = proto_tree_add_item(tree, hf_spnego_mechtype, tvb, 
-                               start_offset, len1, FALSE);
-       subtree = proto_item_add_subtree(item, ett_spnego_mechtype);
 
+       item = proto_tree_add_item(tree, hf_spnego, tvb, offset, 
+                                  -1, FALSE);
+
+       subtree = proto_item_add_subtree(item, ett_spnego);
        /*
-        * Now, the object IDs ...
+        * The TVB contains a [0] header and a sequence that consists of an
+        * object ID and a blob containing the data ...
+        * XXX - is this RFC 2743's "Mechanism-Independent Token Format",
+        * with the "optional" "use in non-initial tokens" being chosen.
+        * ASN1 code addet to spnego.asn to handle this.
         */
-       start_oid_offset=offset;
-       end_oid_offset = start_oid_offset+len1;
-       while (offset<end_oid_offset) {
-         gssapi_oid_value *value;
-
-         offset=dissect_ber_object_identifier(FALSE, pinfo, subtree, tvb, offset, hf_spnego_mech, oid);
-         value = gssapi_lookup_oid_str(oid);
 
-         /*
-          * Tell our caller the first mechanism we see, so that if
-          * this is a negTokenInit with a mechToken, it can interpret
-          * the mechToken according to the first mechType.  (There
-          * might not have been any indication of the mechType
-          * in prior frames, so we can't necessarily use the
-          * mechanism from the conversation; i.e., a negTokenInit
-          * can contain the initial security token for the desired
-          * mechanism of the initiator - that's the first mechanism
-          * in the list.)
-          */
-         if (!saw_mechanism) {
-           if (value)
-             *next_level_value_p = value;
-           saw_mechanism = TRUE;
-         }
-       }
-
- done:
+       offset = dissect_spnego_InitialContextToken(FALSE, tvb, offset, pinfo , subtree, -1);
 
        return offset;
-
-}
-
-static int
-dissect_spnego_reqFlags(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
-                       proto_tree *tree, ASN1_SCK *hnd)
-{
-       gboolean def;
-       guint len1, cls, con, tag, flags;
-       int ret;
-        proto_item *item;
-        proto_tree *subtree;
-
-       ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
-
-       if (ret != ASN1_ERR_NOERROR) {
-               dissect_parse_error(tvb, offset, pinfo, tree,
-                                   "SPNEGO reqFlags header", ret);
-               goto done;
-       }
-
-       if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_BTS)) {
-               proto_tree_add_text(
-                       tree, tvb, offset, 0,
-                       "Unknown header (cls=%d, con=%d, tag=%d)",
-                       cls, con, tag);
-               goto done;
-       }
-
-       /* We must have a Bit String ... insert it */ 
-
-       offset = hnd->offset;
-
-        flags = tvb_get_guint8(tvb, offset);
-
-       item = proto_tree_add_item(tree, hf_spnego_reqflags, tvb, offset, len1,
-            FALSE);
-
-        subtree = proto_item_add_subtree(item, ett_spnego_reqflags);
-
-        /*
-         * Now, the bits. XXX: Assume 8 bits. FIXME.
-         */
-
-        proto_tree_add_boolean(subtree, hf_gssapi_reqflags_deleg, tvb, offset, len1, flags);
-        proto_tree_add_boolean(subtree, hf_gssapi_reqflags_mutual, tvb, offset, len1, flags);
-        proto_tree_add_boolean(subtree, hf_gssapi_reqflags_replay, tvb, offset, len1, flags);
-        proto_tree_add_boolean(subtree, hf_gssapi_reqflags_sequence, tvb, offset, len1, flags);
-        proto_tree_add_boolean(subtree, hf_gssapi_reqflags_anon, tvb, offset, len1, flags);
-        proto_tree_add_boolean(subtree, hf_gssapi_reqflags_conf, tvb, offset, len1, flags);
-        proto_tree_add_boolean(subtree, hf_gssapi_reqflags_integ, tvb, offset, len1, flags);
-
-       hnd->offset += len1;
-
- done:
-       return offset + len1;
-
 }
 
-static int
-dissect_spnego_mechToken(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
-                        proto_tree *tree, ASN1_SCK *hnd,
-                        dissector_handle_t next_level_dissector)
-{
-        proto_item *item;
-       proto_tree *subtree;
-       gboolean def;
-       int ret;
-       guint cls, con, tag, nbytes = 0;
-       gint length_remaining, reported_length_remaining;
-       tvbuff_t *token_tvb;
-
-       /*
-        * This appears to be a simple octet string ...
-        */
-
-       ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &nbytes);
-
-       if (ret != ASN1_ERR_NOERROR) {
-               dissect_parse_error(tvb, offset, pinfo, tree,
-                                   "SPNEGO sequence header", ret);
-               goto done;
-       }
-
-       if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS)) {
-               proto_tree_add_text(
-                       tree, tvb, offset, 0,
-                       "Unknown header (cls=%d, con=%d, tag=%d)",
-                       cls, con, tag);
-               goto done;
-       }
-
-       offset = hnd->offset;
-
-
-       /* Dont try to create an item with more bytes than remains in the
-        * frame or we will not even attempt to dissect those bytes we
-        * do have. (since there will be an exception)
-        *
-        * We use "tvb_ensure_length_remaining()" so that we throw
-        * an exception if there's nothing to dissect.
-        */
-       length_remaining = tvb_ensure_length_remaining(tvb,offset);
-       reported_length_remaining = tvb_reported_length_remaining(tvb,offset);
-       if ((guint)length_remaining > nbytes)
-               length_remaining = nbytes;
-       if ((guint)reported_length_remaining > nbytes)
-               reported_length_remaining = nbytes;
-       item = proto_tree_add_item(tree, hf_spnego_mechtoken, tvb, offset, 
-                                  length_remaining, FALSE);
-       subtree = proto_item_add_subtree(item, ett_spnego_mechtoken);
-
-       /*
-        * Now, we should be able to dispatch after creating a new TVB.
-        */
-
-       token_tvb = tvb_new_subset(tvb, offset, length_remaining,
-           reported_length_remaining);
-       if (next_level_dissector)
-         call_dissector(next_level_dissector, token_tvb, pinfo, subtree);
-
-       hnd->offset += nbytes; /* Update this ... */
-
-done:
-       return offset + nbytes;
-}
-
-static int
-dissect_spnego_mechListMIC(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
-                          proto_tree *tree, ASN1_SCK *hnd,
-                          dissector_handle_t next_level_dissector)
-{
-       guint len1, cls, con, tag;
-       int ret;
-       gboolean def;
-       proto_tree *subtree = NULL;
-
-       /*
-        * Add the mechListMIC [3] Octet String or General String ...
-        */
-       ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
-
-       if (ret != ASN1_ERR_NOERROR) {
-               dissect_parse_error(tvb, offset, pinfo, subtree,
-                                   "SPNEGO sequence header", ret);
-               goto done;
-       }
-
-       offset = hnd->offset;
-
-       if (cls == ASN1_UNI && con == ASN1_CON && tag == ASN1_SEQ) {
-
-         /*
-          * There seems to be two different forms this can take
-          * One as an Octet string, and one as a general string in a 
-          * sequence ... We will have to dissect this later
-          */
-        
-         proto_tree_add_text(tree, tvb, offset + 4, len1 - 4,
-                             "mechListMIC: %s",
-                             tvb_format_text(tvb, offset + 4, len1 - 4));
-
-         /* Naughty ... but we have to adjust for what we never took */
-
-         hnd->offset += len1;
-         offset += len1;
-
-       }
-       else if (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS) {
-         tvbuff_t *token_tvb;
-         proto_item *item;
-         proto_tree *subtree;
-
-         item = proto_tree_add_item(tree, hf_spnego_mechlistmic, tvb, offset, 
-                             len1, FALSE); 
-         subtree = proto_item_add_subtree(item, ett_spnego_mechlistmic);
-         
-       /*
-        * Now, we should be able to dispatch after creating a new TVB.
-        */
-
-         token_tvb = tvb_new_subset(tvb, offset, len1, -1);
-         if (next_level_dissector)
-           call_dissector(next_level_dissector, token_tvb, pinfo, subtree);
-
-         hnd->offset += len1; /* Update this ... */
-         offset += len1;
-
-       }
-       else {
-
-         proto_tree_add_text(subtree, tvb, offset, 0,
-                             "Unknown header (cls=%d, con=%d, tag=%d)",
-                             cls, con, tag);
-         goto done;
-       }
-
- done:
-
-       return offset;
-
-}
-
-static int
-dissect_spnego_negTokenInit(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
-                           proto_tree *tree, ASN1_SCK *hnd,
-                           gssapi_oid_value **next_level_value_p)
-{
-       proto_item *item;
-       proto_tree *subtree;
-       gboolean def;
-       guint len1, len, cls, con, tag;
-       int ret;
-
-       item = proto_tree_add_item( tree, hf_spnego_negtokeninit, tvb, offset,
-                                   -1, FALSE);
-       subtree = proto_item_add_subtree(item, ett_spnego_negtokeninit);
-
-       /*
-        * Here is what we need to get ...
-        * NegTokenInit ::= SEQUENCE {
-        *          mechTypes [0] MechTypeList OPTIONAL,
-        *          reqFlags [1] ContextFlags OPTIONAL,
-        *          mechToken [2] OCTET STRING OPTIONAL,
-        *          mechListMIC [3] OCTET STRING OPTIONAL }
-
-        */
-
-       ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
-
-       if (ret != ASN1_ERR_NOERROR) {
-               dissect_parse_error(tvb, offset, pinfo, subtree,
-                                   "SPNEGO sequence header", ret);
-               goto done;
-       }
-
-       if (!(cls == ASN1_UNI && con == ASN1_CON && tag == ASN1_SEQ)) {
-               proto_tree_add_text(
-                       subtree, tvb, offset, 0,
-                       "Unknown header (cls=%d, con=%d, tag=%d)",
-                       cls, con, tag);
-               goto done;
-       }
-
-       offset = hnd->offset;
-
-       while (len1) {
-         int hdr_ofs;
-
-         hdr_ofs = hnd->offset;
-
-         ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len);
-
-         if (ret != ASN1_ERR_NOERROR) {
-           dissect_parse_error(tvb, offset, pinfo, subtree,
-                               "SPNEGO context header", ret);
-           goto done;
-         }
-
-         if (!(cls == ASN1_CTX && con == ASN1_CON)) {
-           proto_tree_add_text(subtree, tvb, offset, 0,
-                               "Unknown header (cls=%d, con=%d, tag=%d)",
-                               cls, con, tag);
-           goto done;
-         }
-
-         /* Adjust for the length of the header */
-
-         len1 -= (hnd->offset - hdr_ofs);
-
-         /* Should be one of the fields */
-
-         switch (tag) {
-
-         case SPNEGO_mechTypes:
-
-           offset = dissect_spnego_mechTypes(tvb, hnd->offset, pinfo,
-                                             subtree,
-                                             next_level_value_p);
-           hnd->offset=offset;
-
-           break;
-
-         case SPNEGO_reqFlags:
-
-           offset = dissect_spnego_reqFlags(tvb, offset, pinfo, subtree, hnd);
-
-           break;
-
-         case SPNEGO_mechToken:
-
-           offset = dissect_spnego_mechToken(tvb, offset, pinfo, subtree, 
-                                             hnd, gssapi_dissector_handle(*next_level_value_p));
-           break;
-
-         case SPNEGO_mechListMIC:
-
-           offset = dissect_spnego_mechListMIC(tvb, offset, pinfo, subtree,
-                                               hnd, gssapi_dissector_handle(*next_level_value_p));
-           break;
-
-         default:
-
-           break;
-         }
-
-         len1 -= len;
-
-       }
-
- done:
-
-       return offset; /* Not sure this is right */
-}
-
-static int
-dissect_spnego_negResult(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
-                           proto_tree *tree, ASN1_SCK *hnd)
-{
-        gboolean def;
-       int ret;
-       guint len, cls, con, tag, val;
-
-       ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len);
-
-       if (ret != ASN1_ERR_NOERROR) {
-         dissect_parse_error(tvb, offset, pinfo, tree,
-                             "SPNEGO context header", ret);
-         goto done;
-       }
-
-       if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_ENUM)) {
-         proto_tree_add_text(
-                             tree, tvb, offset, 0,
-                             "Unknown header (cls=%d, con=%d, tag=%d) xxx",
-                             cls, con, tag);
-         goto done;
-       }
-
-       offset = hnd->offset;
-
-       /* Now, get the value */
-
-       ret = asn1_uint32_value_decode(hnd, len, &val);
-
-       if (ret != ASN1_ERR_NOERROR) {
-         dissect_parse_error(tvb, offset, pinfo, tree,
-                             "SPNEGO negResult value", ret);
-         goto done;
-       }
-       
-       proto_tree_add_item(tree, hf_spnego_negtokentarg_negresult, tvb, 
-                           offset, 1, FALSE);
-
-       offset = hnd->offset;
-
- done:
-       return offset;
-}
-
-static int
-dissect_spnego_supportedMech(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
-                            proto_tree *tree, ASN1_SCK *hnd,
-                            gssapi_oid_value **next_level_value_p)
-{
-       gchar oid[MAX_OID_STR_LEN];
-       gssapi_oid_value *value;
-       conversation_t *conversation;
-
-       /*
-        * Now, get the OID, and find the handle, if any
-        */
-
-       offset = hnd->offset;
-
-       offset=dissect_ber_object_identifier(FALSE, pinfo, tree, tvb, offset, hf_spnego_supportedMech, oid);
-       value = gssapi_lookup_oid_str(oid);
-       /* put the right offset into asn1:s struct for now */
-       hnd->offset = offset;
-
-       /* Should check for an unrecognized OID ... */
-
-       if (value)
-         *next_level_value_p = value;
-
-       /*
-        * Now, we need to save this in per proto info in the
-        * conversation if it exists. We also should create a 
-        * conversation if one does not exist. FIXME!
-        * Hmmm, might need to be smarter, because there can be
-        * multiple mechTypes in a negTokenInit with one being the
-        * default used in the Token if present. Then the negTokenTarg
-        * could override that. :-(
-        */
-
-       if ((conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
-                                            pinfo->ptype, pinfo->srcport,
-                                            pinfo->destport, 0))) {
-
-
-         conversation_add_proto_data(conversation, proto_spnego, 
-                                     *next_level_value_p);
-       }
-       else {
-
-       }
-
-       return offset;
-}
-
-static int
-dissect_spnego_responseToken(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
-                            proto_tree *tree, ASN1_SCK *hnd,
-                            dissector_handle_t next_level_dissector)
-{
-       gboolean def;
-       int ret;
-       guint cls, con, tag, nbytes;
-       tvbuff_t *token_tvb;
-       proto_item *item;
-       proto_tree *subtree;
-
-       ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &nbytes);
-
-       if (ret != ASN1_ERR_NOERROR) {
-               dissect_parse_error(tvb, offset, pinfo, tree,
-                                   "SPNEGO sequence header", ret);
-               goto done;
-       }
-
-       if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS)) {
-               proto_tree_add_text(
-                       tree, tvb, offset, 0,
-                       "Unknown header (cls=%d, con=%d, tag=%d)",
-                       cls, con, tag);
-               goto done;
-       }
-
-       offset = hnd->offset;
-
-       item = proto_tree_add_item(tree, hf_spnego_responsetoken, tvb, offset -2 , 
-                                  nbytes + 2, FALSE); 
-
-       subtree = proto_item_add_subtree(item, ett_spnego_responsetoken);
-
-
-       /*
-        * Now, we should be able to dispatch after creating a new TVB.
-        * However, we should make sure that there is something in the 
-        * response token ...
-        */
-
-       if (nbytes) {
-         token_tvb = tvb_new_subset(tvb, offset, nbytes, -1);
-         if (next_level_dissector)
-           call_dissector(next_level_dissector, token_tvb, pinfo, subtree);
-       }
-       else {
-         proto_tree_add_text(subtree, tvb, offset-2, 2, "<Empty String>");
-       }
-       hnd->offset += nbytes; /* Update this ... */
-
- done:
-       return offset + nbytes;
-}
-
-static int
-dissect_spnego_negTokenTarg(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
-                           proto_tree *tree, ASN1_SCK *hnd,
-                           gssapi_oid_value **next_level_value_p)
-
-{
-       proto_item *item;
-       proto_tree *subtree;
-       gboolean def;
-       int ret;
-       guint len1, len, cls, con, tag;
-
-       item = proto_tree_add_item( tree, hf_spnego_negtokentarg, tvb, offset,
-                                   -1, FALSE);
-       subtree = proto_item_add_subtree(item, ett_spnego_negtokentarg);
-
-       /* 
-        * Here is what we need to get ...
-         * NegTokenTarg ::= SEQUENCE {
-        *          negResult [0] ENUMERATED {
-        *              accept_completed (0),
-        *              accept_incomplete (1),
-        *              reject (2) } OPTIONAL,
-         *          supportedMech [1] MechType OPTIONAL,
-         *          responseToken [2] OCTET STRING OPTIONAL,
-         *          mechListMIC [3] OCTET STRING OPTIONAL }
-        */
-
-       ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
-
-       if (ret != ASN1_ERR_NOERROR) {
-               dissect_parse_error(tvb, offset, pinfo, subtree,
-                                   "SPNEGO sequence header", ret);
-               goto done;
-       }
-
-       if (!(cls == ASN1_UNI && con == ASN1_CON && tag == ASN1_SEQ)) {
-               proto_tree_add_text(
-                       subtree, tvb, offset, 0,
-                       "Unknown header (cls=%d, con=%d, tag=%d)",
-                       cls, con, tag);
-               goto done;
-       }
-
-       offset = hnd->offset;
-
-       while (len1) {
-         int hdr_ofs;
-
-         hdr_ofs = hnd->offset; 
-
-         ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len);
-
-         if (ret != ASN1_ERR_NOERROR) {
-           dissect_parse_error(tvb, offset, pinfo, subtree,
-                               "SPNEGO context header", ret);
-           goto done;
-         }
-
-         if (!(cls == ASN1_CTX && con == ASN1_CON)) {
-           proto_tree_add_text(
-                               subtree, tvb, offset, 0,
-                               "Unknown header (cls=%d, con=%d, tag=%d)",
-                               cls, con, tag);
-           goto done;
-         }
-
-         /* Adjust for the length of the header */
-
-         len1 -= (hnd->offset - hdr_ofs);
-
-         /* Should be one of the fields */
-
-         switch (tag) {
-
-         case SPNEGO_negResult:
-
-           offset = dissect_spnego_negResult(tvb, offset, pinfo, subtree, 
-                                             hnd);
-           break;
-
-         case SPNEGO_supportedMech:
-
-           offset = dissect_spnego_supportedMech(tvb, offset, pinfo, subtree,
-                                                 hnd, next_level_value_p);
-
-           break;
-
-         case SPNEGO_responseToken:
-
-           offset = dissect_spnego_responseToken(tvb, offset, pinfo, subtree,
-                                                 hnd, gssapi_dissector_handle(*next_level_value_p));
-           break;
-
-         case SPNEGO_mechListMIC:
-
-           offset = dissect_spnego_mechListMIC(tvb, offset, pinfo, subtree, 
-                                               hnd, gssapi_dissector_handle(*next_level_value_p));
-           break;
-
-         default:
-
-           break;
-         }
-
-         len1 -= len;
-
-       }
-
- done:
-       return offset;
-
-}
 
 static void
-dissect_spnego(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+dissect_spnego(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
 {
        proto_item *item;
        proto_tree *subtree;
-       int ret, offset = 0;
-       ASN1_SCK hnd;
-       gboolean def;
-       guint len1, cls, con, tag;
+       int offset = 0;
        conversation_t *conversation;
-       gssapi_oid_value *next_level_value;
 
        /*
         * We need this later, so lets get it now ...
@@ -1643,7 +1277,7 @@ dissect_spnego(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
            }
        }
 
-       item = proto_tree_add_item(tree, hf_spnego, tvb, offset, 
+       item = proto_tree_add_item(parent_tree, hf_spnego, tvb, offset, 
                                   -1, FALSE);
 
        subtree = proto_item_add_subtree(item, ett_spnego);
@@ -1652,7 +1286,7 @@ dissect_spnego(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
         * The TVB contains a [0] header and a sequence that consists of an
         * object ID and a blob containing the data ...
         * Actually, it contains, according to RFC2478:
-         * NegotiationToken ::= CHOICE {
+     * NegotiationToken ::= CHOICE {
         *          negTokenInit [0] NegTokenInit,
         *          negTokenTarg [1] NegTokenTarg }
         * NegTokenInit ::= SEQUENCE {
@@ -1660,268 +1294,43 @@ dissect_spnego(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
         *          reqFlags [1] ContextFlags OPTIONAL,
         *          mechToken [2] OCTET STRING OPTIONAL,
         *          mechListMIC [3] OCTET STRING OPTIONAL }
-         * NegTokenTarg ::= SEQUENCE {
+     * NegTokenTarg ::= SEQUENCE {
         *          negResult [0] ENUMERATED {
         *              accept_completed (0),
         *              accept_incomplete (1),
         *              reject (2) } OPTIONAL,
-         *          supportedMech [1] MechType OPTIONAL,
-         *          responseToken [2] OCTET STRING OPTIONAL,
-         *          mechListMIC [3] OCTET STRING OPTIONAL }
-         *
+     *          supportedMech [1] MechType OPTIONAL,
+     *          responseToken [2] OCTET STRING OPTIONAL,
+     *          mechListMIC [3] OCTET STRING OPTIONAL }
+     *
         * Windows typically includes mechTypes and mechListMic ('NONE'
         * in the case of NTLMSSP only).
-         * It seems to duplicate the responseToken into the mechListMic field
-         * as well. Naughty, naughty.
-         *
-        */
-
-       asn1_open(&hnd, tvb, offset);
-
-       /*
-        * Get the first header ...
+     * It seems to duplicate the responseToken into the mechListMic field
+     * as well. Naughty, naughty.
+     *
         */
-
-       ret = asn1_header_decode(&hnd, &cls, &con, &tag, &def, &len1);
-
-       if (ret != ASN1_ERR_NOERROR) {
-               dissect_parse_error(tvb, offset, pinfo, subtree,
-                                   "SPNEGO context header", ret);
-               goto done;
-       }
-
-       if (!(cls == ASN1_CTX && con == ASN1_CON)) {
-               proto_tree_add_text(
-                       subtree, tvb, offset, 0,
-                       "Unknown header (cls=%d, con=%d, tag=%d)",
-                       cls, con, tag);
-               goto done;
-       }
-
-       offset = hnd.offset;
-
-       /*
-        * The Tag is one of negTokenInit or negTokenTarg
-        */
-
-       switch (tag) {
-
-       case SPNEGO_negTokenInit:
-
-         offset = dissect_spnego_negTokenInit(tvb, offset, pinfo,
-                                              subtree, &hnd,
-                                              &next_level_value);
-
-         break;
-
-       case SPNEGO_negTokenTarg:
-
-         offset = dissect_spnego_negTokenTarg(tvb, offset, pinfo,
-                                              subtree, &hnd,
-                                              &next_level_value);
-         break;
-
-       default: /* Broken, what to do? */
-
-         break;
-       }
-
-
- done:
-       asn1_close(&hnd, &offset);
+       offset = dissect_spnego_NegotiationToken(FALSE, tvb, offset, pinfo, subtree, -1);
 
 }
 
-static int
-dissect_spnego_wrap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
-{
-       proto_item *item;
-       proto_tree *subtree;
-       int return_offset;
-       conversation_t *conversation;
-       gssapi_oid_value *next_level_value;
-       tvbuff_t *token_tvb;
-       int len, offset, start_offset;
-       gint8 class;
-       gboolean pc, ind_field;
-       gint32 tag;
-       guint32 len1;
-       gchar oid[MAX_OID_STR_LEN];
-
-       start_offset=0;
-       offset=start_offset;
-
-       /*
-        * We need this later, so lets get it now ...
-        * It has to be per-frame as there can be more than one GSS-API
-        * negotiation in a conversation.
-        */
-
-       next_level_value = p_get_proto_data(pinfo->fd, proto_spnego);
-       if (!next_level_value && !pinfo->fd->flags.visited) {
-           /*
-            * No handle attached to this frame, but it's the first
-            * pass, so it'd be attached to the conversation.
-            * If we have a conversation, try to get the handle,
-            * and if we get one, attach it to the frame.
-            */
-           conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
-                                            pinfo->ptype, pinfo->srcport,
-                                            pinfo->destport, 0);
-
-           if (conversation) {
-               next_level_value = conversation_get_proto_data(conversation, 
-                                                              proto_spnego);
-               if (next_level_value)
-                   p_add_proto_data(pinfo->fd, proto_spnego, next_level_value);
-           }
-       }
-
-       item = proto_tree_add_item(tree, hf_spnego, tvb, offset, 
-                                  -1, FALSE);
-
-       subtree = proto_item_add_subtree(item, ett_spnego);
-
-       /*
-        * The TVB contains a [0] header and a sequence that consists of an
-        * object ID and a blob containing the data ...
-        * XXX - is this RFC 2743's "Mechanism-Independent Token Format",
-        * with the "optional" "use in non-initial tokens" being chosen.
-        */
-
-       /*
-        * Get the first header ...
-        */
-       offset = get_ber_identifier(tvb, offset, &class, &pc, &tag);
-       offset = get_ber_length(tree, tvb, offset, &len1, &ind_field);
-
-       if (!(class == BER_CLASS_APP && pc && tag == 0)) {
-               proto_tree_add_text(
-                       subtree, tvb, start_offset, 0,
-                       "Unknown header (class=%d, pc=%d, tag=%d)",
-                       class, pc, tag);
-               return_offset = tvb_length(tvb);
-               goto done;
-       }
-
-       /*
-        * Get the OID, and find the handle, if any
-        *
-        * XXX - what should we do if this OID doesn't match the value
-        * attached to the frame or conversation?  (That would be
-        * bogus, but that's not impossible - some broken implementation
-        * might negotiate some security mechanism but put the OID
-        * for some other security mechanism in GSS_Wrap tokens.)
-        */
-       offset=dissect_ber_object_identifier(FALSE, pinfo, subtree, tvb, offset, hf_spnego_this_mech, oid);
-       next_level_value = gssapi_lookup_oid_str(oid);
-
-       /*
-        * Now dissect the GSS_Wrap token; it's assumed to be in the
-        * rest of the tvbuff.
-        */
-       item = proto_tree_add_item(tree, hf_spnego_wraptoken, tvb, offset, 
-                                  -1, FALSE); 
+/*--- proto_register_spnego -------------------------------------------*/
+void proto_register_spnego(void) {
 
-       subtree = proto_item_add_subtree(item, ett_spnego_wraptoken);
-
-       /*
-        * Now, we should be able to dispatch after creating a new TVB.
-        * The subdissector must return the length of the part of the
-        * token it dissected, so we can return the length of the part
-        * we (and it) dissected.
-        */
-
-       token_tvb = tvb_new_subset(tvb, offset, -1, -1);
-       if (next_level_value->wrap_handle) {
-         len = call_dissector(next_level_value->wrap_handle, token_tvb, pinfo, subtree);
-         if (len == 0)
-           return_offset = tvb_length(tvb);
-         else
-           return_offset = offset + len;
-       } else
-         return_offset = tvb_length(tvb);
- done:
-
-       return return_offset;
-}
-
-void
-proto_register_spnego(void)
-{
-       static hf_register_info hf[] = {
+  /* List of fields */
+  static hf_register_info hf[] = {
                { &hf_spnego,
                  { "SPNEGO", "spnego", FT_NONE, BASE_NONE, NULL, 0x0,
                    "SPNEGO", HFILL }},
-               { &hf_spnego_mech, {
-                   "Mech", "spnego.mech", FT_STRING, BASE_NONE,
-                   NULL, 0, "This is a SPNEGO Object Identifier", HFILL }},
-               { &hf_spnego_supportedMech, {
-                   "supportedMech", "spnego.supportedMech", FT_STRING, BASE_NONE,
-                   NULL, 0, "This is a SPNEGO Object Identifier", HFILL }},
-                       {&hf_spnego_krb5_oid, {
-                   "KRB5 OID", "spnego.krb5_oid", FT_STRING, BASE_NONE,
-                   NULL, 0, "KRB5 OID", HFILL }},
-               { &hf_spnego_this_mech, {
-                   "thisMech", "spnego.this_mech", FT_STRING, BASE_NONE,
-                   NULL, 0, "This is a SPNEGO Object Identifier", HFILL }},
-               { &hf_spnego_negtokeninit,
-                 { "negTokenInit", "spnego.negtokeninit", FT_NONE, BASE_NONE,
-                   NULL, 0x0, "SPNEGO negTokenInit", HFILL}},
-               { &hf_spnego_negtokentarg,
-                 { "negTokenTarg", "spnego.negtokentarg", FT_NONE, BASE_NONE,
-                   NULL, 0x0, "SPNEGO negTokenTarg", HFILL}},
-               { &hf_spnego_mechtype,
-                 { "mechType", "spnego.negtokeninit.mechtype", FT_NONE,
-                   BASE_NONE, NULL, 0x0, "SPNEGO negTokenInit mechTypes", HFILL}},
-               { &hf_spnego_mechtoken,
-                 { "mechToken", "spnego.negtokeninit.mechtoken", FT_NONE,
-                   BASE_NONE, NULL, 0x0, "SPNEGO negTokenInit mechToken", HFILL}},
-               { &hf_spnego_mechlistmic,
-                 { "mechListMIC", "spnego.mechlistmic", FT_NONE,
-                   BASE_NONE, NULL, 0x0, "SPNEGO mechListMIC", HFILL}}, 
-               { &hf_spnego_responsetoken,
-                 { "responseToken", "spnego.negtokentarg.responsetoken",
-                   FT_NONE, BASE_NONE, NULL, 0x0, "SPNEGO responseToken",
-                   HFILL}},
-               { &hf_spnego_negtokentarg_negresult,
-                 { "negResult", "spnego.negtokeninit.negresult", FT_UINT16,
-                   BASE_HEX, VALS(spnego_negResult_vals), 0, "negResult", HFILL}},
-               { &hf_spnego_reqflags, 
-                 { "reqFlags", "spnego.negtokeninit.reqflags", FT_BYTES,
-                   BASE_HEX, NULL, 0, "reqFlags", HFILL }},
-                { &hf_gssapi_reqflags_deleg,
-                  { "Delegation", "gssapi.reqflags.deleg", FT_BOOLEAN, 8,
-                    TFS(&tfs_reqflags_deleg), 0x01, "Delegation", HFILL }},
-                { &hf_gssapi_reqflags_mutual,
-                  { "Mutual Authentication", "gssapi.reqflags.mutual", FT_BOOLEAN,
-                    8, TFS(&tfs_reqflags_mutual), 0x02, "Mutual Authentication", HFILL}},
-                { &hf_gssapi_reqflags_replay,
-                  { "Replay Detection", "gssapi.reqflags.replay", FT_BOOLEAN,
-                    8, TFS(&tfs_reqflags_replay), 0x04, "Replay Detection", HFILL}},
-                { &hf_gssapi_reqflags_sequence,
-                  { "Out-of-sequence Detection", "gssapi.reqflags.sequence",
-                    FT_BOOLEAN, 8, TFS(&tfs_reqflags_sequence), 0x08, 
-                    "Out-of-sequence Detection", HFILL}},
-                { &hf_gssapi_reqflags_anon,
-                  { "Anonymous Authentication", "gssapi.reqflags.anon", 
-                    FT_BOOLEAN, 8, TFS(&tfs_reqflags_anon), 0x10,
-                    "Anonymous Authentication", HFILL}},
-                { &hf_gssapi_reqflags_conf,
-                  { "Per-message Confidentiality", "gssapi.reqflags.conf",
-                    FT_BOOLEAN, 8, TFS(&tfs_reqflags_conf), 0x20, 
-                    "Per-message Confidentiality", HFILL}},
-                { &hf_gssapi_reqflags_integ,
-                  { "Per-message Integrity", "gssapi.reqflags.integ", 
-                    FT_BOOLEAN, 8, TFS(&tfs_reqflags_integ), 0x40,
-                    "Per-message Integrity", HFILL}},
-               { &hf_spnego_wraptoken,
+         { &hf_spnego_wraptoken,
                  { "wrapToken", "spnego.wraptoken",
                    FT_NONE, BASE_NONE, NULL, 0x0, "SPNEGO wrapToken",
                    HFILL}},
                { &hf_spnego_krb5,
                  { "krb5_blob", "spnego.krb5.blob", FT_BYTES,
                    BASE_NONE, NULL, 0, "krb5_blob", HFILL }},
+               {&hf_spnego_krb5_oid,
+               {"KRB5 OID", "spnego.krb5_oid", FT_STRING, 
+                       BASE_NONE, NULL, 0, "KRB5 OID", HFILL }},
                { &hf_spnego_krb5_tok_id,
                  { "krb5_tok_id", "spnego.krb5.tok_id", FT_UINT16, BASE_HEX,
                    VALS(spnego_krb5_tok_id_vals), 0, "KRB5 Token Id", HFILL}},
@@ -1940,33 +1349,127 @@ proto_register_spnego(void)
                { &hf_spnego_krb5_confounder,
                  { "krb5_confounder", "spnego.krb5.confounder", FT_BYTES, BASE_NONE,
                    NULL, 0, "KRB5 Confounder", HFILL}},
-       };
 
-       static gint *ett[] = {
+
+/*--- Included file: packet-spnego-hfarr.c ---*/
+
+    { &hf_spnego_negTokenInit,
+      { "negTokenInit", "spnego.negTokenInit",
+        FT_NONE, BASE_NONE, NULL, 0,
+        "NegotiationToken/negTokenInit", HFILL }},
+    { &hf_spnego_negTokenTarg,
+      { "negTokenTarg", "spnego.negTokenTarg",
+        FT_NONE, BASE_NONE, NULL, 0,
+        "NegotiationToken/negTokenTarg", HFILL }},
+    { &hf_spnego_MechTypeList_item,
+      { "Item", "spnego.MechTypeList_item",
+        FT_STRING, BASE_NONE, NULL, 0,
+        "MechTypeList/_item", HFILL }},
+    { &hf_spnego_mechTypes,
+      { "mechTypes", "spnego.mechTypes",
+        FT_UINT32, BASE_DEC, NULL, 0,
+        "NegTokenInit/mechTypes", HFILL }},
+    { &hf_spnego_reqFlags,
+      { "reqFlags", "spnego.reqFlags",
+        FT_BYTES, BASE_HEX, NULL, 0,
+        "NegTokenInit/reqFlags", HFILL }},
+    { &hf_spnego_mechToken,
+      { "mechToken", "spnego.mechToken",
+        FT_BYTES, BASE_HEX, NULL, 0,
+        "NegTokenInit/mechToken", HFILL }},
+    { &hf_spnego_mechListMIC,
+      { "mechListMIC", "spnego.mechListMIC",
+        FT_BYTES, BASE_HEX, NULL, 0,
+        "", HFILL }},
+    { &hf_spnego_negResult,
+      { "negResult", "spnego.negResult",
+        FT_UINT32, BASE_DEC, VALS(spnego_T_negResult_vals), 0,
+        "NegTokenTarg/negResult", HFILL }},
+    { &hf_spnego_supportedMech,
+      { "supportedMech", "spnego.supportedMech",
+        FT_STRING, BASE_NONE, NULL, 0,
+        "NegTokenTarg/supportedMech", HFILL }},
+    { &hf_spnego_responseToken,
+      { "responseToken", "spnego.responseToken",
+        FT_BYTES, BASE_HEX, NULL, 0,
+        "NegTokenTarg/responseToken", HFILL }},
+    { &hf_spnego_thisMech,
+      { "thisMech", "spnego.thisMech",
+        FT_STRING, BASE_NONE, NULL, 0,
+        "InitialContextToken/thisMech", HFILL }},
+    { &hf_spnego_innerContextToken,
+      { "innerContextToken", "spnego.innerContextToken",
+        FT_NONE, BASE_NONE, NULL, 0,
+        "InitialContextToken/innerContextToken", HFILL }},
+    { &hf_spnego_ContextFlags_delegFlag,
+      { "delegFlag", "spnego.delegFlag",
+        FT_BOOLEAN, 8, NULL, 0x80,
+        "", HFILL }},
+    { &hf_spnego_ContextFlags_mutualFlag,
+      { "mutualFlag", "spnego.mutualFlag",
+        FT_BOOLEAN, 8, NULL, 0x40,
+        "", HFILL }},
+    { &hf_spnego_ContextFlags_replayFlag,
+      { "replayFlag", "spnego.replayFlag",
+        FT_BOOLEAN, 8, NULL, 0x20,
+        "", HFILL }},
+    { &hf_spnego_ContextFlags_sequenceFlag,
+      { "sequenceFlag", "spnego.sequenceFlag",
+        FT_BOOLEAN, 8, NULL, 0x10,
+        "", HFILL }},
+    { &hf_spnego_ContextFlags_anonFlag,
+      { "anonFlag", "spnego.anonFlag",
+        FT_BOOLEAN, 8, NULL, 0x08,
+        "", HFILL }},
+    { &hf_spnego_ContextFlags_confFlag,
+      { "confFlag", "spnego.confFlag",
+        FT_BOOLEAN, 8, NULL, 0x04,
+        "", HFILL }},
+    { &hf_spnego_ContextFlags_integFlag,
+      { "integFlag", "spnego.integFlag",
+        FT_BOOLEAN, 8, NULL, 0x02,
+        "", HFILL }},
+
+/*--- End of included file: packet-spnego-hfarr.c ---*/
+
+  };
+
+  /* List of subtrees */
+  static gint *ett[] = {
                &ett_spnego,
-               &ett_spnego_negtokeninit,
-               &ett_spnego_negtokentarg,
-               &ett_spnego_mechtype,
-               &ett_spnego_mechtoken,
-               &ett_spnego_mechlistmic,
-               &ett_spnego_responsetoken,
                &ett_spnego_wraptoken,
                &ett_spnego_krb5,
-       };
 
-       proto_spnego = proto_register_protocol(
-               "Spnego", "Spnego", "spnego");
+
+/*--- Included file: packet-spnego-ettarr.c ---*/
+
+    &ett_spnego_NegotiationToken,
+    &ett_spnego_MechTypeList,
+    &ett_spnego_NegTokenInit,
+    &ett_spnego_ContextFlags,
+    &ett_spnego_NegTokenTarg,
+    &ett_spnego_InitialContextToken,
+
+/*--- End of included file: packet-spnego-ettarr.c ---*/
+
+  };
+
+  /* Register protocol */
+  proto_spnego = proto_register_protocol(PNAME, PSNAME, PFNAME);
+
        proto_spnego_krb5 = proto_register_protocol("SPNEGO-KRB5",
                                                    "SPNEGO-KRB5",
                                                    "spnego-krb5");
+  /* Register fields and subtrees */
+  proto_register_field_array(proto_spnego, hf, array_length(hf));
+  proto_register_subtree_array(ett, array_length(ett));
 
-       proto_register_field_array(proto_spnego, hf, array_length(hf));
-       proto_register_subtree_array(ett, array_length(ett));
 }
 
-void
-proto_reg_handoff_spnego(void)
-{
+
+/*--- proto_reg_handoff_spnego ---------------------------------------*/
+void proto_reg_handoff_spnego(void) {
+
        dissector_handle_t spnego_handle, spnego_wrap_handle;
        dissector_handle_t spnego_krb5_handle, spnego_krb5_wrap_handle;
 
@@ -2006,4 +1509,5 @@ proto_reg_handoff_spnego(void)
         * Find the data handle for some calls
         */
        data_handle = find_dissector("data");
+
 }
diff --git a/epan/dissectors/packet-spnego.h b/epan/dissectors/packet-spnego.h
new file mode 100644 (file)
index 0000000..8a37f99
--- /dev/null
@@ -0,0 +1,37 @@
+/* Do not modify this file.                                                   */
+/* It is created automatically by the ASN.1 to Ethereal dissector compiler    */
+/* .\packet-spnego.h                                                          */
+/* ../../tools/asn2eth.py -X -b -e -p spnego -c spnego.cnf -s packet-spnego-template spnego.asn */
+
+/* Input file: packet-spnego-template.h */
+
+/* packet-spnego.h
+ * Routines for spnego packet dissection
+ *
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef PACKET_SPNEGO_H
+#define PACKET_SPNEGO_H
+
+/*#include "packet-spnego-exp.h"*/
+
+#endif  /* PACKET_spnego_H */