* command.c (scd_update_reader_status_file): Send a signal back to
[gnupg.git] / scd / pcsc-wrapper.c
1 /* pcsc-wrapper.c - Wrapper for ccessing 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 2 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, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 /*
22   This wrapper is required to handle problems with the libpscslite
23   library.  That library assumes that pthreads are used and fails
24   badly if one tries to use it with a procerss using Pth.
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) " 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
70 /* PC/SC constants and function pointer. */
71 #define PCSC_SCOPE_USER      0 
72 #define PCSC_SCOPE_TERMINAL  1 
73 #define PCSC_SCOPE_SYSTEM    2 
74 #define PCSC_SCOPE_GLOBAL    3 
75
76 #define PCSC_PROTOCOL_T0     1 
77 #define PCSC_PROTOCOL_T1     2 
78 #define PCSC_PROTOCOL_RAW    4 
79
80 #define PCSC_SHARE_EXCLUSIVE 1
81 #define PCSC_SHARE_SHARED    2
82 #define PCSC_SHARE_DIRECT    3
83
84 #define PCSC_LEAVE_CARD      0
85 #define PCSC_RESET_CARD      1
86 #define PCSC_UNPOWER_CARD    2
87 #define PCSC_EJECT_CARD      3
88
89 struct pcsc_io_request_s {
90   unsigned long protocol; 
91   unsigned long pci_len;
92 };
93
94 typedef struct pcsc_io_request_s *pcsc_io_request_t;
95
96
97 static int driver_is_open;     /* True if the PC/SC driver has been
98                                   initialzied and is ready for
99                                   operations.  The follwoing variables
100                                   are then valid. */
101 static unsigned long pcsc_context;  /* The current PC/CS context. */
102 static unsigned long pcsc_card;
103 static unsigned long pcsc_protocol;
104 static unsigned char current_atr[33];
105 static size_t current_atrlen;
106
107 long (* pcsc_establish_context) (unsigned long scope,
108                                  const void *reserved1,
109                                  const void *reserved2,
110                                  unsigned long *r_context);
111 long (* pcsc_release_context) (unsigned long context);
112 long (* pcsc_list_readers) (unsigned long context,
113                             const char *groups,
114                             char *readers, unsigned long*readerslen);
115 long (* pcsc_connect) (unsigned long context,
116                        const char *reader,
117                        unsigned long share_mode,
118                        unsigned long preferred_protocols,
119                        unsigned long *r_card,
120                        unsigned long *r_active_protocol);
121 long (* pcsc_disconnect) (unsigned long card,
122                           unsigned long disposition);
123 long (* pcsc_status) (unsigned long card,
124                       char *reader, unsigned long *readerlen,
125                       unsigned long *r_state,
126                       unsigned long *r_protocol,
127                       unsigned char *atr, unsigned long *atrlen);
128 long (* pcsc_begin_transaction) (unsigned long card);
129 long (* pcsc_end_transaction) (unsigned long card);
130 long (* pcsc_transmit) (unsigned long card,
131                         const pcsc_io_request_t send_pci,
132                         const unsigned char *send_buffer,
133                         unsigned long send_len,
134                         pcsc_io_request_t recv_pci,
135                         unsigned char *recv_buffer,
136                         unsigned long *recv_len);
137 long (* pcsc_set_timeout) (unsigned long context,
138                            unsigned long timeout);
139
140
141
142 static void
143 bad_request (const char *type)
144 {
145   fprintf (stderr, PGM ": bad `%s' request\n", type);
146   exit (1);
147 }
148
149 static void
150 request_failed (int err)
151 {
152   if (!err)
153     err = -1;
154
155   putchar (0x81); /* Simple error/success response. */
156
157   putchar (0);
158   putchar (0);
159   putchar (0);
160   putchar (4);
161
162   putchar ((err >> 24) & 0xff);
163   putchar ((err >> 16) & 0xff);
164   putchar ((err >>  8) & 0xff);
165   putchar ((err      ) & 0xff);
166
167   fflush (stdout);
168 }
169
170
171 static void
172 request_succeeded (const void *buffer, size_t buflen)
173 {
174   size_t len;
175
176   putchar (0x81); /* Simple error/success response. */
177
178   len = 4 + buflen;
179   putchar ((len >> 24) & 0xff);
180   putchar ((len >> 16) & 0xff);
181   putchar ((len >>  8) & 0xff);
182   putchar ((len      ) & 0xff);
183
184   /* Error code. */
185   putchar (0);
186   putchar (0);
187   putchar (0);
188   putchar (0);
189
190   /* Optional reponse string. */
191   if (buffer)
192     fwrite (buffer, buflen, 1, stdout);
193
194   fflush (stdout);
195 }
196   
197
198
199 static unsigned long
200 read_32 (FILE *fp)
201 {
202   int c1, c2, c3, c4;
203
204   c1 = getc (stdin);
205   c2 = getc (stdin);
206   c3 = getc (stdin);
207   c4 = getc (stdin);
208   if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF)
209     {
210       fprintf (stderr, PGM ": premature EOF while parsing request\n");
211       exit (1);
212     }
213   return (c1 << 24) | (c2 << 16) | (c3 << 8) | c4;
214 }
215
216
217
218 static const char *
219 pcsc_error_string (long err)
220 {
221   const char *s;
222
223   if (!err)
224     return "okay";
225   if ((err & 0x80100000) != 0x80100000)
226     return "invalid PC/SC error code";
227   err &= 0xffff;
228   switch (err)
229     {
230     case 0x0002: s = "cancelled"; break;
231     case 0x000e: s = "can't dispose"; break;
232     case 0x0008: s = "insufficient buffer"; break;   
233     case 0x0015: s = "invalid ATR"; break;
234     case 0x0003: s = "invalid handle"; break;
235     case 0x0004: s = "invalid parameter"; break; 
236     case 0x0005: s = "invalid target"; break;
237     case 0x0011: s = "invalid value"; break; 
238     case 0x0006: s = "no memory"; break;  
239     case 0x0013: s = "comm error"; break;      
240     case 0x0001: s = "internal error"; break;     
241     case 0x0014: s = "unknown error"; break; 
242     case 0x0007: s = "waited too long"; break;  
243     case 0x0009: s = "unknown reader"; break;
244     case 0x000a: s = "timeout"; break; 
245     case 0x000b: s = "sharing violation"; break;       
246     case 0x000c: s = "no smartcard"; break;
247     case 0x000d: s = "unknown card"; break;   
248     case 0x000f: s = "proto mismatch"; break;          
249     case 0x0010: s = "not ready"; break;               
250     case 0x0012: s = "system cancelled"; break;        
251     case 0x0016: s = "not transacted"; break;
252     case 0x0017: s = "reader unavailable"; break; 
253     case 0x0065: s = "unsupported card"; break;        
254     case 0x0066: s = "unresponsive card"; break;       
255     case 0x0067: s = "unpowered card"; break;          
256     case 0x0068: s = "reset card"; break;              
257     case 0x0069: s = "removed card"; break;            
258     case 0x006a: s = "inserted card"; break;           
259     case 0x001f: s = "unsupported feature"; break;     
260     case 0x0019: s = "PCI too small"; break;           
261     case 0x001a: s = "reader unsupported"; break;      
262     case 0x001b: s = "duplicate reader"; break;        
263     case 0x001c: s = "card unsupported"; break;        
264     case 0x001d: s = "no service"; break;              
265     case 0x001e: s = "service stopped"; break;      
266     default:     s = "unknown PC/SC error code"; break;
267     }
268   return s;
269 }
270
271 static void
272 load_pcsc_driver (const char *libname)
273 {
274   void *handle;
275
276   handle = dlopen (libname, RTLD_LAZY);
277   if (!handle)
278     {
279       fprintf (stderr, PGM ": failed to open driver `%s': %s",
280                libname, dlerror ());
281       exit (1);
282     }
283
284   pcsc_establish_context = dlsym (handle, "SCardEstablishContext");
285   pcsc_release_context   = dlsym (handle, "SCardReleaseContext");
286   pcsc_list_readers      = dlsym (handle, "SCardListReaders");
287   pcsc_connect           = dlsym (handle, "SCardConnect");
288   pcsc_disconnect        = dlsym (handle, "SCardDisconnect");
289   pcsc_status            = dlsym (handle, "SCardStatus");
290   pcsc_begin_transaction = dlsym (handle, "SCardBeginTransaction");
291   pcsc_end_transaction   = dlsym (handle, "SCardEndTransaction");
292   pcsc_transmit          = dlsym (handle, "SCardTransmit");
293   pcsc_set_timeout       = dlsym (handle, "SCardSetTimeout");
294
295   if (!pcsc_establish_context
296       || !pcsc_release_context  
297       || !pcsc_list_readers     
298       || !pcsc_connect          
299       || !pcsc_disconnect
300       || !pcsc_status
301       || !pcsc_begin_transaction
302       || !pcsc_end_transaction
303       || !pcsc_transmit         
304       /* || !pcsc_set_timeout */)
305     {
306       /* Note that set_timeout is currently not used and also not
307          available under Windows. */
308       fprintf (stderr,
309                "apdu_open_reader: invalid PC/SC driver "
310                "(%d%d%d%d%d%d%d%d%d%d)\n",
311                !!pcsc_establish_context,
312                !!pcsc_release_context,  
313                !!pcsc_list_readers,     
314                !!pcsc_connect,          
315                !!pcsc_disconnect,
316                !!pcsc_status,
317                !!pcsc_begin_transaction,
318                !!pcsc_end_transaction,
319                !!pcsc_transmit,         
320                !!pcsc_set_timeout );
321       dlclose (handle);
322       exit (1);
323     }
324 }
325   
326
327
328
329 /* Handle a open request.  The argument is expected to be a string
330    with the port indentification. ARGBUF is always guaranteed to be
331    terminted by a 0 which is not counted in ARGLEN. We may modifiy
332    ARGBUF. */
333 static void
334 handle_open (unsigned char *argbuf, size_t arglen)
335 {
336   long err;
337   const char * portstr;
338   char *list = NULL;
339   unsigned long nreader, listlen, atrlen;
340   char *p;
341   unsigned long card_state, card_protocol;
342   unsigned char atr[33];
343
344   /* Make sure there is only the port string */
345   if (arglen != strlen (argbuf))
346     bad_request ("OPEN");
347   portstr = argbuf;
348
349   if (driver_is_open)
350     {
351       fprintf (stderr, PGM ": PC/SC has already been opened\n");
352       request_failed (-1);
353     }
354
355   err = pcsc_establish_context (PCSC_SCOPE_SYSTEM, NULL, NULL, &pcsc_context);
356   if (err)
357     {
358       fprintf (stderr, PGM": pcsc_establish_context failed: %s (0x%lx)\n",
359                pcsc_error_string (err), err);
360       request_failed (err);
361       return;
362     }
363   
364   err = pcsc_list_readers (pcsc_context, NULL, NULL, &nreader);
365   if (!err)
366     {
367       list = malloc (nreader+1); /* Better add 1 for safety reasons. */
368       if (!list)
369         {
370           fprintf (stderr, PGM": error allocating memory for reader list\n");
371           exit (1);
372         }
373       err = pcsc_list_readers (pcsc_context, NULL, list, &nreader);
374     }
375   if (err)
376     {
377       fprintf (stderr, PGM": pcsc_list_readers failed: %s (0x%lx)\n",
378                pcsc_error_string (err), err);
379       pcsc_release_context (pcsc_context);
380       free (list);
381       request_failed (err);
382       return;
383     }
384
385   listlen = nreader;
386   p = list;
387   while (nreader)
388     {
389       if (!*p && !p[1])
390         break;
391       fprintf (stderr, PGM": detected reader `%s'\n", p);
392       if (nreader < (strlen (p)+1))
393         {
394           fprintf (stderr, PGM": invalid response from pcsc_list_readers\n");
395           break;
396         }
397       nreader -= strlen (p)+1;
398       p += strlen (p) + 1;
399     }
400
401   err = pcsc_connect (pcsc_context,
402                       portstr && *portstr? portstr : list,
403                       PCSC_SHARE_EXCLUSIVE,
404                       PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
405                       &pcsc_card,
406                       &pcsc_protocol);
407   if (err)
408     {
409       fprintf (stderr, PGM": pcsc_connect failed: %s (0x%lx)\n",
410                pcsc_error_string (err), err);
411       pcsc_release_context (pcsc_context);
412       free (list);
413       request_failed (err);
414       return;
415     }      
416   
417   atrlen = 32;
418   /* (We need to pass a dummy buffer.  We use LIST because it ought to
419      be large enough.) */
420   err = pcsc_status (pcsc_card,
421                      list, &listlen,
422                      &card_state, &card_protocol,
423                      atr, &atrlen);
424   free (list);
425   if (err)
426     {
427       fprintf (stderr, PGM": pcsc_status failed: %s (0x%lx)\n",
428                pcsc_error_string (err), err);
429       pcsc_release_context (pcsc_context);
430       request_failed (err);
431       return;
432     }
433   if (atrlen >= sizeof atr || atrlen >= sizeof current_atr)
434     {
435       fprintf (stderr, PGM": ATR returned by pcsc_status is too large\n");
436       exit (4);
437     }
438   memcpy (current_atr, atr, atrlen);
439   current_atrlen = atrlen;
440   driver_is_open = 1;
441   request_succeeded (current_atr, current_atrlen);
442 }
443
444
445
446 /* Handle a close request.  We expect no arguments.  We may modifiy
447    ARGBUF. */
448 static void
449 handle_close (unsigned char *argbuf, size_t arglen)
450 {
451   if (!driver_is_open)
452     {
453       fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
454       request_failed (-1);
455     }
456
457   pcsc_release_context (pcsc_context);
458
459   request_succeeded (NULL, 0);
460 }
461
462
463
464 /* Handle a transmit request.  The argument is expected to be a bufer
465    with the APDU.  We may modifiy ARGBUF. */
466 static void
467 handle_transmit (unsigned char *argbuf, size_t arglen)
468 {
469   long err;
470   struct pcsc_io_request_s send_pci;
471   unsigned long recv_len;
472   unsigned char buffer[1024];
473
474   /* The apdu should at least be one byte. */
475   if (!arglen)
476     bad_request ("TRANSMIT");
477
478   if (!driver_is_open)
479     {
480       fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
481       request_failed (-1);
482     }
483
484   if ((pcsc_protocol & PCSC_PROTOCOL_T1))
485     send_pci.protocol = PCSC_PROTOCOL_T1;
486   else
487     send_pci.protocol = PCSC_PROTOCOL_T0;
488   send_pci.pci_len = sizeof send_pci;
489   recv_len = sizeof (buffer);
490   err = pcsc_transmit (pcsc_card, &send_pci, argbuf, arglen,
491                        NULL, buffer, &recv_len);
492   if (err)
493     {
494       if (verbose)
495         fprintf (stderr, PGM": pcsc_transmit failed: %s (0x%lx)\n",
496                  pcsc_error_string (err), err);
497       request_failed (err);
498       return;
499     }
500   request_succeeded (buffer, recv_len);
501 }
502
503
504
505
506
507
508
509
510
511
512
513
514 static void
515 print_version (int with_help)
516 {
517   fputs (MYVERSION_LINE "\n"
518          "Copyright (C) 2004 Free Software Foundation, Inc.\n"
519          "This program comes with ABSOLUTELY NO WARRANTY.\n"
520          "This is free software, and you are welcome to redistribute it\n"
521          "under certain conditions. See the file COPYING for details.\n",
522          stdout);
523         
524   if (with_help)
525     fputs ("\n"
526           "Usage: " PGM " [OPTIONS] API-NUMBER [LIBNAME]\n"
527           "Helper to connect scdaemon to the PC/SC library\n"
528           "\n"
529           "  --verbose   enable extra informational output\n"
530           "  --version   print version of the program and exit\n"
531           "  --help      display this help and exit\n"
532           BUGREPORT_LINE, stdout );
533   
534   exit (0);
535 }
536
537
538 int
539 main (int argc, char **argv)
540 {
541   int last_argc = -1;
542   int api_number = 0;
543   int c;
544  
545   if (argc)
546     {
547       argc--; argv++;
548     }
549   while (argc && last_argc != argc )
550     {
551       last_argc = argc;
552       if (!strcmp (*argv, "--"))
553         {
554           argc--; argv++;
555           break;
556         }
557       else if (!strcmp (*argv, "--version"))
558         print_version (0);
559       else if (!strcmp (*argv, "--help"))
560         print_version (1);
561       else if (!strcmp (*argv, "--verbose"))
562         {
563           verbose = 1;
564           argc--; argv++;
565         }
566     }          
567   if (argc != 1 && argc != 2)
568     {
569       fprintf (stderr, "usage: " PGM " API-NUMBER [LIBNAME]\n");
570       exit (1);
571     }
572
573   api_number = atoi (*argv);
574   argv++; argc--;
575   if (api_number != 1)
576     {
577       fprintf (stderr, PGM ": api-number %d is not valid\n", api_number);
578       exit (1);
579     }
580
581   load_pcsc_driver (argc? *argv : DEFAULT_PCSC_DRIVER);
582
583   while ((c = getc (stdin)) != EOF)
584     {
585       size_t arglen;
586       unsigned char argbuffer[2048];
587       
588       arglen = read_32 (stdin);
589       if (arglen >= sizeof argbuffer - 1)
590         {
591           fprintf (stderr, PGM ": request too long\n");
592           exit (1);
593         }
594       if (arglen && fread (argbuffer, arglen, 1, stdin) != 1)
595         {
596           fprintf (stderr, PGM ": error reading request: %s\n",
597                    strerror (errno));
598           exit (1);
599         }
600       argbuffer[arglen] = 0;
601       switch (c)
602         {
603         case 1:
604           handle_open (argbuffer, arglen);
605           break;
606
607         case 2:
608           handle_close (argbuffer, arglen);
609           exit (0);
610           break;
611
612         case 3:
613           handle_transmit (argbuffer, arglen);
614           break;
615
616         default:
617           fprintf (stderr, PGM ": invalid request 0x%02X\n", c);
618           exit (1);
619         }
620       free (argbuffer);
621     }
622   return 0;
623 }
624
625
626
627 /*
628 Local Variables:
629 compile-command: "gcc -Wall -g -o pcsc-wrapper pcsc-wrapper.c -ldl"
630 End:
631 */