Пример #1
0
/*
 * Creates a vector of driver bundle info structures from the hot-plug driver
 * directory.
 *
 * Returns NULL on error and a pointer to an allocated HPDriver vector on
 * success.  The caller must free the HPDriver with a call to
 * HPDriversRelease().
 */
static HPDriverVector HPDriversGetFromDirectory(const char *driverBundlePath)
{
	int i;
#ifdef DEBUG_HOTPLUG
	Log2(PCSC_LOG_DEBUG, "Entering HPDriversGetFromDirectory: %s",
		driverBundlePath);
#endif

	int readersNumber = 0;
	HPDriverVector bundleVector = NULL;
	CFArrayRef bundleArray;
	CFStringRef driverBundlePathString =
		CFStringCreateWithCString(kCFAllocatorDefault,
		driverBundlePath,
		kCFStringEncodingMacRoman);
	CFURLRef pluginUrl = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
		driverBundlePathString,
		kCFURLPOSIXPathStyle, TRUE);

	CFRelease(driverBundlePathString);
	if (!pluginUrl)
	{
		Log1(PCSC_LOG_ERROR, "error getting plugin directory URL");
		return NULL;
	}
	bundleArray = CFBundleCreateBundlesFromDirectory(kCFAllocatorDefault,
		pluginUrl, NULL);
	if (!bundleArray)
	{
		Log1(PCSC_LOG_ERROR, "error getting plugin directory bundles");
		return NULL;
	}
	CFRelease(pluginUrl);

	size_t bundleArraySize = CFArrayGetCount(bundleArray);

	/* get the number of readers (including aliases) */
	for (i = 0; i < bundleArraySize; i++)
	{
		CFBundleRef currBundle =
			(CFBundleRef) CFArrayGetValueAtIndex(bundleArray, i);
		CFDictionaryRef dict = CFBundleGetInfoDictionary(currBundle);

		const void * blobValue = CFDictionaryGetValue(dict,
			CFSTR(PCSCLITE_HP_MANUKEY_NAME));

		if (!blobValue)
		{
			Log1(PCSC_LOG_ERROR, "error getting vendor ID from bundle");
			return NULL;
		}

		if (CFGetTypeID(blobValue) == CFArrayGetTypeID())
		{
			/* alias found, each reader count as 1 */
			CFArrayRef propertyArray = blobValue;
			readersNumber += CFArrayGetCount(propertyArray);
		}
		else
			/* No alias, only one reader supported */
			readersNumber++;
	}
#ifdef DEBUG_HOTPLUG
	Log2(PCSC_LOG_DEBUG, "Total of %d readers supported", readersNumber);
#endif

	/* The last entry is an end marker (m_vendorId = 0)
	 * see checks in HPDriversMatchUSBDevices:503
	 *  and HPDriverVectorRelease:376 */
	readersNumber++;

	bundleVector = (HPDriver *) calloc(readersNumber, sizeof(HPDriver));
	if (!bundleVector)
	{
		Log1(PCSC_LOG_ERROR, "memory allocation failure");
		return NULL;
	}

	HPDriver *driverBundle = bundleVector;
	for (i = 0; i < bundleArraySize; i++)
	{
		CFBundleRef currBundle =
			(CFBundleRef) CFArrayGetValueAtIndex(bundleArray, i);
		CFDictionaryRef dict = CFBundleGetInfoDictionary(currBundle);

		CFURLRef bundleUrl = CFBundleCopyBundleURL(currBundle);
		CFStringRef bundlePath = CFURLCopyPath(bundleUrl);

		driverBundle->m_libPath = strdup(CFStringGetCStringPtr(bundlePath,
				CFStringGetSystemEncoding()));

		const void * blobValue = CFDictionaryGetValue(dict,
			CFSTR(PCSCLITE_HP_MANUKEY_NAME));

		if (!blobValue)
		{
			Log1(PCSC_LOG_ERROR, "error getting vendor ID from bundle");
			return bundleVector;
		}

		if (CFGetTypeID(blobValue) == CFArrayGetTypeID())
		{
			CFArrayRef vendorArray = blobValue;
			CFArrayRef productArray;
			CFArrayRef friendlyNameArray;
			char *libPath = driverBundle->m_libPath;

#ifdef DEBUG_HOTPLUG
			Log2(PCSC_LOG_DEBUG, "Driver with aliases: %s", libPath);
#endif
			/* get list of ProductID */
			productArray = CFDictionaryGetValue(dict,
				 CFSTR(PCSCLITE_HP_PRODKEY_NAME));
			if (!productArray)
			{
				Log1(PCSC_LOG_ERROR, "error getting product ID from bundle");
				return bundleVector;
			}

			/* get list of FriendlyName */
			friendlyNameArray = CFDictionaryGetValue(dict,
				 CFSTR(PCSCLITE_HP_NAMEKEY_NAME));
			if (!friendlyNameArray)
			{
				Log1(PCSC_LOG_ERROR, "error getting product ID from bundle");
				return bundleVector;
			}

			int reader_nb = CFArrayGetCount(vendorArray);

			if (reader_nb != CFArrayGetCount(productArray))
			{
				Log3(PCSC_LOG_ERROR,
					"Malformed Info.plist: %d vendors and %d products",
					reader_nb, CFArrayGetCount(productArray));
				return bundleVector;
			}

			if (reader_nb != CFArrayGetCount(friendlyNameArray))
			{
				Log3(PCSC_LOG_ERROR,
					"Malformed Info.plist: %d vendors and %d friendlynames",
					reader_nb, CFArrayGetCount(friendlyNameArray));
				return bundleVector;
			}

			int j;
			for (j=0; j<reader_nb; j++)
			{
				CFStringRef strValue = CFArrayGetValueAtIndex(vendorArray, j);

				driverBundle->m_vendorId = strtoul(CFStringGetCStringPtr(strValue,
					CFStringGetSystemEncoding()), NULL, 16);

				strValue = CFArrayGetValueAtIndex(productArray, j);
				driverBundle->m_productId = strtoul(CFStringGetCStringPtr(strValue,
					CFStringGetSystemEncoding()), NULL, 16);

				strValue = CFArrayGetValueAtIndex(friendlyNameArray, j);
				const char *cstr = CFStringGetCStringPtr(strValue,
					CFStringGetSystemEncoding());

				driverBundle->m_friendlyName = strdup(cstr);
				if (!driverBundle->m_libPath)
					driverBundle->m_libPath = strdup(libPath);

#ifdef DEBUG_HOTPLUG
				Log2(PCSC_LOG_DEBUG, "VendorID: 0x%04X",
					driverBundle->m_vendorId);
				Log2(PCSC_LOG_DEBUG, "ProductID: 0x%04X",
					driverBundle->m_productId);
				Log2(PCSC_LOG_DEBUG, "Friendly name: %s",
					driverBundle->m_friendlyName);
				Log2(PCSC_LOG_DEBUG, "Driver: %s", driverBundle->m_libPath);
#endif

				/* go to next bundle in the vector */
				driverBundle++;
			}
		}
		else
		{
			CFStringRef strValue = blobValue;

#ifdef DEBUG_HOTPLUG
			Log3(PCSC_LOG_DEBUG, "Driver without alias: %s",
				driverBundle, driverBundle->m_libPath);
#endif

			driverBundle->m_vendorId = strtoul(CFStringGetCStringPtr(strValue,
					CFStringGetSystemEncoding()), NULL, 16);

			strValue = (CFStringRef) CFDictionaryGetValue(dict,
				CFSTR(PCSCLITE_HP_PRODKEY_NAME));
			if (!strValue)
			{
				Log1(PCSC_LOG_ERROR, "error getting product ID from bundle");
				return bundleVector;
			}
			driverBundle->m_productId = strtoul(CFStringGetCStringPtr(strValue,
				CFStringGetSystemEncoding()), NULL, 16);

			strValue = (CFStringRef) CFDictionaryGetValue(dict,
				CFSTR(PCSCLITE_HP_NAMEKEY_NAME));
			if (!strValue)
			{
				Log1(PCSC_LOG_ERROR, "error getting product friendly name from bundle");
				driverBundle->m_friendlyName = strdup("unnamed device");
			}
			else
			{
				const char *cstr = CFStringGetCStringPtr(strValue,
					CFStringGetSystemEncoding());

				driverBundle->m_friendlyName = strdup(cstr);
			}
#ifdef DEBUG_HOTPLUG
			Log2(PCSC_LOG_DEBUG, "VendorID: 0x%04X", driverBundle->m_vendorId);
			Log2(PCSC_LOG_DEBUG, "ProductID: 0x%04X", driverBundle->m_productId);
			Log2(PCSC_LOG_DEBUG, "Friendly name: %s", driverBundle->m_friendlyName);
			Log2(PCSC_LOG_DEBUG, "Driver: %s", driverBundle->m_libPath);
#endif

			/* go to next bundle in the vector */
			driverBundle++;
		}
	}
	CFRelease(bundleArray);
	return bundleVector;
}
Пример #2
0
LONG RFAddReader(const char *readerNameLong, int port, const char *library,
	const char *device)
{
	DWORD dwContext = 0, dwGetSize;
	UCHAR ucGetData[1], ucThread[1];
	LONG rv, parentNode;
	int i, j;
	int lrv = 0;
	char *readerName = NULL;

	if ((readerNameLong == NULL) || (library == NULL) || (device == NULL))
		return SCARD_E_INVALID_VALUE;

	/* allocate memory that is automatically freed */
	readerName = alloca(strlen(readerNameLong)+1);
	strcpy(readerName, readerNameLong);

	/* Reader name too long? also count " 00 00"*/
	if (strlen(readerName) > MAX_READERNAME - sizeof(" 00 00"))
	{
		Log3(PCSC_LOG_ERROR,
			"Reader name too long: %zd chars instead of max %zd. Truncating!",
			strlen(readerName), MAX_READERNAME - sizeof(" 00 00"));
		readerName[MAX_READERNAME - sizeof(" 00 00")] = '\0';
	}

	/* Same name, same port - duplicate reader cannot be used */
	if (dwNumReadersContexts != 0)
	{
		for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
		{
			if (sReadersContexts[i]->vHandle != 0)
			{
				char lpcStripReader[MAX_READERNAME];
				int tmplen;

				/* get the reader name without the reader and slot numbers */
				strncpy(lpcStripReader,
					sReadersContexts[i]->readerState->readerName,
					sizeof(lpcStripReader));
				tmplen = strlen(lpcStripReader);
				lpcStripReader[tmplen - 6] = 0;

				if ((strcmp(readerName, lpcStripReader) == 0) &&
					(port == sReadersContexts[i]->port))
				{
					Log1(PCSC_LOG_ERROR, "Duplicate reader found.");
					return SCARD_E_DUPLICATE_READER;
				}
			}
		}
	}

	/* We must find an empty slot to put the reader structure */
	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
	{
		if (sReadersContexts[i]->vHandle == 0)
		{
			dwContext = i;
			break;
		}
	}

	if (i == PCSCLITE_MAX_READERS_CONTEXTS)
	{
		/* No more spots left return */
		return SCARD_E_NO_MEMORY;
	}

	/* Check and set the readername to see if it must be enumerated */
	parentNode = RFSetReaderName(sReadersContexts[dwContext], readerName,
		library, port);
	if (parentNode < -1)
		return SCARD_E_NO_MEMORY;

	sReadersContexts[dwContext]->library = strdup(library);
	sReadersContexts[dwContext]->device = strdup(device);
	sReadersContexts[dwContext]->version = 0;
	sReadersContexts[dwContext]->port = port;
	sReadersContexts[dwContext]->mMutex = NULL;
	sReadersContexts[dwContext]->contexts = 0;
	sReadersContexts[dwContext]->pthThread = 0;
	sReadersContexts[dwContext]->hLockId = 0;
	sReadersContexts[dwContext]->LockCount = 0;
	sReadersContexts[dwContext]->vHandle = NULL;
	sReadersContexts[dwContext]->pFeeds = NULL;
	sReadersContexts[dwContext]->pMutex = NULL;
	sReadersContexts[dwContext]->pthCardEvent = NULL;

	lrv = list_init(&sReadersContexts[dwContext]->handlesList);
	if (lrv < 0)
	{
		Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
		return SCARD_E_NO_MEMORY;
	}

	lrv = list_attributes_seeker(&sReadersContexts[dwContext]->handlesList,
		RDR_CLIHANDLES_seeker);
	if (lrv < 0)
	{
		Log2(PCSC_LOG_CRITICAL,
			"list_attributes_seeker failed with return value: %d", lrv);
		return SCARD_E_NO_MEMORY;
	}

	(void)pthread_mutex_init(&sReadersContexts[dwContext]->handlesList_lock,
		NULL);

	(void)pthread_mutex_init(&sReadersContexts[dwContext]->powerState_lock,
		NULL);
	sReadersContexts[dwContext]->powerState = POWER_STATE_UNPOWERED;

	/* reference count */
	(void)pthread_mutex_init(&sReadersContexts[dwContext]->reference_lock,
		NULL);
	sReadersContexts[dwContext]->reference = 1;

	/* If a clone to this reader exists take some values from that clone */
	if (parentNode >= 0 && parentNode < PCSCLITE_MAX_READERS_CONTEXTS)
	{
		sReadersContexts[dwContext]->pFeeds =
		  sReadersContexts[parentNode]->pFeeds;
		*(sReadersContexts[dwContext])->pFeeds += 1;
		sReadersContexts[dwContext]->vHandle =
		  sReadersContexts[parentNode]->vHandle;
		sReadersContexts[dwContext]->mMutex =
		  sReadersContexts[parentNode]->mMutex;
		sReadersContexts[dwContext]->pMutex =
		  sReadersContexts[parentNode]->pMutex;

		/* Call on the parent driver to see if it is thread safe */
		dwGetSize = sizeof(ucThread);
		rv = IFDGetCapabilities(sReadersContexts[parentNode],
			TAG_IFD_THREAD_SAFE, &dwGetSize, ucThread);

		if (rv == IFD_SUCCESS && dwGetSize == 1 && ucThread[0] == 1)
		{
			Log1(PCSC_LOG_INFO, "Driver is thread safe");
			sReadersContexts[dwContext]->mMutex = NULL;
			sReadersContexts[dwContext]->pMutex = NULL;
		}
		else
			*(sReadersContexts[dwContext])->pMutex += 1;
	}

	if (sReadersContexts[dwContext]->pFeeds == NULL)
	{
		sReadersContexts[dwContext]->pFeeds = malloc(sizeof(int));

		/* Initialize pFeeds to 1, otherwise multiple
		   cloned readers will cause pcscd to crash when
		   RFUnloadReader unloads the driver library
		   and there are still devices attached using it --mikeg*/
		*(sReadersContexts[dwContext])->pFeeds = 1;
	}

	if (sReadersContexts[dwContext]->mMutex == 0)
	{
		sReadersContexts[dwContext]->mMutex =
			malloc(sizeof(pthread_mutex_t));
		(void)pthread_mutex_init(sReadersContexts[dwContext]->mMutex, NULL);
	}

	if (sReadersContexts[dwContext]->pMutex == NULL)
	{
		sReadersContexts[dwContext]->pMutex = malloc(sizeof(int));
		*(sReadersContexts[dwContext])->pMutex = 1;
	}

	dwNumReadersContexts += 1;

	rv = RFInitializeReader(sReadersContexts[dwContext]);
	if (rv != SCARD_S_SUCCESS)
	{
		/* Cannot connect to reader. Exit gracefully */
		Log2(PCSC_LOG_ERROR, "%s init failed.", readerName);
		(void)RFRemoveReader(readerName, port);
		return rv;
	}

	/* asynchronous card movement?  */
	{
		RESPONSECODE (*fct)(DWORD, int) = NULL;

		dwGetSize = sizeof(fct);

		rv = IFDGetCapabilities(sReadersContexts[dwContext],
			TAG_IFD_POLLING_THREAD_WITH_TIMEOUT, &dwGetSize, (PUCHAR)&fct);
		if ((rv != SCARD_S_SUCCESS) || (dwGetSize != sizeof(fct)))
		{
			Log1(PCSC_LOG_INFO, "Using the pcscd polling thread");
		}
		else
		{
			sReadersContexts[dwContext]->pthCardEvent = fct;
			Log1(PCSC_LOG_INFO, "Using the reader polling thread");
		}

		rv = EHSpawnEventHandler(sReadersContexts[dwContext]);
		if (rv != SCARD_S_SUCCESS)
		{
			Log2(PCSC_LOG_ERROR, "%s init failed.", readerName);
			(void)RFRemoveReader(readerName, port);
			return rv;
		}
	}

	/* Call on the driver to see if there are multiple slots */
	dwGetSize = sizeof(ucGetData);
	rv = IFDGetCapabilities((sReadersContexts[dwContext]),
		TAG_IFD_SLOTS_NUMBER, &dwGetSize, ucGetData);

	if (rv != IFD_SUCCESS || dwGetSize != 1 || ucGetData[0] == 0)
		/* Reader does not have this defined.  Must be a single slot
		 * reader so we can just return SCARD_S_SUCCESS. */
		return SCARD_S_SUCCESS;

	if (rv == IFD_SUCCESS && dwGetSize == 1 && ucGetData[0] == 1)
		/* Reader has this defined and it only has one slot */
		return SCARD_S_SUCCESS;

	/*
	 * Check the number of slots and create a different
	 * structure for each one accordingly
	 */

	/* Initialize the rest of the slots */
	for (j = 1; j < ucGetData[0]; j++)
	{
		char *tmpReader = NULL;
		DWORD dwContextB = 0;
		RESPONSECODE (*fct)(DWORD, int) = NULL;

		/* We must find an empty spot to put the reader structure */
		for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
		{
			if (sReadersContexts[i]->vHandle == 0)
			{
				dwContextB = i;
				break;
			}
		}

		if (i == PCSCLITE_MAX_READERS_CONTEXTS)
		{
			/* No more slot left return */
			RFRemoveReader(readerName, port);
			return SCARD_E_NO_MEMORY;
		}

		/* Copy the previous reader name and increment the slot number */
		tmpReader = sReadersContexts[dwContextB]->readerState->readerName;
		(void)strlcpy(tmpReader,
			sReadersContexts[dwContext]->readerState->readerName,
			sizeof(sReadersContexts[dwContextB]->readerState->readerName));
		snprintf(tmpReader + strlen(tmpReader) - 2, 3, "%02X", j);

		sReadersContexts[dwContextB]->library =
			sReadersContexts[dwContext]->library;
		sReadersContexts[dwContextB]->device =
			sReadersContexts[dwContext]->device;
		sReadersContexts[dwContextB]->version =
		  sReadersContexts[dwContext]->version;
		sReadersContexts[dwContextB]->port =
		  sReadersContexts[dwContext]->port;
		sReadersContexts[dwContextB]->vHandle =
		  sReadersContexts[dwContext]->vHandle;
		sReadersContexts[dwContextB]->mMutex =
		  sReadersContexts[dwContext]->mMutex;
		sReadersContexts[dwContextB]->pMutex =
		  sReadersContexts[dwContext]->pMutex;
		sReadersContexts[dwContextB]->slot =
			sReadersContexts[dwContext]->slot + j;
		sReadersContexts[dwContextB]->pthCardEvent = NULL;

		/*
		 * Added by Dave - slots did not have a pFeeds
		 * parameter so it was by luck they were working
		 */
		sReadersContexts[dwContextB]->pFeeds =
		  sReadersContexts[dwContext]->pFeeds;

		/* Added by Dave for multiple slots */
		*(sReadersContexts[dwContextB])->pFeeds += 1;

		sReadersContexts[dwContextB]->contexts = 0;
		sReadersContexts[dwContextB]->hLockId = 0;
		sReadersContexts[dwContextB]->LockCount = 0;

		lrv = list_init(&sReadersContexts[dwContextB]->handlesList);
		if (lrv < 0)
		{
			Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
			return SCARD_E_NO_MEMORY;
		}

		lrv = list_attributes_seeker(&sReadersContexts[dwContextB]->handlesList,
			RDR_CLIHANDLES_seeker);
		if (lrv < 0)
		{
			Log2(PCSC_LOG_CRITICAL,
					"list_attributes_seeker failed with return value: %d", lrv);
			return SCARD_E_NO_MEMORY;
		}

		(void)pthread_mutex_init(&sReadersContexts[dwContextB]->handlesList_lock, NULL);
		(void)pthread_mutex_init(&sReadersContexts[dwContextB]->powerState_lock,
			NULL);
		sReadersContexts[dwContextB]->powerState = POWER_STATE_UNPOWERED;

		/* reference count */
		(void)pthread_mutex_init(&sReadersContexts[dwContextB]->reference_lock,
			NULL);
		sReadersContexts[dwContextB]->reference = 1;

		/* Call on the parent driver to see if the slots are thread safe */
		dwGetSize = sizeof(ucThread);
		rv = IFDGetCapabilities((sReadersContexts[dwContext]),
			TAG_IFD_SLOT_THREAD_SAFE, &dwGetSize, ucThread);

		if (rv == IFD_SUCCESS && dwGetSize == 1 && ucThread[0] == 1)
		{
			Log1(PCSC_LOG_INFO, "Driver is slot thread safe");

			sReadersContexts[dwContextB]->library =
				strdup(sReadersContexts[dwContext]->library);
			sReadersContexts[dwContextB]->device =
				strdup(sReadersContexts[dwContext]->device);
			sReadersContexts[dwContextB]->mMutex =
				malloc(sizeof(pthread_mutex_t));
			(void)pthread_mutex_init(sReadersContexts[dwContextB]->mMutex,
				NULL);

			sReadersContexts[dwContextB]->pMutex = malloc(sizeof(int));
			*(sReadersContexts[dwContextB])->pMutex = 1;
		}
		else
			*(sReadersContexts[dwContextB])->pMutex += 1;

		dwNumReadersContexts += 1;

		rv = RFInitializeReader(sReadersContexts[dwContextB]);
		if (rv != SCARD_S_SUCCESS)
		{
			/* Cannot connect to slot. Exit gracefully */
			(void)RFRemoveReader(readerName, port);
			return rv;
		}

		/* asynchronous card movement? */
		dwGetSize = sizeof(fct);

		rv = IFDGetCapabilities((sReadersContexts[dwContextB]),
			TAG_IFD_POLLING_THREAD_WITH_TIMEOUT, &dwGetSize, (PUCHAR)&fct);
		if ((rv != SCARD_S_SUCCESS) || (dwGetSize != sizeof(fct)))
		{
			Log1(PCSC_LOG_INFO, "Using the pcscd polling thread");
		}
		else
		{
			sReadersContexts[dwContextB]->pthCardEvent = fct;
			Log1(PCSC_LOG_INFO, "Using the reader polling thread");
		}

		rv = EHSpawnEventHandler(sReadersContexts[dwContextB]);
		if (rv != SCARD_S_SUCCESS)
		{
			Log2(PCSC_LOG_ERROR, "%s init failed.", readerName);
			(void)RFRemoveReader(readerName, port);
			return rv;
		}
	}

	return SCARD_S_SUCCESS;
}
Пример #3
0
int main(int argc, char **argv)
{
	int rv;
	char setToForeground;
	char HotPlug;
	char *newReaderConfig;
	struct stat fStatBuf;
	int opt;
#ifdef HAVE_GETOPT_LONG
	int option_index = 0;
	static struct option long_options[] = {
		{"config", 1, 0, 'c'},
		{"foreground", 0, 0, 'f'},
		{"help", 0, 0, 'h'},
		{"version", 0, 0, 'v'},
		{"apdu", 0, 0, 'a'},
		{"debug", 0, 0, 'd'},
		{"info", 0, 0, 0},
		{"error", 0, 0, 'e'},
		{"critical", 0, 0, 'C'},
		{"hotplug", 0, 0, 'H'},
		{"force-reader-polling", optional_argument, 0, 0},
		{0, 0, 0, 0}
	};
#endif
#define OPT_STRING "c:fdhvaeCH"

	rv = 0;
	newReaderConfig = NULL;
	setToForeground = 0;
	HotPlug = 0;
	globalArgv = argv;
	
	/*
	 * test the version
	 */
	if (strcmp(PCSCLITE_VERSION_NUMBER, VERSION) != 0)
	{
		printf("BUILD ERROR: The release version number PCSCLITE_VERSION_NUMBER\n");
		printf("  in pcsclite.h (%s) does not match the release version number\n",
			PCSCLITE_VERSION_NUMBER);
		printf("  generated in config.h (%s) (see configure.in).\n", VERSION);

		return EXIT_FAILURE;
	}

	/*
	 * By default we create a daemon (not connected to any output)
	 * The log will go to wherever securityd log output goes.
	 */
	DebugLogSetLogType(DEBUGLOG_NO_DEBUG);

	/*
	 * Handle any command line arguments
	 */
#ifdef  HAVE_GETOPT_LONG
	while ((opt = getopt_long (argc, argv, OPT_STRING, long_options, &option_index)) != -1) {
#else
	while ((opt = getopt (argc, argv, OPT_STRING)) != -1) {
#endif
		switch (opt) {
#ifdef  HAVE_GETOPT_LONG
			case 0:
				if (strcmp(long_options[option_index].name,
					"force-reader-polling") == 0)
					HPForceReaderPolling = optarg ? abs(atoi(optarg)) : 1;
				break;
#endif
			case 'c':
				Log2(PCSC_LOG_INFO, "using new config file: %s", optarg);
				newReaderConfig = optarg;
				break;

			case 'f':
				setToForeground = 1;
				/* debug to stderr instead of default syslog */
				Log1(PCSC_LOG_INFO,
					"pcscd set to foreground with debug send to stderr");
				break;

			case 'd':
				DebugLogSetLogType(DEBUGLOG_STDERR_DEBUG);
				DebugLogSetLevel(PCSC_LOG_DEBUG);
				break;

			case 'e':
				DebugLogSetLogType(DEBUGLOG_STDERR_DEBUG);
				DebugLogSetLevel(PCSC_LOG_ERROR);
				break;

			case 'C':
				DebugLogSetLogType(DEBUGLOG_STDERR_DEBUG);
				DebugLogSetLevel(PCSC_LOG_CRITICAL);
				break;

			case 'h':
				print_usage (argv[0]);
				return EXIT_SUCCESS;

			case 'v':
				print_version ();
				return EXIT_SUCCESS;

			case 'a':
				DebugLogSetCategory(DEBUG_CATEGORY_APDU);
				break;

			case 'H':
				/* debug to stderr instead of default syslog */
				DebugLogSetLogType(DEBUGLOG_STDERR_DEBUG);
				HotPlug = 1;
				break;

			default:
				print_usage (argv[0]);
				return EXIT_FAILURE;
		}

	}

	if (argv[optind])
	{
		printf("Unknown option: %s\n\n", argv[optind]);
		print_usage(argv[0]);
		return EXIT_SUCCESS;
	}

	/*
		If this run of pcscd has the hotplug option, just send a signal to the
		running one and exit
	*/
	
	if (HotPlug)
		return ProcessHotplugRequest();

	/*
	 * test the presence of /var/run/pcsc.comm
	 */

	rv = SYS_Stat(PCSCLITE_CSOCK_NAME, &fStatBuf);

	if (rv == 0)
	{
#ifdef USE_RUN_PID
		pid_t pid;

		/* read the pid file to get the old pid and test if the old pcscd is
		 * still running
		 */
		pid = GetDaemonPid();

		if (pid != -1)
		{
			if (kill(pid, 0) == 0)
			{
				Log2(PCSC_LOG_CRITICAL,
					"Another pcscd (pid: %d) seems to be running.", pid);
				Log1(PCSC_LOG_CRITICAL,
					"Remove " USE_RUN_PID " if pcscd is not running to clear this message.");
				return EXIT_FAILURE;
			}
			else
				/* the old pcscd is dead. Do some cleanup */
				clean_temp_files();
		}
#else
		{
			Log1(PCSC_LOG_CRITICAL,
				"file " PCSCLITE_CSOCK_NAME " already exists.");
			Log1(PCSC_LOG_CRITICAL,
				"Maybe another pcscd is running?");
			Log1(PCSC_LOG_CRITICAL,
				"Remove " PCSCLITE_CSOCK_NAME "if pcscd is not running to clear this message.");
			return EXIT_FAILURE;
		}
#endif
	}

	/*
	 * If this is set to one the user has asked it not to fork
	 */
	if (!setToForeground)
	{
		if (SYS_Daemon(0, 0))
			Log2(PCSC_LOG_CRITICAL, "SYS_Daemon() failed: %s",
				strerror(errno));
	}

	/*
	 * cleanly remove /tmp/pcsc when exiting
	 */
	signal(SIGQUIT, signal_trap);
	signal(SIGTERM, signal_trap);
	signal(SIGINT, signal_trap);
	signal(SIGHUP, signal_trap);

#ifdef USE_RUN_PID
	/*
	 * Record our pid to make it easier
	 * to kill the correct pcscd
	 */
	{
		FILE *f;

		if ((f = fopen(USE_RUN_PID, "wb")) != NULL)
		{
			fprintf(f, "%u\n", (unsigned) getpid());
			fclose(f);
		}
	}
#endif

	/*
	 * If PCSCLITE_IPC_DIR does not exist then create it
	 */
	rv = SYS_Stat(PCSCLITE_IPC_DIR, &fStatBuf);
	if (rv < 0)
	{
		rv = SYS_Mkdir(PCSCLITE_IPC_DIR, S_ISVTX | S_IRWXO | S_IRWXG | S_IRWXU);
		if (rv != 0)
		{
			Log2(PCSC_LOG_CRITICAL,
				"cannot create " PCSCLITE_IPC_DIR ": %s", strerror(errno));
			return EXIT_FAILURE;
		}
	}

	/* cleanly remove /var/run/pcsc.* files when exiting */
	if (atexit(at_exit))
		Log2(PCSC_LOG_CRITICAL, "atexit() failed: %s", strerror(errno));

	/*
	 * Allocate memory for reader structures
	 */
	RFAllocateReaderSpace();

	/*
		Grab the information from the reader.conf. If a file has been specified
		and there is any error, consider it fatal. If no file was explicitly
		specified, ignore if file not present.

		 DBUpdateReaders returns:
		 
		 1	if config file can't be opened
		 -1	if config file is broken
		 0	if all good
	 
		We skip this step if running in 64 bit mode, as serial readers are considered
		legacy code.
	*/

	rv = RFStartSerialReaders(newReaderConfig?newReaderConfig:PCSCLITE_READER_CONFIG);
	if (rv == -1)
	{
		Log3(PCSC_LOG_CRITICAL, "invalid file %s: %s", newReaderConfig,
				strerror(errno));
		at_exit();
	}
	else
	if ((rv == 1) && newReaderConfig)
	{
		Log3(PCSC_LOG_CRITICAL, "file %s can't be opened: %s", 
				 newReaderConfig, strerror(errno));
		at_exit();
	}

	/*
	 * Set the default globals
	 */
	g_rgSCardT0Pci.dwProtocol = SCARD_PROTOCOL_T0;
	g_rgSCardT1Pci.dwProtocol = SCARD_PROTOCOL_T1;
	g_rgSCardRawPci.dwProtocol = SCARD_PROTOCOL_RAW;

	Log1(PCSC_LOG_INFO, "pcsc-lite " VERSION " daemon ready.");

	/*
	 * post initialistion
	 */
	Init = 0;

	/*
	 * signal_trap() does just set a global variable used by the main loop
	 */
	signal(SIGQUIT, signal_trap);
	signal(SIGTERM, signal_trap);
	signal(SIGINT, signal_trap);
	signal(SIGHUP, signal_trap);

	signal(SIGUSR1, signal_reload);

	SVCServiceRunLoop();

	Log1(PCSC_LOG_ERROR, "SVCServiceRunLoop returned");
	return EXIT_FAILURE;
}

void at_exit(void)
{
	Log1(PCSC_LOG_INFO, "cleaning " PCSCLITE_IPC_DIR);

	clean_temp_files();

	SYS_Exit(EXIT_SUCCESS);
}
Пример #4
0
static int
dds_op_extended( Operation *op, SlapReply *rs )
{
	slap_overinst	*on = (slap_overinst *)op->o_bd->bd_info;
	dds_info_t	*di = on->on_bi.bi_private;

	if ( DDS_OFF( di ) ) {
		return SLAP_CB_CONTINUE;
	}

	if ( bvmatch( &op->ore_reqoid, &slap_EXOP_REFRESH ) ) {
		Entry		*e = NULL;
		time_t		ttl;
		BackendDB	db = *op->o_bd;
		SlapReply	rs2 = { REP_RESULT };
		Operation	op2 = *op;
		slap_callback	sc = { 0 };
		Modifications	ttlmod = { { 0 } };
		struct berval	ttlvalues[ 2 ];
		char		ttlbuf[STRLENOF("31557600") + 1];

		rs->sr_err = slap_parse_refresh( op->ore_reqdata, NULL, &ttl,
			&rs->sr_text, NULL );
		assert( rs->sr_err == LDAP_SUCCESS );

		if ( ttl <= 0 || ttl > DDS_RF2589_MAX_TTL ) {
			rs->sr_err = LDAP_PROTOCOL_ERROR;
			rs->sr_text = "invalid time-to-live for dynamicObject";
			return rs->sr_err;
		}

		if ( ttl > di->di_max_ttl ) {
			/* FIXME: I don't understand if this has to be an error,
			 * or an indication that the requested Ttl has been
			 * shortened to di->di_max_ttl >= 1 day */
			rs->sr_err = LDAP_SIZELIMIT_EXCEEDED;
			rs->sr_text = "time-to-live for dynamicObject exceeds limit";
			return rs->sr_err;
		}

		if ( di->di_min_ttl && ttl < di->di_min_ttl ) {
			ttl = di->di_min_ttl;
		}

		/* This does not apply to multi-master case */
		if ( !( !SLAP_SINGLE_SHADOW( op->o_bd ) || be_isupdate( op ) ) ) {
			/* we SHOULD return a referral in this case */
			BerVarray defref = op->o_bd->be_update_refs
				? op->o_bd->be_update_refs : default_referral;

			if ( defref != NULL ) {
				rs->sr_ref = referral_rewrite( op->o_bd->be_update_refs,
					NULL, NULL, LDAP_SCOPE_DEFAULT );
				if ( rs->sr_ref ) {
					rs->sr_flags |= REP_REF_MUSTBEFREED;
				} else {
					rs->sr_ref = defref;
				}
				rs->sr_err = LDAP_REFERRAL;

			} else {
				rs->sr_text = "shadow context; no update referral";
				rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
			}

			return rs->sr_err;
		}

		assert( !BER_BVISNULL( &op->o_req_ndn ) );



		/* check if exists but not dynamicObject */
		op->o_bd->bd_info = (BackendInfo *)on->on_info;
		rs->sr_err = be_entry_get_rw( op, &op->o_req_ndn,
			slap_schema.si_oc_dynamicObject, NULL, 0, &e );
		if ( rs->sr_err != LDAP_SUCCESS ) {
			rs->sr_err = be_entry_get_rw( op, &op->o_req_ndn,
				NULL, NULL, 0, &e );
			if ( rs->sr_err == LDAP_SUCCESS && e != NULL ) {
				/* return referral only if "disclose"
				 * is granted on the object */
				if ( ! access_allowed( op, e,
						slap_schema.si_ad_entry,
						NULL, ACL_DISCLOSE, NULL ) )
				{
					rs->sr_err = LDAP_NO_SUCH_OBJECT;

				} else {
					rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
					rs->sr_text = "refresh operation only applies to dynamic objects";
				}
				be_entry_release_r( op, e );

			} else {
				rs->sr_err = LDAP_NO_SUCH_OBJECT;
			}
			return rs->sr_err;

		} else if ( e != NULL ) {
			be_entry_release_r( op, e );
		}

		/* we require manage privileges on the entryTtl,
		 * and fake a Relax control */
		op2.o_tag = LDAP_REQ_MODIFY;
		op2.o_bd = &db;
		db.bd_info = (BackendInfo *)on->on_info;
		op2.o_callback = &sc;
		sc.sc_response = slap_null_cb;
		op2.o_relax = SLAP_CONTROL_CRITICAL;
		op2.orm_modlist = &ttlmod;

		ttlmod.sml_op = LDAP_MOD_REPLACE;
		ttlmod.sml_flags = SLAP_MOD_MANAGING;
		ttlmod.sml_desc = slap_schema.si_ad_entryTtl;
		ttlmod.sml_values = ttlvalues;
		ttlmod.sml_numvals = 1;
		ttlvalues[ 0 ].bv_val = ttlbuf;
		ttlvalues[ 0 ].bv_len = snprintf( ttlbuf, sizeof( ttlbuf ), "%ld", ttl );
		BER_BVZERO( &ttlvalues[ 1 ] );

		/* the entryExpireTimestamp is added by modify */
		rs->sr_err = op2.o_bd->be_modify( &op2, &rs2 );

		if ( ttlmod.sml_next != NULL ) {
			slap_mods_free( ttlmod.sml_next, 1 );
		}

		if ( rs->sr_err == LDAP_SUCCESS ) {
			int			rc;
			BerElementBuffer	berbuf;
			BerElement		*ber = (BerElement *)&berbuf;

			if ( rs->sr_err == LDAP_SUCCESS ) {
				ber_init_w_nullc( ber, LBER_USE_DER );

				rc = ber_printf( ber, "{tiN}", LDAP_TAG_EXOP_REFRESH_RES_TTL, (int)ttl );

				if ( rc < 0 ) {
					rs->sr_err = LDAP_OTHER;
					rs->sr_text = "internal error";

				} else {
					(void)ber_flatten( ber, &rs->sr_rspdata );
					rs->sr_rspoid = ch_strdup( slap_EXOP_REFRESH.bv_val );

					Log3( LDAP_DEBUG_TRACE, LDAP_LEVEL_INFO,
						"%s REFRESH dn=\"%s\" TTL=%ld\n",
						op->o_log_prefix, op->o_req_ndn.bv_val, ttl );
				}

				ber_free_buf( ber );
			}
		}

		return rs->sr_err;
	}

	return SLAP_CB_CONTINUE;
}