Document the new Copy Profile button.
[obnox/wireshark/wip.git] / epan / dissectors / packet-rmi.c
1 /* packet-rmi.c
2  * Routines for java rmiregistry dissection
3  * Copyright 2002, Michael Stiller <ms@2scale.net>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
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;
129         guint epid_len;
130
131     offset     = 0;
132     rmitype    = 0;
133
134 /* Make entries in Protocol column and Info column on summary display */
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_set_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_set_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                 epid_len = len < ITEM_LABEL_LENGTH ? len : ITEM_LABEL_LENGTH;
206                 if (epid_len > 0) {
207                         epid_hostname = tvb_format_text(tvb, offset + 3, epid_len);
208                 } else {
209                         epid_hostname = "[Empty]";
210                 }
211                 proto_tree_add_string(rmi_tree, hf_rmi_epid_hostname,
212                                       tvb, offset + 3, len, epid_hostname);
213
214                 port = tvb_get_ntohs(tvb, offset + len + 5);
215                 proto_tree_add_uint(rmi_tree, hf_rmi_epid_port,
216                                     tvb, offset + len + 5, 2, port);
217             }
218             if(message == RMI_INPUTSTREAM_MESSAGE_RETURNDATA) {
219                 proto_tree_add_text(rmi_tree, tvb, offset + 1, -1,
220                                     "Serialization Data");
221                 next_tvb = tvb_new_subset_remaining(tvb, offset + 1);
222                 dissect_ser(next_tvb, tree);
223             }
224             break;
225         case RMI_OUTPUTMESSAGE:
226             message = tvb_get_guint8(tvb, 0);
227             proto_tree_add_uint(rmi_tree, hf_rmi_outputmessage,
228                                   tvb, offset, 1, message);
229             if(message == RMI_OUTPUTSTREAM_MESSAGE_CALL) {
230                 proto_tree_add_text(rmi_tree, tvb, offset + 1, -1,
231                                     "Serialization Data");
232                 /* XXX */
233                 next_tvb = tvb_new_subset_remaining(tvb, offset + 1);
234                 dissect_ser(next_tvb, tree);
235             }
236             if(message == RMI_OUTPUTSTREAM_MESSAGE_DGCACK) {
237                 proto_tree_add_text(rmi_tree, tvb, offset + 1, -1,
238                                     "UniqueIdentifier");
239             }
240             break;
241         case SERIALIZATION_DATA:
242             dissect_ser(tvb, tree);
243             break;
244         default:
245             break;
246         }
247     }
248 }
249
250 static void
251 dissect_ser(tvbuff_t *tvb, proto_tree *tree)
252 {
253     proto_item *ti;
254     proto_tree *ser_tree;
255
256     gint offset;
257
258     offset = 0;
259
260     if(tree) {
261         ti = proto_tree_add_item(tree, proto_ser, tvb, 0, -1, FALSE);
262         ser_tree = proto_item_add_subtree(ti, ett_ser);
263         proto_tree_add_item(ser_tree, hf_ser_magic,
264                             tvb, offset,     2, FALSE);
265         proto_tree_add_item(ser_tree, hf_ser_version,
266                             tvb, offset + 2, 2, FALSE);
267
268     }
269 }
270
271 static rmi_type
272 get_rmi_type(const guchar *data, int datalen)
273 {
274     guint16 ser_magic;
275
276     if (datalen >= 2) {
277         ser_magic = data[0] << 8 | data[1];
278         if (ser_magic == SER_STREAM_MAGIC) {
279             return SERIALIZATION_DATA;
280         }
281     }
282     if (datalen >= 4) {
283         if(strncmp(data, RMI_MAGIC, 4) == 0) {
284             return RMI_OUTPUTSTREAM;
285         }
286     }
287     if (datalen >= 1) {
288         if (data[0] == RMI_INPUTSTREAM_MESSAGE_ACK ||
289             data[0] == RMI_INPUTSTREAM_MESSAGE_NOTSUPPORTED ||
290             data[0] == RMI_INPUTSTREAM_MESSAGE_RETURNDATA ||
291             data[0] == RMI_INPUTSTREAM_MESSAGE_PINGACK) {
292             return RMI_INPUTSTREAM;
293         }
294     }
295     if (datalen >= 1) {
296         if (data[0] == RMI_OUTPUTSTREAM_MESSAGE_CALL ||
297             data[0] == RMI_OUTPUTSTREAM_MESSAGE_PING ||
298             data[0] == RMI_OUTPUTSTREAM_MESSAGE_DGCACK) {
299             return RMI_OUTPUTMESSAGE;
300         }
301     }
302     return CONTINUATION;
303 }
304
305 void
306 proto_register_rmi(void)
307 {
308
309     static hf_register_info hf[] = {
310         { &hf_rmi_magic,
311           { "Magic",   "rmi.magic",
312             FT_UINT32, BASE_HEX, NULL, 0x0,
313             "RMI Header Magic", HFILL }},
314         { &hf_rmi_version,
315           { "Version", "rmi.version",
316             FT_UINT16, BASE_DEC, NULL, 0x0,
317             "RMI Protocol Version", HFILL }},
318         { &hf_rmi_protocol,
319           { "Protocol","rmi.protocol",
320             FT_UINT8, BASE_HEX, VALS(rmi_protocol_str), 0x0,
321             "RMI Protocol Type", HFILL }},
322         { &hf_rmi_inputmessage,
323           { "Input Stream Message", "rmi.inputstream.message",
324             FT_UINT8, BASE_HEX, VALS(rmi_input_message_str), 0x0,
325             "RMI Inputstream Message Token", HFILL }},
326         { &hf_rmi_outputmessage,
327           { "Output Stream Message", "rmi.outputstream.message",
328             FT_UINT8, BASE_HEX, VALS(rmi_output_message_str), 0x0,
329             "RMI Outputstream Message token", HFILL }},
330         { &hf_rmi_epid_length,
331           { "Length", "rmi.endpoint_id.length",
332             FT_UINT16, BASE_DEC, NULL, 0x0,
333             "RMI Endpointidentifier Length", HFILL }},
334         { &hf_rmi_epid_hostname,
335           { "Hostname", "rmi.endpoint_id.hostname",
336             FT_STRING, BASE_NONE, NULL, 0x0,
337             "RMI Endpointidentifier Hostname", HFILL }},
338         { &hf_rmi_epid_port,
339           { "Port", "rmi.endpoint_id.port",
340             FT_UINT16, BASE_DEC, NULL, 0x0,
341             "RMI Endpointindentifier Port", HFILL }},
342
343         { &hf_ser_magic,
344           { "Magic",   "rmi.ser.magic",
345             FT_UINT16, BASE_HEX, NULL, 0x0,
346             "Java Serialization Magic", HFILL }},
347         { &hf_ser_version,
348           { "Version", "rmi.ser.version",
349             FT_UINT16, BASE_DEC, NULL, 0x0,
350             "Java Serialization Version", HFILL }},
351     };
352
353     static gint *ett[] = {
354         &ett_rmi,
355         &ett_rmi_magic,
356         &ett_rmi_version,
357         &ett_rmi_inputmessage,
358         &ett_rmi_outputmessage,
359         &ett_rmi_epid_length,
360         &ett_rmi_epid_hostname,
361         &ett_rmi_epid_port,
362         &ett_ser,
363     };
364
365     proto_rmi = proto_register_protocol("Java RMI", "RMI", "rmi");
366     proto_ser = proto_register_protocol("Java Serialization", "Serialization",
367                                         "serialization");
368     proto_register_field_array(proto_rmi, hf, array_length(hf));
369     proto_register_subtree_array(ett, array_length(ett));
370
371 }
372
373 void
374 proto_reg_handoff_rmi(void)
375 {
376     dissector_handle_t rmi_handle;
377
378     rmi_handle = create_dissector_handle(dissect_rmi, proto_rmi);
379     dissector_add("tcp.port", TCP_PORT_RMI, rmi_handle);
380 }