Fix Uninitialized argument value found by Clang Analyzer
[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 #ifdef HAVE_SYS_STAT_H
25 #include <sys/stat.h>
26 #endif
27
28 #include "wtap-int.h"
29 #include "file_wrappers.h"
30 #include "buffer.h"
31 #include "ber.h"
32
33
34 #define BER_CLASS_UNI   0
35 #define BER_CLASS_APP   1
36 #define BER_CLASS_CON   2
37
38 #define BER_UNI_TAG_SEQ 16      /* SEQUENCE, SEQUENCE OF */
39 #define BER_UNI_TAG_SET 17      /* SET, SET OF */
40
41 static gboolean ber_read_file(wtap *wth, FILE_T fh, struct wtap_pkthdr *phdr,
42                               Buffer *buf, int *err, gchar **err_info)
43 {
44   gint64 file_size;
45   int packet_size;
46
47   if ((file_size = wtap_file_size(wth, err)) == -1)
48     return FALSE;
49
50   if (file_size > WTAP_MAX_PACKET_SIZE) {
51     /*
52      * Probably a corrupt capture file; don't blow up trying
53      * to allocate space for an immensely-large packet.
54      */
55     *err = WTAP_ERR_BAD_FILE;
56     *err_info = g_strdup_printf("ber: File has %" G_GINT64_MODIFIER "d-byte packet, bigger than maximum of %u",
57                                 file_size, WTAP_MAX_PACKET_SIZE);
58     return FALSE;
59   }
60   packet_size = (int)file_size;
61
62   phdr->rec_type = REC_TYPE_PACKET;
63   phdr->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */
64
65   phdr->caplen = packet_size;
66   phdr->len = packet_size;
67
68   phdr->ts.secs = 0;
69   phdr->ts.nsecs = 0;
70
71   return wtap_read_packet_bytes(fh, buf, packet_size, err, err_info);
72 }
73
74 static gboolean ber_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
75 {
76   gint64 offset;
77
78   *err = 0;
79
80   offset = file_tell(wth->fh);
81
82   /* there is only ever one packet */
83   if (offset != 0)
84     return FALSE;
85
86   *data_offset = offset;
87
88   return ber_read_file(wth, wth->fh, &wth->phdr, wth->frame_buffer, err, err_info);
89 }
90
91 static gboolean ber_seek_read(wtap *wth, gint64 seek_off, struct wtap_pkthdr *phdr _U_,
92                               Buffer *buf, int *err, gchar **err_info)
93 {
94   /* there is only one packet */
95   if(seek_off > 0) {
96     *err = 0;
97     return FALSE;
98   }
99
100   if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
101     return FALSE;
102
103   return ber_read_file(wth, wth->random_fh, phdr, buf, err, err_info);
104 }
105
106 int ber_open(wtap *wth, int *err, gchar **err_info)
107 {
108 #define BER_BYTES_TO_CHECK 8
109   guint8 bytes[BER_BYTES_TO_CHECK];
110   int bytes_read;
111   guint8 ber_id;
112   gint8 ber_class;
113   gint8 ber_tag;
114   gboolean ber_pc;
115   guint8 oct, nlb = 0;
116   int len = 0;
117   gint64 file_size;
118   int offset = 0, i;
119
120   bytes_read = file_read(&bytes, BER_BYTES_TO_CHECK, wth->fh);
121   if (bytes_read != BER_BYTES_TO_CHECK) {
122     *err = file_error(wth->fh, err_info);
123     if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
124       return -1;
125     return 0;
126   }
127
128   ber_id = bytes[offset++];
129
130   ber_class = (ber_id>>6) & 0x03;
131   ber_pc = (ber_id>>5) & 0x01;
132   ber_tag = ber_id & 0x1F;
133
134   /* it must be constructed and either a SET or a SEQUENCE */
135   /* or a CONTEXT less than 32 (arbitrary) */
136   /* XXX: do we also want to allow APPLICATION */
137   if(!(ber_pc &&
138        (((ber_class == BER_CLASS_UNI) && ((ber_tag == BER_UNI_TAG_SET) || (ber_tag == BER_UNI_TAG_SEQ))) ||
139         ((ber_class == BER_CLASS_CON) && (ber_tag < 32)))))
140     return 0;
141
142   /* now check the length */
143   oct = bytes[offset++];
144
145   if(oct != 0x80) {
146     /* not indefinite length encoded */
147
148     if(!(oct & 0x80))
149       /* length fits into a single byte */
150       len = oct;
151     else {
152       nlb = oct & 0x7F; /* number of length bytes */
153
154       if((nlb > 0) && (nlb <= (BER_BYTES_TO_CHECK - 2))) {
155         /* not indefinite length and we have read enough bytes to compute the length */
156         i = nlb;
157         while(i--) {
158           oct = bytes[offset++];
159           len = (len<<8) + oct;
160         }
161       }
162     }
163
164     len += (2 + nlb); /* add back Tag and Length bytes */
165     file_size = wtap_file_size(wth, err);
166
167     if(len != file_size) {
168       return 0; /* not ASN.1 */
169     }
170   } else {
171     /* Indefinite length encoded - assume it is BER */
172   }
173
174   /* seek back to the start of the file  */
175   if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
176     return -1;
177
178   wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_BER;
179   wth->file_encap = WTAP_ENCAP_BER;
180   wth->snapshot_length = 0;
181
182   wth->subtype_read = ber_read;
183   wth->subtype_seek_read = ber_seek_read;
184   wth->tsprecision = WTAP_FILE_TSPREC_SEC;
185
186   return 1;
187 }