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
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
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.
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.
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.
32 #ifdef HAVE_SYS_TYPES_H
33 # include <sys/types.h>
39 #include <epan/packet.h>
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 "packet-ber.h"
48 static int proto_gssapi = -1;
50 static int hf_gssapi_oid = -1;
52 static gint ett_gssapi = -1;
58 static dissector_handle_t ntlmssp_handle = NULL;
60 static GHashTable *gssapi_oids;
62 static gint gssapi_oid_equal(gconstpointer k1, gconstpointer k2)
64 const char *key1 = (const char *)k1;
65 const char *key2 = (const char *)k2;
67 return strcmp(key1, key2) == 0;
71 gssapi_oid_hash(gconstpointer k)
73 const char *key = (const char *)k;
76 for (i = 0; i < strlen(key); i++)
83 gssapi_init_oid(const char *oid, int proto, int ett, dissector_handle_t handle,
84 dissector_handle_t wrap_handle, const gchar *comment)
86 char *key = g_strdup(oid);
87 gssapi_oid_value *value = g_malloc(sizeof(*value));
89 value->proto = find_protocol_by_id(proto);
91 value->handle = handle;
92 value->wrap_handle = wrap_handle;
93 value->comment = comment;
95 g_hash_table_insert(gssapi_oids, key, value);
96 register_ber_oid_dissector_handle(key, handle, proto, comment);
100 * This takes an OID in text string form as
104 gssapi_lookup_oid_str(const char *oid_key)
106 gssapi_oid_value *value;
110 value = g_hash_table_lookup(gssapi_oids, oid_key);
115 dissect_gssapi_work(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
116 gboolean is_verifier)
120 volatile int return_offset = 0;
121 gssapi_oid_value *value;
122 volatile dissector_handle_t handle;
123 conversation_t *volatile conversation;
125 int len, offset, start_offset, oid_start_offset;
127 gboolean pc, ind_field;
136 * We don't know whether the data is encrypted, so say it's
137 * not, for now. The subdissector must set gssapi_data_encrypted
140 pinfo->gssapi_data_encrypted = FALSE;
143 * We need this later, so lets get it now ...
146 conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
147 pinfo->ptype, pinfo->srcport,
150 item = proto_tree_add_item(
151 tree, proto_gssapi, tvb, offset, -1, FALSE);
153 subtree = proto_item_add_subtree(item, ett_gssapi);
156 * Catch the ReportedBoundsError exception; the stuff we've been
157 * handed doesn't necessarily run to the end of the packet, it's
158 * an item inside a packet, so if it happens to be malformed (or
159 * we, or a dissector we call, has a bug), so that an exception
160 * is thrown, we want to report the error, but return and let
161 * our caller dissect the rest of the packet.
163 * If it gets a BoundsError, we can stop, as there's nothing more
164 * in the packet after our blob to see, so we just re-throw the
169 offset = get_ber_identifier(tvb, offset, &class, &pc, &tag);
170 offset = get_ber_length(tree, tvb, offset, &len1, &ind_field);
172 if (!(class == BER_CLASS_APP && pc && tag == 0)) {
174 * If we do not recognise an Application class,
175 * then we are probably dealing with an inner context
176 * token or a wrap token, and we should retrieve the
177 * gssapi_oid_value pointer from the per-frame data or,
178 * if there is no per-frame data (as would be the case
179 * the first time we dissect this frame), from the
180 * conversation that exists or that we created from
181 * pinfo (and then make it per-frame data).
182 * We need to make it per-frame data as there can be
183 * more than one GSS-API negotiation in a conversation.
185 * Note! We "cheat". Since we only need the pointer,
186 * we store that as the data. (That's not really
187 * "cheating" - the per-frame data and per-conversation
188 * data code doesn't care what you supply as a data
189 * pointer; it just treats it as an opaque pointer, it
190 * doesn't dereference it or free what it points to.)
192 value = p_get_proto_data(pinfo->fd, proto_gssapi);
193 if (!value && !pinfo->fd->flags.visited)
195 /* No handle attached to this frame, but it's the first */
196 /* pass, so it'd be attached to the conversation. */
197 /* If we have a conversation, try to get the handle, */
198 /* and if we get one, attach it to the frame. */
201 value = conversation_get_proto_data(conversation,
204 p_add_proto_data(pinfo->fd, proto_gssapi, value);
209 /* It could be NTLMSSP, with no OID. This can happen
210 for anything that microsoft calls 'Negotiate' or GSS-SPNEGO */
211 if (tvb_strneql(tvb, start_offset, "NTLMSSP", 7) == 0) {
212 call_dissector(ntlmssp_handle, tvb_new_subset(tvb, start_offset, -1, -1), pinfo, subtree);
214 proto_tree_add_text(subtree, tvb, start_offset, 0,
215 "Unknown header (class=%d, pc=%d, tag=%d)",
218 return_offset = tvb_length(tvb);
224 oid_tvb = tvb_new_subset(tvb, start_offset, -1, -1);
226 handle = value->wrap_handle;
228 handle = value->handle;
229 len = call_dissector(handle, oid_tvb, pinfo, subtree);
231 return_offset = tvb_length(tvb);
233 return_offset = start_offset + len;
234 goto done; /* We are finished here */
239 oid_start_offset=offset;
240 offset=dissect_ber_object_identifier_str(FALSE, pinfo, subtree, tvb, offset, hf_gssapi_oid, &oid);
243 * Hand off to subdissector.
246 if (((value = gssapi_lookup_oid_str(oid)) == NULL) ||
247 !proto_is_protocol_enabled(value->proto)) {
248 /* No dissector for this oid */
249 proto_tree_add_text(subtree, tvb, oid_start_offset, -1,
252 return_offset = tvb_length(tvb);
257 * This is not needed, as the sub-dissector adds a tree
258 sub_item = proto_tree_add_item(subtree, value->proto, tvb,
261 oid_subtree = proto_item_add_subtree(sub_item, value->ett);
265 * Here we should create a conversation if needed and
266 * save a pointer to the data for that OID for the
270 if (!conversation) { /* Create one */
271 conversation = conversation_new(pinfo->fd->num, &pinfo->src,
279 * Now add the proto data ...
280 * but only if it is not already there.
283 if (!conversation_get_proto_data(conversation,
285 conversation_add_proto_data(conversation,
286 proto_gssapi, value);
290 handle = value->wrap_handle;
291 if (handle != NULL) {
292 oid_tvb = tvb_new_subset(tvb, offset, -1, -1);
293 len = call_dissector(handle, oid_tvb, pinfo,
296 return_offset = tvb_length(tvb);
298 return_offset = offset + len;
300 proto_tree_add_text(subtree, tvb, offset, -1,
301 "Authentication verifier");
302 return_offset = tvb_length(tvb);
305 handle = value->handle;
306 if (handle != NULL) {
307 oid_tvb = tvb_new_subset(tvb, offset, -1, -1);
308 len = call_dissector(handle, oid_tvb, pinfo,
311 return_offset = tvb_length(tvb);
313 return_offset = offset + len;
315 proto_tree_add_text(subtree, tvb, offset, -1,
316 "Authentication credentials");
317 return_offset = tvb_length(tvb);
323 } CATCH(BoundsError) {
325 } CATCH(ReportedBoundsError) {
326 show_reported_bounds_error(tvb, pinfo, tree);
329 proto_item_set_len(item, return_offset);
330 return return_offset;
334 dissect_gssapi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
336 dissect_gssapi_work(tvb, pinfo, tree, FALSE);
340 dissect_gssapi_verf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
342 return dissect_gssapi_work(tvb, pinfo, tree, TRUE);
346 proto_register_gssapi(void)
348 static hf_register_info hf[] = {
350 "OID", "gss-api.OID", FT_STRING, BASE_NONE,
351 NULL, 0, "This is a GSS-API Object Identifier", HFILL }},
354 static gint *ett[] = {
358 proto_gssapi = proto_register_protocol(
359 "GSS-API Generic Security Service Application Program Interface",
360 "GSS-API", "gss-api");
362 proto_register_field_array(proto_gssapi, hf, array_length(hf));
363 proto_register_subtree_array(ett, array_length(ett));
365 register_dissector("gssapi", dissect_gssapi, proto_gssapi);
366 new_register_dissector("gssapi_verf", dissect_gssapi_verf, proto_gssapi);
368 gssapi_oids = g_hash_table_new(gssapi_oid_hash, gssapi_oid_equal);
371 static int wrap_dissect_gssapi(tvbuff_t *tvb, int offset,
373 proto_tree *tree, guint8 *drep _U_)
377 auth_tvb = tvb_new_subset(tvb, offset, -1, -1);
379 dissect_gssapi(auth_tvb, pinfo, tree);
381 return tvb_length_remaining(tvb, offset);
384 int wrap_dissect_gssapi_verf(tvbuff_t *tvb, int offset,
386 proto_tree *tree, guint8 *drep _U_)
390 auth_tvb = tvb_new_subset(tvb, offset, -1, -1);
392 return dissect_gssapi_verf(auth_tvb, pinfo, tree);
396 wrap_dissect_gssapi_payload(tvbuff_t *data_tvb,
400 dcerpc_auth_info *auth_info _U_)
404 /* we need a full auth and a full data tvb or else we cant
407 if((!auth_tvb)||(!data_tvb)){
411 pinfo->decrypt_gssapi_tvb=DECRYPT_GSSAPI_DCE;
412 pinfo->gssapi_wrap_tvb=NULL;
413 pinfo->gssapi_encrypted_tvb=data_tvb;
414 pinfo->gssapi_decrypted_tvb=NULL;
415 dissect_gssapi_verf(auth_tvb, pinfo, NULL);
416 result=pinfo->gssapi_decrypted_tvb;
418 pinfo->decrypt_gssapi_tvb=0;
419 pinfo->gssapi_wrap_tvb=NULL;
420 pinfo->gssapi_encrypted_tvb=NULL;
421 pinfo->gssapi_decrypted_tvb=NULL;
426 static dcerpc_auth_subdissector_fns gssapi_auth_fns = {
427 wrap_dissect_gssapi, /* Bind */
428 wrap_dissect_gssapi, /* Bind ACK */
429 wrap_dissect_gssapi, /* AUTH3 */
430 wrap_dissect_gssapi_verf, /* Request verifier */
431 wrap_dissect_gssapi_verf, /* Response verifier */
432 NULL, /* Request data */
433 NULL /* Response data */
437 proto_reg_handoff_gssapi(void)
439 dissector_handle_t gssapi_handle;
441 ntlmssp_handle = find_dissector("ntlmssp");
443 register_dcerpc_auth_subdissector(DCE_C_AUTHN_LEVEL_CONNECT,
444 DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO,
446 register_dcerpc_auth_subdissector(DCE_C_AUTHN_LEVEL_PKT_INTEGRITY,
447 DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO,
449 register_dcerpc_auth_subdissector(DCE_C_AUTHN_LEVEL_PKT_PRIVACY,
450 DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO,
453 gssapi_handle = create_dissector_handle(dissect_gssapi, proto_gssapi);
454 dissector_add_string("dns.tsig.mac", "gss.microsoft.com", gssapi_handle);