~ubuntu-branches/ubuntu/precise/gnupg2/precise-proposed

« back to all changes in this revision

Viewing changes to scd/pcsc-wrapper.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Mueller
  • Date: 2005-03-29 10:30:32 UTC
  • Revision ID: james.westby@ubuntu.com-20050329103032-sj42n2ain3ipx310
Tags: upstream-1.9.15
ImportĀ upstreamĀ versionĀ 1.9.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* pcsc-wrapper.c - Wrapper for ccessing the PC/SC service
 
2
 *      Copyright (C) 2003, 2004 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 2 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, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 
19
 */
 
20
 
 
21
/*
 
22
  This wrapper is required to handle problems with the libpscslite
 
23
  library.  That library assumes that pthreads are used and fails
 
24
  badly if one tries to use it with a procerss using Pth.
 
25
 
 
26
  The operation model is pretty simple: It reads requests from stdin
 
27
  and returns the answer on stdout.  There is no direct mapping to the
 
28
  pcsc interface but to a higher level one which resembles the code
 
29
  used in scdaemon (apdu.c) when not using Pth or while running under
 
30
  Windows.
 
31
  
 
32
  The interface is binary consisting of a command tag and the length
 
33
  of the parameter list.  The calling process needs to pass the
 
34
  version number of the interface on the command line to make sure
 
35
  that both agree on the same interface.  For each port a separate
 
36
  instance of this process needs to be started.
 
37
 
 
38
*/
 
39
 
 
40
#ifdef HAVE_CONFIG_H
 
41
#include <config.h>
 
42
#endif
 
43
#include <stdio.h>
 
44
#include <stdlib.h>
 
45
#include <stddef.h>
 
46
#include <string.h>
 
47
#include <errno.h>
 
48
#include <stdarg.h>
 
49
#include <assert.h>
 
50
#include <dlfcn.h>
 
51
 
 
52
 
 
53
#define PGM "pcsc-wrapper"
 
54
 
 
55
/* Allow for a standalone build. */
 
56
#ifdef VERSION
 
57
#define MYVERSION_LINE PGM " (GnuPG) " VERSION
 
58
#define BUGREPORT_LINE "\nReport bugs to <bug-gnupg@gnu.org>.\n"
 
59
#else
 
60
#define MYVERSION_LINE PGM 
 
61
#define BUGREPORT_LINE ""
 
62
#endif
 
63
 
 
64
#define DEFAULT_PCSC_DRIVER "libpcsclite.so"
 
65
 
 
66
 
 
67
static int verbose;
 
68
 
 
69
 
 
70
/* PC/SC constants and function pointer. */
 
71
#define PCSC_SCOPE_USER      0 
 
72
#define PCSC_SCOPE_TERMINAL  1 
 
73
#define PCSC_SCOPE_SYSTEM    2 
 
74
#define PCSC_SCOPE_GLOBAL    3 
 
75
 
 
76
#define PCSC_PROTOCOL_T0     1 
 
77
#define PCSC_PROTOCOL_T1     2 
 
78
#define PCSC_PROTOCOL_RAW    4 
 
79
 
 
80
#define PCSC_SHARE_EXCLUSIVE 1
 
81
#define PCSC_SHARE_SHARED    2
 
82
#define PCSC_SHARE_DIRECT    3
 
83
 
 
84
#define PCSC_LEAVE_CARD      0
 
85
#define PCSC_RESET_CARD      1
 
86
#define PCSC_UNPOWER_CARD    2
 
87
#define PCSC_EJECT_CARD      3
 
88
 
 
89
#define PCSC_UNKNOWN    0x0001  
 
90
#define PCSC_ABSENT     0x0002  /* Card is absent.  */
 
91
#define PCSC_PRESENT    0x0004  /* Card is present.  */
 
92
#define PCSC_SWALLOWED  0x0008  /* Card is present and electrical connected. */
 
93
#define PCSC_POWERED    0x0010  /* Card is powered.  */
 
94
#define PCSC_NEGOTIABLE 0x0020  /* Card is awaiting PTS.  */
 
95
#define PCSC_SPECIFIC   0x0040  /* Card is ready for use.  */
 
96
 
 
97
#define PCSC_STATE_UNAWARE     0x0000  /* Want status.  */
 
98
#define PCSC_STATE_IGNORE      0x0001  /* Ignore this reader.  */
 
99
#define PCSC_STATE_CHANGED     0x0002  /* State has changed.  */
 
100
#define PCSC_STATE_UNKNOWN     0x0004  /* Reader unknown.  */
 
101
#define PCSC_STATE_UNAVAILABLE 0x0008  /* Status unavailable.  */
 
102
#define PCSC_STATE_EMPTY       0x0010  /* Card removed.  */
 
103
#define PCSC_STATE_PRESENT     0x0020  /* Card inserted.  */
 
104
#define PCSC_STATE_ATRMATCH    0x0040  /* ATR matches card. */
 
105
#define PCSC_STATE_EXCLUSIVE   0x0080  /* Exclusive Mode.  */
 
106
#define PCSC_STATE_INUSE       0x0100  /* Shared mode.  */
 
107
#define PCSC_STATE_MUTE        0x0200  /* Unresponsive card.  */
 
108
 
 
109
struct pcsc_io_request_s {
 
110
  unsigned long protocol; 
 
111
  unsigned long pci_len;
 
112
};
 
113
 
 
114
typedef struct pcsc_io_request_s *pcsc_io_request_t;
 
115
 
 
116
struct pcsc_readerstate_s
 
117
{
 
118
  const char *reader;
 
119
  void *user_data;
 
120
  unsigned long current_state;
 
121
  unsigned long event_state;
 
122
  unsigned long atrlen;
 
123
  unsigned char atr[33];
 
124
};
 
125
 
 
126
typedef struct pcsc_readerstate_s *pcsc_readerstate_t;
 
127
 
 
128
 
 
129
static int driver_is_open;     /* True if the PC/SC driver has been
 
130
                                  initialzied and is ready for
 
131
                                  operations.  The following variables
 
132
                                  are then valid. */
 
133
static unsigned long pcsc_context;  /* The current PC/CS context. */
 
134
static char *current_rdrname;
 
135
static unsigned long pcsc_card;
 
136
static unsigned long pcsc_protocol;
 
137
static unsigned char current_atr[33];
 
138
static size_t current_atrlen;
 
139
 
 
140
long (* pcsc_establish_context) (unsigned long scope,
 
141
                                 const void *reserved1,
 
142
                                 const void *reserved2,
 
143
                                 unsigned long *r_context);
 
144
long (* pcsc_release_context) (unsigned long context);
 
145
long (* pcsc_list_readers) (unsigned long context,
 
146
                            const char *groups,
 
147
                            char *readers, unsigned long*readerslen);
 
148
long (* pcsc_get_status_change) (unsigned long context,
 
149
                                 unsigned long timeout,
 
150
                                 pcsc_readerstate_t readerstates,
 
151
                                 unsigned long nreaderstates);
 
152
long (* pcsc_connect) (unsigned long context,
 
153
                       const char *reader,
 
154
                       unsigned long share_mode,
 
155
                       unsigned long preferred_protocols,
 
156
                       unsigned long *r_card,
 
157
                       unsigned long *r_active_protocol);
 
158
long (* pcsc_reconnect) (unsigned long card,
 
159
                         unsigned long share_mode,
 
160
                         unsigned long preferred_protocols,
 
161
                         unsigned long initialization,
 
162
                         unsigned long *r_active_protocol);
 
163
long (* pcsc_disconnect) (unsigned long card,
 
164
                          unsigned long disposition);
 
165
long (* pcsc_status) (unsigned long card,
 
166
                      char *reader, unsigned long *readerlen,
 
167
                      unsigned long *r_state,
 
168
                      unsigned long *r_protocol,
 
169
                      unsigned char *atr, unsigned long *atrlen);
 
170
long (* pcsc_begin_transaction) (unsigned long card);
 
171
long (* pcsc_end_transaction) (unsigned long card);
 
172
long (* pcsc_transmit) (unsigned long card,
 
173
                        const pcsc_io_request_t send_pci,
 
174
                        const unsigned char *send_buffer,
 
175
                        unsigned long send_len,
 
176
                        pcsc_io_request_t recv_pci,
 
177
                        unsigned char *recv_buffer,
 
178
                        unsigned long *recv_len);
 
179
long (* pcsc_set_timeout) (unsigned long context,
 
180
                           unsigned long timeout);
 
181
 
 
182
 
 
183
 
 
184
static void
 
185
bad_request (const char *type)
 
186
{
 
187
  fprintf (stderr, PGM ": bad `%s' request\n", type);
 
188
  exit (1);
 
189
}
 
190
 
 
191
static void
 
192
request_failed (int err)
 
193
{
 
194
  if (!err)
 
195
    err = -1;
 
196
 
 
197
  putchar (0x81); /* Simple error/success response. */
 
198
 
 
199
  putchar (0);
 
200
  putchar (0);
 
201
  putchar (0);
 
202
  putchar (4);
 
203
 
 
204
  putchar ((err >> 24) & 0xff);
 
205
  putchar ((err >> 16) & 0xff);
 
206
  putchar ((err >>  8) & 0xff);
 
207
  putchar ((err      ) & 0xff);
 
208
 
 
209
  fflush (stdout);
 
210
}
 
211
 
 
212
 
 
213
static void
 
214
request_succeeded (const void *buffer, size_t buflen)
 
215
{
 
216
  size_t len;
 
217
 
 
218
  putchar (0x81); /* Simple error/success response. */
 
219
 
 
220
  len = 4 + buflen;
 
221
  putchar ((len >> 24) & 0xff);
 
222
  putchar ((len >> 16) & 0xff);
 
223
  putchar ((len >>  8) & 0xff);
 
224
  putchar ((len      ) & 0xff);
 
225
 
 
226
  /* Error code. */
 
227
  putchar (0);
 
228
  putchar (0);
 
229
  putchar (0);
 
230
  putchar (0);
 
231
 
 
232
  /* Optional reponse string. */
 
233
  if (buffer)
 
234
    fwrite (buffer, buflen, 1, stdout);
 
235
 
 
236
  fflush (stdout);
 
237
}
 
238
  
 
239
 
 
240
 
 
241
static unsigned long
 
242
read_32 (FILE *fp)
 
243
{
 
244
  int c1, c2, c3, c4;
 
245
 
 
246
  c1 = getc (stdin);
 
247
  c2 = getc (stdin);
 
248
  c3 = getc (stdin);
 
249
  c4 = getc (stdin);
 
250
  if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF)
 
251
    {
 
252
      fprintf (stderr, PGM ": premature EOF while parsing request\n");
 
253
      exit (1);
 
254
    }
 
255
  return (c1 << 24) | (c2 << 16) | (c3 << 8) | c4;
 
256
}
 
257
 
 
258
 
 
259
 
 
260
static const char *
 
261
pcsc_error_string (long err)
 
262
{
 
263
  const char *s;
 
264
 
 
265
  if (!err)
 
266
    return "okay";
 
267
  if ((err & 0x80100000) != 0x80100000)
 
268
    return "invalid PC/SC error code";
 
269
  err &= 0xffff;
 
270
  switch (err)
 
271
    {
 
272
    case 0x0002: s = "cancelled"; break;
 
273
    case 0x000e: s = "can't dispose"; break;
 
274
    case 0x0008: s = "insufficient buffer"; break;   
 
275
    case 0x0015: s = "invalid ATR"; break;
 
276
    case 0x0003: s = "invalid handle"; break;
 
277
    case 0x0004: s = "invalid parameter"; break; 
 
278
    case 0x0005: s = "invalid target"; break;
 
279
    case 0x0011: s = "invalid value"; break; 
 
280
    case 0x0006: s = "no memory"; break;  
 
281
    case 0x0013: s = "comm error"; break;      
 
282
    case 0x0001: s = "internal error"; break;     
 
283
    case 0x0014: s = "unknown error"; break; 
 
284
    case 0x0007: s = "waited too long"; break;  
 
285
    case 0x0009: s = "unknown reader"; break;
 
286
    case 0x000a: s = "timeout"; break; 
 
287
    case 0x000b: s = "sharing violation"; break;       
 
288
    case 0x000c: s = "no smartcard"; break;
 
289
    case 0x000d: s = "unknown card"; break;   
 
290
    case 0x000f: s = "proto mismatch"; break;          
 
291
    case 0x0010: s = "not ready"; break;               
 
292
    case 0x0012: s = "system cancelled"; break;        
 
293
    case 0x0016: s = "not transacted"; break;
 
294
    case 0x0017: s = "reader unavailable"; break; 
 
295
    case 0x0065: s = "unsupported card"; break;        
 
296
    case 0x0066: s = "unresponsive card"; break;       
 
297
    case 0x0067: s = "unpowered card"; break;          
 
298
    case 0x0068: s = "reset card"; break;              
 
299
    case 0x0069: s = "removed card"; break;            
 
300
    case 0x006a: s = "inserted card"; break;           
 
301
    case 0x001f: s = "unsupported feature"; break;     
 
302
    case 0x0019: s = "PCI too small"; break;           
 
303
    case 0x001a: s = "reader unsupported"; break;      
 
304
    case 0x001b: s = "duplicate reader"; break;        
 
305
    case 0x001c: s = "card unsupported"; break;        
 
306
    case 0x001d: s = "no service"; break;              
 
307
    case 0x001e: s = "service stopped"; break;      
 
308
    default:     s = "unknown PC/SC error code"; break;
 
309
    }
 
310
  return s;
 
311
}
 
312
 
 
313
static void
 
314
load_pcsc_driver (const char *libname)
 
315
{
 
316
  void *handle;
 
317
 
 
318
  handle = dlopen (libname, RTLD_LAZY);
 
319
  if (!handle)
 
320
    {
 
321
      fprintf (stderr, PGM ": failed to open driver `%s': %s",
 
322
               libname, dlerror ());
 
323
      exit (1);
 
324
    }
 
325
 
 
326
  pcsc_establish_context = dlsym (handle, "SCardEstablishContext");
 
327
  pcsc_release_context   = dlsym (handle, "SCardReleaseContext");
 
328
  pcsc_list_readers      = dlsym (handle, "SCardListReaders");
 
329
  pcsc_get_status_change = dlsym (handle, "SCardGetStatusChange");
 
330
  pcsc_connect           = dlsym (handle, "SCardConnect");
 
331
  pcsc_reconnect         = dlsym (handle, "SCardReconnect");
 
332
  pcsc_disconnect        = dlsym (handle, "SCardDisconnect");
 
333
  pcsc_status            = dlsym (handle, "SCardStatus");
 
334
  pcsc_begin_transaction = dlsym (handle, "SCardBeginTransaction");
 
335
  pcsc_end_transaction   = dlsym (handle, "SCardEndTransaction");
 
336
  pcsc_transmit          = dlsym (handle, "SCardTransmit");
 
337
  pcsc_set_timeout       = dlsym (handle, "SCardSetTimeout");
 
338
 
 
339
  if (!pcsc_establish_context
 
340
      || !pcsc_release_context  
 
341
      || !pcsc_list_readers     
 
342
      || !pcsc_get_status_change
 
343
      || !pcsc_connect          
 
344
      || !pcsc_reconnect          
 
345
      || !pcsc_disconnect
 
346
      || !pcsc_status
 
347
      || !pcsc_begin_transaction
 
348
      || !pcsc_end_transaction
 
349
      || !pcsc_transmit         
 
350
      /* || !pcsc_set_timeout */)
 
351
    {
 
352
      /* Note that set_timeout is currently not used and also not
 
353
         available under Windows. */
 
354
      fprintf (stderr,
 
355
               "apdu_open_reader: invalid PC/SC driver "
 
356
               "(%d%d%d%d%d%d%d%d%d%d%d%d)\n",
 
357
               !!pcsc_establish_context,
 
358
               !!pcsc_release_context,  
 
359
               !!pcsc_list_readers,     
 
360
               !!pcsc_get_status_change,     
 
361
               !!pcsc_connect,          
 
362
               !!pcsc_reconnect,          
 
363
               !!pcsc_disconnect,
 
364
               !!pcsc_status,
 
365
               !!pcsc_begin_transaction,
 
366
               !!pcsc_end_transaction,
 
367
               !!pcsc_transmit,         
 
368
               !!pcsc_set_timeout );
 
369
      dlclose (handle);
 
370
      exit (1);
 
371
    }
 
372
}
 
373
  
 
374
 
 
375
 
 
376
 
 
377
/* Handle a open request.  The argument is expected to be a string
 
378
   with the port identification.  ARGBUF is always guaranteed to be
 
379
   terminted by a 0 which is not counted in ARGLEN.  We may modifiy
 
380
   ARGBUF. */
 
381
static void
 
382
handle_open (unsigned char *argbuf, size_t arglen)
 
383
{
 
384
  long err;
 
385
  const char * portstr;
 
386
  char *list = NULL;
 
387
  unsigned long nreader, listlen, atrlen;
 
388
  char *p;
 
389
  unsigned long card_state, card_protocol;
 
390
  unsigned char atr[33];
 
391
 
 
392
  /* Make sure there is only the port string */
 
393
  if (arglen != strlen (argbuf))
 
394
    bad_request ("OPEN");
 
395
  portstr = argbuf;
 
396
 
 
397
  if (driver_is_open)
 
398
    {
 
399
      fprintf (stderr, PGM ": PC/SC has already been opened\n");
 
400
      request_failed (-1);
 
401
      return;
 
402
    }
 
403
 
 
404
  err = pcsc_establish_context (PCSC_SCOPE_SYSTEM, NULL, NULL, &pcsc_context);
 
405
  if (err)
 
406
    {
 
407
      fprintf (stderr, PGM": pcsc_establish_context failed: %s (0x%lx)\n",
 
408
               pcsc_error_string (err), err);
 
409
      request_failed (err);
 
410
      return;
 
411
    }
 
412
  
 
413
  err = pcsc_list_readers (pcsc_context, NULL, NULL, &nreader);
 
414
  if (!err)
 
415
    {
 
416
      list = malloc (nreader+1); /* Better add 1 for safety reasons. */
 
417
      if (!list)
 
418
        {
 
419
          fprintf (stderr, PGM": error allocating memory for reader list\n");
 
420
          exit (1);
 
421
        }
 
422
      err = pcsc_list_readers (pcsc_context, NULL, list, &nreader);
 
423
    }
 
424
  if (err)
 
425
    {
 
426
      fprintf (stderr, PGM": pcsc_list_readers failed: %s (0x%lx)\n",
 
427
               pcsc_error_string (err), err);
 
428
      pcsc_release_context (pcsc_context);
 
429
      free (list);
 
430
      request_failed (err);
 
431
      return;
 
432
    }
 
433
 
 
434
  listlen = nreader;
 
435
  p = list;
 
436
  while (nreader)
 
437
    {
 
438
      if (!*p && !p[1])
 
439
        break;
 
440
      fprintf (stderr, PGM": detected reader `%s'\n", p);
 
441
      if (nreader < (strlen (p)+1))
 
442
        {
 
443
          fprintf (stderr, PGM": invalid response from pcsc_list_readers\n");
 
444
          break;
 
445
        }
 
446
      nreader -= strlen (p)+1;
 
447
      p += strlen (p) + 1;
 
448
    }
 
449
 
 
450
  current_rdrname = malloc (strlen (portstr && *portstr? portstr:list)+1);
 
451
  if (!current_rdrname)
 
452
    {
 
453
      fprintf (stderr, PGM": error allocating memory for reader name\n");
 
454
      exit (1);
 
455
    }
 
456
  strcpy (current_rdrname, portstr && *portstr? portstr:list);
 
457
  free (list);
 
458
 
 
459
  err = pcsc_connect (pcsc_context,
 
460
                      current_rdrname,
 
461
                      PCSC_SHARE_EXCLUSIVE,
 
462
                      PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
 
463
                      &pcsc_card,
 
464
                      &pcsc_protocol);
 
465
  if (err == 0x8010000c) /* No smartcard.  */
 
466
    {
 
467
      pcsc_card = 0;
 
468
    }
 
469
  else if (err)
 
470
    {
 
471
      fprintf (stderr, PGM": pcsc_connect failed: %s (0x%lx)\n",
 
472
               pcsc_error_string (err), err);
 
473
      pcsc_release_context (pcsc_context);
 
474
      free (current_rdrname);
 
475
      current_rdrname = NULL;
 
476
      request_failed (err);
 
477
      return;
 
478
    }      
 
479
  
 
480
  current_atrlen = 0;
 
481
  if (!err)
 
482
    {
 
483
      char reader[250];
 
484
      unsigned long readerlen;
 
485
 
 
486
      atrlen = 33;
 
487
      readerlen = sizeof reader -1;
 
488
      err = pcsc_status (pcsc_card,
 
489
                         reader, &readerlen,
 
490
                         &card_state, &card_protocol,
 
491
                         atr, &atrlen);
 
492
      if (err)
 
493
        fprintf (stderr, PGM": pcsc_status failed: %s (0x%lx)\n",
 
494
                 pcsc_error_string (err), err);
 
495
      else
 
496
        {
 
497
          if (atrlen >= sizeof atr || atrlen >= sizeof current_atr)
 
498
            {
 
499
              fprintf (stderr, PGM": ATR returned by pcsc_status"
 
500
                       " is too large\n");
 
501
              exit (4);
 
502
            }
 
503
          memcpy (current_atr, atr, atrlen);
 
504
          current_atrlen = atrlen;
 
505
        }
 
506
    }
 
507
 
 
508
  driver_is_open = 1;
 
509
  request_succeeded (current_atr, current_atrlen);
 
510
}
 
511
 
 
512
 
 
513
 
 
514
/* Handle a close request.  We expect no arguments.  We may modifiy
 
515
   ARGBUF. */
 
516
static void
 
517
handle_close (unsigned char *argbuf, size_t arglen)
 
518
{
 
519
  if (!driver_is_open)
 
520
    {
 
521
      fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
 
522
      request_failed (-1);
 
523
      return;
 
524
    }
 
525
 
 
526
  free (current_rdrname);
 
527
  current_rdrname = NULL;
 
528
  pcsc_release_context (pcsc_context);
 
529
 
 
530
  request_succeeded (NULL, 0);
 
531
}
 
532
 
 
533
 
 
534
 
 
535
/* Handle a status request.  We expect no arguments.  We may modifiy
 
536
   ARGBUF. */
 
537
static void
 
538
handle_status (unsigned char *argbuf, size_t arglen)
 
539
{
 
540
  long err;
 
541
  struct pcsc_readerstate_s rdrstates[1];
 
542
  int status;
 
543
  unsigned char buf[20];
 
544
 
 
545
  if (!driver_is_open)
 
546
    {
 
547
      fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
 
548
      request_failed (-1);
 
549
      return;
 
550
    }
 
551
 
 
552
  memset (rdrstates, 0, sizeof *rdrstates);
 
553
  rdrstates[0].reader = current_rdrname;
 
554
  rdrstates[0].current_state = PCSC_STATE_UNAWARE;
 
555
  err = pcsc_get_status_change (pcsc_context,
 
556
                                0,
 
557
                                rdrstates, 1);
 
558
  if (err == 0x8010000a) /* Timeout.  */
 
559
    err = 0;
 
560
  if (err)
 
561
    {
 
562
      fprintf (stderr, PGM": pcsc_get_status_change failed: %s (0x%lx)\n",
 
563
               pcsc_error_string (err), err);
 
564
      request_failed (err);
 
565
      return;
 
566
    }
 
567
 
 
568
  status = 0;
 
569
  if ( (rdrstates[0].event_state & PCSC_STATE_PRESENT) )
 
570
    status |= 2;
 
571
  if ( !(rdrstates[0].event_state & PCSC_STATE_MUTE) )
 
572
    status |= 4;
 
573
  /* We indicate a useful card if it is not in use by another
 
574
     application.  This is because we only use exclusive access
 
575
     mode.  */
 
576
  if ( (status & 6) == 6
 
577
       && !(rdrstates[0].event_state & PCSC_STATE_INUSE) )
 
578
    status |= 1;
 
579
  
 
580
  /* First word is identical to the one used by apdu.c. */
 
581
  buf[0] = 0;
 
582
  buf[1] = 0;
 
583
  buf[2] = 0;
 
584
  buf[3] = status;
 
585
  /* The second word is the native PCSC state.  */
 
586
  buf[4] = (rdrstates[0].event_state >> 24);
 
587
  buf[5] = (rdrstates[0].event_state >> 16);
 
588
  buf[6] = (rdrstates[0].event_state >>  8);
 
589
  buf[7] = (rdrstates[0].event_state >>  0);
 
590
 
 
591
  request_succeeded (buf, 8);
 
592
}
 
593
 
 
594
 
 
595
/* Handle a reset request.  We expect no arguments.  We may modifiy
 
596
   ARGBUF. */
 
597
static void
 
598
handle_reset (unsigned char *argbuf, size_t arglen)
 
599
{
 
600
  long err;
 
601
  char reader[250];
 
602
  unsigned long nreader, atrlen;
 
603
  unsigned long card_state, card_protocol;
 
604
 
 
605
  if (!driver_is_open)
 
606
    {
 
607
      fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
 
608
      request_failed (-1);
 
609
      return;
 
610
    }
 
611
 
 
612
  if (pcsc_card)
 
613
    {
 
614
      err = pcsc_disconnect (pcsc_card, PCSC_LEAVE_CARD);
 
615
      if (err)
 
616
        {
 
617
          fprintf (stderr, PGM": pcsc_disconnect failed: %s (0x%lx)\n",
 
618
                     pcsc_error_string (err), err);
 
619
          request_failed (err);
 
620
          return;
 
621
        }
 
622
      pcsc_card = 0;
 
623
    }
 
624
 
 
625
  err = pcsc_connect (pcsc_context,
 
626
                      current_rdrname,
 
627
                      PCSC_SHARE_EXCLUSIVE,
 
628
                      PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
 
629
                      &pcsc_card,
 
630
                      &pcsc_protocol);
 
631
  if (err)
 
632
    {
 
633
      fprintf (stderr, PGM": pcsc_connect failed: %s (0x%lx)\n",
 
634
               pcsc_error_string (err), err);
 
635
      pcsc_card = 0;
 
636
      request_failed (err);
 
637
      return;
 
638
    }      
 
639
 
 
640
  
 
641
  atrlen = 33;
 
642
  nreader = sizeof reader - 1;
 
643
  err = pcsc_status (pcsc_card,
 
644
                     reader, &nreader,
 
645
                     &card_state, &card_protocol,
 
646
                     current_atr, &atrlen);
 
647
  if (err)
 
648
    {
 
649
      fprintf (stderr, PGM": pcsc_status failed: %s (0x%lx)\n",
 
650
               pcsc_error_string (err), err);
 
651
      current_atrlen = 0;
 
652
      request_failed (err);
 
653
      return;
 
654
    }
 
655
 
 
656
  request_succeeded (current_atr, current_atrlen);
 
657
}
 
658
 
 
659
 
 
660
 
 
661
/* Handle a transmit request.  The argument is expected to be a buffer
 
662
   with the APDU.  We may modifiy ARGBUF. */
 
663
static void
 
664
handle_transmit (unsigned char *argbuf, size_t arglen)
 
665
{
 
666
  long err;
 
667
  struct pcsc_io_request_s send_pci;
 
668
  unsigned long recv_len;
 
669
  unsigned char buffer[1024];
 
670
 
 
671
  /* The apdu should at least be one byte. */
 
672
  if (!arglen)
 
673
    bad_request ("TRANSMIT");
 
674
 
 
675
  if (!driver_is_open)
 
676
    {
 
677
      fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
 
678
      request_failed (-1);
 
679
      return;
 
680
    }
 
681
  if ((pcsc_protocol & PCSC_PROTOCOL_T1))
 
682
    send_pci.protocol = PCSC_PROTOCOL_T1;
 
683
  else
 
684
    send_pci.protocol = PCSC_PROTOCOL_T0;
 
685
  send_pci.pci_len = sizeof send_pci;
 
686
  recv_len = sizeof (buffer);
 
687
  err = pcsc_transmit (pcsc_card, &send_pci, argbuf, arglen,
 
688
                       NULL, buffer, &recv_len);
 
689
  if (err)
 
690
    {
 
691
      if (verbose)
 
692
        fprintf (stderr, PGM": pcsc_transmit failed: %s (0x%lx)\n",
 
693
                 pcsc_error_string (err), err);
 
694
      request_failed (err);
 
695
      return;
 
696
    }
 
697
  request_succeeded (buffer, recv_len);
 
698
}
 
699
 
 
700
 
 
701
 
 
702
static void
 
703
print_version (int with_help)
 
704
{
 
705
  fputs (MYVERSION_LINE "\n"
 
706
         "Copyright (C) 2004 Free Software Foundation, Inc.\n"
 
707
         "This program comes with ABSOLUTELY NO WARRANTY.\n"
 
708
         "This is free software, and you are welcome to redistribute it\n"
 
709
         "under certain conditions. See the file COPYING for details.\n",
 
710
         stdout);
 
711
        
 
712
  if (with_help)
 
713
    fputs ("\n"
 
714
          "Usage: " PGM " [OPTIONS] API-NUMBER [LIBNAME]\n"
 
715
          "Helper to connect scdaemon to the PC/SC library\n"
 
716
          "\n"
 
717
          "  --verbose   enable extra informational output\n"
 
718
          "  --version   print version of the program and exit\n"
 
719
          "  --help      display this help and exit\n"
 
720
          BUGREPORT_LINE, stdout );
 
721
  
 
722
  exit (0);
 
723
}
 
724
 
 
725
 
 
726
int
 
727
main (int argc, char **argv)
 
728
{
 
729
  int last_argc = -1;
 
730
  int api_number = 0;
 
731
  int c;
 
732
 
 
733
  if (argc)
 
734
    {
 
735
      argc--; argv++;
 
736
    }
 
737
  while (argc && last_argc != argc )
 
738
    {
 
739
      last_argc = argc;
 
740
      if (!strcmp (*argv, "--"))
 
741
        {
 
742
          argc--; argv++;
 
743
          break;
 
744
        }
 
745
      else if (!strcmp (*argv, "--version"))
 
746
        print_version (0);
 
747
      else if (!strcmp (*argv, "--help"))
 
748
        print_version (1);
 
749
      else if (!strcmp (*argv, "--verbose"))
 
750
        {
 
751
          verbose = 1;
 
752
          argc--; argv++;
 
753
        }
 
754
    }          
 
755
  if (argc != 1 && argc != 2)
 
756
    {
 
757
      fprintf (stderr, "usage: " PGM " API-NUMBER [LIBNAME]\n");
 
758
      exit (1);
 
759
    }
 
760
 
 
761
  api_number = atoi (*argv);
 
762
  argv++; argc--;
 
763
  if (api_number != 1)
 
764
    {
 
765
      fprintf (stderr, PGM ": api-number %d is not valid\n", api_number);
 
766
      exit (1);
 
767
    }
 
768
 
 
769
  load_pcsc_driver (argc? *argv : DEFAULT_PCSC_DRIVER);
 
770
 
 
771
  while ((c = getc (stdin)) != EOF)
 
772
    {
 
773
      size_t arglen;
 
774
      unsigned char argbuffer[2048];
 
775
      
 
776
      arglen = read_32 (stdin);
 
777
      if (arglen >= sizeof argbuffer - 1)
 
778
        {
 
779
          fprintf (stderr, PGM ": request too long\n");
 
780
          exit (1);
 
781
        }
 
782
      if (arglen && fread (argbuffer, arglen, 1, stdin) != 1)
 
783
        {
 
784
          fprintf (stderr, PGM ": error reading request: %s\n",
 
785
                   strerror (errno));
 
786
          exit (1);
 
787
        }
 
788
      argbuffer[arglen] = 0;
 
789
      switch (c)
 
790
        {
 
791
        case 1:
 
792
          handle_open (argbuffer, arglen);
 
793
          break;
 
794
 
 
795
        case 2:
 
796
          handle_close (argbuffer, arglen);
 
797
          exit (0);
 
798
          break;
 
799
 
 
800
        case 3:
 
801
          handle_transmit (argbuffer, arglen);
 
802
          break;
 
803
 
 
804
        case 4:
 
805
          handle_status (argbuffer, arglen);
 
806
          break;
 
807
 
 
808
        case 5:
 
809
          handle_reset (argbuffer, arglen);
 
810
          break;
 
811
 
 
812
        default:
 
813
          fprintf (stderr, PGM ": invalid request 0x%02X\n", c);
 
814
          exit (1);
 
815
        }
 
816
      free (argbuffer);
 
817
    }
 
818
  return 0;
 
819
}
 
820
 
 
821
 
 
822
 
 
823
/*
 
824
Local Variables:
 
825
compile-command: "gcc -Wall -g -o pcsc-wrapper pcsc-wrapper.c -ldl"
 
826
End:
 
827
*/