Add HP Switch Protocol SAP value
[obnox/wireshark/wip.git] / epan / dissectors / packet-gssapi.c
1 /* packet-gssapi.c
2  * Dissector for GSS-API tokens as described in rfc2078, section 3.1
3  * Copyright 2002, Tim Potter <tpot@samba.org>
4  * Copyright 2002, Richard Sharpe <rsharpe@samba.org> Added a few 
5  *                 bits and pieces ...
6  *
7  * $Id$
8  *
9  * Wireshark - Network traffic analyzer
10  * By Gerald Combs <gerald@wireshark.org>
11  * Copyright 1998 Gerald Combs
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #ifdef HAVE_SYS_TYPES_H
33 # include <sys/types.h>
34 #endif
35
36 #include <string.h>
37
38 #include <glib.h>
39 #include <epan/packet.h>
40
41 #include <epan/dissectors/packet-dcerpc.h>
42 #include <epan/dissectors/packet-gssapi.h>
43 #include <epan/dissectors/packet-frame.h>
44 #include "epan/conversation.h"
45 #include "epan/emem.h"
46 #include "epan/prefs.h"
47 #include "epan/reassemble.h"
48 #include "packet-ber.h"
49 #include "to_str.h"
50
51 static int proto_gssapi = -1;
52
53 static int hf_gssapi_oid = -1;
54 static int hf_gssapi_segments = -1;
55 static int hf_gssapi_segment = -1;
56 static int hf_gssapi_segment_overlap = -1;
57 static int hf_gssapi_segment_overlap_conflict = -1;
58 static int hf_gssapi_segment_multiple_tails = -1;
59 static int hf_gssapi_segment_too_long_fragment = -1;
60 static int hf_gssapi_segment_error = -1;
61 static int hf_gssapi_reassembled_in = -1;
62
63 static gint ett_gssapi = -1;
64 static gint ett_gssapi_segment = -1;
65 static gint ett_gssapi_segments = -1;
66
67 static gboolean gssapi_reassembly = TRUE;
68
69 typedef struct _gssapi_conv_info_t {
70         gssapi_oid_value *oid;
71
72         emem_tree_t *frags;
73
74         gboolean do_reassembly;  /* this field is used on first sequential scan of packets to help indicate when the next blob is a fragment continuing a previous one */
75         int first_frame;
76         int frag_offset;        
77 } gssapi_conv_info_t;
78
79 typedef struct _gssapi_frag_info_t {
80         guint32 first_frame;
81         guint32 reassembled_in;
82 } gssapi_frag_info_t;
83
84 static const fragment_items gssapi_frag_items = {
85         &ett_gssapi_segment,
86         &ett_gssapi_segments,
87
88         &hf_gssapi_segments,
89         &hf_gssapi_segment,
90         &hf_gssapi_segment_overlap,
91         &hf_gssapi_segment_overlap_conflict,
92         &hf_gssapi_segment_multiple_tails,
93         &hf_gssapi_segment_too_long_fragment,
94         &hf_gssapi_segment_error,
95         NULL,
96
97         "fragments"
98 };
99
100
101 static GHashTable *gssapi_fragment_table = NULL;
102
103 static void
104 gssapi_reassembly_init(void)
105 {
106         fragment_table_init(&gssapi_fragment_table);
107 }
108
109 /*
110  * Subdissectors
111  */
112
113 static dissector_handle_t ntlmssp_handle = NULL;
114
115 static GHashTable *gssapi_oids;
116
117 static gint gssapi_oid_equal(gconstpointer k1, gconstpointer k2)
118 {
119         const char *key1 = (const char *)k1;
120         const char *key2 = (const char *)k2;
121
122         return strcmp(key1, key2) == 0;
123 }
124
125 static guint
126 gssapi_oid_hash(gconstpointer k)
127 {
128         const char *key = (const char *)k;
129         guint hash = 0, i;
130
131         for (i = 0; i < strlen(key); i++)
132                 hash += key[i];
133
134         return hash;
135 }
136
137 void
138 gssapi_init_oid(const char *oid, int proto, int ett, dissector_handle_t handle,
139                 dissector_handle_t wrap_handle, const gchar *comment)
140 {
141         char *key = g_strdup(oid);
142         gssapi_oid_value *value = g_malloc(sizeof(*value));
143
144         value->proto = find_protocol_by_id(proto);
145         value->ett = ett;
146         value->handle = handle;
147         value->wrap_handle = wrap_handle;
148         value->comment = comment;
149
150         g_hash_table_insert(gssapi_oids, key, value);
151         register_ber_oid_dissector_handle(key, handle, proto, comment);
152 }
153
154 /*
155  * This takes an OID in text string form as
156  * an argument.
157  */
158 gssapi_oid_value *
159 gssapi_lookup_oid_str(const char *oid_key)
160 {
161         gssapi_oid_value *value;
162         if(!oid_key){
163                 return NULL;
164         }
165         value = g_hash_table_lookup(gssapi_oids, oid_key);
166         return value;
167 }
168
169 static int
170 dissect_gssapi_work(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
171     gboolean is_verifier)
172 {
173         proto_item *item;
174         proto_tree *subtree;
175         int return_offset = 0;
176         gssapi_conv_info_t *gss_info;
177         gssapi_oid_value *oidvalue;
178         dissector_handle_t handle;
179         conversation_t *conversation;
180         tvbuff_t *oid_tvb;
181         int len, offset, start_offset, oid_start_offset;
182         gint8 class;
183         gboolean pc, ind_field;
184         gint32 tag;
185         guint32 len1;
186         const char *oid;
187         fragment_data *fd_head=NULL;
188         gssapi_frag_info_t *fi;
189         tvbuff_t *gss_tvb=NULL;
190
191         start_offset=0;
192         offset=0;
193
194         /*
195          * We don't know whether the data is encrypted, so say it's
196          * not, for now.  The subdissector must set gssapi_data_encrypted
197          * if it is.
198          */
199         pinfo->gssapi_data_encrypted = FALSE;
200
201
202         /*
203          * We need a conversation for later
204          */
205         conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
206                                          pinfo->ptype, pinfo->srcport,
207                                          pinfo->destport, 0);
208         if(!conversation){
209                 conversation = conversation_new(pinfo->fd->num, &pinfo->src,
210                                           &pinfo->dst, 
211                                           pinfo->ptype, 
212                                           pinfo->srcport, 
213                                           pinfo->destport, 0);
214         }
215         gss_info = conversation_get_proto_data(conversation, proto_gssapi);
216         if (!gss_info) {
217                 gss_info = se_alloc(sizeof(gssapi_conv_info_t));
218                 gss_info->oid=NULL;
219                 gss_info->do_reassembly=FALSE;
220                 gss_info->frags=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "gssapi_frags");
221
222                 conversation_add_proto_data(conversation, proto_gssapi, gss_info);
223         }
224
225
226         item = proto_tree_add_item(
227                 tree, proto_gssapi, tvb, offset, -1, FALSE);
228
229         subtree = proto_item_add_subtree(item, ett_gssapi);
230
231         /*
232          * Catch the ReportedBoundsError exception; the stuff we've been
233          * handed doesn't necessarily run to the end of the packet, it's
234          * an item inside a packet, so if it happens to be malformed (or
235          * we, or a dissector we call, has a bug), so that an exception
236          * is thrown, we want to report the error, but return and let
237          * our caller dissect the rest of the packet.
238          *
239          * If it gets a BoundsError, we can stop, as there's nothing more
240          * in the packet after our blob to see, so we just re-throw the
241          * exception.
242          */
243         TRY {
244                 gss_tvb=tvb;
245
246
247                 /* First of all, if its the first time we see this packet
248                  * then check whether we are in the middle of reassembly or not
249                  */
250                 if( (!pinfo->fd->flags.visited)
251                 &&  (gss_info->do_reassembly)
252                 &&  (gssapi_reassembly) ){
253                         fi=se_tree_lookup32(gss_info->frags, gss_info->first_frame);
254                         if(!fi){
255                                 goto done;
256                         }
257                         se_tree_insert32(gss_info->frags, pinfo->fd->num, fi);
258                         fd_head=fragment_add(tvb, 0, pinfo, fi->first_frame,
259                                 gssapi_fragment_table, gss_info->frag_offset,
260                                 tvb_length(tvb), TRUE);
261                         gss_info->frag_offset+=tvb_length(tvb);
262
263                         /* we need more fragments */
264                         if(!fd_head){
265                                 goto done;
266                         }
267
268                         /* this blob is now fully reassembled */
269                         gss_info->do_reassembly=FALSE;
270                         fi->reassembled_in=pinfo->fd->num;
271
272                         gss_tvb=tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
273                         tvb_set_child_real_data_tvbuff(tvb, gss_tvb);
274                         add_new_data_source(pinfo, gss_tvb, "Reassembled GSSAPI");
275                 }
276                 /* We have seen this packet before.
277                  * Is this blob part of reassembly or a normal blob ?
278                  */
279                 if( (pinfo->fd->flags.visited)
280                 &&  (gssapi_reassembly) ){      
281                         fi=se_tree_lookup32(gss_info->frags, pinfo->fd->num);
282                         if(fi){
283                                 fd_head=fragment_get(pinfo, fi->first_frame, gssapi_fragment_table);
284                                 if(fd_head && (fd_head->flags&FD_DEFRAGMENTED)){
285                                         if(pinfo->fd->num==fi->reassembled_in){
286                                                 proto_item *frag_tree_item;
287                                                 gss_tvb=tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
288                                                 tvb_set_child_real_data_tvbuff(tvb, gss_tvb);
289                                                 add_new_data_source(pinfo, gss_tvb, "Reassembled GSSAPI");
290                                                 show_fragment_tree(fd_head, &gssapi_frag_items, tree, pinfo, tvb, &frag_tree_item);
291                                         } else {
292                                                 proto_item *it;
293                                                 it=proto_tree_add_uint(tree, hf_gssapi_reassembled_in, tvb, 0, 0, fi->reassembled_in);
294                                                 PROTO_ITEM_SET_GENERATED(it);
295                                                 goto done;
296                                         }
297                                 }
298                         }
299                 }
300
301                 /* Read header */
302                 offset = get_ber_identifier(gss_tvb, offset, &class, &pc, &tag);
303                 offset = get_ber_length(tree, gss_tvb, offset, &len1, &ind_field);
304
305
306                 if (!(class == BER_CLASS_APP && pc && tag == 0)) {
307                   /* 
308                    * If we do not recognise an Application class,
309                    * then we are probably dealing with an inner context
310                    * token or a wrap token, and we should retrieve the
311                    * gssapi_oid_value pointer from the per-frame data or,
312                    * if there is no per-frame data (as would be the case
313                    * the first time we dissect this frame), from the
314                    * conversation that exists or that we created from
315                    * pinfo (and then make it per-frame data).
316                    * We need to make it per-frame data as there can be
317                    * more than one GSS-API negotiation in a conversation.
318                    *
319                    * Note! We "cheat". Since we only need the pointer,
320                    * we store that as the data.  (That's not really
321                    * "cheating" - the per-frame data and per-conversation
322                    * data code doesn't care what you supply as a data
323                    * pointer; it just treats it as an opaque pointer, it
324                    * doesn't dereference it or free what it points to.)
325                    */
326                   oidvalue = p_get_proto_data(pinfo->fd, proto_gssapi);
327                   if (!oidvalue && !pinfo->fd->flags.visited)
328                   {
329                     /* No handle attached to this frame, but it's the first */
330                     /* pass, so it'd be attached to the conversation. */
331                     oidvalue = gss_info->oid;
332                     if (gss_info->oid)
333                       p_add_proto_data(pinfo->fd, proto_gssapi, gss_info->oid);
334                   }
335                   if (!oidvalue)
336                   {
337                     /* It could be NTLMSSP, with no OID.  This can happen 
338                        for anything that microsoft calls 'Negotiate' or GSS-SPNEGO */
339                     if (tvb_strneql(gss_tvb, start_offset, "NTLMSSP", 7) == 0) {
340                       call_dissector(ntlmssp_handle, tvb_new_subset(gss_tvb, start_offset, -1, -1), pinfo, subtree);
341                     } else {
342                       proto_tree_add_text(subtree, gss_tvb, start_offset, 0,
343                                           "Unknown header (class=%d, pc=%d, tag=%d)",
344                                           class, pc, tag);
345                     }
346                     return_offset = tvb_length(gss_tvb);
347                     goto done;
348
349                   } else {
350                     tvbuff_t *oid_tvb;
351
352                     oid_tvb = tvb_new_subset(gss_tvb, start_offset, -1, -1);
353                     if (is_verifier)
354                         handle = oidvalue->wrap_handle;
355                     else
356                         handle = oidvalue->handle;
357                     len = call_dissector(handle, oid_tvb, pinfo, subtree);
358                     if (len == 0)
359                         return_offset = tvb_length(gss_tvb);
360                     else
361                         return_offset = start_offset + len;
362                     goto done; /* We are finished here */
363                   }
364                 }
365
366                 /* Read oid */
367                 oid_start_offset=offset;
368                 offset=dissect_ber_object_identifier_str(FALSE, pinfo, subtree, gss_tvb, offset, hf_gssapi_oid, &oid);
369                 oidvalue = gssapi_lookup_oid_str(oid);
370
371
372                 /* Check if we need reassembly of this blob.
373                  * Only try reassembly for OIDs we recognize
374                  * and when we have the entire tvb
375                  *
376                  * SMB will sometimes split one large GSSAPI blob
377                  * across multiple SMB/SessionSetup commands.
378                  * While we should look at the uid returned in the response
379                  * to the first SessionSetup and use that as a key
380                  * instead for simplicity we assume there will not be several
381                  * such authentication at once on a single tcp session
382                  */
383                 if( (!pinfo->fd->flags.visited)
384                 &&  (oidvalue)
385                 &&  (tvb_length(gss_tvb)==tvb_reported_length(gss_tvb))
386                 &&  (len1>(guint32)tvb_length_remaining(gss_tvb, oid_start_offset))
387                 &&  (gssapi_reassembly) ){      
388                         fi=se_alloc(sizeof(gssapi_frag_info_t));
389                         fi->first_frame=pinfo->fd->num;
390                         fi->reassembled_in=0;
391                         se_tree_insert32(gss_info->frags, pinfo->fd->num, fi);
392
393                         fragment_add(gss_tvb, 0, pinfo, pinfo->fd->num,
394                                 gssapi_fragment_table, 0,
395                                 tvb_length(gss_tvb), TRUE);
396                         fragment_set_tot_len(pinfo, pinfo->fd->num, gssapi_fragment_table, len1+oid_start_offset);
397
398                         gss_info->do_reassembly=TRUE;
399                         gss_info->first_frame=pinfo->fd->num;
400                         gss_info->frag_offset=tvb_length(gss_tvb);
401                         goto done;
402                 }
403
404
405                 /*
406                  * Hand off to subdissector.
407                  */
408
409                 if ((oidvalue == NULL) ||
410                     !proto_is_protocol_enabled(oidvalue->proto)) {
411                         /* No dissector for this oid */
412                         proto_tree_add_text(subtree, gss_tvb, oid_start_offset, -1,
413                                             "Token object");
414
415                         return_offset = tvb_length(gss_tvb);
416                         goto done;
417                 }
418
419                 /* Save a pointer to the data for the OID for the
420                  * GSSAPI protocol for this conversation.
421                  */
422
423                 /*
424                  * Now add the proto data ... 
425                  * but only if it is not already there.
426                  */
427                 if(!gss_info->oid){
428                   gss_info->oid=oidvalue;
429                 }
430
431                 if (is_verifier) {
432                         handle = oidvalue->wrap_handle;
433                         if (handle != NULL) {
434                                 oid_tvb = tvb_new_subset(gss_tvb, offset, -1, -1);
435                                 len = call_dissector(handle, oid_tvb, pinfo,
436                                     subtree);
437                                 if (len == 0)
438                                         return_offset = tvb_length(gss_tvb);
439                                 else
440                                         return_offset = offset + len;
441                         } else {
442                                 proto_tree_add_text(subtree, gss_tvb, offset, -1,
443                                     "Authentication verifier");
444                                 return_offset = tvb_length(gss_tvb);
445                         }
446                 } else {
447                         handle = oidvalue->handle;
448                         if (handle != NULL) {
449                                 oid_tvb = tvb_new_subset(gss_tvb, offset, -1, -1);
450                                 len = call_dissector(handle, oid_tvb, pinfo,
451                                     subtree);
452                                 if (len == 0)
453                                         return_offset = tvb_length(gss_tvb);
454                                 else
455                                         return_offset = offset + len;
456                         } else {
457                                 proto_tree_add_text(subtree, gss_tvb, offset, -1,
458                                     "Authentication credentials");
459                                 return_offset = tvb_length(gss_tvb);
460                         }
461                 }
462
463          done:
464                 ;
465         } CATCH(BoundsError) {
466                 RETHROW;
467         } CATCH(ReportedBoundsError) {
468                 show_reported_bounds_error(gss_tvb, pinfo, tree);
469         } ENDTRY;
470
471         proto_item_set_len(item, return_offset);
472         return return_offset;
473 }
474
475 static void
476 dissect_gssapi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
477 {
478         dissect_gssapi_work(tvb, pinfo, tree, FALSE);
479 }
480
481 static int
482 dissect_gssapi_verf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
483 {
484         return dissect_gssapi_work(tvb, pinfo, tree, TRUE);
485 }
486
487 void
488 proto_register_gssapi(void)
489 {
490         static hf_register_info hf[] = {
491         { &hf_gssapi_oid, 
492                 { "OID", "gssapi.OID", FT_STRING, BASE_NONE,
493                   NULL, 0, "This is a GSS-API Object Identifier", HFILL }},
494         { &hf_gssapi_segment,
495                 { "GSSAPI Segment", "gssapi.segment", FT_FRAMENUM, BASE_NONE, 
496                   NULL, 0x0, "GSSAPI Segment", HFILL }},
497         { &hf_gssapi_segments,
498                 { "GSSAPI Segments", "gssapi.segment.segments", FT_NONE, BASE_NONE, 
499                   NULL, 0x0, "GSSAPI Segments", HFILL }},
500         { &hf_gssapi_segment_overlap,
501                 { "Fragment overlap",   "gssapi.segment.overlap", FT_BOOLEAN, BASE_NONE, 
502                    NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
503         { &hf_gssapi_segment_overlap_conflict,
504                 { "Conflicting data in fragment overlap",       "gssapi.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, 
505                   NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
506         { &hf_gssapi_segment_multiple_tails,
507                 { "Multiple tail fragments found",      "gssapi.segment.multipletails", FT_BOOLEAN, BASE_NONE, 
508                   NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
509         { &hf_gssapi_segment_too_long_fragment,
510                 { "Fragment too long",  "gssapi.segment.toolongfragment", FT_BOOLEAN, BASE_NONE, 
511                   NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
512         { &hf_gssapi_segment_error,
513                 { "Defragmentation error", "gssapi.segment.error", FT_FRAMENUM, BASE_NONE, 
514                   NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
515         { &hf_gssapi_reassembled_in,
516                 { "Reassembled In", "gssapi.reassembled_in", FT_FRAMENUM, BASE_DEC, 
517                   NULL, 0x0, "The frame where this pdu is reassembled", HFILL }},
518
519         };
520
521         static gint *ett[] = {
522                 &ett_gssapi,
523                 &ett_gssapi_segment,
524                 &ett_gssapi_segments,
525         };
526         module_t *gssapi_module;
527
528         proto_gssapi = proto_register_protocol(
529                 "GSS-API Generic Security Service Application Program Interface",
530                 "GSS-API", "gss-api");
531
532         gssapi_module = prefs_register_protocol(proto_gssapi, NULL);
533         prefs_register_bool_preference(gssapi_module, "gssapi_reassembly",
534                 "Reassemble fragmented GSSAPI blobs",
535                 "Whether or not to try reassembling GSSAPI blobs spanning multiple (SMB/SessionSetup) PDUs",
536                 &gssapi_reassembly);
537         proto_register_field_array(proto_gssapi, hf, array_length(hf));
538         proto_register_subtree_array(ett, array_length(ett));
539
540         register_dissector("gssapi", dissect_gssapi, proto_gssapi);
541         new_register_dissector("gssapi_verf", dissect_gssapi_verf, proto_gssapi);
542
543         gssapi_oids = g_hash_table_new(gssapi_oid_hash, gssapi_oid_equal);
544         register_init_routine(gssapi_reassembly_init);
545 }
546
547 static int wrap_dissect_gssapi(tvbuff_t *tvb, int offset, 
548                                packet_info *pinfo, 
549                                proto_tree *tree, guint8 *drep _U_)
550 {
551         tvbuff_t *auth_tvb;
552
553         auth_tvb = tvb_new_subset(tvb, offset, -1, -1);
554
555         dissect_gssapi(auth_tvb, pinfo, tree);
556
557         return tvb_length_remaining(tvb, offset);
558 }
559
560 int wrap_dissect_gssapi_verf(tvbuff_t *tvb, int offset, 
561                                     packet_info *pinfo, 
562                                     proto_tree *tree, guint8 *drep _U_)
563 {
564         tvbuff_t *auth_tvb;
565
566         auth_tvb = tvb_new_subset(tvb, offset, -1, -1);
567
568         return dissect_gssapi_verf(auth_tvb, pinfo, tree);
569 }
570
571 tvbuff_t *
572 wrap_dissect_gssapi_payload(tvbuff_t *data_tvb, 
573                         tvbuff_t *auth_tvb,
574                         int offset _U_,
575                         packet_info *pinfo, 
576                         dcerpc_auth_info *auth_info _U_)
577 {
578         tvbuff_t *result;
579
580         /* we need a full auth and a full data tvb or else we cant
581            decrypt anything 
582         */
583         if((!auth_tvb)||(!data_tvb)){
584                 return NULL;
585         }
586
587         pinfo->decrypt_gssapi_tvb=DECRYPT_GSSAPI_DCE;
588         pinfo->gssapi_wrap_tvb=NULL;
589         pinfo->gssapi_encrypted_tvb=data_tvb;
590         pinfo->gssapi_decrypted_tvb=NULL;
591         dissect_gssapi_verf(auth_tvb, pinfo, NULL);
592         result=pinfo->gssapi_decrypted_tvb;
593
594         pinfo->decrypt_gssapi_tvb=0;
595         pinfo->gssapi_wrap_tvb=NULL;
596         pinfo->gssapi_encrypted_tvb=NULL;
597         pinfo->gssapi_decrypted_tvb=NULL;
598
599         return result;
600 }
601
602 static dcerpc_auth_subdissector_fns gssapi_auth_fns = {
603         wrap_dissect_gssapi,                    /* Bind */
604         wrap_dissect_gssapi,                    /* Bind ACK */
605         wrap_dissect_gssapi,                    /* AUTH3 */
606         wrap_dissect_gssapi_verf,               /* Request verifier */
607         wrap_dissect_gssapi_verf,               /* Response verifier */
608         wrap_dissect_gssapi_payload,            /* Request data */
609         wrap_dissect_gssapi_payload             /* Response data */
610 };
611
612 void
613 proto_reg_handoff_gssapi(void)
614 {
615         dissector_handle_t gssapi_handle;
616
617         ntlmssp_handle = find_dissector("ntlmssp");
618
619         register_dcerpc_auth_subdissector(DCE_C_AUTHN_LEVEL_CONNECT,
620                                           DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO,
621                                           &gssapi_auth_fns);
622         register_dcerpc_auth_subdissector(DCE_C_AUTHN_LEVEL_PKT_INTEGRITY,
623                                           DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO,
624                                           &gssapi_auth_fns);
625         register_dcerpc_auth_subdissector(DCE_C_AUTHN_LEVEL_PKT_PRIVACY,
626                                           DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO,
627                                           &gssapi_auth_fns);
628
629         gssapi_handle = create_dissector_handle(dissect_gssapi, proto_gssapi);
630         dissector_add_string("dns.tsig.mac", "gss.microsoft.com", gssapi_handle);
631 }