wiretap: fix truncated reads while reading compressed file formats
authorPeter Wu <peter@lekensteyn.nl>
Sat, 10 Nov 2018 22:03:16 +0000 (23:03 +0100)
committerMichael Mann <mmann78@netscape.net>
Sat, 10 Nov 2018 23:24:05 +0000 (23:24 +0000)
A lot of file dissectors (pcapng, json, etc.) assumed that the packet
size is equal to the file size. This is not true if the file was
compressed and could result in silently truncating reads or failing to
open a file (if the compressed file is larger than the actual data).

Observe that a lot of file dissectors are simply copies of each other.
Move the fixed implementation to wtap.c and reuse the methods everywhere
else. While at it, avoid an unnecessary large allocation/read in
ruby_marshal.

Change-Id: I8e9cd0af9c4d1bd37789a3b509146ae2182a5379
Reviewed-on: https://code.wireshark.org/review/30570
Petri-Dish: Peter Wu <peter@lekensteyn.nl>
Reviewed-by: Dario Lombardo <lomato@gmail.com>
Tested-by: Dario Lombardo <lomato@gmail.com>
Tested-by: Petri Dish Buildbot
Reviewed-by: Michael Mann <mmann78@netscape.net>
test/suite_fileformats.py
wiretap/ber.c
wiretap/json.c
wiretap/json.h
wiretap/mime_file.c
wiretap/rfc7468.c
wiretap/ruby_marshal.c
wiretap/tnef.c
wiretap/wtap-int.h
wiretap/wtap.c

index 6ebf88d2fb64bdd85a41806b60fa7f3db36d58a4..3c3f55136b06b4e4f414d74631e22a6c68182348 100644 (file)
@@ -15,6 +15,7 @@ import os.path
 import subprocesstest
 import sys
 import unittest
+import fixtures
 
 # XXX Currently unused. It would be nice to be able to use this below.
 time_output_args = ('-Tfields', '-e', 'frame.number', '-e', 'frame.time_epoch', '-e', 'frame.time_delta')
@@ -110,3 +111,16 @@ class case_fileformat_pcapng(subprocesstest.SubprocessTestCase):
             )
         self.assertTrue(self.diffOutput(capture_proc.stdout_str, baseline_str, 'tshark', baseline_file))
 
+
+@fixtures.mark_usefixtures('test_env')
+@fixtures.uses_fixtures
+class case_fileformat_mime(subprocesstest.SubprocessTestCase):
+    def test_mime_pcapng_gz(self, cmd_tshark, dirs):
+        '''Test that the full uncompressed contents is shown.'''
+        capture_file = os.path.join(dirs.capture_dir, 'icmp.pcapng.gz')
+        proc = self.runProcess((cmd_tshark,
+                '-r', capture_file,
+                '-Xread_format:MIME Files Format',
+                '-Tfields', '-e', 'frame.len', '-e', 'pcapng.block.length',
+            ))
+        self.assertEqual(proc.stdout_str.strip(), '480\t128,128,88,88,132,132,132,132')
index a9bac44a9badead71c57a91d9d4b378b23b18d1b..ea4e243cc4f1a5c60ad3fe304682053b0ffa1eed 100644 (file)
 #define BER_UNI_TAG_SEQ 16      /* SEQUENCE, SEQUENCE OF */
 #define BER_UNI_TAG_SET 17      /* SET, SET OF */
 
-static gboolean ber_read_file(wtap *wth, FILE_T fh, wtap_rec *rec,
-                              Buffer *buf, int *err, gchar **err_info)
-{
-  gint64 file_size;
-  int packet_size;
-
-  if ((file_size = wtap_file_size(wth, err)) == -1)
-    return FALSE;
-
-  if (file_size > G_MAXINT) {
-    /*
-     * Probably a corrupt capture file; don't blow up trying
-     * to allocate space for an immensely-large packet.
-     */
-    *err = WTAP_ERR_BAD_FILE;
-    *err_info = g_strdup_printf("ber: File has %" G_GINT64_MODIFIER "d-byte packet, bigger than maximum of %u",
-                                file_size, G_MAXINT);
-    return FALSE;
-  }
-  packet_size = (int)file_size;
-
-  rec->rec_type = REC_TYPE_PACKET;
-  rec->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */
-
-  rec->rec_header.packet_header.caplen = packet_size;
-  rec->rec_header.packet_header.len = packet_size;
-
-  rec->ts.secs = 0;
-  rec->ts.nsecs = 0;
-
-  return wtap_read_packet_bytes(fh, buf, packet_size, err, err_info);
-}
-
-static gboolean ber_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
-{
-  gint64 offset;
-
-  *err = 0;
-
-  offset = file_tell(wth->fh);
-
-  /* there is only ever one packet */
-  if (offset != 0)
-    return FALSE;
-
-  *data_offset = offset;
-
-  return ber_read_file(wth, wth->fh, &wth->rec, wth->rec_data, err, err_info);
-}
-
-static gboolean ber_seek_read(wtap *wth, gint64 seek_off, wtap_rec *rec,
-                              Buffer *buf, int *err, gchar **err_info)
-{
-  /* there is only one packet */
-  if(seek_off > 0) {
-    *err = 0;
-    return FALSE;
-  }
-
-  if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
-    return FALSE;
-
-  return ber_read_file(wth, wth->random_fh, rec, buf, err, err_info);
-}
-
 wtap_open_return_val ber_open(wtap *wth, int *err, gchar **err_info)
 {
 #define BER_BYTES_TO_CHECK 8
@@ -159,8 +94,8 @@ wtap_open_return_val ber_open(wtap *wth, int *err, gchar **err_info)
   wth->file_encap = WTAP_ENCAP_BER;
   wth->snapshot_length = 0;
 
-  wth->subtype_read = ber_read;
-  wth->subtype_seek_read = ber_seek_read;
+  wth->subtype_read = wtap_full_file_read;
+  wth->subtype_seek_read = wtap_full_file_seek_read;
   wth->file_tsprec = WTAP_TSPREC_SEC;
 
   return WTAP_OPEN_MINE;
index c8d016905d61d3d6dedf3f06b6adff5dc31ed44c..8bb7fe4d20494262562446e876e1df70258c3f00 100644 (file)
 #include "json.h"
 #include <wsutil/wsjson.h>
 
-static gboolean json_read_file(wtap *wth, FILE_T fh, wtap_rec *rec,
-    Buffer *buf, int *err, gchar **err_info)
-{
-    gint64 file_size;
-    int packet_size;
-
-    if ((file_size = wtap_file_size(wth, err)) == -1)
-        return FALSE;
-
-    if (file_size > MAX_FILE_SIZE) {
-        /*
-         * Don't blow up trying to allocate space for an
-         * immensely-large file.
-         */
-        *err = WTAP_ERR_BAD_FILE;
-        *err_info = g_strdup_printf("json: File has %" G_GINT64_MODIFIER "d-byte packet, bigger than maximum of %u",
-            file_size, MAX_FILE_SIZE);
-        return FALSE;
-    }
-    packet_size = (int)file_size;
-
-    rec->rec_type = REC_TYPE_PACKET;
-    rec->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */
-
-    rec->rec_header.packet_header.caplen = packet_size;
-    rec->rec_header.packet_header.len = packet_size;
-
-    rec->ts.secs = 0;
-    rec->ts.nsecs = 0;
-
-    return wtap_read_packet_bytes(fh, buf, packet_size, err, err_info);
-}
-
-static gboolean json_seek_read(wtap *wth, gint64 seek_off, wtap_rec *rec, Buffer *buf,
-    int *err, gchar **err_info)
-{
-    /* there is only one packet */
-    if (seek_off > 0) {
-        *err = 0;
-        return FALSE;
-    }
-
-    if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
-        return FALSE;
-
-    return json_read_file(wth, wth->random_fh, rec, buf, err, err_info);
-}
-
-static gboolean json_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
-{
-    gint64 offset;
-
-    *err = 0;
-
-    offset = file_tell(wth->fh);
-
-    /* there is only ever one packet */
-    if (offset != 0)
-        return FALSE;
-
-    *data_offset = offset;
-
-    return json_read_file(wth, wth->fh, &wth->rec, wth->rec_data, err, err_info);
-}
+/* Maximum size of json file. */
+#define MAX_FILE_SIZE  (50*1024*1024)
 
 wtap_open_return_val json_open(wtap *wth, int *err, gchar **err_info)
 {
     guint8* filebuf;
     int bytes_read;
 
+    /* XXX checking the full file contents might be a bit expensive, maybe
+     * resort to simpler heuristics like '{' or '[' (with some other chars)? */
     filebuf = (guint8*)g_malloc0(MAX_FILE_SIZE);
     if (!filebuf)
         return WTAP_OPEN_ERROR;
@@ -115,8 +55,8 @@ wtap_open_return_val json_open(wtap *wth, int *err, gchar **err_info)
     wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_JSON;
     wth->file_encap = WTAP_ENCAP_JSON;
     wth->file_tsprec = WTAP_TSPREC_SEC;
-    wth->subtype_read = json_read;
-    wth->subtype_seek_read = json_seek_read;
+    wth->subtype_read = wtap_full_file_read;
+    wth->subtype_seek_read = wtap_full_file_seek_read;
     wth->snapshot_length = 0;
 
     g_free(filebuf);
index 0803ef0b737606cbeb6278dcf39fe7ea38b1b0f0..5b13852d81bed0fd25c228c9874a7b7d45f6969b 100644 (file)
 
 #include "wtap.h"
 
-/*
- * Impose a not-too-large limit on the maximum file size, to avoid eating
- * up 99% of the (address space, swap partition, disk space for swap/page
- * files); if we were to return smaller chunks and let the dissector do
- * reassembly, it would *still* have to allocate a buffer the size of
- * the file, so it's not as if we'd neve try to allocate a buffer the
- * size of the file.
- *
- * For now, go for 50MB.
- */
-#define MAX_FILE_SIZE  (50*1024*1024)
-
 wtap_open_return_val json_open(wtap *wth, int *err, gchar **err_info);
 
 #endif
index 021f27a5e7fec523baa4d6d60f8f150bde87cb08..88bf207ea840cebabeda1087037e1df34b87e0fd 100644 (file)
@@ -81,83 +81,6 @@ static const mime_files_t magic_files[] = {
 
 #define        N_MAGIC_TYPES   (sizeof(magic_files) / sizeof(magic_files[0]))
 
-/*
- * Impose a not-too-large limit on the maximum file size, to avoid eating
- * up 99% of the (address space, swap partition, disk space for swap/page
- * files); if we were to return smaller chunks and let the dissector do
- * reassembly, it would *still* have to allocate a buffer the size of
- * the file, so it's not as if we'd neve try to allocate a buffer the
- * size of the file.
- */
-#define MAX_FILE_SIZE  G_MAXINT
-
-static gboolean
-mime_read_file(wtap *wth, FILE_T fh, wtap_rec *rec,
-    Buffer *buf, int *err, gchar **err_info)
-{
-       gint64 file_size;
-       int packet_size;
-
-       if ((file_size = wtap_file_size(wth, err)) == -1)
-               return FALSE;
-
-       if (file_size > MAX_FILE_SIZE) {
-               /*
-                * Don't blow up trying to allocate space for an
-                * immensely-large file.
-                */
-               *err = WTAP_ERR_BAD_FILE;
-               *err_info = g_strdup_printf("mime_file: File has %" G_GINT64_MODIFIER "d-byte packet, bigger than maximum of %u",
-                               file_size, MAX_FILE_SIZE);
-               return FALSE;
-       }
-       packet_size = (int)file_size;
-
-       rec->rec_type = REC_TYPE_PACKET;
-       rec->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */
-
-       rec->rec_header.packet_header.caplen = packet_size;
-       rec->rec_header.packet_header.len = packet_size;
-
-       rec->ts.secs = 0;
-       rec->ts.nsecs = 0;
-
-       return wtap_read_packet_bytes(fh, buf, packet_size, err, err_info);
-}
-
-static gboolean
-mime_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
-{
-       gint64 offset;
-
-       *err = 0;
-
-       offset = file_tell(wth->fh);
-
-       /* there is only ever one packet */
-       if (offset != 0)
-               return FALSE;
-
-       *data_offset = offset;
-
-       return mime_read_file(wth, wth->fh, &wth->rec, wth->rec_data, err, err_info);
-}
-
-static gboolean
-mime_seek_read(wtap *wth, gint64 seek_off, wtap_rec *rec, Buffer *buf, int *err, gchar **err_info)
-{
-       /* there is only one packet */
-       if (seek_off > 0) {
-               *err = 0;
-               return FALSE;
-       }
-
-       if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
-               return FALSE;
-
-       return mime_read_file(wth, wth->random_fh, rec, buf, err, err_info);
-}
-
 wtap_open_return_val
 mime_file_open(wtap *wth, int *err, gchar **err_info)
 {
@@ -206,8 +129,8 @@ mime_file_open(wtap *wth, int *err, gchar **err_info)
        wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_MIME;
        wth->file_encap = WTAP_ENCAP_MIME;
        wth->file_tsprec = WTAP_TSPREC_SEC;
-       wth->subtype_read = mime_read;
-       wth->subtype_seek_read = mime_seek_read;
+       wth->subtype_read = wtap_full_file_read;
+       wth->subtype_seek_read = wtap_full_file_seek_read;
        wth->snapshot_length = 0;
 
        return WTAP_OPEN_MINE;
index 3d7cb56b82a220c440ad38b711551b289d4d7feb..d5c53d67a7d2f409eccdcd9b5bc01373c573a09c 100644 (file)
 
 #include <string.h>
 
-static gboolean rfc7468_read_file(wtap *wth, FILE_T fh, wtap_rec *rec,
-                                  Buffer *buf, int *err, gchar **err_info)
-{
-    gint64 file_size;
-    int packet_size;
-
-    if ((file_size = wtap_file_size(wth, err)) == -1)
-        return FALSE;
-
-    if (file_size > G_MAXINT) {
-        /*
-         * Probably a corrupt capture file; don't blow up trying
-         * to allocate space for an immensely-large packet.
-         */
-        *err = WTAP_ERR_BAD_FILE;
-        *err_info = g_strdup_printf("rfc7468: File has %" G_GINT64_MODIFIER "d-byte packet, bigger than maximum of %u",
-                                    file_size, G_MAXINT);
-        return FALSE;
-    }
-    packet_size = (int)file_size;
-
-    rec->rec_type = REC_TYPE_PACKET;
-    rec->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */
-
-    rec->rec_header.packet_header.caplen = packet_size;
-    rec->rec_header.packet_header.len = packet_size;
-
-    rec->ts.secs = 0;
-    rec->ts.nsecs = 0;
-
-    return wtap_read_packet_bytes(fh, buf, packet_size, err, err_info);
-}
-
 /* 128 bytes should be enough to contain any line. Strictly speaking, 64 is
    enough, but we provide some leeway to accomodate nonconformant producers and
    trailing whitespace. The 2 extra bytes are for the trailing newline and NUL
@@ -79,38 +46,6 @@ static char *read_complete_text_line(char line[MAX_LINE_LENGTH], FILE_T fh, int
     return line_end;
 }
 
-static gboolean rfc7468_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
-{
-    gint64 offset;
-
-    *err = 0;
-
-    offset = file_tell(wth->fh);
-
-    /* there is only ever one packet */
-    if (offset != 0)
-        return FALSE;
-
-    *data_offset = offset;
-
-    return rfc7468_read_file(wth, wth->fh, &wth->rec, wth->rec_data, err, err_info);
-}
-
-static gboolean rfc7468_seek_read(wtap *wth, gint64 seek_off, wtap_rec *rec,
-                              Buffer *buf, int *err, gchar **err_info)
-{
-    /* there is only one packet */
-    if (seek_off > 0) {
-        *err = 0;
-        return FALSE;
-    }
-
-    if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
-        return FALSE;
-
-    return rfc7468_read_file(wth, wth->random_fh, rec, buf, err, err_info);
-}
-
 //
 // Arbitrary value - we don't want to read all of a huge non-RFC 7468 file
 // only to find no pre-encapsulation boundary.
@@ -154,8 +89,8 @@ wtap_open_return_val rfc7468_open(wtap *wth, int *err, gchar **err_info)
     wth->snapshot_length = 0;
     wth->file_tsprec = WTAP_TSPREC_SEC;
 
-    wth->subtype_read = rfc7468_read;
-    wth->subtype_seek_read = rfc7468_seek_read;
+    wth->subtype_read = wtap_full_file_read;
+    wth->subtype_seek_read = wtap_full_file_seek_read;
 
     return WTAP_OPEN_MINE;
 }
index 1cff7ccbd1c8639da64b224bdc9f53c83c8b58c7..abe54467684383246a9c7de553106cdea6c4fe5f 100644 (file)
 
 #include "ruby_marshal.h"
 
-/*
- * Impose a not-too-large limit on the maximum file size, to avoid eating
- * up 99% of the (address space, swap partition, disk space for swap/page
- * files); if we were to return smaller chunks and let the dissector do
- * reassembly, it would *still* have to allocate a buffer the size of
- * the file, so it's not as if we'd neve try to allocate a buffer the
- * size of the file.
- *
- * For now, go for 50MB.
- */
-#define MAX_FILE_SIZE (50*1024*1024)
-
-static gboolean ruby_marshal_read_file(wtap *wth, FILE_T fh, wtap_rec *rec,
-    Buffer *buf, int *err, gchar **err_info)
-{
-    gint64 file_size;
-    int packet_size;
-
-    if ((file_size = wtap_file_size(wth, err)) == -1)
-        return FALSE;
-
-    if (file_size > MAX_FILE_SIZE) {
-        /*
-         * Don't blow up trying to allocate space for an
-         * immensely-large file.
-         */
-        *err = WTAP_ERR_BAD_FILE;
-        *err_info = g_strdup_printf("ruby_marshal: File has %" G_GINT64_MODIFIER "d-byte packet, bigger than maximum of %u",
-            file_size, MAX_FILE_SIZE);
-        return FALSE;
-    }
-    packet_size = (int)file_size;
-
-    rec->rec_type = REC_TYPE_PACKET;
-    rec->presence_flags = 0;
-
-    rec->rec_header.packet_header.caplen = packet_size;
-    rec->rec_header.packet_header.len = packet_size;
-
-    rec->ts.secs = 0;
-    rec->ts.nsecs = 0;
-
-    return wtap_read_packet_bytes(fh, buf, packet_size, err, err_info);
-}
-
-static gboolean ruby_marshal_seek_read(wtap *wth, gint64 seek_off, wtap_rec *rec, Buffer *buf,
-    int *err, gchar **err_info)
-{
-    /* there is only one packet */
-    if (seek_off > 0) {
-        *err = 0;
-        return FALSE;
-    }
-
-    if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
-        return FALSE;
-
-    return ruby_marshal_read_file(wth, wth->random_fh, rec, buf, err, err_info);
-}
-
-static gboolean ruby_marshal_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
-{
-    gint64 offset;
-
-    *err = 0;
-
-    offset = file_tell(wth->fh);
-
-    /* there is only ever one packet */
-    if (offset != 0)
-        return FALSE;
-
-    *data_offset = offset;
-
-    return ruby_marshal_read_file(wth, wth->fh, &wth->rec, wth->rec_data, err, err_info);
-}
-
 static gboolean is_ruby_marshal(const guint8* filebuf)
 {
     if (filebuf[0] != RUBY_MARSHAL_MAJOR)
@@ -128,44 +51,32 @@ static gboolean is_ruby_marshal(const guint8* filebuf)
 
 wtap_open_return_val ruby_marshal_open(wtap *wth, int *err, gchar **err_info)
 {
-    guint8* filebuf;
+    /* The size of this buffer should match the expectations of is_ruby_marshal */
+    guint8 filebuf[3];
     int bytes_read;
 
-    filebuf = (guint8*)g_malloc0(MAX_FILE_SIZE);
-    if (!filebuf)
-        return WTAP_OPEN_ERROR;
-
-    bytes_read = file_read(filebuf, MAX_FILE_SIZE, wth->fh);
+    bytes_read = file_read(filebuf, sizeof(filebuf), wth->fh);
     if (bytes_read < 0) {
         /* Read error. */
         *err = file_error(wth->fh, err_info);
-        g_free(filebuf);
         return WTAP_OPEN_ERROR;
     }
-    if (bytes_read == 0) {
-        /* empty file, not *anybody's* */
-        g_free(filebuf);
-        return WTAP_OPEN_NOT_MINE;
-    }
 
-    if (!is_ruby_marshal(filebuf)) {
-        g_free(filebuf);
+    if (bytes_read != sizeof(filebuf) || !is_ruby_marshal(filebuf)) {
         return WTAP_OPEN_NOT_MINE;
     }
 
     if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
-        g_free(filebuf);
         return WTAP_OPEN_ERROR;
     }
 
     wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_RUBY_MARSHAL;
     wth->file_encap = WTAP_ENCAP_RUBY_MARSHAL;
     wth->file_tsprec = WTAP_TSPREC_SEC;
-    wth->subtype_read = ruby_marshal_read;
-    wth->subtype_seek_read = ruby_marshal_seek_read;
+    wth->subtype_read = wtap_full_file_read;
+    wth->subtype_seek_read = wtap_full_file_seek_read;
     wth->snapshot_length = 0;
 
-    g_free(filebuf);
     return WTAP_OPEN_MINE;
 }
 
index 224fbe2809dfcadf1fc35c7c1e5e04760147b219..c169fecef8ed0eca607719b7fb38e9584194682f 100644 (file)
 #include <wsutil/buffer.h>
 #include "tnef.h"
 
-static gboolean tnef_read_file(wtap *wth, FILE_T fh, wtap_rec *rec,
-                               Buffer *buf, int *err, gchar **err_info)
-{
-  gint64 file_size;
-  int packet_size;
-
-  if ((file_size = wtap_file_size(wth, err)) == -1)
-    return FALSE;
-
-  if (file_size > WTAP_MAX_PACKET_SIZE_STANDARD) {
-    /*
-     * Probably a corrupt capture file; don't blow up trying
-     * to allocate space for an immensely-large packet.
-     */
-    *err = WTAP_ERR_BAD_FILE;
-    *err_info = g_strdup_printf("tnef: File has %" G_GINT64_MODIFIER "d-byte packet, bigger than maximum of %u",
-                                file_size, WTAP_MAX_PACKET_SIZE_STANDARD);
-    return FALSE;
-  }
-  packet_size = (int)file_size;
-
-  rec->rec_type = REC_TYPE_PACKET;
-  rec->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */
-
-  rec->rec_header.packet_header.caplen = packet_size;
-  rec->rec_header.packet_header.len = packet_size;
-
-  rec->ts.secs = 0;
-  rec->ts.nsecs = 0;
-
-  return wtap_read_packet_bytes(fh, buf, packet_size, err, err_info);
-}
-
-static gboolean tnef_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
-{
-  gint64 offset;
-
-  *err = 0;
-
-  offset = file_tell(wth->fh);
-
-  /* there is only ever one packet */
-  if (offset)
-    return FALSE;
-
-  *data_offset = offset;
-
-  return tnef_read_file(wth, wth->fh, &wth->rec, wth->rec_data, err, err_info);
-}
-
-static gboolean tnef_seek_read(wtap *wth, gint64 seek_off,
-                               wtap_rec *rec,
-                               Buffer *buf, int *err, gchar **err_info)
-{
-  /* there is only one packet */
-  if(seek_off > 0) {
-    *err = 0;
-    return FALSE;
-  }
-
-  if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
-    return FALSE;
-
-  return tnef_read_file(wth, wth->random_fh, rec, buf, err, err_info);
-}
-
 wtap_open_return_val tnef_open(wtap *wth, int *err, gchar **err_info)
 {
   guint32 magic;
@@ -99,8 +33,8 @@ wtap_open_return_val tnef_open(wtap *wth, int *err, gchar **err_info)
   wth->file_encap = WTAP_ENCAP_TNEF;
   wth->snapshot_length = 0;
 
-  wth->subtype_read = tnef_read;
-  wth->subtype_seek_read = tnef_seek_read;
+  wth->subtype_read = wtap_full_file_read;
+  wth->subtype_seek_read = wtap_full_file_seek_read;
   wth->file_tsprec = WTAP_TSPREC_SEC;
 
   return WTAP_OPEN_MINE;
index fb8d78e471fb4e0cf5d94c9cf0dd57d041b0f889..f62a8dffde9a369f572d4d5da97dda4850e46ce9 100644 (file)
@@ -309,6 +309,19 @@ gboolean
 wtap_read_packet_bytes(FILE_T fh, Buffer *buf, guint length, int *err,
     gchar **err_info);
 
+/*
+ * Implementation of wth->subtype_read that reads the full file contents
+ * as a single packet.
+ */
+gboolean
+wtap_full_file_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset);
+
+/*
+ * Implementation of wth->subtype_seek_read that reads the full file contents
+ * as a single packet.
+ */
+gboolean
+wtap_full_file_seek_read(wtap *wth, gint64 seek_off, wtap_rec *rec, Buffer *buf, int *err, gchar **err_info);
 #endif /* __WTAP_INT_H__ */
 
 /*
index 1944c4ce11ae02236df10e49db275dd5f2de9f6e..f43bf464ab394254b0993a8dd4a2c5bc49b787d9 100644 (file)
@@ -1450,6 +1450,95 @@ wtap_seek_read(wtap *wth, gint64 seek_off, wtap_rec *rec, Buffer *buf,
        return TRUE;
 }
 
+static gboolean
+wtap_full_file_read_file(wtap *wth, FILE_T fh, wtap_rec *rec, Buffer *buf, int *err, gchar **err_info)
+{
+       gint64 file_size;
+       int packet_size = 0;
+       const int block_size = 1024 * 1024;
+
+       if ((file_size = wtap_file_size(wth, err)) == -1)
+               return FALSE;
+
+       if (file_size > G_MAXINT) {
+               /*
+                * Avoid allocating space for an immensely-large file.
+                */
+               *err = WTAP_ERR_BAD_FILE;
+               *err_info = g_strdup_printf("%s: File has %" G_GINT64_MODIFIER "d-byte packet, bigger than maximum of %u",
+                               wtap_encap_short_string(wth->file_encap), file_size, G_MAXINT);
+               return FALSE;
+       }
+
+       /*
+        * Compressed files might expand to a larger size than the actual file
+        * size. Try to read the full size and then read in smaller increments
+        * to avoid frequent memory reallocations.
+        */
+       int buffer_size = block_size * (1 + (int)file_size / block_size);
+       for (;;) {
+               if (buffer_size <= 0) {
+                       *err = WTAP_ERR_BAD_FILE;
+                       *err_info = g_strdup_printf("%s: Uncompressed file is bigger than maximum of %u",
+                                       wtap_encap_short_string(wth->file_encap), G_MAXINT);
+                       return FALSE;
+               }
+               ws_buffer_assure_space(buf, buffer_size);
+               int nread = file_read(ws_buffer_start_ptr(buf) + packet_size, buffer_size - packet_size, fh);
+               if (nread < 0) {
+                       *err = file_error(fh, err_info);
+                       if (*err == 0)
+                               *err = WTAP_ERR_BAD_FILE;
+                       return FALSE;
+               }
+               packet_size += nread;
+               if (packet_size != buffer_size) {
+                       /* EOF */
+                       break;
+               }
+               buffer_size += block_size;
+       }
+
+       rec->rec_type = REC_TYPE_PACKET;
+       rec->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */
+       rec->ts.secs = 0;
+       rec->ts.nsecs = 0;
+       rec->rec_header.packet_header.caplen = packet_size;
+       rec->rec_header.packet_header.len = packet_size;
+
+       return TRUE;
+}
+
+gboolean
+wtap_full_file_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
+{
+       gint64 offset = file_tell(wth->fh);
+
+       /* There is only one packet with the full file contents. */
+       if (offset != 0) {
+               *err = 0;
+               return FALSE;
+       }
+
+       *data_offset = offset;
+       return wtap_full_file_read_file(wth, wth->fh, &wth->rec, wth->rec_data, err, err_info);
+}
+
+gboolean
+wtap_full_file_seek_read(wtap *wth, gint64 seek_off, wtap_rec *rec, Buffer *buf, int *err, gchar **err_info)
+{
+       /* There is only one packet with the full file contents. */
+       if (seek_off > 0) {
+               *err = 0;
+               return FALSE;
+       }
+
+       if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
+               return FALSE;
+
+       return wtap_full_file_read_file(wth, wth->random_fh, rec, buf, err, err_info);
+}
+
 /*
  * Initialize the library.
  */