pcsc-lite  1.8.11
hotplug_libusb.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( http://pcsclite.alioth.debian.org/pcsclite.html )
3  *
4  * Copyright (C) 2001-2004
5  * David Corcoran <corcoran@musclecard.com>
6  * Copyright (C) 2003-2011
7  * Ludovic Rousseau <ludovic.rousseau@free.fr>
8  * Copyright (C) 2003
9  * Toni Andjelkovic <toni@soth.at>
10  * Copyright (C) 2003-2004
11  * Damien Sauveron <damien.sauveron@labri.fr>
12  *
13 Redistribution and use in source and binary forms, with or without
14 modification, are permitted provided that the following conditions
15 are met:
16 
17 1. Redistributions of source code must retain the above copyright
18  notice, this list of conditions and the following disclaimer.
19 2. Redistributions in binary form must reproduce the above copyright
20  notice, this list of conditions and the following disclaimer in the
21  documentation and/or other materials provided with the distribution.
22 3. The name of the author may not be used to endorse or promote products
23  derived from this software without specific prior written permission.
24 
25 Changes to this license can be made only by the copyright author with
26 explicit written consent.
27 
28 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
29 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
30 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
31 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
32 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
33 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
37 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38  *
39  * $Id: hotplug_libusb.c 6851 2014-02-14 15:43:32Z rousseau $
40  */
41 
47 #include "config.h"
48 #ifdef HAVE_LIBUSB
49 
50 #include <string.h>
51 #include <sys/types.h>
52 #include <stdio.h>
53 #include <dirent.h>
54 #include <fcntl.h>
55 #include <time.h>
56 #include <stdlib.h>
57 #include <unistd.h>
58 #include <errno.h>
59 #include <libusb.h>
60 #include <pthread.h>
61 #include <signal.h>
62 
63 #include "misc.h"
64 #include "wintypes.h"
65 #include "pcscd.h"
66 #include "debuglog.h"
67 #include "parser.h"
68 #include "readerfactory.h"
69 #include "winscard_msg.h"
70 #include "sys_generic.h"
71 #include "hotplug.h"
72 #include "utils.h"
73 
74 #undef DEBUG_HOTPLUG
75 
76 /* format is "%d:%d:%d", bus_number, device_address, interface */
77 #define BUS_DEVICE_STRSIZE 10+1+10+1+10+1
78 
79 #define READER_ABSENT 0
80 #define READER_PRESENT 1
81 #define READER_FAILED 2
82 
83 #define FALSE 0
84 #define TRUE 1
85 
86 extern char Add_Serial_In_Name;
87 
88 /* we use the default libusb context */
89 #define ctx NULL
90 
91 pthread_mutex_t usbNotifierMutex;
92 
93 static pthread_t usbNotifyThread;
94 static int driverSize = -1;
95 static char AraKiriHotPlug = FALSE;
96 static int rescan_pipe[] = { -1, -1 };
97 extern int HPForceReaderPolling;
98 
99 /* values of ifdCapabilities bits */
100 #define IFD_GENERATE_HOTPLUG 1
101 
105 static struct _driverTracker
106 {
107  unsigned int manuID;
108  unsigned int productID;
109 
110  char *bundleName;
111  char *libraryPath;
112  char *readerName;
113  int ifdCapabilities;
114 } *driverTracker = NULL;
115 #define DRIVER_TRACKER_SIZE_STEP 8
116 
120 static struct _readerTracker
121 {
122  char status;
123  char bus_device[BUS_DEVICE_STRSIZE];
124  char *fullName;
125 } readerTracker[PCSCLITE_MAX_READERS_CONTEXTS];
126 
127 static LONG HPAddHotPluggable(struct libusb_device *dev,
128  struct libusb_device_descriptor desc,
129  const char bus_device[], int interface,
130  struct _driverTracker *driver);
131 static LONG HPRemoveHotPluggable(int reader_index);
132 
133 static LONG HPReadBundleValues(void)
134 {
135  LONG rv;
136  DIR *hpDir;
137  struct dirent *currFP = NULL;
138  char fullPath[FILENAME_MAX];
139  char fullLibPath[FILENAME_MAX];
140  int listCount = 0;
141 
142  hpDir = opendir(PCSCLITE_HP_DROPDIR);
143 
144  if (hpDir == NULL)
145  {
146  Log1(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: " PCSCLITE_HP_DROPDIR);
147  Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd.");
148  return -1;
149  }
150 
151  /* allocate a first array */
152  driverTracker = calloc(DRIVER_TRACKER_SIZE_STEP, sizeof(*driverTracker));
153  if (NULL == driverTracker)
154  {
155  Log1(PCSC_LOG_CRITICAL, "Not enough memory");
156  return -1;
157  }
158  driverSize = DRIVER_TRACKER_SIZE_STEP;
159 
160 #define GET_KEY(key, values) \
161  rv = LTPBundleFindValueWithKey(&plist, key, values); \
162  if (rv) \
163  { \
164  Log2(PCSC_LOG_ERROR, "Value/Key not defined for " key " in %s", \
165  fullPath); \
166  continue; \
167  }
168 
169  while ((currFP = readdir(hpDir)) != 0)
170  {
171  if (strstr(currFP->d_name, ".bundle") != 0)
172  {
173  unsigned int alias;
174  list_t plist, *values;
175  list_t *manuIDs, *productIDs, *readerNames;
176  char *libraryPath;
177  int ifdCapabilities;
178 
179  /*
180  * The bundle exists - let's form a full path name and get the
181  * vendor and product ID's for this particular bundle
182  */
183  snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist",
184  PCSCLITE_HP_DROPDIR, currFP->d_name);
185  fullPath[sizeof(fullPath) - 1] = '\0';
186 
187  rv = bundleParse(fullPath, &plist);
188  if (rv)
189  continue;
190 
191  /* get CFBundleExecutable */
192  GET_KEY(PCSCLITE_HP_LIBRKEY_NAME, &values)
193  libraryPath = list_get_at(values, 0);
194  (void)snprintf(fullLibPath, sizeof(fullLibPath),
195  "%s/%s/Contents/%s/%s",
196  PCSCLITE_HP_DROPDIR, currFP->d_name, PCSC_ARCH,
197  libraryPath);
198  fullLibPath[sizeof(fullLibPath) - 1] = '\0';
199 
200  /* Get ifdCapabilities */
201  GET_KEY(PCSCLITE_HP_CPCTKEY_NAME, &values)
202  ifdCapabilities = strtol(list_get_at(values, 0), NULL, 16);
203 
204  GET_KEY(PCSCLITE_HP_MANUKEY_NAME, &manuIDs)
205  GET_KEY(PCSCLITE_HP_PRODKEY_NAME, &productIDs)
206  GET_KEY(PCSCLITE_HP_NAMEKEY_NAME, &readerNames)
207 
208  /* while we find a nth ifdVendorID in Info.plist */
209  for (alias=0; alias<list_size(manuIDs); alias++)
210  {
211  char *value;
212 
213  /* variables entries */
214  value = list_get_at(manuIDs, alias);
215  driverTracker[listCount].manuID = strtol(value, NULL, 16);
216 
217  value = list_get_at(productIDs, alias);
218  driverTracker[listCount].productID = strtol(value, NULL, 16);
219 
220  driverTracker[listCount].readerName = strdup(list_get_at(readerNames, alias));
221 
222  /* constant entries for a same driver */
223  driverTracker[listCount].bundleName = strdup(currFP->d_name);
224  driverTracker[listCount].libraryPath = strdup(fullLibPath);
225  driverTracker[listCount].ifdCapabilities = ifdCapabilities;
226 
227 #ifdef DEBUG_HOTPLUG
228  Log2(PCSC_LOG_INFO, "Found driver for: %s",
229  driverTracker[listCount].readerName);
230 #endif
231  listCount++;
232  if (listCount >= driverSize)
233  {
234  int i;
235 
236  /* increase the array size */
237  driverSize += DRIVER_TRACKER_SIZE_STEP;
238 #ifdef DEBUG_HOTPLUG
239  Log2(PCSC_LOG_INFO,
240  "Increase driverTracker to %d entries", driverSize);
241 #endif
242  driverTracker = realloc(driverTracker,
243  driverSize * sizeof(*driverTracker));
244  if (NULL == driverTracker)
245  {
246  Log1(PCSC_LOG_CRITICAL, "Not enough memory");
247  driverSize = -1;
248  closedir(hpDir);
249  return -1;
250  }
251 
252  /* clean the newly allocated entries */
253  for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++)
254  {
255  driverTracker[i].manuID = 0;
256  driverTracker[i].productID = 0;
257  driverTracker[i].bundleName = NULL;
258  driverTracker[i].libraryPath = NULL;
259  driverTracker[i].readerName = NULL;
260  driverTracker[i].ifdCapabilities = 0;
261  }
262  }
263  }
264  bundleRelease(&plist);
265  }
266  }
267 
268  driverSize = listCount;
269  closedir(hpDir);
270 
271  rv = TRUE;
272  if (driverSize == 0)
273  {
274  Log1(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: " PCSCLITE_HP_DROPDIR);
275  Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
276  rv = FALSE;
277  }
278 #ifdef DEBUG_HOTPLUG
279  else
280  Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount);
281 #endif
282 
283  return rv;
284 }
285 
286 static void HPRescanUsbBus(void)
287 {
288  int i, j;
289  char bus_device[BUS_DEVICE_STRSIZE];
290  libusb_device **devs, *dev;
291  ssize_t cnt;
292 
293  for (i=0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
294  /* clear rollcall */
295  readerTracker[i].status = READER_ABSENT;
296 
297  cnt = libusb_get_device_list(ctx, &devs);
298  if (cnt < 0)
299  {
300  Log1(PCSC_LOG_CRITICAL, "libusb_get_device_list() failed\n");
301  return;
302  }
303 
304  /* For each USB device */
305  cnt = 0;
306  while ((dev = devs[cnt++]) != NULL)
307  {
308  struct libusb_device_descriptor desc;
309  struct libusb_config_descriptor *config_desc;
310  uint8_t bus_number = libusb_get_bus_number(dev);
311  uint8_t device_address = libusb_get_device_address(dev);
312 
313  int r = libusb_get_device_descriptor(dev, &desc);
314  if (r < 0)
315  {
316  Log3(PCSC_LOG_ERROR, "failed to get device descriptor for %d/%d",
317  bus_number, device_address);
318  continue;
319  }
320 
321  r = libusb_get_active_config_descriptor(dev, &config_desc);
322  if (r < 0)
323  {
324  Log3(PCSC_LOG_ERROR, "failed to get device config for %d/%d",
325  bus_number, device_address);
326  continue;
327  }
328 
329  /* check if the device is supported by one driver */
330  for (i=0; i<driverSize; i++)
331  {
332  if (driverTracker[i].libraryPath != NULL &&
333  desc.idVendor == driverTracker[i].manuID &&
334  desc.idProduct == driverTracker[i].productID)
335  {
336  int interface;
337 
338 #ifdef DEBUG_HOTPLUG
339  Log3(PCSC_LOG_DEBUG, "Found matching USB device: %d:%d",
340  bus_number, device_address);
341 #endif
342 
343  for (interface = 0; interface < config_desc->bNumInterfaces;
344  interface++)
345  {
346  int newreader;
347 
348  /* A known device has been found */
349  snprintf(bus_device, BUS_DEVICE_STRSIZE, "%d:%d:%d",
350  bus_number, device_address, interface);
351  bus_device[BUS_DEVICE_STRSIZE - 1] = '\0';
352  newreader = TRUE;
353 
354  /* Check if the reader is a new one */
355  for (j=0; j<PCSCLITE_MAX_READERS_CONTEXTS; j++)
356  {
357  if (strncmp(readerTracker[j].bus_device,
358  bus_device, BUS_DEVICE_STRSIZE) == 0)
359  {
360  /* The reader is already known */
361  readerTracker[j].status = READER_PRESENT;
362  newreader = FALSE;
363 #ifdef DEBUG_HOTPLUG
364  Log2(PCSC_LOG_DEBUG, "Refresh USB device: %s",
365  bus_device);
366 #endif
367  break;
368  }
369  }
370 
371  /* New reader found */
372  if (newreader)
373  {
374  if (config_desc->bNumInterfaces > 1)
375  HPAddHotPluggable(dev, desc, bus_device,
376  interface, &driverTracker[i]);
377  else
378  HPAddHotPluggable(dev, desc, bus_device,
379  -1, &driverTracker[i]);
380  }
381  }
382  }
383  }
384  libusb_free_config_descriptor(config_desc);
385  }
386 
387  /*
388  * check if all the previously found readers are still present
389  */
390  for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
391  {
392  if ((readerTracker[i].status == READER_ABSENT) &&
393  (readerTracker[i].fullName != NULL))
394  HPRemoveHotPluggable(i);
395  }
396 
397  if (AraKiriHotPlug)
398  {
399  int retval;
400 
401  for (i=0; i<driverSize; i++)
402  {
403  /* free strings allocated by strdup() */
404  free(driverTracker[i].bundleName);
405  free(driverTracker[i].libraryPath);
406  free(driverTracker[i].readerName);
407  }
408  free(driverTracker);
409 
410  Log1(PCSC_LOG_INFO, "Hotplug stopped");
411  pthread_exit(&retval);
412  }
413 
414  /* free the libusb allocated list & devices */
415  libusb_free_device_list(devs, 1);
416 }
417 
418 static void HPEstablishUSBNotifications(int pipefd[2])
419 {
420  int i, do_polling;
421  int r;
422  char c = 42; /* magic value */
423 
424  r = libusb_init(ctx);
425  if (r < 0)
426  {
427  Log2(PCSC_LOG_CRITICAL, "libusb_init failed: %d", r);
428  /* emergency exit */
429  kill(getpid(), SIGTERM);
430  return;
431  }
432 
433  /* scan the USB bus for devices at startup */
434  HPRescanUsbBus();
435 
436  /* signal that the initially connected readers are now visible */
437  write(pipefd[1], &c, 1);
438  close(pipefd[1]);
439 
440  /* if at least one driver do not have IFD_GENERATE_HOTPLUG */
441  do_polling = FALSE;
442  for (i=0; i<driverSize; i++)
443  if (driverTracker[i].libraryPath)
444  if ((driverTracker[i].ifdCapabilities & IFD_GENERATE_HOTPLUG) == 0)
445  {
446  Log2(PCSC_LOG_INFO,
447  "Driver %s does not support IFD_GENERATE_HOTPLUG. Using active polling instead.",
448  driverTracker[i].bundleName);
449  if (HPForceReaderPolling < 1)
450  HPForceReaderPolling = 1;
451  break;
452  }
453 
454  if (HPForceReaderPolling)
455  {
456  Log2(PCSC_LOG_INFO,
457  "Polling forced every %d second(s)", HPForceReaderPolling);
458  do_polling = TRUE;
459  }
460 
461  if (do_polling)
462  {
463  while (!AraKiriHotPlug)
464  {
465  SYS_Sleep(HPForceReaderPolling);
466  HPRescanUsbBus();
467  }
468  }
469  else
470  {
471  char dummy;
472 
473  pipe(rescan_pipe);
474  while (read(rescan_pipe[0], &dummy, sizeof(dummy)) > 0)
475  {
476  Log1(PCSC_LOG_INFO, "Reload serial configuration");
477  HPRescanUsbBus();
478 #ifdef USE_SERIAL
479  RFReCheckReaderConf();
480 #endif
481  Log1(PCSC_LOG_INFO, "End reload serial configuration");
482  }
483  close(rescan_pipe[0]);
484  rescan_pipe[0] = -1;
485  }
486 }
487 
488 LONG HPSearchHotPluggables(void)
489 {
490  int i;
491 
492  for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
493  {
494  readerTracker[i].status = READER_ABSENT;
495  readerTracker[i].bus_device[0] = '\0';
496  readerTracker[i].fullName = NULL;
497  }
498 
499  if (HPReadBundleValues())
500  {
501  int pipefd[2];
502  char c;
503 
504  if (pipe(pipefd) == -1)
505  {
506  Log2(PCSC_LOG_ERROR, "pipe: %s", strerror(errno));
507  return -1;
508  }
509 
510  ThreadCreate(&usbNotifyThread, THREAD_ATTR_DETACHED,
511  (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, pipefd);
512 
513  /* Wait for initial readers to setup */
514  read(pipefd[0], &c, 1);
515  close(pipefd[0]);
516  }
517 
518  return 0;
519 }
520 
521 LONG HPStopHotPluggables(void)
522 {
523  AraKiriHotPlug = TRUE;
524  if (rescan_pipe[1] >= 0)
525  {
526  close(rescan_pipe[1]);
527  rescan_pipe[1] = -1;
528  }
529 
530  return 0;
531 }
532 
533 static LONG HPAddHotPluggable(struct libusb_device *dev,
534  struct libusb_device_descriptor desc,
535  const char bus_device[], int interface,
536  struct _driverTracker *driver)
537 {
538  int i;
539  char deviceName[MAX_DEVICENAME];
540 
541  Log2(PCSC_LOG_INFO, "Adding USB device: %s", bus_device);
542 
543  if (interface >= 0)
544  snprintf(deviceName, sizeof(deviceName), "usb:%04x/%04x:libhal:/org/freedesktop/Hal/devices/usb_device_%04x_%04x_serialnotneeded_if%d",
545  desc.idVendor, desc.idProduct, desc.idVendor, desc.idProduct,
546  interface);
547  else
548  snprintf(deviceName, sizeof(deviceName), "usb:%04x/%04x:libusb-1.0:%s",
549  desc.idVendor, desc.idProduct, bus_device);
550 
551  deviceName[sizeof(deviceName) -1] = '\0';
552 
553  pthread_mutex_lock(&usbNotifierMutex);
554 
555  /* find a free entry */
556  for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
557  {
558  if (readerTracker[i].fullName == NULL)
559  break;
560  }
561 
562  if (i==PCSCLITE_MAX_READERS_CONTEXTS)
563  {
564  Log2(PCSC_LOG_ERROR,
565  "Not enough reader entries. Already found %d readers", i);
566  pthread_mutex_unlock(&usbNotifierMutex);
567  return 0;
568  }
569 
570  strncpy(readerTracker[i].bus_device, bus_device,
571  sizeof(readerTracker[i].bus_device));
572  readerTracker[i].bus_device[sizeof(readerTracker[i].bus_device) - 1] = '\0';
573 
574  if (Add_Serial_In_Name && desc.iSerialNumber)
575  {
576  libusb_device_handle *device;
577  int ret;
578 
579  ret = libusb_open(dev, &device);
580  if (ret < 0)
581  {
582  Log2(PCSC_LOG_ERROR, "libusb_open failed: %d", ret);
583  }
584  else
585  {
586  unsigned char serialNumber[MAX_READERNAME];
587 
588  ret = libusb_get_string_descriptor_ascii(device, desc.iSerialNumber,
589  serialNumber, MAX_READERNAME);
590  libusb_close(device);
591 
592  if (ret < 0)
593  {
594  Log2(PCSC_LOG_ERROR,
595  "libusb_get_string_descriptor_ascii failed: %d", ret);
596  readerTracker[i].fullName = strdup(driver->readerName);
597  }
598  else
599  {
600  char fullname[MAX_READERNAME];
601 
602  snprintf(fullname, sizeof(fullname), "%s (%s)",
603  driver->readerName, serialNumber);
604  readerTracker[i].fullName = strdup(fullname);
605  }
606  }
607  }
608  else
609  readerTracker[i].fullName = strdup(driver->readerName);
610 
611  if (RFAddReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i,
612  driver->libraryPath, deviceName) == SCARD_S_SUCCESS)
613  readerTracker[i].status = READER_PRESENT;
614  else
615  {
616  readerTracker[i].status = READER_FAILED;
617 
618  (void)CheckForOpenCT();
619  }
620 
621  pthread_mutex_unlock(&usbNotifierMutex);
622 
623  return 1;
624 } /* End of function */
625 
626 static LONG HPRemoveHotPluggable(int reader_index)
627 {
628  pthread_mutex_lock(&usbNotifierMutex);
629 
630  Log3(PCSC_LOG_INFO, "Removing USB device[%d]: %s", reader_index,
631  readerTracker[reader_index].bus_device);
632 
633  RFRemoveReader(readerTracker[reader_index].fullName,
634  PCSCLITE_HP_BASE_PORT + reader_index);
635  free(readerTracker[reader_index].fullName);
636  readerTracker[reader_index].status = READER_ABSENT;
637  readerTracker[reader_index].bus_device[0] = '\0';
638  readerTracker[reader_index].fullName = NULL;
639 
640  pthread_mutex_unlock(&usbNotifierMutex);
641 
642  return 1;
643 } /* End of function */
644 
648 ULONG HPRegisterForHotplugEvents(void)
649 {
650  (void)pthread_mutex_init(&usbNotifierMutex, NULL);
651  return 0;
652 }
653 
654 void HPReCheckSerialReaders(void)
655 {
656  Log0(PCSC_LOG_INFO);
657  if (rescan_pipe[1] >= 0)
658  {
659  char dummy = 0;
660  write(rescan_pipe[1], &dummy, sizeof(dummy));
661  }
662 }
663 
664 #endif
665 
list object
Definition: simclist.h:181
This handles abstract system level calls.
int SYS_Sleep(int)
Makes the current process sleep for some seconds.
Definition: sys_unix.c:70
Reads lexical config files and updates database.
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
Definition: pcsclite.h:221
This defines some structures and #defines to be used over the transport layer.
This keeps a list of Windows(R) types.
This keeps a list of defines for pcsc-lite.
This keeps track of a list of currently available reader structures.
This provides a search API for hot pluggble devices.
int bundleParse(const char *fileName, list_t *l)
Parse a Info.plist file and file a list.
Definition: tokenparser.c:1962
void bundleRelease(list_t *l)
Free the list created by bundleParse()
Definition: tokenparser.c:2020
#define SCARD_S_SUCCESS
error codes from http://msdn.microsoft.com/en-us/library/aa924526.aspx
Definition: pcsclite.h:106
This handles debugging.