pcsc-lite
1.7.4
|
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 5711 2011-05-05 09:02:08Z 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 libusb_free_config_descriptor(config_desc); 00356 } 00357 00358 /* 00359 * check if all the previously found readers are still present 00360 */ 00361 for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++) 00362 { 00363 if ((readerTracker[i].status == READER_ABSENT) && 00364 (readerTracker[i].fullName != NULL)) 00365 HPRemoveHotPluggable(i); 00366 } 00367 00368 if (AraKiriHotPlug) 00369 { 00370 int retval; 00371 00372 for (i=0; i<driverSize; i++) 00373 { 00374 /* free strings allocated by strdup() */ 00375 free(driverTracker[i].bundleName); 00376 free(driverTracker[i].libraryPath); 00377 free(driverTracker[i].readerName); 00378 } 00379 free(driverTracker); 00380 00381 Log1(PCSC_LOG_INFO, "Hotplug stopped"); 00382 pthread_exit(&retval); 00383 } 00384 00385 /* free the libusb allocated list & devices */ 00386 libusb_free_device_list(devs, 1); 00387 } 00388 00389 static void HPEstablishUSBNotifications(int pipefd[2]) 00390 { 00391 int i, do_polling; 00392 char c = 42; /* magic value */ 00393 00394 libusb_init(ctx); 00395 00396 /* scan the USB bus for devices at startup */ 00397 HPRescanUsbBus(); 00398 00399 /* signal that the initially connected readers are now visible */ 00400 write(pipefd[1], &c, 1); 00401 close(pipefd[1]); 00402 00403 /* if at least one driver do not have IFD_GENERATE_HOTPLUG */ 00404 do_polling = FALSE; 00405 for (i=0; i<driverSize; i++) 00406 if (driverTracker[i].libraryPath) 00407 if ((driverTracker[i].ifdCapabilities & IFD_GENERATE_HOTPLUG) == 0) 00408 { 00409 Log2(PCSC_LOG_INFO, 00410 "Driver %s does not support IFD_GENERATE_HOTPLUG. Using active polling instead.", 00411 driverTracker[i].bundleName); 00412 if (HPForceReaderPolling < 1) 00413 HPForceReaderPolling = 1; 00414 break; 00415 } 00416 00417 if (HPForceReaderPolling) 00418 { 00419 Log2(PCSC_LOG_INFO, 00420 "Polling forced every %d second(s)", HPForceReaderPolling); 00421 do_polling = TRUE; 00422 } 00423 00424 if (do_polling) 00425 { 00426 while (!AraKiriHotPlug) 00427 { 00428 SYS_Sleep(HPForceReaderPolling); 00429 HPRescanUsbBus(); 00430 } 00431 } 00432 else 00433 { 00434 char dummy; 00435 00436 pipe(rescan_pipe); 00437 while (read(rescan_pipe[0], &dummy, sizeof(dummy)) > 0) 00438 { 00439 Log1(PCSC_LOG_INFO, "Reload serial configuration"); 00440 HPRescanUsbBus(); 00441 #ifdef USE_SERIAL 00442 RFReCheckReaderConf(); 00443 #endif 00444 Log1(PCSC_LOG_INFO, "End reload serial configuration"); 00445 } 00446 close(rescan_pipe[0]); 00447 rescan_pipe[0] = -1; 00448 } 00449 } 00450 00451 LONG HPSearchHotPluggables(void) 00452 { 00453 int i; 00454 00455 for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++) 00456 { 00457 readerTracker[i].status = READER_ABSENT; 00458 readerTracker[i].bus_device[0] = '\0'; 00459 readerTracker[i].fullName = NULL; 00460 } 00461 00462 if (HPReadBundleValues()) 00463 { 00464 int pipefd[2]; 00465 char c; 00466 00467 if (pipe(pipefd) == -1) 00468 { 00469 Log2(PCSC_LOG_ERROR, "pipe: %s", strerror(errno)); 00470 return -1; 00471 } 00472 00473 ThreadCreate(&usbNotifyThread, THREAD_ATTR_DETACHED, 00474 (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, pipefd); 00475 00476 /* Wait for initial readers to setup */ 00477 read(pipefd[0], &c, 1); 00478 close(pipefd[0]); 00479 } 00480 00481 return 0; 00482 } 00483 00484 LONG HPStopHotPluggables(void) 00485 { 00486 AraKiriHotPlug = TRUE; 00487 if (rescan_pipe[1] >= 0) 00488 { 00489 close(rescan_pipe[1]); 00490 rescan_pipe[1] = -1; 00491 } 00492 00493 return 0; 00494 } 00495 00496 static LONG HPAddHotPluggable(struct libusb_device *dev, 00497 struct libusb_device_descriptor desc, 00498 const char bus_device[], int interface, 00499 struct _driverTracker *driver) 00500 { 00501 int i; 00502 char deviceName[MAX_DEVICENAME]; 00503 00504 Log2(PCSC_LOG_INFO, "Adding USB device: %s", bus_device); 00505 00506 if (interface >= 0) 00507 snprintf(deviceName, sizeof(deviceName), "usb:%04x/%04x:libhal:/org/freedesktop/Hal/devices/usb_device_%04x_%04x_serialnotneeded_if%d", 00508 desc.idVendor, desc.idProduct, desc.idVendor, desc.idProduct, 00509 interface); 00510 else 00511 snprintf(deviceName, sizeof(deviceName), "usb:%04x/%04x:libusb-1.0:%s", 00512 desc.idVendor, desc.idProduct, bus_device); 00513 00514 deviceName[sizeof(deviceName) -1] = '\0'; 00515 00516 pthread_mutex_lock(&usbNotifierMutex); 00517 00518 /* find a free entry */ 00519 for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++) 00520 { 00521 if (readerTracker[i].fullName == NULL) 00522 break; 00523 } 00524 00525 if (i==PCSCLITE_MAX_READERS_CONTEXTS) 00526 { 00527 Log2(PCSC_LOG_ERROR, 00528 "Not enough reader entries. Already found %d readers", i); 00529 pthread_mutex_unlock(&usbNotifierMutex); 00530 return 0; 00531 } 00532 00533 strncpy(readerTracker[i].bus_device, bus_device, 00534 sizeof(readerTracker[i].bus_device)); 00535 readerTracker[i].bus_device[sizeof(readerTracker[i].bus_device) - 1] = '\0'; 00536 00537 #ifdef ADD_SERIAL_NUMBER 00538 if (desc.iSerialNumber) 00539 { 00540 libusb_device_handle *device; 00541 unsigned char serialNumber[MAX_READERNAME]; 00542 char fullname[MAX_READERNAME]; 00543 int ret; 00544 00545 ret = libusb_open(dev, &device); 00546 if (ret < 0) 00547 { 00548 Log2(PCSC_LOG_ERROR, "libusb_open failed: %d", ret); 00549 } 00550 else 00551 { 00552 ret = libusb_get_string_descriptor_ascii(device, desc.iSerialNumber, 00553 serialNumber, MAX_READERNAME); 00554 libusb_close(device); 00555 00556 if (ret < 0) 00557 { 00558 Log2(PCSC_LOG_ERROR, 00559 "libusb_get_string_descriptor_ascii failed: %d", ret); 00560 readerTracker[i].fullName = strdup(driver->readerName); 00561 } 00562 else 00563 { 00564 snprintf(fullname, sizeof(fullname), "%s (%s)", 00565 driver->readerName, serialNumber); 00566 readerTracker[i].fullName = strdup(fullname); 00567 } 00568 } 00569 } 00570 else 00571 #endif 00572 readerTracker[i].fullName = strdup(driver->readerName); 00573 00574 if (RFAddReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i, 00575 driver->libraryPath, deviceName) == SCARD_S_SUCCESS) 00576 readerTracker[i].status = READER_PRESENT; 00577 else 00578 { 00579 readerTracker[i].status = READER_FAILED; 00580 00581 (void)CheckForOpenCT(); 00582 } 00583 00584 pthread_mutex_unlock(&usbNotifierMutex); 00585 00586 return 1; 00587 } /* End of function */ 00588 00589 static LONG HPRemoveHotPluggable(int reader_index) 00590 { 00591 pthread_mutex_lock(&usbNotifierMutex); 00592 00593 Log3(PCSC_LOG_INFO, "Removing USB device[%d]: %s", reader_index, 00594 readerTracker[reader_index].bus_device); 00595 00596 RFRemoveReader(readerTracker[reader_index].fullName, 00597 PCSCLITE_HP_BASE_PORT + reader_index); 00598 free(readerTracker[reader_index].fullName); 00599 readerTracker[reader_index].status = READER_ABSENT; 00600 readerTracker[reader_index].bus_device[0] = '\0'; 00601 readerTracker[reader_index].fullName = NULL; 00602 00603 pthread_mutex_unlock(&usbNotifierMutex); 00604 00605 return 1; 00606 } /* End of function */ 00607 00611 ULONG HPRegisterForHotplugEvents(void) 00612 { 00613 (void)pthread_mutex_init(&usbNotifierMutex, NULL); 00614 return 0; 00615 } 00616 00617 void HPReCheckSerialReaders(void) 00618 { 00619 if (rescan_pipe[1] >= 0) 00620 { 00621 char dummy = 0; 00622 write(rescan_pipe[1], &dummy, sizeof(dummy)); 00623 } 00624 } 00625 00626 #endif 00627