public dissect_krb5_PAC_NDRHEADERBLOB
[wireshark-sm.git] / wiretap / logcat.c
blob78ff336d5cb51f35cbd7300bca78396b29039104
1 /* logcat.c
3 * Copyright 2014, Michal Labedzki for Tieto Corporation
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
8 #include "config.h"
9 #include "logcat.h"
11 #include <string.h>
13 #include "wtap-int.h"
14 #include "file_wrappers.h"
16 static int logcat_file_type_subtype = -1;
18 void register_logcat(void);
20 /* Returns '?' for invalid priorities */
21 static char get_priority(const uint8_t priority) {
22 static char priorities[] = "??VDIWEFS";
24 if (priority >= (uint8_t) sizeof(priorities))
25 return '?';
27 return priorities[priority];
31 * Returns:
33 * -2 if we get an EOF at the beginning;
34 * -1 on an I/O error;
35 * 0 if the record doesn't appear to be valid;
36 * 1-{max int} as a version number if we got a valid record.
38 static int detect_version(FILE_T fh, int *err, char **err_info)
40 uint16_t payload_length;
41 uint16_t hdr_size;
42 uint16_t read_sofar;
43 uint16_t entry_len;
44 int version;
45 struct logger_entry *log_entry;
46 struct logger_entry_v2 *log_entry_v2;
47 uint8_t *buffer;
48 uint16_t tmp;
49 uint8_t *msg_payload;
50 uint8_t *msg_part;
51 uint8_t *msg_end;
52 uint16_t msg_len;
54 /* 16-bit payload length */
55 if (!wtap_read_bytes_or_eof(fh, &tmp, 2, err, err_info)) {
56 if (*err == 0) {
58 * Got an EOF at the beginning.
60 return -2;
62 if (*err != WTAP_ERR_SHORT_READ)
63 return -1;
64 return 0;
66 payload_length = pletoh16(&tmp);
68 /* must contain at least priority and two nulls as separator */
69 if (payload_length < 3)
70 return 0;
71 /* payload length may not exceed the maximum payload size */
72 if (payload_length > LOGGER_ENTRY_MAX_PAYLOAD)
73 return 0;
75 /* 16-bit header length (or padding, equal to 0x0000) */
76 if (!wtap_read_bytes(fh, &tmp, 2, err, err_info)) {
77 if (*err != WTAP_ERR_SHORT_READ)
78 return -1;
79 return 0;
81 hdr_size = pletoh16(&tmp);
82 read_sofar = 4;
84 /* ensure buffer is large enough for all versions */
85 buffer = (uint8_t *) g_malloc(sizeof(*log_entry_v2) + payload_length);
86 log_entry_v2 = (struct logger_entry_v2 *)(void *) buffer;
87 log_entry = (struct logger_entry *)(void *) buffer;
89 /* cannot rely on __pad being 0 for v1, use heuristics to find out what
90 * version is in use. First assume the smallest msg. */
91 for (version = 1; version <= 2; ++version) {
92 if (version == 1) {
93 msg_payload = (uint8_t *) (log_entry + 1);
94 entry_len = sizeof(*log_entry) + payload_length;
95 } else if (version == 2) {
96 /* v2 is 4 bytes longer */
97 msg_payload = (uint8_t *) (log_entry_v2 + 1);
98 entry_len = sizeof(*log_entry_v2) + payload_length;
99 if (hdr_size != sizeof(*log_entry_v2))
100 continue;
101 } else {
102 continue;
105 if (!wtap_read_bytes(fh, buffer + read_sofar, entry_len - read_sofar, err, err_info)) {
106 g_free(buffer);
107 if (*err != WTAP_ERR_SHORT_READ)
108 return -1;
109 return 0;
111 read_sofar += entry_len - read_sofar;
113 /* A v2 msg has a 32-bit userid instead of v1 priority */
114 if (get_priority(msg_payload[0]) == '?')
115 continue;
117 /* Is there a terminating '\0' for the tag? */
118 msg_part = (uint8_t *) memchr(msg_payload, '\0', payload_length - 1);
119 if (msg_part == NULL)
120 continue;
122 /* if msg is '\0'-terminated, is it equal to the payload len? */
123 ++msg_part;
124 msg_len = (uint16_t)(payload_length - (msg_part - msg_payload));
125 msg_end = (uint8_t *) memchr(msg_part, '\0', msg_len);
126 /* is the end of the buffer (-1) equal to the end of msg? */
127 if (msg_end && (msg_payload + payload_length - 1 != msg_end))
128 continue;
130 g_free(buffer);
131 return version;
134 /* No version number is valid */
135 g_free(buffer);
136 return 0;
139 int logcat_exported_pdu_length(const uint8_t *pd) {
140 const uint16_t *tag;
141 const uint16_t *tag_length;
142 int length = 0;
144 tag = (const uint16_t *)(const void *) pd;
146 while(GINT16_FROM_BE(*tag)) {
147 tag_length = (const uint16_t *)(const void *) (pd + 2);
148 length += 2 + 2 + GINT16_FROM_BE(*tag_length);
150 pd += 2 + 2 + GINT16_FROM_BE(*tag_length);
151 tag = (const uint16_t *)(const void *) pd;
154 length += 2 + 2;
156 return length;
159 static bool logcat_read_packet(struct logcat_phdr *logcat, FILE_T fh,
160 wtap_rec *rec, Buffer *buf, int *err, char **err_info)
162 int packet_size;
163 uint16_t payload_length;
164 unsigned tmp[2];
165 uint8_t *pd;
166 struct logger_entry *log_entry;
168 if (!wtap_read_bytes_or_eof(fh, &tmp, 2, err, err_info)) {
169 return false;
171 payload_length = pletoh16(tmp);
173 if (logcat->version == 1) {
174 packet_size = (int)sizeof(struct logger_entry) + payload_length;
175 } else if (logcat->version == 2) {
176 packet_size = (int)sizeof(struct logger_entry_v2) + payload_length;
177 } else {
178 return false;
181 * The maximum value of payload_length is 65535, which, even after
182 * the size of the logger entry structure is added to it, is less
183 * than WTAP_MAX_PACKET_SIZE_STANDARD will ever be, so we don't need to check
184 * it.
187 ws_buffer_assure_space(buf, packet_size);
188 pd = ws_buffer_start_ptr(buf);
189 log_entry = (struct logger_entry *)(void *) pd;
191 /* Copy the first two bytes of the packet. */
192 memcpy(pd, tmp, 2);
194 /* Read the rest of the packet. */
195 if (!wtap_read_bytes(fh, pd + 2, packet_size - 2, err, err_info)) {
196 return false;
199 rec->rec_type = REC_TYPE_PACKET;
200 rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
201 rec->presence_flags = WTAP_HAS_TS;
202 rec->ts.secs = (time_t) GINT32_FROM_LE(log_entry->sec);
203 rec->ts.nsecs = GINT32_FROM_LE(log_entry->nsec);
204 rec->rec_header.packet_header.caplen = packet_size;
205 rec->rec_header.packet_header.len = packet_size;
207 rec->rec_header.packet_header.pseudo_header.logcat.version = logcat->version;
209 return true;
212 static bool logcat_read(wtap *wth, wtap_rec *rec, Buffer *buf,
213 int *err, char **err_info, int64_t *data_offset)
215 *data_offset = file_tell(wth->fh);
217 return logcat_read_packet((struct logcat_phdr *) wth->priv, wth->fh,
218 rec, buf, err, err_info);
221 static bool logcat_seek_read(wtap *wth, int64_t seek_off,
222 wtap_rec *rec, Buffer *buf,
223 int *err, char **err_info)
225 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
226 return false;
228 if (!logcat_read_packet((struct logcat_phdr *) wth->priv, wth->random_fh,
229 rec, buf, err, err_info)) {
230 if (*err == 0)
231 *err = WTAP_ERR_SHORT_READ;
232 return false;
234 return true;
237 wtap_open_return_val logcat_open(wtap *wth, int *err, char **err_info)
239 int version;
240 int tmp_version;
241 struct logcat_phdr *logcat;
243 /* check first 3 packets (or 2 or 1 if EOF) versions to check file format is correct */
244 version = detect_version(wth->fh, err, err_info); /* first packet */
245 if (version == -1)
246 return WTAP_OPEN_ERROR; /* I/O error */
247 if (version == 0)
248 return WTAP_OPEN_NOT_MINE; /* not a logcat file */
249 if (version == -2)
250 return WTAP_OPEN_NOT_MINE; /* empty file, so not any type of file */
252 tmp_version = detect_version(wth->fh, err, err_info); /* second packet */
253 if (tmp_version == -1)
254 return WTAP_OPEN_ERROR; /* I/O error */
255 if (tmp_version == 0)
256 return WTAP_OPEN_NOT_MINE; /* not a logcat file */
257 if (tmp_version != -2) {
258 /* we've read two packets; do they have the same version? */
259 if (tmp_version != version) {
260 /* no, so this is presumably not a logcat file */
261 return WTAP_OPEN_NOT_MINE;
264 tmp_version = detect_version(wth->fh, err, err_info); /* third packet */
265 if (tmp_version < 0)
266 return WTAP_OPEN_ERROR; /* I/O error */
267 if (tmp_version == 0)
268 return WTAP_OPEN_NOT_MINE; /* not a logcat file */
271 * we've read three packets and the first two have the same
272 * version; does the third have the same version?
274 if (tmp_version != version) {
275 /* no, so this is presumably not a logcat file */
276 return WTAP_OPEN_NOT_MINE;
280 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
281 return WTAP_OPEN_ERROR;
283 logcat = g_new(struct logcat_phdr, 1);
284 logcat->version = version;
286 wth->priv = logcat;
288 wth->file_type_subtype = logcat_file_type_subtype;
289 wth->file_encap = WTAP_ENCAP_LOGCAT;
290 wth->snapshot_length = 0;
292 wth->subtype_read = logcat_read;
293 wth->subtype_seek_read = logcat_seek_read;
294 wth->file_tsprec = WTAP_TSPREC_USEC;
297 * Add an IDB; we don't know how many interfaces were
298 * involved, so we just say one interface, about which
299 * we only know the link-layer type, snapshot length,
300 * and time stamp resolution.
302 wtap_add_generated_idb(wth);
304 return WTAP_OPEN_MINE;
307 static int logcat_dump_can_write_encap(int encap)
309 if (encap == WTAP_ENCAP_PER_PACKET)
310 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
312 if (encap != WTAP_ENCAP_LOGCAT && encap != WTAP_ENCAP_WIRESHARK_UPPER_PDU)
313 return WTAP_ERR_UNWRITABLE_ENCAP;
315 return 0;
318 static bool logcat_binary_dump(wtap_dumper *wdh,
319 const wtap_rec *rec,
320 const uint8_t *pd, int *err, char **err_info _U_)
322 int caplen;
324 /* We can only write packet records. */
325 if (rec->rec_type != REC_TYPE_PACKET) {
326 *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
327 return false;
331 * Make sure this packet doesn't have a link-layer type that
332 * differs from the one for the file.
334 if (wdh->file_encap != rec->rec_header.packet_header.pkt_encap) {
335 *err = WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
336 return false;
339 caplen = rec->rec_header.packet_header.caplen;
341 /* Skip EXPORTED_PDU*/
342 if (wdh->file_encap == WTAP_ENCAP_WIRESHARK_UPPER_PDU) {
343 int skipped_length;
345 skipped_length = logcat_exported_pdu_length(pd);
346 pd += skipped_length;
347 caplen -= skipped_length;
350 if (!wtap_dump_file_write(wdh, pd, caplen, err))
351 return false;
353 return true;
356 static bool logcat_binary_dump_open(wtap_dumper *wdh, int *err _U_,
357 char **err_info _U_)
359 wdh->subtype_write = logcat_binary_dump;
361 return true;
364 static const struct supported_block_type logcat_blocks_supported[] = {
366 * We support packet blocks, with no comments or other options.
368 { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
371 static const struct file_type_subtype_info logcat_info = {
372 "Android Logcat Binary format", "logcat", "logcat", NULL,
373 false, BLOCKS_SUPPORTED(logcat_blocks_supported),
374 logcat_dump_can_write_encap, logcat_binary_dump_open, NULL
377 void register_logcat(void)
379 logcat_file_type_subtype = wtap_register_file_type_subtype(&logcat_info);
382 * Register name for backwards compatibility with the
383 * wtap_filetypes table in Lua.
385 wtap_register_backwards_compatibility_lua_name("LOGCAT",
386 logcat_file_type_subtype);
390 * Editor modelines - https://www.wireshark.org/tools/modelines.html
392 * Local variables:
393 * c-basic-offset: 4
394 * tab-width: 8
395 * indent-tabs-mode: nil
396 * End:
398 * vi: set shiftwidth=4 tabstop=8 expandtab:
399 * :indentSize=4:tabSize=8:noTabs=true: