scd: PC/SC cleanup.
[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         status |= 2;
606       if ( !(rdrstates[0].event_state & PCSC_STATE_MUTE) )
607         status |= 4;
608       /* We indicate a useful card if it is not in use by another
609          application.  This is because we only use exclusive access
610          mode.  */
611       if ( (status & 6) == 6
612            && !(rdrstates[0].event_state & PCSC_STATE_INUSE) )
613         status |= 1;
614     }
615
616   /* First word is identical to the one used by apdu.c. */
617   buf[0] = 0;
618   buf[1] = 0;
619   buf[2] = 0;
620   buf[3] = status;
621   /* The second word is the native PCSC state.  */
622   buf[4] = (rdrstates[0].event_state >> 24);
623   buf[5] = (rdrstates[0].event_state >> 16);
624   buf[6] = (rdrstates[0].event_state >>  8);
625   buf[7] = (rdrstates[0].event_state >>  0);
626   /* The third word is the protocol. */
627   buf[8]  = (pcsc_protocol >> 24);
628   buf[9]  = (pcsc_protocol >> 16);
629   buf[10] = (pcsc_protocol >> 8);
630   buf[11] = (pcsc_protocol);
631
632   request_succeeded (buf, 8);
633 }
634
635
636 /* Handle a reset request.  We expect no arguments.  We may modifiy
637    ARGBUF. */
638 static void
639 handle_reset (unsigned char *argbuf, size_t arglen)
640 {
641   long err;
642   char reader[250];
643   pcsc_dword_t nreader, atrlen;
644   pcsc_dword_t card_state, card_protocol;
645
646   (void)argbuf;
647   (void)arglen;
648
649   if (!driver_is_open)
650     {
651       fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
652       request_failed (-1);
653       return;
654     }
655
656   if (pcsc_card)
657     {
658       err = pcsc_disconnect (pcsc_card, PCSC_LEAVE_CARD);
659       if (err == 0x80100003)  /* Invalid handle.  (already disconnected) */
660         err = 0;
661       if (err)
662         {
663           fprintf (stderr, PGM": pcsc_disconnect failed: %s (0x%lx)\n",
664                      pcsc_error_string (err), err);
665           request_failed (err);
666           return;
667         }
668       pcsc_card = 0;
669     }
670
671   err = pcsc_connect (pcsc_context,
672                       current_rdrname,
673                       PCSC_SHARE_EXCLUSIVE,
674                       PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
675                       &pcsc_card,
676                       &pcsc_protocol);
677   if (err)
678     {
679       fprintf (stderr, PGM": pcsc_connect failed: %s (0x%lx)\n",
680                pcsc_error_string (err), err);
681       pcsc_card = 0;
682       request_failed (err);
683       return;
684     }
685
686
687   atrlen = 33;
688   nreader = sizeof reader - 1;
689   err = pcsc_status (pcsc_card,
690                      reader, &nreader,
691                      &card_state, &card_protocol,
692                      current_atr, &atrlen);
693   if (err)
694     {
695       fprintf (stderr, PGM": pcsc_status failed: %s (0x%lx)\n",
696                pcsc_error_string (err), err);
697       current_atrlen = 0;
698       request_failed (err);
699       return;
700     }
701
702   request_succeeded (current_atr, current_atrlen);
703 }
704
705
706
707 /* Handle a transmit request.  The argument is expected to be a buffer
708    with the APDU.  We may modifiy ARGBUF. */
709 static void
710 handle_transmit (unsigned char *argbuf, size_t arglen)
711 {
712   long err;
713   struct pcsc_io_request_s send_pci;
714   pcsc_dword_t recv_len;
715   unsigned char buffer[1024];
716
717   /* The apdu should at least be one byte. */
718   if (!arglen)
719     bad_request ("TRANSMIT");
720
721   if (!driver_is_open)
722     {
723       fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
724       request_failed (-1);
725       return;
726     }
727   if ((pcsc_protocol & PCSC_PROTOCOL_T1))
728     send_pci.protocol = PCSC_PROTOCOL_T1;
729   else
730     send_pci.protocol = PCSC_PROTOCOL_T0;
731   send_pci.pci_len = sizeof send_pci;
732   recv_len = sizeof (buffer);
733   err = pcsc_transmit (pcsc_card, &send_pci, argbuf, arglen,
734                        NULL, buffer, &recv_len);
735   if (err)
736     {
737       if (verbose)
738         fprintf (stderr, PGM": pcsc_transmit failed: %s (0x%lx)\n",
739                  pcsc_error_string (err), err);
740       request_failed (err);
741       return;
742     }
743   request_succeeded (buffer, recv_len);
744 }
745
746
747 /* Handle a control request.  The argument is expected to be a buffer
748    which contains CONTROL_CODE (4-byte) and INPUT_BYTES.
749  */
750 static void
751 handle_control (unsigned char *argbuf, size_t arglen)
752 {
753   long err;
754   pcsc_dword_t ioctl_code;
755   pcsc_dword_t recv_len = 1024;
756   unsigned char buffer[1024];
757
758   if (arglen < 4)
759     bad_request ("CONTROL");
760
761   ioctl_code = (argbuf[0] << 24) | (argbuf[1] << 16) | (argbuf[2] << 8) | argbuf[3];
762   argbuf += 4;
763   arglen -= 4;
764
765   recv_len = sizeof (buffer);
766   err = pcsc_control (pcsc_card, ioctl_code, argbuf, arglen,
767                       buffer, recv_len, &recv_len);
768   if (err)
769     {
770       if (verbose)
771         fprintf (stderr, PGM": pcsc_control failed: %s (0x%lx)\n",
772                  pcsc_error_string (err), err);
773       request_failed (err);
774       return;
775     }
776   request_succeeded (buffer, recv_len);
777 }
778
779
780 static void
781 print_version (int with_help)
782 {
783   fputs (MYVERSION_LINE "\n"
784          "Copyright (C) 2004 Free Software Foundation, Inc.\n"
785          "This program comes with ABSOLUTELY NO WARRANTY.\n"
786          "This is free software, and you are welcome to redistribute it\n"
787          "under certain conditions. See the file COPYING for details.\n",
788          stdout);
789
790   if (with_help)
791     fputs ("\n"
792           "Usage: " PGM " [OPTIONS] API-NUMBER [LIBNAME]\n"
793           "Helper to connect scdaemon to the PC/SC library\n"
794           "\n"
795           "  --verbose   enable extra informational output\n"
796           "  --version   print version of the program and exit\n"
797           "  --help      display this help and exit\n"
798           BUGREPORT_LINE, stdout );
799
800   exit (0);
801 }
802
803
804 int
805 main (int argc, char **argv)
806 {
807   int last_argc = -1;
808   int api_number = 0;
809   int c;
810
811   if (argc)
812     {
813       argc--; argv++;
814     }
815   while (argc && last_argc != argc )
816     {
817       last_argc = argc;
818       if (!strcmp (*argv, "--"))
819         {
820           argc--; argv++;
821           break;
822         }
823       else if (!strcmp (*argv, "--version"))
824         print_version (0);
825       else if (!strcmp (*argv, "--help"))
826         print_version (1);
827       else if (!strcmp (*argv, "--verbose"))
828         {
829           verbose = 1;
830           argc--; argv++;
831         }
832     }
833   if (argc != 1 && argc != 2)
834     {
835       fprintf (stderr, "usage: " PGM " API-NUMBER [LIBNAME]\n");
836       exit (1);
837     }
838
839   api_number = atoi (*argv);
840   argv++; argc--;
841   if (api_number != 1)
842     {
843       fprintf (stderr, PGM ": api-number %d is not valid\n", api_number);
844       exit (1);
845     }
846
847   load_pcsc_driver (argc? *argv : DEFAULT_PCSC_DRIVER);
848
849   while ((c = getc (stdin)) != EOF)
850     {
851       size_t arglen;
852       unsigned char argbuffer[2048];
853
854       arglen = read_32 (stdin);
855       if (arglen >= sizeof argbuffer - 1)
856         {
857           fprintf (stderr, PGM ": request too long\n");
858           exit (1);
859         }
860       if (arglen && fread (argbuffer, arglen, 1, stdin) != 1)
861         {
862           fprintf (stderr, PGM ": error reading request: %s\n",
863                    strerror (errno));
864           exit (1);
865         }
866       argbuffer[arglen] = 0;
867       switch (c)
868         {
869         case 1:
870           handle_open (argbuffer, arglen);
871           break;
872
873         case 2:
874           handle_close (argbuffer, arglen);
875           exit (0);
876           break;
877
878         case 3:
879           handle_transmit (argbuffer, arglen);
880           break;
881
882         case 4:
883           handle_status (argbuffer, arglen);
884           break;
885
886         case 5:
887           handle_reset (argbuffer, arglen);
888           break;
889
890         case 6:
891           handle_control (argbuffer, arglen);
892           break;
893
894         default:
895           fprintf (stderr, PGM ": invalid request 0x%02X\n", c);
896           exit (1);
897         }
898     }
899   return 0;
900 }
901
902
903
904 /*
905 Local Variables:
906 compile-command: "gcc -Wall -g -o pcsc-wrapper pcsc-wrapper.c -ldl"
907 End:
908 */