1 |
/* wptCardPCSC.cpp - PC/SC card API interface |
/* wptCardPCSC.cpp - PC/SC card API interface |
2 |
* Copyright (C) 2003 Timo Schulz |
* Copyright (C) 2003, 2006 Timo Schulz |
|
* Copyright (C) 2003, 2004 Free Software Foundation, Inc. |
|
3 |
* |
* |
4 |
* This file is part of WinPT. |
* This file is part of WinPT. |
5 |
* |
* |
21 |
#include <config.h> |
#include <config.h> |
22 |
#endif |
#endif |
23 |
|
|
|
#if 0 /* not needed right now. */ |
|
24 |
#include <stdio.h> |
#include <stdio.h> |
25 |
#include <windows.h> |
#include <windows.h> |
26 |
#ifndef __MINGW32__ |
#ifndef __MINGW32__ |
27 |
#include <winscard.h> |
#include <winscard.h> |
28 |
|
#else |
29 |
|
/* mingw32 has no win32 smartcard API definitions. */ |
30 |
|
typedef ULONG_PTR SCARDCONTEXT; |
31 |
|
#define SCARD_SCOPE_SYSTEM 2 |
32 |
|
#define SCARD_S_SUCCESS NO_ERROR |
33 |
#endif |
#endif |
34 |
|
|
35 |
#include "gpgme.h" |
#include "gpgme.h" |
37 |
#include "wptCard.h" |
#include "wptCard.h" |
38 |
|
|
39 |
|
|
|
/* Definitions usually found in winscard.h but not used here becuase |
|
|
mingw does not come with winscard and we dlopen the stuff |
|
|
anyway. */ |
|
|
typedef unsigned long pcsc_context_t; |
|
|
struct pcsc_readerstate_s |
|
|
{ |
|
|
const char *reader; |
|
|
void *user_data; |
|
|
unsigned long current_state; |
|
|
unsigned long event_state; |
|
|
unsigned long atrlen; |
|
|
unsigned char atr[33]; |
|
|
}; |
|
|
|
|
|
typedef struct pcsc_readerstate_s *pcsc_readerstate_t; |
|
|
|
|
|
/* PC/SC constants and function pointer. */ |
|
|
#define PCSC_SCOPE_USER 0 |
|
|
#define PCSC_SCOPE_TERMINAL 1 |
|
|
#define PCSC_SCOPE_SYSTEM 2 |
|
|
#define PCSC_SCOPE_GLOBAL 3 |
|
|
|
|
|
#define PCSC_PROTOCOL_T0 1 |
|
|
#define PCSC_PROTOCOL_T1 2 |
|
|
#define PCSC_PROTOCOL_RAW 4 |
|
|
|
|
|
#define PCSC_SHARE_EXCLUSIVE 1 |
|
|
#define PCSC_SHARE_SHARED 2 |
|
|
#define PCSC_SHARE_DIRECT 3 |
|
|
|
|
|
#define PCSC_LEAVE_CARD 0 |
|
|
#define PCSC_RESET_CARD 1 |
|
|
#define PCSC_UNPOWER_CARD 2 |
|
|
#define PCSC_EJECT_CARD 3 |
|
|
|
|
|
#define PCSC_UNKNOWN 0x0001 |
|
|
#define PCSC_ABSENT 0x0002 /* Card is absent. */ |
|
|
#define PCSC_PRESENT 0x0004 /* Card is present. */ |
|
|
#define PCSC_SWALLOWED 0x0008 /* Card is present and electrical connected. */ |
|
|
#define PCSC_POWERED 0x0010 /* Card is powered. */ |
|
|
#define PCSC_NEGOTIABLE 0x0020 /* Card is awaiting PTS. */ |
|
|
#define PCSC_SPECIFIC 0x0040 /* Card is ready for use. */ |
|
|
|
|
|
#define PCSC_STATE_UNAWARE 0x0000 /* Want status. */ |
|
|
#define PCSC_STATE_IGNORE 0x0001 /* Ignore this reader. */ |
|
|
#define PCSC_STATE_CHANGED 0x0002 /* State has changed. */ |
|
|
#define PCSC_STATE_UNKNOWN 0x0004 /* Reader unknown. */ |
|
|
#define PCSC_STATE_UNAVAILABLE 0x0008 /* Status unavailable. */ |
|
|
#define PCSC_STATE_EMPTY 0x0010 /* Card removed. */ |
|
|
#define PCSC_STATE_PRESENT 0x0020 /* Card inserted. */ |
|
|
#define PCSC_STATE_ATRMATCH 0x0040 /* ATR matches card. */ |
|
|
#define PCSC_STATE_EXCLUSIVE 0x0080 /* Exclusive Mode. */ |
|
|
#define PCSC_STATE_INUSE 0x0100 /* Shared mode. */ |
|
|
#define PCSC_STATE_MUTE 0x0200 /* Unresponsive card. */ |
|
|
|
|
|
/* Some PC/SC error codes. */ |
|
|
#define PCSC_E_CANCELLED 0x80100002 |
|
|
#define PCSC_E_CANT_DISPOSE 0x8010000E |
|
|
#define PCSC_E_INSUFFICIENT_BUFFER 0x80100008 |
|
|
#define PCSC_E_INVALID_ATR 0x80100015 |
|
|
#define PCSC_E_INVALID_HANDLE 0x80100003 |
|
|
#define PCSC_E_INVALID_PARAMETER 0x80100004 |
|
|
#define PCSC_E_INVALID_TARGET 0x80100005 |
|
|
#define PCSC_E_INVALID_VALUE 0x80100011 |
|
|
#define PCSC_E_NO_MEMORY 0x80100006 |
|
|
#define PCSC_E_UNKNOWN_READER 0x80100009 |
|
|
#define PCSC_E_TIMEOUT 0x8010000A |
|
|
#define PCSC_E_SHARING_VIOLATION 0x8010000B |
|
|
#define PCSC_E_NO_SMARTCARD 0x8010000C |
|
|
#define PCSC_E_UNKNOWN_CARD 0x8010000D |
|
|
#define PCSC_E_PROTO_MISMATCH 0x8010000F |
|
|
#define PCSC_E_NOT_READY 0x80100010 |
|
|
#define PCSC_E_SYSTEM_CANCELLED 0x80100012 |
|
|
#define PCSC_E_NOT_TRANSACTED 0x80100016 |
|
|
#define PCSC_E_READER_UNAVAILABLE 0x80100017 |
|
|
#define PCSC_W_REMOVED_CARD 0x80100069 |
|
|
|
|
|
|
|
|
/* Possible card states. */ |
|
|
enum card_state_t { |
|
|
CARD_STATE_NONE=0, |
|
|
CARD_STATE_UNAWARE, |
|
|
CARD_STATE_UNAVAIL, |
|
|
CARD_STATE_PRESENT, |
|
|
CARD_STATE_EXCLUSI, |
|
|
CARD_STATE_EMPTY, |
|
|
CARD_STATE_INUSE, |
|
|
CARD_STATE_MUTE |
|
|
}; |
|
|
|
|
|
#define MAX_READERS 8 |
|
|
|
|
|
struct pcsc_reader_s { |
|
|
struct pcsc_readerstate_s reader_states[MAX_READERS]; |
|
|
int nreaders; |
|
|
char * readers[MAX_READERS]; |
|
|
}; |
|
|
typedef struct pcsc_reader_s *pcsc_reader_t; |
|
|
|
|
|
|
|
40 |
static LONG (WINAPI *pcsc_establish_context) (unsigned long scope, |
static LONG (WINAPI *pcsc_establish_context) (unsigned long scope, |
41 |
const void *reserved1, |
const void *reserved1, |
42 |
const void *reserved2, |
const void *reserved2, |
43 |
unsigned long *r_context); |
unsigned long *r_context); |
44 |
static LONG (WINAPI *pcsc_release_context) (unsigned long context); |
static LONG (WINAPI *pcsc_release_context) (unsigned long context); |
|
static LONG (WINAPI *pcsc_list_readers) (unsigned long context, |
|
|
const char *groups, |
|
|
char *readers, |
|
|
unsigned long *readerslen); |
|
|
static LONG (WINAPI *pcsc_connect) (unsigned long context, |
|
|
const char *reader, |
|
|
unsigned long share_mode, |
|
|
unsigned long preferred_protocols, |
|
|
unsigned long *r_card, |
|
|
unsigned long *r_active_protocol); |
|
|
static LONG (WINAPI *pcsc_disconnect) (unsigned long card, |
|
|
unsigned long disposition); |
|
|
static LONG (WINAPI *pcsc_status) (unsigned long card, |
|
|
char *reader, unsigned long *readerlen, |
|
|
unsigned long *r_state, unsigned long *r_protocol, |
|
|
unsigned char *atr, unsigned long *atrlen); |
|
|
static LONG (WINAPI *pcsc_get_status_change)(unsigned long ctx, |
|
|
unsigned long timeout, |
|
|
pcsc_readerstate_t readerstate, |
|
|
unsigned long creaders); |
|
45 |
|
|
46 |
static int pcsc_init = 0; |
static int pcsc_init = 0; |
47 |
|
|
57 |
} while (0) |
} while (0) |
58 |
|
|
59 |
|
|
60 |
int |
static int |
61 |
pcsc_loadlib (int scard_support) |
pcsc_loadlib (void) |
62 |
{ |
{ |
63 |
HMODULE hlib; |
HMODULE hlib; |
64 |
FARPROC a; |
FARPROC a; |
65 |
|
|
66 |
if (!scard_support || pcsc_init) |
if (pcsc_init) |
67 |
return 0; |
return 0; |
68 |
hlib = LoadLibrary ("WINSCARD"); |
hlib = LoadLibrary ("WINSCARD"); |
69 |
if (!hlib) |
if (!hlib) |
70 |
goto fail; |
goto fail; |
71 |
load_one_fnc (pcsc_establish_context, hlib, "SCardEstablishContext"); |
load_one_fnc (pcsc_establish_context, hlib, "SCardEstablishContext"); |
72 |
load_one_fnc (pcsc_release_context, hlib, "SCardReleaseContext"); |
load_one_fnc (pcsc_release_context, hlib, "SCardReleaseContext"); |
|
load_one_fnc (pcsc_list_readers, hlib, "SCardListReadersA"); |
|
|
load_one_fnc (pcsc_connect, hlib, "SCardConnectA"); |
|
|
load_one_fnc (pcsc_disconnect, hlib, "SCardDisconnect"); |
|
|
load_one_fnc (pcsc_status, hlib, "SCardStatusA"); |
|
|
load_one_fnc (pcsc_get_status_change, hlib, "SCardGetStatusChangeA"); |
|
73 |
goto success; |
goto success; |
74 |
|
|
75 |
fail: |
fail: |
76 |
FreeLibrary (hlib); |
if (hlib != NULL) |
77 |
|
FreeLibrary (hlib); |
78 |
return -1; |
return -1; |
79 |
|
|
80 |
success: |
success: |
81 |
pcsc_init = 1; |
pcsc_init = 1; |
|
FreeLibrary (hlib); |
|
82 |
return 0; |
return 0; |
83 |
} |
} |
84 |
|
|
85 |
|
|
86 |
void |
/* Return != 0 if the PC/SC smart card interface is available. |
87 |
pcsc_free_readers (pcsc_reader_t rd) |
The purpose of the function is to disable smart card releation |
88 |
{ |
commands on systems with no scard readers. */ |
|
int i; |
|
|
|
|
|
if (!rd) |
|
|
return; |
|
|
|
|
|
for (i=0; i < rd->nreaders; i++) |
|
|
safe_free (rd->readers[i]); |
|
|
safe_free (rd); |
|
|
} |
|
|
|
|
|
|
|
|
const char * |
|
|
pcsc_get_reader (pcsc_reader_t rd, int idx, int * ret_nrd) |
|
|
{ |
|
|
if (!rd) |
|
|
return NULL; |
|
|
if (idx == -1 && ret_nrd) { |
|
|
*ret_nrd = rd->nreaders; |
|
|
return NULL; |
|
|
} |
|
|
if (idx >= rd->nreaders) |
|
|
idx=0; |
|
|
return rd->readers[idx]; |
|
|
} |
|
|
|
|
|
|
|
89 |
int |
int |
90 |
pcsc_scan_readers (pcsc_reader_t * ret_rd) |
pcsc_available (void) |
91 |
{ |
{ |
92 |
pcsc_reader_t rd; |
SCARDCONTEXT ctx; |
93 |
pcsc_context_t hctx; |
LONG err; |
|
struct pcsc_readerstate_s rdstat; |
|
|
DWORD readers; |
|
|
LPSTR rdrstr; |
|
|
char * p; |
|
|
int i; |
|
|
int rc, curr_rd=0; |
|
|
|
|
|
*ret_rd = NULL; |
|
|
if (!pcsc_init) |
|
|
return -1; |
|
|
|
|
|
rc = pcsc_establish_context (PCSC_SCOPE_SYSTEM, NULL, NULL, &hctx); |
|
|
if (rc) |
|
|
return -1; |
|
94 |
|
|
95 |
rc = pcsc_list_readers (hctx, NULL, NULL, &readers); |
if (pcsc_loadlib ()) |
|
if (rc) |
|
|
return -1; |
|
|
|
|
|
rdrstr = malloc (sizeof(char)*readers); |
|
|
if (!rdrstr) |
|
|
BUG (0); |
|
|
|
|
|
rc = pcsc_list_readers (hctx, NULL, rdrstr, &readers); |
|
|
if (rc) { |
|
|
safe_free (rdrstr); |
|
|
return -1; |
|
|
} |
|
|
|
|
|
rd = calloc (1, sizeof *rd); |
|
|
if (!rd) |
|
|
BUG (0); |
|
|
|
|
|
p = rdrstr; |
|
|
while ((*p != '\0') && (rd->nreaders < MAX_READERS)) { |
|
|
rd->readers[rd->nreaders] = strdup (p); |
|
|
p += strlen (p)+1; |
|
|
rd->nreaders++; |
|
|
} |
|
|
|
|
|
if (!rd->nreaders) { |
|
|
safe_free (rdrstr); |
|
|
safe_free (rd); |
|
96 |
return 0; |
return 0; |
|
} |
|
|
|
|
|
/* set the initial states */ |
|
|
for (i=0; i<rd->nreaders; i++) { |
|
|
rd->reader_states[i].reader = rd->readers[i]; |
|
|
rd->reader_states[i].current_state = PCSC_STATE_EMPTY; |
|
|
} |
|
97 |
|
|
98 |
while (1) { |
err = pcsc_establish_context (SCARD_SCOPE_SYSTEM, NULL, NULL, &ctx); |
99 |
rdstat = rd->reader_states[curr_rd]; |
if (err == SCARD_S_SUCCESS) { |
100 |
rc = pcsc_get_status_change (hctx, 0, &rdstat, 1); |
pcsc_release_context (ctx); |
|
if (rc == PCSC_E_TIMEOUT) |
|
|
continue; |
|
|
if (rc) |
|
|
; /* FIXME: What is this?? */ |
|
|
|
|
|
/* next reader */ |
|
|
curr_rd++; |
|
|
if (curr_rd >= rd->nreaders) |
|
|
curr_rd = 0; |
|
|
} |
|
|
|
|
|
safe_free (rdrstr); |
|
|
*ret_rd = rd; |
|
|
rc = pcsc_release_context (hctx); |
|
|
if (rc) |
|
101 |
return -1; |
return -1; |
102 |
|
} |
103 |
return 0; |
return 0; |
104 |
} |
} |
|
|
|
|
|
|
|
int |
|
|
pcsc_get_card_status (void) |
|
|
{ |
|
|
pcsc_reader_t rd; |
|
|
struct pcsc_readerstate_s rdstat; |
|
|
int rc, stat=0; |
|
|
|
|
|
rc = pcsc_scan_readers (&rd); |
|
|
if (rc) |
|
|
return -1; |
|
|
rdstat = rd->reader_states[0]; |
|
|
if (rdstat.current_state & PCSC_STATE_UNAVAILABLE) |
|
|
stat |= CARD_STATE_UNAVAIL; |
|
|
if (rdstat.current_state & PCSC_STATE_EMPTY) |
|
|
stat |= CARD_STATE_EMPTY; |
|
|
if (rdstat.current_state & PCSC_STATE_INUSE) |
|
|
stat |= CARD_STATE_INUSE; |
|
|
if (rdstat.current_state & PCSC_STATE_EXCLUSIVE) |
|
|
stat |= CARD_STATE_EXCLUSI; |
|
|
return stat; |
|
|
} |
|
|
#endif |
|