summaryrefslogtreecommitdiff
path: root/usr/src/lib
diff options
context:
space:
mode:
authorHans Rosenfeld <hans.rosenfeld@joyent.com>2020-01-12 01:01:41 +0100
committerGitHub <noreply@github.com>2020-01-12 01:01:41 +0100
commitb44b91e41531b86f9807aecf62d96cad6f2f06cd (patch)
tree1fe4c2409126f74cddb013d220c824367d9dc788 /usr/src/lib
parent8b175886ef45935e972cf1df20218f2de66d49b1 (diff)
downloadillumos-joyent-b44b91e41531b86f9807aecf62d96cad6f2f06cd.tar.gz
OS-7196 Need native CCID driver
Contributed by: Robert Mustacchi <rm@joyent.com> Reviewed by: John Levon <john.levon@joyent.com> Approved by: Jason King <jbk@joyent.com>
Diffstat (limited to 'usr/src/lib')
-rw-r--r--usr/src/lib/Makefile2
-rw-r--r--usr/src/lib/cfgadm_plugins/Makefile5
-rw-r--r--usr/src/lib/cfgadm_plugins/ccid/Makefile67
-rw-r--r--usr/src/lib/cfgadm_plugins/ccid/Makefile.com67
-rw-r--r--usr/src/lib/cfgadm_plugins/ccid/amd64/Makefile21
-rw-r--r--usr/src/lib/cfgadm_plugins/ccid/common/cfga_ccid.c421
-rw-r--r--usr/src/lib/cfgadm_plugins/ccid/common/mapfile-vers42
-rw-r--r--usr/src/lib/cfgadm_plugins/ccid/i386/Makefile20
-rw-r--r--usr/src/lib/libcmdutils/common/nicenum.c14
-rw-r--r--usr/src/lib/libcmdutils/libcmdutils.h3
-rw-r--r--usr/src/lib/libpcsc/Makefile43
-rw-r--r--usr/src/lib/libpcsc/Makefile.com32
-rw-r--r--usr/src/lib/libpcsc/amd64/Makefile19
-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
-rw-r--r--usr/src/lib/libpcsc/i386/Makefile18
18 files changed, 1627 insertions, 6 deletions
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile
index cb326e5e45..1363c5cc1b 100644
--- a/usr/src/lib/Makefile
+++ b/usr/src/lib/Makefile
@@ -181,6 +181,7 @@ SUBDIRS += \
libofmt \
libpam \
libpcidb \
+ libpcsc \
libpctx \
libpicl \
libpicltree \
@@ -448,6 +449,7 @@ HDRSUBDIRS= \
libofmt \
libpam \
libpcidb \
+ libpcsc \
libpctx \
libpicl \
libpicltree \
diff --git a/usr/src/lib/cfgadm_plugins/Makefile b/usr/src/lib/cfgadm_plugins/Makefile
index 00d258b20a..8fa7f73df7 100644
--- a/usr/src/lib/cfgadm_plugins/Makefile
+++ b/usr/src/lib/cfgadm_plugins/Makefile
@@ -20,13 +20,14 @@
#
#
# Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2019 Joyent, Inc.
#
# lib/cfgadm_plugins/Makefile
#
include $(SRC)/Makefile.master
-COMMON_SUBDIRS= scsi pci usb ib fp shp sbd
+COMMON_SUBDIRS= scsi pci usb ib fp shp sbd ccid
sparc_SUBDIRS= ac sysctrl
i386_SUBDIRS= sata
@@ -37,7 +38,7 @@ ALL_SUBDIRS= $(COMMON_SUBDIRS) $(sparc_SUBDIRS) $(i386_SUBDIRS)
MSGSUBDIRS= $(ALL_SUBDIRS)
-all:= TARGET= all
+all:= TARGET= all
install:= TARGET= install
clean:= TARGET= clean
clobber:= TARGET= clobber
diff --git a/usr/src/lib/cfgadm_plugins/ccid/Makefile b/usr/src/lib/cfgadm_plugins/ccid/Makefile
new file mode 100644
index 0000000000..7d4af31c7d
--- /dev/null
+++ b/usr/src/lib/cfgadm_plugins/ccid/Makefile
@@ -0,0 +1,67 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2019, Joyent, Inc.
+#
+
+include ../../Makefile.lib
+
+$(INTEL_BLD)SUBDIRS = $(MACH) $(BUILD64) $(MACH64)
+
+all := TARGET= all
+clean := TARGET= clean
+clobber := TARGET= clobber
+delete := TARGET= delete
+install := TARGET= install
+_msg := TARGET= _msg
+package := TARGET= package
+
+SED= sed
+GREP= grep
+
+.KEEP_STATE:
+
+all clean delete install package: $(SUBDIRS)
+clobber: $(SUBDIRS)
+ $(RM) $(POFILE) $(POFILES)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+#
+# We don't build any gettext libraries here
+#
+_msg:
+
+$(POFILE): $(POFILES)
+ $(RM) $@
+ $(CAT) $(POFILES) > $@
+
+$(POFILES):
+ $(RM) messages.po
+ $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext */*.[ch]`
+ $(SED) -e '/^# msg/d' -e '/^domain/d' messages.po > $@
+ $(RM) messages.po
+
+FRC:
diff --git a/usr/src/lib/cfgadm_plugins/ccid/Makefile.com b/usr/src/lib/cfgadm_plugins/ccid/Makefile.com
new file mode 100644
index 0000000000..30a2ce1527
--- /dev/null
+++ b/usr/src/lib/cfgadm_plugins/ccid/Makefile.com
@@ -0,0 +1,67 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2019, Joyent, Inc.
+#
+
+LIBRARY= ccid.a
+VERS= .1
+
+OBJECTS= cfga_ccid.o
+
+# include library definitions
+include ../../../Makefile.lib
+
+SRCDIR = ../common
+ROOTLIBDIR= $(ROOT)/usr/lib/cfgadm
+ROOTLIBDIR64= $(ROOTLIBDIR)/$(MACH64)
+
+LIBS= $(DYNLIB)
+
+CFLAGS += $(CCVERBOSE)
+CFLAGS64 += $(CCVERBOSE)
+
+LDLIBS += -lc
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+# Install rules
+
+$(ROOTLIBDIR)/%: % $(ROOTLIBDIR)
+ $(INS.file)
+
+$(ROOTLIBDIR64)/%: % $(ROOTLIBDIR64)
+ $(INS.file)
+
+$(ROOTLIBDIR) $(ROOTLIBDIR64):
+ $(INS.dir)
+
+# include library targets
+include ../../../Makefile.targ
+
+objs/%.o pics/%.o: ../common/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
diff --git a/usr/src/lib/cfgadm_plugins/ccid/amd64/Makefile b/usr/src/lib/cfgadm_plugins/ccid/amd64/Makefile
new file mode 100644
index 0000000000..f2eb3c97a2
--- /dev/null
+++ b/usr/src/lib/cfgadm_plugins/ccid/amd64/Makefile
@@ -0,0 +1,21 @@
+#
+# 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 ../Makefile.com
+include ../../../Makefile.lib.64
+
+.KEEP_STATE:
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/cfgadm_plugins/ccid/common/cfga_ccid.c b/usr/src/lib/cfgadm_plugins/ccid/common/cfga_ccid.c
new file mode 100644
index 0000000000..4ce28c2aec
--- /dev/null
+++ b/usr/src/lib/cfgadm_plugins/ccid/common/cfga_ccid.c
@@ -0,0 +1,421 @@
+/*
+ * 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.
+ */
+
+/*
+ * CCID cfgadm plugin
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+
+#include <sys/usb/clients/ccid/uccid.h>
+
+#define CFGA_PLUGIN_LIB
+#include <config_admin.h>
+
+int cfga_version = CFGA_HSL_V2;
+
+static cfga_err_t
+cfga_ccid_error(cfga_err_t err, char **errp, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (errp == NULL)
+ return (err);
+
+ /*
+ * Try to format a string. However because we have to return allocated
+ * memory, if this fails, then we have no error.
+ */
+ va_start(ap, fmt);
+ (void) vasprintf(errp, fmt, ap);
+ va_end(ap);
+
+ return (err);
+}
+
+cfga_err_t
+cfga_ccid_modify(uccid_cmd_icc_modify_t *modify, const char *ap,
+ struct cfga_confirm *confp, struct cfga_msg *msgp, char **errp,
+ boolean_t force)
+{
+ int fd;
+ uccid_cmd_status_t ucs;
+ uccid_cmd_txn_begin_t begin;
+ boolean_t held = B_FALSE;
+
+ /*
+ * Check ap is valid by doing a status request.
+ */
+ if ((fd = open(ap, O_RDWR)) < 0) {
+ return (cfga_ccid_error(CFGA_LIB_ERROR, errp,
+ "failed to open %s: %s", ap, strerror(errno)));
+ }
+
+ bzero(&ucs, sizeof (ucs));
+ ucs.ucs_version = UCCID_CURRENT_VERSION;
+
+ if (ioctl(fd, UCCID_CMD_STATUS, &ucs) != 0) {
+ int e = errno;
+ if (errno == ENODEV) {
+ (void) close(fd);
+ return (cfga_ccid_error(CFGA_LIB_ERROR, errp,
+ "ap %s going away", ap));
+ }
+ (void) close(fd);
+ return (cfga_ccid_error(CFGA_ERROR, errp,
+ "ioctl on ap %s failed: %s", ap, strerror(e)));
+ }
+
+ /*
+ * Attempt to get a hold. If we cannot obtain a hold, we will not
+ * perform this unless the user has said we should force this.
+ */
+ bzero(&begin, sizeof (begin));
+ begin.uct_version = UCCID_CURRENT_VERSION;
+ begin.uct_flags = UCCID_TXN_DONT_BLOCK;
+ if (ioctl(fd, UCCID_CMD_TXN_BEGIN, &begin) != 0) {
+ if (errno != EBUSY) {
+ int e = errno;
+ (void) close(fd);
+ return (cfga_ccid_error(CFGA_ERROR, errp, "failed to "
+ "begin ccid transaction on ap %s: %s", ap,
+ strerror(e)));
+ }
+
+ /*
+ * If the user didn't force this operation, prompt if we would
+ * interfere.
+ */
+ if (!force) {
+ int confirm = 0;
+ const char *prompt = "CCID slot is held exclusively "
+ "by another program. Proceeding may interrupt "
+ "their functionality. Continue?";
+ if (confp != NULL && confp->appdata_ptr != NULL) {
+ confirm = (*confp->confirm)(confp->appdata_ptr,
+ prompt);
+ }
+
+ if (confirm == 0) {
+ (void) close(fd);
+ return (CFGA_NACK);
+ }
+ }
+ } else {
+ held = B_TRUE;
+ }
+
+ if (ioctl(fd, UCCID_CMD_ICC_MODIFY, modify) != 0) {
+ int e = errno;
+ (void) close(fd);
+ return (cfga_ccid_error(CFGA_ERROR, errp,
+ "failed to modify state on ap %s: %s", ap,
+ strerror(e)));
+ }
+
+ if (held) {
+ uccid_cmd_txn_end_t end;
+
+ bzero(&end, sizeof (end));
+ end.uct_version = UCCID_CURRENT_VERSION;
+ end.uct_flags = UCCID_TXN_END_RELEASE;
+
+ if (ioctl(fd, UCCID_CMD_TXN_END, &end) != 0) {
+ int e = errno;
+ (void) close(fd);
+ return (cfga_ccid_error(CFGA_ERROR, errp, "failed to "
+ "end transaction on ap %s: %s", ap,
+ strerror(e)));
+ }
+ }
+
+ (void) close(fd);
+ return (CFGA_OK);
+
+}
+
+cfga_err_t
+cfga_change_state(cfga_cmd_t cmd, const char *ap, const char *opts,
+ struct cfga_confirm *confp, struct cfga_msg *msgp, char **errp,
+ cfga_flags_t flags)
+{
+ uccid_cmd_icc_modify_t modify;
+
+ if (errp != NULL) {
+ *errp = NULL;
+ }
+
+ if (ap == NULL) {
+ return (cfga_ccid_error(CFGA_APID_NOEXIST, errp, NULL));
+ }
+
+ if (opts != NULL) {
+ return (cfga_ccid_error(CFGA_ERROR, errp,
+ "hardware specific options are not supported"));
+ }
+
+ bzero(&modify, sizeof (modify));
+ modify.uci_version = UCCID_CURRENT_VERSION;
+ switch (cmd) {
+ case CFGA_CMD_CONFIGURE:
+ modify.uci_action = UCCID_ICC_POWER_ON;
+ break;
+ case CFGA_CMD_UNCONFIGURE:
+ modify.uci_action = UCCID_ICC_POWER_OFF;
+ break;
+ default:
+ (void) cfga_help(msgp, opts, flags);
+ return (CFGA_OPNOTSUPP);
+ }
+
+ return (cfga_ccid_modify(&modify, ap, confp, msgp, errp,
+ (flags & CFGA_FLAG_FORCE) != 0));
+}
+
+cfga_err_t
+cfga_private_func(const char *function, const char *ap, const char *opts,
+ struct cfga_confirm *confp, struct cfga_msg *msgp, char **errp,
+ cfga_flags_t flags)
+{
+ uccid_cmd_icc_modify_t modify;
+
+ if (errp != NULL) {
+ *errp = NULL;
+ }
+
+ if (function == NULL) {
+ return (CFGA_ERROR);
+ }
+
+ if (ap == NULL) {
+ return (cfga_ccid_error(CFGA_APID_NOEXIST, errp, NULL));
+ }
+
+ if (opts != NULL) {
+ return (cfga_ccid_error(CFGA_ERROR, errp,
+ "hardware specific options are not supported"));
+ }
+
+ if (strcmp(function, "warm_reset") != 0) {
+ return (CFGA_OPNOTSUPP);
+ }
+
+ bzero(&modify, sizeof (modify));
+ modify.uci_version = UCCID_CURRENT_VERSION;
+ modify.uci_action = UCCID_ICC_WARM_RESET;
+
+ return (cfga_ccid_modify(&modify, ap, confp, msgp, errp,
+ (flags & CFGA_FLAG_FORCE) != 0));
+}
+
+/*
+ * We don't support the test entry point for CCID.
+ */
+cfga_err_t
+cfga_test(const char *ap, const char *opts, struct cfga_msg *msgp, char **errp,
+ cfga_flags_t flags)
+{
+ (void) cfga_help(msgp, opts, flags);
+ return (CFGA_OPNOTSUPP);
+}
+
+static void
+cfga_ccid_fill_info(const uccid_cmd_status_t *ucs, char *buf, size_t len)
+{
+ const char *product, *serial, *tran, *prot;
+ uint_t bits = CCID_CLASS_F_TPDU_XCHG | CCID_CLASS_F_SHORT_APDU_XCHG |
+ CCID_CLASS_F_EXT_APDU_XCHG;
+
+ if ((ucs->ucs_status & UCCID_STATUS_F_PRODUCT_VALID) != 0) {
+ product = ucs->ucs_product;
+ } else {
+ product = "<unknown>";
+ }
+
+ if ((ucs->ucs_status & UCCID_STATUS_F_SERIAL_VALID) != 0) {
+ serial = ucs->ucs_serial;
+ } else {
+ serial = "<unknown>";
+ }
+
+ switch (ucs->ucs_class.ccd_dwFeatures & bits) {
+ case 0:
+ tran = "Character";
+ break;
+ case CCID_CLASS_F_TPDU_XCHG:
+ tran = "TPDU";
+ break;
+ case CCID_CLASS_F_SHORT_APDU_XCHG:
+ case CCID_CLASS_F_EXT_APDU_XCHG:
+ tran = "APDU";
+ break;
+ default:
+ tran = "Unknown";
+ break;
+ }
+
+ if ((ucs->ucs_status & UCCID_STATUS_F_PARAMS_VALID) != 0) {
+ switch (ucs->ucs_prot) {
+ case UCCID_PROT_T0:
+ prot = " (T=0)";
+ break;
+ case UCCID_PROT_T1:
+ prot = " (T=1)";
+ break;
+ default:
+ prot = "<unknown>";
+ break;
+ }
+ } else {
+ prot = "<unknown>";
+ }
+
+ if ((ucs->ucs_status & UCCID_STATUS_F_CARD_ACTIVE) != 0) {
+ (void) snprintf(buf, len, "Product: %s Serial: %s "
+ "Transport: %s Protocol: %s", product, serial,
+ tran, prot);
+ } else {
+ (void) snprintf(buf, len, "Product: %s Serial: %s ",
+ product, serial);
+ }
+}
+
+cfga_err_t
+cfga_list_ext(const char *ap, struct cfga_list_data **ap_list, int *nlist,
+ const char *opts, const char *listopts, char **errp, cfga_flags_t flags)
+{
+ int fd;
+ uccid_cmd_status_t ucs;
+ struct cfga_list_data *cld;
+
+ if (errp != NULL) {
+ *errp = NULL;
+ }
+
+ if (ap == NULL) {
+ return (cfga_ccid_error(CFGA_APID_NOEXIST, errp, NULL));
+ }
+
+ if (opts != NULL) {
+ return (cfga_ccid_error(CFGA_ERROR, errp,
+ "hardware specific options are not supported"));
+ }
+
+ if ((fd = open(ap, O_RDWR)) < 0) {
+ return (cfga_ccid_error(CFGA_LIB_ERROR, errp,
+ "failed to open %s: %s", ap, strerror(errno)));
+ }
+
+ bzero(&ucs, sizeof (ucs));
+ ucs.ucs_version = UCCID_CURRENT_VERSION;
+
+ if (ioctl(fd, UCCID_CMD_STATUS, &ucs) != 0) {
+ int e = errno;
+ (void) close(fd);
+ if (e == ENODEV) {
+ return (cfga_ccid_error(CFGA_LIB_ERROR, errp,
+ "ap %s going away", ap));
+ }
+ return (cfga_ccid_error(CFGA_ERROR, errp,
+ "ioctl on ap %s failed: %s", ap, strerror(e)));
+ }
+ (void) close(fd);
+
+ if ((cld = calloc(1, sizeof (*cld))) == NULL) {
+ return (cfga_ccid_error(CFGA_LIB_ERROR, errp, "failed to "
+ "allocate memory for list entry"));
+ }
+
+ if (snprintf(cld->ap_log_id, sizeof (cld->ap_log_id), "ccid%d/slot%u",
+ ucs.ucs_instance, ucs.ucs_slot) >= sizeof (cld->ap_log_id)) {
+ free(cld);
+ return (cfga_ccid_error(CFGA_LIB_ERROR, errp, "ap %s logical id"
+ " was too large", ap));
+ }
+
+ if (strlcpy(cld->ap_phys_id, ap, sizeof (cld->ap_phys_id)) >=
+ sizeof (cld->ap_phys_id)) {
+ free(cld);
+ return (cfga_ccid_error(CFGA_LIB_ERROR, errp,
+ "ap %s physical id was too long", ap));
+ }
+
+ cld->ap_class[0] = '\0';
+
+ if ((ucs.ucs_status & UCCID_STATUS_F_CARD_PRESENT) != 0) {
+ cld->ap_r_state = CFGA_STAT_CONNECTED;
+ if ((ucs.ucs_status & UCCID_STATUS_F_CARD_ACTIVE) != 0) {
+ cld->ap_o_state = CFGA_STAT_CONFIGURED;
+ } else {
+ cld->ap_o_state = CFGA_STAT_UNCONFIGURED;
+ }
+ } else {
+ cld->ap_r_state = CFGA_STAT_EMPTY;
+ cld->ap_o_state = CFGA_STAT_UNCONFIGURED;
+ }
+
+ /*
+ * XXX We should probably have a way to indicate that there's an error
+ * when the ICC is basically foobar'd. We should also allow the status
+ * ioctl to know that the slot is resetting or something else is going
+ * on I guess.
+ */
+ if ((ucs.ucs_class.ccd_dwFeatures &
+ (CCID_CLASS_F_SHORT_APDU_XCHG | CCID_CLASS_F_EXT_APDU_XCHG)) == 0) {
+ cld->ap_cond = CFGA_COND_UNUSABLE;
+ } else {
+ cld->ap_cond = CFGA_COND_OK;
+ }
+ cld->ap_busy = 0;
+ cld->ap_status_time = (time_t)-1;
+ cfga_ccid_fill_info(&ucs, cld->ap_info, sizeof (cld->ap_info));
+ if (strlcpy(cld->ap_type, "icc", sizeof (cld->ap_type)) >=
+ sizeof (cld->ap_type)) {
+ free(cld);
+ return (cfga_ccid_error(CFGA_LIB_ERROR, errp,
+ "ap %s type overflowed ICC field", ap));
+ }
+
+ *ap_list = cld;
+ *nlist = 1;
+ return (CFGA_OK);
+}
+
+cfga_err_t
+cfga_help(struct cfga_msg *msgp, const char *opts, cfga_flags_t flags)
+{
+ (void) (*msgp->message_routine)(msgp, "CCID specific commands:\n");
+ (void) (*msgp->message_routine)(msgp,
+ " cfgadm -c [configure|unconfigure] ap_id [ap_id...]\n");
+ (void) (*msgp->message_routine)(msgp,
+ " cfgadm -x warm_reset ap_id [ap_id...]\n");
+
+ return (CFGA_OK);
+}
+
+int
+cfga_ap_id_cmp(const cfga_ap_log_id_t ap_id1, const cfga_ap_log_id_t ap_id2)
+{
+ return (strcmp(ap_id1, ap_id2));
+}
diff --git a/usr/src/lib/cfgadm_plugins/ccid/common/mapfile-vers b/usr/src/lib/cfgadm_plugins/ccid/common/mapfile-vers
new file mode 100644
index 0000000000..7c7f7d2c0e
--- /dev/null
+++ b/usr/src/lib/cfgadm_plugins/ccid/common/mapfile-vers
@@ -0,0 +1,42 @@
+#
+# 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_1.1 {
+ global:
+ cfga_change_state;
+ cfga_help;
+ cfga_list_ext;
+ cfga_private_func;
+ cfga_test;
+ cfga_version;
+ local:
+ *;
+};
diff --git a/usr/src/lib/cfgadm_plugins/ccid/i386/Makefile b/usr/src/lib/cfgadm_plugins/ccid/i386/Makefile
new file mode 100644
index 0000000000..66d7a51776
--- /dev/null
+++ b/usr/src/lib/cfgadm_plugins/ccid/i386/Makefile
@@ -0,0 +1,20 @@
+#
+# 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 ../Makefile.com
+
+.KEEP_STATE:
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
diff --git a/usr/src/lib/libcmdutils/common/nicenum.c b/usr/src/lib/libcmdutils/common/nicenum.c
index 8e3202f792..9b9a8fcd5e 100644
--- a/usr/src/lib/libcmdutils/common/nicenum.c
+++ b/usr/src/lib/libcmdutils/common/nicenum.c
@@ -22,6 +22,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2017 Jason king
+ * Copyright 2019, Joyent, Inc.
*/
#include <stdio.h>
@@ -44,8 +45,15 @@ nicenum_scale(uint64_t n, size_t units, char *buf, size_t buflen,
uint64_t divisor = 1;
int index = 0;
int rc = 0;
+ int spclen = 0;
+ char *spc = "";
char u;
+ if (flags & NN_UNIT_SPACE) {
+ spc = " ";
+ spclen = 1;
+ }
+
if (units == 0)
units = 1;
@@ -90,7 +98,7 @@ nicenum_scale(uint64_t n, size_t units, char *buf, size_t buflen,
* If this is an even multiple of the base, always display
* without any decimal precision.
*/
- rc = snprintf(buf, buflen, "%llu%c", n / divisor, u);
+ rc = snprintf(buf, buflen, "%llu%s%c", n / divisor, spc, u);
} else {
/*
* We want to choose a precision that reflects the best choice
@@ -104,8 +112,8 @@ nicenum_scale(uint64_t n, size_t units, char *buf, size_t buflen,
*/
int i;
for (i = 2; i >= 0; i--) {
- if ((rc = snprintf(buf, buflen, "%.*f%c", i,
- (double)n / divisor, u)) <= 5)
+ if ((rc = snprintf(buf, buflen, "%.*f%s%c", i,
+ (double)n / divisor, spc, u)) <= 5 + spclen)
break;
}
}
diff --git a/usr/src/lib/libcmdutils/libcmdutils.h b/usr/src/lib/libcmdutils/libcmdutils.h
index c9a61aab4d..54c025c9d9 100644
--- a/usr/src/lib/libcmdutils/libcmdutils.h
+++ b/usr/src/lib/libcmdutils/libcmdutils.h
@@ -26,7 +26,7 @@
* Copyright (c) 2013 RackTop Systems.
*/
/*
- * Copyright 2018 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
/*
@@ -163,6 +163,7 @@ extern int findnextuid(uid_t, uid_t, uid_t *);
extern int findnextgid(gid_t, gid_t, gid_t *);
#define NN_DIVISOR_1000 (1U << 0)
+#define NN_UNIT_SPACE (1U << 1)
/* Minimum size for the output of nicenum, including NULL */
#define NN_NUMBUF_SZ (6)
diff --git a/usr/src/lib/libpcsc/Makefile b/usr/src/lib/libpcsc/Makefile
new file mode 100644
index 0000000000..b5fdecb2e4
--- /dev/null
+++ b/usr/src/lib/libpcsc/Makefile
@@ -0,0 +1,43 @@
+#
+# 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 ../Makefile.lib
+
+HDRS = wintypes.h winscard.h
+HDRDIR = common
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+
+.KEEP_STATE:
+
+all clean clobber: $(SUBDIRS)
+
+install: $(SUBDIRS) install_h
+
+install_h: $(ROOTHDRS)
+
+check: $(CHECKHDRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../Makefile.targ
diff --git a/usr/src/lib/libpcsc/Makefile.com b/usr/src/lib/libpcsc/Makefile.com
new file mode 100644
index 0000000000..7bc91ef667
--- /dev/null
+++ b/usr/src/lib/libpcsc/Makefile.com
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+
+LIBRARY = libpcsc.a
+VERS = .1
+OBJECTS = libpcsc.o
+
+include ../../Makefile.lib
+
+LIBS = $(DYNLIB)
+LDLIBS += -lc
+CPPFLAGS += -I../common
+
+SRCDIR = ../common
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/libpcsc/amd64/Makefile b/usr/src/lib/libpcsc/amd64/Makefile
new file mode 100644
index 0000000000..a32567f965
--- /dev/null
+++ b/usr/src/lib/libpcsc/amd64/Makefile
@@ -0,0 +1,19 @@
+#
+# 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 ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
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 */
diff --git a/usr/src/lib/libpcsc/i386/Makefile b/usr/src/lib/libpcsc/i386/Makefile
new file mode 100644
index 0000000000..e4bd71f624
--- /dev/null
+++ b/usr/src/lib/libpcsc/i386/Makefile
@@ -0,0 +1,18 @@
+#
+# 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 ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS)