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