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