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