(confucius_mktmpdir): Changed to use mkdtmp(3).
[gnupg.git] / scd / pcsc-wrapper.c
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 */