diff --git a/pcsc-relay/src/Makefile.am b/pcsc-relay/src/Makefile.am index 91bc563..52eafd3 100644 --- a/pcsc-relay/src/Makefile.am +++ b/pcsc-relay/src/Makefile.am @@ -3,8 +3,8 @@ EXTRA_DIST = picc.py bin_PROGRAMS = pcsc-relay bin_SCRIPTS = picc.py -pcsc_relay_SOURCES = pcsc-relay.c pcscutil.c opicc.c lnfc.c +pcsc_relay_SOURCES = pcsc-relay.c pcscutil.c opicc.c lnfc.c binutil.c pcsc_relay_LDADD = $(PCSC_LIBS) $(LIBNFC_LIBS) pcsc_relay_CFLAGS = $(PCSC_CFLAGS) $(LIBNFC_CFLAGS) -noinst_HEADERS = pcscutil.h pcsc-relay.h +noinst_HEADERS = pcscutil.h pcsc-relay.h binutil.h diff --git a/pcsc-relay/src/binutil.c b/pcsc-relay/src/binutil.c new file mode 120000 index 0000000..302cf29 --- /dev/null +++ b/pcsc-relay/src/binutil.c @@ -0,0 +1 @@ +../../ccid/src/binutil.c \ No newline at end of file diff --git a/pcsc-relay/src/binutil.h b/pcsc-relay/src/binutil.h new file mode 120000 index 0000000..b865ace --- /dev/null +++ b/pcsc-relay/src/binutil.h @@ -0,0 +1 @@ +../../ccid/src/binutil.h \ No newline at end of file diff --git a/pcsc-relay/src/lnfc.c b/pcsc-relay/src/lnfc.c index 7203a43..62bb604 100644 --- a/pcsc-relay/src/lnfc.c +++ b/pcsc-relay/src/lnfc.c @@ -127,22 +127,18 @@ static int lnfc_connect(void **driver_data) // Try to open the NFC emulator device data->pndTarget = nfc_connect (NULL); if (data->pndTarget == NULL) { - if (verbose || debug) - fprintf (stderr, "Error connecting NFC emulator device\n"); + ERROR("Error connecting NFC emulator device\n"); return 0; } - if (verbose) - printf ("Connected to the NFC emulator device: %s\n", data->pndTarget->acName); + INFO("Connected to the NFC emulator device: %s\n", data->pndTarget->acName); if (!nfc_target_init (data->pndTarget, &ntEmulatedTarget, data->abtCapdu, &data->szCapduLen)) { - if (verbose || debug) - fprintf (stderr, "%s", "Initialization of NFC emulator failed"); + ERROR("Initialization of NFC emulator failed"); nfc_disconnect (data->pndTarget); return 0; } - if (debug) - printf ("%s\n", "Done, relaying frames now!"); + DEBUG("%s\n", "Done, relaying frames now!"); return 1; @@ -170,7 +166,7 @@ static int lnfc_receive_capdu(void *driver_data, // Receive external reader command through target if (!nfc_target_receive_bytes(data->pndTarget, data->abtCapdu, &data->szCapduLen)) { - if (verbose || debug) + if (verbose >= 0) nfc_perror (data->pndTarget, "nfc_target_receive_bytes"); return 0; } @@ -189,7 +185,8 @@ static int lnfc_send_rapdu(void *driver_data, if (!nfc_target_send_bytes(data->pndTarget, rapdu, len)) { - nfc_perror (data->pndTarget, "nfc_target_send_bytes"); + if (verbose >= 0) + nfc_perror (data->pndTarget, "nfc_target_send_bytes"); return 0; } diff --git a/pcsc-relay/src/opicc.c b/pcsc-relay/src/opicc.c index e219ed4..f06b669 100644 --- a/pcsc-relay/src/opicc.c +++ b/pcsc-relay/src/opicc.c @@ -28,25 +28,27 @@ struct picc_data { size_t buflen; FILE *fd; }; -static size_t picc_encode_rapdu(const unsigned char *inbuf, size_t inlen, char **outbuf); -static size_t picc_decode_apdu(const char *inbuf, size_t inlen, unsigned char **outbuf); +static int picc_encode_rapdu(const unsigned char *inbuf, size_t inlen, + char **outbuf, size_t *outlen); +static int picc_decode_apdu(const char *inbuf, size_t inlen, + unsigned char **outbuf, size_t *outlen); -size_t picc_encode_rapdu(const unsigned char *inbuf, size_t inlen, char **outbuf) +int picc_encode_rapdu(const unsigned char *inbuf, size_t inlen, + char **outbuf, size_t *outlen) { char *p; const unsigned char *next; size_t length; if (!inbuf || inlen > 0xffff || !outbuf) - goto err; + return 0; length = 5+inlen*3+1; p = realloc(*outbuf, length); if (!p) { - if (debug || verbose) - fprintf(stderr, "Error allocating memory for encoded R-APDU\n"); - goto err; + ERROR("Error allocating memory for encoded R-APDU\n"); + return 0; } *outbuf = p; @@ -61,35 +63,38 @@ size_t picc_encode_rapdu(const unsigned char *inbuf, size_t inlen, char **outbuf p += 3; } - return length; - -err: - return 0; + *outlen = length; + return 1; } -size_t picc_decode_apdu(const char *inbuf, size_t inlen, unsigned char **outbuf) +int picc_decode_apdu(const char *inbuf, size_t inlen, + unsigned char **outbuf, size_t *outlen) { size_t pos, length; char *end, *p; unsigned long int b; - if (!outbuf || inbuf == NULL || inlen == 0 || inbuf[0] == '\0') { - /* Ignore invalid parameters, empty and 'RESET' lines */ - goto noapdu; + if (!outbuf || !outlen) { + /* Invalid parameters */ + return 0; + } + if (inbuf == NULL || inlen == 0 || inbuf[0] == '\0') { + /* Ignore empty and 'RESET' lines */ + *outlen = 0; + return 1; } length = strtoul(inbuf, &end, 16); /* check for ':' right behind the length */ if (inbuf+inlen < end+1 || end[0] != ':') - goto noapdu; + return 0; end++; p = realloc(*outbuf, length); if (!p) { - if (debug || verbose) - fprintf(stderr, "Error allocating memory for decoded C-APDU\n"); - goto noapdu; + ERROR("Error allocating memory for decoded C-APDU\n"); + return 0; } *outbuf = p; @@ -97,18 +102,16 @@ size_t picc_decode_apdu(const char *inbuf, size_t inlen, unsigned char **outbuf) while(inbuf+inlen > end && length > pos) { b = strtoul(end, &end, 16); if (b > 0xff) { - if (debug || verbose) - fprintf(stderr, "%s:%u Error decoding C-APDU\n", __FILE__, __LINE__); - goto noapdu; + ERROR( "%s:%u Error decoding C-APDU\n", __FILE__, __LINE__); + return 0; } (*outbuf)[pos++] = b; } - return length; + *outlen = length; -noapdu: - return 0; + return 1; } @@ -127,8 +130,7 @@ static int picc_connect(void **driver_data) data->fd = fopen(PICCDEV, "a+"); /*O_NOCTTY ?*/ if (!data->fd) { - if (debug || verbose) - fprintf(stderr,"Error opening %s\n", PICCDEV); + ERROR("Error opening %s\n", PICCDEV); return 0; } @@ -136,8 +138,7 @@ static int picc_connect(void **driver_data) data->buflen = 0; - if (debug || verbose) - printf("Connected to %s\n", PICCDEV); + INFO("Connected to %s\n", PICCDEV); return 1; } @@ -176,8 +177,7 @@ static int picc_receive_capdu(void *driver_data, linelen = getline(&buf, &buflen, data->fd); if (linelen < 0) { if (linelen < 0) { - if (debug || verbose) - fprintf(stderr,"Error reading from %s\n", PICCDEV); + ERROR("Error reading from %s\n", PICCDEV); return 0; } } @@ -187,12 +187,13 @@ static int picc_receive_capdu(void *driver_data, } fflush(data->fd); - if (debug) - printf("%s\n", buf); + DEBUG("%s\n", buf); /* decode C-APDU */ - *len = picc_decode_apdu(buf, linelen, capdu); + if (!picc_decode_apdu(buf, linelen, capdu, len)) + return 0; + return 1; } @@ -200,28 +201,29 @@ static int picc_receive_capdu(void *driver_data, static int picc_send_rapdu(void *driver_data, const unsigned char *rapdu, size_t len) { - size_t buflen; struct picc_data *data = driver_data; + size_t buflen; if (!data || !rapdu) return 0; /* encode R-APDU */ - buflen = picc_encode_rapdu(rapdu, len, &data->buf); - if (buflen > data->buflen) + if (!picc_encode_rapdu(rapdu, len, &data->buf, &buflen)) + return 0; + if (data->buflen < buflen) data->buflen = buflen; /* write R-APDU */ - if (debug) - printf("INF: Writing R-APDU\n\n%s\n\n", data->buf); + DEBUG("INF: Writing R-APDU\n\n%s\n\n", data->buf); if (fprintf(data->fd,"%s\r\n", (char *) data->buf) < 0 || fflush(data->fd) != 0) { return 0; } + return 1; } diff --git a/pcsc-relay/src/pcsc-relay.c b/pcsc-relay/src/pcsc-relay.c index a01c71c..548ad8a 100644 --- a/pcsc-relay/src/pcsc-relay.c +++ b/pcsc-relay/src/pcsc-relay.c @@ -29,17 +29,41 @@ #include #include +#include "binutil.h" #include "config.h" #include "pcsc-relay.h" #include "pcscutil.h" -struct rf_driver *driver = &driver_libnfc; +#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", + "Emulation 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 LPSTR readers = NULL; static SCARDCONTEXT hContext = 0; static SCARDHANDLE hCard = 0; -int verbose = 0, debug = 0; /* Forward declaration */ static void daemonize(); @@ -93,8 +117,9 @@ void cleanup(void) { int main (int argc, char **argv) { /*printf("%s:%d\n", __FILE__, __LINE__);*/ - void *buf = NULL; + unsigned char *buf = NULL; size_t buflen; + int i, oindex; BYTE outputBuffer[MAX_BUFFER_SIZE]; DWORD outputLength; @@ -102,34 +127,63 @@ int main (int argc, char **argv) LONG r = SCARD_S_SUCCESS; DWORD ctl, protocol; - char *read = NULL; - size_t readlen = 0; - - unsigned int readernum = 0; - struct sigaction new_sig, old_sig; - if (argc > 1) { - readernum = strtoul(argv[1], NULL, 10); - if (argc > 2) { - if (0 == strcmp(argv[2], "verbose")) + while (1) { + i = getopt_long(argc, argv, "hr:fe:v", options, &oindex); + if (i == -1) + 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++; - else if (0 == strcmp(argv[2], "debug")) - debug++; - else - goto parse_err; - if (argc > 3) { -parse_err: - fprintf(stderr, "Usage: " - "%s [reader number] [verbose | debug]\n", argv[0]); - exit(2); - } + 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 (!verbose && !debug) + + if (doinfo) { + fprintf(stderr, "%s written by Frank Morgner.\n" , + PACKAGE_STRING); + return 0; + } + + + if (dodaemon) { + verbose = -1; daemonize(); + } + /* Register signal handlers */ new_sig.sa_handler = cleanup_exit; @@ -144,6 +198,7 @@ parse_err: if (!driver->connect(&driver->data)) goto err; + /* connect to reader and card */ r = pcsc_connect(readernum, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_ANY, &hContext, &readers, &hCard, &protocol); @@ -152,13 +207,14 @@ parse_err: while(1) { - if (!driver->receive_capdu(driver->data, (unsigned char **) &buf, &buflen)) + /* get C-APDU */ + if (!driver->receive_capdu(driver->data, &buf, &buflen)) goto err; - if (!buflen) + if (!buflen || !buf) continue; - if (!verbose) - printb("C-APDU: ===================================================\n", buf, buflen); + if (verbose >= 0) + printb("C-APDU:\n", buf, buflen); /* transmit APDU to card */ @@ -167,9 +223,10 @@ parse_err: if (r != SCARD_S_SUCCESS) goto err; - if (!verbose) - printb("R-APDU:\n", outputBuffer, outputLength); + /* send R-APDU */ + if (verbose >= 0) + printb("R-APDU:\n", outputBuffer, outputLength); if (!driver->send_rapdu(driver->data, outputBuffer, outputLength)) goto err; diff --git a/pcsc-relay/src/pcsc-relay.h b/pcsc-relay/src/pcsc-relay.h index 4c3b787..b9c689a 100644 --- a/pcsc-relay/src/pcsc-relay.h +++ b/pcsc-relay/src/pcsc-relay.h @@ -37,11 +37,23 @@ struct rf_driver { const unsigned char *rapdu, size_t len); }; -extern int verbose, debug; +extern int verbose; extern struct rf_driver driver_openpicc; extern struct rf_driver driver_libnfc; +#define LEVEL_INFO 1 +#define LEVEL_DEBUG 2 +#define DEBUG(...) \ + {if (verbose >= LEVEL_DEBUG) \ + printf (__VA_ARGS__);} +#define INFO(...) \ + {if (verbose >= LEVEL_INFO) \ + printf (__VA_ARGS__);} +#define ERROR(...) \ + {if (verbose >= 0) \ + fprintf (stderr, __VA_ARGS__);} + #ifdef __cplusplus }