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  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * SPDX-License-Identifier: GPL-2.0-or-later
12  */
13 
14 #include "config.h"
15 
16 
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>
24 
25 #include "packet-ber.h"
26 #include "packet-dcerpc.h"
27 #include "packet-gssapi.h"
28 
29 void proto_register_gssapi(void);
30 void proto_reg_handoff_gssapi(void);
31 
32 static int proto_gssapi = -1;
33 
34 static int hf_gssapi_token_object = -1;
35 static int hf_gssapi_auth_verifier = -1;
36 static int hf_gssapi_auth_credentials = -1;
37 static int hf_gssapi_oid = -1;
38 static int hf_gssapi_segments = -1;
39 static int hf_gssapi_segment = -1;
40 static int hf_gssapi_segment_overlap = -1;
41 static int hf_gssapi_segment_overlap_conflict = -1;
42 static int hf_gssapi_segment_multiple_tails = -1;
43 static int hf_gssapi_segment_too_long_fragment = -1;
44 static int hf_gssapi_segment_error = -1;
45 static int hf_gssapi_segment_count = -1;
46 static int hf_gssapi_reassembled_in = -1;
47 static int hf_gssapi_reassembled_length = -1;
48 
49 static gint ett_gssapi = -1;
50 static gint ett_gssapi_segment = -1;
51 static gint ett_gssapi_segments = -1;
52 
53 static expert_field ei_gssapi_unknown_header = EI_INIT;
54 
55 static gboolean gssapi_reassembly = TRUE;
56 
57 static dissector_handle_t gssapi_handle;
58 
59 typedef struct _gssapi_conv_info_t {
60 	gssapi_oid_value *oid;
61 
62 	wmem_tree_t *frags;
63 
64 	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 */
65 	int first_frame;
66 	int frag_offset;
67 } gssapi_conv_info_t;
68 
69 typedef struct _gssapi_frag_info_t {
70 	guint32 first_frame;
71 	guint32 reassembled_in;
72 } gssapi_frag_info_t;
73 
74 static const fragment_items gssapi_frag_items = {
75 	&ett_gssapi_segment,
76 	&ett_gssapi_segments,
77 
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"
91 };
92 
93 
94 static reassembly_table gssapi_reassembly_table;
95 
96 /*
97  * Subdissectors
98  */
99 
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;
105 
106 static GHashTable *gssapi_oids;
107 
108 static gint
gssapi_oid_equal(gconstpointer k1,gconstpointer k2)109 gssapi_oid_equal(gconstpointer k1, gconstpointer k2)
110 {
111 	const char *key1 = (const char *)k1;
112 	const char *key2 = (const char *)k2;
113 
114 	return strcmp(key1, key2) == 0;
115 }
116 
117 static guint
gssapi_oid_hash(gconstpointer k)118 gssapi_oid_hash(gconstpointer k)
119 {
120 	const char *key = (const char *)k;
121 	guint hash = 0, i;
122 
123 	for (i = 0; key[i]; i++)
124 		hash += key[i];
125 
126 	return hash;
127 }
128 
129 void
gssapi_init_oid(const char * oid,int proto,int ett,dissector_handle_t handle,dissector_handle_t wrap_handle,const gchar * comment)130 gssapi_init_oid(const char *oid, int proto, int ett, dissector_handle_t handle,
131 		dissector_handle_t wrap_handle, const gchar *comment)
132 {
133 	char *key = g_strdup(oid);
134 	gssapi_oid_value *value = (gssapi_oid_value *)g_malloc(sizeof(*value));
135 
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;
141 
142 	g_hash_table_insert(gssapi_oids, key, value);
143 	register_ber_oid_dissector_handle(key, handle, proto, comment);
144 }
145 
146 /*
147  * This takes an OID in text string form as
148  * an argument.
149  */
150 gssapi_oid_value *
gssapi_lookup_oid_str(const char * oid_key)151 gssapi_lookup_oid_str(const char *oid_key)
152 {
153 	gssapi_oid_value *value;
154 	if(!oid_key){
155 		return NULL;
156 	}
157 	value = (gssapi_oid_value *)g_hash_table_lookup(gssapi_oids, oid_key);
158 	return value;
159 }
160 
161 static int
dissect_gssapi_work(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gboolean is_verifier,gssapi_encrypt_info_t * encrypt_info)162 dissect_gssapi_work(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
163 		    gboolean is_verifier, gssapi_encrypt_info_t* encrypt_info)
164 {
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 	gint8 appclass;
176 	gboolean pc, ind_field;
177 	gint32 tag;
178 	guint32 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;
184 
185 	start_offset=0;
186 	offset=0;
187 	asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
188 	/*
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.
192 	 */
193 	encrypt_info->gssapi_data_encrypted = FALSE;
194 
195 
196 	/*
197 	 * We need a conversation for later
198 	 */
199 	conversation = find_or_create_conversation(pinfo);
200 
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());
207 
208 		conversation_add_proto_data(conversation, proto_gssapi, gss_info);
209 	}
210 
211 	item = proto_tree_add_item(
212 		tree, proto_gssapi, tvb, offset, -1, ENC_NA);
213 
214 	subtree = proto_item_add_subtree(item, ett_gssapi);
215 
216 	/*
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.
223 	 *
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.
227 	 */
228 	TRY {
229 		gss_tvb=tvb;
230 
231 
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
234 		 */
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;
241 			}
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);
248 
249 			/* we need more fragments */
250 			if(!fd_head){
251 				goto done;
252 			}
253 
254 			/* this blob is now fully reassembled */
255 			gss_info->do_reassembly=FALSE;
256 			fi->reassembled_in=pinfo->num;
257 
258 			gss_tvb=tvb_new_chain(tvb, fd_head->tvb_data);
259 			add_new_data_source(pinfo, gss_tvb, "Reassembled GSSAPI");
260 		}
261 		/* We have seen this packet before.
262 		 * Is this blob part of reassembly or a normal blob ?
263 		 */
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;
281 					}
282 				}
283 			}
284 		}
285 
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);
289 
290 
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;
299 			}
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, "\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;
308 			}
309 			if ((tvb_captured_length_remaining(gss_tvb, start_offset)==16) &&
310 			   ((tvb_memeql(gss_tvb, start_offset, "\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);
315 				}
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;
321 				}
322 				goto done;
323 			}
324 
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, "\04\x04", 2) == 0) ||
328 			    (tvb_memeql(gss_tvb, start_offset, "\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;
333 			}
334 
335 			/*
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.
346 			*
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.)
353 			*/
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);
361 			}
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;
370 
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);
383 					}
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);
396 					}
397 				}
398 
399 				goto done; /* We are finished here */
400 			}
401 		}
402 
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);
407 
408 
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
412 		 *
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
419 		 */
420 		if( (!pinfo->fd->visited)
421 		&&  (oidvalue)
422 		&&  (tvb_captured_length(gss_tvb)==tvb_reported_length(gss_tvb))
423 		&&  (len1>(guint32)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);
429 
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);
435 
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;
440 		}
441 
442 
443 		/*
444 		 * Hand off to subdissector.
445 		 */
446 
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);
450 
451 			return_offset = tvb_captured_length(gss_tvb);
452 			goto done;
453 		}
454 
455 		/* Save a pointer to the data for the OID for the
456 		 * GSSAPI protocol for this conversation.
457 		 */
458 
459 		/*
460 		 * Now add the proto data ...
461 		 * but only if it is not already there.
462 		 */
463 		if(!gss_info->oid) {
464 		  gss_info->oid=oidvalue;
465 		}
466 
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);
479 			}
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);
492 			}
493 		}
494 
495 	 done:
496 		;
497 	} CATCH_NONFATAL_ERRORS {
498 		/*
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.
504 		 *
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.
509 		 */
510 		show_exception(gss_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
511 	} ENDTRY;
512 
513 	proto_item_set_len(item, return_offset);
514 	return return_offset;
515 }
516 
517 static int
dissect_gssapi_work_wrapper(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gssapi_encrypt_info_t * encrypt_info,gboolean is_verifier)518 dissect_gssapi_work_wrapper(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gssapi_encrypt_info_t* encrypt_info, gboolean is_verifier)
519 {
520 	int ret;
521 	gssapi_encrypt_info_t pass_encrypt_info;
522 
523 	/* Ensure a non-null encryption structure */
524 	if (encrypt_info != NULL)
525 	{
526 		pass_encrypt_info = *encrypt_info;
527 	}
528 	else
529 	{
530 		memset(&pass_encrypt_info, 0, sizeof(pass_encrypt_info));
531 	}
532 
533 	ret = dissect_gssapi_work(tvb, pinfo, tree, is_verifier, &pass_encrypt_info);
534 
535 	/* Restore any changes to provided encryption structure */
536 	if (encrypt_info != NULL)
537 	{
538 		*encrypt_info = pass_encrypt_info;
539 	}
540 
541 	return ret;
542 }
543 
544 static int
dissect_gssapi(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)545 dissect_gssapi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
546 {
547 	return dissect_gssapi_work_wrapper(tvb, pinfo, tree, (gssapi_encrypt_info_t*)data, FALSE);
548 }
549 
550 static int
dissect_gssapi_verf(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)551 dissect_gssapi_verf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
552 {
553 	return dissect_gssapi_work_wrapper(tvb, pinfo, tree, (gssapi_encrypt_info_t*)data, TRUE);
554 }
555 
556 static void
gssapi_shutdown(void)557 gssapi_shutdown(void)
558 {
559 	g_hash_table_destroy(gssapi_oids);
560 }
561 
562 void
proto_register_gssapi(void)563 proto_register_gssapi(void)
564 {
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 }},
608 	};
609 
610 	static gint *ett[] = {
611 		&ett_gssapi,
612 		&ett_gssapi_segment,
613 		&ett_gssapi_segments,
614 	};
615 
616 	static ei_register_info ei[] = {
617 		{ &ei_gssapi_unknown_header, { "gssapi.unknown_header", PI_PROTOCOL, PI_WARN, "Unknown header", EXPFILL }},
618 	};
619 
620 	module_t *gssapi_module;
621 	expert_module_t *expert_gssapi;
622 
623 	proto_gssapi = proto_register_protocol(
624 		"GSS-API Generic Security Service Application Program Interface",
625 		"GSS-API", "gss-api");
626 
627 	gssapi_module = prefs_register_protocol(proto_gssapi, NULL);
628 	prefs_register_bool_preference(gssapi_module, "gssapi_reassembly",
629 		"Reassemble fragmented GSSAPI blobs",
630 		"Whether or not to try reassembling GSSAPI blobs spanning multiple (SMB/SessionSetup) PDUs",
631 		&gssapi_reassembly);
632 	proto_register_field_array(proto_gssapi, hf, array_length(hf));
633 	proto_register_subtree_array(ett, array_length(ett));
634 	expert_gssapi = expert_register_protocol(proto_gssapi);
635 	expert_register_field_array(expert_gssapi, ei, array_length(ei));
636 
637 	gssapi_handle = register_dissector("gssapi", dissect_gssapi, proto_gssapi);
638 	register_dissector("gssapi_verf", dissect_gssapi_verf, proto_gssapi);
639 
640 	gssapi_oids = g_hash_table_new_full(gssapi_oid_hash, gssapi_oid_equal, g_free, g_free);
641 
642 	reassembly_table_register(&gssapi_reassembly_table,
643 	                      &addresses_reassembly_table_functions);
644 
645 	register_shutdown_routine(gssapi_shutdown);
646 }
647 
648 static int
wrap_dissect_gssapi(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * tree,dcerpc_info * di _U_,guint8 * drep _U_)649 wrap_dissect_gssapi(tvbuff_t *tvb, int offset, packet_info *pinfo,
650 		    proto_tree *tree, dcerpc_info *di _U_, guint8 *drep _U_)
651 {
652 	tvbuff_t *auth_tvb;
653 
654 	auth_tvb = tvb_new_subset_remaining(tvb, offset);
655 
656 	dissect_gssapi(auth_tvb, pinfo, tree, NULL);
657 
658 	return tvb_captured_length_remaining(tvb, offset);
659 }
660 
661 int
wrap_dissect_gssapi_verf(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * tree,dcerpc_info * di _U_,guint8 * drep _U_)662 wrap_dissect_gssapi_verf(tvbuff_t *tvb, int offset, packet_info *pinfo,
663 			 proto_tree *tree, dcerpc_info *di _U_, guint8 *drep _U_)
664 {
665 	tvbuff_t *auth_tvb;
666 
667 	auth_tvb = tvb_new_subset_remaining(tvb, offset);
668 
669 	return dissect_gssapi_verf(auth_tvb, pinfo, tree, NULL);
670 }
671 
672 tvbuff_t *
wrap_dissect_gssapi_payload(tvbuff_t * header_tvb,tvbuff_t * payload_tvb,tvbuff_t * trailer_tvb,tvbuff_t * auth_tvb,packet_info * pinfo,dcerpc_auth_info * auth_info)673 wrap_dissect_gssapi_payload(tvbuff_t *header_tvb,
674 			    tvbuff_t *payload_tvb,
675 			    tvbuff_t *trailer_tvb,
676 			    tvbuff_t *auth_tvb,
677 			    packet_info *pinfo,
678 			    dcerpc_auth_info *auth_info)
679 {
680 	tvbuff_t *result;
681 	gssapi_encrypt_info_t gssapi_encrypt;
682 
683 	memset(&gssapi_encrypt, 0x0, sizeof(gssapi_encrypt_info_t));
684 
685 	/* we need a full auth and a full data tvb or else we can't
686 	   decrypt anything
687 	*/
688 	if((!auth_tvb)||(!payload_tvb)){
689 		return NULL;
690 	}
691 
692 	if (!auth_info->hdr_signing) {
693 		header_tvb = NULL;
694 		trailer_tvb = NULL;
695 	}
696 
697 	gssapi_encrypt.decrypt_gssapi_tvb=DECRYPT_GSSAPI_DCE;
698 	gssapi_encrypt.gssapi_header_tvb=header_tvb;
699 	gssapi_encrypt.gssapi_encrypted_tvb=payload_tvb;
700 	gssapi_encrypt.gssapi_trailer_tvb=trailer_tvb;
701 
702 	dissect_gssapi(auth_tvb, pinfo, NULL, &gssapi_encrypt);
703 	result=gssapi_encrypt.gssapi_decrypted_tvb;
704 
705 	return result;
706 }
707 
708 static dcerpc_auth_subdissector_fns gssapi_auth_fns = {
709 	wrap_dissect_gssapi,		        /* Bind */
710 	wrap_dissect_gssapi,	 	        /* Bind ACK */
711 	wrap_dissect_gssapi,			/* AUTH3 */
712 	wrap_dissect_gssapi_verf, 		/* Request verifier */
713 	wrap_dissect_gssapi_verf,		/* Response verifier */
714 	wrap_dissect_gssapi_payload,		/* Request data */
715 	wrap_dissect_gssapi_payload             /* Response data */
716 };
717 
718 void
proto_reg_handoff_gssapi(void)719 proto_reg_handoff_gssapi(void)
720 {
721 	ntlmssp_handle = find_dissector_add_dependency("ntlmssp", proto_gssapi);
722 	ntlmssp_payload_handle = find_dissector_add_dependency("ntlmssp_payload", proto_gssapi);
723 	ntlmssp_verf_handle = find_dissector_add_dependency("ntlmssp_verf", proto_gssapi);
724 	ntlmssp_data_only_handle = find_dissector_add_dependency("ntlmssp_data_only", proto_gssapi);
725 	spnego_krb5_wrap_handle = find_dissector_add_dependency("spnego-krb5-wrap", proto_gssapi);
726 
727 	register_dcerpc_auth_subdissector(DCE_C_AUTHN_LEVEL_CONNECT,
728 					  DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO,
729 					  &gssapi_auth_fns);
730 	register_dcerpc_auth_subdissector(DCE_C_AUTHN_LEVEL_PKT_INTEGRITY,
731 					  DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO,
732 					  &gssapi_auth_fns);
733 	register_dcerpc_auth_subdissector(DCE_C_AUTHN_LEVEL_PKT_PRIVACY,
734 					  DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO,
735 					  &gssapi_auth_fns);
736 
737 	dissector_add_string("dns.tsig.mac", "gss.microsoft.com", gssapi_handle);
738 }
739 
740 /*
741  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
742  *
743  * Local variables:
744  * c-basic-offset: 8
745  * tab-width: 8
746  * indent-tabs-mode: t
747  * End:
748  *
749  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
750  * :indentSize=8:tabSize=8:noTabs=false:
751  */
752