1 /* mime_file.c
2 *
3 * MIME file format decoder for the Wiretap library.
4 *
5 * This is for use with Wireshark dissectors that handle file
6 * formats (e.g., because they handle a particular MIME media type).
7 * It breaks the file into chunks of at most WTAP_MAX_PACKET_SIZE_STANDARD,
8 * each of which is reported as a packet, so that files larger than
9 * WTAP_MAX_PACKET_SIZE_STANDARD can be handled by reassembly.
10 *
11 * The "MIME file" dissector does the reassembly, and hands the result
12 * off to heuristic dissectors to try to identify the file's contents.
13 *
14 * Wiretap Library
15 *
16 * SPDX-License-Identifier: GPL-2.0-or-later
17 */
18
19 #include "config.h"
20
21 #include <sys/types.h>
22
23 #ifdef HAVE_UNISTD_H
24 #include <unistd.h>
25 #endif
26
27 #include <errno.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <time.h>
31
32 #include "wtap-int.h"
33 #include "file_wrappers.h"
34 #include <wsutil/buffer.h>
35 #include "mime_file.h"
36
37 typedef struct {
38 const guint8 *magic;
39 guint magic_len;
40 } mime_files_t;
41
42 /*
43 * Written by Marton Nemeth <nm127@freemail.hu>
44 * Copyright 2009 Marton Nemeth
45 * The JPEG specification can be found at:
46 *
47 * https://www.w3.org/Graphics/JPEG/itu-t81.pdf
48 * https://www.itu.int/rec/T-REC-T.81/en (but you have to pay for it)
49 *
50 * and the JFIF specification can be found at:
51 *
52 * https://www.itu.int/rec/T-REC-T.871-201105-I/en
53 * https://www.w3.org/Graphics/JPEG/jfif3.pdf
54 */
55 static const guint8 jpeg_jfif_magic[] = { 0xFF, 0xD8, /* SOF */
56 0xFF /* start of the next marker */
57 };
58
59 /* <?xml */
60 static const guint8 xml_magic[] = { '<', '?', 'x', 'm', 'l' };
61 static const guint8 png_magic[] = { 0x89, 'P', 'N', 'G', '\r', '\n', 0x1A, '\n' };
62 static const guint8 gif87a_magic[] = { 'G', 'I', 'F', '8', '7', 'a'};
63 static const guint8 gif89a_magic[] = { 'G', 'I', 'F', '8', '9', 'a'};
64 static const guint8 elf_magic[] = { 0x7F, 'E', 'L', 'F'};
65 static const guint8 tiff_le_magic[] = { 'I', 'I', 42, 0 };
66 static const guint8 tiff_be_magic[] = { 'M', 'M', 0, 42 };
67 static const guint8 btsnoop_magic[] = { 'b', 't', 's', 'n', 'o', 'o', 'p', 0};
68 static const guint8 pcap_magic[] = { 0xA1, 0xB2, 0xC3, 0xD4 };
69 static const guint8 pcap_swapped_magic[] = { 0xD4, 0xC3, 0xB2, 0xA1 };
70 static const guint8 pcap_nsec_magic[] = { 0xA1, 0xB2, 0x3C, 0x4D };
71 static const guint8 pcap_nsec_swapped_magic[] = { 0x4D, 0x3C, 0xB2, 0xA1 };
72 static const guint8 pcapng_premagic[] = { 0x0A, 0x0D, 0x0D, 0x0A };
73 static const guint8 blf_magic[] = { 'L', 'O', 'G', 'G' };
74
75 /* File does not start with it */
76 static const guint8 pcapng_xmagic[] = { 0x1A, 0x2B, 0x3C, 0x4D };
77 static const guint8 pcapng_swapped_xmagic[] = { 0x4D, 0x3C, 0x2B, 0x1A };
78
79 static const mime_files_t magic_files[] = {
80 { jpeg_jfif_magic, sizeof(jpeg_jfif_magic) },
81 { xml_magic, sizeof(xml_magic) },
82 { png_magic, sizeof(png_magic) },
83 { gif87a_magic, sizeof(gif87a_magic) },
84 { gif89a_magic, sizeof(gif89a_magic) },
85 { elf_magic, sizeof(elf_magic) },
86 { tiff_le_magic, sizeof(tiff_le_magic) },
87 { tiff_be_magic, sizeof(tiff_be_magic) },
88 { btsnoop_magic, sizeof(btsnoop_magic) },
89 { pcap_magic, sizeof(pcap_magic) },
90 { pcap_swapped_magic, sizeof(pcap_swapped_magic) },
91 { pcap_nsec_magic, sizeof(pcap_nsec_magic) },
92 { pcap_nsec_swapped_magic, sizeof(pcap_nsec_swapped_magic) },
93 { pcapng_premagic, sizeof(pcapng_premagic) },
94 { blf_magic, sizeof(blf_magic) }
95 };
96
97 #define N_MAGIC_TYPES (sizeof(magic_files) / sizeof(magic_files[0]))
98
99 static int mime_file_type_subtype = -1;
100
101 void register_mime(void);
102
103 wtap_open_return_val
mime_file_open(wtap * wth,int * err,gchar ** err_info)104 mime_file_open(wtap *wth, int *err, gchar **err_info)
105 {
106 char magic_buf[128]; /* increase buffer size when needed */
107 int bytes_read;
108 gboolean found_file;
109 /* guint file_ok; */
110 guint i;
111
112 guint read_bytes = 12;
113
114 for (i = 0; i < N_MAGIC_TYPES; i++)
115 read_bytes = MAX(read_bytes, magic_files[i].magic_len);
116
117 read_bytes = (guint)MIN(read_bytes, sizeof(magic_buf));
118 bytes_read = file_read(magic_buf, read_bytes, wth->fh);
119
120 if (bytes_read < 0) {
121 *err = file_error(wth->fh, err_info);
122 return WTAP_OPEN_ERROR;
123 }
124 if (bytes_read == 0)
125 return WTAP_OPEN_NOT_MINE;
126
127 found_file = FALSE;
128 for (i = 0; i < N_MAGIC_TYPES; i++) {
129 if ((guint) bytes_read >= magic_files[i].magic_len && !memcmp(magic_buf, magic_files[i].magic, MIN(magic_files[i].magic_len, (guint) bytes_read))) {
130 if (!found_file) {
131 if (magic_files[i].magic == pcapng_premagic) {
132 if (memcmp(magic_buf + 8, pcapng_xmagic, sizeof(pcapng_xmagic)) &&
133 memcmp(magic_buf + 8, pcapng_swapped_xmagic, sizeof(pcapng_swapped_xmagic)))
134 continue;
135 }
136 found_file = TRUE;
137 } else
138 return WTAP_OPEN_NOT_MINE; /* many files matched, bad file */
139 }
140 }
141
142 if (!found_file)
143 return WTAP_OPEN_NOT_MINE;
144
145 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
146 return WTAP_OPEN_ERROR;
147
148 wth->file_type_subtype = mime_file_type_subtype;
149 wth->file_encap = WTAP_ENCAP_MIME;
150 wth->file_tsprec = WTAP_TSPREC_SEC;
151 wth->subtype_read = wtap_full_file_read;
152 wth->subtype_seek_read = wtap_full_file_seek_read;
153 wth->snapshot_length = 0;
154
155 return WTAP_OPEN_MINE;
156 }
157
158 static const struct supported_block_type mime_blocks_supported[] = {
159 /*
160 * This is a file format that we dissect, so we provide
161 * only one "packet" with the file's contents, and don't
162 * support any options.
163 */
164 { WTAP_BLOCK_PACKET, ONE_BLOCK_SUPPORTED, NO_OPTIONS_SUPPORTED }
165 };
166
167 static const struct file_type_subtype_info mime_info = {
168 "MIME File Format", "mime", NULL, NULL,
169 FALSE, BLOCKS_SUPPORTED(mime_blocks_supported),
170 NULL, NULL, NULL
171 };
172
173 /*
174 * XXX - registered solely for the benefit of Lua scripts that
175 * look for the file type "JPEG_JFIF"; it may be removed once
176 * we get rid of wtap_filetypes.
177 */
178 static const struct supported_block_type jpeg_jfif_blocks_supported[] = {
179 /*
180 * This is a file format that we dissect, so we provide
181 * only one "packet" with the file's contents, and don't
182 * support any options.
183 */
184 { WTAP_BLOCK_PACKET, ONE_BLOCK_SUPPORTED, NO_OPTIONS_SUPPORTED }
185 };
186
187 static const struct file_type_subtype_info jpeg_jfif_info = {
188 "JPEG/JFIF", "jpeg", "jpg", "jpeg;jfif",
189 FALSE, BLOCKS_SUPPORTED(jpeg_jfif_blocks_supported),
190 NULL, NULL, NULL
191 };
192
register_mime(void)193 void register_mime(void)
194 {
195 int jpeg_jfif_file_type_subtype;
196
197 mime_file_type_subtype = wtap_register_file_type_subtype(&mime_info);
198
199 /*
200 * Obsoleted by "mime", but we want it for the backwards-
201 * compatibility table for Lua.
202 */
203 jpeg_jfif_file_type_subtype = wtap_register_file_type_subtype(&jpeg_jfif_info);
204
205 /*
206 * Register names for backwards compatibility with the
207 * wtap_filetypes table in Lua.
208 */
209 wtap_register_backwards_compatibility_lua_name("MIME",
210 mime_file_type_subtype);
211 wtap_register_backwards_compatibility_lua_name("JPEG_JFIF",
212 jpeg_jfif_file_type_subtype);
213 }
214
215 /*
216 * Editor modelines - https://www.wireshark.org/tools/modelines.html
217 *
218 * Local variables:
219 * c-basic-offset: 8
220 * tab-width: 8
221 * indent-tabs-mode: t
222 * End:
223 *
224 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
225 * :indentSize=8:tabSize=8:noTabs=false:
226 */
227