ip-over-ib description entry was missing
[metze/wireshark/wip.git] / wiretap / ber.c
1 /* ber.c
2  *
3  * Basic Encoding Rules (BER) file reading
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19
20 #include "config.h"
21
22 #include <errno.h>
23
24 #include "wtap-int.h"
25 #include "file_wrappers.h"
26 #include <wsutil/buffer.h>
27 #include "ber.h"
28
29
30 #define BER_CLASS_UNI   0
31 #define BER_CLASS_APP   1
32 #define BER_CLASS_CON   2
33
34 #define BER_UNI_TAG_SEQ 16      /* SEQUENCE, SEQUENCE OF */
35 #define BER_UNI_TAG_SET 17      /* SET, SET OF */
36
37 static gboolean ber_read_file(wtap *wth, FILE_T fh, struct wtap_pkthdr *phdr,
38                               Buffer *buf, int *err, gchar **err_info)
39 {
40   gint64 file_size;
41   int packet_size;
42
43   if ((file_size = wtap_file_size(wth, err)) == -1)
44     return FALSE;
45
46   if (file_size > G_MAXINT) {
47     /*
48      * Probably a corrupt capture file; don't blow up trying
49      * to allocate space for an immensely-large packet.
50      */
51     *err = WTAP_ERR_BAD_FILE;
52     *err_info = g_strdup_printf("ber: File has %" G_GINT64_MODIFIER "d-byte packet, bigger than maximum of %u",
53                                 file_size, G_MAXINT);
54     return FALSE;
55   }
56   packet_size = (int)file_size;
57
58   phdr->rec_type = REC_TYPE_PACKET;
59   phdr->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */
60
61   phdr->caplen = packet_size;
62   phdr->len = packet_size;
63
64   phdr->ts.secs = 0;
65   phdr->ts.nsecs = 0;
66
67   ws_buffer_assure_space(buf, packet_size);
68   return wtap_read_packet_bytes(fh, buf, packet_size, err, err_info);
69 }
70
71 static gboolean ber_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
72 {
73   gint64 offset;
74
75   *err = 0;
76
77   offset = file_tell(wth->fh);
78
79   /* there is only ever one packet */
80   if (offset != 0)
81     return FALSE;
82
83   *data_offset = offset;
84
85   return ber_read_file(wth, wth->fh, &wth->phdr, wth->frame_buffer, err, err_info);
86 }
87
88 static gboolean ber_seek_read(wtap *wth, gint64 seek_off, struct wtap_pkthdr *phdr,
89                               Buffer *buf, int *err, gchar **err_info)
90 {
91   /* there is only one packet */
92   if(seek_off > 0) {
93     *err = 0;
94     return FALSE;
95   }
96
97   if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
98     return FALSE;
99
100   return ber_read_file(wth, wth->random_fh, phdr, buf, err, err_info);
101 }
102
103 wtap_open_return_val ber_open(wtap *wth, int *err, gchar **err_info)
104 {
105 #define BER_BYTES_TO_CHECK 8
106   guint8 bytes[BER_BYTES_TO_CHECK];
107   guint8 ber_id;
108   gint8 ber_class;
109   gint8 ber_tag;
110   gboolean ber_pc;
111   guint8 oct, nlb = 0;
112   int len = 0;
113   gint64 file_size;
114   int offset = 0, i;
115
116   if (!wtap_read_bytes(wth->fh, &bytes, BER_BYTES_TO_CHECK, err, err_info)) {
117     if (*err != WTAP_ERR_SHORT_READ)
118       return WTAP_OPEN_ERROR;
119     return WTAP_OPEN_NOT_MINE;
120   }
121
122   ber_id = bytes[offset++];
123
124   ber_class = (ber_id>>6) & 0x03;
125   ber_pc = (ber_id>>5) & 0x01;
126   ber_tag = ber_id & 0x1F;
127
128   /* it must be constructed and either a SET or a SEQUENCE */
129   /* or a CONTEXT/APPLICATION less than 32 (arbitrary) */
130   if(!(ber_pc &&
131        (((ber_class == BER_CLASS_UNI) && ((ber_tag == BER_UNI_TAG_SET) || (ber_tag == BER_UNI_TAG_SEQ))) ||
132         (((ber_class == BER_CLASS_CON) || (ber_class == BER_CLASS_APP)) && (ber_tag < 32)))))
133     return WTAP_OPEN_NOT_MINE;
134
135   /* now check the length */
136   oct = bytes[offset++];
137
138   if(oct != 0x80) {
139     /* not indefinite length encoded */
140
141     if(!(oct & 0x80))
142       /* length fits into a single byte */
143       len = oct;
144     else {
145       nlb = oct & 0x7F; /* number of length bytes */
146
147       if((nlb > 0) && (nlb <= (BER_BYTES_TO_CHECK - 2))) {
148         /* not indefinite length and we have read enough bytes to compute the length */
149         i = nlb;
150         while(i--) {
151           oct = bytes[offset++];
152           len = (len<<8) + oct;
153         }
154       }
155     }
156
157     len += (2 + nlb); /* add back Tag and Length bytes */
158     file_size = wtap_file_size(wth, err);
159
160     if(len != file_size) {
161       return WTAP_OPEN_NOT_MINE; /* not ASN.1 */
162     }
163   } else {
164     /* Indefinite length encoded - assume it is BER */
165   }
166
167   /* seek back to the start of the file  */
168   if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
169     return WTAP_OPEN_ERROR;
170
171   wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_BER;
172   wth->file_encap = WTAP_ENCAP_BER;
173   wth->snapshot_length = 0;
174
175   wth->subtype_read = ber_read;
176   wth->subtype_seek_read = ber_seek_read;
177   wth->file_tsprec = WTAP_TSPREC_SEC;
178
179   return WTAP_OPEN_MINE;
180 }
181
182 /*
183  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
184  *
185  * Local Variables:
186  * c-basic-offset: 2
187  * tab-width: 8
188  * indent-tabs-mode: nil
189  * End:
190  *
191  * vi: set shiftwidth=2 tabstop=8 expandtab:
192  * :indentSize=2:tabSize=8:noTabs=true:
193  */