summaryrefslogtreecommitdiff
path: root/usr/src/lib/libpcsc/common
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libpcsc/common')
-rw-r--r--usr/src/lib/libpcsc/common/libpcsc.c615
-rw-r--r--usr/src/lib/libpcsc/common/mapfile-vers50
-rw-r--r--usr/src/lib/libpcsc/common/winscard.h144
-rw-r--r--usr/src/lib/libpcsc/common/wintypes.h50
4 files changed, 859 insertions, 0 deletions
diff --git a/usr/src/lib/libpcsc/common/libpcsc.c b/usr/src/lib/libpcsc/common/libpcsc.c
new file mode 100644
index 0000000000..41d646e8b1
--- /dev/null
+++ b/usr/src/lib/libpcsc/common/libpcsc.c
@@ -0,0 +1,615 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2019, Joyent, Inc.
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <errno.h>
+#include <strings.h>
+#include <unistd.h>
+#include <sys/debug.h>
+#include <sys/filio.h>
+#include <sys/usb/clients/ccid/uccid.h>
+
+#include <winscard.h>
+
+/*
+ * Implementation of the PCSC library leveraging the uccid framework.
+ */
+
+/*
+ * The library handle is basically unused today. We keep this around such that
+ * consumers which expect to receive a non-NULL opaque handle have something
+ * they can use.
+ */
+typedef struct pcsc_hdl {
+ hrtime_t pcsc_create_time;
+} pcsc_hdl_t;
+
+typedef struct pcsc_card {
+ int pcc_fd;
+} pcsc_card_t;
+
+/*
+ * Required globals
+ */
+SCARD_IO_REQUEST g_rgSCardT0Pci = {
+ SCARD_PROTOCOL_T0,
+ 0
+};
+
+SCARD_IO_REQUEST g_rgSCardT1Pci = {
+ SCARD_PROTOCOL_T1,
+ 0
+};
+
+SCARD_IO_REQUEST g_rgSCardRawPci = {
+ SCARD_PROTOCOL_RAW,
+ 0
+};
+
+const char *
+pcsc_stringify_error(const LONG err)
+{
+ switch (err) {
+ case SCARD_S_SUCCESS:
+ return ("no error");
+ case SCARD_F_INTERNAL_ERROR:
+ return ("internal error");
+ case SCARD_E_CANCELLED:
+ return ("request cancelled");
+ case SCARD_E_INVALID_HANDLE:
+ return ("invalid handle");
+ case SCARD_E_INVALID_PARAMETER:
+ return ("invalid parameter");
+ case SCARD_E_NO_MEMORY:
+ return ("no memory");
+ case SCARD_E_INSUFFICIENT_BUFFER:
+ return ("buffer was insufficiently sized");
+ case SCARD_E_INVALID_VALUE:
+ return ("invalid value passed");
+ case SCARD_E_UNKNOWN_READER:
+ return ("unknown reader");
+ case SCARD_E_TIMEOUT:
+ return ("timeout occurred");
+ case SCARD_E_SHARING_VIOLATION:
+ return ("sharing violation");
+ case SCARD_E_NO_SMARTCARD:
+ return ("no smartcard present");
+ case SCARD_E_UNKNOWN_CARD:
+ return ("unknown ICC");
+ case SCARD_E_PROTO_MISMATCH:
+ return ("protocol mismatch");
+ case SCARD_F_COMM_ERROR:
+ return ("communication error");
+ case SCARD_F_UNKNOWN_ERROR:
+ return ("unknown error");
+ case SCARD_E_READER_UNAVAILABLE:
+ return ("reader unavailable");
+ case SCARD_E_NO_SERVICE:
+ return ("service error");
+ case SCARD_E_UNSUPPORTED_FEATURE:
+ return ("ICC requires unsupported feature");
+ case SCARD_E_NO_READERS_AVAILABLE:
+ return ("no readers avaiable");
+ case SCARD_W_UNSUPPORTED_CARD:
+ return ("ICC unsupported");
+ case SCARD_W_UNPOWERED_CARD:
+ return ("ICC is not powered");
+ case SCARD_W_RESET_CARD:
+ return ("ICC was reset");
+ case SCARD_W_REMOVED_CARD:
+ return ("ICC has been removed");
+ default:
+ return ("unknown error");
+ }
+}
+
+
+/*
+ * This is called when a caller wishes to open a new Library context.
+ */
+LONG
+SCardEstablishContext(DWORD scope, LPCVOID unused0, LPCVOID unused1,
+ LPSCARDCONTEXT outp)
+{
+ pcsc_hdl_t *hdl;
+
+ if (outp == NULL) {
+ return (SCARD_E_INVALID_PARAMETER);
+ }
+
+ if (scope != SCARD_SCOPE_SYSTEM) {
+ return (SCARD_E_INVALID_VALUE);
+ }
+
+ hdl = calloc(1, sizeof (pcsc_hdl_t));
+ if (hdl == NULL) {
+ return (SCARD_E_NO_MEMORY);
+ }
+
+ hdl->pcsc_create_time = gethrtime();
+ *outp = hdl;
+ return (SCARD_S_SUCCESS);
+}
+
+/*
+ * This is called to free a library context from a client.
+ */
+LONG
+SCardReleaseContext(SCARDCONTEXT hdl)
+{
+ free(hdl);
+ return (SCARD_S_SUCCESS);
+}
+
+/*
+ * This is called to release memory allocated by the library. No, it doesn't
+ * make sense to take a const pointer when being given memory to free. It just
+ * means we have to cast it, but remember: this isn't our API.
+ */
+LONG
+SCardFreeMemory(SCARDCONTEXT unused, LPCVOID mem)
+{
+ free((void *)mem);
+ return (SCARD_S_SUCCESS);
+}
+
+/*
+ * This is called by a caller to get a list of readers that exist in the system.
+ * If lenp is set to SCARD_AUTOALLOCATE, then we are responsible for dealing
+ * with this memory.
+ */
+LONG
+SCardListReaders(SCARDCONTEXT unused, LPCSTR groups, LPSTR bufp, LPDWORD lenp)
+{
+ FTS *fts;
+ FTSENT *ent;
+ char *const root[] = { "/dev/ccid", NULL };
+ char *ubuf;
+ char **readers;
+ uint32_t len, ulen, npaths, nalloc, off, i;
+ int ret;
+
+ if (groups != NULL || lenp == NULL) {
+ return (SCARD_E_INVALID_PARAMETER);
+ }
+
+ fts = fts_open(root, FTS_LOGICAL | FTS_NOCHDIR, NULL);
+ if (fts == NULL) {
+ switch (errno) {
+ case ENOENT:
+ case ENOTDIR:
+ return (SCARD_E_NO_READERS_AVAILABLE);
+ case ENOMEM:
+ case EAGAIN:
+ return (SCARD_E_NO_MEMORY);
+ default:
+ return (SCARD_E_NO_SERVICE);
+ }
+ }
+
+ npaths = nalloc = 0;
+ /*
+ * Account for the NUL we'll have to place at the end of this.
+ */
+ len = 1;
+ readers = NULL;
+ while ((ent = fts_read(fts)) != NULL) {
+ size_t plen;
+
+ if (ent->fts_level != 2 || ent->fts_info == FTS_DP)
+ continue;
+
+ if (ent->fts_info == FTS_ERR || ent->fts_info == FTS_NS)
+ continue;
+
+ if (S_ISCHR(ent->fts_statp->st_mode) == 0)
+ continue;
+
+ plen = strlen(ent->fts_path) + 1;
+ if (UINT32_MAX - len <= plen) {
+ /*
+ * I mean, it's true. But I wish I could just give you
+ * EOVERFLOW.
+ */
+ ret = SCARD_E_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (npaths == nalloc) {
+ char **tmp;
+
+ nalloc += 8;
+ tmp = reallocarray(readers, nalloc, sizeof (char *));
+ if (tmp == NULL) {
+ ret = SCARD_E_NO_MEMORY;
+ goto out;
+ }
+ readers = tmp;
+ }
+ readers[npaths] = strdup(ent->fts_path);
+ npaths++;
+ len += plen;
+ }
+
+ if (npaths == 0) {
+ ret = SCARD_E_NO_READERS_AVAILABLE;
+ goto out;
+ }
+
+ ulen = *lenp;
+ *lenp = len;
+ if (ulen != SCARD_AUTOALLOCATE) {
+ if (bufp == NULL) {
+ ret = SCARD_S_SUCCESS;
+ goto out;
+ }
+
+ if (ulen < len) {
+ ret = SCARD_E_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ ubuf = bufp;
+ } else {
+ char **bufpp;
+ if (bufp == NULL) {
+ ret = SCARD_E_INVALID_PARAMETER;
+ goto out;
+ }
+
+ ubuf = malloc(ulen);
+ if (ubuf == NULL) {
+ ret = SCARD_E_NO_MEMORY;
+ goto out;
+ }
+
+ bufpp = (void *)bufp;
+ *bufpp = ubuf;
+ }
+ ret = SCARD_S_SUCCESS;
+
+ for (off = 0, i = 0; i < npaths; i++) {
+ size_t slen = strlen(readers[i]) + 1;
+ bcopy(readers[i], ubuf + off, slen);
+ off += slen;
+ VERIFY3U(off, <=, len);
+ }
+ VERIFY3U(off, ==, len - 1);
+ ubuf[off] = '\0';
+out:
+ for (i = 0; i < npaths; i++) {
+ free(readers[i]);
+ }
+ free(readers);
+ (void) fts_close(fts);
+ return (ret);
+}
+
+static LONG
+uccid_status_helper(int fd, DWORD prots, uccid_cmd_status_t *ucs)
+{
+ /*
+ * Get the status of this slot and find out information about the slot.
+ * We need to see if there's an ICC present and if it matches the
+ * current protocol. If not, then we have to fail this.
+ */
+ bzero(ucs, sizeof (uccid_cmd_status_t));
+ ucs->ucs_version = UCCID_CURRENT_VERSION;
+ if (ioctl(fd, UCCID_CMD_STATUS, ucs) != 0) {
+ return (SCARD_F_UNKNOWN_ERROR);
+ }
+
+ if ((ucs->ucs_status & UCCID_STATUS_F_CARD_PRESENT) == 0) {
+ return (SCARD_W_REMOVED_CARD);
+ }
+
+ if ((ucs->ucs_status & UCCID_STATUS_F_CARD_ACTIVE) == 0) {
+ return (SCARD_W_UNPOWERED_CARD);
+ }
+
+ if ((ucs->ucs_status & UCCID_STATUS_F_PARAMS_VALID) == 0) {
+ return (SCARD_W_UNSUPPORTED_CARD);
+ }
+
+ if ((ucs->ucs_prot & prots) == 0) {
+ return (SCARD_E_PROTO_MISMATCH);
+ }
+
+ return (0);
+}
+
+LONG
+SCardConnect(SCARDCONTEXT hdl, LPCSTR reader, DWORD mode, DWORD prots,
+ LPSCARDHANDLE iccp, LPDWORD protp)
+{
+ LONG ret;
+ uccid_cmd_status_t ucs;
+ pcsc_card_t *card;
+
+ if (reader == NULL) {
+ return (SCARD_E_UNKNOWN_READER);
+ }
+
+ if (iccp == NULL || protp == NULL) {
+ return (SCARD_E_INVALID_PARAMETER);
+ }
+
+ if (mode != SCARD_SHARE_SHARED) {
+ return (SCARD_E_INVALID_VALUE);
+ }
+
+ if ((prots & ~(SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1 |
+ SCARD_PROTOCOL_RAW | SCARD_PROTOCOL_T15)) != 0) {
+ return (SCARD_E_INVALID_VALUE);
+ }
+
+ if ((prots & (SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1)) == 0) {
+ return (SCARD_E_UNSUPPORTED_FEATURE);
+ }
+
+ if ((card = malloc(sizeof (*card))) == NULL) {
+ return (SCARD_E_NO_MEMORY);
+ }
+
+ if ((card->pcc_fd = open(reader, O_RDWR)) < 0) {
+ free(card);
+ switch (errno) {
+ case ENOENT:
+ return (SCARD_E_UNKNOWN_READER);
+ default:
+ return (SCARD_F_UNKNOWN_ERROR);
+ }
+ }
+
+ if ((ret = uccid_status_helper(card->pcc_fd, prots, &ucs)) != 0)
+ goto cleanup;
+
+ *protp = ucs.ucs_prot;
+ *iccp = card;
+ return (SCARD_S_SUCCESS);
+cleanup:
+ (void) close(card->pcc_fd);
+ free(card);
+ return (ret);
+}
+
+LONG
+SCardDisconnect(SCARDHANDLE arg, DWORD disposition)
+{
+ pcsc_card_t *card = arg;
+
+ if (arg == NULL) {
+ return (SCARD_E_INVALID_HANDLE);
+ }
+
+ if (disposition != SCARD_LEAVE_CARD) {
+ return (SCARD_E_INVALID_VALUE);
+ }
+
+ if (close(card->pcc_fd) != 0) {
+ return (SCARD_F_UNKNOWN_ERROR);
+ }
+
+ free(card);
+ return (SCARD_S_SUCCESS);
+}
+
+LONG
+SCardBeginTransaction(SCARDHANDLE arg)
+{
+ uccid_cmd_txn_begin_t txn;
+ pcsc_card_t *card = arg;
+
+ if (card == NULL) {
+ return (SCARD_E_INVALID_HANDLE);
+ }
+
+ /*
+ * The semantics of pcsc are that this operation does not block, but
+ * instead fails if we cannot grab it immediately.
+ */
+ bzero(&txn, sizeof (uccid_cmd_txn_begin_t));
+ txn.uct_version = UCCID_CURRENT_VERSION;
+ txn.uct_flags = UCCID_TXN_DONT_BLOCK;
+
+ if (ioctl(card->pcc_fd, UCCID_CMD_TXN_BEGIN, &txn) != 0) {
+ VERIFY3S(errno, !=, EFAULT);
+ switch (errno) {
+ case ENODEV:
+ return (SCARD_E_READER_UNAVAILABLE);
+ case EEXIST:
+ /*
+ * This is an odd case. It's used to tell us that we
+ * already have it. For now, just treat it as success.
+ */
+ return (SCARD_S_SUCCESS);
+ case EBUSY:
+ return (SCARD_E_SHARING_VIOLATION);
+ /*
+ * EINPROGRESS is a weird case. It means that we were trying to
+ * grab a hold while another instance using the same handle was.
+ * For now, treat it as an unknown error.
+ */
+ case EINPROGRESS:
+ case EINTR:
+ default:
+ return (SCARD_F_UNKNOWN_ERROR);
+ }
+ }
+ return (SCARD_S_SUCCESS);
+}
+
+LONG
+SCardEndTransaction(SCARDHANDLE arg, DWORD state)
+{
+ uccid_cmd_txn_end_t txn;
+ pcsc_card_t *card = arg;
+
+ if (card == NULL) {
+ return (SCARD_E_INVALID_HANDLE);
+ }
+
+ bzero(&txn, sizeof (uccid_cmd_txn_end_t));
+ txn.uct_version = UCCID_CURRENT_VERSION;
+
+ switch (state) {
+ case SCARD_LEAVE_CARD:
+ txn.uct_flags = UCCID_TXN_END_RELEASE;
+ break;
+ case SCARD_RESET_CARD:
+ txn.uct_flags = UCCID_TXN_END_RESET;
+ break;
+ case SCARD_UNPOWER_CARD:
+ case SCARD_EJECT_CARD:
+ default:
+ return (SCARD_E_INVALID_VALUE);
+ }
+
+ if (ioctl(card->pcc_fd, UCCID_CMD_TXN_END, &txn) != 0) {
+ VERIFY3S(errno, !=, EFAULT);
+ switch (errno) {
+ case ENODEV:
+ return (SCARD_E_READER_UNAVAILABLE);
+ case ENXIO:
+ return (SCARD_E_SHARING_VIOLATION);
+ default:
+ return (SCARD_F_UNKNOWN_ERROR);
+ }
+ }
+ return (SCARD_S_SUCCESS);
+}
+
+LONG
+SCardReconnect(SCARDHANDLE arg, DWORD mode, DWORD prots, DWORD init,
+ LPDWORD protp)
+{
+ uccid_cmd_status_t ucs;
+ pcsc_card_t *card = arg;
+ LONG ret;
+
+ if (card == NULL) {
+ return (SCARD_E_INVALID_HANDLE);
+ }
+
+ if (protp == NULL) {
+ return (SCARD_E_INVALID_PARAMETER);
+ }
+
+ if (mode != SCARD_SHARE_SHARED) {
+ return (SCARD_E_INVALID_VALUE);
+ }
+
+ if ((prots & ~(SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1 |
+ SCARD_PROTOCOL_RAW | SCARD_PROTOCOL_T15)) != 0) {
+ return (SCARD_E_INVALID_VALUE);
+ }
+
+ if ((prots & (SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1)) == 0) {
+ return (SCARD_E_UNSUPPORTED_FEATURE);
+ }
+
+ if (init != SCARD_LEAVE_CARD) {
+ return (SCARD_E_INVALID_VALUE);
+ }
+
+ if ((ret = uccid_status_helper(card->pcc_fd, prots, &ucs)) != 0)
+ return (ret);
+
+ *protp = ucs.ucs_prot;
+ return (SCARD_S_SUCCESS);
+}
+
+LONG
+SCardTransmit(SCARDHANDLE arg, const SCARD_IO_REQUEST *sendreq,
+ LPCBYTE sendbuf, DWORD sendlen, SCARD_IO_REQUEST *recvreq, LPBYTE recvbuf,
+ LPDWORD recvlenp)
+{
+ int len;
+ ssize_t ret;
+ pcsc_card_t *card = arg;
+
+ if (card == NULL) {
+ return (SCARD_E_INVALID_HANDLE);
+ }
+
+ /*
+ * Ignore sendreq / recvreq.
+ */
+ if (sendbuf == NULL || recvbuf == NULL || recvlenp == NULL) {
+ return (SCARD_E_INVALID_PARAMETER);
+ }
+
+ /*
+ * The CCID write will always consume all data or none.
+ */
+ ret = write(card->pcc_fd, sendbuf, sendlen);
+ if (ret == -1) {
+ switch (errno) {
+ case E2BIG:
+ return (SCARD_E_INVALID_PARAMETER);
+ case ENODEV:
+ return (SCARD_E_READER_UNAVAILABLE);
+ case EACCES:
+ case EBUSY:
+ return (SCARD_E_SHARING_VIOLATION);
+ case ENXIO:
+ return (SCARD_W_REMOVED_CARD);
+ case EFAULT:
+ return (SCARD_E_INVALID_PARAMETER);
+ case ENOMEM:
+ default:
+ return (SCARD_F_UNKNOWN_ERROR);
+ }
+ }
+ ASSERT3S(ret, ==, sendlen);
+
+ /*
+ * Now, we should be able to block in read.
+ */
+ ret = read(card->pcc_fd, recvbuf, *recvlenp);
+ if (ret == -1) {
+ switch (errno) {
+ case EINVAL:
+ case EOVERFLOW:
+ /*
+ * This means that we need to update len with the real
+ * one.
+ */
+ if (ioctl(card->pcc_fd, FIONREAD, &len) != 0) {
+ return (SCARD_F_UNKNOWN_ERROR);
+ }
+ *recvlenp = len;
+ return (SCARD_E_INSUFFICIENT_BUFFER);
+ case ENODEV:
+ return (SCARD_E_READER_UNAVAILABLE);
+ case EACCES:
+ case EBUSY:
+ return (SCARD_E_SHARING_VIOLATION);
+ case EFAULT:
+ return (SCARD_E_INVALID_PARAMETER);
+ case ENODATA:
+ default:
+ return (SCARD_F_UNKNOWN_ERROR);
+ }
+ }
+
+ *recvlenp = ret;
+
+ return (SCARD_S_SUCCESS);
+}
diff --git a/usr/src/lib/libpcsc/common/mapfile-vers b/usr/src/lib/libpcsc/common/mapfile-vers
new file mode 100644
index 0000000000..5a3786670a
--- /dev/null
+++ b/usr/src/lib/libpcsc/common/mapfile-vers
@@ -0,0 +1,50 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2019, Joyent, Inc.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION SUNWprivate {
+ global:
+ g_rgSCardRawPci;
+ g_rgSCardT0Pci;
+ g_rgSCardT1Pci;
+ SCardEstablishContext;
+ SCardReleaseContext;
+ SCardFreeMemory;
+ SCardListReaders;
+ SCardConnect;
+ SCardDisconnect;
+ SCardBeginTransaction;
+ SCardEndTransaction;
+ SCardReconnect;
+ SCardTransmit;
+ pcsc_stringify_error;
+ local:
+ *;
+};
diff --git a/usr/src/lib/libpcsc/common/winscard.h b/usr/src/lib/libpcsc/common/winscard.h
new file mode 100644
index 0000000000..bec4960040
--- /dev/null
+++ b/usr/src/lib/libpcsc/common/winscard.h
@@ -0,0 +1,144 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
+#ifndef _WINSCARD_H
+#define _WINSCARD_H
+
+/*
+ * This library provides a compatibility interface with programs designed
+ * against the PC SmartCard Library. This originates from Microsoft and has been
+ * used on a few different forms over the years by folks. The purpose of this
+ * library is for compatibility.
+ *
+ * At the time of this writing, Microsofts API documentation can be found here:
+ * https://docs.microsoft.com/en-us/windows/win32/api/winscard/
+ *
+ * New consumers should not use this library and instead should leverage
+ * ccid(7D) instead.
+ */
+
+#include <stdint.h>
+#include <wintypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This is a departure from the PCSC system which defines this as a LONG,
+ * which is the same size on 32bit and 64bit Windows (ILP32 and LLP64).
+ * We need to use the real native pointer size for the context handle as
+ * it wouldn't fit into a LONG on our LP64 platform.
+ */
+typedef void *SCARDCONTEXT;
+typedef void **PSCARDCONTEXT;
+typedef void **LPSCARDCONTEXT;
+typedef void *SCARDHANDLE;
+typedef void **PSCARDHANDLE;
+typedef void **LPSCARDHANDLE;
+
+/*
+ * Conventionally this is supposed to be packed.
+ */
+#pragma pack(1)
+typedef struct {
+ unsigned long dwProtocol;
+ unsigned long cbPciLength;
+} SCARD_IO_REQUEST, *PSCARD_IO_REQUEST, *LPSCARD_IO_REQUEST;
+#pragma pack()
+
+extern SCARD_IO_REQUEST g_rgSCardT0Pci, g_rgSCardT1Pci, g_rgSCardRawPci;
+#define SCARD_PCI_T0 (&g_rgSCardT0Pci)
+#define SCARD_PCI_T1 (&g_rgSCardT1Pci)
+#define SCARD_PCI_RAW (&g_rgSCardRawPci)
+
+/*
+ * Return values and error codes. We strive to use the same error codes as
+ * Microsoft.
+ */
+#define SCARD_S_SUCCESS ((LONG)0x00000000)
+#define SCARD_F_INTERNAL_ERROR ((LONG)0x80100001)
+#define SCARD_E_CANCELLED ((LONG)0x80100002)
+#define SCARD_E_INVALID_HANDLE ((LONG)0x80100003)
+#define SCARD_E_INVALID_PARAMETER ((LONG)0x80100004)
+#define SCARD_E_NO_MEMORY ((LONG)0x80100006)
+#define SCARD_E_INSUFFICIENT_BUFFER ((LONG)0x80100008)
+#define SCARD_E_UNKNOWN_READER ((LONG)0x80100009)
+#define SCARD_E_TIMEOUT ((LONG)0x8010000a)
+#define SCARD_E_SHARING_VIOLATION ((LONG)0x8010000b)
+#define SCARD_E_NO_SMARTCARD ((LONG)0x8010000c)
+#define SCARD_E_UNKNOWN_CARD ((LONG)0x8010000d)
+#define SCARD_E_PROTO_MISMATCH ((LONG)0x8010000f)
+#define SCARD_E_INVALID_VALUE ((LONG)0x80100011)
+#define SCARD_F_COMM_ERROR ((LONG)0x80100013)
+#define SCARD_F_UNKNOWN_ERROR ((LONG)0x80100014)
+#define SCARD_E_READER_UNAVAILABLE ((LONG)0x80100017)
+#define SCARD_E_NO_SERVICE ((LONG)0x8010001D)
+#define SCARD_E_UNSUPPORTED_FEATURE ((LONG)0x80100022)
+#define SCARD_E_NO_READERS_AVAILABLE ((LONG)0x8010002E)
+#define SCARD_W_UNSUPPORTED_CARD ((LONG)0x80100065)
+#define SCARD_W_UNPOWERED_CARD ((LONG)0x80100067)
+#define SCARD_W_RESET_CARD ((LONG)0x80100068)
+#define SCARD_W_REMOVED_CARD ((LONG)0x80100069)
+
+#define SCARD_SCOPE_USER 0x0000
+#define SCARD_SCOPE_TERMINAL 0x0001
+#define SCARD_SCOPE_SYSTEM 0x0002
+#define SCARD_SCOPE_GLOBAL 0x0003
+
+#define SCARD_SHARE_EXCLUSIVE 0x0001
+#define SCARD_SHARE_SHARED 0x0002
+#define SCARD_SHARE_DIRECT 0x0003
+
+#define SCARD_PROTOCOL_T0 0x0001
+#define SCARD_PROTOCOL_T1 0x0002
+#define SCARD_PROTOCOL_RAW 0x0004
+#define SCARD_PROTOCOL_T15 0x0008
+
+#define SCARD_LEAVE_CARD 0x0000
+#define SCARD_RESET_CARD 0x0001
+#define SCARD_UNPOWER_CARD 0x0002
+#define SCARD_EJECT_CARD 0x0003
+
+/*
+ * This is used to indicate that the framework should allocate memory.
+ */
+#define SCARD_AUTOALLOCATE UINT32_MAX
+
+extern LONG SCardEstablishContext(DWORD, LPCVOID, LPCVOID, LPSCARDCONTEXT);
+extern LONG SCardReleaseContext(SCARDCONTEXT);
+
+extern LONG SCardListReaders(SCARDCONTEXT, LPCSTR, LPSTR, LPDWORD);
+
+extern LONG SCardFreeMemory(SCARDCONTEXT, LPCVOID);
+
+extern LONG SCardConnect(SCARDCONTEXT, LPCSTR, DWORD, DWORD, LPSCARDHANDLE,
+ LPDWORD);
+extern LONG SCardDisconnect(SCARDHANDLE, DWORD);
+
+extern LONG SCardBeginTransaction(SCARDHANDLE);
+extern LONG SCardEndTransaction(SCARDHANDLE, DWORD);
+extern LONG SCardReconnect(SCARDHANDLE, DWORD, DWORD, DWORD, LPDWORD);
+
+extern LONG SCardTransmit(SCARDHANDLE, const SCARD_IO_REQUEST *, LPCBYTE,
+ DWORD, SCARD_IO_REQUEST *, LPBYTE, LPDWORD);
+
+extern const char *pcsc_stringify_error(const LONG);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _WINSCARD_H */
diff --git a/usr/src/lib/libpcsc/common/wintypes.h b/usr/src/lib/libpcsc/common/wintypes.h
new file mode 100644
index 0000000000..9bb50a87cc
--- /dev/null
+++ b/usr/src/lib/libpcsc/common/wintypes.h
@@ -0,0 +1,50 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2019, Joyent, Inc.
+ */
+
+#ifndef _WINTYPES_H
+#define _WINTYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * While we don't want to, this expects that we have Win32 style type names.
+ * Deal with conversions between Win32 and reality. Remember that Windows is an
+ * ILP32 system, but it is a LLP64 system.
+ */
+
+typedef uint8_t BYTE;
+typedef uint8_t *LPBYTE;
+typedef const uint8_t *LPCBYTE;
+typedef const void *LPCVOID;
+typedef uint32_t DWORD;
+typedef uint32_t *LPDWORD;
+typedef int32_t LONG;
+typedef char *LPSTR;
+typedef const char *LPCSTR;
+
+/*
+ * Include a few deprecated types because folks still use them.
+ */
+typedef char *LPTSTR;
+typedef const char *LPCTSTR;
+typedef char *LPCWSTR;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _WINTYPES_H */