- implemented reader abstraction layer; now it's easier to

add support for e.g. CT-API
- renamed ops_data field to drv_data in struct sc_card
- copied coding style document from Linux kernel


git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@221 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
jey 2002-02-24 19:32:14 +00:00
parent 1f4e5c4b6d
commit 3fa1b27736
23 changed files with 877 additions and 324 deletions

217
CodingStyle Normal file
View File

@ -0,0 +1,217 @@
This is ripped from the Linux kernel tarball, but applies also to
the OpenSC project.
Linux kernel coding style
This is a short document describing the preferred coding style for the
linux kernel. Coding style is very personal, and I won't _force_ my
views on anybody, but this is what goes for anything that I have to be
able to maintain, and I'd prefer it for most other things too. Please
at least consider the points made here.
First off, I'd suggest printing out a copy of the GNU coding standards,
and NOT read it. Burn them, it's a great symbolic gesture.
Anyway, here goes:
Chapter 1: Indentation
Tabs are 8 characters, and thus indentations are also 8 characters.
There are heretic movements that try to make indentations 4 (or even 2!)
characters deep, and that is akin to trying to define the value of PI to
be 3.
Rationale: The whole idea behind indentation is to clearly define where
a block of control starts and ends. Especially when you've been looking
at your screen for 20 straight hours, you'll find it a lot easier to see
how the indentation works if you have large indentations.
Now, some people will claim that having 8-character indentations makes
the code move too far to the right, and makes it hard to read on a
80-character terminal screen. The answer to that is that if you need
more than 3 levels of indentation, you're screwed anyway, and should fix
your program.
In short, 8-char indents make things easier to read, and have the added
benefit of warning you when you're nesting your functions too deep.
Heed that warning.
Chapter 2: Placing Braces
The other issue that always comes up in C styling is the placement of
braces. Unlike the indent size, there are few technical reasons to
choose one placement strategy over the other, but the preferred way, as
shown to us by the prophets Kernighan and Ritchie, is to put the opening
brace last on the line, and put the closing brace first, thusly:
if (x is true) {
we do y
}
However, there is one special case, namely functions: they have the
opening brace at the beginning of the next line, thus:
int function(int x)
{
body of function
}
Heretic people all over the world have claimed that this inconsistency
is ... well ... inconsistent, but all right-thinking people know that
(a) K&R are _right_ and (b) K&R are right. Besides, functions are
special anyway (you can't nest them in C).
Note that the closing brace is empty on a line of its own, _except_ in
the cases where it is followed by a continuation of the same statement,
ie a "while" in a do-statement or an "else" in an if-statement, like
this:
do {
body of do-loop
} while (condition);
and
if (x == y) {
..
} else if (x > y) {
...
} else {
....
}
Rationale: K&R.
Also, note that this brace-placement also minimizes the number of empty
(or almost empty) lines, without any loss of readability. Thus, as the
supply of new-lines on your screen is not a renewable resource (think
25-line terminal screens here), you have more empty lines to put
comments on.
Chapter 3: Naming
C is a Spartan language, and so should your naming be. Unlike Modula-2
and Pascal programmers, C programmers do not use cute names like
ThisVariableIsATemporaryCounter. A C programmer would call that
variable "tmp", which is much easier to write, and not the least more
difficult to understand.
HOWEVER, while mixed-case names are frowned upon, descriptive names for
global variables are a must. To call a global function "foo" is a
shooting offense.
GLOBAL variables (to be used only if you _really_ need them) need to
have descriptive names, as do global functions. If you have a function
that counts the number of active users, you should call that
"count_active_users()" or similar, you should _not_ call it "cntusr()".
Encoding the type of a function into the name (so-called Hungarian
notation) is brain damaged - the compiler knows the types anyway and can
check those, and it only confuses the programmer. No wonder MicroSoft
makes buggy programs.
LOCAL variable names should be short, and to the point. If you have
some random integer loop counter, it should probably be called "i".
Calling it "loop_counter" is non-productive, if there is no chance of it
being mis-understood. Similarly, "tmp" can be just about any type of
variable that is used to hold a temporary value.
If you are afraid to mix up your local variable names, you have another
problem, which is called the function-growth-hormone-imbalance syndrome.
See next chapter.
Chapter 4: Functions
Functions should be short and sweet, and do just one thing. They should
fit on one or two screenfuls of text (the ISO/ANSI screen size is 80x24,
as we all know), and do one thing and do that well.
The maximum length of a function is inversely proportional to the
complexity and indentation level of that function. So, if you have a
conceptually simple function that is just one long (but simple)
case-statement, where you have to do lots of small things for a lot of
different cases, it's OK to have a longer function.
However, if you have a complex function, and you suspect that a
less-than-gifted first-year high-school student might not even
understand what the function is all about, you should adhere to the
maximum limits all the more closely. Use helper functions with
descriptive names (you can ask the compiler to in-line them if you think
it's performance-critical, and it will probably do a better job of it
that you would have done).
Another measure of the function is the number of local variables. They
shouldn't exceed 5-10, or you're doing something wrong. Re-think the
function, and split it into smaller pieces. A human brain can
generally easily keep track of about 7 different things, anything more
and it gets confused. You know you're brilliant, but maybe you'd like
to understand what you did 2 weeks from now.
Chapter 5: Commenting
Comments are good, but there is also a danger of over-commenting. NEVER
try to explain HOW your code works in a comment: it's much better to
write the code so that the _working_ is obvious, and it's a waste of
time to explain badly written code.
Generally, you want your comments to tell WHAT your code does, not HOW.
Also, try to avoid putting comments inside a function body: if the
function is so complex that you need to separately comment parts of it,
you should probably go back to chapter 4 for a while. You can make
small comments to note or warn about something particularly clever (or
ugly), but try to avoid excess. Instead, put the comments at the head
of the function, telling people what it does, and possibly WHY it does
it.
Chapter 6: You've made a mess of it
That's OK, we all do. You've probably been told by your long-time Unix
user helper that "GNU emacs" automatically formats the C sources for
you, and you've noticed that yes, it does do that, but the defaults it
uses are less than desirable (in fact, they are worse than random
typing - a infinite number of monkeys typing into GNU emacs would never
make a good program).
So, you can either get rid of GNU emacs, or change it to use saner
values. To do the latter, you can stick the following in your .emacs file:
(defun linux-c-mode ()
"C mode with adjusted defaults for use with the Linux kernel."
(interactive)
(c-mode)
(c-set-style "K&R")
(setq c-basic-offset 8))
This will define the M-x linux-c-mode command. When hacking on a
module, if you put the string -*- linux-c -*- somewhere on the first
two lines, this mode will be automatically invoked. Also, you may want
to add
(setq auto-mode-alist (cons '("/usr/src/linux.*/.*\\.[ch]$" . linux-c-mode)
auto-mode-alist))
to your .emacs file if you want to have linux-c-mode switched on
automagically when you edit source files under /usr/src/linux.
But even if you fail in getting emacs to do sane formatting, not
everything is lost: use "indent".
Now, again, GNU indent has the same brain dead settings that GNU emacs
has, which is why you need to give it a few command line options.
However, that's not too bad, because even the makers of GNU indent
recognize the authority of K&R (the GNU people aren't evil, they are
just severely misguided in this matter), so you just give indent the
options "-kr -i8" (stands for "K&R, 8 character indents").
"indent" has a lot of options, and especially when it comes to comment
re-formatting you may want to take a look at the manual page. But
remember: "indent" is not a fix for bad programming.

View File

@ -10,9 +10,10 @@ lib_LTLIBRARIES = libopensc.la
libopensc_la_SOURCES = asn1.c base64.c sec.c log.c sc.c card.c iso7816.c \
dir.c pkcs15.c pkcs15-cert.c pkcs15-pin.c \
pkcs15-prkey.c pkcs15-sec.c pkcs15-cache.c \
reader-pcsc.c \
card-setec.c card-flex.c card-gpk.c \
card-tcos.c card-emv.c card-default.c
libopensc_la_LDFLAGS = -version-info 0:5:0
libopensc_la_LDFLAGS = -version-info 0:6:0
if HAVE_SSL
libopensc_la_LIBADD = @LIBPCSC@ @LIBCRYPTO@

View File

@ -23,7 +23,6 @@
static struct sc_card_operations default_ops;
static const struct sc_card_driver default_drv = {
NULL,
"Default driver for unknown cards",
"default",
&default_ops
@ -101,7 +100,7 @@ static int default_init(struct sc_card *card)
{
int r;
card->ops_data = NULL;
card->drv_data = NULL;
r = autodetect_class(card);
if (r) {
error(card->ctx, "unable to determine the right class byte\n");

View File

@ -23,7 +23,6 @@
static struct sc_card_operations emv_ops;
static const struct sc_card_driver emv_drv = {
NULL,
"EMV compatible cards",
"emv",
&emv_ops
@ -117,7 +116,7 @@ static int emv_match_card(struct sc_card *card)
static int emv_init(struct sc_card *card)
{
card->ops_data = NULL;
card->drv_data = NULL;
card->cla = 0x00;
return 0;

View File

@ -35,7 +35,6 @@ struct flex_private_data {
static struct sc_card_operations flex_ops;
static const struct sc_card_driver flex_drv = {
NULL,
"Schlumberger Multiflex/Cryptoflex",
"slb",
&flex_ops
@ -43,7 +42,7 @@ static const struct sc_card_driver flex_drv = {
static int flex_finish(struct sc_card *card)
{
free(card->ops_data);
free(card->drv_data);
return 0;
}
@ -73,8 +72,8 @@ static int flex_match_card(struct sc_card *card)
static int flex_init(struct sc_card *card)
{
card->ops_data = malloc(sizeof(struct flex_private_data));;
if (card->ops_data == NULL)
card->drv_data = malloc(sizeof(struct flex_private_data));;
if (card->drv_data == NULL)
return SC_ERROR_OUT_OF_MEMORY;
card->cla = 0xC0;
@ -580,7 +579,7 @@ static int flex_set_security_env(struct sc_card *card,
const struct sc_security_env *env,
int se_num)
{
struct flex_private_data *prv = (struct flex_private_data *) card->ops_data;
struct flex_private_data *prv = (struct flex_private_data *) card->drv_data;
if (env->operation != SC_SEC_OPERATION_SIGN) {
error(card->ctx, "Invalid crypto operation supplied.\n");
@ -614,7 +613,7 @@ static int flex_restore_security_env(struct sc_card *card, int se_num)
static int flex_compute_signature(struct sc_card *card, const u8 *data,
size_t data_len, u8 * out, size_t outlen)
{
struct flex_private_data *prv = (struct flex_private_data *) card->ops_data;
struct flex_private_data *prv = (struct flex_private_data *) card->drv_data;
struct sc_apdu apdu;
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
int i, r;

View File

@ -63,7 +63,7 @@ struct gpk_private_data {
unsigned int key_reference;
u8 key[16];
};
#define OPSDATA(card) ((struct gpk_private_data *) ((card)->ops_data))
#define DRVDATA(card) ((struct gpk_private_data *) ((card)->drv_data))
/*
* ATRs of GPK4000 cards courtesy of libscez
@ -86,7 +86,6 @@ static struct atrinfo {
*/
static struct sc_card_operations gpk_ops;
static const struct sc_card_driver gpk_drv = {
NULL,
"Gemplus GPK 4000 driver",
"gpk",
&gpk_ops
@ -129,8 +128,8 @@ gpk_init(struct sc_card *card)
if (!(ai = gpk_identify(card)))
return SC_ERROR_INVALID_CARD;
card->ops_data = priv = malloc(sizeof(*priv));
if (card->ops_data == NULL)
card->drv_data = priv = malloc(sizeof(*priv));
if (card->drv_data == NULL)
return SC_ERROR_OUT_OF_MEMORY;
memset(priv, 0, sizeof(*priv));
priv->variant = ai->variant;
@ -145,9 +144,9 @@ gpk_init(struct sc_card *card)
static int
gpk_finish(struct sc_card *card)
{
if (card->ops_data)
free(card->ops_data);
card->ops_data = NULL;
if (card->drv_data)
free(card->drv_data);
card->drv_data = NULL;
return 0;
}
@ -378,7 +377,7 @@ gpk_select(struct sc_card *card, u8 kind,
const u8 *buf, size_t buflen,
struct sc_file **file)
{
struct gpk_private_data *priv = OPSDATA(card);
struct gpk_private_data *priv = DRVDATA(card);
struct sc_apdu apdu;
u8 resbuf[SC_MAX_APDU_BUFFER_SIZE];
int r;
@ -582,7 +581,7 @@ static int
gpk_compute_crycks(struct sc_card *card, struct sc_apdu *apdu,
u8 *crycks1)
{
struct gpk_private_data *priv = OPSDATA(card);
struct gpk_private_data *priv = DRVDATA(card);
des_key_schedule k1, k2;
u8 in[8], out[8], block[64];
unsigned int len = 0, i, j;
@ -654,7 +653,7 @@ gpk_verify_crycks(struct sc_card *card, struct sc_apdu *apdu, u8 *crycks)
static int
gpk_create_file(struct sc_card *card, struct sc_file *file)
{
struct gpk_private_data *priv = OPSDATA(card);
struct gpk_private_data *priv = DRVDATA(card);
struct sc_apdu apdu;
u8 data[28+3], crycks[3], resp[3];
size_t datalen, namelen;
@ -776,7 +775,7 @@ gpk_set_filekey(const u8 *key, const u8 *challenge,
static int
gpk_select_key(struct sc_card *card, int key_sfi, const u8 *buf, size_t buflen)
{
struct gpk_private_data *priv = OPSDATA(card);
struct gpk_private_data *priv = DRVDATA(card);
struct sc_apdu apdu;
u8 random[8], resp[258];
int r;
@ -894,7 +893,7 @@ gpk_verify(struct sc_card *card, unsigned int type, int ref,
static int
gpk_erase_card(struct sc_card *card)
{
struct gpk_private_data *priv = OPSDATA(card);
struct gpk_private_data *priv = DRVDATA(card);
struct sc_apdu apdu;
u8 offset;
int r;
@ -946,7 +945,7 @@ gpk_erase_card(struct sc_card *card)
static int
gpk_lock(struct sc_card *card, struct sc_cardctl_gpk_lock *args)
{
struct gpk_private_data *priv = OPSDATA(card);
struct gpk_private_data *priv = DRVDATA(card);
struct sc_file *file = args->file;
struct sc_apdu apdu;
u8 data[8], crycks[3], resp[3];
@ -1031,7 +1030,7 @@ gpk_pkfile_init(struct sc_card *card, struct sc_cardctl_gpk_pkinit *args)
static int
gpk_pkfile_load(struct sc_card *card, struct sc_cardctl_gpk_pkload *args)
{
struct gpk_private_data *priv = OPSDATA(card);
struct gpk_private_data *priv = DRVDATA(card);
des_key_schedule k1, k2;
struct sc_apdu apdu;
unsigned int n;

View File

@ -33,7 +33,6 @@ static const char *setec_atrs[] = {
static struct sc_card_operations setec_ops;
static const struct sc_card_driver setec_drv = {
NULL,
"Setec smartcards",
"setec",
&setec_ops
@ -70,7 +69,7 @@ static int setec_match_card(struct sc_card *card)
static int setec_init(struct sc_card *card)
{
card->ops_data = NULL;
card->drv_data = NULL;
card->cla = 0x00;
return 0;

View File

@ -28,7 +28,6 @@ static const char *tcos_atrs[] = {
static struct sc_card_operations tcos_ops;
static const struct sc_card_driver tcos_drv = {
NULL,
"TCOS 2.0 cards",
"tcos",
&tcos_ops
@ -65,7 +64,7 @@ static int tcos_match_card(struct sc_card *card)
static int tcos_init(struct sc_card *card)
{
card->ops_data = NULL;
card->drv_data = NULL;
card->cla = 0x00;
return 0;

View File

@ -30,20 +30,6 @@ int sc_check_sw(struct sc_card *card, int sw1, int sw2)
return card->ops->check_sw(card, sw1, sw2);
}
static int _sc_pcscret_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;
default:
return SC_ERROR_UNKNOWN;
}
}
static int sc_check_apdu(struct sc_context *ctx, const struct sc_apdu *apdu)
{
if (apdu->le > 256) {
@ -103,43 +89,18 @@ static int sc_check_apdu(struct sc_context *ctx, const struct sc_apdu *apdu)
return 0;
}
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 sc_transceive_t0(struct sc_card *card, struct sc_apdu *apdu)
{
SCARD_IO_REQUEST sSendPci, sRecvPci;
BYTE s[SC_MAX_APDU_BUFFER_SIZE], r[SC_MAX_APDU_BUFFER_SIZE];
DWORD dwSendLength, dwRecvLength;
LONG rv;
u8 *data = s;
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
size_t sendsize, recvsize;
u8 *data = sbuf;
size_t data_bytes = apdu->lc;
int r;
if (card->reader->ops->transmit == NULL)
return SC_ERROR_NOT_SUPPORTED;
assert(card->reader->ops->transmit != NULL);
if (data_bytes == 0)
data_bytes = 256;
*data++ = apdu->cla;
@ -176,51 +137,30 @@ static int sc_transceive_t0(struct sc_card *card, struct sc_apdu *apdu)
*data++ = (u8) apdu->le;
break;
}
sSendPci.dwProtocol = opensc_proto_to_pcsc(card->protocol);
sSendPci.cbPciLength = 0;
sRecvPci.dwProtocol = opensc_proto_to_pcsc(card->protocol);
sRecvPci.cbPciLength = 0;
dwSendLength = data - s;
dwRecvLength = apdu->resplen + 2;
if (dwRecvLength > 255) /* FIXME: PC/SC Lite quirk */
dwRecvLength = 255;
sendsize = data - sbuf;
recvsize = apdu->resplen + 2; /* space for the SW's */
if (card->ctx->debug >= 5) {
char buf[2048];
sc_hex_dump(card->ctx, s, (size_t) dwSendLength, buf, sizeof(buf));
sc_hex_dump(card->ctx, sbuf, sendsize, buf, sizeof(buf));
debug(card->ctx, "Sending %d bytes (resp. %d bytes):\n%s",
dwSendLength, dwRecvLength, buf);
sendsize, recvsize, buf);
}
rv = SCardTransmit(card->pcsc_card, &sSendPci, s, dwSendLength,
&sRecvPci, r, &dwRecvLength);
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:
if (sc_detect_card(card->ctx, card->reader) != 1)
return SC_ERROR_CARD_REMOVED;
return SC_ERROR_TRANSMIT_FAILED;
default:
error(card->ctx, "SCardTransmit failed: %s\n", pcsc_stringify_error(rv));
return SC_ERROR_TRANSMIT_FAILED;
}
}
if (dwRecvLength < 2)
return SC_ERROR_ILLEGAL_RESPONSE;
apdu->sw1 = (unsigned int) r[dwRecvLength-2];
apdu->sw2 = (unsigned int) r[dwRecvLength-1];
dwRecvLength -= 2;
if ((size_t) dwRecvLength > apdu->resplen)
dwRecvLength = (DWORD) apdu->resplen;
r = card->reader->ops->transmit(card->reader, card->slot, sbuf,
sendsize, rbuf, &recvsize);
memset(sbuf, 0, sendsize);
SC_TEST_RET(card->ctx, r, "Unable to transmit");
assert(recvsize >= 2);
apdu->sw1 = (unsigned int) rbuf[recvsize-2];
apdu->sw2 = (unsigned int) rbuf[recvsize-1];
recvsize -= 2;
if (recvsize > apdu->resplen)
recvsize = apdu->resplen;
else
apdu->resplen = (size_t) dwRecvLength;
if (dwRecvLength > 0)
memcpy(apdu->resp, r, (size_t) dwRecvLength);
apdu->resplen = recvsize;
if (recvsize > 0)
memcpy(apdu->resp, rbuf, recvsize);
return 0;
}
@ -264,7 +204,7 @@ int sc_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu)
}
if (apdu->sw1 == 0x61 && apdu->resplen == 0) {
struct sc_apdu rspapdu;
BYTE rsp[SC_MAX_APDU_BUFFER_SIZE];
u8 rsp[SC_MAX_APDU_BUFFER_SIZE];
if (orig_resplen == 0) {
apdu->sw1 = 0x90; /* FIXME: should we do this? */
@ -361,58 +301,36 @@ static void sc_card_free(struct sc_card *card)
free(card);
}
int sc_connect_card(struct sc_context *ctx,
int reader, struct sc_card **card_out)
int sc_connect_card(struct sc_reader *reader, int slot_id,
struct sc_card **card_out)
{
struct sc_card *card;
DWORD active_proto;
SCARDHANDLE card_handle;
SCARD_READERSTATE_A rgReaderStates[SC_MAX_READERS];
LONG rv;
int i, r = 0;
struct sc_context *ctx = reader->ctx;
struct sc_slot_info *slot = _sc_get_slot_info(reader, slot_id);
int i, r = 0, connected = 0;
assert(card_out != NULL);
SC_FUNC_CALLED(ctx, 1);
if (reader >= ctx->reader_count || reader < 0)
SC_FUNC_RETURN(ctx, 1, SC_ERROR_OBJECT_NOT_FOUND);
rgReaderStates[0].szReader = ctx->readers[reader];
rgReaderStates[0].dwCurrentState = SCARD_STATE_UNAWARE;
rgReaderStates[0].dwEventState = SCARD_STATE_UNAWARE;
rv = SCardGetStatusChange(ctx->pcsc_ctx, SC_STATUS_TIMEOUT, rgReaderStates, 1);
if (rv != 0) {
error(ctx, "SCardGetStatusChange failed: %s\n", pcsc_stringify_error(rv));
SC_FUNC_RETURN(ctx, 1, SC_ERROR_RESOURCE_MANAGER); /* FIXME */
}
if (!(rgReaderStates[0].dwEventState & SCARD_STATE_PRESENT))
SC_FUNC_RETURN(ctx, 1, SC_ERROR_CARD_NOT_PRESENT);
if (reader->ops->connect == NULL)
SC_FUNC_RETURN(ctx, 0, SC_ERROR_NOT_SUPPORTED);
if (slot == NULL)
SC_FUNC_RETURN(ctx, 0, SC_ERROR_SLOT_NOT_FOUND);
card = sc_card_new();
if (card == NULL)
SC_FUNC_RETURN(ctx, 1, SC_ERROR_OUT_OF_MEMORY);
rv = SCardConnect(ctx->pcsc_ctx, ctx->readers[reader],
SCARD_SHARE_SHARED, SCARD_PROTOCOL_ANY,
&card_handle, &active_proto);
if (rv != 0) {
error(ctx, "SCardConnect failed: %s\n", pcsc_stringify_error(rv));
r = -1; /* FIXME: invent a real error value */
r = reader->ops->connect(reader, slot);
if (r)
goto err;
}
card->protocol = pcsc_proto_to_opensc(active_proto);
if (card->protocol == 0) {
error(ctx, "Unknown protocol (%X) selected.\n", active_proto);
r = SC_ERROR_RESOURCE_MANAGER;
goto err;
}
connected = 1;
card->reader = reader;
card->slot = slot;
card->ctx = ctx;
card->pcsc_card = card_handle;
i = rgReaderStates[0].cbAtr;
if (i >= SC_MAX_ATR_SIZE)
i = SC_MAX_ATR_SIZE;
memcpy(card->atr, rgReaderStates[0].rgbAtr, i);
card->atr_len = i;
memcpy(card->atr, slot->atr, slot->atr_len);
card->atr_len = slot->atr_len;
if (ctx->forced_driver != NULL) {
card->driver = ctx->forced_driver;
memcpy(card->ops, card->driver->ops, sizeof(struct sc_card_operations));
@ -425,7 +343,7 @@ int sc_connect_card(struct sc_context *ctx,
}
}
} else for (i = 0; ctx->card_drivers[i] != NULL; i++) {
const struct sc_card_driver *drv = ctx->card_drivers[i];
const struct sc_card_driver *drv = ctx->card_drivers[i];
const struct sc_card_operations *ops = drv->ops;
int r;
@ -466,7 +384,7 @@ err:
SC_FUNC_RETURN(ctx, 1, r);
}
int sc_disconnect_card(struct sc_card *card)
int sc_disconnect_card(struct sc_card *card, int action)
{
struct sc_context *ctx;
assert(sc_card_valid(card));
@ -476,30 +394,19 @@ int sc_disconnect_card(struct sc_card *card)
if (card->ops->finish) {
int r = card->ops->finish(card);
if (r)
error(card->ctx, "driver finish() failed: %s\n",
error(card->ctx, "card driver finish() failed: %s\n",
sc_strerror(r));
}
if (card->reader->ops->disconnect) {
int r = card->reader->ops->disconnect(card->reader, card->slot, action);
if (r)
error(card->ctx, "disconnect() failed: %s\n",
sc_strerror(r));
}
SCardDisconnect(card->pcsc_card, SCARD_LEAVE_CARD);
sc_card_free(card);
SC_FUNC_RETURN(ctx, 1, 0);
}
/* internal lock function -- should make sure that the card is exclusively
* in our use */
static int _sc_lock_int(struct sc_card *card)
{
long rv;
rv = SCardBeginTransaction(card->pcsc_card);
if (rv != SCARD_S_SUCCESS) {
error(card->ctx, "SCardBeginTransaction failed: %s\n", pcsc_stringify_error(rv));
return _sc_pcscret_to_error(rv);
}
card->cache_valid = 1;
return 0;
}
int sc_lock(struct sc_card *card)
{
int r = 0;
@ -507,29 +414,18 @@ int sc_lock(struct sc_card *card)
assert(card != NULL);
SC_FUNC_CALLED(card->ctx, 2);
pthread_mutex_lock(&card->mutex);
if (card->lock_count == 0)
r = _sc_lock_int(card);
if (card->lock_count == 0) {
if (card->reader->ops->lock != NULL)
r = card->reader->ops->lock(card->reader, card->slot);
if (r == 0)
card->cache_valid = 1;
}
if (r == 0)
card->lock_count++;
pthread_mutex_unlock(&card->mutex);
SC_FUNC_RETURN(card->ctx, 2, r);
}
/* internal unlock function */
static int _sc_unlock_int(struct sc_card *card)
{
long rv;
rv = SCardEndTransaction(card->pcsc_card, SCARD_LEAVE_CARD);
if (rv != SCARD_S_SUCCESS) {
error(card->ctx, "SCardEndTransaction failed: %s\n", pcsc_stringify_error(rv));
return -1;
}
card->cache_valid = 0;
memset(&card->cache, 0, sizeof(card->cache));
return 0;
}
int sc_unlock(struct sc_card *card)
{
int r = 0;
@ -539,8 +435,12 @@ int sc_unlock(struct sc_card *card)
pthread_mutex_lock(&card->mutex);
card->lock_count--;
assert(card->lock_count >= 0);
if (card->lock_count == 0)
r = _sc_unlock_int(card);
if (card->lock_count == 0) {
if (card->reader->ops->unlock != NULL)
r = card->reader->ops->unlock(card->reader, card->slot);
card->cache_valid = 0;
memset(&card->cache, 0, sizeof(card->cache));
}
pthread_mutex_unlock(&card->mutex);
SC_FUNC_RETURN(card->ctx, 2, r);
}

View File

@ -33,12 +33,7 @@
/* Internal use only */
int sc_check_sw(struct sc_card *card, int sw1, int sw2);
size_t sc_count_bit_string_size(const void * buf, size_t bufsize);
/* Default timeout value for SCardGetStatusChange */
#ifndef SC_CUSTOM_STATUS_TIMEOUT
#define SC_STATUS_TIMEOUT 0
#else
#define SC_STATUS_TIMEOUT SC_CUSTOM_STATUS_TIMEOUT
#endif
int _sc_add_reader(struct sc_context *ctx, struct sc_reader *reader);
struct sc_slot_info * _sc_get_slot_info(struct sc_reader *reader, int slot_id);
#endif

View File

@ -695,7 +695,7 @@ static int iso7816_restore_security_env(struct sc_card *card, int se_num)
{
struct sc_apdu apdu;
int r;
u8 rbuf[MAX_BUFFER_SIZE];
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
assert(card != NULL);
@ -713,8 +713,8 @@ static int iso7816_compute_signature(struct sc_card *card,
{
int r;
struct sc_apdu apdu;
u8 rbuf[MAX_BUFFER_SIZE];
u8 sbuf[MAX_BUFFER_SIZE];
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
assert(card != NULL && data != NULL && out != NULL);
if (datalen > 255)
@ -786,10 +786,10 @@ static int iso7816_reset_retry_counter(struct sc_card *card, unsigned int type,
size_t newlen)
{
struct sc_apdu apdu;
u8 sbuf[MAX_BUFFER_SIZE];
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
int r, p1 = 0, len = puklen + newlen;
if (len >= MAX_BUFFER_SIZE)
if (len >= SC_MAX_APDU_BUFFER_SIZE)
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS);
switch (type) {
case SC_AC_CHV:
@ -827,7 +827,6 @@ static struct sc_card_operations iso_ops = {
};
static const struct sc_card_driver iso_driver = {
NULL,
"ISO 7816 reference driver",
"iso7816",
&iso_ops

View File

@ -27,7 +27,6 @@
#define _OPENSC_H
#include <pthread.h>
#include <winscard.h>
#ifndef NDEBUG
#include <assert.h>
#endif
@ -80,6 +79,8 @@ extern "C" {
#define SC_ERROR_RECORD_NOT_FOUND -1031
#define SC_ERROR_INTERNAL -1032
#define SC_ERROR_CLASS_NOT_SUPPORTED -1033
#define SC_ERROR_SLOT_NOT_FOUND -1034
#define SC_ERROR_SLOT_ALREADY_CONNECTED -1035
/* Different APDU cases */
#define SC_APDU_CASE_NONE 0
@ -146,8 +147,10 @@ extern "C" {
/* various maximum values */
#define SC_MAX_CARD_DRIVERS 16
#define SC_MAX_READER_DRIVERS 4
#define SC_MAX_CARD_DRIVER_SNAME_SIZE 16
#define SC_MAX_READERS 4
#define SC_MAX_SLOTS 4
#define SC_MAX_CARD_APPS 4
#define SC_MAX_APDU_BUFFER_SIZE 258
#define SC_MAX_PATH_SIZE 16
@ -274,12 +277,78 @@ struct sc_card_cache {
#define SC_PROTO_RAW 0x00001000
#define SC_PROTO_ANY 0xFFFFFFFF
struct sc_reader_driver {
const char *name;
const char *short_name;
struct sc_reader_operations *ops;
};
#define SC_SLOT_CARD_PRESENT 0x00000001
struct sc_slot_info {
int id;
unsigned long flags, capabilities;
unsigned int supported_protocols, active_protocol;
u8 atr[SC_MAX_ATR_SIZE];
size_t atr_len;
void *drv_data;
};
struct sc_event_listener {
unsigned int event_mask;
void (*func)(void *, const struct sc_slot_info *, unsigned int event);
};
struct sc_reader {
struct sc_context *ctx;
const struct sc_reader_driver *driver;
const struct sc_reader_operations *ops;
void *drv_data;
char *name;
struct sc_slot_info slot[SC_MAX_SLOTS];
int slot_count;
};
#define SC_DISCONNECT 0
#define SC_DISCONNECT_AND_RESET 1
#define SC_DISCONNECT_AND_UNPOWER 2
#define SC_DISCONNECT_AND_EJECT 3
struct sc_reader_operations {
/* Called during sc_establish_context(), when the driver
* is loaded */
int (*init)(struct sc_context *ctx, void **priv_data);
/* Called when the driver is being unloaded. finish() has to
* deallocate the private data and any resources. */
int (*finish)(void *priv_data);
/* Called when releasing a reader. release() has to
* deallocate the private data. Other fields will be
* freed by OpenSC. */
int (*release)(struct sc_reader *reader);
int (*detect_card_presence)(struct sc_reader *reader,
struct sc_slot_info *slot);
int (*connect)(struct sc_reader *reader, struct sc_slot_info *slot);
int (*disconnect)(struct sc_reader *reader, struct sc_slot_info *slot,
int action);
int (*transmit)(struct sc_reader *reader, struct sc_slot_info *slot,
const u8 *sendbuf, size_t sendsize,
u8 *recvbuf, size_t *recvsize);
int (*lock)(struct sc_reader *reader, struct sc_slot_info *slot);
int (*unlock)(struct sc_reader *reader, struct sc_slot_info *slot);
int (*set_protocol)(struct sc_reader *reader, struct sc_slot_info *slot,
unsigned int proto);
int (*add_callback)(struct sc_reader *reader, struct sc_slot_info *slot,
const struct sc_event_listener *, void *arg);
};
struct sc_card {
struct sc_context *ctx;
struct sc_reader *reader;
struct sc_slot_info *slot;
SCARDHANDLE pcsc_card;
unsigned int protocol;
int reader;
unsigned long caps, flags;
int cla;
u8 atr[SC_MAX_ATR_SIZE];
@ -293,7 +362,7 @@ struct sc_card {
const struct sc_card_driver *driver;
struct sc_card_operations *ops;
void *ops_data;
void *drv_data;
struct sc_card_cache cache;
int cache_valid;
@ -301,7 +370,6 @@ struct sc_card {
unsigned int magic;
};
struct sc_card_operations {
/* Called in sc_connect_card(). Must return 1, if the current
* card can be handled with this driver, or 0 otherwise. ATR
@ -401,21 +469,23 @@ struct sc_card_operations {
};
struct sc_card_driver {
char *libpath; /* NULL, if compiled in */
const char *name;
const char *short_name;
struct sc_card_operations *ops;
};
struct sc_context {
SCARDCONTEXT pcsc_ctx;
char *readers[SC_MAX_READERS];
int reader_count;
int debug;
FILE *debug_file, *error_file;
int log_errors;
const struct sc_reader_driver *reader_drivers[SC_MAX_READER_DRIVERS+1];
void *reader_drv_data[SC_MAX_READER_DRIVERS];
struct sc_reader *reader[SC_MAX_READERS];
int reader_count;
const struct sc_card_driver *card_drivers[SC_MAX_CARD_DRIVERS+1];
const struct sc_card_driver *forced_driver;
pthread_mutex_t mutex;
@ -463,18 +533,18 @@ int sc_set_card_driver(struct sc_context *ctx, const char *short_name);
/**
* Connects to a card in a reader and auto-detects the card driver.
* The ATR (Answer to Reset) string of the card is also retrieved.
* @param ctx OpenSC context
* @param reader Reader number (this is prone to change)
* @param reader Reader structure
* @param slot_id Slot ID to connect to
* @param card The allocated card object will go here */
int sc_connect_card(struct sc_context *ctx,
int reader, struct sc_card **card);
int sc_connect_card(struct sc_reader *reader, int slot_id,
struct sc_card **card);
/**
* Disconnects from a card, and frees the card structure. Any locks
* made by the application must be released before calling this function.
* NOTE: The card is not reset nor powered down after the operation.
* @param card The card to disconnect
*/
int sc_disconnect_card(struct sc_card *card);
int sc_disconnect_card(struct sc_card *card, int action);
/**
* Returns 1 if the magic value of the card object is correct. Mostly
* used internally by the library.
@ -484,14 +554,15 @@ inline int sc_card_valid(const struct sc_card *card);
/**
* Checks if a card is present in a reader
* @param ctx OpenSC context
* @param reader Reader number to use (this will change)
* @param reader Reader structure
* @param reader Slot ID
* @retval 1 if a card is present
* @retval 0 card absent
* @retval < 0 if an error occured
*/
int sc_detect_card(struct sc_context *ctx, int reader);
int sc_detect_card_presence(struct sc_reader *reader, int slot_id);
#if 0
/**
* Waits for card insertion to a reader
* @param ctx OpenSC context
@ -502,6 +573,7 @@ int sc_detect_card(struct sc_context *ctx, int reader);
* @retval < 0 if an error occured
*/
int sc_wait_for_card(struct sc_context *ctx, int reader, int timeout);
#endif
/**
* Locks the card against modification from other threads.
@ -617,6 +689,8 @@ const char *sc_strerror(int sc_errno);
extern const char *sc_version;
extern const struct sc_reader_driver *sc_get_pcsc_driver(void);
extern const struct sc_card_driver *sc_get_iso7816_driver(void);
extern const struct sc_card_driver *sc_get_emv_driver(void);
extern const struct sc_card_driver *sc_get_setec_driver(void);

View File

@ -475,7 +475,7 @@ void sc_pkcs15_card_free(struct sc_pkcs15_card *p15card)
int sc_pkcs15_bind(struct sc_card *card,
struct sc_pkcs15_card **p15card_out)
{
unsigned char buf[MAX_BUFFER_SIZE];
unsigned char buf[SC_MAX_APDU_BUFFER_SIZE];
int err, len;
struct sc_pkcs15_card *p15card = NULL;
struct sc_path tmppath;

370
src/libopensc/reader-pcsc.c Normal file
View File

@ -0,0 +1,370 @@
/*
* reader-pcsc.c: Reader driver for PC/SC Lite
*
* Copyright (C) 2002 Juha Yrjölä <juha.yrjola@iki.fi>
*
* 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 "sc-internal.h"
#include "sc-log.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <winscard.h>
#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;
};
struct pcsc_private_data {
SCARDCONTEXT pcsc_ctx;
char *reader_name;
};
struct pcsc_slot_data {
SCARDHANDLE pcsc_card;
};
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;
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)
{
SCARD_IO_REQUEST sSendPci, sRecvPci;
DWORD dwSendLength, dwRecvLength;
LONG rv;
SCARDHANDLE card;
struct pcsc_slot_data *pslot = GET_SLOT_DATA(slot);
assert(pslot != NULL);
card = pslot->pcsc_card;
sSendPci.dwProtocol = opensc_proto_to_pcsc(slot->active_protocol);
sSendPci.cbPciLength = 0;
sRecvPci.dwProtocol = opensc_proto_to_pcsc(slot->active_protocol);
sRecvPci.cbPciLength = 0;
dwSendLength = sendsize;
dwRecvLength = *recvsize;
if (dwRecvLength > 255)
dwRecvLength = 255;
rv = SCardTransmit(card, &sSendPci, sendbuf, dwSendLength,
&sRecvPci, recvbuf, &dwRecvLength);
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:
#if 0
FIXME
if (sc_detect_card(card->ctx, card->reader) != 1)
return SC_ERROR_CARD_REMOVED;
#endif
return SC_ERROR_TRANSMIT_FAILED;
default:
error(reader->ctx, "SCardTransmit failed: %s\n", pcsc_stringify_error(rv));
return SC_ERROR_TRANSMIT_FAILED;
}
}
if (dwRecvLength < 2)
return SC_ERROR_ILLEGAL_RESPONSE;
*recvsize = dwRecvLength;
return 0;
}
static int pcsc_detect_card_presence(struct sc_reader *reader, struct sc_slot_info *slot)
{
struct pcsc_private_data *priv = GET_PRIV_DATA(reader);
LONG ret;
SCARD_READERSTATE_A rgReaderStates[SC_MAX_READERS];
rgReaderStates[0].szReader = priv->reader_name;
rgReaderStates[0].dwCurrentState = SCARD_STATE_UNAWARE;
rgReaderStates[0].dwEventState = SCARD_STATE_UNAWARE;
ret = SCardGetStatusChange(priv->pcsc_ctx, 0, rgReaderStates, 1);
if (ret != 0) {
error(reader->ctx, "SCardGetStatusChange failed: %s\n", pcsc_stringify_error(ret));
SC_FUNC_RETURN(reader->ctx, 1, pcsc_ret_to_error(ret));
}
if (rgReaderStates[0].dwEventState & SCARD_STATE_PRESENT) {
slot->flags |= SC_SLOT_CARD_PRESENT;
return 1;
}
slot->flags &= ~SC_SLOT_CARD_PRESENT;
return 0;
}
static int refresh_slot_attributes(struct sc_reader *reader, struct sc_slot_info *slot)
{
struct pcsc_private_data *priv = GET_PRIV_DATA(reader);
LONG ret;
SCARD_READERSTATE_A rgReaderStates[SC_MAX_READERS];
rgReaderStates[0].szReader = priv->reader_name;
rgReaderStates[0].dwCurrentState = SCARD_STATE_UNAWARE;
rgReaderStates[0].dwEventState = SCARD_STATE_UNAWARE;
ret = SCardGetStatusChange(priv->pcsc_ctx, 0, rgReaderStates, 1);
if (ret != 0) {
error(reader->ctx, "SCardGetStatusChange failed: %s\n", pcsc_stringify_error(ret));
return pcsc_ret_to_error(ret);
}
slot->flags = 0;
if (rgReaderStates[0].dwEventState & SCARD_STATE_PRESENT) {
slot->flags = SC_SLOT_CARD_PRESENT;
slot->atr_len = rgReaderStates[0].cbAtr;
if (slot->atr_len > SC_MAX_ATR_SIZE)
slot->atr_len = SC_MAX_ATR_SIZE;
memcpy(slot->atr, rgReaderStates[0].rgbAtr, slot->atr_len);
}
return 0;
}
static int pcsc_connect(struct sc_reader *reader, struct sc_slot_info *slot)
{
DWORD active_proto;
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;
if (pslot != NULL)
return SC_ERROR_SLOT_ALREADY_CONNECTED;
r = refresh_slot_attributes(reader, slot);
if (r)
return r;
if (!(slot->flags & SC_SLOT_CARD_PRESENT))
return SC_ERROR_CARD_NOT_PRESENT;
pslot = malloc(sizeof(struct pcsc_slot_data));
if (pslot == NULL)
return SC_ERROR_OUT_OF_MEMORY;
rv = SCardConnect(priv->pcsc_ctx, priv->reader_name,
SCARD_SHARE_SHARED, SCARD_PROTOCOL_ANY,
&card_handle, &active_proto);
if (rv != 0) {
error(reader->ctx, "SCardConnect failed: %s\n", pcsc_stringify_error(rv));
free(pslot);
return pcsc_ret_to_error(rv);
}
slot->active_protocol = pcsc_proto_to_opensc(active_proto);
slot->drv_data = pslot;
pslot->pcsc_card = card_handle;
return 0;
}
static int pcsc_disconnect(struct sc_reader *reader, struct sc_slot_info *slot,
int action)
{
struct pcsc_slot_data *pslot = GET_SLOT_DATA(slot);
/* FIXME: check action */
SCardDisconnect(pslot->pcsc_card, SCARD_LEAVE_CARD);
free(pslot);
slot->drv_data = NULL;
return 0;
}
static int pcsc_lock(struct sc_reader *reader, struct sc_slot_info *slot)
{
long rv;
struct pcsc_slot_data *pslot = GET_SLOT_DATA(slot);
assert(pslot != NULL);
rv = SCardBeginTransaction(pslot->pcsc_card);
if (rv != SCARD_S_SUCCESS) {
error(reader->ctx, "SCardBeginTransaction failed: %s\n", pcsc_stringify_error(rv));
return pcsc_ret_to_error(rv);
}
return 0;
}
static int pcsc_unlock(struct sc_reader *reader, struct sc_slot_info *slot)
{
long rv;
struct pcsc_slot_data *pslot = GET_SLOT_DATA(slot);
assert(pslot != NULL);
rv = SCardEndTransaction(pslot->pcsc_card, SCARD_LEAVE_CARD);
if (rv != SCARD_S_SUCCESS) {
error(reader->ctx, "SCardEndTransaction failed: %s\n", pcsc_stringify_error(rv));
return pcsc_ret_to_error(rv);
}
return 0;
}
static int pcsc_release(struct sc_reader *reader)
{
struct pcsc_private_data *priv = GET_PRIV_DATA(reader);
free(priv->reader_name);
free(priv);
return 0;
}
static struct sc_reader_operations pcsc_ops;
static const struct sc_reader_driver pcsc_drv = {
"PC/SC Lite Resource Manager",
"pcsc",
&pcsc_ops
};
static int pcsc_init(struct sc_context *ctx, void **reader_data)
{
LONG rv;
DWORD reader_buf_size;
char *reader_buf, *p;
LPCSTR mszGroups = NULL;
SCARDCONTEXT pcsc_ctx;
int r;
struct pcsc_global_private_data *gpriv;
rv = SCardEstablishContext(SCARD_SCOPE_GLOBAL, "localhost", NULL,
&pcsc_ctx);
if (rv != SCARD_S_SUCCESS)
return pcsc_ret_to_error(rv);
SCardListReaders(pcsc_ctx, NULL, NULL,
(LPDWORD) &reader_buf_size);
if (reader_buf_size < 2) {
SCardReleaseContext(pcsc_ctx);
return 0; /* No readers configured */
}
gpriv = malloc(sizeof(struct pcsc_global_private_data));
if (gpriv == NULL) {
SCardReleaseContext(pcsc_ctx);
return SC_ERROR_OUT_OF_MEMORY;
}
gpriv->pcsc_ctx = pcsc_ctx;
*reader_data = gpriv;
reader_buf = (char *) malloc(sizeof(char) * reader_buf_size);
SCardListReaders(pcsc_ctx, mszGroups, reader_buf,
(LPDWORD) &reader_buf_size);
p = reader_buf;
do {
struct sc_reader *reader = malloc(sizeof(struct sc_reader));
struct pcsc_private_data *priv = malloc(sizeof(struct pcsc_private_data));
struct sc_slot_info *slot;
if (reader == NULL || priv == NULL) {
if (reader)
free(reader);
if (priv)
free(priv);
break;
}
reader->drv_data = priv;
reader->ops = &pcsc_ops;
reader->driver = &pcsc_drv;
reader->slot_count = 1;
reader->name = strdup(p);
r = _sc_add_reader(ctx, reader);
if (r) {
free(priv->reader_name);
free(priv);
free(reader);
break;
}
slot = &reader->slot[0];
slot->id = 0;
refresh_slot_attributes(reader, slot);
slot->capabilities = 0;
slot->atr_len = 0;
slot->drv_data = NULL;
priv->pcsc_ctx = pcsc_ctx;
priv->reader_name = strdup(p);
while (*p++ != 0);
} while (p < (reader_buf + reader_buf_size - 1));
free(reader_buf);
return 0;
}
static int pcsc_finish(void *prv_data)
{
struct pcsc_global_private_data *priv = (struct pcsc_global_private_data *) prv_data;
SCardReleaseContext(priv->pcsc_ctx);
free(priv);
return 0;
}
const struct sc_reader_driver * sc_get_pcsc_driver()
{
pcsc_ops.init = pcsc_init;
pcsc_ops.finish = pcsc_finish;
pcsc_ops.transmit = pcsc_transmit;
pcsc_ops.detect_card_presence = pcsc_detect_card_presence;
pcsc_ops.lock = pcsc_lock;
pcsc_ops.unlock = pcsc_unlock;
pcsc_ops.release = pcsc_release;
pcsc_ops.connect = pcsc_connect;
pcsc_ops.disconnect = pcsc_disconnect;
return &pcsc_drv;
}

View File

@ -33,12 +33,7 @@
/* Internal use only */
int sc_check_sw(struct sc_card *card, int sw1, int sw2);
size_t sc_count_bit_string_size(const void * buf, size_t bufsize);
/* Default timeout value for SCardGetStatusChange */
#ifndef SC_CUSTOM_STATUS_TIMEOUT
#define SC_STATUS_TIMEOUT 0
#else
#define SC_STATUS_TIMEOUT SC_CUSTOM_STATUS_TIMEOUT
#endif
int _sc_add_reader(struct sc_context *ctx, struct sc_reader *reader);
struct sc_slot_info * _sc_get_slot_info(struct sc_reader *reader, int slot_id);
#endif

View File

@ -67,34 +67,42 @@ int sc_hex_to_bin(const char *in, u8 *out, size_t *outlen)
return err;
}
int sc_detect_card(struct sc_context *ctx, int reader)
int _sc_add_reader(struct sc_context *ctx, struct sc_reader *reader)
{
LONG ret;
SCARD_READERSTATE_A rgReaderStates[SC_MAX_READERS];
assert(ctx != NULL);
SC_FUNC_CALLED(ctx, 1);
if (reader >= ctx->reader_count || reader < 0)
return SC_ERROR_INVALID_ARGUMENTS;
rgReaderStates[0].szReader = ctx->readers[reader];
rgReaderStates[0].dwCurrentState = SCARD_STATE_UNAWARE;
rgReaderStates[0].dwEventState = SCARD_STATE_UNAWARE;
ret = SCardGetStatusChange(ctx->pcsc_ctx, SC_STATUS_TIMEOUT, rgReaderStates, 1);
if (ret != 0) {
error(ctx, "SCardGetStatusChange failed: %s\n", pcsc_stringify_error(ret));
SC_FUNC_RETURN(ctx, 1, -1); /* FIXME */
}
if (rgReaderStates[0].dwEventState & SCARD_STATE_PRESENT) {
if (ctx->debug >= 1)
debug(ctx, "card present\n");
return 1;
}
if (ctx->debug >= 1)
debug(ctx, "card absent\n");
assert(reader != NULL);
reader->ctx = ctx;
if (ctx->reader_count == SC_MAX_READERS)
return SC_ERROR_TOO_MANY_OBJECTS;
ctx->reader[ctx->reader_count] = reader;
ctx->reader_count++;
return 0;
}
struct sc_slot_info * _sc_get_slot_info(struct sc_reader *reader, int slot_id)
{
assert(reader != NULL);
if (slot_id > reader->slot_count)
return NULL;
return &reader->slot[slot_id];
}
int sc_detect_card_presence(struct sc_reader *reader, int slot_id)
{
int r;
struct sc_slot_info *slot = _sc_get_slot_info(reader, slot_id);
if (slot == NULL)
SC_FUNC_RETURN(reader->ctx, 0, SC_ERROR_SLOT_NOT_FOUND);
SC_FUNC_CALLED(reader->ctx, 1);
if (reader->ops->detect_card_presence == NULL)
SC_FUNC_RETURN(reader->ctx, 0, SC_ERROR_NOT_SUPPORTED);
r = reader->ops->detect_card_presence(reader, slot);
SC_FUNC_RETURN(reader->ctx, 1, r);
}
#if 0
int sc_wait_for_card(struct sc_context *ctx, int reader, int timeout)
{
LONG ret;
@ -132,14 +140,11 @@ int sc_wait_for_card(struct sc_context *ctx, int reader, int timeout)
}
SC_FUNC_RETURN(ctx, 1, 0);
}
#endif
int sc_establish_context(struct sc_context **ctx_out)
{
struct sc_context *ctx;
LONG rv;
DWORD reader_buf_size;
char *reader_buf, *p;
LPCSTR mszGroups = NULL;
int i;
assert(ctx_out != NULL);
@ -148,32 +153,21 @@ int sc_establish_context(struct sc_context **ctx_out)
return SC_ERROR_OUT_OF_MEMORY;
memset(ctx, 0, sizeof(struct sc_context));
ctx->log_errors = 1;
rv = SCardEstablishContext(SCARD_SCOPE_GLOBAL, "localhost", NULL,
&ctx->pcsc_ctx);
if (rv != SCARD_S_SUCCESS) {
free(ctx);
return SC_ERROR_CONNECTING_TO_RES_MGR;
}
SCardListReaders(ctx->pcsc_ctx, NULL, NULL,
(LPDWORD) &reader_buf_size);
if (reader_buf_size < 2) {
free(ctx);
return SC_ERROR_NO_READERS_FOUND;
}
reader_buf = (char *) malloc(sizeof(char) * reader_buf_size);
SCardListReaders(ctx->pcsc_ctx, mszGroups, reader_buf,
(LPDWORD) &reader_buf_size);
p = reader_buf;
ctx->reader_count = 0;
do {
ctx->readers[ctx->reader_count] = strdup(p);
ctx->reader_count++;
while (*p++ != 0);
if (ctx->reader_count == SC_MAX_READERS)
break;
} while (p < (reader_buf + reader_buf_size - 1));
free(reader_buf);
pthread_mutex_init(&ctx->mutex, NULL);
for (i = 0; i < SC_MAX_READER_DRIVERS+1; i++)
ctx->reader_drivers[i] = NULL;
i = 0;
#if 1
ctx->reader_drivers[i++] = sc_get_pcsc_driver();
#endif
i = 0;
while (ctx->reader_drivers[i] != NULL) {
ctx->reader_drivers[i]->ops->init(ctx, &ctx->reader_drv_data[i]);
i++;
}
ctx->forced_driver = NULL;
for (i = 0; i < SC_MAX_CARD_DRIVERS+1; i++)
ctx->card_drivers[i] = NULL;
@ -208,11 +202,21 @@ int sc_destroy_context(struct sc_context *ctx)
assert(ctx != NULL);
SC_FUNC_CALLED(ctx, 1);
for (i = 0; i < ctx->reader_count; i++)
free(ctx->readers[i]);
for (i = 0; i < ctx->reader_count; i++) {
struct sc_reader *rdr = ctx->reader[i];
if (rdr->ops->release != NULL)
rdr->ops->release(rdr);
free(rdr->name);
free(rdr);
}
for (i = 0; ctx->reader_drivers[i] != NULL; i++) {
const struct sc_reader_driver *drv = ctx->reader_drivers[i];
if (drv->ops->finish != NULL)
drv->ops->finish(ctx->reader_drv_data[i]);
}
ctx->debug_file = ctx->error_file = NULL;
SCardReleaseContext(ctx->pcsc_ctx);
ctx->pcsc_ctx = 0;
free(ctx);
return 0;
}
@ -335,6 +339,8 @@ const char *sc_strerror(int error)
"Record not found",
"Internal error",
"Invalid CLA byte in APDU",
"Slot not found",
"Slot already connected",
};
int nr_errors = sizeof(errors) / sizeof(errors[0]);

View File

@ -29,8 +29,8 @@ int sc_decipher(struct sc_card *card,
{
int r;
struct sc_apdu apdu;
u8 rbuf[MAX_BUFFER_SIZE];
u8 sbuf[MAX_BUFFER_SIZE];
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
assert(card != NULL && crgram != NULL && out != NULL);
SC_FUNC_CALLED(card->ctx, 2);

View File

@ -1340,14 +1340,14 @@ int main(int argc, char * const argv[])
err = 1;
goto end;
}
if (sc_detect_card(ctx, opt_reader) != 1) {
if (sc_detect_card_presence(ctx->reader[opt_reader], 0) != 1) {
fprintf(stderr, "Card not present.\n");
err = 3;
goto end;
}
if (!quiet)
fprintf(stderr, "Connecting to card in reader %s...\n", ctx->readers[opt_reader]);
r = sc_connect_card(ctx, opt_reader, &card);
fprintf(stderr, "Connecting to card in reader %s...\n", ctx->reader[opt_reader]->name);
r = sc_connect_card(ctx->reader[opt_reader], 0, &card);
if (r) {
fprintf(stderr, "Failed to connect to card: %s\n", sc_strerror(r));
err = 1;
@ -1402,7 +1402,7 @@ int main(int argc, char * const argv[])
end:
if (card) {
sc_unlock(card);
sc_disconnect_card(card);
sc_disconnect_card(card, 0);
}
if (ctx)
sc_destroy_context(ctx);

View File

@ -63,7 +63,7 @@ void die(int ret)
sc_file_free(current_file);
if (card) {
sc_unlock(card);
sc_disconnect_card(card);
sc_disconnect_card(card, 0);
}
if (ctx)
sc_destroy_context(ctx);
@ -861,7 +861,7 @@ int main(int argc, char * const argv[])
err = 1;
goto end;
}
if (sc_detect_card(ctx, opt_reader) != 1) {
if (sc_detect_card_presence(ctx->reader[opt_reader], 0) != 1) {
fprintf(stderr, "Card not present.\n");
err = 3;
goto end;
@ -874,8 +874,8 @@ int main(int argc, char * const argv[])
goto end;
}
}
fprintf(stderr, "Connecting to card in reader %s...\n", ctx->readers[opt_reader]);
r = sc_connect_card(ctx, opt_reader, &card);
fprintf(stderr, "Connecting to card in reader %s...\n", ctx->reader[opt_reader]->name);
r = sc_connect_card(ctx->reader[opt_reader], 0, &card);
if (r) {
fprintf(stderr, "Failed to connect to card: %s\n", sc_strerror(r));
err = 1;

View File

@ -77,8 +77,10 @@ int list_readers(void)
return 0;
}
printf("Configured readers:\n");
printf("Nr. Driver Name\n");
for (i = 0; i < ctx->reader_count; i++) {
printf(" %d - %s\n", i, ctx->readers[i]);
printf("%-7d%-11s%s\n", i, ctx->reader[i]->driver->short_name,
ctx->reader[i]->name);
}
return 0;
}
@ -150,10 +152,10 @@ int print_file(struct sc_card *card, const struct sc_file *file, const struct sc
printf(" ");
if (file->type == SC_FILE_TYPE_DF)
for (r = 0; r < sizeof(ac_ops_df)/sizeof(ac_ops_df[0]); r++)
printf("%s[%s] ", ac_ops_df[r], acl_to_str(file->acl[r]));
printf("%s[%s] ", ac_ops_df[r], acl_to_str(sc_file_get_acl_entry(file, r)));
else
for (r = 0; r < sizeof(ac_ops_ef)/sizeof(ac_ops_ef[0]); r++)
printf("%s[%s] ", ac_ops_ef[r], acl_to_str(file->acl[r]));
printf("%s[%s] ", ac_ops_ef[r], acl_to_str(sc_file_get_acl_entry(file, r)));
if (file->sec_attr_len) {
printf("sec: ");
@ -194,7 +196,7 @@ int enum_dir(struct sc_path path, int depth)
{
struct sc_file *file;
int r, file_type;
u8 files[MAX_BUFFER_SIZE];
u8 files[SC_MAX_APDU_BUFFER_SIZE];
r = sc_select_file(card, &path, &file);
if (r) {
@ -237,8 +239,8 @@ int list_files(void)
int send_apdu(void)
{
struct sc_apdu apdu;
u8 buf[MAX_BUFFER_SIZE], sbuf[MAX_BUFFER_SIZE],
rbuf[MAX_BUFFER_SIZE], *p;
u8 buf[SC_MAX_APDU_BUFFER_SIZE], sbuf[SC_MAX_APDU_BUFFER_SIZE],
rbuf[SC_MAX_APDU_BUFFER_SIZE], *p;
size_t len, len0, r;
int c;
@ -398,7 +400,7 @@ int main(int argc, char * const argv[])
err = 1;
goto end;
}
if (sc_detect_card(ctx, opt_reader) != 1) {
if (sc_detect_card_presence(ctx->reader[opt_reader], 0) != 1) {
fprintf(stderr, "Card not present.\n");
err = 3;
goto end;
@ -412,8 +414,8 @@ int main(int argc, char * const argv[])
}
}
if (!quiet)
fprintf(stderr, "Connecting to card in reader %s...\n", ctx->readers[opt_reader]);
r = sc_connect_card(ctx, opt_reader, &card);
fprintf(stderr, "Connecting to card in reader %s...\n", ctx->reader[opt_reader]->name);
r = sc_connect_card(ctx->reader[opt_reader], 0, &card);
if (r) {
fprintf(stderr, "Failed to connect to card: %s\n", sc_strerror(r));
err = 1;
@ -445,7 +447,7 @@ int main(int argc, char * const argv[])
end:
if (card) {
sc_unlock(card);
sc_disconnect_card(card);
sc_disconnect_card(card, 0);
}
if (ctx)
sc_destroy_context(ctx);

View File

@ -254,13 +254,13 @@ int main(int argc, char * const argv[])
err = 1;
goto end;
}
if (sc_detect_card(ctx, opt_reader) != 1) {
if (sc_detect_card_presence(ctx->reader[opt_reader], 0) != 1) {
fprintf(stderr, "Card not present.\n");
return 3;
}
if (!quiet)
fprintf(stderr, "Connecting to card in reader %s...\n", ctx->readers[opt_reader]);
r = sc_connect_card(ctx, opt_reader, &card);
fprintf(stderr, "Connecting to card in reader %s...\n", ctx->reader[opt_reader]->name);
r = sc_connect_card(ctx->reader[opt_reader], 0, &card);
if (r) {
fprintf(stderr, "Failed to connect to card: %s\n", sc_strerror(r));
err = 1;
@ -344,7 +344,7 @@ end:
#if 1
sc_unlock(card);
#endif
sc_disconnect_card(card);
sc_disconnect_card(card, 0);
}
if (ctx)
sc_destroy_context(ctx);

View File

@ -196,7 +196,7 @@ main(int argc, char **argv)
done: if (card) {
sc_unlock(card);
sc_disconnect_card(card);
sc_disconnect_card(card, 0);
}
sc_destroy_context(ctx);
return r? 1 : 0;
@ -235,16 +235,16 @@ connect(int reader)
ctx->reader_count == 1? "" : "s");
return 0;
}
if (sc_detect_card(ctx, reader) != 1) {
if (sc_detect_card_presence(ctx->reader[reader], 0) != 1) {
error("Card not present.\n");
return 0;
}
if (!opt_quiet) {
printf("Connecting to card in reader %s...\n",
ctx->readers[reader]);
ctx->reader[reader]->name);
}
r = sc_connect_card(ctx, reader, &card);
r = sc_connect_card(ctx->reader[reader], 0, &card);
if (r) {
error("Failed to connect to card: %s\n", sc_strerror(r));
return 0;

View File

@ -460,13 +460,13 @@ int main(int argc, char * const argv[])
err = 1;
goto end;
}
if (sc_detect_card(ctx, opt_reader) != 1) {
if (sc_detect_card_presence(ctx->reader[opt_reader], 0) != 1) {
fprintf(stderr, "Card not present.\n");
return 3;
}
if (!quiet)
fprintf(stderr, "Connecting to card in reader %s...\n", ctx->readers[opt_reader]);
r = sc_connect_card(ctx, opt_reader, &card);
fprintf(stderr, "Connecting to card in reader %s...\n", ctx->reader[opt_reader]->name);
r = sc_connect_card(ctx->reader[opt_reader], 0, &card);
if (r) {
fprintf(stderr, "Failed to connect to card: %s\n", sc_strerror(r));
err = 1;
@ -526,7 +526,7 @@ end:
sc_pkcs15_unbind(p15card);
if (card) {
sc_unlock(card);
sc_disconnect_card(card);
sc_disconnect_card(card, 0);
}
if (ctx)
sc_destroy_context(ctx);