pcsc-lite  1.8.3
hotplug_libudev.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( http://www.linuxnet.com )
3  *
4  * Copyright (C) 2011
5  * Ludovic Rousseau <ludovic.rousseau@free.fr>
6  *
7  * $Id: hotplug_libudev.c 6130 2011-12-05 14:44:09Z rousseau $
8  */
9 
15 #include "config.h"
16 #if defined(HAVE_LIBUDEV) && defined(USE_USB)
17 
18 #include <string.h>
19 #include <stdio.h>
20 #include <dirent.h>
21 #include <stdlib.h>
22 #include <pthread.h>
23 #include <libudev.h>
24 
25 #include "debuglog.h"
26 #include "parser.h"
27 #include "readerfactory.h"
28 #include "sys_generic.h"
29 #include "hotplug.h"
30 #include "utils.h"
31 #include "strlcpycat.h"
32 
33 #undef DEBUG_HOTPLUG
34 #define ADD_SERIAL_NUMBER
35 #define ADD_INTERFACE_NAME
36 
37 #define FALSE 0
38 #define TRUE 1
39 
40 pthread_mutex_t usbNotifierMutex;
41 
42 static pthread_t usbNotifyThread;
43 static int driverSize = -1;
44 static char AraKiriHotPlug = FALSE;
45 
49 static struct _driverTracker
50 {
51  unsigned int manuID;
52  unsigned int productID;
53 
54  char *bundleName;
55  char *libraryPath;
56  char *readerName;
57  char *CFBundleName;
58 } *driverTracker = NULL;
59 #define DRIVER_TRACKER_SIZE_STEP 10
60 
61 /* The CCID driver already supports 176 readers.
62  * We start with a big array size to avoid reallocation. */
63 #define DRIVER_TRACKER_INITIAL_SIZE 200
64 
65 typedef enum {
66  READER_ABSENT,
67  READER_PRESENT,
68  READER_FAILED
69 } readerState_t;
70 
74 static struct _readerTracker
75 {
76  readerState_t status;
77  char bInterfaceNumber;
78  char *devpath;
79  char *fullName;
80 } readerTracker[PCSCLITE_MAX_READERS_CONTEXTS];
81 
82 
83 static LONG HPReadBundleValues(void)
84 {
85  LONG rv;
86  DIR *hpDir;
87  struct dirent *currFP = NULL;
88  char fullPath[FILENAME_MAX];
89  char fullLibPath[FILENAME_MAX];
90  int listCount = 0;
91 
92  hpDir = opendir(PCSCLITE_HP_DROPDIR);
93 
94  if (NULL == hpDir)
95  {
96  Log1(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: " PCSCLITE_HP_DROPDIR);
97  Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd.");
98  return -1;
99  }
100 
101  /* allocate a first array */
102  driverSize = DRIVER_TRACKER_INITIAL_SIZE;
103  driverTracker = calloc(driverSize, sizeof(*driverTracker));
104  if (NULL == driverTracker)
105  {
106  Log1(PCSC_LOG_CRITICAL, "Not enough memory");
107  (void)closedir(hpDir);
108  return -1;
109  }
110 
111 #define GET_KEY(key, values) \
112  rv = LTPBundleFindValueWithKey(&plist, key, values); \
113  if (rv) \
114  { \
115  Log2(PCSC_LOG_ERROR, "Value/Key not defined for " key " in %s", \
116  fullPath); \
117  continue; \
118  }
119 
120  while ((currFP = readdir(hpDir)) != 0)
121  {
122  if (strstr(currFP->d_name, ".bundle") != 0)
123  {
124  unsigned int alias;
125  list_t plist, *values;
126  list_t *manuIDs, *productIDs, *readerNames;
127  char *CFBundleName;
128  char *libraryPath;
129 
130  /*
131  * The bundle exists - let's form a full path name and get the
132  * vendor and product ID's for this particular bundle
133  */
134  (void)snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist",
135  PCSCLITE_HP_DROPDIR, currFP->d_name);
136  fullPath[sizeof(fullPath) - 1] = '\0';
137 
138  rv = bundleParse(fullPath, &plist);
139  if (rv)
140  continue;
141 
142  /* get CFBundleExecutable */
143  GET_KEY(PCSCLITE_HP_LIBRKEY_NAME, &values)
144  libraryPath = list_get_at(values, 0);
145  (void)snprintf(fullLibPath, sizeof(fullLibPath),
146  "%s/%s/Contents/%s/%s",
147  PCSCLITE_HP_DROPDIR, currFP->d_name, PCSC_ARCH,
148  libraryPath);
149  fullLibPath[sizeof(fullLibPath) - 1] = '\0';
150 
151  GET_KEY(PCSCLITE_HP_MANUKEY_NAME, &manuIDs)
152  GET_KEY(PCSCLITE_HP_PRODKEY_NAME, &productIDs)
153  GET_KEY(PCSCLITE_HP_NAMEKEY_NAME, &readerNames)
154 
155  /* Get CFBundleName */
156  rv = LTPBundleFindValueWithKey(&plist, PCSCLITE_HP_CFBUNDLE_NAME,
157  &values);
158  if (rv)
159  CFBundleName = NULL;
160  else
161  CFBundleName = strdup(list_get_at(values, 0));
162 
163  /* while we find a nth ifdVendorID in Info.plist */
164  for (alias=0; alias<list_size(manuIDs); alias++)
165  {
166  char *value;
167 
168  /* variables entries */
169  value = list_get_at(manuIDs, alias);
170  driverTracker[listCount].manuID = strtol(value, NULL, 16);
171 
172  value = list_get_at(productIDs, alias);
173  driverTracker[listCount].productID = strtol(value, NULL, 16);
174 
175  driverTracker[listCount].readerName = strdup(list_get_at(readerNames, alias));
176 
177  /* constant entries for a same driver */
178  driverTracker[listCount].bundleName = strdup(currFP->d_name);
179  driverTracker[listCount].libraryPath = strdup(fullLibPath);
180  driverTracker[listCount].CFBundleName = CFBundleName;
181 
182 #ifdef DEBUG_HOTPLUG
183  Log2(PCSC_LOG_INFO, "Found driver for: %s",
184  driverTracker[listCount].readerName);
185 #endif
186  listCount++;
187  if (listCount >= driverSize)
188  {
189  int i;
190 
191  /* increase the array size */
192  driverSize += DRIVER_TRACKER_SIZE_STEP;
193 #ifdef DEBUG_HOTPLUG
194  Log2(PCSC_LOG_INFO,
195  "Increase driverTracker to %d entries", driverSize);
196 #endif
197  driverTracker = realloc(driverTracker,
198  driverSize * sizeof(*driverTracker));
199  if (NULL == driverTracker)
200  {
201  Log1(PCSC_LOG_CRITICAL, "Not enough memory");
202  driverSize = -1;
203  (void)closedir(hpDir);
204  return -1;
205  }
206 
207  /* clean the newly allocated entries */
208  for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++)
209  {
210  driverTracker[i].manuID = 0;
211  driverTracker[i].productID = 0;
212  driverTracker[i].bundleName = NULL;
213  driverTracker[i].libraryPath = NULL;
214  driverTracker[i].readerName = NULL;
215  driverTracker[i].CFBundleName = NULL;
216  }
217  }
218  }
219  bundleRelease(&plist);
220  }
221  }
222 
223  driverSize = listCount;
224  (void)closedir(hpDir);
225 
226 #ifdef DEBUG_HOTPLUG
227  Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount);
228 #endif
229 
230  return 0;
231 } /* HPReadBundleValues */
232 
233 
234 /*@null@*/ static struct _driverTracker *get_driver(struct udev_device *dev,
235  const char *devpath, struct _driverTracker **classdriver)
236 {
237  int i;
238  unsigned int idVendor, idProduct;
239  static struct _driverTracker *driver;
240  const char *str;
241 
242  str = udev_device_get_sysattr_value(dev, "idVendor");
243  if (!str)
244  {
245  Log1(PCSC_LOG_ERROR, "udev_device_get_sysattr_value() failed");
246  return NULL;
247  }
248  idVendor = strtol(str, NULL, 16);
249 
250  str = udev_device_get_sysattr_value(dev, "idProduct");
251  if (!str)
252  {
253  Log1(PCSC_LOG_ERROR, "udev_device_get_sysattr_value() failed");
254  return NULL;
255  }
256  idProduct = strtol(str, NULL, 16);
257 
258  Log4(PCSC_LOG_DEBUG,
259  "Looking for a driver for VID: 0x%04X, PID: 0x%04X, path: %s",
260  idVendor, idProduct, devpath);
261 
262  *classdriver = NULL;
263  driver = NULL;
264  /* check if the device is supported by one driver */
265  for (i=0; i<driverSize; i++)
266  {
267  if (driverTracker[i].libraryPath != NULL &&
268  idVendor == driverTracker[i].manuID &&
269  idProduct == driverTracker[i].productID)
270  {
271  if ((driverTracker[i].CFBundleName != NULL)
272  && (0 == strcmp(driverTracker[i].CFBundleName, "CCIDCLASSDRIVER")))
273  *classdriver = &driverTracker[i];
274  else
275  /* it is not a CCID Class driver */
276  driver = &driverTracker[i];
277  }
278  }
279 
280  /* if we found a specific driver */
281  if (driver)
282  return driver;
283 
284  /* else return the Class driver (if any) */
285  return *classdriver;
286 }
287 
288 
289 static void HPAddDevice(struct udev_device *dev, struct udev_device *parent,
290  const char *devpath)
291 {
292  int i;
293  char deviceName[MAX_DEVICENAME];
294  char fullname[MAX_READERNAME];
295  struct _driverTracker *driver, *classdriver;
296  const char *sSerialNumber = NULL, *sInterfaceName = NULL;
297  LONG ret;
298  int bInterfaceNumber;
299 
300  driver = get_driver(parent, devpath, &classdriver);
301  if (NULL == driver)
302  {
303  /* not a smart card reader */
304 #ifdef DEBUG_HOTPLUG
305  Log2(PCSC_LOG_DEBUG, "%s is not a supported smart card reader",
306  devpath);
307 #endif
308  return;
309  }
310 
311  Log2(PCSC_LOG_INFO, "Adding USB device: %s", driver->readerName);
312 
313  bInterfaceNumber = atoi(udev_device_get_sysattr_value(dev,
314  "bInterfaceNumber"));
315  (void)snprintf(deviceName, sizeof(deviceName),
316  "usb:%04x/%04x:libudev:%d:%s", driver->manuID, driver->productID,
317  bInterfaceNumber, devpath);
318  deviceName[sizeof(deviceName) -1] = '\0';
319 
320  (void)pthread_mutex_lock(&usbNotifierMutex);
321 
322  /* find a free entry */
323  for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
324  {
325  if (NULL == readerTracker[i].fullName)
326  break;
327  }
328 
329  if (PCSCLITE_MAX_READERS_CONTEXTS == i)
330  {
331  Log2(PCSC_LOG_ERROR,
332  "Not enough reader entries. Already found %d readers", i);
333  (void)pthread_mutex_unlock(&usbNotifierMutex);
334  return;
335  }
336 
337 #ifdef ADD_INTERFACE_NAME
338  sInterfaceName = udev_device_get_sysattr_value(dev, "interface");
339 #endif
340 
341 #ifdef ADD_SERIAL_NUMBER
342  sSerialNumber = udev_device_get_sysattr_value(parent, "serial");
343 #endif
344 
345  /* name from the Info.plist file */
346  strlcpy(fullname, driver->readerName, sizeof(fullname));
347 
348  /* interface name from the device (if any) */
349  if (sInterfaceName)
350  {
351  strlcat(fullname, " [", sizeof(fullname));
352  strlcat(fullname, sInterfaceName, sizeof(fullname));
353  strlcat(fullname, "]", sizeof(fullname));
354  }
355 
356  /* serial number from the device (if any) */
357  if (sSerialNumber)
358  {
359  /* only add the serial number if it is not already present in the
360  * interface name */
361  if (!sInterfaceName || NULL == strstr(sInterfaceName, sSerialNumber))
362  {
363  strlcat(fullname, " (", sizeof(fullname));
364  strlcat(fullname, sSerialNumber, sizeof(fullname));
365  strlcat(fullname, ")", sizeof(fullname));
366  }
367  }
368 
369  readerTracker[i].fullName = strdup(fullname);
370  readerTracker[i].devpath = strdup(devpath);
371  readerTracker[i].status = READER_PRESENT;
372  readerTracker[i].bInterfaceNumber = bInterfaceNumber;
373 
374  ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + i,
375  driver->libraryPath, deviceName);
376  if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
377  {
378  Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
379  driver->readerName);
380 
381  if (classdriver && driver != classdriver)
382  {
383  /* the reader can also be used by the a class driver */
384  ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + i,
385  classdriver->libraryPath, deviceName);
386  if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
387  {
388  Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
389  driver->readerName);
390 
391  readerTracker[i].status = READER_FAILED;
392 
393  (void)CheckForOpenCT();
394  }
395  }
396  else
397  {
398  readerTracker[i].status = READER_FAILED;
399 
400  (void)CheckForOpenCT();
401  }
402  }
403 
404  (void)pthread_mutex_unlock(&usbNotifierMutex);
405 } /* HPAddDevice */
406 
407 
408 static void HPRescanUsbBus(struct udev *udev)
409 {
410  int i, j;
411  struct udev_enumerate *enumerate;
412  struct udev_list_entry *devices, *dev_list_entry;
413 
414  /* all reader are marked absent */
415  for (i=0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
416  readerTracker[i].status = READER_ABSENT;
417 
418  /* Create a list of the devices in the 'usb' subsystem. */
419  enumerate = udev_enumerate_new(udev);
420  udev_enumerate_add_match_subsystem(enumerate, "usb");
421  udev_enumerate_scan_devices(enumerate);
422  devices = udev_enumerate_get_list_entry(enumerate);
423 
424  /* For each item enumerated */
425  udev_list_entry_foreach(dev_list_entry, devices)
426  {
427  const char *devpath;
428  struct udev_device *dev, *parent;
429  struct _driverTracker *driver, *classdriver;
430  int newreader;
431  int bInterfaceNumber;
432  const char *interface;
433 
434  /* Get the filename of the /sys entry for the device
435  and create a udev_device object (dev) representing it */
436  devpath = udev_list_entry_get_name(dev_list_entry);
437  dev = udev_device_new_from_syspath(udev, devpath);
438 
439  /* The device pointed to by dev contains information about
440  the interface. In order to get information about the USB
441  device, get the parent device with the subsystem/devtype pair
442  of "usb"/"usb_device". This will be several levels up the
443  tree, but the function will find it.*/
444  parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb",
445  "usb_device");
446  if (!parent)
447  continue;
448 
449  devpath = udev_device_get_devnode(parent);
450  if (!devpath)
451  {
452  /* the device disapeared? */
453  Log1(PCSC_LOG_ERROR, "udev_device_get_devnode() failed");
454  continue;
455  }
456 
457  driver = get_driver(parent, devpath, &classdriver);
458  if (NULL == driver)
459  /* no driver known for this device */
460  continue;
461 
462 #ifdef DEBUG_HOTPLUG
463  Log2(PCSC_LOG_DEBUG, "Found matching USB device: %s", devpath);
464 #endif
465 
466  newreader = TRUE;
467  bInterfaceNumber = 0;
468  interface = udev_device_get_sysattr_value(dev, "bInterfaceNumber");
469  if (interface)
470  bInterfaceNumber = atoi(interface);
471 
472  /* Check if the reader is a new one */
473  for (j=0; j<PCSCLITE_MAX_READERS_CONTEXTS; j++)
474  {
475  if (readerTracker[j].devpath
476  && (strcmp(readerTracker[j].devpath, devpath) == 0)
477  && (bInterfaceNumber == readerTracker[j].bInterfaceNumber))
478  {
479  /* The reader is already known */
480  readerTracker[j].status = READER_PRESENT;
481  newreader = FALSE;
482 #ifdef DEBUG_HOTPLUG
483  Log2(PCSC_LOG_DEBUG, "Refresh USB device: %s", devpath);
484 #endif
485  break;
486  }
487  }
488 
489  /* New reader found */
490  if (newreader)
491  HPAddDevice(dev, parent, devpath);
492 
493  /* free device */
494  udev_device_unref(dev);
495  }
496 
497  /* Free the enumerator object */
498  udev_enumerate_unref(enumerate);
499 
500  pthread_mutex_lock(&usbNotifierMutex);
501  /* check if all the previously found readers are still present */
502  for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
503  {
504  if ((READER_ABSENT == readerTracker[i].status)
505  && (readerTracker[i].fullName != NULL))
506  {
507 
508  Log3(PCSC_LOG_INFO, "Removing USB device[%d]: %s", i,
509  readerTracker[i].devpath);
510 
511  RFRemoveReader(readerTracker[i].fullName,
512  PCSCLITE_HP_BASE_PORT + i);
513 
514  readerTracker[i].status = READER_ABSENT;
515  free(readerTracker[i].devpath);
516  readerTracker[i].devpath = NULL;
517  free(readerTracker[i].fullName);
518  readerTracker[i].fullName = NULL;
519 
520  }
521  }
522  pthread_mutex_unlock(&usbNotifierMutex);
523 }
524 
525 static void HPEstablishUSBNotifications(struct udev *udev)
526 {
527  struct udev_monitor *udev_monitor;
528  int r, i;
529  int fd;
530  fd_set fds;
531 
532  udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
533 
534  /* filter only the interfaces */
535  r = udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb",
536  "usb_interface");
537  if (r)
538  {
539  Log2(PCSC_LOG_ERROR, "udev_monitor_filter_add_match_subsystem_devtype() error: %d\n", r);
540  return;
541  }
542 
543  r = udev_monitor_enable_receiving(udev_monitor);
544  if (r)
545  {
546  Log2(PCSC_LOG_ERROR, "udev_monitor_enable_receiving() error: %d\n", r);
547  return;
548  }
549 
550  /* udev monitor file descriptor */
551  fd = udev_monitor_get_fd(udev_monitor);
552 
553  while (!AraKiriHotPlug)
554  {
555  struct udev_device *dev, *parent;
556  const char *action, *devpath;
557 
558 #ifdef DEBUG_HOTPLUG
559  Log0(PCSC_LOG_INFO);
560 #endif
561 
562  FD_ZERO(&fds);
563  FD_SET(fd, &fds);
564 
565  /* wait for a udev event */
566  r = select(fd+1, &fds, NULL, NULL, NULL);
567  if (r < 0)
568  {
569  Log2(PCSC_LOG_ERROR, "select(): %s", strerror(errno));
570  return;
571  }
572 
573  dev = udev_monitor_receive_device(udev_monitor);
574  if (!dev)
575  {
576  Log1(PCSC_LOG_ERROR, "udev_monitor_receive_device() error\n");
577  return;
578  }
579 
580  action = udev_device_get_action(dev);
581  if (0 == strcmp("remove", action))
582  {
583  Log1(PCSC_LOG_INFO, "Device removed");
584  HPRescanUsbBus(udev);
585  continue;
586  }
587 
588  if (strcmp("add", action))
589  continue;
590 
591  parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb",
592  "usb_device");
593  devpath = udev_device_get_devnode(parent);
594  if (!devpath)
595  {
596  /* the device disapeared? */
597  Log1(PCSC_LOG_ERROR, "udev_device_get_devnode() failed");
598  continue;
599  }
600 
601  HPAddDevice(dev, parent, devpath);
602 
603  /* free device */
604  udev_device_unref(dev);
605 
606  }
607 
608  for (i=0; i<driverSize; i++)
609  {
610  /* free strings allocated by strdup() */
611  free(driverTracker[i].bundleName);
612  free(driverTracker[i].libraryPath);
613  free(driverTracker[i].readerName);
614  }
615  free(driverTracker);
616 
617  Log1(PCSC_LOG_INFO, "Hotplug stopped");
618 } /* HPEstablishUSBNotifications */
619 
620 
621 /***
622  * Start a thread waiting for hotplug events
623  */
624 LONG HPSearchHotPluggables(void)
625 {
626  int i;
627 
628  for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
629  {
630  readerTracker[i].status = READER_ABSENT;
631  readerTracker[i].bInterfaceNumber = 0;
632  readerTracker[i].devpath = NULL;
633  readerTracker[i].fullName = NULL;
634  }
635 
636  return HPReadBundleValues();
637 } /* HPSearchHotPluggables */
638 
639 
643 LONG HPStopHotPluggables(void)
644 {
645  AraKiriHotPlug = TRUE;
646 
647  return 0;
648 } /* HPStopHotPluggables */
649 
650 
654 ULONG HPRegisterForHotplugEvents(void)
655 {
656  struct udev *udev;
657 
658  (void)pthread_mutex_init(&usbNotifierMutex, NULL);
659 
660  if (driverSize <= 0)
661  {
662  Log1(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: "
663  PCSCLITE_HP_DROPDIR);
664  Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
665  return 0;
666  }
667 
668  /* Create the udev object */
669  udev = udev_new();
670  if (!udev)
671  {
672  Log1(PCSC_LOG_ERROR, "udev_new() failed");
673  return 0;
674  }
675 
676  HPRescanUsbBus(udev);
677 
678  (void)ThreadCreate(&usbNotifyThread, THREAD_ATTR_DETACHED,
679  (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, udev);
680 
681  return 0;
682 } /* HPRegisterForHotplugEvents */
683 
684 
685 void HPReCheckSerialReaders(void)
686 {
687  /* nothing to do here */
688 #ifdef DEBUG_HOTPLUG
689  Log0(PCSC_LOG_ERROR);
690 #endif
691 } /* HPReCheckSerialReaders */
692 
693 #endif
694