Branch data Line data Source code
1 : : /*
2 : : * Tester for VSCARD protocol, client side.
3 : : *
4 : : * Can be used with ccid-card-passthru.
5 : : *
6 : : * Copyright (c) 2011 Red Hat.
7 : : * Written by Alon Levy.
8 : : *
9 : : * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
10 : : * See the COPYING file in the top-level directory.
11 : : */
12 : :
13 : : #include <glib.h>
14 : :
15 : : #include <stdio.h>
16 : : #include <stdlib.h>
17 : : #include <string.h>
18 : : #ifndef _WIN32
19 : : #include <sys/socket.h>
20 : : #include <netinet/in.h>
21 : : #include <netdb.h>
22 : : #include <unistd.h>
23 : : #define closesocket(x) close(x)
24 : : #else
25 : : #include <winsock2.h>
26 : : #include <ws2tcpip.h>
27 : : #include <getopt.h>
28 : : #endif
29 : :
30 : : #if defined(ENABLE_PCSC)
31 : : # ifdef __APPLE__
32 : : # include <PCSC/winscard.h>
33 : : # include <PCSC/wintypes.h>
34 : : # else
35 : : # include <winscard.h>
36 : : # endif
37 : : #endif
38 : :
39 : : #include "vscard_common.h"
40 : :
41 : : #include "vreader.h"
42 : : #include "vcard_emul.h"
43 : : #include "vevent.h"
44 : :
45 : : static int verbose;
46 : : static int with_pcsc;
47 : :
48 : : static void
49 : 0 : print_byte_array(
50 : : uint8_t *arrBytes,
51 : : int nSize
52 : : ) {
53 : : int i;
54 : 0 : for (i = 0; i < nSize; i++) {
55 : 0 : printf("%02X ", arrBytes[i]);
56 : : }
57 : 0 : printf("\n");
58 : 0 : }
59 : :
60 : : static void
61 : 0 : print_usage(void) {
62 : 0 : printf("vscclient OPTIONS <host> <port>\n");
63 : 0 : printf(" -e <emul_args> - Emulator arguments, see below\n");
64 : 0 : printf(" -c <certname> - Software emulation certificates\n");
65 : 0 : printf(" -d <level> - Debug level\n");
66 : 0 : printf(" -p - Use real smartcard to compare with emulator\n");
67 : 0 : vcard_emul_usage();
68 : 0 : }
69 : :
70 : : #if defined(ENABLE_PCSC)
71 : : static SCARD_IO_REQUEST scard_pci;
72 : : static SCARDHANDLE scard;
73 : : static SCARDCONTEXT scard_ctxt;
74 : :
75 : : static gboolean pcsc_transmit(BYTE *cmd, LONG cmdlen, BYTE *recv, int *recvlen)
76 : : {
77 : : LONG rv;
78 : :
79 : : rv = SCardTransmit(scard, &scard_pci, cmd, cmdlen,
80 : : NULL, recv, (DWORD*)recvlen);
81 : : g_return_val_if_fail(rv == SCARD_S_SUCCESS, FALSE);
82 : :
83 : : return 0;
84 : : }
85 : :
86 : : static gboolean pcsc_init(void)
87 : : {
88 : : LONG rv;
89 : : DWORD nreaders, protocol;
90 : : LPTSTR readers;
91 : :
92 : : rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &scard_ctxt);
93 : : g_return_val_if_fail(rv == SCARD_S_SUCCESS, FALSE);
94 : :
95 : : #ifdef SCARD_AUTOALLOCATE
96 : : nreaders = SCARD_AUTOALLOCATE;
97 : :
98 : : rv = SCardListReaders(scard_ctxt, NULL, (LPTSTR)&readers, &nreaders);
99 : : g_return_val_if_fail(rv == SCARD_S_SUCCESS, FALSE);
100 : : #else
101 : : rv = SCardListReaders(scard_ctxt, NULL, NULL, &nreaders);
102 : : g_return_val_if_fail(rv == SCARD_S_SUCCESS, FALSE);
103 : :
104 : : readers = g_new0(char, nreaders);
105 : : rv = SCardListReaders(scard_ctxt, NULL, readers, &nreaders);
106 : : g_return_val_if_fail(rv == SCARD_S_SUCCESS, FALSE);
107 : : #endif
108 : : printf("reader name: %s\n", readers);
109 : :
110 : : rv = SCardConnect(scard_ctxt, readers, SCARD_SHARE_SHARED,
111 : : SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &scard, &protocol);
112 : : g_return_val_if_fail(rv == SCARD_S_SUCCESS, FALSE);
113 : :
114 : : switch(protocol) {
115 : : case SCARD_PROTOCOL_T0:
116 : : scard_pci = *SCARD_PCI_T0;
117 : : break;
118 : :
119 : : case SCARD_PROTOCOL_T1:
120 : : scard_pci = *SCARD_PCI_T1;
121 : : break;
122 : : default:
123 : : g_return_val_if_reached(FALSE);
124 : : }
125 : :
126 : : #ifdef SCARD_AUTOALLOCATE
127 : : rv = SCardFreeMemory(scard_ctxt, readers);
128 : : g_warn_if_fail(rv == SCARD_S_SUCCESS);
129 : : #else
130 : : g_free(readers);
131 : : #endif
132 : :
133 : : return TRUE;
134 : : }
135 : :
136 : : static void pcsc_deinit(void)
137 : : {
138 : : LONG rv;
139 : :
140 : : rv = SCardDisconnect(scard, SCARD_LEAVE_CARD);
141 : : g_warn_if_fail(rv == SCARD_S_SUCCESS);
142 : : scard = 0;
143 : :
144 : : rv = SCardReleaseContext(scard_ctxt);
145 : : g_warn_if_fail(rv == SCARD_S_SUCCESS);
146 : : scard_ctxt = 0;
147 : : }
148 : : #endif
149 : :
150 : :
151 : : static GIOChannel *channel_socket;
152 : : static GByteArray *socket_to_send;
153 : : static GMutex socket_to_send_lock;
154 : : static guint socket_tag;
155 : :
156 : : static void
157 : : update_socket_watch(void);
158 : :
159 : : static gboolean
160 : 0 : do_socket_send(GIOCondition condition)
161 : : {
162 : : gsize bw;
163 : 0 : GError *err = NULL;
164 : :
165 : 0 : g_return_val_if_fail(socket_to_send->len != 0, FALSE);
166 : 0 : g_return_val_if_fail(condition & G_IO_OUT, FALSE);
167 : :
168 : 0 : g_io_channel_write_chars(channel_socket,
169 : 0 : (gchar *)socket_to_send->data, socket_to_send->len, &bw, &err);
170 : 0 : if (err != NULL) {
171 : 0 : g_error("Error while sending socket %s", err->message);
172 : : return FALSE;
173 : : }
174 : 0 : g_byte_array_remove_range(socket_to_send, 0, bw);
175 : :
176 : 0 : if (socket_to_send->len == 0) {
177 : 0 : update_socket_watch();
178 : 0 : return FALSE;
179 : : }
180 : : return TRUE;
181 : : }
182 : :
183 : : static gboolean
184 : 0 : socket_prepare_sending(G_GNUC_UNUSED gpointer user_data)
185 : : {
186 : 0 : update_socket_watch();
187 : :
188 : 0 : return FALSE;
189 : : }
190 : :
191 : : static int
192 : 0 : send_msg(
193 : : VSCMsgType type,
194 : : uint32_t reader_id,
195 : : const void *msg,
196 : : unsigned int length
197 : : ) {
198 : : VSCMsgHeader mhHeader;
199 : :
200 : 0 : g_mutex_lock(&socket_to_send_lock);
201 : :
202 : 0 : if (verbose > 10) {
203 : 0 : printf("sending type=%d id=%u, len =%u (0x%x)\n",
204 : : type, reader_id, length, length);
205 : : }
206 : :
207 : 0 : mhHeader.type = htonl(type);
208 : 0 : mhHeader.reader_id = 0;
209 : 0 : mhHeader.length = htonl(length);
210 : 0 : g_byte_array_append(socket_to_send, (guint8 *)&mhHeader, sizeof(mhHeader));
211 : 0 : g_byte_array_append(socket_to_send, (guint8 *)msg, length);
212 : 0 : g_idle_add(socket_prepare_sending, NULL);
213 : :
214 : 0 : g_mutex_unlock(&socket_to_send_lock);
215 : :
216 : 0 : return 0;
217 : : }
218 : :
219 : : static VReader *pending_reader;
220 : : static GMutex pending_reader_lock;
221 : : static GCond pending_reader_condition;
222 : :
223 : : #define MAX_ATR_LEN 40
224 : : static gpointer
225 : 0 : event_thread(G_GNUC_UNUSED gpointer arg)
226 : : {
227 : : unsigned char atr[MAX_ATR_LEN];
228 : : int atr_len;
229 : : VEvent *event;
230 : : unsigned int reader_id;
231 : :
232 : : while (1) {
233 : : const char *reader_name;
234 : :
235 : 0 : event = vevent_wait_next_vevent();
236 : 0 : if (event == NULL) {
237 : : break;
238 : : }
239 : 0 : reader_id = vreader_get_id(event->reader);
240 : 0 : if (reader_id == VSCARD_UNDEFINED_READER_ID &&
241 : 0 : event->type != VEVENT_READER_INSERT) {
242 : : /* ignore events from readers qemu has rejected */
243 : : /* if qemu is still deciding on this reader, wait to see if need to
244 : : * forward this event */
245 : 0 : g_mutex_lock(&pending_reader_lock);
246 : 0 : if (!pending_reader || (pending_reader != event->reader)) {
247 : : /* wasn't for a pending reader, this reader has already been
248 : : * rejected by qemu */
249 : 0 : g_mutex_unlock(&pending_reader_lock);
250 : 0 : vevent_delete(event);
251 : 0 : continue;
252 : : }
253 : : /* this reader hasn't been told its status from qemu yet, wait for
254 : : * that status */
255 : 0 : while (pending_reader != NULL) {
256 : 0 : g_cond_wait(&pending_reader_condition, &pending_reader_lock);
257 : : }
258 : 0 : g_mutex_unlock(&pending_reader_lock);
259 : : /* now recheck the id */
260 : 0 : reader_id = vreader_get_id(event->reader);
261 : 0 : if (reader_id == VSCARD_UNDEFINED_READER_ID) {
262 : : /* this reader was rejected */
263 : 0 : vevent_delete(event);
264 : 0 : continue;
265 : : }
266 : : /* reader was accepted, now forward the event */
267 : : }
268 : 0 : switch (event->type) {
269 : 0 : case VEVENT_READER_INSERT:
270 : : /* tell qemu to insert a new CCID reader */
271 : : /* wait until qemu has responded to our first reader insert
272 : : * before we send a second. That way we won't confuse the responses
273 : : * */
274 : 0 : g_mutex_lock(&pending_reader_lock);
275 : 0 : while (pending_reader != NULL) {
276 : 0 : g_cond_wait(&pending_reader_condition, &pending_reader_lock);
277 : : }
278 : 0 : pending_reader = vreader_reference(event->reader);
279 : 0 : g_mutex_unlock(&pending_reader_lock);
280 : 0 : reader_name = vreader_get_name(event->reader);
281 : 0 : if (verbose > 10) {
282 : 0 : printf(" READER INSERT: %s\n", reader_name);
283 : : }
284 : 0 : send_msg(VSC_ReaderAdd,
285 : : reader_id, /* currerntly VSCARD_UNDEFINED_READER_ID */
286 : : NULL, 0 /* TODO reader_name, strlen(reader_name) */);
287 : 0 : break;
288 : 0 : case VEVENT_READER_REMOVE:
289 : : /* future, tell qemu that an old CCID reader has been removed */
290 : 0 : if (verbose > 10) {
291 : 0 : printf(" READER REMOVE: %u\n", reader_id);
292 : : }
293 : 0 : send_msg(VSC_ReaderRemove, reader_id, NULL, 0);
294 : 0 : break;
295 : 0 : case VEVENT_CARD_INSERT:
296 : : /* get the ATR (intended as a response to a power on from the
297 : : * reader */
298 : 0 : atr_len = MAX_ATR_LEN;
299 : 0 : vreader_power_on(event->reader, atr, &atr_len);
300 : : /* ATR call functions as a Card Insert event */
301 : 0 : if (verbose > 10) {
302 : 0 : printf(" CARD INSERT %u: ", reader_id);
303 : 0 : print_byte_array(atr, atr_len);
304 : : }
305 : 0 : send_msg(VSC_ATR, reader_id, atr, atr_len);
306 : 0 : break;
307 : 0 : case VEVENT_CARD_REMOVE:
308 : : /* Card removed */
309 : 0 : if (verbose > 10) {
310 : 0 : printf(" CARD REMOVE %u:\n", reader_id);
311 : : }
312 : 0 : send_msg(VSC_CardRemove, reader_id, NULL, 0);
313 : 0 : break;
314 : : case VEVENT_LAST:
315 : : default:
316 : : break;
317 : : }
318 : 0 : vevent_delete(event);
319 : : }
320 : 0 : return NULL;
321 : : }
322 : :
323 : :
324 : : static unsigned int
325 : : get_id_from_string(char *string, unsigned int default_id)
326 : : {
327 : 0 : unsigned int id = atoi(string);
328 : :
329 : : /* don't accidentally swith to zero because no numbers have been supplied */
330 : 0 : if ((id == 0) && *string != '0') {
331 : 0 : return default_id;
332 : : }
333 : : return id;
334 : : }
335 : :
336 : : static int
337 : 0 : on_host_init(VSCMsgHeader *mhHeader, VSCMsgInit *incoming)
338 : : {
339 : 0 : uint32_t *capabilities = (incoming->capabilities);
340 : 0 : int num_capabilities =
341 : 0 : 1 + ((mhHeader->length - sizeof(VSCMsgInit)) / sizeof(uint32_t));
342 : : int i;
343 : :
344 : 0 : incoming->version = ntohl(incoming->version);
345 : 0 : if (incoming->version != VSCARD_VERSION) {
346 : 0 : if (verbose > 0) {
347 : 0 : printf("warning: host has version %d, we have %d\n",
348 : : verbose, VSCARD_VERSION);
349 : : }
350 : : }
351 : 0 : if (incoming->magic != VSCARD_MAGIC) {
352 : 0 : printf("unexpected magic: got %d, expected %d\n",
353 : : incoming->magic, VSCARD_MAGIC);
354 : 0 : return -1;
355 : : }
356 : 0 : for (i = 0 ; i < num_capabilities; ++i) {
357 : 0 : capabilities[i] = ntohl(capabilities[i]);
358 : : }
359 : : /* Future: check capabilities */
360 : : /* remove whatever reader might be left in qemu,
361 : : * in case of an unclean previous exit. */
362 : 0 : send_msg(VSC_ReaderRemove, VSCARD_MINIMAL_READER_ID, NULL, 0);
363 : : /* launch the event_thread. This will trigger reader adds for all the
364 : : * existing readers */
365 : 0 : g_thread_new("vsc/event", event_thread, NULL);
366 : 0 : return 0;
367 : : }
368 : :
369 : :
370 : : enum {
371 : : STATE_HEADER,
372 : : STATE_MESSAGE,
373 : : };
374 : :
375 : : #define APDUBufSize 270
376 : :
377 : : static gboolean
378 : 0 : do_socket_read(GIOChannel *source,
379 : : GIOCondition condition)
380 : : {
381 : : int rv;
382 : : int dwSendLength;
383 : : int dwRecvLength;
384 : : uint8_t pbRecvBuffer[APDUBufSize];
385 : : static uint8_t pbSendBuffer[APDUBufSize];
386 : : VReaderStatus reader_status;
387 : : VReader *reader = NULL;
388 : : static VSCMsgHeader mhHeader;
389 : : VSCMsgError error_msg;
390 : 0 : GError *err = NULL;
391 : : VSCMsgInit init;
392 : :
393 : : static gchar *buf;
394 : : static gsize br, to_read;
395 : : static int state = STATE_HEADER;
396 : :
397 : 0 : g_return_val_if_fail(condition & G_IO_IN, FALSE);
398 : :
399 : 0 : if (state == STATE_HEADER && to_read == 0) {
400 : 0 : buf = (gchar *)&mhHeader;
401 : 0 : to_read = sizeof(mhHeader);
402 : : }
403 : :
404 : 0 : if (to_read > 0) {
405 : 0 : g_io_channel_read_chars(source, (gchar *)buf, to_read, &br, &err);
406 : 0 : if (err != NULL) {
407 : 0 : g_error("error while reading: %s", err->message);
408 : : }
409 : 0 : buf += br;
410 : 0 : to_read -= br;
411 : 0 : if (to_read != 0) {
412 : : return TRUE;
413 : : }
414 : : }
415 : :
416 : 0 : if (state == STATE_HEADER) {
417 : 0 : mhHeader.type = ntohl(mhHeader.type);
418 : 0 : mhHeader.reader_id = ntohl(mhHeader.reader_id);
419 : 0 : mhHeader.length = ntohl(mhHeader.length);
420 : 0 : if (verbose) {
421 : 0 : printf("Header: type=%d, reader_id=%u length=%d (0x%x)\n",
422 : : mhHeader.type, mhHeader.reader_id, mhHeader.length,
423 : : mhHeader.length);
424 : : }
425 : 0 : switch (mhHeader.type) {
426 : 0 : case VSC_APDU:
427 : : case VSC_Flush:
428 : : case VSC_Error:
429 : : case VSC_Init:
430 : 0 : buf = (gchar *)pbSendBuffer;
431 : 0 : to_read = mhHeader.length;
432 : 0 : state = STATE_MESSAGE;
433 : 0 : return TRUE;
434 : 0 : default:
435 : 0 : fprintf(stderr, "Unexpected message of type 0x%X\n", mhHeader.type);
436 : 0 : return FALSE;
437 : : }
438 : : }
439 : :
440 : 0 : if (state == STATE_MESSAGE) {
441 : : char *reply = NULL;
442 : : #if defined(ENABLE_PCSC)
443 : : int reply_size;
444 : : #endif
445 : :
446 : 0 : switch (mhHeader.type) {
447 : 0 : case VSC_APDU:
448 : 0 : if (verbose) {
449 : : static int n = 0;
450 : 0 : printf("\n\n >>> %d recv APDU: \n", n++);
451 : 0 : print_byte_array(pbSendBuffer, mhHeader.length);
452 : : }
453 : :
454 : : /* Transmit received APDU */
455 : 0 : dwSendLength = mhHeader.length;
456 : 0 : dwRecvLength = sizeof(pbRecvBuffer);
457 : 0 : reader = vreader_get_reader_by_id(mhHeader.reader_id);
458 : 0 : reader_status = vreader_xfr_bytes(reader,
459 : : pbSendBuffer, dwSendLength,
460 : : pbRecvBuffer, &dwRecvLength);
461 : 0 : if (verbose) {
462 : 0 : printf("libcacard response: ");
463 : 0 : print_byte_array(pbRecvBuffer, dwRecvLength);
464 : : }
465 : :
466 : : #if defined(ENABLE_PCSC)
467 : : if (with_pcsc) {
468 : : reply_size = dwRecvLength;
469 : : reply = g_memdup2(pbRecvBuffer, reply_size);
470 : :
471 : : dwSendLength = mhHeader.length;
472 : : dwRecvLength = sizeof(pbRecvBuffer);
473 : :
474 : : if (!pcsc_transmit(pbSendBuffer, dwSendLength,
475 : : pbRecvBuffer, &dwRecvLength))
476 : : reader_status = VREADER_OK;
477 : : else
478 : : reader_status = VREADER_NO_CARD;
479 : : }
480 : : #endif
481 : :
482 : 0 : if (reader_status == VREADER_OK) {
483 : 0 : mhHeader.length = dwRecvLength;
484 : : #if defined(ENABLE_PCSC)
485 : : if (with_pcsc && verbose) {
486 : : int diff = (unsigned int) reply_size != mhHeader.length ||
487 : : memcmp(pbRecvBuffer, reply, reply_size);
488 : : printf("HW response:%s ", diff ? "\x1B[31m!!!\x1B[0m" : "");
489 : : print_byte_array(pbRecvBuffer, mhHeader.length);
490 : : }
491 : : #endif
492 : 0 : send_msg(VSC_APDU, mhHeader.reader_id,
493 : : pbRecvBuffer, dwRecvLength);
494 : : } else {
495 : 0 : rv = reader_status; /* warning: not meaningful */
496 : 0 : send_msg(VSC_Error, mhHeader.reader_id, &rv, sizeof(uint32_t));
497 : : }
498 : 0 : g_free(reply);
499 : 0 : vreader_free(reader);
500 : : reader = NULL; /* we've freed it, don't use it by accident
501 : : again */
502 : 0 : break;
503 : 0 : case VSC_Flush:
504 : : /* TODO: actually flush */
505 : 0 : send_msg(VSC_FlushComplete, mhHeader.reader_id, NULL, 0);
506 : 0 : break;
507 : 0 : case VSC_Error:
508 : 0 : memcpy(&error_msg, pbSendBuffer, sizeof(VSCMsgError));
509 : 0 : if (error_msg.code == VSC_SUCCESS) {
510 : 0 : g_mutex_lock(&pending_reader_lock);
511 : 0 : if (pending_reader) {
512 : 0 : vreader_set_id(pending_reader, mhHeader.reader_id);
513 : 0 : vreader_free(pending_reader);
514 : 0 : pending_reader = NULL;
515 : 0 : g_cond_signal(&pending_reader_condition);
516 : : }
517 : 0 : g_mutex_unlock(&pending_reader_lock);
518 : 0 : break;
519 : : }
520 : 0 : printf("warning: qemu refused to add reader\n");
521 : 0 : if (error_msg.code == VSC_CANNOT_ADD_MORE_READERS) {
522 : : /* clear pending reader, qemu can't handle any more */
523 : 0 : g_mutex_lock(&pending_reader_lock);
524 : 0 : if (pending_reader) {
525 : 0 : pending_reader = NULL;
526 : : /* make sure the event loop doesn't hang */
527 : 0 : g_cond_signal(&pending_reader_condition);
528 : : }
529 : 0 : g_mutex_unlock(&pending_reader_lock);
530 : : }
531 : : break;
532 : 0 : case VSC_Init:
533 : 0 : memcpy(&init, pbSendBuffer, sizeof(VSCMsgInit));
534 : 0 : if (on_host_init(&mhHeader, &init) < 0) {
535 : : return FALSE;
536 : : }
537 : : break;
538 : 0 : default:
539 : 0 : g_assert_not_reached();
540 : : return FALSE;
541 : : }
542 : :
543 : 0 : state = STATE_HEADER;
544 : : }
545 : :
546 : :
547 : : return TRUE;
548 : : }
549 : :
550 : : static gboolean
551 : 0 : do_socket(GIOChannel *source,
552 : : GIOCondition condition,
553 : : G_GNUC_UNUSED gpointer data)
554 : : {
555 : : /* not sure if two watches work well with a single win32 sources */
556 : 0 : if (condition & G_IO_OUT) {
557 : 0 : if (!do_socket_send(condition)) {
558 : : return FALSE;
559 : : }
560 : : }
561 : :
562 : 0 : if (condition & G_IO_IN) {
563 : 0 : if (!do_socket_read(source, condition)) {
564 : : return FALSE;
565 : : }
566 : : }
567 : :
568 : : return TRUE;
569 : : }
570 : :
571 : : static void
572 : 0 : update_socket_watch(void)
573 : : {
574 : 0 : gboolean out = socket_to_send->len > 0;
575 : :
576 : 0 : if (socket_tag != 0) {
577 : 0 : g_source_remove(socket_tag);
578 : : }
579 : :
580 : 0 : socket_tag = g_io_add_watch(channel_socket,
581 : : G_IO_IN | (out ? G_IO_OUT : 0), do_socket, NULL);
582 : 0 : }
583 : :
584 : : static gboolean
585 : 0 : do_command(GIOChannel *source,
586 : : GIOCondition condition,
587 : : G_GNUC_UNUSED gpointer data)
588 : : {
589 : : char *string;
590 : : VCardEmulError error;
591 : : static unsigned int default_reader_id;
592 : : unsigned int reader_id;
593 : : VReader *reader = NULL;
594 : 0 : GError *err = NULL;
595 : :
596 : 0 : g_assert(condition & G_IO_IN);
597 : :
598 : 0 : reader_id = default_reader_id;
599 : 0 : g_io_channel_read_line(source, &string, NULL, NULL, &err);
600 : 0 : if (err != NULL) {
601 : 0 : g_error("Error while reading command: %s", err->message);
602 : : }
603 : :
604 : 0 : if (string != NULL) {
605 : 0 : if (strncmp(string, "exit", 4) == 0) {
606 : : /* remove all the readers */
607 : 0 : VReaderList *list = vreader_get_reader_list();
608 : : VReaderListEntry *reader_entry;
609 : 0 : printf("Active Readers:\n");
610 : 0 : for (reader_entry = vreader_list_get_first(list); reader_entry;
611 : 0 : reader_entry = vreader_list_get_next(reader_entry)) {
612 : 0 : VReader *r = vreader_list_get_reader(reader_entry);
613 : : vreader_id_t id;
614 : 0 : id = vreader_get_id(r);
615 : 0 : if (id == (vreader_id_t)-1) {
616 : 0 : continue;
617 : : }
618 : : /* be nice and signal card removal first (qemu probably should
619 : : * do this itself) */
620 : 0 : if (vreader_card_is_present(r) == VREADER_OK) {
621 : 0 : send_msg(VSC_CardRemove, id, NULL, 0);
622 : : }
623 : 0 : send_msg(VSC_ReaderRemove, id, NULL, 0);
624 : : }
625 : 0 : exit(0);
626 : 0 : } else if (strncmp(string, "insert", 6) == 0) {
627 : 0 : if (string[6] == ' ') {
628 : 0 : reader_id = get_id_from_string(&string[7], reader_id);
629 : : }
630 : 0 : reader = vreader_get_reader_by_id(reader_id);
631 : 0 : if (reader != NULL) {
632 : 0 : error = vcard_emul_force_card_insert(reader);
633 : 0 : printf("insert %s, returned %d\n",
634 : : vreader_get_name(reader), error);
635 : : } else {
636 : 0 : printf("no reader by id %u found\n", reader_id);
637 : : }
638 : 0 : } else if (strncmp(string, "remove", 6) == 0) {
639 : 0 : if (string[6] == ' ') {
640 : 0 : reader_id = get_id_from_string(&string[7], reader_id);
641 : : }
642 : 0 : reader = vreader_get_reader_by_id(reader_id);
643 : 0 : if (reader != NULL) {
644 : 0 : error = vcard_emul_force_card_remove(reader);
645 : 0 : printf("remove %s, returned %d\n",
646 : : vreader_get_name(reader), error);
647 : : } else {
648 : 0 : printf("no reader by id %u found\n", reader_id);
649 : : }
650 : 0 : } else if (strncmp(string, "select", 6) == 0) {
651 : 0 : if (string[6] == ' ') {
652 : 0 : reader_id = get_id_from_string(&string[7],
653 : : VSCARD_UNDEFINED_READER_ID);
654 : : }
655 : 0 : if (reader_id != VSCARD_UNDEFINED_READER_ID) {
656 : 0 : reader = vreader_get_reader_by_id(reader_id);
657 : : }
658 : 0 : if (reader) {
659 : 0 : printf("Selecting reader %u, %s\n", reader_id,
660 : : vreader_get_name(reader));
661 : 0 : default_reader_id = reader_id;
662 : : } else {
663 : 0 : printf("Reader with id %u not found\n", reader_id);
664 : : }
665 : 0 : } else if (strncmp(string, "debug", 5) == 0) {
666 : 0 : if (string[5] == ' ') {
667 : 0 : verbose = get_id_from_string(&string[6], 0);
668 : : }
669 : 0 : printf("debug level = %d\n", verbose);
670 : 0 : } else if (strncmp(string, "list", 4) == 0) {
671 : 0 : VReaderList *list = vreader_get_reader_list();
672 : : VReaderListEntry *reader_entry;
673 : 0 : printf("Active Readers:\n");
674 : 0 : for (reader_entry = vreader_list_get_first(list); reader_entry;
675 : 0 : reader_entry = vreader_list_get_next(reader_entry)) {
676 : 0 : VReader *r = vreader_list_get_reader(reader_entry);
677 : : vreader_id_t id;
678 : 0 : id = vreader_get_id(r);
679 : 0 : if (id == (vreader_id_t)-1) {
680 : 0 : continue;
681 : : }
682 : 0 : printf("%3u %s %s\n", id,
683 : 0 : vreader_card_is_present(r) == VREADER_OK ?
684 : : "CARD_PRESENT" : " ",
685 : : vreader_get_name(r));
686 : : }
687 : 0 : printf("Inactive Readers:\n");
688 : 0 : for (reader_entry = vreader_list_get_first(list); reader_entry;
689 : 0 : reader_entry = vreader_list_get_next(reader_entry)) {
690 : 0 : VReader *r = vreader_list_get_reader(reader_entry);
691 : : vreader_id_t id;
692 : 0 : id = vreader_get_id(reader);
693 : 0 : if (id != (vreader_id_t)-1) {
694 : 0 : continue;
695 : : }
696 : :
697 : 0 : printf("INA %s %s\n",
698 : 0 : vreader_card_is_present(r) == VREADER_OK ?
699 : : "CARD_PRESENT" : " ",
700 : : vreader_get_name(r));
701 : : }
702 : 0 : vreader_list_delete(list);
703 : 0 : } else if (*string != 0) {
704 : 0 : printf("valid commands:\n");
705 : 0 : printf("insert [reader_id]\n");
706 : 0 : printf("remove [reader_id]\n");
707 : 0 : printf("select reader_id\n");
708 : 0 : printf("list\n");
709 : 0 : printf("debug [level]\n");
710 : 0 : printf("exit\n");
711 : : }
712 : : }
713 : 0 : vreader_free(reader);
714 : 0 : printf("> ");
715 : 0 : fflush(stdout);
716 : :
717 : 0 : return TRUE;
718 : : }
719 : :
720 : :
721 : : /* just for ease of parsing command line arguments. */
722 : : #define MAX_CERTS 100
723 : :
724 : : static int
725 : 0 : connect_to_qemu(
726 : : const char *host,
727 : : const char *port
728 : : ) {
729 : : struct addrinfo hints;
730 : 0 : struct addrinfo *server = NULL;
731 : : int ret, sock;
732 : :
733 : 0 : sock = socket(AF_INET, SOCK_STREAM, 0);
734 : 0 : if (sock < 0) {
735 : : /* Error */
736 : 0 : fprintf(stderr, "Error opening socket!\n");
737 : 0 : return -1;
738 : : }
739 : :
740 : 0 : memset(&hints, 0, sizeof(struct addrinfo));
741 : : hints.ai_family = AF_UNSPEC;
742 : 0 : hints.ai_socktype = SOCK_STREAM;
743 : : hints.ai_flags = 0;
744 : : hints.ai_protocol = 0; /* Any protocol */
745 : :
746 : 0 : ret = getaddrinfo(host, port, &hints, &server);
747 : :
748 : 0 : if (ret != 0) {
749 : : /* Error */
750 : 0 : fprintf(stderr, "getaddrinfo failed\n");
751 : 0 : goto cleanup_socket;
752 : : }
753 : :
754 : 0 : if (connect(sock, server->ai_addr, server->ai_addrlen) < 0) {
755 : : /* Error */
756 : 0 : fprintf(stderr, "Could not connect\n");
757 : 0 : goto cleanup_socket;
758 : : }
759 : 0 : if (verbose) {
760 : 0 : printf("Connected (sizeof Header=%zd)!\n", sizeof(VSCMsgHeader));
761 : : }
762 : :
763 : 0 : freeaddrinfo(server);
764 : 0 : return sock;
765 : :
766 : 0 : cleanup_socket:
767 : 0 : if (server) {
768 : 0 : freeaddrinfo(server);
769 : : }
770 : 0 : closesocket(sock);
771 : 0 : return -1;
772 : : }
773 : :
774 : : int
775 : 0 : main(
776 : : int argc,
777 : : char *argv[]
778 : : ) {
779 : : GMainLoop *loop;
780 : : GIOChannel *channel_stdin;
781 : : char *qemu_host;
782 : : char *qemu_port;
783 : : VSCMsgInit init;
784 : : VCardEmulOptions *command_line_options = NULL;
785 : :
786 : : char *cert_names[MAX_CERTS];
787 : : char *emul_args = NULL;
788 : : int cert_count = 0;
789 : : int c, sock;
790 : :
791 : : #ifdef _WIN32
792 : : WSADATA Data;
793 : :
794 : : if (WSAStartup(MAKEWORD(2, 2), &Data) != 0) {
795 : : c = WSAGetLastError();
796 : : fprintf(stderr, "WSAStartup: %d\n", c);
797 : : return 1;
798 : : }
799 : : #endif
800 : :
801 : 0 : while ((c = getopt(argc, argv, "c:e:d:p")) != -1) {
802 : 0 : if (c == '?') {
803 : : break;
804 : : }
805 : :
806 : 0 : switch (c) {
807 : 0 : case 'c':
808 : 0 : assert(optarg != NULL);
809 : 0 : if (cert_count >= MAX_CERTS) {
810 : 0 : printf("too many certificates (max = %d)\n", MAX_CERTS);
811 : 0 : exit(5);
812 : : }
813 : 0 : cert_names[cert_count++] = optarg;
814 : 0 : break;
815 : 0 : case 'e':
816 : 0 : assert(optarg != NULL);
817 : : emul_args = optarg;
818 : : break;
819 : 0 : case 'd':
820 : 0 : assert(optarg != NULL);
821 : 0 : verbose = get_id_from_string(optarg, 1);
822 : 0 : break;
823 : 0 : case 'p':
824 : 0 : with_pcsc = 1;
825 : 0 : break;
826 : 0 : default:
827 : 0 : g_warn_if_reached();
828 : : }
829 : : }
830 : :
831 : 0 : if (argc - optind != 2) {
832 : 0 : print_usage();
833 : 0 : exit(4);
834 : : }
835 : :
836 : 0 : if (cert_count > 0) {
837 : : char *new_args;
838 : : int len, i;
839 : : /* if we've given some -c options, we clearly we want do so some
840 : : * software emulation. add that emulation now. this is NSS Emulator
841 : : * specific */
842 : 0 : if (emul_args == NULL) {
843 : : emul_args = (char *)"db=\"/etc/pki/nssdb\"";
844 : : }
845 : : #define SOFT_STRING ",soft=(,Virtual Reader,CAC,,"
846 : : /* 2 == close paren & null */
847 : 0 : len = strlen(emul_args) + strlen(SOFT_STRING) + 2;
848 : 0 : for (i = 0; i < cert_count; i++) {
849 : 0 : len += strlen(cert_names[i])+1; /* 1 == comma */
850 : : }
851 : 0 : new_args = g_malloc(len);
852 : 0 : strcpy(new_args, emul_args);
853 : 0 : strcat(new_args, SOFT_STRING);
854 : 0 : for (i = 0; i < cert_count; i++) {
855 : 0 : strcat(new_args, cert_names[i]);
856 : 0 : strcat(new_args, ",");
857 : : }
858 : 0 : strcat(new_args, ")");
859 : : emul_args = new_args;
860 : : }
861 : 0 : if (emul_args) {
862 : 0 : command_line_options = vcard_emul_options(emul_args);
863 : : }
864 : 0 : if (cert_count > 0) {
865 : 0 : g_free(emul_args);
866 : : emul_args = NULL;
867 : : }
868 : :
869 : 0 : qemu_host = g_strdup(argv[argc - 2]);
870 : 0 : qemu_port = g_strdup(argv[argc - 1]);
871 : 0 : sock = connect_to_qemu(qemu_host, qemu_port);
872 : 0 : if (sock == -1) {
873 : 0 : fprintf(stderr, "error opening socket, exiting.\n");
874 : 0 : exit(5);
875 : : }
876 : :
877 : 0 : socket_to_send = g_byte_array_new();
878 : 0 : vcard_emul_init(command_line_options);
879 : 0 : loop = g_main_loop_new(NULL, TRUE);
880 : :
881 : 0 : printf("> ");
882 : 0 : fflush(stdout);
883 : :
884 : : #ifdef _WIN32
885 : : channel_stdin = g_io_channel_win32_new_fd(STDIN_FILENO);
886 : : #else
887 : 0 : channel_stdin = g_io_channel_unix_new(STDIN_FILENO);
888 : : #endif
889 : 0 : g_io_add_watch(channel_stdin, G_IO_IN, do_command, NULL);
890 : : #ifdef _WIN32
891 : : channel_socket = g_io_channel_win32_new_socket(sock);
892 : : #else
893 : 0 : channel_socket = g_io_channel_unix_new(sock);
894 : : #endif
895 : 0 : g_io_channel_set_encoding(channel_socket, NULL, NULL);
896 : : /* we buffer ourself for thread safety reasons */
897 : 0 : g_io_channel_set_buffered(channel_socket, FALSE);
898 : :
899 : 0 : if (with_pcsc) {
900 : : #if defined(ENABLE_PCSC)
901 : : if (!pcsc_init())
902 : : return 1;
903 : : #else
904 : 0 : printf("No PCSC support\n");
905 : 0 : return 1;
906 : : #endif
907 : : }
908 : :
909 : : /* Send init message, Host responds (and then we send reader attachments) */
910 : 0 : init = (VSCMsgInit) {
911 : : .version = htonl(VSCARD_VERSION),
912 : : .magic = VSCARD_MAGIC,
913 : : .capabilities = {0}
914 : : };
915 : 0 : send_msg(VSC_Init, 0, &init, sizeof(init));
916 : :
917 : 0 : g_main_loop_run(loop);
918 : 0 : g_main_loop_unref(loop);
919 : :
920 : 0 : g_io_channel_unref(channel_stdin);
921 : 0 : g_io_channel_unref(channel_socket);
922 : 0 : g_byte_array_free(socket_to_send, TRUE);
923 : :
924 : 0 : closesocket(sock);
925 : :
926 : : #if defined(ENABLE_PCSC)
927 : : pcsc_deinit();
928 : : #endif
929 : :
930 : 0 : vcard_emul_finalize();
931 : :
932 : 0 : return 0;
933 : : }
|