1 /* $Id: sectok.c,v 1.6 2003/06/19 22:51:06 rees Exp $ */
2
3 /*
4 copyright 2000
5 the regents of the university of michigan
6 all rights reserved
7
8 permission is granted to use, copy, create derivative works
9 and redistribute this software and such derivative works
10 for any purpose, so long as the name of the university of
11 michigan is not used in any advertising or publicity
12 pertaining to the use or distribution of this software
13 without specific, written prior authorization. if the
14 above copyright notice or any other identification of the
15 university of michigan is included in any copy of any
16 portion of this software, then the disclaimer below must
17 also be included.
18
19 this software is provided as is, without representation
20 from the university of michigan as to its fitness for any
21 purpose, and without warranty by the university of
22 michigan of any kind, either express or implied, including
23 without limitation the implied warranties of
24 merchantability and fitness for a particular purpose. the
25 regents of the university of michigan shall not be liable
26 for any damages, including special, indirect, incidental, or
27 consequential damages, with respect to any claim arising
28 out of or in connection with the use of the software, even
29 if it has been or is hereafter advised of the possibility of
30 such damages.
31 */
32
33 /*
34 * common card routines
35 *
36 * Jim Rees
37 * University of Michigan CITI, July 2001
38 */
39
40 #ifdef __palmos__
41 #include <Common.h>
42 #include <System/SysAll.h>
43 #include <System/Unix/sys_types.h>
44 #include <System/Unix/unix_stdlib.h>
45 #include <System/Unix/unix_string.h>
46 #include <UI/UIAll.h>
47 #include "field.h"
48 #undef open
49 #else
50 #include <sys/types.h>
51 #include <sys/time.h>
52 #include <stdlib.h>
53 #include <unistd.h>
54 #include <stdio.h>
55 #include <string.h>
56 #include <dlfcn.h>
57 #include <errno.h>
58 #endif
59
60 #include "sectok.h"
61 #include "ifdhandler.h"
62 #include "ifdwrapper.h"
63
64 #define MAX_READERS 32
65 #define N_DEFAULT_READERS 4
66
67 #define myisprint(x) ((x) >= '!' && (x) <= 'z')
68
69 #ifdef DL_READERS
70 static char defaultConfigFilePath[] = "/etc/reader.conf";
71 static char defaultDriverPath[] = "/usr/local/pcsc/lib/libtodos_ag.so";
72
73 int DBUpdateReaders(char *readerconf, int (callback) (int rn, unsigned long channelId,
74 unsigned long lun, char *driverFile));
75
76 /* the callback for DBUpdateReaders */
77 static int addReader(int rn, unsigned long channelID, unsigned long lun, char *driverFile);
78 static void *lookupSym(void *handle, char *name);
79 #else
80 static int sillyports[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8};
81 #endif
82
83 static int openReader(int readerNum, int flags);
84
85
86 unsigned int numReaders;
87 readerInfo readers[MAX_READERS];
88
89 unsigned char root_fid[] = {0x3f, 0x00};
90
91 /*
92 if (config_path != NULL and driver_name != NULL) error;
93 if (config_path != NULL) use reader.conf there;
94 if (driver_path != NULL) use the specified driver;
95 if (config_path == NULL and driver_path == NULL) use /etc/reader.conf;
96
97 Note that the config file is read only once, and drivers are only loaded once,
98 so config_path and driver_path are ignored on subsequent calls.
99 */
100
101 int
sectok_xopen(int rn,int flags,char * config_path,char * driver_path,int * swp)102 sectok_xopen(int rn, int flags, char *config_path, char *driver_path, int *swp)
103 {
104 int r = 0;
105
106 #ifdef SCPERF
107 SetTime ("scopen() start");
108 #endif /* SCPERF */
109
110 if (rn < 0 || rn >= MAX_READERS) {
111 r = STENOTTY;
112 goto out;
113 }
114
115 #ifdef DL_READERS
116 if (driver_path) {
117 /* caller specified a particular driver path to use */
118 if (config_path) {
119 /* but also specified a config file, which is an error. */
120 r = STECNFFILES;
121 goto out;
122 }
123 if (!readers[rn].driverPath) {
124 /* need a driver */
125 if (addReader(rn, (0x10000 + rn), 0, driver_path) < 0) {
126 r = STEDRVR;
127 goto out;
128 }
129 }
130 }
131
132 if (numReaders == 0) {
133 /* no drivers; read the config file */
134 if (!config_path)
135 config_path = defaultConfigFilePath;
136 if (DBUpdateReaders(config_path, addReader) < 0) {
137 int i;
138
139 if (config_path != defaultConfigFilePath) {
140 /* Something wrong with caller's config file path. */
141 r = STEDRVR;
142 goto out;
143 }
144 /* This usually means there is no reader.conf. Supply defaults. */
145 for (i = 0; i < N_DEFAULT_READERS; i++)
146 addReader(i, (0x10000 | i), 0, defaultDriverPath);
147 }
148 }
149 #else
150 numReaders = N_DEFAULT_READERS;
151 #endif
152
153 r = openReader(rn, flags);
154
155 #ifdef __palmos__
156 if (sectok_swOK(r) && !sectok_cardpresent(rn))
157 r = STENOCARD;
158 #else
159 if (sectok_swOK(r) && !(flags & STONOWAIT)) {
160 /* Wait for card present */
161 while (!sectok_cardpresent(rn)) {
162 errno = 0;
163 sleep(1);
164 if (errno == EINTR) {
165 r = STENOCARD;
166 break;
167 }
168 }
169 }
170 #endif
171
172 out:
173 #ifdef SCPERF
174 SetTime ("scopen() end");
175 #endif /* SCPERF */
176
177 if (swp)
178 *swp = r;
179 return (!sectok_swOK(r) ? -1 : rn);
180 }
181
sectok_open(int rn,int flags,int * swp)182 int sectok_open(int rn, int flags, int *swp)
183 {
184 return sectok_xopen(rn, flags, NULL, NULL, swp);
185 }
186
sectok_friendly_open(const char * rn,int flags,int * swp)187 int sectok_friendly_open(const char *rn, int flags, int *swp)
188 {
189 /* just convert the reader to a integer for now */
190 if (rn != NULL) {
191 return sectok_xopen(atoi(rn), flags, NULL, NULL, swp);
192 } else {
193 return -1;
194 }
195 }
196
197 static int
openReader(int readerNum,int flags)198 openReader(int readerNum, int flags)
199 {
200 readerInfo *reader;
201 void *p1, *p2;
202
203 #ifdef DEBUG
204 printf("openReader %d\n", readerNum);
205 #endif
206
207 if (readerNum < 0 || readerNum >= MAX_READERS)
208 return STEDRVR;
209 reader = &readers[readerNum];
210
211 if (!reader->driverLoaded) {
212 #ifdef DL_READERS
213 void *libHandle;
214
215 if (!reader->driverPath)
216 return STEDRVR;
217 libHandle = dlopen(reader->driverPath, RTLD_LAZY);
218 if (!libHandle) {
219 #ifdef DEBUG
220 printf("%s: %s\n", reader->driverPath, dlerror());
221 #endif
222 return STEDRVR;
223 }
224
225 p1 = lookupSym(libHandle, "IO_Create_Channel");
226 p2 = lookupSym(libHandle, "IFDHCreateChannel");
227
228 if (p1 == NULL && p2 == NULL)
229 return STEDRVR;
230
231 if (p1) {
232 reader->version = IFDH_VERSION_1_0;
233
234 reader->open = lookupSym(libHandle, "IO_Create_Channel");
235 if (reader->open == NULL)
236 return STEDRVR;
237
238 reader->close = lookupSym(libHandle, "IO_Close_Channel");
239 if (reader->close == NULL)
240 return STEDRVR;
241
242 reader->data = lookupSym(libHandle, "IFD_Transmit_to_ICC");
243 if (reader->data == NULL)
244 return STEDRVR;
245
246 reader->power = lookupSym(libHandle, "IFD_Power_ICC");
247 if (reader->power == NULL)
248 return STEDRVR;
249
250 reader->getcapa = lookupSym(libHandle, "IFD_Get_Capabilities");
251 if (reader->getcapa == NULL)
252 return STEDRVR;
253
254 reader->setcapa = lookupSym(libHandle, "IFD_Set_Capabilities");
255 if (reader->setcapa == NULL)
256 return STEDRVR;
257
258 reader->cardpresent = lookupSym(libHandle, "IFD_Is_ICC_Present");
259 } else {
260 reader->version = IFDH_VERSION_2_0;
261
262 reader->open = lookupSym(libHandle, "IFDHCreateChannel");
263 if (reader->open == NULL)
264 return STEDRVR;
265
266 reader->close = lookupSym(libHandle, "IFDHCloseChannel");
267 if (reader->close == NULL)
268 return STEDRVR;
269
270 reader->data = lookupSym(libHandle, "IFDHTransmitToICC");
271 if (reader->data == NULL)
272 return STEDRVR;
273
274 reader->power = lookupSym(libHandle, "IFDHPowerICC");
275 if (reader->power == NULL)
276 return STEDRVR;
277
278 reader->getcapa = lookupSym(libHandle, "IFDHGetCapabilities");
279 if (reader->getcapa == NULL)
280 return STEDRVR;
281
282 reader->setcapa = lookupSym(libHandle, "IFDHSetCapabilities");
283 if (reader->setcapa == NULL)
284 return STEDRVR;
285
286 reader->cardpresent = lookupSym(libHandle, "IFDHICCPresence");
287 }
288 #else /* DL_READERS */
289 reader->open = IO_Create_Channel;
290 reader->close = IO_Close_Channel;
291 reader->data = IFD_Transmit_to_ICC;
292 reader->power = IFD_Power_ICC;
293 reader->getcapa = IFD_Get_Capabilities;
294 reader->setcapa = IFD_Set_Capabilities;
295 reader->cardpresent = IFD_Is_ICC_Present;
296 reader->channelID = (0x10000 | (readerNum < 4 ? sillyports[readerNum] : readerNum));
297 #endif /* DL_READERS */
298
299 reader->driverLoaded = 1;
300 }
301
302 /* send flags to the driver */
303 flags ^= STONOWAIT;
304 IFDSetCapabilities(reader, SCTAG_OPEN_FLAGS, (unsigned long)sizeof(flags),
305 (unsigned char *)&flags);
306 /* if this returns an error, setcapa is not supported in this driver,
307 but that's OK. */
308
309 if (IFDOpenIFD(reader))
310 return STECOMM;
311 else
312 return STEOK;
313 }
314
315 int
sectok_close(int fd)316 sectok_close(int fd)
317 {
318 readerInfo *reader = &readers[fd];
319
320 if (fd < 0 || fd >= MAX_READERS)
321 return -1;
322
323 reader = &readers[fd];
324
325 if (!reader->driverLoaded)
326 return -1;
327
328 return (IFDCloseIFD(reader)) ? -1 : 0;
329 }
330
331 int
sectok_cardpresent(int fd)332 sectok_cardpresent(int fd)
333 {
334 readerInfo *reader = &readers[fd];
335 unsigned long v;
336
337 if (!reader->driverLoaded)
338 return 0;
339
340 v = IFDPresent(reader);
341 return (v == IFD_ICC_PRESENT || v == 0) ? 1 : 0;
342 }
343
344 int
sectok_reset(int fd,int flags,unsigned char * atr,int * swp)345 sectok_reset(int fd, int flags, unsigned char *atr, int *swp)
346 {
347 readerInfo *reader = &readers[fd];
348 int n = 0, r = STEOK;
349 unsigned long l;
350 #ifdef SCPERF
351 SetTime ("scxreset() start");
352 #endif /* SCPERF */
353
354 if (!reader->driverLoaded) {
355 r = STECLOSED;
356 goto out;
357 }
358
359 if (!sectok_cardpresent(fd)) {
360 r = STENOCARD;
361 goto out;
362 }
363
364 /* send flags to the driver */
365 IFDSetCapabilities(reader, SCTAG_RESET_FLAGS, (unsigned long)sizeof(flags),
366 (unsigned char *)&flags);
367 /* if this returns an error, setcapa is not supported in this driver,
368 but that's OK. */
369
370 if (IFDPowerICC(reader, IFD_RESET, atr, (unsigned long *)&l)) {
371 #ifdef DEBUG
372 printf("power failed!\n");
373 #endif
374 r = STESLAG;
375 goto out;
376 }
377
378 if (atr && IFDGetCapabilities(reader, TAG_IFD_ATR, (unsigned long *)&l,
379 atr)) {
380 #ifdef DEBUG
381 printf("reset failed!\n");
382 #endif
383 r = STESLAG;
384 goto out;
385 }
386
387 if (IFDGetCapabilities(reader, SCTAG_IFD_ATRLEN, (unsigned long *)&l,
388 (unsigned char*) &n) || n <= 0) {
389 /* can't get atr len, take a wild guess */
390 if (atr) {
391 for (n = MAX_ATR_SIZE - 1; !atr[n]; n--)
392 ;
393 n--;
394 } else
395 n = MAX_ATR_SIZE;
396 }
397
398 out:
399 if (swp)
400 *swp = r;
401
402 #ifdef SCPERF
403 SetTime ("scxreset() end");
404 #endif /* SCPERF */
405
406 return n;
407 }
408
409 #ifdef DL_READERS
410 static int
addReader(int rn,unsigned long channelID,unsigned long lun,char * driverFile)411 addReader(int rn, unsigned long channelID, unsigned long lun, char *driverFile)
412 {
413 readerInfo *reader;
414
415 if (rn < 0 || rn >= MAX_READERS)
416 return -1;
417
418 reader = &readers[rn];
419
420 if (reader->driverPath)
421 return -1;
422
423 reader->channelID = channelID;
424 reader->lun = lun;
425 reader->driverPath = strdup(driverFile);
426 reader->driverLoaded = 0;
427 numReaders++;
428 return 0;
429 }
430
431 static void *
lookupSym(void * handle,char * name)432 lookupSym(void *handle, char *name)
433 {
434 #ifdef __linux__
435 return dlsym(handle, name);
436 #elif __sun
437 return dlsym(handle, name);
438 #elif __elf__ /* post OPENBSD_3_3 */
439 return dlsym(handle, name);
440 #else
441 char undername[32];
442
443 sprintf(undername, "_%s", name);
444 return dlsym(handle, undername);
445 #endif
446 }
447 #endif /* DL_READERS */
448
449 int
sectok_apdu(int fd,int cla,int ins,int p1,int p2,int ilen,unsigned char * ibuf,int olen,unsigned char * obuf,int * swp)450 sectok_apdu(int fd, int cla, int ins, int p1, int p2,
451 int ilen, unsigned char *ibuf, int olen, unsigned char *obuf, int *swp)
452 {
453 unsigned char cmd[6+255], rsp[255+2];
454 unsigned long n;
455 int le;
456 readerInfo *reader = &readers[fd];
457 SCARD_IO_HEADER garbage;
458
459 if (reader->driverLoaded == 0) {
460 *swp = STECLOSED;
461 return -1;
462 }
463
464 cmd[0] = cla;
465 cmd[1] = ins;
466 cmd[2] = p1;
467 cmd[3] = p2;
468
469 ilen &= 0xff;
470 le = (255 < olen) ? 255 : olen;
471
472 if (ilen && ibuf) {
473 /* Send "in" data */
474 cmd[4] = ilen;
475 memcpy(&cmd[5], ibuf, ilen);
476 ilen += 5;
477 if (le)
478 cmd[ilen++] = le;
479 n = obuf ? sizeof rsp : 2;
480 if (IFDTransmit(reader, garbage, cmd, ilen, rsp, &n, NULL) || n < 2) {
481 *swp = STECOMM;
482 return -1;
483 }
484 if (rsp[n-2] == 0x61 && olen && obuf) {
485 /* Response available; get it (driver should do this but some don't) */
486 cmd[1] = 0xc0;
487 cmd[2] = cmd[3] = 0;
488 cmd[4] = rsp[n-1];
489 n = sizeof rsp;
490 if (IFDTransmit(reader, garbage, cmd, 5, rsp, &n, NULL)) {
491 *swp = STECOMM;
492 return -1;
493 }
494 }
495 } else {
496 /* Get "out" data */
497 cmd[4] = olen;
498 n = sizeof rsp;
499 if (IFDTransmit(reader, garbage, cmd, 5, rsp, &n, NULL)) {
500 *swp = STECOMM;
501 return -1;
502 }
503 }
504
505 if (n >= 2) {
506 *swp = sectok_mksw(rsp[n-2], rsp[n-1]);
507 n -= 2;
508 } else {
509 /* This shouldn't happen; apdu ok but no status available */
510 *swp = STEOK;
511 }
512
513 if (n && olen)
514 memcpy(obuf, rsp, (n < olen) ? n : olen);
515
516 return n;
517 }
518
519 void
sectok_fmt_fid(char * fname,unsigned char * fid)520 sectok_fmt_fid(char *fname, unsigned char *fid)
521 {
522 int f0 = fid[0], f1 = fid[1];
523
524 if (f0 == 0x3f && f1 == 0)
525 sprintf(fname, "/");
526 else if (myisprint(f0) && f1 == 0)
527 sprintf(fname, "%c", f0);
528 else if (myisprint(f0) && myisprint(f1))
529 sprintf(fname, "%c%c", f0, f1);
530 else
531 sprintf(fname, "%02x%02x", f0, f1);
532 }
533
534 int
sectok_selectfile(int fd,int cla,unsigned char * fid,int * swp)535 sectok_selectfile(int fd, int cla, unsigned char *fid, int *swp)
536 {
537 unsigned char obuf[256];
538
539 sectok_apdu(fd, cla, 0xa4, 0, 0, 2, fid, sizeof obuf, obuf, swp);
540 if (!sectok_swOK(*swp))
541 return -1;
542
543 return 0;
544 }
545