1 /* ccidmon.c - CCID monitor for use with the Linux usbmon facility.
2 * Copyright (C) 2009, 2016, 2019 Werner Koch
3 * Copyright (C) 2021 g10 Code GmbH
4 * Copyright (C) 2009 Free Software Foundation, Inc.
5 *
6 * This file is part of GnuPG.
7 *
8 * GnuPG is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * GnuPG is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <https://www.gnu.org/licenses/>.
20 * SPDX-License-Identifier: GPL-3.0-or-later
21 */
22
23
24 /* This utility takes the output of usbmon, filters out the bulk data
25 and prints the CCID messages in a human friendly way.
26
27 */
28
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <stddef.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <stdarg.h>
39 #include <assert.h>
40 #include <unistd.h>
41 #include <signal.h>
42
43
44 #ifndef PACKAGE_VERSION
45 # define PACKAGE_VERSION "[build on " __DATE__ " " __TIME__ "]"
46 #endif
47 #ifndef PACKAGE_BUGREPORT
48 # define PACKAGE_BUGREPORT "devnull@example.org"
49 #endif
50 #define PGM "ccidmon"
51 #ifndef GNUPG_NAME
52 # define GNUPG_NAME "GnuPG"
53 #endif
54
55 /* Option flags. */
56 static int verbose;
57 static int debug;
58 static int skip_escape;
59 static int usb_bus, usb_dev;
60 static int sniffusb;
61
62
63 /* Error counter. */
64 static int any_error;
65
66 /* Data storage. */
67 struct
68 {
69 int is_bi;
70 char timestamp[20];
71 char address[50];
72 int count;
73 char data[16000];
74 } databuffer;
75
76
77 enum {
78 RDR_to_PC_NotifySlotChange= 0x50,
79 RDR_to_PC_HardwareError = 0x51,
80
81 PC_to_RDR_SetParameters = 0x61,
82 PC_to_RDR_IccPowerOn = 0x62,
83 PC_to_RDR_IccPowerOff = 0x63,
84 PC_to_RDR_GetSlotStatus = 0x65,
85 PC_to_RDR_Secure = 0x69,
86 PC_to_RDR_T0APDU = 0x6a,
87 PC_to_RDR_Escape = 0x6b,
88 PC_to_RDR_GetParameters = 0x6c,
89 PC_to_RDR_ResetParameters = 0x6d,
90 PC_to_RDR_IccClock = 0x6e,
91 PC_to_RDR_XfrBlock = 0x6f,
92 PC_to_RDR_Mechanical = 0x71,
93 PC_to_RDR_Abort = 0x72,
94 PC_to_RDR_SetDataRate = 0x73,
95
96 RDR_to_PC_DataBlock = 0x80,
97 RDR_to_PC_SlotStatus = 0x81,
98 RDR_to_PC_Parameters = 0x82,
99 RDR_to_PC_Escape = 0x83,
100 RDR_to_PC_DataRate = 0x84
101 };
102
103
104 #define digitp(p) (*(p) >= '0' && *(p) <= '9')
105 #define hexdigitp(a) (digitp (a) \
106 || (*(a) >= 'A' && *(a) <= 'F') \
107 || (*(a) >= 'a' && *(a) <= 'f'))
108 #define ascii_isspace(a) ((a)==' ' || (a)=='\n' || (a)=='\r' || (a)=='\t')
109 #define xtoi_1(p) ((p) <= '9'? ((p)- '0'): \
110 (p) <= 'F'? ((p)-'A'+10):((p)-'a'+10))
111
112
113
114 /* Print diagnostic message and exit with failure. */
115 static void
die(const char * format,...)116 die (const char *format, ...)
117 {
118 va_list arg_ptr;
119
120 fflush (stdout);
121 fprintf (stderr, "%s: ", PGM);
122
123 va_start (arg_ptr, format);
124 vfprintf (stderr, format, arg_ptr);
125 va_end (arg_ptr);
126 putc ('\n', stderr);
127
128 exit (1);
129 }
130
131
132 /* Print diagnostic message. */
133 static void
err(const char * format,...)134 err (const char *format, ...)
135 {
136 va_list arg_ptr;
137
138 any_error = 1;
139
140 fflush (stdout);
141 fprintf (stderr, "%s: ", PGM);
142
143 va_start (arg_ptr, format);
144 vfprintf (stderr, format, arg_ptr);
145 va_end (arg_ptr);
146 putc ('\n', stderr);
147 }
148
149
150 /* Convert a little endian stored 4 byte value into an unsigned
151 integer. */
152 static unsigned int
convert_le_u32(const unsigned char * buf)153 convert_le_u32 (const unsigned char *buf)
154 {
155 return buf[0] | (buf[1] << 8) | (buf[2] << 16) | ((unsigned int)buf[3] << 24);
156 }
157
158
159 /* Convert a little endian stored 2 byte value into an unsigned
160 integer. */
161 static unsigned int
convert_le_u16(const unsigned char * buf)162 convert_le_u16 (const unsigned char *buf)
163 {
164 return buf[0] | (buf[1] << 8);
165 }
166
167
168
169
170 static void
print_pr_data(const unsigned char * data,size_t datalen,size_t off)171 print_pr_data (const unsigned char *data, size_t datalen, size_t off)
172 {
173 int needlf = 0;
174 int first = 1;
175
176 for (; off < datalen; off++)
177 {
178 if (!(off % 16) || first)
179 {
180 if (needlf)
181 putchar ('\n');
182 printf (" [%04lu] ", (unsigned long)off);
183 }
184 printf (" %02X", data[off]);
185 needlf = 1;
186 first = 0;
187 }
188 if (needlf)
189 putchar ('\n');
190 }
191
192
193 static void
print_as_ascii(const unsigned char * buf,unsigned int buflen,unsigned int fill)194 print_as_ascii (const unsigned char *buf, unsigned int buflen,unsigned int fill)
195 {
196 unsigned int n;
197
198 if (!buflen)
199 return;
200 if (buflen > 16)
201 buflen = 16;
202
203 for (n = buflen; n < fill; n++)
204 fputs (" ", stdout);
205 fputs (" |", stdout);
206 for (n = 0; n < buflen; n++, buf++)
207 if (*buf >= 32 && *buf < 127 && *buf != '|')
208 putchar (*buf);
209 else
210 putchar ('.');
211 putchar ('|');
212 }
213
214
215 static void
print_t1_block(const unsigned char * msg,size_t msglen,int to_rdr)216 print_t1_block (const unsigned char *msg, size_t msglen, int to_rdr)
217 {
218 unsigned int count, len;
219 unsigned char buf[16];
220
221 if (msglen < 4)
222 {
223 printf (" T=1 ..: invalid block\n");
224 return;
225 }
226 printf (" T=1 ..: NAD=%02x", msg[0]);
227 if (!(msg[1] & 0x80))
228 {
229 printf (" I-block seq=%d%s\n",
230 !!(msg[1] & 0x40), (msg[1] & 0x20)? " chaining":"");
231 len = msg[2];
232 msg += 3;
233 msglen -= 3;
234
235 printf (" APDU-%c:", to_rdr? 's':'r');
236 count = 0;
237 while (msglen > 1 && len)
238 {
239 if (count == 16)
240 {
241 print_as_ascii (buf, count, count);
242 printf ("\n ");
243 count = 0;
244 }
245 buf[count] = msg[0];
246 printf (" %02X", msg[0]);
247 msg++;
248 msglen--;
249 len--;
250 count++;
251 }
252 print_as_ascii (buf, count, 16);
253 putchar ('\n');
254 }
255 else if (!(msg[1] & 0x40))
256 printf (" R-block seq=%d%s\n",
257 !!(msg[1] & 0x10),
258 (msg[1] & 0x0f) == 0 ? "":
259 (msg[1] & 0x0f) == 1 ? "EDC error":
260 (msg[1] & 0x0f) == 2 ? "other error": "?");
261 else
262 printf (" S-block %s %s\n",
263 (msg[1] & 0x1f) == 0 ? "resync":
264 (msg[1] & 0x1f) == 1 ? "info_field_size":
265 (msg[1] & 0x1f) == 2 ? "abort":
266 (msg[1] & 0x1f) == 2 ? "BWT_extension":
267 (msg[1] & 0x1f) == 2 ? "VPP_error": "?",
268 (msg[1] & 0x20)? "response":"request");
269 }
270
271
272 static void
print_p2r_header(const char * name,const unsigned char * msg,size_t msglen)273 print_p2r_header (const char *name, const unsigned char *msg, size_t msglen)
274 {
275 printf ("%s:\n", name);
276 if (msglen < 7)
277 return;
278 printf (" dwLength ..........: %u\n", convert_le_u32 (msg+1));
279 printf (" bSlot .............: %u\n", msg[5]);
280 printf (" bSeq ..............: %u\n", msg[6]);
281 }
282
283
284 static void
print_p2r_iccpoweron(const unsigned char * msg,size_t msglen)285 print_p2r_iccpoweron (const unsigned char *msg, size_t msglen)
286 {
287 print_p2r_header ("PC_to_RDR_IccPowerOn", msg, msglen);
288 if (msglen < 10)
289 return;
290 printf (" bPowerSelect ......: 0x%02x (%s)\n", msg[7],
291 msg[7] == 0? "auto":
292 msg[7] == 1? "5.0 V":
293 msg[7] == 2? "3.0 V":
294 msg[7] == 3? "1.8 V":"");
295 print_pr_data (msg, msglen, 8);
296 }
297
298
299 static void
print_p2r_iccpoweroff(const unsigned char * msg,size_t msglen)300 print_p2r_iccpoweroff (const unsigned char *msg, size_t msglen)
301 {
302 print_p2r_header ("PC_to_RDR_IccPowerOff", msg, msglen);
303 print_pr_data (msg, msglen, 7);
304 }
305
306
307 static void
print_p2r_getslotstatus(const unsigned char * msg,size_t msglen)308 print_p2r_getslotstatus (const unsigned char *msg, size_t msglen)
309 {
310 print_p2r_header ("PC_to_RDR_GetSlotStatus", msg, msglen);
311 print_pr_data (msg, msglen, 7);
312 }
313
314
315 static void
print_p2r_xfrblock(const unsigned char * msg,size_t msglen)316 print_p2r_xfrblock (const unsigned char *msg, size_t msglen)
317 {
318 unsigned int val;
319
320 print_p2r_header ("PC_to_RDR_XfrBlock", msg, msglen);
321 if (msglen < 10)
322 return;
323 printf (" bBWI ..............: 0x%02x\n", msg[7]);
324 val = convert_le_u16 (msg+8);
325 printf (" wLevelParameter ...: 0x%04x%s\n", val,
326 val == 1? " (continued)":
327 val == 2? " (continues+ends)":
328 val == 3? " (continues+continued)":
329 val == 16? " (DataBlock-expected)":"");
330 print_pr_data (msg, msglen, 10);
331 if (msglen < 10)
332 return;
333 msg += 10;
334 msglen -= 10;
335 print_t1_block (msg, msglen, 1);
336 }
337
338
339 static void
print_p2r_getparameters(const unsigned char * msg,size_t msglen)340 print_p2r_getparameters (const unsigned char *msg, size_t msglen)
341 {
342 print_p2r_header ("PC_to_RDR_GetParameters", msg, msglen);
343 print_pr_data (msg, msglen, 7);
344 }
345
346
347 static void
print_p2r_resetparameters(const unsigned char * msg,size_t msglen)348 print_p2r_resetparameters (const unsigned char *msg, size_t msglen)
349 {
350 print_p2r_header ("PC_to_RDR_ResetParameters", msg, msglen);
351 print_pr_data (msg, msglen, 7);
352 }
353
354
355 static void
print_p2r_setparameters(const unsigned char * msg,size_t msglen)356 print_p2r_setparameters (const unsigned char *msg, size_t msglen)
357 {
358 print_p2r_header ("PC_to_RDR_SetParameters", msg, msglen);
359 if (msglen < 10)
360 return;
361 printf (" bProtocolNum ......: 0x%02x\n", msg[7]);
362 print_pr_data (msg, msglen, 8);
363 }
364
365
366 static void
print_p2r_escape(const unsigned char * msg,size_t msglen)367 print_p2r_escape (const unsigned char *msg, size_t msglen)
368 {
369 if (skip_escape)
370 return;
371 print_p2r_header ("PC_to_RDR_Escape", msg, msglen);
372 print_pr_data (msg, msglen, 7);
373 }
374
375
376 static void
print_p2r_iccclock(const unsigned char * msg,size_t msglen)377 print_p2r_iccclock (const unsigned char *msg, size_t msglen)
378 {
379 print_p2r_header ("PC_to_RDR_IccClock", msg, msglen);
380 if (msglen < 10)
381 return;
382 printf (" bClockCommand .....: 0x%02x\n", msg[7]);
383 print_pr_data (msg, msglen, 8);
384 }
385
386
387 static void
print_p2r_to0apdu(const unsigned char * msg,size_t msglen)388 print_p2r_to0apdu (const unsigned char *msg, size_t msglen)
389 {
390 print_p2r_header ("PC_to_RDR_T0APDU", msg, msglen);
391 if (msglen < 10)
392 return;
393 printf (" bmChanges .........: 0x%02x\n", msg[7]);
394 printf (" bClassGetResponse .: 0x%02x\n", msg[8]);
395 printf (" bClassEnvelope ....: 0x%02x\n", msg[9]);
396 print_pr_data (msg, msglen, 10);
397 }
398
399
400 static void
print_p2r_secure(const unsigned char * msg,size_t msglen)401 print_p2r_secure (const unsigned char *msg, size_t msglen)
402 {
403 unsigned int val;
404
405 print_p2r_header ("PC_to_RDR_Secure", msg, msglen);
406 if (msglen < 10)
407 return;
408 printf (" bBMI ..............: 0x%02x\n", msg[7]);
409 val = convert_le_u16 (msg+8);
410 printf (" wLevelParameter ...: 0x%04x%s\n", val,
411 val == 1? " (continued)":
412 val == 2? " (continues+ends)":
413 val == 3? " (continues+continued)":
414 val == 16? " (DataBlock-expected)":"");
415 print_pr_data (msg, msglen, 10);
416 }
417
418
419 static void
print_p2r_mechanical(const unsigned char * msg,size_t msglen)420 print_p2r_mechanical (const unsigned char *msg, size_t msglen)
421 {
422 print_p2r_header ("PC_to_RDR_Mechanical", msg, msglen);
423 if (msglen < 10)
424 return;
425 printf (" bFunction .........: 0x%02x\n", msg[7]);
426 print_pr_data (msg, msglen, 8);
427 }
428
429
430 static void
print_p2r_abort(const unsigned char * msg,size_t msglen)431 print_p2r_abort (const unsigned char *msg, size_t msglen)
432 {
433 print_p2r_header ("PC_to_RDR_Abort", msg, msglen);
434 print_pr_data (msg, msglen, 7);
435 }
436
437
438 static void
print_p2r_setdatarate(const unsigned char * msg,size_t msglen)439 print_p2r_setdatarate (const unsigned char *msg, size_t msglen)
440 {
441 print_p2r_header ("PC_to_RDR_SetDataRate", msg, msglen);
442 if (msglen < 10)
443 return;
444 print_pr_data (msg, msglen, 7);
445 }
446
447
448 static void
print_p2r_unknown(const unsigned char * msg,size_t msglen)449 print_p2r_unknown (const unsigned char *msg, size_t msglen)
450 {
451 char buf[100];
452
453 snprintf (buf, sizeof buf, "Unknown PC_to_RDR command 0x%02X",
454 msglen? msg[0]:0);
455 print_p2r_header (buf, msg, msglen);
456 if (msglen < 10)
457 return;
458 print_pr_data (msg, msglen, 0);
459 }
460
461
462 static void
print_p2r(const unsigned char * msg,size_t msglen)463 print_p2r (const unsigned char *msg, size_t msglen)
464 {
465 switch (msglen? msg[0]:0)
466 {
467 case PC_to_RDR_IccPowerOn:
468 print_p2r_iccpoweron (msg, msglen);
469 break;
470 case PC_to_RDR_IccPowerOff:
471 print_p2r_iccpoweroff (msg, msglen);
472 break;
473 case PC_to_RDR_GetSlotStatus:
474 print_p2r_getslotstatus (msg, msglen);
475 break;
476 case PC_to_RDR_XfrBlock:
477 print_p2r_xfrblock (msg, msglen);
478 break;
479 case PC_to_RDR_GetParameters:
480 print_p2r_getparameters (msg, msglen);
481 break;
482 case PC_to_RDR_ResetParameters:
483 print_p2r_resetparameters (msg, msglen);
484 break;
485 case PC_to_RDR_SetParameters:
486 print_p2r_setparameters (msg, msglen);
487 break;
488 case PC_to_RDR_Escape:
489 print_p2r_escape (msg, msglen);
490 break;
491 case PC_to_RDR_IccClock:
492 print_p2r_iccclock (msg, msglen);
493 break;
494 case PC_to_RDR_T0APDU:
495 print_p2r_to0apdu (msg, msglen);
496 break;
497 case PC_to_RDR_Secure:
498 print_p2r_secure (msg, msglen);
499 break;
500 case PC_to_RDR_Mechanical:
501 print_p2r_mechanical (msg, msglen);
502 break;
503 case PC_to_RDR_Abort:
504 print_p2r_abort (msg, msglen);
505 break;
506 case PC_to_RDR_SetDataRate:
507 print_p2r_setdatarate (msg, msglen);
508 break;
509 default:
510 print_p2r_unknown (msg, msglen);
511 break;
512 }
513 }
514
515
516 static void
print_r2p_header(const char * name,const unsigned char * msg,size_t msglen)517 print_r2p_header (const char *name, const unsigned char *msg, size_t msglen)
518 {
519 printf ("%s:\n", name);
520 if (msglen < 9)
521 return;
522 printf (" dwLength ..........: %u\n", convert_le_u32 (msg+1));
523 printf (" bSlot .............: %u\n", msg[5]);
524 printf (" bSeq ..............: %u\n", msg[6]);
525 printf (" bStatus ...........: %u\n", msg[7]);
526 if (msg[8])
527 printf (" bError ............: %u\n", msg[8]);
528 }
529
530
531 static void
print_r2p_datablock(const unsigned char * msg,size_t msglen)532 print_r2p_datablock (const unsigned char *msg, size_t msglen)
533 {
534 print_r2p_header ("RDR_to_PC_DataBlock", msg, msglen);
535 if (msglen < 10)
536 return;
537 if (msg[9])
538 printf (" bChainParameter ...: 0x%02x%s\n", msg[9],
539 msg[9] == 1? " (continued)":
540 msg[9] == 2? " (continues+ends)":
541 msg[9] == 3? " (continues+continued)":
542 msg[9] == 16? " (XferBlock-expected)":"");
543 print_pr_data (msg, msglen, 10);
544 if (msglen < 10)
545 return;
546 msg += 10;
547 msglen -= 10;
548 print_t1_block (msg, msglen, 0);
549 }
550
551
552 static void
print_r2p_slotstatus(const unsigned char * msg,size_t msglen)553 print_r2p_slotstatus (const unsigned char *msg, size_t msglen)
554 {
555 print_r2p_header ("RDR_to_PC_SlotStatus", msg, msglen);
556 if (msglen < 10)
557 return;
558 printf (" bClockStatus ......: 0x%02x%s\n", msg[9],
559 msg[9] == 0? " (running)":
560 msg[9] == 1? " (stopped-L)":
561 msg[9] == 2? " (stopped-H)":
562 msg[9] == 3? " (stopped)":"");
563 print_pr_data (msg, msglen, 10);
564 }
565
566
567 static void
print_r2p_parameters(const unsigned char * msg,size_t msglen)568 print_r2p_parameters (const unsigned char *msg, size_t msglen)
569 {
570 print_r2p_header ("RDR_to_PC_Parameters", msg, msglen);
571 if (msglen < 10)
572 return;
573
574 printf (" protocol ..........: T=%d\n", msg[9]);
575 if (msglen == 17 && msg[9] == 1)
576 {
577 /* Protocol T=1. */
578 printf (" bmFindexDindex ....: %02X\n", msg[10]);
579 printf (" bmTCCKST1 .........: %02X\n", msg[11]);
580 printf (" bGuardTimeT1 ......: %02X\n", msg[12]);
581 printf (" bmWaitingIntegersT1: %02X\n", msg[13]);
582 printf (" bClockStop ........: %02X\n", msg[14]);
583 printf (" bIFSC .............: %d\n", msg[15]);
584 printf (" bNadValue .........: %d\n", msg[16]);
585 }
586 else
587 print_pr_data (msg, msglen, 10);
588 }
589
590
591 static void
print_r2p_escape(const unsigned char * msg,size_t msglen)592 print_r2p_escape (const unsigned char *msg, size_t msglen)
593 {
594 if (skip_escape)
595 return;
596 print_r2p_header ("RDR_to_PC_Escape", msg, msglen);
597 if (msglen < 10)
598 return;
599 printf (" buffer[9] .........: %02X\n", msg[9]);
600 print_pr_data (msg, msglen, 10);
601 }
602
603
604 static void
print_r2p_datarate(const unsigned char * msg,size_t msglen)605 print_r2p_datarate (const unsigned char *msg, size_t msglen)
606 {
607 print_r2p_header ("RDR_to_PC_DataRate", msg, msglen);
608 if (msglen < 10)
609 return;
610 if (msglen >= 18)
611 {
612 printf (" dwClockFrequency ..: %u\n", convert_le_u32 (msg+10));
613 printf (" dwDataRate ..... ..: %u\n", convert_le_u32 (msg+14));
614 print_pr_data (msg, msglen, 18);
615 }
616 else
617 print_pr_data (msg, msglen, 10);
618 }
619
620
621 static void
print_r2p_unknown(const unsigned char * msg,size_t msglen)622 print_r2p_unknown (const unsigned char *msg, size_t msglen)
623 {
624 char buf[100];
625
626 snprintf (buf, sizeof buf, "Unknown RDR_to_PC command 0x%02X",
627 msglen? msg[0]:0);
628 print_r2p_header (buf, msg, msglen);
629 if (msglen < 10)
630 return;
631 printf (" bMessageType ......: %02X\n", msg[0]);
632 printf (" buffer[9] .........: %02X\n", msg[9]);
633 print_pr_data (msg, msglen, 10);
634 }
635
636
637 static void
print_r2p(const unsigned char * msg,size_t msglen)638 print_r2p (const unsigned char *msg, size_t msglen)
639 {
640 switch (msglen? msg[0]:0)
641 {
642 case RDR_to_PC_DataBlock:
643 print_r2p_datablock (msg, msglen);
644 break;
645 case RDR_to_PC_SlotStatus:
646 print_r2p_slotstatus (msg, msglen);
647 break;
648 case RDR_to_PC_Parameters:
649 print_r2p_parameters (msg, msglen);
650 break;
651 case RDR_to_PC_Escape:
652 print_r2p_escape (msg, msglen);
653 break;
654 case RDR_to_PC_DataRate:
655 print_r2p_datarate (msg, msglen);
656 break;
657 default:
658 print_r2p_unknown (msg, msglen);
659 break;
660 }
661
662 }
663
664
665 static void
flush_data(void)666 flush_data (void)
667 {
668 if (!databuffer.count)
669 return;
670
671 if (verbose)
672 {
673 printf ("Timestamp: %s\n", databuffer.timestamp);
674 printf ("Address..: %s\n", databuffer.address);
675 }
676 if (databuffer.is_bi)
677 {
678 print_r2p (databuffer.data, databuffer.count);
679 if (verbose)
680 putchar ('\n');
681 }
682 else
683 print_p2r (databuffer.data, databuffer.count);
684
685 databuffer.count = 0;
686 }
687
688 static void
collect_data(char * hexdata,const char * timestamp,const char * address,unsigned int lineno)689 collect_data (char *hexdata, const char *timestamp,
690 const char *address, unsigned int lineno)
691 {
692 size_t length;
693 int is_bi;
694 char *s;
695 unsigned int value;
696
697 is_bi = (*address && address[1] == 'i');
698
699 if (databuffer.is_bi != is_bi || strcmp (databuffer.address, address))
700 flush_data ();
701 databuffer.is_bi = is_bi;
702 if (strlen (timestamp) >= sizeof databuffer.timestamp)
703 die ("timestamp field too long");
704 strcpy (databuffer.timestamp, timestamp);
705 if (strlen (address) >= sizeof databuffer.address)
706 die ("address field too long");
707 strcpy (databuffer.address, address);
708
709 length = databuffer.count;
710 for (s=hexdata; *s; s++ )
711 {
712 if (ascii_isspace (*s))
713 continue;
714 if (!hexdigitp (s))
715 {
716 err ("invalid hex digit in line %u - line skipped", lineno);
717 break;
718 }
719 value = xtoi_1 (*s) * 16;
720 s++;
721 if (!hexdigitp (s))
722 {
723 err ("invalid hex digit in line %u - line skipped", lineno);
724 break;
725 }
726 value += xtoi_1 (*s);
727
728 if (length >= sizeof (databuffer.data))
729 {
730 err ("too much data at line %u - can handle only up to %zu bytes",
731 lineno, sizeof (databuffer.data));
732 break;
733 }
734 databuffer.data[length++] = value;
735 }
736 databuffer.count = length;
737 }
738
739
740 static void
parse_line(char * line,unsigned int lineno)741 parse_line (char *line, unsigned int lineno)
742 {
743 char *p;
744 char *timestamp, *event_type, *address, *data, *status, *datatag;
745
746 if (*line == '#' || !*line)
747 return;
748
749 if (debug)
750 printf ("line[%u] ='%s'\n", lineno, line);
751
752 p = strtok (line, " ");
753 if (!p)
754 die ("invalid line %d (no URB)", lineno);
755 timestamp = strtok (NULL, " ");
756 if (!timestamp)
757 die ("invalid line %d (no timestamp)", lineno);
758 event_type = strtok (NULL, " ");
759 if (!event_type)
760 die ("invalid line %d (no event type)", lineno);
761 address = strtok (NULL, " ");
762 if (!address)
763 die ("invalid line %d (no address", lineno);
764 if (usb_bus || usb_dev)
765 {
766 int bus, dev;
767
768 p = strchr (address, ':');
769 if (!p)
770 die ("invalid line %d (invalid address", lineno);
771 p++;
772 bus = atoi (p);
773 p = strchr (p, ':');
774 if (!p)
775 die ("invalid line %d (invalid address", lineno);
776 p++;
777 dev = atoi (p);
778
779 if ((usb_bus && usb_bus != bus) || (usb_dev && usb_dev != dev))
780 return; /* We don't want that one. */
781 }
782 if (*address == 'B' && (address[1] == 'o' || address[1] == 'i'))
783 ; /* We want block ind and out. */
784 else if (*address == 'C' && (address[1] == 'o' || address[1] == 'i'))
785 ; /* We want control ind and out. */
786 else
787 return; /* But nothing else. */
788 status = strtok (NULL, " ");
789 if (!status)
790 return;
791 if (!strchr ("-0123456789", *status))
792 return; /* Setup packet. */
793 /* We don't support "Z[io]" types thus we don't need to check here. */
794 p = strtok (NULL, " ");
795 if (!p)
796 return; /* No data length. */
797
798 datatag = strtok (NULL, " ");
799 if (datatag && *datatag == '=')
800 {
801 data = strtok (NULL, "");
802 collect_data (data?data:"", timestamp, address, lineno);
803 }
804 }
805
806
807 static void
parse_line_sniffusb(char * line,unsigned int lineno)808 parse_line_sniffusb (char *line, unsigned int lineno)
809 {
810 char *p;
811
812 if (debug)
813 printf ("line[%u] ='%s'\n", lineno, line);
814
815 p = strtok (line, " \t");
816 if (!p)
817 return;
818 p = strtok (NULL, " \t");
819 if (!p)
820 return;
821 p = strtok (NULL, " \t");
822 if (!p)
823 return;
824
825 if (hexdigitp (p+0) && hexdigitp (p+1)
826 && hexdigitp (p+2) && hexdigitp (p+3)
827 && p[4] == ':' && !p[5])
828 {
829 size_t length;
830 unsigned int value;
831
832 length = databuffer.count;
833 while ((p=strtok (NULL, " \t")))
834 {
835 if (!hexdigitp (p+0) || !hexdigitp (p+1))
836 {
837 err ("invalid hex digit in line %u (%s)", lineno,p);
838 break;
839 }
840 value = xtoi_1 (p[0]) * 16 + xtoi_1 (p[1]);
841
842 if (length >= sizeof (databuffer.data))
843 {
844 err ("too much data at line %u - can handle only up to % bytes",
845 lineno, sizeof (databuffer.data));
846 break;
847 }
848 databuffer.data[length++] = value;
849 }
850 databuffer.count = length;
851
852 }
853 else if (!strcmp (p, "TransferFlags"))
854 {
855 flush_data ();
856
857 *databuffer.address = 0;
858 while ((p=strtok (NULL, " \t(,)")))
859 {
860 if (!strcmp (p, "USBD_TRANSFER_DIRECTION_IN"))
861 {
862 databuffer.is_bi = 1;
863 break;
864 }
865 else if (!strcmp (p, "USBD_TRANSFER_DIRECTION_OUT"))
866 {
867 databuffer.is_bi = 0;
868 break;
869 }
870 }
871 }
872
873 }
874
875
876 static void
parse_input(FILE * fp)877 parse_input (FILE *fp)
878 {
879 char line[2000];
880 size_t length;
881 unsigned int lineno = 0;
882
883 while (fgets (line, sizeof (line), fp))
884 {
885 lineno++;
886 length = strlen (line);
887 if (length && line[length - 1] == '\n')
888 line[--length] = 0;
889 else
890 err ("line number %u too long or last line not terminated", lineno);
891 if (length && line[length - 1] == '\r')
892 line[--length] = 0;
893 if (sniffusb)
894 parse_line_sniffusb (line, lineno);
895 else
896 parse_line (line, lineno);
897 }
898 flush_data ();
899 if (ferror (fp))
900 err ("error reading input at line %u: %s", lineno, strerror (errno));
901 }
902
903
904 int
main(int argc,char ** argv)905 main (int argc, char **argv)
906 {
907 int last_argc = -1;
908
909 if (argc)
910 {
911 argc--; argv++;
912 }
913 while (argc && last_argc != argc )
914 {
915 last_argc = argc;
916 if (!strcmp (*argv, "--"))
917 {
918 argc--; argv++;
919 break;
920 }
921 else if (!strcmp (*argv, "--version"))
922 {
923 fputs (PGM " (" GNUPG_NAME ") " PACKAGE_VERSION "\n", stdout);
924 exit (0);
925 }
926 else if (!strcmp (*argv, "--help"))
927 {
928 puts ("Usage: " PGM " [BUS:DEV]\n"
929 "Parse the output of usbmod assuming it is CCID compliant.\n\n"
930 " --skip-escape do not show escape packets\n"
931 " --sniffusb Assume output from Sniffusb.exe\n"
932 " --verbose enable extra informational output\n"
933 " --debug enable additional debug output\n"
934 " --help display this help and exit\n\n"
935 "Report bugs to " PACKAGE_BUGREPORT ".");
936 exit (0);
937 }
938 else if (!strcmp (*argv, "--verbose"))
939 {
940 verbose = 1;
941 argc--; argv++;
942 }
943 else if (!strcmp (*argv, "--debug"))
944 {
945 verbose = debug = 1;
946 argc--; argv++;
947 }
948 else if (!strcmp (*argv, "--skip-escape"))
949 {
950 skip_escape = 1;
951 argc--; argv++;
952 }
953 else if (!strcmp (*argv, "--sniffusb"))
954 {
955 sniffusb = 1;
956 argc--; argv++;
957 }
958 }
959
960 if (argc && sniffusb)
961 die ("no arguments expected when using --sniffusb\n");
962 else if (argc > 1)
963 die ("usage: " PGM " [BUS:DEV] (try --help for more information)\n");
964
965 if (argc == 1)
966 {
967 const char *s = strchr (argv[0], ':');
968
969 usb_bus = atoi (argv[0]);
970 if (s)
971 usb_dev = atoi (s+1);
972 if (usb_bus < 1 || usb_bus > 999 || usb_dev < 1 || usb_dev > 999)
973 die ("invalid bus:dev specified");
974 }
975
976
977 signal (SIGPIPE, SIG_IGN);
978
979 parse_input (stdin);
980
981 return any_error? 1:0;
982 }
983
984
985 /*
986 Local Variables:
987 compile-command: "gcc -Wall -Wno-pointer-sign -g -o ccidmon ccidmon.c"
988 End:
989 */
990