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