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 * Copyright 2022 Oxide Computer Company 15 */ 16 17 #include <stdlib.h> 18 #include <stdio.h> 19 #include <stdbool.h> 20 #include <sys/types.h> 21 #include <sys/stat.h> 22 #include <sys/list.h> 23 #include <fcntl.h> 24 #include <fts.h> 25 #include <errno.h> 26 #include <strings.h> 27 #include <unistd.h> 28 #include <upanic.h> 29 #include <sys/debug.h> 30 #include <sys/filio.h> 31 #include <sys/usb/clients/ccid/uccid.h> 32 33 #include <winscard.h> 34 35 /* 36 * Implementation of the PCSC library leveraging the uccid framework. 37 */ 38 39 typedef struct pcsc_hdl { 40 hrtime_t pcsc_create_time; 41 list_t pcsc_autoalloc; 42 list_t pcsc_cards; 43 } pcsc_hdl_t; 44 45 typedef struct pcsc_card { 46 list_node_t pcc_link; 47 pcsc_hdl_t *pcc_hdl; 48 int pcc_fd; 49 char *pcc_name; 50 size_t pcc_namelen; 51 } pcsc_card_t; 52 53 typedef struct pcsc_mem { 54 list_node_t pcm_link; 55 void *pcm_buf; 56 } pcsc_mem_t; 57 58 /* 59 * Required globals 60 */ 61 SCARD_IO_REQUEST g_rgSCardT0Pci = { 62 SCARD_PROTOCOL_T0, 63 0 64 }; 65 66 SCARD_IO_REQUEST g_rgSCardT1Pci = { 67 SCARD_PROTOCOL_T1, 68 0 69 }; 70 71 SCARD_IO_REQUEST g_rgSCardRawPci = { 72 SCARD_PROTOCOL_RAW, 73 0 74 }; 75 76 const char * 77 pcsc_stringify_error(const LONG err) 78 { 79 switch (err) { 80 case SCARD_S_SUCCESS: 81 return ("no error"); 82 case SCARD_F_INTERNAL_ERROR: 83 return ("internal error"); 84 case SCARD_E_CANCELLED: 85 return ("request cancelled"); 86 case SCARD_E_INVALID_HANDLE: 87 return ("invalid handle"); 88 case SCARD_E_INVALID_PARAMETER: 89 return ("invalid parameter"); 90 case SCARD_E_NO_MEMORY: 91 return ("no memory"); 92 case SCARD_E_INSUFFICIENT_BUFFER: 93 return ("buffer was insufficiently sized"); 94 case SCARD_E_INVALID_VALUE: 95 return ("invalid value passed"); 96 case SCARD_E_UNKNOWN_READER: 97 return ("unknown reader"); 98 case SCARD_E_TIMEOUT: 99 return ("timeout occurred"); 100 case SCARD_E_SHARING_VIOLATION: 101 return ("sharing violation"); 102 case SCARD_E_NO_SMARTCARD: 103 return ("no smartcard present"); 104 case SCARD_E_UNKNOWN_CARD: 105 return ("unknown ICC"); 106 case SCARD_E_PROTO_MISMATCH: 107 return ("protocol mismatch"); 108 case SCARD_F_COMM_ERROR: 109 return ("communication error"); 110 case SCARD_F_UNKNOWN_ERROR: 111 return ("unknown error"); 112 case SCARD_E_READER_UNAVAILABLE: 113 return ("reader unavailable"); 114 case SCARD_E_NO_SERVICE: 115 return ("service error"); 116 case SCARD_E_UNSUPPORTED_FEATURE: 117 return ("ICC requires unsupported feature"); 118 case SCARD_E_NO_READERS_AVAILABLE: 119 return ("no readers avaiable"); 120 case SCARD_W_UNSUPPORTED_CARD: 121 return ("ICC unsupported"); 122 case SCARD_W_UNPOWERED_CARD: 123 return ("ICC is not powered"); 124 case SCARD_W_RESET_CARD: 125 return ("ICC was reset"); 126 case SCARD_W_REMOVED_CARD: 127 return ("ICC has been removed"); 128 default: 129 return ("unknown error"); 130 } 131 } 132 133 /* 134 * Allocate a buffer of size "len" for use with an SCARD_AUTOALLOCATE 135 * parameter. Each automatically allocated buffer must be appended to the 136 * context buffer list so that it can be freed during the call to 137 * SCardReleaseContext(). 138 */ 139 static void * 140 pcsc_mem_alloc(pcsc_hdl_t *hdl, size_t len) 141 { 142 pcsc_mem_t *mem; 143 144 if ((mem = malloc(sizeof (*mem))) == NULL) { 145 return (NULL); 146 } 147 148 if ((mem->pcm_buf = malloc(len)) == NULL) { 149 free(mem); 150 return (NULL); 151 } 152 list_link_init(&mem->pcm_link); 153 154 /* 155 * Put the buffer on the per-context list: 156 */ 157 list_insert_tail(&hdl->pcsc_autoalloc, mem); 158 159 return (mem->pcm_buf); 160 } 161 162 static void 163 pcsc_mem_free(pcsc_hdl_t *hdl, void *buf) 164 { 165 for (pcsc_mem_t *mem = list_head(&hdl->pcsc_autoalloc); mem != NULL; 166 mem = list_next(&hdl->pcsc_autoalloc, mem)) { 167 if (mem->pcm_buf == buf) { 168 list_remove(&hdl->pcsc_autoalloc, mem); 169 free(mem->pcm_buf); 170 free(mem); 171 return; 172 } 173 } 174 175 char msg[512]; 176 (void) snprintf(msg, sizeof (msg), "freed buffer %p not in context %p", 177 buf, hdl); 178 upanic(msg, strlen(msg)); 179 } 180 181 static pcsc_card_t * 182 pcsc_card_alloc(pcsc_hdl_t *hdl, const char *reader) 183 { 184 pcsc_card_t *card; 185 186 if ((card = malloc(sizeof (*card))) == NULL) { 187 return (NULL); 188 } 189 card->pcc_hdl = hdl; 190 card->pcc_fd = -1; 191 list_link_init(&card->pcc_link); 192 193 /* 194 * The reader name is returned as a multi-string, which means we need 195 * the regular C string and then an additional null termination byte to 196 * end the list of strings: 197 */ 198 card->pcc_namelen = strlen(reader) + 2; 199 if ((card->pcc_name = malloc(card->pcc_namelen)) == NULL) { 200 free(card); 201 return (NULL); 202 } 203 bcopy(reader, card->pcc_name, card->pcc_namelen - 1); 204 card->pcc_name[card->pcc_namelen - 1] = '\0'; 205 206 /* 207 * Insert the card handle into the per-context list so that we can free 208 * them later during SCardReleaseContext(). 209 */ 210 list_insert_tail(&hdl->pcsc_cards, card); 211 212 return (card); 213 } 214 215 static void 216 pcsc_card_free(pcsc_card_t *card) 217 { 218 if (card == NULL) { 219 return; 220 } 221 222 if (card->pcc_fd >= 0) { 223 (void) close(card->pcc_fd); 224 } 225 226 /* 227 * Remove the card handle from the per-context list: 228 */ 229 pcsc_hdl_t *hdl = card->pcc_hdl; 230 list_remove(&hdl->pcsc_cards, card); 231 232 free(card->pcc_name); 233 free(card); 234 } 235 236 /* 237 * This is called when a caller wishes to open a new Library context. 238 */ 239 LONG 240 SCardEstablishContext(DWORD scope, LPCVOID unused0, LPCVOID unused1, 241 LPSCARDCONTEXT outp) 242 { 243 pcsc_hdl_t *hdl; 244 245 if (outp == NULL) { 246 return (SCARD_E_INVALID_PARAMETER); 247 } 248 249 if (scope != SCARD_SCOPE_SYSTEM) { 250 return (SCARD_E_INVALID_VALUE); 251 } 252 253 hdl = calloc(1, sizeof (pcsc_hdl_t)); 254 if (hdl == NULL) { 255 return (SCARD_E_NO_MEMORY); 256 } 257 list_create(&hdl->pcsc_autoalloc, sizeof (pcsc_mem_t), 258 offsetof(pcsc_mem_t, pcm_link)); 259 list_create(&hdl->pcsc_cards, sizeof (pcsc_card_t), 260 offsetof(pcsc_card_t, pcc_link)); 261 262 hdl->pcsc_create_time = gethrtime(); 263 *outp = hdl; 264 return (SCARD_S_SUCCESS); 265 } 266 267 bool 268 pcsc_valid_context(SCARDCONTEXT hdl) 269 { 270 /* 271 * On some other platforms, the context handle is a signed integer. 272 * Some software has been observed to use -1 as an invalid handle 273 * sentinel value, so we need to explicitly handle that here. 274 */ 275 return (hdl != NULL && (uintptr_t)hdl != UINTPTR_MAX); 276 } 277 278 LONG 279 SCardIsValidContext(SCARDCONTEXT hdl) 280 { 281 if (!pcsc_valid_context(hdl)) { 282 return (SCARD_E_INVALID_HANDLE); 283 } 284 285 return (SCARD_S_SUCCESS); 286 } 287 288 /* 289 * This is called to free a library context from a client. 290 */ 291 LONG 292 SCardReleaseContext(SCARDCONTEXT arg) 293 { 294 if (!pcsc_valid_context(arg)) { 295 return (SCARD_E_INVALID_HANDLE); 296 } 297 298 /* 299 * Free any SCARD_AUTOALLOCATE memory now. 300 */ 301 pcsc_hdl_t *hdl = arg; 302 pcsc_mem_t *mem; 303 while ((mem = list_head(&hdl->pcsc_autoalloc)) != NULL) { 304 pcsc_mem_free(hdl, mem->pcm_buf); 305 } 306 list_destroy(&hdl->pcsc_autoalloc); 307 308 /* 309 * Free any card handles that were not explicitly freed: 310 */ 311 pcsc_card_t *card; 312 while ((card = list_head(&hdl->pcsc_cards)) != NULL) { 313 pcsc_card_free(card); 314 } 315 list_destroy(&hdl->pcsc_cards); 316 317 free(hdl); 318 return (SCARD_S_SUCCESS); 319 } 320 321 /* 322 * This is called to release memory allocated by the library. No, it doesn't 323 * make sense to take a const pointer when being given memory to free. It just 324 * means we have to cast it, but remember: this isn't our API. 325 */ 326 LONG 327 SCardFreeMemory(SCARDCONTEXT hdl, LPCVOID mem) 328 { 329 if (!pcsc_valid_context(hdl)) { 330 return (SCARD_E_INVALID_HANDLE); 331 } 332 333 pcsc_mem_free(hdl, (void *)mem); 334 return (SCARD_S_SUCCESS); 335 } 336 337 /* 338 * This is called by a caller to get a list of readers that exist in the system. 339 * If lenp is set to SCARD_AUTOALLOCATE, then we are responsible for dealing 340 * with this memory. 341 */ 342 LONG 343 SCardListReaders(SCARDCONTEXT arg, LPCSTR groups, LPSTR bufp, LPDWORD lenp) 344 { 345 pcsc_hdl_t *hdl = arg; 346 FTS *fts; 347 FTSENT *ent; 348 char *const root[] = { "/dev/ccid", NULL }; 349 char *ubuf; 350 char **readers; 351 uint32_t len, ulen, npaths, nalloc, off, i; 352 int ret; 353 354 if (!pcsc_valid_context(hdl)) { 355 return (SCARD_E_INVALID_HANDLE); 356 } 357 358 if (groups != NULL || lenp == NULL) { 359 return (SCARD_E_INVALID_PARAMETER); 360 } 361 362 fts = fts_open(root, FTS_LOGICAL | FTS_NOCHDIR, NULL); 363 if (fts == NULL) { 364 switch (errno) { 365 case ENOENT: 366 case ENOTDIR: 367 return (SCARD_E_NO_READERS_AVAILABLE); 368 case ENOMEM: 369 case EAGAIN: 370 return (SCARD_E_NO_MEMORY); 371 default: 372 return (SCARD_E_NO_SERVICE); 373 } 374 } 375 376 npaths = nalloc = 0; 377 /* 378 * Account for the NUL we'll have to place at the end of this. 379 */ 380 len = 1; 381 readers = NULL; 382 while ((ent = fts_read(fts)) != NULL) { 383 size_t plen; 384 385 if (ent->fts_level != 2 || ent->fts_info == FTS_DP) 386 continue; 387 388 if (ent->fts_info == FTS_ERR || ent->fts_info == FTS_NS) 389 continue; 390 391 if (S_ISCHR(ent->fts_statp->st_mode) == 0) 392 continue; 393 394 plen = strlen(ent->fts_path) + 1; 395 if (UINT32_MAX - len <= plen) { 396 /* 397 * I mean, it's true. But I wish I could just give you 398 * EOVERFLOW. 399 */ 400 ret = SCARD_E_INSUFFICIENT_BUFFER; 401 goto out; 402 } 403 404 if (npaths == nalloc) { 405 char **tmp; 406 407 nalloc += 8; 408 tmp = reallocarray(readers, nalloc, sizeof (char *)); 409 if (tmp == NULL) { 410 ret = SCARD_E_NO_MEMORY; 411 goto out; 412 } 413 readers = tmp; 414 } 415 readers[npaths] = strdup(ent->fts_path); 416 npaths++; 417 len += plen; 418 } 419 420 if (npaths == 0) { 421 ret = SCARD_E_NO_READERS_AVAILABLE; 422 goto out; 423 } 424 425 ulen = *lenp; 426 *lenp = len; 427 if (ulen != SCARD_AUTOALLOCATE) { 428 if (bufp == NULL) { 429 ret = SCARD_S_SUCCESS; 430 goto out; 431 } 432 433 if (ulen < len) { 434 ret = SCARD_E_INSUFFICIENT_BUFFER; 435 goto out; 436 } 437 438 ubuf = bufp; 439 } else { 440 char **bufpp; 441 if (bufp == NULL) { 442 ret = SCARD_E_INVALID_PARAMETER; 443 goto out; 444 } 445 446 if ((ubuf = pcsc_mem_alloc(hdl, ulen)) == NULL) { 447 ret = SCARD_E_NO_MEMORY; 448 goto out; 449 } 450 451 bufpp = (void *)bufp; 452 *bufpp = ubuf; 453 } 454 ret = SCARD_S_SUCCESS; 455 456 for (off = 0, i = 0; i < npaths; i++) { 457 size_t slen = strlen(readers[i]) + 1; 458 bcopy(readers[i], ubuf + off, slen); 459 off += slen; 460 VERIFY3U(off, <=, len); 461 } 462 VERIFY3U(off, ==, len - 1); 463 ubuf[off] = '\0'; 464 out: 465 for (i = 0; i < npaths; i++) { 466 free(readers[i]); 467 } 468 free(readers); 469 (void) fts_close(fts); 470 return (ret); 471 } 472 473 static LONG 474 uccid_status_helper(int fd, DWORD prots, uccid_cmd_status_t *ucs) 475 { 476 /* 477 * Get the status of this slot and find out information about the slot. 478 * We need to see if there's an ICC present and if it matches the 479 * current protocol. If not, then we have to fail this. 480 */ 481 bzero(ucs, sizeof (uccid_cmd_status_t)); 482 ucs->ucs_version = UCCID_CURRENT_VERSION; 483 if (ioctl(fd, UCCID_CMD_STATUS, ucs) != 0) { 484 return (SCARD_F_UNKNOWN_ERROR); 485 } 486 487 if ((ucs->ucs_status & UCCID_STATUS_F_CARD_PRESENT) == 0) { 488 return (SCARD_W_REMOVED_CARD); 489 } 490 491 if ((ucs->ucs_status & UCCID_STATUS_F_CARD_ACTIVE) == 0) { 492 return (SCARD_W_UNPOWERED_CARD); 493 } 494 495 if ((ucs->ucs_status & UCCID_STATUS_F_PARAMS_VALID) == 0) { 496 return (SCARD_W_UNSUPPORTED_CARD); 497 } 498 499 if ((ucs->ucs_prot & prots) == 0) { 500 return (SCARD_E_PROTO_MISMATCH); 501 } 502 503 return (0); 504 } 505 506 LONG 507 SCardConnect(SCARDCONTEXT hdl, LPCSTR reader, DWORD mode, DWORD prots, 508 LPSCARDHANDLE iccp, LPDWORD protp) 509 { 510 LONG ret; 511 uccid_cmd_status_t ucs; 512 pcsc_card_t *card; 513 514 if (!pcsc_valid_context(hdl)) { 515 return (SCARD_E_INVALID_HANDLE); 516 } 517 518 if (reader == NULL) { 519 return (SCARD_E_UNKNOWN_READER); 520 } 521 522 if (iccp == NULL || protp == NULL) { 523 return (SCARD_E_INVALID_PARAMETER); 524 } 525 526 if (mode != SCARD_SHARE_SHARED) { 527 return (SCARD_E_INVALID_VALUE); 528 } 529 530 if ((prots & ~(SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1 | 531 SCARD_PROTOCOL_RAW | SCARD_PROTOCOL_T15)) != 0) { 532 return (SCARD_E_INVALID_VALUE); 533 } 534 535 if ((prots & (SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1)) == 0) { 536 return (SCARD_E_UNSUPPORTED_FEATURE); 537 } 538 539 if ((card = pcsc_card_alloc(hdl, reader)) == NULL) { 540 pcsc_card_free(card); 541 return (SCARD_E_NO_MEMORY); 542 } 543 544 if ((card->pcc_fd = open(reader, O_RDWR)) < 0) { 545 pcsc_card_free(card); 546 switch (errno) { 547 case ENOENT: 548 return (SCARD_E_UNKNOWN_READER); 549 default: 550 return (SCARD_F_UNKNOWN_ERROR); 551 } 552 } 553 554 if ((ret = uccid_status_helper(card->pcc_fd, prots, &ucs)) != 0) { 555 pcsc_card_free(card); 556 return (ret); 557 } 558 559 *protp = ucs.ucs_prot; 560 *iccp = card; 561 return (SCARD_S_SUCCESS); 562 } 563 564 /* 565 * The Windows documentation suggests that all of the input/output arguments 566 * (other than the handle) are effectively optional. 567 */ 568 LONG 569 SCardStatus(SCARDHANDLE arg, LPSTR readerp, LPDWORD readerlenp, 570 LPDWORD statep, LPDWORD protop, LPBYTE atrp, LPDWORD atrlenp) 571 { 572 pcsc_card_t *card = arg; 573 pcsc_hdl_t *hdl = card->pcc_hdl; 574 LONG ret = SCARD_S_SUCCESS; 575 576 if (statep == NULL && protop == NULL && atrlenp == NULL) { 577 /* 578 * There is no need to perform the status ioctl. 579 */ 580 goto name; 581 } 582 583 uccid_cmd_status_t ucs = { .ucs_version = UCCID_CURRENT_VERSION }; 584 if (ioctl(card->pcc_fd, UCCID_CMD_STATUS, &ucs) != 0) { 585 VERIFY3S(errno, ==, ENODEV); 586 ret = SCARD_E_READER_UNAVAILABLE; 587 goto out; 588 } 589 590 if (statep != NULL) { 591 if (!(ucs.ucs_status & UCCID_STATUS_F_CARD_PRESENT)) { 592 *statep = SCARD_ABSENT; 593 } else if (ucs.ucs_status & UCCID_STATUS_F_CARD_ACTIVE) { 594 if (ucs.ucs_status & UCCID_STATUS_F_PARAMS_VALID) { 595 *statep = SCARD_SPECIFIC; 596 } else { 597 *statep = SCARD_POWERED; 598 } 599 } else { 600 *statep = SCARD_PRESENT; 601 } 602 } 603 604 if (protop != NULL) { 605 if (ucs.ucs_status & UCCID_STATUS_F_PARAMS_VALID) { 606 switch (ucs.ucs_prot) { 607 case UCCID_PROT_T0: 608 *protop = SCARD_PROTOCOL_T0; 609 break; 610 case UCCID_PROT_T1: 611 *protop = SCARD_PROTOCOL_T1; 612 break; 613 default: 614 *protop = SCARD_PROTOCOL_UNDEFINED; 615 break; 616 } 617 } else { 618 /* 619 * If SCARD_SPECIFIC is not returned as the card 620 * state, this value is not considered meaningful. 621 */ 622 *protop = SCARD_PROTOCOL_UNDEFINED; 623 } 624 } 625 626 if (atrlenp != NULL) { 627 uint8_t *ubuf; 628 uint32_t len = *atrlenp; 629 if (len != SCARD_AUTOALLOCATE) { 630 if (len < ucs.ucs_atrlen) { 631 *atrlenp = ucs.ucs_atrlen; 632 ret = SCARD_E_INSUFFICIENT_BUFFER; 633 goto out; 634 } 635 636 if (atrp == NULL) { 637 ret = SCARD_E_INVALID_PARAMETER; 638 goto out; 639 } 640 641 ubuf = atrp; 642 } else { 643 if ((ubuf = pcsc_mem_alloc(hdl, ucs.ucs_atrlen)) == 644 NULL) { 645 ret = SCARD_E_NO_MEMORY; 646 goto out; 647 } 648 649 *((LPBYTE *)atrp) = ubuf; 650 } 651 652 bcopy(ucs.ucs_atr, ubuf, ucs.ucs_atrlen); 653 *atrlenp = ucs.ucs_atrlen; 654 } 655 656 name: 657 if (readerlenp != NULL) { 658 char *ubuf; 659 uint32_t rlen = *readerlenp; 660 if (rlen != SCARD_AUTOALLOCATE) { 661 if (rlen < card->pcc_namelen) { 662 *readerlenp = card->pcc_namelen; 663 ret = SCARD_E_INSUFFICIENT_BUFFER; 664 goto out; 665 } 666 667 if (readerp == NULL) { 668 ret = SCARD_E_INVALID_PARAMETER; 669 goto out; 670 } 671 672 ubuf = readerp; 673 } else { 674 if ((ubuf = pcsc_mem_alloc(hdl, card->pcc_namelen)) == 675 NULL) { 676 ret = SCARD_E_NO_MEMORY; 677 goto out; 678 } 679 680 *((LPSTR *)readerp) = ubuf; 681 } 682 683 /* 684 * We stored the reader name as a multi-string in 685 * pcsc_card_alloc(), so we can just copy out the whole value 686 * here without further modification: 687 */ 688 bcopy(card->pcc_name, ubuf, card->pcc_namelen); 689 } 690 691 out: 692 return (ret); 693 } 694 695 LONG 696 SCardDisconnect(SCARDHANDLE arg, DWORD disposition) 697 { 698 pcsc_card_t *card = arg; 699 700 if (arg == NULL) { 701 return (SCARD_E_INVALID_HANDLE); 702 } 703 704 switch (disposition) { 705 case SCARD_RESET_CARD: { 706 /* 707 * To reset the card, we first need to get exclusive access to 708 * the card. 709 */ 710 uccid_cmd_txn_begin_t txnbegin = { 711 .uct_version = UCCID_CURRENT_VERSION, 712 }; 713 if (ioctl(card->pcc_fd, UCCID_CMD_TXN_BEGIN, &txnbegin) != 0) { 714 VERIFY3S(errno, !=, EFAULT); 715 716 switch (errno) { 717 case ENODEV: 718 /* 719 * If the card is no longer present, we cannot 720 * reset it. 721 */ 722 goto close; 723 case EEXIST: 724 break; 725 case EBUSY: 726 return (SCARD_E_SHARING_VIOLATION); 727 default: 728 return (SCARD_F_UNKNOWN_ERROR); 729 } 730 } 731 732 /* 733 * Once we have begun the transaction, we can end it 734 * immediately while requesting a reset before the next 735 * transaction. 736 */ 737 uccid_cmd_txn_end_t txnend = { 738 .uct_version = UCCID_CURRENT_VERSION, 739 .uct_flags = UCCID_TXN_END_RESET, 740 }; 741 if (ioctl(card->pcc_fd, UCCID_CMD_TXN_END, &txnend) != 0) { 742 VERIFY3S(errno, !=, EFAULT); 743 744 switch (errno) { 745 case ENODEV: 746 goto close; 747 default: 748 return (SCARD_F_UNKNOWN_ERROR); 749 } 750 } 751 } 752 case SCARD_LEAVE_CARD: 753 break; 754 default: 755 return (SCARD_E_INVALID_VALUE); 756 } 757 758 close: 759 if (close(card->pcc_fd) != 0) { 760 return (SCARD_F_UNKNOWN_ERROR); 761 } 762 card->pcc_fd = -1; 763 764 pcsc_card_free(card); 765 return (SCARD_S_SUCCESS); 766 } 767 768 LONG 769 SCardBeginTransaction(SCARDHANDLE arg) 770 { 771 uccid_cmd_txn_begin_t txn; 772 pcsc_card_t *card = arg; 773 774 if (card == NULL) { 775 return (SCARD_E_INVALID_HANDLE); 776 } 777 778 /* 779 * The semantics of pcsc are that this operation does not block, but 780 * instead fails if we cannot grab it immediately. 781 */ 782 bzero(&txn, sizeof (uccid_cmd_txn_begin_t)); 783 txn.uct_version = UCCID_CURRENT_VERSION; 784 txn.uct_flags = UCCID_TXN_DONT_BLOCK; 785 786 if (ioctl(card->pcc_fd, UCCID_CMD_TXN_BEGIN, &txn) != 0) { 787 VERIFY3S(errno, !=, EFAULT); 788 switch (errno) { 789 case ENODEV: 790 return (SCARD_E_READER_UNAVAILABLE); 791 case EEXIST: 792 /* 793 * This is an odd case. It's used to tell us that we 794 * already have it. For now, just treat it as success. 795 */ 796 return (SCARD_S_SUCCESS); 797 case EBUSY: 798 return (SCARD_E_SHARING_VIOLATION); 799 /* 800 * EINPROGRESS is a weird case. It means that we were trying to 801 * grab a hold while another instance using the same handle was. 802 * For now, treat it as an unknown error. 803 */ 804 case EINPROGRESS: 805 case EINTR: 806 default: 807 return (SCARD_F_UNKNOWN_ERROR); 808 } 809 } 810 return (SCARD_S_SUCCESS); 811 } 812 813 LONG 814 SCardEndTransaction(SCARDHANDLE arg, DWORD state) 815 { 816 uccid_cmd_txn_end_t txn; 817 pcsc_card_t *card = arg; 818 819 if (card == NULL) { 820 return (SCARD_E_INVALID_HANDLE); 821 } 822 823 bzero(&txn, sizeof (uccid_cmd_txn_end_t)); 824 txn.uct_version = UCCID_CURRENT_VERSION; 825 826 switch (state) { 827 case SCARD_LEAVE_CARD: 828 txn.uct_flags = UCCID_TXN_END_RELEASE; 829 break; 830 case SCARD_RESET_CARD: 831 txn.uct_flags = UCCID_TXN_END_RESET; 832 break; 833 case SCARD_UNPOWER_CARD: 834 case SCARD_EJECT_CARD: 835 default: 836 return (SCARD_E_INVALID_VALUE); 837 } 838 839 if (ioctl(card->pcc_fd, UCCID_CMD_TXN_END, &txn) != 0) { 840 VERIFY3S(errno, !=, EFAULT); 841 switch (errno) { 842 case ENODEV: 843 return (SCARD_E_READER_UNAVAILABLE); 844 case ENXIO: 845 return (SCARD_E_SHARING_VIOLATION); 846 default: 847 return (SCARD_F_UNKNOWN_ERROR); 848 } 849 } 850 return (SCARD_S_SUCCESS); 851 } 852 853 LONG 854 SCardReconnect(SCARDHANDLE arg, DWORD mode, DWORD prots, DWORD init, 855 LPDWORD protp) 856 { 857 uccid_cmd_status_t ucs; 858 pcsc_card_t *card = arg; 859 LONG ret; 860 861 if (card == NULL) { 862 return (SCARD_E_INVALID_HANDLE); 863 } 864 865 if (protp == NULL) { 866 return (SCARD_E_INVALID_PARAMETER); 867 } 868 869 if (mode != SCARD_SHARE_SHARED) { 870 return (SCARD_E_INVALID_VALUE); 871 } 872 873 if ((prots & ~(SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1 | 874 SCARD_PROTOCOL_RAW | SCARD_PROTOCOL_T15)) != 0) { 875 return (SCARD_E_INVALID_VALUE); 876 } 877 878 if ((prots & (SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1)) == 0) { 879 return (SCARD_E_UNSUPPORTED_FEATURE); 880 } 881 882 if (init != SCARD_LEAVE_CARD) { 883 return (SCARD_E_INVALID_VALUE); 884 } 885 886 if ((ret = uccid_status_helper(card->pcc_fd, prots, &ucs)) != 0) 887 return (ret); 888 889 *protp = ucs.ucs_prot; 890 return (SCARD_S_SUCCESS); 891 } 892 893 LONG 894 SCardTransmit(SCARDHANDLE arg, const SCARD_IO_REQUEST *sendreq, 895 LPCBYTE sendbuf, DWORD sendlen, SCARD_IO_REQUEST *recvreq, LPBYTE recvbuf, 896 LPDWORD recvlenp) 897 { 898 int len; 899 ssize_t ret; 900 pcsc_card_t *card = arg; 901 902 if (card == NULL) { 903 return (SCARD_E_INVALID_HANDLE); 904 } 905 906 /* 907 * Ignore sendreq / recvreq. 908 */ 909 if (sendbuf == NULL || recvbuf == NULL || recvlenp == NULL) { 910 return (SCARD_E_INVALID_PARAMETER); 911 } 912 913 /* 914 * The CCID write will always consume all data or none. 915 */ 916 ret = write(card->pcc_fd, sendbuf, sendlen); 917 if (ret == -1) { 918 switch (errno) { 919 case E2BIG: 920 return (SCARD_E_INVALID_PARAMETER); 921 case ENODEV: 922 return (SCARD_E_READER_UNAVAILABLE); 923 case EACCES: 924 case EBUSY: 925 return (SCARD_E_SHARING_VIOLATION); 926 case ENXIO: 927 return (SCARD_W_REMOVED_CARD); 928 case EFAULT: 929 return (SCARD_E_INVALID_PARAMETER); 930 case ENOMEM: 931 default: 932 return (SCARD_F_UNKNOWN_ERROR); 933 } 934 } 935 ASSERT3S(ret, ==, sendlen); 936 937 /* 938 * Now, we should be able to block in read. 939 */ 940 ret = read(card->pcc_fd, recvbuf, *recvlenp); 941 if (ret == -1) { 942 switch (errno) { 943 case EINVAL: 944 case EOVERFLOW: 945 /* 946 * This means that we need to update len with the real 947 * one. 948 */ 949 if (ioctl(card->pcc_fd, FIONREAD, &len) != 0) { 950 return (SCARD_F_UNKNOWN_ERROR); 951 } 952 *recvlenp = len; 953 return (SCARD_E_INSUFFICIENT_BUFFER); 954 case ENODEV: 955 return (SCARD_E_READER_UNAVAILABLE); 956 case EACCES: 957 case EBUSY: 958 return (SCARD_E_SHARING_VIOLATION); 959 case EFAULT: 960 return (SCARD_E_INVALID_PARAMETER); 961 case ENODATA: 962 default: 963 return (SCARD_F_UNKNOWN_ERROR); 964 } 965 } 966 967 *recvlenp = ret; 968 969 return (SCARD_S_SUCCESS); 970 } 971