pcsc-lite 1.6.4
|
00001 /* 00002 * MUSCLE SmartCard Development ( http://www.linuxnet.com ) 00003 * 00004 * Copyright (C) 2008-2010 00005 * Ludovic Rousseau <ludovic.rousseau@free.fr> 00006 * 00007 * $Id: hotplug_libhal.c 5071 2010-07-26 13:33:56Z rousseau $ 00008 */ 00009 00015 #include "config.h" 00016 #if defined(HAVE_LIBHAL) && defined(USE_USB) 00017 00018 #include <string.h> 00019 #include <stdio.h> 00020 #include <dirent.h> 00021 #include <stdlib.h> 00022 #include <libhal.h> 00023 #include <pthread.h> 00024 00025 #include "misc.h" 00026 #include "wintypes.h" 00027 #include "pcscd.h" 00028 #include "debuglog.h" 00029 #include "parser.h" 00030 #include "readerfactory.h" 00031 #include "sys_generic.h" 00032 #include "hotplug.h" 00033 #include "utils.h" 00034 #include "strlcpycat.h" 00035 00036 #undef DEBUG_HOTPLUG 00037 #define ADD_SERIAL_NUMBER 00038 #define ADD_INTERFACE_NAME 00039 00040 #define FALSE 0 00041 #define TRUE 1 00042 00043 #define UDI_BASE "/org/freedesktop/Hal/devices/" 00044 00045 pthread_mutex_t usbNotifierMutex; 00046 00047 static pthread_t usbNotifyThread; 00048 static int driverSize = -1; 00049 static char AraKiriHotPlug = FALSE; 00050 00051 static DBusConnection *conn; 00052 static LibHalContext *hal_ctx; 00053 00057 static struct _driverTracker 00058 { 00059 unsigned int manuID; 00060 unsigned int productID; 00061 00062 char *bundleName; 00063 char *libraryPath; 00064 char *readerName; 00065 int ifdCapabilities; 00066 char *CFBundleName; 00067 } *driverTracker = NULL; 00068 #define DRIVER_TRACKER_SIZE_STEP 8 00069 00073 static struct _readerTracker 00074 { 00075 char *udi; 00076 char *fullName; 00077 } readerTracker[PCSCLITE_MAX_READERS_CONTEXTS]; 00078 00079 static LONG HPReadBundleValues(void); 00080 static void HPAddDevice(LibHalContext *ctx, const char *udi); 00081 static void HPRemoveDevice(LibHalContext *ctx, const char *udi); 00082 static void HPEstablishUSBNotifications(void); 00083 00089 #ifndef NO_LOG 00090 static const char *short_name(const char *udi) 00091 { 00092 return &udi[sizeof(UDI_BASE) - 1]; 00093 } /* short_name */ 00094 #endif 00095 00096 00097 static LONG HPReadBundleValues(void) 00098 { 00099 LONG rv; 00100 DIR *hpDir; 00101 struct dirent *currFP = NULL; 00102 char fullPath[FILENAME_MAX]; 00103 char fullLibPath[FILENAME_MAX]; 00104 char keyValue[TOKEN_MAX_VALUE_SIZE]; 00105 int listCount = 0; 00106 00107 hpDir = opendir(PCSCLITE_HP_DROPDIR); 00108 00109 if (NULL == hpDir) 00110 { 00111 Log1(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: " PCSCLITE_HP_DROPDIR); 00112 Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd."); 00113 return -1; 00114 } 00115 00116 /* allocate a first array */ 00117 driverTracker = calloc(DRIVER_TRACKER_SIZE_STEP, sizeof(*driverTracker)); 00118 if (NULL == driverTracker) 00119 { 00120 Log1(PCSC_LOG_CRITICAL, "Not enough memory"); 00121 return -1; 00122 } 00123 driverSize = DRIVER_TRACKER_SIZE_STEP; 00124 00125 while ((currFP = readdir(hpDir)) != 0) 00126 { 00127 if (strstr(currFP->d_name, ".bundle") != 0) 00128 { 00129 int alias = 0; 00130 00131 /* 00132 * The bundle exists - let's form a full path name and get the 00133 * vendor and product ID's for this particular bundle 00134 */ 00135 (void)snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist", 00136 PCSCLITE_HP_DROPDIR, currFP->d_name); 00137 fullPath[sizeof(fullPath) - 1] = '\0'; 00138 00139 /* while we find a nth ifdVendorID in Info.plist */ 00140 while (LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_MANUKEY_NAME, 00141 keyValue, alias) == 0) 00142 { 00143 driverTracker[listCount].bundleName = strdup(currFP->d_name); 00144 00145 /* Get ifdVendorID */ 00146 rv = LTPBundleFindValueWithKey(fullPath, 00147 PCSCLITE_HP_MANUKEY_NAME, keyValue, alias); 00148 if (0 == rv) 00149 driverTracker[listCount].manuID = strtol(keyValue, NULL, 16); 00150 00151 /* get ifdProductID */ 00152 rv = LTPBundleFindValueWithKey(fullPath, 00153 PCSCLITE_HP_PRODKEY_NAME, keyValue, alias); 00154 if (0 == rv) 00155 driverTracker[listCount].productID = 00156 strtol(keyValue, NULL, 16); 00157 00158 /* get ifdFriendlyName */ 00159 rv = LTPBundleFindValueWithKey(fullPath, 00160 PCSCLITE_HP_NAMEKEY_NAME, keyValue, alias); 00161 if (0 == rv) 00162 driverTracker[listCount].readerName = strdup(keyValue); 00163 00164 /* get CFBundleExecutable */ 00165 rv = LTPBundleFindValueWithKey(fullPath, 00166 PCSCLITE_HP_LIBRKEY_NAME, keyValue, 0); 00167 if (0 == rv) 00168 { 00169 (void)snprintf(fullLibPath, sizeof(fullLibPath), 00170 "%s/%s/Contents/%s/%s", 00171 PCSCLITE_HP_DROPDIR, currFP->d_name, PCSC_ARCH, 00172 keyValue); 00173 fullLibPath[sizeof(fullLibPath) - 1] = '\0'; 00174 driverTracker[listCount].libraryPath = strdup(fullLibPath); 00175 } 00176 00177 /* Get ifdCapabilities */ 00178 rv = LTPBundleFindValueWithKey(fullPath, 00179 PCSCLITE_HP_CPCTKEY_NAME, keyValue, 0); 00180 if (0 == rv) 00181 driverTracker[listCount].ifdCapabilities = strtol(keyValue, 00182 NULL, 16); 00183 00184 /* Get CFBundleName */ 00185 rv = LTPBundleFindOptionalValueWithKey(fullPath, 00186 PCSCLITE_HP_CFBUNDLE_NAME, keyValue, 0); 00187 if (0 == rv) 00188 driverTracker[listCount].CFBundleName = strdup(keyValue); 00189 00190 #ifdef DEBUG_HOTPLUG 00191 Log2(PCSC_LOG_INFO, "Found driver for: %s", 00192 driverTracker[listCount].readerName); 00193 #endif 00194 alias++; 00195 00196 if (NULL == driverTracker[listCount].readerName) 00197 continue; 00198 00199 listCount++; 00200 if (listCount >= driverSize) 00201 { 00202 int i; 00203 00204 /* increase the array size */ 00205 driverSize += DRIVER_TRACKER_SIZE_STEP; 00206 #ifdef DEBUG_HOTPLUG 00207 Log2(PCSC_LOG_INFO, 00208 "Increase driverTracker to %d entries", driverSize); 00209 #endif 00210 driverTracker = realloc(driverTracker, 00211 driverSize * sizeof(*driverTracker)); 00212 if (NULL == driverTracker) 00213 { 00214 Log1(PCSC_LOG_CRITICAL, "Not enough memory"); 00215 driverSize = -1; 00216 return -1; 00217 } 00218 00219 /* clean the newly allocated entries */ 00220 for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++) 00221 { 00222 driverTracker[i].manuID = 0; 00223 driverTracker[i].productID = 0; 00224 driverTracker[i].bundleName = NULL; 00225 driverTracker[i].libraryPath = NULL; 00226 driverTracker[i].readerName = NULL; 00227 driverTracker[i].ifdCapabilities = 0; 00228 driverTracker[i].CFBundleName = NULL; 00229 } 00230 } 00231 } 00232 } 00233 } 00234 00235 driverSize = listCount; 00236 (void)closedir(hpDir); 00237 00238 #ifdef DEBUG_HOTPLUG 00239 Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount); 00240 #endif 00241 00242 return 0; 00243 } /* HPReadBundleValues */ 00244 00245 00246 void HPEstablishUSBNotifications(void) 00247 { 00248 while (!AraKiriHotPlug && dbus_connection_read_write_dispatch(conn, -1)) 00249 { 00250 #ifdef DEBUG_HOTPLUG 00251 Log0(PCSC_LOG_INFO); 00252 #endif 00253 } 00254 } /* HPEstablishUSBNotifications */ 00255 00256 00257 /*** 00258 * Start a thread waiting for hotplug events 00259 */ 00260 LONG HPSearchHotPluggables(void) 00261 { 00262 int i; 00263 00264 for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++) 00265 { 00266 readerTracker[i].udi = NULL; 00267 readerTracker[i].fullName = NULL; 00268 } 00269 00270 return HPReadBundleValues(); 00271 } /* HPSearchHotPluggables */ 00272 00273 00277 LONG HPStopHotPluggables(void) 00278 { 00279 AraKiriHotPlug = TRUE; 00280 00281 return 0; 00282 } /* HPStopHotPluggables */ 00283 00284 00285 /*@null@*/ static struct _driverTracker *get_driver(LibHalContext *ctx, 00286 const char *udi) 00287 { 00288 DBusError error; 00289 int i; 00290 unsigned int idVendor, idProduct; 00291 static struct _driverTracker *classdriver, *driver; 00292 00293 if (!libhal_device_property_exists(ctx, udi, "usb.vendor_id", NULL)) 00294 return NULL; 00295 00296 dbus_error_init(&error); 00297 00298 /* Vendor ID */ 00299 idVendor = libhal_device_get_property_int(ctx, udi, 00300 "usb.vendor_id", &error); 00301 if (dbus_error_is_set(&error)) 00302 { 00303 Log3(PCSC_LOG_ERROR, "libhal_device_get_property_int %s: %d", 00304 error.name, error.message); 00305 dbus_error_free(&error); 00306 return NULL; 00307 } 00308 00309 /* Product ID */ 00310 idProduct = libhal_device_get_property_int(ctx, udi, 00311 "usb.product_id", &error); 00312 if (dbus_error_is_set(&error)) 00313 { 00314 Log3(PCSC_LOG_ERROR, "libhal_device_get_property_int %s: %d", 00315 error.name, error.message); 00316 dbus_error_free(&error); 00317 return NULL; 00318 } 00319 00320 Log3(PCSC_LOG_DEBUG, "Looking a driver for VID: 0x%04X, PID: 0x%04X", idVendor, idProduct); 00321 00322 classdriver = NULL; 00323 driver = NULL; 00324 /* check if the device is supported by one driver */ 00325 for (i=0; i<driverSize; i++) 00326 { 00327 if (driverTracker[i].libraryPath != NULL && 00328 idVendor == driverTracker[i].manuID && 00329 idProduct == driverTracker[i].productID) 00330 { 00331 if ((driverTracker[i].CFBundleName != NULL) 00332 && (0 == strcmp(driverTracker[i].CFBundleName, "CCIDCLASSDRIVER"))) 00333 classdriver = &driverTracker[i]; 00334 else 00335 /* it is not a CCID Class driver */ 00336 driver = &driverTracker[i]; 00337 } 00338 } 00339 00340 /* if we found a specific driver */ 00341 if (driver) 00342 return driver; 00343 00344 /* else return the Class driver */ 00345 return classdriver; 00346 } 00347 00348 00349 static void HPAddDevice(LibHalContext *ctx, const char *udi) 00350 { 00351 int i; 00352 char deviceName[MAX_DEVICENAME]; 00353 struct _driverTracker *driver; 00354 char *sSerialNumber = NULL, *sInterfaceName = NULL; 00355 char fullname[MAX_READERNAME]; 00356 LONG ret; 00357 00358 driver = get_driver(ctx, udi); 00359 if (NULL == driver) 00360 { 00361 /* not a smart card reader */ 00362 #ifdef DEBUG_HOTPLUG 00363 Log2(PCSC_LOG_DEBUG, "%s is not a reader", short_name(udi)); 00364 #endif 00365 return; 00366 } 00367 00368 Log2(PCSC_LOG_INFO, "Adding USB device: %s", short_name(udi)); 00369 00370 (void)snprintf(deviceName, sizeof(deviceName), "usb:%04x/%04x:libhal:%s", 00371 driver->manuID, driver->productID, udi); 00372 deviceName[sizeof(deviceName) -1] = '\0'; 00373 00374 /* wait until the device is visible by libusb/etc. */ 00375 (void)SYS_Sleep(1); 00376 00377 (void)pthread_mutex_lock(&usbNotifierMutex); 00378 00379 /* find a free entry */ 00380 for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++) 00381 { 00382 if (NULL == readerTracker[i].fullName) 00383 break; 00384 } 00385 00386 if (PCSCLITE_MAX_READERS_CONTEXTS == i) 00387 { 00388 Log2(PCSC_LOG_ERROR, 00389 "Not enough reader entries. Already found %d readers", i); 00390 (void)pthread_mutex_unlock(&usbNotifierMutex); 00391 return; 00392 } 00393 00394 readerTracker[i].udi = strdup(udi); 00395 00396 #ifdef ADD_INTERFACE_NAME 00397 if (libhal_device_property_exists(ctx, udi, "usb.interface.description", NULL)) 00398 sInterfaceName = libhal_device_get_property_string(ctx, udi, 00399 "usb.interface.description", NULL); 00400 #endif 00401 00402 #ifdef ADD_SERIAL_NUMBER 00403 if (libhal_device_property_exists(ctx, udi, "usb.serial", NULL)) 00404 sSerialNumber = libhal_device_get_property_string(ctx, udi, 00405 "usb.serial", NULL); 00406 #endif 00407 00408 /* name from the Info.plist file */ 00409 strlcpy(fullname, driver->readerName, sizeof(fullname)); 00410 00411 /* interface name from the device (if any) */ 00412 if (sInterfaceName) 00413 { 00414 strlcat(fullname, " [", sizeof(fullname)); 00415 strlcat(fullname, sInterfaceName, sizeof(fullname)); 00416 strlcat(fullname, "]", sizeof(fullname)); 00417 libhal_free_string(sInterfaceName); 00418 } 00419 00420 /* serial number from the device (if any) */ 00421 if (sSerialNumber) 00422 { 00423 strlcat(fullname, " (", sizeof(fullname)); 00424 strlcat(fullname, sSerialNumber, sizeof(fullname)); 00425 strlcat(fullname, ")", sizeof(fullname)); 00426 libhal_free_string(sSerialNumber); 00427 } 00428 00429 readerTracker[i].fullName = strdup(fullname); 00430 00431 ret = RFAddReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i, 00432 driver->libraryPath, deviceName); 00433 if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret)) 00434 { 00435 char *parent, *device_file; 00436 00437 /* get the parent descriptor, without the '_if0' */ 00438 parent = libhal_device_get_property_string(ctx, udi, 00439 "info.parent", NULL); 00440 if (! parent) 00441 goto error; 00442 00443 /* get the linux device file: i.e. '/dev/bus/usb/002/012' */ 00444 device_file = libhal_device_get_property_string(ctx, parent, 00445 "linux.device_file", NULL); 00446 if (! device_file) 00447 goto error; 00448 00449 /* check the format looks correct */ 00450 #define LIBUSB_HEADER "/dev/bus/usb/" 00451 if (strncmp(device_file, LIBUSB_HEADER, strlen(LIBUSB_HEADER))) 00452 goto error; 00453 00454 device_file += strlen(LIBUSB_HEADER); 00455 00456 (void)snprintf(deviceName, sizeof(deviceName), 00457 "usb:%04x/%04x:libusb:%s", 00458 driver->manuID, driver->productID, device_file); 00459 deviceName[sizeof(deviceName) -1] = '\0'; 00460 00461 /* replace the libusb separator '/' by ':' */ 00462 if ('/' == deviceName[strlen(deviceName)-3-1]) 00463 deviceName[strlen(deviceName)-3-1] = ':'; 00464 00465 Log2(PCSC_LOG_INFO, "trying libusb scheme with: %s", deviceName); 00466 ret = RFAddReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i, 00467 driver->libraryPath, deviceName); 00468 00469 if (SCARD_S_SUCCESS != ret) 00470 { 00471 error: 00472 Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s", short_name(udi)); 00473 free(readerTracker[i].fullName); 00474 readerTracker[i].fullName = NULL; 00475 free(readerTracker[i].udi); 00476 readerTracker[i].udi = NULL; 00477 00478 (void)CheckForOpenCT(); 00479 } 00480 } 00481 00482 (void)pthread_mutex_unlock(&usbNotifierMutex); 00483 } /* HPAddDevice */ 00484 00485 00486 static void HPRemoveDevice(/*@unused@*/ LibHalContext *ctx, const char *udi) 00487 { 00488 int i; 00489 00490 (void)ctx; 00491 for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++) 00492 { 00493 if (readerTracker[i].udi && strcmp(readerTracker[i].udi, udi) == 0) 00494 break; 00495 } 00496 if (PCSCLITE_MAX_READERS_CONTEXTS == i) 00497 { 00498 #ifdef DEBUG_HOTPLUG 00499 Log2(PCSC_LOG_DEBUG, "USB device %s not already used", short_name(udi)); 00500 #endif 00501 return; 00502 } 00503 Log3(PCSC_LOG_INFO, "Removing USB device[%d]: %s", i, 00504 short_name(readerTracker[i].udi)); 00505 00506 (void)pthread_mutex_lock(&usbNotifierMutex); 00507 00508 (void)RFRemoveReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i); 00509 free(readerTracker[i].fullName); 00510 readerTracker[i].fullName = NULL; 00511 free(readerTracker[i].udi); 00512 readerTracker[i].udi = NULL; 00513 00514 (void)pthread_mutex_unlock(&usbNotifierMutex); 00515 00516 return; 00517 } /* HPRemoveDevice */ 00518 00519 00523 ULONG HPRegisterForHotplugEvents(void) 00524 { 00525 char **device_names; 00526 int i, num_devices; 00527 DBusError error; 00528 00529 (void)pthread_mutex_init(&usbNotifierMutex, NULL); 00530 00531 if (driverSize <= 0) 00532 { 00533 Log1(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: " PCSCLITE_HP_DROPDIR); 00534 Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd"); 00535 return 1; 00536 } 00537 00538 dbus_error_init(&error); 00539 conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error); 00540 if (conn == NULL) 00541 { 00542 Log3(PCSC_LOG_ERROR, "error: dbus_bus_get: %s: %s", 00543 error.name, error.message); 00544 if (dbus_error_is_set(&error)) 00545 dbus_error_free(&error); 00546 return 1; 00547 } 00548 00549 hal_ctx = libhal_ctx_new(); 00550 if (hal_ctx == NULL) 00551 { 00552 Log1(PCSC_LOG_ERROR, "error: libhal_ctx_new"); 00553 return 1; 00554 } 00555 if (!libhal_ctx_set_dbus_connection(hal_ctx, conn)) 00556 { 00557 Log1(PCSC_LOG_ERROR, "error: libhal_ctx_set_dbus_connection"); 00558 return 1; 00559 } 00560 if (!libhal_ctx_init(hal_ctx, &error)) 00561 { 00562 if (dbus_error_is_set(&error)) 00563 { 00564 Log3(PCSC_LOG_ERROR, "error: libhal_ctx_init: %s: %s", 00565 error.name, error.message); 00566 if (dbus_error_is_set(&error)) 00567 dbus_error_free(&error); 00568 } 00569 Log1(PCSC_LOG_ERROR, "Could not initialise connection to hald."); 00570 Log1(PCSC_LOG_ERROR, "Normally this means the HAL daemon (hald) is not running or not ready."); 00571 return 1; 00572 } 00573 00574 /* callback when device added */ 00575 (void)libhal_ctx_set_device_added(hal_ctx, HPAddDevice); 00576 00577 /* callback when device removed */ 00578 (void)libhal_ctx_set_device_removed(hal_ctx, HPRemoveDevice); 00579 00580 device_names = libhal_get_all_devices(hal_ctx, &num_devices, &error); 00581 if (device_names == NULL) 00582 { 00583 if (dbus_error_is_set(&error)) 00584 dbus_error_free(&error); 00585 Log1(PCSC_LOG_ERROR, "Couldn't obtain list of devices"); 00586 return 1; 00587 } 00588 00589 /* try to add every present USB devices */ 00590 for (i = 0; i < num_devices; i++) 00591 HPAddDevice(hal_ctx, device_names[i]); 00592 00593 libhal_free_string_array(device_names); 00594 00595 (void)ThreadCreate(&usbNotifyThread, THREAD_ATTR_DETACHED, 00596 (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, NULL); 00597 00598 return 0; 00599 } /* HPRegisterForHotplugEvents */ 00600 00601 00602 void HPReCheckSerialReaders(void) 00603 { 00604 /* nothing to do here */ 00605 #ifdef DEBUG_HOTPLUG 00606 Log0(PCSC_LOG_ERROR); 00607 #endif 00608 } /* HPReCheckSerialReaders */ 00609 00610 #endif 00611