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