f2f6d52bc231c7ca06d79fce8b2662469e9d2a0e
[gnupg.git] / scd / pcsc-wrapper.c
1 /* pcsc-wrapper.c - Wrapper for accessing 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 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 wrapper is required to handle problems with the libpscslite
22   library.  That library assumes that pthreads are used and fails
23   badly if one tries to use it with a procerss using Pth.
24
25   The operation model is pretty simple: It reads requests from stdin
26   and returns the answer on stdout.  There is no direct mapping to the
27   pcsc interface but to a higher level one which resembles the code
28   used in scdaemon (apdu.c) when not using Pth or while running under
29   Windows.
30
31   The interface is binary consisting of a command tag and the length
32   of the parameter list.  The calling process needs to pass the
33   version number of the interface on the command line to make sure
34   that both agree on the same interface.  For each port a separate
35   instance of this process needs to be started.
36
37 */
38
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <stddef.h>
45 #include <string.h>
46 #include <errno.h>
47 #include <stdarg.h>
48 #include <assert.h>
49 #include <dlfcn.h>
50
51
52 #define PGM "pcsc-wrapper"
53
54 /* Allow for a standalone build. */
55 #ifdef VERSION
56 #define MYVERSION_LINE PGM " (GnuPG) " VERSION
57 #define BUGREPORT_LINE "\nReport bugs to <bug-gnupg@gnu.org>.\n"
58 #else
59 #define MYVERSION_LINE PGM
60 #define BUGREPORT_LINE ""
61 #endif
62
63 #define DEFAULT_PCSC_DRIVER "libpcsclite.so"
64
65
66 static int verbose;
67
68
69 /* PC/SC constants and function pointer. */
70 #define PCSC_SCOPE_USER      0
71 #define PCSC_SCOPE_TERMINAL  1
72 #define PCSC_SCOPE_SYSTEM    2
73 #define PCSC_SCOPE_GLOBAL    3
74
75 #define PCSC_PROTOCOL_T0     1
76 #define PCSC_PROTOCOL_T1     2
77 #define PCSC_PROTOCOL_RAW    4
78
79 #define PCSC_SHARE_EXCLUSIVE 1
80 #define PCSC_SHARE_SHARED    2
81 #define PCSC_SHARE_DIRECT    3
82
83 #define PCSC_LEAVE_CARD      0
84 #define PCSC_RESET_CARD      1
85 #define PCSC_UNPOWER_CARD    2
86 #define PCSC_EJECT_CARD      3
87
88 #define PCSC_UNKNOWN    0x0001
89 #define PCSC_ABSENT     0x0002  /* Card is absent.  */
90 #define PCSC_PRESENT    0x0004  /* Card is present.  */
91 #define PCSC_SWALLOWED  0x0008  /* Card is present and electrical connected. */
92 #define PCSC_POWERED    0x0010  /* Card is powered.  */
93 #define PCSC_NEGOTIABLE 0x0020  /* Card is awaiting PTS.  */
94 #define PCSC_SPECIFIC   0x0040  /* Card is ready for use.  */
95
96 #define PCSC_STATE_UNAWARE     0x0000  /* Want status.  */
97 #define PCSC_STATE_IGNORE      0x0001  /* Ignore this reader.  */
98 #define PCSC_STATE_CHANGED     0x0002  /* State has changed.  */
99 #define PCSC_STATE_UNKNOWN     0x0004  /* Reader unknown.  */
100 #define PCSC_STATE_UNAVAILABLE 0x0008  /* Status unavailable.  */
101 #define PCSC_STATE_EMPTY       0x0010  /* Card removed.  */
102 #define PCSC_STATE_PRESENT     0x0020  /* Card inserted.  */
103 #define PCSC_STATE_ATRMATCH    0x0040  /* ATR matches card. */
104 #define PCSC_STATE_EXCLUSIVE   0x0080  /* Exclusive Mode.  */
105 #define PCSC_STATE_INUSE       0x0100  /* Shared mode.  */
106 #define PCSC_STATE_MUTE        0x0200  /* Unresponsive card.  */
107
108 struct pcsc_io_request_s {
109   unsigned long protocol;
110   unsigned long pci_len;
111 };
112
113 typedef struct pcsc_io_request_s *pcsc_io_request_t;
114
115 struct pcsc_readerstate_s
116 {
117   const char *reader;
118   void *user_data;
119   unsigned long current_state;
120   unsigned long event_state;
121   unsigned long atrlen;
122   unsigned char atr[33];
123 };
124
125 typedef struct pcsc_readerstate_s *pcsc_readerstate_t;
126
127
128 static int driver_is_open;     /* True if the PC/SC driver has been
129                                   initialzied and is ready for
130                                   operations.  The following variables
131                                   are then valid. */
132 static unsigned long pcsc_context;  /* The current PC/CS context. */
133 static char *current_rdrname;
134 static unsigned long pcsc_card;
135 static unsigned long pcsc_protocol;
136 static unsigned char current_atr[33];
137 static size_t current_atrlen;
138
139 long (* pcsc_establish_context) (unsigned long scope,
140                                  const void *reserved1,
141                                  const void *reserved2,
142                                  unsigned long *r_context);
143 long (* pcsc_release_context) (unsigned long context);
144 long (* pcsc_list_readers) (unsigned long context,
145                             const char *groups,
146                             char *readers, unsigned long*readerslen);
147 long (* pcsc_get_status_change) (unsigned long context,
148                                  unsigned long timeout,
149                                  pcsc_readerstate_t readerstates,
150                                  unsigned long nreaderstates);
151 long (* pcsc_connect) (unsigned long context,
152                        const char *reader,
153                        unsigned long share_mode,
154                        unsigned long preferred_protocols,
155                        unsigned long *r_card,
156                        unsigned long *r_active_protocol);
157 long (* pcsc_reconnect) (unsigned long card,
158                          unsigned long share_mode,
159                          unsigned long preferred_protocols,
160                          unsigned long initialization,
161                          unsigned long *r_active_protocol);
162 long (* pcsc_disconnect) (unsigned long card,
163                           unsigned long disposition);
164 long (* pcsc_status) (unsigned long card,
165                       char *reader, unsigned long *readerlen,
166                       unsigned long *r_state,
167                       unsigned long *r_protocol,
168                       unsigned char *atr, unsigned long *atrlen);
169 long (* pcsc_begin_transaction) (unsigned long card);
170 long (* pcsc_end_transaction) (unsigned long card,
171                                unsigned long disposition);
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 (fp);
247   c2 = getc (fp);
248   c3 = getc (fp);
249   c4 = getc (fp);
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 ((char*)argbuf))
394     bad_request ("OPEN");
395   portstr = (char*)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       pcsc_card = 0;
477       pcsc_protocol = 0;
478       request_failed (err);
479       return;
480     }
481
482   current_atrlen = 0;
483   if (!err)
484     {
485       char reader[250];
486       unsigned long readerlen;
487
488       atrlen = 33;
489       readerlen = sizeof reader -1;
490       err = pcsc_status (pcsc_card,
491                          reader, &readerlen,
492                          &card_state, &card_protocol,
493                          atr, &atrlen);
494       if (err)
495         fprintf (stderr, PGM": pcsc_status failed: %s (0x%lx)\n",
496                  pcsc_error_string (err), err);
497       else
498         {
499           if (atrlen >= sizeof atr || atrlen >= sizeof current_atr)
500             {
501               fprintf (stderr, PGM": ATR returned by pcsc_status"
502                        " is too large\n");
503               exit (4);
504             }
505           memcpy (current_atr, atr, atrlen);
506           current_atrlen = atrlen;
507         }
508     }
509
510   driver_is_open = 1;
511   request_succeeded (current_atr, current_atrlen);
512 }
513
514
515
516 /* Handle a close request.  We expect no arguments.  We may modifiy
517    ARGBUF. */
518 static void
519 handle_close (unsigned char *argbuf, size_t arglen)
520 {
521   (void)argbuf;
522   (void)arglen;
523
524   if (!driver_is_open)
525     {
526       fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
527       request_failed (-1);
528       return;
529     }
530
531   free (current_rdrname);
532   current_rdrname = NULL;
533   pcsc_release_context (pcsc_context);
534   pcsc_card = 0;
535   pcsc_protocol = 0;
536
537   request_succeeded (NULL, 0);
538 }
539
540
541
542 /* Handle a status request.  We expect no arguments.  We may modifiy
543    ARGBUF. */
544 static void
545 handle_status (unsigned char *argbuf, size_t arglen)
546 {
547   long err;
548   struct pcsc_readerstate_s rdrstates[1];
549   int status;
550   unsigned char buf[20];
551
552   (void)argbuf;
553   (void)arglen;
554
555   if (!driver_is_open)
556     {
557       fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
558       request_failed (-1);
559       return;
560     }
561
562   memset (rdrstates, 0, sizeof *rdrstates);
563   rdrstates[0].reader = current_rdrname;
564   rdrstates[0].current_state = PCSC_STATE_UNAWARE;
565   err = pcsc_get_status_change (pcsc_context,
566                                 0,
567                                 rdrstates, 1);
568   if (err == 0x8010000a) /* Timeout.  */
569     err = 0;
570   if (err)
571     {
572       fprintf (stderr, PGM": pcsc_get_status_change failed: %s (0x%lx)\n",
573                pcsc_error_string (err), err);
574       request_failed (err);
575       return;
576     }
577
578   status = 0;
579   if ( !(rdrstates[0].event_state & PCSC_STATE_UNKNOWN) )
580     {
581       if ( (rdrstates[0].event_state & PCSC_STATE_PRESENT) )
582         status |= 2;
583       if ( !(rdrstates[0].event_state & PCSC_STATE_MUTE) )
584         status |= 4;
585       /* We indicate a useful card if it is not in use by another
586          application.  This is because we only use exclusive access
587          mode.  */
588       if ( (status & 6) == 6
589            && !(rdrstates[0].event_state & PCSC_STATE_INUSE) )
590         status |= 1;
591     }
592
593   /* First word is identical to the one used by apdu.c. */
594   buf[0] = 0;
595   buf[1] = 0;
596   buf[2] = 0;
597   buf[3] = status;
598   /* The second word is the native PCSC state.  */
599   buf[4] = (rdrstates[0].event_state >> 24);
600   buf[5] = (rdrstates[0].event_state >> 16);
601   buf[6] = (rdrstates[0].event_state >>  8);
602   buf[7] = (rdrstates[0].event_state >>  0);
603   /* The third word is the protocol. */
604   buf[8]  = (pcsc_protocol >> 24);
605   buf[9]  = (pcsc_protocol >> 16);
606   buf[10] = (pcsc_protocol >> 8);
607   buf[11] = (pcsc_protocol);
608
609   request_succeeded (buf, 8);
610 }
611
612
613 /* Handle a reset request.  We expect no arguments.  We may modifiy
614    ARGBUF. */
615 static void
616 handle_reset (unsigned char *argbuf, size_t arglen)
617 {
618   long err;
619   char reader[250];
620   unsigned long nreader, atrlen;
621   unsigned long card_state, card_protocol;
622
623   (void)argbuf;
624   (void)arglen;
625
626   if (!driver_is_open)
627     {
628       fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
629       request_failed (-1);
630       return;
631     }
632
633   if (pcsc_card)
634     {
635       err = pcsc_disconnect (pcsc_card, PCSC_LEAVE_CARD);
636       if (err == 0x80100003)  /* Invalid handle.  (already disconnected) */
637         err = 0;
638       if (err)
639         {
640           fprintf (stderr, PGM": pcsc_disconnect failed: %s (0x%lx)\n",
641                      pcsc_error_string (err), err);
642           request_failed (err);
643           return;
644         }
645       pcsc_card = 0;
646     }
647
648   err = pcsc_connect (pcsc_context,
649                       current_rdrname,
650                       PCSC_SHARE_EXCLUSIVE,
651                       PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
652                       &pcsc_card,
653                       &pcsc_protocol);
654   if (err)
655     {
656       fprintf (stderr, PGM": pcsc_connect failed: %s (0x%lx)\n",
657                pcsc_error_string (err), err);
658       pcsc_card = 0;
659       request_failed (err);
660       return;
661     }
662
663
664   atrlen = 33;
665   nreader = sizeof reader - 1;
666   err = pcsc_status (pcsc_card,
667                      reader, &nreader,
668                      &card_state, &card_protocol,
669                      current_atr, &atrlen);
670   if (err)
671     {
672       fprintf (stderr, PGM": pcsc_status failed: %s (0x%lx)\n",
673                pcsc_error_string (err), err);
674       current_atrlen = 0;
675       request_failed (err);
676       return;
677     }
678
679   request_succeeded (current_atr, current_atrlen);
680 }
681
682
683
684 /* Handle a transmit request.  The argument is expected to be a buffer
685    with the APDU.  We may modifiy ARGBUF. */
686 static void
687 handle_transmit (unsigned char *argbuf, size_t arglen)
688 {
689   long err;
690   struct pcsc_io_request_s send_pci;
691   unsigned long recv_len;
692   unsigned char buffer[1024];
693
694   /* The apdu should at least be one byte. */
695   if (!arglen)
696     bad_request ("TRANSMIT");
697
698   if (!driver_is_open)
699     {
700       fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
701       request_failed (-1);
702       return;
703     }
704   if ((pcsc_protocol & PCSC_PROTOCOL_T1))
705     send_pci.protocol = PCSC_PROTOCOL_T1;
706   else
707     send_pci.protocol = PCSC_PROTOCOL_T0;
708   send_pci.pci_len = sizeof send_pci;
709   recv_len = sizeof (buffer);
710   err = pcsc_transmit (pcsc_card, &send_pci, argbuf, arglen,
711                        NULL, buffer, &recv_len);
712   if (err)
713     {
714       if (verbose)
715         fprintf (stderr, PGM": pcsc_transmit failed: %s (0x%lx)\n",
716                  pcsc_error_string (err), err);
717       request_failed (err);
718       return;
719     }
720   request_succeeded (buffer, recv_len);
721 }
722
723
724
725 static void
726 print_version (int with_help)
727 {
728   fputs (MYVERSION_LINE "\n"
729          "Copyright (C) 2004 Free Software Foundation, Inc.\n"
730          "This program comes with ABSOLUTELY NO WARRANTY.\n"
731          "This is free software, and you are welcome to redistribute it\n"
732          "under certain conditions. See the file COPYING for details.\n",
733          stdout);
734
735   if (with_help)
736     fputs ("\n"
737           "Usage: " PGM " [OPTIONS] API-NUMBER [LIBNAME]\n"
738           "Helper to connect scdaemon to the PC/SC library\n"
739           "\n"
740           "  --verbose   enable extra informational output\n"
741           "  --version   print version of the program and exit\n"
742           "  --help      display this help and exit\n"
743           BUGREPORT_LINE, stdout );
744
745   exit (0);
746 }
747
748
749 int
750 main (int argc, char **argv)
751 {
752   int last_argc = -1;
753   int api_number = 0;
754   int c;
755
756   if (argc)
757     {
758       argc--; argv++;
759     }
760   while (argc && last_argc != argc )
761     {
762       last_argc = argc;
763       if (!strcmp (*argv, "--"))
764         {
765           argc--; argv++;
766           break;
767         }
768       else if (!strcmp (*argv, "--version"))
769         print_version (0);
770       else if (!strcmp (*argv, "--help"))
771         print_version (1);
772       else if (!strcmp (*argv, "--verbose"))
773         {
774           verbose = 1;
775           argc--; argv++;
776         }
777     }
778   if (argc != 1 && argc != 2)
779     {
780       fprintf (stderr, "usage: " PGM " API-NUMBER [LIBNAME]\n");
781       exit (1);
782     }
783
784   api_number = atoi (*argv);
785   argv++; argc--;
786   if (api_number != 1)
787     {
788       fprintf (stderr, PGM ": api-number %d is not valid\n", api_number);
789       exit (1);
790     }
791
792   load_pcsc_driver (argc? *argv : DEFAULT_PCSC_DRIVER);
793
794   while ((c = getc (stdin)) != EOF)
795     {
796       size_t arglen;
797       unsigned char argbuffer[2048];
798
799       arglen = read_32 (stdin);
800       if (arglen >= sizeof argbuffer - 1)
801         {
802           fprintf (stderr, PGM ": request too long\n");
803           exit (1);
804         }
805       if (arglen && fread (argbuffer, arglen, 1, stdin) != 1)
806         {
807           fprintf (stderr, PGM ": error reading request: %s\n",
808                    strerror (errno));
809           exit (1);
810         }
811       argbuffer[arglen] = 0;
812       switch (c)
813         {
814         case 1:
815           handle_open (argbuffer, arglen);
816           break;
817
818         case 2:
819           handle_close (argbuffer, arglen);
820           exit (0);
821           break;
822
823         case 3:
824           handle_transmit (argbuffer, arglen);
825           break;
826
827         case 4:
828           handle_status (argbuffer, arglen);
829           break;
830
831         case 5:
832           handle_reset (argbuffer, arglen);
833           break;
834
835         default:
836           fprintf (stderr, PGM ": invalid request 0x%02X\n", c);
837           exit (1);
838         }
839     }
840   return 0;
841 }
842
843
844
845 /*
846 Local Variables:
847 compile-command: "gcc -Wall -g -o pcsc-wrapper pcsc-wrapper.c -ldl"
848 End:
849 */