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