scd: change default value of pinpad maxlen.
[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 long (* pcsc_control) (unsigned long card,
182                        unsigned long control_code,
183                        const void *send_buffer,
184                        unsigned long send_len,
185                        void *recv_buffer,
186                        unsigned long recv_len,
187                        unsigned long *bytes_returned);
188
189
190
191 static void
192 bad_request (const char *type)
193 {
194   fprintf (stderr, PGM ": bad '%s' request\n", type);
195   exit (1);
196 }
197
198 static void
199 request_failed (int err)
200 {
201   if (!err)
202     err = -1;
203
204   putchar (0x81); /* Simple error/success response. */
205
206   putchar (0);
207   putchar (0);
208   putchar (0);
209   putchar (4);
210
211   putchar ((err >> 24) & 0xff);
212   putchar ((err >> 16) & 0xff);
213   putchar ((err >>  8) & 0xff);
214   putchar ((err      ) & 0xff);
215
216   fflush (stdout);
217 }
218
219
220 static void
221 request_succeeded (const void *buffer, size_t buflen)
222 {
223   size_t len;
224
225   putchar (0x81); /* Simple error/success response. */
226
227   len = 4 + buflen;
228   putchar ((len >> 24) & 0xff);
229   putchar ((len >> 16) & 0xff);
230   putchar ((len >>  8) & 0xff);
231   putchar ((len      ) & 0xff);
232
233   /* Error code. */
234   putchar (0);
235   putchar (0);
236   putchar (0);
237   putchar (0);
238
239   /* Optional reponse string. */
240   if (buffer)
241     fwrite (buffer, buflen, 1, stdout);
242
243   fflush (stdout);
244 }
245
246
247
248 static unsigned long
249 read_32 (FILE *fp)
250 {
251   int c1, c2, c3, c4;
252
253   c1 = getc (fp);
254   c2 = getc (fp);
255   c3 = getc (fp);
256   c4 = getc (fp);
257   if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF)
258     {
259       fprintf (stderr, PGM ": premature EOF while parsing request\n");
260       exit (1);
261     }
262   return (c1 << 24) | (c2 << 16) | (c3 << 8) | c4;
263 }
264
265
266
267 static const char *
268 pcsc_error_string (long err)
269 {
270   const char *s;
271
272   if (!err)
273     return "okay";
274   if ((err & 0x80100000) != 0x80100000)
275     return "invalid PC/SC error code";
276   err &= 0xffff;
277   switch (err)
278     {
279     case 0x0002: s = "cancelled"; break;
280     case 0x000e: s = "can't dispose"; break;
281     case 0x0008: s = "insufficient buffer"; break;
282     case 0x0015: s = "invalid ATR"; break;
283     case 0x0003: s = "invalid handle"; break;
284     case 0x0004: s = "invalid parameter"; break;
285     case 0x0005: s = "invalid target"; break;
286     case 0x0011: s = "invalid value"; break;
287     case 0x0006: s = "no memory"; break;
288     case 0x0013: s = "comm error"; break;
289     case 0x0001: s = "internal error"; break;
290     case 0x0014: s = "unknown error"; break;
291     case 0x0007: s = "waited too long"; break;
292     case 0x0009: s = "unknown reader"; break;
293     case 0x000a: s = "timeout"; break;
294     case 0x000b: s = "sharing violation"; break;
295     case 0x000c: s = "no smartcard"; break;
296     case 0x000d: s = "unknown card"; break;
297     case 0x000f: s = "proto mismatch"; break;
298     case 0x0010: s = "not ready"; break;
299     case 0x0012: s = "system cancelled"; break;
300     case 0x0016: s = "not transacted"; break;
301     case 0x0017: s = "reader unavailable"; break;
302     case 0x0065: s = "unsupported card"; break;
303     case 0x0066: s = "unresponsive card"; break;
304     case 0x0067: s = "unpowered card"; break;
305     case 0x0068: s = "reset card"; break;
306     case 0x0069: s = "removed card"; break;
307     case 0x006a: s = "inserted card"; break;
308     case 0x001f: s = "unsupported feature"; break;
309     case 0x0019: s = "PCI too small"; break;
310     case 0x001a: s = "reader unsupported"; break;
311     case 0x001b: s = "duplicate reader"; break;
312     case 0x001c: s = "card unsupported"; break;
313     case 0x001d: s = "no service"; break;
314     case 0x001e: s = "service stopped"; break;
315     default:     s = "unknown PC/SC error code"; break;
316     }
317   return s;
318 }
319
320 static void
321 load_pcsc_driver (const char *libname)
322 {
323   void *handle;
324
325   handle = dlopen (libname, RTLD_LAZY);
326   if (!handle)
327     {
328       fprintf (stderr, PGM ": failed to open driver '%s': %s",
329                libname, dlerror ());
330       exit (1);
331     }
332
333   pcsc_establish_context = dlsym (handle, "SCardEstablishContext");
334   pcsc_release_context   = dlsym (handle, "SCardReleaseContext");
335   pcsc_list_readers      = dlsym (handle, "SCardListReaders");
336   pcsc_get_status_change = dlsym (handle, "SCardGetStatusChange");
337   pcsc_connect           = dlsym (handle, "SCardConnect");
338   pcsc_reconnect         = dlsym (handle, "SCardReconnect");
339   pcsc_disconnect        = dlsym (handle, "SCardDisconnect");
340   pcsc_status            = dlsym (handle, "SCardStatus");
341   pcsc_begin_transaction = dlsym (handle, "SCardBeginTransaction");
342   pcsc_end_transaction   = dlsym (handle, "SCardEndTransaction");
343   pcsc_transmit          = dlsym (handle, "SCardTransmit");
344   pcsc_set_timeout       = dlsym (handle, "SCardSetTimeout");
345   pcsc_control           = dlsym (handle, "SCardControl");
346
347   if (!pcsc_establish_context
348       || !pcsc_release_context
349       || !pcsc_list_readers
350       || !pcsc_get_status_change
351       || !pcsc_connect
352       || !pcsc_reconnect
353       || !pcsc_disconnect
354       || !pcsc_status
355       || !pcsc_begin_transaction
356       || !pcsc_end_transaction
357       || !pcsc_transmit
358       || !pcsc_control
359       /* || !pcsc_set_timeout */)
360     {
361       /* Note that set_timeout is currently not used and also not
362          available under Windows. */
363       fprintf (stderr,
364                "apdu_open_reader: invalid PC/SC driver "
365                "(%d%d%d%d%d%d%d%d%d%d%d%d%d)\n",
366                !!pcsc_establish_context,
367                !!pcsc_release_context,
368                !!pcsc_list_readers,
369                !!pcsc_get_status_change,
370                !!pcsc_connect,
371                !!pcsc_reconnect,
372                !!pcsc_disconnect,
373                !!pcsc_status,
374                !!pcsc_begin_transaction,
375                !!pcsc_end_transaction,
376                !!pcsc_transmit,
377                !!pcsc_set_timeout,
378                !!pcsc_control );
379       dlclose (handle);
380       exit (1);
381     }
382 }
383
384
385
386
387 /* Handle a open request.  The argument is expected to be a string
388    with the port identification.  ARGBUF is always guaranteed to be
389    terminted by a 0 which is not counted in ARGLEN.  We may modifiy
390    ARGBUF. */
391 static void
392 handle_open (unsigned char *argbuf, size_t arglen)
393 {
394   long err;
395   const char * portstr;
396   char *list = NULL;
397   unsigned long nreader, atrlen;
398   char *p;
399   unsigned long card_state, card_protocol;
400   unsigned char atr[33];
401
402   /* Make sure there is only the port string */
403   if (arglen != strlen ((char*)argbuf))
404     bad_request ("OPEN");
405   portstr = (char*)argbuf;
406
407   if (driver_is_open)
408     {
409       fprintf (stderr, PGM ": PC/SC has already been opened\n");
410       request_failed (-1);
411       return;
412     }
413
414   err = pcsc_establish_context (PCSC_SCOPE_SYSTEM, NULL, NULL, &pcsc_context);
415   if (err)
416     {
417       fprintf (stderr, PGM": pcsc_establish_context failed: %s (0x%lx)\n",
418                pcsc_error_string (err), err);
419       request_failed (err);
420       return;
421     }
422
423   err = pcsc_list_readers (pcsc_context, NULL, NULL, &nreader);
424   if (!err)
425     {
426       list = malloc (nreader+1); /* Better add 1 for safety reasons. */
427       if (!list)
428         {
429           fprintf (stderr, PGM": error allocating memory for reader list\n");
430           exit (1);
431         }
432       err = pcsc_list_readers (pcsc_context, NULL, list, &nreader);
433     }
434   if (err)
435     {
436       fprintf (stderr, PGM": pcsc_list_readers failed: %s (0x%lx)\n",
437                pcsc_error_string (err), err);
438       pcsc_release_context (pcsc_context);
439       free (list);
440       request_failed (err);
441       return;
442     }
443
444   p = list;
445   while (nreader)
446     {
447       if (!*p && !p[1])
448         break;
449       fprintf (stderr, PGM": detected reader '%s'\n", p);
450       if (nreader < (strlen (p)+1))
451         {
452           fprintf (stderr, PGM": invalid response from pcsc_list_readers\n");
453           break;
454         }
455       nreader -= strlen (p)+1;
456       p += strlen (p) + 1;
457     }
458
459   current_rdrname = malloc (strlen (portstr && *portstr? portstr:list)+1);
460   if (!current_rdrname)
461     {
462       fprintf (stderr, PGM": error allocating memory for reader name\n");
463       exit (1);
464     }
465   strcpy (current_rdrname, portstr && *portstr? portstr:list);
466   free (list);
467
468   err = pcsc_connect (pcsc_context,
469                       current_rdrname,
470                       PCSC_SHARE_EXCLUSIVE,
471                       PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
472                       &pcsc_card,
473                       &pcsc_protocol);
474   if (err == 0x8010000c) /* No smartcard.  */
475     {
476       pcsc_card = 0;
477     }
478   else if (err)
479     {
480       fprintf (stderr, PGM": pcsc_connect failed: %s (0x%lx)\n",
481                pcsc_error_string (err), err);
482       pcsc_release_context (pcsc_context);
483       free (current_rdrname);
484       current_rdrname = NULL;
485       pcsc_card = 0;
486       pcsc_protocol = 0;
487       request_failed (err);
488       return;
489     }
490
491   current_atrlen = 0;
492   if (!err)
493     {
494       char reader[250];
495       unsigned long readerlen;
496
497       atrlen = 33;
498       readerlen = sizeof reader -1;
499       err = pcsc_status (pcsc_card,
500                          reader, &readerlen,
501                          &card_state, &card_protocol,
502                          atr, &atrlen);
503       if (err)
504         fprintf (stderr, PGM": pcsc_status failed: %s (0x%lx)\n",
505                  pcsc_error_string (err), err);
506       else
507         {
508           if (atrlen >= sizeof atr || atrlen >= sizeof current_atr)
509             {
510               fprintf (stderr, PGM": ATR returned by pcsc_status"
511                        " is too large\n");
512               exit (4);
513             }
514           memcpy (current_atr, atr, atrlen);
515           current_atrlen = atrlen;
516         }
517     }
518
519   driver_is_open = 1;
520   request_succeeded (current_atr, current_atrlen);
521 }
522
523
524
525 /* Handle a close request.  We expect no arguments.  We may modifiy
526    ARGBUF. */
527 static void
528 handle_close (unsigned char *argbuf, size_t arglen)
529 {
530   (void)argbuf;
531   (void)arglen;
532
533   if (!driver_is_open)
534     {
535       fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
536       request_failed (-1);
537       return;
538     }
539
540   free (current_rdrname);
541   current_rdrname = NULL;
542   pcsc_release_context (pcsc_context);
543   pcsc_card = 0;
544   pcsc_protocol = 0;
545
546   request_succeeded (NULL, 0);
547 }
548
549
550
551 /* Handle a status request.  We expect no arguments.  We may modifiy
552    ARGBUF. */
553 static void
554 handle_status (unsigned char *argbuf, size_t arglen)
555 {
556   long err;
557   struct pcsc_readerstate_s rdrstates[1];
558   int status;
559   unsigned char buf[20];
560
561   (void)argbuf;
562   (void)arglen;
563
564   if (!driver_is_open)
565     {
566       fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
567       request_failed (-1);
568       return;
569     }
570
571   memset (rdrstates, 0, sizeof *rdrstates);
572   rdrstates[0].reader = current_rdrname;
573   rdrstates[0].current_state = PCSC_STATE_UNAWARE;
574   err = pcsc_get_status_change (pcsc_context,
575                                 0,
576                                 rdrstates, 1);
577   if (err == 0x8010000a) /* Timeout.  */
578     err = 0;
579   if (err)
580     {
581       fprintf (stderr, PGM": pcsc_get_status_change failed: %s (0x%lx)\n",
582                pcsc_error_string (err), err);
583       request_failed (err);
584       return;
585     }
586
587   status = 0;
588   if ( !(rdrstates[0].event_state & PCSC_STATE_UNKNOWN) )
589     {
590       if ( (rdrstates[0].event_state & PCSC_STATE_PRESENT) )
591         status |= 2;
592       if ( !(rdrstates[0].event_state & PCSC_STATE_MUTE) )
593         status |= 4;
594       /* We indicate a useful card if it is not in use by another
595          application.  This is because we only use exclusive access
596          mode.  */
597       if ( (status & 6) == 6
598            && !(rdrstates[0].event_state & PCSC_STATE_INUSE) )
599         status |= 1;
600     }
601
602   /* First word is identical to the one used by apdu.c. */
603   buf[0] = 0;
604   buf[1] = 0;
605   buf[2] = 0;
606   buf[3] = status;
607   /* The second word is the native PCSC state.  */
608   buf[4] = (rdrstates[0].event_state >> 24);
609   buf[5] = (rdrstates[0].event_state >> 16);
610   buf[6] = (rdrstates[0].event_state >>  8);
611   buf[7] = (rdrstates[0].event_state >>  0);
612   /* The third word is the protocol. */
613   buf[8]  = (pcsc_protocol >> 24);
614   buf[9]  = (pcsc_protocol >> 16);
615   buf[10] = (pcsc_protocol >> 8);
616   buf[11] = (pcsc_protocol);
617
618   request_succeeded (buf, 8);
619 }
620
621
622 /* Handle a reset request.  We expect no arguments.  We may modifiy
623    ARGBUF. */
624 static void
625 handle_reset (unsigned char *argbuf, size_t arglen)
626 {
627   long err;
628   char reader[250];
629   unsigned long nreader, atrlen;
630   unsigned long card_state, card_protocol;
631
632   (void)argbuf;
633   (void)arglen;
634
635   if (!driver_is_open)
636     {
637       fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
638       request_failed (-1);
639       return;
640     }
641
642   if (pcsc_card)
643     {
644       err = pcsc_disconnect (pcsc_card, PCSC_LEAVE_CARD);
645       if (err == 0x80100003)  /* Invalid handle.  (already disconnected) */
646         err = 0;
647       if (err)
648         {
649           fprintf (stderr, PGM": pcsc_disconnect failed: %s (0x%lx)\n",
650                      pcsc_error_string (err), err);
651           request_failed (err);
652           return;
653         }
654       pcsc_card = 0;
655     }
656
657   err = pcsc_connect (pcsc_context,
658                       current_rdrname,
659                       PCSC_SHARE_EXCLUSIVE,
660                       PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
661                       &pcsc_card,
662                       &pcsc_protocol);
663   if (err)
664     {
665       fprintf (stderr, PGM": pcsc_connect failed: %s (0x%lx)\n",
666                pcsc_error_string (err), err);
667       pcsc_card = 0;
668       request_failed (err);
669       return;
670     }
671
672
673   atrlen = 33;
674   nreader = sizeof reader - 1;
675   err = pcsc_status (pcsc_card,
676                      reader, &nreader,
677                      &card_state, &card_protocol,
678                      current_atr, &atrlen);
679   if (err)
680     {
681       fprintf (stderr, PGM": pcsc_status failed: %s (0x%lx)\n",
682                pcsc_error_string (err), err);
683       current_atrlen = 0;
684       request_failed (err);
685       return;
686     }
687
688   request_succeeded (current_atr, current_atrlen);
689 }
690
691
692
693 /* Handle a transmit request.  The argument is expected to be a buffer
694    with the APDU.  We may modifiy ARGBUF. */
695 static void
696 handle_transmit (unsigned char *argbuf, size_t arglen)
697 {
698   long err;
699   struct pcsc_io_request_s send_pci;
700   unsigned long recv_len;
701   unsigned char buffer[1024];
702
703   /* The apdu should at least be one byte. */
704   if (!arglen)
705     bad_request ("TRANSMIT");
706
707   if (!driver_is_open)
708     {
709       fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
710       request_failed (-1);
711       return;
712     }
713   if ((pcsc_protocol & PCSC_PROTOCOL_T1))
714     send_pci.protocol = PCSC_PROTOCOL_T1;
715   else
716     send_pci.protocol = PCSC_PROTOCOL_T0;
717   send_pci.pci_len = sizeof send_pci;
718   recv_len = sizeof (buffer);
719   err = pcsc_transmit (pcsc_card, &send_pci, argbuf, arglen,
720                        NULL, buffer, &recv_len);
721   if (err)
722     {
723       if (verbose)
724         fprintf (stderr, PGM": pcsc_transmit failed: %s (0x%lx)\n",
725                  pcsc_error_string (err), err);
726       request_failed (err);
727       return;
728     }
729   request_succeeded (buffer, recv_len);
730 }
731
732
733 /* Handle a control request.  The argument is expected to be a buffer
734    which contains CONTROL_CODE (4-byte) and INPUT_BYTES.
735  */
736 static void
737 handle_control (unsigned char *argbuf, size_t arglen)
738 {
739   long err;
740   unsigned long ioctl_code;
741   unsigned long recv_len = 1024;
742   unsigned char buffer[1024];
743
744   if (arglen < 4)
745     bad_request ("CONTROL");
746
747   ioctl_code = (argbuf[0] << 24) | (argbuf[1] << 16) | (argbuf[2] << 8) | argbuf[3];
748   argbuf += 4;
749   arglen -= 4;
750
751   recv_len = sizeof (buffer);
752   err = pcsc_control (pcsc_card, ioctl_code, argbuf, arglen,
753                       buffer, recv_len, &recv_len);
754   if (err)
755     {
756       if (verbose)
757         fprintf (stderr, PGM": pcsc_control failed: %s (0x%lx)\n",
758                  pcsc_error_string (err), err);
759       request_failed (err);
760       return;
761     }
762   request_succeeded (buffer, recv_len);
763 }
764
765
766 static void
767 print_version (int with_help)
768 {
769   fputs (MYVERSION_LINE "\n"
770          "Copyright (C) 2004 Free Software Foundation, Inc.\n"
771          "This program comes with ABSOLUTELY NO WARRANTY.\n"
772          "This is free software, and you are welcome to redistribute it\n"
773          "under certain conditions. See the file COPYING for details.\n",
774          stdout);
775
776   if (with_help)
777     fputs ("\n"
778           "Usage: " PGM " [OPTIONS] API-NUMBER [LIBNAME]\n"
779           "Helper to connect scdaemon to the PC/SC library\n"
780           "\n"
781           "  --verbose   enable extra informational output\n"
782           "  --version   print version of the program and exit\n"
783           "  --help      display this help and exit\n"
784           BUGREPORT_LINE, stdout );
785
786   exit (0);
787 }
788
789
790 int
791 main (int argc, char **argv)
792 {
793   int last_argc = -1;
794   int api_number = 0;
795   int c;
796
797   if (argc)
798     {
799       argc--; argv++;
800     }
801   while (argc && last_argc != argc )
802     {
803       last_argc = argc;
804       if (!strcmp (*argv, "--"))
805         {
806           argc--; argv++;
807           break;
808         }
809       else if (!strcmp (*argv, "--version"))
810         print_version (0);
811       else if (!strcmp (*argv, "--help"))
812         print_version (1);
813       else if (!strcmp (*argv, "--verbose"))
814         {
815           verbose = 1;
816           argc--; argv++;
817         }
818     }
819   if (argc != 1 && argc != 2)
820     {
821       fprintf (stderr, "usage: " PGM " API-NUMBER [LIBNAME]\n");
822       exit (1);
823     }
824
825   api_number = atoi (*argv);
826   argv++; argc--;
827   if (api_number != 1)
828     {
829       fprintf (stderr, PGM ": api-number %d is not valid\n", api_number);
830       exit (1);
831     }
832
833   load_pcsc_driver (argc? *argv : DEFAULT_PCSC_DRIVER);
834
835   while ((c = getc (stdin)) != EOF)
836     {
837       size_t arglen;
838       unsigned char argbuffer[2048];
839
840       arglen = read_32 (stdin);
841       if (arglen >= sizeof argbuffer - 1)
842         {
843           fprintf (stderr, PGM ": request too long\n");
844           exit (1);
845         }
846       if (arglen && fread (argbuffer, arglen, 1, stdin) != 1)
847         {
848           fprintf (stderr, PGM ": error reading request: %s\n",
849                    strerror (errno));
850           exit (1);
851         }
852       argbuffer[arglen] = 0;
853       switch (c)
854         {
855         case 1:
856           handle_open (argbuffer, arglen);
857           break;
858
859         case 2:
860           handle_close (argbuffer, arglen);
861           exit (0);
862           break;
863
864         case 3:
865           handle_transmit (argbuffer, arglen);
866           break;
867
868         case 4:
869           handle_status (argbuffer, arglen);
870           break;
871
872         case 5:
873           handle_reset (argbuffer, arglen);
874           break;
875
876         case 6:
877           handle_control (argbuffer, arglen);
878           break;
879
880         default:
881           fprintf (stderr, PGM ": invalid request 0x%02X\n", c);
882           exit (1);
883         }
884     }
885   return 0;
886 }
887
888
889
890 /*
891 Local Variables:
892 compile-command: "gcc -Wall -g -o pcsc-wrapper pcsc-wrapper.c -ldl"
893 End:
894 */