diff --git a/scd/apdu.c b/scd/apdu.c index ce7f41f61..c0b1bbea4 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -105,6 +105,7 @@ struct reader_table_s { int (*check_pinpad)(int, int, pininfo_t *); void (*dump_status_reader)(int); int (*set_progress_cb)(int, gcry_handler_progress_t, void*); + int (*set_prompt_cb)(int, void (*) (void *, int), void*); int (*pinpad_verify)(int, int, int, int, int, pininfo_t *); int (*pinpad_modify)(int, int, int, int, int, pininfo_t *); @@ -444,6 +445,7 @@ new_reader_slot (void) reader_table[reader].check_pinpad = check_pcsc_pinpad; reader_table[reader].dump_status_reader = NULL; reader_table[reader].set_progress_cb = NULL; + reader_table[reader].set_prompt_cb = NULL; reader_table[reader].pinpad_verify = pcsc_pinpad_verify; reader_table[reader].pinpad_modify = pcsc_pinpad_modify; @@ -1404,6 +1406,14 @@ set_progress_cb_ccid_reader (int slot, gcry_handler_progress_t cb, void *cb_arg) return ccid_set_progress_cb (slotp->ccid.handle, cb, cb_arg); } +static int +set_prompt_cb_ccid_reader (int slot, void (*cb) (void *, int ), void *cb_arg) +{ + reader_table_t slotp = reader_table + slot; + + return ccid_set_prompt_cb (slotp->ccid.handle, cb, cb_arg); +} + static int get_status_ccid (int slot, unsigned int *status, int on_wire) @@ -1543,6 +1553,7 @@ open_ccid_reader (struct dev_list *dl) reader_table[slot].check_pinpad = check_ccid_pinpad; reader_table[slot].dump_status_reader = dump_ccid_reader_status; reader_table[slot].set_progress_cb = set_progress_cb_ccid_reader; + reader_table[slot].set_prompt_cb = set_prompt_cb_ccid_reader; reader_table[slot].pinpad_verify = ccid_pinpad_operation; reader_table[slot].pinpad_modify = ccid_pinpad_operation; /* Our CCID reader code does not support T=0 at all, thus reset the @@ -2382,6 +2393,29 @@ apdu_set_progress_cb (int slot, gcry_handler_progress_t cb, void *cb_arg) } +int +apdu_set_prompt_cb (int slot, void (*cb) (void *, int), void *cb_arg) +{ + int sw; + + if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used ) + return SW_HOST_NO_DRIVER; + + if (reader_table[slot].set_prompt_cb) + { + sw = lock_slot (slot); + if (!sw) + { + sw = reader_table[slot].set_prompt_cb (slot, cb, cb_arg); + unlock_slot (slot); + } + } + else + sw = 0; + return sw; +} + + /* Do a reset for the card in reader at SLOT. */ int apdu_reset (int slot) diff --git a/scd/apdu.h b/scd/apdu.h index 8a0d4bda8..8621ddc41 100644 --- a/scd/apdu.h +++ b/scd/apdu.h @@ -117,6 +117,7 @@ int apdu_connect (int slot); int apdu_disconnect (int slot); int apdu_set_progress_cb (int slot, gcry_handler_progress_t cb, void *cb_arg); +int apdu_set_prompt_cb (int slot, void (*cb) (void *, int), void *cb_arg); int apdu_reset (int slot); int apdu_get_status (int slot, int hang, unsigned int *status); diff --git a/scd/app.c b/scd/app.c index f3f1205f8..a82db26cd 100644 --- a/scd/app.c +++ b/scd/app.c @@ -67,6 +67,7 @@ lock_app (app_t app, ctrl_t ctrl) } apdu_set_progress_cb (app->slot, print_progress_line, ctrl); + apdu_set_prompt_cb (app->slot, popup_prompt, ctrl); return 0; } @@ -76,6 +77,7 @@ static void unlock_app (app_t app) { apdu_set_progress_cb (app->slot, NULL, NULL); + apdu_set_prompt_cb (app->slot, NULL, NULL); if (npth_mutex_unlock (&app->lock)) { diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index ae40f0118..6b0833b2c 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -255,6 +255,9 @@ struct ccid_driver_s void (*progress_cb)(void *, const char *, int, int, int); void *progress_cb_arg; + void (*prompt_cb)(void *, int); + void *prompt_cb_arg; + unsigned char intr_buf[64]; struct libusb_transfer *transfer; }; @@ -1802,6 +1805,19 @@ ccid_set_progress_cb (ccid_driver_t handle, } +int +ccid_set_prompt_cb (ccid_driver_t handle, + void (*cb)(void *, int), void *cb_arg) +{ + if (!handle) + return CCID_DRIVER_ERR_INV_VALUE; + + handle->prompt_cb = cb; + handle->prompt_cb_arg = cb_arg; + return 0; +} + + /* Close the reader HANDLE. */ int ccid_close_reader (ccid_driver_t handle) @@ -1930,6 +1946,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, { int rc; int msglen; + int notified = 0; /* Fixme: The next line for the current Valgrind without support for USB IOCTLs. */ @@ -1982,14 +1999,25 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, we got the expected message type. This is in particular required for the Cherry keyboard which sends a time extension request for each key hit. */ - if ( !(buffer[7] & 0x03) && (buffer[7] & 0xC0) == 0x80) + if (!(buffer[7] & 0x03) && (buffer[7] & 0xC0) == 0x80) { /* Card present and active, time extension requested. */ DEBUGOUT_2 ("time extension requested (%02X,%02X)\n", buffer[7], buffer[8]); + + /* Gnuk enhancement to prompt user input by ack button */ + if (buffer[8] == 0xff && !notified) + { + notified = 1; + handle->prompt_cb (handle->prompt_cb_arg, 1); + } + goto retry; } + if (notified) + handle->prompt_cb (handle->prompt_cb_arg, 0); + if (buffer[0] != expected_type && buffer[0] != RDR_to_PC_SlotStatus) { DEBUGOUT_1 ("unexpected bulk-in msg type (%02x)\n", buffer[0]); diff --git a/scd/ccid-driver.h b/scd/ccid-driver.h index c31c25fa7..1550b3eba 100644 --- a/scd/ccid-driver.h +++ b/scd/ccid-driver.h @@ -126,6 +126,8 @@ int ccid_open_reader (const char *spec_reader_name, int ccid_set_progress_cb (ccid_driver_t handle, void (*cb)(void *, const char *, int, int, int), void *cb_arg); +int ccid_set_prompt_cb (ccid_driver_t handle, void (*cb)(void *, int), + void *cb_arg); int ccid_shutdown_reader (ccid_driver_t handle); int ccid_close_reader (ccid_driver_t handle); int ccid_get_atr (ccid_driver_t handle, diff --git a/scd/command.c b/scd/command.c index 66d9fb971..0a9654693 100644 --- a/scd/command.c +++ b/scd/command.c @@ -1898,6 +1898,34 @@ send_status_direct (ctrl_t ctrl, const char *keyword, const char *args) } +void +popup_prompt (void *opaque, int on) +{ + ctrl_t ctrl = opaque; + + if (ctrl) + { + assuan_context_t ctx = ctrl->server_local->assuan_ctx; + + if (ctx) + { + const char *cmd; + gpg_error_t err; + unsigned char *value; + size_t valuelen; + + if (on) + cmd = "POPUPPINPADPROMPT --ack"; + else + cmd = "DISMISSPINPADPROMPT"; + err = assuan_inquire (ctx, cmd, &value, &valuelen, 100); + if (!err) + xfree (value); + } + } +} + + /* Helper to send the clients a status change notification. */ void send_client_notifications (app_t app, int removal) diff --git a/scd/scdaemon.h b/scd/scdaemon.h index 4797f3df0..238e6a8fd 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -123,6 +123,7 @@ int scd_command_handler (ctrl_t, int); void send_status_info (ctrl_t ctrl, const char *keyword, ...) GPGRT_ATTR_SENTINEL(1); void send_status_direct (ctrl_t ctrl, const char *keyword, const char *args); +void popup_prompt (void *opaque, int on); void send_client_notifications (app_t app, int removal); void scd_kick_the_loop (void); int get_active_connection_count (void);