00001
00002
00003
00004
00005
00006
00007
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 }
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
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
00131
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
00138 while (LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_MANUKEY_NAME,
00139 keyValue, alias) == 0)
00140 {
00141 driverTracker[listCount].bundleName = strdup(currFP->d_name);
00142
00143
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
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
00157 rv = LTPBundleFindValueWithKey(fullPath,
00158 PCSCLITE_HP_NAMEKEY_NAME, keyValue, alias);
00159 if (0 == rv)
00160 driverTracker[listCount].readerName = strdup(keyValue);
00161
00162
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
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
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
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
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 }
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 }
00253
00254
00255
00256
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 }
00270
00271
00275 LONG HPStopHotPluggables(void)
00276 {
00277 AraKiriHotPlug = TRUE;
00278
00279 return 0;
00280 }
00281
00282
00283 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
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
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
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
00334 driver = &driverTracker[i];
00335 }
00336 }
00337
00338
00339 if (driver)
00340 return driver;
00341
00342
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
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
00373 (void)SYS_Sleep(1);
00374
00375 (void)SYS_MutexLock(&usbNotifierMutex);
00376
00377
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
00407 strlcpy(fullname, driver->readerName, sizeof(fullname));
00408
00409
00410 if (sInterfaceName)
00411 {
00412 strlcat(fullname, " [", sizeof(fullname));
00413 strlcat(fullname, sInterfaceName, sizeof(fullname));
00414 strlcat(fullname, "]", sizeof(fullname));
00415 }
00416
00417
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
00434 parent = libhal_device_get_property_string(ctx, udi,
00435 "info.parent", NULL);
00436 if (! parent)
00437 goto error;
00438
00439
00440 device_file = libhal_device_get_property_string(ctx, parent,
00441 "linux.device_file", NULL);
00442 if (! device_file)
00443 goto error;
00444
00445
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
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 }
00480
00481
00482 static void HPRemoveDevice( 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 }
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
00568 (void)libhal_ctx_set_device_added(hal_ctx, HPAddDevice);
00569
00570
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
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 }
00593
00594
00595 void HPReCheckSerialReaders(void)
00596 {
00597
00598 #ifdef DEBUG_HOTPLUG
00599 Log0(PCSC_LOG_ERROR);
00600 #endif
00601 }
00602
00603 #endif
00604