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