1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2019, Joyent, Inc. 14 */ 15 16 #include <stdlib.h> 17 #include <sys/types.h> 18 #include <sys/stat.h> 19 #include <fcntl.h> 20 #include <fts.h> 21 #include <errno.h> 22 #include <strings.h> 23 #include <unistd.h> 24 #include <sys/debug.h> 25 #include <sys/filio.h> 26 #include <sys/usb/clients/ccid/uccid.h> 27 28 #include <winscard.h> 29 30 /* 31 * Implementation of the PCSC library leveraging the uccid framework. 32 */ 33 34 /* 35 * The library handle is basically unused today. We keep this around such that 36 * consumers which expect to receive a non-NULL opaque handle have something 37 * they can use. 38 */ 39 typedef struct pcsc_hdl { 40 hrtime_t pcsc_create_time; 41 } pcsc_hdl_t; 42 43 typedef struct pcsc_card { 44 int pcc_fd; 45 } pcsc_card_t; 46 47 /* 48 * Required globals 49 */ 50 SCARD_IO_REQUEST g_rgSCardT0Pci = { 51 SCARD_PROTOCOL_T0, 52 0 53 }; 54 55 SCARD_IO_REQUEST g_rgSCardT1Pci = { 56 SCARD_PROTOCOL_T1, 57 0 58 }; 59 60 SCARD_IO_REQUEST g_rgSCardRawPci = { 61 SCARD_PROTOCOL_RAW, 62 0 63 }; 64 65 const char * 66 pcsc_stringify_error(const LONG err) 67 { 68 switch (err) { 69 case SCARD_S_SUCCESS: 70 return ("no error"); 71 case SCARD_F_INTERNAL_ERROR: 72 return ("internal error"); 73 case SCARD_E_CANCELLED: 74 return ("request cancelled"); 75 case SCARD_E_INVALID_HANDLE: 76 return ("invalid handle"); 77 case SCARD_E_INVALID_PARAMETER: 78 return ("invalid parameter"); 79 case SCARD_E_NO_MEMORY: 80 return ("no memory"); 81 case SCARD_E_INSUFFICIENT_BUFFER: 82 return ("buffer was insufficiently sized"); 83 case SCARD_E_INVALID_VALUE: 84 return ("invalid value passed"); 85 case SCARD_E_UNKNOWN_READER: 86 return ("unknown reader"); 87 case SCARD_E_TIMEOUT: 88 return ("timeout occurred"); 89 case SCARD_E_SHARING_VIOLATION: 90 return ("sharing violation"); 91 case SCARD_E_NO_SMARTCARD: 92 return ("no smartcard present"); 93 case SCARD_E_UNKNOWN_CARD: 94 return ("unknown ICC"); 95 case SCARD_E_PROTO_MISMATCH: 96 return ("protocol mismatch"); 97 case SCARD_F_COMM_ERROR: 98 return ("communication error"); 99 case SCARD_F_UNKNOWN_ERROR: 100 return ("unknown error"); 101 case SCARD_E_READER_UNAVAILABLE: 102 return ("reader unavailable"); 103 case SCARD_E_NO_SERVICE: 104 return ("service error"); 105 case SCARD_E_UNSUPPORTED_FEATURE: 106 return ("ICC requires unsupported feature"); 107 case SCARD_E_NO_READERS_AVAILABLE: 108 return ("no readers avaiable"); 109 case SCARD_W_UNSUPPORTED_CARD: 110 return ("ICC unsupported"); 111 case SCARD_W_UNPOWERED_CARD: 112 return ("ICC is not powered"); 113 case SCARD_W_RESET_CARD: 114 return ("ICC was reset"); 115 case SCARD_W_REMOVED_CARD: 116 return ("ICC has been removed"); 117 default: 118 return ("unknown error"); 119 } 120 } 121 122 123 /* 124 * This is called when a caller wishes to open a new Library context. 125 */ 126 LONG 127 SCardEstablishContext(DWORD scope, LPCVOID unused0, LPCVOID unused1, 128 LPSCARDCONTEXT outp) 129 { 130 pcsc_hdl_t *hdl; 131 132 if (outp == NULL) { 133 return (SCARD_E_INVALID_PARAMETER); 134 } 135 136 if (scope != SCARD_SCOPE_SYSTEM) { 137 return (SCARD_E_INVALID_VALUE); 138 } 139 140 hdl = calloc(1, sizeof (pcsc_hdl_t)); 141 if (hdl == NULL) { 142 return (SCARD_E_NO_MEMORY); 143 } 144 145 hdl->pcsc_create_time = gethrtime(); 146 *outp = hdl; 147 return (SCARD_S_SUCCESS); 148 } 149 150 /* 151 * This is called to free a library context from a client. 152 */ 153 LONG 154 SCardReleaseContext(SCARDCONTEXT hdl) 155 { 156 free(hdl); 157 return (SCARD_S_SUCCESS); 158 } 159 160 /* 161 * This is called to release memory allocated by the library. No, it doesn't 162 * make sense to take a const pointer when being given memory to free. It just 163 * means we have to cast it, but remember: this isn't our API. 164 */ 165 LONG 166 SCardFreeMemory(SCARDCONTEXT unused, LPCVOID mem) 167 { 168 free((void *)mem); 169 return (SCARD_S_SUCCESS); 170 } 171 172 /* 173 * This is called by a caller to get a list of readers that exist in the system. 174 * If lenp is set to SCARD_AUTOALLOCATE, then we are responsible for dealing 175 * with this memory. 176 */ 177 LONG 178 SCardListReaders(SCARDCONTEXT unused, LPCSTR groups, LPSTR bufp, LPDWORD lenp) 179 { 180 FTS *fts; 181 FTSENT *ent; 182 char *const root[] = { "/dev/ccid", NULL }; 183 char *ubuf; 184 char **readers; 185 uint32_t len, ulen, npaths, nalloc, off, i; 186 int ret; 187 188 if (groups != NULL || lenp == NULL) { 189 return (SCARD_E_INVALID_PARAMETER); 190 } 191 192 fts = fts_open(root, FTS_LOGICAL | FTS_NOCHDIR, NULL); 193 if (fts == NULL) { 194 switch (errno) { 195 case ENOENT: 196 case ENOTDIR: 197 return (SCARD_E_NO_READERS_AVAILABLE); 198 case ENOMEM: 199 case EAGAIN: 200 return (SCARD_E_NO_MEMORY); 201 default: 202 return (SCARD_E_NO_SERVICE); 203 } 204 } 205 206 npaths = nalloc = 0; 207 /* 208 * Account for the NUL we'll have to place at the end of this. 209 */ 210 len = 1; 211 readers = NULL; 212 while ((ent = fts_read(fts)) != NULL) { 213 size_t plen; 214 215 if (ent->fts_level != 2 || ent->fts_info == FTS_DP) 216 continue; 217 218 if (ent->fts_info == FTS_ERR || ent->fts_info == FTS_NS) 219 continue; 220 221 if (S_ISCHR(ent->fts_statp->st_mode) == 0) 222 continue; 223 224 plen = strlen(ent->fts_path) + 1; 225 if (UINT32_MAX - len <= plen) { 226 /* 227 * I mean, it's true. But I wish I could just give you 228 * EOVERFLOW. 229 */ 230 ret = SCARD_E_INSUFFICIENT_BUFFER; 231 goto out; 232 } 233 234 if (npaths == nalloc) { 235 char **tmp; 236 237 nalloc += 8; 238 tmp = reallocarray(readers, nalloc, sizeof (char *)); 239 if (tmp == NULL) { 240 ret = SCARD_E_NO_MEMORY; 241 goto out; 242 } 243 readers = tmp; 244 } 245 readers[npaths] = strdup(ent->fts_path); 246 npaths++; 247 len += plen; 248 } 249 250 if (npaths == 0) { 251 ret = SCARD_E_NO_READERS_AVAILABLE; 252 goto out; 253 } 254 255 ulen = *lenp; 256 *lenp = len; 257 if (ulen != SCARD_AUTOALLOCATE) { 258 if (bufp == NULL) { 259 ret = SCARD_S_SUCCESS; 260 goto out; 261 } 262 263 if (ulen < len) { 264 ret = SCARD_E_INSUFFICIENT_BUFFER; 265 goto out; 266 } 267 268 ubuf = bufp; 269 } else { 270 char **bufpp; 271 if (bufp == NULL) { 272 ret = SCARD_E_INVALID_PARAMETER; 273 goto out; 274 } 275 276 ubuf = malloc(ulen); 277 if (ubuf == NULL) { 278 ret = SCARD_E_NO_MEMORY; 279 goto out; 280 } 281 282 bufpp = (void *)bufp; 283 *bufpp = ubuf; 284 } 285 ret = SCARD_S_SUCCESS; 286 287 for (off = 0, i = 0; i < npaths; i++) { 288 size_t slen = strlen(readers[i]) + 1; 289 bcopy(readers[i], ubuf + off, slen); 290 off += slen; 291 VERIFY3U(off, <=, len); 292 } 293 VERIFY3U(off, ==, len - 1); 294 ubuf[off] = '\0'; 295 out: 296 for (i = 0; i < npaths; i++) { 297 free(readers[i]); 298 } 299 free(readers); 300 (void) fts_close(fts); 301 return (ret); 302 } 303 304 static LONG 305 uccid_status_helper(int fd, DWORD prots, uccid_cmd_status_t *ucs) 306 { 307 /* 308 * Get the status of this slot and find out information about the slot. 309 * We need to see if there's an ICC present and if it matches the 310 * current protocol. If not, then we have to fail this. 311 */ 312 bzero(ucs, sizeof (uccid_cmd_status_t)); 313 ucs->ucs_version = UCCID_CURRENT_VERSION; 314 if (ioctl(fd, UCCID_CMD_STATUS, ucs) != 0) { 315 return (SCARD_F_UNKNOWN_ERROR); 316 } 317 318 if ((ucs->ucs_status & UCCID_STATUS_F_CARD_PRESENT) == 0) { 319 return (SCARD_W_REMOVED_CARD); 320 } 321 322 if ((ucs->ucs_status & UCCID_STATUS_F_CARD_ACTIVE) == 0) { 323 return (SCARD_W_UNPOWERED_CARD); 324 } 325 326 if ((ucs->ucs_status & UCCID_STATUS_F_PARAMS_VALID) == 0) { 327 return (SCARD_W_UNSUPPORTED_CARD); 328 } 329 330 if ((ucs->ucs_prot & prots) == 0) { 331 return (SCARD_E_PROTO_MISMATCH); 332 } 333 334 return (0); 335 } 336 337 LONG 338 SCardConnect(SCARDCONTEXT hdl, LPCSTR reader, DWORD mode, DWORD prots, 339 LPSCARDHANDLE iccp, LPDWORD protp) 340 { 341 LONG ret; 342 uccid_cmd_status_t ucs; 343 pcsc_card_t *card; 344 345 if (reader == NULL) { 346 return (SCARD_E_UNKNOWN_READER); 347 } 348 349 if (iccp == NULL || protp == NULL) { 350 return (SCARD_E_INVALID_PARAMETER); 351 } 352 353 if (mode != SCARD_SHARE_SHARED) { 354 return (SCARD_E_INVALID_VALUE); 355 } 356 357 if ((prots & ~(SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1 | 358 SCARD_PROTOCOL_RAW | SCARD_PROTOCOL_T15)) != 0) { 359 return (SCARD_E_INVALID_VALUE); 360 } 361 362 if ((prots & (SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1)) == 0) { 363 return (SCARD_E_UNSUPPORTED_FEATURE); 364 } 365 366 if ((card = malloc(sizeof (*card))) == NULL) { 367 return (SCARD_E_NO_MEMORY); 368 } 369 370 if ((card->pcc_fd = open(reader, O_RDWR)) < 0) { 371 free(card); 372 switch (errno) { 373 case ENOENT: 374 return (SCARD_E_UNKNOWN_READER); 375 default: 376 return (SCARD_F_UNKNOWN_ERROR); 377 } 378 } 379 380 if ((ret = uccid_status_helper(card->pcc_fd, prots, &ucs)) != 0) 381 goto cleanup; 382 383 *protp = ucs.ucs_prot; 384 *iccp = card; 385 return (SCARD_S_SUCCESS); 386 cleanup: 387 (void) close(card->pcc_fd); 388 free(card); 389 return (ret); 390 } 391 392 LONG 393 SCardDisconnect(SCARDHANDLE arg, DWORD disposition) 394 { 395 pcsc_card_t *card = arg; 396 397 if (arg == NULL) { 398 return (SCARD_E_INVALID_HANDLE); 399 } 400 401 if (disposition != SCARD_LEAVE_CARD) { 402 return (SCARD_E_INVALID_VALUE); 403 } 404 405 if (close(card->pcc_fd) != 0) { 406 return (SCARD_F_UNKNOWN_ERROR); 407 } 408 409 free(card); 410 return (SCARD_S_SUCCESS); 411 } 412 413 LONG 414 SCardBeginTransaction(SCARDHANDLE arg) 415 { 416 uccid_cmd_txn_begin_t txn; 417 pcsc_card_t *card = arg; 418 419 if (card == NULL) { 420 return (SCARD_E_INVALID_HANDLE); 421 } 422 423 /* 424 * The semantics of pcsc are that this operation does not block, but 425 * instead fails if we cannot grab it immediately. 426 */ 427 bzero(&txn, sizeof (uccid_cmd_txn_begin_t)); 428 txn.uct_version = UCCID_CURRENT_VERSION; 429 txn.uct_flags = UCCID_TXN_DONT_BLOCK; 430 431 if (ioctl(card->pcc_fd, UCCID_CMD_TXN_BEGIN, &txn) != 0) { 432 VERIFY3S(errno, !=, EFAULT); 433 switch (errno) { 434 case ENODEV: 435 return (SCARD_E_READER_UNAVAILABLE); 436 case EEXIST: 437 /* 438 * This is an odd case. It's used to tell us that we 439 * already have it. For now, just treat it as success. 440 */ 441 return (SCARD_S_SUCCESS); 442 case EBUSY: 443 return (SCARD_E_SHARING_VIOLATION); 444 /* 445 * EINPROGRESS is a weird case. It means that we were trying to 446 * grab a hold while another instance using the same handle was. 447 * For now, treat it as an unknown error. 448 */ 449 case EINPROGRESS: 450 case EINTR: 451 default: 452 return (SCARD_F_UNKNOWN_ERROR); 453 } 454 } 455 return (SCARD_S_SUCCESS); 456 } 457 458 LONG 459 SCardEndTransaction(SCARDHANDLE arg, DWORD state) 460 { 461 uccid_cmd_txn_end_t txn; 462 pcsc_card_t *card = arg; 463 464 if (card == NULL) { 465 return (SCARD_E_INVALID_HANDLE); 466 } 467 468 bzero(&txn, sizeof (uccid_cmd_txn_end_t)); 469 txn.uct_version = UCCID_CURRENT_VERSION; 470 471 switch (state) { 472 case SCARD_LEAVE_CARD: 473 txn.uct_flags = UCCID_TXN_END_RELEASE; 474 break; 475 case SCARD_RESET_CARD: 476 txn.uct_flags = UCCID_TXN_END_RESET; 477 break; 478 case SCARD_UNPOWER_CARD: 479 case SCARD_EJECT_CARD: 480 default: 481 return (SCARD_E_INVALID_VALUE); 482 } 483 484 if (ioctl(card->pcc_fd, UCCID_CMD_TXN_END, &txn) != 0) { 485 VERIFY3S(errno, !=, EFAULT); 486 switch (errno) { 487 case ENODEV: 488 return (SCARD_E_READER_UNAVAILABLE); 489 case ENXIO: 490 return (SCARD_E_SHARING_VIOLATION); 491 default: 492 return (SCARD_F_UNKNOWN_ERROR); 493 } 494 } 495 return (SCARD_S_SUCCESS); 496 } 497 498 LONG 499 SCardReconnect(SCARDHANDLE arg, DWORD mode, DWORD prots, DWORD init, 500 LPDWORD protp) 501 { 502 uccid_cmd_status_t ucs; 503 pcsc_card_t *card = arg; 504 LONG ret; 505 506 if (card == NULL) { 507 return (SCARD_E_INVALID_HANDLE); 508 } 509 510 if (protp == NULL) { 511 return (SCARD_E_INVALID_PARAMETER); 512 } 513 514 if (mode != SCARD_SHARE_SHARED) { 515 return (SCARD_E_INVALID_VALUE); 516 } 517 518 if ((prots & ~(SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1 | 519 SCARD_PROTOCOL_RAW | SCARD_PROTOCOL_T15)) != 0) { 520 return (SCARD_E_INVALID_VALUE); 521 } 522 523 if ((prots & (SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1)) == 0) { 524 return (SCARD_E_UNSUPPORTED_FEATURE); 525 } 526 527 if (init != SCARD_LEAVE_CARD) { 528 return (SCARD_E_INVALID_VALUE); 529 } 530 531 if ((ret = uccid_status_helper(card->pcc_fd, prots, &ucs)) != 0) 532 return (ret); 533 534 *protp = ucs.ucs_prot; 535 return (SCARD_S_SUCCESS); 536 } 537 538 LONG 539 SCardTransmit(SCARDHANDLE arg, const SCARD_IO_REQUEST *sendreq, 540 LPCBYTE sendbuf, DWORD sendlen, SCARD_IO_REQUEST *recvreq, LPBYTE recvbuf, 541 LPDWORD recvlenp) 542 { 543 int len; 544 ssize_t ret; 545 pcsc_card_t *card = arg; 546 547 if (card == NULL) { 548 return (SCARD_E_INVALID_HANDLE); 549 } 550 551 /* 552 * Ignore sendreq / recvreq. 553 */ 554 if (sendbuf == NULL || recvbuf == NULL || recvlenp == NULL) { 555 return (SCARD_E_INVALID_PARAMETER); 556 } 557 558 /* 559 * The CCID write will always consume all data or none. 560 */ 561 ret = write(card->pcc_fd, sendbuf, sendlen); 562 if (ret == -1) { 563 switch (errno) { 564 case E2BIG: 565 return (SCARD_E_INVALID_PARAMETER); 566 case ENODEV: 567 return (SCARD_E_READER_UNAVAILABLE); 568 case EACCES: 569 case EBUSY: 570 return (SCARD_E_SHARING_VIOLATION); 571 case ENXIO: 572 return (SCARD_W_REMOVED_CARD); 573 case EFAULT: 574 return (SCARD_E_INVALID_PARAMETER); 575 case ENOMEM: 576 default: 577 return (SCARD_F_UNKNOWN_ERROR); 578 } 579 } 580 ASSERT3S(ret, ==, sendlen); 581 582 /* 583 * Now, we should be able to block in read. 584 */ 585 ret = read(card->pcc_fd, recvbuf, *recvlenp); 586 if (ret == -1) { 587 switch (errno) { 588 case EINVAL: 589 case EOVERFLOW: 590 /* 591 * This means that we need to update len with the real 592 * one. 593 */ 594 if (ioctl(card->pcc_fd, FIONREAD, &len) != 0) { 595 return (SCARD_F_UNKNOWN_ERROR); 596 } 597 *recvlenp = len; 598 return (SCARD_E_INSUFFICIENT_BUFFER); 599 case ENODEV: 600 return (SCARD_E_READER_UNAVAILABLE); 601 case EACCES: 602 case EBUSY: 603 return (SCARD_E_SHARING_VIOLATION); 604 case EFAULT: 605 return (SCARD_E_INVALID_PARAMETER); 606 case ENODATA: 607 default: 608 return (SCARD_F_UNKNOWN_ERROR); 609 } 610 } 611 612 *recvlenp = ret; 613 614 return (SCARD_S_SUCCESS); 615 } 616