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:
@@ -1,15 +1,35 @@
|
|||||||
EXTRA_DIST = $(shell find $(top_srcdir)/src/opensc -path '*/.svn' -prune -o -type f -a -name '*.h' -print)
|
do_subst = sed \
|
||||||
EXTRA_DIST += $(shell find -L $(top_srcdir)/src/opensc-npa -path '*/.git' -prune -o -type f -a -name '*.h' -print)
|
-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_LDADD = $(OPENSSL_LIBS) $(PTHREAD_LIBS)
|
||||||
ccid_emulator_CFLAGS = $(OPENSSL_CFLAGS) $(PTHREAD_CFLAGS)
|
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 =
|
bin_PROGRAMS =
|
||||||
|
|
||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
binutil.h \
|
|
||||||
pcscutil.h \
|
pcscutil.h \
|
||||||
scutil.h \
|
scutil.h \
|
||||||
ccid.h \
|
ccid.h \
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
51
ccid/src/ccid-emulator.ggo.in
Normal file
51
ccid/src/ccid-emulator.ggo.in
Normal 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>"
|
||||||
412
ccid/src/usb.c
412
ccid/src/usb.c
@@ -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
|
* ccid-emulator is free software: you can redistribute it and/or modify it
|
||||||
* terms of the GNU General Public License as published by the Free Software
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Foundation, either version 3 of the License, or (at your option) any later
|
* Software Foundation, either version 3 of the License, or (at your option)
|
||||||
* version.
|
* any later version.
|
||||||
*
|
*
|
||||||
* ccid is distributed in the hope that it will be useful, but WITHOUT ANY
|
* ccid-emulator is distributed in the hope that it will be useful, but WITHOUT
|
||||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
* details.
|
* more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with
|
* 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 <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -37,17 +37,16 @@
|
|||||||
#include <linux/usb/ch9.h>
|
#include <linux/usb/ch9.h>
|
||||||
//#include <usb.h>
|
//#include <usb.h>
|
||||||
//
|
//
|
||||||
#include <getopt.h>
|
|
||||||
|
|
||||||
#ifdef AIO
|
#ifdef AIO
|
||||||
/* this aio code works with libaio-0.3.106 */
|
/* this aio code works with libaio-0.3.106 */
|
||||||
#include <libaio.h>
|
#include <libaio.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "ccid.h"
|
||||||
|
#include "cmdline.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "usbstring.h"
|
#include "usbstring.h"
|
||||||
#include "ccid.h"
|
|
||||||
#include "binutil.h"
|
|
||||||
|
|
||||||
#define DRIVER_VENDOR_NUM 0x0D46 /* KOBIL Systems */
|
#define DRIVER_VENDOR_NUM 0x0D46 /* KOBIL Systems */
|
||||||
#define DRIVER_PRODUCT_NUM 0x3010 /* KOBIL Class 3 Reader */
|
#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 productid = DRIVER_PRODUCT_NUM;
|
||||||
static int verbose = 0;
|
static int verbose = 0;
|
||||||
static int debug = 0;
|
static int debug = 0;
|
||||||
static int dohid = 0;
|
|
||||||
static int doint = 0;
|
static int doint = 0;
|
||||||
static int doinfo = 0;
|
|
||||||
static const char *doserial = NULL;
|
|
||||||
static const char *doiintf = NULL;
|
static const char *doiintf = NULL;
|
||||||
static int usb_reader_num = -1;
|
|
||||||
static const char *cdriver = NULL;
|
|
||||||
static const char *gadgetfs = "/dev/gadget";
|
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
|
/* NOTE: these IDs don't imply endpoint numbering; host side drivers
|
||||||
* should use endpoint descriptors, or perhaps bcdDevice, to configure
|
* should use endpoint descriptors, or perhaps bcdDevice, to configure
|
||||||
* such things. Other product IDs could have different policies.
|
* 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_SERIAL 3
|
||||||
#define STRINGID_CONFIG 4
|
#define STRINGID_CONFIG 4
|
||||||
#define STRINGID_INTERFACE 5
|
#define STRINGID_INTERFACE 5
|
||||||
#define STRINGID_HID_INTERFACE 6
|
|
||||||
|
|
||||||
static struct usb_device_descriptor
|
static struct usb_device_descriptor
|
||||||
device_desc = {
|
device_desc = {
|
||||||
@@ -172,14 +123,6 @@ source_sink_intf = {
|
|||||||
.bInterfaceProtocol = 0,
|
.bInterfaceProtocol = 0,
|
||||||
.iInterface = STRINGID_INTERFACE,
|
.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
|
/* Full speed configurations are used for full-speed only devices as
|
||||||
* well as dual-speed ones (the only kind with high speed support).
|
* 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),
|
.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] = {
|
static const struct usb_endpoint_descriptor *fs_eps [3] = {
|
||||||
&fs_source_desc,
|
&fs_source_desc,
|
||||||
&fs_sink_desc,
|
&fs_sink_desc,
|
||||||
@@ -273,16 +206,6 @@ hs_status_desc = {
|
|||||||
.bInterval = LOG2_STATUS_POLL_MSEC + 3,
|
.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 [] = {
|
static const struct usb_endpoint_descriptor *hs_eps [] = {
|
||||||
&hs_source_desc,
|
&hs_source_desc,
|
||||||
&hs_sink_desc,
|
&hs_sink_desc,
|
||||||
@@ -308,7 +231,6 @@ static struct usb_string stringtab [] = {
|
|||||||
{ STRINGID_CONFIG, "PACE support disabled", },
|
{ STRINGID_CONFIG, "PACE support disabled", },
|
||||||
#endif
|
#endif
|
||||||
{ STRINGID_INTERFACE, interrupt_on_string, },
|
{ STRINGID_INTERFACE, interrupt_on_string, },
|
||||||
{ STRINGID_HID_INTERFACE, "Human Device Interface Gadget", },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct usb_gadget_strings strings = {
|
static struct usb_gadget_strings strings = {
|
||||||
@@ -324,7 +246,7 @@ static struct usb_gadget_strings strings = {
|
|||||||
|
|
||||||
static int HIGHSPEED;
|
static int HIGHSPEED;
|
||||||
static char *DEVNAME;
|
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
|
/* gadgetfs currently has no chunking (or O_DIRECT/zerocopy) support
|
||||||
* to turn big requests into lots of smaller ones; so this is "small".
|
* to turn big requests into lots of smaller ones; so this is "small".
|
||||||
@@ -362,14 +284,6 @@ static int autoconfig ()
|
|||||||
= USB_DIR_IN | 11;
|
= USB_DIR_IN | 11;
|
||||||
EP_STATUS_NAME = "ep-f";
|
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 */
|
/* Intel PXA 2xx processor, full speed only */
|
||||||
} else if (stat (DEVNAME = "pxa2xx_udc", &statb) == 0) {
|
} else if (stat (DEVNAME = "pxa2xx_udc", &statb) == 0) {
|
||||||
HIGHSPEED = 0;
|
HIGHSPEED = 0;
|
||||||
@@ -387,10 +301,6 @@ static int autoconfig ()
|
|||||||
fs_status_desc.bEndpointAddress = USB_DIR_IN | 11;
|
fs_status_desc.bEndpointAddress = USB_DIR_IN | 11;
|
||||||
EP_STATUS_NAME = "ep11in-bulk";
|
EP_STATUS_NAME = "ep11in-bulk";
|
||||||
|
|
||||||
if (dohid) {
|
|
||||||
EP_HID_STATUS_NAME = "ep12in-bulk";
|
|
||||||
fs_hid_status_desc.bEndpointAddress = USB_DIR_IN | 12;
|
|
||||||
}
|
|
||||||
#if 0
|
#if 0
|
||||||
/* AMD au1x00 processor, full speed only */
|
/* AMD au1x00 processor, full speed only */
|
||||||
} else if (stat (DEVNAME = "au1x00_udc", &statb) == 0) {
|
} else if (stat (DEVNAME = "au1x00_udc", &statb) == 0) {
|
||||||
@@ -431,19 +341,10 @@ static int autoconfig ()
|
|||||||
fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 1;
|
fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 1;
|
||||||
EP_OUT_NAME = "ep1-bulk";
|
EP_OUT_NAME = "ep1-bulk";
|
||||||
|
|
||||||
if (dohid) {
|
source_sink_intf.bNumEndpoints = 3;
|
||||||
source_sink_intf.bNumEndpoints = 2;
|
|
||||||
// USB Wake up signaling not supported
|
|
||||||
ccid_desc.dwFeatures &= ~__constant_cpu_to_le32(0x100000);
|
|
||||||
|
|
||||||
EP_HID_STATUS_NAME = "ep3-bulk";
|
EP_STATUS_NAME = "ep3-bulk";
|
||||||
fs_hid_status_desc.bEndpointAddress = USB_DIR_IN | 3;
|
fs_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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Samsung S3C24xx series, full speed only */
|
/* Samsung S3C24xx series, full speed only */
|
||||||
} else if (stat (DEVNAME = "s3c2410_udc", &statb) == 0) {
|
} else if (stat (DEVNAME = "s3c2410_udc", &statb) == 0) {
|
||||||
@@ -459,11 +360,6 @@ static int autoconfig ()
|
|||||||
fs_status_desc.bEndpointAddress = USB_DIR_IN | 3;
|
fs_status_desc.bEndpointAddress = USB_DIR_IN | 3;
|
||||||
EP_STATUS_NAME = "ep3-bulk";
|
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 */
|
/* Renesas SH77xx processors, full speed only */
|
||||||
} else if (stat (DEVNAME = "sh_udc", &statb) == 0) {
|
} else if (stat (DEVNAME = "sh_udc", &statb) == 0) {
|
||||||
HIGHSPEED = 0;
|
HIGHSPEED = 0;
|
||||||
@@ -478,11 +374,6 @@ static int autoconfig ()
|
|||||||
fs_status_desc.bEndpointAddress = USB_DIR_IN | 3;
|
fs_status_desc.bEndpointAddress = USB_DIR_IN | 3;
|
||||||
EP_STATUS_NAME = "ep3in-bulk";
|
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 */
|
/* OMAP 1610 and newer devices, full speed only, fifo mode 0 or 3 */
|
||||||
} else if (stat (DEVNAME = "omap_udc", &statb) == 0) {
|
} else if (stat (DEVNAME = "omap_udc", &statb) == 0) {
|
||||||
HIGHSPEED = 0;
|
HIGHSPEED = 0;
|
||||||
@@ -497,11 +388,6 @@ static int autoconfig ()
|
|||||||
fs_status_desc.bEndpointAddress = USB_DIR_IN | 3;
|
fs_status_desc.bEndpointAddress = USB_DIR_IN | 3;
|
||||||
EP_STATUS_NAME = "ep3in-int";
|
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 */
|
/* Something based on Mentor USB Highspeed Dual-Role Controller */
|
||||||
} else if (stat (DEVNAME = "musb_hdrc", &statb) == 0) {
|
} else if (stat (DEVNAME = "musb_hdrc", &statb) == 0) {
|
||||||
HIGHSPEED = 1;
|
HIGHSPEED = 1;
|
||||||
@@ -535,11 +421,6 @@ static int autoconfig ()
|
|||||||
fs_status_desc.bEndpointAddress = USB_DIR_IN | 3;
|
fs_status_desc.bEndpointAddress = USB_DIR_IN | 3;
|
||||||
EP_STATUS_NAME = "ep3-int";
|
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 */
|
/* Sharp LH740x processors, full speed only */
|
||||||
} else if (stat (DEVNAME = "lh740x_udc", &statb) == 0) {
|
} else if (stat (DEVNAME = "lh740x_udc", &statb) == 0) {
|
||||||
HIGHSPEED = 0;
|
HIGHSPEED = 0;
|
||||||
@@ -550,19 +431,10 @@ static int autoconfig ()
|
|||||||
fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 2;
|
fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 2;
|
||||||
EP_OUT_NAME = "ep2out-bulk";
|
EP_OUT_NAME = "ep2out-bulk";
|
||||||
|
|
||||||
if (dohid) {
|
source_sink_intf.bNumEndpoints = 3;
|
||||||
source_sink_intf.bNumEndpoints = 2;
|
|
||||||
// USB Wake up signaling not supported
|
|
||||||
ccid_desc.dwFeatures &= ~__constant_cpu_to_le32(0x100000);
|
|
||||||
|
|
||||||
fs_hid_status_desc.bEndpointAddress = USB_DIR_IN | 3;
|
fs_status_desc.bEndpointAddress = USB_DIR_IN | 3;
|
||||||
EP_HID_STATUS_NAME = "ep3in-int";
|
EP_STATUS_NAME = "ep3in-int";
|
||||||
} else {
|
|
||||||
source_sink_intf.bNumEndpoints = 3;
|
|
||||||
|
|
||||||
fs_status_desc.bEndpointAddress = USB_DIR_IN | 3;
|
|
||||||
EP_STATUS_NAME = "ep3in-int";
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Atmel AT32AP700x processors, high/full speed */
|
/* Atmel AT32AP700x processors, high/full speed */
|
||||||
} else if (stat (DEVNAME = "atmel_usba_udc", &statb) == 0) {
|
} else if (stat (DEVNAME = "atmel_usba_udc", &statb) == 0) {
|
||||||
@@ -578,23 +450,12 @@ static int autoconfig ()
|
|||||||
= USB_DIR_OUT | 2;
|
= USB_DIR_OUT | 2;
|
||||||
EP_OUT_NAME = "ep2out-bulk";
|
EP_OUT_NAME = "ep2out-bulk";
|
||||||
|
|
||||||
if (dohid) {
|
source_sink_intf.bNumEndpoints = 3;
|
||||||
source_sink_intf.bNumEndpoints = 2;
|
|
||||||
// USB Wake up signaling not supported
|
|
||||||
ccid_desc.dwFeatures &= ~__constant_cpu_to_le32(0x100000);
|
|
||||||
|
|
||||||
fs_hid_status_desc.bEndpointAddress
|
fs_status_desc.bEndpointAddress
|
||||||
= hs_hid_status_desc.bEndpointAddress
|
= hs_status_desc.bEndpointAddress
|
||||||
= USB_DIR_IN | 3;
|
= USB_DIR_IN | 3;
|
||||||
EP_HID_STATUS_NAME = "ep3in-int";
|
EP_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";
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
DEVNAME = 0;
|
DEVNAME = 0;
|
||||||
@@ -874,12 +735,10 @@ static int iso_autoconfig ()
|
|||||||
static pthread_t ep0;
|
static pthread_t ep0;
|
||||||
|
|
||||||
static pthread_t ccid_thread;
|
static pthread_t ccid_thread;
|
||||||
static pthread_t hidthread;
|
|
||||||
static pthread_t interrupt_thread;
|
static pthread_t interrupt_thread;
|
||||||
static int source_fd = -1;
|
static int source_fd = -1;
|
||||||
static int sink_fd = -1;
|
static int sink_fd = -1;
|
||||||
static int status_fd = -1;
|
static int status_fd = -1;
|
||||||
static int hidstatus_fd = -1;
|
|
||||||
|
|
||||||
// FIXME no result i/o yet
|
// 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)
|
ep_config(name,__FUNCTION__, &fs_sink_desc, &hs_sink_desc)
|
||||||
#define status_open(name) \
|
#define status_open(name) \
|
||||||
ep_config(name,__FUNCTION__, &fs_status_desc, &hs_status_desc)
|
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)
|
static void *interrupt (void *param)
|
||||||
{
|
{
|
||||||
@@ -1087,59 +944,6 @@ error:
|
|||||||
pthread_exit(0);
|
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)
|
static void start_io (void)
|
||||||
{
|
{
|
||||||
//int tmp;
|
//int tmp;
|
||||||
@@ -1187,19 +991,6 @@ static void start_io (void)
|
|||||||
perror ("can't create ccid thread");
|
perror ("can't create ccid thread");
|
||||||
goto cleanup;
|
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) {
|
if (doint) {
|
||||||
static char * interruptnames[1];
|
static char * interruptnames[1];
|
||||||
interruptnames[0] = EP_STATUS_NAME;
|
interruptnames[0] = EP_STATUS_NAME;
|
||||||
@@ -1236,13 +1027,6 @@ static void stop_io ()
|
|||||||
ccid_thread = ep0;
|
ccid_thread = ep0;
|
||||||
fprintf (stderr, "cancled ccid\n");
|
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)) {
|
if (!pthread_equal (interrupt_thread, ep0)) {
|
||||||
pthread_cancel (interrupt_thread);
|
pthread_cancel (interrupt_thread);
|
||||||
if (pthread_join (interrupt_thread, 0) != 0)
|
if (pthread_join (interrupt_thread, 0) != 0)
|
||||||
@@ -1255,7 +1039,7 @@ static void stop_io ()
|
|||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
static char *
|
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;
|
struct usb_config_descriptor *c;
|
||||||
int i;
|
int i;
|
||||||
@@ -1277,28 +1061,6 @@ build_config (char *cp, const struct usb_endpoint_descriptor **ep, const struct
|
|||||||
cp += USB_DT_ENDPOINT_SIZE;
|
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);
|
c->wTotalLength = __cpu_to_le16 (cp - (char *) c);
|
||||||
return cp;
|
return cp;
|
||||||
}
|
}
|
||||||
@@ -1331,9 +1093,9 @@ static int init_device (void)
|
|||||||
cp += 4;
|
cp += 4;
|
||||||
|
|
||||||
/* write full then high speed configs */
|
/* write full then high speed configs */
|
||||||
cp = build_config (cp, fs_eps, &fs_hid_status_desc);
|
cp = build_config (cp, fs_eps);
|
||||||
if (HIGHSPEED)
|
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.idVendor = __cpu_to_le16 (vendorid);
|
||||||
device_desc.idProduct = __cpu_to_le16 (productid);
|
device_desc.idProduct = __cpu_to_le16 (productid);
|
||||||
@@ -1432,7 +1194,7 @@ static void handle_control (int fd, struct usb_ctrlrequest *setup)
|
|||||||
*/
|
*/
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case CONFIG_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 ();
|
stop_io ();
|
||||||
start_io ();
|
start_io ();
|
||||||
break;
|
break;
|
||||||
@@ -1495,12 +1257,6 @@ static void handle_control (int fd, struct usb_ctrlrequest *setup)
|
|||||||
perror ("reset status fd");
|
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 */
|
/* FIXME eventually reset the result endpoint too */
|
||||||
if (result)
|
if (result)
|
||||||
goto stall;
|
goto stall;
|
||||||
@@ -1606,7 +1362,7 @@ static void *ep0_thread (void *param)
|
|||||||
time_t now, last;
|
time_t now, last;
|
||||||
struct pollfd ep0_poll;
|
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 (stop_io, NULL);
|
||||||
pthread_cleanup_push (close_fd, param);
|
pthread_cleanup_push (close_fd, param);
|
||||||
|
|
||||||
@@ -1734,85 +1490,24 @@ main (int argc, char **argv)
|
|||||||
int fd, c, i;
|
int fd, c, i;
|
||||||
int oindex = 0;
|
int oindex = 0;
|
||||||
|
|
||||||
while (1) {
|
struct gengetopt_args_info cmdline;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (optind < argc) {
|
|
||||||
fprintf (stderr, "Unknown argument%s:", optind+1 == argc ? "" : "s");
|
/* Parse command line */
|
||||||
while (optind < argc) {
|
if (cmdline_parser (argc, argv, &cmdline) != 0)
|
||||||
fprintf(stderr, " \"%s\"", argv[optind++]);
|
|
||||||
fprintf(stderr, "%c", optind == argc ? '\n' : ',');
|
|
||||||
}
|
|
||||||
exit(1);
|
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) {
|
if (cmdline.info_flag)
|
||||||
fprintf(stderr, "%s %s written by Frank Morgner.\n\n" ,
|
|
||||||
argv[0], VERSION);
|
|
||||||
return print_avail(verbose);
|
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");
|
fprintf (stderr, "Can't initialize ccid\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -1822,14 +1517,7 @@ main (int argc, char **argv)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doserial) {
|
if (strncmp(cmdline.serial_arg, "random", strlen("random")) == 0) {
|
||||||
for (i=0; i<sizeof stringtab/sizeof(struct usb_string); i++) {
|
|
||||||
if (stringtab[i].id == STRINGID_SERIAL) {
|
|
||||||
stringtab[i].s = doserial;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* random initial serial number */
|
/* random initial serial number */
|
||||||
srand ((int) time (0));
|
srand ((int) time (0));
|
||||||
for (i = 0; i < sizeof serial - 1; ) {
|
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')))
|
if ((('a' <= c && c <= 'z') || ('0' <= c && c <= '9')))
|
||||||
serial [i++] = c;
|
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) {
|
if (doiintf) {
|
||||||
for (i=0; i<sizeof stringtab/sizeof(struct usb_string); i++) {
|
for (i=0; i<sizeof stringtab/sizeof(struct usb_string); i++) {
|
||||||
if (stringtab[i].id == STRINGID_INTERFACE) {
|
if (stringtab[i].id == STRINGID_INTERFACE) {
|
||||||
|
|||||||
@@ -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
|
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_LIBADD = $(OPENSSL_LIBS) $(OPENSC_LIBS)
|
||||||
libnpa_la_CFLAGS = $(OPENSSL_CFLAGS)
|
libnpa_la_CFLAGS = $(OPENSSL_CFLAGS)
|
||||||
libnpa_la_LDFLAGS = -no-undefined
|
libnpa_la_LDFLAGS = -no-undefined
|
||||||
if WIN32
|
#if WIN32
|
||||||
libnpa_la_LIBADD += -lws2_32
|
#libnpa_la_LIBADD += -lws2_32
|
||||||
endif
|
#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_LDADD = $(OPENSSL_LIBS) $(OPENSC_LIBS) libnpa.la
|
||||||
npa_tool_CFLAGS = $(OPENSSL_CFLAGS)
|
npa_tool_CFLAGS = $(OPENSSL_CFLAGS)
|
||||||
|
|
||||||
@@ -19,14 +31,22 @@ example_LDADD = $(OPENSSL_LIBS) $(OPENSC_LIBS) libnpa.la
|
|||||||
example_CFLAGS = $(OPENSSL_CFLAGS)
|
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
|
bin_PROGRAMS = npa-tool
|
||||||
noinst_PROGRAMS = example
|
noinst_PROGRAMS = example
|
||||||
|
|
||||||
lib_LTLIBRARIES = libnpa.la
|
lib_LTLIBRARIES = libnpa.la
|
||||||
|
|
||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
sslutil.h \
|
sslutil.h
|
||||||
binutil.h
|
|
||||||
|
|
||||||
nobase_include_HEADERS = \
|
nobase_include_HEADERS = \
|
||||||
npa/sm.h \
|
npa/sm.h \
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
../../ccid/src/binutil.c
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../ccid/src/binutil.h
|
|
||||||
@@ -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.
|
* This file is part of npa.
|
||||||
*
|
*
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along with
|
||||||
* npa. If not, see <http://www.gnu.org/licenses/>.
|
* npa. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include "binutil.h"
|
#include "cmdline.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <libopensc/log.h>
|
#include <libopensc/log.h>
|
||||||
#include <npa/npa.h>
|
#include <npa/npa.h>
|
||||||
@@ -46,90 +46,18 @@ static ssize_t getline(char **lineptr, size_t *n, FILE *stream)
|
|||||||
}
|
}
|
||||||
#endif
|
#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 const char *newpin = NULL;
|
||||||
static int usb_reader_num = -1;
|
|
||||||
static const char *pin = NULL;
|
static const char *pin = NULL;
|
||||||
static u8 usepin = 0;
|
|
||||||
static const char *puk = NULL;
|
static const char *puk = NULL;
|
||||||
static u8 usepuk = 0;
|
|
||||||
static const char *can = NULL;
|
static const char *can = NULL;
|
||||||
static u8 usecan = 0;
|
|
||||||
static const char *mrz = NULL;
|
static const char *mrz = NULL;
|
||||||
static u8 usemrz = 0;
|
|
||||||
static u8 chat[0xff];
|
static u8 chat[0xff];
|
||||||
static u8 desc[0xffff];
|
static u8 desc[0xffff];
|
||||||
static const char *cdriver = NULL;
|
|
||||||
static char *file = NULL;
|
|
||||||
|
|
||||||
static sc_context_t *ctx = NULL;
|
static sc_context_t *ctx = NULL;
|
||||||
static sc_card_t *card = NULL;
|
static sc_card_t *card = NULL;
|
||||||
static sc_reader_t *reader;
|
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)
|
int npa_translate_apdus(struct sm_ctx *sctx, sc_card_t *card, FILE *input)
|
||||||
{
|
{
|
||||||
u8 buf[4 + 3 + 0xffff + 3];
|
u8 buf[4 + 3 + 0xffff + 3];
|
||||||
@@ -206,129 +134,57 @@ main (int argc, char **argv)
|
|||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
size_t outlen;
|
size_t outlen;
|
||||||
|
|
||||||
|
struct gengetopt_args_info cmdline;
|
||||||
|
|
||||||
memset(&sctx, 0, sizeof sctx);
|
memset(&sctx, 0, sizeof sctx);
|
||||||
memset(&tmpctx, 0, sizeof tmpctx);
|
memset(&tmpctx, 0, sizeof tmpctx);
|
||||||
memset(&pace_input, 0, sizeof pace_input);
|
memset(&pace_input, 0, sizeof pace_input);
|
||||||
memset(&pace_output, 0, sizeof pace_output);
|
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) {
|
/* Parse command line */
|
||||||
fprintf (stderr, "Unknown argument%s:", optind+1 == argc ? "" : "s");
|
if (cmdline_parser (argc, argv, &cmdline) != 0)
|
||||||
while (optind < argc) {
|
|
||||||
fprintf(stderr, " \"%s\"", argv[optind++]);
|
|
||||||
fprintf(stderr, "%c", optind == argc ? '\n' : ',');
|
|
||||||
}
|
|
||||||
exit(1);
|
exit(1);
|
||||||
|
if (cmdline.env_flag) {
|
||||||
|
can = getenv("CAN");
|
||||||
|
mrz = getenv("MRZ");
|
||||||
|
pin = getenv("PIN");
|
||||||
|
puk = getenv("PUK");
|
||||||
|
newpin = getenv("NEWPIN");
|
||||||
}
|
}
|
||||||
|
can = cmdline.can_arg;
|
||||||
|
mrz = cmdline.mrz_arg;
|
||||||
if (doinfo) {
|
pin = cmdline.pin_arg;
|
||||||
fprintf(stderr, "%s %s written by Frank Morgner.\n\n" ,
|
puk = cmdline.puk_arg;
|
||||||
argv[0], VERSION);
|
newpin = cmdline.new_pin_arg;
|
||||||
return print_avail(verbose);
|
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) {
|
if (r < 0) {
|
||||||
fprintf(stderr, "Can't initialize reader\n");
|
fprintf(stderr, "Can't initialize reader\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -340,13 +196,13 @@ main (int argc, char **argv)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dobreak) {
|
if (cmdline.break_flag) {
|
||||||
/* The biggest buffer sprintf could write with "%llu" */
|
/* The biggest buffer sprintf could write with "%llu" */
|
||||||
char secretbuf[strlen("18446744073709551615")+1];
|
char secretbuf[strlen("18446744073709551615")+1];
|
||||||
unsigned long long secret = 0;
|
unsigned long long secret = 0;
|
||||||
unsigned long long maxsecret = 0;
|
unsigned long long maxsecret = 0;
|
||||||
|
|
||||||
if (usepin) {
|
if (cmdline.pin_given) {
|
||||||
pace_input.pin_id = PACE_PIN;
|
pace_input.pin_id = PACE_PIN;
|
||||||
pace_input.pin_length = 6;
|
pace_input.pin_length = 6;
|
||||||
maxsecret = 999999;
|
maxsecret = 999999;
|
||||||
@@ -363,7 +219,7 @@ main (int argc, char **argv)
|
|||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (usecan) {
|
} else if (cmdline.can_given) {
|
||||||
pace_input.pin_id = PACE_CAN;
|
pace_input.pin_id = PACE_CAN;
|
||||||
pace_input.pin_length = 6;
|
pace_input.pin_length = 6;
|
||||||
maxsecret = 999999;
|
maxsecret = 999999;
|
||||||
@@ -380,7 +236,7 @@ main (int argc, char **argv)
|
|||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (usepuk) {
|
} else if (cmdline.puk_given) {
|
||||||
pace_input.pin_id = PACE_PUK;
|
pace_input.pin_id = PACE_PUK;
|
||||||
pace_input.pin_length = 10;
|
pace_input.pin_length = 10;
|
||||||
maxsecret = 9999999999LLU;
|
maxsecret = 9999999999LLU;
|
||||||
@@ -433,7 +289,7 @@ main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doresumepin) {
|
if (cmdline.resume_flag) {
|
||||||
pace_input.pin_id = PACE_CAN;
|
pace_input.pin_id = PACE_CAN;
|
||||||
if (can) {
|
if (can) {
|
||||||
pace_input.pin = can;
|
pace_input.pin = can;
|
||||||
@@ -463,7 +319,7 @@ main (int argc, char **argv)
|
|||||||
printf("Established PACE channel with PIN. PIN resumed.\n");
|
printf("Established PACE channel with PIN. PIN resumed.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dounblock) {
|
if (cmdline.unblock_flag) {
|
||||||
pace_input.pin_id = PACE_PUK;
|
pace_input.pin_id = PACE_PUK;
|
||||||
if (puk) {
|
if (puk) {
|
||||||
pace_input.pin = puk;
|
pace_input.pin = puk;
|
||||||
@@ -484,7 +340,7 @@ main (int argc, char **argv)
|
|||||||
printf("Unblocked PIN.\n");
|
printf("Unblocked PIN.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dochangepin) {
|
if (cmdline.new_pin_given) {
|
||||||
pace_input.pin_id = PACE_PIN;
|
pace_input.pin_id = PACE_PIN;
|
||||||
if (pin) {
|
if (pin) {
|
||||||
pace_input.pin = pin;
|
pace_input.pin = pin;
|
||||||
@@ -505,28 +361,30 @@ main (int argc, char **argv)
|
|||||||
printf("Changed PIN.\n");
|
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 = NULL;
|
||||||
pace_input.pin_length = 0;
|
pace_input.pin_length = 0;
|
||||||
if (usepin) {
|
if (cmdline.pin_given) {
|
||||||
pace_input.pin_id = PACE_PIN;
|
pace_input.pin_id = PACE_PIN;
|
||||||
if (pin) {
|
if (pin) {
|
||||||
pace_input.pin = pin;
|
pace_input.pin = pin;
|
||||||
pace_input.pin_length = strlen(pin);
|
pace_input.pin_length = strlen(pin);
|
||||||
}
|
}
|
||||||
} else if (usecan) {
|
} else if (cmdline.can_given) {
|
||||||
pace_input.pin_id = PACE_CAN;
|
pace_input.pin_id = PACE_CAN;
|
||||||
if (can) {
|
if (can) {
|
||||||
pace_input.pin = can;
|
pace_input.pin = can;
|
||||||
pace_input.pin_length = strlen(can);
|
pace_input.pin_length = strlen(can);
|
||||||
}
|
}
|
||||||
} else if (usemrz) {
|
} else if (cmdline.mrz_given) {
|
||||||
pace_input.pin_id = PACE_MRZ;
|
pace_input.pin_id = PACE_MRZ;
|
||||||
if (mrz) {
|
if (mrz) {
|
||||||
pace_input.pin = mrz;
|
pace_input.pin = mrz;
|
||||||
pace_input.pin_length = strlen(mrz);
|
pace_input.pin_length = strlen(mrz);
|
||||||
}
|
}
|
||||||
} else if (usepuk) {
|
} else if (cmdline.puk_given) {
|
||||||
pace_input.pin_id = PACE_PUK;
|
pace_input.pin_id = PACE_PUK;
|
||||||
if (puk) {
|
if (puk) {
|
||||||
pace_input.pin = puk;
|
pace_input.pin = puk;
|
||||||
@@ -543,14 +401,14 @@ main (int argc, char **argv)
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto err;
|
goto err;
|
||||||
printf("Established PACE channel with %s.\n",
|
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;
|
FILE *input;
|
||||||
if (!file || strncmp(file, "stdin", strlen("stdin")) == 0)
|
if (strncmp(cmdline.translate_arg, "stdin", strlen("stdin")) == 0)
|
||||||
input = stdin;
|
input = stdin;
|
||||||
else {
|
else {
|
||||||
input = fopen(file, "r");
|
input = fopen(cmdline.translate_arg, "r");
|
||||||
if (!input) {
|
if (!input) {
|
||||||
perror("Opening file with APDUs");
|
perror("Opening file with APDUs");
|
||||||
goto err;
|
goto err;
|
||||||
|
|||||||
81
npa/src/npa-tool.ggo.in
Normal file
81
npa/src/npa-tool.ggo.in
Normal 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>"
|
||||||
@@ -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_PROGRAMS = pcsc-relay
|
||||||
bin_SCRIPTS = picc.py
|
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_LDADD = $(PCSC_LIBS) $(LIBNFC_LIBS)
|
||||||
pcsc_relay_CFLAGS = $(PCSC_CFLAGS) $(LIBNFC_CFLAGS)
|
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)/$@
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
../../ccid/src/binutil.c
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../ccid/src/binutil.h
|
|
||||||
@@ -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.
|
* This file is part of pcsc-relay.
|
||||||
*
|
*
|
||||||
@@ -29,35 +30,13 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include "binutil.h"
|
#include "cmdline.h"
|
||||||
#include "config.h"
|
|
||||||
#include "pcsc-relay.h"
|
#include "pcsc-relay.h"
|
||||||
#include "pcscutil.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 doinfo = 0;
|
||||||
static int dodaemon = 1;
|
static int dodaemon = 1;
|
||||||
int verbose = 0;
|
int verbose = 0;
|
||||||
static unsigned int readernum = 0;
|
|
||||||
static struct rf_driver *driver = &driver_openpicc;
|
static struct rf_driver *driver = &driver_openpicc;
|
||||||
static driver_data_t *driver_data = NULL;
|
static driver_data_t *driver_data = NULL;
|
||||||
|
|
||||||
@@ -137,63 +116,21 @@ int main (int argc, char **argv)
|
|||||||
DWORD ctl, protocol;
|
DWORD ctl, protocol;
|
||||||
|
|
||||||
struct sigaction new_sig, old_sig;
|
struct sigaction new_sig, old_sig;
|
||||||
|
struct gengetopt_args_info args_info;
|
||||||
|
|
||||||
|
|
||||||
while (1) {
|
/* Parse command line */
|
||||||
i = getopt_long(argc, argv, "hr:fe:v", options, &oindex);
|
if (cmdline_parser (argc, argv, &args_info) != 0)
|
||||||
if (i == -1)
|
exit(1) ;
|
||||||
|
switch (args_info.emulator_arg) {
|
||||||
|
case emulator_arg_openpicc:
|
||||||
|
driver = &driver_openpicc;
|
||||||
break;
|
break;
|
||||||
switch (i) {
|
case emulator_arg_libnfc:
|
||||||
case OPT_HELP:
|
driver = &driver_libnfc;
|
||||||
print_usage(argv[0] , options, option_help);
|
break;
|
||||||
exit(0);
|
default:
|
||||||
break;
|
exit(2);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -214,13 +151,13 @@ int main (int argc, char **argv)
|
|||||||
|
|
||||||
|
|
||||||
/* connect to reader and card */
|
/* 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);
|
&hContext, &readers, &hCard, &protocol);
|
||||||
if (r != SCARD_S_SUCCESS)
|
if (r != SCARD_S_SUCCESS)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
|
||||||
if (dodaemon) {
|
if (!args_info.foreground_flag) {
|
||||||
INFO("Forking to background...\n");
|
INFO("Forking to background...\n");
|
||||||
verbose = -1;
|
verbose = -1;
|
||||||
daemonize();
|
daemonize();
|
||||||
|
|||||||
24
pcsc-relay/src/pcsc-relay.ggo.in
Normal file
24
pcsc-relay/src/pcsc-relay.ggo.in
Normal 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>"
|
||||||
Reference in New Issue
Block a user