~ubuntu-branches/ubuntu/jaunty/pcsc-lite/jaunty-security

« back to all changes in this revision

Viewing changes to src/hotplug_libusb.c

  • Committer: Bazaar Package Importer
  • Author(s): Ludovic Rousseau
  • Date: 2005-11-27 18:04:59 UTC
  • mfrom: (1.2.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20051127180459-qrex2gzpq9d8jexd
Tags: 1.2.9-beta9-1
* New upstream version
* debian/compat: change from 3 to 4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * MUSCLE SmartCard Development ( http://www.linuxnet.com )
 
3
 *
 
4
 * Copyright (C) 2001-2004
 
5
 *  David Corcoran <corcoran@linuxnet.com>
 
6
 *  Ludovic Rousseau <ludovic.rousseau@free.fr>
 
7
 *  Toni Andjelkovic <toni@soth.at>
 
8
 *  Damien Sauveron <damien.sauveron@labri.fr>
 
9
 *
 
10
 * $Id: hotplug_libusb.c,v 1.3 2005-09-06 20:37:24 rousseau Exp $
 
11
 */
 
12
 
 
13
/**
 
14
 * @file
 
15
 * @brief This provides a search API for hot pluggble devices.
 
16
 */
 
17
 
 
18
#include "config.h"
 
19
#ifdef HAVE_LIBUSB
 
20
 
 
21
#include <string.h>
 
22
#include <sys/types.h>
 
23
#include <stdio.h>
 
24
#include <dirent.h>
 
25
#include <fcntl.h>
 
26
#include <time.h>
 
27
#include <stdlib.h>
 
28
#include <unistd.h>
 
29
#include <errno.h>
 
30
#include <usb.h>
 
31
 
 
32
#include "pcsclite.h"
 
33
#include "debuglog.h"
 
34
#include "parser.h"
 
35
#include "readerfactory.h"
 
36
#include "winscard_msg.h"
 
37
#include "sys_generic.h"
 
38
#include "hotplug.h"
 
39
 
 
40
#undef DEBUG_HOTPLUG
 
41
 
 
42
#define BUS_DEVICE_STRSIZE      256
 
43
 
 
44
#define READER_ABSENT           0
 
45
#define READER_PRESENT          1
 
46
#define READER_FAILED           2
 
47
 
 
48
#define FALSE                   0
 
49
#define TRUE                    1
 
50
 
 
51
extern PCSCLITE_MUTEX usbNotifierMutex;
 
52
 
 
53
static PCSCLITE_THREAD_T usbNotifyThread;
 
54
static int driverSize = -1;
 
55
static char AraKiriHotPlug = FALSE;
 
56
char ReCheckSerialReaders = FALSE;
 
57
 
 
58
/*
 
59
 * keep track of drivers in a dynamically allocated array
 
60
 */
 
61
static struct _driverTracker
 
62
{
 
63
        long manuID;
 
64
        long productID;
 
65
 
 
66
        char *bundleName;
 
67
        char *libraryPath;
 
68
        char *readerName;
 
69
} *driverTracker = NULL;
 
70
#define DRIVER_TRACKER_SIZE_STEP 8
 
71
 
 
72
/*
 
73
 * keep track of PCSCLITE_MAX_READERS_CONTEXTS simultaneous readers
 
74
 */
 
75
static struct _readerTracker
 
76
{
 
77
        char status;
 
78
        char bus_device[BUS_DEVICE_STRSIZE];    /* device name */
 
79
 
 
80
        struct _driverTracker *driver;  /* driver for this reader */
 
81
} readerTracker[PCSCLITE_MAX_READERS_CONTEXTS];
 
82
 
 
83
LONG HPReadBundleValues(void);
 
84
LONG HPAddHotPluggable(struct usb_device *dev, const char bus_device[],
 
85
        struct _driverTracker *driver);
 
86
LONG HPRemoveHotPluggable(int index);
 
87
 
 
88
LONG HPReadBundleValues(void)
 
89
{
 
90
        LONG rv;
 
91
        DIR *hpDir;
 
92
        struct dirent *currFP = 0;
 
93
        char fullPath[FILENAME_MAX];
 
94
        char fullLibPath[FILENAME_MAX];
 
95
        char keyValue[TOKEN_MAX_VALUE_SIZE];
 
96
        int listCount = 0;
 
97
 
 
98
        hpDir = opendir(PCSCLITE_HP_DROPDIR);
 
99
 
 
100
        if (hpDir == NULL)
 
101
        {
 
102
                Log1(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: " PCSCLITE_HP_DROPDIR);
 
103
                Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd.");
 
104
                return -1;
 
105
        }
 
106
 
 
107
        /* allocate a first array */
 
108
        driverTracker = calloc(DRIVER_TRACKER_SIZE_STEP, sizeof(*driverTracker));
 
109
        if (NULL == driverTracker)
 
110
        {
 
111
                Log1(PCSC_LOG_CRITICAL, "Not enough memory");
 
112
                return -1;
 
113
        }
 
114
        driverSize = DRIVER_TRACKER_SIZE_STEP;
 
115
 
 
116
        while ((currFP = readdir(hpDir)) != 0)
 
117
        {
 
118
                if (strstr(currFP->d_name, ".bundle") != 0)
 
119
                {
 
120
                        int alias = 0;
 
121
 
 
122
                        /*
 
123
                         * The bundle exists - let's form a full path name and get the
 
124
                         * vendor and product ID's for this particular bundle
 
125
                         */
 
126
                        snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist",
 
127
                                PCSCLITE_HP_DROPDIR, currFP->d_name);
 
128
                        fullPath[sizeof(fullPath) - 1] = '\0';
 
129
 
 
130
                        /* while we find a nth ifdVendorID in Info.plist */
 
131
                        while (LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_MANUKEY_NAME,
 
132
                                keyValue, alias) == 0)
 
133
                        {
 
134
                                driverTracker[listCount].bundleName = strdup(currFP->d_name);
 
135
 
 
136
                                /* Get ifdVendorID */
 
137
                                rv = LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_MANUKEY_NAME,
 
138
                                        keyValue, alias);
 
139
                                if (rv == 0)
 
140
                                        driverTracker[listCount].manuID = strtol(keyValue, 0, 16);
 
141
 
 
142
                                /* get ifdProductID */
 
143
                                rv = LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_PRODKEY_NAME,
 
144
                                        keyValue, alias);
 
145
                                if (rv == 0)
 
146
                                        driverTracker[listCount].productID =
 
147
                                                strtol(keyValue, 0, 16);
 
148
 
 
149
                                /* get ifdFriendlyName */
 
150
                                rv = LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_NAMEKEY_NAME,
 
151
                                        keyValue, alias);
 
152
                                if (rv == 0)
 
153
                                        driverTracker[listCount].readerName = strdup(keyValue);
 
154
 
 
155
                                /* get CFBundleExecutable */
 
156
                                rv = LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_LIBRKEY_NAME,
 
157
                                        keyValue, 0);
 
158
                                if (rv == 0)
 
159
                                {
 
160
                                        snprintf(fullLibPath, sizeof(fullLibPath),
 
161
                                                "%s/%s/Contents/%s/%s",
 
162
                                                PCSCLITE_HP_DROPDIR, currFP->d_name, PCSC_ARCH, keyValue);
 
163
                                        fullLibPath[sizeof(fullLibPath) - 1] = '\0';
 
164
                                        driverTracker[listCount].libraryPath = strdup(fullLibPath);
 
165
                                }
 
166
 
 
167
#ifdef DEBUG_HOTPLUG
 
168
                                        Log2(PCSC_LOG_INFO, "Found driver for: %s",
 
169
                                                driverTracker[listCount].readerName);
 
170
#endif
 
171
 
 
172
                                listCount++;
 
173
                                alias++;
 
174
 
 
175
                                if (listCount >= driverSize)
 
176
                                {
 
177
                                        int i;
 
178
 
 
179
                                        /* increase the array size */
 
180
                                        driverSize += DRIVER_TRACKER_SIZE_STEP;
 
181
#ifdef DEBUG_HOTPLUG
 
182
                                        Log2(PCSC_LOG_INFO,
 
183
                                                "Increase driverTracker to %d entries", driverSize);
 
184
#endif
 
185
                                        driverTracker = realloc(driverTracker,
 
186
                                                driverSize * sizeof(*driverTracker));
 
187
                                        if (NULL == driverTracker)
 
188
                                        {
 
189
                                                Log1(PCSC_LOG_CRITICAL, "Not enough memory");
 
190
                                                driverSize = -1;
 
191
                                                return -1;
 
192
                                        }
 
193
 
 
194
                                        /* clean the newly allocated entries */
 
195
                                        for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++)
 
196
                                        {
 
197
                                                driverTracker[i].manuID = 0;
 
198
                                                driverTracker[i].productID = 0;
 
199
                                                driverTracker[i].bundleName = NULL;
 
200
                                                driverTracker[i].libraryPath = NULL;
 
201
                                                driverTracker[i].readerName = NULL;
 
202
                                        }
 
203
                                }
 
204
                        }
 
205
                }
 
206
        }
 
207
 
 
208
        driverSize = listCount;
 
209
        closedir(hpDir);
 
210
 
 
211
        rv = TRUE;
 
212
        if (driverSize == 0)
 
213
        {
 
214
                Log1(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: " PCSCLITE_HP_DROPDIR);
 
215
                Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
 
216
                rv = FALSE;
 
217
        }
 
218
#ifdef DEBUG_HOTPLUG
 
219
        else
 
220
                Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount);
 
221
#endif
 
222
 
 
223
        return rv;
 
224
}
 
225
 
 
226
void HPEstablishUSBNotifications(void)
 
227
{
 
228
        int i, j;
 
229
        struct usb_bus *bus;
 
230
        struct usb_device *dev;
 
231
        char bus_device[BUS_DEVICE_STRSIZE];
 
232
 
 
233
        usb_init();
 
234
        while (1)
 
235
        {
 
236
                usb_find_busses();
 
237
                usb_find_devices();
 
238
 
 
239
                for (i=0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
 
240
                        /* clear rollcall */
 
241
                        readerTracker[i].status = READER_ABSENT;
 
242
 
 
243
                /* For each USB bus */
 
244
                for (bus = usb_get_busses(); bus; bus = bus->next)
 
245
                {
 
246
                        /* For each USB device */
 
247
                        for (dev = bus->devices; dev; dev = dev->next)
 
248
                        {
 
249
                                /* check if the device is supported by one driver */
 
250
                                for (i=0; i<driverSize; i++)
 
251
                                {
 
252
                                        if (driverTracker[i].libraryPath != NULL &&
 
253
                                                dev->descriptor.idVendor == driverTracker[i].manuID &&
 
254
                                                dev->descriptor.idProduct == driverTracker[i].productID)
 
255
                                        {
 
256
                                                int newreader;
 
257
 
 
258
                                                /* A known device has been found */
 
259
                                                snprintf(bus_device, BUS_DEVICE_STRSIZE, "%s:%s",
 
260
                                                        bus->dirname, dev->filename);
 
261
                                                bus_device[BUS_DEVICE_STRSIZE - 1] = '\0';
 
262
#ifdef DEBUG_HOTPLUG
 
263
                                                Log2(PCSC_LOG_DEBUG, "Found matching USB device: %s", bus_device);
 
264
#endif
 
265
                                                newreader = TRUE;
 
266
 
 
267
                                                /* Check if the reader is a new one */
 
268
                                                for (j=0; j<PCSCLITE_MAX_READERS_CONTEXTS; j++)
 
269
                                                {
 
270
                                                        if (strncmp(readerTracker[j].bus_device,
 
271
                                                                bus_device, BUS_DEVICE_STRSIZE) == 0)
 
272
                                                        {
 
273
                                                                /* The reader is already known */
 
274
                                                                readerTracker[j].status = READER_PRESENT;
 
275
                                                                newreader = FALSE;
 
276
#ifdef DEBUG_HOTPLUG
 
277
                                                                Log2(PCSC_LOG_DEBUG, "Refresh USB device: %s", bus_device);
 
278
#endif
 
279
                                                                break;
 
280
                                                        }
 
281
                                                }
 
282
 
 
283
                                                /* New reader found */
 
284
                                                if (newreader)
 
285
                                                        HPAddHotPluggable(dev, bus_device, &driverTracker[i]);
 
286
                                        }
 
287
                                }
 
288
                        } /* End of USB device for..loop */
 
289
 
 
290
                } /* End of USB bus for..loop */
 
291
 
 
292
                /*
 
293
                 * check if all the previously found readers are still present
 
294
                 */
 
295
                for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
 
296
                {
 
297
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
 
298
                        int fd;
 
299
                        char filename[BUS_DEVICE_STRSIZE];
 
300
 
 
301
                        /*      BSD workaround:
 
302
                         *      ugenopen() in sys/dev/usb/ugen.c returns EBUSY
 
303
                         *      when the character device file is already open.
 
304
                         *      Because of this, open usb devices will not be
 
305
                         *      detected by usb_find_devices(), so we have to
 
306
                         *      check for this explicitly.
 
307
                         */
 
308
                        if (readerTracker[i].status == READER_PRESENT ||
 
309
                                 readerTracker[i].driver == NULL)
 
310
                                continue;
 
311
 
 
312
                        sscanf(readerTracker[i].bus_device, "%*[^:]%*[:]%s", filename);
 
313
                        fd = open(filename, O_RDONLY);
 
314
                        if (fd == -1)
 
315
                        {
 
316
                                if (errno == EBUSY)
 
317
                                {
 
318
                                        /* The device is present */
 
319
#ifdef DEBUG_HOTPLUG
 
320
                                        Log2(PCSC_LOG_DEBUG, "BSD: EBUSY on %s", filename);
 
321
#endif
 
322
                                        readerTracker[i].status = READER_PRESENT;
 
323
                                }
 
324
#ifdef DEBUG_HOTPLUG
 
325
                                else
 
326
                                        Log3(PCSC_LOG_DEBUG, "BSD: %s error: %s", filename,
 
327
                                                strerror(errno));
 
328
#endif
 
329
                        }
 
330
                        else
 
331
                        {
 
332
#ifdef DEBUG_HOTPLUG
 
333
                                Log2(PCSC_LOG_DEBUG, "BSD: %s still present", filename);
 
334
#endif
 
335
                                readerTracker[i].status = READER_PRESENT;
 
336
                                close(fd);
 
337
                        }
 
338
#endif
 
339
                        if (readerTracker[i].status == READER_ABSENT &&
 
340
                                        readerTracker[i].driver != NULL)
 
341
                                HPRemoveHotPluggable(i);
 
342
                }
 
343
 
 
344
                SYS_Sleep(1);
 
345
                if (AraKiriHotPlug)
 
346
                {
 
347
                        int retval;
 
348
 
 
349
                        for (i=0; i<driverSize; i++)
 
350
                        {
 
351
                                /* free strings allocated by strdup() */
 
352
                                free(driverTracker[i].bundleName);
 
353
                                free(driverTracker[i].libraryPath);
 
354
                                free(driverTracker[i].readerName);
 
355
                        }
 
356
                        free(driverTracker);
 
357
 
 
358
                        Log1(PCSC_LOG_INFO, "Hotplug stopped");
 
359
                        pthread_exit(&retval);
 
360
                }
 
361
 
 
362
                if (ReCheckSerialReaders)
 
363
                {
 
364
                        ReCheckSerialReaders = FALSE;
 
365
                        RFReCheckReaderConf();
 
366
                }
 
367
 
 
368
        }       /* End of while loop */
 
369
}
 
370
 
 
371
LONG HPSearchHotPluggables(void)
 
372
{
 
373
        int i;
 
374
 
 
375
        for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
 
376
        {
 
377
                readerTracker[i].driver = NULL;
 
378
                readerTracker[i].status = READER_ABSENT;
 
379
                readerTracker[i].bus_device[0] = '\0';
 
380
        }
 
381
 
 
382
        if (HPReadBundleValues())
 
383
                SYS_ThreadCreate(&usbNotifyThread, THREAD_ATTR_DETACHED,
 
384
                        (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, 0);
 
385
 
 
386
        return 0;
 
387
}
 
388
 
 
389
LONG HPStopHotPluggables(void)
 
390
{
 
391
        AraKiriHotPlug = TRUE;
 
392
 
 
393
        return 0;
 
394
}
 
395
 
 
396
LONG HPAddHotPluggable(struct usb_device *dev, const char bus_device[],
 
397
        struct _driverTracker *driver)
 
398
{
 
399
        int i;
 
400
        char deviceName[MAX_DEVICENAME];
 
401
 
 
402
        SYS_MutexLock(&usbNotifierMutex);
 
403
 
 
404
        Log2(PCSC_LOG_INFO, "Adding USB device: %s", bus_device);
 
405
 
 
406
        snprintf(deviceName, sizeof(deviceName), "usb:%04x/%04x:libusb:%s",
 
407
                dev->descriptor.idVendor, dev->descriptor.idProduct, bus_device);
 
408
        deviceName[sizeof(deviceName) -1] = '\0';
 
409
 
 
410
        /* find a free entry */
 
411
        for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
 
412
        {
 
413
                if (readerTracker[i].driver == NULL)
 
414
                        break;
 
415
        }
 
416
 
 
417
        if (i==PCSCLITE_MAX_READERS_CONTEXTS)
 
418
        {
 
419
                Log2(PCSC_LOG_ERROR,
 
420
                        "Not enough reader entries. Already found %d readers", i);
 
421
                return 0;
 
422
        }
 
423
 
 
424
        strncpy(readerTracker[i].bus_device, bus_device,
 
425
                sizeof(readerTracker[i].bus_device));
 
426
        readerTracker[i].bus_device[sizeof(readerTracker[i].bus_device) - 1] = '\0';
 
427
   
 
428
        readerTracker[i].driver = driver;
 
429
 
 
430
        if (RFAddReader(driver->readerName, PCSCLITE_HP_BASE_PORT + i,
 
431
                driver->libraryPath, deviceName) == SCARD_S_SUCCESS)
 
432
                readerTracker[i].status = READER_PRESENT;
 
433
        else
 
434
                readerTracker[i].status = READER_FAILED;
 
435
 
 
436
        SYS_MutexUnLock(&usbNotifierMutex);
 
437
 
 
438
        return 1;
 
439
}       /* End of function */
 
440
 
 
441
LONG HPRemoveHotPluggable(int index)
 
442
{
 
443
        SYS_MutexLock(&usbNotifierMutex);
 
444
 
 
445
        Log3(PCSC_LOG_INFO, "Removing USB device[%d]: %s", index,
 
446
                readerTracker[index].bus_device);
 
447
 
 
448
        RFRemoveReader(readerTracker[index].driver->readerName,
 
449
                PCSCLITE_HP_BASE_PORT + index);
 
450
        readerTracker[index].status = READER_ABSENT;
 
451
        readerTracker[index].bus_device[0] = '\0';
 
452
        readerTracker[index].driver = NULL;
 
453
 
 
454
        SYS_MutexUnLock(&usbNotifierMutex);
 
455
 
 
456
        return 1;
 
457
}       /* End of function */
 
458
 
 
459
/*
 
460
 * Sets up callbacks for device hotplug events.
 
461
 */
 
462
ULONG HPRegisterForHotplugEvents(void)
 
463
{
 
464
        return 0;
 
465
}
 
466
 
 
467
void HPReCheckSerialReaders(void)
 
468
{
 
469
        ReCheckSerialReaders = TRUE;
 
470
}
 
471
 
 
472
#endif
 
473