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
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 
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