diff options
60 files changed, 929 insertions, 5981 deletions
diff --git a/.gitignore b/.gitignore index fdd721dba1..75bceb9975 100644 --- a/.gitignore +++ b/.gitignore @@ -19,7 +19,6 @@ /trace/generated-ust.c /ui/shader/texture-blit-frag.h /ui/shader/texture-blit-vert.h -/libcacard/trace/generated-tracers.c *-timestamp /*-softmmu /*-darwin-user diff --git a/MAINTAINERS b/MAINTAINERS index b2e5fbd8e5..7aff1627b6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -266,10 +266,10 @@ F: *win32* ARM Machines ------------ Allwinner-a10 -M: Li Guang <lig.fnst@cn.fujitsu.com> +M: Beniamino Galvani <b.galvani@gmail.com> S: Maintained -F: hw/*/allwinner-a10* -F: include/hw/*/allwinner-a10* +F: hw/*/allwinner* +F: include/hw/*/allwinner* F: hw/arm/cubieboard.c Exynos @@ -163,9 +163,6 @@ dummy := $(call unnest-vars,, \ ifneq ($(wildcard config-host.mak),) include $(SRC_PATH)/tests/Makefile endif -ifeq ($(CONFIG_SMARTCARD_NSS),y) -include $(SRC_PATH)/libcacard/Makefile -endif all: $(DOCS) $(TOOLS) $(HELPERS-y) recurse-all modules @@ -626,6 +623,7 @@ endif # SIGNCODE $(if $(DLL_PATH),-DDLLDIR="$(DLL_PATH)") \ -DSRCDIR="$(SRC_PATH)" \ -DOUTFILE="$(INSTALLER)" \ + -DDISPLAYVERSION="$(VERSION)" \ $(SRC_PATH)/qemu.nsi rm -r ${INSTDIR} ifdef SIGNCODE diff --git a/Makefile.objs b/Makefile.objs index ce87778828..bc43e5c1dd 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -33,18 +33,6 @@ crypto-aes-obj-y = crypto/ qom-obj-y = qom/ ###################################################################### -# smartcard - -libcacard-y += libcacard/cac.o libcacard/event.o -libcacard-y += libcacard/vcard.o libcacard/vreader.o -libcacard-y += libcacard/vcard_emul_nss.o -libcacard-y += libcacard/vcard_emul_type.o -libcacard-y += libcacard/card_7816.o -libcacard-y += libcacard/vcardt.o -libcacard/vcard_emul_nss.o-cflags := $(NSS_CFLAGS) -libcacard/vcard_emul_nss.o-libs := $(NSS_LIBS) - -###################################################################### # Target independent part of system emulation. The long term path is to # suppress *all* target specific code in case of system emulation, i.e. a # single QEMU executable should support all CPUs and machines. @@ -85,8 +73,6 @@ common-obj-y += backends/ common-obj-$(CONFIG_SECCOMP) += qemu-seccomp.o -common-obj-$(CONFIG_SMARTCARD_NSS) += $(libcacard-y) - common-obj-$(CONFIG_FDT) += device_tree.o ###################################################################### @@ -302,7 +302,7 @@ trace_backends="nop" trace_file="trace" spice="" rbd="" -smartcard_nss="" +smartcard="" libusb="" usb_redir="" opengl="" @@ -1039,9 +1039,9 @@ for opt do ;; --enable-xfsctl) xfs="yes" ;; - --disable-smartcard-nss) smartcard_nss="no" + --disable-smartcard) smartcard="no" ;; - --enable-smartcard-nss) smartcard_nss="yes" + --enable-smartcard) smartcard="yes" ;; --disable-libusb) libusb="no" ;; @@ -1354,7 +1354,7 @@ disabled with --disable-FEATURE, default is enabled if available: rbd rados block device (rbd) libiscsi iscsi support libnfs nfs support - smartcard-nss smartcard nss support + smartcard smartcard support (libcacard) libusb libusb (for usb passthrough) usb-redir usb network redirection support lzo support of lzo compression library @@ -1737,6 +1737,37 @@ else fi ########################################## +# MinGW / Mingw-w64 localtime_r/gmtime_r check + +if test "$mingw32" = "yes"; then + # Some versions of MinGW / Mingw-w64 lack localtime_r + # and gmtime_r entirely. + # + # Some versions of Mingw-w64 define a macro for + # localtime_r/gmtime_r. + # + # Some versions of Mingw-w64 will define functions + # for localtime_r/gmtime_r, but only if you have + # _POSIX_THREAD_SAFE_FUNCTIONS defined. For fun + # though, unistd.h and pthread.h both define + # that for you. + # + # So this #undef localtime_r and #include <unistd.h> + # are not in fact redundant. +cat > $TMPC << EOF +#include <unistd.h> +#include <time.h> +#undef localtime_r +int main(void) { localtime_r(NULL, NULL); return 0; } +EOF + if compile_prog "" "" ; then + localtime_r="yes" + else + localtime_r="no" + fi +fi + +########################################## # pkg-config probe if ! has "$pkg_config_exe"; then @@ -3810,34 +3841,20 @@ EOF fi fi -# check for libcacard for smartcard support +# check for smartcard support smartcard_cflags="" -# TODO - what's the minimal nss version we support? -if test "$smartcard_nss" != "no"; then - cat > $TMPC << EOF -#include <pk11pub.h> -int main(void) { PK11_FreeSlot(0); return 0; } -EOF - # FIXME: do not include $glib_* in here - nss_libs="$($pkg_config --libs nss 2>/dev/null) $glib_libs" - nss_cflags="$($pkg_config --cflags nss 2>/dev/null) $glib_cflags" - test_cflags="$nss_cflags" - # The header files in nss < 3.13.3 have a bug which causes them to - # emit a warning. If we're going to compile QEMU with -Werror, then - # test that the headers don't have this bug. Otherwise we would pass - # the configure test but fail to compile QEMU later. - if test "$werror" = "yes"; then - test_cflags="-Werror $test_cflags" - fi - if test -n "$libtool" && - $pkg_config --atleast-version=3.12.8 nss && \ - compile_prog "$test_cflags" "$nss_libs"; then - smartcard_nss="yes" +if test "$smartcard" != "no"; then + if $pkg_config libcacard; then + libcacard_cflags=$($pkg_config --cflags libcacard) + libcacard_libs=$($pkg_config --libs libcacard) + QEMU_CFLAGS="$QEMU_CFLAGS $libcacard_cflags" + libs_softmmu="$libs_softmmu $libcacard_libs" + smartcard="yes" else - if test "$smartcard_nss" = "yes"; then - feature_not_found "nss" "Install nss devel >= 3.12.8" + if test "$smartcard" = "yes"; then + feature_not_found "smartcard" "Install libcacard devel" fi - smartcard_nss="no" + smartcard="no" fi fi @@ -4618,7 +4635,7 @@ echo "spice support $spice" fi echo "rbd support $rbd" echo "xfsctl support $xfs" -echo "nss used $smartcard_nss" +echo "smartcard support $smartcard" echo "libusb $libusb" echo "usb net redir $usb_redir" echo "OpenGL support $opengl" @@ -4995,10 +5012,8 @@ if test "$spice" = "yes" ; then echo "CONFIG_SPICE=y" >> $config_host_mak fi -if test "$smartcard_nss" = "yes" ; then - echo "CONFIG_SMARTCARD_NSS=y" >> $config_host_mak - echo "NSS_LIBS=$nss_libs" >> $config_host_mak - echo "NSS_CFLAGS=$nss_cflags" >> $config_host_mak +if test "$smartcard" = "yes" ; then + echo "CONFIG_SMARTCARD=y" >> $config_host_mak fi if test "$libusb" = "yes" ; then @@ -5050,6 +5065,9 @@ fi if test "$zero_malloc" = "yes" ; then echo "CONFIG_ZERO_MALLOC=y" >> $config_host_mak fi +if test "$localtime_r" = "yes" ; then + echo "CONFIG_LOCALTIME_R=y" >> $config_host_mak +fi if test "$qom_cast_debug" = "yes" ; then echo "CONFIG_QOM_CAST_DEBUG=y" >> $config_host_mak fi diff --git a/docs/libcacard.txt b/docs/libcacard.txt deleted file mode 100644 index 499cf7d79c..0000000000 --- a/docs/libcacard.txt +++ /dev/null @@ -1,483 +0,0 @@ -This file documents the CAC (Common Access Card) library in the libcacard -subdirectory. - -Virtual Smart Card Emulator - -This emulator is designed to provide emulation of actual smart cards to a -virtual card reader running in a guest virtual machine. The emulated smart -cards can be representations of real smart cards, where the necessary functions -such as signing, card removal/insertion, etc. are mapped to real, physical -cards which are shared with the client machine the emulator is running on, or -the cards could be pure software constructs. - -The emulator is structured to allow multiple replaceable or additional pieces, -so it can be easily modified for future requirements. The primary envisioned -modifications are: - -1) The socket connection to the virtual card reader (presumably a CCID reader, -but other ISO-7816 compatible readers could be used). The code that handles -this is in vscclient.c. - -2) The virtual card low level emulation. This is currently supplied by using -NSS. This emulation could be replaced by implementations based on other -security libraries, including but not limitted to openssl+pkcs#11 library, -raw pkcs#11, Microsoft CAPI, direct opensc calls, etc. The code that handles -this is in vcard_emul_nss.c. - -3) Emulation for new types of cards. The current implementation emulates the -original DoD CAC standard with separate pki containers. This emulator lives in -cac.c. More than one card type emulator could be included. Other cards could -be emulated as well, including PIV, newer versions of CAC, PKCS #15, etc. - --------------------- -Replacing the Socket Based Virtual Reader Interface. - -The current implementation contains a replaceable module vscclient.c. The -current vscclient.c implements a sockets interface to the virtual ccid reader -on the guest. CCID commands that are pertinent to emulation are passed -across the socket, and their responses are passed back along that same socket. -The protocol that vscclient uses is defined in vscard_common.h and connects -to a qemu ccid usb device. Since this socket runs as a client, vscclient.c -implements a program with a main entry. It also handles argument parsing for -the emulator. - -An application that wants to use the virtual reader can replace vscclient.c -with its own implementation that connects to its own CCID reader. The calls -that the CCID reader can call are: - - VReaderList * vreader_get_reader_list(); - - This function returns a list of virtual readers. These readers may map to - physical devices, or simulated devices depending on vcard the back end. Each - reader in the list should represent a reader to the virtual machine. Virtual - USB address mapping is left to the CCID reader front end. This call can be - made any time to get an updated list. The returned list is a copy of the - internal list that can be referenced by the caller without locking. This copy - must be freed by the caller with vreader_list_delete when it is no longer - needed. - - VReaderListEntry *vreader_list_get_first(VReaderList *); - - This function gets the first entry on the reader list. Along with - vreader_list_get_next(), vreader_list_get_first() can be used to walk the - reader list returned from vreader_get_reader_list(). VReaderListEntries are - part of the list themselves and do not need to be freed separately from the - list. If there are no entries on the list, it will return NULL. - - VReaderListEntry *vreader_list_get_next(VReaderListEntry *); - - This function gets the next entry in the list. If there are no more entries - it will return NULL. - - VReader * vreader_list_get_reader(VReaderListEntry *) - - This function returns the reader stored in the reader List entry. Caller gets - a new reference to a reader. The caller must free its reference when it is - finished with vreader_free(). - - void vreader_free(VReader *reader); - - This function frees a reference to a reader. Readers are reference counted - and are automatically deleted when the last reference is freed. - - void vreader_list_delete(VReaderList *list); - - This function frees the list, all the elements on the list, and all the - reader references held by the list. - - VReaderStatus vreader_power_on(VReader *reader, char *atr, int *len); - - This function simulates a card power on. A virtual card does not care about - the actual voltage and other physical parameters, but it does care that the - card is actually on or off. Cycling the card causes the card to reset. If - the caller provides enough space, vreader_power_on will return the ATR of - the virtual card. The amount of space provided in atr should be indicated - in *len. The function modifies *len to be the actual length of of the - returned ATR. - - VReaderStatus vreader_power_off(VReader *reader); - - This function simulates a power off of a virtual card. - - VReaderStatus vreader_xfer_bytes(VReader *reader, unsigne char *send_buf, - int send_buf_len, - unsigned char *receive_buf, - int receive_buf_len); - - This function sends a raw apdu to a card and returns the card's response. - The CCID front end should return the response back. Most of the emulation - is driven from these APDUs. - - VReaderStatus vreader_card_is_present(VReader *reader); - - This function returns whether or not the reader has a card inserted. The - vreader_power_on, vreader_power_off, and vreader_xfer_bytes will return - VREADER_NO_CARD. - - const char *vreader_get_name(VReader *reader); - - This function returns the name of the reader. The name comes from the card - emulator level and is usually related to the name of the physical reader. - - VReaderID vreader_get_id(VReader *reader); - - This function returns the id of a reader. All readers start out with an id - of -1. The application can set the id with vreader_set_id. - - VReaderStatus vreader_get_id(VReader *reader, VReaderID id); - - This function sets the reader id. The application is responsible for making - sure that the id is unique for all readers it is actively using. - - VReader *vreader_find_reader_by_id(VReaderID id); - - This function returns the reader which matches the id. If two readers match, - only one is returned. The function returns NULL if the id is -1. - - Event *vevent_wait_next_vevent(); - - This function blocks waiting for reader and card insertion events. There - will be one event for each card insertion, each card removal, each reader - insertion and each reader removal. At start up, events are created for all - the initial readers found, as well as all the cards that are inserted. - - Event *vevent_get_next_vevent(); - - This function returns a pending event if it exists, otherwise it returns - NULL. It does not block. - ----------------- -Card Type Emulator: Adding a New Virtual Card Type - -The ISO 7816 card spec describes 2 types of cards: - 1) File system cards, where the smartcard is managed by reading and writing -data to files in a file system. There is currently only boiler plate -implemented for file system cards. - 2) VM cards, where the card has loadable applets which perform the card -functions. The current implementation supports VM cards. - -In the case of VM cards, the difference between various types of cards is -really what applets have been installed in that card. This structure is -mirrored in card type emulators. The 7816 emulator already handles the basic -ISO 7186 commands. Card type emulators simply need to add the virtual applets -which emulate the real card applets. Card type emulators have exactly one -public entry point: - - VCARDStatus xxx_card_init(VCard *card, const char *flags, - const unsigned char *cert[], - int cert_len[], - VCardKey *key[], - int cert_count); - - The parameters for this are: - card - the virtual card structure which will represent this card. - flags - option flags that may be specific to this card type. - cert - array of binary certificates. - cert_len - array of lengths of each of the certificates specified in cert. - key - array of opaque key structures representing the private keys on - the card. - cert_count - number of entries in cert, cert_len, and key arrays. - - Any cert, cert_len, or key with the same index are matching sets. That is - cert[0] is cert_len[0] long and has the corresponding private key of key[0]. - -The card type emulator is expected to own the VCardKeys, but it should copy -any raw cert data it wants to save. It can create new applets and add them to -the card using the following functions: - - VCardApplet *vcard_new_applet(VCardProcessAPDU apdu_func, - VCardResetApplet reset_func, - const unsigned char *aid, - int aid_len); - - This function creates a new applet. Applet structures store the following - information: - 1) the AID of the applet (set by aid and aid_len). - 2) a function to handle APDUs for this applet. (set by apdu_func, more on - this below). - 3) a function to reset the applet state when the applet is selected. - (set by reset_func, more on this below). - 3) applet private data, a data pointer used by the card type emulator to - store any data or state it needs to complete requests. (set by a - separate call). - 4) applet private data free, a function used to free the applet private - data when the applet itself is destroyed. - The created applet can be added to the card with vcard_add_applet below. - - void vcard_set_applet_private(VCardApplet *applet, - VCardAppletPrivate *private, - VCardAppletPrivateFree private_free); - This function sets the private data and the corresponding free function. - VCardAppletPrivate is an opaque data structure to the rest of the emulator. - The card type emulator can define it any way it wants by defining - struct VCardAppletPrivateStruct {};. If there is already a private data - structure on the applet, the old one is freed before the new one is set up. - passing two NULL clear any existing private data. - - VCardStatus vcard_add_applet(VCard *card, VCardApplet *applet); - - Add an applet onto the list of applets attached to the card. Once an applet - has been added, it can be selected by its AID, and then commands will be - routed to it VCardProcessAPDU function. This function adopts the applet that - is passed into it. Note: 2 applets with the same AID should not be added to - the same card. It is permissible to add more than one applet. Multiple applets - may have the same VCardPRocessAPDU entry point. - -The certs and keys should be attached to private data associated with one or -more appropriate applets for that card. Control will come to the card type -emulators once one of its applets are selected through the VCardProcessAPDU -function it specified when it created the applet. - -The signature of VCardResetApplet is: - VCardStatus (*VCardResetApplet) (VCard *card, int channel); - This function will reset the any internal applet state that needs to be - cleared after a select applet call. It should return VCARD_DONE; - -The signature of VCardProcessAPDU is: - VCardStatus (*VCardProcessAPDU)(VCard *card, VCardAPDU *apdu, - VCardResponse **response); - This function examines the APDU and determines whether it should process - the apdu directly, reject the apdu as invalid, or pass the apdu on to - the basic 7816 emulator for processing. - If the 7816 emulator should process the apdu, then the VCardProcessAPDU - should return VCARD_NEXT. - If there is an error, then VCardProcessAPDU should return an error - response using vcard_make_response and the appropriate 7816 error code - (see card_7816t.h) or vcard_make_response with a card type specific error - code. It should then return VCARD_DONE. - If the apdu can be processed correctly, VCardProcessAPDU should do so, - set the response value appropriately for that APDU, and return VCARD_DONE. - VCardProcessAPDU should always set the response if it returns VCARD_DONE. - It should always either return VCARD_DONE or VCARD_NEXT. - -Parsing the APDU -- - -Prior to processing calling the card type emulator's VCardProcessAPDU function, the emulator has already decoded the APDU header and set several fields: - - apdu->a_data - The raw apdu data bytes. - apdu->a_len - The len of the raw apdu data. - apdu->a_body - The start of any post header parameter data. - apdu->a_Lc - The parameter length value. - apdu->a_Le - The expected length of any returned data. - apdu->a_cla - The raw apdu class. - apdu->a_channel - The channel (decoded from the class). - apdu->a_secure_messaging_type - The decoded secure messaging type - (from class). - apdu->a_type - The decode class type. - apdu->a_gen_type - the generic class type (7816, PROPRIETARY, RFU, PTS). - apdu->a_ins - The instruction byte. - apdu->a_p1 - Parameter 1. - apdu->a_p2 - Parameter 2. - -Creating a Response -- - -The expected result of any APDU call is a response. The card type emulator must -set *response with an appropriate VCardResponse value if it returns VCARD_DONE. -Responses could be as simple as returning a 2 byte status word response, to as -complex as returning a block of data along with a 2 byte response. Which is -returned will depend on the semantics of the APDU. The following functions will -create card responses. - - VCardResponse *vcard_make_response(VCard7816Status status); - - This is the most basic function to get a response. This function will - return a response the consists solely one 2 byte status code. If that status - code is defined in card_7816t.h, then this function is guaranteed to - return a response with that status. If a cart type specific status code - is passed and vcard_make_response fails to allocate the appropriate memory - for that response, then vcard_make_response will return a VCardResponse - of VCARD7816_STATUS_EXC_ERROR_MEMORY. In any case, this function is - guaranteed to return a valid VCardResponse. - - VCardResponse *vcard_response_new(unsigned char *buf, int len, - VCard7816Status status); - - This function is similar to vcard_make_response except it includes some - returned data with the response. It could also fail to allocate enough - memory, in which case it will return NULL. - - VCardResponse *vcard_response_new_status_bytes(unsigned char sw1, - unsigned char sw2); - - Sometimes in 7816 the response bytes are treated as two separate bytes with - split meanings. This function allows you to create a response based on - two separate bytes. This function could fail, in which case it will return - NULL. - - VCardResponse *vcard_response_new_bytes(unsigned char *buf, int len, - unsigned char sw1, - unsigned char sw2); - - This function is the same as vcard_response_new except you may specify - the status as two separate bytes like vcard_response_new_status_bytes. - - -Implementing functionality --- - -The following helper functions access information about the current card -and applet. - - VCARDAppletPrivate *vcard_get_current_applet_private(VCard *card, - int channel); - - This function returns any private data set by the card type emulator on - the currently selected applet. The card type emulator keeps track of the - current applet state in this data structure. Any certs and keys associated - with a particular applet is also stored here. - - int vcard_emul_get_login_count(VCard *card); - - This function returns the number of remaining login attempts for this - card. If the card emulator does not know, or the card does not have a - way of giving this information, this function returns -1. - - - VCard7816Status vcard_emul_login(VCard *card, unsigned char *pin, - int pin_len); - - This function logs into the card and returns the standard 7816 status - word depending on the success or failure of the call. - - void vcard_emul_delete_key(VCardKey *key); - - This function frees the VCardKey passed in to xxxx_card_init. The card - type emulator is responsible for freeing this key when it no longer needs - it. - - VCard7816Status vcard_emul_rsa_op(VCard *card, VCardKey *key, - unsigned char *buffer, - int buffer_size); - - This function does a raw rsa op on the buffer with the given key. - -The sample card type emulator is found in cac.c. It implements the cac specific -applets. Only those applets needed by the coolkey pkcs#11 driver on the guest -have been implemented. To support the full range CAC middleware, a complete CAC -card according to the CAC specs should be implemented here. - ------------------------------- -Virtual Card Emulator - -This code accesses both real smart cards and simulated smart cards through -services provided on the client. The current implementation uses NSS, which -already knows how to talk to various PKCS #11 modules on the client, and is -portable to most operating systems. A particular emulator can have only one -virtual card implementation at a time. - -The virtual card emulator consists of a series of virtual card services. In -addition to the services describe above (services starting with -vcard_emul_xxxx), the virtual card emulator also provides the following -functions: - - VCardEmulError vcard_emul_init(cont VCardEmulOptions *options); - - The options structure is built by another function in the virtual card - interface where a string of virtual card emulator specific strings are - mapped to the options. The actual structure is defined by the virtual card - emulator and is used to determine the configuration of soft cards, or to - determine which physical cards to present to the guest. - - The vcard_emul_init function will build up sets of readers, create any - threads that are needed to watch for changes in the reader state. If readers - have cards present in them, they are also initialized. - - Readers are created with the function. - - VReader *vreader_new(VReaderEmul *reader_emul, - VReaderEmulFree reader_emul_free); - - The freeFunc is used to free the VReaderEmul * when the reader is - destroyed. The VReaderEmul structure is an opaque structure to the - rest of the code, but defined by the virtual card emulator, which can - use it to store any reader specific state. - - Once the reader has been created, it can be added to the front end with the - call: - - VReaderStatus vreader_add_reader(VReader *reader); - - This function will automatically generate the appropriate new reader - events and add the reader to the list. - - To create a new card, the virtual card emulator will call a similar - function. - - VCard *vcard_new(VCardEmul *card_emul, - VCardEmulFree card_emul_free); - - Like vreader_new, this function takes a virtual card emulator specific - structure which it uses to keep track of the card state. - - Once the card is created, it is attached to a card type emulator with the - following function: - - VCardStatus vcard_init(VCard *vcard, VCardEmulType type, - const char *flags, - unsigned char *const *certs, - int *cert_len, - VCardKey *key[], - int cert_count); - - The vcard is the value returned from vcard_new. The type is the - card type emulator that this card should presented to the guest as. - The flags are card type emulator specific options. The certs, - cert_len, and keys are all arrays of length cert_count. These are - the same of the parameters xxxx_card_init() accepts. - - Finally the card is associated with its reader by the call: - - VReaderStatus vreader_insert_card(VReader *vreader, VCard *vcard); - - This function, like vreader_add_reader, will take care of any event - notification for the card insert. - - - VCardEmulError vcard_emul_force_card_remove(VReader *vreader); - - Force a card that is present to appear to be removed to the guest, even if - that card is a physical card and is present. - - - VCardEmulError vcard_emul_force_card_insert(VReader *reader); - - Force a card that has been removed by vcard_emul_force_card_remove to be - reinserted from the point of view of the guest. This will only work if the - card is physically present (which is always true fro a soft card). - - void vcard_emul_get_atr(Vcard *card, unsigned char *atr, int *atr_len); - - Return the virtual ATR for the card. By convention this should be the value - VCARD_ATR_PREFIX(size) followed by several ascii bytes related to this - particular emulator. For instance the NSS emulator returns - {VCARD_ATR_PREFIX(3), 'N', 'S', 'S' }. Do ot return more data then *atr_len; - - void vcard_emul_reset(VCard *card, VCardPower power) - - Set the state of 'card' to the current power level and reset its internal - state (logout, etc). - -------------------------------------------------------- -List of files and their function: -README - This file -card_7816.c - emulate basic 7816 functionality. Parse APDUs. -card_7816.h - apdu and response services definitions. -card_7816t.h - 7816 specific structures, types and definitions. -event.c - event handling code. -event.h - event handling services definitions. -eventt.h - event handling structures and types -vcard.c - handle common virtual card services like creation, destruction, and - applet management. -vcard.h - common virtual card services function definitions. -vcardt.h - comon virtual card types -vreader.c - common virtual reader services. -vreader.h - common virtual reader services definitions. -vreadert.h - comon virtual reader types. -vcard_emul_type.c - manage the card type emulators. -vcard_emul_type.h - definitions for card type emulators. -cac.c - card type emulator for CAC cards -vcard_emul.h - virtual card emulator service definitions. -vcard_emul_nss.c - virtual card emulator implementation for nss. -vscclient.c - socket connection to guest qemu usb driver. -vscard_common.h - common header with the guest qemu usb driver. -mutex.h - header file for machine independent mutexes. -link_test.c - static test to make sure all the symbols are properly defined. diff --git a/docs/win32-qemu-event.promela b/docs/win32-qemu-event.promela new file mode 100644 index 0000000000..c446a71555 --- /dev/null +++ b/docs/win32-qemu-event.promela @@ -0,0 +1,98 @@ +/* + * This model describes the implementation of QemuEvent in + * util/qemu-thread-win32.c. + * + * Author: Paolo Bonzini <pbonzini@redhat.com> + * + * This file is in the public domain. If you really want a license, + * the WTFPL will do. + * + * To verify it: + * spin -a docs/event.promela + * gcc -O2 pan.c -DSAFETY + * ./a.out + */ + +bool event; +int value; + +/* Primitives for a Win32 event */ +#define RAW_RESET event = false +#define RAW_SET event = true +#define RAW_WAIT do :: event -> break; od + +#if 0 +/* Basic sanity checking: test the Win32 event primitives */ +#define RESET RAW_RESET +#define SET RAW_SET +#define WAIT RAW_WAIT +#else +/* Full model: layer a userspace-only fast path on top of the RAW_* + * primitives. SET/RESET/WAIT have exactly the same semantics as + * RAW_SET/RAW_RESET/RAW_WAIT, but try to avoid invoking them. + */ +#define EV_SET 0 +#define EV_FREE 1 +#define EV_BUSY -1 + +int state = EV_FREE; + +int xchg_result; +#define SET if :: state != EV_SET -> \ + atomic { /* xchg_result=xchg(state, EV_SET) */ \ + xchg_result = state; \ + state = EV_SET; \ + } \ + if :: xchg_result == EV_BUSY -> RAW_SET; \ + :: else -> skip; \ + fi; \ + :: else -> skip; \ + fi + +#define RESET if :: state == EV_SET -> atomic { state = state | EV_FREE; } \ + :: else -> skip; \ + fi + +int tmp1, tmp2; +#define WAIT tmp1 = state; \ + if :: tmp1 != EV_SET -> \ + if :: tmp1 == EV_FREE -> \ + RAW_RESET; \ + atomic { /* tmp2=cas(state, EV_FREE, EV_BUSY) */ \ + tmp2 = state; \ + if :: tmp2 == EV_FREE -> state = EV_BUSY; \ + :: else -> skip; \ + fi; \ + } \ + if :: tmp2 == EV_SET -> tmp1 = EV_SET; \ + :: else -> tmp1 = EV_BUSY; \ + fi; \ + :: else -> skip; \ + fi; \ + assert(tmp1 != EV_FREE); \ + if :: tmp1 == EV_BUSY -> RAW_WAIT; \ + :: else -> skip; \ + fi; \ + :: else -> skip; \ + fi +#endif + +active proctype waiter() +{ + if + :: !value -> + RESET; + if + :: !value -> WAIT; + :: else -> skip; + fi; + :: else -> skip; + fi; + assert(value); +} + +active proctype notifier() +{ + value = true; + SET; +} diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 9088248c3a..1aaff1f662 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -114,7 +114,7 @@ static void acpi_dsdt_add_flash(Aml *scope, const MemMapEntry *flash_memmap) { Aml *dev, *crs; hwaddr base = flash_memmap->base; - hwaddr size = flash_memmap->size; + hwaddr size = flash_memmap->size / 2; dev = aml_device("FLS0"); aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0015"))); @@ -443,33 +443,43 @@ build_madt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info, madt = acpi_data_push(table_data, sizeof *madt); - for (i = 0; i < guest_info->smp_cpus; i++) { - AcpiMadtGenericInterrupt *gicc = acpi_data_push(table_data, - sizeof *gicc); - gicc->type = ACPI_APIC_GENERIC_INTERRUPT; - gicc->length = sizeof(*gicc); - gicc->base_address = memmap[VIRT_GIC_CPU].base; - gicc->cpu_interface_number = i; - gicc->arm_mpidr = i; - gicc->uid = i; - if (test_bit(i, cpuinfo->found_cpus)) { - gicc->flags = cpu_to_le32(ACPI_GICC_ENABLED); - } - } - gicd = acpi_data_push(table_data, sizeof *gicd); gicd->type = ACPI_APIC_GENERIC_DISTRIBUTOR; gicd->length = sizeof(*gicd); gicd->base_address = memmap[VIRT_GIC_DIST].base; - gic_msi = acpi_data_push(table_data, sizeof *gic_msi); - gic_msi->type = ACPI_APIC_GENERIC_MSI_FRAME; - gic_msi->length = sizeof(*gic_msi); - gic_msi->gic_msi_frame_id = 0; - gic_msi->base_address = cpu_to_le64(memmap[VIRT_GIC_V2M].base); - gic_msi->flags = cpu_to_le32(1); - gic_msi->spi_count = cpu_to_le16(NUM_GICV2M_SPIS); - gic_msi->spi_base = cpu_to_le16(irqmap[VIRT_GIC_V2M] + ARM_SPI_BASE); + if (guest_info->gic_version == 3) { + AcpiMadtGenericRedistributor *gicr = acpi_data_push(table_data, + sizeof *gicr); + + gicr->type = ACPI_APIC_GENERIC_REDISTRIBUTOR; + gicr->length = sizeof(*gicr); + gicr->base_address = cpu_to_le64(memmap[VIRT_GIC_REDIST].base); + gicr->range_length = cpu_to_le32(memmap[VIRT_GIC_REDIST].size); + } else { + for (i = 0; i < guest_info->smp_cpus; i++) { + AcpiMadtGenericInterrupt *gicc = acpi_data_push(table_data, + sizeof *gicc); + gicc->type = ACPI_APIC_GENERIC_INTERRUPT; + gicc->length = sizeof(*gicc); + gicc->base_address = memmap[VIRT_GIC_CPU].base; + gicc->cpu_interface_number = i; + gicc->arm_mpidr = i; + gicc->uid = i; + if (test_bit(i, cpuinfo->found_cpus)) { + gicc->flags = cpu_to_le32(ACPI_GICC_ENABLED); + } + } + + gic_msi = acpi_data_push(table_data, sizeof *gic_msi); + gic_msi->type = ACPI_APIC_GENERIC_MSI_FRAME; + gic_msi->length = sizeof(*gic_msi); + gic_msi->gic_msi_frame_id = 0; + gic_msi->base_address = cpu_to_le64(memmap[VIRT_GIC_V2M].base); + gic_msi->flags = cpu_to_le32(1); + gic_msi->spi_count = cpu_to_le16(NUM_GICV2M_SPIS); + gic_msi->spi_base = cpu_to_le16(irqmap[VIRT_GIC_V2M] + ARM_SPI_BASE); + } build_header(linker, table_data, (void *)(table_data->data + madt_start), "APIC", diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 6bf0d6d591..d25d6cfce7 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -51,6 +51,7 @@ #include "hw/intc/arm_gic_common.h" #include "kvm_arm.h" #include "hw/smbios/smbios.h" +#include "qapi/visitor.h" /* Number of external interrupt lines to configure the GIC with */ #define NUM_IRQS 256 @@ -81,6 +82,7 @@ typedef struct { MachineState parent; bool secure; bool highmem; + int32_t gic_version; } VirtMachineState; #define TYPE_VIRT_MACHINE MACHINE_TYPE_NAME("virt") @@ -111,6 +113,10 @@ static const MemMapEntry a15memmap[] = { [VIRT_GIC_DIST] = { 0x08000000, 0x00010000 }, [VIRT_GIC_CPU] = { 0x08010000, 0x00010000 }, [VIRT_GIC_V2M] = { 0x08020000, 0x00001000 }, + /* The space in between here is reserved for GICv3 CPU/vCPU/HYP */ + [VIRT_GIC_ITS] = { 0x08080000, 0x00020000 }, + /* This redistributor space allows up to 2*64kB*123 CPUs */ + [VIRT_GIC_REDIST] = { 0x080A0000, 0x00F60000 }, [VIRT_UART] = { 0x09000000, 0x00001000 }, [VIRT_RTC] = { 0x09010000, 0x00001000 }, [VIRT_FW_CFG] = { 0x09020000, 0x0000000a }, @@ -255,7 +261,7 @@ static void fdt_add_psci_node(const VirtBoardInfo *vbi) qemu_fdt_setprop_cell(fdt, "/psci", "migrate", migrate_fn); } -static void fdt_add_timer_nodes(const VirtBoardInfo *vbi) +static void fdt_add_timer_nodes(const VirtBoardInfo *vbi, int gictype) { /* Note that on A15 h/w these interrupts are level-triggered, * but for the GIC implementation provided by both QEMU and KVM @@ -264,8 +270,11 @@ static void fdt_add_timer_nodes(const VirtBoardInfo *vbi) ARMCPU *armcpu; uint32_t irqflags = GIC_FDT_IRQ_FLAGS_EDGE_LO_HI; - irqflags = deposit32(irqflags, GIC_FDT_IRQ_PPI_CPU_START, - GIC_FDT_IRQ_PPI_CPU_WIDTH, (1 << vbi->smp_cpus) - 1); + if (gictype == 2) { + irqflags = deposit32(irqflags, GIC_FDT_IRQ_PPI_CPU_START, + GIC_FDT_IRQ_PPI_CPU_WIDTH, + (1 << vbi->smp_cpus) - 1); + } qemu_fdt_add_subnode(vbi->fdt, "/timer"); @@ -355,25 +364,36 @@ static void fdt_add_v2m_gic_node(VirtBoardInfo *vbi) qemu_fdt_setprop_cell(vbi->fdt, "/intc/v2m", "phandle", vbi->v2m_phandle); } -static void fdt_add_gic_node(VirtBoardInfo *vbi) +static void fdt_add_gic_node(VirtBoardInfo *vbi, int type) { vbi->gic_phandle = qemu_fdt_alloc_phandle(vbi->fdt); qemu_fdt_setprop_cell(vbi->fdt, "/", "interrupt-parent", vbi->gic_phandle); qemu_fdt_add_subnode(vbi->fdt, "/intc"); - /* 'cortex-a15-gic' means 'GIC v2' */ - qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible", - "arm,cortex-a15-gic"); qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#interrupt-cells", 3); qemu_fdt_setprop(vbi->fdt, "/intc", "interrupt-controller", NULL, 0); - qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg", - 2, vbi->memmap[VIRT_GIC_DIST].base, - 2, vbi->memmap[VIRT_GIC_DIST].size, - 2, vbi->memmap[VIRT_GIC_CPU].base, - 2, vbi->memmap[VIRT_GIC_CPU].size); qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#address-cells", 0x2); qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#size-cells", 0x2); qemu_fdt_setprop(vbi->fdt, "/intc", "ranges", NULL, 0); + if (type == 3) { + qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible", + "arm,gic-v3"); + qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg", + 2, vbi->memmap[VIRT_GIC_DIST].base, + 2, vbi->memmap[VIRT_GIC_DIST].size, + 2, vbi->memmap[VIRT_GIC_REDIST].base, + 2, vbi->memmap[VIRT_GIC_REDIST].size); + } else { + /* 'cortex-a15-gic' means 'GIC v2' */ + qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible", + "arm,cortex-a15-gic"); + qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg", + 2, vbi->memmap[VIRT_GIC_DIST].base, + 2, vbi->memmap[VIRT_GIC_DIST].size, + 2, vbi->memmap[VIRT_GIC_CPU].base, + 2, vbi->memmap[VIRT_GIC_CPU].size); + } + qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", vbi->gic_phandle); } @@ -396,18 +416,18 @@ static void create_v2m(VirtBoardInfo *vbi, qemu_irq *pic) fdt_add_v2m_gic_node(vbi); } -static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, bool secure) +static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, bool secure) { - /* We create a standalone GIC v2 */ + /* We create a standalone GIC */ DeviceState *gicdev; SysBusDevice *gicbusdev; const char *gictype; int i; - gictype = gic_class_name(); + gictype = (type == 3) ? gicv3_class_name() : gic_class_name(); gicdev = qdev_create(NULL, gictype); - qdev_prop_set_uint32(gicdev, "revision", 2); + qdev_prop_set_uint32(gicdev, "revision", type); qdev_prop_set_uint32(gicdev, "num-cpu", smp_cpus); /* Note that the num-irq property counts both internal and external * interrupts; there are always 32 of the former (mandated by GIC spec). @@ -419,7 +439,11 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, bool secure) qdev_init_nofail(gicdev); gicbusdev = SYS_BUS_DEVICE(gicdev); sysbus_mmio_map(gicbusdev, 0, vbi->memmap[VIRT_GIC_DIST].base); - sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_CPU].base); + if (type == 3) { + sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_REDIST].base); + } else { + sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_CPU].base); + } /* Wire the outputs from each CPU's generic timer to the * appropriate GIC PPI inputs, and the GIC's IRQ output to @@ -454,9 +478,11 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, bool secure) pic[i] = qdev_get_gpio_in(gicdev, i); } - fdt_add_gic_node(vbi); + fdt_add_gic_node(vbi, type); - create_v2m(vbi, pic); + if (type == 2) { + create_v2m(vbi, pic); + } } static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic) @@ -773,7 +799,10 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic, qemu_fdt_setprop_cells(vbi->fdt, nodename, "bus-range", 0, nr_pcie_buses - 1); - qemu_fdt_setprop_cells(vbi->fdt, nodename, "msi-parent", vbi->v2m_phandle); + if (vbi->v2m_phandle) { + qemu_fdt_setprop_cells(vbi->fdt, nodename, "msi-parent", + vbi->v2m_phandle); + } qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", 2, base_ecam, 2, size_ecam); @@ -888,6 +917,7 @@ static void machvirt_init(MachineState *machine) VirtMachineState *vms = VIRT_MACHINE(machine); qemu_irq pic[NUM_IRQS]; MemoryRegion *sysmem = get_system_memory(); + int gic_version = vms->gic_version; int n; MemoryRegion *ram = g_new(MemoryRegion, 1); const char *cpu_model = machine->cpu_model; @@ -900,6 +930,18 @@ static void machvirt_init(MachineState *machine) cpu_model = "cortex-a15"; } + /* We can probe only here because during property set + * KVM is not available yet + */ + if (!gic_version) { + gic_version = kvm_arm_vgic_probe(); + if (!gic_version) { + error_report("Unable to determine GIC version supported by host\n" + "Probably KVM acceleration is not supported\n"); + exit(1); + } + } + /* Separate the actual CPU model name from any appended features */ cpustr = g_strsplit(cpu_model, ",", 2); @@ -960,7 +1002,7 @@ static void machvirt_init(MachineState *machine) object_property_set_bool(cpuobj, true, "realized", NULL); } g_strfreev(cpustr); - fdt_add_timer_nodes(vbi); + fdt_add_timer_nodes(vbi, gic_version); fdt_add_cpu_nodes(vbi); fdt_add_psci_node(vbi); @@ -970,7 +1012,7 @@ static void machvirt_init(MachineState *machine) create_flash(vbi); - create_gic(vbi, pic, vms->secure); + create_gic(vbi, pic, gic_version, vms->secure); create_uart(vbi, pic); @@ -992,6 +1034,7 @@ static void machvirt_init(MachineState *machine) guest_info->memmap = vbi->memmap; guest_info->irqmap = vbi->irqmap; guest_info->use_highmem = vms->highmem; + guest_info->gic_version = gic_version; guest_info_state->machine_done.notify = virt_guest_info_machine_done; qemu_add_machine_init_done_notifier(&guest_info_state->machine_done); @@ -1043,6 +1086,31 @@ static void virt_set_highmem(Object *obj, bool value, Error **errp) vms->highmem = value; } +static char *virt_get_gic_version(Object *obj, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + const char *val = vms->gic_version == 3 ? "3" : "2"; + + return g_strdup(val); +} + +static void virt_set_gic_version(Object *obj, const char *value, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + if (!strcmp(value, "3")) { + vms->gic_version = 3; + } else if (!strcmp(value, "2")) { + vms->gic_version = 2; + } else if (!strcmp(value, "host")) { + vms->gic_version = 0; /* Will probe later */ + } else { + error_report("Invalid gic-version option value\n" + "Allowed values are: 3, 2, host\n"); + exit(1); + } +} + static void virt_instance_init(Object *obj) { VirtMachineState *vms = VIRT_MACHINE(obj); @@ -1067,6 +1135,13 @@ static void virt_instance_init(Object *obj) "Set on/off to enable/disable using " "physical address space above 32 bits", NULL); + /* Default GIC type is v2 */ + vms->gic_version = 2; + object_property_add_str(obj, "gic-version", virt_get_gic_version, + virt_set_gic_version, NULL); + object_property_set_description(obj, "gic-version", + "Set GIC version. " + "Valid values are 2, 3 and host", NULL); } static void virt_class_init(ObjectClass *oc, void *data) @@ -1075,7 +1150,10 @@ static void virt_class_init(ObjectClass *oc, void *data) mc->desc = "ARM Virtual Machine", mc->init = machvirt_init; - mc->max_cpus = 8; + /* Our maximum number of CPUs depends on how many redistributors + * we can fit into memory map + */ + mc->max_cpus = a15memmap[VIRT_GIC_REDIST].size / 0x20000; mc->has_dynamic_sysbus = true; mc->block_default_type = IF_VIRTIO; mc->no_cdrom = 1; diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs index 092d8a80ac..004b0c25e4 100644 --- a/hw/intc/Makefile.objs +++ b/hw/intc/Makefile.objs @@ -12,10 +12,12 @@ common-obj-$(CONFIG_IOAPIC) += ioapic_common.o common-obj-$(CONFIG_ARM_GIC) += arm_gic_common.o common-obj-$(CONFIG_ARM_GIC) += arm_gic.o common-obj-$(CONFIG_ARM_GIC) += arm_gicv2m.o +common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_common.o common-obj-$(CONFIG_OPENPIC) += openpic.o obj-$(CONFIG_APIC) += apic.o apic_common.o obj-$(CONFIG_ARM_GIC_KVM) += arm_gic_kvm.o +obj-$(call land,$(CONFIG_ARM_GIC_KVM),$(TARGET_AARCH64)) += arm_gicv3_kvm.o obj-$(CONFIG_STELLARIS) += armv7m_nvic.o obj-$(CONFIG_EXYNOS4) += exynos4210_gic.o exynos4210_combiner.o obj-$(CONFIG_GRLIB) += grlib_irqmp.o diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index e5d0f67186..e8b2386908 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -23,6 +23,7 @@ #include "sysemu/kvm.h" #include "kvm_arm.h" #include "gic_internal.h" +#include "vgic_common.h" //#define DEBUG_GIC_KVM @@ -52,7 +53,7 @@ typedef struct KVMARMGICClass { void (*parent_reset)(DeviceState *dev); } KVMARMGICClass; -static void kvm_arm_gic_set_irq(void *opaque, int irq, int level) +void kvm_arm_gic_set_irq(uint32_t num_irq, int irq, int level) { /* Meaning of the 'irq' parameter: * [0..N-1] : external interrupts @@ -63,10 +64,9 @@ static void kvm_arm_gic_set_irq(void *opaque, int irq, int level) * has separate fields in the irq number for type, * CPU number and interrupt number. */ - GICState *s = (GICState *)opaque; int kvm_irq, irqtype, cpu; - if (irq < (s->num_irq - GIC_INTERNAL)) { + if (irq < (num_irq - GIC_INTERNAL)) { /* External interrupt. The kernel numbers these like the GIC * hardware, with external interrupt IDs starting after the * internal ones. @@ -77,7 +77,7 @@ static void kvm_arm_gic_set_irq(void *opaque, int irq, int level) } else { /* Internal interrupt: decode into (cpu, interrupt id) */ irqtype = KVM_ARM_IRQ_TYPE_PPI; - irq -= (s->num_irq - GIC_INTERNAL); + irq -= (num_irq - GIC_INTERNAL); cpu = irq / GIC_INTERNAL; irq %= GIC_INTERNAL; } @@ -87,69 +87,36 @@ static void kvm_arm_gic_set_irq(void *opaque, int irq, int level) kvm_set_irq(kvm_state, kvm_irq, !!level); } -static bool kvm_arm_gic_can_save_restore(GICState *s) -{ - return s->dev_fd >= 0; -} - -static bool kvm_gic_supports_attr(GICState *s, int group, int attrnum) +static void kvm_arm_gicv2_set_irq(void *opaque, int irq, int level) { - struct kvm_device_attr attr = { - .group = group, - .attr = attrnum, - .flags = 0, - }; - - if (s->dev_fd == -1) { - return false; - } + GICState *s = (GICState *)opaque; - return kvm_device_ioctl(s->dev_fd, KVM_HAS_DEVICE_ATTR, &attr) == 0; + kvm_arm_gic_set_irq(s->num_irq, irq, level); } -static void kvm_gic_access(GICState *s, int group, int offset, - int cpu, uint32_t *val, bool write) +static bool kvm_arm_gic_can_save_restore(GICState *s) { - struct kvm_device_attr attr; - int type; - int err; - - cpu = cpu & 0xff; - - attr.flags = 0; - attr.group = group; - attr.attr = (((uint64_t)cpu << KVM_DEV_ARM_VGIC_CPUID_SHIFT) & - KVM_DEV_ARM_VGIC_CPUID_MASK) | - (((uint64_t)offset << KVM_DEV_ARM_VGIC_OFFSET_SHIFT) & - KVM_DEV_ARM_VGIC_OFFSET_MASK); - attr.addr = (uintptr_t)val; - - if (write) { - type = KVM_SET_DEVICE_ATTR; - } else { - type = KVM_GET_DEVICE_ATTR; - } - - err = kvm_device_ioctl(s->dev_fd, type, &attr); - if (err < 0) { - fprintf(stderr, "KVM_{SET/GET}_DEVICE_ATTR failed: %s\n", - strerror(-err)); - abort(); - } + return s->dev_fd >= 0; } +#define KVM_VGIC_ATTR(offset, cpu) \ + ((((uint64_t)(cpu) << KVM_DEV_ARM_VGIC_CPUID_SHIFT) & \ + KVM_DEV_ARM_VGIC_CPUID_MASK) | \ + (((uint64_t)(offset) << KVM_DEV_ARM_VGIC_OFFSET_SHIFT) & \ + KVM_DEV_ARM_VGIC_OFFSET_MASK)) + static void kvm_gicd_access(GICState *s, int offset, int cpu, uint32_t *val, bool write) { - kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, - offset, cpu, val, write); + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, + KVM_VGIC_ATTR(offset, cpu), val, write); } static void kvm_gicc_access(GICState *s, int offset, int cpu, uint32_t *val, bool write) { - kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_CPU_REGS, - offset, cpu, val, write); + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_REGS, + KVM_VGIC_ATTR(offset, cpu), val, write); } #define for_each_irq_reg(_ctr, _max_irq, _field_width) \ @@ -559,7 +526,7 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) return; } - gic_init_irqs_and_mmio(s, kvm_arm_gic_set_irq, NULL); + gic_init_irqs_and_mmio(s, kvm_arm_gicv2_set_irq, NULL); for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) { qemu_irq irq = qdev_get_gpio_in(dev, i); @@ -571,23 +538,24 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_V2, false); if (ret >= 0) { s->dev_fd = ret; + + /* Newstyle API is used, we may have attributes */ + if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0)) { + uint32_t numirqs = s->num_irq; + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0, + &numirqs, true); + } + /* Tell the kernel to complete VGIC initialization now */ + if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_VGIC_CTRL_INIT)) { + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); + } } else if (ret != -ENODEV && ret != -ENOTSUP) { error_setg_errno(errp, -ret, "error creating in-kernel VGIC"); return; } - if (kvm_gic_supports_attr(s, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0)) { - uint32_t numirqs = s->num_irq; - kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0, 0, &numirqs, 1); - } - - /* Tell the kernel to complete VGIC initialization now */ - if (kvm_gic_supports_attr(s, KVM_DEV_ARM_VGIC_GRP_CTRL, - KVM_DEV_ARM_VGIC_CTRL_INIT)) { - kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_CTRL, - KVM_DEV_ARM_VGIC_CTRL_INIT, 0, 0, 1); - } - /* Distributor */ kvm_arm_register_device(&s->iomem, (KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT) diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c new file mode 100644 index 0000000000..032ece2166 --- /dev/null +++ b/hw/intc/arm_gicv3_common.c @@ -0,0 +1,140 @@ +/* + * ARM GICv3 support - common bits of emulated and KVM kernel model + * + * Copyright (c) 2012 Linaro Limited + * Copyright (c) 2015 Huawei. + * Written by Peter Maydell + * Extended to 64 cores by Shlomo Pongratz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "hw/intc/arm_gicv3_common.h" + +static void gicv3_pre_save(void *opaque) +{ + GICv3State *s = (GICv3State *)opaque; + ARMGICv3CommonClass *c = ARM_GICV3_COMMON_GET_CLASS(s); + + if (c->pre_save) { + c->pre_save(s); + } +} + +static int gicv3_post_load(void *opaque, int version_id) +{ + GICv3State *s = (GICv3State *)opaque; + ARMGICv3CommonClass *c = ARM_GICV3_COMMON_GET_CLASS(s); + + if (c->post_load) { + c->post_load(s); + } + return 0; +} + +static const VMStateDescription vmstate_gicv3 = { + .name = "arm_gicv3", + .unmigratable = 1, + .pre_save = gicv3_pre_save, + .post_load = gicv3_post_load, +}; + +void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler, + const MemoryRegionOps *ops) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(s); + int i; + + /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU. + * GPIO array layout is thus: + * [0..N-1] spi + * [N..N+31] PPIs for CPU 0 + * [N+32..N+63] PPIs for CPU 1 + * ... + */ + i = s->num_irq - GIC_INTERNAL + GIC_INTERNAL * s->num_cpu; + qdev_init_gpio_in(DEVICE(s), handler, i); + + s->parent_irq = g_malloc(s->num_cpu * sizeof(qemu_irq)); + s->parent_fiq = g_malloc(s->num_cpu * sizeof(qemu_irq)); + + for (i = 0; i < s->num_cpu; i++) { + sysbus_init_irq(sbd, &s->parent_irq[i]); + } + for (i = 0; i < s->num_cpu; i++) { + sysbus_init_irq(sbd, &s->parent_fiq[i]); + } + + memory_region_init_io(&s->iomem_dist, OBJECT(s), ops, s, + "gicv3_dist", 0x10000); + memory_region_init_io(&s->iomem_redist, OBJECT(s), ops ? &ops[1] : NULL, s, + "gicv3_redist", 0x20000 * s->num_cpu); + + sysbus_init_mmio(sbd, &s->iomem_dist); + sysbus_init_mmio(sbd, &s->iomem_redist); +} + +static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) +{ + GICv3State *s = ARM_GICV3_COMMON(dev); + + /* revision property is actually reserved and currently used only in order + * to keep the interface compatible with GICv2 code, avoiding extra + * conditions. However, in future it could be used, for example, if we + * implement GICv4. + */ + if (s->revision != 3) { + error_setg(errp, "unsupported GIC revision %d", s->revision); + return; + } +} + +static void arm_gicv3_common_reset(DeviceState *dev) +{ + /* TODO */ +} + +static Property arm_gicv3_common_properties[] = { + DEFINE_PROP_UINT32("num-cpu", GICv3State, num_cpu, 1), + DEFINE_PROP_UINT32("num-irq", GICv3State, num_irq, 32), + DEFINE_PROP_UINT32("revision", GICv3State, revision, 3), + DEFINE_PROP_BOOL("has-security-extensions", GICv3State, security_extn, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void arm_gicv3_common_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = arm_gicv3_common_reset; + dc->realize = arm_gicv3_common_realize; + dc->props = arm_gicv3_common_properties; + dc->vmsd = &vmstate_gicv3; +} + +static const TypeInfo arm_gicv3_common_type = { + .name = TYPE_ARM_GICV3_COMMON, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(GICv3State), + .class_size = sizeof(ARMGICv3CommonClass), + .class_init = arm_gicv3_common_class_init, + .abstract = true, +}; + +static void register_types(void) +{ + type_register_static(&arm_gicv3_common_type); +} + +type_init(register_types) diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c new file mode 100644 index 0000000000..b48f78f13d --- /dev/null +++ b/hw/intc/arm_gicv3_kvm.c @@ -0,0 +1,149 @@ +/* + * ARM Generic Interrupt Controller using KVM in-kernel support + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Written by Pavel Fedin + * Based on vGICv2 code by Peter Maydell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "hw/intc/arm_gicv3_common.h" +#include "hw/sysbus.h" +#include "sysemu/kvm.h" +#include "kvm_arm.h" +#include "vgic_common.h" + +#ifdef DEBUG_GICV3_KVM +#define DPRINTF(fmt, ...) \ + do { fprintf(stderr, "kvm_gicv3: " fmt, ## __VA_ARGS__); } while (0) +#else +#define DPRINTF(fmt, ...) \ + do { } while (0) +#endif + +#define TYPE_KVM_ARM_GICV3 "kvm-arm-gicv3" +#define KVM_ARM_GICV3(obj) \ + OBJECT_CHECK(GICv3State, (obj), TYPE_KVM_ARM_GICV3) +#define KVM_ARM_GICV3_CLASS(klass) \ + OBJECT_CLASS_CHECK(KVMARMGICv3Class, (klass), TYPE_KVM_ARM_GICV3) +#define KVM_ARM_GICV3_GET_CLASS(obj) \ + OBJECT_GET_CLASS(KVMARMGICv3Class, (obj), TYPE_KVM_ARM_GICV3) + +typedef struct KVMARMGICv3Class { + ARMGICv3CommonClass parent_class; + DeviceRealize parent_realize; + void (*parent_reset)(DeviceState *dev); +} KVMARMGICv3Class; + +static void kvm_arm_gicv3_set_irq(void *opaque, int irq, int level) +{ + GICv3State *s = (GICv3State *)opaque; + + kvm_arm_gic_set_irq(s->num_irq, irq, level); +} + +static void kvm_arm_gicv3_put(GICv3State *s) +{ + /* TODO */ + DPRINTF("Cannot put kernel gic state, no kernel interface\n"); +} + +static void kvm_arm_gicv3_get(GICv3State *s) +{ + /* TODO */ + DPRINTF("Cannot get kernel gic state, no kernel interface\n"); +} + +static void kvm_arm_gicv3_reset(DeviceState *dev) +{ + GICv3State *s = ARM_GICV3_COMMON(dev); + KVMARMGICv3Class *kgc = KVM_ARM_GICV3_GET_CLASS(s); + + DPRINTF("Reset\n"); + + kgc->parent_reset(dev); + kvm_arm_gicv3_put(s); +} + +static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) +{ + GICv3State *s = KVM_ARM_GICV3(dev); + KVMARMGICv3Class *kgc = KVM_ARM_GICV3_GET_CLASS(s); + Error *local_err = NULL; + + DPRINTF("kvm_arm_gicv3_realize\n"); + + kgc->parent_realize(dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + if (s->security_extn) { + error_setg(errp, "the in-kernel VGICv3 does not implement the " + "security extensions"); + return; + } + + gicv3_init_irqs_and_mmio(s, kvm_arm_gicv3_set_irq, NULL); + + /* Try to create the device via the device control API */ + s->dev_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_V3, false); + if (s->dev_fd < 0) { + error_setg_errno(errp, -s->dev_fd, "error creating in-kernel VGIC"); + return; + } + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, + 0, &s->num_irq, true); + + /* Tell the kernel to complete VGIC initialization now */ + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); + + kvm_arm_register_device(&s->iomem_dist, -1, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_DIST, s->dev_fd); + kvm_arm_register_device(&s->iomem_redist, -1, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST, s->dev_fd); +} + +static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ARMGICv3CommonClass *agcc = ARM_GICV3_COMMON_CLASS(klass); + KVMARMGICv3Class *kgc = KVM_ARM_GICV3_CLASS(klass); + + agcc->pre_save = kvm_arm_gicv3_get; + agcc->post_load = kvm_arm_gicv3_put; + kgc->parent_realize = dc->realize; + kgc->parent_reset = dc->reset; + dc->realize = kvm_arm_gicv3_realize; + dc->reset = kvm_arm_gicv3_reset; +} + +static const TypeInfo kvm_arm_gicv3_info = { + .name = TYPE_KVM_ARM_GICV3, + .parent = TYPE_ARM_GICV3_COMMON, + .instance_size = sizeof(GICv3State), + .class_init = kvm_arm_gicv3_class_init, + .class_size = sizeof(KVMARMGICv3Class), +}; + +static void kvm_arm_gicv3_register_types(void) +{ + type_register_static(&kvm_arm_gicv3_info); +} + +type_init(kvm_arm_gicv3_register_types) diff --git a/hw/intc/vgic_common.h b/hw/intc/vgic_common.h new file mode 100644 index 0000000000..80d919eb93 --- /dev/null +++ b/hw/intc/vgic_common.h @@ -0,0 +1,35 @@ +/* + * ARM KVM vGIC utility functions + * + * Copyright (c) 2015 Samsung Electronics + * Written by Pavel Fedin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef QEMU_ARM_VGIC_COMMON_H +#define QEMU_ARM_VGIC_COMMON_H + +/** + * kvm_arm_gic_set_irq - Send an IRQ to the in-kernel vGIC + * @num_irq: Total number of IRQs configured for the GIC instance + * @irq: qemu internal IRQ line number: + * [0..N-1] : external interrupts + * [N..N+31] : PPI (internal) interrupts for CPU 0 + * [N+32..N+63] : PPI (internal interrupts for CPU 1 + * @level: level of the IRQ line. + */ +void kvm_arm_gic_set_irq(uint32_t num_irq, int irq, int level); + +#endif diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs index 7443e386b3..8f00fbd8f6 100644 --- a/hw/usb/Makefile.objs +++ b/hw/usb/Makefile.objs @@ -23,9 +23,8 @@ common-obj-$(CONFIG_USB_BLUETOOTH) += dev-bluetooth.o ifeq ($(CONFIG_USB_SMARTCARD),y) common-obj-y += dev-smartcard-reader.o -common-obj-y += ccid-card-passthru.o -common-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o -ccid-card-emulated.o-cflags := -I$(SRC_PATH)/libcacard +common-obj-$(CONFIG_SMARTCARD) += ccid-card-passthru.o +common-obj-$(CONFIG_SMARTCARD) += ccid-card-emulated.o endif ifeq ($(CONFIG_POSIX),y) diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c index 85a4fc3e53..9f49c0537f 100644 --- a/hw/usb/ccid-card-passthru.c +++ b/hw/usb/ccid-card-passthru.c @@ -12,7 +12,7 @@ #include "qemu/error-report.h" #include "qemu/sockets.h" #include "ccid.h" -#include "libcacard/vscard_common.h" +#include "cacard/vscard_common.h" #define DPRINTF(card, lvl, fmt, ...) \ do { \ diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h index 2b431e6242..c7a03d43b9 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h @@ -384,6 +384,15 @@ struct AcpiMadtGenericMsiFrame { typedef struct AcpiMadtGenericMsiFrame AcpiMadtGenericMsiFrame; +struct AcpiMadtGenericRedistributor { + ACPI_SUB_HEADER_DEF + uint16_t reserved; + uint64_t base_address; + uint32_t range_length; +} QEMU_PACKED; + +typedef struct AcpiMadtGenericRedistributor AcpiMadtGenericRedistributor; + /* * Generic Timer Description Table (GTDT) */ diff --git a/include/hw/arm/virt-acpi-build.h b/include/hw/arm/virt-acpi-build.h index 19b68a404e..744b666385 100644 --- a/include/hw/arm/virt-acpi-build.h +++ b/include/hw/arm/virt-acpi-build.h @@ -32,6 +32,7 @@ typedef struct VirtGuestInfo { const MemMapEntry *memmap; const int *irqmap; bool use_highmem; + int gic_version; } VirtGuestInfo; diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index 808753f08e..f464586304 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -46,6 +46,9 @@ enum { VIRT_CPUPERIPHS, VIRT_GIC_DIST, VIRT_GIC_CPU, + VIRT_GIC_V2M, + VIRT_GIC_ITS, + VIRT_GIC_REDIST, VIRT_UART, VIRT_MMIO, VIRT_RTC, @@ -54,7 +57,6 @@ enum { VIRT_PCIE_MMIO, VIRT_PCIE_PIO, VIRT_PCIE_ECAM, - VIRT_GIC_V2M, VIRT_PLATFORM_BUS, VIRT_PCIE_MMIO_HIGH, }; diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h new file mode 100644 index 0000000000..c2fd8da4ef --- /dev/null +++ b/include/hw/intc/arm_gicv3_common.h @@ -0,0 +1,68 @@ +/* + * ARM GIC support + * + * Copyright (c) 2012 Linaro Limited + * Copyright (c) 2015 Huawei. + * Written by Peter Maydell + * Extended to 64 cores by Shlomo Pongratz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef HW_ARM_GICV3_COMMON_H +#define HW_ARM_GICV3_COMMON_H + +#include "hw/sysbus.h" +#include "hw/intc/arm_gic_common.h" + +typedef struct GICv3State { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + qemu_irq *parent_irq; + qemu_irq *parent_fiq; + + MemoryRegion iomem_dist; /* Distributor */ + MemoryRegion iomem_redist; /* Redistributors */ + + uint32_t num_cpu; + uint32_t num_irq; + uint32_t revision; + bool security_extn; + + int dev_fd; /* kvm device fd if backed by kvm vgic support */ +} GICv3State; + +#define TYPE_ARM_GICV3_COMMON "arm-gicv3-common" +#define ARM_GICV3_COMMON(obj) \ + OBJECT_CHECK(GICv3State, (obj), TYPE_ARM_GICV3_COMMON) +#define ARM_GICV3_COMMON_CLASS(klass) \ + OBJECT_CLASS_CHECK(ARMGICv3CommonClass, (klass), TYPE_ARM_GICV3_COMMON) +#define ARM_GICV3_COMMON_GET_CLASS(obj) \ + OBJECT_GET_CLASS(ARMGICv3CommonClass, (obj), TYPE_ARM_GICV3_COMMON) + +typedef struct ARMGICv3CommonClass { + /*< private >*/ + SysBusDeviceClass parent_class; + /*< public >*/ + + void (*pre_save)(GICv3State *s); + void (*post_load)(GICv3State *s); +} ARMGICv3CommonClass; + +void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler, + const MemoryRegionOps *ops); + +#endif diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index ab3c8766b4..ef21efb683 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -38,10 +38,12 @@ #include <strings.h> #include <inttypes.h> #include <limits.h> +/* Put unistd.h before time.h as that triggers localtime_r/gmtime_r + * function availability on recentish Mingw-w64 platforms. */ +#include <unistd.h> #include <time.h> #include <ctype.h> #include <errno.h> -#include <unistd.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/time.h> diff --git a/include/qemu/thread-win32.h b/include/qemu/thread-win32.h index 3d58081bed..385ff5f76a 100644 --- a/include/qemu/thread-win32.h +++ b/include/qemu/thread-win32.h @@ -18,6 +18,7 @@ struct QemuSemaphore { }; struct QemuEvent { + int value; HANDLE event; }; diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 983e99e1e7..2a58b4d19e 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -240,6 +240,32 @@ int kvm_device_ioctl(int fd, int type, ...); int kvm_vm_check_attr(KVMState *s, uint32_t group, uint64_t attr); /** + * kvm_device_check_attr - check for existence of a specific device attribute + * @fd: The device file descriptor + * @group: the group + * @attr: the attribute of that group to query for + * + * Returns: 1 if the attribute exists + * 0 if the attribute either does not exist or if the vm device + * interface is unavailable + */ +int kvm_device_check_attr(int fd, uint32_t group, uint64_t attr); + +/** + * kvm_device_access - set or get value of a specific vm attribute + * @fd: The device file descriptor + * @group: the group + * @attr: the attribute of that group to set or get + * @val: pointer to a storage area for the value + * @write: true for set and false for get operation + * + * This function is not allowed to fail. Use kvm_device_check_attr() + * in order to check for the availability of optional attributes. + */ +void kvm_device_access(int fd, int group, uint64_t attr, + void *val, bool write); + +/** * kvm_create_device - create a KVM device for the device control API * @KVMState: The KVMState pointer * @type: The KVM device type (see Documentation/virtual/kvm/devices in the diff --git a/include/sysemu/os-win32.h b/include/sysemu/os-win32.h index 706d85a98e..13dcef6b4c 100644 --- a/include/sysemu/os-win32.h +++ b/include/sysemu/os-win32.h @@ -73,10 +73,12 @@ #define siglongjmp(env, val) longjmp(env, val) /* Missing POSIX functions. Don't use MinGW-w64 macros. */ +#ifndef CONFIG_LOCALTIME_R #undef gmtime_r struct tm *gmtime_r(const time_t *timep, struct tm *result); #undef localtime_r struct tm *localtime_r(const time_t *timep, struct tm *result); +#endif /* CONFIG_LOCALTIME_R */ static inline void os_setup_signal_handling(void) {} diff --git a/include/ui/gtk.h b/include/ui/gtk.h index ee6dffd306..0359333fce 100644 --- a/include/ui/gtk.h +++ b/include/ui/gtk.h @@ -1,10 +1,6 @@ #ifndef UI_GTK_H #define UI_GTK_H -#ifdef _WIN32 -# define _WIN32_WINNT 0x0601 /* needed to get definition of MAPVK_VK_TO_VSC */ -#endif - #ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE /* Work around an -Wstrict-prototypes warning in GTK headers */ #pragma GCC diagnostic push @@ -24,6 +24,7 @@ #include "qemu/atomic.h" #include "qemu/option.h" #include "qemu/config-file.h" +#include "qemu/error-report.h" #include "hw/hw.h" #include "hw/pci/msi.h" #include "hw/s390x/adapter.h" @@ -2008,6 +2009,39 @@ int kvm_vm_check_attr(KVMState *s, uint32_t group, uint64_t attr) return ret ? 0 : 1; } +int kvm_device_check_attr(int dev_fd, uint32_t group, uint64_t attr) +{ + struct kvm_device_attr attribute = { + .group = group, + .attr = attr, + .flags = 0, + }; + + return kvm_device_ioctl(dev_fd, KVM_HAS_DEVICE_ATTR, &attribute) ? 0 : 1; +} + +void kvm_device_access(int fd, int group, uint64_t attr, + void *val, bool write) +{ + struct kvm_device_attr kvmattr; + int err; + + kvmattr.flags = 0; + kvmattr.group = group; + kvmattr.attr = attr; + kvmattr.addr = (uintptr_t)val; + + err = kvm_device_ioctl(fd, + write ? KVM_SET_DEVICE_ATTR : KVM_GET_DEVICE_ATTR, + &kvmattr); + if (err < 0) { + error_report("KVM_%s_DEVICE_ATTR failed: %s\n" + "Group %d attr 0x%016" PRIx64, write ? "SET" : "GET", + strerror(-err), group, attr); + abort(); + } +} + int kvm_has_sync_mmu(void) { return kvm_check_extension(kvm_state, KVM_CAP_SYNC_MMU); diff --git a/libcacard/Makefile b/libcacard/Makefile deleted file mode 100644 index b5eddff11e..0000000000 --- a/libcacard/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -libcacard_includedir=$(includedir)/cacard - -TOOLS += vscclient$(EXESUF) - -# objects linked into a shared library, built with libtool with -fPIC if required -libcacard-obj-y = $(libcacard-y) -libcacard-lobj-y=$(patsubst %.o,%.lo,$(libcacard-obj-y)) - -# libtool will build the .o files, too -$(libcacard-obj-y): | $(libcacard-lobj-y) - -all: libcacard.la libcacard.pc - -vscclient$(EXESUF): libcacard/vscclient.o libcacard.la - $(call LINK,$^) - -######################################################################### -# Rules for building libcacard standalone library - -libcacard.la: LDFLAGS += -rpath $(libdir) -no-undefined \ - -export-symbols $(SRC_PATH)/libcacard/libcacard.syms -# Prevent libcacard.so linking against the entire world of 3rd party libs -libcacard.la: LIBS = -libcacard.la: $(libcacard-lobj-y) - $(call LINK,$^) - -libcacard.pc: $(SRC_PATH)/libcacard/libcacard.pc.in - $(call quiet-command,sed -e 's|@LIBDIR@|$(libdir)|' \ - -e 's|@INCLUDEDIR@|$(libcacard_includedir)|' \ - -e 's|@VERSION@|$(shell cat $(SRC_PATH)/VERSION)|' \ - -e 's|@PREFIX@|$(prefix)|' $< > libcacard.pc,\ - " GEN $@") - -.PHONY: install-libcacard - -install: install-libcacard -install-libcacard: libcacard.pc libcacard.la - $(INSTALL_DIR) "$(DESTDIR)$(libdir)" - $(INSTALL_DIR) "$(DESTDIR)$(libdir)/pkgconfig" - $(INSTALL_DIR) "$(DESTDIR)$(libcacard_includedir)" - $(INSTALL_LIB) libcacard.la "$(DESTDIR)$(libdir)" - $(INSTALL_DATA) libcacard.pc "$(DESTDIR)$(libdir)/pkgconfig" - for inc in $(SRC_PATH)/libcacard/*.h; do \ - $(INSTALL_DATA) $$inc "$(DESTDIR)$(libcacard_includedir)"; \ - done diff --git a/libcacard/cac.c b/libcacard/cac.c deleted file mode 100644 index bc84534f9c..0000000000 --- a/libcacard/cac.c +++ /dev/null @@ -1,414 +0,0 @@ -/* - * implement the applets for the CAC card. - * - * This code is licensed under the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - */ - -#include "glib-compat.h" - -#include <string.h> -#include <stdbool.h> - -#include "cac.h" -#include "vcard.h" -#include "vcard_emul.h" -#include "card_7816.h" - -/* private data for PKI applets */ -typedef struct CACPKIAppletDataStruct { - unsigned char *cert; - int cert_len; - unsigned char *cert_buffer; - int cert_buffer_len; - unsigned char *sign_buffer; - int sign_buffer_len; - VCardKey *key; -} CACPKIAppletData; - -/* - * CAC applet private data - */ -struct VCardAppletPrivateStruct { - union { - CACPKIAppletData pki_data; - void *reserved; - } u; -}; - -/* - * handle all the APDU's that are common to all CAC applets - */ -static VCardStatus -cac_common_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response) -{ - int ef; - VCardStatus ret = VCARD_FAIL; - - switch (apdu->a_ins) { - case VCARD7816_INS_SELECT_FILE: - if (apdu->a_p1 != 0x02) { - /* let the 7816 code handle applet switches */ - ret = VCARD_NEXT; - break; - } - /* handle file id setting */ - if (apdu->a_Lc != 2) { - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_DATA_INVALID); - ret = VCARD_DONE; - break; - } - /* CAC 1.0 only supports ef = 0 */ - ef = apdu->a_body[0] | (apdu->a_body[1] << 8); - if (ef != 0) { - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_FILE_NOT_FOUND); - ret = VCARD_DONE; - break; - } - *response = vcard_make_response(VCARD7816_STATUS_SUCCESS); - ret = VCARD_DONE; - break; - case VCARD7816_INS_GET_RESPONSE: - case VCARD7816_INS_VERIFY: - /* let the 7816 code handle these */ - ret = VCARD_NEXT; - break; - case CAC_GET_PROPERTIES: - case CAC_GET_ACR: - /* skip these for now, this will probably be needed */ - *response = vcard_make_response(VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); - ret = VCARD_DONE; - break; - default: - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); - ret = VCARD_DONE; - break; - } - return ret; -} - -/* - * reset the inter call state between applet selects - */ -static VCardStatus -cac_applet_pki_reset(VCard *card, int channel) -{ - VCardAppletPrivate *applet_private; - CACPKIAppletData *pki_applet; - applet_private = vcard_get_current_applet_private(card, channel); - assert(applet_private); - pki_applet = &(applet_private->u.pki_data); - - pki_applet->cert_buffer = NULL; - g_free(pki_applet->sign_buffer); - pki_applet->sign_buffer = NULL; - pki_applet->cert_buffer_len = 0; - pki_applet->sign_buffer_len = 0; - return VCARD_DONE; -} - -static VCardStatus -cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu, - VCardResponse **response) -{ - CACPKIAppletData *pki_applet; - VCardAppletPrivate *applet_private; - int size, next; - unsigned char *sign_buffer; - bool retain_sign_buffer = FALSE; - vcard_7816_status_t status; - VCardStatus ret = VCARD_FAIL; - - applet_private = vcard_get_current_applet_private(card, apdu->a_channel); - assert(applet_private); - pki_applet = &(applet_private->u.pki_data); - - switch (apdu->a_ins) { - case CAC_UPDATE_BUFFER: - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED); - ret = VCARD_DONE; - break; - case CAC_GET_CERTIFICATE: - if ((apdu->a_p2 != 0) || (apdu->a_p1 != 0)) { - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); - break; - } - assert(pki_applet->cert != NULL); - size = apdu->a_Le; - if (pki_applet->cert_buffer == NULL) { - pki_applet->cert_buffer = pki_applet->cert; - pki_applet->cert_buffer_len = pki_applet->cert_len; - } - size = MIN(size, pki_applet->cert_buffer_len); - next = MIN(255, pki_applet->cert_buffer_len - size); - *response = vcard_response_new_bytes( - card, pki_applet->cert_buffer, size, - apdu->a_Le, next ? - VCARD7816_SW1_WARNING_CHANGE : - VCARD7816_SW1_SUCCESS, - next); - pki_applet->cert_buffer += size; - pki_applet->cert_buffer_len -= size; - if ((*response == NULL) || (next == 0)) { - pki_applet->cert_buffer = NULL; - } - if (*response == NULL) { - *response = vcard_make_response( - VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); - } - ret = VCARD_DONE; - break; - case CAC_SIGN_DECRYPT: - if (apdu->a_p2 != 0) { - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); - break; - } - size = apdu->a_Lc; - - sign_buffer = g_realloc(pki_applet->sign_buffer, - pki_applet->sign_buffer_len + size); - memcpy(sign_buffer+pki_applet->sign_buffer_len, apdu->a_body, size); - size += pki_applet->sign_buffer_len; - switch (apdu->a_p1) { - case 0x80: - /* p1 == 0x80 means we haven't yet sent the whole buffer, wait for - * the rest */ - pki_applet->sign_buffer = sign_buffer; - pki_applet->sign_buffer_len = size; - *response = vcard_make_response(VCARD7816_STATUS_SUCCESS); - retain_sign_buffer = TRUE; - break; - case 0x00: - /* we now have the whole buffer, do the operation, result will be - * in the sign_buffer */ - status = vcard_emul_rsa_op(card, pki_applet->key, - sign_buffer, size); - if (status != VCARD7816_STATUS_SUCCESS) { - *response = vcard_make_response(status); - break; - } - *response = vcard_response_new(card, sign_buffer, size, apdu->a_Le, - VCARD7816_STATUS_SUCCESS); - if (*response == NULL) { - *response = vcard_make_response( - VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); - } - break; - default: - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); - break; - } - if (!retain_sign_buffer) { - g_free(sign_buffer); - pki_applet->sign_buffer = NULL; - pki_applet->sign_buffer_len = 0; - } - ret = VCARD_DONE; - break; - case CAC_READ_BUFFER: - /* new CAC call, go ahead and use the old version for now */ - /* TODO: implement */ - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); - ret = VCARD_DONE; - break; - default: - ret = cac_common_process_apdu(card, apdu, response); - break; - } - return ret; -} - - -static VCardStatus -cac_applet_id_process_apdu(VCard *card, VCardAPDU *apdu, - VCardResponse **response) -{ - VCardStatus ret = VCARD_FAIL; - - switch (apdu->a_ins) { - case CAC_UPDATE_BUFFER: - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED); - ret = VCARD_DONE; - break; - case CAC_READ_BUFFER: - /* new CAC call, go ahead and use the old version for now */ - /* TODO: implement */ - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); - ret = VCARD_DONE; - break; - default: - ret = cac_common_process_apdu(card, apdu, response); - break; - } - return ret; -} - - -/* - * TODO: if we ever want to support general CAC middleware, we will need to - * implement the various containers. - */ -static VCardStatus -cac_applet_container_process_apdu(VCard *card, VCardAPDU *apdu, - VCardResponse **response) -{ - VCardStatus ret = VCARD_FAIL; - - switch (apdu->a_ins) { - case CAC_READ_BUFFER: - case CAC_UPDATE_BUFFER: - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); - ret = VCARD_DONE; - break; - default: - ret = cac_common_process_apdu(card, apdu, response); - break; - } - return ret; -} - -/* - * utilities for creating and destroying the private applet data - */ -static void -cac_delete_pki_applet_private(VCardAppletPrivate *applet_private) -{ - CACPKIAppletData *pki_applet_data; - - if (applet_private == NULL) { - return; - } - pki_applet_data = &(applet_private->u.pki_data); - g_free(pki_applet_data->cert); - g_free(pki_applet_data->sign_buffer); - if (pki_applet_data->key != NULL) { - vcard_emul_delete_key(pki_applet_data->key); - } - g_free(applet_private); -} - -static VCardAppletPrivate * -cac_new_pki_applet_private(const unsigned char *cert, - int cert_len, VCardKey *key) -{ - CACPKIAppletData *pki_applet_data; - VCardAppletPrivate *applet_private; - - applet_private = g_new0(VCardAppletPrivate, 1); - pki_applet_data = &(applet_private->u.pki_data); - pki_applet_data->cert = (unsigned char *)g_malloc(cert_len+1); - /* - * if we want to support compression, then we simply change the 0 to a 1 - * and compress the cert data with libz - */ - pki_applet_data->cert[0] = 0; /* not compressed */ - memcpy(&pki_applet_data->cert[1], cert, cert_len); - pki_applet_data->cert_len = cert_len+1; - - pki_applet_data->key = key; - return applet_private; -} - - -/* - * create a new cac applet which links to a given cert - */ -static VCardApplet * -cac_new_pki_applet(int i, const unsigned char *cert, - int cert_len, VCardKey *key) -{ - VCardAppletPrivate *applet_private; - VCardApplet *applet; - unsigned char pki_aid[] = { 0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00 }; - int pki_aid_len = sizeof(pki_aid); - - pki_aid[pki_aid_len-1] = i; - - applet_private = cac_new_pki_applet_private(cert, cert_len, key); - if (applet_private == NULL) { - goto failure; - } - applet = vcard_new_applet(cac_applet_pki_process_apdu, cac_applet_pki_reset, - pki_aid, pki_aid_len); - if (applet == NULL) { - goto failure; - } - vcard_set_applet_private(applet, applet_private, - cac_delete_pki_applet_private); - applet_private = NULL; - - return applet; - -failure: - if (applet_private != NULL) { - cac_delete_pki_applet_private(applet_private); - } - return NULL; -} - - -static unsigned char cac_default_container_aid[] = { - 0xa0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00 }; -static unsigned char cac_id_aid[] = { - 0xa0, 0x00, 0x00, 0x00, 0x79, 0x03, 0x00 }; -/* - * Initialize the cac card. This is the only public function in this file. All - * the rest are connected through function pointers. - */ -VCardStatus -cac_card_init(VReader *reader, VCard *card, - const char *params, - unsigned char * const *cert, - int cert_len[], - VCardKey *key[] /* adopt the keys*/, - int cert_count) -{ - int i; - VCardApplet *applet; - - /* CAC Cards are VM Cards */ - vcard_set_type(card, VCARD_VM); - - /* create one PKI applet for each cert */ - for (i = 0; i < cert_count; i++) { - applet = cac_new_pki_applet(i, cert[i], cert_len[i], key[i]); - if (applet == NULL) { - goto failure; - } - vcard_add_applet(card, applet); - } - - /* create a default blank container applet */ - applet = vcard_new_applet(cac_applet_container_process_apdu, - NULL, cac_default_container_aid, - sizeof(cac_default_container_aid)); - if (applet == NULL) { - goto failure; - } - vcard_add_applet(card, applet); - - /* create a default blank container applet */ - applet = vcard_new_applet(cac_applet_id_process_apdu, - NULL, cac_id_aid, - sizeof(cac_id_aid)); - if (applet == NULL) { - goto failure; - } - vcard_add_applet(card, applet); - return VCARD_DONE; - -failure: - return VCARD_FAIL; -} - diff --git a/libcacard/cac.h b/libcacard/cac.h deleted file mode 100644 index d24a2a846a..0000000000 --- a/libcacard/cac.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * defines the entry point for the cac card. Only used by cac.c anc - * vcard_emul_type.c - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - */ -#ifndef CAC_H -#define CAC_H 1 -#include "vcard.h" -#include "vreader.h" - -#define CAC_GET_PROPERTIES 0x56 -#define CAC_GET_ACR 0x4c -#define CAC_READ_BUFFER 0x52 -#define CAC_UPDATE_BUFFER 0x58 -#define CAC_SIGN_DECRYPT 0x42 -#define CAC_GET_CERTIFICATE 0x36 - -/* - * Initialize the cac card. This is the only public function in this file. All - * the rest are connected through function pointers. - */ -VCardStatus cac_card_init(VReader *reader, VCard *card, const char *params, - unsigned char * const *cert, int cert_len[], - VCardKey *key[] /* adopt the keys*/, - int cert_count); - -/* not yet implemented */ -VCardStatus cac_is_cac_card(VReader *reader); -#endif diff --git a/libcacard/card_7816.c b/libcacard/card_7816.c deleted file mode 100644 index 22fd334d15..0000000000 --- a/libcacard/card_7816.c +++ /dev/null @@ -1,757 +0,0 @@ -/* - * Implement the 7816 portion of the card spec - * - * This code is licensed under the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - */ - -#include "glib-compat.h" - -#include <string.h> - -#include "vcard.h" -#include "vcard_emul.h" -#include "card_7816.h" - -/* - * set the status bytes based on the status word - */ -static void -vcard_response_set_status(VCardResponse *response, vcard_7816_status_t status) -{ - unsigned char sw1, sw2; - response->b_status = status; /* make sure the status and swX representations - * are consistent */ - sw1 = (status >> 8) & 0xff; - sw2 = status & 0xff; - response->b_sw1 = sw1; - response->b_sw2 = sw2; - response->b_data[response->b_len] = sw1; - response->b_data[response->b_len+1] = sw2; -} - -/* - * set the status bytes in a response buffer - */ -static void -vcard_response_set_status_bytes(VCardResponse *response, - unsigned char sw1, unsigned char sw2) -{ - response->b_status = sw1 << 8 | sw2; - response->b_sw1 = sw1; - response->b_sw2 = sw2; - response->b_data[response->b_len] = sw1; - response->b_data[response->b_len+1] = sw2; -} - -/* - * allocate a VCardResponse structure, plus space for the data buffer, and - * set up everything but the resonse bytes. - */ -VCardResponse * -vcard_response_new_data(unsigned char *buf, int len) -{ - VCardResponse *new_response; - - new_response = g_new(VCardResponse, 1); - new_response->b_data = g_malloc(len + 2); - memcpy(new_response->b_data, buf, len); - new_response->b_total_len = len+2; - new_response->b_len = len; - new_response->b_type = VCARD_MALLOC; - return new_response; -} - -static VCardResponse * -vcard_init_buffer_response(VCard *card, unsigned char *buf, int len) -{ - VCardResponse *response; - VCardBufferResponse *buffer_response; - - buffer_response = vcard_get_buffer_response(card); - if (buffer_response) { - vcard_set_buffer_response(card, NULL); - vcard_buffer_response_delete(buffer_response); - } - buffer_response = vcard_buffer_response_new(buf, len); - if (buffer_response == NULL) { - return NULL; - } - response = vcard_response_new_status_bytes(VCARD7816_SW1_RESPONSE_BYTES, - len > 255 ? 0 : len); - if (response == NULL) { - return NULL; - } - vcard_set_buffer_response(card, buffer_response); - return response; -} - -/* - * general buffer to hold results from APDU calls - */ -VCardResponse * -vcard_response_new(VCard *card, unsigned char *buf, - int len, int Le, vcard_7816_status_t status) -{ - VCardResponse *new_response; - - if (len > Le) { - return vcard_init_buffer_response(card, buf, len); - } - new_response = vcard_response_new_data(buf, len); - if (new_response == NULL) { - return NULL; - } - vcard_response_set_status(new_response, status); - return new_response; -} - -/* - * general buffer to hold results from APDU calls - */ -VCardResponse * -vcard_response_new_bytes(VCard *card, unsigned char *buf, int len, int Le, - unsigned char sw1, unsigned char sw2) -{ - VCardResponse *new_response; - - if (len > Le) { - return vcard_init_buffer_response(card, buf, len); - } - new_response = vcard_response_new_data(buf, len); - if (new_response == NULL) { - return NULL; - } - vcard_response_set_status_bytes(new_response, sw1, sw2); - return new_response; -} - -/* - * get a new Response buffer that only has a status. - */ -static VCardResponse * -vcard_response_new_status(vcard_7816_status_t status) -{ - VCardResponse *new_response; - - new_response = g_new(VCardResponse, 1); - new_response->b_data = &new_response->b_sw1; - new_response->b_len = 0; - new_response->b_total_len = 2; - new_response->b_type = VCARD_MALLOC_STRUCT; - vcard_response_set_status(new_response, status); - return new_response; -} - -/* - * same as above, but specify the status as separate bytes - */ -VCardResponse * -vcard_response_new_status_bytes(unsigned char sw1, unsigned char sw2) -{ - VCardResponse *new_response; - - new_response = g_new(VCardResponse, 1); - new_response->b_data = &new_response->b_sw1; - new_response->b_len = 0; - new_response->b_total_len = 2; - new_response->b_type = VCARD_MALLOC_STRUCT; - vcard_response_set_status_bytes(new_response, sw1, sw2); - return new_response; -} - - -/* - * free the response buffer. The Buffer has a type to handle the buffer - * allocated in other ways than through malloc. - */ -void -vcard_response_delete(VCardResponse *response) -{ - if (response == NULL) { - return; - } - switch (response->b_type) { - case VCARD_MALLOC: - /* everything was malloc'ed */ - g_free(response->b_data); - g_free(response); - break; - case VCARD_MALLOC_DATA: - /* only the data buffer was malloc'ed */ - g_free(response->b_data); - break; - case VCARD_MALLOC_STRUCT: - /* only the structure was malloc'ed */ - g_free(response); - break; - case VCARD_STATIC: - break; - } -} - -/* - * decode the class bit and set our generic type field, channel, and - * secure messaging values. - */ -static vcard_7816_status_t -vcard_apdu_set_class(VCardAPDU *apdu) { - apdu->a_channel = 0; - apdu->a_secure_messaging = 0; - apdu->a_type = apdu->a_cla & 0xf0; - apdu->a_gen_type = VCARD_7816_ISO; - - /* parse the class tables 8 & 9 of the 7816-4 Part 4 spec */ - switch (apdu->a_type) { - /* we only support the basic types */ - case 0x00: - case 0x80: - case 0x90: - case 0xa0: - apdu->a_channel = apdu->a_cla & 3; - apdu->a_secure_messaging = apdu->a_cla & 0xe; - break; - case 0xb0: - case 0xc0: - break; - - case 0x10: - case 0x20: - case 0x30: - case 0x40: - case 0x50: - case 0x60: - case 0x70: - /* Reserved for future use */ - apdu->a_gen_type = VCARD_7816_RFU; - break; - case 0xd0: - case 0xe0: - case 0xf0: - default: - apdu->a_gen_type = - (apdu->a_cla == 0xff) ? VCARD_7816_PTS : VCARD_7816_PROPRIETARY; - break; - } - return VCARD7816_STATUS_SUCCESS; -} - -/* - * set the Le and Lc fields according to table 5 of the - * 7816-4 part 4 spec - */ -static vcard_7816_status_t -vcard_apdu_set_length(VCardAPDU *apdu) -{ - int L, Le; - - /* process according to table 5 of the 7816-4 Part 4 spec. - * variable names match the variables in the spec */ - L = apdu->a_len-4; /* fixed APDU header */ - apdu->a_Lc = 0; - apdu->a_Le = 0; - apdu->a_body = NULL; - switch (L) { - case 0: - /* 1 minimal apdu */ - return VCARD7816_STATUS_SUCCESS; - case 1: - /* 2S only return values apdu */ - /* zero maps to 256 here */ - apdu->a_Le = apdu->a_header->ah_Le ? - apdu->a_header->ah_Le : 256; - return VCARD7816_STATUS_SUCCESS; - default: - /* if the ah_Le byte is zero and we have more than - * 1 byte in the header, then we must be using extended Le and Lc. - * process the extended now. */ - if (apdu->a_header->ah_Le == 0) { - if (L < 3) { - /* coding error, need at least 3 bytes */ - return VCARD7816_STATUS_ERROR_WRONG_LENGTH; - } - /* calculate the first extended value. Could be either Le or Lc */ - Le = (apdu->a_header->ah_body[0] << 8) - || apdu->a_header->ah_body[1]; - if (L == 3) { - /* 2E extended, return data only */ - /* zero maps to 65536 */ - apdu->a_Le = Le ? Le : 65536; - return VCARD7816_STATUS_SUCCESS; - } - if (Le == 0) { - /* reserved for future use, probably for next time we need - * to extend the lengths */ - return VCARD7816_STATUS_ERROR_WRONG_LENGTH; - } - /* we know that the first extended value is Lc now */ - apdu->a_Lc = Le; - apdu->a_body = &apdu->a_header->ah_body[2]; - if (L == Le+3) { - /* 3E extended, only body parameters */ - return VCARD7816_STATUS_SUCCESS; - } - if (L == Le+5) { - /* 4E extended, parameters and return data */ - Le = (apdu->a_data[apdu->a_len-2] << 8) - || apdu->a_data[apdu->a_len-1]; - apdu->a_Le = Le ? Le : 65536; - return VCARD7816_STATUS_SUCCESS; - } - return VCARD7816_STATUS_ERROR_WRONG_LENGTH; - } - /* not extended */ - apdu->a_Lc = apdu->a_header->ah_Le; - apdu->a_body = &apdu->a_header->ah_body[0]; - if (L == apdu->a_Lc + 1) { - /* 3S only body parameters */ - return VCARD7816_STATUS_SUCCESS; - } - if (L == apdu->a_Lc + 2) { - /* 4S parameters and return data */ - Le = apdu->a_data[apdu->a_len-1]; - apdu->a_Le = Le ? Le : 256; - return VCARD7816_STATUS_SUCCESS; - } - break; - } - return VCARD7816_STATUS_ERROR_WRONG_LENGTH; -} - -/* - * create a new APDU from a raw set of bytes. This will decode all the - * above fields. users of VCARDAPDU's can then depend on the already decoded - * values. - */ -VCardAPDU * -vcard_apdu_new(unsigned char *raw_apdu, int len, vcard_7816_status_t *status) -{ - VCardAPDU *new_apdu; - - *status = VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE; - if (len < 4) { - *status = VCARD7816_STATUS_ERROR_WRONG_LENGTH; - return NULL; - } - - new_apdu = g_new(VCardAPDU, 1); - new_apdu->a_data = g_memdup(raw_apdu, len); - new_apdu->a_len = len; - *status = vcard_apdu_set_class(new_apdu); - if (*status != VCARD7816_STATUS_SUCCESS) { - g_free(new_apdu); - return NULL; - } - *status = vcard_apdu_set_length(new_apdu); - if (*status != VCARD7816_STATUS_SUCCESS) { - g_free(new_apdu); - new_apdu = NULL; - } - return new_apdu; -} - -void -vcard_apdu_delete(VCardAPDU *apdu) -{ - if (apdu == NULL) { - return; - } - g_free(apdu->a_data); - g_free(apdu); -} - - -/* - * declare response buffers for all the 7816 defined error codes - */ -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_SUCCESS) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_RET_CORUPT) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_CHANGE) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_FILE_FILLED) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR_CHANGE) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_LENGTH) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED) -VCARD_RESPONSE_NEW_STATIC_STATUS( - VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_INVALID) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_NO_EF) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_PARAMETERS) -VCARD_RESPONSE_NEW_STATIC_STATUS( - VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_FILE_NOT_FOUND) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_P1_P2_INCORRECT) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_NOT_FOUND) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_INS_CODE_INVALID) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CLA_INVALID) -VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_GENERAL) - -/* - * return a single response code. This function cannot fail. It will always - * return a response. - */ -VCardResponse * -vcard_make_response(vcard_7816_status_t status) -{ - VCardResponse *response; - - switch (status) { - /* known 7816 response codes */ - case VCARD7816_STATUS_SUCCESS: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_SUCCESS); - case VCARD7816_STATUS_WARNING: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_WARNING); - case VCARD7816_STATUS_WARNING_RET_CORUPT: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_WARNING_RET_CORUPT); - case VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE); - case VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED); - case VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID); - case VCARD7816_STATUS_WARNING_CHANGE: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_WARNING_CHANGE); - case VCARD7816_STATUS_WARNING_FILE_FILLED: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_WARNING_FILE_FILLED); - case VCARD7816_STATUS_EXC_ERROR: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_EXC_ERROR); - case VCARD7816_STATUS_EXC_ERROR_CHANGE: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_EXC_ERROR_CHANGE); - case VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); - case VCARD7816_STATUS_ERROR_WRONG_LENGTH: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_WRONG_LENGTH); - case VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED); - case VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED); - case VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED); - case VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); - case VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE); - case VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED); - case VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED); - case VCARD7816_STATUS_ERROR_DATA_INVALID: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_DATA_INVALID); - case VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED); - case VCARD7816_STATUS_ERROR_DATA_NO_EF: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_DATA_NO_EF); - case VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING); - case VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT); - case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_WRONG_PARAMETERS); - case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA); - case VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED); - case VCARD7816_STATUS_ERROR_FILE_NOT_FOUND: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_FILE_NOT_FOUND); - case VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND); - case VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE); - case VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT); - case VCARD7816_STATUS_ERROR_P1_P2_INCORRECT: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); - case VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT); - case VCARD7816_STATUS_ERROR_DATA_NOT_FOUND: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_DATA_NOT_FOUND); - case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2); - case VCARD7816_STATUS_ERROR_INS_CODE_INVALID: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_INS_CODE_INVALID); - case VCARD7816_STATUS_ERROR_CLA_INVALID: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_CLA_INVALID); - case VCARD7816_STATUS_ERROR_GENERAL: - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_ERROR_GENERAL); - default: - /* we don't know this status code, create a response buffer to - * hold it */ - response = vcard_response_new_status(status); - if (response == NULL) { - /* couldn't allocate the buffer, return memmory error */ - return VCARD_RESPONSE_GET_STATIC( - VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); - } - return response; - } -} - -/* - * Add File card support here if you need it. - */ -static VCardStatus -vcard7816_file_system_process_apdu(VCard *card, VCardAPDU *apdu, - VCardResponse **response) -{ - /* TODO: if we want to support a virtual file system card, we do it here. - * It would probably be a pkcs #15 card type */ - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); - return VCARD_DONE; -} - -/* - * VM card (including java cards) - */ -static VCardStatus -vcard7816_vm_process_apdu(VCard *card, VCardAPDU *apdu, - VCardResponse **response) -{ - int bytes_to_copy, next_byte_count, count; - VCardApplet *current_applet; - VCardBufferResponse *buffer_response; - vcard_7816_status_t status; - - /* parse the class first */ - if (apdu->a_gen_type != VCARD_7816_ISO) { - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); - return VCARD_DONE; - } - - /* use a switch so that if we need to support secure channel stuff later, - * we know where to put it */ - switch (apdu->a_secure_messaging) { - case 0x0: /* no SM */ - break; - case 0x4: /* proprietary SM */ - case 0x8: /* header not authenticated */ - case 0xc: /* header authenticated */ - default: - /* for now, don't try to support secure channel stuff in the - * virtual card. */ - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED); - return VCARD_DONE; - } - - /* now parse the instruction */ - switch (apdu->a_ins) { - case VCARD7816_INS_MANAGE_CHANNEL: /* secure channel op */ - case VCARD7816_INS_EXTERNAL_AUTHENTICATE: /* secure channel op */ - case VCARD7816_INS_GET_CHALLENGE: /* secure channel op */ - case VCARD7816_INS_INTERNAL_AUTHENTICATE: /* secure channel op */ - case VCARD7816_INS_ERASE_BINARY: /* applet control op */ - case VCARD7816_INS_READ_BINARY: /* applet control op */ - case VCARD7816_INS_WRITE_BINARY: /* applet control op */ - case VCARD7816_INS_UPDATE_BINARY: /* applet control op */ - case VCARD7816_INS_READ_RECORD: /* file op */ - case VCARD7816_INS_WRITE_RECORD: /* file op */ - case VCARD7816_INS_UPDATE_RECORD: /* file op */ - case VCARD7816_INS_APPEND_RECORD: /* file op */ - case VCARD7816_INS_ENVELOPE: - case VCARD7816_INS_PUT_DATA: - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); - break; - - case VCARD7816_INS_SELECT_FILE: - if (apdu->a_p1 != 0x04) { - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED); - break; - } - - /* side effect, deselect the current applet if no applet has been found - * */ - current_applet = vcard_find_applet(card, apdu->a_body, apdu->a_Lc); - vcard_select_applet(card, apdu->a_channel, current_applet); - if (current_applet) { - unsigned char *aid; - int aid_len; - aid = vcard_applet_get_aid(current_applet, &aid_len); - *response = vcard_response_new(card, aid, aid_len, apdu->a_Le, - VCARD7816_STATUS_SUCCESS); - } else { - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_FILE_NOT_FOUND); - } - break; - - case VCARD7816_INS_VERIFY: - if ((apdu->a_p1 != 0x00) || (apdu->a_p2 != 0x00)) { - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_WRONG_PARAMETERS); - } else { - if (apdu->a_Lc == 0) { - /* handle pin count if possible */ - count = vcard_emul_get_login_count(card); - if (count < 0) { - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_DATA_NOT_FOUND); - } else { - if (count > 0xf) { - count = 0xf; - } - *response = vcard_response_new_status_bytes( - VCARD7816_SW1_WARNING_CHANGE, - 0xc0 | count); - if (*response == NULL) { - *response = vcard_make_response( - VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); - } - } - } else { - status = vcard_emul_login(card, apdu->a_body, apdu->a_Lc); - *response = vcard_make_response(status); - } - } - break; - - case VCARD7816_INS_GET_RESPONSE: - buffer_response = vcard_get_buffer_response(card); - if (!buffer_response) { - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_DATA_NOT_FOUND); - /* handle error */ - break; - } - bytes_to_copy = MIN(buffer_response->len, apdu->a_Le); - next_byte_count = MIN(256, buffer_response->len - bytes_to_copy); - *response = vcard_response_new_bytes( - card, buffer_response->current, bytes_to_copy, - apdu->a_Le, - next_byte_count ? - VCARD7816_SW1_RESPONSE_BYTES : VCARD7816_SW1_SUCCESS, - next_byte_count); - buffer_response->current += bytes_to_copy; - buffer_response->len -= bytes_to_copy; - if (*response == NULL || (next_byte_count == 0)) { - vcard_set_buffer_response(card, NULL); - vcard_buffer_response_delete(buffer_response); - } - if (*response == NULL) { - *response = - vcard_make_response(VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); - } - break; - - case VCARD7816_INS_GET_DATA: - *response = - vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); - break; - - default: - *response = - vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); - break; - } - - /* response should have been set somewhere */ - assert(*response != NULL); - return VCARD_DONE; -} - - -/* - * APDU processing starts here. This routes the card processing stuff to the - * right location. - */ -VCardStatus -vcard_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response) -{ - VCardStatus status; - VCardBufferResponse *buffer_response; - - /* first handle any PTS commands, which aren't really APDU's */ - if (apdu->a_type == VCARD_7816_PTS) { - /* the PTS responses aren't really responses either */ - *response = vcard_response_new_data(apdu->a_data, apdu->a_len); - /* PTS responses have no status bytes */ - (*response)->b_total_len = (*response)->b_len; - return VCARD_DONE; - } - buffer_response = vcard_get_buffer_response(card); - if (buffer_response && apdu->a_ins != VCARD7816_INS_GET_RESPONSE) { - /* clear out buffer_response, return an error */ - vcard_set_buffer_response(card, NULL); - vcard_buffer_response_delete(buffer_response); - *response = vcard_make_response(VCARD7816_STATUS_EXC_ERROR); - return VCARD_DONE; - } - - status = vcard_process_applet_apdu(card, apdu, response); - if (status != VCARD_NEXT) { - return status; - } - switch (vcard_get_type(card)) { - case VCARD_FILE_SYSTEM: - return vcard7816_file_system_process_apdu(card, apdu, response); - case VCARD_VM: - return vcard7816_vm_process_apdu(card, apdu, response); - case VCARD_DIRECT: - /* if we are type direct, then the applet should handle everything */ - assert(!"VCARD_DIRECT: applet failure"); - break; - } - *response = - vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); - return VCARD_DONE; -} diff --git a/libcacard/card_7816.h b/libcacard/card_7816.h deleted file mode 100644 index 4a01993d2d..0000000000 --- a/libcacard/card_7816.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Implement the 7816 portion of the card spec - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - */ -#ifndef CARD_7816_H -#define CARD_7816_H 1 - -#include "card_7816t.h" -#include "vcardt.h" - -/* - * constructors for VCardResponse's - */ -/* response from a return buffer and a status */ -VCardResponse *vcard_response_new(VCard *card, unsigned char *buf, int len, - int Le, vcard_7816_status_t status); -/* response from a return buffer and status bytes */ -VCardResponse *vcard_response_new_bytes(VCard *card, unsigned char *buf, - int len, int Le, - unsigned char sw1, unsigned char sw2); -/* response from just status bytes */ -VCardResponse *vcard_response_new_status_bytes(unsigned char sw1, - unsigned char sw2); -/* response from just status: NOTE this cannot fail, it will always return a - * valid response, if it can't allocate memory, the response will be - * VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE */ -VCardResponse *vcard_make_response(vcard_7816_status_t status); - -/* create a raw response (status has already been encoded */ -VCardResponse *vcard_response_new_data(unsigned char *buf, int len); - - - - -/* - * destructor for VCardResponse. - * Can be called with a NULL response - */ -void vcard_response_delete(VCardResponse *response); - -/* - * constructor for VCardAPDU - */ -VCardAPDU *vcard_apdu_new(unsigned char *raw_apdu, int len, - unsigned short *status); - -/* - * destructor for VCardAPDU - * Can be called with a NULL apdu - */ -void vcard_apdu_delete(VCardAPDU *apdu); - -/* - * APDU processing starts here. This routes the card processing stuff to the - * right location. Always returns a valid response. - */ -VCardStatus vcard_process_apdu(VCard *card, VCardAPDU *apdu, - VCardResponse **response); - -#endif diff --git a/libcacard/card_7816t.h b/libcacard/card_7816t.h deleted file mode 100644 index 386acc5dc0..0000000000 --- a/libcacard/card_7816t.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Implement the 7816 portion of the card spec - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - */ -#ifndef CARD_7816T_H -#define CARD_7816T_H 1 - -typedef unsigned short vcard_7816_status_t; - -struct VCardResponseStruct { - unsigned char *b_data; - vcard_7816_status_t b_status; - unsigned char b_sw1; - unsigned char b_sw2; - int b_len; - int b_total_len; - enum VCardResponseBufferType { - VCARD_MALLOC, - VCARD_MALLOC_DATA, - VCARD_MALLOC_STRUCT, - VCARD_STATIC - } b_type; -}; - -#define VCARD_RESPONSE_NEW_STATIC_STATUS(stat) \ -static const VCardResponse VCardResponse##stat = \ - {(unsigned char *)&VCardResponse##stat.b_sw1, (stat), ((stat) >> 8), \ - ((stat) & 0xff), 0, 2, VCARD_STATIC}; - -#define VCARD_RESPONSE_NEW_STATIC_STATUS_BYTES(sw1, sw2) \ -static const VCardResponse VCARDResponse##sw1 = \ - {(unsigned char *)&VCardResponse##name.b_sw1, ((sw1) << 8 | (sw2)), \ - (sw1), (sw2), 0, 2, VCARD_STATIC}; - -/* cast away the const, callers need may need to 'free' the - * result, and const implies that they don't */ -#define VCARD_RESPONSE_GET_STATIC(name) \ - ((VCardResponse *)(&VCardResponse##name)) - -typedef enum { - VCARD_7816_ISO, - VCARD_7816_RFU, - VCARD_7816_PTS, - VCARD_7816_PROPRIETARY -} VCardAPDUType; - - -/* - * 7816 header. All APDU's have this header. - * They must be laid out in this order. - */ -struct VCardAPDUHeader { - unsigned char ah_cla; - unsigned char ah_ins; - unsigned char ah_p1; - unsigned char ah_p2; - unsigned char ah_Le; - unsigned char ah_body[1]; /* indefinite length */ -}; - -/* - * 7816 APDU structure. The raw bytes are stored in the union and can be - * accessed directly through u.data (which is aliased as a_data). - * - * Names of the fields match the 7816 documentation. - */ -struct VCardAPDUStruct { - int a_len; /* length of the whole buffer, including header */ - int a_Lc; /* 7816 Lc (parameter length) value */ - int a_Le; /* 7816 Le (expected result length) value */ - unsigned char *a_body; /* pointer to the parameter */ - int a_channel; /* decoded channel */ - int a_secure_messaging; /* decoded secure messaging type */ - int a_type; /* decoded type from cla (top nibble of class) */ - VCardAPDUType a_gen_type; /* generic type (7816, PROPRIETARY, RFU, etc) */ - union { - struct VCardAPDUHeader *header; - unsigned char *data; - } u; -/* give the subfields a unified look */ -#define a_header u.header -#define a_data u.data -#define a_cla a_header->ah_cla /* class */ -#define a_ins a_header->ah_ins /* instruction */ -#define a_p1 a_header->ah_p1 /* parameter 1 */ -#define a_p2 a_header->ah_p2 /* parameter 2 */ -}; - -/* 7816 status codes */ -#define VCARD7816_STATUS_SUCCESS 0x9000 -#define VCARD7816_STATUS_WARNING 0x6200 -#define VCARD7816_STATUS_WARNING_RET_CORUPT 0x6281 -#define VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE 0x6282 -#define VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED 0x6283 -#define VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID 0x6284 -#define VCARD7816_STATUS_WARNING_CHANGE 0x6300 -#define VCARD7816_STATUS_WARNING_FILE_FILLED 0x6381 -#define VCARD7816_STATUS_EXC_ERROR 0x6400 -#define VCARD7816_STATUS_EXC_ERROR_CHANGE 0x6500 -#define VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE 0x6581 -#define VCARD7816_STATUS_ERROR_WRONG_LENGTH 0x6700 -#define VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED 0x6800 -#define VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED 0x6881 -#define VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED 0x6882 -#define VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED 0x6900 -#define VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE 0x6981 -#define VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED 0x6982 -#define VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED 0x6983 -#define VCARD7816_STATUS_ERROR_DATA_INVALID 0x6984 -#define VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED 0x6985 -#define VCARD7816_STATUS_ERROR_DATA_NO_EF 0x6986 -#define VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING 0x6987 -#define VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT 0x6988 -#define VCARD7816_STATUS_ERROR_WRONG_PARAMETERS 0x6a00 -#define VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA 0x6a80 -#define VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED 0x6a81 -#define VCARD7816_STATUS_ERROR_FILE_NOT_FOUND 0x6a82 -#define VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND 0x6a83 -#define VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE 0x6a84 -#define VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT 0x6a85 -#define VCARD7816_STATUS_ERROR_P1_P2_INCORRECT 0x6a86 -#define VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT 0x6a87 -#define VCARD7816_STATUS_ERROR_DATA_NOT_FOUND 0x6a88 -#define VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2 0x6b00 -#define VCARD7816_STATUS_ERROR_INS_CODE_INVALID 0x6d00 -#define VCARD7816_STATUS_ERROR_CLA_INVALID 0x6e00 -#define VCARD7816_STATUS_ERROR_GENERAL 0x6f00 -/* 7816 sw1 codes */ -#define VCARD7816_SW1_SUCCESS 0x90 -#define VCARD7816_SW1_RESPONSE_BYTES 0x61 -#define VCARD7816_SW1_WARNING 0x62 -#define VCARD7816_SW1_WARNING_CHANGE 0x63 -#define VCARD7816_SW1_EXC_ERROR 0x64 -#define VCARD7816_SW1_EXC_ERROR_CHANGE 0x65 -#define VCARD7816_SW1_ERROR_WRONG_LENGTH 0x67 -#define VCARD7816_SW1_CLA_ERROR 0x68 -#define VCARD7816_SW1_COMMAND_ERROR 0x69 -#define VCARD7816_SW1_P1_P2_ERROR 0x6a -#define VCARD7816_SW1_LE_ERROR 0x6c -#define VCARD7816_SW1_INS_ERROR 0x6d -#define VCARD7816_SW1_CLA_NOT_SUPPORTED 0x6e - -/* 7816 Instructions */ -#define VCARD7816_INS_MANAGE_CHANNEL 0x70 -#define VCARD7816_INS_EXTERNAL_AUTHENTICATE 0x82 -#define VCARD7816_INS_GET_CHALLENGE 0x84 -#define VCARD7816_INS_INTERNAL_AUTHENTICATE 0x88 -#define VCARD7816_INS_ERASE_BINARY 0x0e -#define VCARD7816_INS_READ_BINARY 0xb0 -#define VCARD7816_INS_WRITE_BINARY 0xd0 -#define VCARD7816_INS_UPDATE_BINARY 0xd6 -#define VCARD7816_INS_READ_RECORD 0xb2 -#define VCARD7816_INS_WRITE_RECORD 0xd2 -#define VCARD7816_INS_UPDATE_RECORD 0xdc -#define VCARD7816_INS_APPEND_RECORD 0xe2 -#define VCARD7816_INS_ENVELOPE 0xc2 -#define VCARD7816_INS_PUT_DATA 0xda -#define VCARD7816_INS_GET_DATA 0xca -#define VCARD7816_INS_SELECT_FILE 0xa4 -#define VCARD7816_INS_VERIFY 0x20 -#define VCARD7816_INS_GET_RESPONSE 0xc0 - -#endif diff --git a/libcacard/event.c b/libcacard/event.c deleted file mode 100644 index 63f4057fe5..0000000000 --- a/libcacard/event.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - * event queue implementation. - * - * This code is licensed under the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - */ - -#include "glib-compat.h" - -#include "vcard.h" -#include "vreader.h" -#include "vevent.h" - -VEvent * -vevent_new(VEventType type, VReader *reader, VCard *card) -{ - VEvent *new_vevent; - - new_vevent = g_new(VEvent, 1); - new_vevent->next = NULL; - new_vevent->type = type; - new_vevent->reader = vreader_reference(reader); - new_vevent->card = vcard_reference(card); - - return new_vevent; -} - -void -vevent_delete(VEvent *vevent) -{ - if (vevent == NULL) { - return; - } - vreader_free(vevent->reader); - vcard_free(vevent->card); - g_free(vevent); -} - -/* - * VEvent queue management - */ - -static VEvent *vevent_queue_head; -static VEvent *vevent_queue_tail; -static CompatGMutex vevent_queue_lock; -static CompatGCond vevent_queue_condition; - -void vevent_queue_init(void) -{ - vevent_queue_head = vevent_queue_tail = NULL; -} - -void -vevent_queue_vevent(VEvent *vevent) -{ - vevent->next = NULL; - g_mutex_lock(&vevent_queue_lock); - if (vevent_queue_head) { - assert(vevent_queue_tail); - vevent_queue_tail->next = vevent; - } else { - vevent_queue_head = vevent; - } - vevent_queue_tail = vevent; - g_cond_signal(&vevent_queue_condition); - g_mutex_unlock(&vevent_queue_lock); -} - -/* must have lock */ -static VEvent * -vevent_dequeue_vevent(void) -{ - VEvent *vevent = NULL; - if (vevent_queue_head) { - vevent = vevent_queue_head; - vevent_queue_head = vevent->next; - vevent->next = NULL; - } - return vevent; -} - -VEvent *vevent_wait_next_vevent(void) -{ - VEvent *vevent; - - g_mutex_lock(&vevent_queue_lock); - while ((vevent = vevent_dequeue_vevent()) == NULL) { - g_cond_wait(&vevent_queue_condition, &vevent_queue_lock); - } - g_mutex_unlock(&vevent_queue_lock); - return vevent; -} - -VEvent *vevent_get_next_vevent(void) -{ - VEvent *vevent; - - g_mutex_lock(&vevent_queue_lock); - vevent = vevent_dequeue_vevent(); - g_mutex_unlock(&vevent_queue_lock); - return vevent; -} - diff --git a/libcacard/eventt.h b/libcacard/eventt.h deleted file mode 100644 index 0dc7bd468c..0000000000 --- a/libcacard/eventt.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - */ - -#ifndef EVENTT_H -#define EVENTT_H 1 -#include "vreadert.h" -#include "vcardt.h" - -typedef struct VEventStruct VEvent; - -typedef enum { - VEVENT_READER_INSERT, - VEVENT_READER_REMOVE, - VEVENT_CARD_INSERT, - VEVENT_CARD_REMOVE, - VEVENT_LAST, -} VEventType; - -struct VEventStruct { - VEvent *next; - VEventType type; - VReader *reader; - VCard *card; -}; -#endif - - diff --git a/libcacard/libcacard.pc.in b/libcacard/libcacard.pc.in deleted file mode 100644 index 4b60023ce9..0000000000 --- a/libcacard/libcacard.pc.in +++ /dev/null @@ -1,13 +0,0 @@ -prefix=@PREFIX@ -exec_prefix=${prefix} -libdir=@LIBDIR@ -includedir=@INCLUDEDIR@ - -Name: cacard -Description: CA Card library -Version: @VERSION@ - -Requires.private: nss glib-2.0 -Libs: -L${libdir} -lcacard -Libs.private: -Cflags: -I${includedir} diff --git a/libcacard/libcacard.syms b/libcacard/libcacard.syms deleted file mode 100644 index 1697515a7f..0000000000 --- a/libcacard/libcacard.syms +++ /dev/null @@ -1,77 +0,0 @@ -cac_card_init -cac_is_cac_card -vcard_add_applet -vcard_apdu_delete -vcard_apdu_new -vcard_applet_get_aid -vcard_buffer_response_delete -vcard_buffer_response_new -vcard_delete_applet -vcard_emul_delete_key -vcard_emul_force_card_insert -vcard_emul_force_card_remove -vcard_emul_get_atr -vcard_emul_get_login_count -vcard_emul_init -vcard_emul_login -vcard_emul_options -vcard_emul_replay_insertion_events -vcard_emul_reset -vcard_emul_rsa_op -vcard_emul_type_from_string -vcard_emul_type_select -vcard_emul_usage -vcard_find_applet -vcard_free -vcard_get_atr -vcard_get_buffer_response -vcard_get_current_applet_private -vcard_get_private -vcard_get_type -vcard_init -vcard_make_response -vcard_new -vcard_new_applet -vcard_process_apdu -vcard_process_applet_apdu -vcard_reference -vcard_reset -vcard_response_delete -vcard_response_new -vcard_response_new_bytes -vcard_response_new_data -vcard_response_new_status_bytes -vcard_select_applet -vcard_set_applet_private -vcard_set_atr_func -vcard_set_buffer_response -vcard_set_type -vevent_delete -vevent_get_next_vevent -vevent_new -vevent_queue_init -vevent_queue_vevent -vevent_wait_next_vevent -vreader_add_reader -vreader_card_is_present -vreader_free -vreader_get_id -vreader_get_name -vreader_get_private -vreader_get_reader_by_id -vreader_get_reader_by_name -vreader_get_reader_list -vreader_init -vreader_insert_card -vreader_list_delete -vreader_list_get_first -vreader_list_get_next -vreader_list_get_reader -vreader_new -vreader_power_off -vreader_power_on -vreader_queue_card_event -vreader_reference -vreader_remove_reader -vreader_set_id -vreader_xfr_bytes diff --git a/libcacard/link_test.c b/libcacard/link_test.c deleted file mode 100644 index 6f67a23d95..0000000000 --- a/libcacard/link_test.c +++ /dev/null @@ -1,22 +0,0 @@ -/* - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - */ - -#include <stdio.h> -#include "vcard.h" - -VCardStatus cac_card_init(const char *flags, VCard *card, - const unsigned char *cert[], - int cert_len[], VCardKey *key[] /* adopt the keys*/, - int cert_count); -/* - * this will crash... just test the linkage right now - */ - -main(int argc, char **argv) -{ - VCard *card; /* no constructor yet */ - cac_card_init("", card, NULL, 0, NULL, 0); -} - diff --git a/libcacard/vcard.c b/libcacard/vcard.c deleted file mode 100644 index 1a87208f3d..0000000000 --- a/libcacard/vcard.c +++ /dev/null @@ -1,325 +0,0 @@ -/* - * implement the Java card standard. - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - */ - -#include "glib-compat.h" - -#include <string.h> - -#include "vcard.h" -#include "vcard_emul.h" -#include "card_7816t.h" - -struct VCardAppletStruct { - VCardApplet *next; - VCardProcessAPDU process_apdu; - VCardResetApplet reset_applet; - unsigned char *aid; - int aid_len; - void *applet_private; - VCardAppletPrivateFree applet_private_free; -}; - -struct VCardStruct { - int reference_count; - VCardApplet *applet_list; - VCardApplet *current_applet[MAX_CHANNEL]; - VCardBufferResponse *vcard_buffer_response; - VCardType type; - VCardEmul *vcard_private; - VCardEmulFree vcard_private_free; - VCardGetAtr vcard_get_atr; -}; - -VCardBufferResponse * -vcard_buffer_response_new(unsigned char *buffer, int size) -{ - VCardBufferResponse *new_buffer; - - new_buffer = g_new(VCardBufferResponse, 1); - new_buffer->buffer = (unsigned char *)g_memdup(buffer, size); - new_buffer->buffer_len = size; - new_buffer->current = new_buffer->buffer; - new_buffer->len = size; - return new_buffer; -} - -void -vcard_buffer_response_delete(VCardBufferResponse *buffer_response) -{ - if (buffer_response == NULL) { - return; - } - g_free(buffer_response->buffer); - g_free(buffer_response); -} - - -/* - * clean up state after a reset - */ -void -vcard_reset(VCard *card, VCardPower power) -{ - int i; - VCardApplet *applet = NULL; - - if (card->type == VCARD_DIRECT) { - /* select the last applet */ - VCardApplet *current_applet = NULL; - for (current_applet = card->applet_list; current_applet; - current_applet = current_applet->next) { - applet = current_applet; - } - } - for (i = 0; i < MAX_CHANNEL; i++) { - card->current_applet[i] = applet; - } - if (card->vcard_buffer_response) { - vcard_buffer_response_delete(card->vcard_buffer_response); - card->vcard_buffer_response = NULL; - } - vcard_emul_reset(card, power); - if (applet) { - applet->reset_applet(card, 0); - } -} - -/* applet utilities */ - -/* - * applet utilities - */ -/* constructor */ -VCardApplet * -vcard_new_applet(VCardProcessAPDU applet_process_function, - VCardResetApplet applet_reset_function, - unsigned char *aid, int aid_len) -{ - VCardApplet *applet; - - applet = g_new0(VCardApplet, 1); - applet->process_apdu = applet_process_function; - applet->reset_applet = applet_reset_function; - - applet->aid = g_memdup(aid, aid_len); - applet->aid_len = aid_len; - return applet; -} - -/* destructor */ -void -vcard_delete_applet(VCardApplet *applet) -{ - if (applet == NULL) { - return; - } - if (applet->applet_private_free) { - applet->applet_private_free(applet->applet_private); - } - g_free(applet->aid); - g_free(applet); -} - -/* accessor */ -void -vcard_set_applet_private(VCardApplet *applet, VCardAppletPrivate *private, - VCardAppletPrivateFree private_free) -{ - if (applet->applet_private_free) { - applet->applet_private_free(applet->applet_private); - } - applet->applet_private = private; - applet->applet_private_free = private_free; -} - -VCard * -vcard_new(VCardEmul *private, VCardEmulFree private_free) -{ - VCard *new_card; - - new_card = g_new0(VCard, 1); - new_card->type = VCARD_VM; - new_card->vcard_private = private; - new_card->vcard_private_free = private_free; - new_card->reference_count = 1; - return new_card; -} - -VCard * -vcard_reference(VCard *vcard) -{ - if (vcard == NULL) { - return NULL; - } - vcard->reference_count++; - return vcard; -} - -void -vcard_free(VCard *vcard) -{ - VCardApplet *current_applet; - VCardApplet *next_applet; - - if (vcard == NULL) { - return; - } - vcard->reference_count--; - if (vcard->reference_count != 0) { - return; - } - if (vcard->vcard_private_free) { - (*vcard->vcard_private_free)(vcard->vcard_private); - } - for (current_applet = vcard->applet_list; current_applet; - current_applet = next_applet) { - next_applet = current_applet->next; - vcard_delete_applet(current_applet); - } - vcard_buffer_response_delete(vcard->vcard_buffer_response); - g_free(vcard); -} - -void -vcard_get_atr(VCard *vcard, unsigned char *atr, int *atr_len) -{ - if (vcard->vcard_get_atr) { - (*vcard->vcard_get_atr)(vcard, atr, atr_len); - return; - } - vcard_emul_get_atr(vcard, atr, atr_len); -} - -void -vcard_set_atr_func(VCard *card, VCardGetAtr vcard_get_atr) -{ - card->vcard_get_atr = vcard_get_atr; -} - - -VCardStatus -vcard_add_applet(VCard *card, VCardApplet *applet) -{ - applet->next = card->applet_list; - card->applet_list = applet; - /* if our card-type is direct, always call the applet */ - if (card->type == VCARD_DIRECT) { - int i; - - for (i = 0; i < MAX_CHANNEL; i++) { - card->current_applet[i] = applet; - } - } - return VCARD_DONE; -} - -/* - * manage applets - */ -VCardApplet * -vcard_find_applet(VCard *card, unsigned char *aid, int aid_len) -{ - VCardApplet *current_applet; - - for (current_applet = card->applet_list; current_applet; - current_applet = current_applet->next) { - if (current_applet->aid_len != aid_len) { - continue; - } - if (memcmp(current_applet->aid, aid, aid_len) == 0) { - break; - } - } - return current_applet; -} - -unsigned char * -vcard_applet_get_aid(VCardApplet *applet, int *aid_len) -{ - if (applet == NULL) { - return NULL; - } - *aid_len = applet->aid_len; - return applet->aid; -} - - -void -vcard_select_applet(VCard *card, int channel, VCardApplet *applet) -{ - assert(channel < MAX_CHANNEL); - - /* If using an emulated card, make sure to log out of any already logged in - * session. */ - vcard_emul_logout(card); - - card->current_applet[channel] = applet; - /* reset the applet */ - if (applet && applet->reset_applet) { - applet->reset_applet(card, channel); - } -} - -VCardAppletPrivate * -vcard_get_current_applet_private(VCard *card, int channel) -{ - VCardApplet *applet = card->current_applet[channel]; - - if (applet == NULL) { - return NULL; - } - return applet->applet_private; -} - -VCardStatus -vcard_process_applet_apdu(VCard *card, VCardAPDU *apdu, - VCardResponse **response) -{ - if (card->current_applet[apdu->a_channel]) { - return card->current_applet[apdu->a_channel]->process_apdu( - card, apdu, response); - } - return VCARD_NEXT; -} - -/* - * Accessor functions - */ -/* accessor functions for the response buffer */ -VCardBufferResponse * -vcard_get_buffer_response(VCard *card) -{ - return card->vcard_buffer_response; -} - -void -vcard_set_buffer_response(VCard *card, VCardBufferResponse *buffer) -{ - card->vcard_buffer_response = buffer; -} - - -/* accessor functions for the type */ -VCardType -vcard_get_type(VCard *card) -{ - return card->type; -} - -void -vcard_set_type(VCard *card, VCardType type) -{ - card->type = type; -} - -/* accessor for private data */ -VCardEmul * -vcard_get_private(VCard *vcard) -{ - return vcard->vcard_private; -} - diff --git a/libcacard/vcard.h b/libcacard/vcard.h deleted file mode 100644 index 47dc70382b..0000000000 --- a/libcacard/vcard.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - */ -#ifndef VCARD_H -#define VCARD_H 1 - -#include "vcardt.h" - -/* - * response buffer constructors and destructors. - * - * response buffers are used when we need to return more data than will fit in - * a normal APDU response (nominally 254 bytes). - */ -VCardBufferResponse *vcard_buffer_response_new(unsigned char *buffer, int size); -void vcard_buffer_response_delete(VCardBufferResponse *buffer_response); - - -/* - * clean up state on reset - */ -void vcard_reset(VCard *card, VCardPower power); - -/* - * applet utilities - */ -/* - * Constructor for a VCardApplet - */ -VCardApplet *vcard_new_applet(VCardProcessAPDU applet_process_function, - VCardResetApplet applet_reset_function, - unsigned char *aid, int aid_len); - -/* - * destructor for a VCardApplet - * Can be called with a NULL applet - */ -void vcard_delete_applet(VCardApplet *applet); - -/* accessor - set the card type specific private data */ -void vcard_set_applet_private(VCardApplet *applet, VCardAppletPrivate *_private, - VCardAppletPrivateFree private_free); - -/* set type of vcard */ -void vcard_set_type(VCard *card, VCardType type); - -/* - * utilities interacting with the current applet - */ -/* add a new applet to a card */ -VCardStatus vcard_add_applet(VCard *card, VCardApplet *applet); -/* find the applet on the card with the given aid */ -VCardApplet *vcard_find_applet(VCard *card, unsigned char *aid, int aid_len); -/* set the following applet to be current on the given channel */ -void vcard_select_applet(VCard *card, int channel, VCardApplet *applet); -/* get the card type specific private data on the given channel */ -VCardAppletPrivate *vcard_get_current_applet_private(VCard *card, int channel); -/* fetch the applet's id */ -unsigned char *vcard_applet_get_aid(VCardApplet *applet, int *aid_len); - -/* process the apdu for the current selected applet/file */ -VCardStatus vcard_process_applet_apdu(VCard *card, VCardAPDU *apdu, - VCardResponse **response); -/* - * VCard utilities - */ -/* constructor */ -VCard *vcard_new(VCardEmul *_private, VCardEmulFree private_free); -/* get a reference */ -VCard *vcard_reference(VCard *); -/* destructor (reference counted) */ -void vcard_free(VCard *); -/* get the atr from the card */ -void vcard_get_atr(VCard *card, unsigned char *atr, int *atr_len); -void vcard_set_atr_func(VCard *card, VCardGetAtr vcard_get_atr); - -/* accessor functions for the response buffer */ -VCardBufferResponse *vcard_get_buffer_response(VCard *card); -void vcard_set_buffer_response(VCard *card, VCardBufferResponse *buffer); -/* accessor functions for the type */ -VCardType vcard_get_type(VCard *card); -/* get the private data */ -VCardEmul *vcard_get_private(VCard *card); - -#endif diff --git a/libcacard/vcard_emul.h b/libcacard/vcard_emul.h deleted file mode 100644 index f09ee98dc8..0000000000 --- a/libcacard/vcard_emul.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * This is the actual card emulator. - * - * These functions can be implemented in different ways on different platforms - * using the underlying system primitives. For Linux it uses NSS, though direct - * to PKCS #11, openssl+pkcs11, or even gnu crypto libraries+pkcs #11 could be - * used. On Windows CAPI could be used. - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - */ - -#ifndef VCARD_EMUL_H -#define VCARD_EMUL_H 1 - -#include "card_7816t.h" -#include "vcard.h" -#include "vcard_emul_type.h" - -/* - * types - */ -typedef enum { - VCARD_EMUL_OK = 0, - VCARD_EMUL_FAIL, - /* return values by vcard_emul_init */ - VCARD_EMUL_INIT_ALREADY_INITED, -} VCardEmulError; - -/* options are emul specific. call card_emul_parse_args to change a string - * To an options struct */ -typedef struct VCardEmulOptionsStruct VCardEmulOptions; - -/* - * Login functions - */ -/* return the number of login attempts still possible on the card. if unknown, - * return -1 */ -int vcard_emul_get_login_count(VCard *card); -/* login into the card, return the 7816 status word (sw2 || sw1) */ -vcard_7816_status_t vcard_emul_login(VCard *card, unsigned char *pin, - int pin_len); -void vcard_emul_logout(VCard *card); - -/* - * key functions - */ -/* delete a key */ -void vcard_emul_delete_key(VCardKey *key); -/* RSA sign/decrypt with the key, signature happens 'in place' */ -vcard_7816_status_t vcard_emul_rsa_op(VCard *card, VCardKey *key, - unsigned char *buffer, int buffer_size); - -void vcard_emul_reset(VCard *card, VCardPower power); -void vcard_emul_get_atr(VCard *card, unsigned char *atr, int *atr_len); - -/* Re-insert of a card that has been removed by force removal */ -VCardEmulError vcard_emul_force_card_insert(VReader *vreader); -/* Force a card removal even if the card is not physically removed */ -VCardEmulError vcard_emul_force_card_remove(VReader *vreader); - -VCardEmulOptions *vcard_emul_options(const char *args); -VCardEmulError vcard_emul_init(const VCardEmulOptions *options); -void vcard_emul_replay_insertion_events(void); -void vcard_emul_usage(void); -#endif diff --git a/libcacard/vcard_emul_nss.c b/libcacard/vcard_emul_nss.c deleted file mode 100644 index d9761eedc2..0000000000 --- a/libcacard/vcard_emul_nss.c +++ /dev/null @@ -1,1274 +0,0 @@ -/* - * This is the actual card emulator. - * - * These functions can be implemented in different ways on different platforms - * using the underlying system primitives. For Linux it uses NSS, though direct - * to PKCS #11, openssl+pkcs11, or even gnu crypto libraries+pkcs #11 could be - * used. On Windows CAPI could be used. - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - */ - -/* - * NSS headers - */ - -/* avoid including prototypes.h that redefines uint32 */ -#define NO_NSPR_10_SUPPORT - -#include <nss.h> -#include <pk11pub.h> -#include <cert.h> -#include <key.h> -#include <secmod.h> -#include <prthread.h> -#include <secerr.h> - -#include "glib-compat.h" - -#include "vcard.h" -#include "card_7816t.h" -#include "vcard_emul.h" -#include "vreader.h" -#include "vevent.h" - -#include "vcardt_internal.h" - - -typedef enum { - VCardEmulUnknown = -1, - VCardEmulFalse = 0, - VCardEmulTrue = 1 -} VCardEmulTriState; - -struct VCardKeyStruct { - CERTCertificate *cert; - PK11SlotInfo *slot; - SECKEYPrivateKey *key; - VCardEmulTriState failedX509; -}; - - -typedef struct VirtualReaderOptionsStruct VirtualReaderOptions; - -struct VReaderEmulStruct { - PK11SlotInfo *slot; - VCardEmulType default_type; - char *type_params; - PRBool present; - int series; - VCard *saved_vcard; -}; - -/* - * NSS Specific options - */ -struct VirtualReaderOptionsStruct { - char *name; - char *vname; - VCardEmulType card_type; - char *type_params; - char **cert_name; - int cert_count; -}; - -struct VCardEmulOptionsStruct { - void *nss_db; - VirtualReaderOptions *vreader; - int vreader_count; - VCardEmulType hw_card_type; - const char *hw_type_params; - PRBool use_hw; -}; - -static int nss_emul_init; - -/* if we have more that just the slot, define - * VCardEmulStruct here */ - -/* - * allocate the set of arrays for certs, cert_len, key - */ -static void -vcard_emul_alloc_arrays(unsigned char ***certsp, int **cert_lenp, - VCardKey ***keysp, int cert_count) -{ - *certsp = g_new(unsigned char *, cert_count); - *cert_lenp = g_new(int, cert_count); - *keysp = g_new(VCardKey *, cert_count); -} - -/* - * Emulator specific card information - */ -typedef struct CardEmulCardStruct CardEmulPrivate; - -static VCardEmul * -vcard_emul_new_card(PK11SlotInfo *slot) -{ - PK11_ReferenceSlot(slot); - /* currently we don't need anything other than the slot */ - return (VCardEmul *)slot; -} - -static void -vcard_emul_delete_card(VCardEmul *vcard_emul) -{ - PK11SlotInfo *slot = (PK11SlotInfo *)vcard_emul; - if (slot == NULL) { - return; - } - PK11_FreeSlot(slot); -} - -static PK11SlotInfo * -vcard_emul_card_get_slot(VCard *card) -{ - /* note, the card is holding the reference, no need to get another one */ - return (PK11SlotInfo *)vcard_get_private(card); -} - - -/* - * key functions - */ -/* private constructure */ -static VCardKey * -vcard_emul_make_key(PK11SlotInfo *slot, CERTCertificate *cert) -{ - VCardKey *key; - - key = g_new(VCardKey, 1); - key->slot = PK11_ReferenceSlot(slot); - key->cert = CERT_DupCertificate(cert); - /* NOTE: if we aren't logged into the token, this could return NULL */ - /* NOTE: the cert is a temp cert, not necessarily the cert in the token, - * use the DER version of this function */ - key->key = PK11_FindKeyByDERCert(slot, cert, NULL); - key->failedX509 = VCardEmulUnknown; - return key; -} - -/* destructor */ -void -vcard_emul_delete_key(VCardKey *key) -{ - if (!nss_emul_init || (key == NULL)) { - return; - } - if (key->key) { - SECKEY_DestroyPrivateKey(key->key); - key->key = NULL; - } - if (key->cert) { - CERT_DestroyCertificate(key->cert); - } - if (key->slot) { - PK11_FreeSlot(key->slot); - } -} - -/* - * grab the nss key from a VCardKey. If it doesn't exist, try to look it up - */ -static SECKEYPrivateKey * -vcard_emul_get_nss_key(VCardKey *key) -{ - if (key->key) { - return key->key; - } - /* NOTE: if we aren't logged into the token, this could return NULL */ - key->key = PK11_FindPrivateKeyFromCert(key->slot, key->cert, NULL); - return key->key; -} - -/* - * Map NSS errors to 7816 errors - */ -static vcard_7816_status_t -vcard_emul_map_error(int error) -{ - switch (error) { - case SEC_ERROR_TOKEN_NOT_LOGGED_IN: - return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED; - case SEC_ERROR_BAD_DATA: - case SEC_ERROR_OUTPUT_LEN: - case SEC_ERROR_INPUT_LEN: - case SEC_ERROR_INVALID_ARGS: - case SEC_ERROR_INVALID_ALGORITHM: - case SEC_ERROR_NO_KEY: - case SEC_ERROR_INVALID_KEY: - case SEC_ERROR_DECRYPTION_DISALLOWED: - return VCARD7816_STATUS_ERROR_DATA_INVALID; - case SEC_ERROR_NO_MEMORY: - return VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE; - } - return VCARD7816_STATUS_EXC_ERROR_CHANGE; -} - -/* RSA sign/decrypt with the key, signature happens 'in place' */ -vcard_7816_status_t -vcard_emul_rsa_op(VCard *card, VCardKey *key, - unsigned char *buffer, int buffer_size) -{ - SECKEYPrivateKey *priv_key; - unsigned signature_len; - PK11SlotInfo *slot; - SECStatus rv; - unsigned char buf[2048]; - unsigned char *bp = NULL; - int pad_len; - vcard_7816_status_t ret = VCARD7816_STATUS_SUCCESS; - - if ((!nss_emul_init) || (key == NULL)) { - /* couldn't get the key, indicate that we aren't logged in */ - return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED; - } - priv_key = vcard_emul_get_nss_key(key); - if (priv_key == NULL) { - /* couldn't get the key, indicate that we aren't logged in */ - return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED; - } - slot = vcard_emul_card_get_slot(card); - - /* - * this is only true of the rsa signature - */ - signature_len = PK11_SignatureLen(priv_key); - if (buffer_size != signature_len) { - return VCARD7816_STATUS_ERROR_DATA_INVALID; - } - /* be able to handle larger keys if necessariy */ - bp = &buf[0]; - if (sizeof(buf) < signature_len) { - bp = g_malloc(signature_len); - } - - /* - * do the raw operations. Some tokens claim to do CKM_RSA_X_509, but then - * choke when they try to do the actual operations. Try to detect - * those cases and treat them as if the token didn't claim support for - * X_509. - */ - if (key->failedX509 != VCardEmulTrue - && PK11_DoesMechanism(slot, CKM_RSA_X_509)) { - rv = PK11_PrivDecryptRaw(priv_key, bp, &signature_len, signature_len, - buffer, buffer_size); - if (rv == SECSuccess) { - assert(buffer_size == signature_len); - memcpy(buffer, bp, signature_len); - key->failedX509 = VCardEmulFalse; - goto cleanup; - } - /* - * we've had a successful X509 operation, this failure must be - * somethine else - */ - if (key->failedX509 == VCardEmulFalse) { - ret = vcard_emul_map_error(PORT_GetError()); - goto cleanup; - } - /* - * key->failedX509 must be Unknown at this point, try the - * non-x_509 case - */ - } - /* token does not support CKM_RSA_X509, emulate that with CKM_RSA_PKCS */ - /* is this a PKCS #1 formatted signature? */ - if ((buffer[0] == 0) && (buffer[1] == 1)) { - int i; - - for (i = 2; i < buffer_size; i++) { - /* rsa signature pad */ - if (buffer[i] != 0xff) { - break; - } - } - if ((i < buffer_size) && (buffer[i] == 0)) { - /* yes, we have a properly formatted PKCS #1 signature */ - /* - * NOTE: even if we accidentally got an encrypt buffer, which - * through sheer luck started with 00, 01, ff, 00, it won't matter - * because the resulting Sign operation will effectively decrypt - * the real buffer. - */ - SECItem signature; - SECItem hash; - - i++; - hash.data = &buffer[i]; - hash.len = buffer_size - i; - signature.data = bp; - signature.len = signature_len; - rv = PK11_Sign(priv_key, &signature, &hash); - if (rv != SECSuccess) { - ret = vcard_emul_map_error(PORT_GetError()); - goto cleanup; - } - assert(buffer_size == signature.len); - memcpy(buffer, bp, signature.len); - /* - * we got here because either the X509 attempt failed, or the - * token couldn't do the X509 operation, in either case stay - * with the PKCS version for future operations on this key - */ - key->failedX509 = VCardEmulTrue; - goto cleanup; - } - } - pad_len = buffer_size - signature_len; - assert(pad_len < 4); - /* - * OK now we've decrypted the payload, package it up in PKCS #1 for the - * upper layer. - */ - buffer[0] = 0; - buffer[1] = 2; /* RSA_encrypt */ - pad_len -= 3; /* format is 0 || 2 || pad || 0 || data */ - /* - * padding for PKCS #1 encrypted data is a string of random bytes. The - * random butes protect against potential decryption attacks against RSA. - * Since PrivDecrypt has already stripped those bytes, we can't reconstruct - * them. This shouldn't matter to the upper level code which should just - * strip this code out anyway, so We'll pad with a constant 3. - */ - memset(&buffer[2], 0x03, pad_len); - pad_len += 2; /* index to the end of the pad */ - buffer[pad_len] = 0; - pad_len++; /* index to the start of the data */ - memcpy(&buffer[pad_len], bp, signature_len); - /* - * we got here because either the X509 attempt failed, or the - * token couldn't do the X509 operation, in either case stay - * with the PKCS version for future operations on this key - */ - key->failedX509 = VCardEmulTrue; -cleanup: - if (bp != buf) { - g_free(bp); - } - return ret; -} - -/* - * Login functions - */ -/* return the number of login attempts still possible on the card. if unknown, - * return -1 */ -int -vcard_emul_get_login_count(VCard *card) -{ - return -1; -} - -/* login into the card, return the 7816 status word (sw2 || sw1) */ -vcard_7816_status_t -vcard_emul_login(VCard *card, unsigned char *pin, int pin_len) -{ - PK11SlotInfo *slot; - unsigned char *pin_string; - int i; - SECStatus rv; - - if (!nss_emul_init) { - return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED; - } - slot = vcard_emul_card_get_slot(card); - /* We depend on the PKCS #11 module internal login state here because we - * create a separate process to handle each guest instance. If we needed - * to handle multiple guests from one process, then we would need to keep - * a lot of extra state in our card structure - * */ - pin_string = g_malloc(pin_len+1); - memcpy(pin_string, pin, pin_len); - pin_string[pin_len] = 0; - - /* handle CAC expanded pins correctly */ - for (i = pin_len-1; i >= 0 && (pin_string[i] == 0xff); i--) { - pin_string[i] = 0; - } - - rv = PK11_Authenticate(slot, PR_FALSE, pin_string); - memset(pin_string, 0, pin_len); /* don't let the pin hang around in memory - to be snooped */ - g_free(pin_string); - if (rv == SECSuccess) { - return VCARD7816_STATUS_SUCCESS; - } - /* map the error from port get error */ - return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED; -} - -void -vcard_emul_logout(VCard *card) -{ - PK11SlotInfo *slot; - - if (!nss_emul_init) { - return; - } - - slot = vcard_emul_card_get_slot(card); - if (PK11_IsLoggedIn(slot, NULL)) { - PK11_Logout(slot); /* NOTE: ignoring SECStatus return value */ - } -} - -void -vcard_emul_reset(VCard *card, VCardPower power) -{ - /* - * if we reset the card (either power on or power off), we lose our login - * state - */ - vcard_emul_logout(card); - - /* TODO: we may also need to send insertion/removal events? */ -} - -static VReader * -vcard_emul_find_vreader_from_slot(PK11SlotInfo *slot) -{ - VReaderList *reader_list = vreader_get_reader_list(); - VReaderListEntry *current_entry; - - if (reader_list == NULL) { - return NULL; - } - for (current_entry = vreader_list_get_first(reader_list); current_entry; - current_entry = vreader_list_get_next(current_entry)) { - VReader *reader = vreader_list_get_reader(current_entry); - VReaderEmul *reader_emul = vreader_get_private(reader); - if (reader_emul->slot == slot) { - vreader_list_delete(reader_list); - return reader; - } - vreader_free(reader); - } - - vreader_list_delete(reader_list); - return NULL; -} - -/* - * create a new reader emul - */ -static VReaderEmul * -vreader_emul_new(PK11SlotInfo *slot, VCardEmulType type, const char *params) -{ - VReaderEmul *new_reader_emul; - - new_reader_emul = g_new(VReaderEmul, 1); - - new_reader_emul->slot = PK11_ReferenceSlot(slot); - new_reader_emul->default_type = type; - new_reader_emul->type_params = g_strdup(params); - new_reader_emul->present = PR_FALSE; - new_reader_emul->series = 0; - new_reader_emul->saved_vcard = NULL; - return new_reader_emul; -} - -static void -vreader_emul_delete(VReaderEmul *vreader_emul) -{ - if (vreader_emul == NULL) { - return; - } - if (vreader_emul->slot) { - PK11_FreeSlot(vreader_emul->slot); - } - g_free(vreader_emul->type_params); - g_free(vreader_emul); -} - -/* - * TODO: move this to emulater non-specific file - */ -static VCardEmulType -vcard_emul_get_type(VReader *vreader) -{ - VReaderEmul *vreader_emul; - - vreader_emul = vreader_get_private(vreader); - if (vreader_emul && vreader_emul->default_type != VCARD_EMUL_NONE) { - return vreader_emul->default_type; - } - - return vcard_emul_type_select(vreader); -} -/* - * TODO: move this to emulater non-specific file - */ -static const char * -vcard_emul_get_type_params(VReader *vreader) -{ - VReaderEmul *vreader_emul; - - vreader_emul = vreader_get_private(vreader); - if (vreader_emul && vreader_emul->type_params) { - return vreader_emul->type_params; - } - - return ""; -} - -/* pull the slot out of the reader private data */ -static PK11SlotInfo * -vcard_emul_reader_get_slot(VReader *vreader) -{ - VReaderEmul *vreader_emul = vreader_get_private(vreader); - if (vreader_emul == NULL) { - return NULL; - } - return vreader_emul->slot; -} - -/* - * Card ATR's map to physical cards. vcard_alloc_atr will set appropriate - * historical bytes for any software emulated card. The remaining bytes can be - * used to indicate the actual emulator - */ -static unsigned char *nss_atr; -static int nss_atr_len; - -void -vcard_emul_get_atr(VCard *card, unsigned char *atr, int *atr_len) -{ - int len; - assert(atr != NULL); - - if (nss_atr == NULL) { - nss_atr = vcard_alloc_atr("NSS", &nss_atr_len); - } - len = MIN(nss_atr_len, *atr_len); - memcpy(atr, nss_atr, len); - *atr_len = len; -} - -/* - * create a new card from certs and keys - */ -static VCard * -vcard_emul_make_card(VReader *reader, - unsigned char * const *certs, int *cert_len, - VCardKey *keys[], int cert_count) -{ - VCardEmul *vcard_emul; - VCard *vcard; - PK11SlotInfo *slot; - VCardEmulType type; - const char *params; - - type = vcard_emul_get_type(reader); - - /* ignore the inserted card */ - if (type == VCARD_EMUL_NONE) { - return NULL; - } - slot = vcard_emul_reader_get_slot(reader); - if (slot == NULL) { - return NULL; - } - - params = vcard_emul_get_type_params(reader); - /* params these can be NULL */ - - vcard_emul = vcard_emul_new_card(slot); - if (vcard_emul == NULL) { - return NULL; - } - vcard = vcard_new(vcard_emul, vcard_emul_delete_card); - if (vcard == NULL) { - vcard_emul_delete_card(vcard_emul); - return NULL; - } - vcard_init(reader, vcard, type, params, certs, cert_len, keys, cert_count); - return vcard; -} - - -/* - * 'clone' a physical card as a virtual card - */ -static VCard * -vcard_emul_mirror_card(VReader *vreader) -{ - /* - * lookup certs using the C_FindObjects. The Stan Cert handle won't give - * us the real certs until we log in. - */ - PK11GenericObject *firstObj, *thisObj; - int cert_count; - unsigned char **certs; - int *cert_len; - VCardKey **keys; - PK11SlotInfo *slot; - VCard *card; - - slot = vcard_emul_reader_get_slot(vreader); - if (slot == NULL) { - return NULL; - } - - firstObj = PK11_FindGenericObjects(slot, CKO_CERTIFICATE); - if (firstObj == NULL) { - return NULL; - } - - /* count the certs */ - cert_count = 0; - for (thisObj = firstObj; thisObj; - thisObj = PK11_GetNextGenericObject(thisObj)) { - cert_count++; - } - - /* allocate the arrays */ - vcard_emul_alloc_arrays(&certs, &cert_len, &keys, cert_count); - - /* fill in the arrays */ - cert_count = 0; - for (thisObj = firstObj; thisObj; - thisObj = PK11_GetNextGenericObject(thisObj)) { - SECItem derCert; - CERTCertificate *cert; - SECStatus rv; - - rv = PK11_ReadRawAttribute(PK11_TypeGeneric, thisObj, - CKA_VALUE, &derCert); - if (rv != SECSuccess) { - continue; - } - /* create floating temp cert. This gives us a cert structure even if - * the token isn't logged in */ - cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &derCert, - NULL, PR_FALSE, PR_TRUE); - SECITEM_FreeItem(&derCert, PR_FALSE); - if (cert == NULL) { - continue; - } - - certs[cert_count] = cert->derCert.data; - cert_len[cert_count] = cert->derCert.len; - keys[cert_count] = vcard_emul_make_key(slot, cert); - cert_count++; - CERT_DestroyCertificate(cert); /* key obj still has a reference */ - } - - /* now create the card */ - card = vcard_emul_make_card(vreader, certs, cert_len, keys, cert_count); - g_free(certs); - g_free(cert_len); - g_free(keys); - - return card; -} - -static VCardEmulType default_card_type = VCARD_EMUL_NONE; -static const char *default_type_params = ""; - -/* - * This thread looks for card and reader insertions and puts events on the - * event queue - */ -static void -vcard_emul_event_thread(void *arg) -{ - PK11SlotInfo *slot; - VReader *vreader; - VReaderEmul *vreader_emul; - VCard *vcard; - SECMODModule *module = (SECMODModule *)arg; - - do { - /* - * XXX - the latency value doesn't matter one bit. you only get no - * blocking (flags |= CKF_DONT_BLOCK) or PKCS11_WAIT_LATENCY (==500), - * hard coded in coolkey. And it isn't coolkey's fault - the timeout - * value we pass get's dropped on the floor before C_WaitForSlotEvent - * is called. - */ - slot = SECMOD_WaitForAnyTokenEvent(module, 0, 500); - if (slot == NULL) { - /* this could be just a no event indication */ - if (PORT_GetError() == SEC_ERROR_NO_EVENT) { - continue; - } - break; - } - vreader = vcard_emul_find_vreader_from_slot(slot); - if (vreader == NULL) { - /* new vreader */ - vreader_emul = vreader_emul_new(slot, default_card_type, - default_type_params); - vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul, - vreader_emul_delete); - PK11_FreeSlot(slot); - slot = NULL; - vreader_add_reader(vreader); - vreader_free(vreader); - continue; - } - /* card remove/insert */ - vreader_emul = vreader_get_private(vreader); - if (PK11_IsPresent(slot)) { - int series = PK11_GetSlotSeries(slot); - if (series != vreader_emul->series) { - if (vreader_emul->present) { - vreader_insert_card(vreader, NULL); - } - vcard = vcard_emul_mirror_card(vreader); - vreader_insert_card(vreader, vcard); - vcard_free(vcard); - } - vreader_emul->series = series; - vreader_emul->present = 1; - vreader_free(vreader); - PK11_FreeSlot(slot); - continue; - } - if (vreader_emul->present) { - vreader_insert_card(vreader, NULL); - } - vreader_emul->series = 0; - vreader_emul->present = 0; - PK11_FreeSlot(slot); - vreader_free(vreader); - } while (1); -} - -/* if the card is inserted when we start up, make sure our state is correct */ -static void -vcard_emul_init_series(VReader *vreader, VCard *vcard) -{ - VReaderEmul *vreader_emul = vreader_get_private(vreader); - PK11SlotInfo *slot = vreader_emul->slot; - - vreader_emul->present = PK11_IsPresent(slot); - vreader_emul->series = PK11_GetSlotSeries(slot); - if (vreader_emul->present == 0) { - vreader_insert_card(vreader, NULL); - } -} - -/* - * each module has a separate wait call, create a thread for each module that - * we are using. - */ -static void -vcard_emul_new_event_thread(SECMODModule *module) -{ - PR_CreateThread(PR_SYSTEM_THREAD, vcard_emul_event_thread, - module, PR_PRIORITY_HIGH, PR_GLOBAL_THREAD, - PR_UNJOINABLE_THREAD, 0); -} - -static const VCardEmulOptions default_options = { - .nss_db = NULL, - .vreader = NULL, - .vreader_count = 0, - .hw_card_type = VCARD_EMUL_CAC, - .hw_type_params = "", - .use_hw = PR_TRUE -}; - - -/* - * NSS needs the app to supply a password prompt. In our case the only time - * the password is supplied is as part of the Login APDU. The actual password - * is passed in the pw_arg in that case. In all other cases pw_arg should be - * NULL. - */ -static char * -vcard_emul_get_password(PK11SlotInfo *slot, PRBool retries, void *pw_arg) -{ - /* if it didn't work the first time, don't keep trying */ - if (retries) { - return NULL; - } - /* we are looking up a password when we don't have one in hand */ - if (pw_arg == NULL) { - return NULL; - } - /* TODO: we really should verify that were are using the right slot */ - return PORT_Strdup(pw_arg); -} - -/* Force a card removal even if the card is not physically removed */ -VCardEmulError -vcard_emul_force_card_remove(VReader *vreader) -{ - if (!nss_emul_init || (vreader_card_is_present(vreader) != VREADER_OK)) { - return VCARD_EMUL_FAIL; /* card is already removed */ - } - - /* OK, remove it */ - vreader_insert_card(vreader, NULL); - return VCARD_EMUL_OK; -} - -/* Re-insert of a card that has been removed by force removal */ -VCardEmulError -vcard_emul_force_card_insert(VReader *vreader) -{ - VReaderEmul *vreader_emul; - VCard *vcard; - - if (!nss_emul_init || (vreader_card_is_present(vreader) == VREADER_OK)) { - return VCARD_EMUL_FAIL; /* card is already removed */ - } - vreader_emul = vreader_get_private(vreader); - - /* if it's a softcard, get the saved vcard from the reader emul structure */ - if (vreader_emul->saved_vcard) { - vcard = vcard_reference(vreader_emul->saved_vcard); - } else { - /* it must be a physical card, rebuild it */ - if (!PK11_IsPresent(vreader_emul->slot)) { - /* physical card has been removed, not way to reinsert it */ - return VCARD_EMUL_FAIL; - } - vcard = vcard_emul_mirror_card(vreader); - } - vreader_insert_card(vreader, vcard); - vcard_free(vcard); - - return VCARD_EMUL_OK; -} - - -static PRBool -module_has_removable_hw_slots(SECMODModule *mod) -{ - int i; - PRBool ret = PR_FALSE; - SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock(); - - if (!moduleLock) { - PORT_SetError(SEC_ERROR_NOT_INITIALIZED); - return ret; - } - SECMOD_GetReadLock(moduleLock); - for (i = 0; i < mod->slotCount; i++) { - PK11SlotInfo *slot = mod->slots[i]; - if (PK11_IsRemovable(slot) && PK11_IsHW(slot)) { - ret = PR_TRUE; - break; - } - } - SECMOD_ReleaseReadLock(moduleLock); - return ret; -} - -/* Previously we returned FAIL if no readers found. This makes - * no sense when using hardware, since there may be no readers connected - * at the time vcard_emul_init is called, but they will be properly - * recognized later. So Instead return FAIL only if no_hw==1 and no - * vcards can be created (indicates error with certificates provided - * or db), or if any other higher level error (NSS error, missing coolkey). */ -static int vcard_emul_init_called; - -VCardEmulError -vcard_emul_init(const VCardEmulOptions *options) -{ - SECStatus rv; - PRBool has_readers = PR_FALSE; - VReader *vreader; - VReaderEmul *vreader_emul; - SECMODListLock *module_lock; - SECMODModuleList *module_list; - SECMODModuleList *mlp; - int i; - - if (vcard_emul_init_called) { - return VCARD_EMUL_INIT_ALREADY_INITED; - } - vcard_emul_init_called = 1; - vreader_init(); - vevent_queue_init(); - - if (options == NULL) { - options = &default_options; - } - - /* first initialize NSS */ - if (options->nss_db) { - rv = NSS_Init(options->nss_db); - } else { - gchar *path; -#ifndef _WIN32 - path = g_strdup("/etc/pki/nssdb"); -#else - if (g_get_system_config_dirs() == NULL || - g_get_system_config_dirs()[0] == NULL) { - return VCARD_EMUL_FAIL; - } - - path = g_build_filename( - g_get_system_config_dirs()[0], "pki", "nssdb", NULL); -#endif - - rv = NSS_Init(path); - g_free(path); - } - if (rv != SECSuccess) { - return VCARD_EMUL_FAIL; - } - /* Set password callback function */ - PK11_SetPasswordFunc(vcard_emul_get_password); - - /* set up soft cards emulated by software certs rather than physical cards - * */ - for (i = 0; i < options->vreader_count; i++) { - int j; - int cert_count; - unsigned char **certs; - int *cert_len; - VCardKey **keys; - PK11SlotInfo *slot; - - slot = PK11_FindSlotByName(options->vreader[i].name); - if (slot == NULL) { - continue; - } - vreader_emul = vreader_emul_new(slot, options->vreader[i].card_type, - options->vreader[i].type_params); - vreader = vreader_new(options->vreader[i].vname, vreader_emul, - vreader_emul_delete); - vreader_add_reader(vreader); - - vcard_emul_alloc_arrays(&certs, &cert_len, &keys, - options->vreader[i].cert_count); - - cert_count = 0; - for (j = 0; j < options->vreader[i].cert_count; j++) { - /* we should have a better way of identifying certs than by - * nickname here */ - CERTCertificate *cert = PK11_FindCertFromNickname( - options->vreader[i].cert_name[j], - NULL); - if (cert == NULL) { - continue; - } - certs[cert_count] = cert->derCert.data; - cert_len[cert_count] = cert->derCert.len; - keys[cert_count] = vcard_emul_make_key(slot, cert); - /* this is safe because the key is still holding a cert reference */ - CERT_DestroyCertificate(cert); - cert_count++; - } - if (cert_count) { - VCard *vcard = vcard_emul_make_card(vreader, certs, cert_len, - keys, cert_count); - vreader_insert_card(vreader, vcard); - vcard_emul_init_series(vreader, vcard); - /* allow insertion and removal of soft cards */ - vreader_emul->saved_vcard = vcard_reference(vcard); - vcard_free(vcard); - vreader_free(vreader); - has_readers = PR_TRUE; - } - g_free(certs); - g_free(cert_len); - g_free(keys); - } - - /* if we aren't suppose to use hw, skip looking up hardware tokens */ - if (!options->use_hw) { - nss_emul_init = has_readers; - return has_readers ? VCARD_EMUL_OK : VCARD_EMUL_FAIL; - } - - /* make sure we have some PKCS #11 module loaded */ - module_lock = SECMOD_GetDefaultModuleListLock(); - module_list = SECMOD_GetDefaultModuleList(); - SECMOD_GetReadLock(module_lock); - for (mlp = module_list; mlp; mlp = mlp->next) { - SECMODModule *module = mlp->module; - if (module_has_removable_hw_slots(module)) { - break; - } - } - SECMOD_ReleaseReadLock(module_lock); - - /* now examine all the slots, finding which should be readers */ - /* We should control this with options. For now we mirror out any - * removable hardware slot */ - default_card_type = options->hw_card_type; - default_type_params = g_strdup(options->hw_type_params); - - SECMOD_GetReadLock(module_lock); - for (mlp = module_list; mlp; mlp = mlp->next) { - SECMODModule *module = mlp->module; - - /* Ignore the internal module */ - if (module == NULL || module == SECMOD_GetInternalModule()) { - continue; - } - - for (i = 0; i < module->slotCount; i++) { - PK11SlotInfo *slot = module->slots[i]; - - /* only map removable HW slots */ - if (slot == NULL || !PK11_IsRemovable(slot) || !PK11_IsHW(slot)) { - continue; - } - if (strcmp("E-Gate 0 0", PK11_GetSlotName(slot)) == 0) { - /* - * coolkey <= 1.1.0-20 emulates this reader if it can't find - * any hardware readers. This causes problems, warn user of - * problems. - */ - fprintf(stderr, "known bad coolkey version - see " - "https://bugzilla.redhat.com/show_bug.cgi?id=802435\n"); - continue; - } - vreader_emul = vreader_emul_new(slot, options->hw_card_type, - options->hw_type_params); - vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul, - vreader_emul_delete); - vreader_add_reader(vreader); - - if (PK11_IsPresent(slot)) { - VCard *vcard; - vcard = vcard_emul_mirror_card(vreader); - vreader_insert_card(vreader, vcard); - vcard_emul_init_series(vreader, vcard); - vcard_free(vcard); - } - } - vcard_emul_new_event_thread(module); - } - SECMOD_ReleaseReadLock(module_lock); - nss_emul_init = PR_TRUE; - - return VCARD_EMUL_OK; -} - -/* Recreate card insert events for all readers (user should - * deduce implied reader insert. perhaps do a reader insert as well?) - */ -void -vcard_emul_replay_insertion_events(void) -{ - VReaderListEntry *current_entry; - VReaderListEntry *next_entry; - VReaderList *list = vreader_get_reader_list(); - - for (current_entry = vreader_list_get_first(list); current_entry; - current_entry = next_entry) { - VReader *vreader = vreader_list_get_reader(current_entry); - next_entry = vreader_list_get_next(current_entry); - vreader_queue_card_event(vreader); - } - - vreader_list_delete(list); -} - -/* - * Silly little functions to help parsing our argument string - */ -static int -count_tokens(const char *str, char token, char token_end) -{ - int count = 0; - - for (; *str; str++) { - if (*str == token) { - count++; - } - if (*str == token_end) { - break; - } - } - return count; -} - -static const char * -strip(const char *str) -{ - for (; *str && isspace(*str); str++) { - } - return str; -} - -static const char * -find_blank(const char *str) -{ - for (; *str && !isspace(*str); str++) { - } - return str; -} - - -/* - * We really want to use some existing argument parsing library here. That - * would give us a consistent look */ -static VCardEmulOptions options; -#define READER_STEP 4 - -/* Expects "args" to be at the beginning of a token (ie right after the ',' - * ending the previous token), and puts the next token start in "token", - * and its length in "token_length". "token" will not be nul-terminated. - * After calling the macro, "args" will be advanced to the beginning of - * the next token. - * This macro may call continue or break. - */ -#define NEXT_TOKEN(token) \ - (token) = args; \ - args = strpbrk(args, ",)"); \ - if (*args == 0) { \ - break; \ - } \ - if (*args == ')') { \ - args++; \ - continue; \ - } \ - (token##_length) = args - (token); \ - args = strip(args+1); - -VCardEmulOptions * -vcard_emul_options(const char *args) -{ - int reader_count = 0; - VCardEmulOptions *opts; - - /* Allow the future use of allocating the options structure on the fly */ - memcpy(&options, &default_options, sizeof(options)); - opts = &options; - - do { - args = strip(args); /* strip off the leading spaces */ - if (*args == ',') { - continue; - } - /* soft=(slot_name,virt_name,emul_type,emul_flags,cert_1, (no eol) - * cert_2,cert_3...) */ - if (strncmp(args, "soft=", 5) == 0) { - const char *name; - size_t name_length; - const char *vname; - size_t vname_length; - const char *type_params; - size_t type_params_length; - char type_str[100]; - VCardEmulType type; - int count, i; - VirtualReaderOptions *vreaderOpt; - - args = strip(args + 5); - if (*args != '(') { - continue; - } - args = strip(args+1); - - NEXT_TOKEN(name) - NEXT_TOKEN(vname) - NEXT_TOKEN(type_params) - type_params_length = MIN(type_params_length, sizeof(type_str)-1); - memcpy(type_str, type_params, type_params_length); - type_str[type_params_length] = '\0'; - type = vcard_emul_type_from_string(type_str); - - NEXT_TOKEN(type_params) - - if (*args == 0) { - break; - } - - if (opts->vreader_count >= reader_count) { - reader_count += READER_STEP; - opts->vreader = g_renew(VirtualReaderOptions, opts->vreader, - reader_count); - } - vreaderOpt = &opts->vreader[opts->vreader_count]; - vreaderOpt->name = g_strndup(name, name_length); - vreaderOpt->vname = g_strndup(vname, vname_length); - vreaderOpt->card_type = type; - vreaderOpt->type_params = - g_strndup(type_params, type_params_length); - count = count_tokens(args, ',', ')') + 1; - vreaderOpt->cert_count = count; - vreaderOpt->cert_name = g_new(char *, count); - for (i = 0; i < count; i++) { - const char *cert = args; - args = strpbrk(args, ",)"); - vreaderOpt->cert_name[i] = g_strndup(cert, args - cert); - args = strip(args+1); - } - if (*args == ')') { - args++; - } - opts->vreader_count++; - /* use_hw= */ - } else if (strncmp(args, "use_hw=", 7) == 0) { - args = strip(args+7); - if (*args == '0' || *args == 'N' || *args == 'n' || *args == 'F') { - opts->use_hw = PR_FALSE; - } else { - opts->use_hw = PR_TRUE; - } - args = find_blank(args); - /* hw_type= */ - } else if (strncmp(args, "hw_type=", 8) == 0) { - args = strip(args+8); - opts->hw_card_type = vcard_emul_type_from_string(args); - args = find_blank(args); - /* hw_params= */ - } else if (strncmp(args, "hw_params=", 10) == 0) { - const char *params; - args = strip(args+10); - params = args; - args = find_blank(args); - opts->hw_type_params = g_strndup(params, args-params); - /* db="/data/base/path" */ - } else if (strncmp(args, "db=", 3) == 0) { - const char *db; - args = strip(args+3); - if (*args != '"') { - continue; - } - args++; - db = args; - args = strpbrk(args, "\"\n"); - opts->nss_db = g_strndup(db, args-db); - if (*args != 0) { - args++; - } - } else { - args = find_blank(args); - } - } while (*args != 0); - - return opts; -} - -void -vcard_emul_usage(void) -{ - fprintf(stderr, -"emul args: comma separated list of the following arguments\n" -" db={nss_database} (default sql:/etc/pki/nssdb)\n" -" use_hw=[yes|no] (default yes)\n" -" hw_type={card_type_to_emulate} (default CAC)\n" -" hw_param={param_for_card} (default \"\")\n" -" soft=({slot_name},{vreader_name},{card_type_to_emulate},{params_for_card},\n" -" {cert1},{cert2},{cert3} (default none)\n" -"\n" -" {nss_database} The location of the NSS cert & key database\n" -" {card_type_to_emulate} What card interface to present to the guest\n" -" {param_for_card} Card interface specific parameters\n" -" {slot_name} NSS slot that contains the certs\n" -" {vreader_name} Virtual reader name to present to the guest\n" -" {certN} Nickname of the certificate n on the virtual card\n" -"\n" -"These parameters come as a single string separated by blanks or newlines." -"\n" -"Unless use_hw is set to no, all tokens that look like removable hardware\n" -"tokens will be presented to the guest using the emulator specified by\n" -"hw_type, and parameters of hw_param.\n" -"\n" -"If more one or more soft= parameters are specified, these readers will be\n" -"presented to the guest\n"); -} diff --git a/libcacard/vcard_emul_type.c b/libcacard/vcard_emul_type.c deleted file mode 100644 index 59a1458201..0000000000 --- a/libcacard/vcard_emul_type.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * This file contains utility functions which abstract the different card - * types. The goal is that new card types can easily be added by simply - * changing this file and vcard_emul_type.h. It is currently not a requirement - * to dynamically add new card types. - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - */ - -#include <strings.h> -#include "vcardt.h" -#include "vcard_emul_type.h" -#include "cac.h" - -VCardStatus vcard_init(VReader *vreader, VCard *vcard, - VCardEmulType type, const char *params, - unsigned char *const *cert, int cert_len[], - VCardKey *key[], int cert_count) -{ - switch (type) { - case VCARD_EMUL_NONE: - break; - case VCARD_EMUL_CAC: - return cac_card_init(vreader, vcard, params, - cert, cert_len, key, cert_count); - /* add new ones here */ - default: - break; - } - return VCARD_FAIL; -} - -VCardEmulType vcard_emul_type_select(VReader *vreader) -{ -#ifdef notdef - /* since there is only one emulator no need to call this function */ - if (cac_is_cac_card(vreader) == VCARD_DONE) { - return VCARD_EMUL_CAC; - } -#endif - /* return the default */ - return VCARD_EMUL_CAC; -} - -VCardEmulType vcard_emul_type_from_string(const char *type_string) -{ - if (strcasecmp(type_string, "CAC") == 0) { - return VCARD_EMUL_CAC; - } -#ifdef USE_PASSTHRU - if (strcasecmp(type_string, "PASSTHRU") == 0) { - return VCARD_EMUL_PASSTHRU; - } -#endif - return VCARD_EMUL_NONE; -} diff --git a/libcacard/vcard_emul_type.h b/libcacard/vcard_emul_type.h deleted file mode 100644 index 0242f40eb1..0000000000 --- a/libcacard/vcard_emul_type.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * This header file abstracts the different card types. The goal is new card - * types can easily be added by simply changing this file and - * vcard_emul_type.c. It is currently not a requirement to dynamically add new - * card types. - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - */ - -#ifndef VCARD_EMUL_TYPE_H -#define VCARD_EMUL_TYPE_H 1 -#include "vcardt.h" -#include "vreadert.h" - -/* - * types - */ -typedef enum { - VCARD_EMUL_NONE = 0, - VCARD_EMUL_CAC, - VCARD_EMUL_PASSTHRU -} VCardEmulType; - -/* functions used by the rest of the emulator */ -VCardStatus vcard_init(VReader *vreader, VCard *vcard, VCardEmulType type, - const char *params, unsigned char * const *cert, - int cert_len[], VCardKey *key[], int cert_count); -VCardEmulType vcard_emul_type_select(VReader *vreader); -VCardEmulType vcard_emul_type_from_string(const char *type_string); - -#endif diff --git a/libcacard/vcardt.c b/libcacard/vcardt.c deleted file mode 100644 index c67de2f3c1..0000000000 --- a/libcacard/vcardt.c +++ /dev/null @@ -1,40 +0,0 @@ -#include <stdlib.h> -#include <string.h> -#include <glib.h> - -#include "vcardt.h" - -#include "vcardt_internal.h" - -/* create an ATR with appropriate historical bytes */ -#define ATR_TS_DIRECT_CONVENTION 0x3b -#define ATR_TA_PRESENT 0x10 -#define ATR_TB_PRESENT 0x20 -#define ATR_TC_PRESENT 0x40 -#define ATR_TD_PRESENT 0x80 - -unsigned char *vcard_alloc_atr(const char *postfix, int *atr_len) -{ - int postfix_len; - const char prefix[] = "VCARD_"; - const char default_postfix[] = "DEFAULT"; - const int prefix_len = sizeof(prefix) - 1; - int total_len; - unsigned char *atr; - - if (postfix == NULL) { - postfix = default_postfix; - } - postfix_len = strlen(postfix); - total_len = 3 + prefix_len + postfix_len; - atr = g_malloc(total_len); - atr[0] = ATR_TS_DIRECT_CONVENTION; - atr[1] = ATR_TD_PRESENT + prefix_len + postfix_len; - atr[2] = 0x00; - memcpy(&atr[3], prefix, prefix_len); - memcpy(&atr[3 + prefix_len], postfix, postfix_len); - if (atr_len) { - *atr_len = total_len; - } - return atr; -} diff --git a/libcacard/vcardt.h b/libcacard/vcardt.h deleted file mode 100644 index 795e265304..0000000000 --- a/libcacard/vcardt.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - */ -#ifndef VCARDT_H -#define VCARDT_H 1 - -/* - * these should come from some common spice header file - */ -#include <assert.h> -#ifndef MIN -#define MIN(x, y) ((x) > (y) ? (y) : (x)) -#define MAX(x, y) ((x) > (y) ? (x) : (y)) -#endif - -typedef struct VCardStruct VCard; -typedef struct VCardAPDUStruct VCardAPDU; -typedef struct VCardResponseStruct VCardResponse; -typedef struct VCardBufferResponseStruct VCardBufferResponse; -typedef struct VCardAppletStruct VCardApplet; -typedef struct VCardAppletPrivateStruct VCardAppletPrivate; -typedef struct VCardKeyStruct VCardKey; /* opaque */ -typedef struct VCardEmulStruct VCardEmul; - -#define MAX_CHANNEL 4 - -typedef enum { - VCARD_DONE, - VCARD_NEXT, - VCARD_FAIL -} VCardStatus; - -typedef enum { - VCARD_FILE_SYSTEM, - VCARD_VM, - VCARD_DIRECT -} VCardType; - -typedef enum { - VCARD_POWER_ON, - VCARD_POWER_OFF -} VCardPower; - -typedef VCardStatus (*VCardProcessAPDU)(VCard *card, VCardAPDU *apdu, - VCardResponse **response); -typedef VCardStatus (*VCardResetApplet)(VCard *card, int channel); -typedef void (*VCardAppletPrivateFree) (VCardAppletPrivate *); -typedef void (*VCardEmulFree) (VCardEmul *); -typedef void (*VCardGetAtr) (VCard *, unsigned char *atr, int *atr_len); - -struct VCardBufferResponseStruct { - unsigned char *buffer; - int buffer_len; - unsigned char *current; - int len; -}; - -#endif diff --git a/libcacard/vcardt_internal.h b/libcacard/vcardt_internal.h deleted file mode 100644 index e5c8d2dd3e..0000000000 --- a/libcacard/vcardt_internal.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef VCARDT_INTERNAL_H -#define VCARDT_INTERNAL_H - -unsigned char *vcard_alloc_atr(const char *postfix, int *atr_len); - -#endif diff --git a/libcacard/vevent.h b/libcacard/vevent.h deleted file mode 100644 index 38c3482c35..0000000000 --- a/libcacard/vevent.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - */ -#ifndef EVENT_H -#define EVENT_H 1 -#include "eventt.h" -#include "vreadert.h" -#include "vcardt.h" - -VEvent *vevent_new(VEventType type, VReader *reader, VCard *card); -void vevent_delete(VEvent *); - -/* - * VEvent queueing services - */ -void vevent_queue_vevent(VEvent *); -void vevent_queue_init(void); - -/* - * VEvent dequeing services - */ -VEvent *vevent_wait_next_vevent(void); -VEvent *vevent_get_next_vevent(void); - - -#endif diff --git a/libcacard/vreader.c b/libcacard/vreader.c deleted file mode 100644 index 9725f46a74..0000000000 --- a/libcacard/vreader.c +++ /dev/null @@ -1,578 +0,0 @@ -/* - * emulate the reader - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - */ - -#ifdef G_LOG_DOMAIN -#undef G_LOG_DOMAIN -#endif -#define G_LOG_DOMAIN "libcacard" - -#include "glib-compat.h" - -#include <string.h> - -#include "vcard.h" -#include "vcard_emul.h" -#include "card_7816.h" -#include "vreader.h" -#include "vevent.h" -#include "cac.h" /* just for debugging defines */ - -#define LIBCACARD_LOG_DOMAIN "libcacard" - -struct VReaderStruct { - int reference_count; - VCard *card; - char *name; - vreader_id_t id; - CompatGMutex lock; - VReaderEmul *reader_private; - VReaderEmulFree reader_private_free; -}; - -/* - * Debug helpers - */ - -static const char * -apdu_ins_to_string(int ins) -{ - switch (ins) { - case VCARD7816_INS_MANAGE_CHANNEL: - return "manage channel"; - case VCARD7816_INS_EXTERNAL_AUTHENTICATE: - return "external authenticate"; - case VCARD7816_INS_GET_CHALLENGE: - return "get challenge"; - case VCARD7816_INS_INTERNAL_AUTHENTICATE: - return "internal authenticate"; - case VCARD7816_INS_ERASE_BINARY: - return "erase binary"; - case VCARD7816_INS_READ_BINARY: - return "read binary"; - case VCARD7816_INS_WRITE_BINARY: - return "write binary"; - case VCARD7816_INS_UPDATE_BINARY: - return "update binary"; - case VCARD7816_INS_READ_RECORD: - return "read record"; - case VCARD7816_INS_WRITE_RECORD: - return "write record"; - case VCARD7816_INS_UPDATE_RECORD: - return "update record"; - case VCARD7816_INS_APPEND_RECORD: - return "append record"; - case VCARD7816_INS_ENVELOPE: - return "envelope"; - case VCARD7816_INS_PUT_DATA: - return "put data"; - case VCARD7816_INS_GET_DATA: - return "get data"; - case VCARD7816_INS_SELECT_FILE: - return "select file"; - case VCARD7816_INS_VERIFY: - return "verify"; - case VCARD7816_INS_GET_RESPONSE: - return "get response"; - case CAC_GET_PROPERTIES: - return "get properties"; - case CAC_GET_ACR: - return "get acr"; - case CAC_READ_BUFFER: - return "read buffer"; - case CAC_UPDATE_BUFFER: - return "update buffer"; - case CAC_SIGN_DECRYPT: - return "sign decrypt"; - case CAC_GET_CERTIFICATE: - return "get certificate"; - } - return "unknown"; -} - -/* manage locking */ -static inline void -vreader_lock(VReader *reader) -{ - g_mutex_lock(&reader->lock); -} - -static inline void -vreader_unlock(VReader *reader) -{ - g_mutex_unlock(&reader->lock); -} - -/* - * vreader constructor - */ -VReader * -vreader_new(const char *name, VReaderEmul *private, - VReaderEmulFree private_free) -{ - VReader *reader; - - reader = g_new(VReader, 1); - g_mutex_init(&reader->lock); - reader->reference_count = 1; - reader->name = g_strdup(name); - reader->card = NULL; - reader->id = (vreader_id_t)-1; - reader->reader_private = private; - reader->reader_private_free = private_free; - return reader; -} - -/* get a reference */ -VReader* -vreader_reference(VReader *reader) -{ - if (reader == NULL) { - return NULL; - } - vreader_lock(reader); - reader->reference_count++; - vreader_unlock(reader); - return reader; -} - -/* free a reference */ -void -vreader_free(VReader *reader) -{ - if (reader == NULL) { - return; - } - vreader_lock(reader); - if (reader->reference_count-- > 1) { - vreader_unlock(reader); - return; - } - vreader_unlock(reader); - g_mutex_clear(&reader->lock); - if (reader->card) { - vcard_free(reader->card); - } - g_free(reader->name); - if (reader->reader_private_free) { - reader->reader_private_free(reader->reader_private); - } - g_free(reader); -} - -static VCard * -vreader_get_card(VReader *reader) -{ - VCard *card; - - vreader_lock(reader); - card = vcard_reference(reader->card); - vreader_unlock(reader); - return card; -} - -VReaderStatus -vreader_card_is_present(VReader *reader) -{ - VCard *card = vreader_get_card(reader); - - if (card == NULL) { - return VREADER_NO_CARD; - } - vcard_free(card); - return VREADER_OK; -} - -vreader_id_t -vreader_get_id(VReader *reader) -{ - if (reader == NULL) { - return (vreader_id_t)-1; - } - return reader->id; -} - -VReaderStatus -vreader_set_id(VReader *reader, vreader_id_t id) -{ - if (reader == NULL) { - return VREADER_NO_CARD; - } - reader->id = id; - return VREADER_OK; -} - -const char * -vreader_get_name(VReader *reader) -{ - if (reader == NULL) { - return NULL; - } - return reader->name; -} - -VReaderEmul * -vreader_get_private(VReader *reader) -{ - return reader->reader_private; -} - -static VReaderStatus -vreader_reset(VReader *reader, VCardPower power, unsigned char *atr, int *len) -{ - VCard *card = vreader_get_card(reader); - - if (card == NULL) { - return VREADER_NO_CARD; - } - /* - * clean up our state - */ - vcard_reset(card, power); - if (atr) { - vcard_get_atr(card, atr, len); - } - vcard_free(card); /* free our reference */ - return VREADER_OK; -} - -VReaderStatus -vreader_power_on(VReader *reader, unsigned char *atr, int *len) -{ - return vreader_reset(reader, VCARD_POWER_ON, atr, len); -} - -VReaderStatus -vreader_power_off(VReader *reader) -{ - return vreader_reset(reader, VCARD_POWER_OFF, NULL, 0); -} - - -VReaderStatus -vreader_xfr_bytes(VReader *reader, - unsigned char *send_buf, int send_buf_len, - unsigned char *receive_buf, int *receive_buf_len) -{ - VCardAPDU *apdu; - VCardResponse *response = NULL; - VCardStatus card_status; - unsigned short status; - VCard *card = vreader_get_card(reader); - - if (card == NULL) { - return VREADER_NO_CARD; - } - - apdu = vcard_apdu_new(send_buf, send_buf_len, &status); - if (apdu == NULL) { - response = vcard_make_response(status); - card_status = VCARD_DONE; - } else { - g_debug("%s: CLS=0x%x,INS=0x%x,P1=0x%x,P2=0x%x,Lc=%d,Le=%d %s", - __func__, apdu->a_cla, apdu->a_ins, apdu->a_p1, apdu->a_p2, - apdu->a_Lc, apdu->a_Le, apdu_ins_to_string(apdu->a_ins)); - card_status = vcard_process_apdu(card, apdu, &response); - if (response) { - g_debug("%s: status=%d sw1=0x%x sw2=0x%x len=%d (total=%d)", - __func__, response->b_status, response->b_sw1, - response->b_sw2, response->b_len, response->b_total_len); - } - } - assert(card_status == VCARD_DONE && response); - int size = MIN(*receive_buf_len, response->b_total_len); - memcpy(receive_buf, response->b_data, size); - *receive_buf_len = size; - vcard_response_delete(response); - vcard_apdu_delete(apdu); - vcard_free(card); /* free our reference */ - return VREADER_OK; -} - -struct VReaderListStruct { - VReaderListEntry *head; - VReaderListEntry *tail; -}; - -struct VReaderListEntryStruct { - VReaderListEntry *next; - VReaderListEntry *prev; - VReader *reader; -}; - - -static VReaderListEntry * -vreader_list_entry_new(VReader *reader) -{ - VReaderListEntry *new_reader_list_entry; - - new_reader_list_entry = g_new0(VReaderListEntry, 1); - new_reader_list_entry->reader = vreader_reference(reader); - return new_reader_list_entry; -} - -static void -vreader_list_entry_delete(VReaderListEntry *entry) -{ - if (entry == NULL) { - return; - } - vreader_free(entry->reader); - g_free(entry); -} - - -static VReaderList * -vreader_list_new(void) -{ - VReaderList *new_reader_list; - - new_reader_list = g_new0(VReaderList, 1); - return new_reader_list; -} - -void -vreader_list_delete(VReaderList *list) -{ - VReaderListEntry *current_entry; - VReaderListEntry *next_entry; - for (current_entry = vreader_list_get_first(list); current_entry; - current_entry = next_entry) { - next_entry = vreader_list_get_next(current_entry); - vreader_list_entry_delete(current_entry); - } - g_free(list); -} - - -VReaderListEntry * -vreader_list_get_first(VReaderList *list) -{ - return list ? list->head : NULL; -} - -VReaderListEntry * -vreader_list_get_next(VReaderListEntry *current) -{ - return current ? current->next : NULL; -} - -VReader * -vreader_list_get_reader(VReaderListEntry *entry) -{ - return entry ? vreader_reference(entry->reader) : NULL; -} - -static void -vreader_queue(VReaderList *list, VReaderListEntry *entry) -{ - if (entry == NULL) { - return; - } - entry->next = NULL; - entry->prev = list->tail; - if (list->head) { - list->tail->next = entry; - } else { - list->head = entry; - } - list->tail = entry; -} - -static void -vreader_dequeue(VReaderList *list, VReaderListEntry *entry) -{ - if (entry == NULL) { - return; - } - if (entry->next == NULL) { - list->tail = entry->prev; - } else if (entry->prev == NULL) { - list->head = entry->next; - } else { - entry->prev->next = entry->next; - entry->next->prev = entry->prev; - } - if ((list->tail == NULL) || (list->head == NULL)) { - list->head = list->tail = NULL; - } - entry->next = entry->prev = NULL; -} - -static VReaderList *vreader_list; -static CompatGMutex vreader_list_mutex; - -static void -vreader_list_init(void) -{ - vreader_list = vreader_list_new(); -} - -static void -vreader_list_lock(void) -{ - g_mutex_lock(&vreader_list_mutex); -} - -static void -vreader_list_unlock(void) -{ - g_mutex_unlock(&vreader_list_mutex); -} - -static VReaderList * -vreader_copy_list(VReaderList *list) -{ - VReaderList *new_list; - VReaderListEntry *current_entry; - - new_list = vreader_list_new(); - if (new_list == NULL) { - return NULL; - } - for (current_entry = vreader_list_get_first(list); current_entry; - current_entry = vreader_list_get_next(current_entry)) { - VReader *reader = vreader_list_get_reader(current_entry); - VReaderListEntry *new_entry = vreader_list_entry_new(reader); - - vreader_free(reader); - vreader_queue(new_list, new_entry); - } - return new_list; -} - -VReaderList * -vreader_get_reader_list(void) -{ - VReaderList *new_reader_list; - - vreader_list_lock(); - new_reader_list = vreader_copy_list(vreader_list); - vreader_list_unlock(); - return new_reader_list; -} - -VReader * -vreader_get_reader_by_id(vreader_id_t id) -{ - VReader *reader = NULL; - VReaderListEntry *current_entry; - - if (id == (vreader_id_t) -1) { - return NULL; - } - - vreader_list_lock(); - for (current_entry = vreader_list_get_first(vreader_list); current_entry; - current_entry = vreader_list_get_next(current_entry)) { - VReader *creader = vreader_list_get_reader(current_entry); - if (creader->id == id) { - reader = creader; - break; - } - vreader_free(creader); - } - vreader_list_unlock(); - return reader; -} - -VReader * -vreader_get_reader_by_name(const char *name) -{ - VReader *reader = NULL; - VReaderListEntry *current_entry; - - vreader_list_lock(); - for (current_entry = vreader_list_get_first(vreader_list); current_entry; - current_entry = vreader_list_get_next(current_entry)) { - VReader *creader = vreader_list_get_reader(current_entry); - if (strcmp(creader->name, name) == 0) { - reader = creader; - break; - } - vreader_free(creader); - } - vreader_list_unlock(); - return reader; -} - -/* called from card_emul to initialize the readers */ -VReaderStatus -vreader_add_reader(VReader *reader) -{ - VReaderListEntry *reader_entry; - - reader_entry = vreader_list_entry_new(reader); - if (reader_entry == NULL) { - return VREADER_OUT_OF_MEMORY; - } - vreader_list_lock(); - vreader_queue(vreader_list, reader_entry); - vreader_list_unlock(); - vevent_queue_vevent(vevent_new(VEVENT_READER_INSERT, reader, NULL)); - return VREADER_OK; -} - - -VReaderStatus -vreader_remove_reader(VReader *reader) -{ - VReaderListEntry *current_entry; - - vreader_list_lock(); - for (current_entry = vreader_list_get_first(vreader_list); current_entry; - current_entry = vreader_list_get_next(current_entry)) { - if (current_entry->reader == reader) { - break; - } - } - vreader_dequeue(vreader_list, current_entry); - vreader_list_unlock(); - vreader_list_entry_delete(current_entry); - vevent_queue_vevent(vevent_new(VEVENT_READER_REMOVE, reader, NULL)); - return VREADER_OK; -} - -/* - * Generate VEVENT_CARD_INSERT or VEVENT_CARD_REMOVE based on vreader - * state. Separated from vreader_insert_card to allow replaying events - * for a given state. - */ -void -vreader_queue_card_event(VReader *reader) -{ - vevent_queue_vevent(vevent_new( - reader->card ? VEVENT_CARD_INSERT : VEVENT_CARD_REMOVE, reader, - reader->card)); -} - -/* - * insert/remove a new card. for removal, card == NULL - */ -VReaderStatus -vreader_insert_card(VReader *reader, VCard *card) -{ - vreader_lock(reader); - if (reader->card) { - /* decrement reference count */ - vcard_free(reader->card); - reader->card = NULL; - } - reader->card = vcard_reference(card); - vreader_unlock(reader); - vreader_queue_card_event(reader); - return VREADER_OK; -} - -/* - * initialize all the static reader structures - */ -void -vreader_init(void) -{ - vreader_list_init(); -} - diff --git a/libcacard/vreader.h b/libcacard/vreader.h deleted file mode 100644 index ec2042136c..0000000000 --- a/libcacard/vreader.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - */ - -#ifndef VREADER_H -#define VREADER_H 1 - -#include "eventt.h" -#include "vreadert.h" -#include "vcardt.h" - -/* - * calls for reader front end - */ -VReaderStatus vreader_power_on(VReader *reader, unsigned char *atr, int *len); -VReaderStatus vreader_power_off(VReader *reader); -VReaderStatus vreader_xfr_bytes(VReader *reader, unsigned char *send_buf, - int send_buf_len, unsigned char *receive_buf, - int *receive_buf_len); - -/* constructor */ -VReader *vreader_new(const char *readerName, VReaderEmul *emul_private, - VReaderEmulFree private_free); -/* get a new reference to a reader */ -VReader *vreader_reference(VReader *reader); -/* "destructor" (readers are reference counted) */ -void vreader_free(VReader *reader); - -/* accessors */ -VReaderEmul *vreader_get_private(VReader *); -VReaderStatus vreader_card_is_present(VReader *reader); -void vreader_queue_card_event(VReader *reader); -const char *vreader_get_name(VReader *reader); -vreader_id_t vreader_get_id(VReader *reader); -VReaderStatus vreader_set_id(VReader *reader, vreader_id_t id); - -/* list operations */ -VReaderList *vreader_get_reader_list(void); -void vreader_list_delete(VReaderList *list); -VReader *vreader_list_get_reader(VReaderListEntry *entry); -VReaderListEntry *vreader_list_get_first(VReaderList *list); -VReaderListEntry *vreader_list_get_next(VReaderListEntry *list); -VReader *vreader_get_reader_by_id(vreader_id_t id); -VReader *vreader_get_reader_by_name(const char *name); - -/* - * list tools for vcard_emul - */ -void vreader_init(void); -VReaderStatus vreader_add_reader(VReader *reader); -VReaderStatus vreader_remove_reader(VReader *reader); -VReaderStatus vreader_insert_card(VReader *reader, VCard *card); - -#endif diff --git a/libcacard/vreadert.h b/libcacard/vreadert.h deleted file mode 100644 index f97e0a79ec..0000000000 --- a/libcacard/vreadert.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - */ - -#ifndef VREADERT_H -#define VREADERT_H 1 - -typedef enum { - VREADER_OK = 0, - VREADER_NO_CARD, - VREADER_OUT_OF_MEMORY -} VReaderStatus; - -typedef unsigned int vreader_id_t; -typedef struct VReaderStruct VReader; -typedef struct VReaderListStruct VReaderList; -typedef struct VReaderListEntryStruct VReaderListEntry; - -typedef struct VReaderEmulStruct VReaderEmul; -typedef void (*VReaderEmulFree)(VReaderEmul *); - -#endif - diff --git a/libcacard/vscard_common.h b/libcacard/vscard_common.h deleted file mode 100644 index 08f68e4dd2..0000000000 --- a/libcacard/vscard_common.h +++ /dev/null @@ -1,178 +0,0 @@ -/* Virtual Smart Card protocol definition - * - * This protocol is between a host using virtual smart card readers, - * and a client providing the smart cards, perhaps by emulating them or by - * access to real cards. - * - * Definitions for this protocol: - * Host - user of the card - * Client - owner of the card - * - * The current implementation passes the raw APDU's from 7816 and additionally - * contains messages to setup and teardown readers, handle insertion and - * removal of cards, negotiate the protocol via capabilities and provide - * for error responses. - * - * Copyright (c) 2011 Red Hat. - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - */ - -#ifndef VSCARD_COMMON_H -#define VSCARD_COMMON_H - -#include <stdint.h> - -#define VERSION_MAJOR_BITS 11 -#define VERSION_MIDDLE_BITS 11 -#define VERSION_MINOR_BITS 10 - -#define MAKE_VERSION(major, middle, minor) \ - ((major << (VERSION_MINOR_BITS + VERSION_MIDDLE_BITS)) \ - | (middle << VERSION_MINOR_BITS) \ - | (minor)) - -/* - * IMPORTANT NOTE on VERSION - * - * The version below MUST be changed whenever a change in this file is made. - * - * The last digit, the minor, is for bug fix changes only. - * - * The middle digit is for backward / forward compatible changes, updates - * to the existing messages, addition of fields. - * - * The major digit is for a breaking change of protocol, presumably - * something that cannot be accommodated with the existing protocol. - */ - -#define VSCARD_VERSION MAKE_VERSION(0, 0, 2) - -typedef enum VSCMsgType { - VSC_Init = 1, - VSC_Error, - VSC_ReaderAdd, - VSC_ReaderRemove, - VSC_ATR, - VSC_CardRemove, - VSC_APDU, - VSC_Flush, - VSC_FlushComplete -} VSCMsgType; - -typedef enum VSCErrorCode { - VSC_SUCCESS = 0, - VSC_GENERAL_ERROR = 1, - VSC_CANNOT_ADD_MORE_READERS, - VSC_CARD_ALREAY_INSERTED, -} VSCErrorCode; - -#define VSCARD_UNDEFINED_READER_ID 0xffffffff -#define VSCARD_MINIMAL_READER_ID 0 - -#define VSCARD_MAGIC (*(uint32_t *)"VSCD") - -/* - * Header - * Each message starts with the header. - * type - message type - * reader_id - used by messages that are reader specific - * length - length of payload (not including header, i.e. zero for - * messages containing empty payloads) - */ -typedef struct VSCMsgHeader { - uint32_t type; - uint32_t reader_id; - uint32_t length; - uint8_t data[0]; -} VSCMsgHeader; - -/* - * VSCMsgInit Client <-> Host - * Client sends it on connection, with its own capabilities. - * Host replies with VSCMsgInit filling in its capabilities. - * - * It is not meant to be used for negotiation, i.e. sending more then - * once from any side, but could be used for that in the future. - */ -typedef struct VSCMsgInit { - uint32_t magic; - uint32_t version; - uint32_t capabilities[1]; /* receiver must check length, - array may grow in the future*/ -} VSCMsgInit; - -/* - * VSCMsgError Client <-> Host - * This message is a response to any of: - * Reader Add - * Reader Remove - * Card Remove - * If the operation was successful then VSC_SUCCESS - * is returned, other wise a specific error code. - */ -typedef struct VSCMsgError { - uint32_t code; -} VSCMsgError; - -/* - * VSCMsgReaderAdd Client -> Host - * Host replies with allocated reader id in VSCMsgError with code==SUCCESS. - * - * name - name of the reader on client side, UTF-8 encoded. Only used - * for client presentation (may be translated to the device presented to the - * guest), protocol wise only reader_id is important. - */ -typedef struct VSCMsgReaderAdd { - uint8_t name[0]; -} VSCMsgReaderAdd; - -/* - * VSCMsgReaderRemove Client -> Host - * The client's reader has been removed. - */ -typedef struct VSCMsgReaderRemove { -} VSCMsgReaderRemove; - -/* - * VSCMsgATR Client -> Host - * Answer to reset. Sent for card insertion or card reset. The reset/insertion - * happens on the client side, they do not require any action from the host. - */ -typedef struct VSCMsgATR { - uint8_t atr[0]; -} VSCMsgATR; - -/* - * VSCMsgCardRemove Client -> Host - * The client card has been removed. - */ -typedef struct VSCMsgCardRemove { -} VSCMsgCardRemove; - -/* - * VSCMsgAPDU Client <-> Host - * Main reason of existence. Transfer a single APDU in either direction. - */ -typedef struct VSCMsgAPDU { - uint8_t data[0]; -} VSCMsgAPDU; - -/* - * VSCMsgFlush Host -> Client - * Request client to send a FlushComplete message when it is done - * servicing all outstanding APDUs - */ -typedef struct VSCMsgFlush { -} VSCMsgFlush; - -/* - * VSCMsgFlush Client -> Host - * Client response to Flush after all APDUs have been processed and - * responses sent. - */ -typedef struct VSCMsgFlushComplete { -} VSCMsgFlushComplete; - -#endif /* VSCARD_COMMON_H */ diff --git a/libcacard/vscclient.c b/libcacard/vscclient.c deleted file mode 100644 index 0652684437..0000000000 --- a/libcacard/vscclient.c +++ /dev/null @@ -1,785 +0,0 @@ -/* - * Tester for VSCARD protocol, client side. - * - * Can be used with ccid-card-passthru. - * - * Copyright (c) 2011 Red Hat. - * Written by Alon Levy. - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#ifndef _WIN32 -#include <sys/socket.h> -#include <netinet/in.h> -#include <netdb.h> -#include <unistd.h> -#define closesocket(x) close(x) -#else -#include <getopt.h> -#endif - -#include "glib-compat.h" - -#include "vscard_common.h" - -#include "vreader.h" -#include "vcard_emul.h" -#include "vevent.h" - -static int verbose; - -static void -print_byte_array( - uint8_t *arrBytes, - unsigned int nSize -) { - int i; - for (i = 0; i < nSize; i++) { - printf("%02X ", arrBytes[i]); - } - printf("\n"); -} - -static void -print_usage(void) { - printf("vscclient [-c <certname> .. -e <emul_args> -d <level>%s] " - "<host> <port>\n", -#ifdef USE_PASSTHRU - " -p"); - printf(" -p use passthrough mode\n"); -#else - ""); -#endif - vcard_emul_usage(); -} - -static GIOChannel *channel_socket; -static GByteArray *socket_to_send; -static CompatGMutex socket_to_send_lock; -static guint socket_tag; - -static void -update_socket_watch(void); - -static gboolean -do_socket_send(GIOChannel *source, - GIOCondition condition, - gpointer data) -{ - gsize bw; - GError *err = NULL; - - g_return_val_if_fail(socket_to_send->len != 0, FALSE); - g_return_val_if_fail(condition & G_IO_OUT, FALSE); - - g_io_channel_write_chars(channel_socket, - (gchar *)socket_to_send->data, socket_to_send->len, &bw, &err); - if (err != NULL) { - g_error("Error while sending socket %s", err->message); - return FALSE; - } - g_byte_array_remove_range(socket_to_send, 0, bw); - - if (socket_to_send->len == 0) { - update_socket_watch(); - return FALSE; - } - return TRUE; -} - -static gboolean -socket_prepare_sending(gpointer user_data) -{ - update_socket_watch(); - - return FALSE; -} - -static int -send_msg( - VSCMsgType type, - uint32_t reader_id, - const void *msg, - unsigned int length -) { - VSCMsgHeader mhHeader; - - g_mutex_lock(&socket_to_send_lock); - - if (verbose > 10) { - printf("sending type=%d id=%u, len =%u (0x%x)\n", - type, reader_id, length, length); - } - - mhHeader.type = htonl(type); - mhHeader.reader_id = 0; - mhHeader.length = htonl(length); - g_byte_array_append(socket_to_send, (guint8 *)&mhHeader, sizeof(mhHeader)); - g_byte_array_append(socket_to_send, (guint8 *)msg, length); - g_idle_add(socket_prepare_sending, NULL); - - g_mutex_unlock(&socket_to_send_lock); - - return 0; -} - -static VReader *pending_reader; -static CompatGMutex pending_reader_lock; -static CompatGCond pending_reader_condition; - -#define MAX_ATR_LEN 40 -static gpointer -event_thread(gpointer arg) -{ - unsigned char atr[MAX_ATR_LEN]; - int atr_len; - VEvent *event; - unsigned int reader_id; - - - while (1) { - const char *reader_name; - - event = vevent_wait_next_vevent(); - if (event == NULL) { - break; - } - reader_id = vreader_get_id(event->reader); - if (reader_id == VSCARD_UNDEFINED_READER_ID && - event->type != VEVENT_READER_INSERT) { - /* ignore events from readers qemu has rejected */ - /* if qemu is still deciding on this reader, wait to see if need to - * forward this event */ - g_mutex_lock(&pending_reader_lock); - if (!pending_reader || (pending_reader != event->reader)) { - /* wasn't for a pending reader, this reader has already been - * rejected by qemu */ - g_mutex_unlock(&pending_reader_lock); - vevent_delete(event); - continue; - } - /* this reader hasn't been told its status from qemu yet, wait for - * that status */ - while (pending_reader != NULL) { - g_cond_wait(&pending_reader_condition, &pending_reader_lock); - } - g_mutex_unlock(&pending_reader_lock); - /* now recheck the id */ - reader_id = vreader_get_id(event->reader); - if (reader_id == VSCARD_UNDEFINED_READER_ID) { - /* this reader was rejected */ - vevent_delete(event); - continue; - } - /* reader was accepted, now forward the event */ - } - switch (event->type) { - case VEVENT_READER_INSERT: - /* tell qemu to insert a new CCID reader */ - /* wait until qemu has responded to our first reader insert - * before we send a second. That way we won't confuse the responses - * */ - g_mutex_lock(&pending_reader_lock); - while (pending_reader != NULL) { - g_cond_wait(&pending_reader_condition, &pending_reader_lock); - } - pending_reader = vreader_reference(event->reader); - g_mutex_unlock(&pending_reader_lock); - reader_name = vreader_get_name(event->reader); - if (verbose > 10) { - printf(" READER INSERT: %s\n", reader_name); - } - send_msg(VSC_ReaderAdd, - reader_id, /* currerntly VSCARD_UNDEFINED_READER_ID */ - NULL, 0 /* TODO reader_name, strlen(reader_name) */); - break; - case VEVENT_READER_REMOVE: - /* future, tell qemu that an old CCID reader has been removed */ - if (verbose > 10) { - printf(" READER REMOVE: %u\n", reader_id); - } - send_msg(VSC_ReaderRemove, reader_id, NULL, 0); - break; - case VEVENT_CARD_INSERT: - /* get the ATR (intended as a response to a power on from the - * reader */ - atr_len = MAX_ATR_LEN; - vreader_power_on(event->reader, atr, &atr_len); - /* ATR call functions as a Card Insert event */ - if (verbose > 10) { - printf(" CARD INSERT %u: ", reader_id); - print_byte_array(atr, atr_len); - } - send_msg(VSC_ATR, reader_id, atr, atr_len); - break; - case VEVENT_CARD_REMOVE: - /* Card removed */ - if (verbose > 10) { - printf(" CARD REMOVE %u:\n", reader_id); - } - send_msg(VSC_CardRemove, reader_id, NULL, 0); - break; - default: - break; - } - vevent_delete(event); - } - return NULL; -} - - -static unsigned int -get_id_from_string(char *string, unsigned int default_id) -{ - unsigned int id = atoi(string); - - /* don't accidentally swith to zero because no numbers have been supplied */ - if ((id == 0) && *string != '0') { - return 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; - - 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 */ - g_thread_new("vsc/event", event_thread, NULL); - return 0; -} - - -enum { - STATE_HEADER, - STATE_MESSAGE, -}; - -#define APDUBufSize 270 - -static gboolean -do_socket_read(GIOChannel *source, - GIOCondition condition, - gpointer data) -{ - int rv; - int dwSendLength; - int dwRecvLength; - uint8_t pbRecvBuffer[APDUBufSize]; - static uint8_t pbSendBuffer[APDUBufSize]; - VReaderStatus reader_status; - VReader *reader = NULL; - static VSCMsgHeader mhHeader; - VSCMsgError *error_msg; - GError *err = NULL; - - static gchar *buf; - static gsize br, to_read; - static int state = STATE_HEADER; - - if (state == STATE_HEADER && to_read == 0) { - buf = (gchar *)&mhHeader; - to_read = sizeof(mhHeader); - } - - if (to_read > 0) { - g_io_channel_read_chars(source, (gchar *)buf, to_read, &br, &err); - if (err != NULL) { - g_error("error while reading: %s", err->message); - } - buf += br; - to_read -= br; - if (to_read != 0) { - return TRUE; - } - } - - if (state == STATE_HEADER) { - 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: - buf = (gchar *)pbSendBuffer; - to_read = mhHeader.length; - state = STATE_MESSAGE; - return TRUE; - default: - fprintf(stderr, "Unexpected message of type 0x%X\n", mhHeader.type); - return FALSE; - } - } - - if (state == STATE_MESSAGE) { - switch (mhHeader.type) { - case VSC_APDU: - 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) { - g_mutex_lock(&pending_reader_lock); - if (pending_reader) { - vreader_set_id(pending_reader, mhHeader.reader_id); - vreader_free(pending_reader); - pending_reader = NULL; - g_cond_signal(&pending_reader_condition); - } - g_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 */ - g_mutex_lock(&pending_reader_lock); - if (pending_reader) { - pending_reader = NULL; - /* make sure the event loop doesn't hang */ - g_cond_signal(&pending_reader_condition); - } - g_mutex_unlock(&pending_reader_lock); - } - break; - case VSC_Init: - if (on_host_init(&mhHeader, (VSCMsgInit *)pbSendBuffer) < 0) { - return FALSE; - } - break; - default: - g_assert_not_reached(); - return FALSE; - } - - state = STATE_HEADER; - } - - - return TRUE; -} - -static gboolean -do_socket(GIOChannel *source, - GIOCondition condition, - gpointer data) -{ - /* not sure if two watches work well with a single win32 sources */ - if (condition & G_IO_OUT) { - if (!do_socket_send(source, condition, data)) { - return FALSE; - } - } - - if (condition & G_IO_IN) { - if (!do_socket_read(source, condition, data)) { - return FALSE; - } - } - - return TRUE; -} - -static void -update_socket_watch(void) -{ - gboolean out = socket_to_send->len > 0; - - if (socket_tag != 0) { - g_source_remove(socket_tag); - } - - socket_tag = g_io_add_watch(channel_socket, - G_IO_IN | (out ? G_IO_OUT : 0), do_socket, NULL); -} - -static gboolean -do_command(GIOChannel *source, - GIOCondition condition, - gpointer data) -{ - char *string; - VCardEmulError error; - static unsigned int default_reader_id; - unsigned int reader_id; - VReader *reader = NULL; - GError *err = NULL; - - g_assert(condition & G_IO_IN); - - reader_id = default_reader_id; - g_io_channel_read_line(source, &string, NULL, NULL, &err); - if (err != NULL) { - g_error("Error while reading command: %s", err->message); - } - - if (string != NULL) { - if (strncmp(string, "exit", 4) == 0) { - /* remove all the readers */ - VReaderList *list = vreader_get_reader_list(); - VReaderListEntry *reader_entry; - printf("Active Readers:\n"); - for (reader_entry = vreader_list_get_first(list); reader_entry; - reader_entry = vreader_list_get_next(reader_entry)) { - VReader *reader = vreader_list_get_reader(reader_entry); - vreader_id_t reader_id; - reader_id = vreader_get_id(reader); - if (reader_id == -1) { - continue; - } - /* be nice and signal card removal first (qemu probably should - * do this itself) */ - if (vreader_card_is_present(reader) == VREADER_OK) { - send_msg(VSC_CardRemove, reader_id, NULL, 0); - } - send_msg(VSC_ReaderRemove, reader_id, NULL, 0); - } - exit(0); - } else if (strncmp(string, "insert", 6) == 0) { - if (string[6] == ' ') { - reader_id = get_id_from_string(&string[7], reader_id); - } - reader = vreader_get_reader_by_id(reader_id); - if (reader != NULL) { - error = vcard_emul_force_card_insert(reader); - printf("insert %s, returned %d\n", - vreader_get_name(reader), error); - } else { - printf("no reader by id %u found\n", reader_id); - } - } else if (strncmp(string, "remove", 6) == 0) { - if (string[6] == ' ') { - reader_id = get_id_from_string(&string[7], reader_id); - } - reader = vreader_get_reader_by_id(reader_id); - if (reader != NULL) { - error = vcard_emul_force_card_remove(reader); - printf("remove %s, returned %d\n", - vreader_get_name(reader), error); - } else { - printf("no reader by id %u found\n", reader_id); - } - } else if (strncmp(string, "select", 6) == 0) { - if (string[6] == ' ') { - reader_id = get_id_from_string(&string[7], - VSCARD_UNDEFINED_READER_ID); - } - if (reader_id != VSCARD_UNDEFINED_READER_ID) { - reader = vreader_get_reader_by_id(reader_id); - } - if (reader) { - printf("Selecting reader %u, %s\n", reader_id, - vreader_get_name(reader)); - default_reader_id = reader_id; - } else { - printf("Reader with id %u not found\n", reader_id); - } - } else if (strncmp(string, "debug", 5) == 0) { - if (string[5] == ' ') { - verbose = get_id_from_string(&string[6], 0); - } - printf("debug level = %d\n", verbose); - } else if (strncmp(string, "list", 4) == 0) { - VReaderList *list = vreader_get_reader_list(); - VReaderListEntry *reader_entry; - printf("Active Readers:\n"); - for (reader_entry = vreader_list_get_first(list); reader_entry; - reader_entry = vreader_list_get_next(reader_entry)) { - VReader *reader = vreader_list_get_reader(reader_entry); - vreader_id_t reader_id; - reader_id = vreader_get_id(reader); - if (reader_id == -1) { - continue; - } - printf("%3u %s %s\n", reader_id, - vreader_card_is_present(reader) == VREADER_OK ? - "CARD_PRESENT" : " ", - vreader_get_name(reader)); - } - printf("Inactive Readers:\n"); - for (reader_entry = vreader_list_get_first(list); reader_entry; - reader_entry = vreader_list_get_next(reader_entry)) { - VReader *reader = vreader_list_get_reader(reader_entry); - vreader_id_t reader_id; - reader_id = vreader_get_id(reader); - if (reader_id != -1) { - continue; - } - - printf("INA %s %s\n", - vreader_card_is_present(reader) == VREADER_OK ? - "CARD_PRESENT" : " ", - vreader_get_name(reader)); - } - vreader_list_delete(list); - } else if (*string != 0) { - printf("valid commands:\n"); - printf("insert [reader_id]\n"); - printf("remove [reader_id]\n"); - printf("select reader_id\n"); - printf("list\n"); - printf("debug [level]\n"); - printf("exit\n"); - } - } - vreader_free(reader); - printf("> "); - fflush(stdout); - - return TRUE; -} - - -/* just for ease of parsing command line arguments. */ -#define MAX_CERTS 100 - -static int -connect_to_qemu( - const char *host, - const char *port -) { - struct addrinfo hints; - struct addrinfo *server = NULL; - int ret, sock; - - sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock < 0) { - /* Error */ - fprintf(stderr, "Error opening socket!\n"); - return -1; - } - - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = 0; - hints.ai_protocol = 0; /* Any protocol */ - - ret = getaddrinfo(host, port, &hints, &server); - - if (ret != 0) { - /* Error */ - fprintf(stderr, "getaddrinfo failed\n"); - goto cleanup_socket; - } - - if (connect(sock, server->ai_addr, server->ai_addrlen) < 0) { - /* Error */ - fprintf(stderr, "Could not connect\n"); - goto cleanup_socket; - } - if (verbose) { - printf("Connected (sizeof Header=%zd)!\n", sizeof(VSCMsgHeader)); - } - - freeaddrinfo(server); - return sock; - -cleanup_socket: - if (server) { - freeaddrinfo(server); - } - closesocket(sock); - return -1; -} - -int -main( - int argc, - char *argv[] -) { - GMainLoop *loop; - GIOChannel *channel_stdin; - char *qemu_host; - char *qemu_port; - - VCardEmulOptions *command_line_options = NULL; - - char *cert_names[MAX_CERTS]; - char *emul_args = NULL; - int cert_count = 0; - int c, sock; - -#ifdef _WIN32 - WSADATA Data; - - if (WSAStartup(MAKEWORD(2, 2), &Data) != 0) { - c = WSAGetLastError(); - fprintf(stderr, "WSAStartup: %d\n", c); - return 1; - } -#endif -#if !GLIB_CHECK_VERSION(2, 31, 0) - if (!g_thread_supported()) { - g_thread_init(NULL); - } -#endif - - 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); - } - - socket_to_send = g_byte_array_new(); - vcard_emul_init(command_line_options); - loop = g_main_loop_new(NULL, TRUE); - - printf("> "); - fflush(stdout); - -#ifdef _WIN32 - channel_stdin = g_io_channel_win32_new_fd(STDIN_FILENO); -#else - channel_stdin = g_io_channel_unix_new(STDIN_FILENO); -#endif - g_io_add_watch(channel_stdin, G_IO_IN, do_command, NULL); -#ifdef _WIN32 - channel_socket = g_io_channel_win32_new_socket(sock); -#else - channel_socket = g_io_channel_unix_new(sock); -#endif - g_io_channel_set_encoding(channel_socket, NULL, NULL); - /* we buffer ourself for thread safety reasons */ - g_io_channel_set_buffered(channel_socket, FALSE); - - /* 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, 0, &init, sizeof(init)); - - g_main_loop_run(loop); - g_main_loop_unref(loop); - - g_io_channel_unref(channel_stdin); - g_io_channel_unref(channel_socket); - g_byte_array_free(socket_to_send, TRUE); - - closesocket(sock); - return 0; -} @@ -139,6 +139,9 @@ Section "${PRODUCT} (required)" ; Write the uninstall keys for Windows WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "QEMU" +!ifdef DISPLAYVERSION + WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${DISPLAYVERSION}" +!endif WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" '"${UNINST_EXE}"' WriteRegDWORD HKLM "${UNINST_KEY}" "NoModify" 1 WriteRegDWORD HKLM "${UNINST_KEY}" "NoRepair" 1 diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c index f946db8dc0..00a77b4a5f 100644 --- a/slirp/tcp_input.c +++ b/slirp/tcp_input.c @@ -584,7 +584,13 @@ findso: goto cont_input; } - if((tcp_fconnect(so) == -1) && (errno != EINPROGRESS) && (errno != EWOULDBLOCK)) { + if ((tcp_fconnect(so) == -1) && +#if defined(_WIN32) + socket_error() != WSAEWOULDBLOCK +#else + (errno != EINPROGRESS) && (errno != EWOULDBLOCK) +#endif + ) { u_char code=ICMP_UNREACH_NET; DEBUG_MISC((dfd, " tcp fconnect errno = %d-%s\n", errno,strerror(errno))); diff --git a/target-arm/kvm.c b/target-arm/kvm.c index b278542085..6aadcd88f7 100644 --- a/target-arm/kvm.c +++ b/target-arm/kvm.c @@ -585,18 +585,23 @@ void kvm_arch_init_irq_routing(KVMState *s) int kvm_arch_irqchip_create(KVMState *s) { - int ret; - /* If we can create the VGIC using the newer device control API, we * let the device do this when it initializes itself, otherwise we * fall back to the old API */ + return kvm_check_extension(s, KVM_CAP_DEVICE_CTRL); +} - ret = kvm_create_device(s, KVM_DEV_TYPE_ARM_VGIC_V2, true); - if (ret == 0) { - return 1; +int kvm_arm_vgic_probe(void) +{ + if (kvm_create_device(kvm_state, + KVM_DEV_TYPE_ARM_VGIC_V3, true) == 0) { + return 3; + } else if (kvm_create_device(kvm_state, + KVM_DEV_TYPE_ARM_VGIC_V2, true) == 0) { + return 2; + } else { + return 0; } - - return 0; } int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, diff --git a/target-arm/kvm_arm.h b/target-arm/kvm_arm.h index b3e0ab7e7c..b516041779 100644 --- a/target-arm/kvm_arm.h +++ b/target-arm/kvm_arm.h @@ -189,6 +189,15 @@ int kvm_arm_sync_mpstate_to_kvm(ARMCPU *cpu); */ int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu); +int kvm_arm_vgic_probe(void); + +#else + +static inline int kvm_arm_vgic_probe(void) +{ + return 0; +} + #endif static inline const char *gic_class_name(void) @@ -196,4 +205,14 @@ static inline const char *gic_class_name(void) return kvm_irqchip_in_kernel() ? "kvm-arm-gic" : "arm_gic"; } +/** + * gicv3_class_name + * + * Return name of GICv3 class to use depending on whether KVM acceleration is + * in use. May throw an error if the chosen implementation is not available. + * + * Returns: class name to use + */ +const char *gicv3_class_name(void); + #endif diff --git a/target-arm/machine.c b/target-arm/machine.c index 32adfe792e..36a0d159cc 100644 --- a/target-arm/machine.c +++ b/target-arm/machine.c @@ -1,5 +1,6 @@ #include "hw/hw.h" #include "hw/boards.h" +#include "qemu/error-report.h" #include "sysemu/kvm.h" #include "kvm_arm.h" #include "internals.h" @@ -328,3 +329,20 @@ const VMStateDescription vmstate_arm_cpu = { NULL } }; + +const char *gicv3_class_name(void) +{ + if (kvm_irqchip_in_kernel()) { +#ifdef TARGET_AARCH64 + return "kvm-arm-gicv3"; +#else + error_report("KVM GICv3 acceleration is not supported on this " + "platform\n"); +#endif + } else { + /* TODO: Software emulation is not implemented yet */ + error_report("KVM is currently required for GICv3 emulation\n"); + } + + exit(1); +} @@ -104,6 +104,15 @@ #define GDK_KEY_Pause GDK_Pause #endif +/* Some older mingw versions lack this constant or have + * it conditionally defined */ +#ifdef _WIN32 +# ifndef MAPVK_VK_TO_VSC +# define MAPVK_VK_TO_VSC 0 +# endif +#endif + + #define HOTKEY_MODIFIERS (GDK_CONTROL_MASK | GDK_MOD1_MASK) static const int modifier_keycode[] = { diff --git a/util/oslib-win32.c b/util/oslib-win32.c index 730a6707a0..08f5a9cda2 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -95,6 +95,7 @@ void qemu_anon_ram_free(void *ptr, size_t size) } } +#ifndef CONFIG_LOCALTIME_R /* FIXME: add proper locking */ struct tm *gmtime_r(const time_t *timep, struct tm *result) { @@ -118,6 +119,7 @@ struct tm *localtime_r(const time_t *timep, struct tm *result) } return p; } +#endif /* CONFIG_LOCALTIME_R */ void qemu_set_block(int fd) { diff --git a/util/qemu-thread-win32.c b/util/qemu-thread-win32.c index 406b52f91d..6cdd553e9a 100644 --- a/util/qemu-thread-win32.c +++ b/util/qemu-thread-win32.c @@ -238,10 +238,34 @@ void qemu_sem_wait(QemuSemaphore *sem) } } +/* Wrap a Win32 manual-reset event with a fast userspace path. The idea + * is to reset the Win32 event lazily, as part of a test-reset-test-wait + * sequence. Such a sequence is, indeed, how QemuEvents are used by + * RCU and other subsystems! + * + * Valid transitions: + * - free->set, when setting the event + * - busy->set, when setting the event, followed by futex_wake + * - set->free, when resetting the event + * - free->busy, when waiting + * + * set->busy does not happen (it can be observed from the outside but + * it really is set->free->busy). + * + * busy->free provably cannot happen; to enforce it, the set->free transition + * is done with an OR, which becomes a no-op if the event has concurrently + * transitioned to free or busy (and is faster than cmpxchg). + */ + +#define EV_SET 0 +#define EV_FREE 1 +#define EV_BUSY -1 + void qemu_event_init(QemuEvent *ev, bool init) { /* Manual reset. */ - ev->event = CreateEvent(NULL, TRUE, init, NULL); + ev->event = CreateEvent(NULL, TRUE, TRUE, NULL); + ev->value = (init ? EV_SET : EV_FREE); } void qemu_event_destroy(QemuEvent *ev) @@ -251,17 +275,51 @@ void qemu_event_destroy(QemuEvent *ev) void qemu_event_set(QemuEvent *ev) { - SetEvent(ev->event); + if (atomic_mb_read(&ev->value) != EV_SET) { + if (atomic_xchg(&ev->value, EV_SET) == EV_BUSY) { + /* There were waiters, wake them up. */ + SetEvent(ev->event); + } + } } void qemu_event_reset(QemuEvent *ev) { - ResetEvent(ev->event); + if (atomic_mb_read(&ev->value) == EV_SET) { + /* If there was a concurrent reset (or even reset+wait), + * do nothing. Otherwise change EV_SET->EV_FREE. + */ + atomic_or(&ev->value, EV_FREE); + } } void qemu_event_wait(QemuEvent *ev) { - WaitForSingleObject(ev->event, INFINITE); + unsigned value; + + value = atomic_mb_read(&ev->value); + if (value != EV_SET) { + if (value == EV_FREE) { + /* qemu_event_set is not yet going to call SetEvent, but we are + * going to do another check for EV_SET below when setting EV_BUSY. + * At that point it is safe to call WaitForSingleObject. + */ + ResetEvent(ev->event); + + /* Tell qemu_event_set that there are waiters. No need to retry + * because there cannot be a concurent busy->free transition. + * After the CAS, the event will be either set or busy. + */ + if (atomic_cmpxchg(&ev->value, EV_FREE, EV_BUSY) == EV_SET) { + value = EV_SET; + } else { + value = EV_BUSY; + } + } + if (value == EV_BUSY) { + WaitForSingleObject(ev->event, INFINITE); + } + } } struct QemuThreadData { |