1 /* packet-imf.c
2 * Routines for Internet Message Format (IMF) packet disassembly
3 *
4 * Copyright (c) 2007 by Graeme Lunt
5 *
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1999 Gerald Combs
9 *
10 * SPDX-License-Identifier: GPL-2.0-or-later
11 */
12
13 #include "config.h"
14
15 #include <epan/packet.h>
16 #include <epan/prefs.h>
17 #include <epan/uat.h>
18 #include <epan/expert.h>
19 #include <wsutil/str_util.h>
20
21 #include <epan/tap.h>
22 #include <epan/export_object.h>
23
24 #include "packet-ber.h"
25 #include "packet-http.h"
26 #include "packet-imf.h"
27 #include "packet-ess.h"
28 #include "packet-p1.h"
29
30 void proto_register_imf(void);
31 void proto_reg_handoff_imf(void);
32
33 static int imf_eo_tap = -1;
34
35 #define PNAME "Internet Message Format"
36 #define PSNAME "IMF"
37 #define PFNAME "imf"
38
39 static int proto_imf = -1;
40
41 static int hf_imf_date = -1;
42 static int hf_imf_from = -1;
43 static int hf_imf_sender = -1;
44 static int hf_imf_reply_to = -1;
45 static int hf_imf_to = -1;
46 static int hf_imf_cc = -1;
47 static int hf_imf_bcc = -1;
48 static int hf_imf_message_id = -1;
49 static int hf_imf_in_reply_to = -1;
50 static int hf_imf_references = -1;
51 static int hf_imf_subject = -1;
52 static int hf_imf_comments = -1;
53 static int hf_imf_user_agent = -1;
54 static int hf_imf_keywords = -1;
55 static int hf_imf_resent_date = -1;
56 static int hf_imf_resent_from = -1;
57 static int hf_imf_resent_sender = -1;
58 static int hf_imf_resent_to = -1;
59 static int hf_imf_resent_cc = -1;
60 static int hf_imf_resent_bcc = -1;
61 static int hf_imf_resent_message_id = -1;
62 static int hf_imf_return_path = -1;
63 static int hf_imf_received = -1;
64 static int hf_imf_content_type = -1;
65 static int hf_imf_content_type_type = -1;
66 static int hf_imf_content_type_parameters = -1;
67 static int hf_imf_content_id = -1;
68 static int hf_imf_content_transfer_encoding = -1;
69 static int hf_imf_content_description = -1;
70 static int hf_imf_mime_version = -1;
71 static int hf_imf_thread_index = -1;
72 static int hf_imf_ext_mailer = -1;
73 static int hf_imf_ext_mimeole = -1;
74 static int hf_imf_ext_tnef_correlator = -1;
75 static int hf_imf_ext_expiry_date = -1;
76 static int hf_imf_ext_uidl = -1;
77 static int hf_imf_ext_authentication_warning = -1;
78 static int hf_imf_ext_virus_scanned = -1;
79 static int hf_imf_extension = -1;
80 static int hf_imf_extension_type = -1;
81 static int hf_imf_extension_value = -1;
82
83 /* RFC 2156 */
84 static int hf_imf_autoforwarded = -1;
85 static int hf_imf_autosubmitted = -1;
86 static int hf_imf_x400_content_identifier = -1;
87 static int hf_imf_content_language = -1;
88 static int hf_imf_conversion = -1;
89 static int hf_imf_conversion_with_loss = -1;
90 static int hf_imf_delivery_date = -1;
91 static int hf_imf_discarded_x400_ipms_extensions = -1;
92 static int hf_imf_discarded_x400_mts_extensions = -1;
93 static int hf_imf_dl_expansion_history = -1;
94 static int hf_imf_deferred_delivery = -1;
95 static int hf_imf_expires = -1;
96 static int hf_imf_importance = -1;
97 static int hf_imf_incomplete_copy = -1;
98 static int hf_imf_latest_delivery_time = -1;
99 static int hf_imf_message_type = -1;
100 static int hf_imf_original_encoded_information_types = -1;
101 static int hf_imf_originator_return_address = -1;
102 static int hf_imf_priority = -1;
103 static int hf_imf_reply_by = -1;
104 static int hf_imf_sensitivity = -1;
105 static int hf_imf_supersedes = -1;
106 static int hf_imf_x400_content_type = -1;
107 static int hf_imf_x400_mts_identifier = -1;
108 static int hf_imf_x400_originator = -1;
109 static int hf_imf_x400_received = -1;
110 static int hf_imf_x400_recipients = -1;
111
112 static int hf_imf_delivered_to = -1;
113
114 static int hf_imf_message_text = -1;
115
116 static int hf_imf_display_name = -1;
117 static int hf_imf_address = -1;
118 /* static int hf_imf_mailbox_list = -1; */
119 static int hf_imf_mailbox_list_item = -1;
120 /* static int hf_imf_address_list = -1; */
121 static int hf_imf_address_list_item = -1;
122
123 /* draft-zeilenga-email-seclabel-04 */
124 static int hf_imf_siolabel = -1;
dissect_igap(tvbuff_t * tvb,packet_info * pinfo,proto_tree * parent_tree,void * data _U_)125 static int hf_imf_siolabel_marking = -1;
126 static int hf_imf_siolabel_fgcolor = -1;
127 static int hf_imf_siolabel_bgcolor = -1;
128 static int hf_imf_siolabel_type = -1;
129 static int hf_imf_siolabel_label = -1;
130 static int hf_imf_siolabel_unknown = -1;
131
132 static int ett_imf = -1;
133 static int ett_imf_content_type = -1;
134 static int ett_imf_mailbox = -1;
135 static int ett_imf_group = -1;
136 static int ett_imf_mailbox_list = -1;
137 static int ett_imf_address_list = -1;
138 static int ett_imf_siolabel = -1;
139 static int ett_imf_extension = -1;
140 static int ett_imf_message_text = -1;
141
142 static dissector_handle_t imf_handle;
143
144 static expert_field ei_imf_unknown_param = EI_INIT;
145
146 /* Used for IMF Export Object feature */
147 typedef struct _imf_eo_t {
148 gchar *filename;
149 gchar *sender_data;
150 gchar *subject_data;
151 guint32 payload_len;
152 gchar *payload_data;
153 } imf_eo_t;
154
155 static tap_packet_status
156 imf_eo_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data)
157 {
158 export_object_list_t *object_list = (export_object_list_t *)tapdata;
159 const imf_eo_t *eo_info = (const imf_eo_t *)data;
160 export_object_entry_t *entry;
161
162 if(eo_info) { /* We have data waiting for us */
163 /* These values will be freed when the Export Object window
164 * is closed. */
165 entry = g_new(export_object_entry_t, 1);
166
167 gchar *start = g_strrstr_len(eo_info->sender_data, -1, "<");
168 gchar *stop = g_strrstr_len(eo_info->sender_data, -1, ">");
169 /* Only include the string inside of the "<>" brackets. If there is nothing between
170 the two brackets use the sender_data string */
171 if(start && stop && stop > start && (stop - start) > 2){
172 entry->hostname = g_strdup_printf("%.*s", (int) (stop - start - 1), start + 1);
173 } else {
174 entry->hostname = g_strdup(eo_info->sender_data);
175 }
176
177 entry->pkt_num = pinfo->num;
178 entry->content_type = g_strdup("EML file");
179 entry->filename = g_strdup_printf("%s.eml", eo_info->subject_data);
180 entry->payload_len = eo_info->payload_len;
181 entry->payload_data = (guint8 *)g_memdup2(eo_info->payload_data, eo_info->payload_len);
182
183 object_list->add_entry(object_list->gui_data, entry);
184
185 return TAP_PACKET_REDRAW; /* State changed - window should be redrawn */
186 } else {
187 return TAP_PACKET_DONT_REDRAW; /* State unchanged - no window updates needed */
188 }
189 }
190
191
192 struct imf_field {
193 char *name; /* field name - in lower case for matching purposes */
194 int *hf_id; /* wireshark field */
195 void (*subdissector)(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo);
196 gboolean add_to_col_info; /* add field to column info */
197 };
198
199 #define NO_SUBDISSECTION NULL
200
201 static void dissect_imf_mailbox(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo);
202 static void dissect_imf_address(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo);
203 static void dissect_imf_address_list(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo);
204 static void dissect_imf_mailbox_list(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo);
205 static void dissect_imf_siolabel(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo);
206
207 static struct imf_field imf_fields[] = {
208 {"unknown-extension", &hf_imf_extension_type, NO_SUBDISSECTION, FALSE}, /* unknown extension */
209 {"date", &hf_imf_date, NO_SUBDISSECTION, FALSE}, /* date-time */
210 {"from", &hf_imf_from, dissect_imf_mailbox_list , TRUE}, /* mailbox_list */
211 {"sender", &hf_imf_sender, dissect_imf_mailbox, FALSE}, /* mailbox */
212 {"reply-to", &hf_imf_reply_to, dissect_imf_address_list , FALSE}, /* address_list */
213 {"to", &hf_imf_to, dissect_imf_address_list , FALSE}, /* address_list */
214 {"cc", &hf_imf_cc, dissect_imf_address_list , FALSE}, /* address_list */
215 {"bcc", &hf_imf_bcc, dissect_imf_address_list , FALSE}, /* address_list */
216 {"message-id", &hf_imf_message_id, NO_SUBDISSECTION, FALSE}, /* msg-id */
217 {"in-reply-to", &hf_imf_in_reply_to, NO_SUBDISSECTION, FALSE}, /* msg-id */
218 {"references", &hf_imf_references, NO_SUBDISSECTION, FALSE}, /* msg-id */
219 {"subject", &hf_imf_subject, NO_SUBDISSECTION, TRUE}, /* unstructured */
220 {"comments", &hf_imf_comments, NO_SUBDISSECTION, FALSE}, /* unstructured */
221 {"user-agent", &hf_imf_user_agent, NO_SUBDISSECTION, FALSE}, /* unstructured */
222 {"keywords", &hf_imf_keywords, NULL, FALSE}, /* phrase_list */
223 {"resent-date", &hf_imf_resent_date, NO_SUBDISSECTION, FALSE},
224 {"resent-from", &hf_imf_resent_from, dissect_imf_mailbox_list, FALSE},
225 {"resent-sender", &hf_imf_resent_sender, dissect_imf_mailbox, FALSE},
226 {"resent-to", &hf_imf_resent_to, dissect_imf_address_list, FALSE},
227 {"resent-cc", &hf_imf_resent_cc, dissect_imf_address_list, FALSE},
228 {"resent-bcc", &hf_imf_resent_bcc, dissect_imf_address_list, FALSE},
229 {"resent-message-id", &hf_imf_resent_message_id, NO_SUBDISSECTION, FALSE},
230 {"return-path", &hf_imf_return_path, NULL, FALSE},
proto_register_igap(void)231 {"received", &hf_imf_received, NO_SUBDISSECTION, FALSE},
232 /* these are really multi-part - but we parse them anyway */
233 {"content-type", &hf_imf_content_type, NULL, FALSE}, /* handled separately as a special case */
234 {"content-id", &hf_imf_content_id, NULL, FALSE},
235 {"content-description", &hf_imf_content_description, NULL, FALSE},
236 {"content-transfer-encoding", &hf_imf_content_transfer_encoding, NULL, FALSE},
237 {"mime-version", &hf_imf_mime_version, NO_SUBDISSECTION, FALSE},
238 /* MIXER - RFC 2156 */
239 {"autoforwarded", &hf_imf_autoforwarded, NULL, FALSE},
240 {"autosubmitted", &hf_imf_autosubmitted, NULL, FALSE},
241 {"x400-content-identifier", &hf_imf_x400_content_identifier, NULL, FALSE},
242 {"content-language", &hf_imf_content_language, NULL, FALSE},
243 {"conversion", &hf_imf_conversion, NULL, FALSE},
244 {"conversion-with-loss", &hf_imf_conversion_with_loss, NULL, FALSE},
245 {"delivery-date", &hf_imf_delivery_date, NULL, FALSE},
246 {"discarded-x400-ipms-extensions", &hf_imf_discarded_x400_ipms_extensions, NULL, FALSE},
247 {"discarded-x400-mts-extensions", &hf_imf_discarded_x400_mts_extensions, NULL, FALSE},
248 {"dl-expansion-history", &hf_imf_dl_expansion_history, NULL, FALSE},
249 {"deferred-delivery", &hf_imf_deferred_delivery, NULL, FALSE},
250 {"expires", &hf_imf_expires, NULL, FALSE},
251 {"importance", &hf_imf_importance, NULL, FALSE},
252 {"incomplete-copy", &hf_imf_incomplete_copy, NULL, FALSE},
253 {"latest-delivery-time", &hf_imf_latest_delivery_time, NULL, FALSE},
254 {"message-type", &hf_imf_message_type, NULL, FALSE},
255 {"original-encoded-information-types", &hf_imf_original_encoded_information_types, NULL, FALSE},
256 {"originator-return-address", &hf_imf_originator_return_address, NULL, FALSE},
257 {"priority", &hf_imf_priority, NULL, FALSE},
258 {"reply-by", &hf_imf_reply_by, NULL, FALSE},
259 {"sensitivity", &hf_imf_sensitivity, NULL, FALSE},
260 {"supersedes", &hf_imf_supersedes, NULL, FALSE},
261 {"x400-content-type", &hf_imf_x400_content_type, NULL, FALSE},
262 {"x400-mts-identifier", &hf_imf_x400_mts_identifier, NULL, FALSE},
263 {"x400-originator", &hf_imf_x400_originator, NULL, FALSE},
264 {"x400-received", &hf_imf_x400_received, NULL, FALSE},
265 {"x400-recipients", &hf_imf_x400_recipients, NULL, FALSE},
266 /* delivery */
267 {"delivered-to", &hf_imf_delivered_to, dissect_imf_mailbox, FALSE}, /* mailbox */
268 /* some others */
269 {"x-mailer", &hf_imf_ext_mailer, NO_SUBDISSECTION, FALSE}, /* unstructured */
270 {"thread-index", &hf_imf_thread_index, NO_SUBDISSECTION, FALSE}, /* unstructured */
271 {"x-mimeole", &hf_imf_ext_mimeole, NO_SUBDISSECTION, FALSE}, /* unstructured */
272 {"expiry-date", &hf_imf_ext_expiry_date, NO_SUBDISSECTION, FALSE}, /* unstructured */
273 {"x-ms-tnef-correlator", &hf_imf_ext_tnef_correlator, NO_SUBDISSECTION, FALSE}, /* unstructured */
274 {"x-uidl", &hf_imf_ext_uidl, NO_SUBDISSECTION, FALSE}, /* unstructured */
275 {"x-authentication-warning", &hf_imf_ext_authentication_warning, NO_SUBDISSECTION, FALSE}, /* unstructured */
276 {"x-virus-scanned", &hf_imf_ext_virus_scanned, NO_SUBDISSECTION, FALSE}, /* unstructured */
277 {"sio-label", &hf_imf_siolabel, dissect_imf_siolabel, FALSE}, /* sio-label */
278 {NULL, NULL, NULL, FALSE},
279 };
280
281 static wmem_map_t *imf_field_table=NULL;
282
283 #define FORMAT_UNSTRUCTURED 0
284 #define FORMAT_MAILBOX 1
285 #define FORMAT_ADDRESS 2
286 #define FORMAT_MAILBOX_LIST 3
287 #define FORMAT_ADDRESS_LIST 4
288 #define FORMAT_SIO_LABEL 5
289
290 static const value_string header_format[] = {
291 { FORMAT_UNSTRUCTURED, "Unstructured" },
292 { FORMAT_MAILBOX, "Mailbox" },
293 { FORMAT_ADDRESS, "Address" },
294 { FORMAT_MAILBOX_LIST, "Mailbox List" },
295 { FORMAT_ADDRESS_LIST, "Address List" },
296 { FORMAT_SIO_LABEL, "SIO-Label" },
297 { 0, NULL }
298 };
299
300 static const value_string add_to_col_info[] = {
301 { 0, "No" },
302 { 1, "Yes" },
303 { 0, NULL }
304 };
305
306 typedef struct _header_field_t {
307 gchar *header_name;
308 gchar *description;
309 guint header_format;
310 guint add_to_col_info;
311 } header_field_t;
312
313 static header_field_t *header_fields;
314 static guint num_header_fields;
315
316 static GHashTable *custom_field_table;
317 static hf_register_info *dynamic_hf;
318 static guint dynamic_hf_size;
319
320 static gboolean
321 header_fields_update_cb(void *r, char **err)
322 {
323 header_field_t *rec = (header_field_t *)r;
324 char c;
325
326 if (rec->header_name == NULL) {
327 *err = g_strdup("Header name can't be empty");
328 return FALSE;
329 }
330
331 g_strstrip(rec->header_name);
332 if (rec->header_name[0] == 0) {
333 *err = g_strdup("Header name can't be empty");
334 return FALSE;
335 }
336
337 /* Check for invalid characters (to avoid asserting out when
338 * registering the field).
339 */
340 c = proto_check_field_name(rec->header_name);
proto_reg_handoff_igap(void)341 if (c) {
342 *err = g_strdup_printf("Header name can't contain '%c'", c);
343 return FALSE;
344 }
345
346 *err = NULL;
347 return TRUE;
348 }
349
350 static void *
351 header_fields_copy_cb(void *n, const void *o, size_t siz _U_)
352 {
353 header_field_t *new_rec = (header_field_t *)n;
354 const header_field_t *old_rec = (const header_field_t *)o;
355
356 new_rec->header_name = g_strdup(old_rec->header_name);
357 new_rec->description = g_strdup(old_rec->description);
358 new_rec->header_format = old_rec->header_format;
359 new_rec->add_to_col_info = old_rec->add_to_col_info;
360
361 return new_rec;
362 }
363
364 static void
365 header_fields_free_cb(void *r)
366 {
367 header_field_t *rec = (header_field_t *)r;
368
369 g_free(rec->header_name);
370 g_free(rec->description);
371 }
372
373 UAT_CSTRING_CB_DEF(header_fields, header_name, header_field_t)
374 UAT_CSTRING_CB_DEF(header_fields, description, header_field_t)
375 UAT_VS_DEF(header_fields, header_format, header_field_t, guint, 0, "Unstructured")
376 UAT_VS_DEF(header_fields, add_to_col_info, header_field_t, guint, 0, "No")
377
378
379 /* Define media_type/Content type table */
380 static dissector_table_t media_type_dissector_table;
381
382 static void
383 dissect_imf_address(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo)
384 {
385 proto_tree *group_tree;
386 proto_item *group_item;
387 int addr_pos;
388
389 /* if there is a colon present it is a group */
390 if((addr_pos = tvb_find_guint8(tvb, offset, length, ':')) == -1) {
391
392 /* there isn't - so it must be a mailbox */
393 dissect_imf_mailbox(tvb, offset, length, item, pinfo);
394
395 } else {
396
397 /* it is a group */
398 group_tree = proto_item_add_subtree(item, ett_imf_group);
399
400 /* the display-name is mandatory */
401 group_item = proto_tree_add_item(group_tree, hf_imf_display_name, tvb, offset, addr_pos - offset - 1, ENC_ASCII|ENC_NA);
402
403 /* consume any whitespace */
404 for(addr_pos++ ;addr_pos < (offset + length); addr_pos++) {
405 if(!g_ascii_isspace(tvb_get_guint8(tvb, addr_pos))) {
406 break;
407 }
408 }
409
410 if(tvb_get_guint8(tvb, addr_pos) != ';') {
411
412 dissect_imf_mailbox_list(tvb, addr_pos, length - (addr_pos - offset), group_item, pinfo);
413
414 /* XXX: need to check for final ';' */
415
416 }
417
418 }
419 }
420
421 static void
422 dissect_imf_mailbox(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo _U_)
423 {
424 proto_tree *mbox_tree;
425 int addr_pos, end_pos;
426
427 mbox_tree = proto_item_add_subtree(item, ett_imf_mailbox);
428
429 /* Here is the plan:
430 If we can't find and angle brackets, then the whole field is an address.
431 If we find angle brackets, then the address is between them and the display name is
432 anything before the opening angle bracket
433 */
434
435 if((addr_pos = tvb_find_guint8(tvb, offset, length, '<')) == -1) {
436 /* we can't find an angle bracket - the whole field is therefore the address */
437
438 (void) proto_tree_add_item(mbox_tree, hf_imf_address, tvb, offset, length, ENC_ASCII|ENC_NA);
439
440 } else {
441 /* we can find an angle bracket - let's see if we can find a display name */
442 /* XXX: the '<' could be in the display name */
443
444 for(; offset < addr_pos; offset++) {
445 if(!g_ascii_isspace(tvb_get_guint8(tvb, offset))) {
446 break;
447 }
448 }
449
450 if(offset != addr_pos) { /* there is a display name */
451 (void) proto_tree_add_item(mbox_tree, hf_imf_display_name, tvb, offset, addr_pos - offset - 1, ENC_ASCII|ENC_NA);
452 }
453 end_pos = tvb_find_guint8(tvb, addr_pos + 1, length - (addr_pos + 1 - offset), '>');
454
455 if(end_pos != -1) {
456 (void) proto_tree_add_item(mbox_tree, hf_imf_address, tvb, addr_pos + 1, end_pos - addr_pos - 1, ENC_ASCII|ENC_NA);
457 }
458 }
459 }
460
461 static void
462 dissect_imf_address_list(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo)
463 {
464 proto_item *addr_item = NULL;
465 proto_tree *tree = NULL;
466 int count = 0;
467 int item_offset;
468 int end_offset;
469 int item_length;
470
471 /* a comma separated list of addresses */
472 tree = proto_item_add_subtree(item, ett_imf_address_list);
473
474 item_offset = offset;
475
476 do {
477
478 end_offset = tvb_find_guint8(tvb, item_offset, length - (item_offset - offset), ',');
479
480 count++; /* increase the number of items */
481
482 if(end_offset == -1) {
483 /* length is to the end of the buffer */
484 item_length = length - (item_offset - offset);
485 } else {
486 item_length = end_offset - item_offset;
487 }
488 addr_item = proto_tree_add_item(tree, hf_imf_address_list_item, tvb, item_offset, item_length, ENC_ASCII|ENC_NA);
489 dissect_imf_address(tvb, item_offset, item_length, addr_item, pinfo);
490
491 if(end_offset != -1) {
492 item_offset = end_offset + 1;
493 }
494 } while(end_offset != -1);
495
496 /* now indicate the number of items found */
497 proto_item_append_text(item, ", %d item%s", count, plurality(count, "", "s"));
498 }
499
500 static void
501 dissect_imf_mailbox_list(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo)
502 {
503 proto_item *mbox_item = NULL;
504 proto_tree *tree = NULL;
505 int count = 0;
506 int item_offset;
507 int end_offset;
508 int item_length;
509
510 /* a comma separated list of mailboxes */
511 tree = proto_item_add_subtree(item, ett_imf_mailbox_list);
512
513 item_offset = offset;
514
515 do {
516
517 end_offset = tvb_find_guint8(tvb, item_offset, length - (item_offset - offset), ',');
518
519 count++; /* increase the number of items */
520
521 if(end_offset == -1) {
522 /* length is to the end of the buffer */
523 item_length = length - (item_offset - offset);
524 } else {
525 item_length = end_offset - item_offset;
526 }
527 mbox_item = proto_tree_add_item(tree, hf_imf_mailbox_list_item, tvb, item_offset, item_length, ENC_ASCII|ENC_NA);
528 dissect_imf_mailbox(tvb, item_offset, item_length, mbox_item, pinfo);
529
530 if(end_offset != -1) {
531 item_offset = end_offset + 1;
532 }
533 } while(end_offset != -1);
534
535 /* now indicate the number of items found */
536 proto_item_append_text(item, ", %d item%s", count, plurality(count, "", "s"));
537 }
538
539 static void
540 dissect_imf_siolabel(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo)
541 {
542 proto_tree *tree = NULL;
543 proto_item *sub_item = NULL;
544 int item_offset, item_length;
545 int value_offset, value_length;
546 int end_offset;
547 tvbuff_t *label_tvb;
548 gchar *type = NULL;
549 wmem_strbuf_t *label_string = wmem_strbuf_new(pinfo->pool, "");
550
551 /* a semicolon separated list of attributes */
552 tree = proto_item_add_subtree(item, ett_imf_siolabel);
553 item_offset = offset;
554
555 do {
556 end_offset = tvb_find_guint8(tvb, item_offset, length - (item_offset - offset), ';');
557
558 /* skip leading space */
559 while (g_ascii_isspace(tvb_get_guint8(tvb, item_offset))) {
560 item_offset++;
561 }
562
563 if (end_offset == -1) {
564 /* length is to the end of the buffer */
565 item_length = tvb_find_line_end(tvb, item_offset, length - (item_offset - offset), NULL, FALSE);
566 } else {
567 item_length = end_offset - item_offset;
568 }
569
570 value_offset = tvb_find_guint8(tvb, item_offset, length - (item_offset - offset), '=') + 1;
571 while (g_ascii_isspace(tvb_get_guint8(tvb, value_offset))) {
572 value_offset++;
573 }
574
575 value_length = item_length - (value_offset - item_offset);
576 while (g_ascii_isspace(tvb_get_guint8(tvb, value_offset + value_length - 1))) {
577 value_length--;
578 }
579
580 if (tvb_strneql(tvb, item_offset, "marking", 7) == 0) {
581 const guint8* marking;
582 proto_tree_add_item_ret_string(tree, hf_imf_siolabel_marking, tvb, value_offset, value_length, ENC_ASCII|ENC_NA, pinfo->pool, &marking);
583 proto_item_append_text(item, ": %s", marking);
584
585 } else if (tvb_strneql(tvb, item_offset, "fgcolor", 7) == 0) {
586 proto_tree_add_item(tree, hf_imf_siolabel_fgcolor, tvb, value_offset, value_length, ENC_ASCII|ENC_NA);
587
588 } else if (tvb_strneql(tvb, item_offset, "bgcolor", 7) == 0) {
589 proto_tree_add_item(tree, hf_imf_siolabel_bgcolor, tvb, value_offset, value_length, ENC_ASCII|ENC_NA);
590
591 } else if (tvb_strneql(tvb, item_offset, "type", 4) == 0) {
592 type = tvb_get_string_enc(pinfo->pool, tvb, value_offset + 1, value_length - 2, ENC_ASCII); /* quoted */
593 proto_tree_add_item(tree, hf_imf_siolabel_type, tvb, value_offset, value_length, ENC_ASCII|ENC_NA);
594
595 } else if (tvb_strneql(tvb, item_offset, "label", 5) == 0) {
596 gchar *label = tvb_get_string_enc(pinfo->pool, tvb, value_offset + 1, value_length - 2, ENC_ASCII); /* quoted */
597 wmem_strbuf_append(label_string, label);
598
599 if (tvb_get_guint8(tvb, item_offset + 5) == '*') { /* continuations */
600 int num = (int)strtol(tvb_get_string_enc(pinfo->pool, tvb, item_offset + 6, value_offset - item_offset + 6, ENC_ASCII), NULL, 10);
601 proto_tree_add_string_format(tree, hf_imf_siolabel_label, tvb, value_offset, value_length,
602 label, "Label[%d]: \"%s\"", num, label);
603 } else {
604 proto_tree_add_item(tree, hf_imf_siolabel_label, tvb, value_offset, value_length, ENC_ASCII|ENC_NA);
605 }
606
607 } else {
608 sub_item = proto_tree_add_item(tree, hf_imf_siolabel_unknown, tvb, item_offset, item_length, ENC_ASCII|ENC_NA);
609 expert_add_info(pinfo, sub_item, &ei_imf_unknown_param);
610 }
611
612 if (end_offset != -1) {
613 item_offset = end_offset + 1;
614 }
615 } while (end_offset != -1);
616
617 if (type && wmem_strbuf_get_len(label_string) > 0) {
618 if (strcmp (type, ":ess") == 0) {
619 label_tvb = base64_to_tvb(tvb, wmem_strbuf_get_str(label_string));
620 add_new_data_source(pinfo, label_tvb, "ESS Security Label");
621 dissect_ess_ESSSecurityLabel_PDU(label_tvb, pinfo, tree, NULL);
622 } else if (strcmp (type, ":x411") == 0) {
623 label_tvb = base64_to_tvb(tvb, wmem_strbuf_get_str(label_string));
624 add_new_data_source(pinfo, label_tvb, "X.411 Security Label");
625 dissect_p1_MessageSecurityLabel_PDU(label_tvb, pinfo, tree, NULL);
626 }
627 }
628 }
629
630 static void
631 dissect_imf_content_type(tvbuff_t *tvb, packet_info *pinfo, int offset, int length, proto_item *item,
632 const guint8 **type, const guint8 **parameters)
633 {
634 int first_colon;
635 int end_offset;
636 int len;
637 int i;
638 proto_tree *ct_tree;
639
640 /* first strip any whitespace */
641 for(i = 0; i < length; i++) {
642 if(!g_ascii_isspace(tvb_get_guint8(tvb, offset + i))) {
643 offset += i;
644 break;
645 }
646 }
647
648 /* find the first colon - there has to be a colon as there will have to be a boundary */
649 first_colon = tvb_find_guint8(tvb, offset, length, ';');
650
651 if(first_colon != -1) {
652 ct_tree = proto_item_add_subtree(item, ett_imf_content_type);
653
654 len = first_colon - offset;
655 proto_tree_add_item_ret_string(ct_tree, hf_imf_content_type_type, tvb, offset, len, ENC_ASCII|ENC_NA, pinfo->pool, type);
656 end_offset = imf_find_field_end (tvb, first_colon + 1, offset + length, NULL);
657 if (end_offset == -1) {
658 /* No end found */
659 return;
660 }
661 len = end_offset - (first_colon + 1) - 2; /* Do not include the last CRLF */
662 proto_tree_add_item_ret_string(ct_tree, hf_imf_content_type_parameters, tvb, first_colon + 1, len, ENC_ASCII|ENC_NA, pinfo->pool, parameters);
663 }
664 }
665
666
667 int
668 imf_find_field_end(tvbuff_t *tvb, int offset, gint max_length, gboolean *last_field)
669 {
670
671 while(offset < max_length) {
672
673 /* look for CR */
674 offset = tvb_find_guint8(tvb, offset, max_length - offset, '\r');
675
676 if(offset != -1) {
677 /* protect against buffer overrun and only then look for next char */
678 if (++offset < max_length && tvb_get_guint8(tvb, offset) == '\n') {
679 /* OK - so we have found CRLF */
680 if (++offset >= max_length) {
681 /* end of buffer and also end of fields */
682 if (last_field) {
683 *last_field = TRUE;
684 }
685 /* caller expects that there is CRLF after returned offset, if last_field is set */
686 return offset - 2;
687 }
688 /* peek the next character */
689 switch(tvb_get_guint8(tvb, offset)) {
690 case '\r':
691 /* probably end of the fields */
692 if ((offset + 1) < max_length && tvb_get_guint8(tvb, offset + 1) == '\n') {
693 if(last_field) {
694 *last_field = TRUE;
695 }
696 }
697 return offset;
698 case ' ':
699 case '\t':
700 /* continuation line */
701 break;
702 default:
703 /* this is a new field */
704 return offset;
705 }
706 }
707 } else {
708 /* couldn't find a CR - strange */
709 break;
710 }
711
712 }
713
714 return -1; /* Fail: No CR found (other than possible continuation) */
715
716 }
717
718 static int
719 dissect_imf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
720 {
721 proto_item *item;
722 proto_tree *unknown_tree, *text_tree;
723 const guint8 *content_type_str = NULL;
724 char *content_encoding_str = NULL;
725 const guint8 *parameters = NULL;
726 int hf_id;
727 gint start_offset = 0;
728 gint value_offset = 0;
729 gint unknown_offset = 0;
730 gint end_offset = 0;
731 gint max_length;
732 guint8 *key;
733 gboolean last_field = FALSE;
734 tvbuff_t *next_tvb;
735 struct imf_field *f_info;
736 imf_eo_t *eo_info = NULL;
737
738 if (have_tap_listener(imf_eo_tap)) {
739 eo_info = wmem_new(pinfo->pool, imf_eo_t);
740 /* initialize the eo_info fields in case they are missing later */
741 eo_info->sender_data = "";
742 eo_info->subject_data = "";
743 }
744
745 /* Want to preserve existing protocol name and show that it is carrying IMF */
746 col_append_str(pinfo->cinfo, COL_PROTOCOL, "/");
747 col_set_fence(pinfo->cinfo, COL_PROTOCOL);
748 col_set_str(pinfo->cinfo, COL_PROTOCOL, PSNAME);
749
750 col_clear(pinfo->cinfo, COL_INFO);
751
752 item = proto_tree_add_item(tree, proto_imf, tvb, 0, -1, ENC_NA);
753 tree = proto_item_add_subtree(item, ett_imf);
754
755 max_length = tvb_captured_length(tvb);
756 /* first go through the tvb until we find a blank line and extract the content type if
757 we find one */
758
759 /* XXX: What if the tvb contains encrypted data ? is there a way to bypass dissection if so ? */
760 /* As it is, the following code blithely tries to parse what may be binary data. */
761
762 while(!last_field) {
763
764 /* look for a colon first */
765 end_offset = tvb_find_guint8(tvb, start_offset, max_length - start_offset, ':');
766
767 if(end_offset == -1) {
768 /* we couldn't find another colon - strange - we should have broken out of here by now */
769 /* XXX: flag an error */
770 break;
771 } else {
772 key = tvb_get_string_enc(pinfo->pool, tvb, start_offset, end_offset - start_offset, ENC_ASCII);
773
774 /* convert to lower case */
775 ascii_strdown_inplace (key);
776
777 /* look up the key in built-in fields */
778 f_info = (struct imf_field *)wmem_map_lookup(imf_field_table, key);
779
780 if(f_info == NULL && custom_field_table) {
781 /* look up the key in custom fields */
782 f_info = (struct imf_field *)g_hash_table_lookup(custom_field_table, key);
783 }
784
785 if(f_info == NULL) {
786 /* set as an unknown extension */
787 f_info = imf_fields;
788 unknown_offset = start_offset;
789 }
790
791 hf_id = *(f_info->hf_id);
792
793 /* value starts immediately after the colon */
794 start_offset = end_offset+1;
795
796 end_offset = imf_find_field_end(tvb, start_offset, max_length, &last_field);
797 if(end_offset == -1) {
798 break; /* Something's fishy */
799 }
800
801 /* remove any leading whitespace */
802
803 for(value_offset = start_offset; value_offset < end_offset; value_offset++)
804 if(!g_ascii_isspace(tvb_get_guint8(tvb, value_offset))) {
805 break;
806 }
807
808 if(value_offset == end_offset) {
809 /* empty field - show whole value */
810 value_offset = start_offset;
811 }
812
813 if(hf_id == hf_imf_extension_type) {
814
815 /* remove 2 bytes to take off the final CRLF to make things a little prettier */
816 item = proto_tree_add_item(tree, hf_imf_extension, tvb, unknown_offset, end_offset - unknown_offset - 2, ENC_ASCII|ENC_NA);
817
818 proto_item_append_text(item, " (Contact Wireshark developers if you want this supported.)");
819
820 unknown_tree = proto_item_add_subtree(item, ett_imf_extension);
821
822 proto_tree_add_item(unknown_tree, hf_imf_extension_type, tvb, unknown_offset, start_offset - 1 - unknown_offset, ENC_ASCII|ENC_NA);
823
824 /* remove 2 bytes to take off the final CRLF to make things a little prettier */
825 item = proto_tree_add_item(unknown_tree, hf_imf_extension_value, tvb, value_offset, end_offset - value_offset - 2, ENC_ASCII|ENC_NA);
826
827 } else {
828 /* remove 2 bytes to take off the final CRLF to make things a little prettier */
829 item = proto_tree_add_item(tree, hf_id, tvb, value_offset, end_offset - value_offset - 2, ENC_ASCII|ENC_NA);
830 }
831 if(f_info->add_to_col_info) {
832
833 col_append_fstr(pinfo->cinfo, COL_INFO, "%s: %s, ", f_info->name,
834 tvb_format_text(pinfo->pool, tvb, value_offset, end_offset - value_offset - 2));
835
836 /* if sender or subject, store for sending to the tap */
837 if (eo_info && have_tap_listener(imf_eo_tap)) {
838 if (*f_info->hf_id == hf_imf_from) {
839 eo_info->sender_data = tvb_get_string_enc(pinfo->pool, tvb, value_offset, end_offset - value_offset - 2, ENC_ASCII|ENC_NA);
840 } else if(*f_info->hf_id == hf_imf_subject) {
841 eo_info->subject_data = tvb_get_string_enc(pinfo->pool, tvb, value_offset, end_offset - value_offset - 2, ENC_ASCII|ENC_NA);
842 }
843 }
844 }
845
846 if(hf_id == hf_imf_content_type) {
847 /* we need some additional processing to extract the content type and parameters */
848
849 dissect_imf_content_type(tvb, pinfo, start_offset, end_offset - start_offset, item,
850 &content_type_str, ¶meters);
851
852 } else if (hf_id == hf_imf_content_transfer_encoding) {
853 content_encoding_str = tvb_get_string_enc (pinfo->pool, tvb, value_offset, end_offset - value_offset - 2, ENC_ASCII);
854 } else if(f_info->subdissector) {
855
856 /* we have a subdissector */
857 f_info->subdissector(tvb, value_offset, end_offset - value_offset, item, pinfo);
858
859 }
860 }
861 start_offset = end_offset;
862 }
863
864 if (last_field) {
865 /* Remove the extra CRLF after all the fields */
866 end_offset += 2;
867 }
868
869 if (end_offset == -1) {
870 end_offset = 0;
871 }
872
873 /* specify a content type until we can work it out for ourselves */
874 /* content_type_str = "multipart/mixed"; */
875
876 /* now dissect the MIME based upon the content type */
877
878 if(content_type_str && media_type_dissector_table) {
879 http_message_info_t message_info;
880
881 col_set_fence(pinfo->cinfo, COL_INFO);
882
883 if(content_encoding_str && !g_ascii_strncasecmp(content_encoding_str, "base64", 6)) {
884 char *string_data = tvb_get_string_enc(pinfo->pool, tvb, end_offset, tvb_reported_length(tvb) - end_offset, ENC_ASCII);
885 next_tvb = base64_to_tvb(tvb, string_data);
886 add_new_data_source(pinfo, next_tvb, content_encoding_str);
887 } else {
888 next_tvb = tvb_new_subset_remaining(tvb, end_offset);
889 }
890
891 message_info.type = HTTP_OTHERS;
892 message_info.media_str = parameters;
893 message_info.data = NULL;
894 dissector_try_string(media_type_dissector_table, content_type_str, next_tvb, pinfo, tree, (void*)&message_info);
895 } else {
896
897 /* just show the lines or highlight the rest of the buffer as message text */
898
899 item = proto_tree_add_item(tree, hf_imf_message_text, tvb, end_offset, tvb_reported_length_remaining(tvb, end_offset) , ENC_NA);
900 text_tree = proto_item_add_subtree(item, ett_imf_message_text);
901
902 start_offset = end_offset;
903 while (tvb_offset_exists(tvb, start_offset)) {
904
905 /*
906 * Find the end of the line.
907 */
908 tvb_find_line_end(tvb, start_offset, -1, &end_offset, FALSE);
909
910 /*
911 * Put this line.
912 */
913 proto_tree_add_format_wsp_text(text_tree, tvb, start_offset, end_offset - start_offset);
914 col_append_sep_str(pinfo->cinfo, COL_INFO, ", ",
915 tvb_format_text_wsp(pinfo->pool, tvb, start_offset, end_offset - start_offset));
916
917 /*
918 * Step to the next line.
919 */
920 start_offset = end_offset;
921 }
922 }
923
924 if (eo_info && have_tap_listener(imf_eo_tap)) {
925 /* Set payload info */
926 eo_info->payload_len = max_length;
927 eo_info->payload_data = (gchar *) tvb_memdup(pinfo->pool, tvb, 0, max_length);
928
929 /* Send to tap */
930 tap_queue_packet(imf_eo_tap, pinfo, eo_info);
931 }
932 return tvb_captured_length(tvb);
933 }
934
935 static void
936 free_imf_field (gpointer data)
937 {
938 struct imf_field *imffield = (struct imf_field *) data;
939
940 g_free (imffield->name);
941 g_free (imffield);
942 }
943
944 static void
945 deregister_header_fields(void)
946 {
947 if (dynamic_hf) {
948 /* Deregister all fields */
949 for (guint i = 0; i < dynamic_hf_size; i++) {
950 proto_deregister_field (proto_imf, *(dynamic_hf[i].p_id));
951 g_free (dynamic_hf[i].p_id);
952 }
953
954 proto_add_deregistered_data (dynamic_hf);
955 dynamic_hf = NULL;
956 dynamic_hf_size = 0;
957 }
958
959 if (custom_field_table) {
960 g_hash_table_destroy (custom_field_table);
961 custom_field_table = NULL;
962 }
963 }
964
965 static void
966 header_fields_post_update_cb (void)
967 {
968 gint *hf_id;
969 struct imf_field *imffield;
970 gchar *header_name;
971
972 deregister_header_fields();
973
974 if (num_header_fields) {
975 custom_field_table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, free_imf_field);
976 dynamic_hf = g_new0(hf_register_info, num_header_fields);
977 dynamic_hf_size = num_header_fields;
978
979 for (guint i = 0; i < dynamic_hf_size; i++) {
980 hf_id = g_new(gint, 1);
981 *hf_id = -1;
982 header_name = g_strdup (header_fields[i].header_name);
983
984 dynamic_hf[i].p_id = hf_id;
985 dynamic_hf[i].hfinfo.name = header_name;
986 dynamic_hf[i].hfinfo.abbrev = g_strdup_printf ("imf.header.%s", header_name);
987 dynamic_hf[i].hfinfo.type = FT_STRING;
988 dynamic_hf[i].hfinfo.display = BASE_NONE;
989 dynamic_hf[i].hfinfo.strings = NULL;
990 dynamic_hf[i].hfinfo.bitmask = 0;
991 dynamic_hf[i].hfinfo.blurb = g_strdup (header_fields[i].description);
992 HFILL_INIT(dynamic_hf[i]);
993
994 imffield = g_new(struct imf_field, 1);
995 imffield->hf_id = hf_id;
996 imffield->name = g_ascii_strdown(header_name, -1);
997 switch (header_fields[i].header_format) {
998 case FORMAT_UNSTRUCTURED:
999 imffield->subdissector = NO_SUBDISSECTION;
1000 break;
1001 case FORMAT_MAILBOX:
1002 imffield->subdissector = dissect_imf_mailbox;
1003 break;
1004 case FORMAT_ADDRESS:
1005 imffield->subdissector = dissect_imf_address;
1006 break;
1007 case FORMAT_MAILBOX_LIST:
1008 imffield->subdissector = dissect_imf_mailbox_list;
1009 break;
1010 case FORMAT_ADDRESS_LIST:
1011 imffield->subdissector = dissect_imf_address_list;
1012 break;
1013 case FORMAT_SIO_LABEL:
1014 dynamic_hf[i].hfinfo.type = FT_NONE; /* constructed */
1015 imffield->subdissector = dissect_imf_siolabel;
1016 break;
1017 default:
1018 /* unknown */
1019 imffield->subdissector = NO_SUBDISSECTION;
1020 break;
1021 }
1022 imffield->add_to_col_info = header_fields[i].add_to_col_info;
1023 g_hash_table_insert (custom_field_table, (gpointer)imffield->name, (gpointer)imffield);
1024 }
1025
1026 proto_register_field_array (proto_imf, dynamic_hf, dynamic_hf_size);
1027 }
1028 }
1029
1030 static void
1031 header_fields_reset_cb(void)
1032 {
1033 deregister_header_fields();
1034 }
1035
1036 /* Register all the bits needed by the filtering engine */
1037
1038 void
1039 proto_register_imf(void)
1040 {
1041 static hf_register_info hf[] = {
1042 { &hf_imf_date,
1043 { "Date", "imf.date", FT_STRING, BASE_NONE, NULL, 0x0,
1044 "DateTime", HFILL }},
1045 { &hf_imf_from,
1046 { "From", "imf.from", FT_STRING, BASE_NONE, NULL, 0x0,
1047 "MailboxList", HFILL }},
1048 { &hf_imf_sender,
1049 { "Sender", "imf.sender", FT_STRING, BASE_NONE, NULL, 0x0,
1050 NULL, HFILL }},
1051 { &hf_imf_reply_to,
1052 { "Reply-To", "imf.reply_to", FT_STRING, BASE_NONE, NULL, 0x0,
1053 NULL, HFILL }},
1054 { &hf_imf_to,
1055 { "To", "imf.to", FT_STRING, BASE_NONE, NULL, 0x0,
1056 NULL, HFILL }},
1057 { &hf_imf_cc,
1058 { "Cc", "imf.cc", FT_STRING, BASE_NONE, NULL, 0x0,
1059 NULL, HFILL }},
1060 { &hf_imf_bcc,
1061 { "Bcc", "imf.bcc", FT_STRING, BASE_NONE, NULL, 0x0,
1062 NULL, HFILL }},
1063 { &hf_imf_message_id,
1064 { "Message-ID", "imf.message_id", FT_STRING, BASE_NONE, NULL, 0x0,
1065 NULL, HFILL }},
1066 { &hf_imf_in_reply_to,
1067 { "In-Reply-To", "imf.in_reply_to", FT_STRING, BASE_NONE, NULL, 0x0,
1068 NULL, HFILL }},
1069 { &hf_imf_references,
1070 { "References", "imf.references", FT_STRING, BASE_NONE, NULL, 0x0,
1071 NULL, HFILL }},
1072 { &hf_imf_subject,
1073 { "Subject", "imf.subject", FT_STRING, BASE_NONE, NULL, 0x0,
1074 NULL, HFILL }},
1075 { &hf_imf_comments,
1076 { "Comments", "imf.comments", FT_STRING, BASE_NONE, NULL, 0x0,
1077 NULL, HFILL }},
1078 { &hf_imf_user_agent,
1079 { "User-Agent", "imf.user_agent", FT_STRING, BASE_NONE, NULL, 0x0,
1080 NULL, HFILL }},
1081 { &hf_imf_keywords,
1082 { "Keywords", "imf.keywords", FT_STRING, BASE_NONE, NULL, 0x0,
1083 NULL, HFILL }},
1084 { &hf_imf_resent_date,
1085 { "Resent-Date", "imf.resent.date", FT_STRING, BASE_NONE, NULL, 0x0,
1086 NULL, HFILL }},
1087 { &hf_imf_resent_from,
1088 { "Resent-From", "imf.resent.from", FT_STRING, BASE_NONE, NULL, 0x0,
1089 NULL, HFILL }},
1090 { &hf_imf_resent_sender,
1091 { "Resent-Sender", "imf.resent.sender", FT_STRING, BASE_NONE, NULL, 0x0,
1092 NULL, HFILL }},
1093 { &hf_imf_resent_to,
1094 { "Resent-To", "imf.resent.to", FT_STRING, BASE_NONE, NULL, 0x0,
1095 NULL, HFILL }},
1096 { &hf_imf_resent_cc,
1097 { "Resent-Cc", "imf.resent.cc", FT_STRING, BASE_NONE, NULL, 0x0,
1098 NULL, HFILL }},
1099 { &hf_imf_resent_bcc,
1100 { "Resent-Bcc", "imf.resent.bcc", FT_STRING, BASE_NONE, NULL, 0x0,
1101 NULL, HFILL }},
1102 { &hf_imf_resent_message_id,
1103 { "Resent-Message-ID", "imf.resent.message_id", FT_STRING, BASE_NONE, NULL, 0x0,
1104 NULL, HFILL }},
1105 { &hf_imf_return_path,
1106 { "Return-Path", "imf.return_path", FT_STRING, BASE_NONE, NULL, 0x0,
1107 NULL, HFILL }},
1108 { &hf_imf_received,
1109 { "Received", "imf.received", FT_STRING, BASE_NONE, NULL, 0x0,
1110 NULL, HFILL }},
1111 { &hf_imf_content_type,
1112 { "Content-Type", "imf.content.type", FT_STRING, BASE_NONE, NULL, 0x0,
1113 NULL, HFILL }},
1114 { &hf_imf_content_type_type,
1115 { "Type", "imf.content.type.type", FT_STRING, BASE_NONE, NULL, 0x0,
1116 NULL, HFILL }},
1117 { &hf_imf_content_type_parameters,
1118 { "Parameters", "imf.content.type.parameters", FT_STRING, BASE_NONE, NULL, 0x0,
1119 NULL, HFILL }},
1120 { &hf_imf_content_description,
1121 { "Content-Description", "imf.content.description", FT_STRING, BASE_NONE, NULL, 0x0,
1122 NULL, HFILL }},
1123 { &hf_imf_content_id,
1124 { "Content-ID", "imf.content.id", FT_STRING, BASE_NONE, NULL, 0x0,
1125 NULL, HFILL }},
1126 { &hf_imf_content_transfer_encoding,
1127 { "Content-Transfer-Encoding", "imf.content.transfer_encoding", FT_STRING, BASE_NONE, NULL, 0x0,
1128 NULL, HFILL }},
1129 { &hf_imf_mime_version,
1130 { "MIME-Version", "imf.mime_version", FT_STRING, BASE_NONE, NULL, 0x0,
1131 NULL, HFILL }},
1132 { &hf_imf_autoforwarded,
1133 { "Autoforwarded", "imf.autoforwarded", FT_STRING, BASE_NONE, NULL, 0x0,
1134 NULL, HFILL }},
1135 { &hf_imf_autosubmitted,
1136 { "Autosubmitted", "imf.autosubmitted", FT_STRING, BASE_NONE, NULL, 0x0,
1137 NULL, HFILL }},
1138 { &hf_imf_x400_content_identifier,
1139 { "X400-Content-Identifier", "imf.x400_content_identifier", FT_STRING, BASE_NONE, NULL, 0x0,
1140 NULL, HFILL }},
1141 { &hf_imf_content_language,
1142 { "Content-Language", "imf.content_language", FT_STRING, BASE_NONE, NULL, 0x0,
1143 NULL, HFILL }},
1144 { &hf_imf_conversion,
1145 { "Conversion", "imf.conversion", FT_STRING, BASE_NONE, NULL, 0x0,
1146 NULL, HFILL }},
1147 { &hf_imf_conversion_with_loss,
1148 { "Conversion-With-Loss", "imf.conversion_with_loss", FT_STRING, BASE_NONE, NULL, 0x0,
1149 NULL, HFILL }},
1150 { &hf_imf_delivery_date,
1151 { "Delivery-Date", "imf.delivery_date", FT_STRING, BASE_NONE, NULL, 0x0,
1152 NULL, HFILL }},
1153 { &hf_imf_discarded_x400_ipms_extensions,
1154 { "Discarded-X400-IPMS-Extensions", "imf.discarded_x400_ipms_extensions", FT_STRING, BASE_NONE, NULL, 0x0,
1155 NULL, HFILL }},
1156 { &hf_imf_discarded_x400_mts_extensions,
1157 { "Discarded-X400-MTS-Extensions", "imf.discarded_x400_mts_extensions", FT_STRING, BASE_NONE, NULL, 0x0,
1158 NULL, HFILL }},
1159 { &hf_imf_dl_expansion_history,
1160 { "DL-Expansion-History", "imf.dl_expansion_history", FT_STRING, BASE_NONE, NULL, 0x0,
1161 NULL, HFILL }},
1162 { &hf_imf_deferred_delivery,
1163 { "Deferred-Delivery", "imf.deferred_delivery", FT_STRING, BASE_NONE, NULL, 0x0,
1164 NULL, HFILL }},
1165 { &hf_imf_expires,
1166 { "Expires", "imf.expires", FT_STRING, BASE_NONE, NULL, 0x0,
1167 NULL, HFILL }},
1168 { &hf_imf_importance,
1169 { "Importance", "imf.importance", FT_STRING, BASE_NONE, NULL, 0x0,
1170 NULL, HFILL }},
1171 { &hf_imf_incomplete_copy,
1172 { "Incomplete-Copy", "imf.incomplete_copy", FT_STRING, BASE_NONE, NULL, 0x0,
1173 NULL, HFILL }},
1174 { &hf_imf_latest_delivery_time,
1175 { "Latest-Delivery-Time", "imf.latest_delivery_time", FT_STRING, BASE_NONE, NULL, 0x0,
1176 NULL, HFILL }},
1177 { &hf_imf_message_type,
1178 { "Message-Type", "imf.message_type", FT_STRING, BASE_NONE, NULL, 0x0,
1179 NULL, HFILL }},
1180 { &hf_imf_original_encoded_information_types,
1181 { "Original-Encoded-Information-Types", "imf.original_encoded_information_types", FT_STRING, BASE_NONE, NULL, 0x0,
1182 NULL, HFILL }},
1183 { &hf_imf_originator_return_address,
1184 { "Originator-Return-Address", "imf.originator_return_address", FT_STRING, BASE_NONE, NULL, 0x0,
1185 NULL, HFILL }},
1186 { &hf_imf_priority,
1187 { "Priority", "imf.priority", FT_STRING, BASE_NONE, NULL, 0x0,
1188 NULL, HFILL }},
1189 { &hf_imf_reply_by,
1190 { "Reply-By", "imf.reply_by", FT_STRING, BASE_NONE, NULL, 0x0,
1191 NULL, HFILL }},
1192 { &hf_imf_sensitivity,
1193 { "Sensitivity", "imf.sensitivity", FT_STRING, BASE_NONE, NULL, 0x0,
1194 NULL, HFILL }},
1195 { &hf_imf_supersedes,
1196 { "Supersedes", "imf.supersedes", FT_STRING, BASE_NONE, NULL, 0x0,
1197 NULL, HFILL }},
1198 { &hf_imf_x400_content_type,
1199 { "X400-Content-Type", "imf.x400_content_type", FT_STRING, BASE_NONE, NULL, 0x0,
1200 NULL, HFILL }},
1201 { &hf_imf_x400_mts_identifier,
1202 { "X400-MTS-Identifier", "imf.x400_mts_identifier", FT_STRING, BASE_NONE, NULL, 0x0,
1203 NULL, HFILL }},
1204 { &hf_imf_x400_originator,
1205 { "X400-Originator", "imf.x400_originator", FT_STRING, BASE_NONE, NULL, 0x0,
1206 NULL, HFILL }},
1207 { &hf_imf_x400_received,
1208 { "X400-Received", "imf.x400_received", FT_STRING, BASE_NONE, NULL, 0x0,
1209 NULL, HFILL }},
1210 { &hf_imf_x400_recipients,
1211 { "X400-Recipients", "imf.x400_recipients", FT_STRING, BASE_NONE, NULL, 0x0,
1212 NULL, HFILL }},
1213 { &hf_imf_delivered_to,
1214 { "Delivered-To", "imf.delivered_to", FT_STRING, BASE_NONE, NULL, 0x0,
1215 NULL, HFILL }},
1216 { &hf_imf_ext_mailer,
1217 { "X-Mailer", "imf.ext.mailer", FT_STRING, BASE_NONE, NULL, 0x0,
1218 NULL, HFILL }},
1219 { &hf_imf_ext_mimeole,
1220 { "X-MimeOLE", "imf.ext.mimeole", FT_STRING, BASE_NONE, NULL, 0x0,
1221 NULL, HFILL }},
1222 { &hf_imf_ext_expiry_date,
1223 { "Expiry-Date", "imf.ext.expiry-date", FT_STRING, BASE_NONE, NULL, 0x0,
1224 NULL, HFILL }},
1225 { &hf_imf_ext_tnef_correlator,
1226 { "X-MS-TNEF-Correlator", "imf.ext.tnef-correlator", FT_STRING, BASE_NONE, NULL, 0x0,
1227 NULL, HFILL }},
1228 { &hf_imf_ext_uidl,
1229 { "X-UIDL", "imf.ext.uidl", FT_STRING, BASE_NONE, NULL, 0x0,
1230 NULL, HFILL }},
1231 { &hf_imf_ext_authentication_warning,
1232 { "X-Authentication-Warning", "imf.ext.authentication_warning", FT_STRING, BASE_NONE,
1233 NULL, 0x0, NULL, HFILL }},
1234 { &hf_imf_ext_virus_scanned,
1235 { "X-Virus-Scanned", "imf.ext.virus_scanned", FT_STRING, BASE_NONE, NULL, 0x0,
1236 NULL, HFILL }},
1237 { &hf_imf_thread_index,
1238 { "Thread-Index", "imf.thread-index", FT_STRING, BASE_NONE, NULL, 0x0,
1239 NULL, HFILL }},
1240 { &hf_imf_extension,
1241 { "Unknown-Extension", "imf.extension", FT_STRING, BASE_NONE, NULL, 0x0,
1242 NULL, HFILL }},
1243 { &hf_imf_extension_type,
1244 { "Type", "imf.extension.type", FT_STRING, BASE_NONE, NULL, 0x0,
1245 NULL, HFILL }},
1246 { &hf_imf_extension_value,
1247 { "Value", "imf.extension.value", FT_STRING, BASE_NONE, NULL, 0x0,
1248 NULL, HFILL }},
1249 { &hf_imf_display_name,
1250 { "Display-Name", "imf.display_name", FT_STRING, BASE_NONE, NULL, 0x0,
1251 NULL, HFILL }},
1252 { &hf_imf_address,
1253 { "Address", "imf.address", FT_STRING, BASE_NONE, NULL, 0x0,
1254 NULL, HFILL }},
1255 #if 0
1256 { &hf_imf_address_list,
1257 { "Address List", "imf.address_list", FT_UINT32, BASE_DEC, NULL, 0x0,
1258 NULL, HFILL }},
1259 #endif
1260 { &hf_imf_address_list_item,
1261 { "Item", "imf.address_list.item", FT_STRING, BASE_NONE, NULL, 0x0,
1262 NULL, HFILL }},
1263 #if 0
1264 { &hf_imf_mailbox_list,
1265 { "Mailbox List", "imf.mailbox_list", FT_UINT32, BASE_DEC, NULL, 0x0,
1266 NULL, HFILL }},
1267 #endif
1268 { &hf_imf_mailbox_list_item,
1269 { "Item", "imf.mailbox_list.item", FT_STRING, BASE_NONE, NULL, 0x0,
1270 NULL, HFILL }},
1271 { &hf_imf_siolabel,
1272 { "SIO-Label", "imf.siolabel", FT_NONE, BASE_NONE, NULL, 0x0,
1273 NULL, HFILL }},
1274 { &hf_imf_siolabel_marking,
1275 { "Marking", "imf.siolabel.marking", FT_STRING, BASE_NONE, NULL, 0x0,
1276 NULL, HFILL }},
1277 { &hf_imf_siolabel_fgcolor,
1278 { "Foreground Color", "imf.siolabel.fgcolor", FT_STRING, BASE_NONE, NULL, 0x0,
1279 NULL, HFILL }},
1280 { &hf_imf_siolabel_bgcolor,
1281 { "Background Color", "imf.siolabel.bgcolor", FT_STRING, BASE_NONE, NULL, 0x0,
1282 NULL, HFILL }},
1283 { &hf_imf_siolabel_type,
1284 { "Type", "imf.siolabel.type", FT_STRING, BASE_NONE, NULL, 0x0,
1285 NULL, HFILL }},
1286 { &hf_imf_siolabel_label,
1287 { "Label", "imf.siolabel.label", FT_STRING, BASE_NONE, NULL, 0x0,
1288 NULL, HFILL }},
1289 { &hf_imf_siolabel_unknown,
1290 { "Unknown parameter", "imf.siolabel.unknown", FT_STRING, BASE_NONE, NULL, 0x0,
1291 NULL, HFILL }},
1292 { &hf_imf_message_text,
1293 { "Message-Text", "imf.message_text", FT_NONE, BASE_NONE, NULL, 0x0,
1294 NULL, HFILL }},
1295 };
1296 static gint *ett[] = {
1297 &ett_imf,
1298 &ett_imf_content_type,
1299 &ett_imf_group,
1300 &ett_imf_mailbox,
1301 &ett_imf_mailbox_list,
1302 &ett_imf_address_list,
1303 &ett_imf_siolabel,
1304 &ett_imf_extension,
1305 &ett_imf_message_text,
1306 };
1307
1308 static ei_register_info ei[] = {
1309 { &ei_imf_unknown_param, { "imf.unknown_param", PI_PROTOCOL, PI_WARN, "Unknown parameter", EXPFILL }},
1310 };
1311
1312 static uat_field_t attributes_flds[] = {
1313 UAT_FLD_CSTRING(header_fields, header_name, "Header name", "IMF header name"),
1314 UAT_FLD_CSTRING(header_fields, description, "Description", "Description of the value contained in the header"),
1315 UAT_FLD_VS(header_fields, header_format, "Format", header_format, 0),
1316 UAT_FLD_VS(header_fields, add_to_col_info, "Add to Info column", add_to_col_info, 0),
1317 UAT_END_FIELDS
1318 };
1319
1320 uat_t *headers_uat = uat_new("Custom IMF headers",
1321 sizeof(header_field_t),
1322 "imf_header_fields",
1323 TRUE,
1324 &header_fields,
1325 &num_header_fields,
1326 /* specifies named fields, so affects dissection
1327 and the set of named fields */
1328 UAT_AFFECTS_DISSECTION|UAT_AFFECTS_FIELDS,
1329 NULL,
1330 header_fields_copy_cb,
1331 header_fields_update_cb,
1332 header_fields_free_cb,
1333 header_fields_post_update_cb,
1334 header_fields_reset_cb,
1335 attributes_flds);
1336
1337 module_t *imf_module;
1338 expert_module_t* expert_imf;
1339 struct imf_field *f;
1340
1341 proto_imf = proto_register_protocol(PNAME, PSNAME, PFNAME);
1342
1343 proto_register_field_array(proto_imf, hf, array_length(hf));
1344 proto_register_subtree_array(ett, array_length(ett));
1345 expert_imf = expert_register_protocol(proto_imf);
1346 expert_register_field_array(expert_imf, ei, array_length(ei));
1347
1348 /* Allow dissector to find be found by name. */
1349 imf_handle = register_dissector(PFNAME, dissect_imf, proto_imf);
1350
1351 imf_module = prefs_register_protocol(proto_imf, NULL);
1352 prefs_register_uat_preference(imf_module, "custom_header_fields", "Custom IMF headers",
1353 "A table to define custom IMF headers for which fields can be "
1354 "setup and used for filtering/data extraction etc.",
1355 headers_uat);
1356
1357 imf_field_table=wmem_map_new(wmem_epan_scope(), wmem_str_hash, g_str_equal); /* oid to syntax */
1358
1359 /* register the fields for lookup */
1360 for(f = imf_fields; f->name; f++)
1361 wmem_map_insert(imf_field_table, (gpointer)f->name, (gpointer)f);
1362
1363 /* Register for tapping */
1364 imf_eo_tap = register_export_object(proto_imf, imf_eo_packet, NULL);
1365
1366 }
1367
1368 /* The registration hand-off routine */
1369 void
1370 proto_reg_handoff_imf(void)
1371 {
1372 dissector_add_string("media_type",
1373 "message/rfc822", imf_handle);
1374
1375 register_ber_oid_dissector_handle("1.2.840.113549.1.7.1", imf_handle, proto_imf, "id-data");
1376
1377 /*
1378 * Get the content type and Internet media type table
1379 */
1380 media_type_dissector_table = find_dissector_table("media_type");
1381
1382 }
1383
1384 /*
1385 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1386 *
1387 * Local Variables:
1388 * c-basic-offset: 2
1389 * tab-width: 8
1390 * indent-tabs-mode: nil
1391 * End:
1392 *
1393 * ex: set shiftwidth=2 tabstop=8 expandtab:
1394 * :indentSize=2:tabSize=8:noTabs=true:
1395 */
1396