pcsc-lite
1.7.4
|
00001 /* 00002 * MUSCLE SmartCard Development ( http://www.linuxnet.com ) 00003 * 00004 * Copyright (C) 2011 00005 * Ludovic Rousseau <ludovic.rousseau@free.fr> 00006 * 00007 * $Id: hotplug_libudev.c 5793 2011-06-15 14:10:45Z rousseau $ 00008 */ 00009 00015 #include "config.h" 00016 #if defined(HAVE_LIBUDEV) && defined(USE_USB) 00017 00018 #include <string.h> 00019 #include <stdio.h> 00020 #include <dirent.h> 00021 #include <stdlib.h> 00022 #include <pthread.h> 00023 #include <libudev.h> 00024 00025 #include "debuglog.h" 00026 #include "parser.h" 00027 #include "readerfactory.h" 00028 #include "sys_generic.h" 00029 #include "hotplug.h" 00030 #include "utils.h" 00031 #include "strlcpycat.h" 00032 00033 #undef DEBUG_HOTPLUG 00034 #define ADD_SERIAL_NUMBER 00035 #define ADD_INTERFACE_NAME 00036 00037 #define FALSE 0 00038 #define TRUE 1 00039 00040 pthread_mutex_t usbNotifierMutex; 00041 00042 static pthread_t usbNotifyThread; 00043 static int driverSize = -1; 00044 static char AraKiriHotPlug = FALSE; 00045 00049 static struct _driverTracker 00050 { 00051 unsigned int manuID; 00052 unsigned int productID; 00053 00054 char *bundleName; 00055 char *libraryPath; 00056 char *readerName; 00057 char *CFBundleName; 00058 } *driverTracker = NULL; 00059 #define DRIVER_TRACKER_SIZE_STEP 10 00060 00061 /* The CCID driver already supports 176 readers. 00062 * We start with a big array size to avoid reallocation. */ 00063 #define DRIVER_TRACKER_INITIAL_SIZE 200 00064 00065 typedef enum { 00066 READER_ABSENT, 00067 READER_PRESENT, 00068 READER_FAILED 00069 } readerState_t; 00070 00074 static struct _readerTracker 00075 { 00076 readerState_t status; 00077 char bInterfaceNumber; 00078 char *devpath; 00079 char *fullName; 00080 } readerTracker[PCSCLITE_MAX_READERS_CONTEXTS]; 00081 00082 00083 static LONG HPReadBundleValues(void) 00084 { 00085 LONG rv; 00086 DIR *hpDir; 00087 struct dirent *currFP = NULL; 00088 char fullPath[FILENAME_MAX]; 00089 char fullLibPath[FILENAME_MAX]; 00090 int listCount = 0; 00091 00092 hpDir = opendir(PCSCLITE_HP_DROPDIR); 00093 00094 if (NULL == hpDir) 00095 { 00096 Log1(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: " PCSCLITE_HP_DROPDIR); 00097 Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd."); 00098 return -1; 00099 } 00100 00101 /* allocate a first array */ 00102 driverSize = DRIVER_TRACKER_INITIAL_SIZE; 00103 driverTracker = calloc(driverSize, sizeof(*driverTracker)); 00104 if (NULL == driverTracker) 00105 { 00106 Log1(PCSC_LOG_CRITICAL, "Not enough memory"); 00107 return -1; 00108 } 00109 00110 #define GET_KEY(key, values) \ 00111 rv = LTPBundleFindValueWithKey(&plist, key, values); \ 00112 if (rv) \ 00113 { \ 00114 Log2(PCSC_LOG_ERROR, "Value/Key not defined for " key " in %s", \ 00115 fullPath); \ 00116 continue; \ 00117 } 00118 00119 while ((currFP = readdir(hpDir)) != 0) 00120 { 00121 if (strstr(currFP->d_name, ".bundle") != 0) 00122 { 00123 unsigned int alias; 00124 list_t plist, *values; 00125 list_t *manuIDs, *productIDs, *readerNames; 00126 char *CFBundleName; 00127 char *libraryPath; 00128 00129 /* 00130 * The bundle exists - let's form a full path name and get the 00131 * vendor and product ID's for this particular bundle 00132 */ 00133 (void)snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist", 00134 PCSCLITE_HP_DROPDIR, currFP->d_name); 00135 fullPath[sizeof(fullPath) - 1] = '\0'; 00136 00137 rv = bundleParse(fullPath, &plist); 00138 if (rv) 00139 continue; 00140 00141 /* get CFBundleExecutable */ 00142 GET_KEY(PCSCLITE_HP_LIBRKEY_NAME, &values) 00143 libraryPath = list_get_at(values, 0); 00144 (void)snprintf(fullLibPath, sizeof(fullLibPath), 00145 "%s/%s/Contents/%s/%s", 00146 PCSCLITE_HP_DROPDIR, currFP->d_name, PCSC_ARCH, 00147 libraryPath); 00148 fullLibPath[sizeof(fullLibPath) - 1] = '\0'; 00149 00150 GET_KEY(PCSCLITE_HP_MANUKEY_NAME, &manuIDs) 00151 GET_KEY(PCSCLITE_HP_PRODKEY_NAME, &productIDs) 00152 GET_KEY(PCSCLITE_HP_NAMEKEY_NAME, &readerNames) 00153 00154 /* Get CFBundleName */ 00155 rv = LTPBundleFindValueWithKey(&plist, PCSCLITE_HP_CFBUNDLE_NAME, 00156 &values); 00157 if (rv) 00158 CFBundleName = NULL; 00159 else 00160 CFBundleName = strdup(list_get_at(values, 0)); 00161 00162 /* while we find a nth ifdVendorID in Info.plist */ 00163 for (alias=0; alias<list_size(manuIDs); alias++) 00164 { 00165 char *value; 00166 00167 /* variables entries */ 00168 value = list_get_at(manuIDs, alias); 00169 driverTracker[listCount].manuID = strtol(value, NULL, 16); 00170 00171 value = list_get_at(productIDs, alias); 00172 driverTracker[listCount].productID = strtol(value, NULL, 16); 00173 00174 driverTracker[listCount].readerName = strdup(list_get_at(readerNames, alias)); 00175 00176 /* constant entries for a same driver */ 00177 driverTracker[listCount].bundleName = strdup(currFP->d_name); 00178 driverTracker[listCount].libraryPath = strdup(fullLibPath); 00179 driverTracker[listCount].CFBundleName = CFBundleName; 00180 00181 #ifdef DEBUG_HOTPLUG 00182 Log2(PCSC_LOG_INFO, "Found driver for: %s", 00183 driverTracker[listCount].readerName); 00184 #endif 00185 listCount++; 00186 if (listCount >= driverSize) 00187 { 00188 int i; 00189 00190 /* increase the array size */ 00191 driverSize += DRIVER_TRACKER_SIZE_STEP; 00192 #ifdef DEBUG_HOTPLUG 00193 Log2(PCSC_LOG_INFO, 00194 "Increase driverTracker to %d entries", driverSize); 00195 #endif 00196 driverTracker = realloc(driverTracker, 00197 driverSize * sizeof(*driverTracker)); 00198 if (NULL == driverTracker) 00199 { 00200 Log1(PCSC_LOG_CRITICAL, "Not enough memory"); 00201 driverSize = -1; 00202 return -1; 00203 } 00204 00205 /* clean the newly allocated entries */ 00206 for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++) 00207 { 00208 driverTracker[i].manuID = 0; 00209 driverTracker[i].productID = 0; 00210 driverTracker[i].bundleName = NULL; 00211 driverTracker[i].libraryPath = NULL; 00212 driverTracker[i].readerName = NULL; 00213 driverTracker[i].CFBundleName = NULL; 00214 } 00215 } 00216 } 00217 bundleRelease(&plist); 00218 } 00219 } 00220 00221 driverSize = listCount; 00222 (void)closedir(hpDir); 00223 00224 #ifdef DEBUG_HOTPLUG 00225 Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount); 00226 #endif 00227 00228 return 0; 00229 } /* HPReadBundleValues */ 00230 00231 00232 /*@null@*/ static struct _driverTracker *get_driver(struct udev_device *dev, 00233 const char *devpath, struct _driverTracker **classdriver) 00234 { 00235 int i; 00236 unsigned int idVendor, idProduct; 00237 static struct _driverTracker *driver; 00238 const char *str; 00239 00240 str = udev_device_get_sysattr_value(dev, "idVendor"); 00241 if (!str) 00242 { 00243 Log1(PCSC_LOG_ERROR, "udev_device_get_sysattr_value() failed"); 00244 return NULL; 00245 } 00246 sscanf(str, "%X", &idVendor); 00247 00248 str = udev_device_get_sysattr_value(dev, "idProduct"); 00249 if (!str) 00250 { 00251 Log1(PCSC_LOG_ERROR, "udev_device_get_sysattr_value() failed"); 00252 return NULL; 00253 } 00254 sscanf(str, "%X", &idProduct); 00255 00256 Log4(PCSC_LOG_DEBUG, 00257 "Looking for a driver for VID: 0x%04X, PID: 0x%04X, path: %s", 00258 idVendor, idProduct, devpath); 00259 00260 *classdriver = NULL; 00261 driver = NULL; 00262 /* check if the device is supported by one driver */ 00263 for (i=0; i<driverSize; i++) 00264 { 00265 if (driverTracker[i].libraryPath != NULL && 00266 idVendor == driverTracker[i].manuID && 00267 idProduct == driverTracker[i].productID) 00268 { 00269 if ((driverTracker[i].CFBundleName != NULL) 00270 && (0 == strcmp(driverTracker[i].CFBundleName, "CCIDCLASSDRIVER"))) 00271 *classdriver = &driverTracker[i]; 00272 else 00273 /* it is not a CCID Class driver */ 00274 driver = &driverTracker[i]; 00275 } 00276 } 00277 00278 /* if we found a specific driver */ 00279 if (driver) 00280 return driver; 00281 00282 /* else return the Class driver (if any) */ 00283 return *classdriver; 00284 } 00285 00286 00287 static void HPAddDevice(struct udev_device *dev, struct udev_device *parent, 00288 const char *devpath) 00289 { 00290 int i; 00291 char deviceName[MAX_DEVICENAME]; 00292 char fullname[MAX_READERNAME]; 00293 struct _driverTracker *driver, *classdriver; 00294 const char *sSerialNumber = NULL, *sInterfaceName = NULL; 00295 LONG ret; 00296 int bInterfaceNumber; 00297 00298 driver = get_driver(parent, devpath, &classdriver); 00299 if (NULL == driver) 00300 { 00301 /* not a smart card reader */ 00302 #ifdef DEBUG_HOTPLUG 00303 Log2(PCSC_LOG_DEBUG, "%s is not a supported smart card reader", 00304 devpath); 00305 #endif 00306 return; 00307 } 00308 00309 Log2(PCSC_LOG_INFO, "Adding USB device: %s", driver->readerName); 00310 00311 bInterfaceNumber = atoi(udev_device_get_sysattr_value(dev, 00312 "bInterfaceNumber")); 00313 (void)snprintf(deviceName, sizeof(deviceName), 00314 "usb:%04x/%04x:libudev:%d:%s", driver->manuID, driver->productID, 00315 bInterfaceNumber, devpath); 00316 deviceName[sizeof(deviceName) -1] = '\0'; 00317 00318 (void)pthread_mutex_lock(&usbNotifierMutex); 00319 00320 /* find a free entry */ 00321 for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++) 00322 { 00323 if (NULL == readerTracker[i].fullName) 00324 break; 00325 } 00326 00327 if (PCSCLITE_MAX_READERS_CONTEXTS == i) 00328 { 00329 Log2(PCSC_LOG_ERROR, 00330 "Not enough reader entries. Already found %d readers", i); 00331 (void)pthread_mutex_unlock(&usbNotifierMutex); 00332 return; 00333 } 00334 00335 #ifdef ADD_INTERFACE_NAME 00336 sInterfaceName = udev_device_get_sysattr_value(dev, "interface"); 00337 #endif 00338 00339 #ifdef ADD_SERIAL_NUMBER 00340 sSerialNumber = udev_device_get_sysattr_value(parent, "serial"); 00341 #endif 00342 00343 /* name from the Info.plist file */ 00344 strlcpy(fullname, driver->readerName, sizeof(fullname)); 00345 00346 /* interface name from the device (if any) */ 00347 if (sInterfaceName) 00348 { 00349 strlcat(fullname, " [", sizeof(fullname)); 00350 strlcat(fullname, sInterfaceName, sizeof(fullname)); 00351 strlcat(fullname, "]", sizeof(fullname)); 00352 } 00353 00354 /* serial number from the device (if any) */ 00355 if (sSerialNumber) 00356 { 00357 /* only add the serial number if it is not already present in the 00358 * interface name */ 00359 if (!sInterfaceName || NULL == strstr(sInterfaceName, sSerialNumber)) 00360 { 00361 strlcat(fullname, " (", sizeof(fullname)); 00362 strlcat(fullname, sSerialNumber, sizeof(fullname)); 00363 strlcat(fullname, ")", sizeof(fullname)); 00364 } 00365 } 00366 00367 readerTracker[i].fullName = strdup(fullname); 00368 readerTracker[i].devpath = strdup(devpath); 00369 readerTracker[i].status = READER_PRESENT; 00370 readerTracker[i].bInterfaceNumber = bInterfaceNumber; 00371 00372 ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + i, 00373 driver->libraryPath, deviceName); 00374 if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret)) 00375 { 00376 Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s", 00377 driver->readerName); 00378 00379 if (classdriver && driver != classdriver) 00380 { 00381 /* the reader can also be used by the a class driver */ 00382 ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + i, 00383 classdriver->libraryPath, deviceName); 00384 if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret)) 00385 { 00386 Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s", 00387 driver->readerName); 00388 00389 readerTracker[i].status = READER_FAILED; 00390 00391 (void)CheckForOpenCT(); 00392 } 00393 } 00394 else 00395 { 00396 readerTracker[i].status = READER_FAILED; 00397 00398 (void)CheckForOpenCT(); 00399 } 00400 } 00401 00402 (void)pthread_mutex_unlock(&usbNotifierMutex); 00403 } /* HPAddDevice */ 00404 00405 00406 static void HPRescanUsbBus(struct udev *udev) 00407 { 00408 int i, j; 00409 struct udev_enumerate *enumerate; 00410 struct udev_list_entry *devices, *dev_list_entry; 00411 00412 /* all reader are marked absent */ 00413 for (i=0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 00414 readerTracker[i].status = READER_ABSENT; 00415 00416 /* Create a list of the devices in the 'usb' subsystem. */ 00417 enumerate = udev_enumerate_new(udev); 00418 udev_enumerate_add_match_subsystem(enumerate, "usb"); 00419 udev_enumerate_scan_devices(enumerate); 00420 devices = udev_enumerate_get_list_entry(enumerate); 00421 00422 /* For each item enumerated */ 00423 udev_list_entry_foreach(dev_list_entry, devices) 00424 { 00425 const char *devpath; 00426 struct udev_device *dev, *parent; 00427 struct _driverTracker *driver, *classdriver; 00428 int newreader; 00429 int bInterfaceNumber; 00430 const char *interface; 00431 00432 /* Get the filename of the /sys entry for the device 00433 and create a udev_device object (dev) representing it */ 00434 devpath = udev_list_entry_get_name(dev_list_entry); 00435 dev = udev_device_new_from_syspath(udev, devpath); 00436 00437 /* The device pointed to by dev contains information about 00438 the interface. In order to get information about the USB 00439 device, get the parent device with the subsystem/devtype pair 00440 of "usb"/"usb_device". This will be several levels up the 00441 tree, but the function will find it.*/ 00442 parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb", 00443 "usb_device"); 00444 if (!parent) 00445 continue; 00446 00447 devpath = udev_device_get_devnode(parent); 00448 if (!devpath) 00449 { 00450 /* the device disapeared? */ 00451 Log1(PCSC_LOG_ERROR, "udev_device_get_devnode() failed"); 00452 continue; 00453 } 00454 00455 driver = get_driver(parent, devpath, &classdriver); 00456 if (NULL == driver) 00457 /* no driver known for this device */ 00458 continue; 00459 00460 #ifdef DEBUG_HOTPLUG 00461 Log2(PCSC_LOG_DEBUG, "Found matching USB device: %s", devpath); 00462 #endif 00463 00464 newreader = TRUE; 00465 bInterfaceNumber = 0; 00466 interface = udev_device_get_sysattr_value(dev, "bInterfaceNumber"); 00467 if (interface) 00468 bInterfaceNumber = atoi(interface); 00469 00470 /* Check if the reader is a new one */ 00471 for (j=0; j<PCSCLITE_MAX_READERS_CONTEXTS; j++) 00472 { 00473 if (readerTracker[j].devpath 00474 && (strcmp(readerTracker[j].devpath, devpath) == 0) 00475 && (bInterfaceNumber == readerTracker[j].bInterfaceNumber)) 00476 { 00477 /* The reader is already known */ 00478 readerTracker[j].status = READER_PRESENT; 00479 newreader = FALSE; 00480 #ifdef DEBUG_HOTPLUG 00481 Log2(PCSC_LOG_DEBUG, "Refresh USB device: %s", devpath); 00482 #endif 00483 break; 00484 } 00485 } 00486 00487 /* New reader found */ 00488 if (newreader) 00489 HPAddDevice(dev, parent, devpath); 00490 00491 /* free device */ 00492 udev_device_unref(dev); 00493 } 00494 00495 /* Free the enumerator object */ 00496 udev_enumerate_unref(enumerate); 00497 00498 /* check if all the previously found readers are still present */ 00499 for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++) 00500 { 00501 if ((READER_ABSENT == readerTracker[i].status) 00502 && (readerTracker[i].fullName != NULL)) 00503 { 00504 pthread_mutex_lock(&usbNotifierMutex); 00505 00506 Log3(PCSC_LOG_INFO, "Removing USB device[%d]: %s", i, 00507 readerTracker[i].devpath); 00508 00509 RFRemoveReader(readerTracker[i].fullName, 00510 PCSCLITE_HP_BASE_PORT + i); 00511 00512 readerTracker[i].status = READER_ABSENT; 00513 free(readerTracker[i].devpath); 00514 readerTracker[i].devpath = NULL; 00515 free(readerTracker[i].fullName); 00516 readerTracker[i].fullName = NULL; 00517 00518 pthread_mutex_unlock(&usbNotifierMutex); 00519 } 00520 } 00521 } 00522 00523 static void HPEstablishUSBNotifications(struct udev *udev) 00524 { 00525 struct udev_monitor *udev_monitor; 00526 int r, i; 00527 int fd; 00528 fd_set fds; 00529 00530 udev_monitor = udev_monitor_new_from_netlink(udev, "udev"); 00531 00532 /* filter only the interfaces */ 00533 r = udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", 00534 "usb_interface"); 00535 if (r) 00536 { 00537 Log2(PCSC_LOG_ERROR, "udev_monitor_filter_add_match_subsystem_devtype() error: %d\n", r); 00538 return; 00539 } 00540 00541 r = udev_monitor_enable_receiving(udev_monitor); 00542 if (r) 00543 { 00544 Log2(PCSC_LOG_ERROR, "udev_monitor_enable_receiving() error: %d\n", r); 00545 return; 00546 } 00547 00548 /* udev monitor file descriptor */ 00549 fd = udev_monitor_get_fd(udev_monitor); 00550 00551 while (!AraKiriHotPlug) 00552 { 00553 struct udev_device *dev, *parent; 00554 const char *action, *devpath; 00555 00556 #ifdef DEBUG_HOTPLUG 00557 Log0(PCSC_LOG_INFO); 00558 #endif 00559 00560 FD_ZERO(&fds); 00561 FD_SET(fd, &fds); 00562 00563 /* wait for a udev event */ 00564 r = select(fd+1, &fds, NULL, NULL, NULL); 00565 if (r < 0) 00566 { 00567 Log2(PCSC_LOG_ERROR, "select(): %s", strerror(errno)); 00568 return; 00569 } 00570 00571 dev = udev_monitor_receive_device(udev_monitor); 00572 if (!dev) 00573 { 00574 Log1(PCSC_LOG_ERROR, "udev_monitor_receive_device() error\n"); 00575 return; 00576 } 00577 00578 action = udev_device_get_action(dev); 00579 if (0 == strcmp("remove", action)) 00580 { 00581 Log1(PCSC_LOG_INFO, "Device removed"); 00582 HPRescanUsbBus(udev); 00583 continue; 00584 } 00585 00586 if (strcmp("add", action)) 00587 continue; 00588 00589 parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb", 00590 "usb_device"); 00591 devpath = udev_device_get_devnode(parent); 00592 if (!devpath) 00593 { 00594 /* the device disapeared? */ 00595 Log1(PCSC_LOG_ERROR, "udev_device_get_devnode() failed"); 00596 continue; 00597 } 00598 00599 HPAddDevice(dev, parent, devpath); 00600 00601 /* free device */ 00602 udev_device_unref(dev); 00603 00604 } 00605 00606 for (i=0; i<driverSize; i++) 00607 { 00608 /* free strings allocated by strdup() */ 00609 free(driverTracker[i].bundleName); 00610 free(driverTracker[i].libraryPath); 00611 free(driverTracker[i].readerName); 00612 } 00613 free(driverTracker); 00614 00615 Log1(PCSC_LOG_INFO, "Hotplug stopped"); 00616 } /* HPEstablishUSBNotifications */ 00617 00618 00619 /*** 00620 * Start a thread waiting for hotplug events 00621 */ 00622 LONG HPSearchHotPluggables(void) 00623 { 00624 int i; 00625 00626 for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++) 00627 { 00628 readerTracker[i].status = READER_ABSENT; 00629 readerTracker[i].bInterfaceNumber = 0; 00630 readerTracker[i].devpath = NULL; 00631 readerTracker[i].fullName = NULL; 00632 } 00633 00634 return HPReadBundleValues(); 00635 } /* HPSearchHotPluggables */ 00636 00637 00641 LONG HPStopHotPluggables(void) 00642 { 00643 AraKiriHotPlug = TRUE; 00644 00645 return 0; 00646 } /* HPStopHotPluggables */ 00647 00648 00652 ULONG HPRegisterForHotplugEvents(void) 00653 { 00654 struct udev *udev; 00655 00656 (void)pthread_mutex_init(&usbNotifierMutex, NULL); 00657 00658 if (driverSize <= 0) 00659 { 00660 Log1(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: " 00661 PCSCLITE_HP_DROPDIR); 00662 Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd"); 00663 return 0; 00664 } 00665 00666 /* Create the udev object */ 00667 udev = udev_new(); 00668 if (!udev) 00669 { 00670 Log1(PCSC_LOG_ERROR, "udev_new() failed"); 00671 return 0; 00672 } 00673 00674 HPRescanUsbBus(udev); 00675 00676 (void)ThreadCreate(&usbNotifyThread, THREAD_ATTR_DETACHED, 00677 (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, udev); 00678 00679 return 0; 00680 } /* HPRegisterForHotplugEvents */ 00681 00682 00683 void HPReCheckSerialReaders(void) 00684 { 00685 /* nothing to do here */ 00686 #ifdef DEBUG_HOTPLUG 00687 Log0(PCSC_LOG_ERROR); 00688 #endif 00689 } /* HPReCheckSerialReaders */ 00690 00691 #endif 00692