From 30f7c26cfd9ccc6dc82dff8553520791f2a7420a Mon Sep 17 00:00:00 2001 From: Ben Mehlman Date: Fri, 12 Aug 2016 20:39:51 +0000 Subject: [PATCH 1/6] Fix Lun not assigned for non-usb device. Fixes segfault, allows multiple serial readers. --- src/ifd-nfc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ifd-nfc.c b/src/ifd-nfc.c index acca73e..97ba2aa 100644 --- a/src/ifd-nfc.c +++ b/src/ifd-nfc.c @@ -422,9 +422,10 @@ IFDHCreateChannelByName(DWORD Lun, LPSTR DeviceName) memcpy(ifd_connstring + 8, filename, 3); ifdnfc->device = nfc_open(context, ifd_connstring); ifdnfc->connected = (ifdnfc->device) ? true : false; - ifdnfc->Lun = Lun; } - } + + ifdnfc->Lun = Lun; + free(vidpid); free(hpdriver); free(ifn); From 27040a99e0bdadf09832c3a6ed7986e03cf6683f Mon Sep 17 00:00:00 2001 From: Ben Mehlman Date: Fri, 12 Aug 2016 21:39:10 +0000 Subject: [PATCH 2/6] nfc_open serial device upon IFDHCreateChannelByName, same as usb has been. Fix calling nfc_open on already opened device. --- src/ifd-nfc.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/ifd-nfc.c b/src/ifd-nfc.c index 97ba2aa..eff6594 100644 --- a/src/ifd-nfc.c +++ b/src/ifd-nfc.c @@ -365,6 +365,15 @@ static bool ifdnfc_target_is_available(struct ifd_device *ifdnfc) return false; } +static bool ifdnfc_nfc_open(struct ifd_device *ifdnfc, nfc_connstring connstring) +{ + if(NULL == ifdnfc->device) { + ifdnfc->device = nfc_open(context, connstring); + ifdnfc->connected = (ifdnfc->device) ? true : false; + } + return ifdnfc->connected; +} + /* * List of Defined Functions Available to IFD_Handler 3.0 */ @@ -420,10 +429,11 @@ IFDHCreateChannelByName(DWORD Lun, LPSTR DeviceName) strcpy(ifd_connstring, "usb:xxx:xxx"); memcpy(ifd_connstring + 4, dirname, 3); memcpy(ifd_connstring + 8, filename, 3); - ifdnfc->device = nfc_open(context, ifd_connstring); - ifdnfc->connected = (ifdnfc->device) ? true : false; + ifdnfc_nfc_open(ifdnfc, ifd_connstring); } - + } else { + ifdnfc_nfc_open(ifdnfc, DeviceName); + } ifdnfc->Lun = Lun; free(vidpid); @@ -789,9 +799,7 @@ IFDHControl(DWORD Lun, DWORD dwControlCode, PUCHAR TxBuffer, DWORD TxLength, if ((TxLength - (1 + sizeof(u16ConnstringLength))) != u16ConnstringLength) return IFD_COMMUNICATION_ERROR; memcpy(ifd_connstring, TxBuffer + (1 + sizeof(u16ConnstringLength)), u16ConnstringLength); - ifdnfc->device = nfc_open(context, ifd_connstring); - ifdnfc->connected = (ifdnfc->device) ? true : false; - ifdnfc->Lun = Lun; + ifdnfc_nfc_open(ifdnfc, ifd_connstring); ifdnfc->secure_element_as_card = (TxBuffer[0] == IFDNFC_SET_ACTIVE_SE); } break; From 78451b04c9c74dcfccb80a90081af03a1a9f1683 Mon Sep 17 00:00:00 2001 From: Ben Mehlman Date: Fri, 12 Aug 2016 23:06:10 +0000 Subject: [PATCH 3/6] Use pcscd polling (IFDHICCPresence) to retry nfc_open periodically if device wasn't responding the first time. --- src/ifd-nfc.c | 25 +++++++++++++++++++++++-- src/ifd-nfc.h | 4 ++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/ifd-nfc.c b/src/ifd-nfc.c index eff6594..4d4972f 100644 --- a/src/ifd-nfc.c +++ b/src/ifd-nfc.c @@ -100,6 +100,7 @@ void log_msg(const int priority, const char *fmt, ...) #include #include #include +#include /* * This implementation was written based on information provided by the @@ -128,6 +129,8 @@ struct ifd_device { bool connected; bool secure_element_as_card; int Lun; + time_t open_attempted_at; + char *ifd_connstring; }; nfc_context *context = NULL; @@ -168,6 +171,10 @@ static void ifdnfc_disconnect(struct ifd_device *ifdnfc) ifdnfc->connected = false; ifdnfc->device = NULL; ifdnfc->Lun = -1; + if(ifdnfc->ifd_connstring != NULL) { + free(ifdnfc->ifd_connstring); + ifdnfc->ifd_connstring = NULL; + } } } @@ -368,6 +375,13 @@ static bool ifdnfc_target_is_available(struct ifd_device *ifdnfc) static bool ifdnfc_nfc_open(struct ifd_device *ifdnfc, nfc_connstring connstring) { if(NULL == ifdnfc->device) { + // save connstring for later use, in case we need to retry + if(ifdnfc->ifd_connstring == NULL) + if((ifdnfc->ifd_connstring = strdup(connstring)) == NULL) { + Log1(PCSC_LOG_ERROR, "The strdup of ifd_connstring failed (malloc)."); + return false; + } + ifdnfc->open_attempted_at = time(NULL); ifdnfc->device = nfc_open(context, connstring); ifdnfc->connected = (ifdnfc->device) ? true : false; } @@ -410,6 +424,7 @@ IFDHCreateChannelByName(DWORD Lun, LPSTR DeviceName) ifdnfc->device = NULL; ifdnfc->connected = false; ifdnfc->slot.present = false; + ifdnfc->open_attempted_at = (time_t)0; // USB DeviceNames can be immediately handled, e.g.: // usb:1fd3/0608:libudev:0:/dev/bus/usb/002/079 @@ -764,8 +779,14 @@ IFDHICCPresence(DWORD Lun) if (device_index < 0) return IFD_COMMUNICATION_ERROR; struct ifd_device *ifdnfc = &ifd_devices[device_index]; - if (!ifdnfc->connected) - return IFD_ICC_NOT_PRESENT; + + if (!ifdnfc->connected) { + if(time(NULL) - ifdnfc->open_attempted_at < IFD_NFC_OPEN_RETRY_INTERVAL) + return IFD_ICC_NOT_PRESENT; + if(!ifdnfc_nfc_open(ifdnfc, ifdnfc->ifd_connstring)) + return IFD_ICC_NOT_PRESENT; + } + if (ifdnfc->secure_element_as_card) return ifdnfc->slot.present ? IFD_SUCCESS : IFD_ICC_NOT_PRESENT; // If available once, available forever :) return ifdnfc_target_is_available(ifdnfc) ? IFD_SUCCESS : IFD_ICC_NOT_PRESENT; diff --git a/src/ifd-nfc.h b/src/ifd-nfc.h index 210990c..ed9b3fd 100644 --- a/src/ifd-nfc.h +++ b/src/ifd-nfc.h @@ -31,4 +31,8 @@ #define IFDNFC_SET_ACTIVE_SE 2 #define IFDNFC_GET_STATUS 3 +#ifndef IFD_NFC_OPEN_RETRY_INTERVAL +#define IFD_NFC_OPEN_RETRY_INTERVAL 10 +#endif + #endif From 4ed7f6727ead9920295196a62c72a58fca722e72 Mon Sep 17 00:00:00 2001 From: Ben Mehlman Date: Mon, 15 Aug 2016 16:31:03 +0000 Subject: [PATCH 4/6] Don't retry nfc_open if was shut down via ifdnfc-activate, or if in SE mode. --- src/ifd-nfc.c | 8 +++++++- src/ifdnfc-activate.c | 5 +++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/ifd-nfc.c b/src/ifd-nfc.c index 4d4972f..ed94a68 100644 --- a/src/ifd-nfc.c +++ b/src/ifd-nfc.c @@ -131,6 +131,7 @@ struct ifd_device { int Lun; time_t open_attempted_at; char *ifd_connstring; + int mode; }; nfc_context *context = NULL; @@ -176,6 +177,7 @@ static void ifdnfc_disconnect(struct ifd_device *ifdnfc) ifdnfc->ifd_connstring = NULL; } } + ifdnfc->mode = IFDNFC_SET_INACTIVE; } static bool ifdnfc_target_to_atr(struct ifd_device *ifdnfc) @@ -425,6 +427,7 @@ IFDHCreateChannelByName(DWORD Lun, LPSTR DeviceName) ifdnfc->connected = false; ifdnfc->slot.present = false; ifdnfc->open_attempted_at = (time_t)0; + ifdnfc->mode = IFDNFC_SET_ACTIVE; // USB DeviceNames can be immediately handled, e.g.: // usb:1fd3/0608:libudev:0:/dev/bus/usb/002/079 @@ -781,7 +784,8 @@ IFDHICCPresence(DWORD Lun) struct ifd_device *ifdnfc = &ifd_devices[device_index]; if (!ifdnfc->connected) { - if(time(NULL) - ifdnfc->open_attempted_at < IFD_NFC_OPEN_RETRY_INTERVAL) + Log2(PCSC_LOG_DEBUG, "ifdnfc->mode=%d.", ifdnfc->mode); + if(ifdnfc->mode != IFDNFC_SET_ACTIVE || time(NULL) - ifdnfc->open_attempted_at < IFD_NFC_OPEN_RETRY_INTERVAL) return IFD_ICC_NOT_PRESENT; if(!ifdnfc_nfc_open(ifdnfc, ifdnfc->ifd_connstring)) return IFD_ICC_NOT_PRESENT; @@ -823,6 +827,7 @@ IFDHControl(DWORD Lun, DWORD dwControlCode, PUCHAR TxBuffer, DWORD TxLength, ifdnfc_nfc_open(ifdnfc, ifd_connstring); ifdnfc->secure_element_as_card = (TxBuffer[0] == IFDNFC_SET_ACTIVE_SE); } + ifdnfc->mode = *TxBuffer; break; case IFDNFC_SET_INACTIVE: ifdnfc_disconnect(ifdnfc); @@ -857,5 +862,6 @@ IFDHControl(DWORD Lun, DWORD dwControlCode, PUCHAR TxBuffer, DWORD TxLength, return IFD_ERROR_NOT_SUPPORTED; } + return IFD_SUCCESS; } diff --git a/src/ifdnfc-activate.c b/src/ifdnfc-activate.c index 90ecec5..c713f18 100644 --- a/src/ifdnfc-activate.c +++ b/src/ifdnfc-activate.c @@ -76,6 +76,11 @@ main(int argc, char *argv[]) if (rv < 0) goto pcsc_error; + int count; + for (reader = mszReaders, count = 0; ++count < dwReaders; reader += strlen(reader) + 1) { + printf("READER: '%s'\n", reader); + } + int l; for (reader = mszReaders; dwReaders > 0; From a2aad50c883ea56c5c7dd610a1192e8e117bf287 Mon Sep 17 00:00:00 2001 From: Ben Mehlman Date: Thu, 18 Aug 2016 19:40:01 +0000 Subject: [PATCH 5/6] cleanup of ifdnfc-activate. Support connect retry and multiple ifdnfc serial devices, fix protocol buffer overflows. --- src/ifd-nfc.c | 114 +++++++++------ src/ifd-nfc.h | 13 ++ src/ifdnfc-activate.c | 332 ++++++++++++++++++++++++------------------ 3 files changed, 270 insertions(+), 189 deletions(-) diff --git a/src/ifd-nfc.c b/src/ifd-nfc.c index ed94a68..dc5424b 100644 --- a/src/ifd-nfc.c +++ b/src/ifd-nfc.c @@ -68,6 +68,7 @@ void log_msg(const int priority, const char *fmt, ...) syslog(syslog_level, "%s", debug_buffer); } + #define Log0(priority) log_msg(priority, "%s:%d:%s()", __FILE__, __LINE__, __FUNCTION__) #define Log1(priority, fmt) log_msg(priority, "%s:%d:%s() " fmt, __FILE__, __LINE__, __FUNCTION__) #define Log2(priority, fmt, data) log_msg(priority, "%s:%d:%s() " fmt, __FILE__, __LINE__, __FUNCTION__, data) @@ -102,6 +103,8 @@ void log_msg(const int priority, const char *fmt, ...) #include #include +extern char *strdup(char *); + /* * This implementation was written based on information provided by the * following documents: @@ -171,11 +174,6 @@ static void ifdnfc_disconnect(struct ifd_device *ifdnfc) nfc_close(ifdnfc->device); ifdnfc->connected = false; ifdnfc->device = NULL; - ifdnfc->Lun = -1; - if(ifdnfc->ifd_connstring != NULL) { - free(ifdnfc->ifd_connstring); - ifdnfc->ifd_connstring = NULL; - } } ifdnfc->mode = IFDNFC_SET_INACTIVE; } @@ -377,15 +375,25 @@ static bool ifdnfc_target_is_available(struct ifd_device *ifdnfc) static bool ifdnfc_nfc_open(struct ifd_device *ifdnfc, nfc_connstring connstring) { if(NULL == ifdnfc->device) { - // save connstring for later use, in case we need to retry - if(ifdnfc->ifd_connstring == NULL) - if((ifdnfc->ifd_connstring = strdup(connstring)) == NULL) { - Log1(PCSC_LOG_ERROR, "The strdup of ifd_connstring failed (malloc)."); - return false; + // if we are passed a connect string, save it for later use + // for example we save the connstring passed in IFDHCreateChannelByName and use it for + // connect attempts in IFDHICCPresence or in IFDHControl. + if(connstring != NULL && strchr(connstring, ':') != NULL) { + if(ifdnfc->ifd_connstring == NULL) + ifdnfc->ifd_connstring = malloc(strlen(connstring)); + else + ifdnfc->ifd_connstring = realloc(ifdnfc->ifd_connstring, strlen(connstring)); + if(ifdnfc->ifd_connstring == NULL) { + Log1(PCSC_LOG_ERROR, "The strdup of ifd_connstring failed (malloc/realloc)."); + return false; } - ifdnfc->open_attempted_at = time(NULL); - ifdnfc->device = nfc_open(context, connstring); - ifdnfc->connected = (ifdnfc->device) ? true : false; + strcpy(ifdnfc->ifd_connstring, connstring); + } + if(ifdnfc->ifd_connstring != NULL && *ifdnfc->ifd_connstring != 0) { + ifdnfc->open_attempted_at = time(NULL); + ifdnfc->device = nfc_open(context, ifdnfc->ifd_connstring); + ifdnfc->connected = (ifdnfc->device != NULL ? true : false); + } } return ifdnfc->connected; } @@ -427,7 +435,7 @@ IFDHCreateChannelByName(DWORD Lun, LPSTR DeviceName) ifdnfc->connected = false; ifdnfc->slot.present = false; ifdnfc->open_attempted_at = (time_t)0; - ifdnfc->mode = IFDNFC_SET_ACTIVE; + ifdnfc->mode = IFDNFC_SET_INACTIVE; // USB DeviceNames can be immediately handled, e.g.: // usb:1fd3/0608:libudev:0:/dev/bus/usb/002/079 @@ -448,9 +456,16 @@ IFDHCreateChannelByName(DWORD Lun, LPSTR DeviceName) memcpy(ifd_connstring + 4, dirname, 3); memcpy(ifd_connstring + 8, filename, 3); ifdnfc_nfc_open(ifdnfc, ifd_connstring); + ifdnfc->mode = IFDNFC_SET_ACTIVE; } } else { - ifdnfc_nfc_open(ifdnfc, DeviceName); + if(DeviceName != NULL && strchr(DeviceName, ':') != NULL) { + // Compatibility with prior versions of code: If devicename does not contain a colon, it has not been configured + // as a valid nfc_connstring. Do not go into ACTIVE mode, wait for control message from ifdnfc-activate. + // But if there is a colon, go into ACTIVE mode now. + ifdnfc_nfc_open(ifdnfc, DeviceName); + ifdnfc->mode = IFDNFC_SET_ACTIVE; + } } ifdnfc->Lun = Lun; @@ -490,6 +505,12 @@ IFDHCloseChannel(DWORD Lun) struct ifd_device *ifdnfc = &ifd_devices[device_index]; ifdnfc_disconnect(ifdnfc); + ifdnfc->Lun = -1; + if(ifdnfc->ifd_connstring != NULL) { + free(ifdnfc->ifd_connstring); + ifdnfc->ifd_connstring = NULL; + } + // Check if there are still devices used int i; for (i = 0; i < IFDNFC_MAX_DEVICES; i++) @@ -784,9 +805,13 @@ IFDHICCPresence(DWORD Lun) struct ifd_device *ifdnfc = &ifd_devices[device_index]; if (!ifdnfc->connected) { - Log2(PCSC_LOG_DEBUG, "ifdnfc->mode=%d.", ifdnfc->mode); - if(ifdnfc->mode != IFDNFC_SET_ACTIVE || time(NULL) - ifdnfc->open_attempted_at < IFD_NFC_OPEN_RETRY_INTERVAL) + // check that we are in an active mode + if(!(ifdnfc->mode == IFDNFC_SET_ACTIVE || ifdnfc->mode == IFDNFC_SET_ACTIVE_SE)) + return IFD_ICC_NOT_PRESENT; + // check that enough time has elapsed since the last attempt + if(time(NULL) - ifdnfc->open_attempted_at < IFD_NFC_OPEN_RETRY_INTERVAL) return IFD_ICC_NOT_PRESENT; + // try to open if(!ifdnfc_nfc_open(ifdnfc, ifdnfc->ifd_connstring)) return IFD_ICC_NOT_PRESENT; } @@ -811,26 +836,22 @@ IFDHControl(DWORD Lun, DWORD dwControlCode, PUCHAR TxBuffer, DWORD TxLength, switch (dwControlCode) { case IFDNFC_CTRL_ACTIVE: - if (TxLength < 1 || !TxBuffer || RxLength < 1 || !RxBuffer) + if (TxLength != sizeof(IFDNFC_CONTROL_REQ) || !TxBuffer || RxLength != sizeof(IFDNFC_CONTROL_RESP) || !RxBuffer) return IFD_COMMUNICATION_ERROR; - switch (*TxBuffer) { + IFDNFC_CONTROL_REQ *req = (IFDNFC_CONTROL_REQ *)TxBuffer; + IFDNFC_CONTROL_RESP *rsp = (IFDNFC_CONTROL_RESP *)RxBuffer; + + switch (req->command) { case IFDNFC_SET_ACTIVE: - case IFDNFC_SET_ACTIVE_SE: { - uint16_t u16ConnstringLength; - if (TxLength < (1 + sizeof(u16ConnstringLength))) - return IFD_COMMUNICATION_ERROR; - memcpy(&u16ConnstringLength, TxBuffer + 1, sizeof(u16ConnstringLength)); - if ((TxLength - (1 + sizeof(u16ConnstringLength))) != u16ConnstringLength) - return IFD_COMMUNICATION_ERROR; - memcpy(ifd_connstring, TxBuffer + (1 + sizeof(u16ConnstringLength)), u16ConnstringLength); - ifdnfc_nfc_open(ifdnfc, ifd_connstring); - ifdnfc->secure_element_as_card = (TxBuffer[0] == IFDNFC_SET_ACTIVE_SE); - } - ifdnfc->mode = *TxBuffer; - break; + case IFDNFC_SET_ACTIVE_SE: + ifdnfc_nfc_open(ifdnfc, req->connstring); + ifdnfc->secure_element_as_card = (req->command == IFDNFC_SET_ACTIVE_SE); + ifdnfc->mode = req->command; + break; case IFDNFC_SET_INACTIVE: ifdnfc_disconnect(ifdnfc); + ifdnfc->mode = req->command; break; case IFDNFC_GET_STATUS: break; @@ -843,25 +864,24 @@ IFDHControl(DWORD Lun, DWORD dwControlCode, PUCHAR TxBuffer, DWORD TxLength, return IFD_COMMUNICATION_ERROR; } - if ((ifdnfc->connected) && ((!ifdnfc->secure_element_as_card) || ifdnfc_se_is_available(ifdnfc))) { - Log1(PCSC_LOG_INFO, "IFD-handler for libnfc is active."); - RxBuffer[0] = IFDNFC_IS_ACTIVE; - const uint16_t u16ConnstringLength = strlen(ifd_connstring) + 1; - memcpy(RxBuffer + 1, &u16ConnstringLength, sizeof(u16ConnstringLength)); - memcpy(RxBuffer + 1 + sizeof(u16ConnstringLength), ifd_connstring, u16ConnstringLength); - if (pdwBytesReturned) - *pdwBytesReturned = 1 + sizeof(u16ConnstringLength) + u16ConnstringLength; - } else { - Log1(PCSC_LOG_INFO, "IFD-handler for libnfc is inactive."); - if (pdwBytesReturned) - *pdwBytesReturned = 1; - *RxBuffer = IFDNFC_IS_INACTIVE; - } + memset(rsp, 0, sizeof(IFDNFC_CONTROL_RESP)); + rsp->mode = ifdnfc->mode; + rsp->connected = ifdnfc->connected; + if(ifdnfc->ifd_connstring != NULL) + strncpy(rsp->connstring, ifdnfc->ifd_connstring, sizeof(nfc_connstring)-1); + + if (ifdnfc->connected && ifdnfc->secure_element_as_card && ifdnfc_se_is_available(ifdnfc)) + rsp->se_avail = 1; + + *pdwBytesReturned = sizeof(IFDNFC_CONTROL_RESP); + + Log9(PCSC_LOG_INFO, "Lun '%0x', mode='%d', connected='%s', se='%s', connstring='%s'.", + Lun, rsp->mode, (rsp->connected ? "Yes" : "No"), (rsp->se_avail ? "Yes" : "No"), rsp->connstring, + NULL, NULL, NULL); break; default: return IFD_ERROR_NOT_SUPPORTED; } - return IFD_SUCCESS; } diff --git a/src/ifd-nfc.h b/src/ifd-nfc.h index ed9b3fd..cfe542f 100644 --- a/src/ifd-nfc.h +++ b/src/ifd-nfc.h @@ -35,4 +35,17 @@ #define IFD_NFC_OPEN_RETRY_INTERVAL 10 #endif +#include +typedef struct { + int command; + nfc_connstring connstring; +} IFDNFC_CONTROL_REQ; + +typedef struct { + int mode; + int connected; + int se_avail; + nfc_connstring connstring; +} IFDNFC_CONTROL_RESP; + #endif diff --git a/src/ifdnfc-activate.c b/src/ifdnfc-activate.c index c713f18..e413cc7 100644 --- a/src/ifdnfc-activate.c +++ b/src/ifdnfc-activate.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #define MAX_DEVICE_COUNT 16 @@ -33,104 +35,39 @@ typedef uint32_t DWORD; typedef uint8_t BYTE; #endif -int -main(int argc, char *argv[]) -{ - LONG rv; - SCARDCONTEXT hContext; - SCARDHANDLE hCard; - char *reader; - BYTE pbSendBuffer[1 + 1 + sizeof(nfc_connstring)]; - DWORD dwSendLength; - BYTE pbRecvBuffer[1]; - DWORD dwActiveProtocol, dwRecvLength, dwReaders; - char* mszReaders = NULL; - - if (argc == 1 || - (argc == 2 && (strncmp(argv[1], "yes", strlen("yes")) == 0))) - pbSendBuffer[0] = IFDNFC_SET_ACTIVE; - else if (argc == 2 && (strncmp(argv[1], "no", strlen("no")) == 0)) - pbSendBuffer[0] = IFDNFC_SET_INACTIVE; - else if (argc == 2 && (strncmp(argv[1], "se", strlen("se")) == 0)) - pbSendBuffer[0] = IFDNFC_SET_ACTIVE_SE; - else if (argc == 2 && (strncmp(argv[1], "status", strlen("status")) == 0)) - pbSendBuffer[0] = IFDNFC_GET_STATUS; - else { - printf("Usage: %s [yes|no|status]\n", argv[0]); - exit(EXIT_FAILURE); - } - - - rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); - if (rv < 0) - goto pcsc_error; - - dwReaders = 0; - // Ask how many bytes readers list take - rv = SCardListReaders(hContext, NULL, NULL, &dwReaders); - if (rv < 0) - goto pcsc_error; - // Then allocate and fill mszReaders - mszReaders = malloc(dwReaders); - rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders); - if (rv < 0) - goto pcsc_error; - - int count; - for (reader = mszReaders, count = 0; ++count < dwReaders; reader += strlen(reader) + 1) { - printf("READER: '%s'\n", reader); - } - - int l; - for (reader = mszReaders; - dwReaders > 0; - l = strlen(reader) + 1, dwReaders -= l, reader += l) { - if (strcmp(IFDNFC_READER_NAME, reader) <= 0) - break; - } - if (dwReaders <= 0) { - printf("Could not find a reader named: %s\n", IFDNFC_READER_NAME); - rv = SCARD_E_NO_READERS_AVAILABLE; - goto pcsc_error; +char *mode_to_str(int mode) { + switch(mode) { + case IFDNFC_SET_INACTIVE: + return "Inactive"; + case IFDNFC_SET_ACTIVE: + return "Active"; + case IFDNFC_SET_ACTIVE_SE: + return "Active Secure Element"; + default: + return "Undefined"; } +} - // TODO Handle multiple ifdnfc instance for multiple NFC device ? - rv = SCardConnect(hContext, reader, SCARD_SHARE_DIRECT, 0, &hCard, - &dwActiveProtocol); - if (rv < 0) - goto pcsc_error; - - if ((pbSendBuffer[0] == IFDNFC_SET_ACTIVE) || (pbSendBuffer[0] == IFDNFC_SET_ACTIVE_SE)) { - const BYTE command = pbSendBuffer[0]; - // To correctly probe NFC devices, ifdnfc must be disactivated first - pbSendBuffer[0] = IFDNFC_SET_INACTIVE; - dwSendLength = 1; - rv = SCardControl(hCard, IFDNFC_CTRL_ACTIVE, pbSendBuffer, - dwSendLength, pbRecvBuffer, sizeof(pbRecvBuffer), - &dwRecvLength); - if (rv < 0) { - goto pcsc_error; - } +int get_connstring(nfc_connstring *pConnstring) { + + (*pConnstring)[0] = 0; - pbSendBuffer[0] = command; // Initialize libnfc nfc_context *context; nfc_init(&context); if (context == NULL) { - fprintf(stderr, "Unable to init libnfc (malloc)\n"); - goto error; + fprintf(stderr, "Unable to init libnfc: %s\n", strerror(errno)); + return -1; } - // Allocate nfc_connstring array + + // List devices nfc_connstring connstrings[MAX_DEVICE_COUNT]; - // List devices size_t szDeviceFound = nfc_list_devices(context, connstrings, MAX_DEVICE_COUNT); - int connstring_index = -1; + int connstring_index = -1, selection; switch (szDeviceFound) { case 0: fprintf(stderr, "Unable to activate ifdnfc: no NFC device found.\n"); - nfc_exit(context); - goto error; break; case 1: // Only one NFC device available, so auto-select it! @@ -145,84 +82,195 @@ main(int argc, char *argv[]) printf("[%d] %s\t (%s)\n", (int)i, nfc_device_get_name(pnd), nfc_device_get_connstring(pnd)); nfc_close(pnd); } else { - fprintf(stderr, "nfc_open failed for %s\n", connstrings[i]); + fprintf(stderr, "nfc_open failed for %s.\n", connstrings[i]); } } - // libnfc isn't needed anymore - nfc_exit(context); + printf(">> "); // Take user's choice - if (1 != scanf("%2d", &connstring_index)) { + if (1 != scanf("%2d", &selection)) { fprintf(stderr, "Value must an integer.\n"); - goto error; + break; } - if ((connstring_index < 0) || (connstring_index >= (int)szDeviceFound)) { + if ((selection < 0) || (selection >= (int)szDeviceFound)) { fprintf(stderr, "Invalid index selection.\n"); - goto error; + break; } + connstring_index = selection; break; } - printf("Activating ifdnfc with \"%s\"...\n", connstrings[connstring_index]); - // pbSendBuffer = { IFDNFC_SET_ACTIVE (1 byte), length (2 bytes), nfc_connstring (lenght bytes)} - const uint16_t u16ConnstringLength = strlen(connstrings[connstring_index]) + 1; - memcpy(pbSendBuffer + 1, &u16ConnstringLength, sizeof(u16ConnstringLength)); - memcpy(pbSendBuffer + 1 + sizeof(u16ConnstringLength), connstrings[connstring_index], u16ConnstringLength); - dwSendLength = 1 + sizeof(u16ConnstringLength) + u16ConnstringLength; - } else { - // pbSendBuffer[0] != IFDNFC_SET_ACTIVE - dwSendLength = 1; - } + nfc_exit(context); + if(connstring_index > -1) { + strncpy(*pConnstring, connstrings[connstring_index], sizeof(nfc_connstring)); + (*pConnstring)[sizeof(nfc_connstring)-1] = 0; + return 0; + } + return 1; +} - rv = SCardControl(hCard, IFDNFC_CTRL_ACTIVE, pbSendBuffer, - dwSendLength, pbRecvBuffer, sizeof(pbRecvBuffer), - &dwRecvLength); - if (rv < 0) { - goto pcsc_error; - } - if (dwRecvLength < 1) { - rv = SCARD_F_INTERNAL_ERROR; - goto pcsc_error; +int print_status(char *reader, IFDNFC_CONTROL_RESP *rxmsg, int rxlen) { + if(rxlen != sizeof(IFDNFC_CONTROL_RESP)) { + printf("Reader '%s', PCSC Control Error (while getting status): %d length response from PCSC, expected %d.\n", + reader, rxlen, sizeof(rxmsg)); + return -1; } + printf("Reader '%s', mode='%s', connected='%s', se='%s', connstring='%s'.\n", + reader, mode_to_str(rxmsg->mode), + (rxmsg->connected ? "Yes" : "No"), + (rxmsg->se_avail ? "Yes" : "No"), + rxmsg->connstring); + return 0; +} - switch (pbRecvBuffer[0]) { - case IFDNFC_IS_ACTIVE: { - uint16_t u16ConnstringLength; - if (dwRecvLength < (1 + sizeof(u16ConnstringLength))) { - rv = SCARD_F_INTERNAL_ERROR; - goto pcsc_error; - } - memcpy(&u16ConnstringLength, pbRecvBuffer + 1, sizeof(u16ConnstringLength)); - if ((dwRecvLength - (1 + sizeof(u16ConnstringLength))) != u16ConnstringLength) { - rv = SCARD_F_INTERNAL_ERROR; - goto pcsc_error; - } - nfc_connstring connstring; - memcpy(connstring, pbRecvBuffer + 1 + sizeof(u16ConnstringLength), u16ConnstringLength); - printf("%s is active using %s.\n", IFDNFC_READER_NAME, connstring); - } - break; - case IFDNFC_IS_INACTIVE: - printf("%s is inactive.\n", IFDNFC_READER_NAME); +int +main(int argc, char *argv[]) +{ + LONG rv; + SCARDCONTEXT hContext; + SCARDHANDLE hCard; + char *reader; + DWORD dwActiveProtocol, rxlen, dwReaders; + char* mszReaders = NULL; + char *devicename_prefix = IFDNFC_READER_NAME; + + IFDNFC_CONTROL_REQ txmsg; + IFDNFC_CONTROL_RESP rxmsg; + + nfc_connstring connstring; + + int command = -1; + + switch(argc) { + case 1: + command = IFDNFC_SET_ACTIVE; + break; + case 2: + case 3: + if(!strcmp(argv[1], "yes")) + command = IFDNFC_SET_ACTIVE; + else + if(!strcmp(argv[1], "no")) + command = IFDNFC_SET_INACTIVE; + else + if(!strcmp(argv[1], "se")) + command = IFDNFC_SET_ACTIVE_SE; + else + if(!strcmp(argv[1], "status")) + command = IFDNFC_GET_STATUS; + if(argc == 3) + devicename_prefix = argv[2]; break; default: - rv = SCARD_F_INTERNAL_ERROR; - goto pcsc_error; + break; } + if(command < 0) { + printf("Usage: %s [yes|no|status] [nameprefix]\n", argv[0]); + exit(EXIT_FAILURE); + } + + if((rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext)) < 0) { + printf("SCardEstablishContext Error: %s\n", pcsc_stringify_error(rv)); + exit(EXIT_FAILURE); + } - rv = SCardDisconnect(hCard, SCARD_LEAVE_CARD); - if (rv < 0) - goto pcsc_error; + dwReaders = 0; + // Ask how many bytes readers list take + if((rv = SCardListReaders(hContext, NULL, NULL, &dwReaders)) >= 0) { + // Then allocate and fill mszReaders + mszReaders = malloc(dwReaders); + rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders); + } + if(rv < 0) { + printf("SCardListReaders Error: %s\n", pcsc_stringify_error(rv)); + free(mszReaders); + exit(EXIT_FAILURE); + } - free(mszReaders); + int l, foundcount = 0, prefixlen = strlen(devicename_prefix); + for(reader = mszReaders; dwReaders > 0; l = strlen(reader) + 1, dwReaders -= l, reader += l) { + // If reader FRIENDLYNAME does not start with "IFD-NFC" (the default) or specified prefix, we skip it. + printf("'%s' '%s' %d\n", devicename_prefix, reader, prefixlen); + if(strncmp(devicename_prefix, reader, prefixlen) != 0) + continue; - exit(EXIT_SUCCESS); + foundcount++; -pcsc_error: - puts(pcsc_stringify_error(rv)); -error: - if (mszReaders) - free(mszReaders); + if((rv = SCardConnect(hContext, reader, SCARD_SHARE_DIRECT, 0, &hCard, &dwActiveProtocol)) < 0) { + printf("Reader '%s', SCardConnect Error: %s\n", reader, pcsc_stringify_error(rv)); + continue; + } + + switch(command) { + case IFDNFC_SET_ACTIVE: + case IFDNFC_SET_ACTIVE_SE: + if(!strcmp(devicename_prefix, IFDNFC_READER_NAME)) { + // Backward compatibility, if friendlyname is just "IFD-NFC" then we assume that there is one and only one + // device that we are accessing through ifdnfc, and that DEVICENAME is missing or not meaningful, eg: + // FRIENDLYNAME "IFD-NFC" + memset(&txmsg, 0, sizeof(txmsg)); + txmsg.command = IFDNFC_SET_INACTIVE; + if((rv = SCardControl(hCard, IFDNFC_CTRL_ACTIVE, &txmsg, sizeof(txmsg), &rxmsg, sizeof(rxmsg), &rxlen)) < 0) { + printf("Reader '%s', SCardControl Error (Setting Inactive): %s\n", reader, pcsc_stringify_error(rv)); + break; + } + if(get_connstring(&connstring) != 0) { + printf("Reader '%s', did not get NFC connect string so can't activate.\n", reader); + break; + } + printf("Reader '%s', activating ifdnfc with '%s'.\n", reader, connstring); + } else { + // In the new, multiple-device capable method, FRIENLYNAME should be in the form IFD-NFC-unique, + // and DEVICENAME must be the libnfc connstring, eg, /etc/readers.d/reader_1.conf: + // FRIENDLYNAME "IFD-NFC-NXP-PN532.1" + // DEVICENAME pn532_uart:/dev/ttyS0 + // LIBPATH /usr/lib/pcsc/drivers/ifdnfc.bundle/Contents/Linux/libifdnfc.so.0.1.4 + // Since pcscd passes DEVICENAME to ifdnfc, we don't need to know it here. + printf("Reader '%s', activating ifdnfc using nfc_connstring in pcscd DEVICENAME.\n", reader); + connstring[0] = 0; + } + memset(&txmsg, 0, sizeof(txmsg)); + txmsg.command = command; + strncpy(txmsg.connstring, connstring, sizeof(txmsg.connstring)); + txmsg.connstring[sizeof(txmsg.connstring)-1] = 0; + // pbSendBuf = { IFDNFC_SET_ACTIVE (1 byte), length (2 bytes), nfc_connstring (lenght bytes)} + if((rv = SCardControl(hCard, IFDNFC_CTRL_ACTIVE, &txmsg, sizeof(txmsg), &rxmsg, sizeof(rxmsg), &rxlen)) < 0) { + printf("Reader '%s', SCardControl Error (while setting mode %d): %s\n", reader, command, pcsc_stringify_error(rv)); + break; + } + print_status(reader, &rxmsg, rxlen); + break; + case IFDNFC_SET_INACTIVE: + memset(&txmsg, 0, sizeof(txmsg)); + txmsg.command = command; + if((rv = SCardControl(hCard, IFDNFC_CTRL_ACTIVE, &txmsg, sizeof(txmsg), &rxmsg, sizeof(rxmsg), &rxlen)) < 0) { + printf("Reader '%s', SCardControl Error (while setting Inactive): %s\n", reader, pcsc_stringify_error(rv)); + break; + } + print_status(reader, &rxmsg, rxlen); + break; + case IFDNFC_GET_STATUS: + memset(&txmsg, 0, sizeof(txmsg)); + txmsg.command = command; + if((rv = SCardControl(hCard, IFDNFC_CTRL_ACTIVE, &txmsg, sizeof(txmsg), &rxmsg, sizeof(rxmsg), &rxlen)) < 0) { + printf("Reader '%s', SCardControl Error (while getting status): %s\n", reader, pcsc_stringify_error(rv)); + break; + } + print_status(reader, &rxmsg, rxlen); + break; + default: + printf("Invalid command number: %d.\n", command); + } + } - exit(EXIT_FAILURE); + if((rv = SCardDisconnect(hCard, SCARD_LEAVE_CARD)) < 0) { + printf("SCardDisconnect Error: %s\n", pcsc_stringify_error(rv)); + } + free(mszReaders); + + if(!foundcount) { + printf("Could not find any pcsc readers with name prefix of: %s. Check your configuration.\n", IFDNFC_READER_NAME); + exit(EXIT_FAILURE); + } + exit(EXIT_SUCCESS); } From edcfbe01def9eb4321324f18f34330743b76ed62 Mon Sep 17 00:00:00 2001 From: Ben Mehlman Date: Thu, 1 Sep 2016 19:50:15 +0000 Subject: [PATCH 6/6] Remove strdup prototype. Since strdup isn't posix we eliminated it. --- src/ifd-nfc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ifd-nfc.c b/src/ifd-nfc.c index dc5424b..102d7cb 100644 --- a/src/ifd-nfc.c +++ b/src/ifd-nfc.c @@ -103,8 +103,6 @@ void log_msg(const int priority, const char *fmt, ...) #include #include -extern char *strdup(char *); - /* * This implementation was written based on information provided by the * following documents: