/src/wireshark/wiretap/mime_file.c
Line | Count | Source |
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 | | #include "mime_file.h" |
21 | | |
22 | | #include <sys/types.h> |
23 | | |
24 | | #ifdef HAVE_UNISTD_H |
25 | | #include <unistd.h> |
26 | | #endif |
27 | | |
28 | | #include <stdlib.h> |
29 | | #include <string.h> |
30 | | #include <time.h> |
31 | | |
32 | | #include "wtap_module.h" |
33 | | #include "file_wrappers.h" |
34 | | #include <wsutil/array.h> |
35 | | #include <wsutil/buffer.h> |
36 | | |
37 | | typedef struct { |
38 | | const uint8_t *magic; |
39 | | unsigned 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 uint8_t jpeg_jfif_magic[] = { 0xFF, 0xD8, /* SOF */ |
56 | | 0xFF /* start of the next marker */ |
57 | | }; |
58 | | |
59 | | /* <?xml */ |
60 | | static const uint8_t xml_magic[] = { '<', '?', 'x', 'm', 'l' }; |
61 | | static const uint8_t png_magic[] = { 0x89, 'P', 'N', 'G', '\r', '\n', 0x1A, '\n' }; |
62 | | static const uint8_t gif87a_magic[] = { 'G', 'I', 'F', '8', '7', 'a'}; |
63 | | static const uint8_t gif89a_magic[] = { 'G', 'I', 'F', '8', '9', 'a'}; |
64 | | static const uint8_t elf_magic[] = { 0x7F, 'E', 'L', 'F'}; |
65 | | static const uint8_t tiff_le_magic[] = { 'I', 'I', 42, 0 }; |
66 | | static const uint8_t tiff_be_magic[] = { 'M', 'M', 0, 42 }; |
67 | | static const uint8_t riff_magic[] = { 'R', 'I', 'F', 'F' }; |
68 | | static const uint8_t btsnoop_magic[] = { 'b', 't', 's', 'n', 'o', 'o', 'p', 0}; |
69 | | static const uint8_t pcap_magic[] = { 0xA1, 0xB2, 0xC3, 0xD4 }; |
70 | | static const uint8_t pcap_swapped_magic[] = { 0xD4, 0xC3, 0xB2, 0xA1 }; |
71 | | static const uint8_t pcap_nsec_magic[] = { 0xA1, 0xB2, 0x3C, 0x4D }; |
72 | | static const uint8_t pcap_nsec_swapped_magic[] = { 0x4D, 0x3C, 0xB2, 0xA1 }; |
73 | | static const uint8_t pcapng_premagic[] = { 0x0A, 0x0D, 0x0D, 0x0A }; |
74 | | static const uint8_t blf_magic[] = { 'L', 'O', 'G', 'G' }; |
75 | | static const uint8_t autosar_dlt_magic[] = { 'D', 'L', 'T', 0x01 }; |
76 | | static const uint8_t ttl_magic[] = { 'T', 'T', 'L', ' ' }; |
77 | | static const uint8_t zip_magic[] = { 'P', 'K', 0x03, 0x04 }; |
78 | | static const uint8_t rtpdump_magic[] = { '#', '!', 'r', 't', 'p', 'p', 'l', 'a', 'y', '1', '.', '0', ' ' }; |
79 | | |
80 | | /* File does not start with it */ |
81 | | static const uint8_t pcapng_xmagic[] = { 0x1A, 0x2B, 0x3C, 0x4D }; |
82 | | static const uint8_t pcapng_swapped_xmagic[] = { 0x4D, 0x3C, 0x2B, 0x1A }; |
83 | | |
84 | | static const mime_files_t magic_files[] = { |
85 | | { jpeg_jfif_magic, sizeof(jpeg_jfif_magic) }, |
86 | | { xml_magic, sizeof(xml_magic) }, |
87 | | { png_magic, sizeof(png_magic) }, |
88 | | { gif87a_magic, sizeof(gif87a_magic) }, |
89 | | { gif89a_magic, sizeof(gif89a_magic) }, |
90 | | { elf_magic, sizeof(elf_magic) }, |
91 | | { tiff_le_magic, sizeof(tiff_le_magic) }, |
92 | | { tiff_be_magic, sizeof(tiff_be_magic) }, |
93 | | { riff_magic, sizeof(riff_magic) }, |
94 | | { btsnoop_magic, sizeof(btsnoop_magic) }, |
95 | | { pcap_magic, sizeof(pcap_magic) }, |
96 | | { pcap_swapped_magic, sizeof(pcap_swapped_magic) }, |
97 | | { pcap_nsec_magic, sizeof(pcap_nsec_magic) }, |
98 | | { pcap_nsec_swapped_magic, sizeof(pcap_nsec_swapped_magic) }, |
99 | | { pcapng_premagic, sizeof(pcapng_premagic) }, |
100 | | { blf_magic, sizeof(blf_magic) }, |
101 | | { autosar_dlt_magic, sizeof(autosar_dlt_magic) }, |
102 | | { ttl_magic, sizeof(ttl_magic) }, |
103 | | { zip_magic, sizeof(zip_magic) }, |
104 | | { rtpdump_magic, sizeof(rtpdump_magic) }, |
105 | | }; |
106 | | |
107 | 0 | #define N_MAGIC_TYPES array_length(magic_files) |
108 | | |
109 | | static int mime_file_type_subtype = -1; |
110 | | |
111 | | void register_mime(void); |
112 | | |
113 | | wtap_open_return_val |
114 | | mime_file_open(wtap *wth, int *err, char **err_info) |
115 | 0 | { |
116 | 0 | char magic_buf[128]; /* increase buffer size when needed */ |
117 | 0 | int bytes_read; |
118 | 0 | bool found_file; |
119 | | /* unsigned file_ok; */ |
120 | 0 | unsigned i; |
121 | |
|
122 | 0 | unsigned read_bytes = 12; |
123 | |
|
124 | 0 | for (i = 0; i < N_MAGIC_TYPES; i++) |
125 | 0 | read_bytes = MAX(read_bytes, magic_files[i].magic_len); |
126 | |
|
127 | 0 | read_bytes = (unsigned)MIN(read_bytes, sizeof(magic_buf)); |
128 | 0 | bytes_read = file_read(magic_buf, read_bytes, wth->fh); |
129 | |
|
130 | 0 | if (bytes_read < 0) { |
131 | 0 | *err = file_error(wth->fh, err_info); |
132 | 0 | return WTAP_OPEN_ERROR; |
133 | 0 | } |
134 | 0 | if (bytes_read == 0) |
135 | 0 | return WTAP_OPEN_NOT_MINE; |
136 | | |
137 | 0 | found_file = false; |
138 | 0 | for (i = 0; i < N_MAGIC_TYPES; i++) { |
139 | 0 | if ((unsigned) bytes_read >= magic_files[i].magic_len && !memcmp(magic_buf, magic_files[i].magic, MIN(magic_files[i].magic_len, (unsigned) bytes_read))) { |
140 | 0 | if (!found_file) { |
141 | 0 | if (magic_files[i].magic == pcapng_premagic) { |
142 | 0 | if (memcmp(magic_buf + 8, pcapng_xmagic, sizeof(pcapng_xmagic)) && |
143 | 0 | memcmp(magic_buf + 8, pcapng_swapped_xmagic, sizeof(pcapng_swapped_xmagic))) |
144 | 0 | continue; |
145 | 0 | } |
146 | 0 | found_file = true; |
147 | 0 | } else |
148 | 0 | return WTAP_OPEN_NOT_MINE; /* many files matched, bad file */ |
149 | 0 | } |
150 | 0 | } |
151 | | |
152 | 0 | if (!found_file) |
153 | 0 | return WTAP_OPEN_NOT_MINE; |
154 | | |
155 | 0 | if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) |
156 | 0 | return WTAP_OPEN_ERROR; |
157 | | |
158 | 0 | wth->file_type_subtype = mime_file_type_subtype; |
159 | 0 | wth->file_encap = WTAP_ENCAP_MIME; |
160 | 0 | wth->file_tsprec = WTAP_TSPREC_SEC; |
161 | 0 | wth->subtype_read = wtap_full_file_read; |
162 | 0 | wth->subtype_seek_read = wtap_full_file_seek_read; |
163 | 0 | wth->snapshot_length = 0; |
164 | |
|
165 | 0 | return WTAP_OPEN_MINE; |
166 | 0 | } |
167 | | |
168 | | static const struct supported_block_type mime_blocks_supported[] = { |
169 | | /* |
170 | | * This is a file format that we dissect, so we provide |
171 | | * only one "packet" with the file's contents, and don't |
172 | | * support any options. |
173 | | */ |
174 | | { WTAP_BLOCK_PACKET, ONE_BLOCK_SUPPORTED, NO_OPTIONS_SUPPORTED } |
175 | | }; |
176 | | |
177 | | static const struct file_type_subtype_info mime_info = { |
178 | | "MIME File Format", "mime", NULL, NULL, |
179 | | false, BLOCKS_SUPPORTED(mime_blocks_supported), |
180 | | NULL, NULL, NULL |
181 | | }; |
182 | | |
183 | | /* |
184 | | * XXX - registered solely for the benefit of Lua scripts that |
185 | | * look for the file type "JPEG_JFIF"; it may be removed once |
186 | | * we get rid of wtap_filetypes. |
187 | | */ |
188 | | static const struct supported_block_type jpeg_jfif_blocks_supported[] = { |
189 | | /* |
190 | | * This is a file format that we dissect, so we provide |
191 | | * only one "packet" with the file's contents, and don't |
192 | | * support any options. |
193 | | */ |
194 | | { WTAP_BLOCK_PACKET, ONE_BLOCK_SUPPORTED, NO_OPTIONS_SUPPORTED } |
195 | | }; |
196 | | |
197 | | static const struct file_type_subtype_info jpeg_jfif_info = { |
198 | | "JPEG/JFIF", "jpeg", "jpg", "jpeg;jfif", |
199 | | false, BLOCKS_SUPPORTED(jpeg_jfif_blocks_supported), |
200 | | NULL, NULL, NULL |
201 | | }; |
202 | | |
203 | | void register_mime(void) |
204 | 15 | { |
205 | 15 | int jpeg_jfif_file_type_subtype; |
206 | | |
207 | 15 | mime_file_type_subtype = wtap_register_file_type_subtype(&mime_info); |
208 | | |
209 | | /* |
210 | | * Obsoleted by "mime", but we want it for the backwards- |
211 | | * compatibility table for Lua. |
212 | | */ |
213 | 15 | jpeg_jfif_file_type_subtype = wtap_register_file_type_subtype(&jpeg_jfif_info); |
214 | | |
215 | | /* |
216 | | * Register names for backwards compatibility with the |
217 | | * wtap_filetypes table in Lua. |
218 | | */ |
219 | 15 | wtap_register_backwards_compatibility_lua_name("MIME", |
220 | 15 | mime_file_type_subtype); |
221 | 15 | wtap_register_backwards_compatibility_lua_name("JPEG_JFIF", |
222 | 15 | jpeg_jfif_file_type_subtype); |
223 | 15 | } |
224 | | |
225 | | /* |
226 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
227 | | * |
228 | | * Local variables: |
229 | | * c-basic-offset: 8 |
230 | | * tab-width: 8 |
231 | | * indent-tabs-mode: t |
232 | | * End: |
233 | | * |
234 | | * vi: set shiftwidth=8 tabstop=8 noexpandtab: |
235 | | * :indentSize=8:tabSize=8:noTabs=false: |
236 | | */ |