Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-sapigs.c
blob958ebb80ed360fc7e85ca21d61e21bf9061f73a7
1 /* packet-sapigs.c
2 * Routines for SAP IGS (Internet Graphics Server) dissection
3 * Copyright 2022, Yvan Genuer (@iggy38), Devoteam
4 * Copyright 2022, Martin Gallo <martin.gallo [AT] gmail.com>
5 * Code contributed by SecureAuth Corp.
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * SPDX-License-Identifier: GPL-2.0-or-later
15 * This is a simple dissector for the IGS protocol, initially added by Yvan Genuer as part of their research around the protocol:
16 * https://www.troopers.de/troopers18/agenda/3r38lr/. Some details and example requests can be found in pysap's documentation:
17 * https://pysap.readthedocs.io/en/latest/protocols/SAPIGS.html
20 #include <config.h>
21 #include <inttypes.h>
22 #include <stdlib.h>
24 #include <epan/packet.h>
25 #include <epan/prefs.h>
26 #include <epan/expert.h>
27 #include <wsutil/strtoi.h>
28 #include <wsutil/wmem/wmem.h>
31 * Define default ports. The right range should be 4NNNN, but as port numbers are proprietary and not
32 * IANA assigned, we leave only the ones corresponding to the instance 00.
34 #define SAPIGS_PORT_RANGE "40000"
36 /* IGS Functions values */
37 static const value_string sapigs_function_lst[] = {
38 { 1, "ADM:REGPW"}, /* Register a PortWatcher */
39 { 2, "ADM:UNREGPW"}, /* Unregister a PortWatcher */
40 { 3, "ADM:REGIP"}, /* Register an Interpreter */
41 { 4, "ADM:UNREGIP"}, /* Unregister an Interpreter */
42 { 5, "ADM:FREEIP"}, /* Inform than Interpreter is free */
43 { 6, "ADM:ILLBEBACK"}, /* Call back function */
44 { 7, "ADM:ABORT"}, /* Abort Interpreter work */
45 { 8, "ADM:PING"}, /* Ping receive */
46 { 9, "ADM:PONG"}, /* Ping send */
47 { 10, "ADM:SHUTDOWNIGS"}, /* Shutdown IGS */
48 { 11, "ADM:SHUTDOWNPW"}, /* Shutdown PortWatcher */
49 { 12, "ADM:CHECKCONSUMER"}, /* Check Portwatcher status */
50 { 13, "ADM:FREECONSUMER"}, /* Inform than portwather is free */
51 { 14, "ADM:GETLOGFILE"}, /* Display log file */
52 { 15, "ADM:GETCONFIGFILE"}, /* Display configfile */
53 { 16, "ADM:GETDUMP"}, /* Display dump file */
54 { 17, "ADM:DELETEDUMP"}, /* Delete dump file */
55 { 18, "ADM:INSTALL"}, /* Upload shapefiles for GIS */
56 { 19, "ADM:SWITCH"}, /* Switch trace log level */
57 { 20, "ADM:GETVERSION"}, /* Get IGS Version */
58 { 21, "ADM:STATUS"}, /* Display IGS Status */
59 { 22, "ADM:STATISTIC"}, /* old Display IGS Statistic */
60 { 23, "ADM:STATISTICNEW"}, /* Display IGS Statistic */
61 { 24, "ADM:GETSTATCHART"}, /* Get IGS Statistic chart */
62 { 25, "ADM:SIM"}, /* Simulation function */
63 { 30, "ZIPPER"}, /* ZIP provide file(s) */
64 { 31, "IMGCONV"}, /* Image converter */
65 { 32, "RSPOCONNECTOR"}, /* Remote Spool Connector */
66 { 33, "XMLCHART"}, /* Chart generator through xml input */
67 { 34, "CHART"}, /* Chart generator through ABAP Table input */
68 { 35, "BWGIS"}, /* BW Geographic Information System */
69 { 36, "SAPGISXML"}, /* old SAP GIS through xml input */
70 /* NULL */
71 { 0, NULL}
74 static int proto_sapigs;
76 /* Headers */
77 static int hf_sapigs_function;
78 static int hf_sapigs_listener;
79 static int hf_sapigs_hostname;
80 static int hf_sapigs_id;
81 static int hf_sapigs_padd1;
82 static int hf_sapigs_flag1;
83 static int hf_sapigs_padd2;
84 static int hf_sapigs_flag2;
85 static int hf_sapigs_padd3;
87 /* Data */
88 static int hf_sapigs_eye_catcher;
89 static int hf_sapigs_padd4;
90 static int hf_sapigs_codepage;
91 static int hf_sapigs_offset_data;
92 static int hf_sapigs_data_size;
93 static int hf_sapigs_data;
95 /* Table definition */
96 static int hf_sapigs_tables;
97 static int hf_sapigs_table_version;
98 static int hf_sapigs_table_name;
99 static int hf_sapigs_table_line_number;
100 static int hf_sapigs_table_width;
101 static int hf_sapigs_table_column_name;
102 static int hf_sapigs_table_column_number;
103 static int hf_sapigs_table_column_width;
105 /* Others */
106 static int hf_sapigs_portwatcher;
107 static int hf_sapigs_portwatcher_version;
108 static int hf_sapigs_portwatcher_info;
109 static int hf_sapigs_interpreter;
110 static int hf_sapigs_chart_config;
112 static int ett_sapigs;
114 /* Global port preference */
115 static range_t *global_sapigs_port_range;
117 /* Global highlight preference */
118 static bool global_sapigs_highlight_items = true;
120 /* Protocol handle */
121 static dissector_handle_t sapigs_handle;
123 void proto_reg_handoff_sapigs(void);
124 void proto_register_sapigs(void);
127 static int
128 dissect_sapigs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
130 uint32_t offset = 0, err_val = 0;
131 int data_offset = 0, data_length = 0;
132 char *sapigs_info_function = NULL, *illbeback_type = NULL, *is_table = NULL;
133 proto_item *ti = NULL, *sapigs_tables = NULL;
134 proto_tree *sapigs_tree = NULL, *sapigs_tables_tree = NULL;
136 /* Add the protocol to the column */
137 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SAPIGS");
138 /* Add function name in the info column */
139 col_add_fstr(pinfo->cinfo, COL_INFO, " function: %s", tvb_get_string_enc(pinfo->pool, tvb, 0, 32, ENC_ASCII));
141 /* Add the main sapigs subtree */
142 ti = proto_tree_add_item(tree, proto_sapigs, tvb, 0, -1, ENC_NA);
143 sapigs_tree = proto_item_add_subtree(ti, ett_sapigs);
145 /* Retrieve function name */
146 sapigs_info_function = (char *)tvb_get_string_enc(pinfo->pool, tvb, offset, 32, ENC_ASCII);
148 /* Headers */
149 proto_tree_add_item(sapigs_tree, hf_sapigs_function, tvb, offset, 32, ENC_ASCII|ENC_NA);
150 offset += 32;
151 proto_tree_add_item(sapigs_tree, hf_sapigs_listener, tvb, offset, 32, ENC_ASCII|ENC_NA);
152 offset += 32;
153 proto_tree_add_item(sapigs_tree, hf_sapigs_hostname, tvb, offset, 81, ENC_ASCII|ENC_NA);
154 offset += 81;
155 proto_tree_add_item(sapigs_tree, hf_sapigs_id, tvb, offset, 4, ENC_ASCII|ENC_NA);
156 offset += 4;
157 proto_tree_add_item(sapigs_tree, hf_sapigs_padd1, tvb, offset, 15, ENC_ASCII);
158 offset += 15;
159 proto_tree_add_item(sapigs_tree, hf_sapigs_flag1, tvb, offset, 1, ENC_ASCII);
160 offset += 1;
161 proto_tree_add_item(sapigs_tree, hf_sapigs_padd2, tvb, offset, 20, ENC_ASCII);
162 offset += 20;
163 proto_tree_add_item(sapigs_tree, hf_sapigs_flag2, tvb, offset, 1, ENC_ASCII);
164 offset += 1;
165 proto_tree_add_item(sapigs_tree, hf_sapigs_padd3, tvb, offset, 6, ENC_ASCII);
166 offset += 6;
168 /* switch over function name value */
169 switch (str_to_val(sapigs_info_function, sapigs_function_lst, err_val)){
170 case 8:{ /* ADM:PING */
171 proto_tree_add_item(sapigs_tree, hf_sapigs_portwatcher, tvb, offset, 5, ENC_ASCII|ENC_NA);
172 break;
174 case 9:{ /* ADM:PONG */
175 break;
177 case 1:{ /* ADM:REGPW */
178 proto_tree_add_item(sapigs_tree, hf_sapigs_portwatcher, tvb, offset, 5, ENC_ASCII|ENC_NA);
179 offset += 32;
180 proto_tree_add_item(sapigs_tree, hf_sapigs_portwatcher_version, tvb, offset, 16, ENC_ASCII|ENC_NA);
181 break;
183 case 3: /* ADM:REGIP */
184 case 5:{ /* ADM:FREEIP */
185 proto_tree_add_item(sapigs_tree, hf_sapigs_portwatcher, tvb, offset, 5, ENC_ASCII|ENC_NA);
186 offset += 32;
187 proto_tree_add_item(sapigs_tree, hf_sapigs_interpreter, tvb, offset, 16, ENC_ASCII|ENC_NA);
188 offset += 32;
189 proto_tree_add_item(sapigs_tree, hf_sapigs_portwatcher_version, tvb, offset, 16, ENC_ASCII|ENC_NA);
190 offset += 32;
191 proto_tree_add_item(sapigs_tree, hf_sapigs_portwatcher_info, tvb, offset, 16, ENC_ASCII|ENC_NA);
192 break;
194 case 6:{ /* ADM:ILLBEBACK */
195 illbeback_type = (char *)tvb_get_string_enc(pinfo->pool, tvb, offset, 10, ENC_ASCII|ENC_NA);
196 if (strncmp("TransMagic", illbeback_type, 10) == 0){
197 /* data is raw after eye_catcher */
198 proto_tree_add_item(sapigs_tree, hf_sapigs_eye_catcher, tvb, offset, 10, ENC_ASCII|ENC_NA);
199 offset += 16;
200 proto_tree_add_item(sapigs_tree, hf_sapigs_data, tvb, offset, -1, ENC_NA);
201 } else {
202 /* we receive sized data */
203 ws_strtoi((char *)tvb_get_string_enc(pinfo->pool, tvb, offset, 5, ENC_ASCII), NULL, &data_length);
204 proto_tree_add_item(sapigs_tree, hf_sapigs_data_size, tvb, offset, 5, ENC_ASCII|ENC_NA);
205 offset += 5;
206 /* Data */
207 if ((data_length > 0) && (tvb_reported_length_remaining(tvb, offset) >= data_length)) {
208 proto_tree_add_item(sapigs_tree, hf_sapigs_data, tvb, offset, data_length, ENC_NA);
211 break;
213 case 30: /* ZIPPER */
214 case 31: /* IMGCONV */
215 case 33: /* XMLCHART */
216 case 16:{ /* ADM:GETDUMP */
217 proto_tree_add_item(sapigs_tree, hf_sapigs_eye_catcher, tvb, offset, 10, ENC_ASCII|ENC_NA);
218 offset += 10;
219 proto_tree_add_item(sapigs_tree, hf_sapigs_padd4, tvb, offset, 2, ENC_ASCII);
220 offset += 2;
221 proto_tree_add_item(sapigs_tree, hf_sapigs_codepage, tvb, offset, 4, ENC_ASCII|ENC_NA);
222 offset += 4;
223 /* Data offset */
224 ws_strtoi((char *)tvb_get_string_enc(pinfo->pool, tvb, offset, 16, ENC_ASCII), NULL, &data_offset);
225 proto_tree_add_item(sapigs_tree, hf_sapigs_offset_data, tvb, offset, 16, ENC_ASCII|ENC_NA);
226 offset += 16;
227 /* Data length */
228 ws_strtoi((char *)tvb_get_string_enc(pinfo->pool, tvb, offset, 16, ENC_ASCII), NULL, &data_length);
229 proto_tree_add_item(sapigs_tree, hf_sapigs_data_size, tvb, offset, 16, ENC_ASCII|ENC_NA);
230 offset += 16;
231 data_offset += offset;
232 /* Definition tables */
233 is_table = (char *)tvb_get_string_enc(pinfo->pool, tvb, offset, 4, ENC_ASCII);
234 /* if the 4 next char is VERS, we are at the beginning of one definition table */
235 while(strncmp("VERS", is_table, 4) == 0){
236 /* Build a tree for Tables */
237 sapigs_tables = proto_tree_add_item(sapigs_tree, hf_sapigs_tables, tvb, offset, 336, ENC_NA);
238 sapigs_tables_tree = proto_item_add_subtree(sapigs_tables, ett_sapigs);
239 proto_tree_add_item(sapigs_tables_tree, hf_sapigs_table_version, tvb, offset+8, 40, ENC_ASCII);
240 offset += 48;
241 proto_tree_add_item(sapigs_tables_tree, hf_sapigs_table_name, tvb, offset+8, 40, ENC_ASCII);
242 offset += 48;
243 proto_tree_add_item(sapigs_tables_tree, hf_sapigs_table_line_number, tvb, offset+8, 40, ENC_ASCII);
244 offset += 48;
245 proto_tree_add_item(sapigs_tables_tree, hf_sapigs_table_width, tvb, offset+8, 40, ENC_ASCII);
246 offset += 48;
247 proto_tree_add_item(sapigs_tables_tree, hf_sapigs_table_column_name, tvb, offset+8, 40, ENC_ASCII);
248 offset += 48;
249 proto_tree_add_item(sapigs_tables_tree, hf_sapigs_table_column_number, tvb, offset+8, 40, ENC_ASCII);
250 offset += 48;
251 proto_tree_add_item(sapigs_tables_tree, hf_sapigs_table_column_width, tvb, offset+8, 40, ENC_ASCII);
252 offset += 48;
253 is_table = (char *)tvb_get_string_enc(pinfo->pool, tvb, offset, 4, ENC_ASCII);
255 /* Data */
256 if ((data_length > 0) && (tvb_reported_length_remaining(tvb, offset) >= data_length)) {
257 proto_tree_add_item(sapigs_tree, hf_sapigs_data, tvb, data_offset, data_length, ENC_NA);
259 break;
261 case 34:{ /* CHART */
262 proto_tree_add_item(sapigs_tree, hf_sapigs_chart_config, tvb, offset, 32, ENC_ASCII|ENC_NA);
263 offset += 32;
264 proto_tree_add_item(sapigs_tree, hf_sapigs_data, tvb, offset, -1, ENC_NA);
265 break;
269 return tvb_reported_length(tvb);
273 void
274 proto_register_sapigs(void)
276 static hf_register_info hf[] = {
277 /* General Header fields */
278 { &hf_sapigs_function,
279 { "Function", "sapigs.function", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
280 { &hf_sapigs_listener,
281 { "Listener", "sapigs.listener", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
282 { &hf_sapigs_hostname,
283 { "Hostname", "sapigs.hostname", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
284 { &hf_sapigs_id,
285 { "Id", "sapigs.id", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
286 { &hf_sapigs_padd1,
287 { "Padd1", "sapigs.padd1", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
288 { &hf_sapigs_flag1,
289 { "Flag1", "sapigs.flag1", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
290 { &hf_sapigs_padd2,
291 { "Padd2", "sapigs.padd2", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
292 { &hf_sapigs_flag2,
293 { "Flag2", "sapigs.flag2", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
294 { &hf_sapigs_padd3,
295 { "Padd3", "sapigs.padd3", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
297 /* Data headers */
298 { &hf_sapigs_eye_catcher,
299 { "Eye catcher", "sapigs.eye_catcher", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
300 { &hf_sapigs_padd4,
301 { "Padd4", "sapigs.padd4", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
302 { &hf_sapigs_codepage,
303 { "Codepage", "sapigs.codepage", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
304 { &hf_sapigs_offset_data,
305 { "Offset to data", "sapigs.offset_data", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
306 { &hf_sapigs_data_size,
307 { "Data size", "sapigs.data_size", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
309 /* Portwatcher fields */
310 { &hf_sapigs_portwatcher,
311 { "Portwatcher Port", "sapigs.portwatcher", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
312 { &hf_sapigs_portwatcher_version,
313 { "Portwatcher version", "sapigs.portwatcher_version", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
314 { &hf_sapigs_portwatcher_info,
315 { "Portwatcher Info", "sapigs.portwatcher_info", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
317 /* Interpreter information */
318 { &hf_sapigs_interpreter,
319 { "Interpreter name", "sapigs.interpreter", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
320 { &hf_sapigs_chart_config,
321 { "Chart configuration", "sapigs.chart_config", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
323 /* Table definition fields */
324 { &hf_sapigs_tables,
325 { "Table definition", "sapigs.tables", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
326 { &hf_sapigs_table_version,
327 { "VERS", "sapigs.table_version", FT_STRING, BASE_NONE, NULL, 0x0, "Table version", HFILL }},
328 { &hf_sapigs_table_name,
329 { "TBNM", "sapigs.table_name", FT_STRING, BASE_NONE, NULL, 0x0, "Table name", HFILL }},
330 { &hf_sapigs_table_line_number,
331 { "TBLN", "sapigs.table_line_number", FT_STRING, BASE_NONE, NULL, 0x0, "Line count", HFILL }},
332 { &hf_sapigs_table_width,
333 { "TBWD", "sapigs.table_width", FT_STRING, BASE_NONE, NULL, 0x0, "Table width", HFILL }},
334 { &hf_sapigs_table_column_name,
335 { "TBCL", "sapigs.table_column_name", FT_STRING, BASE_NONE, NULL, 0x0, "Table column name", HFILL }},
336 { &hf_sapigs_table_column_number,
337 { "CLNM", "sapigs.table_column_number", FT_STRING, BASE_NONE, NULL, 0x0, "Column count", HFILL }},
338 { &hf_sapigs_table_column_width,
339 { "CLWD", "sapigs.table_column_width", FT_STRING, BASE_NONE, NULL, 0x0, "Column width", HFILL }},
341 /* Data */
342 { &hf_sapigs_data,
343 { "Data", "sapigs.table_data", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}
346 /* Setup protocol subtre array */
347 static int *ett[] = {
348 &ett_sapigs
351 module_t *sapigs_module;
353 /* Register the protocol */
354 proto_sapigs = proto_register_protocol("SAP Internet Graphic Server", "SAPIGS", "sapigs");
356 register_dissector("sapigs", dissect_sapigs, proto_sapigs);
358 proto_register_field_array(proto_sapigs, hf, array_length(hf));
359 proto_register_subtree_array(ett, array_length(ett));
361 /* Register the preferences */
362 sapigs_module = prefs_register_protocol(proto_sapigs, proto_reg_handoff_sapigs);
364 range_convert_str(wmem_epan_scope(), &global_sapigs_port_range, SAPIGS_PORT_RANGE, MAX_TCP_PORT);
365 prefs_register_range_preference(sapigs_module, "tcp_ports", "SAP IGS Protocol TCP port numbers", "Port numbers used for SAP IGS Protocol (default "SAPIGS_PORT_RANGE ")", &global_sapigs_port_range, MAX_TCP_PORT);
367 prefs_register_bool_preference(sapigs_module, "highlight_unknow_items", "Highlight unknown SAP IGS messages", "Whether the SAP IGS Protocol dissector should highlight unknown IGS messages", &global_sapigs_highlight_items);
372 * Helpers for dealing with the port range
374 static void range_delete_callback (uint32_t port, void *ptr _U_)
376 dissector_delete_uint("sapni.port", port, sapigs_handle);
379 static void range_add_callback (uint32_t port, void *ptr _U_)
381 dissector_add_uint("sapni.port", port, sapigs_handle);
385 * Register Hand off for the SAP IGS Protocol
387 void
388 proto_reg_handoff_sapigs(void)
390 static range_t *sapigs_port_range;
391 static bool initialized = false;
393 if (!initialized) {
394 sapigs_handle = create_dissector_handle(dissect_sapigs, proto_sapigs);
395 initialized = true;
396 } else {
397 range_foreach(sapigs_port_range, range_delete_callback, NULL);
398 wmem_free(wmem_epan_scope(), sapigs_port_range);
401 sapigs_port_range = range_copy(wmem_epan_scope(), global_sapigs_port_range);
402 range_foreach(sapigs_port_range, range_add_callback, NULL);
406 * Editor modelines - https://www.wireshark.org/tools/modelines.html
408 * Local variables:
409 * c-basic-offset: 8
410 * tab-width: 8
411 * indent-tabs-mode: t
412 * End:
414 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
415 * :indentSize=8:tabSize=8:noTabs=false: