Пример #1
0
/************************* READER MANAGER DISCONNECT ***********/
int
readersManagerDisconnect(
                        tReaderManager *pManager
                        )
{
    LONG 		    rv;

    if ( pManager == NULL )
        return( SCARD_E_INVALID_PARAMETER );

    if ( pManager->hContext )
    {
        readersLogMessage( pManager, LOG_INFO, 2, "Disconnecting from pcscd server");

        rv = SCardReleaseContext( (SCARDCONTEXT) (pManager->hContext) );
        if ( rv != SCARD_S_SUCCESS )
            PCSC_ERROR( pManager, rv, "SCardReleaseContext");

        /* libreate memory that was allocated when we connected to manager */
        if (pManager->mszReaders)
        {
            free(pManager->mszReaders);
            pManager->mszReaders = NULL;
        }
    }
    else
        rv = SCARD_E_INVALID_PARAMETER;

    /* now it should be NULL either way */
    pManager->hContext = NULL;

    eventDispatch( PCSCD_DISCONNECT, NULL, 0, pManager );

    return( rv );
}
static int pcsc_internal_transmit(sc_reader_t *reader, sc_slot_info_t *slot,
			 const u8 *sendbuf, size_t sendsize,
			 u8 *recvbuf, size_t *recvsize,
			 unsigned long control)
{
	struct pcsc_private_data *priv = GET_PRIV_DATA(reader);
	SCARD_IO_REQUEST sSendPci, sRecvPci;
	DWORD dwSendLength, dwRecvLength;
	LONG rv;
	SCARDHANDLE card;
	struct pcsc_slot_data *pslot = GET_SLOT_DATA(slot);

	SC_FUNC_CALLED(reader->ctx, 3);
	assert(pslot != NULL);
	card = pslot->pcsc_card;

	sSendPci.dwProtocol = opensc_proto_to_pcsc(slot->active_protocol);
	sSendPci.cbPciLength = sizeof(sSendPci);
	sRecvPci.dwProtocol = opensc_proto_to_pcsc(slot->active_protocol);
	sRecvPci.cbPciLength = sizeof(sRecvPci);

	dwSendLength = sendsize;
	dwRecvLength = *recvsize;

	if (!control) {
		rv = priv->gpriv->SCardTransmit(card, &sSendPci, sendbuf, dwSendLength,
				   &sRecvPci, recvbuf, &dwRecvLength);
	} else {
		if (priv->gpriv->SCardControlOLD != NULL) {
			rv = priv->gpriv->SCardControlOLD(card, sendbuf, dwSendLength,
				  recvbuf, &dwRecvLength);
		}
		else {
			rv = priv->gpriv->SCardControl(card, (DWORD) control, sendbuf, dwSendLength,
				  recvbuf, dwRecvLength, &dwRecvLength);
		}
	}

	if (rv != SCARD_S_SUCCESS) {
		switch (rv) {
		case SCARD_W_REMOVED_CARD:
			return SC_ERROR_CARD_REMOVED;
		case SCARD_E_NOT_TRANSACTED:
			if (!(pcsc_detect_card_presence(reader, slot) & SC_SLOT_CARD_PRESENT))
				return SC_ERROR_CARD_REMOVED;
			return SC_ERROR_TRANSMIT_FAILED;
		default:
			/* Windows' PC/SC returns 0x8010002f (??) if a card is removed */
			if (pcsc_detect_card_presence(reader, slot) != 1)
				return SC_ERROR_CARD_REMOVED;
			PCSC_ERROR(reader->ctx, "SCardTransmit failed", rv);
			return SC_ERROR_TRANSMIT_FAILED;
		}
	}
	if (!control && dwRecvLength < 2)
		return SC_ERROR_UNKNOWN_DATA_RECEIVED;
	*recvsize = dwRecvLength;

	return SC_SUCCESS;
}
Пример #3
0
/* then they will all use the same context and avoid overhead  */
int
readersManagerConnect(
                    tReaderManager *pManager
                    )
{
    LONG 		    rv;

    if ( pManager == NULL )
        return( SCARD_E_INVALID_PARAMETER );

    rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, (LPSCARDCONTEXT)&(pManager->hContext) );
    if (rv != SCARD_S_SUCCESS)
    {
        PCSC_ERROR( pManager, rv, "SCardEstablishContext");
        pManager->hContext = NULL;

        eventDispatch( PCSCD_FAIL, NULL, 0, pManager );

        return( rv );
    }

    eventDispatch( PCSCD_CONNECT, NULL, 0, pManager );

    /* Find all the readers and fill the readerManager data structure */
    rv = readersEnumerate( pManager );

    return (rv);

}
Пример #4
0
/* TODO : this function hasn't really been tested                */
int
readerGetContactlessStatus(
                            tReaderManager  *pManager,
                            tReader	        *pReader
                          )
{
    DWORD		dwRecvLength;
    BYTE		pbRecvBuffer[20];
    LONG		rv;
    int         i;
    BOOL        automatic;

    /* Duh. If you pass me a NULL pointer then I'm out of here */
    if ( ( pManager == NULL ) || ( pManager->hContext == NULL ) )
       return( SCARD_E_INVALID_PARAMETER );

    automatic = readersSettingBitmapBitTest( pManager, READER_BIT_AUTO );

    if ( automatic )
    {
        /* re-enumerate the readers in the system as it may have changed */
        rv = readersConnect( pManager );
        if ( rv != SCARD_S_SUCCESS )
            return( rv );
    }

    sprintf(messageString, "Requesting contactles status");
    readersLogMessage( pManager, LOG_INFO, 2, messageString);

    /* then check all readers we were ABLE to connect to */
    for ( i = 0; i < pManager->nbReaders; i++ )
    {
        /* check we have connected and have a driver for this reader */
        if ( ( pReader[i].hCard != NULL ) && ( pReader[i].pDriver != NULL ) &&
             ( automatic || readersSettingBitmapNumberTest( pManager, i ) ) )
        {
            dwRecvLength = sizeof(pbRecvBuffer);
            rv = ((tReaderDriver *)(pReader[i].pDriver))->getContactlessStatus(pReader, pbRecvBuffer, &dwRecvLength);

            if ( rv == SCARD_S_SUCCESS )
            {
                if (pManager->libVerbosityLevel)
                {
                    sprintf(messageString, "Reader %d Status: ", i);
                    sPrintBufferHex( (messageString + strlen("Reader %d Status: ") ), dwRecvLength, pbRecvBuffer);
                    readersLogMessage( pManager, LOG_INFO, 2, messageString);

                    sprintf(messageString, "Number of Tags = %d", pbRecvBuffer[4]);
                    readersLogMessage( pManager, LOG_INFO, 2, messageString);
                }
            }
            else
                PCSC_ERROR( pManager, rv, "driver->getConnectlessStatus:");
        }
    }

   return (rv);
}
static int pcsc_lock(sc_reader_t *reader, sc_slot_info_t *slot)
{
	long rv;
	struct pcsc_slot_data *pslot = GET_SLOT_DATA(slot);
	struct pcsc_private_data *priv = GET_PRIV_DATA(reader);

	SC_FUNC_CALLED(reader->ctx, 3);
	assert(pslot != NULL);

	rv = priv->gpriv->SCardBeginTransaction(pslot->pcsc_card);

	switch (rv) {
		case SCARD_E_INVALID_HANDLE:
		case SCARD_E_READER_UNAVAILABLE:
			rv = pcsc_connect(reader, slot);
			if (rv != SCARD_S_SUCCESS) {
				PCSC_ERROR(reader->ctx, "SCardConnect failed", rv);
				return pcsc_ret_to_error(rv);
			}
			/* return failure so that upper layers will be notified and try to lock again */
			return SC_ERROR_READER_REATTACHED;
		case SCARD_W_RESET_CARD:
			/* try to reconnect if the card was reset by some other application */
			rv = pcsc_reconnect(reader, slot, 0);
			if (rv != SCARD_S_SUCCESS) {
				PCSC_ERROR(reader->ctx, "SCardReconnect failed", rv);
				return pcsc_ret_to_error(rv);
			}
			/* return failure so that upper layers will be notified and try to lock again */
			return SC_ERROR_CARD_RESET;
		case SCARD_S_SUCCESS:
			pslot->locked = 1;
			return SC_SUCCESS;
		default:
			PCSC_ERROR(reader->ctx, "SCardBeginTransaction failed", rv);
			return pcsc_ret_to_error(rv);
	}
}
static int pcsc_unlock(sc_reader_t *reader, sc_slot_info_t *slot)
{
	long rv;
	struct pcsc_slot_data *pslot = GET_SLOT_DATA(slot);
	struct pcsc_private_data *priv = GET_PRIV_DATA(reader);

	SC_FUNC_CALLED(reader->ctx, 3);
	assert(pslot != NULL);

	rv = priv->gpriv->SCardEndTransaction(pslot->pcsc_card, priv->gpriv->transaction_reset ?
                           SCARD_RESET_CARD : SCARD_LEAVE_CARD);

	pslot->locked = 0;
	if (rv != SCARD_S_SUCCESS) {
		PCSC_ERROR(reader->ctx, "SCardEndTransaction failed", rv);
		return pcsc_ret_to_error(rv);
	}
	return SC_SUCCESS;
}
static int pcsc_reconnect(sc_reader_t * reader, sc_slot_info_t * slot, int reset)
{
	DWORD active_proto, protocol;
	LONG rv;
	struct pcsc_slot_data *pslot = GET_SLOT_DATA(slot);
	struct pcsc_private_data *priv = GET_PRIV_DATA(reader);
	int r;

	sc_debug(reader->ctx, "Reconnecting to the card...");

	r = refresh_slot_attributes(reader, slot);
	if (r)
		return r;
	if (!(slot->flags & SC_SLOT_CARD_PRESENT))
		return SC_ERROR_CARD_NOT_PRESENT;

	/* reconnect always unlocks transaction */
	pslot->locked = 0;
	
	rv = priv->gpriv->SCardReconnect(pslot->pcsc_card,
			    priv->gpriv->connect_exclusive ? SCARD_SHARE_EXCLUSIVE : SCARD_SHARE_SHARED,
			    SCARD_PROTOCOL_ANY, reset ? SCARD_UNPOWER_CARD : SCARD_LEAVE_CARD, &active_proto);

	/* Check for protocol difference */
	if (rv == SCARD_S_SUCCESS && _sc_check_forced_protocol
	    (reader->ctx, slot->atr, slot->atr_len,
	     (unsigned int *)&protocol)) {
		protocol = opensc_proto_to_pcsc(protocol);
		if (pcsc_proto_to_opensc(active_proto) != protocol) {
		 rv = priv->gpriv->SCardReconnect(pslot->pcsc_card,
		 		     priv->gpriv->connect_exclusive ? SCARD_SHARE_EXCLUSIVE : SCARD_SHARE_SHARED,
		 		     protocol, SCARD_UNPOWER_CARD, &active_proto);
		}
	}

	if (rv != SCARD_S_SUCCESS) {
		PCSC_ERROR(reader->ctx, "SCardReconnect failed", rv);
		return rv;
	}
	
	slot->active_protocol = pcsc_proto_to_opensc(active_proto);
	return rv;
}
Пример #8
0
/************************ READER DISCONNECT ********************/
void
readersDisconnect(
                tReaderManager  *pManager
                   )
{
    LONG    rv;
    int     i;

    /* Duh. If you pass me a NULL pointer then I'm out of here */
    if ( ( pManager == NULL ) || ( pManager->hContext == NULL ) )
       return;

    if ( readersSettingBitmapBitTest( pManager, READER_BIT_AUTO ) )
    {
        /* re-enumerate the readers in the system as it may have changed */
        rv = readersEnumerate( pManager );
        if ( rv != SCARD_S_SUCCESS )
            return;
    }

    /* then check all readers we were ABLE to connect to */
    for ( i = 0; i < pManager->nbReaders; i++ )
    {
        if ( pManager->readers[i].hCard != NULL )
        {
            sprintf(messageString, "Disconnecting from reader %d", i );
            readersLogMessage( pManager, LOG_INFO, 2, messageString);

            rv = SCardDisconnect( (SCARDHANDLE) (pManager->readers[i].hCard), SCARD_UNPOWER_CARD);
            RESET_READER( pManager->readers[i] );

            eventDispatch( READER_DISCONNECT, NULL, i, pManager );

            if ( rv != SCARD_S_SUCCESS )
                PCSC_ERROR( pManager, rv, "SCardDisconnect");
        }
    }
}
static int pcsc_detect_readers(sc_context_t *ctx, void *prv_data)
{
	struct pcsc_global_private_data *gpriv = (struct pcsc_global_private_data *) prv_data;
	LONG rv;
	DWORD reader_buf_size;
	char *reader_buf = NULL, *reader_name;
	const char *mszGroups = NULL;
	int ret = SC_ERROR_INTERNAL;

	SC_FUNC_CALLED(ctx, 3);

	if (!gpriv) {
		ret = SC_ERROR_NO_READERS_FOUND;
		goto out;
	}

	sc_debug(ctx, "Probing pcsc readers");

	do {
		if (gpriv->pcsc_ctx == -1) {
			/*
			 * Cannot call SCardListReaders with -1
			 * context as in Windows ERROR_INVALID_HANDLE
			 * is returned instead of SCARD_E_INVALID_HANDLE
			 */
			rv = SCARD_E_INVALID_HANDLE;
		}
		else {
			rv = gpriv->SCardListReaders(gpriv->pcsc_ctx, NULL, NULL,
					      (LPDWORD) &reader_buf_size);
		}
		if (rv != SCARD_S_SUCCESS) {
			if (rv != SCARD_E_INVALID_HANDLE) {
				PCSC_ERROR(ctx, "SCardListReaders failed", rv);
				ret = pcsc_ret_to_error(rv);
				goto out;
			}

			sc_debug(ctx, "Establish pcsc context");

			rv = gpriv->SCardEstablishContext(SCARD_SCOPE_USER,
					      NULL, NULL, &gpriv->pcsc_ctx);
			if (rv != SCARD_S_SUCCESS) {
				PCSC_ERROR(ctx, "SCardEstablishContext failed", rv);
				ret = pcsc_ret_to_error(rv);
				goto out;
			}

			rv = SCARD_E_INVALID_HANDLE;
		}
	} while (rv != SCARD_S_SUCCESS);

	reader_buf = (char *) malloc(sizeof(char) * reader_buf_size);
	if (!reader_buf) {
		ret = SC_ERROR_OUT_OF_MEMORY;
		goto out;
	}
	rv = gpriv->SCardListReaders(gpriv->pcsc_ctx, mszGroups, reader_buf,
	                      (LPDWORD) &reader_buf_size);
	if (rv != SCARD_S_SUCCESS) {
		PCSC_ERROR(ctx, "SCardListReaders failed", rv);
		ret = pcsc_ret_to_error(rv);
		goto out;
	}
	for (reader_name = reader_buf; *reader_name != '\x0'; reader_name += strlen (reader_name) + 1) {
		sc_reader_t *reader = NULL;
		struct pcsc_private_data *priv = NULL;
		struct pcsc_slot_data *pslot = NULL;
		sc_slot_info_t *slot = NULL;
		unsigned int i;
		int found = 0;

		for (i=0;i < sc_ctx_get_reader_count (ctx) && !found;i++) {
			sc_reader_t *reader2 = sc_ctx_get_reader (ctx, i);
			if (reader2 == NULL) {
				ret = SC_ERROR_INTERNAL;
				goto err1;
			}
			if (reader2->ops == &pcsc_ops && !strcmp (reader2->name, reader_name)) {
				found = 1;
			}
		}

		/* Reader already available, skip */
		if (found) {
			continue;
		}

		sc_debug(ctx, "Found new pcsc reader '%s'", reader_name);

		if ((reader = (sc_reader_t *) calloc(1, sizeof(sc_reader_t))) == NULL) {
			ret = SC_ERROR_OUT_OF_MEMORY;
			goto err1;
		}
		if ((priv = (struct pcsc_private_data *) malloc(sizeof(struct pcsc_private_data))) == NULL) {
			ret = SC_ERROR_OUT_OF_MEMORY;
			goto err1;
		}
		if ((pslot = (struct pcsc_slot_data *) malloc(sizeof(struct pcsc_slot_data))) == NULL) {
			ret = SC_ERROR_OUT_OF_MEMORY;
			goto err1;
		}

		reader->drv_data = priv;
		reader->ops = &pcsc_ops;
		reader->driver = &pcsc_drv;
		reader->slot_count = 1;
		if ((reader->name = strdup(reader_name)) == NULL) {
			ret = SC_ERROR_OUT_OF_MEMORY;
			goto err1;
		}
		priv->gpriv = gpriv;
		if ((priv->reader_name = strdup(reader_name)) == NULL) {
			ret = SC_ERROR_OUT_OF_MEMORY;
			goto err1;
		}
		slot = &reader->slot[0];
		memset(slot, 0, sizeof(*slot));
		slot->drv_data = pslot;
		memset(pslot, 0, sizeof(*pslot));
		if (_sc_add_reader(ctx, reader)) {
			ret = SC_SUCCESS;	/* silent ignore */
			goto err1;
		}
		refresh_slot_attributes(reader, slot);

		continue;
	
	err1:
		if (priv != NULL) {
			if (priv->reader_name)
				free(priv->reader_name);
			free(priv);
		}
		if (reader != NULL) {
			if (reader->name)
				free(reader->name);
			free(reader);
		}
		if (slot != NULL)
			free(pslot);

		goto out;
	}

	ret = SC_SUCCESS;

out:

	if (reader_buf != NULL)
		free (reader_buf);

	SC_FUNC_RETURN(ctx, 3, ret);
}
static int pcsc_connect(sc_reader_t *reader, sc_slot_info_t *slot)
{
	DWORD active_proto, protocol;
	SCARDHANDLE card_handle;
	LONG rv;
	struct pcsc_private_data *priv = GET_PRIV_DATA(reader);
	struct pcsc_slot_data *pslot = GET_SLOT_DATA(slot);
	int r;
	u8 feature_buf[256], rbuf[SC_MAX_APDU_BUFFER_SIZE];
	size_t rcount;
	DWORD i, feature_len, display_ioctl = 0;
	PCSC_TLV_STRUCTURE *pcsc_tlv;

	r = refresh_slot_attributes(reader, slot);
	if (r)
		return r;
	if (!(slot->flags & SC_SLOT_CARD_PRESENT))
		return SC_ERROR_CARD_NOT_PRESENT;

	/* Always connect with whatever protocol possible */
	rv = priv->gpriv->SCardConnect(priv->gpriv->pcsc_ctx, priv->reader_name,
			  priv->gpriv->connect_exclusive ? SCARD_SHARE_EXCLUSIVE : SCARD_SHARE_SHARED,
			  SCARD_PROTOCOL_ANY, &card_handle, &active_proto);
	if (rv != SCARD_S_SUCCESS) {
		PCSC_ERROR(reader->ctx, "SCardConnect failed", rv);
		return pcsc_ret_to_error(rv);
	}
	slot->active_protocol = pcsc_proto_to_opensc(active_proto);
	pslot->pcsc_card = card_handle;

	/* after connect reader is not locked yet */
	pslot->locked = 0;
	sc_debug(reader->ctx, "After connect protocol = %d", slot->active_protocol);
	
	/* If we need a specific protocol, reconnect if needed */
	if (_sc_check_forced_protocol(reader->ctx, slot->atr, slot->atr_len, (unsigned int *) &protocol)) {
		/* If current protocol differs from the protocol we want to force */
		if (slot->active_protocol != protocol) {
			sc_debug(reader->ctx, "Protocol difference, forcing protocol (%d)", protocol);
			/* Reconnect with a reset. pcsc_reconnect figures out the right forced protocol */
			rv = pcsc_reconnect(reader, slot, 1);
			if (rv != SCARD_S_SUCCESS) {
				PCSC_ERROR(reader->ctx, "SCardReconnect (to force protocol) failed", rv);
				return pcsc_ret_to_error(rv);
			}
			sc_debug(reader->ctx, "Proto after reconnect = %d", slot->active_protocol);
		}
	}

	/* check for pinpad support */
	if (priv->gpriv->SCardControl != NULL) {
		sc_debug(reader->ctx, "Requesting reader features ... ");

		rv = priv->gpriv->SCardControl(pslot->pcsc_card, CM_IOCTL_GET_FEATURE_REQUEST, NULL,
				  0, feature_buf, sizeof(feature_buf), &feature_len);
		if (rv != SCARD_S_SUCCESS) {
			sc_debug(reader->ctx, "SCardControl failed %08x", rv);
		}
		else {
			if ((feature_len % sizeof(PCSC_TLV_STRUCTURE)) != 0) {
				sc_debug(reader->ctx, "Inconsistent TLV from reader!");
			}
			else {
				char *log_disabled = "but it's disabled in configuration file";
				/* get the number of elements instead of the complete size */
				feature_len /= sizeof(PCSC_TLV_STRUCTURE);

				pcsc_tlv = (PCSC_TLV_STRUCTURE *)feature_buf;
				for (i = 0; i < feature_len; i++) {
					if (pcsc_tlv[i].tag == FEATURE_VERIFY_PIN_DIRECT) {
						pslot->verify_ioctl = ntohl(pcsc_tlv[i].value);
					} else if (pcsc_tlv[i].tag == FEATURE_VERIFY_PIN_START) {
						pslot->verify_ioctl_start = ntohl(pcsc_tlv[i].value);
					} else if (pcsc_tlv[i].tag == FEATURE_VERIFY_PIN_FINISH) {
						pslot->verify_ioctl_finish = ntohl(pcsc_tlv[i].value);
					} else if (pcsc_tlv[i].tag == FEATURE_MODIFY_PIN_DIRECT) {
						pslot->modify_ioctl = ntohl(pcsc_tlv[i].value);
					} else if (pcsc_tlv[i].tag == FEATURE_MODIFY_PIN_START) {
						pslot->modify_ioctl_start = ntohl(pcsc_tlv[i].value);
					} else if (pcsc_tlv[i].tag == FEATURE_MODIFY_PIN_FINISH) {
						pslot->modify_ioctl_finish = ntohl(pcsc_tlv[i].value);
					} else if (pcsc_tlv[i].tag == FEATURE_IFD_PIN_PROPERTIES) {
					        display_ioctl = ntohl(pcsc_tlv[i].value);
					} else {
						sc_debug(reader->ctx, "Reader feature %02x is not supported", pcsc_tlv[i].tag);
					}
				}
				
				/* Set slot capabilities based on detected IOCTLs */
				if (pslot->verify_ioctl || (pslot->verify_ioctl_start && pslot->verify_ioctl_finish)) {
					char *log_text = "Reader supports pinpad PIN verification";
					if (priv->gpriv->enable_pinpad) {
						sc_debug(reader->ctx, log_text);
						slot->capabilities |= SC_SLOT_CAP_PIN_PAD;
					} else {
						sc_debug(reader->ctx, "%s %s", log_text, log_disabled);
					}
				}
				
				if (pslot->modify_ioctl || (pslot->modify_ioctl_start && pslot->modify_ioctl_finish)) {
					char *log_text = "Reader supports pinpad PIN modification";
					if (priv->gpriv->enable_pinpad) {
						sc_debug(reader->ctx, log_text);
						slot->capabilities |= SC_SLOT_CAP_PIN_PAD;
					} else {
						sc_debug(reader->ctx, "%s %s", log_text, log_disabled);
					}
				}

				if (display_ioctl) {
					rcount = sizeof(rbuf);
					r = pcsc_internal_transmit(reader, slot, NULL, 0, rbuf, &rcount, display_ioctl);
					if (r == SC_SUCCESS) {
						if (rcount != sizeof(PIN_PROPERTIES_STRUCTURE)) {
							PIN_PROPERTIES_STRUCTURE *caps = (PIN_PROPERTIES_STRUCTURE *)rbuf;
							if (caps->wLcdLayout > 0) {
								sc_debug(reader->ctx, "Reader has a display: %04X", caps->wLcdLayout);
								slot->capabilities |= SC_SLOT_CAP_DISPLAY;
							} else
								sc_debug(reader->ctx, "Reader does not have a display.");
						} else {
							sc_debug(reader->ctx, "Returned PIN properties structure has bad length (%d)", rcount);
						}
					}
				}
			}
		}
	}
	return SC_SUCCESS;
}
/* Wait for an event to occur.
 * This function ignores the list of slots, because with
 * pcsc we have a 1:1 mapping of readers and slots anyway
 */
static int pcsc_wait_for_event(sc_reader_t **readers,
			       sc_slot_info_t **slots,
			       size_t nslots,
                               unsigned int event_mask,
                               int *reader,
			       unsigned int *event, int timeout)
{
	struct pcsc_private_data *priv = GET_PRIV_DATA(readers[0]);
	sc_context_t *ctx;
	SCARDCONTEXT pcsc_ctx;
	LONG ret;
	SCARD_READERSTATE_A rgReaderStates[SC_MAX_READERS];
	unsigned long on_bits, off_bits;
	time_t end_time, now, delta;
	size_t i;

	/* Prevent buffer overflow */
	if (nslots >= SC_MAX_READERS)
		return SC_ERROR_INVALID_ARGUMENTS;

	on_bits = off_bits = 0;
	if (event_mask & SC_EVENT_CARD_INSERTED) {
		event_mask &= ~SC_EVENT_CARD_INSERTED;
		on_bits |= SCARD_STATE_PRESENT;
	}
	if (event_mask & SC_EVENT_CARD_REMOVED) {
		event_mask &= ~SC_EVENT_CARD_REMOVED;
		off_bits |= SCARD_STATE_PRESENT;
	}
	if (event_mask != 0)
		return SC_ERROR_INVALID_ARGUMENTS;

	/* Find out the current status */
	ctx = readers[0]->ctx;
	pcsc_ctx = priv->gpriv->pcsc_ctx;
	for (i = 0; i < nslots; i++) {
		struct pcsc_private_data *priv2 = GET_PRIV_DATA(readers[i]);

		rgReaderStates[i].szReader = priv2->reader_name;
		rgReaderStates[i].dwCurrentState = SCARD_STATE_UNAWARE;
		rgReaderStates[i].dwEventState = SCARD_STATE_UNAWARE;

		/* Can we handle readers from different PCSC contexts? */
		if (priv2->gpriv->pcsc_ctx != pcsc_ctx)
			return SC_ERROR_INVALID_ARGUMENTS;
	}

	ret = priv->gpriv->SCardGetStatusChange(pcsc_ctx, 0, rgReaderStates, nslots);
	if (ret != SCARD_S_SUCCESS) {
		PCSC_ERROR(ctx, "SCardGetStatusChange(1) failed", ret);
		return pcsc_ret_to_error(ret);
	}

	time(&now);
	end_time = now + (timeout + 999) / 1000;

	/* Wait for a status change and return if it's a card insert/removal
	 */
	for( ; ; ) {
		SCARD_READERSTATE_A *rsp;

		/* Scan the current state of all readers to see if they
		 * match any of the events we're polling for */
		*event = 0;
		for (i = 0, rsp = rgReaderStates; i < nslots; i++, rsp++) {
			unsigned long state, prev_state;

			prev_state = rsp->dwCurrentState;
			state = rsp->dwEventState;
			if ((state & on_bits & SCARD_STATE_PRESENT) &&
			    (prev_state & SCARD_STATE_EMPTY))
				*event |= SC_EVENT_CARD_INSERTED;
			if ((~state & off_bits & SCARD_STATE_PRESENT) &&
			    (prev_state & SCARD_STATE_PRESENT))
				*event |= SC_EVENT_CARD_REMOVED;
			if (*event) {
				*reader = i;
				return SC_SUCCESS;
			}

			/* No match - copy the state so pcscd knows
			 * what to watch out for */
			rsp->dwCurrentState = rsp->dwEventState;
		}

		/* Set the timeout if caller wants to time out */
		if (timeout == 0)
			return SC_ERROR_EVENT_TIMEOUT;
		if (timeout > 0) {
			time(&now);
			if (now >= end_time)
				return SC_ERROR_EVENT_TIMEOUT;
			delta = end_time - now;
		} else {
			delta = 3600;
		}

		ret = priv->gpriv->SCardGetStatusChange(pcsc_ctx, 1000 * delta,
					   rgReaderStates, nslots);
		if (ret == (LONG) SCARD_E_TIMEOUT) {
			if (timeout < 0)
				continue;
			return SC_ERROR_EVENT_TIMEOUT;
		}
		if (ret != SCARD_S_SUCCESS) {
			PCSC_ERROR(ctx, "SCardGetStatusChange(2) failed", ret);
			return pcsc_ret_to_error(ret);
		}
	}
}
static int refresh_slot_attributes(sc_reader_t *reader, sc_slot_info_t *slot)
{
	struct pcsc_private_data *priv = GET_PRIV_DATA(reader);
	struct pcsc_slot_data *pslot = GET_SLOT_DATA(slot);
	LONG ret;

	SC_FUNC_CALLED(reader->ctx, 3);
	if (pslot->reader_state.szReader == NULL) {
		pslot->reader_state.szReader = priv->reader_name;
		pslot->reader_state.dwCurrentState = SCARD_STATE_UNAWARE;
		pslot->reader_state.dwEventState = SCARD_STATE_UNAWARE;
	} else {
		pslot->reader_state.dwCurrentState = pslot->reader_state.dwEventState;
	}

	ret = priv->gpriv->SCardGetStatusChange(priv->gpriv->pcsc_ctx, 0, &pslot->reader_state, 1);
	if (ret == (LONG)SCARD_E_TIMEOUT) { /* timeout: nothing changed */
		slot->flags &= ~SCARD_STATE_CHANGED;
		return 0;
	}
	if (ret != SCARD_S_SUCCESS) {
		PCSC_ERROR(reader->ctx, "SCardGetStatusChange failed", ret);
		return pcsc_ret_to_error(ret);
	}
	if (pslot->reader_state.dwEventState & SCARD_STATE_PRESENT) {
		int old_flags = slot->flags;
		int maybe_changed = 0;

		slot->flags |= SC_SLOT_CARD_PRESENT;
		slot->atr_len = pslot->reader_state.cbAtr;
		if (slot->atr_len > SC_MAX_ATR_SIZE)
			slot->atr_len = SC_MAX_ATR_SIZE;
		memcpy(slot->atr, pslot->reader_state.rgbAtr, slot->atr_len);

#ifndef _WIN32
		/* On Linux, SCARD_STATE_CHANGED always means there was an
		 * insert or removal. But we may miss events that way. */
		if (pslot->reader_state.dwEventState & SCARD_STATE_CHANGED) {
			slot->flags |= SC_SLOT_CARD_CHANGED;
		} else {
			maybe_changed = 1;
		}
#else
		/* On windows, SCARD_STATE_CHANGED is turned on by lots of
		 * other events, so it gives us a lot of false positives.
		 * But if it's off, there really was no change */
		if (pslot->reader_state.dwEventState & SCARD_STATE_CHANGED) {
			maybe_changed = 1;
		}
#endif
		/* If we aren't sure if the card state changed, check if
		 * the card handle is still valid. If the card changed,
		 * the handle will be invalid. */
		slot->flags &= ~SC_SLOT_CARD_CHANGED;
		if (maybe_changed) {
			if (old_flags & SC_SLOT_CARD_PRESENT) {
				DWORD readers_len = 0, state, prot, atr_len = SC_MAX_ATR_SIZE;
				unsigned char atr[SC_MAX_ATR_SIZE];
				LONG rv = priv->gpriv->SCardStatus(pslot->pcsc_card, NULL, &readers_len,
					&state,	&prot, atr, &atr_len);
				if (rv == (LONG)SCARD_W_REMOVED_CARD)
					slot->flags |= SC_SLOT_CARD_CHANGED;
			}
			else
				slot->flags |= SC_SLOT_CARD_CHANGED;
		}
	} else {
		slot->flags &= ~(SC_SLOT_CARD_PRESENT|SC_SLOT_CARD_CHANGED);
	}
	return 0;
}
Пример #13
0
/* function allocates the memory for the list you must handle it!*/
int
readersGetTagList(
                tReaderManager  *pManager
                )
{
    LONG		rv = SCARD_S_SUCCESS;
    tTag        *pTags[MAX_NUM_READERS]; /* an array of pointers to tags (that act like arrays) ! */
    int         i, j;
    int         uniqueListIndex;
    BOOL        automatic;
    char        *namePointer;

    /* Duh. If you pass me a NULL pointer then I'm out of here */
    if ( ( pManager == NULL ) || ( pManager->hContext == NULL ) )
       return( SCARD_E_INVALID_PARAMETER );

    automatic = readersSettingBitmapBitTest( pManager, READER_BIT_AUTO );

    if ( automatic )
    {
        /* re-connect the readers in the system as it may have changed */
        rv = readersConnect( pManager );
        if ( rv != SCARD_S_SUCCESS )
            return( rv );
    }

    /* before we start, reset the total count to 0 */
    pManager->tagList.numTags = 0;

    /* for all readers we were connected to PREVIOUSLY or are now after AUTMATIC reconnect */
    for ( i = 0; i < pManager->nbReaders; i++ )
    {
        /* make sure it's initialized, as depending on reader settings we may skip over */
        /* one of these pointers in the array and later try to free an invalid pointer */
        pTags[i] = NULL;
        pManager->readers[i].tagList.numTags = 0;

        /* check we are connected, have a driver and should be reading it */
        if ( ( pManager->readers[i].hCard != NULL ) && ( pManager->readers[i].pDriver != NULL ) &&
             ( automatic || readersSettingBitmapNumberTest( pManager, i ) ) )
        {
            /* I'd normally check if a tag is present using readerGetContactlessStatus() before    */
            /* querying the tag list, but all my testing to date has failed to get the contactless */
            /* status APDU to work, it always returns D5 05 00 00 00 80 90 00 to indicate no tag   */
            /* is present. I have reported this issue to ACS by e-mail - Andrew                    */

            /* allocate the structure for this reader to read tag list into upto max size */
            pTags[i] = (tTag *)malloc( ( ((tReaderDriver *)(pManager->readers[i].pDriver))->maxTags ) * sizeof(tTag) );

            /* call the reader's associated driver's function to read the tag list */
            rv = ((tReaderDriver *)(pManager->readers[i].pDriver))->getTagList( &(pManager->readers[i]), pTags[i] );
            if ( rv != SCARD_S_SUCCESS )
            {
                PCSC_ERROR( pManager, rv, "driver->getTagList():");
                RESET_READER( pManager->readers[i] );
                if ( pTags[i] != NULL )
                    free( pTags[i] );
                pTags[i] = NULL;
            }
            /* accumulate the total number of tags found */
            pManager->tagList.numTags += pManager->readers[i].tagList.numTags;
        }
    }

    /* now mash them all up into one big list */
    pManager->tagList.pTags = NULL; /* for the zero tag case */
    uniqueListIndex = 0;

    if ( pManager->tagList.numTags > 0 )
    {
        pManager->tagList.pTags = (tTag *)malloc( (pManager->tagList.numTags) * sizeof( tTag ) );

        /* copy all the individual lists across into the unique list */
        for( i = 0; i < pManager->nbReaders; i++)
        {
            /* make the pointer in the per-reader structure point to it's parts of the overall list */
            pManager->readers[i].tagList.pTags = &(pManager->tagList.pTags[uniqueListIndex]);

            /* for each of the tags detected in this reader */
            for ( j = 0; j < pManager->readers[i].tagList.numTags; j++ )
            {
                /* copy the tag from the tempory list to the unique one */
                pManager->tagList.pTags[uniqueListIndex] = (pTags[i])[j];

                TAG_TYPE_NAME_FROM_ENUM( pManager->tagList.pTags[uniqueListIndex].tagType, namePointer );

                sprintf(messageString, "Tag ID:   %s\tType: %s", pManager->tagList.pTags[uniqueListIndex].uid, namePointer);

                readersLogMessage( pManager, LOG_INFO, 2, messageString);
                uniqueListIndex++;
            }

            /* free the space allocated for that list, even if it was never filled with anything */
            if ( pTags[i] )
                free( pTags[i] );
        }
    }

    sprintf( messageString, "Total Number of tags: %d", (int)(pManager->tagList.numTags) );
    readersLogMessage( pManager, LOG_INFO, 2, messageString );

   return (rv);
}
Пример #14
0
/************************* READER CONNECT **********************/
int readersConnect (
                    tReaderManager  *pManager
                 )
{
    LONG 		    rv;
    BOOL			    readerSupported;
    DWORD 		    dwActiveProtocol;
    int              i, num;
    BOOL             automatic;

    /* Duh. If you pass me a NULL pointer then I'm out of here */
    if ( pManager == NULL )
        return( SCARD_E_INVALID_PARAMETER );

    automatic = ( readersSettingBitmapBitTest( pManager, READER_BIT_AUTO ) != 0 );

    if ( automatic )
    {
        /* re-enumerate the readers in the system as it may have changed */
        rv = readersEnumerate( pManager );
        if ( rv != SCARD_S_SUCCESS )
            return( rv );
    }

    if ( pManager->nbReaders == 0 )
        return( SCARD_E_NO_READERS_AVAILABLE );

    /* try and connect to all readers that are present according to readerSetting */
    for ( num = 0; num < pManager->nbReaders; num++ )
    {
        /* if we are not already connected and should be trying then do so */
        if ( ( pManager->readers[num].hCard == NULL) &&
             ( automatic || readersSettingBitmapNumberTest( pManager, num ) ) )
        {
            dwActiveProtocol = -1;
            rv = SCardConnect( (SCARDCONTEXT)(pManager->hContext),
                                pManager->readers[num].name,
                                SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 ,
                                (LPSCARDHANDLE) &(pManager->readers[num].hCard),
                                &dwActiveProtocol);
            if (rv == SCARD_S_SUCCESS)
            {
                eventDispatch( READER_DETECTED, NULL, num, pManager );

                /* Query the drivers in the list until one of them can handle the reader */
                i = 0;
                readerSupported = FALSE;
                /* call the function to check if this driver works with this reader */
                while ( (readerDriverTable[i] != NULL) && (readerSupported == FALSE) )
                    rv = readerDriverTable[i++]->readerCheck( &(pManager->readers[num]), &readerSupported );

                if ( rv != SCARD_S_SUCCESS )
                {
                    RESET_READER( pManager->readers[num] );
                    PCSC_ERROR( pManager, rv, "readerCheck:" );
                    return( rv );
                }

                /* we couldn't find a driver that knows how to handle this reader... */
                if ( ( readerSupported == FALSE) )
                {
                    pManager->readers[num].pDriver = NULL;
                    sprintf(messageString, "Reader (%s) not supported by any known driver", pManager->readers[num].name );
                    readersLogMessage( pManager, LOG_ERR, 0, messageString);
                    return (SCARD_E_UNKNOWN_READER);
                }
                else
                {
                    /* if we got this far then a driver was successfully found, remember it! */
                    pManager->readers[num].pDriver = readerDriverTable[i -1];
                    pManager->readers[num].driverDescriptor = readerDriverTable[i -1]->driverDescriptor;
                    eventDispatch( READER_DETECTED, NULL, num, pManager );

                }
            }
            else
                RESET_READER( pManager->readers[num] );
        }
    }

    return ( SCARD_S_SUCCESS );

}
Пример #15
0
/*************************** READERS ENUMERATE *****************/
static int
readersEnumerate(
                tReaderManager  *pManager
                )
{

    LONG    rv;
    DWORD   dwReaders;
    char 	*ptr;
    int     i, previousNumReaders;

    /* remember how many readers there used to be */
    previousNumReaders = pManager->nbReaders;

    /* Call with a null buffer to get the number of bytes to allocate */
    rv = SCardListReaders( (SCARDCONTEXT)(pManager->hContext), NULL, NULL, &dwReaders);
    if ( rv != SCARD_S_SUCCESS )
    {
        /* if there are no readers, then zero everything out but don't report an error */
        if ( rv == SCARD_E_NO_READERS_AVAILABLE )
        {
            pManager->nbReaders = 0;

            if ( pManager->mszReaders )
                free( pManager->mszReaders );
            pManager->mszReaders = NULL;

            readersLogMessage( pManager, LOG_INFO, 2, "Found 0 Readers" );
        }
        else
            PCSC_ERROR( pManager, rv, "SCardListReaders");

        return ( rv );
    }

    /* if array already exists, then liberate it and alloc a new one for the */
    /* number of readers reported from SCardListReader */
    if ( pManager->mszReaders )
        free( pManager->mszReaders );
    /* malloc enough memory for dwReader string */
    pManager->mszReaders = malloc(sizeof(char)*dwReaders);

    /* now get the list into the mszReaders array */
    rv = SCardListReaders( (SCARDCONTEXT)(pManager->hContext), NULL, pManager->mszReaders, &dwReaders);
    if (rv != SCARD_S_SUCCESS)
    {
        /* Avoid reporting an error just because no reader is connected */
        if ( rv != SCARD_E_NO_READERS_AVAILABLE )
            PCSC_ERROR( pManager, rv, "SCardListReaders");
        return (rv);
    }

    /* Extract readers from the null separated string and get the total
        * number of readers */
    pManager->nbReaders = 0;
    ptr = pManager->mszReaders;
    while (*ptr != '\0')
    {
        ptr += strlen(ptr)+1;
        (pManager->nbReaders)++;
    }

    sprintf(messageString, "Found %d Readers", pManager->nbReaders);
    readersLogMessage( pManager, LOG_INFO, 2, messageString);

    /* fill the array of readers with pointers to the appropriate point */
    /* in the long mszReaders multi-string */
    pManager->nbReaders = 0;
    ptr = pManager->mszReaders;
    while (*ptr != '\0')
    {
        sprintf(messageString, "Reader [%d]: %s", pManager->nbReaders, ptr);
        readersLogMessage( pManager, LOG_INFO, 3, messageString);
        pManager->readers[pManager->nbReaders].name = ptr;
        ptr += strlen(ptr)+1;
        (pManager->nbReaders)++;
    }

    /* if we have fewer readers than we used to then zero out the "lost ones" */
    if ( pManager->nbReaders < previousNumReaders )
       for ( i = pManager->nbReaders; i < previousNumReaders; i++ )
          RESET_READER( pManager->readers[i] );

    return( SCARD_S_SUCCESS );

}
Пример #16
0
/**************************** APDU SEND ************************/
static LONG
apduSend (
    tCardHandle     hCard,
    const BYTE    	*apdu,
    DWORD			apduLength,
    BYTE			*pbRecvBuffer,
    DWORD			*dwRecvLength
)
{
    LONG 			rv;
    SCARD_IO_REQUEST 	pioRecvPci;
    BYTE 			pbSendBuffer[40];
    DWORD 			dwSendLength = 0;
    DWORD			rBufferMax;
    BOOL			psuedoAPDU = FALSE;


    /* remember the size of the input buffer passed to us, so we don't exceed */
    rBufferMax = *dwRecvLength;

    /* The special psuedo APDU's to talk to a tag, need to have their */
    /* response read back in two chunks, using GET_RESPONSE for the second */
    if (apdu[0] == 0xd4)
    {
        psuedoAPDU = TRUE;
        /* prepend the DIRECT_TRANSMIT APDU  */
        memcpy(pbSendBuffer, APDU_DIRECT_TRANSMIT, sizeof(APDU_DIRECT_TRANSMIT));

        /* then a byte that tells it the length of the psuedo APDU to follow */
        pbSendBuffer[sizeof(APDU_DIRECT_TRANSMIT)] = (BYTE)apduLength;

        dwSendLength += (sizeof(APDU_DIRECT_TRANSMIT) + 1);
    }

    /* Add the APDU that was requested to be sent and increase length to send */
    memcpy((pbSendBuffer + dwSendLength), apdu, apduLength);
    dwSendLength += apduLength;

#if 0
    sprintf(messageString, "APDU: ");
    sPrintBufferHex((messageString + strlen("APDU: ")), dwSendLength, pbSendBuffer);
    readersLogMessage( pManager, LOG_INFO, 3, messageString);
#endif

    rv = SCardTransmit((SCARDHANDLE) hCard,
                       pioSendPci, pbSendBuffer, dwSendLength,
                       &pioRecvPci, pbRecvBuffer, dwRecvLength);

    /* if it was a psuedo APDU then we need to get the response */
    if ( (rv == SCARD_S_SUCCESS) && psuedoAPDU )
    {
#if 0
        sprintf(messageString, "Received: ");
        sPrintBufferHex((messageString + strlen("Received: ")), *dwRecvLength, pbRecvBuffer);
        readersLogMessage(LOG_INFO, 3, messageString);
#endif

        /* command went OK? */
        if (pbRecvBuffer[SW1] != SW1_SUCCESS)
        {
#if 0
            sprintf(messageString, "APDU failed: SW1 = %02X", pbRecvBuffer[SW1]);
            readersLogMessage(LOG_ERR, 0, messageString);
#endif
            return ( SCARD_F_COMM_ERROR );
        }

        /* are their response bytes to get? */
        if (pbRecvBuffer[SW2] > 0)
        {
#if 0
            sprintf(messageString, "Requesting Response Data (%d)",
                    pbRecvBuffer[SW2]);
            readersLogMessage(LOG_INFO, 3, messageString);
#endif

            /* copy the get_response APDU into the first bytes */
            memcpy(pbSendBuffer, APDU_GET_RESPONSE, sizeof(APDU_GET_RESPONSE));

            /* the second response byte tells us how many bytes are pending */
            /* add that value at the end of the GET_RESPONSE APDU */
            pbSendBuffer[sizeof(APDU_GET_RESPONSE)] = pbRecvBuffer[SW2];
            dwSendLength = sizeof(APDU_GET_RESPONSE) + 1;

            /* specify the maximum size of the buffer that was passed in */
            *dwRecvLength = rBufferMax;

            rv = SCardTransmit((SCARDCONTEXT)hCard, pioSendPci, pbSendBuffer,
                               dwSendLength, &pioRecvPci, pbRecvBuffer, dwRecvLength );
#if 0
            PCSC_ERROR(rv, "SCardTransmit");
            sprintf(messageString, "Received: ");
            sPrintBufferHex(messageString, rBufferMax, pbRecvBuffer);
            readersLogMessage(LOG_INFO, 3, messageString);
#endif
        }
        else
            *dwRecvLength = 0;
    }

    return(rv);

}