Removed some more "statement not reached" warnings.
[obnox/wireshark/wip.git] / epan / dissectors / packet-kerberos4.c
1 /* packet-kerberos4.c
2  * Routines for Kerberos v4 packet dissection
3  *
4  * Ronnie Sahlberg 2004
5  *
6  * $Id$
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26 /*
27  * PDU structure based on the document :
28  *                                                              Section E.2.1
29  *
30  *                            Kerberos Authentication and Authorization System
31  *
32  *            by S. P. Miller, B. C. Neuman, J. I. Schiller, and J. H. Saltzer
33  *
34  */
35
36 #ifdef HAVE_CONFIG_H
37 # include "config.h"
38 #endif
39
40 #include <glib.h>
41 #include <epan/packet.h>
42 #include <epan/conversation.h>
43
44 static int proto_krb4 = -1;
45 static int hf_krb4_version = -1;
46 static int hf_krb4_auth_msg_type = -1;
47 static int hf_krb4_m_type = -1;
48 static int hf_krb4_byte_order = -1;
49 static int hf_krb4_name = -1;
50 static int hf_krb4_instance = -1;
51 static int hf_krb4_realm = -1;
52 static int hf_krb4_time_sec = -1;
53 static int hf_krb4_exp_date = -1;
54 static int hf_krb4_req_date = -1;
55 static int hf_krb4_lifetime = -1;
56 static int hf_krb4_s_name = -1;
57 static int hf_krb4_s_instance = -1;
58 static int hf_krb4_kvno = -1;
59 static int hf_krb4_length = -1;
60 static int hf_krb4_ticket_length = -1;
61 static int hf_krb4_request_length = -1;
62 static int hf_krb4_ticket_blob = -1;
63 static int hf_krb4_request_blob = -1;
64 static int hf_krb4_encrypted_blob = -1;
65 static int hf_krb4_unknown_transarc_blob = -1;
66
67 static gint ett_krb4 = -1;
68 static gint ett_krb4_auth_msg_type = -1;
69
70 #define UDP_PORT_KRB4    750
71 #define TRANSARC_SPECIAL_VERSION 0x63
72
73 static const value_string byte_order_vals[] = {
74         { 0,    "Big Endian" },
75         { 1,    "Little Endian" },
76         { 0,    NULL }
77 };
78
79 #define AUTH_MSG_KDC_REQUEST            1
80 #define AUTH_MSG_KDC_REPLY              2
81 #define AUTH_MSG_APPL_REQUEST           3
82 #define AUTH_MSG_APPL_REQUEST_MUTUAL    4
83 #define AUTH_MSG_ERR_REPLY              5
84 #define AUTH_MSG_PRIVATE                6
85 #define AUTH_MSG_SAFE                   7
86 #define AUTH_MSG_APPL_ERR               8
87 #define AUTH_MSG_DIE                    63
88 static const value_string m_type_vals[] = {
89         { AUTH_MSG_KDC_REQUEST,         "KDC Request" },
90         { AUTH_MSG_KDC_REPLY,           "KDC Reply" },
91         { AUTH_MSG_APPL_REQUEST,        "Appl Request" },
92         { AUTH_MSG_APPL_REQUEST_MUTUAL, "Appl Request Mutual" },
93         { AUTH_MSG_ERR_REPLY,           "Err Reply" },
94         { AUTH_MSG_PRIVATE,             "Private" },
95         { AUTH_MSG_SAFE,                "Safe" },
96         { AUTH_MSG_APPL_ERR,            "Appl Err" },
97         { AUTH_MSG_DIE,                 "Die" },
98         { 0,    NULL }
99 };
100
101
102 static int
103 dissect_krb4_string(packet_info *pinfo _U_, int hf_index, proto_tree *tree, tvbuff_t *tvb, int offset)
104 {
105         proto_tree_add_item(tree, hf_index, tvb, offset, -1, FALSE);
106         while(tvb_get_guint8(tvb, offset)!=0){
107                 offset++;
108         }
109         offset++;
110
111         return offset;
112 }
113
114 static int
115 dissect_krb4_kdc_request(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gboolean little_endian, int version)
116 {
117         nstime_t time_sec;
118         guint8 lifetime;
119
120         if(version==TRANSARC_SPECIAL_VERSION){
121                 proto_tree_add_item(tree, hf_krb4_unknown_transarc_blob, tvb, offset, 8, FALSE);
122                 offset+=8;
123         }
124
125         /* Name */
126         offset=dissect_krb4_string(pinfo, hf_krb4_name, tree, tvb, offset);
127
128         /* Instance */
129         offset=dissect_krb4_string(pinfo, hf_krb4_instance, tree, tvb, offset);
130
131         /* Realm */
132         offset=dissect_krb4_string(pinfo, hf_krb4_realm, tree, tvb, offset);
133
134         /* Time sec */
135         time_sec.secs=little_endian?tvb_get_letohl(tvb, offset):tvb_get_ntohl(tvb, offset);
136         time_sec.nsecs=0;
137         proto_tree_add_time(tree, hf_krb4_time_sec, tvb, offset, 4, &time_sec);
138         offset+=4;
139
140         /* lifetime */
141         lifetime=tvb_get_guint8(tvb, offset);
142         proto_tree_add_uint_format(tree, hf_krb4_lifetime, tvb, offset, 1, lifetime, "Lifetime: %d (%d minutes)", lifetime, lifetime*5);
143         offset++;
144
145         /* service Name */
146         offset=dissect_krb4_string(pinfo, hf_krb4_s_name, tree, tvb, offset);
147
148         /* service Instance */
149         offset=dissect_krb4_string(pinfo, hf_krb4_s_instance, tree, tvb, offset);
150
151         return offset;
152 }
153
154
155 static int
156 dissect_krb4_kdc_reply(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gboolean little_endian)
157 {
158         nstime_t time_sec;
159         guint32 length;
160
161         /* Name */
162         offset=dissect_krb4_string(pinfo, hf_krb4_name, tree, tvb, offset);
163
164         /* Instance */
165         offset=dissect_krb4_string(pinfo, hf_krb4_instance, tree, tvb, offset);
166
167         /* Realm */
168         offset=dissect_krb4_string(pinfo, hf_krb4_realm, tree, tvb, offset);
169
170         /* Time sec */
171         time_sec.secs=little_endian?tvb_get_letohl(tvb, offset):tvb_get_ntohl(tvb, offset);
172         time_sec.nsecs=0;
173         proto_tree_add_time(tree, hf_krb4_time_sec, tvb, offset, 4, &time_sec);
174         offset+=4;
175
176         /*XXX unknown byte here */
177         offset++;
178
179         /* exp date */
180         time_sec.secs=little_endian?tvb_get_letohl(tvb, offset):tvb_get_ntohl(tvb, offset);
181         time_sec.nsecs=0;
182         proto_tree_add_time(tree, hf_krb4_exp_date, tvb, offset, 4, &time_sec);
183         offset+=4;
184
185         /* kvno */
186         proto_tree_add_item(tree, hf_krb4_kvno, tvb, offset, 1, FALSE);
187         offset++;
188
189         /* length2 */
190         length=little_endian?tvb_get_letohs(tvb, offset):tvb_get_ntohs(tvb, offset);
191         proto_tree_add_uint_format(tree, hf_krb4_length, tvb, offset, 2, length, "Length: %d", length);
192         offset+=2;
193
194         /* encrypted blob */
195         proto_tree_add_item(tree, hf_krb4_encrypted_blob, tvb, offset, length, FALSE);
196         offset+=length;
197
198         return offset;
199 }
200
201
202 static int
203 dissect_krb4_appl_request(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gboolean little_endian)
204 {
205         guint8 tlen, rlen;
206         nstime_t time_sec;
207         guint8 lifetime;
208
209         /* kvno */
210         proto_tree_add_item(tree, hf_krb4_kvno, tvb, offset, 1, FALSE);
211         offset++;
212
213         /* Realm */
214         offset=dissect_krb4_string(pinfo, hf_krb4_realm, tree, tvb, offset);
215
216         /* ticket length */
217         tlen=tvb_get_guint8(tvb, offset);
218         proto_tree_add_item(tree, hf_krb4_ticket_length, tvb, offset, 1, FALSE);
219         offset++;
220
221         /* request length */
222         rlen=tvb_get_guint8(tvb, offset);
223         proto_tree_add_item(tree, hf_krb4_request_length, tvb, offset, 1, FALSE);
224         offset++;
225
226         /* ticket */
227         proto_tree_add_item(tree, hf_krb4_ticket_blob, tvb, offset, tlen, FALSE);
228         offset+=tlen;
229
230         /* request */
231         proto_tree_add_item(tree, hf_krb4_request_blob, tvb, offset, rlen, FALSE);
232         offset+=rlen;
233
234         /* request time */
235         time_sec.secs=little_endian?tvb_get_letohl(tvb, offset):tvb_get_ntohl(tvb, offset);
236         time_sec.nsecs=0;
237         proto_tree_add_time(tree, hf_krb4_req_date, tvb, offset, 4, &time_sec);
238         offset+=4;
239
240         /* lifetime */
241         lifetime=tvb_get_guint8(tvb, offset);
242         proto_tree_add_uint_format(tree, hf_krb4_lifetime, tvb, offset, 1, lifetime, "Lifetime: %d (%d minutes)", lifetime, lifetime*5);
243         offset++;
244
245         /* service Name */
246         offset=dissect_krb4_string(pinfo, hf_krb4_s_name, tree, tvb, offset);
247
248         /* service Instance */
249         offset=dissect_krb4_string(pinfo, hf_krb4_s_instance, tree, tvb, offset);
250
251         return offset;
252 }
253
254
255
256 static int
257 dissect_krb4_auth_msg_type(packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *tvb, int offset, int version)
258 {
259         proto_tree *tree;
260         proto_item *item;
261         guint8 auth_msg_type;
262
263         auth_msg_type=tvb_get_guint8(tvb, offset);
264         item = proto_tree_add_item(parent_tree, hf_krb4_auth_msg_type, tvb, offset, 1, FALSE);
265         tree = proto_item_add_subtree(item, ett_krb4_auth_msg_type);
266
267         /* m_type */
268         proto_tree_add_item(tree, hf_krb4_m_type, tvb, offset, 1, FALSE);
269         if (check_col(pinfo->cinfo, COL_INFO))
270           col_append_fstr(pinfo->cinfo, COL_INFO, "%s%s",
271            (version==TRANSARC_SPECIAL_VERSION)?"TRANSARC-":"", 
272             val_to_str(auth_msg_type>>1, m_type_vals, "Unknown (0x%04x)"));
273         proto_item_append_text(item, " %s%s", 
274            (version==TRANSARC_SPECIAL_VERSION)?"TRANSARC-":"", 
275            val_to_str(auth_msg_type>>1, m_type_vals, "Unknown (0x%04x)"));
276
277         /* byte order */
278         proto_tree_add_item(tree, hf_krb4_byte_order, tvb, offset, 1, FALSE);
279         proto_item_append_text(item, " (%s)", val_to_str(auth_msg_type&0x01, byte_order_vals, "Unknown (0x%04x)"));
280
281         offset++;
282         return offset;
283 }
284
285 static gboolean
286 dissect_krb4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
287 {
288         proto_tree *tree;
289         proto_item *item;
290         guint8 version, opcode;
291         int offset=0;
292         
293         /* this should better have the value 4 or it might be a weirdo
294          * Transarc AFS special unknown thing.
295          */
296         version=tvb_get_guint8(tvb, offset);
297         if((version!=4)&&(version!=TRANSARC_SPECIAL_VERSION)){ 
298                 return FALSE;
299         }
300
301         opcode=tvb_get_guint8(tvb, offset+1);
302         switch(opcode>>1){
303         case AUTH_MSG_KDC_REQUEST:
304         case AUTH_MSG_KDC_REPLY:
305         case AUTH_MSG_APPL_REQUEST:
306         case AUTH_MSG_APPL_REQUEST_MUTUAL:
307         case AUTH_MSG_ERR_REPLY:
308         case AUTH_MSG_PRIVATE:
309         case AUTH_MSG_SAFE:
310         case AUTH_MSG_APPL_ERR:
311         case AUTH_MSG_DIE:
312                 break;
313         default:
314                 return FALSE;
315         }
316
317         /* create a tree for krb4 */
318         item = proto_tree_add_item(parent_tree, proto_krb4, tvb, offset, -1, FALSE);
319         tree = proto_item_add_subtree(item, ett_krb4);
320         
321         if (check_col(pinfo->cinfo, COL_PROTOCOL))
322                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "KRB4");
323         if (check_col(pinfo->cinfo, COL_INFO))
324                 col_clear(pinfo->cinfo, COL_INFO);
325
326         /* version */
327         proto_tree_add_item(tree, hf_krb4_version, tvb, offset, 1, FALSE);
328         offset++;
329
330         /* auth_msg_type */
331         offset = dissect_krb4_auth_msg_type(pinfo, tree, tvb, offset, version);
332
333         switch(opcode>>1){
334         case AUTH_MSG_KDC_REQUEST:
335                 offset = dissect_krb4_kdc_request(pinfo, tree, tvb, offset, opcode&0x01, version);
336                 break;
337         case AUTH_MSG_KDC_REPLY:
338                 offset = dissect_krb4_kdc_reply(pinfo, tree, tvb, offset, opcode&0x01);
339                 break;
340         case AUTH_MSG_APPL_REQUEST:
341                 offset = dissect_krb4_appl_request(pinfo, tree, tvb, offset, opcode&0x01);
342                 break;
343         case AUTH_MSG_APPL_REQUEST_MUTUAL:
344         case AUTH_MSG_ERR_REPLY:
345         case AUTH_MSG_PRIVATE:
346         case AUTH_MSG_SAFE:
347         case AUTH_MSG_APPL_ERR:
348         case AUTH_MSG_DIE:
349                 break;
350         }
351         return TRUE;
352 }
353
354 void
355 proto_register_krb4(void)
356 {
357   static hf_register_info hf[] = {
358     { &hf_krb4_version,
359       { "Version", "krb4.version",
360         FT_UINT8, BASE_DEC, NULL, 0x0,
361         "Kerberos(v4) version number", HFILL }},
362     { &hf_krb4_auth_msg_type,
363       { "Msg Type", "krb4.auth_msg_type",
364         FT_UINT8, BASE_HEX, NULL, 0x0,
365         "Message Type/Byte Order", HFILL }},
366     { &hf_krb4_m_type,
367       { "M Type", "krb4.m_type",
368         FT_UINT8, BASE_HEX, VALS(m_type_vals), 0xfe,
369         "Message Type", HFILL }},
370     { &hf_krb4_byte_order,
371       { "Byte Order", "krb4.byte_order",
372         FT_UINT8, BASE_HEX, VALS(byte_order_vals), 0x01,
373         "Byte Order", HFILL }},
374     { &hf_krb4_name,
375       { "Name", "krb4.name",
376         FT_STRINGZ, BASE_NONE, NULL, 0x00,
377         "Name", HFILL }},
378     { &hf_krb4_instance,
379       { "Instance", "krb4.instance",
380         FT_STRINGZ, BASE_NONE, NULL, 0x00,
381         "Instance", HFILL }},
382     { &hf_krb4_realm,
383       { "Realm", "krb4.realm",
384         FT_STRINGZ, BASE_NONE, NULL, 0x00,
385         "Realm", HFILL }},
386     { &hf_krb4_time_sec,
387       { "Time Sec", "krb4.time_sec",
388         FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
389         "Time Sec", HFILL }},
390     { &hf_krb4_exp_date,
391       { "Exp Date", "krb4.exp_date",
392         FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
393         "Exp Date", HFILL }},
394     { &hf_krb4_req_date,
395       { "Req Date", "krb4.req_date",
396         FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
397         "Req Date", HFILL }},
398     { &hf_krb4_lifetime,
399       { "Lifetime", "krb4.lifetime",
400         FT_UINT8, BASE_DEC, NULL, 0x00,
401         "Lifetime (in 5 min units)", HFILL }},
402     { &hf_krb4_s_name,
403       { "Service Name", "krb4.s_name",
404         FT_STRINGZ, BASE_NONE, NULL, 0x00,
405         "Service Name", HFILL }},
406     { &hf_krb4_s_instance,
407       { "Service Instance", "krb4.s_instance",
408         FT_STRINGZ, BASE_NONE, NULL, 0x00,
409         "Service Instance", HFILL }},
410     { &hf_krb4_kvno,
411       { "Kvno", "krb4.kvno",
412         FT_UINT8, BASE_DEC, NULL, 0x00,
413         "Key Version No", HFILL }},
414     { &hf_krb4_length,
415       { "Length", "krb4.length",
416         FT_UINT32, BASE_DEC, NULL, 0x00,
417         "Length of encrypted blob", HFILL }},
418     { &hf_krb4_ticket_length,
419       { "Ticket Length", "krb4.ticket.length",
420         FT_UINT8, BASE_DEC, NULL, 0x00,
421         "Length of ticket", HFILL }},
422     { &hf_krb4_request_length,
423       { "Request Length", "krb4.request.length",
424         FT_UINT8, BASE_DEC, NULL, 0x00,
425         "Length of request", HFILL }},
426     { &hf_krb4_ticket_blob,
427       { "Ticket Blob", "krb4.ticket.blob",
428         FT_BYTES, BASE_HEX, NULL, 0x00,
429         "Ticket blob", HFILL }},
430     { &hf_krb4_request_blob,
431       { "Request Blob", "krb4.request.blob",
432         FT_BYTES, BASE_HEX, NULL, 0x00,
433         "Request Blob", HFILL }},
434     { &hf_krb4_encrypted_blob,
435       { "Encrypted Blob", "krb4.encrypted_blob",
436         FT_BYTES, BASE_HEX, NULL, 0x00,
437         "Encrypted blob", HFILL }},
438     { &hf_krb4_unknown_transarc_blob,
439       { "Unknown Transarc Blob", "krb4.unknown_transarc_blob",
440         FT_BYTES, BASE_HEX, NULL, 0x00,
441         "Unknown blob only present in Transarc packets", HFILL }},
442   };
443   static gint *ett[] = {
444     &ett_krb4,
445     &ett_krb4_auth_msg_type,
446   };
447
448   proto_krb4 = proto_register_protocol("Kerberos v4",
449                                        "KRB4", "krb4");
450   new_register_dissector("krb4", dissect_krb4, proto_krb4);
451   proto_register_field_array(proto_krb4, hf, array_length(hf));
452   proto_register_subtree_array(ett, array_length(ett));
453 }
454
455 void
456 proto_reg_handoff_krb4(void)
457 {
458   dissector_handle_t krb4_handle;
459
460   krb4_handle = new_create_dissector_handle(dissect_krb4, proto_krb4);
461   dissector_add("udp.port", UDP_PORT_KRB4, krb4_handle);
462 }