The function pointer in a "per_choice_t" or a "per_sequence_t" is to a
[obnox/wireshark/wip.git] / packet-rmi.c
1 /* packet-rmi.c
2  * Routines for java rmiregistry dissection
3  * Copyright 2002, Michael Stiller <ms@2scale.net>
4  *
5  * $Id: packet-rmi.c,v 1.9 2003/05/26 21:44:28 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include <glib.h>
35
36 #include <epan/packet.h>
37 #include <epan/strutil.h>
38
39 #include "packet-rmi.h"
40
41 static void
42 dissect_ser(tvbuff_t *tvb, proto_tree *tree);
43
44 static rmi_type
45 get_rmi_type(const guchar *data, int datalen);
46
47 /* Initialize the protocol and registered fields */
48 static int proto_rmi             = -1;
49 static int proto_ser             = -1;
50 static int hf_rmi_magic          = -1;
51 static int hf_rmi_version        = -1;
52 static int hf_rmi_protocol       = -1;
53 static int hf_rmi_inputmessage   = -1;
54 static int hf_rmi_outputmessage  = -1;
55 static int hf_rmi_epid_length    = -1;
56 static int hf_rmi_epid_hostname  = -1;
57 static int hf_rmi_epid_port      = -1;
58
59 static int hf_ser_magic          = -1;
60 static int hf_ser_version        = -1;
61
62 /* Initialize the subtree pointers */
63 static gint ett_rmi               = -1;
64 static gint ett_rmi_magic         = -1;
65 static gint ett_rmi_version       = -1;
66 static gint ett_rmi_inputmessage  = -1;
67 static gint ett_rmi_outputmessage = -1;
68 static gint ett_rmi_epid_length   = -1;
69 static gint ett_rmi_epid_hostname = -1;
70 static gint ett_rmi_epid_port     = -1;
71
72 static gint ett_ser               = -1;
73
74 /*
75  * See
76  *
77  *      http://java.sun.com/products/jdk/1.2/docs/guide/rmi/spec/rmi-protocol.doc1.html
78  *
79  * for RMI, and
80  *
81  *      http://java.sun.com/products/jdk/1.2/docs/guide/serialization/spec/protocol.doc.html
82  *
83  * for the serialization protocol.
84  */
85
86 #define TCP_PORT_RMI    1099
87
88 static const value_string rmi_protocol_str[] = {
89     {RMI_OUTPUTSTREAM_PROTOCOL_STREAM,    "StreamProtocol"},
90     {RMI_OUTPUTSTREAM_PROTOCOL_SINGLEOP,  "SingleOpProtocol"},
91     {RMI_OUTPUTSTREAM_PROTOCOL_MULTIPLEX, "MultiPlexProtocol"},
92     {0, NULL}
93 };
94
95 static const value_string rmi_output_message_str[] = {
96     {RMI_OUTPUTSTREAM_MESSAGE_CALL,       "Call"},
97     {RMI_OUTPUTSTREAM_MESSAGE_PING,       "Ping"},
98     {RMI_OUTPUTSTREAM_MESSAGE_DGCACK,     "DgcAck"},
99     {0, NULL}
100 };
101
102 static const value_string rmi_input_message_str[] = {
103     {RMI_INPUTSTREAM_MESSAGE_ACK,          "ProtocolAck"},
104     {RMI_INPUTSTREAM_MESSAGE_NOTSUPPORTED, "ProtocolNotSupported"},
105     {RMI_INPUTSTREAM_MESSAGE_RETURNDATA,   "ReturnData"},
106     {RMI_INPUTSTREAM_MESSAGE_PINGACK,      "PingAck"},
107     {0, NULL}
108 };
109
110 static void
111 dissect_rmi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
112 {
113     proto_item *ti;
114     proto_tree *rmi_tree;
115
116     tvbuff_t   *next_tvb;
117
118     gint       offset;
119     gint       next_offset;
120     int        datalen;
121     const guchar *data;
122
123     guint16    version, len, port;
124     guint8     message, proto;
125
126     rmi_type   rmitype;
127
128     char epid_hostname[256];
129
130     offset     = 0;
131     rmitype    = 0;
132
133 /* Make entries in Protocol column and Info column on summary display */
134     if (check_col(pinfo->cinfo, COL_PROTOCOL))
135         col_set_str(pinfo->cinfo, COL_PROTOCOL, "RMI");
136
137     datalen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
138     data = tvb_get_ptr(tvb, offset, datalen);
139
140     rmitype = get_rmi_type(data, datalen);
141
142     if (check_col(pinfo->cinfo, COL_INFO)) {
143         switch(rmitype) {
144         case RMI_OUTPUTSTREAM:
145             version = tvb_get_ntohs(tvb,4);
146             col_add_fstr(pinfo->cinfo, COL_INFO,
147                          "JRMI, Version: %d, ", version);
148
149             proto   = tvb_get_guint8(tvb, 6);
150             col_append_str(pinfo->cinfo, COL_INFO,
151                            val_to_str(proto, rmi_protocol_str,
152                                       "Unknown protocol"));
153             break;
154         case RMI_OUTPUTMESSAGE:
155             message = tvb_get_guint8(tvb,0);
156             col_add_str(pinfo->cinfo, COL_INFO,
157                         "JRMI, ");
158             col_append_str(pinfo->cinfo, COL_INFO,
159                            val_to_str(message, rmi_output_message_str,
160                                       "Unknown message"));
161             break;
162         case RMI_INPUTSTREAM:
163             message = tvb_get_guint8(tvb,0);
164             col_add_str(pinfo->cinfo, COL_INFO,
165                         "JRMI, ");
166             col_append_str(pinfo->cinfo, COL_INFO,
167                            val_to_str(message, rmi_input_message_str,
168                                       "Unknown message"));
169             break;
170         case SERIALIZATION_DATA:
171             version = tvb_get_ntohs(tvb,2);
172             col_add_fstr(pinfo->cinfo, COL_INFO,
173                          "Serialization data, Version: %d", version);
174             break;
175         default:
176             col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
177             break;
178         }
179     }
180
181     if (tree) {
182         ti = proto_tree_add_item(tree, proto_rmi, tvb, 0, -1, FALSE);
183         rmi_tree = proto_item_add_subtree(ti, ett_rmi);
184         switch(rmitype) {
185         case RMI_OUTPUTSTREAM:
186             /* XXX - uint, or string? */
187             proto_tree_add_uint(rmi_tree, hf_rmi_magic,
188                                 tvb, offset,     4, tvb_get_ntohl(tvb,0));
189             proto_tree_add_item(rmi_tree, hf_rmi_version,
190                                 tvb, offset + 4, 2, FALSE);
191             proto_tree_add_item(rmi_tree, hf_rmi_protocol,
192                                   tvb, offset + 6, 1, FALSE);
193             break;
194         case RMI_INPUTSTREAM:
195             message = tvb_get_guint8(tvb, 0);
196             proto_tree_add_uint(rmi_tree, hf_rmi_inputmessage,
197                                   tvb, offset, 1, message);
198             if(message == RMI_INPUTSTREAM_MESSAGE_ACK) {
199                 proto_tree_add_text(rmi_tree, tvb, offset + 1, -1,
200                                     "EndPointIdentifier");
201                 /* MESSAGE_ACK should include EndpointIdentifier */
202                 len = tvb_get_ntohs(tvb, 1);
203                 proto_tree_add_uint(rmi_tree, hf_rmi_epid_length,
204                                        tvb, offset + 1, 2, len);
205                 memset(epid_hostname, 0, sizeof(epid_hostname));
206                 if (len < sizeof(epid_hostname)) {
207                     strncpy(epid_hostname,tvb_get_ptr(tvb, offset + 3, len),
208                             sizeof(epid_hostname));
209                 } else {
210                     strncpy(epid_hostname,
211                             "<string too long>", sizeof(epid_hostname));
212                 }
213                 epid_hostname[sizeof(epid_hostname)-1] = '\0';
214                 proto_tree_add_string(rmi_tree, hf_rmi_epid_hostname,
215                                       tvb, offset + 3, strlen(epid_hostname),
216                                       epid_hostname);
217
218                 port = tvb_get_ntohs(tvb, offset + len + 5);
219                 proto_tree_add_uint(rmi_tree, hf_rmi_epid_port,
220                                     tvb, offset + len + 5, 2, port);
221             }
222             if(message == RMI_INPUTSTREAM_MESSAGE_RETURNDATA) {
223                 proto_tree_add_text(rmi_tree, tvb, offset + 1, -1,
224                                     "Serialization Data");
225                 next_tvb = tvb_new_subset(tvb, offset + 1, -1, -1);
226                 dissect_ser(next_tvb, tree);
227             }
228             break;
229         case RMI_OUTPUTMESSAGE:
230             message = tvb_get_guint8(tvb, 0);
231             proto_tree_add_uint(rmi_tree, hf_rmi_outputmessage,
232                                   tvb, offset, 1, message);
233             if(message == RMI_OUTPUTSTREAM_MESSAGE_CALL) {
234                 proto_tree_add_text(rmi_tree, tvb, offset + 1, -1,
235                                     "Serialization Data");
236                 /* XXX */
237                 next_tvb = tvb_new_subset(tvb, offset + 1, -1, -1);
238                 dissect_ser(next_tvb, tree);
239             }
240             if(message == RMI_OUTPUTSTREAM_MESSAGE_DGCACK) {
241                 proto_tree_add_text(rmi_tree, tvb, offset + 1, -1,
242                                     "UniqueIdentifier");
243             }
244             break;
245         case SERIALIZATION_DATA:
246             dissect_ser(tvb, tree);
247             break;
248         default:
249             break;
250         }
251     }
252 }
253
254 static void
255 dissect_ser(tvbuff_t *tvb, proto_tree *tree)
256 {
257     proto_item *ti;
258     proto_tree *ser_tree;
259
260     gint offset;
261
262     offset = 0;
263
264     if(tree) {
265         ti = proto_tree_add_item(tree, proto_ser, tvb, 0, -1, FALSE);
266         ser_tree = proto_item_add_subtree(ti, ett_ser);
267         proto_tree_add_item(ser_tree, hf_ser_magic,
268                             tvb, offset,     2, FALSE);
269         proto_tree_add_item(ser_tree, hf_ser_version,
270                             tvb, offset + 2, 2, FALSE);
271
272     }
273 }
274
275 static rmi_type
276 get_rmi_type(const guchar *data, int datalen)
277 {
278     guint16 ser_magic;
279
280     if (datalen >= 2) {
281         ser_magic = data[0] << 8 | data[1];
282         if (ser_magic == SER_STREAM_MAGIC) {
283             return SERIALIZATION_DATA;
284         }
285     }
286     if (datalen >= 4) {
287         if(strncmp(data, RMI_MAGIC, 4) == 0) {
288             return RMI_OUTPUTSTREAM;
289         }
290     }
291     if (datalen >= 1) {
292         if (data[0] == RMI_INPUTSTREAM_MESSAGE_ACK ||
293             data[0] == RMI_INPUTSTREAM_MESSAGE_NOTSUPPORTED ||
294             data[0] == RMI_INPUTSTREAM_MESSAGE_RETURNDATA ||
295             data[0] == RMI_INPUTSTREAM_MESSAGE_PINGACK) {
296             return RMI_INPUTSTREAM;
297         }
298     }
299     if (datalen >= 1) {
300         if (data[0] == RMI_OUTPUTSTREAM_MESSAGE_CALL ||
301             data[0] == RMI_OUTPUTSTREAM_MESSAGE_PING ||
302             data[0] == RMI_OUTPUTSTREAM_MESSAGE_DGCACK) {
303             return RMI_OUTPUTMESSAGE;
304         }
305     }
306     return CONTINUATION;
307 }
308
309 void
310 proto_register_rmi(void)
311 {
312
313     static hf_register_info hf[] = {
314         { &hf_rmi_magic,
315           { "Magic",   "rmi.magic",
316             FT_UINT32, BASE_HEX, NULL, 0x0,
317             "RMI Header Magic", HFILL }},
318         { &hf_rmi_version,
319           { "Version", "rmi.version",
320             FT_UINT16, BASE_DEC, NULL, 0x0,
321             "RMI Protocol Version", HFILL }},
322         { &hf_rmi_protocol,
323           { "Protocol","rmi.protocol",
324             FT_UINT8, BASE_HEX, VALS(rmi_protocol_str), 0x0,
325             "RMI Protocol Type", HFILL }},
326         { &hf_rmi_inputmessage,
327           { "Input Stream Message", "rmi.inputstream.message",
328             FT_UINT8, BASE_HEX, VALS(rmi_input_message_str), 0x0,
329             "RMI Inputstream Message Token", HFILL }},
330         { &hf_rmi_outputmessage,
331           { "Output Stream Message", "rmi.outputstream.message",
332             FT_UINT8, BASE_HEX, VALS(rmi_output_message_str), 0x0,
333             "RMI Outputstream Message token", HFILL }},
334         { &hf_rmi_epid_length,
335           { "Length", "rmi.endpoint_id.length",
336             FT_UINT16, BASE_DEC, NULL, 0x0,
337             "RMI Endpointidentifier Length", HFILL }},
338         { &hf_rmi_epid_hostname,
339           { "Hostname", "rmi.endpoint_id.hostname",
340             FT_STRING, BASE_HEX, NULL, 0x0,
341             "RMI Endpointidentifier Hostname", HFILL }},
342         { &hf_rmi_epid_port,
343           { "Port", "rmi.endpoint_id.port",
344             FT_UINT16, BASE_DEC, NULL, 0x0,
345             "RMI Endpointindentifier Port", HFILL }},
346
347         { &hf_ser_magic,
348           { "Magic",   "rmi.ser.magic",
349             FT_UINT16, BASE_HEX, NULL, 0x0,
350             "Java Serialization Magic", HFILL }},
351         { &hf_ser_version,
352           { "Version", "rmi.ser.version",
353             FT_UINT16, BASE_DEC, NULL, 0x0,
354             "Java Serialization Version", HFILL }},
355     };
356
357     static gint *ett[] = {
358         &ett_rmi,
359         &ett_rmi_magic,
360         &ett_rmi_version,
361         &ett_rmi_inputmessage,
362         &ett_rmi_outputmessage,
363         &ett_rmi_epid_length,
364         &ett_rmi_epid_hostname,
365         &ett_rmi_epid_port,
366         &ett_ser,
367     };
368
369     proto_rmi = proto_register_protocol("Java RMI", "RMI", "rmi");
370     proto_ser = proto_register_protocol("Java Serialization", "Serialization",
371                                         "serialization");
372     proto_register_field_array(proto_rmi, hf, array_length(hf));
373     proto_register_subtree_array(ett, array_length(ett));
374
375 }
376
377 void
378 proto_reg_handoff_rmi(void)
379 {
380     dissector_handle_t rmi_handle;
381
382     rmi_handle = create_dissector_handle(dissect_rmi, proto_rmi);
383     dissector_add("tcp.port", TCP_PORT_RMI, rmi_handle);
384 }