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