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