1 |
/* wptCardPCSC.cpp - PC/SC card API interface |
/* wptCardPCSC.cpp - PC/SC card API interface |
2 |
* Copyright (C) 2003 Timo Schulz |
* Copyright (C) 2003 Timo Schulz |
3 |
* |
* Copyright (C) 2003, 2004 Free Software Foundation, Inc. |
4 |
* This file is part of WinPT. |
* |
5 |
* |
* This file is part of WinPT. |
6 |
* WinPT is free software; you can redistribute it and/or modify |
* |
7 |
* it under the terms of the GNU General Public License as published by |
* WinPT is free software; you can redistribute it and/or modify |
8 |
* the Free Software Foundation; either version 2 of the License, or |
* it under the terms of the GNU General Public License as published by |
9 |
* (at your option) any later version. |
* the Free Software Foundation; either version 2 of the License, or |
10 |
* |
* (at your option) any later version. |
11 |
* WinPT is distributed in the hope that it will be useful, |
* |
12 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* WinPT is distributed in the hope that it will be useful, |
13 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
* GNU General Public License for more details. |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
* |
* GNU General Public License for more details. |
16 |
* You should have received a copy of the GNU General Public License |
* |
17 |
* along with WinPT; if not, write to the Free Software Foundation, |
* You should have received a copy of the GNU General Public License |
18 |
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
* along with WinPT; if not, write to the Free Software Foundation, |
19 |
*/ |
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
20 |
|
*/ |
21 |
#include <stdio.h> |
|
22 |
#include <windows.h> |
#ifdef HAVE_CONFIG_H |
23 |
#include <winscard.h> |
#include <config.h> |
24 |
|
#endif |
25 |
#include "w32gpgme.h" |
|
26 |
#include "wptTypes.h" |
#include <stdio.h> |
27 |
#include "wptCard.h" |
#include <stdio.h> |
28 |
|
#include <windows.h> |
29 |
|
|
30 |
#define MAX_READERS 8 |
#include "gpgme.h" |
31 |
|
#include "wptTypes.h" |
32 |
struct pcsc_reader_s { |
#include "wptCard.h" |
33 |
SCARD_READERSTATE_A reader_states[MAX_READERS]; |
|
34 |
int nreaders; |
|
35 |
char * readers[MAX_READERS]; |
/* Definitions usually found in winscard.h but not used here becuase |
36 |
}; |
mingw does not come with winscard and we dlopen the stuff |
37 |
typedef struct pcsc_reader_s *pcsc_reader_t; |
anyway. */ |
38 |
|
typedef unsigned long pcsc_context_t; |
39 |
|
|
40 |
static LONG (WINAPI *pcsc_establish_context) (unsigned long scope, |
struct pcsc_readerstate_s |
41 |
const void *reserved1, |
{ |
42 |
const void *reserved2, |
const char *reader; |
43 |
unsigned long *r_context); |
void *user_data; |
44 |
static LONG (WINAPI *pcsc_release_context) (unsigned long context); |
unsigned long current_state; |
45 |
static LONG (WINAPI *pcsc_list_readers) (unsigned long context, |
unsigned long event_state; |
46 |
const char *groups, |
unsigned long atrlen; |
47 |
char *readers, |
unsigned char atr[33]; |
48 |
unsigned long *readerslen); |
}; |
49 |
static LONG (WINAPI *pcsc_connect) (unsigned long context, |
|
50 |
const char *reader, |
typedef struct pcsc_readerstate_s *pcsc_readerstate_t; |
51 |
unsigned long share_mode, |
|
52 |
unsigned long preferred_protocols, |
/* PC/SC constants and function pointer. */ |
53 |
unsigned long *r_card, |
#define PCSC_SCOPE_USER 0 |
54 |
unsigned long *r_active_protocol); |
#define PCSC_SCOPE_TERMINAL 1 |
55 |
static LONG (WINAPI *pcsc_disconnect) (unsigned long card, |
#define PCSC_SCOPE_SYSTEM 2 |
56 |
unsigned long disposition); |
#define PCSC_SCOPE_GLOBAL 3 |
57 |
static LONG (WINAPI *pcsc_status) (unsigned long card, |
|
58 |
char *reader, unsigned long *readerlen, |
#define PCSC_PROTOCOL_T0 1 |
59 |
unsigned long *r_state, unsigned long *r_protocol, |
#define PCSC_PROTOCOL_T1 2 |
60 |
unsigned char *atr, unsigned long *atrlen); |
#define PCSC_PROTOCOL_RAW 4 |
61 |
static LONG (WINAPI *pcsc_get_status_change)(unsigned long ctx, |
|
62 |
unsigned long timeout, |
#define PCSC_SHARE_EXCLUSIVE 1 |
63 |
SCARD_READERSTATE * readerstate, |
#define PCSC_SHARE_SHARED 2 |
64 |
unsigned long creaders); |
#define PCSC_SHARE_DIRECT 3 |
65 |
|
|
66 |
static int pcsc_init = 0; |
#define PCSC_LEAVE_CARD 0 |
67 |
|
#define PCSC_RESET_CARD 1 |
68 |
|
#define PCSC_UNPOWER_CARD 2 |
69 |
#define load_one_fnc(ptr, hlib, name) do { \ |
#define PCSC_EJECT_CARD 3 |
70 |
a = ptr = (void *)GetProcAddress (hlib, name); \ |
|
71 |
if (!a) { \ |
#define PCSC_UNKNOWN 0x0001 |
72 |
char msg[256]; \ |
#define PCSC_ABSENT 0x0002 /* Card is absent. */ |
73 |
_snprintf (msg, sizeof msg-1, "Could not load '%s'", name); \ |
#define PCSC_PRESENT 0x0004 /* Card is present. */ |
74 |
MessageBox (NULL, msg, "PC/SC Driver", MB_ICONERROR|MB_OK); \ |
#define PCSC_SWALLOWED 0x0008 /* Card is present and electrical connected. */ |
75 |
goto fail; \ |
#define PCSC_POWERED 0x0010 /* Card is powered. */ |
76 |
} \ |
#define PCSC_NEGOTIABLE 0x0020 /* Card is awaiting PTS. */ |
77 |
} while (0) |
#define PCSC_SPECIFIC 0x0040 /* Card is ready for use. */ |
78 |
|
|
79 |
|
#define PCSC_STATE_UNAWARE 0x0000 /* Want status. */ |
80 |
int |
#define PCSC_STATE_IGNORE 0x0001 /* Ignore this reader. */ |
81 |
pcsc_loadlib (int scard_support) |
#define PCSC_STATE_CHANGED 0x0002 /* State has changed. */ |
82 |
{ |
#define PCSC_STATE_UNKNOWN 0x0004 /* Reader unknown. */ |
83 |
HMODULE hlib; |
#define PCSC_STATE_UNAVAILABLE 0x0008 /* Status unavailable. */ |
84 |
FARPROC a; |
#define PCSC_STATE_EMPTY 0x0010 /* Card removed. */ |
85 |
|
#define PCSC_STATE_PRESENT 0x0020 /* Card inserted. */ |
86 |
if (!scard_support || pcsc_init) |
#define PCSC_STATE_ATRMATCH 0x0040 /* ATR matches card. */ |
87 |
return 0; |
#define PCSC_STATE_EXCLUSIVE 0x0080 /* Exclusive Mode. */ |
88 |
hlib = LoadLibrary ("WINSCARD"); |
#define PCSC_STATE_INUSE 0x0100 /* Shared mode. */ |
89 |
if (!hlib) |
#define PCSC_STATE_MUTE 0x0200 /* Unresponsive card. */ |
90 |
goto fail; |
|
91 |
load_one_fnc (pcsc_establish_context, hlib, "SCardEstablishContext"); |
/* Some PC/SC error codes. */ |
92 |
load_one_fnc (pcsc_release_context, hlib, "SCardReleaseContext"); |
#define PCSC_E_CANCELLED 0x80100002 |
93 |
load_one_fnc (pcsc_list_readers, hlib, "SCardListReadersA"); |
#define PCSC_E_CANT_DISPOSE 0x8010000E |
94 |
load_one_fnc (pcsc_connect, hlib, "SCardConnectA"); |
#define PCSC_E_INSUFFICIENT_BUFFER 0x80100008 |
95 |
load_one_fnc (pcsc_disconnect, hlib, "SCardDisconnect"); |
#define PCSC_E_INVALID_ATR 0x80100015 |
96 |
load_one_fnc (pcsc_status, hlib, "SCardStatusA"); |
#define PCSC_E_INVALID_HANDLE 0x80100003 |
97 |
load_one_fnc (pcsc_get_status_change, hlib, "SCardGetStatusChangeA"); |
#define PCSC_E_INVALID_PARAMETER 0x80100004 |
98 |
goto success; |
#define PCSC_E_INVALID_TARGET 0x80100005 |
99 |
|
#define PCSC_E_INVALID_VALUE 0x80100011 |
100 |
fail: |
#define PCSC_E_NO_MEMORY 0x80100006 |
101 |
FreeLibrary (hlib); |
#define PCSC_E_UNKNOWN_READER 0x80100009 |
102 |
return -1; |
#define PCSC_E_TIMEOUT 0x8010000A |
103 |
success: |
#define PCSC_E_SHARING_VIOLATION 0x8010000B |
104 |
pcsc_init = 1; |
#define PCSC_E_NO_SMARTCARD 0x8010000C |
105 |
FreeLibrary (hlib); |
#define PCSC_E_UNKNOWN_CARD 0x8010000D |
106 |
return 0; |
#define PCSC_E_PROTO_MISMATCH 0x8010000F |
107 |
} |
#define PCSC_E_NOT_READY 0x80100010 |
108 |
|
#define PCSC_E_SYSTEM_CANCELLED 0x80100012 |
109 |
|
#define PCSC_E_NOT_TRANSACTED 0x80100016 |
110 |
void |
#define PCSC_E_READER_UNAVAILABLE 0x80100017 |
111 |
pcsc_free_readers (pcsc_reader_t rd) |
#define PCSC_W_REMOVED_CARD 0x80100069 |
112 |
{ |
|
113 |
int i; |
/* Possible card states. */ |
114 |
|
enum card_state_t { |
115 |
if (!rd) |
CARD_STATE_NONE=0, |
116 |
return; |
CARD_STATE_UNAWARE, |
117 |
|
CARD_STATE_UNAVAIL, |
118 |
for (i=0; i < rd->nreaders; i++) |
CARD_STATE_PRESENT, |
119 |
safe_free (rd->readers[i]); |
CARD_STATE_EXCLUSI, |
120 |
safe_free (rd); |
CARD_STATE_EMPTY, |
121 |
} |
CARD_STATE_INUSE, |
122 |
|
CARD_STATE_MUTE |
123 |
|
}; |
124 |
const char * |
|
125 |
pcsc_get_reader (pcsc_reader_t rd, int idx, int * ret_nrd) |
#define MAX_READERS 8 |
126 |
{ |
|
127 |
if (!rd) |
struct pcsc_reader_s { |
128 |
return NULL; |
struct pcsc_readerstate_s reader_states[MAX_READERS]; |
129 |
if (idx == -1 && ret_nrd) { |
int nreaders; |
130 |
*ret_nrd = rd->nreaders; |
char * readers[MAX_READERS]; |
131 |
return NULL; |
}; |
132 |
} |
typedef struct pcsc_reader_s *pcsc_reader_t; |
133 |
if (idx >= rd->nreaders) |
|
134 |
idx=0; |
|
135 |
return rd->readers[idx]; |
static LONG (WINAPI *pcsc_establish_context) (unsigned long scope, |
136 |
} |
const void *reserved1, |
137 |
|
const void *reserved2, |
138 |
|
unsigned long *r_context); |
139 |
int |
static LONG (WINAPI *pcsc_release_context) (unsigned long context); |
140 |
pcsc_scan_readers (pcsc_reader_t * ret_rd) |
static LONG (WINAPI *pcsc_list_readers) (unsigned long context, |
141 |
{ |
const char *groups, |
142 |
pcsc_reader_t rd; |
char *readers, |
143 |
SCARDCONTEXT hctx; |
unsigned long *readerslen); |
144 |
SCARD_READERSTATE_A rdstat; |
static LONG (WINAPI *pcsc_connect) (unsigned long context, |
145 |
DWORD readers; |
const char *reader, |
146 |
LPSTR rdrstr; |
unsigned long share_mode, |
147 |
char * p; |
unsigned long preferred_protocols, |
148 |
int i; |
unsigned long *r_card, |
149 |
int rc, curr_rd=0; |
unsigned long *r_active_protocol); |
150 |
|
static LONG (WINAPI *pcsc_disconnect) (unsigned long card, |
151 |
*ret_rd = NULL; |
unsigned long disposition); |
152 |
if (!pcsc_init) |
static LONG (WINAPI *pcsc_status) (unsigned long card, |
153 |
return -1; |
char *reader, unsigned long *readerlen, |
154 |
|
unsigned long *r_state, unsigned long *r_protocol, |
155 |
rc = pcsc_establish_context (SCARD_SCOPE_SYSTEM, NULL, NULL, &hctx); |
unsigned char *atr, unsigned long *atrlen); |
156 |
if (rc != SCARD_S_SUCCESS) |
static LONG (WINAPI *pcsc_get_status_change)(unsigned long ctx, |
157 |
return -1; |
unsigned long timeout, |
158 |
|
pcsc_readerstate_t readerstate, |
159 |
rc = pcsc_list_readers (hctx, NULL, NULL, &readers); |
unsigned long creaders); |
160 |
if (rc != SCARD_S_SUCCESS) |
|
161 |
return -1; |
static int pcsc_init = 0; |
162 |
|
|
163 |
rdrstr = malloc (sizeof(char)*readers); |
|
164 |
if (!rdrstr) |
#define load_one_fnc(ptr, hlib, name) do { \ |
165 |
BUG (0); |
a = ptr = (void *)GetProcAddress (hlib, name); \ |
166 |
|
if (!a) { \ |
167 |
rc = pcsc_list_readers (hctx, NULL, rdrstr, &readers); |
char msg[256]; \ |
168 |
if (rc != SCARD_S_SUCCESS) { |
_snprintf (msg, sizeof msg-1, "Could not load '%s'", name); \ |
169 |
safe_free (rdrstr); |
MessageBox (NULL, msg, "PC/SC Driver", MB_ICONERROR|MB_OK); \ |
170 |
return -1; |
goto fail; \ |
171 |
} |
} \ |
172 |
|
} while (0) |
173 |
rd = calloc (1, sizeof *rd); |
|
174 |
if (!rd) |
|
175 |
BUG (0); |
int |
176 |
|
pcsc_loadlib (int scard_support) |
177 |
p = rdrstr; |
{ |
178 |
while ((*p != '\0') && (rd->nreaders < MAX_READERS)) { |
HMODULE hlib; |
179 |
rd->readers[rd->nreaders] = strdup (p); |
FARPROC a; |
180 |
p += strlen (p)+1; |
|
181 |
rd->nreaders++; |
if (!scard_support || pcsc_init) |
182 |
} |
return 0; |
183 |
|
hlib = LoadLibrary ("WINSCARD"); |
184 |
if (!rd->nreaders) { |
if (!hlib) |
185 |
safe_free (rdrstr); |
goto fail; |
186 |
safe_free (rd); |
load_one_fnc (pcsc_establish_context, hlib, "SCardEstablishContext"); |
187 |
return 0; |
load_one_fnc (pcsc_release_context, hlib, "SCardReleaseContext"); |
188 |
} |
load_one_fnc (pcsc_list_readers, hlib, "SCardListReadersA"); |
189 |
|
load_one_fnc (pcsc_connect, hlib, "SCardConnectA"); |
190 |
/* set the initial states */ |
load_one_fnc (pcsc_disconnect, hlib, "SCardDisconnect"); |
191 |
for (i=0; i<rd->nreaders; i++) { |
load_one_fnc (pcsc_status, hlib, "SCardStatusA"); |
192 |
rd->reader_states[i].szReader = rd->readers[i]; |
load_one_fnc (pcsc_get_status_change, hlib, "SCardGetStatusChangeA"); |
193 |
rd->reader_states[i].dwCurrentState = SCARD_STATE_EMPTY; |
goto success; |
194 |
} |
|
195 |
|
fail: |
196 |
while (1) { |
FreeLibrary (hlib); |
197 |
rdstat = rd->reader_states[curr_rd]; |
return -1; |
198 |
rc = pcsc_get_status_change (hctx, 0, &rdstat, 1); |
success: |
199 |
if (rc == SCARD_E_TIMEOUT) |
pcsc_init = 1; |
200 |
continue; |
FreeLibrary (hlib); |
201 |
if (rc != SCARD_S_SUCCESS) |
return 0; |
202 |
; |
} |
203 |
|
|
204 |
/* next reader */ |
|
205 |
curr_rd++; |
void |
206 |
if (curr_rd >= rd->nreaders) |
pcsc_free_readers (pcsc_reader_t rd) |
207 |
curr_rd = 0; |
{ |
208 |
} |
int i; |
209 |
|
|
210 |
safe_free (rdrstr); |
if (!rd) |
211 |
*ret_rd = rd; |
return; |
212 |
rc = pcsc_release_context (hctx); |
|
213 |
if (rc != SCARD_S_SUCCESS) |
for (i=0; i < rd->nreaders; i++) |
214 |
return -1; |
safe_free (rd->readers[i]); |
215 |
return 0; |
safe_free (rd); |
216 |
} |
} |
217 |
|
|
218 |
|
|
219 |
int |
const char * |
220 |
pcsc_get_card_status (void) |
pcsc_get_reader (pcsc_reader_t rd, int idx, int * ret_nrd) |
221 |
{ |
{ |
222 |
pcsc_reader_t rd; |
if (!rd) |
223 |
SCARD_READERSTATE_A rdstat; |
return NULL; |
224 |
int rc, stat=0; |
if (idx == -1 && ret_nrd) { |
225 |
|
*ret_nrd = rd->nreaders; |
226 |
rc = pcsc_scan_readers (&rd); |
return NULL; |
227 |
if (rc) |
} |
228 |
return -1; |
if (idx >= rd->nreaders) |
229 |
rdstat = rd->reader_states[0]; |
idx=0; |
230 |
if (rdstat.dwCurrentState & SCARD_STATE_UNAVAILABLE) |
return rd->readers[idx]; |
231 |
stat |= CARD_STATE_UNAVAIL; |
} |
232 |
if (rdstat.dwCurrentState & SCARD_STATE_EMPTY) |
|
233 |
stat |= CARD_STATE_EMPTY; |
|
234 |
if (rdstat.dwCurrentState & SCARD_STATE_INUSE) |
int |
235 |
stat |= CARD_STATE_INUSE; |
pcsc_scan_readers (pcsc_reader_t * ret_rd) |
236 |
if (rdstat.dwCurrentState & SCARD_STATE_EXCLUSIVE) |
{ |
237 |
stat |= CARD_STATE_EXCLUSI; |
pcsc_reader_t rd; |
238 |
return stat; |
pcsc_context_t hctx; |
239 |
} |
struct pcsc_readerstate_s rdstat; |
240 |
|
DWORD readers; |
241 |
|
LPSTR rdrstr; |
242 |
|
char * p; |
243 |
|
int i; |
244 |
|
int rc, curr_rd=0; |
245 |
|
|
246 |
|
*ret_rd = NULL; |
247 |
|
if (!pcsc_init) |
248 |
|
return -1; |
249 |
|
|
250 |
|
rc = pcsc_establish_context (PCSC_SCOPE_SYSTEM, NULL, NULL, &hctx); |
251 |
|
if (rc) |
252 |
|
return -1; |
253 |
|
|
254 |
|
rc = pcsc_list_readers (hctx, NULL, NULL, &readers); |
255 |
|
if (rc) |
256 |
|
return -1; |
257 |
|
|
258 |
|
rdrstr = malloc (sizeof(char)*readers); |
259 |
|
if (!rdrstr) |
260 |
|
BUG (0); |
261 |
|
|
262 |
|
rc = pcsc_list_readers (hctx, NULL, rdrstr, &readers); |
263 |
|
if (rc) { |
264 |
|
safe_free (rdrstr); |
265 |
|
return -1; |
266 |
|
} |
267 |
|
|
268 |
|
rd = calloc (1, sizeof *rd); |
269 |
|
if (!rd) |
270 |
|
BUG (0); |
271 |
|
|
272 |
|
p = rdrstr; |
273 |
|
while ((*p != '\0') && (rd->nreaders < MAX_READERS)) { |
274 |
|
rd->readers[rd->nreaders] = strdup (p); |
275 |
|
p += strlen (p)+1; |
276 |
|
rd->nreaders++; |
277 |
|
} |
278 |
|
|
279 |
|
if (!rd->nreaders) { |
280 |
|
safe_free (rdrstr); |
281 |
|
safe_free (rd); |
282 |
|
return 0; |
283 |
|
} |
284 |
|
|
285 |
|
/* set the initial states */ |
286 |
|
for (i=0; i<rd->nreaders; i++) { |
287 |
|
rd->reader_states[i].reader = rd->readers[i]; |
288 |
|
rd->reader_states[i].current_state = PCSC_STATE_EMPTY; |
289 |
|
} |
290 |
|
|
291 |
|
while (1) { |
292 |
|
rdstat = rd->reader_states[curr_rd]; |
293 |
|
rc = pcsc_get_status_change (hctx, 0, &rdstat, 1); |
294 |
|
if (rc == PCSC_E_TIMEOUT) |
295 |
|
continue; |
296 |
|
if (rc) |
297 |
|
; /* FIXME: What is this?? */ |
298 |
|
|
299 |
|
/* next reader */ |
300 |
|
curr_rd++; |
301 |
|
if (curr_rd >= rd->nreaders) |
302 |
|
curr_rd = 0; |
303 |
|
} |
304 |
|
|
305 |
|
safe_free (rdrstr); |
306 |
|
*ret_rd = rd; |
307 |
|
rc = pcsc_release_context (hctx); |
308 |
|
if (rc) |
309 |
|
return -1; |
310 |
|
return 0; |
311 |
|
} |
312 |
|
|
313 |
|
|
314 |
|
int |
315 |
|
pcsc_get_card_status (void) |
316 |
|
{ |
317 |
|
pcsc_reader_t rd; |
318 |
|
struct pcsc_readerstate_s rdstat; |
319 |
|
int rc, stat=0; |
320 |
|
|
321 |
|
rc = pcsc_scan_readers (&rd); |
322 |
|
if (rc) |
323 |
|
return -1; |
324 |
|
rdstat = rd->reader_states[0]; |
325 |
|
if (rdstat.current_state & PCSC_STATE_UNAVAILABLE) |
326 |
|
stat |= CARD_STATE_UNAVAIL; |
327 |
|
if (rdstat.current_state & PCSC_STATE_EMPTY) |
328 |
|
stat |= CARD_STATE_EMPTY; |
329 |
|
if (rdstat.current_state & PCSC_STATE_INUSE) |
330 |
|
stat |= CARD_STATE_INUSE; |
331 |
|
if (rdstat.current_state & PCSC_STATE_EXCLUSIVE) |
332 |
|
stat |= CARD_STATE_EXCLUSI; |
333 |
|
return stat; |
334 |
|
} |