Coverage Report

Created: 2026-09-28 06:52

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
119
{
665
666
480
  while(offset < max_length) {
667
668
    /* look for CR */
669
476
    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
431
        if (++offset < max_length && tvb_get_uint8(tvb, offset) == '\n') {
672
        /* OK - so we have found CRLF */
673
75
          if (++offset >= max_length) {
674
            /* end of buffer and also end of fields */
675
1
            if (last_field) {
676
1
              *last_field = true;
677
1
            }
678
            /* caller expects that there is CRLF after returned offset, if last_field is set */
679
1
            return offset - 2;
680
1
          }
681
        /* peek the next character */
682
74
        switch(tvb_get_uint8(tvb, offset)) {
683
27
        case '\r':
684
          /* probably end of the fields */
685
27
          if ((offset + 1) < max_length && tvb_get_uint8(tvb, offset + 1) == '\n') {
686
1
            if(last_field) {
687
1
              *last_field = true;
688
1
            }
689
1
          }
690
27
          return offset;
691
0
        case  ' ':
692
5
        case '\t':
693
          /* continuation line */
694
5
          break;
695
42
        default:
696
          /* this is a new field */
697
42
          return offset;
698
74
        }
699
74
      }
700
431
    } else {
701
      /* couldn't find a CR - strange */
702
45
      break;
703
45
    }
704
705
476
  }
706
707
49
  return -1;  /* Fail: No CR found (other than possible continuation) */
708
709
119
}
710
711
static int
712
dissect_imf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
713
86
{
714
86
  proto_item  *item;
715
86
  proto_tree  *unknown_tree, *text_tree;
716
86
  const char *content_type_str = NULL;
717
86
  char  *content_encoding_str = NULL;
718
86
  const char *parameters = NULL;
719
86
  int   hf_id;
720
86
  unsigned start_offset = 0;
721
86
  unsigned value_offset = 0;
722
86
  unsigned unknown_offset = 0;
723
86
  unsigned end_offset = 0;
724
86
  int t_offset;
725
86
  unsigned max_length;
726
86
  bool end_offset_found;
727
86
  char *key;
728
86
  bool last_field = false;
729
86
  tvbuff_t *next_tvb;
730
86
  const struct imf_field *f_info;
731
86
  imf_eo_t *eo_info = NULL;
732
733
86
  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
86
  col_append_str(pinfo->cinfo, COL_PROTOCOL, "/");
742
86
  col_set_fence(pinfo->cinfo, COL_PROTOCOL);
743
86
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "IMF");
744
745
86
  col_clear(pinfo->cinfo, COL_INFO);
746
747
86
  item = proto_tree_add_item(tree, proto_imf, tvb, 0, -1, ENC_NA);
748
86
  tree = proto_item_add_subtree(item, ett_imf);
749
750
86
  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
156
  while(!last_field) {
758
759
    /* look for a colon first */
760
154
    end_offset_found = tvb_find_uint8_length(tvb, start_offset, max_length - start_offset, ':', &end_offset);
761
762
154
    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
35
      break;
766
119
    } else {
767
119
      key = (char*)tvb_get_string_enc(pinfo->pool, tvb, start_offset, end_offset - start_offset, ENC_ASCII);
768
769
      /* convert to lower case */
770
119
      ascii_strdown_inplace (key);
771
772
      /* look up the key in built-in fields */
773
119
      f_info = (const struct imf_field *)wmem_map_lookup(imf_field_table, key);
774
775
119
      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
119
      if(f_info == NULL) {
781
        /* set as an unknown extension */
782
119
        f_info = imf_fields;
783
119
        unknown_offset = start_offset;
784
119
      }
785
786
119
      hf_id = *(f_info->hf_id);
787
788
      /* value starts immediately after the colon */
789
119
      start_offset = end_offset+1;
790
791
119
      t_offset = imf_find_field_end(tvb, start_offset, max_length, &last_field);
792
119
      if(t_offset == -1) {
793
49
        break;   /* Something's fishy */
794
49
      }
795
70
      end_offset = (unsigned)t_offset;
796
797
      /* remove any leading whitespace */
798
799
102
      for(value_offset = start_offset; value_offset < end_offset; value_offset++)
800
101
        if(!g_ascii_isspace(tvb_get_uint8(tvb, value_offset))) {
801
69
          break;
802
69
        }
803
804
70
      if(value_offset == end_offset) {
805
        /* empty field - show whole value */
806
1
        value_offset = start_offset;
807
1
      }
808
809
70
      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
70
        item = proto_tree_add_item(tree, hf_imf_extension, tvb, unknown_offset, end_offset - unknown_offset - 2, ENC_ASCII);
813
814
70
        proto_item_append_text(item, " (Contact Wireshark developers if you want this supported.)");
815
816
70
        unknown_tree = proto_item_add_subtree(item, ett_imf_extension);
817
818
70
        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
70
        item = proto_tree_add_item(unknown_tree, hf_imf_extension_value, tvb, value_offset, end_offset - value_offset - 2, ENC_ASCII);
822
823
70
      } 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
70
      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
70
      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
70
      } 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
70
      } 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
70
    }
857
70
    start_offset = end_offset;
858
70
  }
859
860
86
  if (last_field) {
861
    /* Remove the extra CRLF after all the fields */
862
2
    end_offset += 2;
863
2
  }
864
865
86
  if (end_offset_found == false) {
866
35
    end_offset = 0;
867
35
  }
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
86
  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
86
  } else {
892
893
    /* just show the lines or highlight the rest of the buffer as message text */
894
895
86
    item = proto_tree_add_item(tree, hf_imf_message_text, tvb, end_offset, tvb_reported_length_remaining(tvb, end_offset) , ENC_NA);
896
86
    text_tree = proto_item_add_subtree(item, ett_imf_message_text);
897
898
86
    start_offset = end_offset;
899
886
    while (tvb_offset_exists(tvb, start_offset)) {
900
901
      /*
902
       * Find the end of the line.
903
       */
904
800
      tvb_find_line_end_remaining(tvb, start_offset, NULL, &end_offset);
905
906
      /*
907
       * Put this line.
908
       */
909
800
      proto_tree_add_format_wsp_text(text_tree, tvb, start_offset, end_offset - start_offset);
910
800
      col_append_sep_str(pinfo->cinfo, COL_INFO, ", ",
911
800
                         tvb_format_text_wsp(pinfo->pool, tvb, start_offset, end_offset - start_offset));
912
913
      /*
914
       * Step to the next line.
915
       */
916
800
      start_offset = end_offset;
917
800
    }
918
86
  }
919
920
86
  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
86
  return tvb_captured_length(tvb);
929
86
}
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
16
{
943
16
  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
16
  if (custom_field_table) {
956
0
    g_hash_table_destroy (custom_field_table);
957
0
    custom_field_table = NULL;
958
0
  }
959
16
}
960
961
static void
962
header_fields_post_update_cb (void)
963
16
{
964
16
  int *hf_id;
965
16
  struct imf_field *imffield;
966
16
  char *header_name;
967
968
16
  deregister_header_fields();
969
970
16
  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
16
}
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
16
{
1037
16
  static hf_register_info hf[] = {
1038
16
    { &hf_imf_date,
1039
16
      { "Date", "imf.date", FT_STRING,  BASE_NONE, NULL, 0x0,
1040
16
        "DateTime", HFILL }},
1041
16
    { &hf_imf_from,
1042
16
      { "From", "imf.from", FT_STRING,  BASE_NONE, NULL, 0x0,
1043
16
        "MailboxList", HFILL }},
1044
16
    { &hf_imf_sender,
1045
16
      { "Sender", "imf.sender", FT_STRING,  BASE_NONE, NULL, 0x0,
1046
16
        NULL, HFILL }},
1047
16
    { &hf_imf_reply_to,
1048
16
      { "Reply-To", "imf.reply_to", FT_STRING,  BASE_NONE, NULL, 0x0,
1049
16
        NULL, HFILL }},
1050
16
    { &hf_imf_to,
1051
16
      { "To", "imf.to", FT_STRING,  BASE_NONE, NULL, 0x0,
1052
16
        NULL, HFILL }},
1053
16
    { &hf_imf_cc,
1054
16
      { "Cc", "imf.cc", FT_STRING,  BASE_NONE, NULL, 0x0,
1055
16
        NULL, HFILL }},
1056
16
    { &hf_imf_bcc,
1057
16
      { "Bcc", "imf.bcc", FT_STRING,  BASE_NONE, NULL, 0x0,
1058
16
        NULL, HFILL }},
1059
16
    { &hf_imf_message_id,
1060
16
      { "Message-ID", "imf.message_id", FT_STRING,  BASE_NONE, NULL, 0x0,
1061
16
        NULL, HFILL }},
1062
16
    { &hf_imf_in_reply_to,
1063
16
      { "In-Reply-To", "imf.in_reply_to", FT_STRING,  BASE_NONE, NULL, 0x0,
1064
16
        NULL, HFILL }},
1065
16
    { &hf_imf_references,
1066
16
      { "References", "imf.references", FT_STRING,  BASE_NONE, NULL, 0x0,
1067
16
        NULL, HFILL }},
1068
16
    { &hf_imf_subject,
1069
16
      { "Subject", "imf.subject", FT_STRING,  BASE_NONE, NULL, 0x0,
1070
16
        NULL, HFILL }},
1071
16
    { &hf_imf_comments,
1072
16
      { "Comments", "imf.comments", FT_STRING,  BASE_NONE, NULL, 0x0,
1073
16
        NULL, HFILL }},
1074
16
    { &hf_imf_user_agent,
1075
16
      { "User-Agent", "imf.user_agent", FT_STRING,  BASE_NONE, NULL, 0x0,
1076
16
        NULL, HFILL }},
1077
16
    { &hf_imf_keywords,
1078
16
      { "Keywords", "imf.keywords", FT_STRING,  BASE_NONE, NULL, 0x0,
1079
16
        NULL, HFILL }},
1080
16
    { &hf_imf_resent_date,
1081
16
      { "Resent-Date", "imf.resent.date", FT_STRING,  BASE_NONE, NULL, 0x0,
1082
16
        NULL, HFILL }},
1083
16
    { &hf_imf_resent_from,
1084
16
      { "Resent-From", "imf.resent.from", FT_STRING,  BASE_NONE, NULL, 0x0,
1085
16
        NULL, HFILL }},
1086
16
    { &hf_imf_resent_sender,
1087
16
      { "Resent-Sender", "imf.resent.sender", FT_STRING,  BASE_NONE, NULL, 0x0,
1088
16
        NULL, HFILL }},
1089
16
    { &hf_imf_resent_to,
1090
16
      { "Resent-To", "imf.resent.to", FT_STRING,  BASE_NONE, NULL, 0x0,
1091
16
        NULL, HFILL }},
1092
16
    { &hf_imf_resent_cc,
1093
16
      { "Resent-Cc", "imf.resent.cc", FT_STRING,  BASE_NONE, NULL, 0x0,
1094
16
        NULL, HFILL }},
1095
16
    { &hf_imf_resent_bcc,
1096
16
      { "Resent-Bcc", "imf.resent.bcc", FT_STRING,  BASE_NONE, NULL, 0x0,
1097
16
        NULL, HFILL }},
1098
16
    { &hf_imf_resent_message_id,
1099
16
      { "Resent-Message-ID", "imf.resent.message_id", FT_STRING,  BASE_NONE, NULL, 0x0,
1100
16
        NULL, HFILL }},
1101
16
    { &hf_imf_return_path,
1102
16
      { "Return-Path", "imf.return_path", FT_STRING,  BASE_NONE, NULL, 0x0,
1103
16
        NULL, HFILL }},
1104
16
    { &hf_imf_received,
1105
16
      { "Received", "imf.received", FT_STRING,  BASE_NONE, NULL, 0x0,
1106
16
        NULL, HFILL }},
1107
16
    { &hf_imf_content_type,
1108
16
      { "Content-Type", "imf.content.type", FT_STRING,  BASE_NONE, NULL, 0x0,
1109
16
        NULL, HFILL }},
1110
16
    { &hf_imf_content_type_type,
1111
16
      { "Type", "imf.content.type.type", FT_STRING,  BASE_NONE, NULL, 0x0,
1112
16
        NULL, HFILL }},
1113
16
    { &hf_imf_content_type_parameters,
1114
16
      { "Parameters", "imf.content.type.parameters", FT_STRING,  BASE_NONE, NULL, 0x0,
1115
16
        NULL, HFILL }},
1116
16
    { &hf_imf_content_description,
1117
16
      { "Content-Description", "imf.content.description", FT_STRING,  BASE_NONE, NULL, 0x0,
1118
16
        NULL, HFILL }},
1119
16
    { &hf_imf_content_id,
1120
16
      { "Content-ID", "imf.content.id", FT_STRING,  BASE_NONE, NULL, 0x0,
1121
16
        NULL, HFILL }},
1122
16
    { &hf_imf_content_transfer_encoding,
1123
16
      { "Content-Transfer-Encoding", "imf.content.transfer_encoding", FT_STRING,  BASE_NONE, NULL, 0x0,
1124
16
        NULL, HFILL }},
1125
16
    { &hf_imf_mime_version,
1126
16
      { "MIME-Version", "imf.mime_version", FT_STRING,  BASE_NONE, NULL, 0x0,
1127
16
        NULL, HFILL }},
1128
16
    { &hf_imf_autoforwarded,
1129
16
      { "Autoforwarded", "imf.autoforwarded", FT_STRING, BASE_NONE, NULL, 0x0,
1130
16
        NULL, HFILL }},
1131
16
    { &hf_imf_autosubmitted,
1132
16
      { "Autosubmitted", "imf.autosubmitted", FT_STRING, BASE_NONE, NULL, 0x0,
1133
16
        NULL, HFILL }},
1134
16
    { &hf_imf_x400_content_identifier,
1135
16
      { "X400-Content-Identifier", "imf.x400_content_identifier", FT_STRING, BASE_NONE, NULL, 0x0,
1136
16
        NULL, HFILL }},
1137
16
    { &hf_imf_content_language,
1138
16
      { "Content-Language", "imf.content_language", FT_STRING, BASE_NONE, NULL, 0x0,
1139
16
        NULL, HFILL }},
1140
16
    { &hf_imf_conversion,
1141
16
        { "Conversion", "imf.conversion", FT_STRING, BASE_NONE, NULL, 0x0,
1142
16
          NULL, HFILL }},
1143
16
    { &hf_imf_conversion_with_loss,
1144
16
        { "Conversion-With-Loss", "imf.conversion_with_loss", FT_STRING, BASE_NONE, NULL, 0x0,
1145
16
          NULL, HFILL }},
1146
16
    { &hf_imf_delivery_date,
1147
16
        { "Delivery-Date", "imf.delivery_date", FT_STRING, BASE_NONE, NULL, 0x0,
1148
16
          NULL, HFILL }},
1149
16
    { &hf_imf_discarded_x400_ipms_extensions,
1150
16
        { "Discarded-X400-IPMS-Extensions", "imf.discarded_x400_ipms_extensions", FT_STRING, BASE_NONE, NULL, 0x0,
1151
16
          NULL, HFILL }},
1152
16
    { &hf_imf_discarded_x400_mts_extensions,
1153
16
      { "Discarded-X400-MTS-Extensions", "imf.discarded_x400_mts_extensions", FT_STRING, BASE_NONE, NULL, 0x0,
1154
16
        NULL, HFILL }},
1155
16
    { &hf_imf_dl_expansion_history,
1156
16
        { "DL-Expansion-History", "imf.dl_expansion_history", FT_STRING, BASE_NONE, NULL, 0x0,
1157
16
          NULL, HFILL }},
1158
16
    { &hf_imf_deferred_delivery,
1159
16
        { "Deferred-Delivery", "imf.deferred_delivery", FT_STRING, BASE_NONE, NULL, 0x0,
1160
16
          NULL, HFILL }},
1161
16
    { &hf_imf_expires,
1162
16
        { "Expires", "imf.expires", FT_STRING, BASE_NONE, NULL, 0x0,
1163
16
          NULL, HFILL }},
1164
16
    { &hf_imf_importance,
1165
16
      { "Importance", "imf.importance", FT_STRING, BASE_NONE, NULL, 0x0,
1166
16
        NULL, HFILL }},
1167
16
    { &hf_imf_incomplete_copy,
1168
16
        { "Incomplete-Copy", "imf.incomplete_copy", FT_STRING, BASE_NONE, NULL, 0x0,
1169
16
          NULL, HFILL }},
1170
16
    { &hf_imf_latest_delivery_time,
1171
16
      { "Latest-Delivery-Time", "imf.latest_delivery_time", FT_STRING, BASE_NONE, NULL, 0x0,
1172
16
        NULL, HFILL }},
1173
16
    { &hf_imf_message_type,
1174
16
        { "Message-Type", "imf.message_type", FT_STRING, BASE_NONE, NULL, 0x0,
1175
16
          NULL, HFILL }},
1176
16
    { &hf_imf_original_encoded_information_types,
1177
16
        { "Original-Encoded-Information-Types", "imf.original_encoded_information_types", FT_STRING, BASE_NONE, NULL, 0x0,
1178
16
          NULL, HFILL }},
1179
16
    { &hf_imf_originator_return_address,
1180
16
        { "Originator-Return-Address", "imf.originator_return_address", FT_STRING, BASE_NONE, NULL, 0x0,
1181
16
          NULL, HFILL }},
1182
16
    { &hf_imf_priority,
1183
16
        { "Priority", "imf.priority", FT_STRING, BASE_NONE, NULL, 0x0,
1184
16
          NULL, HFILL }},
1185
16
    { &hf_imf_reply_by,
1186
16
        { "Reply-By", "imf.reply_by", FT_STRING, BASE_NONE, NULL, 0x0,
1187
16
          NULL, HFILL }},
1188
16
    { &hf_imf_sensitivity,
1189
16
        { "Sensitivity", "imf.sensitivity", FT_STRING, BASE_NONE, NULL, 0x0,
1190
16
          NULL, HFILL }},
1191
16
    { &hf_imf_supersedes,
1192
16
        { "Supersedes", "imf.supersedes", FT_STRING, BASE_NONE, NULL, 0x0,
1193
16
          NULL, HFILL }},
1194
16
    { &hf_imf_x400_content_type,
1195
16
        { "X400-Content-Type", "imf.x400_content_type", FT_STRING, BASE_NONE, NULL, 0x0,
1196
16
          NULL, HFILL }},
1197
16
    { &hf_imf_x400_mts_identifier,
1198
16
        { "X400-MTS-Identifier", "imf.x400_mts_identifier", FT_STRING, BASE_NONE, NULL, 0x0,
1199
16
          NULL, HFILL }},
1200
16
    { &hf_imf_x400_originator,
1201
16
        { "X400-Originator", "imf.x400_originator", FT_STRING, BASE_NONE, NULL, 0x0,
1202
16
        NULL, HFILL }},
1203
16
    { &hf_imf_x400_received,
1204
16
        { "X400-Received", "imf.x400_received", FT_STRING, BASE_NONE, NULL, 0x0,
1205
16
        NULL, HFILL }},
1206
16
    { &hf_imf_x400_recipients,
1207
16
        { "X400-Recipients", "imf.x400_recipients", FT_STRING, BASE_NONE, NULL, 0x0,
1208
16
        NULL, HFILL }},
1209
16
    { &hf_imf_delivered_to,
1210
16
      { "Delivered-To", "imf.delivered_to", FT_STRING,  BASE_NONE, NULL, 0x0,
1211
16
        NULL, HFILL }},
1212
16
    { &hf_imf_ext_mailer,
1213
16
      { "X-Mailer", "imf.ext.mailer", FT_STRING,  BASE_NONE, NULL, 0x0,
1214
16
        NULL, HFILL }},
1215
16
    { &hf_imf_ext_mimeole,
1216
16
      { "X-MimeOLE", "imf.ext.mimeole", FT_STRING,  BASE_NONE, NULL, 0x0,
1217
16
        NULL, HFILL }},
1218
16
    { &hf_imf_ext_expiry_date,
1219
16
      { "Expiry-Date", "imf.ext.expiry-date", FT_STRING,  BASE_NONE, NULL, 0x0,
1220
16
        NULL, HFILL }},
1221
16
    { &hf_imf_ext_tnef_correlator,
1222
16
      { "X-MS-TNEF-Correlator", "imf.ext.tnef-correlator", FT_STRING,  BASE_NONE, NULL, 0x0,
1223
16
        NULL, HFILL }},
1224
16
    { &hf_imf_ext_uidl,
1225
16
      { "X-UIDL", "imf.ext.uidl", FT_STRING,  BASE_NONE, NULL, 0x0,
1226
16
        NULL, HFILL }},
1227
16
    { &hf_imf_ext_authentication_warning,
1228
16
      { "X-Authentication-Warning", "imf.ext.authentication_warning", FT_STRING,  BASE_NONE,
1229
16
        NULL, 0x0, NULL, HFILL }},
1230
16
    { &hf_imf_ext_virus_scanned,
1231
16
      { "X-Virus-Scanned", "imf.ext.virus_scanned", FT_STRING,  BASE_NONE, NULL, 0x0,
1232
16
        NULL, HFILL }},
1233
16
    { &hf_imf_ext_original_to,
1234
16
      { "X-Original-To", "imf.ext.original-to", FT_STRING,  BASE_NONE, NULL, 0x0,
1235
16
        NULL, HFILL }},
1236
16
    { &hf_imf_thread_index,
1237
16
      { "Thread-Index", "imf.thread-index", FT_STRING,  BASE_NONE, NULL, 0x0,
1238
16
        NULL, HFILL }},
1239
16
    { &hf_imf_lines,
1240
16
      { "Lines", "imf.lines", FT_STRING,  BASE_NONE, NULL, 0x0,
1241
16
        NULL, HFILL }},
1242
16
    { &hf_imf_precedence,
1243
16
      { "Precedence", "imf.precedence", FT_STRING,  BASE_NONE, NULL, 0x0,
1244
16
        NULL, HFILL }},
1245
16
    { &hf_imf_extension,
1246
16
      { "Unknown-Extension", "imf.extension", FT_STRING,  BASE_NONE, NULL, 0x0,
1247
16
        NULL, HFILL }},
1248
16
    { &hf_imf_extension_type,
1249
16
      { "Type", "imf.extension.type", FT_STRING,  BASE_NONE, NULL, 0x0,
1250
16
        NULL, HFILL }},
1251
16
    { &hf_imf_extension_value,
1252
16
      { "Value", "imf.extension.value", FT_STRING,  BASE_NONE, NULL, 0x0,
1253
16
        NULL, HFILL }},
1254
16
    { &hf_imf_display_name,
1255
16
      { "Display-Name", "imf.display_name", FT_STRING,  BASE_NONE, NULL, 0x0,
1256
16
        NULL, HFILL }},
1257
16
    { &hf_imf_address,
1258
16
      { "Address", "imf.address", FT_STRING,  BASE_NONE, NULL, 0x0,
1259
16
        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
16
    { &hf_imf_address_list_item,
1266
16
      { "Item", "imf.address_list.item", FT_STRING,  BASE_NONE, NULL, 0x0,
1267
16
        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
16
    { &hf_imf_mailbox_list_item,
1274
16
      { "Item", "imf.mailbox_list.item", FT_STRING,  BASE_NONE, NULL, 0x0,
1275
16
        NULL, HFILL }},
1276
16
    { &hf_imf_siolabel,
1277
16
      { "SIO-Label", "imf.siolabel", FT_NONE,  BASE_NONE, NULL, 0x0,
1278
16
        NULL, HFILL }},
1279
16
    { &hf_imf_siolabel_marking,
1280
16
      { "Marking", "imf.siolabel.marking", FT_STRING,  BASE_NONE, NULL, 0x0,
1281
16
        NULL, HFILL }},
1282
16
    { &hf_imf_siolabel_fgcolor,
1283
16
      { "Foreground Color", "imf.siolabel.fgcolor", FT_STRING,  BASE_NONE, NULL, 0x0,
1284
16
        NULL, HFILL }},
1285
16
    { &hf_imf_siolabel_bgcolor,
1286
16
      { "Background Color", "imf.siolabel.bgcolor", FT_STRING,  BASE_NONE, NULL, 0x0,
1287
16
        NULL, HFILL }},
1288
16
    { &hf_imf_siolabel_type,
1289
16
      { "Type", "imf.siolabel.type", FT_STRING,  BASE_NONE, NULL, 0x0,
1290
16
        NULL, HFILL }},
1291
16
    { &hf_imf_siolabel_label,
1292
16
      { "Label", "imf.siolabel.label", FT_STRING,  BASE_NONE, NULL, 0x0,
1293
16
        NULL, HFILL }},
1294
16
    { &hf_imf_siolabel_unknown,
1295
16
      { "Unknown parameter", "imf.siolabel.unknown", FT_STRING,  BASE_NONE, NULL, 0x0,
1296
16
        NULL, HFILL }},
1297
16
    { &hf_imf_message_text,
1298
16
      { "Message-Text", "imf.message_text", FT_NONE,  BASE_NONE, NULL, 0x0,
1299
16
        NULL, HFILL }},
1300
16
  };
1301
16
  static int *ett[] = {
1302
16
    &ett_imf,
1303
16
    &ett_imf_content_type,
1304
16
    &ett_imf_group,
1305
16
    &ett_imf_mailbox,
1306
16
    &ett_imf_mailbox_list,
1307
16
    &ett_imf_address_list,
1308
16
    &ett_imf_siolabel,
1309
16
    &ett_imf_extension,
1310
16
    &ett_imf_message_text,
1311
16
  };
1312
1313
16
  static ei_register_info ei[] = {
1314
16
     { &ei_imf_unknown_param, { "imf.unknown_param", PI_PROTOCOL, PI_WARN, "Unknown parameter", EXPFILL }},
1315
16
  };
1316
1317
16
  static uat_field_t attributes_flds[] = {
1318
16
    UAT_FLD_CSTRING(header_fields, header_name, "Header name", "IMF header name"),
1319
16
    UAT_FLD_CSTRING(header_fields, description, "Description", "Description of the value contained in the header"),
1320
16
    UAT_FLD_VS(header_fields, header_format, "Format", header_format, 0),
1321
16
    UAT_FLD_VS(header_fields, add_to_col_info, "Add to Info column", add_to_col_info, 0),
1322
16
    UAT_END_FIELDS
1323
16
  };
1324
1325
16
  uat_t *headers_uat = uat_new("Custom IMF headers",
1326
16
                               sizeof(header_field_t),
1327
16
                               "imf_header_fields",
1328
16
                               true,
1329
16
                               &header_fields,
1330
16
                               &num_header_fields,
1331
                               /* specifies named fields, so affects dissection
1332
                                  and the set of named fields */
1333
16
                               UAT_AFFECTS_DISSECTION|UAT_AFFECTS_FIELDS,
1334
16
                               NULL,
1335
16
                               header_fields_copy_cb,
1336
16
                               header_fields_update_cb,
1337
16
                               header_fields_free_cb,
1338
16
                               header_fields_post_update_cb,
1339
16
                               header_fields_reset_cb,
1340
16
                               attributes_flds);
1341
1342
16
  module_t *imf_module;
1343
16
  expert_module_t* expert_imf;
1344
16
  const struct imf_field *f;
1345
1346
16
  proto_imf = proto_register_protocol("Internet Message Format", "IMF", "imf");
1347
1348
16
  proto_register_field_array(proto_imf, hf, array_length(hf));
1349
16
  proto_register_subtree_array(ett, array_length(ett));
1350
16
  expert_imf = expert_register_protocol(proto_imf);
1351
16
  expert_register_field_array(expert_imf, ei, array_length(ei));
1352
1353
  /* Allow dissector to find be found by name. */
1354
16
  imf_handle = register_dissector("imf", dissect_imf, proto_imf);
1355
1356
16
  imf_module = prefs_register_protocol(proto_imf, NULL);
1357
16
  prefs_register_uat_preference(imf_module, "custom_header_fields", "Custom IMF headers",
1358
16
                                "A table to define custom IMF headers for which fields can be "
1359
16
                                "setup and used for filtering/data extraction etc.",
1360
16
                                headers_uat);
1361
1362
16
  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
1.12k
  for(f = imf_fields; f->name; f++)
1366
1.10k
    wmem_map_insert(imf_field_table, (void *)f->name, (void *)f);
1367
1368
  /* Register for tapping */
1369
16
  imf_eo_tap = register_export_object(proto_imf, imf_eo_packet, NULL);
1370
1371
16
}
1372
1373
/* The registration hand-off routine */
1374
void
1375
proto_reg_handoff_imf(void)
1376
16
{
1377
16
  dissector_add_string("media_type",
1378
16
                       "message/rfc822", imf_handle);
1379
1380
16
  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
16
  media_type_dissector_table = find_dissector_table("media_type");
1386
1387
16
}
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
 */