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