- 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:
parent
1f4e5c4b6d
commit
3fa1b27736
|
@ -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.
|
||||
|
||||
|
|
@ -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@
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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]);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue