- usb.c: fixed signal handling

- ccid.c: revised construction of RDR_to_PC_*-packages to make the code more readable


git-svn-id: https://vsmartcard.svn.sourceforge.net/svnroot/vsmartcard@217 96b47cad-a561-4643-ad3b-153ac7d7599c
This commit is contained in:
frankmorgner
2010-07-12 22:54:10 +00:00
parent 16ab4562db
commit 68984ac0a2
2 changed files with 119 additions and 156 deletions

View File

@@ -27,12 +27,12 @@
#include <opensc/log.h> #include <opensc/log.h>
#include "ccid.h" #include "ccid.h"
#include "sm.h"
#include "scutil.h" #include "scutil.h"
#include "config.h" #include "config.h"
#ifdef WITH_PACE #ifdef WITH_PACE
#include "pace.h" #include "pace.h"
#include "sm.h"
struct sm_ctx sctx; struct sm_ctx sctx;
#endif #endif
@@ -178,11 +178,7 @@ static int get_rapdu(sc_apdu_t *apdu, size_t slot, __u8 **buf, size_t *resplen)
} }
*buf = apdu->resp; *buf = apdu->resp;
#ifdef WITH_PACE
sc_result = sm_transmit_apdu(&sctx, card_in_slot[slot], apdu); sc_result = sm_transmit_apdu(&sctx, card_in_slot[slot], apdu);
#else
sc_result = sc_transmit_apdu(card_in_slot[slot], apdu);
#endif
if (sc_result < 0) { if (sc_result < 0) {
goto err; goto err;
} }
@@ -239,7 +235,7 @@ static __u8 get_bError(int sc_result)
static __u8 get_bStatus(int sc_result, __u8 bSlot) static __u8 get_bStatus(int sc_result, __u8 bSlot)
{ {
int flags; int flags;
__u8 result = 0; __u8 bstatus = 0;
flags = detect_card_presence(bSlot); flags = detect_card_presence(bSlot);
@@ -250,14 +246,14 @@ static __u8 get_bStatus(int sc_result, __u8 bSlot)
|| (card_in_slot[bSlot] || (card_in_slot[bSlot]
&& !sc_card_valid(card_in_slot[bSlot]))) { && !sc_card_valid(card_in_slot[bSlot]))) {
/*sc_debug(ctx, "error inactive");*/ /*sc_debug(ctx, "error inactive");*/
result = CCID_BSTATUS_ERROR_INACTIVE; bstatus = CCID_BSTATUS_ERROR_INACTIVE;
} else { } else {
/*sc_debug(ctx, "error active");*/ /*sc_debug(ctx, "error active");*/
result = CCID_BSTATUS_ERROR_ACTIVE; bstatus = CCID_BSTATUS_ERROR_ACTIVE;
} }
} else { } else {
/*sc_debug(ctx, "error no icc");*/ /*sc_debug(ctx, "error no icc");*/
result = CCID_BSTATUS_ERROR_NOICC; bstatus = CCID_BSTATUS_ERROR_NOICC;
} }
} else { } else {
if (flags & SC_SLOT_CARD_PRESENT) { if (flags & SC_SLOT_CARD_PRESENT) {
@@ -265,65 +261,85 @@ static __u8 get_bStatus(int sc_result, __u8 bSlot)
card_in_slot[bSlot] card_in_slot[bSlot]
&& !sc_card_valid(card_in_slot[bSlot]))) { && !sc_card_valid(card_in_slot[bSlot]))) {
/*sc_debug(ctx, "ok inactive");*/ /*sc_debug(ctx, "ok inactive");*/
result = CCID_BSTATUS_OK_INACTIVE; bstatus = CCID_BSTATUS_OK_INACTIVE;
} else { } else {
/*sc_debug(ctx, "ok active");*/ /*sc_debug(ctx, "ok active");*/
result = CCID_BSTATUS_OK_ACTIVE; bstatus = CCID_BSTATUS_OK_ACTIVE;
} }
} else { } else {
/*sc_debug(ctx, "ok no icc");*/ /*sc_debug(ctx, "ok no icc");*/
result = CCID_BSTATUS_OK_NOICC; bstatus = CCID_BSTATUS_OK_NOICC;
} }
} }
} else { } else {
debug_sc_result(flags); debug_sc_result(flags);
sc_error(ctx, "Could not detect card presence." sc_error(ctx, "Could not detect card presence."
" Falling back to default (bStatus=0x%02X).", result); " Falling back to default (bStatus=0x%02X).", bstatus);
} }
return result; return bstatus;
} }
static int static int
get_RDR_to_PC_SlotStatus(__u8 bSlot, __u8 bSeq, int sc_result, RDR_to_PC_SlotStatus_t **out) get_RDR_to_PC_SlotStatus(__u8 bSlot, __u8 bSeq, int sc_result, __u8 **outbuf, size_t *outlen,
const __u8 *abProtocolDataStructure, size_t abProtocolDataStructureLen)
{ {
if (!out) if (!outbuf)
return SC_ERROR_INVALID_ARGUMENTS; return SC_ERROR_INVALID_ARGUMENTS;
if (abProtocolDataStructureLen > 0xffffffff) {
sc_error(ctx, "abProtocolDataStructure %u bytes too long",
abProtocolDataStructureLen-0xffffffff);
return SC_ERROR_INVALID_DATA;
}
RDR_to_PC_SlotStatus_t *result = realloc(*out, sizeof *result); RDR_to_PC_SlotStatus_t *status = realloc(*outbuf, sizeof(*status) + abProtocolDataStructureLen);
if (!result) if (!status)
return SC_ERROR_OUT_OF_MEMORY; return SC_ERROR_OUT_OF_MEMORY;
*out = result; *outbuf = (__u8 *) status;
result->bMessageType = 0x81; status->bMessageType = 0x81;
result->dwLength = __constant_cpu_to_le32(0); status->dwLength = __constant_cpu_to_le32(abProtocolDataStructureLen);
result->bSlot = bSlot; status->bSlot = bSlot;
result->bSeq = bSeq; status->bSeq = bSeq;
result->bStatus = get_bStatus(sc_result, bSlot); status->bStatus = get_bStatus(sc_result, bSlot);
result->bError = get_bError(sc_result); status->bError = get_bError(sc_result);
result->bClockStatus = 0; status->bClockStatus = 0;
memcpy((*outbuf) + sizeof(*status), abProtocolDataStructure, abProtocolDataStructureLen);
*outlen = sizeof(*status) + abProtocolDataStructureLen;
return SC_SUCCESS; return SC_SUCCESS;
} }
static int static int
get_RDR_to_PC_DataBlock(__u8 bSlot, __u8 bSeq, int sc_result, RDR_to_PC_DataBlock_t **out) get_RDR_to_PC_DataBlock(__u8 bSlot, __u8 bSeq, int sc_result, __u8 **outbuf,
size_t *outlen, const __u8 *abData, size_t abDataLen)
{ {
if (!out) if (!outbuf)
return SC_ERROR_INVALID_ARGUMENTS; return SC_ERROR_INVALID_ARGUMENTS;
if (abDataLen > 0xffffffff) {
sc_error(ctx, "abProtocolDataStructure %u bytes too long",
abDataLen-0xffffffff);
return SC_ERROR_INVALID_DATA;
}
RDR_to_PC_DataBlock_t *result = realloc(*out, sizeof *result); RDR_to_PC_DataBlock_t *data = realloc(*outbuf, sizeof *data);
if (!result) if (!data)
return SC_ERROR_OUT_OF_MEMORY; return SC_ERROR_OUT_OF_MEMORY;
*out = result; *outbuf = (__u8 *) data;
result->bMessageType = 0x80; data->bMessageType = 0x80;
result->dwLength = __constant_cpu_to_le32(0); data->dwLength = __constant_cpu_to_le32(abDataLen);
result->bSlot = bSlot; data->bSlot = bSlot;
result->bSeq = bSeq; data->bSeq = bSeq;
result->bStatus = get_bStatus(sc_result, bSlot); data->bStatus = get_bStatus(sc_result, bSlot);
result->bError = get_bError(sc_result); data->bError = get_bError(sc_result);
result->bChainParameter = 0; data->bChainParameter = 0;
memcpy((*outbuf) + sizeof(*data), abData, abDataLen);
*outlen = sizeof(*data) + abDataLen;
return SC_SUCCESS; return SC_SUCCESS;
} }
@@ -348,7 +364,7 @@ perform_PC_to_RDR_GetSlotStatus(const __u8 *in, size_t inlen, __u8 **out, size_t
sc_debug(ctx, "warning: malformed PC_to_RDR_GetSlotStatus"); sc_debug(ctx, "warning: malformed PC_to_RDR_GetSlotStatus");
return get_RDR_to_PC_SlotStatus(request->bSlot, request->bSeq, SC_SUCCESS, return get_RDR_to_PC_SlotStatus(request->bSlot, request->bSeq, SC_SUCCESS,
(RDR_to_PC_SlotStatus_t **) out); out, outlen, NULL, 0);
} }
static int static int
@@ -356,7 +372,6 @@ perform_PC_to_RDR_IccPowerOn(const __u8 *in, size_t inlen, __u8 **out, size_t *o
{ {
const PC_to_RDR_IccPowerOn_t *request = (PC_to_RDR_IccPowerOn_t *) in; const PC_to_RDR_IccPowerOn_t *request = (PC_to_RDR_IccPowerOn_t *) in;
int sc_result; int sc_result;
RDR_to_PC_SlotStatus_t *result;
if (!out || !outlen || !in) if (!out || !outlen || !in)
return SC_ERROR_INVALID_ARGUMENTS; return SC_ERROR_INVALID_ARGUMENTS;
@@ -382,34 +397,15 @@ perform_PC_to_RDR_IccPowerOn(const __u8 *in, size_t inlen, __u8 **out, size_t *o
sc_result = SC_ERROR_INVALID_DATA; sc_result = SC_ERROR_INVALID_DATA;
} }
SC_TEST_RET(ctx,
get_RDR_to_PC_SlotStatus(request->bSlot, request->bSeq, sc_result,
(RDR_to_PC_SlotStatus_t **) out),
"Could not get RDR_to_PC_SlotStatus object");
result = (RDR_to_PC_SlotStatus_t *) *out;
if (sc_result >= 0) { if (sc_result >= 0) {
*outlen = sizeof *result + card_in_slot[request->bSlot]->atr_len; return get_RDR_to_PC_SlotStatus(request->bSlot, request->bSeq,
result = realloc(*out, *outlen); sc_result, out, outlen, card_in_slot[request->bSlot]->atr,
if (result) {
*out = (__u8 *) result;
memcpy(*out + sizeof *result, card_in_slot[request->bSlot]->atr,
card_in_slot[request->bSlot]->atr_len); card_in_slot[request->bSlot]->atr_len);
result->dwLength = __cpu_to_le32(card_in_slot[request->bSlot]->atr_len);
} else { } else {
debug_sc_result(SC_ERROR_OUT_OF_MEMORY); sc_error(ctx, "Returning default status package.");
sc_error(ctx, "Could not get memory for ATR." return get_RDR_to_PC_SlotStatus(request->bSlot, request->bSeq,
" Returning package without payload."); sc_result, out, outlen, NULL, 0);
*outlen = sizeof *result;
} }
} else {
debug_sc_result(sc_result);
sc_error(ctx, "Could not connect to card in slot %d."
" Returning default status package.", request->bSlot);
*outlen = sizeof *result;
}
return SC_SUCCESS;
} }
static int static int
@@ -435,14 +431,8 @@ perform_PC_to_RDR_IccPowerOff(const __u8 *in, size_t inlen, __u8 **out, size_t *
else else
sc_result = sc_disconnect_card(card_in_slot[request->bSlot], 0); sc_result = sc_disconnect_card(card_in_slot[request->bSlot], 0);
SC_TEST_RET(ctx, return get_RDR_to_PC_SlotStatus(request->bSlot, request->bSeq, sc_result,
get_RDR_to_PC_SlotStatus(request->bSlot, request->bSeq, sc_result, out, outlen, NULL, 0);
(RDR_to_PC_SlotStatus_t **) out),
"Could not get RDR_to_PC_SlotStatus object");
*outlen = sizeof(RDR_to_PC_SlotStatus_t);
return SC_SUCCESS;
} }
static int static int
@@ -450,11 +440,10 @@ perform_PC_to_RDR_XfrBlock(const u8 *in, size_t inlen, __u8** out, size_t *outle
{ {
const PC_to_RDR_XfrBlock_t *request = (PC_to_RDR_XfrBlock_t *) in; const PC_to_RDR_XfrBlock_t *request = (PC_to_RDR_XfrBlock_t *) in;
const __u8 *abDataIn = in + sizeof *request; const __u8 *abDataIn = in + sizeof *request;
int sc_result, r; int sc_result;
size_t resplen = 0; size_t abDataOutLen = 0;
sc_apdu_t apdu; sc_apdu_t apdu;
__u8 *abDataOut = NULL; __u8 *abDataOut = NULL;
RDR_to_PC_DataBlock_t *result;
if (!in || !out || !outlen) if (!in || !out || !outlen)
return SC_ERROR_INVALID_ARGUMENTS; return SC_ERROR_INVALID_ARGUMENTS;
@@ -471,40 +460,16 @@ perform_PC_to_RDR_XfrBlock(const u8 *in, size_t inlen, __u8** out, size_t *outle
else { else {
sc_result = build_apdu(ctx, abDataIn, request->dwLength, &apdu); sc_result = build_apdu(ctx, abDataIn, request->dwLength, &apdu);
if (sc_result >= 0) if (sc_result >= 0)
sc_result = get_rapdu(&apdu, request->bSlot, &abDataOut, &resplen); sc_result = get_rapdu(&apdu, request->bSlot, &abDataOut, &abDataOutLen);
} }
r = get_RDR_to_PC_DataBlock(request->bSlot, request->bSeq, sc_result, sc_result = get_RDR_to_PC_DataBlock(request->bSlot, request->bSeq, sc_result,
(RDR_to_PC_DataBlock_t **) out); out, outlen, abDataOut, abDataOutLen);
result = (RDR_to_PC_DataBlock_t *) *out;
if (r < 0) { if (abDataOut)
if (sc_result >= 0)
free(abDataOut); free(abDataOut);
return r;
}
if (sc_result >= 0) { return sc_result;
*outlen = sizeof *result + resplen;
result = realloc(*out, *outlen);
if (!result) {
*outlen = sizeof *result;
free(abDataOut);
sc_result = SC_ERROR_OUT_OF_MEMORY;
} else {
*out = (__u8 *) result;
result->dwLength = __cpu_to_le32(resplen);
memcpy(*out + sizeof *result, abDataOut, resplen);
}
} else {
*outlen = sizeof *result;
debug_sc_result(sc_result);
sc_error(ctx, "Could not get memory for response apdu."
" Returning package without payload.");
}
result->bError = get_bError(sc_result);
result->bStatus = get_bStatus(sc_result, request->bSlot);
return SC_SUCCESS;
} }
static int static int
@@ -769,6 +734,7 @@ write_pin(sc_apdu_t *apdu, struct sc_pin_cmd_pin *pin, uint8_t blocksize,
blocksize - justify_offset, pin, encoding, sc_result); blocksize - justify_offset, pin, encoding, sc_result);
} }
#ifdef WITH_PACE
static int static int
perform_PC_to_RDR_Secure_EstablishPACEChannel(sc_card_t *card, perform_PC_to_RDR_Secure_EstablishPACEChannel(sc_card_t *card,
const __u8 *abData, size_t abDatalen, const __u8 *abData, size_t abDatalen,
@@ -967,18 +933,35 @@ perform_PC_to_RDR_Secure_GetReadersPACECapabilities(__u8 **abDataOut,
return SC_SUCCESS; return SC_SUCCESS;
} }
#else
static int
perform_PC_to_RDR_Secure_EstablishPACEChannel(sc_card_t *card,
const __u8 *abData, size_t abDatalen,
__u8 **abDataOut, size_t *abDataOutLen)
{
sc_error(ctx, "ccid compiled without PACE support.");
return SC_ERROR_NOT_SUPPORTED;
}
static int
perform_PC_to_RDR_Secure_GetReadersPACECapabilities(__u8 **abDataOut,
size_t *abDataOutLen)
{
sc_error(ctx, "ccid compiled without PACE support.");
return SC_ERROR_NOT_SUPPORTED;
}
#endif
static int static int
perform_PC_to_RDR_Secure(const __u8 *in, size_t inlen, __u8** out, size_t *outlen) perform_PC_to_RDR_Secure(const __u8 *in, size_t inlen, __u8** out, size_t *outlen)
{ {
int sc_result, r; int sc_result;
struct sc_pin_cmd_pin curr_pin, new_pin; struct sc_pin_cmd_pin curr_pin, new_pin;
sc_apdu_t apdu; sc_apdu_t apdu;
const PC_to_RDR_Secure_t *request = (PC_to_RDR_Secure_t *) in; const PC_to_RDR_Secure_t *request = (PC_to_RDR_Secure_t *) in;
const __u8* abData = in + sizeof *request; const __u8* abData = in + sizeof *request;
size_t abDatalen = inlen - sizeof *request; size_t abDatalen = inlen - sizeof *request;
u8 *abDataOut = NULL; u8 *abDataOut = NULL;
size_t resplen = 0; size_t abDataOutLen = 0;
RDR_to_PC_DataBlock_t *result; RDR_to_PC_DataBlock_t *result;
if (!in || !out || !outlen) if (!in || !out || !outlen)
@@ -1049,21 +1032,19 @@ perform_PC_to_RDR_Secure(const __u8 *in, size_t inlen, __u8** out, size_t *outle
abPINApdu = (__u8*) modify + sizeof(*modify); abPINApdu = (__u8*) modify + sizeof(*modify);
apdulen = __le32_to_cpu(request->dwLength) - sizeof(*modify) - sizeof(__u8); apdulen = __le32_to_cpu(request->dwLength) - sizeof(*modify) - sizeof(__u8);
break; break;
#ifdef WITH_PACE
case 0x10: case 0x10:
sc_result = perform_PC_to_RDR_Secure_GetReadersPACECapabilities( sc_result = perform_PC_to_RDR_Secure_GetReadersPACECapabilities(
&abDataOut, &resplen); &abDataOut, &abDataOutLen);
goto err; goto err;
break; break;
case 0x20: case 0x20:
sc_result = perform_PC_to_RDR_Secure_EstablishPACEChannel( sc_result = perform_PC_to_RDR_Secure_EstablishPACEChannel(
card_in_slot[request->bSlot], abData+1, abDatalen-1, card_in_slot[request->bSlot], abData+1, abDatalen-1,
&abDataOut, &resplen); &abDataOut, &abDataOutLen);
goto err; goto err;
break; break;
#endif
case 0x04: case 0x04:
// Cancel PIN function // Cancel PIN function
default: default:
@@ -1170,7 +1151,7 @@ perform_PC_to_RDR_Secure(const __u8 *in, size_t inlen, __u8** out, size_t *outle
&sc_result)) &sc_result))
goto err; goto err;
sc_result = get_rapdu(&apdu, request->bSlot, &abDataOut, &resplen); sc_result = get_rapdu(&apdu, request->bSlot, &abDataOut, &abDataOutLen);
sc_mem_clear(abPINApdu, apdulen); sc_mem_clear(abPINApdu, apdulen);
err: err:
@@ -1183,36 +1164,13 @@ err:
free((u8 *) new_pin.data); free((u8 *) new_pin.data);
} }
r = get_RDR_to_PC_DataBlock(request->bSlot, request->bSeq, sc_result, (RDR_to_PC_DataBlock_t **) out); sc_result = get_RDR_to_PC_DataBlock(request->bSlot, request->bSeq, sc_result, out,
result = (RDR_to_PC_DataBlock_t *) *out; outlen, abDataOut, abDataOutLen);
if (r < 0) {
if (sc_result >= 0)
free(abDataOut);
return r;
}
if (sc_result >= 0) { if (abDataOut)
*outlen = sizeof *result + resplen;
result = realloc(*out, *outlen);
if (!result) {
*outlen = sizeof *result;
free(abDataOut); free(abDataOut);
sc_result = SC_ERROR_OUT_OF_MEMORY;
} else {
*out = (__u8 *) result;
result->dwLength = __cpu_to_le32(resplen);
memcpy(*out + sizeof *result, abDataOut, resplen);
}
} else {
*outlen = sizeof *result;
debug_sc_result(sc_result);
sc_error(ctx, "Some error occurred."
" Returning package without payload.");
}
result->bError = get_bError(sc_result);
result->bStatus = get_bStatus(sc_result, request->bSlot);
return r; return sc_result;
} }
/* XXX calling sc_wait_for_event blocks all other threads, thats why it /* XXX calling sc_wait_for_event blocks all other threads, thats why it
@@ -1409,7 +1367,7 @@ int ccid_parse_bulkin(const __u8* inbuf, size_t inlen, __u8** outbuf)
int ccid_parse_control(struct usb_ctrlrequest *setup, __u8 **outbuf) int ccid_parse_control(struct usb_ctrlrequest *setup, __u8 **outbuf)
{ {
int result; int r;
__u16 value, index, length; __u16 value, index, length;
__u8 *tmp; __u8 *tmp;
@@ -1428,7 +1386,7 @@ int ccid_parse_control(struct usb_ctrlrequest *setup, __u8 **outbuf)
sc_debug(ctx, "warning: malformed ABORT"); sc_debug(ctx, "warning: malformed ABORT");
} }
result = 0; r = 0;
break; break;
case CCID_CONTROL_GET_CLOCK_FREQUENCIES: case CCID_CONTROL_GET_CLOCK_FREQUENCIES:
@@ -1437,10 +1395,10 @@ int ccid_parse_control(struct usb_ctrlrequest *setup, __u8 **outbuf)
sc_debug(ctx, "warning: malformed GET_CLOCK_FREQUENCIES"); sc_debug(ctx, "warning: malformed GET_CLOCK_FREQUENCIES");
} }
result = sizeof(__le32); r = sizeof(__le32);
tmp = realloc(*outbuf, result); tmp = realloc(*outbuf, r);
if (!tmp) { if (!tmp) {
result = SC_ERROR_OUT_OF_MEMORY; r = SC_ERROR_OUT_OF_MEMORY;
break; break;
} }
*outbuf = tmp; *outbuf = tmp;
@@ -1454,10 +1412,10 @@ int ccid_parse_control(struct usb_ctrlrequest *setup, __u8 **outbuf)
sc_debug(ctx, "warning: malformed GET_DATA_RATES"); sc_debug(ctx, "warning: malformed GET_DATA_RATES");
} }
result = sizeof (__le32); r = sizeof (__le32);
tmp = realloc(*outbuf, result); tmp = realloc(*outbuf, r);
if (tmp == NULL) { if (tmp == NULL) {
result = -1; r = -1;
break; break;
} }
*outbuf = tmp; *outbuf = tmp;
@@ -1468,14 +1426,14 @@ int ccid_parse_control(struct usb_ctrlrequest *setup, __u8 **outbuf)
default: default:
sc_error(ctx, "Unknown ccid control command."); sc_error(ctx, "Unknown ccid control command.");
result = SC_ERROR_NOT_SUPPORTED; r = SC_ERROR_NOT_SUPPORTED;
} }
} }
if (result < 0) if (r < 0)
debug_sc_result(result); debug_sc_result(r);
return result; return r;
} }
int ccid_state_changed(RDR_to_PC_NotifySlotChange_t **slotchange, int timeout) int ccid_state_changed(RDR_to_PC_NotifySlotChange_t **slotchange, int timeout)

View File

@@ -976,6 +976,9 @@ static void *interrupt (void *param)
pthread_cleanup_pop (1); pthread_cleanup_pop (1);
fflush (stdout);
fflush (stderr);
return 0; return 0;
} }
@@ -1534,15 +1537,17 @@ stall:
static void signothing (int sig, siginfo_t *info, void *ptr) static void signothing (int sig, siginfo_t *info, void *ptr)
{ {
unsigned int seconds = 10; unsigned int seconds = 4;
switch (sig) { switch (sig) {
case SIGQUIT:
seconds /= 2;
case SIGINT: case SIGINT:
if (verbose > 1) if (verbose > 1)
fprintf (stderr, "\nInitializing shutdown, " fprintf (stderr, "\nInitializing shutdown, "
"waiting %d seconds for threads to terminate\n", "waiting %d seconds for threads to terminate\n",
seconds); seconds);
sleep(5); pthread_cancel(ep0);
case SIGQUIT: sleep(seconds);
fprintf (stderr, "Doing immediate shutdown.\n"); fprintf (stderr, "Doing immediate shutdown.\n");
exit(1); exit(1);
break; break;