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#include <netdb.h>
  14
  15#include "qemu-common.h"
  16#include "qemu-thread.h"
  17#include "qemu_socket.h"
  18
  19#include "vscard_common.h"
  20
  21#include "vreader.h"
  22#include "vcard_emul.h"
  23#include "vevent.h"
  24
  25int verbose;
  26
  27int sock;
  28
  29static void
  30print_byte_array(
  31    uint8_t *arrBytes,
  32    unsigned int nSize
  33) {
  34    int i;
  35    for (i = 0; i < nSize; i++) {
  36        printf("%02X ", arrBytes[i]);
  37    }
  38    printf("\n");
  39}
  40
  41static void
  42print_usage(void) {
  43    printf("vscclient [-c <certname> .. -e <emul_args> -d <level>%s] "
  44            "<host> <port>\n",
  45#ifdef USE_PASSTHRU
  46    " -p");
  47    printf(" -p use passthrough mode\n");
  48#else
  49   "");
  50#endif
  51    vcard_emul_usage();
  52}
  53
  54static QemuMutex write_lock;
  55
  56static int
  57send_msg(
  58    VSCMsgType type,
  59    uint32_t reader_id,
  60    const void *msg,
  61    unsigned int length
  62) {
  63    int rv;
  64    VSCMsgHeader mhHeader;
  65
  66    qemu_mutex_lock(&write_lock);
  67
  68    if (verbose > 10) {
  69        printf("sending type=%d id=%d, len =%d (0x%x)\n",
  70               type, reader_id, length, length);
  71    }
  72
  73    mhHeader.type = htonl(type);
  74    mhHeader.reader_id = 0;
  75    mhHeader.length = htonl(length);
  76    rv = write(sock, &mhHeader, sizeof(mhHeader));
  77    if (rv < 0) {
  78        /* Error */
  79        fprintf(stderr, "write header error\n");
  80        close(sock);
  81        qemu_mutex_unlock(&write_lock);
  82        return 16;
  83    }
  84    rv = write(sock, msg, length);
  85    if (rv < 0) {
  86        /* Error */
  87        fprintf(stderr, "write error\n");
  88        close(sock);
  89        qemu_mutex_unlock(&write_lock);
  90        return 16;
  91    }
  92    qemu_mutex_unlock(&write_lock);
  93
  94    return 0;
  95}
  96
  97static VReader *pending_reader;
  98static QemuMutex pending_reader_lock;
  99static QemuCond pending_reader_condition;
 100
 101#define MAX_ATR_LEN 40
 102static void *
 103event_thread(void *arg)
 104{
 105    unsigned char atr[MAX_ATR_LEN];
 106    int atr_len = MAX_ATR_LEN;
 107    VEvent *event = NULL;
 108    unsigned int reader_id;
 109
 110
 111    while (1) {
 112        const char *reader_name;
 113
 114        event = vevent_wait_next_vevent();
 115        if (event == NULL) {
 116            break;
 117        }
 118        reader_id = vreader_get_id(event->reader);
 119        if (reader_id == VSCARD_UNDEFINED_READER_ID &&
 120            event->type != VEVENT_READER_INSERT) {
 121            /* ignore events from readers qemu has rejected */
 122            /* if qemu is still deciding on this reader, wait to see if need to
 123             * forward this event */
 124            qemu_mutex_lock(&pending_reader_lock);
 125            if (!pending_reader || (pending_reader != event->reader)) {
 126                /* wasn't for a pending reader, this reader has already been
 127                 * rejected by qemu */
 128                qemu_mutex_unlock(&pending_reader_lock);
 129                vevent_delete(event);
 130                continue;
 131            }
 132            /* this reader hasn't been told it's status from qemu yet, wait for
 133             * that status */
 134            while (pending_reader != NULL) {
 135                qemu_cond_wait(&pending_reader_condition, &pending_reader_lock);
 136            }
 137            qemu_mutex_unlock(&pending_reader_lock);
 138            /* now recheck the id */
 139            reader_id = vreader_get_id(event->reader);
 140            if (reader_id == VSCARD_UNDEFINED_READER_ID) {
 141                /* this reader was rejected */
 142                vevent_delete(event);
 143                continue;
 144            }
 145            /* reader was accepted, now forward the event */
 146        }
 147        switch (event->type) {
 148        case VEVENT_READER_INSERT:
 149            /* tell qemu to insert a new CCID reader */
 150            /* wait until qemu has responded to our first reader insert
 151             * before we send a second. That way we won't confuse the responses
 152             * */
 153            qemu_mutex_lock(&pending_reader_lock);
 154            while (pending_reader != NULL) {
 155                qemu_cond_wait(&pending_reader_condition, &pending_reader_lock);
 156            }
 157            pending_reader = vreader_reference(event->reader);
 158            qemu_mutex_unlock(&pending_reader_lock);
 159            reader_name = vreader_get_name(event->reader);
 160            if (verbose > 10) {
 161                printf(" READER INSERT: %s\n", reader_name);
 162            }
 163            send_msg(VSC_ReaderAdd,
 164                reader_id, /* currerntly VSCARD_UNDEFINED_READER_ID */
 165                NULL, 0 /* TODO reader_name, strlen(reader_name) */);
 166            break;
 167        case VEVENT_READER_REMOVE:
 168            /* future, tell qemu that an old CCID reader has been removed */
 169            if (verbose > 10) {
 170                printf(" READER REMOVE: %d\n", reader_id);
 171            }
 172            send_msg(VSC_ReaderRemove, reader_id, NULL, 0);
 173            break;
 174        case VEVENT_CARD_INSERT:
 175            /* get the ATR (intended as a response to a power on from the
 176             * reader */
 177            atr_len = MAX_ATR_LEN;
 178            vreader_power_on(event->reader, atr, &atr_len);
 179            /* ATR call functions as a Card Insert event */
 180            if (verbose > 10) {
 181                printf(" CARD INSERT %d: ", reader_id);
 182                print_byte_array(atr, atr_len);
 183            }
 184            send_msg(VSC_ATR, reader_id, atr, atr_len);
 185            break;
 186        case VEVENT_CARD_REMOVE:
 187            /* Card removed */
 188            if (verbose > 10) {
 189                printf(" CARD REMOVE %d:\n", reader_id);
 190            }
 191            send_msg(VSC_CardRemove, reader_id, NULL, 0);
 192            break;
 193        default:
 194            break;
 195        }
 196        vevent_delete(event);
 197    }
 198    return NULL;
 199}
 200
 201
 202static unsigned int
 203get_id_from_string(char *string, unsigned int default_id)
 204{
 205    unsigned int id = atoi(string);
 206
 207    /* don't accidentally swith to zero because no numbers have been supplied */
 208    if ((id == 0) && *string != '0') {
 209        return default_id;
 210    }
 211    return id;
 212}
 213
 214static void
 215do_command(void)
 216{
 217    char inbuf[255];
 218    char *string;
 219    VCardEmulError error;
 220    static unsigned int default_reader_id;
 221    unsigned int reader_id;
 222    VReader *reader = NULL;
 223
 224    reader_id = default_reader_id;
 225    string = fgets(inbuf, sizeof(inbuf), stdin);
 226    if (string != NULL) {
 227        if (strncmp(string, "exit", 4) == 0) {
 228            /* remove all the readers */
 229            VReaderList *list = vreader_get_reader_list();
 230            VReaderListEntry *reader_entry;
 231            printf("Active Readers:\n");
 232            for (reader_entry = vreader_list_get_first(list); reader_entry;
 233                 reader_entry = vreader_list_get_next(reader_entry)) {
 234                VReader *reader = vreader_list_get_reader(reader_entry);
 235                vreader_id_t reader_id;
 236                reader_id = vreader_get_id(reader);
 237                if (reader_id == -1) {
 238                    continue;
 239                }
 240                /* be nice and signal card removal first (qemu probably should
 241                 * do this itself) */
 242                if (vreader_card_is_present(reader) == VREADER_OK) {
 243                    send_msg(VSC_CardRemove, reader_id, NULL, 0);
 244                }
 245                send_msg(VSC_ReaderRemove, reader_id, NULL, 0);
 246            }
 247            exit(0);
 248        } else if (strncmp(string, "insert", 6) == 0) {
 249            if (string[6] == ' ') {
 250                reader_id = get_id_from_string(&string[7], reader_id);
 251            }
 252            reader = vreader_get_reader_by_id(reader_id);
 253            if (reader != NULL) {
 254                error = vcard_emul_force_card_insert(reader);
 255                printf("insert %s, returned %d\n",
 256                       reader ? vreader_get_name(reader)
 257                       : "invalid reader", error);
 258            } else {
 259                printf("no reader by id %d found\n", reader_id);
 260            }
 261        } else if (strncmp(string, "remove", 6) == 0) {
 262            if (string[6] == ' ') {
 263                reader_id = get_id_from_string(&string[7], reader_id);
 264            }
 265            reader = vreader_get_reader_by_id(reader_id);
 266            if (reader != NULL) {
 267                error = vcard_emul_force_card_remove(reader);
 268                printf("remove %s, returned %d\n",
 269                        reader ? vreader_get_name(reader)
 270                        : "invalid reader", error);
 271            } else {
 272                printf("no reader by id %d found\n", reader_id);
 273            }
 274        } else if (strncmp(string, "select", 6) == 0) {
 275            if (string[6] == ' ') {
 276                reader_id = get_id_from_string(&string[7],
 277                                               VSCARD_UNDEFINED_READER_ID);
 278            }
 279            if (reader_id != VSCARD_UNDEFINED_READER_ID) {
 280                reader = vreader_get_reader_by_id(reader_id);
 281            }
 282            if (reader) {
 283                printf("Selecting reader %d, %s\n", reader_id,
 284                        vreader_get_name(reader));
 285                default_reader_id = reader_id;
 286            } else {
 287                printf("Reader with id %d not found\n", reader_id);
 288            }
 289        } else if (strncmp(string, "debug", 5) == 0) {
 290            if (string[5] == ' ') {
 291                verbose = get_id_from_string(&string[6], 0);
 292            }
 293            printf("debug level = %d\n", verbose);
 294        } else if (strncmp(string, "list", 4) == 0) {
 295            VReaderList *list = vreader_get_reader_list();
 296            VReaderListEntry *reader_entry;
 297            printf("Active Readers:\n");
 298            for (reader_entry = vreader_list_get_first(list); reader_entry;
 299                 reader_entry = vreader_list_get_next(reader_entry)) {
 300                VReader *reader = vreader_list_get_reader(reader_entry);
 301                vreader_id_t reader_id;
 302                reader_id = vreader_get_id(reader);
 303                if (reader_id == -1) {
 304                    continue;
 305                }
 306                printf("%3d %s %s\n", reader_id,
 307                       vreader_card_is_present(reader) == VREADER_OK ?
 308                       "CARD_PRESENT" : "            ",
 309                       vreader_get_name(reader));
 310            }
 311            printf("Inactive Readers:\n");
 312            for (reader_entry = vreader_list_get_first(list); reader_entry;
 313                 reader_entry = vreader_list_get_next(reader_entry)) {
 314                VReader *reader = vreader_list_get_reader(reader_entry);
 315                vreader_id_t reader_id;
 316                reader_id = vreader_get_id(reader);
 317                if (reader_id != -1) {
 318                    continue;
 319                }
 320
 321                printf("INA %s %s\n",
 322                       vreader_card_is_present(reader) == VREADER_OK ?
 323                       "CARD_PRESENT" : "            ",
 324                       vreader_get_name(reader));
 325            }
 326        } else if (*string != 0) {
 327            printf("valid commands:\n");
 328            printf("insert [reader_id]\n");
 329            printf("remove [reader_id]\n");
 330            printf("select reader_id\n");
 331            printf("list\n");
 332            printf("debug [level]\n");
 333            printf("exit\n");
 334        }
 335    }
 336    vreader_free(reader);
 337    printf("> ");
 338    fflush(stdout);
 339}
 340
 341
 342#define APDUBufSize 270
 343
 344/* just for ease of parsing command line arguments. */
 345#define MAX_CERTS 100
 346
 347static int
 348connect_to_qemu(
 349    const char *host,
 350    const char *port
 351) {
 352    struct addrinfo hints;
 353    struct addrinfo *server;
 354    int ret;
 355
 356    sock = qemu_socket(AF_INET, SOCK_STREAM, 0);
 357    if (sock < 0) {
 358        /* Error */
 359        fprintf(stderr, "Error opening socket!\n");
 360    }
 361
 362    memset(&hints, 0, sizeof(struct addrinfo));
 363    hints.ai_family = AF_UNSPEC;
 364    hints.ai_socktype = SOCK_STREAM;
 365    hints.ai_flags = 0;
 366    hints.ai_protocol = 0;          /* Any protocol */
 367
 368    ret = getaddrinfo(host, port, &hints, &server);
 369
 370    if (ret != 0) {
 371        /* Error */
 372        fprintf(stderr, "getaddrinfo failed\n");
 373        return 5;
 374    }
 375
 376    if (connect(sock, server->ai_addr, server->ai_addrlen) < 0) {
 377        /* Error */
 378        fprintf(stderr, "Could not connect\n");
 379        return 5;
 380    }
 381    if (verbose) {
 382        printf("Connected (sizeof Header=%zd)!\n", sizeof(VSCMsgHeader));
 383    }
 384    return sock;
 385}
 386
 387static int on_host_init(VSCMsgHeader *mhHeader, VSCMsgInit *incoming)
 388{
 389    uint32_t *capabilities = (incoming->capabilities);
 390    int num_capabilities =
 391        1 + ((mhHeader->length - sizeof(VSCMsgInit)) / sizeof(uint32_t));
 392    int i;
 393    int rv;
 394    pthread_t thread_id;
 395
 396    incoming->version = ntohl(incoming->version);
 397    if (incoming->version != VSCARD_VERSION) {
 398        if (verbose > 0) {
 399            printf("warning: host has version %d, we have %d\n",
 400                verbose, VSCARD_VERSION);
 401        }
 402    }
 403    if (incoming->magic != VSCARD_MAGIC) {
 404        printf("unexpected magic: got %d, expected %d\n",
 405            incoming->magic, VSCARD_MAGIC);
 406        return -1;
 407    }
 408    for (i = 0 ; i < num_capabilities; ++i) {
 409        capabilities[i] = ntohl(capabilities[i]);
 410    }
 411    /* Future: check capabilities */
 412    /* remove whatever reader might be left in qemu,
 413     * in case of an unclean previous exit. */
 414    send_msg(VSC_ReaderRemove, VSCARD_MINIMAL_READER_ID, NULL, 0);
 415    /* launch the event_thread. This will trigger reader adds for all the
 416     * existing readers */
 417    rv = pthread_create(&thread_id, NULL, event_thread, NULL);
 418    if (rv < 0) {
 419        perror("pthread_create");
 420        return rv;
 421    }
 422    return 0;
 423}
 424
 425int
 426main(
 427    int argc,
 428    char *argv[]
 429) {
 430    char *qemu_host;
 431    char *qemu_port;
 432    VSCMsgHeader mhHeader;
 433    VSCMsgError *error_msg;
 434
 435    int rv;
 436    int dwSendLength;
 437    int dwRecvLength;
 438    uint8_t pbRecvBuffer[APDUBufSize];
 439    uint8_t pbSendBuffer[APDUBufSize];
 440     VReaderStatus reader_status;
 441    VReader *reader = NULL;
 442    VCardEmulOptions *command_line_options = NULL;
 443
 444    char *cert_names[MAX_CERTS];
 445    char *emul_args = NULL;
 446    int cert_count = 0;
 447    int c;
 448
 449    while ((c = getopt(argc, argv, "c:e:pd:")) != -1) {
 450        switch (c) {
 451        case 'c':
 452            if (cert_count >= MAX_CERTS) {
 453                printf("too many certificates (max = %d)\n", MAX_CERTS);
 454                exit(5);
 455            }
 456            cert_names[cert_count++] = optarg;
 457            break;
 458        case 'e':
 459            emul_args = optarg;
 460            break;
 461        case 'p':
 462            print_usage();
 463            exit(4);
 464            break;
 465        case 'd':
 466            verbose = get_id_from_string(optarg, 1);
 467            break;
 468        }
 469    }
 470
 471    if (argc - optind != 2) {
 472        print_usage();
 473        exit(4);
 474    }
 475
 476    if (cert_count > 0) {
 477        char *new_args;
 478        int len, i;
 479        /* if we've given some -c options, we clearly we want do so some
 480         * software emulation.  add that emulation now. this is NSS Emulator
 481         * specific */
 482        if (emul_args == NULL) {
 483            emul_args = (char *)"db=\"/etc/pki/nssdb\"";
 484        }
 485#define SOFT_STRING ",soft=(,Virtual Reader,CAC,,"
 486             /* 2 == close paren & null */
 487        len = strlen(emul_args) + strlen(SOFT_STRING) + 2;
 488        for (i = 0; i < cert_count; i++) {
 489            len += strlen(cert_names[i])+1; /* 1 == comma */
 490        }
 491        new_args = qemu_malloc(len);
 492        strcpy(new_args, emul_args);
 493        strcat(new_args, SOFT_STRING);
 494        for (i = 0; i < cert_count; i++) {
 495            strcat(new_args, cert_names[i]);
 496            strcat(new_args, ",");
 497        }
 498        strcat(new_args, ")");
 499        emul_args = new_args;
 500    }
 501    if (emul_args) {
 502        command_line_options = vcard_emul_options(emul_args);
 503    }
 504
 505    qemu_host = strdup(argv[argc - 2]);
 506    qemu_port = strdup(argv[argc - 1]);
 507    sock = connect_to_qemu(qemu_host, qemu_port);
 508
 509    qemu_mutex_init(&write_lock);
 510    qemu_mutex_init(&pending_reader_lock);
 511    qemu_cond_init(&pending_reader_condition);
 512
 513    vcard_emul_init(command_line_options);
 514
 515    printf("> ");
 516    fflush(stdout);
 517
 518    /* Send init message, Host responds (and then we send reader attachments) */
 519    VSCMsgInit init = {
 520        .version = htonl(VSCARD_VERSION),
 521        .magic = VSCARD_MAGIC,
 522        .capabilities = {0}
 523    };
 524    send_msg(VSC_Init, mhHeader.reader_id, &init, sizeof(init));
 525
 526    do {
 527        fd_set fds;
 528
 529        FD_ZERO(&fds);
 530        FD_SET(1, &fds);
 531        FD_SET(sock, &fds);
 532
 533        /* waiting on input from the socket */
 534        rv = select(sock+1, &fds, NULL, NULL, NULL);
 535        if (rv < 0) {
 536            /* handle error */
 537            perror("select");
 538            return 7;
 539        }
 540        if (FD_ISSET(1, &fds)) {
 541            do_command();
 542        }
 543        if (!FD_ISSET(sock, &fds)) {
 544            continue;
 545        }
 546
 547        rv = read(sock, &mhHeader, sizeof(mhHeader));
 548        if (rv < sizeof(mhHeader)) {
 549            /* Error */
 550            if (rv < 0) {
 551                perror("header read error\n");
 552            } else {
 553                fprintf(stderr, "header short read %d\n", rv);
 554            }
 555            return 8;
 556        }
 557        mhHeader.type = ntohl(mhHeader.type);
 558        mhHeader.reader_id = ntohl(mhHeader.reader_id);
 559        mhHeader.length = ntohl(mhHeader.length);
 560        if (verbose) {
 561            printf("Header: type=%d, reader_id=%d length=%d (0x%x)\n",
 562                    mhHeader.type, mhHeader.reader_id, mhHeader.length,
 563                                               mhHeader.length);
 564        }
 565        switch (mhHeader.type) {
 566        case VSC_APDU:
 567        case VSC_Flush:
 568        case VSC_Error:
 569        case VSC_Init:
 570            rv = read(sock, pbSendBuffer, mhHeader.length);
 571            break;
 572        default:
 573            fprintf(stderr, "Unexpected message of type 0x%X\n", mhHeader.type);
 574            return 0;
 575        }
 576        switch (mhHeader.type) {
 577        case VSC_APDU:
 578            if (rv < 0) {
 579                /* Error */
 580                fprintf(stderr, "read error\n");
 581                close(sock);
 582                return 8;
 583            }
 584            if (verbose) {
 585                printf(" recv APDU: ");
 586                print_byte_array(pbSendBuffer, mhHeader.length);
 587            }
 588            /* Transmit recieved APDU */
 589            dwSendLength = mhHeader.length;
 590            dwRecvLength = sizeof(pbRecvBuffer);
 591            reader = vreader_get_reader_by_id(mhHeader.reader_id);
 592            reader_status = vreader_xfr_bytes(reader,
 593                pbSendBuffer, dwSendLength,
 594                pbRecvBuffer, &dwRecvLength);
 595            if (reader_status == VREADER_OK) {
 596                mhHeader.length = dwRecvLength;
 597                if (verbose) {
 598                    printf(" send response: ");
 599                    print_byte_array(pbRecvBuffer, mhHeader.length);
 600                }
 601                send_msg(VSC_APDU, mhHeader.reader_id,
 602                         pbRecvBuffer, dwRecvLength);
 603            } else {
 604                rv = reader_status; /* warning: not meaningful */
 605                send_msg(VSC_Error, mhHeader.reader_id, &rv, sizeof(uint32_t));
 606            }
 607            vreader_free(reader);
 608            reader = NULL; /* we've freed it, don't use it by accident
 609                              again */
 610            break;
 611        case VSC_Flush:
 612            /* TODO: actually flush */
 613            send_msg(VSC_FlushComplete, mhHeader.reader_id, NULL, 0);
 614            break;
 615        case VSC_Error:
 616            error_msg = (VSCMsgError *) pbSendBuffer;
 617            if (error_msg->code == VSC_SUCCESS) {
 618                qemu_mutex_lock(&pending_reader_lock);
 619                if (pending_reader) {
 620                    vreader_set_id(pending_reader, mhHeader.reader_id);
 621                    vreader_free(pending_reader);
 622                    pending_reader = NULL;
 623                    qemu_cond_signal(&pending_reader_condition);
 624                }
 625                qemu_mutex_unlock(&pending_reader_lock);
 626                break;
 627            }
 628            printf("warning: qemu refused to add reader\n");
 629            if (error_msg->code == VSC_CANNOT_ADD_MORE_READERS) {
 630                /* clear pending reader, qemu can't handle any more */
 631                qemu_mutex_lock(&pending_reader_lock);
 632                if (pending_reader) {
 633                    pending_reader = NULL;
 634                    /* make sure the event loop doesn't hang */
 635                    qemu_cond_signal(&pending_reader_condition);
 636                }
 637                qemu_mutex_unlock(&pending_reader_lock);
 638            }
 639            break;
 640        case VSC_Init:
 641            if (on_host_init(&mhHeader, (VSCMsgInit *)pbSendBuffer) < 0) {
 642                return -1;
 643            }
 644            break;
 645        default:
 646            printf("Default\n");
 647            return 0;
 648        }
 649    } while (rv >= 0);
 650
 651    return 0;
 652}
 653