static gboolean smartcard_manager_init(SmartcardManagerInitArgs *args) { gchar *emul_args = NULL; VCardEmulOptions *options = NULL; VCardEmulError emul_init_status; gchar *dbname = NULL; GStrv certificates = NULL; gboolean retval = FALSE; SPICE_DEBUG("smartcard_manager_init"); g_return_val_if_fail(SPICE_IS_SESSION(args->session), FALSE); g_object_get(G_OBJECT(args->session), "smartcard-db", &dbname, "smartcard-certificates", &certificates, NULL); if ((certificates == NULL) || (g_strv_length(certificates) != 3)) goto init; if (dbname) { emul_args = g_strdup_printf("db=\"%s\" use_hw=no " "soft=(,%s,CAC,,%s,%s,%s)", dbname, SPICE_SOFTWARE_READER_NAME, certificates[0], certificates[1], certificates[2]); } else { emul_args = g_strdup_printf("use_hw=no soft=(,%s,CAC,,%s,%s,%s)", SPICE_SOFTWARE_READER_NAME, certificates[0], certificates[1], certificates[2]); } options = vcard_emul_options(emul_args); if (options == NULL) { args->err = g_error_new(SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, "vcard_emul_options() failed!"); goto end; } if (g_cancellable_set_error_if_cancelled(args->cancellable, &args->err)) goto end; init: SPICE_DEBUG("vcard_emul_init"); emul_init_status = vcard_emul_init(options); if ((emul_init_status != VCARD_EMUL_OK) && (emul_init_status != VCARD_EMUL_INIT_ALREADY_INITED)) { args->err = g_error_new(SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, "Failed to initialize smartcard"); goto end; } retval = TRUE; end: SPICE_DEBUG("smartcard_manager_init end: %d", retval); g_free(emul_args); g_free(dbname); g_strfreev(certificates); return retval; }
int main( int argc, char *argv[] ) { 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; while ((c = getopt(argc, argv, "c:e:pd:")) != -1) { switch (c) { case 'c': if (cert_count >= MAX_CERTS) { printf("too many certificates (max = %d)\n", MAX_CERTS); exit(5); } cert_names[cert_count++] = optarg; break; case 'e': emul_args = optarg; break; case 'p': print_usage(); exit(4); break; case 'd': verbose = get_id_from_string(optarg, 1); break; } } if (argc - optind != 2) { print_usage(); exit(4); } if (cert_count > 0) { char *new_args; int len, i; /* if we've given some -c options, we clearly we want do so some * software emulation. add that emulation now. this is NSS Emulator * specific */ if (emul_args == NULL) { emul_args = (char *)"db=\"/etc/pki/nssdb\""; } #define SOFT_STRING ",soft=(,Virtual Reader,CAC,," /* 2 == close paren & null */ len = strlen(emul_args) + strlen(SOFT_STRING) + 2; for (i = 0; i < cert_count; i++) { len += strlen(cert_names[i])+1; /* 1 == comma */ } new_args = g_malloc(len); strcpy(new_args, emul_args); strcat(new_args, SOFT_STRING); for (i = 0; i < cert_count; i++) { strcat(new_args, cert_names[i]); strcat(new_args, ","); } strcat(new_args, ")"); emul_args = new_args; } if (emul_args) { command_line_options = vcard_emul_options(emul_args); } qemu_host = g_strdup(argv[argc - 2]); qemu_port = g_strdup(argv[argc - 1]); sock = connect_to_qemu(qemu_host, qemu_port); if (sock == -1) { fprintf(stderr, "error opening socket, exiting.\n"); exit(5); } qemu_mutex_init(&write_lock); qemu_mutex_init(&pending_reader_lock); qemu_cond_init(&pending_reader_condition); vcard_emul_init(command_line_options); printf("> "); fflush(stdout); /* Send init message, Host responds (and then we send reader attachments) */ VSCMsgInit init = { .version = htonl(VSCARD_VERSION), .magic = VSCARD_MAGIC, .capabilities = {0} }; send_msg(VSC_Init, mhHeader.reader_id, &init, sizeof(init)); do { fd_set fds; FD_ZERO(&fds); FD_SET(1, &fds); FD_SET(sock, &fds); /* waiting on input from the socket */ rv = select(sock+1, &fds, NULL, NULL, NULL); if (rv < 0) { /* handle error */ perror("select"); return 7; } if (FD_ISSET(1, &fds)) { do_command(); } 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; } } while (rv >= 0); return 0; }