~ubuntu-branches/ubuntu/karmic/gnupg2/karmic-security

« back to all changes in this revision

Viewing changes to tools/ccidmon.c

  • Committer: Bazaar Package Importer
  • Author(s): Soren Hansen
  • Date: 2009-08-04 12:27:49 UTC
  • mfrom: (1.1.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20090804122749-q0j52zp6xmzvyall
Tags: 2.0.12-0ubuntu1
* New upstream release.
* Add 01-scd-pw2.patch, 03-opgp-writekey.patch, and 06-opgp-sign3072.patch
  from https://bugs.g10code.com/gnupg/issue1094 to make OpenPGP 2.0
  smartcards work.

Show diffs side-by-side

added added

removed removed

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