<commit_before>/*
 * reader-pcsc.c: Reader driver for PC/SC Lite
 *
 * Copyright (C) 2002  <NAME> <<EMAIL>>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "internal.h"
#ifdef HAVE_PCSC
#include "ctbcs.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef __APPLE__
#include <PCSC/wintypes.h>
#include <PCSC/winscard.h>
#else
#include <winscard.h>
#endif

/* Default timeout value for SCardGetStatusChange
 * Needs to be increased for some broken PC/SC
 * Lite implementations.
 */
#ifndef SC_CUSTOM_STATUS_TIMEOUT
#define SC_STATUS_TIMEOUT 0
#else
#define SC_STATUS_TIMEOUT SC_CUSTOM_STATUS_TIMEOUT
#endif

#ifdef _WIN32
/* Some windows specific kludge */
#define SCARD_PROTOCOL_ANY (SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1)
#define SCARD_SCOPE_GLOBAL SCARD_SCOPE_USER

/* Error printing */
#define PCSC_ERROR(ctx, desc, rv) sc_error(ctx, desc ": %lx\n", rv);

#else

#define PCSC_ERROR(ctx, desc, rv) sc_error(ctx, desc ": %s\n", pcsc_stringify_error(rv));

#endif

#define MASQUERADE_NONE		0x00
#define MASQUERADE_4AS3		0x01
#define MASQUERADE_1AS2		0x02
#define MASQUERADE_1AS2_ALWAYS	0x04
#define DO_MASQ(priv, mask)	((prv)->gpriv->apdu_masquerade & (mask))
/* Default value for apdu_fix option */
#ifndef _WIN32
# define DEF_APDU_MASQ		MASQUERADE_NONE
#else
# define DEF_APDU_MASQ		MASQUERADE_4AS3
#endif

#define GET_SLOT_PTR(s, i) (&(s)->slot[(i)])
#define GET_PRIV_DATA(r) ((struct pcsc_private_data *) (r)->drv_data)
#define GET_SLOT_DATA(r) ((struct pcsc_slot_data *) (r)->drv_data)

struct pcsc_global_private_data {
	SCARDCONTEXT pcsc_ctx;
	int apdu_masquerade;  /* bitmask to indicate whether to 
				 'fix' some T=0 APDUs */
};

struct pcsc_private_data {
	SCARDCONTEXT pcsc_ctx;
	char *reader_name;
	struct pcsc_global_private_data *gpriv;
};

struct pcsc_slot_data {
	SCARDHANDLE pcsc_card;
	SCARD_READERSTATE_A readerState;
};

static int pcsc_detect_card_presence(struct sc_reader *reader, struct sc_slot_info *slot);

static int pcsc_ret_to_error(long rv)
{
	switch (rv) {
	case SCARD_W_REMOVED_CARD:
		return SC_ERROR_CARD_REMOVED;
	case SCARD_W_RESET_CARD:
		return SC_ERROR_CARD_RESET;
	case SCARD_E_NOT_TRANSACTED:
		return SC_ERROR_TRANSMIT_FAILED;
	case SCARD_W_UNRESPONSIVE_CARD:
		return SC_ERROR_CARD_UNRESPONSIVE;
	default:
		return SC_ERROR_UNKNOWN;
	}
}

static unsigned int pcsc_proto_to_opensc(DWORD proto)
{
	switch (proto) {
	case SCARD_PROTOCOL_T0:
		return SC_PROTO_T0;
	case SCARD_PROTOCOL_T1:
		return SC_PROTO_T1;
	case SCARD_PROTOCOL_RAW:
		return SC_PROTO_RAW;
	default:
		return 0;
	}
}

static DWORD opensc_proto_to_pcsc(unsigned int proto)
{
	switch (proto) {
	case SC_PROTO_T0:
		return SCARD_PROTOCOL_T0;
	case SC_PROTO_T1:
		return SCARD_PROTOCOL_T1;
	case SC_PROTO_RAW:
		return SCARD_PROTOCOL_RAW;
	default:
		return 0;
	}
}

static int pcsc_transmit(struct sc_reader *reader, struct sc_slot_info *slot,
			 const u8 *sendbuf, size_t sendsize,
			 u8 *recvbuf, size_t *recvsize,
			 int control)
{
	SCARD_IO_REQUEST sSendPci, sRecvPci;
	DWORD dwSendLength, dwRecvLength;
	LONG rv;
	SCARDHANDLE card;
	char masqueraded_apdu[5];
	struct pcsc_slot_data *pslot = GET_SLOT_DATA(slot);
	struct pcsc_private_data *prv = GET_PRIV_DATA(reader);
	int protocol = slot->active_protocol;

	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);
	
	if (sendsize >= 6
	 && DO_MASQ(prv, MASQUERADE_4AS3) && protocol == SC_PROTO_T0) {
		/* Check if the APDU in question is of Case 4 */
		const u8 *p = sendbuf;
		int lc;
		
		p += 4;
		lc = *p;
		if (lc == 0)
			lc = 256;
		if (sendsize == lc + 6) {
			/* Le is present, cut it out */
			if (reader->ctx->debug >= 5) {
				sc_debug(reader->ctx,
					"Removing Le byte from Case 4 APDU\n");
			}
			sendsize--;
		}
	}

	/* Masquerading case 1 APDUs */
	if (sendsize == 4
	 && (DO_MASQ(prv, MASQUERADE_1AS2_ALWAYS)
	  || (DO_MASQ(priv, MASQUERADE_1AS2) && protocol == SC_PROTO_T0))) {
		if (reader->ctx->debug >= 5) {
			sc_debug(reader->ctx,
				"Adding Lc byte to Case 1 APDU\n");
		}
		memcpy(masqueraded_apdu, sendbuf, 4);
		masqueraded_apdu[4] = 0;
		sendbuf = masqueraded_apdu;
		sendsize = 5;
	}

	dwSendLength = sendsize;
	dwRecvLength = *recvsize;

        if (dwRecvLength > 256)
		dwRecvLength = 256;

	if (!control) {
		rv = SCardTransmit(card, &sSendPci, sendbuf, dwSendLength,
				   &sRecvPci, recvbuf, &dwRecvLength);
	} else {
#ifndef _WIN32
		rv = SCardControl(card, sendbuf, dwSendLength,
				  recvbuf, &dwRecvLength);
#else
		rv = SCardControl(card, 0, sendbuf, dwSendLength,
				  recvbuf, dwRecvLength, &dwRecvLength);
#endif
	}

	if (rv != SCARD_S_SUCCESS) {
		switch (rv) {
		case SCARD_W_REMOVED_CARD:
			return SC_ERROR_CARD_REMOVED;
		case SCARD_W_RESET_CARD:
			return SC_ERROR_CARD_RESET;
		case SCARD_E_NOT_TRANSACTED:<commit_msg>Add room for SW1-SW2 in case of maximum reply size (256 bytes)<commit_after>/*
 * reader-pcsc.c: Reader driver for PC/SC Lite
 *
 * Copyright (C) 2002  <NAME> <<EMAIL>>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "internal.h"
#ifdef HAVE_PCSC
#include "ctbcs.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef __APPLE__
#include <PCSC/wintypes.h>
#include <PCSC/winscard.h>
#else
#include <winscard.h>
#endif

/* Default timeout value for SCardGetStatusChange
 * Needs to be increased for some broken PC/SC
 * Lite implementations.
 */
#ifndef SC_CUSTOM_STATUS_TIMEOUT
#define SC_STATUS_TIMEOUT 0
#else
#define SC_STATUS_TIMEOUT SC_CUSTOM_STATUS_TIMEOUT
#endif

#ifdef _WIN32
/* Some windows specific kludge */
#define SCARD_PROTOCOL_ANY (SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1)
#define SCARD_SCOPE_GLOBAL SCARD_SCOPE_USER

/* Error printing */
#define PCSC_ERROR(ctx, desc, rv) sc_error(ctx, desc ": %lx\n", rv);

#else

#define PCSC_ERROR(ctx, desc, rv) sc_error(ctx, desc ": %s\n", pcsc_stringify_error(rv));

#endif

#define MASQUERADE_NONE		0x00
#define MASQUERADE_4AS3		0x01
#define MASQUERADE_1AS2		0x02
#define MASQUERADE_1AS2_ALWAYS	0x04
#define DO_MASQ(priv, mask)	((prv)->gpriv->apdu_masquerade & (mask))
/* Default value for apdu_fix option */
#ifndef _WIN32
# define DEF_APDU_MASQ		MASQUERADE_NONE
#else
# define DEF_APDU_MASQ		MASQUERADE_4AS3
#endif

#define GET_SLOT_PTR(s, i) (&(s)->slot[(i)])
#define GET_PRIV_DATA(r) ((struct pcsc_private_data *) (r)->drv_data)
#define GET_SLOT_DATA(r) ((struct pcsc_slot_data *) (r)->drv_data)

struct pcsc_global_private_data {
	SCARDCONTEXT pcsc_ctx;
	int apdu_masquerade;  /* bitmask to indicate whether to 
				 'fix' some T=0 APDUs */
};

struct pcsc_private_data {
	SCARDCONTEXT pcsc_ctx;
	char *reader_name;
	struct pcsc_global_private_data *gpriv;
};

struct pcsc_slot_data {
	SCARDHANDLE pcsc_card;
	SCARD_READERSTATE_A readerState;
};

static int pcsc_detect_card_presence(struct sc_reader *reader, struct sc_slot_info *slot);

static int pcsc_ret_to_error(long rv)
{
	switch (rv) {
	case SCARD_W_REMOVED_CARD:
		return SC_ERROR_CARD_REMOVED;
	case SCARD_W_RESET_CARD:
		return SC_ERROR_CARD_RESET;
	case SCARD_E_NOT_TRANSACTED:
		return SC_ERROR_TRANSMIT_FAILED;
	case SCARD_W_UNRESPONSIVE_CARD:
		return SC_ERROR_CARD_UNRESPONSIVE;
	default:
		return SC_ERROR_UNKNOWN;
	}
}

static unsigned int pcsc_proto_to_opensc(DWORD proto)
{
	switch (proto) {
	case SCARD_PROTOCOL_T0:
		return SC_PROTO_T0;
	case SCARD_PROTOCOL_T1:
		return SC_PROTO_T1;
	case SCARD_PROTOCOL_RAW:
		return SC_PROTO_RAW;
	default:
		return 0;
	}
}

static DWORD opensc_proto_to_pcsc(unsigned int proto)
{
	switch (proto) {
	case SC_PROTO_T0:
		return SCARD_PROTOCOL_T0;
	case SC_PROTO_T1:
		return SCARD_PROTOCOL_T1;
	case SC_PROTO_RAW:
		return SCARD_PROTOCOL_RAW;
	default:
		return 0;
	}
}

static int pcsc_transmit(struct sc_reader *reader, struct sc_slot_info *slot,
			 const u8 *sendbuf, size_t sendsize,
			 u8 *recvbuf, size_t *recvsize,
			 int control)
{
	SCARD_IO_REQUEST sSendPci, sRecvPci;
	DWORD dwSendLength, dwRecvLength;
	LONG rv;
	SCARDHANDLE card;
	char masqueraded_apdu[5];
	struct pcsc_slot_data *pslot = GET_SLOT_DATA(slot);
	struct pcsc_private_data *prv = GET_PRIV_DATA(reader);
	int protocol = slot->active_protocol;

	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);
	
	if (sendsize >= 6
	 && DO_MASQ(prv, MASQUERADE_4AS3) && protocol == SC_PROTO_T0) {
		/* Check if the APDU in question is of Case 4 */
		const u8 *p = sendbuf;
		int lc;
		
		p += 4;
		lc = *p;
		if (lc == 0)
			lc = 256;
		if (sendsize == lc + 6) {
			/* Le is present, cut it out */
			if (reader->ctx->debug >= 5) {
				sc_debug(reader->ctx,
					"Removing Le byte from Case 4 APDU\n");
			}
			sendsize--;
		}
	}

	/* Masquerading case 1 APDUs */
	if (sendsize == 4
	 && (DO_MASQ(prv, MASQUERADE_1AS2_ALWAYS)
	  || (DO_MASQ(priv, MASQUERADE_1AS2) && protocol == SC_PROTO_T0))) {
		if (reader->ctx->debug >= 5) {
			sc_debug(reader->ctx,
				"Adding Lc byte to Case 1 APDU\n");
		}
		memcpy(masqueraded_apdu, sendbuf, 4);
		masqueraded_apdu[4] = 0;
		sendbuf = masqueraded_apdu;
		sendsize = 5;
	}

	dwSendLength = sendsize;
	dwRecvLength = *recvsize;

        if (dwRecvLength > 258)
		dwRecvLength = 258;

	if (!control) {
		rv = SCardTransmit(card, &sSendPci, sendbuf, dwSendLength,
				   &sRecvPci, recvbuf, &dwRecvLength);
	} else {
#ifndef _WIN32
		rv = SCardControl(card, sendbuf, dwSendLength,
				  recvbuf, &dwRecvLength);
#else
		rv = SCardControl(card, 0, sendbuf, dwSendLength,
				  recvbuf, dwRecvLength, &dwRecvLength);
#endif
	}

	if (rv != SCARD_S_SUCCESS) {
		switch (rv) {
		case SCARD_W_REMOVED_CARD:
			return SC_ERROR_CARD_REMOVED;
		case SCARD_W_RESET_CARD:
			return SC_ERROR_CARD_RESET;
		case SCARD_E_NOT_TRANSACTED:
{'fraction_non_alphanumeric': 0.10042828424088804, 'fraction_numerical': 0.017393584476881392, 'mean_word_length': 4.633677991137371, 'pattern_counts': {'":': 4, '<': 23, '<?xml version=': 0, '>': 61, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1976952', 'n_tokens_mistral': 4806, 'n_tokens_neox': 4476, 'n_words': 1124}