Coverage Report

Created: 2026-06-30 07:22

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