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