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