diff --git a/g10/ChangeLog b/g10/ChangeLog index 423e15a80..b4871247d 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,15 @@ +2004-09-20 Werner Koch + + * cardglue.c (open_card): Use shutdown code if possible. + (check_card_serialno): Ditto. + + * ccid-driver.c (do_close_reader): Factored some code out from ... + (ccid_close_reader): ..here. + (ccid_shutdown_reader): New. + + * apdu.c (apdu_shutdown_reader): New. + (shutdown_ccid_reader): New. + 2004-09-17 Werner Koch * g10.c (list_config): New config option ccid-reader-id. diff --git a/g10/apdu.c b/g10/apdu.c index a3aa1ba9f..228fdec61 100644 --- a/g10/apdu.c +++ b/g10/apdu.c @@ -92,6 +92,7 @@ struct reader_table_s { /* Function pointers intialized to the various backends. */ int (*close_reader)(int); + int (*shutdown_reader)(int); int (*reset_reader)(int); int (*get_status_reader)(int, unsigned int *); int (*send_apdu_reader)(int,unsigned char *,size_t, @@ -244,6 +245,7 @@ new_reader_slot (void) } #endif /*USE_GNU_PTH*/ reader_table[reader].close_reader = NULL; + reader_table[reader].shutdown_reader = NULL; reader_table[reader].reset_reader = NULL; reader_table[reader].get_status_reader = NULL; reader_table[reader].send_apdu_reader = NULL; @@ -1201,6 +1203,14 @@ close_ccid_reader (int slot) } +static int +shutdown_ccid_reader (int slot) +{ + ccid_shutdown_reader (reader_table[slot].ccid.handle); + return 0; +} + + static int reset_ccid_reader (int slot) { @@ -1300,6 +1310,7 @@ open_ccid_reader (const char *portstr) } reader_table[slot].close_reader = close_ccid_reader; + reader_table[slot].shutdown_reader = shutdown_ccid_reader; reader_table[slot].reset_reader = reset_ccid_reader; reader_table[slot].get_status_reader = get_status_ccid; reader_table[slot].send_apdu_reader = send_apdu_ccid; @@ -2051,6 +2062,19 @@ apdu_close_reader (int slot) return SW_HOST_NOT_SUPPORTED; } +/* Shutdown a reader; that is basically the same as a close but keeps + the handle ready for later use. A apdu_reset_header should be used + to get it active again. */ +int +apdu_shutdown_reader (int slot) +{ + if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used ) + return SW_HOST_NO_DRIVER; + if (reader_table[slot].shutdown_reader) + return reader_table[slot].shutdown_reader (slot); + return SW_HOST_NOT_SUPPORTED; +} + /* Enumerate all readers and return information on whether this reader is in use. The caller should start with SLOT set to 0 and increment it with each call until an error is returned. */ diff --git a/g10/apdu.h b/g10/apdu.h index a0654a242..f31e42e3d 100644 --- a/g10/apdu.h +++ b/g10/apdu.h @@ -76,6 +76,7 @@ int apdu_open_remote_reader (const char *portstr, void *writefnc_value, void (*closefnc) (void *opaque), void *closefnc_value); +int apdu_shutdown_reader (int slot); int apdu_close_reader (int slot); int apdu_enum_reader (int slot, int *used); unsigned char *apdu_get_atr (int slot, size_t *atrlen); diff --git a/g10/cardglue.c b/g10/cardglue.c index 7bb3c8488..5faa41bad 100644 --- a/g10/cardglue.c +++ b/g10/cardglue.c @@ -54,7 +54,6 @@ static APP current_app; - /* Create a serialno/fpr string from the serial number and the secret key. caller must free the returned string. There is no error return. [Taken from 1.9's keyid.c]*/ @@ -247,18 +246,25 @@ agent_release_card_info (struct agent_card_info_s *info) static APP open_card (void) { - int slot; + int slot = -1; int rc; APP app; + int did_shutdown = 0; card_close (); + retry: - slot = apdu_open_reader (default_reader_port); - if (slot == -1) + if (did_shutdown) + apdu_reset (slot); + else { - log_error ("card reader not available\n"); - return NULL; + slot = apdu_open_reader (default_reader_port); + if (slot == -1) + { + log_error ("card reader not available\n"); + return NULL; + } } app = xcalloc (1, sizeof *app); @@ -268,11 +274,14 @@ open_card (void) { write_status_text (STATUS_CARDCTRL, "1"); + did_shutdown = !!apdu_shutdown_reader (slot); + if ( cpr_get_answer_okay_cancel ("cardctrl.insert_card.okay", _("Please insert the card and hit return or enter 'c' to cancel: "), 1) ) { - apdu_close_reader (slot); + if (!did_shutdown) + apdu_close_reader (slot); xfree (app); goto retry; } @@ -323,7 +332,7 @@ card_close (void) function return 0 is the present card is okay, -1 if the user selected to insert a new card or an error value. Note that the card context will be closed in all cases except for 0 as return - value. */ + value and if it was possible to merely shutdown the reader. */ static int check_card_serialno (APP app, const char *serialno) { @@ -346,8 +355,12 @@ check_card_serialno (APP app, const char *serialno) if (ask) { char buf[5+32+1]; + int did_shutdown = 0; - card_close (); + if (current_app && !apdu_shutdown_reader (current_app->slot)) + did_shutdown = 1; + else + card_close (); tty_printf (_("Please remove the current card and " "insert the one with the serial number:\n" " %.*s\n"), 32, serialno); @@ -359,7 +372,14 @@ check_card_serialno (APP app, const char *serialno) _("Hit return when ready " "or enter 'c' to cancel: "), 1) ) - return -1; + { + card_close (); + return -1; + } + if (did_shutdown) + apdu_reset (current_app->slot); + else + card_close (); return gpg_error (GPG_ERR_INV_ID); } return 0; diff --git a/g10/ccid-driver.c b/g10/ccid-driver.c index ccdcb461b..77fea944b 100644 --- a/g10/ccid-driver.c +++ b/g10/ccid-driver.c @@ -196,6 +196,7 @@ struct ccid_driver_s int auto_ifsd; int max_ifsd; int ifsd; + int powered_off; int has_pinpad; }; @@ -863,6 +864,102 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid) } +static void +do_close_reader (ccid_driver_t handle) +{ + int rc; + unsigned char msg[100]; + size_t msglen; + unsigned char seqno; + + if (!handle->powered_off) + { + msg[0] = PC_to_RDR_IccPowerOff; + msg[5] = 0; /* slot */ + msg[6] = seqno = handle->seqno++; + msg[7] = 0; /* RFU */ + msg[8] = 0; /* RFU */ + msg[9] = 0; /* RFU */ + set_msg_len (msg, 0); + msglen = 10; + + rc = bulk_out (handle, msg, msglen); + if (!rc) + bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus,seqno); + handle->powered_off = 1; + } + if (handle->idev) + { + usb_release_interface (handle->idev, 0); + usb_close (handle->idev); + handle->idev = NULL; + } +} + + +/* Reset a reader on HANDLE. This is useful in case a reader has been + plugged of and inserted at a different port. By resetting the + handle, the same reader will be get used. Note, that on error the + handle won't get released. + + This does not return an ATR, so ccid_get_atr should be called right + after this one. +*/ +int +ccid_shutdown_reader (ccid_driver_t handle) +{ + int rc = 0; + struct usb_device *dev = NULL; + usb_dev_handle *idev = NULL; + unsigned char *ifcdesc_extra = NULL; + size_t ifcdesc_extra_len; + + if (!handle || !handle->rid) + return CCID_DRIVER_ERR_INV_VALUE; + + do_close_reader (handle); + + idev = scan_or_find_devices (-1, handle->rid, NULL, &dev, + &ifcdesc_extra, &ifcdesc_extra_len); + if (!idev) + { + DEBUGOUT_1 ("no CCID reader with ID %s\n", handle->rid); + return CCID_DRIVER_ERR_NO_READER; + } + + + handle->idev = idev; + + if (parse_ccid_descriptor (handle, ifcdesc_extra, ifcdesc_extra_len)) + { + DEBUGOUT ("device not supported\n"); + rc = CCID_DRIVER_ERR_NO_READER; + goto leave; + } + + /* fixme: Do we need to claim and set the interface as + determined above? */ + rc = usb_claim_interface (idev, 0); + if (rc) + { + DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc); + rc = CCID_DRIVER_ERR_CARD_IO_ERROR; + goto leave; + } + + leave: + free (ifcdesc_extra); + if (rc) + { + usb_close (handle->idev); + handle->idev = NULL; + } + + return rc; + +} + + /* Close the reader HANDLE. */ int ccid_close_reader (ccid_driver_t handle) @@ -870,34 +967,13 @@ ccid_close_reader (ccid_driver_t handle) if (!handle || !handle->idev) return 0; - { - int rc; - unsigned char msg[100]; - size_t msglen; - unsigned char seqno; - - msg[0] = PC_to_RDR_IccPowerOff; - msg[5] = 0; /* slot */ - msg[6] = seqno = handle->seqno++; - msg[7] = 0; /* RFU */ - msg[8] = 0; /* RFU */ - msg[9] = 0; /* RFU */ - set_msg_len (msg, 0); - msglen = 10; - - rc = bulk_out (handle, msg, msglen); - if (!rc) - bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus, seqno); - } - - usb_release_interface (handle->idev, 0); - usb_close (handle->idev); - handle->idev = NULL; + do_close_reader (handle); free (handle->rid); free (handle); return 0; } + /* Return False if a card is present and powered. */ int ccid_check_card_presence (ccid_driver_t handle) @@ -1120,6 +1196,8 @@ ccid_get_atr (ccid_driver_t handle, rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_DataBlock, seqno); if (rc) return rc; + + handle->powered_off = 0; if (atr) { @@ -1680,16 +1758,16 @@ main (int argc, char **argv) ccid_poll (ccid); /* if (!ccid->has_pinpad) */ - { - fputs ("verifying that CHV1 is 123456....\n", stderr); - { - static unsigned char apdu[] = {0, 0x20, 0, 0x81, - 6, '1','2','3','4','5','6'}; - rc = ccid_transceive (ccid, apdu, sizeof apdu, - result, sizeof result, &resultlen); - print_result (rc, result, resultlen); - } - } +/* { */ +/* fputs ("verifying that CHV1 is 123456....\n", stderr); */ +/* { */ +/* static unsigned char apdu[] = {0, 0x20, 0, 0x81, */ +/* 6, '1','2','3','4','5','6'}; */ +/* rc = ccid_transceive (ccid, apdu, sizeof apdu, */ +/* result, sizeof result, &resultlen); */ +/* print_result (rc, result, resultlen); */ +/* } */ +/* } */ /* else */ /* { */ /* fputs ("verifying CHV1 using the PINPad ....\n", stderr); */ diff --git a/g10/ccid-driver.h b/g10/ccid-driver.h index 23562b3b9..cbadb40c1 100644 --- a/g10/ccid-driver.h +++ b/g10/ccid-driver.h @@ -78,6 +78,7 @@ typedef struct ccid_driver_s *ccid_driver_t; int ccid_set_debug_level (int level); char *ccid_get_reader_list (void); int ccid_open_reader (ccid_driver_t *handle, const char *readerid); +int ccid_shutdown_reader (ccid_driver_t handle); int ccid_close_reader (ccid_driver_t handle); int ccid_get_atr (ccid_driver_t handle, unsigned char *atr, size_t maxatrlen, size_t *atrlen);