pcsc-lite  1.8.2
hotplug_libusb.c
Go to the documentation of this file.
00001 /*
00002  * MUSCLE SmartCard Development ( http://www.linuxnet.com )
00003  *
00004  * Copyright (C) 2001-2004
00005  *  David Corcoran <corcoran@linuxnet.com>
00006  * Copyright (C) 2003-2011
00007  *  Ludovic Rousseau <ludovic.rousseau@free.fr>
00008  * Copyright (C) 2003
00009  *  Toni Andjelkovic <toni@soth.at>
00010  * Copyright (C) 2003-2004
00011  *  Damien Sauveron <damien.sauveron@labri.fr>
00012  *
00013  * $Id: hotplug_libusb.c 5938 2011-09-03 21:43:53Z rousseau $
00014  */
00015 
00021 #include "config.h"
00022 #ifdef HAVE_LIBUSB
00023 
00024 #include <string.h>
00025 #include <sys/types.h>
00026 #include <stdio.h>
00027 #include <dirent.h>
00028 #include <fcntl.h>
00029 #include <time.h>
00030 #include <stdlib.h>
00031 #include <unistd.h>
00032 #include <errno.h>
00033 #include <libusb.h>
00034 #include <pthread.h>
00035 #include <signal.h>
00036 
00037 #include "misc.h"
00038 #include "wintypes.h"
00039 #include "pcscd.h"
00040 #include "debuglog.h"
00041 #include "parser.h"
00042 #include "readerfactory.h"
00043 #include "winscard_msg.h"
00044 #include "sys_generic.h"
00045 #include "hotplug.h"
00046 #include "utils.h"
00047 
00048 #undef DEBUG_HOTPLUG
00049 #define ADD_SERIAL_NUMBER
00050 
00051 /* format is "%d:%d:%d", bus_number, device_address, interface */
00052 #define BUS_DEVICE_STRSIZE  10+1+10+1+10+1
00053 
00054 #define READER_ABSENT       0
00055 #define READER_PRESENT      1
00056 #define READER_FAILED       2
00057 
00058 #define FALSE           0
00059 #define TRUE            1
00060 
00061 /* we use the default libusb context */
00062 #define ctx NULL
00063 
00064 pthread_mutex_t usbNotifierMutex;
00065 
00066 static pthread_t usbNotifyThread;
00067 static int driverSize = -1;
00068 static char AraKiriHotPlug = FALSE;
00069 static int rescan_pipe[] = { -1, -1 };
00070 extern int HPForceReaderPolling;
00071 
00072 /* values of ifdCapabilities bits */
00073 #define IFD_GENERATE_HOTPLUG 1
00074 
00078 static struct _driverTracker
00079 {
00080     unsigned int manuID;
00081     unsigned int productID;
00082 
00083     char *bundleName;
00084     char *libraryPath;
00085     char *readerName;
00086     int ifdCapabilities;
00087 } *driverTracker = NULL;
00088 #define DRIVER_TRACKER_SIZE_STEP 8
00089 
00093 static struct _readerTracker
00094 {
00095     char status;
00096     char bus_device[BUS_DEVICE_STRSIZE];    
00097     char *fullName; 
00098 } readerTracker[PCSCLITE_MAX_READERS_CONTEXTS];
00099 
00100 static LONG HPAddHotPluggable(struct libusb_device *dev,
00101     struct libusb_device_descriptor desc,
00102     const char bus_device[], int interface,
00103     struct _driverTracker *driver);
00104 static LONG HPRemoveHotPluggable(int reader_index);
00105 
00106 static LONG HPReadBundleValues(void)
00107 {
00108     LONG rv;
00109     DIR *hpDir;
00110     struct dirent *currFP = NULL;
00111     char fullPath[FILENAME_MAX];
00112     char fullLibPath[FILENAME_MAX];
00113     int listCount = 0;
00114 
00115     hpDir = opendir(PCSCLITE_HP_DROPDIR);
00116 
00117     if (hpDir == NULL)
00118     {
00119         Log1(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: " PCSCLITE_HP_DROPDIR);
00120         Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd.");
00121         return -1;
00122     }
00123 
00124     /* allocate a first array */
00125     driverTracker = calloc(DRIVER_TRACKER_SIZE_STEP, sizeof(*driverTracker));
00126     if (NULL == driverTracker)
00127     {
00128         Log1(PCSC_LOG_CRITICAL, "Not enough memory");
00129         return -1;
00130     }
00131     driverSize = DRIVER_TRACKER_SIZE_STEP;
00132 
00133 #define GET_KEY(key, values) \
00134     rv = LTPBundleFindValueWithKey(&plist, key, values); \
00135     if (rv) \
00136     { \
00137         Log2(PCSC_LOG_ERROR, "Value/Key not defined for " key " in %s", \
00138             fullPath); \
00139         continue; \
00140     }
00141 
00142     while ((currFP = readdir(hpDir)) != 0)
00143     {
00144         if (strstr(currFP->d_name, ".bundle") != 0)
00145         {
00146             unsigned int alias;
00147             list_t plist, *values;
00148             list_t *manuIDs, *productIDs, *readerNames;
00149             char *libraryPath;
00150             int ifdCapabilities;
00151 
00152             /*
00153              * The bundle exists - let's form a full path name and get the
00154              * vendor and product ID's for this particular bundle
00155              */
00156             snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist",
00157                 PCSCLITE_HP_DROPDIR, currFP->d_name);
00158             fullPath[sizeof(fullPath) - 1] = '\0';
00159 
00160             rv = bundleParse(fullPath, &plist);
00161             if (rv)
00162                 continue;
00163 
00164             /* get CFBundleExecutable */
00165             GET_KEY(PCSCLITE_HP_LIBRKEY_NAME, &values)
00166             libraryPath = list_get_at(values, 0);
00167             (void)snprintf(fullLibPath, sizeof(fullLibPath),
00168                 "%s/%s/Contents/%s/%s",
00169                 PCSCLITE_HP_DROPDIR, currFP->d_name, PCSC_ARCH,
00170                 libraryPath);
00171             fullLibPath[sizeof(fullLibPath) - 1] = '\0';
00172 
00173             /* Get ifdCapabilities */
00174             GET_KEY(PCSCLITE_HP_CPCTKEY_NAME, &values)
00175             ifdCapabilities = strtol(list_get_at(values, 0), NULL, 16);
00176 
00177             GET_KEY(PCSCLITE_HP_MANUKEY_NAME, &manuIDs)
00178             GET_KEY(PCSCLITE_HP_PRODKEY_NAME, &productIDs)
00179             GET_KEY(PCSCLITE_HP_NAMEKEY_NAME, &readerNames)
00180 
00181             /* while we find a nth ifdVendorID in Info.plist */
00182             for (alias=0; alias<list_size(manuIDs); alias++)
00183             {
00184                 char *value;
00185 
00186                 /* variables entries */
00187                 value = list_get_at(manuIDs, alias);
00188                 driverTracker[listCount].manuID = strtol(value, NULL, 16);
00189 
00190                 value = list_get_at(productIDs, alias);
00191                 driverTracker[listCount].productID = strtol(value, NULL, 16);
00192 
00193                 driverTracker[listCount].readerName = strdup(list_get_at(readerNames, alias));
00194 
00195                 /* constant entries for a same driver */
00196                 driverTracker[listCount].bundleName = strdup(currFP->d_name);
00197                 driverTracker[listCount].libraryPath = strdup(fullLibPath);
00198                 driverTracker[listCount].ifdCapabilities = ifdCapabilities;
00199 
00200 #ifdef DEBUG_HOTPLUG
00201                 Log2(PCSC_LOG_INFO, "Found driver for: %s",
00202                     driverTracker[listCount].readerName);
00203 #endif
00204                 listCount++;
00205                 if (listCount >= driverSize)
00206                 {
00207                     int i;
00208 
00209                     /* increase the array size */
00210                     driverSize += DRIVER_TRACKER_SIZE_STEP;
00211 #ifdef DEBUG_HOTPLUG
00212                     Log2(PCSC_LOG_INFO,
00213                         "Increase driverTracker to %d entries", driverSize);
00214 #endif
00215                     driverTracker = realloc(driverTracker,
00216                         driverSize * sizeof(*driverTracker));
00217                     if (NULL == driverTracker)
00218                     {
00219                         Log1(PCSC_LOG_CRITICAL, "Not enough memory");
00220                         driverSize = -1;
00221                         closedir(hpDir);
00222                         return -1;
00223                     }
00224 
00225                     /* clean the newly allocated entries */
00226                     for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++)
00227                     {
00228                         driverTracker[i].manuID = 0;
00229                         driverTracker[i].productID = 0;
00230                         driverTracker[i].bundleName = NULL;
00231                         driverTracker[i].libraryPath = NULL;
00232                         driverTracker[i].readerName = NULL;
00233                         driverTracker[i].ifdCapabilities = 0;
00234                     }
00235                 }
00236             }
00237             bundleRelease(&plist);
00238         }
00239     }
00240 
00241     driverSize = listCount;
00242     closedir(hpDir);
00243 
00244     rv = TRUE;
00245     if (driverSize == 0)
00246     {
00247         Log1(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: " PCSCLITE_HP_DROPDIR);
00248         Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
00249         rv = FALSE;
00250     }
00251 #ifdef DEBUG_HOTPLUG
00252     else
00253         Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount);
00254 #endif
00255 
00256     return rv;
00257 }
00258 
00259 static void HPRescanUsbBus(void)
00260 {
00261     int i, j;
00262     char bus_device[BUS_DEVICE_STRSIZE];
00263     libusb_device **devs, *dev;
00264     ssize_t cnt;
00265 
00266     for (i=0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
00267         /* clear rollcall */
00268         readerTracker[i].status = READER_ABSENT;
00269 
00270     cnt = libusb_get_device_list(ctx, &devs);
00271     if (cnt < 0)
00272     {
00273         Log1(PCSC_LOG_CRITICAL, "libusb_get_device_list() failed\n");
00274         return;
00275     }
00276 
00277     /* For each USB device */
00278     cnt = 0;
00279     while ((dev = devs[cnt++]) != NULL)
00280     {
00281         struct libusb_device_descriptor desc;
00282         struct libusb_config_descriptor *config_desc;
00283         uint8_t bus_number = libusb_get_bus_number(dev);
00284         uint8_t device_address = libusb_get_device_address(dev);
00285 
00286         int r = libusb_get_device_descriptor(dev, &desc);
00287         if (r < 0)
00288         {
00289             Log3(PCSC_LOG_ERROR, "failed to get device descriptor for %d/%d",
00290                 bus_number, device_address);
00291             continue;
00292         }
00293 
00294         r = libusb_get_active_config_descriptor(dev, &config_desc);
00295         if (r < 0)
00296         {
00297             Log3(PCSC_LOG_ERROR, "failed to get device config for %d/%d",
00298                 bus_number, device_address);
00299             continue;
00300         }
00301 
00302         /* check if the device is supported by one driver */
00303         for (i=0; i<driverSize; i++)
00304         {
00305             if (driverTracker[i].libraryPath != NULL &&
00306                 desc.idVendor == driverTracker[i].manuID &&
00307                 desc.idProduct == driverTracker[i].productID)
00308             {
00309                 int interface;
00310 
00311 #ifdef DEBUG_HOTPLUG
00312                 Log3(PCSC_LOG_DEBUG, "Found matching USB device: %d:%d",
00313                     bus_number, device_address);
00314 #endif
00315 
00316                 for (interface = 0; interface < config_desc->bNumInterfaces;
00317                     interface++)
00318                 {
00319                     int newreader;
00320 
00321                     /* A known device has been found */
00322                     snprintf(bus_device, BUS_DEVICE_STRSIZE, "%d:%d:%d",
00323                          bus_number, device_address, interface);
00324                     bus_device[BUS_DEVICE_STRSIZE - 1] = '\0';
00325                     newreader = TRUE;
00326 
00327                     /* Check if the reader is a new one */
00328                     for (j=0; j<PCSCLITE_MAX_READERS_CONTEXTS; j++)
00329                     {
00330                         if (strncmp(readerTracker[j].bus_device,
00331                             bus_device, BUS_DEVICE_STRSIZE) == 0)
00332                         {
00333                             /* The reader is already known */
00334                             readerTracker[j].status = READER_PRESENT;
00335                             newreader = FALSE;
00336 #ifdef DEBUG_HOTPLUG
00337                             Log2(PCSC_LOG_DEBUG, "Refresh USB device: %s",
00338                                 bus_device);
00339 #endif
00340                             break;
00341                         }
00342                     }
00343 
00344                     /* New reader found */
00345                     if (newreader)
00346                     {
00347                         if (config_desc->bNumInterfaces > 1)
00348                             HPAddHotPluggable(dev, desc, bus_device,
00349                                 interface, &driverTracker[i]);
00350                             else
00351                             HPAddHotPluggable(dev, desc, bus_device,
00352                                 -1, &driverTracker[i]);
00353                     }
00354                 }
00355             }
00356         }
00357         libusb_free_config_descriptor(config_desc);
00358     }
00359 
00360     /*
00361      * check if all the previously found readers are still present
00362      */
00363     for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00364     {
00365         if ((readerTracker[i].status == READER_ABSENT) &&
00366             (readerTracker[i].fullName != NULL))
00367             HPRemoveHotPluggable(i);
00368     }
00369 
00370     if (AraKiriHotPlug)
00371     {
00372         int retval;
00373 
00374         for (i=0; i<driverSize; i++)
00375         {
00376             /* free strings allocated by strdup() */
00377             free(driverTracker[i].bundleName);
00378             free(driverTracker[i].libraryPath);
00379             free(driverTracker[i].readerName);
00380         }
00381         free(driverTracker);
00382 
00383         Log1(PCSC_LOG_INFO, "Hotplug stopped");
00384         pthread_exit(&retval);
00385     }
00386 
00387     /* free the libusb allocated list & devices */
00388     libusb_free_device_list(devs, 1);
00389 }
00390 
00391 static void HPEstablishUSBNotifications(int pipefd[2])
00392 {
00393     int i, do_polling;
00394     int r;
00395     char c = 42;    /* magic value */
00396 
00397     r = libusb_init(ctx);
00398     if (r < 0)
00399     {
00400         Log2(PCSC_LOG_CRITICAL, "libusb_init failed: %d", r);
00401         /* emergency exit */
00402         kill(getpid(), SIGTERM);
00403         return;
00404     }
00405 
00406     /* scan the USB bus for devices at startup */
00407     HPRescanUsbBus();
00408 
00409     /* signal that the initially connected readers are now visible */
00410     write(pipefd[1], &c, 1);
00411     close(pipefd[1]);
00412 
00413     /* if at least one driver do not have IFD_GENERATE_HOTPLUG */
00414     do_polling = FALSE;
00415     for (i=0; i<driverSize; i++)
00416         if (driverTracker[i].libraryPath)
00417             if ((driverTracker[i].ifdCapabilities & IFD_GENERATE_HOTPLUG) == 0)
00418             {
00419                 Log2(PCSC_LOG_INFO,
00420                     "Driver %s does not support IFD_GENERATE_HOTPLUG. Using active polling instead.",
00421                     driverTracker[i].bundleName);
00422                 if (HPForceReaderPolling < 1)
00423                     HPForceReaderPolling = 1;
00424                 break;
00425             }
00426 
00427     if (HPForceReaderPolling)
00428     {
00429         Log2(PCSC_LOG_INFO,
00430                 "Polling forced every %d second(s)", HPForceReaderPolling);
00431         do_polling = TRUE;
00432     }
00433 
00434     if (do_polling)
00435     {
00436         while (!AraKiriHotPlug)
00437         {
00438             SYS_Sleep(HPForceReaderPolling);
00439             HPRescanUsbBus();
00440         }
00441     }
00442     else
00443     {
00444         char dummy;
00445 
00446         pipe(rescan_pipe);
00447         while (read(rescan_pipe[0], &dummy, sizeof(dummy)) > 0)
00448         {
00449             Log1(PCSC_LOG_INFO, "Reload serial configuration");
00450             HPRescanUsbBus();
00451 #ifdef USE_SERIAL
00452             RFReCheckReaderConf();
00453 #endif
00454             Log1(PCSC_LOG_INFO, "End reload serial configuration");
00455         }
00456         close(rescan_pipe[0]);
00457         rescan_pipe[0] = -1;
00458     }
00459 }
00460 
00461 LONG HPSearchHotPluggables(void)
00462 {
00463     int i;
00464 
00465     for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00466     {
00467         readerTracker[i].status = READER_ABSENT;
00468         readerTracker[i].bus_device[0] = '\0';
00469         readerTracker[i].fullName = NULL;
00470     }
00471 
00472     if (HPReadBundleValues())
00473     {
00474         int pipefd[2];
00475         char c;
00476 
00477         if (pipe(pipefd) == -1)
00478         {
00479             Log2(PCSC_LOG_ERROR, "pipe: %s", strerror(errno));
00480             return -1;
00481         }
00482 
00483         ThreadCreate(&usbNotifyThread, THREAD_ATTR_DETACHED,
00484             (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, pipefd);
00485 
00486         /* Wait for initial readers to setup */
00487         read(pipefd[0], &c, 1);
00488         close(pipefd[0]);
00489     }
00490 
00491     return 0;
00492 }
00493 
00494 LONG HPStopHotPluggables(void)
00495 {
00496     AraKiriHotPlug = TRUE;
00497     if (rescan_pipe[1] >= 0)
00498     {
00499         close(rescan_pipe[1]);
00500         rescan_pipe[1] = -1;
00501     }
00502 
00503     return 0;
00504 }
00505 
00506 static LONG HPAddHotPluggable(struct libusb_device *dev,
00507     struct libusb_device_descriptor desc,
00508     const char bus_device[], int interface,
00509     struct _driverTracker *driver)
00510 {
00511     int i;
00512     char deviceName[MAX_DEVICENAME];
00513 
00514     Log2(PCSC_LOG_INFO, "Adding USB device: %s", bus_device);
00515 
00516     if (interface >= 0)
00517         snprintf(deviceName, sizeof(deviceName), "usb:%04x/%04x:libhal:/org/freedesktop/Hal/devices/usb_device_%04x_%04x_serialnotneeded_if%d",
00518              desc.idVendor, desc.idProduct, desc.idVendor, desc.idProduct,
00519              interface);
00520     else
00521         snprintf(deviceName, sizeof(deviceName), "usb:%04x/%04x:libusb-1.0:%s",
00522             desc.idVendor, desc.idProduct, bus_device);
00523 
00524     deviceName[sizeof(deviceName) -1] = '\0';
00525 
00526     pthread_mutex_lock(&usbNotifierMutex);
00527 
00528     /* find a free entry */
00529     for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00530     {
00531         if (readerTracker[i].fullName == NULL)
00532             break;
00533     }
00534 
00535     if (i==PCSCLITE_MAX_READERS_CONTEXTS)
00536     {
00537         Log2(PCSC_LOG_ERROR,
00538             "Not enough reader entries. Already found %d readers", i);
00539         pthread_mutex_unlock(&usbNotifierMutex);
00540         return 0;
00541     }
00542 
00543     strncpy(readerTracker[i].bus_device, bus_device,
00544         sizeof(readerTracker[i].bus_device));
00545     readerTracker[i].bus_device[sizeof(readerTracker[i].bus_device) - 1] = '\0';
00546 
00547 #ifdef ADD_SERIAL_NUMBER
00548     if (desc.iSerialNumber)
00549     {
00550         libusb_device_handle *device;
00551         unsigned char serialNumber[MAX_READERNAME];
00552         char fullname[MAX_READERNAME];
00553         int ret;
00554 
00555         ret = libusb_open(dev, &device);
00556         if (ret < 0)
00557         {
00558             Log2(PCSC_LOG_ERROR, "libusb_open failed: %d", ret);
00559         }
00560         else
00561         {
00562             ret = libusb_get_string_descriptor_ascii(device, desc.iSerialNumber,
00563                 serialNumber, MAX_READERNAME);
00564             libusb_close(device);
00565 
00566             if (ret < 0)
00567             {
00568                 Log2(PCSC_LOG_ERROR,
00569                     "libusb_get_string_descriptor_ascii failed: %d", ret);
00570                 readerTracker[i].fullName = strdup(driver->readerName);
00571             }
00572             else
00573             {
00574                 snprintf(fullname, sizeof(fullname), "%s (%s)",
00575                     driver->readerName, serialNumber);
00576                 readerTracker[i].fullName = strdup(fullname);
00577             }
00578         }
00579     }
00580     else
00581 #endif
00582         readerTracker[i].fullName = strdup(driver->readerName);
00583 
00584     if (RFAddReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i,
00585         driver->libraryPath, deviceName) == SCARD_S_SUCCESS)
00586         readerTracker[i].status = READER_PRESENT;
00587     else
00588     {
00589         readerTracker[i].status = READER_FAILED;
00590 
00591         (void)CheckForOpenCT();
00592     }
00593 
00594     pthread_mutex_unlock(&usbNotifierMutex);
00595 
00596     return 1;
00597 }   /* End of function */
00598 
00599 static LONG HPRemoveHotPluggable(int reader_index)
00600 {
00601     pthread_mutex_lock(&usbNotifierMutex);
00602 
00603     Log3(PCSC_LOG_INFO, "Removing USB device[%d]: %s", reader_index,
00604         readerTracker[reader_index].bus_device);
00605 
00606     RFRemoveReader(readerTracker[reader_index].fullName,
00607         PCSCLITE_HP_BASE_PORT + reader_index);
00608     free(readerTracker[reader_index].fullName);
00609     readerTracker[reader_index].status = READER_ABSENT;
00610     readerTracker[reader_index].bus_device[0] = '\0';
00611     readerTracker[reader_index].fullName = NULL;
00612 
00613     pthread_mutex_unlock(&usbNotifierMutex);
00614 
00615     return 1;
00616 }   /* End of function */
00617 
00621 ULONG HPRegisterForHotplugEvents(void)
00622 {
00623     (void)pthread_mutex_init(&usbNotifierMutex, NULL);
00624     return 0;
00625 }
00626 
00627 void HPReCheckSerialReaders(void)
00628 {
00629     Log0(PCSC_LOG_INFO);
00630     if (rescan_pipe[1] >= 0)
00631     {
00632         char dummy = 0;
00633         write(rescan_pipe[1], &dummy, sizeof(dummy));
00634     }
00635 }
00636 
00637 #endif
00638