scd: PC/SC reader selection by partial string match.
[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 unsigned 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 ((unsigned long)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   char *rdrname = NULL;
412   pcsc_dword_t nreader, atrlen;
413   char *p;
414   pcsc_dword_t card_state, card_protocol;
415   unsigned char atr[33];
416
417   /* Make sure there is only the port string */
418   if (arglen != strlen ((char*)argbuf))
419     bad_request ("OPEN");
420   if (arglen == 0)
421     portstr = NULL;
422   else
423     portstr = (char*)argbuf;
424
425   if (driver_is_open)
426     {
427       fprintf (stderr, PGM ": PC/SC has already been opened\n");
428       request_failed (-1);
429       return;
430     }
431
432   err = pcsc_establish_context (PCSC_SCOPE_SYSTEM, NULL, NULL, &pcsc_context);
433   if (err)
434     {
435       fprintf (stderr, PGM": pcsc_establish_context failed: %s (0x%lx)\n",
436                pcsc_error_string (err), err);
437       request_failed (err);
438       return;
439     }
440
441   err = pcsc_list_readers (pcsc_context, NULL, NULL, &nreader);
442   if (!err)
443     {
444       list = malloc (nreader+1); /* Better add 1 for safety reasons. */
445       if (!list)
446         {
447           fprintf (stderr, PGM": error allocating memory for reader list\n");
448           exit (1);
449         }
450       err = pcsc_list_readers (pcsc_context, NULL, list, &nreader);
451     }
452   if (err)
453     {
454       fprintf (stderr, PGM": pcsc_list_readers failed: %s (0x%lx)\n",
455                pcsc_error_string (err), err);
456       pcsc_release_context (pcsc_context);
457       free (list);
458       request_failed (err);
459       return;
460     }
461
462   p = list;
463   while (nreader)
464     {
465       if (!*p && !p[1])
466         break;
467       fprintf (stderr, PGM": detected reader `%s'\n", p);
468       if (nreader < (strlen (p)+1))
469         {
470           fprintf (stderr, PGM": invalid response from pcsc_list_readers\n");
471           break;
472         }
473       if (!rdrname && portstr && !strncmp (p, portstr, strlen (portstr)))
474         rdrname = p;
475       nreader -= strlen (p)+1;
476       p += strlen (p) + 1;
477     }
478
479   if (!rdrname)
480     rdrname = list;
481
482   current_rdrname = strdup (rdrname);
483   if (!current_rdrname)
484     {
485       fprintf (stderr, PGM": error allocating memory for reader name\n");
486       exit (1);
487     }
488   free (list);
489
490   err = pcsc_connect (pcsc_context,
491                       current_rdrname,
492                       PCSC_SHARE_EXCLUSIVE,
493                       PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
494                       &pcsc_card,
495                       &pcsc_protocol);
496   if (err == 0x8010000c) /* No smartcard.  */
497     {
498       pcsc_card = 0;
499     }
500   else if (err)
501     {
502       fprintf (stderr, PGM": pcsc_connect failed: %s (0x%lx)\n",
503                pcsc_error_string (err), err);
504       pcsc_release_context (pcsc_context);
505       free (current_rdrname);
506       current_rdrname = NULL;
507       pcsc_card = 0;
508       pcsc_protocol = 0;
509       request_failed (err);
510       return;
511     }
512
513   current_atrlen = 0;
514   if (!err)
515     {
516       char reader[250];
517       pcsc_dword_t readerlen;
518
519       atrlen = 33;
520       readerlen = sizeof reader -1;
521       err = pcsc_status (pcsc_card,
522                          reader, &readerlen,
523                          &card_state, &card_protocol,
524                          atr, &atrlen);
525       if (err)
526         fprintf (stderr, PGM": pcsc_status failed: %s (0x%lx)\n",
527                  pcsc_error_string (err), err);
528       else
529         {
530           if (atrlen >= sizeof atr || atrlen >= sizeof current_atr)
531             {
532               fprintf (stderr, PGM": ATR returned by pcsc_status"
533                        " is too large\n");
534               exit (4);
535             }
536           memcpy (current_atr, atr, atrlen);
537           current_atrlen = atrlen;
538         }
539     }
540
541   driver_is_open = 1;
542   request_succeeded (current_atr, current_atrlen);
543 }
544
545
546
547 /* Handle a close request.  We expect no arguments.  We may modifiy
548    ARGBUF. */
549 static void
550 handle_close (unsigned char *argbuf, size_t arglen)
551 {
552   (void)argbuf;
553   (void)arglen;
554
555   if (!driver_is_open)
556     {
557       fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
558       request_failed (-1);
559       return;
560     }
561
562   free (current_rdrname);
563   current_rdrname = NULL;
564   pcsc_release_context (pcsc_context);
565   pcsc_card = 0;
566   pcsc_protocol = 0;
567
568   request_succeeded (NULL, 0);
569 }
570
571
572
573 /* Handle a status request.  We expect no arguments.  We may modifiy
574    ARGBUF. */
575 static void
576 handle_status (unsigned char *argbuf, size_t arglen)
577 {
578   long err;
579   struct pcsc_readerstate_s rdrstates[1];
580   int status;
581   unsigned char buf[20];
582
583   (void)argbuf;
584   (void)arglen;
585
586   if (!driver_is_open)
587     {
588       fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
589       request_failed (-1);
590       return;
591     }
592
593   memset (rdrstates, 0, sizeof *rdrstates);
594   rdrstates[0].reader = current_rdrname;
595   rdrstates[0].current_state = PCSC_STATE_UNAWARE;
596   err = pcsc_get_status_change (pcsc_context,
597                                 0,
598                                 rdrstates, 1);
599   if (err == 0x8010000a) /* Timeout.  */
600     err = 0;
601   if (err)
602     {
603       fprintf (stderr, PGM": pcsc_get_status_change failed: %s (0x%lx)\n",
604                pcsc_error_string (err), err);
605       request_failed (err);
606       return;
607     }
608
609   status = 0;
610   if ( !(rdrstates[0].event_state & PCSC_STATE_UNKNOWN) )
611     {
612       if ( (rdrstates[0].event_state & PCSC_STATE_PRESENT) )
613         {
614           status |= 2;
615           if ( !(rdrstates[0].event_state & PCSC_STATE_MUTE) )
616             status |= 4;
617         }
618       /* We indicate a useful card if it is not in use by another
619          application.  This is because we only use exclusive access
620          mode.  */
621       if ( (status & 6) == 6
622            && !(rdrstates[0].event_state & PCSC_STATE_INUSE) )
623         status |= 1;
624     }
625
626   /* First word is identical to the one used by apdu.c. */
627   buf[0] = 0;
628   buf[1] = 0;
629   buf[2] = 0;
630   buf[3] = status;
631   /* The second word is the native PCSC state.  */
632   buf[4] = (rdrstates[0].event_state >> 24);
633   buf[5] = (rdrstates[0].event_state >> 16);
634   buf[6] = (rdrstates[0].event_state >>  8);
635   buf[7] = (rdrstates[0].event_state >>  0);
636   /* The third word is the protocol. */
637   buf[8]  = (pcsc_protocol >> 24);
638   buf[9]  = (pcsc_protocol >> 16);
639   buf[10] = (pcsc_protocol >> 8);
640   buf[11] = (pcsc_protocol);
641
642   request_succeeded (buf, 8);
643 }
644
645
646 /* Handle a reset request.  We expect no arguments.  We may modifiy
647    ARGBUF. */
648 static void
649 handle_reset (unsigned char *argbuf, size_t arglen)
650 {
651   long err;
652   char reader[250];
653   pcsc_dword_t nreader, atrlen;
654   pcsc_dword_t card_state, card_protocol;
655
656   (void)argbuf;
657   (void)arglen;
658
659   if (!driver_is_open)
660     {
661       fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
662       request_failed (-1);
663       return;
664     }
665
666   if (pcsc_card)
667     {
668       err = pcsc_disconnect (pcsc_card, PCSC_LEAVE_CARD);
669       if (err == 0x80100003)  /* Invalid handle.  (already disconnected) */
670         err = 0;
671       if (err)
672         {
673           fprintf (stderr, PGM": pcsc_disconnect failed: %s (0x%lx)\n",
674                      pcsc_error_string (err), err);
675           request_failed (err);
676           return;
677         }
678       pcsc_card = 0;
679     }
680
681   err = pcsc_connect (pcsc_context,
682                       current_rdrname,
683                       PCSC_SHARE_EXCLUSIVE,
684                       PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
685                       &pcsc_card,
686                       &pcsc_protocol);
687   if (err)
688     {
689       fprintf (stderr, PGM": pcsc_connect failed: %s (0x%lx)\n",
690                pcsc_error_string (err), err);
691       pcsc_card = 0;
692       request_failed (err);
693       return;
694     }
695
696
697   atrlen = 33;
698   nreader = sizeof reader - 1;
699   err = pcsc_status (pcsc_card,
700                      reader, &nreader,
701                      &card_state, &card_protocol,
702                      current_atr, &atrlen);
703   if (err)
704     {
705       fprintf (stderr, PGM": pcsc_status failed: %s (0x%lx)\n",
706                pcsc_error_string (err), err);
707       current_atrlen = 0;
708       request_failed (err);
709       return;
710     }
711
712   request_succeeded (current_atr, current_atrlen);
713 }
714
715
716
717 /* Handle a transmit request.  The argument is expected to be a buffer
718    with the APDU.  We may modifiy ARGBUF. */
719 static void
720 handle_transmit (unsigned char *argbuf, size_t arglen)
721 {
722   long err;
723   struct pcsc_io_request_s send_pci;
724   pcsc_dword_t recv_len;
725   unsigned char buffer[4096];
726
727   /* The apdu should at least be one byte. */
728   if (!arglen)
729     bad_request ("TRANSMIT");
730
731   if (!driver_is_open)
732     {
733       fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
734       request_failed (-1);
735       return;
736     }
737   if ((pcsc_protocol & PCSC_PROTOCOL_T1))
738     send_pci.protocol = PCSC_PROTOCOL_T1;
739   else
740     send_pci.protocol = PCSC_PROTOCOL_T0;
741   send_pci.pci_len = sizeof send_pci;
742   recv_len = sizeof (buffer);
743   err = pcsc_transmit (pcsc_card, &send_pci, argbuf, arglen,
744                        NULL, buffer, &recv_len);
745   if (err)
746     {
747       if (verbose)
748         fprintf (stderr, PGM": pcsc_transmit failed: %s (0x%lx)\n",
749                  pcsc_error_string (err), err);
750       request_failed (err);
751       return;
752     }
753   request_succeeded (buffer, recv_len);
754 }
755
756
757 /* Handle a control request.  The argument is expected to be a buffer
758    which contains CONTROL_CODE (4-byte) and INPUT_BYTES.
759  */
760 static void
761 handle_control (unsigned char *argbuf, size_t arglen)
762 {
763   long err;
764   pcsc_dword_t ioctl_code;
765   pcsc_dword_t recv_len = 1024;
766   unsigned char buffer[1024];
767
768   if (arglen < 4)
769     bad_request ("CONTROL");
770
771   ioctl_code = (((pcsc_dword_t)argbuf[0] << 24)
772                 | (argbuf[1] << 16) | (argbuf[2] << 8) | argbuf[3]);
773   argbuf += 4;
774   arglen -= 4;
775
776   recv_len = sizeof (buffer);
777   err = pcsc_control (pcsc_card, ioctl_code, argbuf, arglen,
778                       buffer, recv_len, &recv_len);
779   if (err)
780     {
781       if (verbose)
782         fprintf (stderr, PGM": pcsc_control failed: %s (0x%lx)\n",
783                  pcsc_error_string (err), err);
784       request_failed (err);
785       return;
786     }
787   request_succeeded (buffer, recv_len);
788 }
789
790
791 static void
792 print_version (int with_help)
793 {
794   fputs (MYVERSION_LINE "\n"
795          "Copyright (C) 2004 Free Software Foundation, Inc.\n"
796          "This program comes with ABSOLUTELY NO WARRANTY.\n"
797          "This is free software, and you are welcome to redistribute it\n"
798          "under certain conditions. See the file COPYING for details.\n",
799          stdout);
800
801   if (with_help)
802     fputs ("\n"
803           "Usage: " PGM " [OPTIONS] API-NUMBER [LIBNAME]\n"
804           "Helper to connect scdaemon to the PC/SC library\n"
805           "\n"
806           "  --verbose   enable extra informational output\n"
807           "  --version   print version of the program and exit\n"
808           "  --help      display this help and exit\n"
809           BUGREPORT_LINE, stdout );
810
811   exit (0);
812 }
813
814
815 int
816 main (int argc, char **argv)
817 {
818   int last_argc = -1;
819   int api_number = 0;
820   int c;
821
822   if (argc)
823     {
824       argc--; argv++;
825     }
826   while (argc && last_argc != argc )
827     {
828       last_argc = argc;
829       if (!strcmp (*argv, "--"))
830         {
831           argc--; argv++;
832           break;
833         }
834       else if (!strcmp (*argv, "--version"))
835         print_version (0);
836       else if (!strcmp (*argv, "--help"))
837         print_version (1);
838       else if (!strcmp (*argv, "--verbose"))
839         {
840           verbose = 1;
841           argc--; argv++;
842         }
843     }
844   if (argc != 1 && argc != 2)
845     {
846       fprintf (stderr, "usage: " PGM " API-NUMBER [LIBNAME]\n");
847       exit (1);
848     }
849
850   api_number = atoi (*argv);
851   argv++; argc--;
852   if (api_number != 1)
853     {
854       fprintf (stderr, PGM ": api-number %d is not valid\n", api_number);
855       exit (1);
856     }
857
858   load_pcsc_driver (argc? *argv : DEFAULT_PCSC_DRIVER);
859
860   while ((c = getc (stdin)) != EOF)
861     {
862       size_t arglen;
863       unsigned char argbuffer[2048];
864
865       arglen = read_32 (stdin);
866       if (arglen >= sizeof argbuffer - 1)
867         {
868           fprintf (stderr, PGM ": request too long\n");
869           exit (1);
870         }
871       if (arglen && fread (argbuffer, arglen, 1, stdin) != 1)
872         {
873           fprintf (stderr, PGM ": error reading request: %s\n",
874                    strerror (errno));
875           exit (1);
876         }
877       argbuffer[arglen] = 0;
878       switch (c)
879         {
880         case 1:
881           handle_open (argbuffer, arglen);
882           break;
883
884         case 2:
885           handle_close (argbuffer, arglen);
886           exit (0);
887           break;
888
889         case 3:
890           handle_transmit (argbuffer, arglen);
891           break;
892
893         case 4:
894           handle_status (argbuffer, arglen);
895           break;
896
897         case 5:
898           handle_reset (argbuffer, arglen);
899           break;
900
901         case 6:
902           handle_control (argbuffer, arglen);
903           break;
904
905         default:
906           fprintf (stderr, PGM ": invalid request 0x%02X\n", c);
907           exit (1);
908         }
909     }
910   return 0;
911 }
912
913
914
915 /*
916 Local Variables:
917 compile-command: "gcc -Wall -g -o pcsc-wrapper pcsc-wrapper.c -ldl"
918 End:
919 */