1 /*
2  * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3  *
4  * Copyright (C) 2011
5  *  Ludovic Rousseau <ludovic.rousseau@free.fr>
6  * Copyright (C) 2014
7  *  Stefani Seibold <stefani@seibold.net>
8  *
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions
11 are met:
12 
13 1. Redistributions of source code must retain the above copyright
14    notice, this list of conditions and the following disclaimer.
15 2. Redistributions in binary form must reproduce the above copyright
16    notice, this list of conditions and the following disclaimer in the
17    documentation and/or other materials provided with the distribution.
18 3. The name of the author may not be used to endorse or promote products
19    derived from this software without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /**
34  * @file
35  * @brief This provides a search API for hot plugable devices using libudev
36  */
37 
38 #include "config.h"
39 #if defined(HAVE_LIBUDEV) && defined(USE_USB)
40 
41 #define _GNU_SOURCE		/* for asprintf(3) */
42 #include <string.h>
43 #include <stdio.h>
44 #include <dirent.h>
45 #include <stdlib.h>
46 #include <pthread.h>
47 #include <libudev.h>
48 #include <poll.h>
49 #include <ctype.h>
50 
51 #include "debuglog.h"
52 #include "parser.h"
53 #include "readerfactory.h"
54 #include "sys_generic.h"
55 #include "hotplug.h"
56 #include "utils.h"
57 
58 #ifndef TEMP_FAILURE_RETRY
59 #define TEMP_FAILURE_RETRY(expression) \
60   (__extension__							      \
61     ({ long int __result;						      \
62        do __result = (long int) (expression);				      \
63        while (__result == -1L && errno == EINTR);			      \
64        __result; }))
65 #endif
66 
67 #undef DEBUG_HOTPLUG
68 
69 #define FALSE			0
70 #define TRUE			1
71 
72 extern char Add_Interface_In_Name;
73 extern char Add_Serial_In_Name;
74 
75 static pthread_t usbNotifyThread;
76 static int driverSize = -1;
77 static struct udev *Udev;
78 
79 
80 /**
81  * keep track of drivers in a dynamically allocated array
82  */
83 static struct _driverTracker
84 {
85 	unsigned int manuID;
86 	unsigned int productID;
87 
88 	char *bundleName;
89 	char *libraryPath;
90 	char *readerName;
91 	char *CFBundleName;
92 } *driverTracker = NULL;
93 #define DRIVER_TRACKER_SIZE_STEP 10
94 
95 /* The CCID driver already supports 176 readers.
96  * We start with a big array size to avoid reallocation. */
97 #define DRIVER_TRACKER_INITIAL_SIZE 200
98 
99 /**
100  * keep track of PCSCLITE_MAX_READERS_CONTEXTS simultaneous readers
101  */
102 static struct _readerTracker
103 {
104 	char *devpath;	/**< device name seen by udev */
105 	char *fullName;	/**< full reader name (including serial number) */
106 	char *sysname;	/**< sysfs path */
107 } readerTracker[PCSCLITE_MAX_READERS_CONTEXTS];
108 
109 
HPReadBundleValues(void)110 static LONG HPReadBundleValues(void)
111 {
112 	LONG rv;
113 	DIR *hpDir;
114 	struct dirent *currFP = NULL;
115 	char fullPath[FILENAME_MAX];
116 	char fullLibPath[FILENAME_MAX];
117 	int listCount = 0;
118 
119 	hpDir = opendir(PCSCLITE_HP_DROPDIR);
120 
121 	if (NULL == hpDir)
122 	{
123 		Log1(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: " PCSCLITE_HP_DROPDIR);
124 		Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd.");
125 		return -1;
126 	}
127 
128 	/* allocate a first array */
129 	driverSize = DRIVER_TRACKER_INITIAL_SIZE;
130 	driverTracker = calloc(driverSize, sizeof(*driverTracker));
131 	if (NULL == driverTracker)
132 	{
133 		Log1(PCSC_LOG_CRITICAL, "Not enough memory");
134 		(void)closedir(hpDir);
135 		return -1;
136 	}
137 
138 #define GET_KEY(key, values) \
139 	rv = LTPBundleFindValueWithKey(&plist, key, values); \
140 	if (rv) \
141 	{ \
142 		Log2(PCSC_LOG_ERROR, "Value/Key not defined for " key " in %s", \
143 			fullPath); \
144 		continue; \
145 	}
146 
147 	while ((currFP = readdir(hpDir)) != 0)
148 	{
149 		if (strstr(currFP->d_name, ".bundle") != 0)
150 		{
151 			unsigned int alias;
152 			list_t plist, *values;
153 			list_t *manuIDs, *productIDs, *readerNames;
154 			char *CFBundleName;
155 			char *libraryPath;
156 
157 			/*
158 			 * The bundle exists - let's form a full path name and get the
159 			 * vendor and product ID's for this particular bundle
160 			 */
161 			(void)snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist",
162 				PCSCLITE_HP_DROPDIR, currFP->d_name);
163 			fullPath[sizeof(fullPath) - 1] = '\0';
164 
165 			rv = bundleParse(fullPath, &plist);
166 			if (rv)
167 				continue;
168 
169 			/* get CFBundleExecutable */
170 			GET_KEY(PCSCLITE_HP_LIBRKEY_NAME, &values)
171 			libraryPath = list_get_at(values, 0);
172 			(void)snprintf(fullLibPath, sizeof(fullLibPath),
173 				"%s/%s/Contents/%s/%s",
174 				PCSCLITE_HP_DROPDIR, currFP->d_name, PCSC_ARCH,
175 				libraryPath);
176 			fullLibPath[sizeof(fullLibPath) - 1] = '\0';
177 
178 			GET_KEY(PCSCLITE_HP_MANUKEY_NAME, &manuIDs)
179 			GET_KEY(PCSCLITE_HP_PRODKEY_NAME, &productIDs)
180 			GET_KEY(PCSCLITE_HP_NAMEKEY_NAME, &readerNames)
181 
182 			if  ((list_size(manuIDs) != list_size(productIDs))
183 				|| (list_size(manuIDs) != list_size(readerNames)))
184 			{
185 				Log2(PCSC_LOG_CRITICAL, "Error parsing %s", fullPath);
186 				(void)closedir(hpDir);
187 				return -1;
188 			}
189 
190 			/* Get CFBundleName */
191 			rv = LTPBundleFindValueWithKey(&plist, PCSCLITE_HP_CFBUNDLE_NAME,
192 				&values);
193 			if (rv)
194 				CFBundleName = NULL;
195 			else
196 				CFBundleName = strdup(list_get_at(values, 0));
197 
198 			/* while we find a nth ifdVendorID in Info.plist */
199 			for (alias=0; alias<list_size(manuIDs); alias++)
200 			{
201 				char *value;
202 
203 				/* variables entries */
204 				value = list_get_at(manuIDs, alias);
205 				driverTracker[listCount].manuID = strtol(value, NULL, 16);
206 
207 				value = list_get_at(productIDs, alias);
208 				driverTracker[listCount].productID = strtol(value, NULL, 16);
209 
210 				driverTracker[listCount].readerName = strdup(list_get_at(readerNames, alias));
211 
212 				/* constant entries for a same driver */
213 				driverTracker[listCount].bundleName = strdup(currFP->d_name);
214 				driverTracker[listCount].libraryPath = strdup(fullLibPath);
215 				driverTracker[listCount].CFBundleName = CFBundleName;
216 
217 #ifdef DEBUG_HOTPLUG
218 				Log2(PCSC_LOG_INFO, "Found driver for: %s",
219 					driverTracker[listCount].readerName);
220 #endif
221 				listCount++;
222 				if (listCount >= driverSize)
223 				{
224 					int i;
225 
226 					/* increase the array size */
227 					driverSize += DRIVER_TRACKER_SIZE_STEP;
228 #ifdef DEBUG_HOTPLUG
229 					Log2(PCSC_LOG_INFO,
230 						"Increase driverTracker to %d entries", driverSize);
231 #endif
232 
233 					void* tmp = realloc(driverTracker,
234 						driverSize * sizeof(*driverTracker));
235 
236 					if (NULL == tmp)
237 					{
238 						free(driverTracker);
239 						Log1(PCSC_LOG_CRITICAL, "Not enough memory");
240 						driverSize = -1;
241 						(void)closedir(hpDir);
242 						return -1;
243 					}
244 					driverTracker = tmp;
245 
246 					/* clean the newly allocated entries */
247 					for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++)
248 					{
249 						driverTracker[i].manuID = 0;
250 						driverTracker[i].productID = 0;
251 						driverTracker[i].bundleName = NULL;
252 						driverTracker[i].libraryPath = NULL;
253 						driverTracker[i].readerName = NULL;
254 						driverTracker[i].CFBundleName = NULL;
255 					}
256 				}
257 			}
258 			bundleRelease(&plist);
259 		}
260 	}
261 
262 	driverSize = listCount;
263 	(void)closedir(hpDir);
264 
265 #ifdef DEBUG_HOTPLUG
266 	Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount);
267 #endif
268 
269 	return 0;
270 } /* HPReadBundleValues */
271 
272 
get_driver(struct udev_device * dev,const char * devpath,struct _driverTracker ** classdriver)273 /*@null@*/ static struct _driverTracker *get_driver(struct udev_device *dev,
274 	const char *devpath, struct _driverTracker **classdriver)
275 {
276 	int i;
277 	unsigned int idVendor, idProduct;
278 	static struct _driverTracker *driver;
279 	const char *str;
280 
281 	str = udev_device_get_sysattr_value(dev, "idVendor");
282 	if (!str)
283 	{
284 		Log1(PCSC_LOG_ERROR, "udev_device_get_sysattr_value() failed");
285 		return NULL;
286 	}
287 	idVendor = strtol(str, NULL, 16);
288 
289 	str = udev_device_get_sysattr_value(dev, "idProduct");
290 	if (!str)
291 	{
292 		Log1(PCSC_LOG_ERROR, "udev_device_get_sysattr_value() failed");
293 		return NULL;
294 	}
295 	idProduct = strtol(str, NULL, 16);
296 
297 #ifdef NO_LOG
298 	(void)devpath;
299 #endif
300 	Log4(PCSC_LOG_DEBUG,
301 		"Looking for a driver for VID: 0x%04X, PID: 0x%04X, path: %s",
302 		idVendor, idProduct, devpath);
303 
304 	*classdriver = NULL;
305 	driver = NULL;
306 	/* check if the device is supported by one driver */
307 	for (i=0; i<driverSize; i++)
308 	{
309 		if (driverTracker[i].libraryPath != NULL &&
310 			idVendor == driverTracker[i].manuID &&
311 			idProduct == driverTracker[i].productID)
312 		{
313 			if ((driverTracker[i].CFBundleName != NULL)
314 				&& (0 == strcmp(driverTracker[i].CFBundleName, "CCIDCLASSDRIVER")))
315 				*classdriver = &driverTracker[i];
316 			else
317 				/* it is not a CCID Class driver */
318 				driver = &driverTracker[i];
319 		}
320 	}
321 
322 	/* if we found a specific driver */
323 	if (driver)
324 		return driver;
325 
326 	/* else return the Class driver (if any) */
327 	return *classdriver;
328 }
329 
330 
HPRemoveDevice(struct udev_device * dev)331 static void HPRemoveDevice(struct udev_device *dev)
332 {
333 	int i;
334 	const char *devpath;
335 	struct udev_device *parent;
336 	const char *sysname;
337 
338 	/* The device pointed to by dev contains information about
339 	   the interface. In order to get information about the USB
340 	   device, get the parent device with the subsystem/devtype pair
341 	   of "usb"/"usb_device". This will be several levels up the
342 	   tree, but the function will find it.*/
343 	parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb",
344 		"usb_device");
345 	if (!parent)
346 		return;
347 
348 	devpath = udev_device_get_devnode(parent);
349 	if (!devpath)
350 	{
351 		/* the device disapeared? */
352 		Log1(PCSC_LOG_ERROR, "udev_device_get_devnode() failed");
353 		return;
354 	}
355 
356 	sysname = udev_device_get_sysname(dev);
357 	if (!sysname)
358 	{
359 		Log1(PCSC_LOG_ERROR, "udev_device_get_sysname() failed");
360 		return;
361 	}
362 
363 	for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
364 	{
365 		if (readerTracker[i].fullName && !strcmp(sysname, readerTracker[i].sysname))
366 		{
367 			Log4(PCSC_LOG_INFO, "Removing USB device[%d]: %s at %s", i,
368 				readerTracker[i].fullName, readerTracker[i].devpath);
369 
370 			RFRemoveReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i);
371 
372 			free(readerTracker[i].devpath);
373 			readerTracker[i].devpath = NULL;
374 			free(readerTracker[i].fullName);
375 			readerTracker[i].fullName = NULL;
376 			free(readerTracker[i].sysname);
377 			readerTracker[i].sysname = NULL;
378 			break;
379 		}
380 	}
381 }
382 
383 
HPAddDevice(struct udev_device * dev)384 static void HPAddDevice(struct udev_device *dev)
385 {
386 	int index, a;
387 	char *deviceName = NULL;
388 	char *fullname = NULL;
389 	struct _driverTracker *driver, *classdriver;
390 	const char *sSerialNumber = NULL, *sInterfaceName = NULL;
391 	const char *sInterfaceNumber;
392 	LONG ret;
393 	int bInterfaceNumber;
394 	const char *devpath;
395 	struct udev_device *parent;
396 	const char *sysname;
397 
398 	/* The device pointed to by dev contains information about
399 	   the interface. In order to get information about the USB
400 	   device, get the parent device with the subsystem/devtype pair
401 	   of "usb"/"usb_device". This will be several levels up the
402 	   tree, but the function will find it.*/
403 	parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb",
404 		"usb_device");
405 	if (!parent)
406 		return;
407 
408 	devpath = udev_device_get_devnode(parent);
409 	if (!devpath)
410 	{
411 		/* the device disapeared? */
412 		Log1(PCSC_LOG_ERROR, "udev_device_get_devnode() failed");
413 		return;
414 	}
415 
416 	driver = get_driver(parent, devpath, &classdriver);
417 	if (NULL == driver)
418 	{
419 		/* not a smart card reader */
420 #ifdef DEBUG_HOTPLUG
421 		Log2(PCSC_LOG_DEBUG, "%s is not a supported smart card reader",
422 			devpath);
423 #endif
424 		return;
425 	}
426 
427 	sysname = udev_device_get_sysname(dev);
428 	if (!sysname)
429 	{
430 		Log1(PCSC_LOG_ERROR, "udev_device_get_sysname() failed");
431 		return;
432 	}
433 
434 	/* check for duplicated add */
435 	for (index=0; index<PCSCLITE_MAX_READERS_CONTEXTS; index++)
436 	{
437 		if (readerTracker[index].fullName && !strcmp(sysname, readerTracker[index].sysname))
438 			return;
439 	}
440 
441 	Log2(PCSC_LOG_INFO, "Adding USB device: %s", driver->readerName);
442 
443 	sInterfaceNumber = udev_device_get_sysattr_value(dev, "bInterfaceNumber");
444 	if (sInterfaceNumber)
445 		bInterfaceNumber = atoi(sInterfaceNumber);
446 	else
447 		bInterfaceNumber = 0;
448 
449 	a = asprintf(&deviceName, "usb:%04x/%04x:libudev:%d:%s",
450 		driver->manuID, driver->productID, bInterfaceNumber, devpath);
451 	if (-1 ==  a)
452 	{
453 		Log1(PCSC_LOG_ERROR, "asprintf() failed");
454 		return;
455 	}
456 
457 	/* find a free entry */
458 	for (index=0; index<PCSCLITE_MAX_READERS_CONTEXTS; index++)
459 	{
460 		if (NULL == readerTracker[index].fullName)
461 			break;
462 	}
463 
464 	if (PCSCLITE_MAX_READERS_CONTEXTS == index)
465 	{
466 		Log2(PCSC_LOG_ERROR,
467 			"Not enough reader entries. Already found %d readers", index);
468 		return;
469 	}
470 
471 	if (Add_Interface_In_Name)
472 		sInterfaceName = udev_device_get_sysattr_value(dev, "interface");
473 
474 	if (Add_Serial_In_Name)
475 		sSerialNumber = udev_device_get_sysattr_value(parent, "serial");
476 
477 	/* name from the Info.plist file */
478 	fullname = strdup(driver->readerName);
479 
480 	/* interface name from the device (if any) */
481 	if (sInterfaceName)
482 	{
483 		char *result;
484 
485 		char *tmpInterfaceName = strdup(sInterfaceName);
486 
487 		/* check the interface name contains only valid ASCII codes */
488 		for (size_t i=0; i<strlen(tmpInterfaceName); i++)
489 		{
490 			if (! isascii(tmpInterfaceName[i]))
491 				tmpInterfaceName[i] = '.';
492 		}
493 
494 		/* create a new name */
495 		a = asprintf(&result, "%s [%s]", fullname, tmpInterfaceName);
496 		if (-1 ==  a)
497 		{
498 			Log1(PCSC_LOG_ERROR, "asprintf() failed");
499 			free(tmpInterfaceName);
500 			goto exit;
501 		}
502 
503 		free(fullname);
504 		free(tmpInterfaceName);
505 		fullname = result;
506 	}
507 
508 	/* serial number from the device (if any) */
509 	if (sSerialNumber)
510 	{
511 		/* only add the serial number if it is not already present in the
512 		 * interface name */
513 		if (!sInterfaceName || NULL == strstr(sInterfaceName, sSerialNumber))
514 		{
515 			char *result;
516 
517 			/* create a new name */
518 			a = asprintf(&result, "%s (%s)", fullname, sSerialNumber);
519 			if (-1 ==  a)
520 			{
521 				Log1(PCSC_LOG_ERROR, "asprintf() failed");
522 				goto exit;
523 			}
524 
525 			free(fullname);
526 			fullname = result;
527 		}
528 	}
529 
530 	readerTracker[index].fullName = strdup(fullname);
531 	readerTracker[index].devpath = strdup(devpath);
532 	readerTracker[index].sysname = strdup(sysname);
533 
534 	ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + index,
535 		driver->libraryPath, deviceName);
536 	if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
537 	{
538 		Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
539 			driver->readerName);
540 
541 		if (classdriver && driver != classdriver)
542 		{
543 			/* the reader can also be used by the a class driver */
544 			ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + index,
545 				classdriver->libraryPath, deviceName);
546 			if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
547 			{
548 				Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
549 						driver->readerName);
550 				(void)CheckForOpenCT();
551 			}
552 		}
553 		else
554 		{
555 			(void)CheckForOpenCT();
556 		}
557 	}
558 
559 	if (SCARD_S_SUCCESS != ret)
560 	{
561 		/* adding the reader failed */
562 		free(readerTracker[index].devpath);
563 		readerTracker[index].devpath = NULL;
564 		free(readerTracker[index].fullName);
565 		readerTracker[index].fullName = NULL;
566 		free(readerTracker[index].sysname);
567 		readerTracker[index].sysname = NULL;
568 	}
569 
570 exit:
571 	free(fullname);
572 	free(deviceName);
573 } /* HPAddDevice */
574 
575 
HPScanUSB(struct udev * udev)576 static void HPScanUSB(struct udev *udev)
577 {
578 	struct udev_enumerate *enumerate;
579 	struct udev_list_entry *devices, *dev_list_entry;
580 
581 	/* Create a list of the devices in the 'usb' subsystem. */
582 	enumerate = udev_enumerate_new(udev);
583 	udev_enumerate_add_match_subsystem(enumerate, "usb");
584 	udev_enumerate_scan_devices(enumerate);
585 	devices = udev_enumerate_get_list_entry(enumerate);
586 
587 	/* For each item enumerated */
588 	udev_list_entry_foreach(dev_list_entry, devices)
589 	{
590 		struct udev_device *dev;
591 		const char *devpath;
592 
593 		/* Get the filename of the /sys entry for the device
594 		   and create a udev_device object (dev) representing it */
595 		devpath = udev_list_entry_get_name(dev_list_entry);
596 		dev = udev_device_new_from_syspath(udev, devpath);
597 
598 #ifdef DEBUG_HOTPLUG
599 		Log2(PCSC_LOG_DEBUG, "Found matching USB device: %s", devpath);
600 #endif
601 		HPAddDevice(dev);
602 
603 		/* free device */
604 		udev_device_unref(dev);
605 	}
606 
607 	/* Free the enumerator object */
608 	udev_enumerate_unref(enumerate);
609 }
610 
611 
HPEstablishUSBNotifications(void * arg)612 static void * HPEstablishUSBNotifications(void *arg)
613 {
614 	struct udev_monitor *udev_monitor = arg;
615 	int r;
616 	int fd;
617 	struct pollfd pfd;
618 
619 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
620 	pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
621 
622 	/* udev monitor file descriptor */
623 	fd = udev_monitor_get_fd(udev_monitor);
624 	if (fd < 0)
625 	{
626 		Log2(PCSC_LOG_ERROR, "udev_monitor_get_fd() error: %d", fd);
627 		pthread_exit(NULL);
628 	}
629 
630 	pfd.fd = fd;
631 	pfd.events = POLLIN;
632 
633 	for (;;)
634 	{
635 		struct udev_device *dev;
636 
637 #ifdef DEBUG_HOTPLUG
638 		Log0(PCSC_LOG_INFO);
639 #endif
640 		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
641 
642 		/* wait for a udev event */
643 		r = TEMP_FAILURE_RETRY(poll(&pfd, 1, -1));
644 		if (r < 0)
645 		{
646 			Log2(PCSC_LOG_ERROR, "select(): %s", strerror(errno));
647 			pthread_exit(NULL);
648 		}
649 
650 		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
651 
652 		dev = udev_monitor_receive_device(udev_monitor);
653 		if (dev)
654 		{
655 			const char *action = udev_device_get_action(dev);
656 
657 			if (action)
658 			{
659 				if (!strcmp("remove", action))
660 				{
661 					Log1(PCSC_LOG_INFO, "USB Device removed");
662 					HPRemoveDevice(dev);
663 				}
664 				else
665 				if (!strcmp("add", action))
666 				{
667 					Log1(PCSC_LOG_INFO, "USB Device add");
668 					HPAddDevice(dev);
669 				}
670 			}
671 
672 			/* free device */
673 			udev_device_unref(dev);
674 		}
675 	}
676 
677 	pthread_exit(NULL);
678 } /* HPEstablishUSBNotifications */
679 
680 
681 /***
682  * Start a thread waiting for hotplug events
683  */
HPSearchHotPluggables(void)684 LONG HPSearchHotPluggables(void)
685 {
686 	int i;
687 
688 	for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
689 	{
690 		readerTracker[i].devpath = NULL;
691 		readerTracker[i].fullName = NULL;
692 		readerTracker[i].sysname = NULL;
693 	}
694 
695 	return HPReadBundleValues();
696 } /* HPSearchHotPluggables */
697 
698 
699 /**
700  * Stop the hotplug thread
701  */
HPStopHotPluggables(void)702 LONG HPStopHotPluggables(void)
703 {
704 	int i;
705 
706 	if (driverSize <= 0)
707 		return 0;
708 
709 	if (!Udev)
710 		return 0;
711 
712 	pthread_cancel(usbNotifyThread);
713 	pthread_join(usbNotifyThread, NULL);
714 
715 	for (i=0; i<driverSize; i++)
716 	{
717 		/* free strings allocated by strdup() */
718 		free(driverTracker[i].bundleName);
719 		free(driverTracker[i].libraryPath);
720 		free(driverTracker[i].readerName);
721 	}
722 	free(driverTracker);
723 
724 	udev_unref(Udev);
725 
726 	Udev = NULL;
727 	driverSize = -1;
728 
729 	Log1(PCSC_LOG_INFO, "Hotplug stopped");
730 	return 0;
731 } /* HPStopHotPluggables */
732 
733 
734 /**
735  * Sets up callbacks for device hotplug events.
736  */
HPRegisterForHotplugEvents(void)737 ULONG HPRegisterForHotplugEvents(void)
738 {
739 	struct udev_monitor *udev_monitor;
740 	int r;
741 
742 	if (driverSize <= 0)
743 	{
744 		Log1(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: "
745 			PCSCLITE_HP_DROPDIR);
746 		Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
747 		return 0;
748 	}
749 
750 	/* Create the udev object */
751 	Udev = udev_new();
752 	if (!Udev)
753 	{
754 		Log1(PCSC_LOG_ERROR, "udev_new() failed");
755 		return SCARD_F_INTERNAL_ERROR;
756 	}
757 
758 	udev_monitor = udev_monitor_new_from_netlink(Udev, "udev");
759 	if (NULL == udev_monitor)
760 	{
761 		Log1(PCSC_LOG_ERROR, "udev_monitor_new_from_netlink() error");
762 		pthread_exit(NULL);
763 	}
764 
765 	/* filter only the interfaces */
766 	r = udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb",
767 		"usb_interface");
768 	if (r)
769 	{
770 		Log2(PCSC_LOG_ERROR, "udev_monitor_filter_add_match_subsystem_devtype() error: %d\n", r);
771 		pthread_exit(NULL);
772 	}
773 
774 	r = udev_monitor_enable_receiving(udev_monitor);
775 	if (r)
776 	{
777 		Log2(PCSC_LOG_ERROR, "udev_monitor_enable_receiving() error: %d\n", r);
778 		pthread_exit(NULL);
779 	}
780 
781 	/* scan the USB bus at least once before accepting client connections */
782 	HPScanUSB(Udev);
783 
784 	if (ThreadCreate(&usbNotifyThread, 0,
785 		(PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, udev_monitor))
786 	{
787 		Log1(PCSC_LOG_ERROR, "ThreadCreate() failed");
788 		return SCARD_F_INTERNAL_ERROR;
789 	}
790 
791 	return 0;
792 } /* HPRegisterForHotplugEvents */
793 
794 
HPReCheckSerialReaders(void)795 void HPReCheckSerialReaders(void)
796 {
797 	/* nothing to do here */
798 #ifdef DEBUG_HOTPLUG
799 	Log0(PCSC_LOG_ERROR);
800 #endif
801 } /* HPReCheckSerialReaders */
802 
803 #endif
804 
805