From 931f51e2f1ca5247cc830a02da1783fd03051f63 Mon Sep 17 00:00:00 2001 From: frankmorgner Date: Tue, 10 Apr 2012 01:18:18 +0000 Subject: [PATCH] switched to command line handling with gengetopt git-svn-id: https://vsmartcard.svn.sourceforge.net/svnroot/vsmartcard@737 96b47cad-a561-4643-ad3b-153ac7d7599c --- ccid/src/Makefile.am | 28 ++- ccid/src/binutil.c | 71 ------ ccid/src/binutil.h | 29 --- ccid/src/ccid-emulator.ggo.in | 51 ++++ ccid/src/usb.c | 412 ++++--------------------------- npa/src/Makefile.am | 34 ++- npa/src/binutil.c | 1 - npa/src/binutil.h | 1 - npa/src/npa-tool.c | 264 +++++--------------- npa/src/npa-tool.ggo.in | 81 ++++++ pcsc-relay/src/Makefile.am | 25 +- pcsc-relay/src/binutil.c | 1 - pcsc-relay/src/binutil.h | 1 - pcsc-relay/src/pcsc-relay.c | 97 ++------ pcsc-relay/src/pcsc-relay.ggo.in | 24 ++ 15 files changed, 361 insertions(+), 759 deletions(-) delete mode 100644 ccid/src/binutil.c delete mode 100644 ccid/src/binutil.h create mode 100644 ccid/src/ccid-emulator.ggo.in delete mode 120000 npa/src/binutil.c delete mode 120000 npa/src/binutil.h create mode 100644 npa/src/npa-tool.ggo.in delete mode 120000 pcsc-relay/src/binutil.c delete mode 120000 pcsc-relay/src/binutil.h create mode 100644 pcsc-relay/src/pcsc-relay.ggo.in 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 "