pcsc-lite  1.8.8
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 6380 2012-06-29 14:18:31Z 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  const char *sInterfaceNumber;
298  LONG ret;
299  int bInterfaceNumber;
300 
301  driver = get_driver(parent, devpath, &classdriver);
302  if (NULL == driver)
303  {
304  /* not a smart card reader */
305 #ifdef DEBUG_HOTPLUG
306  Log2(PCSC_LOG_DEBUG, "%s is not a supported smart card reader",
307  devpath);
308 #endif
309  return;
310  }
311 
312  Log2(PCSC_LOG_INFO, "Adding USB device: %s", driver->readerName);
313 
314  sInterfaceNumber = udev_device_get_sysattr_value(dev, "bInterfaceNumber");
315  if (sInterfaceNumber)
316  bInterfaceNumber = atoi(sInterfaceNumber);
317  else
318  bInterfaceNumber = 0;
319 
320  (void)snprintf(deviceName, sizeof(deviceName),
321  "usb:%04x/%04x:libudev:%d:%s", driver->manuID, driver->productID,
322  bInterfaceNumber, devpath);
323  deviceName[sizeof(deviceName) -1] = '\0';
324 
325  (void)pthread_mutex_lock(&usbNotifierMutex);
326 
327  /* find a free entry */
328  for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
329  {
330  if (NULL == readerTracker[i].fullName)
331  break;
332  }
333 
334  if (PCSCLITE_MAX_READERS_CONTEXTS == i)
335  {
336  Log2(PCSC_LOG_ERROR,
337  "Not enough reader entries. Already found %d readers", i);
338  (void)pthread_mutex_unlock(&usbNotifierMutex);
339  return;
340  }
341 
342 #ifdef ADD_INTERFACE_NAME
343  sInterfaceName = udev_device_get_sysattr_value(dev, "interface");
344 #endif
345 
346 #ifdef ADD_SERIAL_NUMBER
347  sSerialNumber = udev_device_get_sysattr_value(parent, "serial");
348 #endif
349 
350  /* name from the Info.plist file */
351  strlcpy(fullname, driver->readerName, sizeof(fullname));
352 
353  /* interface name from the device (if any) */
354  if (sInterfaceName)
355  {
356  strlcat(fullname, " [", sizeof(fullname));
357  strlcat(fullname, sInterfaceName, sizeof(fullname));
358  strlcat(fullname, "]", sizeof(fullname));
359  }
360 
361  /* serial number from the device (if any) */
362  if (sSerialNumber)
363  {
364  /* only add the serial number if it is not already present in the
365  * interface name */
366  if (!sInterfaceName || NULL == strstr(sInterfaceName, sSerialNumber))
367  {
368  strlcat(fullname, " (", sizeof(fullname));
369  strlcat(fullname, sSerialNumber, sizeof(fullname));
370  strlcat(fullname, ")", sizeof(fullname));
371  }
372  }
373 
374  readerTracker[i].fullName = strdup(fullname);
375  readerTracker[i].devpath = strdup(devpath);
376  readerTracker[i].status = READER_PRESENT;
377  readerTracker[i].bInterfaceNumber = bInterfaceNumber;
378 
379  ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + i,
380  driver->libraryPath, deviceName);
381  if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
382  {
383  Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
384  driver->readerName);
385 
386  if (classdriver && driver != classdriver)
387  {
388  /* the reader can also be used by the a class driver */
389  ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + i,
390  classdriver->libraryPath, deviceName);
391  if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
392  {
393  Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
394  driver->readerName);
395 
396  readerTracker[i].status = READER_FAILED;
397 
398  (void)CheckForOpenCT();
399  }
400  }
401  else
402  {
403  readerTracker[i].status = READER_FAILED;
404 
405  (void)CheckForOpenCT();
406  }
407  }
408 
409  (void)pthread_mutex_unlock(&usbNotifierMutex);
410 } /* HPAddDevice */
411 
412 
413 static void HPRescanUsbBus(struct udev *udev)
414 {
415  int i, j;
416  struct udev_enumerate *enumerate;
417  struct udev_list_entry *devices, *dev_list_entry;
418 
419  /* all reader are marked absent */
420  for (i=0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
421  readerTracker[i].status = READER_ABSENT;
422 
423  /* Create a list of the devices in the 'usb' subsystem. */
424  enumerate = udev_enumerate_new(udev);
425  udev_enumerate_add_match_subsystem(enumerate, "usb");
426  udev_enumerate_scan_devices(enumerate);
427  devices = udev_enumerate_get_list_entry(enumerate);
428 
429  /* For each item enumerated */
430  udev_list_entry_foreach(dev_list_entry, devices)
431  {
432  const char *devpath;
433  struct udev_device *dev, *parent;
434  struct _driverTracker *driver, *classdriver;
435  int newreader;
436  int bInterfaceNumber;
437  const char *interface;
438 
439  /* Get the filename of the /sys entry for the device
440  and create a udev_device object (dev) representing it */
441  devpath = udev_list_entry_get_name(dev_list_entry);
442  dev = udev_device_new_from_syspath(udev, devpath);
443 
444  /* The device pointed to by dev contains information about
445  the interface. In order to get information about the USB
446  device, get the parent device with the subsystem/devtype pair
447  of "usb"/"usb_device". This will be several levels up the
448  tree, but the function will find it.*/
449  parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb",
450  "usb_device");
451  if (!parent)
452  continue;
453 
454  devpath = udev_device_get_devnode(parent);
455  if (!devpath)
456  {
457  /* the device disapeared? */
458  Log1(PCSC_LOG_ERROR, "udev_device_get_devnode() failed");
459  continue;
460  }
461 
462  driver = get_driver(parent, devpath, &classdriver);
463  if (NULL == driver)
464  /* no driver known for this device */
465  continue;
466 
467 #ifdef DEBUG_HOTPLUG
468  Log2(PCSC_LOG_DEBUG, "Found matching USB device: %s", devpath);
469 #endif
470 
471  newreader = TRUE;
472  bInterfaceNumber = 0;
473  interface = udev_device_get_sysattr_value(dev, "bInterfaceNumber");
474  if (interface)
475  bInterfaceNumber = atoi(interface);
476 
477  /* Check if the reader is a new one */
478  for (j=0; j<PCSCLITE_MAX_READERS_CONTEXTS; j++)
479  {
480  if (readerTracker[j].devpath
481  && (strcmp(readerTracker[j].devpath, devpath) == 0)
482  && (bInterfaceNumber == readerTracker[j].bInterfaceNumber))
483  {
484  /* The reader is already known */
485  readerTracker[j].status = READER_PRESENT;
486  newreader = FALSE;
487 #ifdef DEBUG_HOTPLUG
488  Log2(PCSC_LOG_DEBUG, "Refresh USB device: %s", devpath);
489 #endif
490  break;
491  }
492  }
493 
494  /* New reader found */
495  if (newreader)
496  HPAddDevice(dev, parent, devpath);
497 
498  /* free device */
499  udev_device_unref(dev);
500  }
501 
502  /* Free the enumerator object */
503  udev_enumerate_unref(enumerate);
504 
505  pthread_mutex_lock(&usbNotifierMutex);
506  /* check if all the previously found readers are still present */
507  for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
508  {
509  if ((READER_ABSENT == readerTracker[i].status)
510  && (readerTracker[i].fullName != NULL))
511  {
512  Log4(PCSC_LOG_INFO, "Removing USB device[%d]: %s at %s", i,
513  readerTracker[i].fullName, readerTracker[i].devpath);
514 
515  RFRemoveReader(readerTracker[i].fullName,
516  PCSCLITE_HP_BASE_PORT + i);
517 
518  readerTracker[i].status = READER_ABSENT;
519  free(readerTracker[i].devpath);
520  readerTracker[i].devpath = NULL;
521  free(readerTracker[i].fullName);
522  readerTracker[i].fullName = NULL;
523 
524  }
525  }
526  pthread_mutex_unlock(&usbNotifierMutex);
527 }
528 
529 static void HPEstablishUSBNotifications(struct udev *udev)
530 {
531  struct udev_monitor *udev_monitor;
532  int r, i;
533  int fd;
534  fd_set fds;
535 
536  udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
537 
538  /* filter only the interfaces */
539  r = udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb",
540  "usb_interface");
541  if (r)
542  {
543  Log2(PCSC_LOG_ERROR, "udev_monitor_filter_add_match_subsystem_devtype() error: %d\n", r);
544  return;
545  }
546 
547  r = udev_monitor_enable_receiving(udev_monitor);
548  if (r)
549  {
550  Log2(PCSC_LOG_ERROR, "udev_monitor_enable_receiving() error: %d\n", r);
551  return;
552  }
553 
554  /* udev monitor file descriptor */
555  fd = udev_monitor_get_fd(udev_monitor);
556 
557  while (!AraKiriHotPlug)
558  {
559  struct udev_device *dev, *parent;
560  const char *action, *devpath;
561 
562 #ifdef DEBUG_HOTPLUG
563  Log0(PCSC_LOG_INFO);
564 #endif
565 
566  FD_ZERO(&fds);
567  FD_SET(fd, &fds);
568 
569  /* wait for a udev event */
570  r = select(fd+1, &fds, NULL, NULL, NULL);
571  if (r < 0)
572  {
573  Log2(PCSC_LOG_ERROR, "select(): %s", strerror(errno));
574  return;
575  }
576 
577  dev = udev_monitor_receive_device(udev_monitor);
578  if (!dev)
579  {
580  Log1(PCSC_LOG_ERROR, "udev_monitor_receive_device() error\n");
581  return;
582  }
583 
584  action = udev_device_get_action(dev);
585  if (0 == strcmp("remove", action))
586  {
587  Log1(PCSC_LOG_INFO, "Device removed");
588  HPRescanUsbBus(udev);
589  continue;
590  }
591 
592  if (strcmp("add", action))
593  continue;
594 
595  parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb",
596  "usb_device");
597  devpath = udev_device_get_devnode(parent);
598  if (!devpath)
599  {
600  /* the device disapeared? */
601  Log1(PCSC_LOG_ERROR, "udev_device_get_devnode() failed");
602  continue;
603  }
604 
605  HPAddDevice(dev, parent, devpath);
606 
607  /* free device */
608  udev_device_unref(dev);
609 
610  }
611 
612  for (i=0; i<driverSize; i++)
613  {
614  /* free strings allocated by strdup() */
615  free(driverTracker[i].bundleName);
616  free(driverTracker[i].libraryPath);
617  free(driverTracker[i].readerName);
618  }
619  free(driverTracker);
620 
621  Log1(PCSC_LOG_INFO, "Hotplug stopped");
622 } /* HPEstablishUSBNotifications */
623 
624 
625 /***
626  * Start a thread waiting for hotplug events
627  */
628 LONG HPSearchHotPluggables(void)
629 {
630  int i;
631 
632  for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
633  {
634  readerTracker[i].status = READER_ABSENT;
635  readerTracker[i].bInterfaceNumber = 0;
636  readerTracker[i].devpath = NULL;
637  readerTracker[i].fullName = NULL;
638  }
639 
640  return HPReadBundleValues();
641 } /* HPSearchHotPluggables */
642 
643 
647 LONG HPStopHotPluggables(void)
648 {
649  AraKiriHotPlug = TRUE;
650 
651  return 0;
652 } /* HPStopHotPluggables */
653 
654 
658 ULONG HPRegisterForHotplugEvents(void)
659 {
660  struct udev *udev;
661 
662  (void)pthread_mutex_init(&usbNotifierMutex, NULL);
663 
664  if (driverSize <= 0)
665  {
666  Log1(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: "
667  PCSCLITE_HP_DROPDIR);
668  Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
669  return 0;
670  }
671 
672  /* Create the udev object */
673  udev = udev_new();
674  if (!udev)
675  {
676  Log1(PCSC_LOG_ERROR, "udev_new() failed");
677  return 0;
678  }
679 
680  HPRescanUsbBus(udev);
681 
682  (void)ThreadCreate(&usbNotifyThread, THREAD_ATTR_DETACHED,
683  (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, udev);
684 
685  return 0;
686 } /* HPRegisterForHotplugEvents */
687 
688 
689 void HPReCheckSerialReaders(void)
690 {
691  /* nothing to do here */
692 #ifdef DEBUG_HOTPLUG
693  Log0(PCSC_LOG_ERROR);
694 #endif
695 } /* HPReCheckSerialReaders */
696 
697 #endif
698 
list object
Definition: simclist.h:181
This handles abstract system level calls.
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
prototypes of strlcpy()/strlcat() imported from OpenBSD
int LTPBundleFindValueWithKey(list_t *l, const char *key, list_t **values)
Find an optional key in a configuration file No error is logged if the key is not found...
Definition: tokenparser.c:1905
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_E_UNKNOWN_READER
The specified reader name is not recognized.
Definition: pcsclite.h:89
#define SCARD_S_SUCCESS
error codes from http://msdn.microsoft.com/en-us/library/aa924526.aspx
Definition: pcsclite.h:80
This handles debugging.