switched to command line handling with gengetopt

git-svn-id: https://vsmartcard.svn.sourceforge.net/svnroot/vsmartcard@737 96b47cad-a561-4643-ad3b-153ac7d7599c
This commit is contained in:
frankmorgner
2012-04-10 01:18:18 +00:00
parent 7549ed4d2b
commit 931f51e2f1
15 changed files with 361 additions and 759 deletions

View File

@@ -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 \

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#include "binutil.h"
#include <stdio.h>
#include <string.h>
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 = " <arg>";
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);
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef _CCID_BINUTIL_H
#define _CCID_BINUTIL_H
#include <getopt.h>
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

View File

@@ -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 <morgner@informatik.hu-berlin.de>"

View File

@@ -1,20 +1,20 @@
/*
* Copyright (C) 2009 Frank Morgner
* Copyright (C) 2009-2012 Frank Morgner <morgner@informatik.hu-berlin.de>
*
* 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 <http://www.gnu.org/licenses/>.
* ccid-emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <fcntl.h>
@@ -37,17 +37,16 @@
#include <linux/usb/ch9.h>
//#include <usb.h>
//
#include <getopt.h>
#ifdef AIO
/* this aio code works with libaio-0.3.106 */
#include <libaio.h>
#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<sizeof stringtab/sizeof(struct usb_string); i++) {
if (stringtab[i].id == STRINGID_SERIAL) {
stringtab[i].s = doserial;
break;
}
}
} else {
if (strncmp(cmdline.serial_arg, "random", strlen("random")) == 0) {
/* random initial serial number */
srand ((int) time (0));
for (i = 0; i < sizeof serial - 1; ) {
@@ -1837,11 +1525,19 @@ main (int argc, char **argv)
if ((('a' <= c && c <= 'z') || ('0' <= c && c <= '9')))
serial [i++] = c;
}
if (verbose)
fprintf (stderr, "serial=\"%s\"\n", serial);
} else {
for (i=0; i<sizeof stringtab/sizeof(struct usb_string); i++) {
if (stringtab[i].id == STRINGID_SERIAL) {
stringtab[i].s = cmdline.serial_arg;
break;
}
}
if (verbose)
fprintf (stderr, "serial=\"%s\"\n", cmdline.serial_arg);
}
if (verbose)
fprintf (stderr, "serial=\"%s\"\n", doserial ? doserial : serial);
if (doiintf) {
for (i=0; i<sizeof stringtab/sizeof(struct usb_string); i++) {
if (stringtab[i].id == STRINGID_INTERFACE) {

View File

@@ -1,4 +1,16 @@
EXTRA_DIST = $(shell find -L $(top_srcdir)/src/opensc -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'
BUILT_SOURCES = cmdline.h cmdline.c
EXTRA_DIST = npa-tool.ggo npa-tool.ggo.in
EXTRA_DIST += $(shell find -L $(top_srcdir)/src/opensc -path '*/.git' -prune -o -type f -a -name '*.h' -print)
DISTCLEANFILES = $(BUILT_SOURCES) npa-tool.ggo
AM_CPPFLAGS = -I$(top_srcdir)/src/npa -I$(top_srcdir)/src/opensc/src
@@ -6,11 +18,11 @@ libnpa_la_SOURCES = sm.c scutil.c npa.c sslutil.c
libnpa_la_LIBADD = $(OPENSSL_LIBS) $(OPENSC_LIBS)
libnpa_la_CFLAGS = $(OPENSSL_CFLAGS)
libnpa_la_LDFLAGS = -no-undefined
if WIN32
libnpa_la_LIBADD += -lws2_32
endif
#if WIN32
#libnpa_la_LIBADD += -lws2_32
#endif
npa_tool_SOURCES = npa-tool.c binutil.c
npa_tool_SOURCES = npa-tool.c $(BUILT_SOURCES)
npa_tool_LDADD = $(OPENSSL_LIBS) $(OPENSC_LIBS) libnpa.la
npa_tool_CFLAGS = $(OPENSSL_CFLAGS)
@@ -19,14 +31,22 @@ example_LDADD = $(OPENSSL_LIBS) $(OPENSC_LIBS) libnpa.la
example_CFLAGS = $(OPENSSL_CFLAGS)
npa-tool.c: $(BUILT_SOURCES)
$(BUILT_SOURCES): npa-tool.ggo
gengetopt --output-dir=$(srcdir) < $<
npa-tool.ggo: npa-tool.ggo.in
$(do_subst) < $< > $(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 \

View File

@@ -1 +0,0 @@
../../ccid/src/binutil.c

View File

@@ -1 +0,0 @@
../../ccid/src/binutil.h

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Frank Morgner
* Copyright (C) 2010-2012 Frank Morgner <morgner@informatik.hu-berlin.de>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "binutil.h"
#include "cmdline.h"
#include "config.h"
#include <libopensc/log.h>
#include <npa/npa.h>
@@ -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;

81
npa/src/npa-tool.ggo.in Normal file
View File

@@ -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 <morgner@informatik.hu-berlin.de>"

View File

@@ -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)/$@

View File

@@ -1 +0,0 @@
../../ccid/src/binutil.c

View File

@@ -1 +0,0 @@
../../ccid/src/binutil.h

View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 Dominik Oepen, Frank Morgner
* Copyright (C) 2009 by Dominik Oepen <oepen@informatik.hu-berlin.de>.
* Copyright (C) 2010-2012 by Frank Morgner <morgner@informatik.hu-berlin.de>.
*
* This file is part of pcsc-relay.
*
@@ -29,35 +30,13 @@
#include <string.h>
#include <errno.h>
#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();

View File

@@ -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 <morgner@informatik.hu-berlin.de> and Dominik Oepen <oepen@informatik.hu-berlin.de>"