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