On Mon, 2011-02-07 at 11:32 -0600, Douglas E. Engert wrote:
> 
> On 2/4/2011 2:20 AM, Martin Paljak wrote:
> 
> > I think Douglas is incrementally working on the existing codebase. Why the 
> > cardmod
>  > driver was squeezed into reader-pcsc.c the way it is in the first place is 
> beyond
>  > me, as Francois noted, I "was not very hot about it" [1].
> >
> 
> Yes, I am trying to work with the current code base. The missing piece is 
> passing
> in the two handles from the cardmod.c to the reader-pcsc.c cardmod code.
> The use of the use_reader and sc_ctx_use_reader can do this.

Have a look at the attached patch.

1. It uses the init() function of reader-drivers to pass in additional
arguments.

2. It adds two fields to sc_context_param_t to let the caller of
sc_context_create() provide its own custom driver. How that is to be
used is shown in the diff of src/cardmod/cardmod.c

Additionally a stripped down reader-pcsc (renamed to reader-cardmod) is
attached. It works well with a modified version of opensc-pkcs11.so and
should work in the same way for cardmod. Integration into the build
system is still required and possibly some debugging.

Regards
Andre
Index: src/libopensc/reader-pcsc.c
===================================================================
--- src/libopensc/reader-pcsc.c	(revision 5188)
+++ src/libopensc/reader-pcsc.c	(working copy)
@@ -612,7 +612,7 @@
 	0, 0, NULL
 };
 
-static int pcsc_init(sc_context_t *ctx)
+static int pcsc_init(void *init_data, sc_context_t *ctx)
 {
 	struct pcsc_global_private_data *gpriv;
 	scconf_block *conf_block = NULL;
@@ -1580,7 +1580,7 @@
 	0, 0, NULL
 };
 
-static int cardmod_init(sc_context_t *ctx)
+static int cardmod_init(void *init_data, sc_context_t *ctx)
 {
 	struct pcsc_global_private_data *gpriv;
 	scconf_block *conf_block = NULL;
Index: src/libopensc/ctx.c
===================================================================
--- src/libopensc/ctx.c	(revision 5188)
+++ src/libopensc/ctx.c	(working copy)
@@ -105,6 +105,7 @@
 	/* The default driver should be last, as it handles all the
 	 * unrecognized cards. */
 	{ "default",	(void *(*)(void)) sc_get_default_driver },
+	{ "iso7816",    (void *(*)(void)) sc_get_iso7816_driver },
 	{ NULL, NULL }
 };
 
@@ -648,21 +649,20 @@
 		return SC_ERROR_OUT_OF_MEMORY;
 	}
 
+	if (parm->reader_drv != NULL) {
+		ctx->reader_driver = parm->reader_drv;
+	} else {
 #ifdef ENABLE_PCSC
 	ctx->reader_driver = sc_get_pcsc_driver();
-	#ifdef ENABLE_CARDMOD
-	if(strcmp(ctx->app_name, "cardmod") == 0) {
-		ctx->reader_driver = sc_get_cardmod_driver();
-	}
-	#endif
 #elif ENABLE_CTAPI
 	ctx->reader_driver = sc_get_ctapi_driver();
 #elif ENABLE_OPENCT
 	ctx->reader_driver = sc_get_openct_driver();
 #endif
+	}
 
 	load_reader_driver_options(ctx);
-	ctx->reader_driver->ops->init(ctx);
+	ctx->reader_driver->ops->init(parm->reader_drv_init_data, ctx);
 	
 	load_card_drivers(ctx, &opts);
 	load_card_atrs(ctx);
Index: src/libopensc/reader-ctapi.c
===================================================================
--- src/libopensc/reader-ctapi.c	(revision 5188)
+++ src/libopensc/reader-ctapi.c	(working copy)
@@ -499,7 +499,7 @@
 	return -1;
 }
 
-static int ctapi_init(sc_context_t *ctx)
+static int ctapi_init(void *init_data, sc_context_t *ctx)
 {
 	int i;
 	struct ctapi_global_private_data *gpriv;
Index: src/libopensc/reader-openct.c
===================================================================
--- src/libopensc/reader-openct.c	(revision 5188)
+++ src/libopensc/reader-openct.c	(working copy)
@@ -64,7 +64,7 @@
  * is loaded
  */
 static int
-openct_reader_init(sc_context_t *ctx)
+openct_reader_init(void *init_data, sc_context_t *ctx)
 {
 	unsigned int	i,max_virtual;
 	scconf_block *conf_block;
Index: src/libopensc/opensc.h
===================================================================
--- src/libopensc/opensc.h	(revision 5188)
+++ src/libopensc/opensc.h	(working copy)
@@ -250,7 +250,7 @@
 #define SC_PROTO_RAW		0x00001000
 #define SC_PROTO_ANY		0xFFFFFFFF
 
-struct sc_reader_driver {
+typedef struct sc_reader_driver {
 	const char *name;
 	const char *short_name;
 	struct sc_reader_operations *ops;
@@ -258,7 +258,7 @@
 	size_t max_send_size; /* Max Lc supported by the reader layer */
 	size_t max_recv_size; /* Mac Le supported by the reader layer */
 	void *dll;
-};
+} sc_reader_driver_t;
 
 /* reader flags */
 #define SC_READER_CARD_PRESENT		0x00000001
@@ -359,7 +359,7 @@
 struct sc_reader_operations {
 	/* Called during sc_establish_context(), when the driver
 	 * is loaded */
-	int (*init)(struct sc_context *ctx);
+	int (*init)(void *init_data, struct sc_context *ctx);
 	/* Called when the driver is being unloaded.  finish() has to
 	 * release any resources. */
 	int (*finish)(struct sc_context *ctx);
@@ -692,6 +692,10 @@
 	unsigned long flags;
 	/** mutex functions to use (optional) */
 	sc_thread_context_t *thread_ctx;
+	/** custom reader driver or NULL for default driver **/
+	sc_reader_driver_t *reader_drv;
+	/** initial data **/
+	void *reader_drv_init_data;
 } sc_context_param_t;
 /**
  * Creates a new sc_context_t object.
Index: src/cardmod/cardmod.c
===================================================================
--- src/cardmod/cardmod.c	(revision 5188)
+++ src/cardmod/cardmod.c	(working copy)
@@ -1412,6 +1412,8 @@
 		memset(&ctx_param, 0, sizeof(ctx_param));
 		ctx_param.ver = 1;
 		ctx_param.app_name = "cardmod";
+		ctx_param.reader_drv = get_reader_driver();
+		ctx_param.reader_drv_init_data = /* pointer to struct {SCARDCONTEXT hSCardCtx, SCARDHANDLE hSCard} */
 
 		if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenSC Project\\Opensc", 0, NULL, \
 			REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS)
/*
 * reader-pcsc.c: Reader driver for PC/SC interface
 *
 * Copyright (C) 2002  Juha Yrjölä <juha.yrj...@iki.fi>
 * Copyright (C) 2009,2010 Martin Paljak <mar...@paljak.pri.ee>
 *
 * 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 "config.h"

#include <assert.h>
#include <stdlib.h>
#include <string.h>

#include "../libopensc/internal.h"
#include "../libopensc/internal-winscard.h"

#include "reader-cardmod.h"

/* Logging */
#define PCSC_TRACE(reader, desc, rv) do { sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "%s:" desc ": 0x%08lx\n", reader->name, rv); } while (0)
#define PCSC_LOG(ctx, desc, rv) do { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, desc ": 0x%08lx\n", rv); } while (0)


struct pcsc_private_data {
	SCARDCONTEXT hSCardCtx;
	SCARDHANDLE hSCard;
	DWORD dwProtocol;
};


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 int pcsc_internal_transmit(sc_reader_t *reader,
			 const u8 *sendbuf, size_t sendsize,
			 u8 *recvbuf, size_t *recvsize,
			 unsigned long control)
{
	struct pcsc_private_data *priv = (struct pcsc_private_data *) reader->ctx->reader_drv_data;
	SCARD_IO_REQUEST sSendPci, sRecvPci;
	DWORD dwSendLength, dwRecvLength;
	LONG rv;
	SCARDHANDLE card;

	SC_FUNC_CALLED(reader->ctx, SC_LOG_DEBUG_NORMAL);
	card = priv->hSCard;

	sSendPci.dwProtocol = priv->dwProtocol;
	sSendPci.cbPciLength = sizeof(sSendPci);
	sRecvPci.dwProtocol = priv->dwProtocol;
	sRecvPci.cbPciLength = sizeof(sRecvPci);

	dwSendLength = sendsize;
	dwRecvLength = *recvsize;

	if (!control) {
		rv = SCardTransmit(card, &sSendPci, sendbuf, dwSendLength,
				   &sRecvPci, recvbuf, &dwRecvLength);
	} else {
		rv = SCardControl(card, (DWORD) control, sendbuf, dwSendLength,
				  recvbuf, dwRecvLength, &dwRecvLength);
	}

	if (rv != SCARD_S_SUCCESS) {
		PCSC_TRACE(reader, "SCardTransmit/Control failed", rv);
		switch (rv) {
		case SCARD_W_REMOVED_CARD:
			return SC_ERROR_CARD_REMOVED;
		default:
			return SC_ERROR_TRANSMIT_FAILED;
		}
	}
	if (!control && dwRecvLength < 2)
		return SC_ERROR_UNKNOWN_DATA_RECEIVED;
	*recvsize = dwRecvLength;

	return SC_SUCCESS;
}

static int pcsc_transmit(sc_reader_t *reader, sc_apdu_t *apdu)
{
	size_t       ssize, rsize, rbuflen = 0;
	u8           *sbuf = NULL, *rbuf = NULL;
	int          r;
	struct pcsc_private_data *priv = (struct pcsc_private_data *) reader->ctx->reader_drv_data;

	/* we always use a at least 258 byte size big return buffer
	 * to mimic the behaviour of the old implementation (some readers
	 * seems to require a larger than necessary return buffer).
	 * The buffer for the returned data needs to be at least 2 bytes
	 * larger than the expected data length to store SW1 and SW2. */
	rsize = rbuflen = apdu->resplen <= 256 ? 258 : apdu->resplen + 2;
	rbuf     = malloc(rbuflen);
	if (rbuf == NULL) {
		r = SC_ERROR_OUT_OF_MEMORY;
		goto out;
	}
	/* encode and log the APDU */
	r = sc_apdu_get_octets(reader->ctx, apdu, &sbuf, &ssize, pcsc_proto_to_opensc(priv->dwProtocol));
	if (r != SC_SUCCESS)
		goto out;
	if (reader->name)
		sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "reader '%s'", reader->name);
	sc_apdu_log(reader->ctx, SC_LOG_DEBUG_NORMAL, sbuf, ssize, 1);

	r = pcsc_internal_transmit(reader, sbuf, ssize,
				rbuf, &rsize, apdu->control);
	if (r < 0) {
		/* unable to transmit ... most likely a reader problem */
		sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "unable to transmit");
		goto out;
	}
	sc_apdu_log(reader->ctx, SC_LOG_DEBUG_NORMAL, rbuf, rsize, 0);
	/* set response */
	r = sc_apdu_set_resp(reader->ctx, apdu, rbuf, rsize);
out:
	if (sbuf != NULL) {
		sc_mem_clear(sbuf, ssize);
		free(sbuf);
	}
	if (rbuf != NULL) {
		sc_mem_clear(rbuf, rbuflen);
		free(rbuf);
	}

	return r;
}


static
int pcsc_init(void *init_data, sc_context_t *ctx)
{
	struct pcsc_private_data *priv;
	sc_reader_t *reader;
	DWORD atr_len = SC_MAX_ATR_SIZE;
	DWORD name_len;
	DWORD dwState;
	size_t i;
	int r;

	if (init_data == NULL || ctx == NULL) {
		return SC_ERROR_INVALID_ARGUMENTS;
	}

	if (ctx->reader_drv_data != NULL) {
		return SC_ERROR_INVALID_DATA;	/* Already initialised */
	}

	ctx->reader_drv_data = calloc(1, sizeof(struct pcsc_private_data));
	if (ctx->reader_drv_data == NULL) {
		return SC_ERROR_OUT_OF_MEMORY;
	}

	priv = ctx->reader_drv_data;

	priv->hSCardCtx = ((pcsc_ctx_t *) init_data)->hSCardCtx;
	priv->hSCard = ((pcsc_ctx_t *) init_data)->hSCard;

	reader = calloc(1, sizeof(sc_reader_t));
	if (reader == NULL) {
		r = SC_ERROR_OUT_OF_MEMORY;
		goto error;
	}

	name_len = 127;
	reader->name = malloc(sizeof(char) * (name_len + 1));
	if (reader->name == NULL) {
		r = SC_ERROR_OUT_OF_MEMORY;
		goto error;
	}

	r = SCardStatus(priv->hSCard, reader->name, &name_len,
			&dwState, &priv->dwProtocol, reader->atr.value, &atr_len);

	if (r != SCARD_S_SUCCESS) {
		printf("%s\n", pcsc_stringify_error(r));
		r = SC_ERROR_READER;
		goto error;
	}

	reader->name[name_len] = 0;
	reader->atr.len = atr_len;

	printf("Current Reader Name              : %s\n", reader->name);
	printf("Current Reader State             : 0x%lx\n", dwState);
	printf("Current Reader Protocol          : T%ld\n", priv->dwProtocol - 1);
	printf("Current Reader ATR Size          : %u\n", reader->atr.len);
	printf("Current Reader ATR Value         : ");

	for (i = 0; i < reader->atr.len; i++) {
		printf("%02X ", reader->atr.value[i]);
	}
	printf("\n");

	reader->flags = SC_READER_CARD_PRESENT;
	reader->driver = ctx->reader_driver;
	reader->ops = reader->driver->ops;

	r = _sc_add_reader(ctx, reader);
	if (r != SC_SUCCESS) {
		goto error;
	}

	return SC_SUCCESS;

error:
	if (reader != NULL) {
		if (reader->name != NULL)
			free(reader->name);
		free(reader);
	}

	free(ctx->reader_drv_data);
	ctx->reader_drv_data = NULL;

	return r;
}

static
int pcsc_finish(sc_context_t *ctx)
{
	if (ctx->reader_drv_data != NULL) {
		free(ctx->reader_drv_data);
		ctx->reader_drv_data = NULL;
	}

	return SC_SUCCESS;
}

static
int pcsc_detect_card_presence(sc_reader_t *reader)
{
	return SC_READER_CARD_PRESENT;
}

static
int pcsc_connect(sc_reader_t *reader)
{
	return SC_SUCCESS;
}

static
int pcsc_disconnect(sc_reader_t * reader)
{
	return SC_SUCCESS;
}

struct sc_reader_driver * get_reader_driver(void)
{
	struct sc_reader_driver *pcsc_drv;

	pcsc_drv = calloc(1, sizeof(struct sc_reader_driver));
	if (pcsc_drv == NULL) {
		return NULL;
	}

	pcsc_drv->ops = calloc(1, sizeof(struct sc_reader_operations));
	if (pcsc_drv->ops == NULL) {
		free(pcsc_drv);
		return NULL;
	}

	pcsc_drv->name = "cardmod";
	pcsc_drv->short_name = "cardmod";

	pcsc_drv->ops->init = pcsc_init;
	pcsc_drv->ops->finish = pcsc_finish;
	pcsc_drv->ops->detect_card_presence = pcsc_detect_card_presence;
	pcsc_drv->ops->connect = pcsc_connect;
	pcsc_drv->ops->disconnect = pcsc_disconnect;
	pcsc_drv->ops->transmit = pcsc_transmit;

	return pcsc_drv;
}

typedef struct pcsc_ctx {
	SCARDCONTEXT hSCardCtx;
	SCARDHANDLE hSCard;
} pcsc_ctx_t;

struct sc_reader_driver * get_reader_driver(void);
_______________________________________________
opensc-devel mailing list
opensc-devel@lists.opensc-project.org
http://www.opensc-project.org/mailman/listinfo/opensc-devel

Reply via email to