STEP01x ? OK RFC6113.asn ....
[metze/wireshark/wip.git] / epan / dissectors / asn1 / kerberos / packet-kerberos-template.c
1 /* packet-kerberos.c
2  * Routines for Kerberos
3  * Wes Hardaker (c) 2000
4  * wjhardaker@ucdavis.edu
5  * Richard Sharpe (C) 2002, rsharpe@samba.org, modularized a bit more and
6  *                          added AP-REQ and AP-REP dissection
7  *
8  * Ronnie Sahlberg (C) 2004, major rewrite for new ASN.1/BER API.
9  *                           decryption of kerberos blobs if keytab is provided
10  *
11  * See RFC 1510, and various I-Ds and other documents showing additions,
12  * e.g. ones listed under
13  *
14  *      http://www.isi.edu/people/bcn/krb-revisions/
15  *
16  * and
17  *
18  *      http://www.ietf.org/internet-drafts/draft-ietf-krb-wg-kerberos-clarifications-07.txt
19  *
20  * and
21  *
22  *      http://www.ietf.org/internet-drafts/draft-ietf-krb-wg-kerberos-referrals-05.txt
23  *
24  * Some structures from RFC2630
25  *
26  * Wireshark - Network traffic analyzer
27  * By Gerald Combs <gerald@wireshark.org>
28  * Copyright 1998 Gerald Combs
29  *
30  * SPDX-License-Identifier: GPL-2.0-or-later
31  */
32
33 /*
34  * Some of the development of the Kerberos protocol decoder was sponsored by
35  * Cable Television Laboratories, Inc. ("CableLabs") based upon proprietary
36  * CableLabs' specifications. Your license and use of this protocol decoder
37  * does not mean that you are licensed to use the CableLabs'
38  * specifications.  If you have questions about this protocol, contact
39  * jf.mule [AT] cablelabs.com or c.stuart [AT] cablelabs.com for additional
40  * information.
41  */
42
43 #include <config.h>
44
45 #include <stdio.h>
46
47 #include <epan/packet.h>
48 #include <epan/exceptions.h>
49 #include <epan/strutil.h>
50 #include <epan/conversation.h>
51 #include <epan/asn1.h>
52 #include <epan/expert.h>
53 #include <epan/prefs.h>
54 #include <wsutil/wsgcrypt.h>
55 #include <wsutil/file_util.h>
56 #include <wsutil/str_util.h>
57 #include "packet-kerberos.h"
58 #include "packet-netbios.h"
59 #include "packet-tcp.h"
60 #include "packet-ber.h"
61 #include "packet-pkinit.h"
62 #include "packet-cms.h"
63 #include "packet-windows-common.h"
64
65 #include "read_keytab_file.h"
66
67 #include "packet-dcerpc-netlogon.h"
68 #include "packet-dcerpc.h"
69
70 #include "packet-gssapi.h"
71 #include "packet-smb-common.h"
72 #include "packet-x509af.h"
73
74 #define KEY_USAGE_FAST_REQ_CHKSUM       50
75 #define KEY_USAGE_FAST_ENC              51
76 #define KEY_USAGE_FAST_REP              52
77 #define KEY_USAGE_FAST_FINISHED         53
78 #define KEY_USAGE_ENC_CHALLENGE_CLIENT  54
79 #define KEY_USAGE_ENC_CHALLENGE_KDC     55
80
81 void proto_register_kerberos(void);
82 void proto_reg_handoff_kerberos(void);
83
84 #define UDP_PORT_KERBEROS               88
85 #define TCP_PORT_KERBEROS               88
86
87 #define ADDRESS_STR_BUFSIZ 256
88
89 typedef struct kerberos_key {
90         guint32 keytype;
91         int keylength;
92         const guint8 *keyvalue;
93 } kerberos_key_t;
94
95 typedef struct {
96         guint32 msg_type;
97         gboolean kdc_response_initialized;
98         gboolean kdc_response;
99         guint32 etype;
100         guint32 padata_type;
101         guint32 is_enc_padata;
102         guint32 enctype;
103         kerberos_key_t key;
104         guint32 ad_type;
105         guint32 addr_type;
106         guint32 checksum_type;
107 } kerberos_private_data_t;
108
109 static dissector_handle_t kerberos_handle_udp;
110
111 /* Forward declarations */
112 static int dissect_kerberos_Applications(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
113 static int dissect_kerberos_PA_ENC_TIMESTAMP(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
114 static int dissect_kerberos_PA_ENC_TS_ENC(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
115 static int dissect_kerberos_KERB_PA_PAC_REQUEST(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
116 static int dissect_kerberos_PA_S4U2Self(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
117 static int dissect_kerberos_PA_S4U_X509_USER(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
118 static int dissect_kerberos_ETYPE_INFO(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
119 static int dissect_kerberos_ETYPE_INFO2(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
120 static int dissect_kerberos_AD_IF_RELEVANT(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
121 static int dissect_kerberos_PA_AUTHENTICATION_SET_ELEM(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
122 static int dissect_kerberos_PA_FX_FAST_REQUEST(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
123 static int dissect_kerberos_PA_FX_FAST_REPLY(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
124 static int dissect_kerberos_KrbFastReq(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
125 static int dissect_kerberos_KrbFastResponse(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
126 static int dissect_kerberos_EncryptedChallenge(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
127
128 /* Desegment Kerberos over TCP messages */
129 static gboolean krb_desegment = TRUE;
130
131 static gint proto_kerberos = -1;
132
133 static gint hf_krb_rm_reserved = -1;
134 static gint hf_krb_rm_reclen = -1;
135 static gint hf_krb_provsrv_location = -1;
136 static gint hf_krb_smb_nt_status = -1;
137 static gint hf_krb_smb_unknown = -1;
138 static gint hf_krb_address_ip = -1;
139 static gint hf_krb_address_netbios = -1;
140 static gint hf_krb_address_ipv6 = -1;
141 static gint hf_krb_gssapi_len = -1;
142 static gint hf_krb_gssapi_bnd = -1;
143 static gint hf_krb_gssapi_dlgopt = -1;
144 static gint hf_krb_gssapi_dlglen = -1;
145 static gint hf_krb_gssapi_c_flag_deleg = -1;
146 static gint hf_krb_gssapi_c_flag_mutual = -1;
147 static gint hf_krb_gssapi_c_flag_replay = -1;
148 static gint hf_krb_gssapi_c_flag_sequence = -1;
149 static gint hf_krb_gssapi_c_flag_conf = -1;
150 static gint hf_krb_gssapi_c_flag_integ = -1;
151 static gint hf_krb_gssapi_c_flag_dce_style = -1;
152 static gint hf_krb_midl_version = -1;
153 static gint hf_krb_midl_hdr_len = -1;
154 static gint hf_krb_midl_fill_bytes = -1;
155 static gint hf_krb_midl_blob_len = -1;
156 static gint hf_krb_pac_signature_type = -1;
157 static gint hf_krb_pac_signature_signature = -1;
158 static gint hf_krb_w2k_pac_entries = -1;
159 static gint hf_krb_w2k_pac_version = -1;
160 static gint hf_krb_w2k_pac_type = -1;
161 static gint hf_krb_w2k_pac_size = -1;
162 static gint hf_krb_w2k_pac_offset = -1;
163 static gint hf_krb_pac_clientid = -1;
164 static gint hf_krb_pac_namelen = -1;
165 static gint hf_krb_pac_clientname = -1;
166 static gint hf_krb_pac_logon_info = -1;
167 static gint hf_krb_pac_credential_type = -1;
168 static gint hf_krb_pac_s4u_delegation_info = -1;
169 static gint hf_krb_pac_upn_dns_info = -1;
170 static gint hf_krb_pac_upn_flags = -1;
171 static gint hf_krb_pac_upn_dns_offset = -1;
172 static gint hf_krb_pac_upn_dns_len = -1;
173 static gint hf_krb_pac_upn_upn_offset = -1;
174 static gint hf_krb_pac_upn_upn_len = -1;
175 static gint hf_krb_pac_upn_upn_name = -1;
176 static gint hf_krb_pac_upn_dns_name = -1;
177 static gint hf_krb_pac_server_checksum = -1;
178 static gint hf_krb_pac_privsvr_checksum = -1;
179 static gint hf_krb_pac_client_info_type = -1;
180 #include "packet-kerberos-hf.c"
181
182 /* Initialize the subtree pointers */
183 static gint ett_kerberos = -1;
184 static gint ett_krb_recordmark = -1;
185 static gint ett_krb_pac = -1;
186 static gint ett_krb_pac_drep = -1;
187 static gint ett_krb_pac_midl_blob = -1;
188 static gint ett_krb_pac_logon_info = -1;
189 static gint ett_krb_pac_s4u_delegation_info = -1;
190 static gint ett_krb_pac_upn_dns_info = -1;
191 static gint ett_krb_pac_server_checksum = -1;
192 static gint ett_krb_pac_privsvr_checksum = -1;
193 static gint ett_krb_pac_client_info_type = -1;
194 #include "packet-kerberos-ett.c"
195
196 static expert_field ei_kerberos_decrypted_keytype = EI_INIT;
197 static expert_field ei_kerberos_address = EI_INIT;
198 static expert_field ei_krb_gssapi_dlglen = EI_INIT;
199
200 static dissector_handle_t krb4_handle=NULL;
201
202 /* Global variables */
203 static guint32 krb5_errorcode;
204 static guint32 gbl_keytype;
205 static gboolean gbl_do_col_info;
206
207 #include "packet-kerberos-val.h"
208
209 static void
210 call_kerberos_callbacks(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int tag, kerberos_callbacks *cb)
211 {
212         if(!cb){
213                 return;
214         }
215
216         while(cb->tag){
217                 if(cb->tag==tag){
218                         cb->callback(pinfo, tvb, tree);
219                         return;
220                 }
221                 cb++;
222         }
223         return;
224 }
225
226 static kerberos_private_data_t*
227 kerberos_get_private_data(asn1_ctx_t *actx)
228 {
229         if (!actx->private_data) {
230                 actx->private_data = wmem_new0(wmem_packet_scope(), kerberos_private_data_t);
231         }
232         return (kerberos_private_data_t *)(actx->private_data);
233 }
234
235 #ifdef HAVE_KERBEROS
236
237 /* Decrypt Kerberos blobs */
238 gboolean krb_decrypt = FALSE;
239
240 /* keytab filename */
241 static const char *keytab_filename = "";
242
243 void
244 read_keytab_file_from_preferences(void)
245 {
246         static char *last_keytab = NULL;
247
248         if (!krb_decrypt) {
249                 return;
250         }
251
252         if (keytab_filename == NULL) {
253                 return;
254         }
255
256         if (last_keytab && !strcmp(last_keytab, keytab_filename)) {
257                 return;
258         }
259
260         g_free(last_keytab);
261         last_keytab = g_strdup(keytab_filename);
262
263         read_keytab_file(last_keytab);
264 }
265 #endif /* HAVE_KERBEROS */
266
267 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
268 #ifdef _WIN32
269 /* prevent redefinition warnings in kfw-2.5\inc\win_mac.h */
270 #undef HAVE_GETADDRINFO
271 #undef HAVE_SYS_TYPES_H
272 #endif /* _WIN32 */
273 #include <krb5.h>
274 enc_key_t *enc_key_list=NULL;
275
276 static void
277 add_encryption_key(packet_info *pinfo, int keytype, int keylength, const char *keyvalue, const char *origin)
278 {
279         enc_key_t *new_key;
280
281         if(pinfo->fd->visited){
282                 return;
283         }
284
285         new_key=(enc_key_t *)g_malloc(sizeof(enc_key_t));
286         g_snprintf(new_key->key_origin, KRB_MAX_ORIG_LEN, "%s learnt from frame %u",origin,pinfo->num);
287         new_key->fd_num = pinfo->num;
288         new_key->next=enc_key_list;
289         enc_key_list=new_key;
290         new_key->keytype=keytype;
291         new_key->keylength=keylength;
292         /*XXX this needs to be freed later */
293         new_key->keyvalue=(char *)g_memdup(keyvalue, keylength);
294 }
295 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
296
297 #if defined(HAVE_MIT_KERBEROS)
298
299 static krb5_context krb5_ctx;
300
301 USES_APPLE_DEPRECATED_API
302 void
303 read_keytab_file(const char *filename)
304 {
305         krb5_keytab keytab;
306         krb5_error_code ret;
307         krb5_keytab_entry key;
308         krb5_kt_cursor cursor;
309         static gboolean first_time=TRUE;
310
311         if (filename == NULL || filename[0] == 0) {
312                 return;
313         }
314
315         if(first_time){
316                 first_time=FALSE;
317                 ret = krb5_init_context(&krb5_ctx);
318                 if(ret && ret != KRB5_CONFIG_CANTOPEN){
319                         return;
320                 }
321         }
322
323         /* should use a file in the wireshark users dir */
324         ret = krb5_kt_resolve(krb5_ctx, filename, &keytab);
325         if(ret){
326                 fprintf(stderr, "KERBEROS ERROR: Badly formatted keytab filename :%s\n",filename);
327
328                 return;
329         }
330
331         ret = krb5_kt_start_seq_get(krb5_ctx, keytab, &cursor);
332         if(ret){
333                 fprintf(stderr, "KERBEROS ERROR: Could not open or could not read from keytab file :%s\n",filename);
334                 return;
335         }
336
337         do{
338                 ret = krb5_kt_next_entry(krb5_ctx, keytab, &key, &cursor);
339                 if(ret==0){
340                         enc_key_t *new_key;
341                         int i;
342                         char *pos;
343
344                         new_key = g_new(enc_key_t, 1);
345                         new_key->fd_num = -1;
346                         new_key->next = enc_key_list;
347
348                         /* generate origin string, describing where this key came from */
349                         pos=new_key->key_origin;
350                         pos+=MIN(KRB_MAX_ORIG_LEN,
351                                          g_snprintf(pos, KRB_MAX_ORIG_LEN, "keytab principal "));
352                         for(i=0;i<key.principal->length;i++){
353                                 pos+=MIN(KRB_MAX_ORIG_LEN-(pos-new_key->key_origin),
354                                                  g_snprintf(pos, (gulong)(KRB_MAX_ORIG_LEN-(pos-new_key->key_origin)), "%s%s",(i?"/":""),(key.principal->data[i]).data));
355                         }
356                         pos+=MIN(KRB_MAX_ORIG_LEN-(pos-new_key->key_origin),
357                                          g_snprintf(pos, (gulong)(KRB_MAX_ORIG_LEN-(pos-new_key->key_origin)), "@%s",key.principal->realm.data));
358                         *pos=0;
359                         new_key->keytype=key.key.enctype;
360                         new_key->keylength=key.key.length;
361                         new_key->keyvalue=(char *)g_memdup(key.key.contents, key.key.length);
362                         enc_key_list=new_key;
363                         ret = krb5_free_keytab_entry_contents(krb5_ctx, &key);
364                         if (ret) {
365                                 fprintf(stderr, "KERBEROS ERROR: Could not release the entry: %d", ret);
366                                 ret = 0; /* try to continue with the next entry */
367                         }
368                 }
369         }while(ret==0);
370
371         ret = krb5_kt_end_seq_get(krb5_ctx, keytab, &cursor);
372         if(ret){
373                 fprintf(stderr, "KERBEROS ERROR: Could not release the keytab cursor: %d", ret);
374         }
375         ret = krb5_kt_close(krb5_ctx, keytab);
376         if(ret){
377                 fprintf(stderr, "KERBEROS ERROR: Could not close the key table handle: %d", ret);
378         }
379 }
380
381
382 guint8 *
383 decrypt_krb5_data(proto_tree *tree _U_, packet_info *pinfo,
384                                         int usage,
385                                         tvbuff_t *cryptotvb,
386                                         int keytype,
387                                         int *datalen)
388 {
389         krb5_error_code ret;
390         enc_key_t *ek;
391         krb5_data data = {0,0,NULL};
392         krb5_keytab_entry key;
393         int length = tvb_captured_length(cryptotvb);
394         const guint8 *cryptotext = tvb_get_ptr(cryptotvb, 0, length);
395
396         /* don't do anything if we are not attempting to decrypt data */
397         if(!krb_decrypt || length < 1){
398                 return NULL;
399         }
400
401         /* make sure we have all the data we need */
402         if (tvb_captured_length(cryptotvb) < tvb_reported_length(cryptotvb)) {
403                 return NULL;
404         }
405
406         read_keytab_file_from_preferences();
407         data.data = (char *)wmem_alloc(pinfo->pool, length);
408         data.length = length;
409
410         for(ek=enc_key_list;ek;ek=ek->next){
411                 krb5_enc_data input;
412
413                 /* shortcircuit and bail out if enctypes are not matching */
414                 if((keytype != -1) && (ek->keytype != keytype)) {
415                         continue;
416                 }
417
418                 input.enctype = ek->keytype;
419                 input.ciphertext.length = length;
420                 input.ciphertext.data = (guint8 *)cryptotext;
421
422                 key.key.enctype=ek->keytype;
423                 key.key.length=ek->keylength;
424                 key.key.contents=ek->keyvalue;
425                 ret = krb5_c_decrypt(krb5_ctx, &(key.key), usage, 0, &input, &data);
426                 if(ret == 0){
427                         char *user_data;
428
429                         expert_add_info_format(pinfo, NULL, &ei_kerberos_decrypted_keytype,
430                                                                    "Decrypted keytype %d in frame %u using %s",
431                                                                    ek->keytype, pinfo->num, ek->key_origin);
432
433                         proto_tree_add_text(tree, NULL, 0, 0, "[Decrypted using: %s]", ek->key_origin);
434
435                         user_data=data.data;
436                         if (datalen) {
437                                 *datalen = data.length;
438                         }
439                         return user_data;
440                 }
441         }
442
443         return NULL;
444 }
445 USES_APPLE_RST
446
447 #elif defined(HAVE_HEIMDAL_KERBEROS)
448 static krb5_context krb5_ctx;
449
450 USES_APPLE_DEPRECATED_API
451 void
452 read_keytab_file(const char *filename)
453 {
454         krb5_keytab keytab;
455         krb5_error_code ret;
456         krb5_keytab_entry key;
457         krb5_kt_cursor cursor;
458         enc_key_t *new_key;
459         static gboolean first_time=TRUE;
460
461         if (filename == NULL || filename[0] == 0) {
462                 return;
463         }
464
465         if(first_time){
466                 first_time=FALSE;
467                 ret = krb5_init_context(&krb5_ctx);
468                 if(ret){
469                         return;
470                 }
471         }
472
473         /* should use a file in the wireshark users dir */
474         ret = krb5_kt_resolve(krb5_ctx, filename, &keytab);
475         if(ret){
476                 fprintf(stderr, "KERBEROS ERROR: Could not open keytab file :%s\n",filename);
477
478                 return;
479         }
480
481         ret = krb5_kt_start_seq_get(krb5_ctx, keytab, &cursor);
482         if(ret){
483                 fprintf(stderr, "KERBEROS ERROR: Could not read from keytab file :%s\n",filename);
484                 return;
485         }
486
487         do{
488                 ret = krb5_kt_next_entry(krb5_ctx, keytab, &key, &cursor);
489                 if(ret==0){
490                         unsigned int i;
491                         char *pos;
492
493                         new_key = g_new0(enc_key_t, 1);
494                         new_key->fd_num = -1;
495                         new_key->next = enc_key_list;
496
497                         /* generate origin string, describing where this key came from */
498                         pos=new_key->key_origin;
499                         pos+=MIN(KRB_MAX_ORIG_LEN,
500                                          g_snprintf(pos, KRB_MAX_ORIG_LEN, "keytab principal "));
501                         for(i=0;i<key.principal->name.name_string.len;i++){
502                                 pos+=MIN(KRB_MAX_ORIG_LEN-(pos-new_key->key_origin),
503                                                  g_snprintf(pos, KRB_MAX_ORIG_LEN-(pos-new_key->key_origin), "%s%s",(i?"/":""),key.principal->name.name_string.val[i]));
504                         }
505                         pos+=MIN(KRB_MAX_ORIG_LEN-(pos-new_key->key_origin),
506                                          g_snprintf(pos, KRB_MAX_ORIG_LEN-(pos-new_key->key_origin), "@%s",key.principal->realm));
507                         *pos=0;
508                         new_key->keytype=key.keyblock.keytype;
509                         new_key->keylength=(int)key.keyblock.keyvalue.length;
510                         new_key->keyvalue = (guint8 *)g_memdup(key.keyblock.keyvalue.data, (guint)key.keyblock.keyvalue.length);
511                         enc_key_list=new_key;
512                         ret = krb5_kt_free_entry(krb5_ctx, &key);
513                         if (ret) {
514                                 fprintf(stderr, "KERBEROS ERROR: Could not release the entry: %d", ret);
515                                 ret = 0; /* try to continue with the next entry */
516                         }
517                 }
518         }while(ret==0);
519
520         ret = krb5_kt_end_seq_get(krb5_ctx, keytab, &cursor);
521         if(ret){
522                 fprintf(stderr, "KERBEROS ERROR: Could not release the keytab cursor: %d", ret);
523         }
524         ret = krb5_kt_close(krb5_ctx, keytab);
525         if(ret){
526                 fprintf(stderr, "KERBEROS ERROR: Could not close the key table handle: %d", ret);
527         }
528
529 }
530 USES_APPLE_RST
531
532
533 guint8 *
534 decrypt_krb5_data(proto_tree *tree _U_, packet_info *pinfo,
535                                         int usage,
536                                         tvbuff_t *cryptotvb,
537                                         int keytype,
538                                         int *datalen)
539 {
540         krb5_error_code ret;
541         krb5_data data;
542         enc_key_t *ek;
543         int length = tvb_captured_length(cryptotvb);
544         const guint8 *cryptotext = tvb_get_ptr(cryptotvb, 0, length);
545
546         /* don't do anything if we are not attempting to decrypt data */
547         if(!krb_decrypt){
548                 return NULL;
549         }
550
551         /* make sure we have all the data we need */
552         if (tvb_captured_length(cryptotvb) < tvb_reported_length(cryptotvb)) {
553                 return NULL;
554         }
555
556         read_keytab_file_from_preferences();
557
558         for(ek=enc_key_list;ek;ek=ek->next){
559                 krb5_keytab_entry key;
560                 krb5_crypto crypto;
561                 guint8 *cryptocopy; /* workaround for pre-0.6.1 heimdal bug */
562
563                 /* shortcircuit and bail out if enctypes are not matching */
564                 if((keytype != -1) && (ek->keytype != keytype)) {
565                         continue;
566                 }
567
568                 key.keyblock.keytype=ek->keytype;
569                 key.keyblock.keyvalue.length=ek->keylength;
570                 key.keyblock.keyvalue.data=ek->keyvalue;
571                 ret = krb5_crypto_init(krb5_ctx, &(key.keyblock), (krb5_enctype)ENCTYPE_NULL, &crypto);
572                 if(ret){
573                         return NULL;
574                 }
575
576                 /* pre-0.6.1 versions of Heimdal would sometimes change
577                    the cryptotext data even when the decryption failed.
578                    This would obviously not work since we iterate over the
579                    keys. So just give it a copy of the crypto data instead.
580                    This has been seen for RC4-HMAC blobs.
581                 */
582                 cryptocopy = (guint8 *)wmem_memdup(wmem_packet_scope(), cryptotext, length);
583                 ret = krb5_decrypt_ivec(krb5_ctx, crypto, usage,
584                                                                 cryptocopy, length,
585                                                                 &data,
586                                                                 NULL);
587                 if((ret == 0) && (length>0)){
588                         char *user_data;
589
590                         expert_add_info_format(pinfo, NULL, &ei_kerberos_decrypted_keytype,
591                                                                    "Decrypted keytype %d in frame %u using %s",
592                                                                    ek->keytype, pinfo->num, ek->key_origin);
593
594                         proto_tree_add_text(tree, NULL, 0, 0, "[Decrypted using: %s]", ek->key_origin);
595
596                         krb5_crypto_destroy(krb5_ctx, crypto);
597                         /* return a private wmem_alloced blob to the caller */
598                         user_data = (char *)wmem_memdup(pinfo->pool, data.data, (guint)data.length);
599                         if (datalen) {
600                                 *datalen = (int)data.length;
601                         }
602                         return user_data;
603                 }
604                 krb5_crypto_destroy(krb5_ctx, crypto);
605         }
606         return NULL;
607 }
608
609 #elif defined (HAVE_LIBNETTLE)
610
611 #define SERVICE_KEY_SIZE (DES3_KEY_SIZE + 2)
612 #define KEYTYPE_DES3_CBC_MD5 5  /* Currently the only one supported */
613
614 typedef struct _service_key_t {
615         guint16 kvno;
616         int     keytype;
617         int     length;
618         guint8 *contents;
619         char    origin[KRB_MAX_ORIG_LEN+1];
620 } service_key_t;
621 GSList *service_key_list = NULL;
622
623
624 static void
625 add_encryption_key(packet_info *pinfo, int keytype, int keylength, const char *keyvalue, const char *origin)
626 {
627         service_key_t *new_key;
628
629         if(pinfo->fd->visited){
630                 return;
631         }
632
633         new_key = g_malloc(sizeof(service_key_t));
634         new_key->kvno = 0;
635         new_key->keytype = keytype;
636         new_key->length = keylength;
637         new_key->contents = g_memdup(keyvalue, keylength);
638         g_snprintf(new_key->origin, KRB_MAX_ORIG_LEN, "%s learnt from frame %u", origin, pinfo->num);
639         service_key_list = g_slist_append(service_key_list, (gpointer) new_key);
640 }
641
642 static void
643 clear_keytab(void) {
644         GSList *ske;
645         service_key_t *sk;
646
647         for(ske = service_key_list; ske != NULL; ske = g_slist_next(ske)){
648                 sk = (service_key_t *) ske->data;
649                 if (sk) {
650                         g_free(sk->contents);
651                         g_free(sk);
652                 }
653         }
654         g_slist_free(service_key_list);
655         service_key_list = NULL;
656 }
657
658 static void
659 read_keytab_file(const char *service_key_file)
660 {
661         FILE *skf;
662         ws_statb64 st;
663         service_key_t *sk;
664         unsigned char buf[SERVICE_KEY_SIZE];
665         int newline_skip = 0, count = 0;
666
667         if (service_key_file != NULL && ws_stat64 (service_key_file, &st) == 0) {
668
669                 /* The service key file contains raw 192-bit (24 byte) 3DES keys.
670                  * There can be zero, one (\n), or two (\r\n) characters between
671                  * keys.  Trailing characters are ignored.
672                  */
673
674                 /* XXX We should support the standard keytab format instead */
675                 if (st.st_size > SERVICE_KEY_SIZE) {
676                         if ( (st.st_size % (SERVICE_KEY_SIZE + 1) == 0) ||
677                                  (st.st_size % (SERVICE_KEY_SIZE + 1) == SERVICE_KEY_SIZE) ) {
678                                 newline_skip = 1;
679                         } else if ( (st.st_size % (SERVICE_KEY_SIZE + 2) == 0) ||
680                                  (st.st_size % (SERVICE_KEY_SIZE + 2) == SERVICE_KEY_SIZE) ) {
681                                 newline_skip = 2;
682                         }
683                 }
684
685                 skf = ws_fopen(service_key_file, "rb");
686                 if (! skf) return;
687
688                 while (fread(buf, SERVICE_KEY_SIZE, 1, skf) == 1) {
689                         sk = g_malloc(sizeof(service_key_t));
690                         sk->kvno = buf[0] << 8 | buf[1];
691                         sk->keytype = KEYTYPE_DES3_CBC_MD5;
692                         sk->length = DES3_KEY_SIZE;
693                         sk->contents = g_memdup(buf + 2, DES3_KEY_SIZE);
694                         g_snprintf(sk->origin, KRB_MAX_ORIG_LEN, "3DES service key file, key #%d, offset %ld", count, ftell(skf));
695                         service_key_list = g_slist_append(service_key_list, (gpointer) sk);
696                         if (fseek(skf, newline_skip, SEEK_CUR) < 0) {
697                                 fprintf(stderr, "unable to seek...\n");
698                                 return;
699                         }
700                         count++;
701                 }
702                 fclose(skf);
703         }
704 }
705
706 #define CONFOUNDER_PLUS_CHECKSUM 24
707
708 guint8 *
709 decrypt_krb5_data(proto_tree *tree, packet_info *pinfo,
710                                         int _U_ usage,
711                                         tvbuff_t *cryptotvb,
712                                         int keytype,
713                                         int *datalen)
714 {
715         tvbuff_t *encr_tvb;
716         guint8 *decrypted_data = NULL, *plaintext = NULL;
717         guint8 cls;
718         gboolean pc;
719         guint32 tag, item_len, data_len;
720         int id_offset, offset;
721         guint8 key[DES3_KEY_SIZE];
722         guint8 initial_vector[DES_BLOCK_SIZE];
723         gcry_md_hd_t md5_handle;
724         guint8 *digest;
725         guint8 zero_fill[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
726         guint8 confounder[8];
727         gboolean ind;
728         GSList *ske;
729         service_key_t *sk;
730         struct des3_ctx ctx;
731         int length = tvb_captured_length(cryptotvb);
732         const guint8 *cryptotext = tvb_get_ptr(cryptotvb, 0, length);
733
734
735         /* don't do anything if we are not attempting to decrypt data */
736         if(!krb_decrypt){
737                 return NULL;
738         }
739
740         /* make sure we have all the data we need */
741         if (tvb_captured_length(cryptotvb) < tvb_reported_length(cryptotvb)) {
742                 return NULL;
743         }
744
745         if (keytype != KEYTYPE_DES3_CBC_MD5 || service_key_list == NULL) {
746                 return NULL;
747         }
748
749         decrypted_data = wmem_alloc(wmem_packet_scope(), length);
750         for(ske = service_key_list; ske != NULL; ske = g_slist_next(ske)){
751                 gboolean do_continue = FALSE;
752                 gboolean digest_ok;
753                 sk = (service_key_t *) ske->data;
754
755                 des_fix_parity(DES3_KEY_SIZE, key, sk->contents);
756
757                 memset(initial_vector, 0, DES_BLOCK_SIZE);
758                 des3_set_key(&ctx, key);
759                 cbc_decrypt(&ctx, des3_decrypt, DES_BLOCK_SIZE, initial_vector,
760                                         length, decrypted_data, cryptotext);
761                 encr_tvb = tvb_new_real_data(decrypted_data, length, length);
762
763                 tvb_memcpy(encr_tvb, confounder, 0, 8);
764
765                 /* We have to pull the decrypted data length from the decrypted
766                  * content.  If the key doesn't match or we otherwise get garbage,
767                  * an exception may get thrown while decoding the ASN.1 header.
768                  * Catch it, just in case.
769                  */
770                 TRY {
771                         id_offset = get_ber_identifier(encr_tvb, CONFOUNDER_PLUS_CHECKSUM, &cls, &pc, &tag);
772                         offset = get_ber_length(encr_tvb, id_offset, &item_len, &ind);
773                 }
774                 CATCH_BOUNDS_ERRORS {
775                         tvb_free(encr_tvb);
776                         do_continue = TRUE;
777                 }
778                 ENDTRY;
779
780                 if (do_continue) continue;
781
782                 data_len = item_len + offset - CONFOUNDER_PLUS_CHECKSUM;
783                 if ((int) item_len + offset > length) {
784                         tvb_free(encr_tvb);
785                         continue;
786                 }
787
788                 if (gcry_md_open(&md5_handle, GCRY_MD_MD5, 0)) {
789                         return NULL;
790                 }
791                 gcry_md_write(md5_handle, confounder, 8);
792                 gcry_md_write(md5_handle, zero_fill, 16);
793                 gcry_md_write(md5_handle, decrypted_data + CONFOUNDER_PLUS_CHECKSUM, data_len);
794                 digest = gcry_md_read(md5_handle, 0);
795
796                 digest_ok = (tvb_memeql (encr_tvb, 8, digest, HASH_MD5_LENGTH) == 0);
797                 gcry_md_close(md5_handle);
798                 if (digest_ok) {
799                         plaintext = (guint8* )tvb_memdup(pinfo->pool, encr_tvb, CONFOUNDER_PLUS_CHECKSUM, data_len);
800                         tvb_free(encr_tvb);
801
802                         if (datalen) {
803                                 *datalen = data_len;
804                         }
805                         return(plaintext);
806                 }
807                 tvb_free(encr_tvb);
808         }
809
810         return NULL;
811 }
812
813 #endif  /* HAVE_MIT_KERBEROS / HAVE_HEIMDAL_KERBEROS / HAVE_LIBNETTLE */
814
815 #define INET6_ADDRLEN   16
816
817 /* TCP Record Mark */
818 #define KRB_RM_RESERVED 0x80000000U
819 #define KRB_RM_RECLEN   0x7fffffffU
820
821 #define KRB5_MSG_TICKET                 1       /* Ticket */
822 #define KRB5_MSG_AUTHENTICATOR          2       /* Authenticator */
823 #define KRB5_MSG_ENC_TICKET_PART        3       /* EncTicketPart */
824 #define KRB5_MSG_AS_REQ                 10      /* AS-REQ type */
825 #define KRB5_MSG_AS_REP                 11      /* AS-REP type */
826 #define KRB5_MSG_TGS_REQ                12      /* TGS-REQ type */
827 #define KRB5_MSG_TGS_REP                13      /* TGS-REP type */
828 #define KRB5_MSG_AP_REQ                 14      /* AP-REQ type */
829 #define KRB5_MSG_AP_REP                 15      /* AP-REP type */
830
831 #define KRB5_MSG_SAFE                   20      /* KRB-SAFE type */
832 #define KRB5_MSG_PRIV                   21      /* KRB-PRIV type */
833 #define KRB5_MSG_CRED                   22      /* KRB-CRED type */
834 #define KRB5_MSG_ENC_AS_REP_PART        25      /* EncASRepPart */
835 #define KRB5_MSG_ENC_TGS_REP_PART       26      /* EncTGSRepPart */
836 #define KRB5_MSG_ENC_AP_REP_PART        27      /* EncAPRepPart */
837 #define KRB5_MSG_ENC_KRB_PRIV_PART      28      /* EncKrbPrivPart */
838 #define KRB5_MSG_ENC_KRB_CRED_PART      29      /* EncKrbCredPart */
839 #define KRB5_MSG_ERROR                  30      /* KRB-ERROR type */
840
841 #define KRB5_CHKSUM_GSSAPI              0x8003
842 /*
843  * For KERB_ENCTYPE_RC4_HMAC and KERB_ENCTYPE_RC4_HMAC_EXP, see
844  *
845  *      http://www.ietf.org/internet-drafts/draft-brezak-win2k-krb-rc4-hmac-04.txt
846  *
847  * unless it's expired.
848  */
849
850 /* Principal name-type */
851 #define KRB5_NT_UNKNOWN         0
852 #define KRB5_NT_PRINCIPAL       1
853 #define KRB5_NT_SRV_INST        2
854 #define KRB5_NT_SRV_HST         3
855 #define KRB5_NT_SRV_XHST        4
856 #define KRB5_NT_UID             5
857 #define KRB5_NT_X500_PRINCIPAL  6
858 #define KRB5_NT_SMTP_NAME       7
859 #define KRB5_NT_ENTERPRISE      10
860
861 /*
862  * MS specific name types, from
863  *
864  *      http://msdn.microsoft.com/library/en-us/security/security/kerb_external_name.asp
865  */
866 #define KRB5_NT_MS_PRINCIPAL            -128
867 #define KRB5_NT_MS_PRINCIPAL_AND_SID    -129
868 #define KRB5_NT_ENT_PRINCIPAL_AND_SID   -130
869 #define KRB5_NT_PRINCIPAL_AND_SID       -131
870 #define KRB5_NT_SRV_INST_AND_SID        -132
871
872 /* error table constants */
873 /* I prefixed the krb5_err.et constant names with KRB5_ET_ for these */
874 #define KRB5_ET_KRB5KDC_ERR_NONE                        0
875 #define KRB5_ET_KRB5KDC_ERR_NAME_EXP                    1
876 #define KRB5_ET_KRB5KDC_ERR_SERVICE_EXP                 2
877 #define KRB5_ET_KRB5KDC_ERR_BAD_PVNO                    3
878 #define KRB5_ET_KRB5KDC_ERR_C_OLD_MAST_KVNO             4
879 #define KRB5_ET_KRB5KDC_ERR_S_OLD_MAST_KVNO             5
880 #define KRB5_ET_KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN         6
881 #define KRB5_ET_KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN         7
882 #define KRB5_ET_KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE        8
883 #define KRB5_ET_KRB5KDC_ERR_NULL_KEY                    9
884 #define KRB5_ET_KRB5KDC_ERR_CANNOT_POSTDATE             10
885 #define KRB5_ET_KRB5KDC_ERR_NEVER_VALID                 11
886 #define KRB5_ET_KRB5KDC_ERR_POLICY                      12
887 #define KRB5_ET_KRB5KDC_ERR_BADOPTION                   13
888 #define KRB5_ET_KRB5KDC_ERR_ETYPE_NOSUPP                14
889 #define KRB5_ET_KRB5KDC_ERR_SUMTYPE_NOSUPP              15
890 #define KRB5_ET_KRB5KDC_ERR_PADATA_TYPE_NOSUPP          16
891 #define KRB5_ET_KRB5KDC_ERR_TRTYPE_NOSUPP               17
892 #define KRB5_ET_KRB5KDC_ERR_CLIENT_REVOKED              18
893 #define KRB5_ET_KRB5KDC_ERR_SERVICE_REVOKED             19
894 #define KRB5_ET_KRB5KDC_ERR_TGT_REVOKED                 20
895 #define KRB5_ET_KRB5KDC_ERR_CLIENT_NOTYET               21
896 #define KRB5_ET_KRB5KDC_ERR_SERVICE_NOTYET              22
897 #define KRB5_ET_KRB5KDC_ERR_KEY_EXP                     23
898 #define KRB5_ET_KRB5KDC_ERR_PREAUTH_FAILED              24
899 #define KRB5_ET_KRB5KDC_ERR_PREAUTH_REQUIRED            25
900 #define KRB5_ET_KRB5KDC_ERR_SERVER_NOMATCH              26
901 #define KRB5_ET_KRB5KDC_ERR_MUST_USE_USER2USER          27
902 #define KRB5_ET_KRB5KDC_ERR_PATH_NOT_ACCEPTED           28
903 #define KRB5_ET_KRB5KDC_ERR_SVC_UNAVAILABLE             29
904 #define KRB5_ET_KRB5KRB_AP_ERR_BAD_INTEGRITY            31
905 #define KRB5_ET_KRB5KRB_AP_ERR_TKT_EXPIRED              32
906 #define KRB5_ET_KRB5KRB_AP_ERR_TKT_NYV                  33
907 #define KRB5_ET_KRB5KRB_AP_ERR_REPEAT                   34
908 #define KRB5_ET_KRB5KRB_AP_ERR_NOT_US                   35
909 #define KRB5_ET_KRB5KRB_AP_ERR_BADMATCH                 36
910 #define KRB5_ET_KRB5KRB_AP_ERR_SKEW                     37
911 #define KRB5_ET_KRB5KRB_AP_ERR_BADADDR                  38
912 #define KRB5_ET_KRB5KRB_AP_ERR_BADVERSION               39
913 #define KRB5_ET_KRB5KRB_AP_ERR_MSG_TYPE                 40
914 #define KRB5_ET_KRB5KRB_AP_ERR_MODIFIED                 41
915 #define KRB5_ET_KRB5KRB_AP_ERR_BADORDER                 42
916 #define KRB5_ET_KRB5KRB_AP_ERR_ILL_CR_TKT               43
917 #define KRB5_ET_KRB5KRB_AP_ERR_BADKEYVER                44
918 #define KRB5_ET_KRB5KRB_AP_ERR_NOKEY                    45
919 #define KRB5_ET_KRB5KRB_AP_ERR_MUT_FAIL                 46
920 #define KRB5_ET_KRB5KRB_AP_ERR_BADDIRECTION             47
921 #define KRB5_ET_KRB5KRB_AP_ERR_METHOD                   48
922 #define KRB5_ET_KRB5KRB_AP_ERR_BADSEQ                   49
923 #define KRB5_ET_KRB5KRB_AP_ERR_INAPP_CKSUM              50
924 #define KRB5_ET_KRB5KDC_AP_PATH_NOT_ACCEPTED            51
925 #define KRB5_ET_KRB5KRB_ERR_RESPONSE_TOO_BIG            52
926 #define KRB5_ET_KRB5KRB_ERR_GENERIC                     60
927 #define KRB5_ET_KRB5KRB_ERR_FIELD_TOOLONG               61
928 #define KRB5_ET_KDC_ERROR_CLIENT_NOT_TRUSTED            62
929 #define KRB5_ET_KDC_ERROR_KDC_NOT_TRUSTED               63
930 #define KRB5_ET_KDC_ERROR_INVALID_SIG                   64
931 #define KRB5_ET_KDC_ERR_KEY_TOO_WEAK                    65
932 #define KRB5_ET_KDC_ERR_CERTIFICATE_MISMATCH            66
933 #define KRB5_ET_KRB_AP_ERR_NO_TGT                       67
934 #define KRB5_ET_KDC_ERR_WRONG_REALM                     68
935 #define KRB5_ET_KRB_AP_ERR_USER_TO_USER_REQUIRED        69
936 #define KRB5_ET_KDC_ERR_CANT_VERIFY_CERTIFICATE         70
937 #define KRB5_ET_KDC_ERR_INVALID_CERTIFICATE             71
938 #define KRB5_ET_KDC_ERR_REVOKED_CERTIFICATE             72
939 #define KRB5_ET_KDC_ERR_REVOCATION_STATUS_UNKNOWN       73
940 #define KRB5_ET_KDC_ERR_REVOCATION_STATUS_UNAVAILABLE   74
941 #define KRB5_ET_KDC_ERR_CLIENT_NAME_MISMATCH            75
942 #define KRB5_ET_KDC_ERR_KDC_NAME_MISMATCH               76
943
944 static const value_string krb5_error_codes[] = {
945         { KRB5_ET_KRB5KDC_ERR_NONE, "KRB5KDC_ERR_NONE" },
946         { KRB5_ET_KRB5KDC_ERR_NAME_EXP, "KRB5KDC_ERR_NAME_EXP" },
947         { KRB5_ET_KRB5KDC_ERR_SERVICE_EXP, "KRB5KDC_ERR_SERVICE_EXP" },
948         { KRB5_ET_KRB5KDC_ERR_BAD_PVNO, "KRB5KDC_ERR_BAD_PVNO" },
949         { KRB5_ET_KRB5KDC_ERR_C_OLD_MAST_KVNO, "KRB5KDC_ERR_C_OLD_MAST_KVNO" },
950         { KRB5_ET_KRB5KDC_ERR_S_OLD_MAST_KVNO, "KRB5KDC_ERR_S_OLD_MAST_KVNO" },
951         { KRB5_ET_KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN, "KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN" },
952         { KRB5_ET_KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN, "KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN" },
953         { KRB5_ET_KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE, "KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE" },
954         { KRB5_ET_KRB5KDC_ERR_NULL_KEY, "KRB5KDC_ERR_NULL_KEY" },
955         { KRB5_ET_KRB5KDC_ERR_CANNOT_POSTDATE, "KRB5KDC_ERR_CANNOT_POSTDATE" },
956         { KRB5_ET_KRB5KDC_ERR_NEVER_VALID, "KRB5KDC_ERR_NEVER_VALID" },
957         { KRB5_ET_KRB5KDC_ERR_POLICY, "KRB5KDC_ERR_POLICY" },
958         { KRB5_ET_KRB5KDC_ERR_BADOPTION, "KRB5KDC_ERR_BADOPTION" },
959         { KRB5_ET_KRB5KDC_ERR_ETYPE_NOSUPP, "KRB5KDC_ERR_ETYPE_NOSUPP" },
960         { KRB5_ET_KRB5KDC_ERR_SUMTYPE_NOSUPP, "KRB5KDC_ERR_SUMTYPE_NOSUPP" },
961         { KRB5_ET_KRB5KDC_ERR_PADATA_TYPE_NOSUPP, "KRB5KDC_ERR_PADATA_TYPE_NOSUPP" },
962         { KRB5_ET_KRB5KDC_ERR_TRTYPE_NOSUPP, "KRB5KDC_ERR_TRTYPE_NOSUPP" },
963         { KRB5_ET_KRB5KDC_ERR_CLIENT_REVOKED, "KRB5KDC_ERR_CLIENT_REVOKED" },
964         { KRB5_ET_KRB5KDC_ERR_SERVICE_REVOKED, "KRB5KDC_ERR_SERVICE_REVOKED" },
965         { KRB5_ET_KRB5KDC_ERR_TGT_REVOKED, "KRB5KDC_ERR_TGT_REVOKED" },
966         { KRB5_ET_KRB5KDC_ERR_CLIENT_NOTYET, "KRB5KDC_ERR_CLIENT_NOTYET" },
967         { KRB5_ET_KRB5KDC_ERR_SERVICE_NOTYET, "KRB5KDC_ERR_SERVICE_NOTYET" },
968         { KRB5_ET_KRB5KDC_ERR_KEY_EXP, "KRB5KDC_ERR_KEY_EXP" },
969         { KRB5_ET_KRB5KDC_ERR_PREAUTH_FAILED, "KRB5KDC_ERR_PREAUTH_FAILED" },
970         { KRB5_ET_KRB5KDC_ERR_PREAUTH_REQUIRED, "KRB5KDC_ERR_PREAUTH_REQUIRED" },
971         { KRB5_ET_KRB5KDC_ERR_SERVER_NOMATCH, "KRB5KDC_ERR_SERVER_NOMATCH" },
972         { KRB5_ET_KRB5KDC_ERR_MUST_USE_USER2USER, "KRB5KDC_ERR_MUST_USE_USER2USER" },
973         { KRB5_ET_KRB5KDC_ERR_PATH_NOT_ACCEPTED, "KRB5KDC_ERR_PATH_NOT_ACCEPTED" },
974         { KRB5_ET_KRB5KDC_ERR_SVC_UNAVAILABLE, "KRB5KDC_ERR_SVC_UNAVAILABLE" },
975         { KRB5_ET_KRB5KRB_AP_ERR_BAD_INTEGRITY, "KRB5KRB_AP_ERR_BAD_INTEGRITY" },
976         { KRB5_ET_KRB5KRB_AP_ERR_TKT_EXPIRED, "KRB5KRB_AP_ERR_TKT_EXPIRED" },
977         { KRB5_ET_KRB5KRB_AP_ERR_TKT_NYV, "KRB5KRB_AP_ERR_TKT_NYV" },
978         { KRB5_ET_KRB5KRB_AP_ERR_REPEAT, "KRB5KRB_AP_ERR_REPEAT" },
979         { KRB5_ET_KRB5KRB_AP_ERR_NOT_US, "KRB5KRB_AP_ERR_NOT_US" },
980         { KRB5_ET_KRB5KRB_AP_ERR_BADMATCH, "KRB5KRB_AP_ERR_BADMATCH" },
981         { KRB5_ET_KRB5KRB_AP_ERR_SKEW, "KRB5KRB_AP_ERR_SKEW" },
982         { KRB5_ET_KRB5KRB_AP_ERR_BADADDR, "KRB5KRB_AP_ERR_BADADDR" },
983         { KRB5_ET_KRB5KRB_AP_ERR_BADVERSION, "KRB5KRB_AP_ERR_BADVERSION" },
984         { KRB5_ET_KRB5KRB_AP_ERR_MSG_TYPE, "KRB5KRB_AP_ERR_MSG_TYPE" },
985         { KRB5_ET_KRB5KRB_AP_ERR_MODIFIED, "KRB5KRB_AP_ERR_MODIFIED" },
986         { KRB5_ET_KRB5KRB_AP_ERR_BADORDER, "KRB5KRB_AP_ERR_BADORDER" },
987         { KRB5_ET_KRB5KRB_AP_ERR_ILL_CR_TKT, "KRB5KRB_AP_ERR_ILL_CR_TKT" },
988         { KRB5_ET_KRB5KRB_AP_ERR_BADKEYVER, "KRB5KRB_AP_ERR_BADKEYVER" },
989         { KRB5_ET_KRB5KRB_AP_ERR_NOKEY, "KRB5KRB_AP_ERR_NOKEY" },
990         { KRB5_ET_KRB5KRB_AP_ERR_MUT_FAIL, "KRB5KRB_AP_ERR_MUT_FAIL" },
991         { KRB5_ET_KRB5KRB_AP_ERR_BADDIRECTION, "KRB5KRB_AP_ERR_BADDIRECTION" },
992         { KRB5_ET_KRB5KRB_AP_ERR_METHOD, "KRB5KRB_AP_ERR_METHOD" },
993         { KRB5_ET_KRB5KRB_AP_ERR_BADSEQ, "KRB5KRB_AP_ERR_BADSEQ" },
994         { KRB5_ET_KRB5KRB_AP_ERR_INAPP_CKSUM, "KRB5KRB_AP_ERR_INAPP_CKSUM" },
995         { KRB5_ET_KRB5KDC_AP_PATH_NOT_ACCEPTED, "KRB5KDC_AP_PATH_NOT_ACCEPTED" },
996         { KRB5_ET_KRB5KRB_ERR_RESPONSE_TOO_BIG, "KRB5KRB_ERR_RESPONSE_TOO_BIG"},
997         { KRB5_ET_KRB5KRB_ERR_GENERIC, "KRB5KRB_ERR_GENERIC" },
998         { KRB5_ET_KRB5KRB_ERR_FIELD_TOOLONG, "KRB5KRB_ERR_FIELD_TOOLONG" },
999         { KRB5_ET_KDC_ERROR_CLIENT_NOT_TRUSTED, "KDC_ERROR_CLIENT_NOT_TRUSTED" },
1000         { KRB5_ET_KDC_ERROR_KDC_NOT_TRUSTED, "KDC_ERROR_KDC_NOT_TRUSTED" },
1001         { KRB5_ET_KDC_ERROR_INVALID_SIG, "KDC_ERROR_INVALID_SIG" },
1002         { KRB5_ET_KDC_ERR_KEY_TOO_WEAK, "KDC_ERR_KEY_TOO_WEAK" },
1003         { KRB5_ET_KDC_ERR_CERTIFICATE_MISMATCH, "KDC_ERR_CERTIFICATE_MISMATCH" },
1004         { KRB5_ET_KRB_AP_ERR_NO_TGT, "KRB_AP_ERR_NO_TGT" },
1005         { KRB5_ET_KDC_ERR_WRONG_REALM, "KDC_ERR_WRONG_REALM" },
1006         { KRB5_ET_KRB_AP_ERR_USER_TO_USER_REQUIRED, "KRB_AP_ERR_USER_TO_USER_REQUIRED" },
1007         { KRB5_ET_KDC_ERR_CANT_VERIFY_CERTIFICATE, "KDC_ERR_CANT_VERIFY_CERTIFICATE" },
1008         { KRB5_ET_KDC_ERR_INVALID_CERTIFICATE, "KDC_ERR_INVALID_CERTIFICATE" },
1009         { KRB5_ET_KDC_ERR_REVOKED_CERTIFICATE, "KDC_ERR_REVOKED_CERTIFICATE" },
1010         { KRB5_ET_KDC_ERR_REVOCATION_STATUS_UNKNOWN, "KDC_ERR_REVOCATION_STATUS_UNKNOWN" },
1011         { KRB5_ET_KDC_ERR_REVOCATION_STATUS_UNAVAILABLE, "KDC_ERR_REVOCATION_STATUS_UNAVAILABLE" },
1012         { KRB5_ET_KDC_ERR_CLIENT_NAME_MISMATCH, "KDC_ERR_CLIENT_NAME_MISMATCH" },
1013         { KRB5_ET_KDC_ERR_KDC_NAME_MISMATCH, "KDC_ERR_KDC_NAME_MISMATCH" },
1014         { 0, NULL }
1015 };
1016
1017
1018 #define PAC_LOGON_INFO          1
1019 #define PAC_CREDENTIAL_TYPE     2
1020 #define PAC_SERVER_CHECKSUM     6
1021 #define PAC_PRIVSVR_CHECKSUM    7
1022 #define PAC_CLIENT_INFO_TYPE    10
1023 #define PAC_S4U_DELEGATION_INFO 11
1024 #define PAC_UPN_DNS_INFO                12
1025 static const value_string w2k_pac_types[] = {
1026         { PAC_LOGON_INFO                , "Logon Info" },
1027         { PAC_CREDENTIAL_TYPE   , "Credential Type" },
1028         { PAC_SERVER_CHECKSUM   , "Server Checksum" },
1029         { PAC_PRIVSVR_CHECKSUM  , "Privsvr Checksum" },
1030         { PAC_CLIENT_INFO_TYPE  , "Client Info Type" },
1031         { PAC_S4U_DELEGATION_INFO, "S4U Delegation Info" },
1032         { PAC_UPN_DNS_INFO              , "UPN DNS Info" },
1033         { 0, NULL },
1034 };
1035
1036 static const value_string krb5_msg_types[] = {
1037         { KRB5_MSG_TICKET,              "Ticket" },
1038         { KRB5_MSG_AUTHENTICATOR,       "Authenticator" },
1039         { KRB5_MSG_ENC_TICKET_PART,     "EncTicketPart" },
1040         { KRB5_MSG_TGS_REQ,             "TGS-REQ" },
1041         { KRB5_MSG_TGS_REP,             "TGS-REP" },
1042         { KRB5_MSG_AS_REQ,              "AS-REQ" },
1043         { KRB5_MSG_AS_REP,              "AS-REP" },
1044         { KRB5_MSG_AP_REQ,              "AP-REQ" },
1045         { KRB5_MSG_AP_REP,              "AP-REP" },
1046         { KRB5_MSG_SAFE,                "KRB-SAFE" },
1047         { KRB5_MSG_PRIV,                "KRB-PRIV" },
1048         { KRB5_MSG_CRED,                "KRB-CRED" },
1049         { KRB5_MSG_ENC_AS_REP_PART,     "EncASRepPart" },
1050         { KRB5_MSG_ENC_TGS_REP_PART,    "EncTGSRepPart" },
1051         { KRB5_MSG_ENC_AP_REP_PART,     "EncAPRepPart" },
1052         { KRB5_MSG_ENC_KRB_PRIV_PART,   "EncKrbPrivPart" },
1053         { KRB5_MSG_ENC_KRB_CRED_PART,   "EncKrbCredPart" },
1054         { KRB5_MSG_ERROR,               "KRB-ERROR" },
1055         { 0, NULL },
1056 };
1057
1058 #define KRB5_GSS_C_DELEG_FLAG             0x01
1059 #define KRB5_GSS_C_MUTUAL_FLAG            0x02
1060 #define KRB5_GSS_C_REPLAY_FLAG            0x04
1061 #define KRB5_GSS_C_SEQUENCE_FLAG          0x08
1062 #define KRB5_GSS_C_CONF_FLAG              0x10
1063 #define KRB5_GSS_C_INTEG_FLAG             0x20
1064 #define KRB5_GSS_C_DCE_STYLE            0x1000
1065
1066 static const true_false_string tfs_gss_flags_deleg = {
1067         "Delegate credentials to remote peer",
1068         "Do NOT delegate"
1069 };
1070 static const true_false_string tfs_gss_flags_mutual = {
1071         "Request that remote peer authenticates itself",
1072         "Mutual authentication NOT required"
1073 };
1074 static const true_false_string tfs_gss_flags_replay = {
1075         "Enable replay protection for signed or sealed messages",
1076         "Do NOT enable replay protection"
1077 };
1078 static const true_false_string tfs_gss_flags_sequence = {
1079         "Enable Out-of-sequence detection for sign or sealed messages",
1080         "Do NOT enable out-of-sequence detection"
1081 };
1082 static const true_false_string tfs_gss_flags_conf = {
1083         "Confidentiality (sealing) may be invoked",
1084         "Do NOT use Confidentiality (sealing)"
1085 };
1086 static const true_false_string tfs_gss_flags_integ = {
1087         "Integrity protection (signing) may be invoked",
1088         "Do NOT use integrity protection"
1089 };
1090
1091 static const true_false_string tfs_gss_flags_dce_style = {
1092         "DCE-STYLE",
1093         "Not using DCE-STYLE"
1094 };
1095
1096 #ifdef HAVE_KERBEROS
1097 static int
1098 dissect_krb5_decrypt_ticket_data (gboolean imp_tag _U_, tvbuff_t *tvb, int offset, asn1_ctx_t *actx,
1099                                                                         proto_tree *tree, int hf_index _U_)
1100 {
1101         guint8 *plaintext;
1102         int length;
1103         kerberos_private_data_t *private_data = kerberos_get_private_data(actx);
1104         tvbuff_t *next_tvb;
1105
1106         next_tvb=tvb_new_subset_remaining(tvb, offset);
1107         length=tvb_captured_length_remaining(tvb, offset);
1108
1109         /* draft-ietf-krb-wg-kerberos-clarifications-05.txt :
1110          * 7.5.1
1111          * All Ticket encrypted parts use usage == 2
1112          */
1113         plaintext=decrypt_krb5_data(tree, actx->pinfo, 2, next_tvb, private_data->etype, NULL);
1114
1115         if(plaintext){
1116                 tvbuff_t *child_tvb;
1117                 child_tvb = tvb_new_child_real_data(tvb, plaintext, length, length);
1118
1119                 /* Add the decrypted data to the data source list. */
1120                 add_new_data_source(actx->pinfo, child_tvb, "Decrypted Krb5");
1121
1122                 offset=dissect_kerberos_Applications(FALSE, child_tvb, 0, actx , tree, /* hf_index*/ -1);
1123         }
1124         return offset;
1125 }
1126
1127 static int
1128 dissect_krb5_decrypt_authenticator_data (gboolean imp_tag _U_, tvbuff_t *tvb, int offset, asn1_ctx_t *actx,
1129                                                                                         proto_tree *tree, int hf_index _U_)
1130 {
1131         guint8 *plaintext;
1132         int length;
1133         kerberos_private_data_t *private_data = kerberos_get_private_data(actx);
1134         tvbuff_t *next_tvb;
1135
1136         next_tvb=tvb_new_subset_remaining(tvb, offset);
1137         length=tvb_captured_length_remaining(tvb, offset);
1138
1139         /* draft-ietf-krb-wg-kerberos-clarifications-05.txt :
1140          * 7.5.1
1141          * Authenticators are encrypted with usage
1142          * == 7 or
1143          * == 11
1144          */
1145         plaintext=decrypt_krb5_data(tree, actx->pinfo, 7, next_tvb, private_data->etype, NULL);
1146
1147         if(!plaintext){
1148                 plaintext=decrypt_krb5_data(tree, actx->pinfo, 11, next_tvb, private_data->etype, NULL);
1149         }
1150
1151         if(plaintext){
1152                 tvbuff_t *child_tvb;
1153                 child_tvb = tvb_new_child_real_data(tvb, plaintext, length, length);
1154
1155                 /* Add the decrypted data to the data source list. */
1156                 add_new_data_source(actx->pinfo, child_tvb, "Decrypted Krb5");
1157
1158                 offset=dissect_kerberos_Applications(FALSE, child_tvb, 0, actx , tree, /* hf_index*/ -1);
1159         }
1160         return offset;
1161 }
1162
1163 static int
1164 dissect_krb5_decrypt_KDC_REP_data (gboolean imp_tag _U_, tvbuff_t *tvb, int offset, asn1_ctx_t *actx,
1165                                                                         proto_tree *tree, int hf_index _U_)
1166 {
1167         guint8 *plaintext;
1168         int length;
1169         kerberos_private_data_t *private_data = kerberos_get_private_data(actx);
1170         tvbuff_t *next_tvb;
1171
1172         next_tvb=tvb_new_subset_remaining(tvb, offset);
1173         length=tvb_captured_length_remaining(tvb, offset);
1174
1175         /* draft-ietf-krb-wg-kerberos-clarifications-05.txt :
1176          * 7.5.1
1177          * ASREP/TGSREP encryptedparts are encrypted with usage
1178          * == 3 or
1179          * == 8 or
1180          * == 9
1181          */
1182         plaintext=decrypt_krb5_data(tree, actx->pinfo, 3, next_tvb, private_data->etype, NULL);
1183
1184         if(!plaintext){
1185                 plaintext=decrypt_krb5_data(tree, actx->pinfo, 8, next_tvb, private_data->etype, NULL);
1186         }
1187
1188         if(!plaintext){
1189                 plaintext=decrypt_krb5_data(tree, actx->pinfo, 9, next_tvb, private_data->etype, NULL);
1190         }
1191
1192         if(plaintext){
1193                 tvbuff_t *child_tvb;
1194                 child_tvb = tvb_new_child_real_data(tvb, plaintext, length, length);
1195
1196                 /* Add the decrypted data to the data source list. */
1197                 add_new_data_source(actx->pinfo, child_tvb, "Decrypted Krb5");
1198
1199                 offset=dissect_kerberos_Applications(FALSE, child_tvb, 0, actx , tree, /* hf_index*/ -1);
1200         }
1201         return offset;
1202 }
1203
1204 static int
1205 dissect_krb5_decrypt_PA_ENC_TIMESTAMP (gboolean imp_tag _U_, tvbuff_t *tvb, int offset, asn1_ctx_t *actx,
1206                                                                                 proto_tree *tree, int hf_index _U_)
1207 {
1208         guint8 *plaintext;
1209         int length;
1210         kerberos_private_data_t *private_data = kerberos_get_private_data(actx);
1211         tvbuff_t *next_tvb;
1212
1213         next_tvb=tvb_new_subset_remaining(tvb, offset);
1214         length=tvb_captured_length_remaining(tvb, offset);
1215
1216         /* draft-ietf-krb-wg-kerberos-clarifications-05.txt :
1217          * 7.5.1
1218          * AS-REQ PA_ENC_TIMESTAMP are encrypted with usage
1219          * == 1
1220          */
1221         plaintext=decrypt_krb5_data(tree, actx->pinfo, 1, next_tvb, private_data->etype, NULL);
1222
1223         if(plaintext){
1224                 tvbuff_t *child_tvb;
1225                 child_tvb = tvb_new_child_real_data(tvb, plaintext, length, length);
1226
1227                 /* Add the decrypted data to the data source list. */
1228                 add_new_data_source(actx->pinfo, child_tvb, "Decrypted Krb5");
1229
1230                 offset=dissect_kerberos_PA_ENC_TS_ENC(FALSE, child_tvb, 0, actx , tree, /* hf_index*/ -1);
1231         }
1232         return offset;
1233 }
1234
1235 static int
1236 dissect_krb5_decrypt_AP_REP_data (gboolean imp_tag _U_, tvbuff_t *tvb, int offset, asn1_ctx_t *actx,
1237                                                                         proto_tree *tree, int hf_index _U_)
1238 {
1239         guint8 *plaintext;
1240         int length;
1241         kerberos_private_data_t *private_data = kerberos_get_private_data(actx);
1242         tvbuff_t *next_tvb;
1243
1244         next_tvb=tvb_new_subset_remaining(tvb, offset);
1245         length=tvb_captured_length_remaining(tvb, offset);
1246
1247         /* draft-ietf-krb-wg-kerberos-clarifications-05.txt :
1248          * 7.5.1
1249          * AP-REP are encrypted with usage == 12
1250          */
1251         plaintext=decrypt_krb5_data(tree, actx->pinfo, 12, next_tvb, private_data->etype, NULL);
1252
1253         if(plaintext){
1254                 tvbuff_t *child_tvb;
1255                 child_tvb = tvb_new_child_real_data(tvb, plaintext, length, length);
1256
1257                 /* Add the decrypted data to the data source list. */
1258                 add_new_data_source(actx->pinfo, child_tvb, "Decrypted Krb5");
1259
1260                 offset=dissect_kerberos_Applications(FALSE, child_tvb, 0, actx , tree, /* hf_index*/ -1);
1261         }
1262         return offset;
1263 }
1264
1265 static int
1266 dissect_krb5_decrypt_PRIV_data (gboolean imp_tag _U_, tvbuff_t *tvb, int offset, asn1_ctx_t *actx,
1267                                                                         proto_tree *tree, int hf_index _U_)
1268 {
1269         guint8 *plaintext;
1270         int length;
1271         kerberos_private_data_t *private_data = kerberos_get_private_data(actx);
1272         tvbuff_t *next_tvb;
1273
1274         next_tvb=tvb_new_subset_remaining(tvb, offset);
1275         length=tvb_captured_length_remaining(tvb, offset);
1276
1277         /* RFC4120 :
1278          * EncKrbPrivPart encrypted with usage
1279          * == 13
1280          */
1281         plaintext=decrypt_krb5_data(tree, actx->pinfo, 13, next_tvb, private_data->etype, NULL);
1282
1283         if(plaintext){
1284                 tvbuff_t *child_tvb;
1285                 child_tvb = tvb_new_child_real_data(tvb, plaintext, length, length);
1286
1287                 /* Add the decrypted data to the data source list. */
1288                 add_new_data_source(actx->pinfo, child_tvb, "Decrypted Krb5");
1289
1290                 offset=dissect_kerberos_Applications(FALSE, child_tvb, 0, actx , tree, /* hf_index*/ -1);
1291         }
1292         return offset;
1293 }
1294
1295 static int
1296 dissect_krb5_decrypt_CRED_data (gboolean imp_tag _U_, tvbuff_t *tvb, int offset, asn1_ctx_t *actx,
1297                                                                         proto_tree *tree, int hf_index _U_)
1298 {
1299         guint8 *plaintext;
1300         int length;
1301         kerberos_private_data_t *private_data = kerberos_get_private_data(actx);
1302         tvbuff_t *next_tvb;
1303
1304         next_tvb=tvb_new_subset_remaining(tvb, offset);
1305         length=tvb_captured_length_remaining(tvb, offset);
1306
1307         /* RFC4120 :
1308          * EncKrbCredPart encrypted with usage
1309          * == 14
1310          */
1311         plaintext=decrypt_krb5_data(tree, actx->pinfo, 14, next_tvb, private_data->etype, NULL);
1312
1313         if(plaintext){
1314                 tvbuff_t *child_tvb;
1315                 child_tvb = tvb_new_child_real_data(tvb, plaintext, length, length);
1316
1317                 /* Add the decrypted data to the data source list. */
1318                 add_new_data_source(actx->pinfo, child_tvb, "Decrypted Krb5");
1319
1320                 offset=dissect_kerberos_Applications(FALSE, child_tvb, 0, actx , tree, /* hf_index*/ -1);
1321         }
1322         return offset;
1323 }
1324
1325 static int
1326 dissect_krb5_decrypt_KrbFastReq(gboolean imp_tag _U_, tvbuff_t *tvb, int offset, asn1_ctx_t *actx,
1327                                 proto_tree *tree, int hf_index _U_)
1328 {
1329         guint8 *plaintext;
1330         int length;
1331         kerberos_private_data_t *private_data = kerberos_get_private_data(actx);
1332         tvbuff_t *next_tvb;
1333
1334         next_tvb=tvb_new_subset_remaining(tvb, offset);
1335         length=tvb_captured_length_remaining(tvb, offset);
1336
1337         /* RFC6113 :
1338          * KrbFastResponse encrypted with usage
1339          * KEY_USAGE_FAST_ENC 51
1340          */
1341         plaintext=decrypt_krb5_data(tree, actx->pinfo, KEY_USAGE_FAST_ENC,
1342                                     next_tvb, private_data->etype, NULL);
1343
1344         if(plaintext){
1345                 tvbuff_t *child_tvb;
1346                 child_tvb = tvb_new_child_real_data(tvb, plaintext, length, length);
1347                 tvb_set_free_cb(child_tvb, g_free);
1348
1349                 /* Add the decrypted data to the data source list. */
1350                 add_new_data_source(actx->pinfo, child_tvb, "Decrypted Krb5");
1351
1352                 offset=dissect_kerberos_KrbFastReq(FALSE, child_tvb, 0, actx , tree, /* hf_index*/ -1);
1353         }
1354         return offset;
1355 }
1356
1357 static int
1358 dissect_krb5_decrypt_KrbFastResponse(gboolean imp_tag _U_, tvbuff_t *tvb, int offset, asn1_ctx_t *actx,
1359                                      proto_tree *tree, int hf_index _U_)
1360 {
1361         guint8 *plaintext;
1362         int length;
1363         kerberos_private_data_t *private_data = kerberos_get_private_data(actx);
1364         tvbuff_t *next_tvb;
1365
1366         next_tvb=tvb_new_subset_remaining(tvb, offset);
1367         length=tvb_captured_length_remaining(tvb, offset);
1368
1369         /*
1370          * RFC6113 :
1371          * KrbFastResponse encrypted with usage
1372          * KEY_USAGE_FAST_REP 52
1373          */
1374         plaintext=decrypt_krb5_data(tree, actx->pinfo, KEY_USAGE_FAST_REP,
1375                                     next_tvb, private_data->etype, NULL);
1376
1377         if(plaintext){
1378                 tvbuff_t *child_tvb;
1379                 child_tvb = tvb_new_child_real_data(tvb, plaintext, length, length);
1380                 tvb_set_free_cb(child_tvb, g_free);
1381
1382                 /* Add the decrypted data to the data source list. */
1383                 add_new_data_source(actx->pinfo, child_tvb, "Decrypted Krb5");
1384
1385                 offset=dissect_kerberos_KrbFastResponse(FALSE, child_tvb, 0, actx , tree, /* hf_index*/ -1);
1386         }
1387         return offset;
1388 }
1389
1390 static int
1391 dissect_krb5_decrypt_EncryptedChallenge(gboolean imp_tag _U_, tvbuff_t *tvb, int offset, asn1_ctx_t *actx,
1392                                         proto_tree *tree, int hf_index _U_)
1393 {
1394         guint8 *plaintext;
1395         int length;
1396         kerberos_private_data_t *private_data = kerberos_get_private_data(actx);
1397         tvbuff_t *next_tvb;
1398         int usage = 0;
1399
1400         next_tvb=tvb_new_subset_remaining(tvb, offset);
1401         length=tvb_captured_length_remaining(tvb, offset);
1402
1403         /* RFC6113 :
1404          * KEY_USAGE_ENC_CHALLENGE_CLIENT  54
1405          * KEY_USAGE_ENC_CHALLENGE_KDC     55
1406          */
1407         if (private_data->kdc_response) {
1408                 usage = KEY_USAGE_ENC_CHALLENGE_KDC;
1409         } else {
1410                 usage = KEY_USAGE_ENC_CHALLENGE_CLIENT;
1411         }
1412         plaintext=decrypt_krb5_data(tree, actx->pinfo, usage, next_tvb, private_data->etype, NULL);
1413
1414         if(plaintext){
1415                 tvbuff_t *child_tvb;
1416                 child_tvb = tvb_new_child_real_data(tvb, plaintext, length, length);
1417                 tvb_set_free_cb(child_tvb, g_free);
1418
1419                 /* Add the decrypted data to the data source list. */
1420                 add_new_data_source(actx->pinfo, child_tvb, "Decrypted Krb5");
1421
1422                 offset=dissect_kerberos_PA_ENC_TS_ENC(FALSE, child_tvb, 0, actx , tree, /* hf_index*/ -1);
1423         }
1424         return offset;
1425 }
1426 #endif
1427
1428 /* Dissect a GSSAPI checksum as per RFC1964. This is NOT ASN.1 encoded.
1429  */
1430 static int
1431 dissect_krb5_rfc1964_checksum(asn1_ctx_t *actx _U_, proto_tree *tree, tvbuff_t *tvb)
1432 {
1433         int offset=0;
1434         guint32 len;
1435         guint16 dlglen;
1436
1437         /* Length of Bnd field */
1438         len=tvb_get_letohl(tvb, offset);
1439         proto_tree_add_item(tree, hf_krb_gssapi_len, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1440         offset += 4;
1441
1442         /* Bnd field */
1443         proto_tree_add_item(tree, hf_krb_gssapi_bnd, tvb, offset, len, ENC_NA);
1444         offset += len;
1445
1446
1447         /* flags */
1448         proto_tree_add_item(tree, hf_krb_gssapi_c_flag_dce_style, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1449         proto_tree_add_item(tree, hf_krb_gssapi_c_flag_integ, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1450         proto_tree_add_item(tree, hf_krb_gssapi_c_flag_conf, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1451         proto_tree_add_item(tree, hf_krb_gssapi_c_flag_sequence, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1452         proto_tree_add_item(tree, hf_krb_gssapi_c_flag_replay, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1453         proto_tree_add_item(tree, hf_krb_gssapi_c_flag_mutual, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1454         proto_tree_add_item(tree, hf_krb_gssapi_c_flag_deleg, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1455         offset += 4;
1456
1457         /* the next fields are optional so we have to check that we have
1458          * more data in our buffers */
1459         if(tvb_reported_length_remaining(tvb, offset)<2){
1460                 return offset;
1461         }
1462         /* dlgopt identifier */
1463         proto_tree_add_item(tree, hf_krb_gssapi_dlgopt, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1464         offset += 2;
1465
1466         if(tvb_reported_length_remaining(tvb, offset)<2){
1467                 return offset;
1468         }
1469         /* dlglen identifier */
1470         dlglen=tvb_get_letohs(tvb, offset);
1471         proto_tree_add_item(tree, hf_krb_gssapi_dlglen, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1472         offset += 2;
1473
1474         if(dlglen!=tvb_reported_length_remaining(tvb, offset)){
1475                 proto_tree_add_expert_format(tree, actx->pinfo, &ei_krb_gssapi_dlglen, tvb, 0, 0,
1476                                 "Error: DlgLen:%d is not the same as number of bytes remaining:%d", dlglen, tvb_captured_length_remaining(tvb, offset));
1477                 return offset;
1478         }
1479
1480         /* this should now be a KRB_CRED message */
1481         offset=dissect_kerberos_Applications(FALSE, tvb, offset, actx, tree, /* hf_index */ -1);
1482
1483         return offset;
1484 }
1485
1486 static int
1487 dissect_krb5_PA_PROV_SRV_LOCATION(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_)
1488 {
1489         offset=dissect_ber_GeneralString(actx, tree, tvb, offset, hf_krb_provsrv_location, NULL, 0);
1490
1491         return offset;
1492 }
1493
1494 static int
1495 dissect_krb5_PW_SALT(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_)
1496 {
1497         guint32 nt_status;
1498
1499         /* Microsoft stores a special 12 byte blob here
1500          * guint32 NT_status
1501          * guint32 unknown
1502          * guint32 unknown
1503          * decode everything as this blob for now until we see if anyone
1504          * else ever uses it   or we learn how to tell whether this
1505          * is such an MS blob or not.
1506          */
1507         proto_tree_add_item(tree, hf_krb_smb_nt_status, tvb, offset, 4,
1508                         ENC_LITTLE_ENDIAN);
1509         nt_status=tvb_get_letohl(tvb, offset);
1510         if(nt_status) {
1511                 col_append_fstr(actx->pinfo->cinfo, COL_INFO,
1512                         " NT Status: %s",
1513                         val_to_str(nt_status, NT_errors,
1514                         "Unknown error code %#x"));
1515         }
1516         offset += 4;
1517
1518         proto_tree_add_item(tree, hf_krb_smb_unknown, tvb, offset, 4,
1519                         ENC_LITTLE_ENDIAN);
1520         offset += 4;
1521
1522         proto_tree_add_item(tree, hf_krb_smb_unknown, tvb, offset, 4,
1523                         ENC_LITTLE_ENDIAN);
1524         offset += 4;
1525
1526         return offset;
1527 }
1528
1529 static int
1530 dissect_krb5_PAC_DREP(proto_tree *parent_tree, tvbuff_t *tvb, int offset, guint8 *drep)
1531 {
1532         proto_tree *tree;
1533         guint8 val;
1534
1535         tree = proto_tree_add_subtree(parent_tree, tvb, offset, 16, ett_krb_pac_drep, NULL, "DREP");
1536
1537         val = tvb_get_guint8(tvb, offset);
1538         proto_tree_add_uint(tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, val>>4);
1539
1540         offset++;
1541
1542         if (drep) {
1543                 *drep = val;
1544         }
1545
1546         return offset;
1547 }
1548
1549 /* This might be some sort of header that MIDL generates when creating
1550  * marshalling/unmarshalling code for blobs that are not to be transported
1551  * ontop of DCERPC and where the DREP fields specifying things such as
1552  * endianess and similar are not available.
1553  */
1554 static int
1555 dissect_krb5_PAC_NDRHEADERBLOB(proto_tree *parent_tree, tvbuff_t *tvb, int offset, guint8 *drep, asn1_ctx_t *actx _U_)
1556 {
1557         proto_tree *tree;
1558
1559         tree = proto_tree_add_subtree(parent_tree, tvb, offset, 16, ett_krb_pac_midl_blob, NULL, "MES header");
1560
1561         /* modified DREP field that is used for stuff that is transporetd ontop
1562            of non dcerpc
1563         */
1564         proto_tree_add_item(tree, hf_krb_midl_version, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1565         offset++;
1566
1567         offset = dissect_krb5_PAC_DREP(tree, tvb, offset, drep);
1568
1569
1570         proto_tree_add_item(tree, hf_krb_midl_hdr_len, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1571         offset+=2;
1572
1573         proto_tree_add_item(tree, hf_krb_midl_fill_bytes, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1574         offset += 4;
1575
1576         /* length of blob that follows */
1577         proto_tree_add_item(tree, hf_krb_midl_blob_len, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1578         offset += 8;
1579
1580         return offset;
1581 }
1582
1583 static int
1584 dissect_krb5_PAC_LOGON_INFO(proto_tree *parent_tree, tvbuff_t *tvb, int offset, asn1_ctx_t *actx _U_)
1585 {
1586         proto_item *item;
1587         proto_tree *tree;
1588         guint8 drep[4] = { 0x10, 0x00, 0x00, 0x00}; /* fake DREP struct */
1589         static dcerpc_info di;      /* fake dcerpc_info struct */
1590         static dcerpc_call_value call_data;
1591
1592         item = proto_tree_add_item(parent_tree, hf_krb_pac_logon_info, tvb, offset, -1, ENC_NA);
1593         tree = proto_item_add_subtree(item, ett_krb_pac_logon_info);
1594
1595         /* skip the first 16 bytes, they are some magic created by the idl
1596          * compiler   the first 4 bytes might be flags?
1597          */
1598         offset = dissect_krb5_PAC_NDRHEADERBLOB(tree, tvb, offset, &drep[0], actx);
1599
1600         /* the PAC_LOGON_INFO blob */
1601         /* fake whatever state the dcerpc runtime support needs */
1602         di.conformant_run=0;
1603         /* we need di->call_data->flags.NDR64 == 0 */
1604         di.call_data=&call_data;
1605         init_ndr_pointer_list(&di);
1606         offset = dissect_ndr_pointer(tvb, offset, actx->pinfo, tree, &di, drep,
1607                                                                         netlogon_dissect_PAC_LOGON_INFO, NDR_POINTER_UNIQUE,
1608                                                                         "PAC_LOGON_INFO:", -1);
1609
1610         return offset;
1611 }
1612
1613 static int
1614 dissect_krb5_PAC_S4U_DELEGATION_INFO(proto_tree *parent_tree, tvbuff_t *tvb, int offset, asn1_ctx_t *actx)
1615 {
1616         proto_item *item;
1617         proto_tree *tree;
1618         guint8 drep[4] = { 0x10, 0x00, 0x00, 0x00}; /* fake DREP struct */
1619         static dcerpc_info di;      /* fake dcerpc_info struct */
1620         static dcerpc_call_value call_data;
1621
1622         item = proto_tree_add_item(parent_tree, hf_krb_pac_s4u_delegation_info, tvb, offset, -1, ENC_NA);
1623         tree = proto_item_add_subtree(item, ett_krb_pac_s4u_delegation_info);
1624
1625         /* skip the first 16 bytes, they are some magic created by the idl
1626          * compiler   the first 4 bytes might be flags?
1627          */
1628         offset = dissect_krb5_PAC_NDRHEADERBLOB(tree, tvb, offset, &drep[0], actx);
1629
1630
1631         /* the S4U_DELEGATION_INFO blob. See [MS-PAC] */
1632         /* fake whatever state the dcerpc runtime support needs */
1633         di.conformant_run=0;
1634         /* we need di->call_data->flags.NDR64 == 0 */
1635         di.call_data=&call_data;
1636         init_ndr_pointer_list(&di);
1637         offset = dissect_ndr_pointer(tvb, offset, actx->pinfo, tree, &di, drep,
1638                                                                         netlogon_dissect_PAC_S4U_DELEGATION_INFO, NDR_POINTER_UNIQUE,
1639                                                                         "PAC_S4U_DELEGATION_INFO:", -1);
1640
1641         return offset;
1642 }
1643
1644 static int
1645 dissect_krb5_PAC_UPN_DNS_INFO(proto_tree *parent_tree, tvbuff_t *tvb, int offset, asn1_ctx_t *actx _U_)
1646 {
1647         proto_item *item;
1648         proto_tree *tree;
1649         guint16 dns_offset, dns_len;
1650         guint16 upn_offset, upn_len;
1651         const char *dn;
1652         int dn_len;
1653         guint16 bc;
1654
1655         item = proto_tree_add_item(parent_tree, hf_krb_pac_upn_dns_info, tvb, offset, -1, ENC_NA);
1656         tree = proto_item_add_subtree(item, ett_krb_pac_upn_dns_info);
1657
1658         /* upn */
1659         upn_len = tvb_get_letohs(tvb, offset);
1660         proto_tree_add_item(tree, hf_krb_pac_upn_upn_len, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1661         offset+=2;
1662         upn_offset = tvb_get_letohs(tvb, offset);
1663         proto_tree_add_item(tree, hf_krb_pac_upn_upn_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1664         offset+=2;
1665
1666         /* dns */
1667         dns_len = tvb_get_letohs(tvb, offset);
1668         proto_tree_add_item(tree, hf_krb_pac_upn_dns_len, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1669         offset+=2;
1670         dns_offset = tvb_get_letohs(tvb, offset);
1671         proto_tree_add_item(tree, hf_krb_pac_upn_dns_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1672         offset+=2;
1673
1674         /* flags */
1675         proto_tree_add_item(tree, hf_krb_pac_upn_flags, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1676
1677         /* upn */
1678         offset = upn_offset;
1679         dn_len = upn_len;
1680         bc = tvb_reported_length_remaining(tvb, offset);
1681         dn = get_unicode_or_ascii_string(tvb, &offset, TRUE, &dn_len, TRUE, TRUE, &bc);
1682         proto_tree_add_string(tree, hf_krb_pac_upn_upn_name, tvb, upn_offset, upn_len, dn);
1683
1684         /* dns */
1685         offset = dns_offset;
1686         dn_len = dns_len;
1687         bc = tvb_reported_length_remaining(tvb, offset);
1688         dn = get_unicode_or_ascii_string(tvb, &offset, TRUE, &dn_len, TRUE, TRUE, &bc);
1689         proto_tree_add_string(tree, hf_krb_pac_upn_dns_name, tvb, dns_offset, dns_len, dn);
1690
1691         return offset;
1692 }
1693
1694 static int
1695 dissect_krb5_PAC_CREDENTIAL_TYPE(proto_tree *parent_tree, tvbuff_t *tvb, int offset, asn1_ctx_t *actx _U_)
1696 {
1697         proto_tree_add_item(parent_tree, hf_krb_pac_credential_type, tvb, offset, -1, ENC_NA);
1698
1699         return offset;
1700 }
1701
1702 static int
1703 dissect_krb5_PAC_SERVER_CHECKSUM(proto_tree *parent_tree, tvbuff_t *tvb, int offset, asn1_ctx_t *actx _U_)
1704 {
1705         proto_item *item;
1706         proto_tree *tree;
1707
1708         item = proto_tree_add_item(parent_tree, hf_krb_pac_server_checksum, tvb, offset, -1, ENC_NA);
1709         tree = proto_item_add_subtree(item, ett_krb_pac_server_checksum);
1710
1711         /* signature type */
1712         proto_tree_add_item(tree, hf_krb_pac_signature_type, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1713         offset+=4;
1714
1715         /* signature data */
1716         proto_tree_add_item(tree, hf_krb_pac_signature_signature, tvb, offset, -1, ENC_NA);
1717
1718         return offset;
1719 }
1720
1721 static int
1722 dissect_krb5_PAC_PRIVSVR_CHECKSUM(proto_tree *parent_tree, tvbuff_t *tvb, int offset, asn1_ctx_t *actx _U_)
1723 {
1724         proto_item *item;
1725         proto_tree *tree;
1726
1727         item = proto_tree_add_item(parent_tree, hf_krb_pac_privsvr_checksum, tvb, offset, -1, ENC_NA);
1728         tree = proto_item_add_subtree(item, ett_krb_pac_privsvr_checksum);
1729
1730         /* signature type */
1731         proto_tree_add_item(tree, hf_krb_pac_signature_type, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1732         offset+=4;
1733
1734         /* signature data */
1735         proto_tree_add_item(tree, hf_krb_pac_signature_signature, tvb, offset, -1, ENC_NA);
1736
1737         return offset;
1738 }
1739
1740 static int
1741 dissect_krb5_PAC_CLIENT_INFO_TYPE(proto_tree *parent_tree, tvbuff_t *tvb, int offset, asn1_ctx_t *actx _U_)
1742 {
1743         proto_item *item;
1744         proto_tree *tree;
1745         guint16 namelen;
1746
1747         item = proto_tree_add_item(parent_tree, hf_krb_pac_client_info_type, tvb, offset, -1, ENC_NA);
1748         tree = proto_item_add_subtree(item, ett_krb_pac_client_info_type);
1749
1750         /* clientid */
1751         offset = dissect_nt_64bit_time(tvb, tree, offset, hf_krb_pac_clientid);
1752
1753         /* name length */
1754         namelen=tvb_get_letohs(tvb, offset);
1755         proto_tree_add_uint(tree, hf_krb_pac_namelen, tvb, offset, 2, namelen);
1756         offset+=2;
1757
1758         /* client name */
1759         proto_tree_add_item(tree, hf_krb_pac_clientname, tvb, offset, namelen, ENC_UTF_16|ENC_LITTLE_ENDIAN);
1760         offset+=namelen;
1761
1762         return offset;
1763 }
1764
1765 static int
1766 dissect_krb5_AD_WIN2K_PAC_struct(proto_tree *tree, tvbuff_t *tvb, int offset, asn1_ctx_t *actx)
1767 {
1768         guint32 pac_type;
1769         guint32 pac_size;
1770         guint32 pac_offset;
1771         proto_item *it=NULL;
1772         proto_tree *tr=NULL;
1773         tvbuff_t *next_tvb;
1774
1775         /* type of pac data */
1776         pac_type=tvb_get_letohl(tvb, offset);
1777         it=proto_tree_add_uint(tree, hf_krb_w2k_pac_type, tvb, offset, 4, pac_type);
1778         tr=proto_item_add_subtree(it, ett_krb_pac);
1779
1780         offset += 4;
1781
1782         /* size of pac data */
1783         pac_size=tvb_get_letohl(tvb, offset);
1784         proto_tree_add_uint(tr, hf_krb_w2k_pac_size, tvb, offset, 4, pac_size);
1785         offset += 4;
1786
1787         /* offset to pac data */
1788         pac_offset=tvb_get_letohl(tvb, offset);
1789         proto_tree_add_uint(tr, hf_krb_w2k_pac_offset, tvb, offset, 4, pac_offset);
1790         offset += 8;
1791
1792         next_tvb=tvb_new_subset_length_caplen(tvb, pac_offset, pac_size, pac_size);
1793         switch(pac_type){
1794         case PAC_LOGON_INFO:
1795                 dissect_krb5_PAC_LOGON_INFO(tr, next_tvb, 0, actx);
1796                 break;
1797         case PAC_CREDENTIAL_TYPE:
1798                 dissect_krb5_PAC_CREDENTIAL_TYPE(tr, next_tvb, 0, actx);
1799                 break;
1800         case PAC_SERVER_CHECKSUM:
1801                 dissect_krb5_PAC_SERVER_CHECKSUM(tr, next_tvb, 0, actx);
1802                 break;
1803         case PAC_PRIVSVR_CHECKSUM:
1804                 dissect_krb5_PAC_PRIVSVR_CHECKSUM(tr, next_tvb, 0, actx);
1805                 break;
1806         case PAC_CLIENT_INFO_TYPE:
1807                 dissect_krb5_PAC_CLIENT_INFO_TYPE(tr, next_tvb, 0, actx);
1808                 break;
1809         case PAC_S4U_DELEGATION_INFO:
1810                 dissect_krb5_PAC_S4U_DELEGATION_INFO(tr, next_tvb, 0, actx);
1811                 break;
1812         case PAC_UPN_DNS_INFO:
1813                 dissect_krb5_PAC_UPN_DNS_INFO(tr, next_tvb, 0, actx);
1814                 break;
1815
1816         default:
1817                 break;
1818         }
1819         return offset;
1820 }
1821
1822 static int
1823 dissect_krb5_AD_WIN2K_PAC(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index _U_)
1824 {
1825         guint32 entries;
1826         guint32 version;
1827         guint32 i;
1828
1829         /* first in the PAC structure comes the number of entries */
1830         entries=tvb_get_letohl(tvb, offset);
1831         proto_tree_add_uint(tree, hf_krb_w2k_pac_entries, tvb, offset, 4, entries);
1832         offset += 4;
1833
1834         /* second comes the version */
1835         version=tvb_get_letohl(tvb, offset);
1836         proto_tree_add_uint(tree, hf_krb_w2k_pac_version, tvb, offset, 4, version);
1837         offset += 4;
1838
1839         for(i=0;i<entries;i++){
1840                 offset=dissect_krb5_AD_WIN2K_PAC_struct(tree, tvb, offset, actx);
1841         }
1842
1843         return offset;
1844 }
1845
1846 #include "packet-kerberos-fn.c"
1847
1848 /* Make wrappers around exported functions for now */
1849 int
1850 dissect_krb5_Checksum(proto_tree *tree, tvbuff_t *tvb, int offset, asn1_ctx_t *actx _U_)
1851 {
1852         return dissect_kerberos_Checksum(FALSE, tvb, offset, actx, tree, hf_kerberos_cksum);
1853
1854 }
1855
1856 int
1857 dissect_krb5_ctime(proto_tree *tree, tvbuff_t *tvb, int offset, asn1_ctx_t *actx _U_)
1858 {
1859         return dissect_kerberos_KerberosTime(FALSE, tvb, offset, actx, tree, hf_kerberos_ctime);
1860 }
1861
1862
1863 int
1864 dissect_krb5_cname(proto_tree *tree, tvbuff_t *tvb, int offset, asn1_ctx_t *actx _U_)
1865 {
1866         return dissect_kerberos_PrincipalName(FALSE, tvb, offset, actx, tree, hf_kerberos_cname);
1867 }
1868 int
1869 dissect_krb5_realm(proto_tree *tree, tvbuff_t *tvb, int offset, asn1_ctx_t *actx _U_)
1870 {
1871         return dissect_kerberos_Realm(FALSE, tvb, offset, actx, tree, hf_kerberos_realm);
1872 }
1873
1874
1875 static gint
1876 dissect_kerberos_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1877     gboolean dci, gboolean do_col_protocol, gboolean have_rm,
1878     kerberos_callbacks *cb)
1879 {
1880         volatile int offset = 0;
1881         proto_tree *volatile kerberos_tree = NULL;
1882         proto_item *volatile item = NULL;
1883         asn1_ctx_t asn1_ctx;
1884
1885         /* TCP record mark and length */
1886         guint32 krb_rm = 0;
1887         gint krb_reclen = 0;
1888
1889         gbl_do_col_info=dci;
1890
1891         if (have_rm) {
1892                 krb_rm = tvb_get_ntohl(tvb, offset);
1893                 krb_reclen = kerberos_rm_to_reclen(krb_rm);
1894                 /*
1895                  * What is a reasonable size limit?
1896                  */
1897                 if (krb_reclen > 10 * 1024 * 1024) {
1898                         return (-1);
1899                 }
1900
1901                 if (do_col_protocol) {
1902                         col_set_str(pinfo->cinfo, COL_PROTOCOL, "KRB5");
1903                 }
1904
1905                 if (tree) {
1906                         item = proto_tree_add_item(tree, proto_kerberos, tvb, 0, -1, ENC_NA);
1907                         kerberos_tree = proto_item_add_subtree(item, ett_kerberos);
1908                 }
1909
1910                 show_krb_recordmark(kerberos_tree, tvb, offset, krb_rm);
1911                 offset += 4;
1912         } else {
1913                 /* Do some sanity checking here,
1914                  * All krb5 packets start with a TAG class that is BER_CLASS_APP
1915                  * and a tag value that is either of the values below:
1916                  * If it doesn't look like kerberos, return 0 and let someone else have
1917                  * a go at it.
1918                  */
1919                 gint8 tmp_class;
1920                 gboolean tmp_pc;
1921                 gint32 tmp_tag;
1922
1923                 get_ber_identifier(tvb, offset, &tmp_class, &tmp_pc, &tmp_tag);
1924                 if(tmp_class!=BER_CLASS_APP){
1925                         return 0;
1926                 }
1927                 switch(tmp_tag){
1928                         case KRB5_MSG_TICKET:
1929                         case KRB5_MSG_AUTHENTICATOR:
1930                         case KRB5_MSG_ENC_TICKET_PART:
1931                         case KRB5_MSG_AS_REQ:
1932                         case KRB5_MSG_AS_REP:
1933                         case KRB5_MSG_TGS_REQ:
1934                         case KRB5_MSG_TGS_REP:
1935                         case KRB5_MSG_AP_REQ:
1936                         case KRB5_MSG_AP_REP:
1937                         case KRB5_MSG_ENC_AS_REP_PART:
1938                         case KRB5_MSG_ENC_TGS_REP_PART:
1939                         case KRB5_MSG_ENC_AP_REP_PART:
1940                         case KRB5_MSG_ENC_KRB_PRIV_PART:
1941                         case KRB5_MSG_ENC_KRB_CRED_PART:
1942                         case KRB5_MSG_SAFE:
1943                         case KRB5_MSG_PRIV:
1944                         case KRB5_MSG_ERROR:
1945                                 break;
1946                         default:
1947                                 return 0;
1948                 }
1949                 if (do_col_protocol) {
1950                         col_set_str(pinfo->cinfo, COL_PROTOCOL, "KRB5");
1951                 }
1952                 if (gbl_do_col_info) {
1953                         col_clear(pinfo->cinfo, COL_INFO);
1954                 }
1955                 if (tree) {
1956                         item = proto_tree_add_item(tree, proto_kerberos, tvb, 0, -1, ENC_NA);
1957                         kerberos_tree = proto_item_add_subtree(item, ett_kerberos);
1958                 }
1959         }
1960         asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
1961         asn1_ctx.private_data = cb;
1962
1963         TRY {
1964                 offset=dissect_kerberos_Applications(FALSE, tvb, offset, &asn1_ctx , kerberos_tree, /* hf_index */ -1);
1965         } CATCH_BOUNDS_ERRORS {
1966                 RETHROW;
1967         } ENDTRY;
1968
1969         proto_item_set_len(item, offset);
1970         return offset;
1971 }
1972
1973 /*
1974  * Display the TCP record mark.
1975  */
1976 void
1977 show_krb_recordmark(proto_tree *tree, tvbuff_t *tvb, gint start, guint32 krb_rm)
1978 {
1979         gint rec_len;
1980         proto_tree *rm_tree;
1981
1982         if (tree == NULL)
1983                 return;
1984
1985         rec_len = kerberos_rm_to_reclen(krb_rm);
1986         rm_tree = proto_tree_add_subtree_format(tree, tvb, start, 4, ett_krb_recordmark, NULL,
1987                 "Record Mark: %u %s", rec_len, plurality(rec_len, "byte", "bytes"));
1988         proto_tree_add_boolean(rm_tree, hf_krb_rm_reserved, tvb, start, 4, krb_rm);
1989         proto_tree_add_uint(rm_tree, hf_krb_rm_reclen, tvb, start, 4, krb_rm);
1990 }
1991
1992 gint
1993 dissect_kerberos_main(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int do_col_info, kerberos_callbacks *cb)
1994 {
1995         return (dissect_kerberos_common(tvb, pinfo, tree, do_col_info, FALSE, FALSE, cb));
1996 }
1997
1998 guint32
1999 kerberos_output_keytype(void)
2000 {
2001         return gbl_keytype;
2002 }
2003
2004 static gint
2005 dissect_kerberos_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
2006 {
2007         /* Some weird kerberos implementation apparently do krb4 on the krb5 port.
2008            Since all (except weirdo transarc krb4 stuff) use
2009            an opcode <=16 in the first byte, use this to see if it might
2010            be krb4.
2011            All krb5 commands start with an APPL tag and thus is >=0x60
2012            so if first byte is <=16  just blindly assume it is krb4 then
2013         */
2014         if(tvb_captured_length(tvb) >= 1 && tvb_get_guint8(tvb, 0)<=0x10){
2015                 if(krb4_handle){
2016                         gboolean res;
2017
2018                         res=call_dissector_only(krb4_handle, tvb, pinfo, tree, NULL);
2019                         return res;
2020                 }else{
2021                         return 0;
2022                 }
2023         }
2024
2025
2026         return dissect_kerberos_common(tvb, pinfo, tree, TRUE, TRUE, FALSE, NULL);
2027 }
2028
2029 gint
2030 kerberos_rm_to_reclen(guint krb_rm)
2031 {
2032     return (krb_rm & KRB_RM_RECLEN);
2033 }
2034
2035 guint
2036 get_krb_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
2037 {
2038         guint krb_rm;
2039         gint pdulen;
2040
2041         krb_rm = tvb_get_ntohl(tvb, offset);
2042         pdulen = kerberos_rm_to_reclen(krb_rm);
2043         return (pdulen + 4);
2044 }
2045 static void
2046 kerberos_prefs_apply_cb(void) {
2047 #ifdef HAVE_LIBNETTLE
2048         clear_keytab();
2049         read_keytab_file(keytab_filename);
2050 #endif
2051 }
2052
2053 static int
2054 dissect_kerberos_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
2055 {
2056         pinfo->fragmented = TRUE;
2057         if (dissect_kerberos_common(tvb, pinfo, tree, TRUE, TRUE, TRUE, NULL) < 0) {
2058                 /*
2059                  * The dissector failed to recognize this as a valid
2060                  * Kerberos message.  Mark it as a continuation packet.
2061                  */
2062                 col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
2063         }
2064
2065         return tvb_captured_length(tvb);
2066 }
2067
2068 static int
2069 dissect_kerberos_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
2070 {
2071         col_set_str(pinfo->cinfo, COL_PROTOCOL, "KRB5");
2072         col_clear(pinfo->cinfo, COL_INFO);
2073
2074         tcp_dissect_pdus(tvb, pinfo, tree, krb_desegment, 4, get_krb_pdu_len,
2075                                          dissect_kerberos_tcp_pdu, data);
2076         return tvb_captured_length(tvb);
2077 }
2078
2079 /*--- proto_register_kerberos -------------------------------------------*/
2080 void proto_register_kerberos(void) {
2081
2082         /* List of fields */
2083
2084         static hf_register_info hf[] = {
2085         { &hf_krb_rm_reserved, {
2086                 "Reserved", "kerberos.rm.reserved", FT_BOOLEAN, 32,
2087                 TFS(&tfs_set_notset), KRB_RM_RESERVED, "Record mark reserved bit", HFILL }},
2088         { &hf_krb_rm_reclen, {
2089                 "Record Length", "kerberos.rm.length", FT_UINT32, BASE_DEC,
2090                 NULL, KRB_RM_RECLEN, NULL, HFILL }},
2091         { &hf_krb_provsrv_location, {
2092                 "PROVSRV Location", "kerberos.provsrv_location", FT_STRING, BASE_NONE,
2093                 NULL, 0, "PacketCable PROV SRV Location", HFILL }},
2094         { &hf_krb_smb_nt_status,
2095                 { "NT Status", "kerberos.smb.nt_status", FT_UINT32, BASE_HEX,
2096                 VALS(NT_errors), 0, "NT Status code", HFILL }},
2097         { &hf_krb_smb_unknown,
2098                 { "Unknown", "kerberos.smb.unknown", FT_UINT32, BASE_HEX,
2099                 NULL, 0, NULL, HFILL }},
2100         { &hf_krb_address_ip, {
2101                 "IP Address", "kerberos.addr_ip", FT_IPv4, BASE_NONE,
2102                 NULL, 0, NULL, HFILL }},
2103         { &hf_krb_address_ipv6, {
2104                 "IPv6 Address", "kerberos.addr_ipv6", FT_IPv6, BASE_NONE,
2105                 NULL, 0, NULL, HFILL }},
2106         { &hf_krb_address_netbios, {
2107                 "NetBIOS Address", "kerberos.addr_nb", FT_STRING, BASE_NONE,
2108                 NULL, 0, "NetBIOS Address and type", HFILL }},
2109         { &hf_krb_gssapi_len, {
2110                 "Length", "kerberos.gssapi.len", FT_UINT32, BASE_DEC,
2111                 NULL, 0, "Length of GSSAPI Bnd field", HFILL }},
2112         { &hf_krb_gssapi_bnd, {
2113                 "Bnd", "kerberos.gssapi.bdn", FT_BYTES, BASE_NONE,
2114                 NULL, 0, "GSSAPI Bnd field", HFILL }},
2115         { &hf_krb_gssapi_c_flag_deleg, {
2116                 "Deleg", "kerberos.gssapi.checksum.flags.deleg", FT_BOOLEAN, 32,
2117                 TFS(&tfs_gss_flags_deleg), KRB5_GSS_C_DELEG_FLAG, NULL, HFILL }},
2118         { &hf_krb_gssapi_c_flag_mutual, {
2119                 "Mutual", "kerberos.gssapi.checksum.flags.mutual", FT_BOOLEAN, 32,
2120                 TFS(&tfs_gss_flags_mutual), KRB5_GSS_C_MUTUAL_FLAG, NULL, HFILL }},
2121         { &hf_krb_gssapi_c_flag_replay, {
2122                 "Replay", "kerberos.gssapi.checksum.flags.replay", FT_BOOLEAN, 32,
2123                 TFS(&tfs_gss_flags_replay), KRB5_GSS_C_REPLAY_FLAG, NULL, HFILL }},
2124         { &hf_krb_gssapi_c_flag_sequence, {
2125                 "Sequence", "kerberos.gssapi.checksum.flags.sequence", FT_BOOLEAN, 32,
2126                 TFS(&tfs_gss_flags_sequence), KRB5_GSS_C_SEQUENCE_FLAG, NULL, HFILL }},
2127         { &hf_krb_gssapi_c_flag_conf, {
2128                 "Conf", "kerberos.gssapi.checksum.flags.conf", FT_BOOLEAN, 32,
2129                 TFS(&tfs_gss_flags_conf), KRB5_GSS_C_CONF_FLAG, NULL, HFILL }},
2130         { &hf_krb_gssapi_c_flag_integ, {
2131                 "Integ", "kerberos.gssapi.checksum.flags.integ", FT_BOOLEAN, 32,
2132                 TFS(&tfs_gss_flags_integ), KRB5_GSS_C_INTEG_FLAG, NULL, HFILL }},
2133         { &hf_krb_gssapi_c_flag_dce_style, {
2134                 "DCE-style", "kerberos.gssapi.checksum.flags.dce-style", FT_BOOLEAN, 32,
2135                 TFS(&tfs_gss_flags_dce_style), KRB5_GSS_C_DCE_STYLE, NULL, HFILL }},
2136         { &hf_krb_gssapi_dlgopt, {
2137                 "DlgOpt", "kerberos.gssapi.dlgopt", FT_UINT16, BASE_DEC,
2138                 NULL, 0, "GSSAPI DlgOpt", HFILL }},
2139         { &hf_krb_gssapi_dlglen, {
2140                 "DlgLen", "kerberos.gssapi.dlglen", FT_UINT16, BASE_DEC,
2141                 NULL, 0, "GSSAPI DlgLen", HFILL }},
2142         { &hf_krb_midl_blob_len, {
2143                 "Blob Length", "kerberos.midl_blob_len", FT_UINT64, BASE_DEC,
2144                 NULL, 0, "Length of NDR encoded data that follows", HFILL }},
2145         { &hf_krb_midl_fill_bytes, {
2146                 "Fill bytes", "kerberos.midl.fill_bytes", FT_UINT32, BASE_HEX,
2147                 NULL, 0, "Just some fill bytes", HFILL }},
2148         { &hf_krb_midl_version, {
2149         "Version", "kerberos.midl.version", FT_UINT8, BASE_DEC,
2150         NULL, 0, "Version of pickling", HFILL }},
2151         { &hf_krb_midl_hdr_len, {
2152                 "HDR Length", "kerberos.midl.hdr_len", FT_UINT16, BASE_DEC,
2153                 NULL, 0, "Length of header", HFILL }},
2154         { &hf_krb_pac_signature_type, {
2155                 "Type", "kerberos.pac.signature.type", FT_INT32, BASE_DEC,
2156                 NULL, 0, "PAC Signature Type", HFILL }},
2157         { &hf_krb_pac_signature_signature, {
2158                 "Signature", "kerberos.pac.signature.signature", FT_BYTES, BASE_NONE,
2159                 NULL, 0, "A PAC signature blob", HFILL }},
2160         { &hf_krb_w2k_pac_entries, {
2161                 "Num Entries", "kerberos.pac.entries", FT_UINT32, BASE_DEC,
2162                 NULL, 0, "Number of W2k PAC entries", HFILL }},
2163         { &hf_krb_w2k_pac_version, {
2164                 "Version", "kerberos.pac.version", FT_UINT32, BASE_DEC,
2165                 NULL, 0, "Version of PAC structures", HFILL }},
2166         { &hf_krb_w2k_pac_type, {
2167                 "Type", "kerberos.pac.type", FT_UINT32, BASE_DEC,
2168                 VALS(w2k_pac_types), 0, "Type of W2k PAC entry", HFILL }},
2169         { &hf_krb_w2k_pac_size, {
2170                 "Size", "kerberos.pac.size", FT_UINT32, BASE_DEC,
2171                 NULL, 0, "Size of W2k PAC entry", HFILL }},
2172         { &hf_krb_w2k_pac_offset, {
2173                 "Offset", "kerberos.pac.offset", FT_UINT32, BASE_DEC,
2174                 NULL, 0, "Offset to W2k PAC entry", HFILL }},
2175         { &hf_krb_pac_clientid, {
2176                 "ClientID", "kerberos.pac.clientid", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
2177                 NULL, 0, "ClientID Timestamp", HFILL }},
2178         { &hf_krb_pac_namelen, {
2179                 "Name Length", "kerberos.pac.namelen", FT_UINT16, BASE_DEC,
2180                 NULL, 0, "Length of client name", HFILL }},
2181         { &hf_krb_pac_clientname, {
2182                 "Name", "kerberos.pac.name", FT_STRING, BASE_NONE,
2183                 NULL, 0, "Name of the Client in the PAC structure", HFILL }},
2184         { &hf_krb_pac_logon_info, {
2185                 "PAC_LOGON_INFO", "kerberos.pac_logon_info", FT_BYTES, BASE_NONE,
2186                 NULL, 0, "PAC_LOGON_INFO structure", HFILL }},
2187         { &hf_krb_pac_credential_type, {
2188                 "PAC_CREDENTIAL_TYPE", "kerberos.pac_credential_type", FT_BYTES, BASE_NONE,
2189                 NULL, 0, "PAC_CREDENTIAL_TYPE structure", HFILL }},
2190         { &hf_krb_pac_server_checksum, {
2191                 "PAC_SERVER_CHECKSUM", "kerberos.pac_server_checksum", FT_BYTES, BASE_NONE,
2192                 NULL, 0, "PAC_SERVER_CHECKSUM structure", HFILL }},
2193         { &hf_krb_pac_privsvr_checksum, {
2194                 "PAC_PRIVSVR_CHECKSUM", "kerberos.pac_privsvr_checksum", FT_BYTES, BASE_NONE,
2195                 NULL, 0, "PAC_PRIVSVR_CHECKSUM structure", HFILL }},
2196         { &hf_krb_pac_client_info_type, {
2197                 "PAC_CLIENT_INFO_TYPE", "kerberos.pac_client_info_type", FT_BYTES, BASE_NONE,
2198                 NULL, 0, "PAC_CLIENT_INFO_TYPE structure", HFILL }},
2199         { &hf_krb_pac_s4u_delegation_info, {
2200                 "PAC_S4U_DELEGATION_INFO", "kerberos.pac_s4u_delegation_info", FT_BYTES, BASE_NONE,
2201                 NULL, 0, "PAC_S4U_DELEGATION_INFO structure", HFILL }},
2202         { &hf_krb_pac_upn_dns_info, {
2203                 "UPN_DNS_INFO", "kerberos.pac_upn_dns_info", FT_BYTES, BASE_NONE,
2204                 NULL, 0, "UPN_DNS_INFO structure", HFILL }},
2205         { &hf_krb_pac_upn_flags, {
2206                 "Flags", "kerberos.pac.upn.flags", FT_UINT32, BASE_HEX,
2207                 NULL, 0, "UPN flags", HFILL }},
2208         { &hf_krb_pac_upn_dns_offset, {
2209                 "DNS Offset", "kerberos.pac.upn.dns_offset", FT_UINT16, BASE_DEC,
2210                 NULL, 0, NULL, HFILL }},
2211         { &hf_krb_pac_upn_dns_len, {
2212                 "DNS Len", "kerberos.pac.upn.dns_len", FT_UINT16, BASE_DEC,
2213                 NULL, 0, NULL, HFILL }},
2214         { &hf_krb_pac_upn_upn_offset, {
2215                 "UPN Offset", "kerberos.pac.upn.upn_offset", FT_UINT16, BASE_DEC,
2216                 NULL, 0, NULL, HFILL }},
2217         { &hf_krb_pac_upn_upn_len, {
2218                 "UPN Len", "kerberos.pac.upn.upn_len", FT_UINT16, BASE_DEC,
2219                 NULL, 0, NULL, HFILL }},
2220         { &hf_krb_pac_upn_upn_name, {
2221                 "UPN Name", "kerberos.pac.upn.upn_name", FT_STRING, BASE_NONE,
2222                 NULL, 0, NULL, HFILL }},
2223         { &hf_krb_pac_upn_dns_name, {
2224                 "DNS Name", "kerberos.pac.upn.dns_name", FT_STRING, BASE_NONE,
2225                 NULL, 0, NULL, HFILL }},
2226
2227 #include "packet-kerberos-hfarr.c"
2228         };
2229
2230         /* List of subtrees */
2231         static gint *ett[] = {
2232                 &ett_kerberos,
2233                 &ett_krb_recordmark,
2234                 &ett_krb_pac,
2235                 &ett_krb_pac_drep,
2236                 &ett_krb_pac_midl_blob,
2237                 &ett_krb_pac_logon_info,
2238                 &ett_krb_pac_s4u_delegation_info,
2239                 &ett_krb_pac_upn_dns_info,
2240                 &ett_krb_pac_server_checksum,
2241                 &ett_krb_pac_privsvr_checksum,
2242                 &ett_krb_pac_client_info_type,
2243 #include "packet-kerberos-ettarr.c"
2244         };
2245
2246         static ei_register_info ei[] = {
2247                 { &ei_kerberos_decrypted_keytype, { "kerberos.decrypted_keytype", PI_SECURITY, PI_CHAT, "Decryted keytype", EXPFILL }},
2248                 { &ei_kerberos_address, { "kerberos.address.unknown", PI_UNDECODED, PI_WARN, "KRB Address: I don't know how to parse this type of address yet", EXPFILL }},
2249                 { &ei_krb_gssapi_dlglen, { "kerberos.gssapi.dlglen.error", PI_MALFORMED, PI_ERROR, "DlgLen is not the same as number of bytes remaining", EXPFILL }},
2250         };
2251
2252         expert_module_t* expert_krb;
2253         module_t *krb_module;
2254
2255         proto_kerberos = proto_register_protocol("Kerberos", "KRB5", "kerberos");
2256         proto_register_field_array(proto_kerberos, hf, array_length(hf));
2257         proto_register_subtree_array(ett, array_length(ett));
2258         expert_krb = expert_register_protocol(proto_kerberos);
2259         expert_register_field_array(expert_krb, ei, array_length(ei));
2260
2261         /* Register preferences */
2262         krb_module = prefs_register_protocol(proto_kerberos, kerberos_prefs_apply_cb);
2263         prefs_register_bool_preference(krb_module, "desegment",
2264         "Reassemble Kerberos over TCP messages spanning multiple TCP segments",
2265         "Whether the Kerberos dissector should reassemble messages spanning multiple TCP segments."
2266         " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
2267         &krb_desegment);
2268 #ifdef HAVE_KERBEROS
2269         prefs_register_bool_preference(krb_module, "decrypt",
2270         "Try to decrypt Kerberos blobs",
2271         "Whether the dissector should try to decrypt "
2272         "encrypted Kerberos blobs. This requires that the proper "
2273         "keytab file is installed as well.", &krb_decrypt);
2274
2275         prefs_register_filename_preference(krb_module, "file",
2276                                    "Kerberos keytab file",
2277                                    "The keytab file containing all the secrets",
2278                                    &keytab_filename, FALSE);
2279 #endif
2280
2281 }
2282 static int wrap_dissect_gss_kerb(tvbuff_t *tvb, int offset, packet_info *pinfo,
2283                                  proto_tree *tree, dcerpc_info *di _U_,guint8 *drep _U_)
2284 {
2285         tvbuff_t *auth_tvb;
2286
2287         auth_tvb = tvb_new_subset_remaining(tvb, offset);
2288
2289         dissect_kerberos_main(auth_tvb, pinfo, tree, FALSE, NULL);
2290
2291         return tvb_captured_length_remaining(tvb, offset);
2292 }
2293
2294
2295 static dcerpc_auth_subdissector_fns gss_kerb_auth_connect_fns = {
2296         wrap_dissect_gss_kerb,                      /* Bind */
2297         wrap_dissect_gss_kerb,                      /* Bind ACK */
2298         wrap_dissect_gss_kerb,                      /* AUTH3 */
2299         NULL,                                       /* Request verifier */
2300         NULL,                                       /* Response verifier */
2301         NULL,                                       /* Request data */
2302         NULL                                        /* Response data */
2303 };
2304
2305 static dcerpc_auth_subdissector_fns gss_kerb_auth_sign_fns = {
2306         wrap_dissect_gss_kerb,                      /* Bind */
2307         wrap_dissect_gss_kerb,                      /* Bind ACK */
2308         wrap_dissect_gss_kerb,                      /* AUTH3 */
2309         wrap_dissect_gssapi_verf,                   /* Request verifier */
2310         wrap_dissect_gssapi_verf,                   /* Response verifier */
2311         NULL,                                       /* Request data */
2312         NULL                                        /* Response data */
2313 };
2314
2315 static dcerpc_auth_subdissector_fns gss_kerb_auth_seal_fns = {
2316         wrap_dissect_gss_kerb,                      /* Bind */
2317         wrap_dissect_gss_kerb,                      /* Bind ACK */
2318         wrap_dissect_gss_kerb,                      /* AUTH3 */
2319         wrap_dissect_gssapi_verf,                   /* Request verifier */
2320         wrap_dissect_gssapi_verf,                   /* Response verifier */
2321         wrap_dissect_gssapi_payload,                /* Request data */
2322         wrap_dissect_gssapi_payload                 /* Response data */
2323 };
2324
2325
2326
2327 void
2328 proto_reg_handoff_kerberos(void)
2329 {
2330         dissector_handle_t kerberos_handle_tcp;
2331
2332         krb4_handle = find_dissector_add_dependency("krb4", proto_kerberos);
2333
2334         kerberos_handle_udp = create_dissector_handle(dissect_kerberos_udp,
2335         proto_kerberos);
2336
2337         kerberos_handle_tcp = create_dissector_handle(dissect_kerberos_tcp,
2338         proto_kerberos);
2339
2340         dissector_add_uint_with_preference("udp.port", UDP_PORT_KERBEROS, kerberos_handle_udp);
2341         dissector_add_uint_with_preference("tcp.port", TCP_PORT_KERBEROS, kerberos_handle_tcp);
2342
2343         register_dcerpc_auth_subdissector(DCE_C_AUTHN_LEVEL_CONNECT,
2344                                                                           DCE_C_RPC_AUTHN_PROTOCOL_GSS_KERBEROS,
2345                                                                           &gss_kerb_auth_connect_fns);
2346
2347         register_dcerpc_auth_subdissector(DCE_C_AUTHN_LEVEL_PKT_INTEGRITY,
2348                                                                           DCE_C_RPC_AUTHN_PROTOCOL_GSS_KERBEROS,
2349                                                                           &gss_kerb_auth_sign_fns);
2350
2351         register_dcerpc_auth_subdissector(DCE_C_AUTHN_LEVEL_PKT_PRIVACY,
2352                                                                           DCE_C_RPC_AUTHN_PROTOCOL_GSS_KERBEROS,
2353                                                                           &gss_kerb_auth_seal_fns);
2354 }
2355
2356 /*
2357  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
2358  *
2359  * Local variables:
2360  * c-basic-offset: 8
2361  * tab-width: 8
2362  * indent-tabs-mode: t
2363  * End:
2364  *
2365  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
2366  * :indentSize=8:tabSize=8:noTabs=false:
2367  */