diff --git a/ccid/src/Makefile.am b/ccid/src/Makefile.am
index 4177d15..cc9d74e 100644
--- a/ccid/src/Makefile.am
+++ b/ccid/src/Makefile.am
@@ -1,15 +1,35 @@
-EXTRA_DIST = $(shell find $(top_srcdir)/src/opensc -path '*/.svn' -prune -o -type f -a -name '*.h' -print)
-EXTRA_DIST += $(shell find -L $(top_srcdir)/src/opensc-npa -path '*/.git' -prune -o -type f -a -name '*.h' -print)
+do_subst = sed \
+ -e 's,[@]PACKAGE[@],$(PACKAGE),g' \
+ -e 's,[@]PACKAGE_NAME[@],$(PACKAGE_NAME),g' \
+ -e 's,[@]PACKAGE_TARNAME[@],$(PACKAGE_TARNAME),g' \
+ -e 's,[@]PACKAGE_BUGREPORT[@],$(PACKAGE_BUGREPORT),g' \
+ -e 's,[@]PACKAGE_URL[@],$(PACKAGE_URL),g' \
+ -e 's,[@]PACKAGE_VERSION[@],$(PACKAGE_VERSION),g'
-ccid_emulator_SOURCES = ccid.c usbstring.c usb.c binutil.c sslutil.c
+BUILT_SOURCES = cmdline.h cmdline.c
+
+EXTRA_DIST = ccid-emulator.ggo ccid-emulator.ggo.in
+EXTRA_DIST += $(shell find $(top_srcdir)/src/opensc -path '*/.svn' -prune -o -type f -a -name '*.h' -print)
+EXTRA_DIST += $(shell find -L $(top_srcdir)/src/opensc-npa -path '*/.git' -prune -o -type f -a -name '*.h' -print)
+DISTCLEANFILES = $(BUILT_SOURCES) ccid-emulator.ggo
+
+ccid_emulator_SOURCES = ccid.c usbstring.c usb.c sslutil.c $(BUILT_SOURCES)
ccid_emulator_LDADD = $(OPENSSL_LIBS) $(PTHREAD_LIBS)
ccid_emulator_CFLAGS = $(OPENSSL_CFLAGS) $(PTHREAD_CFLAGS)
+ccid-emulator.c: $(BUILT_SOURCES)
+
+$(BUILT_SOURCES): ccid-emulator.ggo
+ gengetopt --output-dir=$(srcdir) < $<
+
+ccid-emulator.ggo: ccid-emulator.ggo.in
+ $(do_subst) < $< > $(srcdir)/$@
+
+
bin_PROGRAMS =
noinst_HEADERS = \
- binutil.h \
pcscutil.h \
scutil.h \
ccid.h \
diff --git a/ccid/src/binutil.c b/ccid/src/binutil.c
deleted file mode 100644
index 87879f7..0000000
--- a/ccid/src/binutil.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2010 Frank Morgner
- *
- * This file is part of ccid.
- *
- * ccid is free software: you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later
- * version.
- *
- * ccid is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * ccid. If not, see .
- */
-#include "binutil.h"
-#include
-#include
-
-void print_usage(const char *app_name, const struct option options[],
- const char *option_help[])
-{
- int i = 0;
- printf("Usage: %s [OPTIONS]\nOptions:\n", app_name);
-
- while (options[i].name) {
- /* Flawfinder: ignore */
- char buf[40], tmp[5];
- const char *arg_str;
-
- /* Skip "hidden" options */
- if (option_help[i] == NULL) {
- i++;
- continue;
- }
-
- if (options[i].val > 0 && options[i].val < 128)
- /* Flawfinder: ignore */
- sprintf(tmp, "-%c", options[i].val);
- else
- tmp[0] = 0;
- switch (options[i].has_arg) {
- case 1:
- arg_str = " ";
- break;
- case 2:
- arg_str = " [arg]";
- break;
- default:
- arg_str = "";
- break;
- }
- snprintf(buf, sizeof buf, "--%-13s%s%s", options[i].name, tmp, arg_str);
- if (strlen(buf) > 24) {
- printf(" %s\n", buf);
- buf[0] = '\0';
- }
- printf(" %-24s %s\n", buf, option_help[i]);
- i++;
- }
-}
-
-void parse_error(const char *app_name, const struct option options[],
- const char *option_help[], const char *optarg, int opt_ind)
-{
- printf("Could not parse %s ('%s').\n", options[opt_ind].name, optarg);
- print_usage(app_name , options, option_help);
-}
diff --git a/ccid/src/binutil.h b/ccid/src/binutil.h
deleted file mode 100644
index 6314dc3..0000000
--- a/ccid/src/binutil.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2010 Frank Morgner
- *
- * This file is part of ccid.
- *
- * ccid is free software: you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later
- * version.
- *
- * ccid is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * ccid. If not, see .
- */
-#ifndef _CCID_BINUTIL_H
-#define _CCID_BINUTIL_H
-
-#include
-
-void print_usage(const char *app_name, const struct option options[],
- const char *option_help[]);
-void parse_error(const char *app_name, const struct option options[],
- const char *option_help[], const char *optarg, int opt_ind);
-
-#endif
diff --git a/ccid/src/ccid-emulator.ggo.in b/ccid/src/ccid-emulator.ggo.in
new file mode 100644
index 0000000..78dddef
--- /dev/null
+++ b/ccid/src/ccid-emulator.ggo.in
@@ -0,0 +1,51 @@
+package "npa-tool"
+purpose "Access the German electronic identity card (neuer Personalausweis, nPA)"
+
+option "info" i
+ "Print available readers and drivers."
+ flag off
+option "reader" r
+ "Number of the PC/SC reader to use (-1 for autodetect)"
+ int
+ default="-1"
+ optional
+option "gadgetfs" -
+ "Directory where GadgetFS is mounted"
+ string
+ typestr="FILENAME"
+ default="/dev/gadget"
+ optional
+option "verbose" v
+ "Use (several times) to be more verbose"
+ multiple
+ optional
+
+section "Changing the appearance on the Universal Serial Bus"
+option "product" p
+ "USB product ID"
+ int
+ default="0x3010"
+ optional
+option "vendor" e
+ "USB vendor ID"
+ int
+ default="0x0D46"
+ optional
+option "serial" -
+ "USB serial number"
+ string
+ default="random"
+ optional
+option "interface" -
+ "USB serial number"
+ string
+ default="notification status"
+ optional
+option "interrupt" -
+ "Add interrupt pipe for CCID"
+ flag off
+
+text "
+Report bugs to @PACKAGE_BUGREPORT@
+
+Written by Frank Morgner "
diff --git a/ccid/src/usb.c b/ccid/src/usb.c
index 25cb3aa..8d186b6 100644
--- a/ccid/src/usb.c
+++ b/ccid/src/usb.c
@@ -1,20 +1,20 @@
/*
- * Copyright (C) 2009 Frank Morgner
+ * Copyright (C) 2009-2012 Frank Morgner
*
- * This file is part of ccid.
+ * This file is part of ccid-emulator.
*
- * ccid is free software: you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later
- * version.
+ * ccid-emulator is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
*
- * ccid is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
+ * ccid-emulator is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
*
* You should have received a copy of the GNU General Public License along with
- * ccid. If not, see .
+ * ccid-emulator. If not, see .
*/
#include
#include
@@ -37,17 +37,16 @@
#include
//#include
//
-#include
#ifdef AIO
/* this aio code works with libaio-0.3.106 */
#include
#endif
+#include "ccid.h"
+#include "cmdline.h"
#include "config.h"
#include "usbstring.h"
-#include "ccid.h"
-#include "binutil.h"
#define DRIVER_VENDOR_NUM 0x0D46 /* KOBIL Systems */
#define DRIVER_PRODUCT_NUM 0x3010 /* KOBIL Class 3 Reader */
@@ -55,57 +54,10 @@ static int vendorid = DRIVER_VENDOR_NUM;
static int productid = DRIVER_PRODUCT_NUM;
static int verbose = 0;
static int debug = 0;
-static int dohid = 0;
static int doint = 0;
-static int doinfo = 0;
-static const char *doserial = NULL;
static const char *doiintf = NULL;
-static int usb_reader_num = -1;
-static const char *cdriver = NULL;
static const char *gadgetfs = "/dev/gadget";
-#define OPT_HELP 'h'
-#define OPT_INTERRUPT 'n'
-#define OPT_READER 'r'
-#define OPT_SERIAL 's'
-#define OPT_IINTERFACE 'i'
-#define OPT_PRODUCT 'p'
-#define OPT_VENDOR 'e'
-#define OPT_VERBOSE 'v'
-#define OPT_INFO 'o'
-#define OPT_CARD 'c'
-#define OPT_GADGETFS 'g'
-
-static const struct option options[] = {
- /*{ "hid", no_argument, &dohid, 1 },*/
- { "help", no_argument, NULL, OPT_HELP },
- { "reader", required_argument, NULL, OPT_READER },
- { "card-driver", required_argument, NULL, OPT_CARD },
- { "serial", required_argument, NULL, OPT_SERIAL },
- { "interface", required_argument, NULL, OPT_IINTERFACE },
- { "product", required_argument, NULL, OPT_PRODUCT },
- { "vendor", required_argument, NULL, OPT_VENDOR },
- { "interrupt", no_argument, NULL, OPT_INTERRUPT },
- { "verbose", no_argument, NULL, OPT_VERBOSE },
- { "info", no_argument, NULL, OPT_INFO },
- { "gadgetfs", required_argument, NULL, OPT_GADGETFS },
- { NULL, 0, NULL, 0 }
-};
-static const char *option_help[] = {
- /*"Emulate HID device",*/
- "Print help and exit",
- "Number of reader (default: auto-detect)",
- "Card driver to use (default: auto-detect)",
- "USB serial number (default: random)",
- "USB iInterface (default: notification status)",
- "USB product ID (default: 0x3010)",
- "USB vendor ID (default: 0x0D46)",
- "Add interrupt pipe for CCID",
- "Use (several times) to be more verbose",
- "Print version, available readers and drivers",
- "Directory where GadgetFS is mounted",
-};
-
/* NOTE: these IDs don't imply endpoint numbering; host side drivers
* should use endpoint descriptors, or perhaps bcdDevice, to configure
* such things. Other product IDs could have different policies.
@@ -122,7 +74,6 @@ extern struct ccid_class_descriptor ccid_desc;
#define STRINGID_SERIAL 3
#define STRINGID_CONFIG 4
#define STRINGID_INTERFACE 5
-#define STRINGID_HID_INTERFACE 6
static struct usb_device_descriptor
device_desc = {
@@ -172,14 +123,6 @@ source_sink_intf = {
.bInterfaceProtocol = 0,
.iInterface = STRINGID_INTERFACE,
};
-static struct hid_class_descriptor
-hid_desc = {
- .bLength = sizeof hid_desc,
- .bDescriptorType = 0x21,
- .bcdHID = __constant_cpu_to_le16(0x101),
- .bCountryCode = 0,
- .bNumDescriptors = 0,
-};
/* Full speed configurations are used for full-speed only devices as
* well as dual-speed ones (the only kind with high speed support).
@@ -222,16 +165,6 @@ fs_status_desc = {
.bInterval = (1 << LOG2_STATUS_POLL_MSEC),
};
-static struct usb_endpoint_descriptor
-fs_hid_status_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
-
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = __constant_cpu_to_le16 (STATUS_MAXPACKET),
- .bInterval = (1 << LOG2_STATUS_POLL_MSEC),
-};
-
static const struct usb_endpoint_descriptor *fs_eps [3] = {
&fs_source_desc,
&fs_sink_desc,
@@ -273,16 +206,6 @@ hs_status_desc = {
.bInterval = LOG2_STATUS_POLL_MSEC + 3,
};
-static struct usb_endpoint_descriptor
-hs_hid_status_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
-
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = __constant_cpu_to_le16 (STATUS_MAXPACKET),
- .bInterval = LOG2_STATUS_POLL_MSEC + 3,
-};
-
static const struct usb_endpoint_descriptor *hs_eps [] = {
&hs_source_desc,
&hs_sink_desc,
@@ -308,7 +231,6 @@ static struct usb_string stringtab [] = {
{ STRINGID_CONFIG, "PACE support disabled", },
#endif
{ STRINGID_INTERFACE, interrupt_on_string, },
- { STRINGID_HID_INTERFACE, "Human Device Interface Gadget", },
};
static struct usb_gadget_strings strings = {
@@ -324,7 +246,7 @@ static struct usb_gadget_strings strings = {
static int HIGHSPEED;
static char *DEVNAME;
-static char *EP_IN_NAME, *EP_OUT_NAME, *EP_STATUS_NAME, *EP_HID_STATUS_NAME;
+static char *EP_IN_NAME, *EP_OUT_NAME, *EP_STATUS_NAME;
/* gadgetfs currently has no chunking (or O_DIRECT/zerocopy) support
* to turn big requests into lots of smaller ones; so this is "small".
@@ -362,14 +284,6 @@ static int autoconfig ()
= USB_DIR_IN | 11;
EP_STATUS_NAME = "ep-f";
- if (dohid) {
- // TODO EP_HID_STATUS_NAME?
- EP_HID_STATUS_NAME = "ep-e";
- fs_hid_status_desc.bEndpointAddress
- = hs_hid_status_desc.bEndpointAddress
- = USB_DIR_IN | 10;
- }
-
/* Intel PXA 2xx processor, full speed only */
} else if (stat (DEVNAME = "pxa2xx_udc", &statb) == 0) {
HIGHSPEED = 0;
@@ -387,10 +301,6 @@ static int autoconfig ()
fs_status_desc.bEndpointAddress = USB_DIR_IN | 11;
EP_STATUS_NAME = "ep11in-bulk";
- if (dohid) {
- EP_HID_STATUS_NAME = "ep12in-bulk";
- fs_hid_status_desc.bEndpointAddress = USB_DIR_IN | 12;
- }
#if 0
/* AMD au1x00 processor, full speed only */
} else if (stat (DEVNAME = "au1x00_udc", &statb) == 0) {
@@ -431,19 +341,10 @@ static int autoconfig ()
fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 1;
EP_OUT_NAME = "ep1-bulk";
- if (dohid) {
- source_sink_intf.bNumEndpoints = 2;
- // USB Wake up signaling not supported
- ccid_desc.dwFeatures &= ~__constant_cpu_to_le32(0x100000);
+ source_sink_intf.bNumEndpoints = 3;
- EP_HID_STATUS_NAME = "ep3-bulk";
- fs_hid_status_desc.bEndpointAddress = USB_DIR_IN | 3;
- } else {
- source_sink_intf.bNumEndpoints = 3;
-
- EP_STATUS_NAME = "ep3-bulk";
- fs_status_desc.bEndpointAddress = USB_DIR_IN | 3;
- }
+ EP_STATUS_NAME = "ep3-bulk";
+ fs_status_desc.bEndpointAddress = USB_DIR_IN | 3;
/* Samsung S3C24xx series, full speed only */
} else if (stat (DEVNAME = "s3c2410_udc", &statb) == 0) {
@@ -459,11 +360,6 @@ static int autoconfig ()
fs_status_desc.bEndpointAddress = USB_DIR_IN | 3;
EP_STATUS_NAME = "ep3-bulk";
- if (dohid) {
- EP_HID_STATUS_NAME = "ep4-bulk";
- fs_hid_status_desc.bEndpointAddress = USB_DIR_IN | 4;
- }
-
/* Renesas SH77xx processors, full speed only */
} else if (stat (DEVNAME = "sh_udc", &statb) == 0) {
HIGHSPEED = 0;
@@ -478,11 +374,6 @@ static int autoconfig ()
fs_status_desc.bEndpointAddress = USB_DIR_IN | 3;
EP_STATUS_NAME = "ep3in-bulk";
- if (dohid) {
- EP_HID_STATUS_NAME = "ep4in-bulk";
- fs_hid_status_desc.bEndpointAddress = USB_DIR_IN | 4;
- }
-
/* OMAP 1610 and newer devices, full speed only, fifo mode 0 or 3 */
} else if (stat (DEVNAME = "omap_udc", &statb) == 0) {
HIGHSPEED = 0;
@@ -497,11 +388,6 @@ static int autoconfig ()
fs_status_desc.bEndpointAddress = USB_DIR_IN | 3;
EP_STATUS_NAME = "ep3in-int";
- if (dohid) {
- EP_HID_STATUS_NAME = "ep4in-bulk";
- fs_hid_status_desc.bEndpointAddress = USB_DIR_IN | 4;
- }
-
/* Something based on Mentor USB Highspeed Dual-Role Controller */
} else if (stat (DEVNAME = "musb_hdrc", &statb) == 0) {
HIGHSPEED = 1;
@@ -535,11 +421,6 @@ static int autoconfig ()
fs_status_desc.bEndpointAddress = USB_DIR_IN | 3;
EP_STATUS_NAME = "ep3-int";
- if (dohid) {
- EP_HID_STATUS_NAME = "ep4";
- fs_hid_status_desc.bEndpointAddress = USB_DIR_IN | 4;
- }
-
/* Sharp LH740x processors, full speed only */
} else if (stat (DEVNAME = "lh740x_udc", &statb) == 0) {
HIGHSPEED = 0;
@@ -550,19 +431,10 @@ static int autoconfig ()
fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 2;
EP_OUT_NAME = "ep2out-bulk";
- if (dohid) {
- source_sink_intf.bNumEndpoints = 2;
- // USB Wake up signaling not supported
- ccid_desc.dwFeatures &= ~__constant_cpu_to_le32(0x100000);
+ source_sink_intf.bNumEndpoints = 3;
- fs_hid_status_desc.bEndpointAddress = USB_DIR_IN | 3;
- EP_HID_STATUS_NAME = "ep3in-int";
- } else {
- source_sink_intf.bNumEndpoints = 3;
-
- fs_status_desc.bEndpointAddress = USB_DIR_IN | 3;
- EP_STATUS_NAME = "ep3in-int";
- }
+ fs_status_desc.bEndpointAddress = USB_DIR_IN | 3;
+ EP_STATUS_NAME = "ep3in-int";
/* Atmel AT32AP700x processors, high/full speed */
} else if (stat (DEVNAME = "atmel_usba_udc", &statb) == 0) {
@@ -578,23 +450,12 @@ static int autoconfig ()
= USB_DIR_OUT | 2;
EP_OUT_NAME = "ep2out-bulk";
- if (dohid) {
- source_sink_intf.bNumEndpoints = 2;
- // USB Wake up signaling not supported
- ccid_desc.dwFeatures &= ~__constant_cpu_to_le32(0x100000);
+ source_sink_intf.bNumEndpoints = 3;
- fs_hid_status_desc.bEndpointAddress
- = hs_hid_status_desc.bEndpointAddress
- = USB_DIR_IN | 3;
- EP_HID_STATUS_NAME = "ep3in-int";
- } else {
- source_sink_intf.bNumEndpoints = 3;
-
- fs_status_desc.bEndpointAddress
- = hs_status_desc.bEndpointAddress
- = USB_DIR_IN | 3;
- EP_STATUS_NAME = "ep3in-int";
- }
+ fs_status_desc.bEndpointAddress
+ = hs_status_desc.bEndpointAddress
+ = USB_DIR_IN | 3;
+ EP_STATUS_NAME = "ep3in-int";
} else {
DEVNAME = 0;
@@ -874,12 +735,10 @@ static int iso_autoconfig ()
static pthread_t ep0;
static pthread_t ccid_thread;
-static pthread_t hidthread;
static pthread_t interrupt_thread;
static int source_fd = -1;
static int sink_fd = -1;
static int status_fd = -1;
-static int hidstatus_fd = -1;
// FIXME no result i/o yet
@@ -966,8 +825,6 @@ ep_config (char *name, const char *label,
ep_config(name,__FUNCTION__, &fs_sink_desc, &hs_sink_desc)
#define status_open(name) \
ep_config(name,__FUNCTION__, &fs_status_desc, &hs_status_desc)
-#define hidstatus_open(name) \
- ep_config(name,__FUNCTION__, &fs_hid_status_desc, &hs_hid_status_desc)
static void *interrupt (void *param)
{
@@ -1087,59 +944,6 @@ error:
pthread_exit(0);
}
-static void *hid (void *param)
-{
- char **names = (char **) param;
- char *status_name = names[0];
- int result = 0;
-
- hidstatus_fd = hidstatus_open (status_name);
- if (hidstatus_fd < 0) {
- if (verbose > 1)
- perror("hidstatus_fd");
- goto error;
- }
- pthread_cleanup_push (close_fd, &hidstatus_fd);
-
- __u8 *outbuf = NULL;
- pthread_cleanup_push (free, outbuf);
- size_t bufsize = 512;
- __u8 *inbuf = malloc(bufsize);
- pthread_cleanup_push (free, inbuf);
- if (inbuf == NULL) {
- if (verbose > 1)
- perror("malloc");
- goto error;
- }
-
- do {
-
- /* original LinuxThreads cancelation didn't work right
- * so test for it explicitly.
- */
- pthread_testcancel ();
-
- } while (result >= 0);
-
- if (errno != ESHUTDOWN || result < 0) {
- perror ("hid loop aborted");
- pthread_cancel(ep0);
- }
-
- pthread_cleanup_pop (1);
- pthread_cleanup_pop (1);
- pthread_cleanup_pop (1);
-
- fflush (stdout);
- fflush (stderr);
-
- return 0;
-
-error:
- pthread_cancel(ep0);
- pthread_exit(0);
-}
-
static void start_io (void)
{
//int tmp;
@@ -1187,19 +991,6 @@ static void start_io (void)
perror ("can't create ccid thread");
goto cleanup;
}
- static char * hidnames[1];
- hidnames[0] = EP_HID_STATUS_NAME;
- if (dohid) {
- config.bNumInterfaces = 2;
- if (pthread_create (&hidthread, NULL, hid, (void *)
- hidnames) != 0) {
- perror ("can't create hid thread");
- goto cleanup;
- }
- } else {
- if (verbose)
- fprintf (stderr, "HID disabled.\n");
- }
if (doint) {
static char * interruptnames[1];
interruptnames[0] = EP_STATUS_NAME;
@@ -1236,13 +1027,6 @@ static void stop_io ()
ccid_thread = ep0;
fprintf (stderr, "cancled ccid\n");
}
- if (!pthread_equal (hidthread, ep0)) {
- pthread_cancel (hidthread);
- if (pthread_join (hidthread, 0) != 0)
- perror ("can't join hid thread");
- hidthread = ep0;
- fprintf (stderr, "cancled hid\n");
- }
if (!pthread_equal (interrupt_thread, ep0)) {
pthread_cancel (interrupt_thread);
if (pthread_join (interrupt_thread, 0) != 0)
@@ -1255,7 +1039,7 @@ static void stop_io ()
/*-------------------------------------------------------------------------*/
static char *
-build_config (char *cp, const struct usb_endpoint_descriptor **ep, const struct usb_endpoint_descriptor *hid_ep)
+build_config (char *cp, const struct usb_endpoint_descriptor **ep)
{
struct usb_config_descriptor *c;
int i;
@@ -1277,28 +1061,6 @@ build_config (char *cp, const struct usb_endpoint_descriptor **ep, const struct
cp += USB_DT_ENDPOINT_SIZE;
}
- if (dohid) {
- struct usb_interface_descriptor hid_intf = {
- .bLength = sizeof hid_intf,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 1,
-
- .bInterfaceClass = USB_CLASS_HID,
- .iInterface = STRINGID_HID_INTERFACE,
- .bNumEndpoints = 1,
- };
- memcpy (cp, &hid_intf, sizeof hid_intf);
- cp += sizeof hid_intf;
- // Append vendor class specification
- memcpy (cp, &hid_desc, sizeof hid_desc);
- cp += sizeof hid_desc;
-
- for (i = 0; i < hid_intf.bNumEndpoints; i++) {
- memcpy (cp, &(hid_ep [i]), USB_DT_ENDPOINT_SIZE);
- cp += USB_DT_ENDPOINT_SIZE;
- }
- }
-
c->wTotalLength = __cpu_to_le16 (cp - (char *) c);
return cp;
}
@@ -1331,9 +1093,9 @@ static int init_device (void)
cp += 4;
/* write full then high speed configs */
- cp = build_config (cp, fs_eps, &fs_hid_status_desc);
+ cp = build_config (cp, fs_eps);
if (HIGHSPEED)
- cp = build_config (cp, hs_eps, &hs_hid_status_desc);
+ cp = build_config (cp, hs_eps);
device_desc.idVendor = __cpu_to_le16 (vendorid);
device_desc.idProduct = __cpu_to_le16 (productid);
@@ -1432,7 +1194,7 @@ static void handle_control (int fd, struct usb_ctrlrequest *setup)
*/
switch (value) {
case CONFIG_VALUE:
- if ( source_fd >= 0 || sink_fd >= 0 || status_fd >= 0 || hidstatus_fd >= 0 )
+ if ( source_fd >= 0 || sink_fd >= 0 || status_fd >= 0)
stop_io ();
start_io ();
break;
@@ -1495,12 +1257,6 @@ static void handle_control (int fd, struct usb_ctrlrequest *setup)
perror ("reset status fd");
}
}
- if (hidstatus_fd > 0) {
- if (ioctl (hidstatus_fd, GADGETFS_CLEAR_HALT) < 0) {
- result = errno;
- perror ("reset hidstatus fd");
- }
- }
/* FIXME eventually reset the result endpoint too */
if (result)
goto stall;
@@ -1606,7 +1362,7 @@ static void *ep0_thread (void *param)
time_t now, last;
struct pollfd ep0_poll;
- interrupt_thread = ccid_thread = hidthread = ep0 = pthread_self ();
+ interrupt_thread = ccid_thread = ep0 = pthread_self ();
pthread_cleanup_push (stop_io, NULL);
pthread_cleanup_push (close_fd, param);
@@ -1734,85 +1490,24 @@ main (int argc, char **argv)
int fd, c, i;
int oindex = 0;
- while (1) {
- c = getopt_long(argc, argv, "hnr:s:i:p:e:voc:g:", options, &oindex);
- if (c == -1)
- break;
- switch (c) {
- case OPT_HELP:
- print_usage(argv[0] , options, option_help);
- exit(0);
- break;
- case OPT_READER:
- errno = 0;
- usb_reader_num = strtol(optarg, NULL, 10);
- if (errno) {
- parse_error(argv[0], options, option_help, optarg, oindex);
- exit(2);
- }
- break;
- case OPT_SERIAL:
- doserial = optarg;
- break;
- case OPT_IINTERFACE:
- doiintf = optarg;
- break;
- case OPT_PRODUCT:
- errno = 0;
- productid = strtol(optarg, NULL, 16);
- if (errno) {
- parse_error(argv[0], options, option_help, optarg, oindex);
- exit(2);
- }
- break;
- case OPT_VENDOR:
- errno = 0;
- vendorid = strtol(optarg, NULL, 16);
- if (errno) {
- parse_error(argv[0], options, option_help, optarg, oindex);
- exit(2);
- }
- break;
- case OPT_CARD:
- cdriver = optarg;
- break;
- case OPT_VERBOSE:
- verbose++;
- break;
- case OPT_INFO:
- doinfo++;
- break;
- case OPT_INTERRUPT:
- doint++;
- break;
- case OPT_GADGETFS:
- gadgetfs = optarg;
- break;
- case '?':
- /* fall through */
- default:
- exit(1);
- break;
- }
- }
+ struct gengetopt_args_info cmdline;
- if (optind < argc) {
- fprintf (stderr, "Unknown argument%s:", optind+1 == argc ? "" : "s");
- while (optind < argc) {
- fprintf(stderr, " \"%s\"", argv[optind++]);
- fprintf(stderr, "%c", optind == argc ? '\n' : ',');
- }
+
+ /* Parse command line */
+ if (cmdline_parser (argc, argv, &cmdline) != 0)
exit(1);
- }
+ doiintf = cmdline.interface_arg;
+ productid = cmdline.product_arg;
+ vendorid = cmdline.vendor_arg;
+ verbose = cmdline.verbose_given;
+ doint = cmdline.interrupt_flag;
+ gadgetfs = cmdline.gadgetfs_arg;
- if (doinfo) {
- fprintf(stderr, "%s %s written by Frank Morgner.\n\n" ,
- argv[0], VERSION);
+ if (cmdline.info_flag)
return print_avail(verbose);
- }
- if (ccid_initialize(usb_reader_num, cdriver, verbose) < 0) {
+ if (ccid_initialize(cmdline.reader_arg, NULL, verbose) < 0) {
fprintf (stderr, "Can't initialize ccid\n");
return 1;
}
@@ -1822,14 +1517,7 @@ main (int argc, char **argv)
return 1;
}
- if (doserial) {
- for (i=0; i $(srcdir)/$@
+
+
bin_PROGRAMS = npa-tool
noinst_PROGRAMS = example
lib_LTLIBRARIES = libnpa.la
noinst_HEADERS = \
- sslutil.h \
- binutil.h
+ sslutil.h
nobase_include_HEADERS = \
npa/sm.h \
diff --git a/npa/src/binutil.c b/npa/src/binutil.c
deleted file mode 120000
index 302cf29..0000000
--- a/npa/src/binutil.c
+++ /dev/null
@@ -1 +0,0 @@
-../../ccid/src/binutil.c
\ No newline at end of file
diff --git a/npa/src/binutil.h b/npa/src/binutil.h
deleted file mode 120000
index b865ace..0000000
--- a/npa/src/binutil.h
+++ /dev/null
@@ -1 +0,0 @@
-../../ccid/src/binutil.h
\ No newline at end of file
diff --git a/npa/src/npa-tool.c b/npa/src/npa-tool.c
index 7aca2b4..6ee1e3c 100644
--- a/npa/src/npa-tool.c
+++ b/npa/src/npa-tool.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Frank Morgner
+ * Copyright (C) 2010-2012 Frank Morgner
*
* This file is part of npa.
*
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU General Public License along with
* npa. If not, see .
*/
-#include "binutil.h"
+#include "cmdline.h"
#include "config.h"
#include
#include
@@ -46,90 +46,18 @@ static ssize_t getline(char **lineptr, size_t *n, FILE *stream)
}
#endif
-static int verbose = 0;
-static int doinfo = 0;
-static u8 dobreak = 0;
-static u8 dochangepin = 0;
-static u8 doresumepin = 0;
-static u8 dounblock = 0;
-static u8 dotranslate = 0;
static const char *newpin = NULL;
-static int usb_reader_num = -1;
static const char *pin = NULL;
-static u8 usepin = 0;
static const char *puk = NULL;
-static u8 usepuk = 0;
static const char *can = NULL;
-static u8 usecan = 0;
static const char *mrz = NULL;
-static u8 usemrz = 0;
static u8 chat[0xff];
static u8 desc[0xffff];
-static const char *cdriver = NULL;
-static char *file = NULL;
static sc_context_t *ctx = NULL;
static sc_card_t *card = NULL;
static sc_reader_t *reader;
-#define OPT_HELP 'h'
-#define OPT_READER 'r'
-#define OPT_PIN 'i'
-#define OPT_PUK 'u'
-#define OPT_CAN 'a'
-#define OPT_MRZ 'z'
-#define OPT_BREAK 'b'
-#define OPT_CHAT 'C'
-#define OPT_CERTDESC 'D'
-#define OPT_CHANGE_PIN 'N'
-#define OPT_RESUME_PIN 'R'
-#define OPT_UNBLOCK_PIN 'U'
-#define OPT_TRANSLATE 't'
-#define OPT_VERBOSE 'v'
-#define OPT_INFO 'o'
-#define OPT_CARD 'c'
-#define OPT_TRVERSION 'n'
-
-static const struct option options[] = {
- { "help", no_argument, NULL, OPT_HELP },
- { "reader", required_argument, NULL, OPT_READER },
- { "card-driver", required_argument, NULL, OPT_CARD },
- { "pin", optional_argument, NULL, OPT_PIN },
- { "puk", optional_argument, NULL, OPT_PUK },
- { "can", optional_argument, NULL, OPT_CAN },
- { "mrz", optional_argument, NULL, OPT_MRZ },
- { "break", no_argument, NULL, OPT_BREAK },
- { "chat", required_argument, NULL, OPT_CHAT },
- { "cert-desc", required_argument, NULL, OPT_CERTDESC },
- { "new-pin", optional_argument, NULL, OPT_CHANGE_PIN },
- { "resume-pin", no_argument, NULL, OPT_RESUME_PIN },
- { "unblock-pin", no_argument, NULL, OPT_UNBLOCK_PIN },
- { "translate", optional_argument, NULL, OPT_TRANSLATE },
- { "tr-03110v20", required_argument, NULL, OPT_TRVERSION },
- { "verbose", no_argument, NULL, OPT_VERBOSE },
- { "info", no_argument, NULL, OPT_INFO },
- { NULL, 0, NULL, 0 }
-};
-static const char *option_help[] = {
- "Print help and exit",
- "Number of reader to use (default: auto-detect)",
- "Which card driver to use (default: auto-detect)",
- "Run PACE with (transport) PIN",
- "Run PACE with PUK",
- "Run PACE with CAN",
- "Run PACE with MRZ (insert MRZ without newlines)",
- "Brute force the secret (only for PIN, CAN, PUK)",
- "Card holder authorization template to use (hex string)",
- "Certificate description to use (hex string)",
- "Install a new PIN",
- "Resume PIN (uses CAN to activate last retry)",
- "Unblock PIN (uses PUK to activate three more retries)",
- "APDUs to send through SM channel (default: stdin)",
- "Version of TR-03110 (default: 2, for v2.02 and later)",
- "Use (several times) to be more verbose",
- "Print version, available readers and drivers.",
-};
-
int npa_translate_apdus(struct sm_ctx *sctx, sc_card_t *card, FILE *input)
{
u8 buf[4 + 3 + 0xffff + 3];
@@ -206,129 +134,57 @@ main (int argc, char **argv)
struct timeval tv;
size_t outlen;
+ struct gengetopt_args_info cmdline;
+
memset(&sctx, 0, sizeof sctx);
memset(&tmpctx, 0, sizeof tmpctx);
memset(&pace_input, 0, sizeof pace_input);
memset(&pace_output, 0, sizeof pace_output);
- while (1) {
- r = getopt_long(argc, argv, "hr:i::u::a::z::bC:D:N::RUt::voc:n:", options, &oindex);
- if (r == -1)
- break;
- switch (r) {
- case OPT_HELP:
- print_usage(argv[0] , options, option_help);
- exit(0);
- break;
- case OPT_READER:
- if (sscanf(optarg, "%d", &usb_reader_num) != 1) {
- parse_error(argv[0], options, option_help, optarg, oindex);
- exit(2);
- }
- break;
- case OPT_CARD:
- cdriver = optarg;
- break;
- case OPT_VERBOSE:
- verbose++;
- break;
- case OPT_INFO:
- doinfo = 1;
- break;
- case OPT_PUK:
- usepuk = 1;
- puk = optarg;
- if (!puk)
- pin = getenv("PUK");
- break;
- case OPT_PIN:
- usepin = 1;
- pin = optarg;
- if (!pin)
- pin = getenv("PIN");
- break;
- case OPT_CAN:
- usecan = 1;
- can = optarg;
- if (!can)
- can = getenv("CAN");
- break;
- case OPT_MRZ:
- usemrz = 1;
- mrz = optarg;
- if (!mrz)
- can = getenv("MRZ");
- break;
- case OPT_BREAK:
- dobreak = 1;
- break;
- case OPT_CHAT:
- pace_input.chat = chat;
- pace_input.chat_length = sizeof chat;
- if (sc_hex_to_bin(optarg, (u8 *) pace_input.chat,
- &pace_input.chat_length) < 0) {
- parse_error(argv[0], options, option_help, optarg, oindex);
- exit(2);
- }
- break;
- case OPT_CERTDESC:
- pace_input.certificate_description = desc;
- pace_input.certificate_description_length = sizeof desc;
- if (sc_hex_to_bin(optarg, (u8 *) pace_input.certificate_description,
- &pace_input.certificate_description_length) < 0) {
- parse_error(argv[0], options, option_help, optarg, oindex);
- exit(2);
- }
- break;
- case OPT_CHANGE_PIN:
- dochangepin = 1;
- newpin = optarg;
- if (!newpin)
- pin = getenv("NEWPIN");
- break;
- case OPT_RESUME_PIN:
- doresumepin = 1;
- break;
- case OPT_UNBLOCK_PIN:
- dounblock = 1;
- break;
- case OPT_TRANSLATE:
- dotranslate = 1;
- if (optarg) {
- file = optarg;
- }
- break;
- case OPT_TRVERSION:
- if (sscanf(optarg, "%d", (int *) &tr_version) != 1) {
- parse_error(argv[0], options, option_help, optarg, oindex);
- exit(2);
- }
- break;
- case '?':
- /* fall through */
- default:
- exit(1);
- break;
- }
- }
- if (optind < argc) {
- fprintf (stderr, "Unknown argument%s:", optind+1 == argc ? "" : "s");
- while (optind < argc) {
- fprintf(stderr, " \"%s\"", argv[optind++]);
- fprintf(stderr, "%c", optind == argc ? '\n' : ',');
- }
+ /* Parse command line */
+ if (cmdline_parser (argc, argv, &cmdline) != 0)
exit(1);
+ if (cmdline.env_flag) {
+ can = getenv("CAN");
+ mrz = getenv("MRZ");
+ pin = getenv("PIN");
+ puk = getenv("PUK");
+ newpin = getenv("NEWPIN");
}
-
-
- if (doinfo) {
- fprintf(stderr, "%s %s written by Frank Morgner.\n\n" ,
- argv[0], VERSION);
- return print_avail(verbose);
+ can = cmdline.can_arg;
+ mrz = cmdline.mrz_arg;
+ pin = cmdline.pin_arg;
+ puk = cmdline.puk_arg;
+ newpin = cmdline.new_pin_arg;
+ if (cmdline.chat_given) {
+ pace_input.chat = chat;
+ pace_input.chat_length = sizeof chat;
+ if (sc_hex_to_bin(cmdline.chat_arg, (u8 *) pace_input.chat,
+ &pace_input.chat_length) < 0) {
+ fprintf(stderr, "Could not parse CHAT.\n");
+ exit(2);
+ }
}
+ if (cmdline.cert_desc_given) {
+ pace_input.certificate_description = desc;
+ pace_input.certificate_description_length = sizeof desc;
+ if (sc_hex_to_bin(cmdline.cert_desc_arg,
+ (u8 *) pace_input.certificate_description,
+ &pace_input.certificate_description_length) < 0) {
+ fprintf(stderr, "Could not parse certificate description.\n");
+ exit(2);
+ }
+ }
+ if (cmdline.tr_03110v201_flag)
+ tr_version = EAC_TR_VERSION_2_01;
- r = initialize(usb_reader_num, cdriver, verbose, &ctx, &reader);
+
+ if (cmdline.info_flag)
+ return print_avail(cmdline.verbose_given);
+
+
+ r = initialize(cmdline.reader_arg, NULL, cmdline.verbose_given, &ctx, &reader);
if (r < 0) {
fprintf(stderr, "Can't initialize reader\n");
exit(1);
@@ -340,13 +196,13 @@ main (int argc, char **argv)
exit(1);
}
- if (dobreak) {
+ if (cmdline.break_flag) {
/* The biggest buffer sprintf could write with "%llu" */
char secretbuf[strlen("18446744073709551615")+1];
unsigned long long secret = 0;
unsigned long long maxsecret = 0;
- if (usepin) {
+ if (cmdline.pin_given) {
pace_input.pin_id = PACE_PIN;
pace_input.pin_length = 6;
maxsecret = 999999;
@@ -363,7 +219,7 @@ main (int argc, char **argv)
exit(2);
}
}
- } else if (usecan) {
+ } else if (cmdline.can_given) {
pace_input.pin_id = PACE_CAN;
pace_input.pin_length = 6;
maxsecret = 999999;
@@ -380,7 +236,7 @@ main (int argc, char **argv)
exit(2);
}
}
- } else if (usepuk) {
+ } else if (cmdline.puk_given) {
pace_input.pin_id = PACE_PUK;
pace_input.pin_length = 10;
maxsecret = 9999999999LLU;
@@ -433,7 +289,7 @@ main (int argc, char **argv)
}
}
- if (doresumepin) {
+ if (cmdline.resume_flag) {
pace_input.pin_id = PACE_CAN;
if (can) {
pace_input.pin = can;
@@ -463,7 +319,7 @@ main (int argc, char **argv)
printf("Established PACE channel with PIN. PIN resumed.\n");
}
- if (dounblock) {
+ if (cmdline.unblock_flag) {
pace_input.pin_id = PACE_PUK;
if (puk) {
pace_input.pin = puk;
@@ -484,7 +340,7 @@ main (int argc, char **argv)
printf("Unblocked PIN.\n");
}
- if (dochangepin) {
+ if (cmdline.new_pin_given) {
pace_input.pin_id = PACE_PIN;
if (pin) {
pace_input.pin = pin;
@@ -505,28 +361,30 @@ main (int argc, char **argv)
printf("Changed PIN.\n");
}
- if (dotranslate || (!doresumepin && !dochangepin && !dounblock && !dobreak)) {
+ if (cmdline.translate_given
+ || (!cmdline.resume_flag && !cmdline.new_pin_given
+ && !cmdline.unblock_flag && !cmdline.break_given)) {
pace_input.pin = NULL;
pace_input.pin_length = 0;
- if (usepin) {
+ if (cmdline.pin_given) {
pace_input.pin_id = PACE_PIN;
if (pin) {
pace_input.pin = pin;
pace_input.pin_length = strlen(pin);
}
- } else if (usecan) {
+ } else if (cmdline.can_given) {
pace_input.pin_id = PACE_CAN;
if (can) {
pace_input.pin = can;
pace_input.pin_length = strlen(can);
}
- } else if (usemrz) {
+ } else if (cmdline.mrz_given) {
pace_input.pin_id = PACE_MRZ;
if (mrz) {
pace_input.pin = mrz;
pace_input.pin_length = strlen(mrz);
}
- } else if (usepuk) {
+ } else if (cmdline.puk_given) {
pace_input.pin_id = PACE_PUK;
if (puk) {
pace_input.pin = puk;
@@ -543,14 +401,14 @@ main (int argc, char **argv)
if (r < 0)
goto err;
printf("Established PACE channel with %s.\n",
- npa_secret_name(pace_input.pin_id), file);
+ npa_secret_name(pace_input.pin_id), cmdline.translate_arg);
- if (dotranslate) {
+ if (cmdline.translate_given) {
FILE *input;
- if (!file || strncmp(file, "stdin", strlen("stdin")) == 0)
+ if (strncmp(cmdline.translate_arg, "stdin", strlen("stdin")) == 0)
input = stdin;
else {
- input = fopen(file, "r");
+ input = fopen(cmdline.translate_arg, "r");
if (!input) {
perror("Opening file with APDUs");
goto err;
diff --git a/npa/src/npa-tool.ggo.in b/npa/src/npa-tool.ggo.in
new file mode 100644
index 0000000..ce2665a
--- /dev/null
+++ b/npa/src/npa-tool.ggo.in
@@ -0,0 +1,81 @@
+package "npa-tool"
+purpose "Access the German electronic identity card (neuer Personalausweis, nPA)"
+
+option "info" i
+ "Print available readers and drivers."
+ flag off
+option "reader" r
+ "Number of the PC/SC reader to use (-1 for autodetect)"
+ int
+ default="-1"
+ optional
+option "verbose" v
+ "Use (several times) to be more verbose"
+ multiple
+ optional
+option "env" -
+ "Whether to use environment variables PIN, PUK, CAN, MRZ and NEWPIN. You may want to clean your environment before enabling this."
+ flag off
+
+section "Secrets for establishing the secure PACE channel to the card"
+option "pin" p
+ "Run PACE with (transport) eID-PIN"
+ string
+ argoptional
+ optional
+option "puk" u
+ "Run PACE with PUK"
+ string
+ argoptional
+ optional
+option "can" c
+ "Run PACE with CAN"
+ string
+ argoptional
+ optional
+option "mrz" m
+ "Run PACE with MRZ (insert MRZ without newlines)"
+ string
+ argoptional
+ optional
+
+section "PIN management"
+option "new-pin" N
+ "Install a new PIN"
+ string
+ optional
+option "resume" R
+ "Resume eID-PIN (uses CAN to activate last retry)"
+ flag off
+option "unblock" U
+ "Unblock PIN (uses PUK to activate three more retries)"
+ flag off
+
+section "Special options, not always useful"
+option "break" b
+ "Brute force PIN, CAN or PUK"
+ flag off
+option "chat" -
+ "Card holder authorization template to use"
+ string
+ typestr="HEX_STRING"
+ optional
+option "cert-desc" -
+ "Certificate description to use for Terminal Authentication"
+ string
+ typestr="HEX_STRING"
+ optional
+option "translate" t
+ "File with APDUs to send through the secure channel"
+ string
+ typestr="FILENAME"
+ default="stdin"
+ optional
+option "tr-03110v201" -
+ "Force compliance to BSI TR-03110 version 2.01"
+ flag off
+
+text "
+Report bugs to @PACKAGE_BUGREPORT@
+
+Written by Frank Morgner "
diff --git a/pcsc-relay/src/Makefile.am b/pcsc-relay/src/Makefile.am
index 52eafd3..a9f66b0 100644
--- a/pcsc-relay/src/Makefile.am
+++ b/pcsc-relay/src/Makefile.am
@@ -1,10 +1,29 @@
-EXTRA_DIST = picc.py
+do_subst = sed \
+ -e 's,[@]PACKAGE[@],$(PACKAGE),g' \
+ -e 's,[@]PACKAGE_NAME[@],$(PACKAGE_NAME),g' \
+ -e 's,[@]PACKAGE_TARNAME[@],$(PACKAGE_TARNAME),g' \
+ -e 's,[@]PACKAGE_BUGREPORT[@],$(PACKAGE_BUGREPORT),g' \
+ -e 's,[@]PACKAGE_URL[@],$(PACKAGE_URL),g' \
+ -e 's,[@]PACKAGE_VERSION[@],$(PACKAGE_VERSION),g'
+
+BUILT_SOURCES = cmdline.h cmdline.c
+
+EXTRA_DIST = pcsc-relay.ggo pcsc-relay.ggo.in
+EXTRA_DIST += picc.py
bin_PROGRAMS = pcsc-relay
bin_SCRIPTS = picc.py
-pcsc_relay_SOURCES = pcsc-relay.c pcscutil.c opicc.c lnfc.c binutil.c
+pcsc_relay_SOURCES = pcsc-relay.c pcscutil.c opicc.c lnfc.c $(BUILT_SOURCES)
pcsc_relay_LDADD = $(PCSC_LIBS) $(LIBNFC_LIBS)
pcsc_relay_CFLAGS = $(PCSC_CFLAGS) $(LIBNFC_CFLAGS)
-noinst_HEADERS = pcscutil.h pcsc-relay.h binutil.h
+noinst_HEADERS = pcscutil.h pcsc-relay.h
+
+pcsc-relay.c: $(BUILT_SOURCES)
+
+$(BUILT_SOURCES): pcsc-relay.ggo
+ gengetopt --output-dir=$(srcdir) < $<
+
+pcsc-relay.ggo: pcsc-relay.ggo.in
+ $(do_subst) < $< > $(srcdir)/$@
diff --git a/pcsc-relay/src/binutil.c b/pcsc-relay/src/binutil.c
deleted file mode 120000
index 302cf29..0000000
--- a/pcsc-relay/src/binutil.c
+++ /dev/null
@@ -1 +0,0 @@
-../../ccid/src/binutil.c
\ No newline at end of file
diff --git a/pcsc-relay/src/binutil.h b/pcsc-relay/src/binutil.h
deleted file mode 120000
index b865ace..0000000
--- a/pcsc-relay/src/binutil.h
+++ /dev/null
@@ -1 +0,0 @@
-../../ccid/src/binutil.h
\ No newline at end of file
diff --git a/pcsc-relay/src/pcsc-relay.c b/pcsc-relay/src/pcsc-relay.c
index 8f7ff95..75073be 100644
--- a/pcsc-relay/src/pcsc-relay.c
+++ b/pcsc-relay/src/pcsc-relay.c
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2010 Dominik Oepen, Frank Morgner
+ * Copyright (C) 2009 by Dominik Oepen .
+ * Copyright (C) 2010-2012 by Frank Morgner .
*
* This file is part of pcsc-relay.
*
@@ -29,35 +30,13 @@
#include
#include
-#include "binutil.h"
-#include "config.h"
+#include "cmdline.h"
#include "pcsc-relay.h"
#include "pcscutil.h"
-#define OPT_HELP 'h'
-#define OPT_READER 'r'
-#define OPT_VERBOSE 'v'
-#define OPT_FOREGROUND 'f'
-#define OPT_EMULATOR 'e'
-static const struct option options[] = {
- { "help", no_argument, NULL, OPT_HELP },
- { "reader", required_argument, NULL, OPT_READER },
- { "foreground", no_argument, NULL, OPT_FOREGROUND },
- { "emulator", required_argument, NULL, OPT_EMULATOR },
- { "verbose", no_argument, NULL, OPT_VERBOSE },
- { NULL, 0, NULL, 0 }
-};
-static const char *option_help[] = {
- "Print help and exit",
- "Number of reader to use (default: 0)",
- "Stay in foreground",
- "NFC emulator backend (openpicc [default], libnfc)",
- "Use (several times) to be more verbose",
-};
static int doinfo = 0;
static int dodaemon = 1;
int verbose = 0;
-static unsigned int readernum = 0;
static struct rf_driver *driver = &driver_openpicc;
static driver_data_t *driver_data = NULL;
@@ -137,63 +116,21 @@ int main (int argc, char **argv)
DWORD ctl, protocol;
struct sigaction new_sig, old_sig;
+ struct gengetopt_args_info args_info;
- while (1) {
- i = getopt_long(argc, argv, "hr:fe:v", options, &oindex);
- if (i == -1)
+ /* Parse command line */
+ if (cmdline_parser (argc, argv, &args_info) != 0)
+ exit(1) ;
+ switch (args_info.emulator_arg) {
+ case emulator_arg_openpicc:
+ driver = &driver_openpicc;
break;
- switch (i) {
- case OPT_HELP:
- print_usage(argv[0] , options, option_help);
- exit(0);
- break;
- case OPT_READER:
- if (sscanf(optarg, "%u", &readernum) != 1) {
- parse_error(argv[0], options, option_help, optarg, oindex);
- exit(2);
- }
- break;
- case OPT_VERBOSE:
- verbose++;
- dodaemon = 0;
- break;
- case OPT_FOREGROUND:
- dodaemon = 0;
- break;
- case OPT_EMULATOR:
- if (strncmp(optarg, "openpicc", strlen("openpicc")) == 0)
- driver = &driver_openpicc;
- else
- if (strncmp(optarg, "libnfc", strlen("libnfc")) == 0)
- driver = &driver_libnfc;
- else {
- parse_error(argv[0], options, option_help, optarg, oindex);
- exit(2);
- }
- break;
- case '?':
- /* fall through */
- default:
- exit(1);
- break;
- }
- }
-
- if (optind < argc) {
- fprintf (stderr, "Unknown argument%s:", optind+1 == argc ? "" : "s");
- while (optind < argc) {
- fprintf(stderr, " \"%s\"", argv[optind++]);
- fprintf(stderr, "%c", optind == argc ? '\n' : ',');
- }
- exit(1);
- }
-
-
- if (doinfo) {
- fprintf(stderr, "%s written by Frank Morgner.\n" ,
- PACKAGE_STRING);
- return 0;
+ case emulator_arg_libnfc:
+ driver = &driver_libnfc;
+ break;
+ default:
+ exit(2);
}
@@ -214,13 +151,13 @@ int main (int argc, char **argv)
/* connect to reader and card */
- r = pcsc_connect(readernum, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_ANY,
+ r = pcsc_connect(args_info.reader_arg, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_ANY,
&hContext, &readers, &hCard, &protocol);
if (r != SCARD_S_SUCCESS)
goto err;
- if (dodaemon) {
+ if (!args_info.foreground_flag) {
INFO("Forking to background...\n");
verbose = -1;
daemonize();
diff --git a/pcsc-relay/src/pcsc-relay.ggo.in b/pcsc-relay/src/pcsc-relay.ggo.in
new file mode 100644
index 0000000..433570a
--- /dev/null
+++ b/pcsc-relay/src/pcsc-relay.ggo.in
@@ -0,0 +1,24 @@
+purpose "Emulate a contact-less smart card"
+description "Using an contact-less interface (currently OpenPICC or libnfc) @PACKAGE@ receives command APDUs which are forwared to an existing smart card via PC/SC. @PACKAGE@ sends the response APDU back to the contact-less interface."
+
+option "reader" r
+ "Number of the PC/SC reader to use (-1 for autodetect)"
+ int default="-1"
+ optional
+option "emulator" e
+ "Contact-less emulator backend"
+ values="openpicc","libnfc" default="openpicc"
+ enum
+ optional
+option "foreground" f
+ "Stay in foreground"
+ flag off
+option "verbose" v
+ "Use (several times) to be more verbose"
+ multiple
+ optional
+
+text "
+Report bugs to @PACKAGE_BUGREPORT@
+
+Written by Frank Morgner and Dominik Oepen "