2013-09-03 19:01:17 +00:00
|
|
|
From 6a7a90c34f62ffca270db3dbe3653f4eb2145c32 Mon Sep 17 00:00:00 2001
|
2013-08-18 10:25:16 +00:00
|
|
|
From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
|
|
|
|
Date: Mon, 25 Feb 2013 23:31:14 +0100
|
2013-09-03 19:01:17 +00:00
|
|
|
Subject: [PATCH] libcacard: split vscclient main() from socket reading
|
2013-08-18 10:25:16 +00:00
|
|
|
MIME-Version: 1.0
|
|
|
|
Content-Type: text/plain; charset=UTF-8
|
|
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
|
|
|
|
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
|
|
|
|
Reviewed-by: Alon Levy <alevy@redhat.com>
|
|
|
|
(cherry picked from commit a50b831ae1fe039b7c22793f307e0b8afdf50589)
|
|
|
|
---
|
|
|
|
libcacard/vscclient.c | 314 ++++++++++++++++++++++++++------------------------
|
|
|
|
1 file changed, 162 insertions(+), 152 deletions(-)
|
|
|
|
|
|
|
|
diff --git a/libcacard/vscclient.c b/libcacard/vscclient.c
|
|
|
|
index 9b744f2..5e00db3 100644
|
|
|
|
--- a/libcacard/vscclient.c
|
|
|
|
+++ b/libcacard/vscclient.c
|
|
|
|
@@ -211,6 +211,166 @@ get_id_from_string(char *string, unsigned int default_id)
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
+static int
|
|
|
|
+on_host_init(VSCMsgHeader *mhHeader, VSCMsgInit *incoming)
|
|
|
|
+{
|
|
|
|
+ uint32_t *capabilities = (incoming->capabilities);
|
|
|
|
+ int num_capabilities =
|
|
|
|
+ 1 + ((mhHeader->length - sizeof(VSCMsgInit)) / sizeof(uint32_t));
|
|
|
|
+ int i;
|
|
|
|
+ int rv;
|
|
|
|
+ pthread_t thread_id;
|
|
|
|
+
|
|
|
|
+ incoming->version = ntohl(incoming->version);
|
|
|
|
+ if (incoming->version != VSCARD_VERSION) {
|
|
|
|
+ if (verbose > 0) {
|
|
|
|
+ printf("warning: host has version %d, we have %d\n",
|
|
|
|
+ verbose, VSCARD_VERSION);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (incoming->magic != VSCARD_MAGIC) {
|
|
|
|
+ printf("unexpected magic: got %d, expected %d\n",
|
|
|
|
+ incoming->magic, VSCARD_MAGIC);
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+ for (i = 0 ; i < num_capabilities; ++i) {
|
|
|
|
+ capabilities[i] = ntohl(capabilities[i]);
|
|
|
|
+ }
|
|
|
|
+ /* Future: check capabilities */
|
|
|
|
+ /* remove whatever reader might be left in qemu,
|
|
|
|
+ * in case of an unclean previous exit. */
|
|
|
|
+ send_msg(VSC_ReaderRemove, VSCARD_MINIMAL_READER_ID, NULL, 0);
|
|
|
|
+ /* launch the event_thread. This will trigger reader adds for all the
|
|
|
|
+ * existing readers */
|
|
|
|
+ rv = pthread_create(&thread_id, NULL, event_thread, NULL);
|
|
|
|
+ if (rv < 0) {
|
|
|
|
+ perror("pthread_create");
|
|
|
|
+ return rv;
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#define APDUBufSize 270
|
|
|
|
+
|
|
|
|
+static int
|
|
|
|
+do_socket_read(void)
|
|
|
|
+{
|
|
|
|
+ int rv;
|
|
|
|
+ int dwSendLength;
|
|
|
|
+ int dwRecvLength;
|
|
|
|
+ uint8_t pbRecvBuffer[APDUBufSize];
|
|
|
|
+ uint8_t pbSendBuffer[APDUBufSize];
|
|
|
|
+ VReaderStatus reader_status;
|
|
|
|
+ VReader *reader = NULL;
|
|
|
|
+ VSCMsgHeader mhHeader;
|
|
|
|
+ VSCMsgError *error_msg;
|
|
|
|
+
|
|
|
|
+ rv = read(sock, &mhHeader, sizeof(mhHeader));
|
|
|
|
+ if (rv < sizeof(mhHeader)) {
|
|
|
|
+ /* Error */
|
|
|
|
+ if (rv < 0) {
|
|
|
|
+ perror("header read error\n");
|
|
|
|
+ } else {
|
|
|
|
+ fprintf(stderr, "header short read %d\n", rv);
|
|
|
|
+ }
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+ mhHeader.type = ntohl(mhHeader.type);
|
|
|
|
+ mhHeader.reader_id = ntohl(mhHeader.reader_id);
|
|
|
|
+ mhHeader.length = ntohl(mhHeader.length);
|
|
|
|
+ if (verbose) {
|
|
|
|
+ printf("Header: type=%d, reader_id=%u length=%d (0x%x)\n",
|
|
|
|
+ mhHeader.type, mhHeader.reader_id, mhHeader.length,
|
|
|
|
+ mhHeader.length);
|
|
|
|
+ }
|
|
|
|
+ switch (mhHeader.type) {
|
|
|
|
+ case VSC_APDU:
|
|
|
|
+ case VSC_Flush:
|
|
|
|
+ case VSC_Error:
|
|
|
|
+ case VSC_Init:
|
|
|
|
+ rv = read(sock, pbSendBuffer, mhHeader.length);
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ fprintf(stderr, "Unexpected message of type 0x%X\n", mhHeader.type);
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+ switch (mhHeader.type) {
|
|
|
|
+ case VSC_APDU:
|
|
|
|
+ if (rv < 0) {
|
|
|
|
+ /* Error */
|
|
|
|
+ fprintf(stderr, "read error\n");
|
|
|
|
+ close(sock);
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+ if (verbose) {
|
|
|
|
+ printf(" recv APDU: ");
|
|
|
|
+ print_byte_array(pbSendBuffer, mhHeader.length);
|
|
|
|
+ }
|
|
|
|
+ /* Transmit received APDU */
|
|
|
|
+ dwSendLength = mhHeader.length;
|
|
|
|
+ dwRecvLength = sizeof(pbRecvBuffer);
|
|
|
|
+ reader = vreader_get_reader_by_id(mhHeader.reader_id);
|
|
|
|
+ reader_status = vreader_xfr_bytes(reader,
|
|
|
|
+ pbSendBuffer, dwSendLength,
|
|
|
|
+ pbRecvBuffer, &dwRecvLength);
|
|
|
|
+ if (reader_status == VREADER_OK) {
|
|
|
|
+ mhHeader.length = dwRecvLength;
|
|
|
|
+ if (verbose) {
|
|
|
|
+ printf(" send response: ");
|
|
|
|
+ print_byte_array(pbRecvBuffer, mhHeader.length);
|
|
|
|
+ }
|
|
|
|
+ send_msg(VSC_APDU, mhHeader.reader_id,
|
|
|
|
+ pbRecvBuffer, dwRecvLength);
|
|
|
|
+ } else {
|
|
|
|
+ rv = reader_status; /* warning: not meaningful */
|
|
|
|
+ send_msg(VSC_Error, mhHeader.reader_id, &rv, sizeof(uint32_t));
|
|
|
|
+ }
|
|
|
|
+ vreader_free(reader);
|
|
|
|
+ reader = NULL; /* we've freed it, don't use it by accident
|
|
|
|
+ again */
|
|
|
|
+ break;
|
|
|
|
+ case VSC_Flush:
|
|
|
|
+ /* TODO: actually flush */
|
|
|
|
+ send_msg(VSC_FlushComplete, mhHeader.reader_id, NULL, 0);
|
|
|
|
+ break;
|
|
|
|
+ case VSC_Error:
|
|
|
|
+ error_msg = (VSCMsgError *) pbSendBuffer;
|
|
|
|
+ if (error_msg->code == VSC_SUCCESS) {
|
|
|
|
+ qemu_mutex_lock(&pending_reader_lock);
|
|
|
|
+ if (pending_reader) {
|
|
|
|
+ vreader_set_id(pending_reader, mhHeader.reader_id);
|
|
|
|
+ vreader_free(pending_reader);
|
|
|
|
+ pending_reader = NULL;
|
|
|
|
+ qemu_cond_signal(&pending_reader_condition);
|
|
|
|
+ }
|
|
|
|
+ qemu_mutex_unlock(&pending_reader_lock);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ printf("warning: qemu refused to add reader\n");
|
|
|
|
+ if (error_msg->code == VSC_CANNOT_ADD_MORE_READERS) {
|
|
|
|
+ /* clear pending reader, qemu can't handle any more */
|
|
|
|
+ qemu_mutex_lock(&pending_reader_lock);
|
|
|
|
+ if (pending_reader) {
|
|
|
|
+ pending_reader = NULL;
|
|
|
|
+ /* make sure the event loop doesn't hang */
|
|
|
|
+ qemu_cond_signal(&pending_reader_condition);
|
|
|
|
+ }
|
|
|
|
+ qemu_mutex_unlock(&pending_reader_lock);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ case VSC_Init:
|
|
|
|
+ if (on_host_init(&mhHeader, (VSCMsgInit *)pbSendBuffer) < 0) {
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ printf("Default\n");
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
static void
|
|
|
|
do_command(void)
|
|
|
|
{
|
|
|
|
@@ -339,8 +499,6 @@ do_command(void)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
-#define APDUBufSize 270
|
|
|
|
-
|
|
|
|
/* just for ease of parsing command line arguments. */
|
|
|
|
#define MAX_CERTS 100
|
|
|
|
|
|
|
|
@@ -385,44 +543,6 @@ connect_to_qemu(
|
|
|
|
return sock;
|
|
|
|
}
|
|
|
|
|
|
|
|
-static int on_host_init(VSCMsgHeader *mhHeader, VSCMsgInit *incoming)
|
|
|
|
-{
|
|
|
|
- uint32_t *capabilities = (incoming->capabilities);
|
|
|
|
- int num_capabilities =
|
|
|
|
- 1 + ((mhHeader->length - sizeof(VSCMsgInit)) / sizeof(uint32_t));
|
|
|
|
- int i;
|
|
|
|
- int rv;
|
|
|
|
- pthread_t thread_id;
|
|
|
|
-
|
|
|
|
- incoming->version = ntohl(incoming->version);
|
|
|
|
- if (incoming->version != VSCARD_VERSION) {
|
|
|
|
- if (verbose > 0) {
|
|
|
|
- printf("warning: host has version %d, we have %d\n",
|
|
|
|
- verbose, VSCARD_VERSION);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- if (incoming->magic != VSCARD_MAGIC) {
|
|
|
|
- printf("unexpected magic: got %d, expected %d\n",
|
|
|
|
- incoming->magic, VSCARD_MAGIC);
|
|
|
|
- return -1;
|
|
|
|
- }
|
|
|
|
- for (i = 0 ; i < num_capabilities; ++i) {
|
|
|
|
- capabilities[i] = ntohl(capabilities[i]);
|
|
|
|
- }
|
|
|
|
- /* Future: check capabilities */
|
|
|
|
- /* remove whatever reader might be left in qemu,
|
|
|
|
- * in case of an unclean previous exit. */
|
|
|
|
- send_msg(VSC_ReaderRemove, VSCARD_MINIMAL_READER_ID, NULL, 0);
|
|
|
|
- /* launch the event_thread. This will trigger reader adds for all the
|
|
|
|
- * existing readers */
|
|
|
|
- rv = pthread_create(&thread_id, NULL, event_thread, NULL);
|
|
|
|
- if (rv < 0) {
|
|
|
|
- perror("pthread_create");
|
|
|
|
- return rv;
|
|
|
|
- }
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
int
|
|
|
|
main(
|
|
|
|
int argc,
|
|
|
|
@@ -431,21 +551,13 @@ main(
|
|
|
|
char *qemu_host;
|
|
|
|
char *qemu_port;
|
|
|
|
VSCMsgHeader mhHeader;
|
|
|
|
- VSCMsgError *error_msg;
|
|
|
|
|
|
|
|
- int rv;
|
|
|
|
- int dwSendLength;
|
|
|
|
- int dwRecvLength;
|
|
|
|
- uint8_t pbRecvBuffer[APDUBufSize];
|
|
|
|
- uint8_t pbSendBuffer[APDUBufSize];
|
|
|
|
- VReaderStatus reader_status;
|
|
|
|
- VReader *reader = NULL;
|
|
|
|
VCardEmulOptions *command_line_options = NULL;
|
|
|
|
|
|
|
|
char *cert_names[MAX_CERTS];
|
|
|
|
char *emul_args = NULL;
|
|
|
|
int cert_count = 0;
|
|
|
|
- int c;
|
|
|
|
+ int c, rv;
|
|
|
|
|
|
|
|
while ((c = getopt(argc, argv, "c:e:pd:")) != -1) {
|
|
|
|
switch (c) {
|
|
|
|
@@ -548,109 +660,7 @@ main(
|
|
|
|
if (!FD_ISSET(sock, &fds)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
-
|
|
|
|
- rv = read(sock, &mhHeader, sizeof(mhHeader));
|
|
|
|
- if (rv < sizeof(mhHeader)) {
|
|
|
|
- /* Error */
|
|
|
|
- if (rv < 0) {
|
|
|
|
- perror("header read error\n");
|
|
|
|
- } else {
|
|
|
|
- fprintf(stderr, "header short read %d\n", rv);
|
|
|
|
- }
|
|
|
|
- return 8;
|
|
|
|
- }
|
|
|
|
- mhHeader.type = ntohl(mhHeader.type);
|
|
|
|
- mhHeader.reader_id = ntohl(mhHeader.reader_id);
|
|
|
|
- mhHeader.length = ntohl(mhHeader.length);
|
|
|
|
- if (verbose) {
|
|
|
|
- printf("Header: type=%d, reader_id=%u length=%d (0x%x)\n",
|
|
|
|
- mhHeader.type, mhHeader.reader_id, mhHeader.length,
|
|
|
|
- mhHeader.length);
|
|
|
|
- }
|
|
|
|
- switch (mhHeader.type) {
|
|
|
|
- case VSC_APDU:
|
|
|
|
- case VSC_Flush:
|
|
|
|
- case VSC_Error:
|
|
|
|
- case VSC_Init:
|
|
|
|
- rv = read(sock, pbSendBuffer, mhHeader.length);
|
|
|
|
- break;
|
|
|
|
- default:
|
|
|
|
- fprintf(stderr, "Unexpected message of type 0x%X\n", mhHeader.type);
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
- switch (mhHeader.type) {
|
|
|
|
- case VSC_APDU:
|
|
|
|
- if (rv < 0) {
|
|
|
|
- /* Error */
|
|
|
|
- fprintf(stderr, "read error\n");
|
|
|
|
- close(sock);
|
|
|
|
- return 8;
|
|
|
|
- }
|
|
|
|
- if (verbose) {
|
|
|
|
- printf(" recv APDU: ");
|
|
|
|
- print_byte_array(pbSendBuffer, mhHeader.length);
|
|
|
|
- }
|
|
|
|
- /* Transmit received APDU */
|
|
|
|
- dwSendLength = mhHeader.length;
|
|
|
|
- dwRecvLength = sizeof(pbRecvBuffer);
|
|
|
|
- reader = vreader_get_reader_by_id(mhHeader.reader_id);
|
|
|
|
- reader_status = vreader_xfr_bytes(reader,
|
|
|
|
- pbSendBuffer, dwSendLength,
|
|
|
|
- pbRecvBuffer, &dwRecvLength);
|
|
|
|
- if (reader_status == VREADER_OK) {
|
|
|
|
- mhHeader.length = dwRecvLength;
|
|
|
|
- if (verbose) {
|
|
|
|
- printf(" send response: ");
|
|
|
|
- print_byte_array(pbRecvBuffer, mhHeader.length);
|
|
|
|
- }
|
|
|
|
- send_msg(VSC_APDU, mhHeader.reader_id,
|
|
|
|
- pbRecvBuffer, dwRecvLength);
|
|
|
|
- } else {
|
|
|
|
- rv = reader_status; /* warning: not meaningful */
|
|
|
|
- send_msg(VSC_Error, mhHeader.reader_id, &rv, sizeof(uint32_t));
|
|
|
|
- }
|
|
|
|
- vreader_free(reader);
|
|
|
|
- reader = NULL; /* we've freed it, don't use it by accident
|
|
|
|
- again */
|
|
|
|
- break;
|
|
|
|
- case VSC_Flush:
|
|
|
|
- /* TODO: actually flush */
|
|
|
|
- send_msg(VSC_FlushComplete, mhHeader.reader_id, NULL, 0);
|
|
|
|
- break;
|
|
|
|
- case VSC_Error:
|
|
|
|
- error_msg = (VSCMsgError *) pbSendBuffer;
|
|
|
|
- if (error_msg->code == VSC_SUCCESS) {
|
|
|
|
- qemu_mutex_lock(&pending_reader_lock);
|
|
|
|
- if (pending_reader) {
|
|
|
|
- vreader_set_id(pending_reader, mhHeader.reader_id);
|
|
|
|
- vreader_free(pending_reader);
|
|
|
|
- pending_reader = NULL;
|
|
|
|
- qemu_cond_signal(&pending_reader_condition);
|
|
|
|
- }
|
|
|
|
- qemu_mutex_unlock(&pending_reader_lock);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- printf("warning: qemu refused to add reader\n");
|
|
|
|
- if (error_msg->code == VSC_CANNOT_ADD_MORE_READERS) {
|
|
|
|
- /* clear pending reader, qemu can't handle any more */
|
|
|
|
- qemu_mutex_lock(&pending_reader_lock);
|
|
|
|
- if (pending_reader) {
|
|
|
|
- pending_reader = NULL;
|
|
|
|
- /* make sure the event loop doesn't hang */
|
|
|
|
- qemu_cond_signal(&pending_reader_condition);
|
|
|
|
- }
|
|
|
|
- qemu_mutex_unlock(&pending_reader_lock);
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
- case VSC_Init:
|
|
|
|
- if (on_host_init(&mhHeader, (VSCMsgInit *)pbSendBuffer) < 0) {
|
|
|
|
- return -1;
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
- default:
|
|
|
|
- printf("Default\n");
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
+ rv = do_socket_read();
|
|
|
|
} while (rv >= 0);
|
|
|
|
|
|
|
|
return 0;
|