Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-gssapi.c
blob46adbd4255f8acade3c97abf9c0e3dc49ccc939c
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 ...
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * SPDX-License-Identifier: GPL-2.0-or-later
14 #include "config.h"
17 #include <epan/packet.h>
18 #include <epan/expert.h>
19 #include <epan/exceptions.h>
20 #include <epan/prefs.h>
21 #include <epan/reassemble.h>
22 #include <epan/show_exception.h>
23 #include <epan/proto_data.h>
25 #include "packet-ber.h"
26 #include "packet-dcerpc.h"
27 #include "packet-gssapi.h"
29 void proto_register_gssapi(void);
30 void proto_reg_handoff_gssapi(void);
32 static int proto_gssapi;
34 static int hf_gssapi_token_object;
35 static int hf_gssapi_auth_verifier;
36 static int hf_gssapi_auth_credentials;
37 static int hf_gssapi_oid;
38 static int hf_gssapi_segments;
39 static int hf_gssapi_segment;
40 static int hf_gssapi_segment_overlap;
41 static int hf_gssapi_segment_overlap_conflict;
42 static int hf_gssapi_segment_multiple_tails;
43 static int hf_gssapi_segment_too_long_fragment;
44 static int hf_gssapi_segment_error;
45 static int hf_gssapi_segment_count;
46 static int hf_gssapi_reassembled_in;
47 static int hf_gssapi_reassembled_length;
49 static int ett_gssapi;
50 static int ett_gssapi_segment;
51 static int ett_gssapi_segments;
53 static expert_field ei_gssapi_unknown_header;
55 static bool gssapi_reassembly = true;
57 static dissector_handle_t gssapi_handle;
59 typedef struct _gssapi_conv_info_t {
60 gssapi_oid_value *oid;
62 wmem_tree_t *frags;
64 bool 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 */
65 int first_frame;
66 int frag_offset;
67 } gssapi_conv_info_t;
69 typedef struct _gssapi_frag_info_t {
70 uint32_t first_frame;
71 uint32_t reassembled_in;
72 } gssapi_frag_info_t;
74 static const fragment_items gssapi_frag_items = {
75 &ett_gssapi_segment,
76 &ett_gssapi_segments,
78 &hf_gssapi_segments,
79 &hf_gssapi_segment,
80 &hf_gssapi_segment_overlap,
81 &hf_gssapi_segment_overlap_conflict,
82 &hf_gssapi_segment_multiple_tails,
83 &hf_gssapi_segment_too_long_fragment,
84 &hf_gssapi_segment_error,
85 &hf_gssapi_segment_count,
86 NULL,
87 &hf_gssapi_reassembled_length,
88 /* Reassembled data field */
89 NULL,
90 "fragments"
94 static reassembly_table gssapi_reassembly_table;
97 * Subdissectors
100 static dissector_handle_t ntlmssp_handle;
101 static dissector_handle_t ntlmssp_payload_handle;
102 static dissector_handle_t ntlmssp_verf_handle;
103 static dissector_handle_t ntlmssp_data_only_handle;
104 static dissector_handle_t spnego_krb5_wrap_handle;
106 static GHashTable *gssapi_oids;
108 static int
109 gssapi_oid_equal(const void *k1, const void *k2)
111 const char *key1 = (const char *)k1;
112 const char *key2 = (const char *)k2;
114 return strcmp(key1, key2) == 0;
117 static unsigned
118 gssapi_oid_hash(const void *k)
120 const char *key = (const char *)k;
121 unsigned hash = 0, i;
123 for (i = 0; key[i]; i++)
124 hash += key[i];
126 return hash;
129 void
130 gssapi_init_oid(const char *oid, int proto, int ett, dissector_handle_t handle,
131 dissector_handle_t wrap_handle, const char *comment)
133 char *key = g_strdup(oid);
134 gssapi_oid_value *value = (gssapi_oid_value *)g_malloc(sizeof(*value));
136 value->proto = find_protocol_by_id(proto);
137 value->ett = ett;
138 value->handle = handle;
139 value->wrap_handle = wrap_handle;
140 value->comment = comment;
142 g_hash_table_insert(gssapi_oids, key, value);
143 register_ber_oid_dissector_handle(key, handle, proto, comment);
147 * This takes an OID in text string form as
148 * an argument.
150 gssapi_oid_value *
151 gssapi_lookup_oid_str(const char *oid_key)
153 gssapi_oid_value *value;
154 if(!oid_key){
155 return NULL;
157 value = (gssapi_oid_value *)g_hash_table_lookup(gssapi_oids, oid_key);
158 return value;
161 static int
162 dissect_gssapi_work(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
163 bool is_verifier, gssapi_encrypt_info_t* encrypt_info)
165 proto_item *volatile item;
166 proto_tree *volatile subtree;
167 volatile int return_offset = 0;
168 gssapi_conv_info_t *volatile gss_info;
169 gssapi_oid_value *oidvalue;
170 dissector_handle_t handle;
171 conversation_t *conversation;
172 tvbuff_t *oid_tvb;
173 int len, start_offset, oid_start_offset;
174 volatile int offset;
175 int8_t appclass;
176 bool pc, ind_field;
177 int32_t tag;
178 uint32_t len1;
179 const char *oid;
180 fragment_head *fd_head=NULL;
181 gssapi_frag_info_t *fi;
182 tvbuff_t *volatile gss_tvb=NULL;
183 asn1_ctx_t asn1_ctx;
185 start_offset=0;
186 offset=0;
187 asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, true, pinfo);
189 * We don't know whether the data is encrypted, so say it's
190 * not, for now. The subdissector must set gssapi_data_encrypted
191 * if it is.
193 encrypt_info->gssapi_data_encrypted = false;
197 * We need a conversation for later
199 conversation = find_or_create_conversation(pinfo);
201 gss_info = (gssapi_conv_info_t *)conversation_get_proto_data(conversation, proto_gssapi);
202 if (!gss_info) {
203 gss_info = wmem_new(wmem_file_scope(), gssapi_conv_info_t);
204 gss_info->oid=NULL;
205 gss_info->do_reassembly=false;
206 gss_info->frags=wmem_tree_new(wmem_file_scope());
208 conversation_add_proto_data(conversation, proto_gssapi, gss_info);
211 item = proto_tree_add_item(
212 tree, proto_gssapi, tvb, offset, -1, ENC_NA);
214 subtree = proto_item_add_subtree(item, ett_gssapi);
217 * Catch the ReportedBoundsError exception; the stuff we've been
218 * handed doesn't necessarily run to the end of the packet, it's
219 * an item inside a packet, so if it happens to be malformed (or
220 * we, or a dissector we call, has a bug), so that an exception
221 * is thrown, we want to report the error, but return and let
222 * our caller dissect the rest of the packet.
224 * If it gets a BoundsError, we can stop, as there's nothing more
225 * in the packet after our blob to see, so we just re-throw the
226 * exception.
228 TRY {
229 gss_tvb=tvb;
232 /* First of all, if it's the first time we see this packet
233 * then check whether we are in the middle of reassembly or not
235 if( (!pinfo->fd->visited)
236 && (gss_info->do_reassembly)
237 && (gssapi_reassembly) ){
238 fi=(gssapi_frag_info_t *)wmem_tree_lookup32(gss_info->frags, gss_info->first_frame);
239 if(!fi){
240 goto done;
242 wmem_tree_insert32(gss_info->frags, pinfo->num, fi);
243 fd_head=fragment_add(&gssapi_reassembly_table,
244 tvb, 0, pinfo, fi->first_frame, NULL,
245 gss_info->frag_offset,
246 tvb_captured_length(tvb), true);
247 gss_info->frag_offset+=tvb_captured_length(tvb);
249 /* we need more fragments */
250 if(!fd_head){
251 goto done;
254 /* this blob is now fully reassembled */
255 gss_info->do_reassembly=false;
256 fi->reassembled_in=pinfo->num;
258 gss_tvb=tvb_new_chain(tvb, fd_head->tvb_data);
259 add_new_data_source(pinfo, gss_tvb, "Reassembled GSSAPI");
261 /* We have seen this packet before.
262 * Is this blob part of reassembly or a normal blob ?
264 if( (pinfo->fd->visited)
265 && (gssapi_reassembly) ){
266 fi=(gssapi_frag_info_t *)wmem_tree_lookup32(gss_info->frags, pinfo->num);
267 if(fi){
268 fd_head=fragment_get(&gssapi_reassembly_table,
269 pinfo, fi->first_frame, NULL);
270 if(fd_head && (fd_head->flags&FD_DEFRAGMENTED)){
271 if(pinfo->num==fi->reassembled_in){
272 proto_item *frag_tree_item;
273 gss_tvb=tvb_new_chain(tvb, fd_head->tvb_data);
274 add_new_data_source(pinfo, gss_tvb, "Reassembled GSSAPI");
275 show_fragment_tree(fd_head, &gssapi_frag_items, tree, pinfo, tvb, &frag_tree_item);
276 } else {
277 proto_item *it;
278 it=proto_tree_add_uint(tree, hf_gssapi_reassembled_in, tvb, 0, 0, fi->reassembled_in);
279 proto_item_set_generated(it);
280 goto done;
286 /* Read header */
287 offset = get_ber_identifier(gss_tvb, offset, &appclass, &pc, &tag);
288 offset = get_ber_length(gss_tvb, offset, &len1, &ind_field);
291 if (!(appclass == BER_CLASS_APP && pc && tag == 0)) {
292 /* It could be NTLMSSP, with no OID. This can happen
293 for anything that microsoft calls 'Negotiate' or GSS-SPNEGO */
294 if ((tvb_captured_length_remaining(gss_tvb, start_offset)>7) && (tvb_strneql(gss_tvb, start_offset, "NTLMSSP", 7) == 0)) {
295 return_offset = call_dissector(ntlmssp_handle,
296 tvb_new_subset_remaining(gss_tvb, start_offset),
297 pinfo, subtree);
298 goto done;
300 /* Maybe it's new NTLMSSP payload */
301 if ((tvb_captured_length_remaining(gss_tvb, start_offset)>16) &&
302 ((tvb_memeql(gss_tvb, start_offset, (const uint8_t*)"\x01\x00\x00\x00", 4) == 0))) {
303 return_offset = call_dissector(ntlmssp_payload_handle,
304 tvb_new_subset_remaining(gss_tvb, start_offset),
305 pinfo, subtree);
306 encrypt_info->gssapi_data_encrypted = true;
307 goto done;
309 if ((tvb_captured_length_remaining(gss_tvb, start_offset)==16) &&
310 ((tvb_memeql(gss_tvb, start_offset, (const uint8_t*)"\x01\x00\x00\x00", 4) == 0))) {
311 if( is_verifier ) {
312 return_offset = call_dissector(ntlmssp_verf_handle,
313 tvb_new_subset_remaining(gss_tvb, start_offset),
314 pinfo, subtree);
316 else if( encrypt_info->gssapi_encrypted_tvb ) {
317 return_offset = call_dissector_with_data(ntlmssp_data_only_handle,
318 tvb_new_subset_remaining(encrypt_info->gssapi_encrypted_tvb, 0),
319 pinfo, subtree, &encrypt_info->gssapi_decrypted_tvb);
320 encrypt_info->gssapi_data_encrypted = true;
322 goto done;
325 /* Maybe it's new GSSKRB5 CFX Wrapping */
326 if ((tvb_captured_length_remaining(gss_tvb, start_offset)>2) &&
327 ((tvb_memeql(gss_tvb, start_offset, (const uint8_t*)"\04\x04", 2) == 0) ||
328 (tvb_memeql(gss_tvb, start_offset, (const uint8_t*)"\05\x04", 2) == 0))) {
329 return_offset = call_dissector_with_data(spnego_krb5_wrap_handle,
330 tvb_new_subset_remaining(gss_tvb, start_offset),
331 pinfo, subtree, encrypt_info);
332 goto done;
336 * If we do not recognise an Application class,
337 * then we are probably dealing with an inner context
338 * token or a wrap token, and we should retrieve the
339 * gssapi_oid_value pointer from the per-frame data or,
340 * if there is no per-frame data (as would be the case
341 * the first time we dissect this frame), from the
342 * conversation that exists or that we created from
343 * pinfo (and then make it per-frame data).
344 * We need to make it per-frame data as there can be
345 * more than one GSS-API negotiation in a conversation.
347 * Note! We "cheat". Since we only need the pointer,
348 * we store that as the data. (That's not really
349 * "cheating" - the per-frame data and per-conversation
350 * data code doesn't care what you supply as a data
351 * pointer; it just treats it as an opaque pointer, it
352 * doesn't dereference it or free what it points to.)
354 oidvalue = (gssapi_oid_value *)p_get_proto_data(wmem_file_scope(), pinfo, proto_gssapi, 0);
355 if (!oidvalue && !pinfo->fd->visited) {
356 /* No handle attached to this frame, but it's the first */
357 /* pass, so it'd be attached to the conversation. */
358 oidvalue = gss_info->oid;
359 if (gss_info->oid)
360 p_add_proto_data(wmem_file_scope(), pinfo, proto_gssapi, 0, gss_info->oid);
362 if (!oidvalue) {
363 proto_tree_add_expert_format(subtree, pinfo, &ei_gssapi_unknown_header, gss_tvb, start_offset, 0,
364 "Unknown header (class=%d, pc=%d, tag=%d)",
365 appclass, pc, tag);
366 return_offset = tvb_captured_length(gss_tvb);
367 goto done;
368 } else {
369 tvbuff_t *oid_tvb_local;
371 if (is_verifier) {
372 handle = oidvalue->wrap_handle;
373 if (handle != NULL) {
374 oid_tvb_local = tvb_new_subset_remaining(gss_tvb, start_offset);
375 len = call_dissector_with_data(handle, oid_tvb_local, pinfo, subtree, encrypt_info);
376 if (len == 0)
377 return_offset = tvb_captured_length(gss_tvb);
378 else
379 return_offset = start_offset + len;
380 } else {
381 proto_tree_add_item(subtree, hf_gssapi_auth_verifier, gss_tvb, offset, -1, ENC_NA);
382 return_offset = tvb_captured_length(gss_tvb);
384 } else {
385 handle = oidvalue->handle;
386 if (handle != NULL) {
387 oid_tvb_local = tvb_new_subset_remaining(gss_tvb, start_offset);
388 len = call_dissector_with_data(handle, oid_tvb_local, pinfo, subtree, encrypt_info);
389 if (len == 0)
390 return_offset = tvb_captured_length(gss_tvb);
391 else
392 return_offset = start_offset + len;
393 } else {
394 proto_tree_add_item(subtree, hf_gssapi_auth_credentials, gss_tvb, offset, -1, ENC_NA);
395 return_offset = tvb_captured_length(gss_tvb);
399 goto done; /* We are finished here */
403 /* Read oid */
404 oid_start_offset=offset;
405 offset=dissect_ber_object_identifier_str(false, &asn1_ctx, subtree, gss_tvb, offset, hf_gssapi_oid, &oid);
406 oidvalue = gssapi_lookup_oid_str(oid);
409 /* Check if we need reassembly of this blob.
410 * Only try reassembly for OIDs we recognize
411 * and when we have the entire tvb
413 * SMB will sometimes split one large GSSAPI blob
414 * across multiple SMB/SessionSetup commands.
415 * While we should look at the uid returned in the response
416 * to the first SessionSetup and use that as a key
417 * instead for simplicity we assume there will not be several
418 * such authentication at once on a single tcp session
420 if( (!pinfo->fd->visited)
421 && (oidvalue)
422 && (tvb_captured_length(gss_tvb)==tvb_reported_length(gss_tvb))
423 && (len1>(uint32_t)tvb_captured_length_remaining(gss_tvb, oid_start_offset))
424 && (gssapi_reassembly) ){
425 fi=wmem_new(wmem_file_scope(), gssapi_frag_info_t);
426 fi->first_frame=pinfo->num;
427 fi->reassembled_in=0;
428 wmem_tree_insert32(gss_info->frags, pinfo->num, fi);
430 fragment_add(&gssapi_reassembly_table,
431 gss_tvb, 0, pinfo, pinfo->num, NULL,
432 0, tvb_captured_length(gss_tvb), true);
433 fragment_set_tot_len(&gssapi_reassembly_table,
434 pinfo, pinfo->num, NULL, len1+oid_start_offset);
436 gss_info->do_reassembly=true;
437 gss_info->first_frame=pinfo->num;
438 gss_info->frag_offset=tvb_captured_length(gss_tvb);
439 goto done;
444 * Hand off to subdissector.
447 if ((oidvalue == NULL) || !proto_is_protocol_enabled(oidvalue->proto)) {
448 /* No dissector for this oid */
449 proto_tree_add_item(subtree, hf_gssapi_token_object, gss_tvb, oid_start_offset, -1, ENC_NA);
451 return_offset = tvb_captured_length(gss_tvb);
452 goto done;
455 /* Save a pointer to the data for the OID for the
456 * GSSAPI protocol for this conversation.
460 * Now add the proto data ...
461 * but only if it is not already there.
463 if(!gss_info->oid) {
464 gss_info->oid=oidvalue;
467 if (is_verifier) {
468 handle = oidvalue->wrap_handle;
469 if (handle != NULL) {
470 oid_tvb = tvb_new_subset_remaining(gss_tvb, offset);
471 len = call_dissector_with_data(handle, oid_tvb, pinfo, subtree, encrypt_info);
472 if (len == 0)
473 return_offset = tvb_captured_length(gss_tvb);
474 else
475 return_offset = offset + len;
476 } else {
477 proto_tree_add_item(subtree, hf_gssapi_auth_verifier, gss_tvb, offset, -1, ENC_NA);
478 return_offset = tvb_captured_length(gss_tvb);
480 } else {
481 handle = oidvalue->handle;
482 if (handle != NULL) {
483 oid_tvb = tvb_new_subset_remaining(gss_tvb, offset);
484 len = call_dissector_with_data(handle, oid_tvb, pinfo, subtree, encrypt_info);
485 if (len == 0)
486 return_offset = tvb_captured_length(gss_tvb);
487 else
488 return_offset = offset + len;
489 } else {
490 proto_tree_add_item(subtree, hf_gssapi_auth_credentials, gss_tvb, offset, -1, ENC_NA);
491 return_offset = tvb_captured_length(gss_tvb);
495 done:
497 } CATCH_NONFATAL_ERRORS {
499 * Somebody threw an exception that means that there
500 * was a problem dissecting the payload; that means
501 * that a dissector was found, so we don't need to
502 * dissect the payload as data or update the protocol
503 * or info columns.
505 * Just show the exception and then drive on to show
506 * the trailer, after noting that a dissector was found
507 * and restoring the protocol value that was in effect
508 * before we called the subdissector.
510 show_exception(gss_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
511 } ENDTRY;
513 proto_item_set_len(item, return_offset);
514 return return_offset;
517 static int
518 dissect_gssapi_work_wrapper(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gssapi_encrypt_info_t* encrypt_info, bool is_verifier)
520 int ret;
521 gssapi_encrypt_info_t pass_encrypt_info;
523 /* Ensure a non-null encryption structure */
524 if (encrypt_info != NULL)
526 pass_encrypt_info = *encrypt_info;
528 else
530 memset(&pass_encrypt_info, 0, sizeof(pass_encrypt_info));
533 ret = dissect_gssapi_work(tvb, pinfo, tree, is_verifier, &pass_encrypt_info);
535 /* Restore any changes to provided encryption structure */
536 if (encrypt_info != NULL)
538 *encrypt_info = pass_encrypt_info;
541 return ret;
544 static int
545 dissect_gssapi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
547 return dissect_gssapi_work_wrapper(tvb, pinfo, tree, (gssapi_encrypt_info_t*)data, false);
550 static int
551 dissect_gssapi_verf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
553 return dissect_gssapi_work_wrapper(tvb, pinfo, tree, (gssapi_encrypt_info_t*)data, true);
556 static void
557 gssapi_shutdown(void)
559 g_hash_table_destroy(gssapi_oids);
562 void
563 proto_register_gssapi(void)
565 static hf_register_info hf[] = {
566 { &hf_gssapi_oid,
567 { "OID", "gss-api.OID", FT_STRING, BASE_NONE,
568 NULL, 0, "This is a GSS-API Object Identifier", HFILL }},
569 { &hf_gssapi_token_object,
570 { "Token object", "gss-api.token_object", FT_BYTES, BASE_NONE,
571 NULL, 0, NULL, HFILL }},
572 { &hf_gssapi_auth_verifier,
573 { "Authentication verifier", "gss-api.auth_verifier", FT_BYTES, BASE_NONE,
574 NULL, 0, NULL, HFILL }},
575 { &hf_gssapi_auth_credentials,
576 { "Authentication credentials", "gss-api.auth_credentials", FT_BYTES, BASE_NONE,
577 NULL, 0, NULL, HFILL }},
578 { &hf_gssapi_segment,
579 { "GSSAPI Segment", "gss-api.segment", FT_FRAMENUM, BASE_NONE,
580 NULL, 0x0, NULL, HFILL }},
581 { &hf_gssapi_segments,
582 { "GSSAPI Segments", "gss-api.segment.segments", FT_NONE, BASE_NONE,
583 NULL, 0x0, NULL, HFILL }},
584 { &hf_gssapi_segment_overlap,
585 { "Fragment overlap", "gss-api.segment.overlap", FT_BOOLEAN, BASE_NONE,
586 NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
587 { &hf_gssapi_segment_overlap_conflict,
588 { "Conflicting data in fragment overlap", "gss-api.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE,
589 NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
590 { &hf_gssapi_segment_multiple_tails,
591 { "Multiple tail fragments found", "gss-api.segment.multipletails", FT_BOOLEAN, BASE_NONE,
592 NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
593 { &hf_gssapi_segment_too_long_fragment,
594 { "Fragment too long", "gss-api.segment.toolongfragment", FT_BOOLEAN, BASE_NONE,
595 NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
596 { &hf_gssapi_segment_error,
597 { "Defragmentation error", "gss-api.segment.error", FT_FRAMENUM, BASE_NONE,
598 NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
599 { &hf_gssapi_segment_count,
600 { "Fragment count", "gss-api.segment.count", FT_UINT32, BASE_DEC,
601 NULL, 0x0, NULL, HFILL }},
602 { &hf_gssapi_reassembled_in,
603 { "Reassembled In", "gss-api.reassembled_in", FT_FRAMENUM, BASE_NONE,
604 NULL, 0x0, "The frame where this pdu is reassembled", HFILL }},
605 { &hf_gssapi_reassembled_length,
606 { "Reassembled GSSAPI length", "gss-api.reassembled.length", FT_UINT32, BASE_DEC,
607 NULL, 0x0, "The total length of the reassembled payload", HFILL }},
610 static int *ett[] = {
611 &ett_gssapi,
612 &ett_gssapi_segment,
613 &ett_gssapi_segments,
616 static ei_register_info ei[] = {
617 { &ei_gssapi_unknown_header, { "gssapi.unknown_header", PI_PROTOCOL, PI_WARN, "Unknown header", EXPFILL }},
620 module_t *gssapi_module;
621 expert_module_t *expert_gssapi;
623 proto_gssapi = proto_register_protocol("GSS-API Generic Security Service Application Program Interface", "GSS-API", "gss-api");
625 gssapi_module = prefs_register_protocol(proto_gssapi, NULL);
626 prefs_register_bool_preference(gssapi_module, "gssapi_reassembly",
627 "Reassemble fragmented GSSAPI blobs",
628 "Whether or not to try reassembling GSSAPI blobs spanning multiple (SMB/SessionSetup) PDUs",
629 &gssapi_reassembly);
630 proto_register_field_array(proto_gssapi, hf, array_length(hf));
631 proto_register_subtree_array(ett, array_length(ett));
632 expert_gssapi = expert_register_protocol(proto_gssapi);
633 expert_register_field_array(expert_gssapi, ei, array_length(ei));
635 gssapi_handle = register_dissector("gssapi", dissect_gssapi, proto_gssapi);
636 register_dissector("gssapi_verf", dissect_gssapi_verf, proto_gssapi);
638 gssapi_oids = g_hash_table_new_full(gssapi_oid_hash, gssapi_oid_equal, g_free, g_free);
640 reassembly_table_register(&gssapi_reassembly_table,
641 &addresses_reassembly_table_functions);
643 register_shutdown_routine(gssapi_shutdown);
646 static int
647 wrap_dissect_gssapi(tvbuff_t *tvb, int offset, packet_info *pinfo,
648 proto_tree *tree, dcerpc_info *di _U_, uint8_t *drep _U_)
650 tvbuff_t *auth_tvb;
652 auth_tvb = tvb_new_subset_remaining(tvb, offset);
654 dissect_gssapi(auth_tvb, pinfo, tree, NULL);
656 return tvb_captured_length_remaining(tvb, offset);
660 wrap_dissect_gssapi_verf(tvbuff_t *tvb, int offset, packet_info *pinfo,
661 proto_tree *tree, dcerpc_info *di _U_, uint8_t *drep _U_)
663 tvbuff_t *auth_tvb;
665 auth_tvb = tvb_new_subset_remaining(tvb, offset);
667 return dissect_gssapi_verf(auth_tvb, pinfo, tree, NULL);
670 tvbuff_t *
671 wrap_dissect_gssapi_payload(tvbuff_t *header_tvb,
672 tvbuff_t *payload_tvb,
673 tvbuff_t *trailer_tvb,
674 tvbuff_t *auth_tvb,
675 packet_info *pinfo,
676 dcerpc_auth_info *auth_info)
678 tvbuff_t *result;
679 gssapi_encrypt_info_t gssapi_encrypt;
681 memset(&gssapi_encrypt, 0x0, sizeof(gssapi_encrypt_info_t));
683 /* we need a full auth and a full data tvb or else we can't
684 decrypt anything
686 if((!auth_tvb)||(!payload_tvb)){
687 return NULL;
690 if (!auth_info->hdr_signing) {
691 header_tvb = NULL;
692 trailer_tvb = NULL;
695 gssapi_encrypt.decrypt_gssapi_tvb=DECRYPT_GSSAPI_DCE;
696 gssapi_encrypt.gssapi_header_tvb=header_tvb;
697 gssapi_encrypt.gssapi_encrypted_tvb=payload_tvb;
698 gssapi_encrypt.gssapi_trailer_tvb=trailer_tvb;
700 dissect_gssapi(auth_tvb, pinfo, NULL, &gssapi_encrypt);
701 auth_info->session_key = gssapi_encrypt.used_decryption_key;
702 result=gssapi_encrypt.gssapi_decrypted_tvb;
704 return result;
707 static dcerpc_auth_subdissector_fns gssapi_auth_fns = {
708 wrap_dissect_gssapi, /* Bind */
709 wrap_dissect_gssapi, /* Bind ACK */
710 wrap_dissect_gssapi, /* AUTH3 */
711 wrap_dissect_gssapi_verf, /* Request verifier */
712 wrap_dissect_gssapi_verf, /* Response verifier */
713 wrap_dissect_gssapi_payload, /* Request data */
714 wrap_dissect_gssapi_payload /* Response data */
717 void
718 proto_reg_handoff_gssapi(void)
720 ntlmssp_handle = find_dissector_add_dependency("ntlmssp", proto_gssapi);
721 ntlmssp_payload_handle = find_dissector_add_dependency("ntlmssp_payload", proto_gssapi);
722 ntlmssp_verf_handle = find_dissector_add_dependency("ntlmssp_verf", proto_gssapi);
723 ntlmssp_data_only_handle = find_dissector_add_dependency("ntlmssp_data_only", proto_gssapi);
724 spnego_krb5_wrap_handle = find_dissector_add_dependency("spnego-krb5-wrap", proto_gssapi);
726 register_dcerpc_auth_subdissector(DCE_C_AUTHN_LEVEL_CONNECT,
727 DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO,
728 &gssapi_auth_fns);
729 register_dcerpc_auth_subdissector(DCE_C_AUTHN_LEVEL_PKT_INTEGRITY,
730 DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO,
731 &gssapi_auth_fns);
732 register_dcerpc_auth_subdissector(DCE_C_AUTHN_LEVEL_PKT_PRIVACY,
733 DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO,
734 &gssapi_auth_fns);
736 dissector_add_string("dns.tsig.mac", "gss.microsoft.com", gssapi_handle);
737 dissector_add_string("dns.tsig.mac", "gss-tsig", gssapi_handle);
741 * Editor modelines - https://www.wireshark.org/tools/modelines.html
743 * Local variables:
744 * c-basic-offset: 8
745 * tab-width: 8
746 * indent-tabs-mode: t
747 * End:
749 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
750 * :indentSize=8:tabSize=8:noTabs=false: