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
00035 #undef DEBUG_HOTPLUG
00036 #define ADD_SERIAL_NUMBER
00037
00038 #define FALSE 0
00039 #define TRUE 1
00040
00041 #define UDI_BASE "/org/freedesktop/Hal/devices/"
00042
00043 extern PCSCLITE_MUTEX usbNotifierMutex;
00044
00045 static PCSCLITE_THREAD_T usbNotifyThread;
00046 static int driverSize = -1;
00047 static char AraKiriHotPlug = FALSE;
00048
00049 static DBusConnection *conn;
00050 static LibHalContext *hal_ctx;
00051
00055 static struct _driverTracker
00056 {
00057 unsigned int manuID;
00058 unsigned int productID;
00059
00060 char *bundleName;
00061 char *libraryPath;
00062 char *readerName;
00063 int ifdCapabilities;
00064 } *driverTracker = NULL;
00065 #define DRIVER_TRACKER_SIZE_STEP 8
00066
00070 static struct _readerTracker
00071 {
00072 char *udi;
00073 char *fullName;
00074 } readerTracker[PCSCLITE_MAX_READERS_CONTEXTS];
00075
00076 static LONG HPReadBundleValues(void);
00077 static void HPAddDevice(LibHalContext *ctx, const char *udi);
00078 static void HPRemoveDevice(LibHalContext *ctx, const char *udi);
00079 static void HPEstablishUSBNotifications(void);
00080
00086 static const char *short_name(const char *udi)
00087 {
00088 return &udi[sizeof(UDI_BASE) - 1];
00089 }
00090
00091
00092 static LONG HPReadBundleValues(void)
00093 {
00094 LONG rv;
00095 DIR *hpDir;
00096 struct dirent *currFP = NULL;
00097 char fullPath[FILENAME_MAX];
00098 char fullLibPath[FILENAME_MAX];
00099 char keyValue[TOKEN_MAX_VALUE_SIZE];
00100 int listCount = 0;
00101
00102 hpDir = opendir(PCSCLITE_HP_DROPDIR);
00103
00104 if (NULL == hpDir)
00105 {
00106 Log1(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: " PCSCLITE_HP_DROPDIR);
00107 Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd.");
00108 return -1;
00109 }
00110
00111
00112 driverTracker = calloc(DRIVER_TRACKER_SIZE_STEP, sizeof(*driverTracker));
00113 if (NULL == driverTracker)
00114 {
00115 Log1(PCSC_LOG_CRITICAL, "Not enough memory");
00116 return -1;
00117 }
00118 driverSize = DRIVER_TRACKER_SIZE_STEP;
00119
00120 while ((currFP = readdir(hpDir)) != 0)
00121 {
00122 if (strstr(currFP->d_name, ".bundle") != 0)
00123 {
00124 int alias = 0;
00125
00126
00127
00128
00129
00130 (void)snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist",
00131 PCSCLITE_HP_DROPDIR, currFP->d_name);
00132 fullPath[sizeof(fullPath) - 1] = '\0';
00133
00134
00135 while (LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_MANUKEY_NAME,
00136 keyValue, alias) == 0)
00137 {
00138 driverTracker[listCount].bundleName = strdup(currFP->d_name);
00139
00140
00141 rv = LTPBundleFindValueWithKey(fullPath,
00142 PCSCLITE_HP_MANUKEY_NAME, keyValue, alias);
00143 if (0 == rv)
00144 driverTracker[listCount].manuID = strtol(keyValue, NULL, 16);
00145
00146
00147 rv = LTPBundleFindValueWithKey(fullPath,
00148 PCSCLITE_HP_PRODKEY_NAME, keyValue, alias);
00149 if (0 == rv)
00150 driverTracker[listCount].productID =
00151 strtol(keyValue, NULL, 16);
00152
00153
00154 rv = LTPBundleFindValueWithKey(fullPath,
00155 PCSCLITE_HP_NAMEKEY_NAME, keyValue, alias);
00156 if (0 == rv)
00157 driverTracker[listCount].readerName = strdup(keyValue);
00158
00159
00160 rv = LTPBundleFindValueWithKey(fullPath,
00161 PCSCLITE_HP_LIBRKEY_NAME, keyValue, 0);
00162 if (0 == rv)
00163 {
00164 (void)snprintf(fullLibPath, sizeof(fullLibPath),
00165 "%s/%s/Contents/%s/%s",
00166 PCSCLITE_HP_DROPDIR, currFP->d_name, PCSC_ARCH,
00167 keyValue);
00168 fullLibPath[sizeof(fullLibPath) - 1] = '\0';
00169 driverTracker[listCount].libraryPath = strdup(fullLibPath);
00170 }
00171
00172
00173 rv = LTPBundleFindValueWithKey(fullPath,
00174 PCSCLITE_HP_CPCTKEY_NAME, keyValue, 0);
00175 if (0 == rv)
00176 driverTracker[listCount].ifdCapabilities = strtol(keyValue,
00177 NULL, 16);
00178
00179 #ifdef DEBUG_HOTPLUG
00180 Log2(PCSC_LOG_INFO, "Found driver for: %s",
00181 driverTracker[listCount].readerName);
00182 #endif
00183 alias++;
00184
00185 if (NULL == driverTracker[listCount].readerName)
00186 continue;
00187
00188 listCount++;
00189 if (listCount >= driverSize)
00190 {
00191 int i;
00192
00193
00194 driverSize += DRIVER_TRACKER_SIZE_STEP;
00195 #ifdef DEBUG_HOTPLUG
00196 Log2(PCSC_LOG_INFO,
00197 "Increase driverTracker to %d entries", driverSize);
00198 #endif
00199 driverTracker = realloc(driverTracker,
00200 driverSize * sizeof(*driverTracker));
00201 if (NULL == driverTracker)
00202 {
00203 Log1(PCSC_LOG_CRITICAL, "Not enough memory");
00204 driverSize = -1;
00205 return -1;
00206 }
00207
00208
00209 for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++)
00210 {
00211 driverTracker[i].manuID = 0;
00212 driverTracker[i].productID = 0;
00213 driverTracker[i].bundleName = NULL;
00214 driverTracker[i].libraryPath = NULL;
00215 driverTracker[i].readerName = NULL;
00216 driverTracker[i].ifdCapabilities = 0;
00217 }
00218 }
00219 }
00220 }
00221 }
00222
00223 driverSize = listCount;
00224 (void)closedir(hpDir);
00225
00226 #ifdef DEBUG_HOTPLUG
00227 Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount);
00228 #endif
00229
00230 return 0;
00231 }
00232
00233
00234 void HPEstablishUSBNotifications(void)
00235 {
00236 while (!AraKiriHotPlug && dbus_connection_read_write_dispatch(conn, -1))
00237 {
00238 #ifdef DEBUG_HOTPLUG
00239 Log0(PCSC_LOG_INFO);
00240 #endif
00241 }
00242 }
00243
00244
00245
00246
00247
00248 LONG HPSearchHotPluggables(void)
00249 {
00250 int i;
00251
00252 for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00253 {
00254 readerTracker[i].udi = NULL;
00255 readerTracker[i].fullName = NULL;
00256 }
00257
00258 return HPReadBundleValues();
00259 }
00260
00261
00265 LONG HPStopHotPluggables(void)
00266 {
00267 AraKiriHotPlug = TRUE;
00268
00269 return 0;
00270 }
00271
00272
00273 static struct _driverTracker *get_driver(LibHalContext *ctx,
00274 const char *udi)
00275 {
00276 DBusError error;
00277 int i;
00278 unsigned int idVendor, idProduct;
00279
00280 if (!libhal_device_property_exists(ctx, udi, "usb.vendor_id", NULL))
00281 return NULL;
00282
00283 dbus_error_init(&error);
00284
00285
00286 idVendor = libhal_device_get_property_int(ctx, udi,
00287 "usb.vendor_id", &error);
00288 if (dbus_error_is_set(&error))
00289 {
00290 Log3(PCSC_LOG_ERROR, "libhal_device_get_property_int %s: %d",
00291 error.name, error.message);
00292 dbus_error_free(&error);
00293 return NULL;
00294 }
00295
00296
00297 idProduct = libhal_device_get_property_int(ctx, udi,
00298 "usb.product_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 Log3(PCSC_LOG_DEBUG, "Looking a driver for VID: 0x%04X, PID: 0x%04X", idVendor, idProduct);
00308
00309
00310 for (i=0; i<driverSize; i++)
00311 {
00312 if (driverTracker[i].libraryPath != NULL &&
00313 idVendor == driverTracker[i].manuID &&
00314 idProduct == driverTracker[i].productID)
00315 {
00316 return &driverTracker[i];
00317 }
00318 }
00319
00320 return NULL;
00321 }
00322
00323
00324 static void HPAddDevice(LibHalContext *ctx, const char *udi)
00325 {
00326 int i;
00327 char deviceName[MAX_DEVICENAME];
00328 DBusError error;
00329 struct _driverTracker *driver;
00330 LONG ret;
00331
00332 driver = get_driver(ctx, udi);
00333 if (NULL == driver)
00334 {
00335
00336 #ifdef DEBUG_HOTPLUG
00337 Log2(PCSC_LOG_DEBUG, "%s is not a reader", short_name(udi));
00338 #endif
00339 return;
00340 }
00341
00342 Log2(PCSC_LOG_INFO, "Adding USB device: %s", short_name(udi));
00343
00344 (void)snprintf(deviceName, sizeof(deviceName), "usb:%04x/%04x:libhal:%s",
00345 driver->manuID, driver->productID, udi);
00346 deviceName[sizeof(deviceName) -1] = '\0';
00347
00348
00349 (void)SYS_Sleep(1);
00350
00351 (void)SYS_MutexLock(&usbNotifierMutex);
00352
00353
00354 for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00355 {
00356 if (NULL == readerTracker[i].fullName)
00357 break;
00358 }
00359
00360 if (PCSCLITE_MAX_READERS_CONTEXTS == i)
00361 {
00362 Log2(PCSC_LOG_ERROR,
00363 "Not enough reader entries. Already found %d readers", i);
00364 (void)SYS_MutexUnLock(&usbNotifierMutex);
00365 return;
00366 }
00367
00368 readerTracker[i].udi = strdup(udi);
00369
00370 #ifdef ADD_SERIAL_NUMBER
00371 dbus_error_init (&error);
00372
00373 if (libhal_device_property_exists(ctx, udi, "usb.serial", &error))
00374 {
00375 char fullname[MAX_READERNAME];
00376 char *sSerialNumber;
00377
00378 sSerialNumber = libhal_device_get_property_string(ctx, udi,
00379 "usb.serial", &error);
00380
00381 (void)snprintf(fullname, sizeof(fullname), "%s (%s)",
00382 driver->readerName, sSerialNumber);
00383 readerTracker[i].fullName = strdup(fullname);
00384 if (sSerialNumber) {
00385 libhal_free_string(sSerialNumber);
00386 }
00387 }
00388 else
00389 #endif
00390 readerTracker[i].fullName = strdup(driver->readerName);
00391 #ifdef ADD_SERIAL_NUMBER
00392 if (dbus_error_is_set(&error))
00393 dbus_error_free(&error);
00394 #endif
00395
00396 ret = RFAddReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i,
00397 driver->libraryPath, deviceName);
00398 if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
00399 {
00400 char *parent= NULL, *device_file;
00401 char *orig_device_file = NULL;
00402
00403
00404 parent = libhal_device_get_property_string(ctx, udi,
00405 "info.parent", NULL);
00406 if (! parent)
00407 goto error;
00408
00409
00410 device_file = libhal_device_get_property_string(ctx, parent,
00411 "linux.device_file", NULL);
00412 if (! device_file)
00413 goto error;
00414 orig_device_file = device_file;
00415
00416
00417 #define LIBUSB_HEADER "/dev/bus/usb/"
00418 if (strncmp(device_file, LIBUSB_HEADER, strlen(LIBUSB_HEADER)))
00419 goto error;
00420
00421 device_file += strlen(LIBUSB_HEADER);
00422
00423 (void)snprintf(deviceName, sizeof(deviceName),
00424 "usb:%04x/%04x:libusb:%s",
00425 driver->manuID, driver->productID, device_file);
00426 deviceName[sizeof(deviceName) -1] = '\0';
00427
00428
00429 if ('/' == deviceName[strlen(deviceName)-3-1])
00430 deviceName[strlen(deviceName)-3-1] = ':';
00431
00432 Log2(PCSC_LOG_INFO, "trying libusb scheme with: %s", deviceName);
00433 ret = RFAddReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i,
00434 driver->libraryPath, deviceName);
00435
00436 if (SCARD_S_SUCCESS != ret)
00437 {
00438 error:
00439 Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s", short_name(udi));
00440 free(readerTracker[i].fullName);
00441 readerTracker[i].fullName = NULL;
00442 free(readerTracker[i].udi);
00443 readerTracker[i].udi = NULL;
00444
00445 (void)CheckForOpenCT();
00446 }
00447 if (parent) {
00448 libhal_free_string(parent);
00449 }
00450 if (orig_device_file) {
00451 libhal_free_string(orig_device_file);
00452 }
00453 }
00454
00455 (void)SYS_MutexUnLock(&usbNotifierMutex);
00456 }
00457
00458
00459 static void HPRemoveDevice( LibHalContext *ctx, const char *udi)
00460 {
00461 int i;
00462
00463 (void)ctx;
00464 for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00465 {
00466 if (readerTracker[i].udi && strcmp(readerTracker[i].udi, udi) == 0)
00467 break;
00468 }
00469 if (PCSCLITE_MAX_READERS_CONTEXTS == i)
00470 {
00471 #ifdef DEBUG_HOTPLUG
00472 Log2(PCSC_LOG_DEBUG, "USB device %s not already used", short_name(udi));
00473 #endif
00474 return;
00475 }
00476 Log3(PCSC_LOG_INFO, "Removing USB device[%d]: %s", i,
00477 short_name(readerTracker[i].udi));
00478
00479 (void)SYS_MutexLock(&usbNotifierMutex);
00480
00481 (void)RFRemoveReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i);
00482 free(readerTracker[i].fullName);
00483 readerTracker[i].fullName = NULL;
00484 free(readerTracker[i].udi);
00485 readerTracker[i].udi = NULL;
00486
00487 (void)SYS_MutexUnLock(&usbNotifierMutex);
00488
00489 return;
00490 }
00491
00492
00496 ULONG HPRegisterForHotplugEvents(void)
00497 {
00498 char **device_names;
00499 int i, num_devices;
00500 DBusError error;
00501
00502 if (driverSize <= 0)
00503 {
00504 Log1(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: " PCSCLITE_HP_DROPDIR);
00505 Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
00506 return 1;
00507 }
00508
00509 dbus_error_init(&error);
00510 conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
00511 if (conn == NULL)
00512 {
00513 Log3(PCSC_LOG_ERROR, "error: dbus_bus_get: %s: %s",
00514 error.name, error.message);
00515 if (dbus_error_is_set(&error))
00516 dbus_error_free(&error);
00517 return 1;
00518 }
00519
00520 if ((hal_ctx = libhal_ctx_new()) == NULL)
00521 {
00522 Log1(PCSC_LOG_ERROR, "error: libhal_ctx_new");
00523 return 1;
00524 }
00525 if (!libhal_ctx_set_dbus_connection(hal_ctx, conn))
00526 {
00527 Log1(PCSC_LOG_ERROR, "error: libhal_ctx_set_dbus_connection");
00528 return 1;
00529 }
00530 if (!libhal_ctx_init(hal_ctx, &error))
00531 {
00532 if (dbus_error_is_set(&error))
00533 {
00534 Log3(PCSC_LOG_ERROR, "error: libhal_ctx_init: %s: %s",
00535 error.name, error.message);
00536 if (dbus_error_is_set(&error))
00537 dbus_error_free(&error);
00538 }
00539 Log1(PCSC_LOG_ERROR, "Could not initialise connection to hald.");
00540 Log1(PCSC_LOG_ERROR, "Normally this means the HAL daemon (hald) is not running or not ready.");
00541 return 1;
00542 }
00543
00544
00545 (void)libhal_ctx_set_device_added(hal_ctx, HPAddDevice);
00546
00547
00548 (void)libhal_ctx_set_device_removed(hal_ctx, HPRemoveDevice);
00549
00550 device_names = libhal_get_all_devices(hal_ctx, &num_devices, &error);
00551 if (device_names == NULL)
00552 {
00553 if (dbus_error_is_set(&error))
00554 dbus_error_free(&error);
00555 Log1(PCSC_LOG_ERROR, "Couldn't obtain list of devices");
00556 return 1;
00557 }
00558
00559
00560 for (i = 0; i < num_devices; i++)
00561 HPAddDevice(hal_ctx, device_names[i]);
00562
00563 libhal_free_string_array(device_names);
00564
00565 (void)SYS_ThreadCreate(&usbNotifyThread, THREAD_ATTR_DETACHED,
00566 (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, NULL);
00567
00568 return 0;
00569 }
00570
00571
00572 void HPReCheckSerialReaders(void)
00573 {
00574
00575 #ifdef DEBUG_HOTPLUG
00576 Log0(PCSC_LOG_ERROR);
00577 #endif
00578 }
00579
00580 #endif
00581