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