00001
00002
00003
00004
00005
00006
00007
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 }
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
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
00133
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
00140 while (LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_MANUKEY_NAME,
00141 keyValue, alias) == 0)
00142 {
00143 driverTracker[listCount].bundleName = strdup(currFP->d_name);
00144
00145
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
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
00159 rv = LTPBundleFindValueWithKey(fullPath,
00160 PCSCLITE_HP_NAMEKEY_NAME, keyValue, alias);
00161 if (0 == rv)
00162 driverTracker[listCount].readerName = strdup(keyValue);
00163
00164
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
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
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
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
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 }
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 }
00255
00256
00257
00258
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 }
00272
00273
00277 LONG HPStopHotPluggables(void)
00278 {
00279 AraKiriHotPlug = TRUE;
00280
00281 return 0;
00282 }
00283
00284
00285 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
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
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
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
00336 driver = &driverTracker[i];
00337 }
00338 }
00339
00340
00341 if (driver)
00342 return driver;
00343
00344
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
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
00375 (void)SYS_Sleep(1);
00376
00377 (void)pthread_mutex_lock(&usbNotifierMutex);
00378
00379
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
00409 strlcpy(fullname, driver->readerName, sizeof(fullname));
00410
00411
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
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
00438 parent = libhal_device_get_property_string(ctx, udi,
00439 "info.parent", NULL);
00440 if (! parent)
00441 goto error;
00442
00443
00444 device_file = libhal_device_get_property_string(ctx, parent,
00445 "linux.device_file", NULL);
00446 if (! device_file)
00447 goto error;
00448
00449
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
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 }
00484
00485
00486 static void HPRemoveDevice( 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 }
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 if ((hal_ctx = libhal_ctx_new()) == NULL)
00550 {
00551 Log1(PCSC_LOG_ERROR, "error: libhal_ctx_new");
00552 return 1;
00553 }
00554 if (!libhal_ctx_set_dbus_connection(hal_ctx, conn))
00555 {
00556 Log1(PCSC_LOG_ERROR, "error: libhal_ctx_set_dbus_connection");
00557 return 1;
00558 }
00559 if (!libhal_ctx_init(hal_ctx, &error))
00560 {
00561 if (dbus_error_is_set(&error))
00562 {
00563 Log3(PCSC_LOG_ERROR, "error: libhal_ctx_init: %s: %s",
00564 error.name, error.message);
00565 if (dbus_error_is_set(&error))
00566 dbus_error_free(&error);
00567 }
00568 Log1(PCSC_LOG_ERROR, "Could not initialise connection to hald.");
00569 Log1(PCSC_LOG_ERROR, "Normally this means the HAL daemon (hald) is not running or not ready.");
00570 return 1;
00571 }
00572
00573
00574 (void)libhal_ctx_set_device_added(hal_ctx, HPAddDevice);
00575
00576
00577 (void)libhal_ctx_set_device_removed(hal_ctx, HPRemoveDevice);
00578
00579 device_names = libhal_get_all_devices(hal_ctx, &num_devices, &error);
00580 if (device_names == NULL)
00581 {
00582 if (dbus_error_is_set(&error))
00583 dbus_error_free(&error);
00584 Log1(PCSC_LOG_ERROR, "Couldn't obtain list of devices");
00585 return 1;
00586 }
00587
00588
00589 for (i = 0; i < num_devices; i++)
00590 HPAddDevice(hal_ctx, device_names[i]);
00591
00592 libhal_free_string_array(device_names);
00593
00594 (void)ThreadCreate(&usbNotifyThread, THREAD_ATTR_DETACHED,
00595 (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, NULL);
00596
00597 return 0;
00598 }
00599
00600
00601 void HPReCheckSerialReaders(void)
00602 {
00603
00604 #ifdef DEBUG_HOTPLUG
00605 Log0(PCSC_LOG_ERROR);
00606 #endif
00607 }
00608
00609 #endif
00610