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