diff options
Diffstat (limited to 'scd/command.c')
-rw-r--r-- | scd/command.c | 586 |
1 files changed, 66 insertions, 520 deletions
diff --git a/scd/command.c b/scd/command.c index 02bf76fa3..0c823d2c9 100644 --- a/scd/command.c +++ b/scd/command.c @@ -37,7 +37,6 @@ #include "iso7816.h" #include "apdu.h" /* Required for apdu_*_reader (). */ #include "atr.h" -#include "exechelp.h" #ifdef HAVE_LIBUSB #include "ccid-driver.h" #endif @@ -59,38 +58,7 @@ #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t)) - -/* Macro to flag a removed card. ENODEV is also tested to catch the - case of a removed reader. */ -#define TEST_CARD_REMOVAL(c,r) \ - do { \ - int _r = (r); \ - if (gpg_err_code (_r) == GPG_ERR_CARD_NOT_PRESENT \ - || gpg_err_code (_r) == GPG_ERR_CARD_REMOVED \ - || gpg_err_code (_r) == GPG_ERR_CARD_RESET \ - || gpg_err_code (_r) == GPG_ERR_ENODEV ) \ - update_card_removed ((c)->server_local->vreader_idx, 1); \ - } while (0) - -#define IS_LOCKED(c) \ - (locked_session \ - && locked_session != (c)->server_local \ - && (c)->server_local->vreader_idx != -1 \ - && locked_session->ctrl_backlink \ - && ((c)->server_local->vreader_idx \ - == locked_session->ctrl_backlink->server_local->vreader_idx)) - - -/* This structure is used to keep track of user readers. To - eventually accommodate this structure for RFID cards, where more - than one card is used per reader, we name it virtual reader. */ -struct vreader_s -{ - int valid; /* True if the other objects are valid. */ - int slot; /* APDU slot number of the reader or -1 if not open. */ - - unsigned int status; /* Last status of the reader. */ -}; +#define IS_LOCKED(c) (locked_session && locked_session != (c)->server_local) /* Data used to associate an Assuan context with local server data. @@ -116,16 +84,10 @@ struct server_local_s int event_signal; /* Or 0 if not used. */ #endif - /* Index into the vreader table (command.c) or -1 if not open. */ - int vreader_idx; - /* True if the card has been removed and a reset is required to continue operation. */ int card_removed; - /* A disconnect command has been sent. */ - int disconnect_allowed; - /* If set to true we will be terminate ourself at the end of the this session. */ int stopme; @@ -133,10 +95,6 @@ struct server_local_s }; -/* The table with information on all used virtual readers. */ -static struct vreader_s vreader_table[10]; - - /* To keep track of all running sessions, we link all active server contexts and the anchor in this variable. */ static struct server_local_s *session_list; @@ -145,88 +103,7 @@ static struct server_local_s *session_list; in this variable. */ static struct server_local_s *locked_session; -/* While doing a reset we need to make sure that the ticker does not - call scd_update_reader_status_file while we are using it. */ -static npth_mutex_t status_file_update_lock; - - -/*-- Local prototypes --*/ -static void update_reader_status_file (int set_card_removed_flag); - - - -/* This function must be called once to initialize this module. This - has to be done before a second thread is spawned. We can't do the - static initialization because Pth emulation code might not be able - to do a static init; in particular, it is not possible for W32. */ -void -initialize_module_command (void) -{ - static int initialized; - int err; - - if (!initialized) - { - err = npth_mutex_init (&status_file_update_lock, NULL); - if (!err) - initialized = 1; - } -} - - -/* Helper to return the slot number for a given virtual reader index - VRDR. In case on an error -1 is returned. */ -static int -vreader_slot (int vrdr) -{ - if (vrdr == -1 || !(vrdr >= 0 && vrdr < DIM(vreader_table))) - return -1; - if (!vreader_table [vrdr].valid) - return -1; - return vreader_table[vrdr].slot; -} - - -/* Update the CARD_REMOVED element of all sessions using the virtual - reader given by VRDR to VALUE. */ -static void -update_card_removed (int vrdr, int value) -{ - struct server_local_s *sl; - - if (vrdr == -1) - return; - - for (sl=session_list; sl; sl = sl->next_session) - { - ctrl_t ctrl = sl->ctrl_backlink; - - if (ctrl && ctrl->server_local->vreader_idx == vrdr) - { - sl->card_removed = value; - if (value) - { - struct app_ctx_s *app = ctrl->app_ctx; - ctrl->app_ctx = NULL; - release_application (app); - } - } - } - - /* Let the card application layer know about the removal. */ - if (value) - { - int slot = vreader_slot (vrdr); - - log_debug ("Removal of a card: %d\n", vrdr); - apdu_close_reader (slot); - application_notify_card_reset (slot); - vreader_table[vrdr].slot = -1; - } -} - - /* Convert the STRING into a newly allocated buffer while translating the hex numbers. Stops at the first invalid character. Blanks and colons are allowed to separate the hex digits. Returns NULL on @@ -265,61 +142,10 @@ hex_to_buffer (const char *string, size_t *r_length) static void do_reset (ctrl_t ctrl, int send_reset) { - int vrdr = ctrl->server_local->vreader_idx; - int slot; - int err; - struct app_ctx_s *app = ctrl->app_ctx; - - if (!(vrdr == -1 || (vrdr >= 0 && vrdr < DIM(vreader_table)))) - BUG (); + app_t app = ctrl->app_ctx; - /* If there is an active application, release it. */ if (app) - { - ctrl->app_ctx = NULL; - release_application (app); - } - - /* Release the same application which is used by other sessions. */ - if (send_reset) - { - struct server_local_s *sl; - - for (sl=session_list; sl; sl = sl->next_session) - { - ctrl_t c = sl->ctrl_backlink; - - if (c && c != ctrl && c->server_local->vreader_idx == vrdr) - { - struct app_ctx_s *app0 = c->app_ctx; - if (app0) - { - c->app_ctx = NULL; - release_application (app0); - } - } - } - } - - /* If we want a real reset for the card, send the reset APDU and - tell the application layer about it. */ - slot = vreader_slot (vrdr); - if (slot != -1 && send_reset && !IS_LOCKED (ctrl) ) - { - application_notify_card_reset (slot); - switch (apdu_reset (slot)) - { - case 0: - break; - case SW_HOST_NO_CARD: - case SW_HOST_CARD_INACTIVE: - break; - default: - apdu_close_reader (slot); - vreader_table[vrdr].slot = -1; - break; - } - } + app_reset (app, ctrl, IS_LOCKED (ctrl)? 0: send_reset); /* If we hold a lock, unlock now. */ if (locked_session && ctrl->server_local == locked_session) @@ -327,30 +153,7 @@ do_reset (ctrl_t ctrl, int send_reset) locked_session = NULL; log_info ("implicitly unlocking due to RESET\n"); } - - /* Reset the card removed flag for the current reader. We need to - take the lock here so that the ticker thread won't concurrently - try to update the file. Calling update_reader_status_file is - required to get hold of the new status of the card in the vreader - table. */ - err = npth_mutex_lock (&status_file_update_lock); - if (err) - { - log_error ("failed to acquire status_file_update lock\n"); - ctrl->server_local->vreader_idx = -1; - return; - } - update_reader_status_file (0); /* Update slot status table. */ - update_card_removed (vrdr, 0); /* Clear card_removed flag. */ - err = npth_mutex_unlock (&status_file_update_lock); - if (err) - log_error ("failed to release status_file_update lock: %s\n", - strerror (err)); - - /* Do this last, so that the update_card_removed above does its job. */ - ctrl->server_local->vreader_idx = -1; } - static gpg_error_t reset_notify (assuan_context_t ctx, char *line) @@ -388,50 +191,11 @@ option_handler (assuan_context_t ctx, const char *key, const char *value) } -/* Return the index of the current reader or open the reader if no - other sessions are using that reader. If it is not possible to - open the reader -1 is returned. Note, that we currently support - only one reader but most of the code (except for this function) - should be able to cope with several readers. */ -static int -get_current_reader (void) -{ - struct vreader_s *vr; - - /* We only support one reader for now. */ - vr = &vreader_table[0]; - - /* Initialize the vreader item if not yet done. */ - if (!vr->valid) - { - vr->slot = -1; - vr->valid = 1; - } - - /* Try to open the reader. */ - if (vr->slot == -1) - { - vr->slot = apdu_open_reader (opt.reader_port); - - /* If we still don't have a slot, we have no readers. - Invalidate for now until a reader is attached. */ - if (vr->slot == -1) - { - vr->valid = 0; - } - } - - /* Return the vreader index or -1. */ - return vr->valid ? 0 : -1; -} - - /* If the card has not yet been opened, do it. */ static gpg_error_t -open_card (ctrl_t ctrl, const char *apptype) +open_card (ctrl_t ctrl, const char *apptype, int scan) { gpg_error_t err; - int vrdr; /* If we ever got a card not present error code, return that. Only the SERIALNO command and a reset are able to clear from that @@ -445,43 +209,11 @@ open_card (ctrl_t ctrl, const char *apptype) /* If we are already initialized for one specific application we need to check that the client didn't requested a specific application different from the one in use before we continue. */ - if (ctrl->app_ctx) - { - return check_application_conflict - (ctrl, vreader_slot (ctrl->server_local->vreader_idx), apptype); - } + if (!scan && ctrl->app_ctx) + return check_application_conflict (apptype, ctrl->app_ctx); - /* Setup the vreader and select the application. */ - if (ctrl->server_local->vreader_idx != -1) - vrdr = ctrl->server_local->vreader_idx; - else - vrdr = get_current_reader (); - ctrl->server_local->vreader_idx = vrdr; - if (vrdr == -1) - err = gpg_error (GPG_ERR_CARD); - else - { - /* Fixme: We should move the apdu_connect call to - select_application. */ - int sw; - int slot = vreader_slot (vrdr); - - ctrl->server_local->disconnect_allowed = 0; - sw = apdu_connect (slot); - if (sw && sw != SW_HOST_ALREADY_CONNECTED) - { - if (sw == SW_HOST_NO_CARD) - err = gpg_error (GPG_ERR_CARD_NOT_PRESENT); - else if (sw == SW_HOST_CARD_INACTIVE) - err = gpg_error (GPG_ERR_CARD_RESET); - else - err = gpg_error (GPG_ERR_ENODEV); - } - else - err = select_application (ctrl, slot, apptype, &ctrl->app_ctx); - } + err = select_application (ctrl, apptype, &ctrl->app_ctx, scan); - TEST_CARD_REMOVAL (ctrl, err); return err; } @@ -509,28 +241,35 @@ static gpg_error_t cmd_serialno (assuan_context_t ctx, char *line) { ctrl_t ctrl = assuan_get_pointer (ctx); + struct server_local_s *sl; int rc = 0; char *serial; time_t stamp; - int retries = 0; /* Clear the remove flag so that the open_card is able to reread it. */ - retry: if (ctrl->server_local->card_removed) { if ( IS_LOCKED (ctrl) ) return gpg_error (GPG_ERR_LOCKED); - do_reset (ctrl, 1); + + ctrl->server_local->card_removed = 0; } - if ((rc = open_card (ctrl, *line? line:NULL))) + if ((rc = open_card (ctrl, *line? line:NULL, 1))) { - /* In case of an inactive card, retry once. */ - if (gpg_err_code (rc) == GPG_ERR_CARD_RESET && retries++ < 1) - goto retry; + ctrl->server_local->card_removed = 1; return rc; } + /* Success, clear the card_removed flag for all sessions. */ + for (sl=session_list; sl; sl = sl->next_session) + { + ctrl_t c = sl->ctrl_backlink; + + if (c != ctrl) + c->server_local->card_removed = 0; + } + rc = app_get_serial_and_stamp (ctrl->app_ctx, &serial, &stamp); if (rc) return rc; @@ -618,7 +357,7 @@ cmd_learn (assuan_context_t ctx, char *line) int rc = 0; int only_keypairinfo = has_option (line, "--keypairinfo"); - if ((rc = open_card (ctrl, NULL))) + if ((rc = open_card (ctrl, NULL, 0))) return rc; /* Unless the force option is used we try a shortcut by identifying @@ -627,13 +366,15 @@ cmd_learn (assuan_context_t ctx, char *line) knows about this card */ if (!only_keypairinfo) { - int slot; const char *reader; char *serial; time_t stamp; + app_t app = ctrl->app_ctx; + + if (!app) + return gpg_error (GPG_ERR_CARD_NOT_PRESENT); - slot = vreader_slot (ctrl->server_local->vreader_idx); - reader = apdu_get_reader_name (slot); + reader = apdu_get_reader_name (app->slot); if (!reader) return out_of_core (); send_status_direct (ctrl, "READER", reader); @@ -682,7 +423,6 @@ cmd_learn (assuan_context_t ctx, char *line) if (!rc) rc = app_write_learn_status (ctrl->app_ctx, ctrl, only_keypairinfo); - TEST_CARD_REMOVAL (ctrl, rc); return rc; } @@ -700,7 +440,7 @@ cmd_readcert (assuan_context_t ctx, char *line) unsigned char *cert; size_t ncert; - if ((rc = open_card (ctrl, NULL))) + if ((rc = open_card (ctrl, NULL, 0))) return rc; line = xstrdup (line); /* Need a copy of the line. */ @@ -717,7 +457,6 @@ cmd_readcert (assuan_context_t ctx, char *line) return rc; } - TEST_CARD_REMOVAL (ctrl, rc); return rc; } @@ -743,7 +482,7 @@ cmd_readkey (assuan_context_t ctx, char *line) unsigned char *pk; size_t pklen; - if ((rc = open_card (ctrl, NULL))) + if ((rc = open_card (ctrl, NULL, 0))) return rc; if (has_option (line, "--advanced")) @@ -804,7 +543,6 @@ cmd_readkey (assuan_context_t ctx, char *line) leave: ksba_cert_release (kc); xfree (cert); - TEST_CARD_REMOVAL (ctrl, rc); return rc; } @@ -966,10 +704,7 @@ cmd_pksign (assuan_context_t ctx, char *line) line = skip_options (line); - if ( IS_LOCKED (ctrl) ) - return gpg_error (GPG_ERR_LOCKED); - - if ((rc = open_card (ctrl, NULL))) + if ((rc = open_card (ctrl, NULL, 0))) return rc; /* We have to use a copy of the key ID because the function may use @@ -998,7 +733,6 @@ cmd_pksign (assuan_context_t ctx, char *line) return rc; /* that is already an assuan error code */ } - TEST_CARD_REMOVAL (ctrl, rc); return rc; } @@ -1014,10 +748,7 @@ cmd_pkauth (assuan_context_t ctx, char *line) size_t outdatalen; char *keyidstr; - if ( IS_LOCKED (ctrl) ) - return gpg_error (GPG_ERR_LOCKED); - - if ((rc = open_card (ctrl, NULL))) + if ((rc = open_card (ctrl, NULL, 0))) return rc; if (!ctrl->app_ctx) @@ -1046,7 +777,6 @@ cmd_pkauth (assuan_context_t ctx, char *line) return rc; /* that is already an assuan error code */ } - TEST_CARD_REMOVAL (ctrl, rc); return rc; } @@ -1063,10 +793,7 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line) char *keyidstr; unsigned int infoflags; - if ( IS_LOCKED (ctrl) ) - return gpg_error (GPG_ERR_LOCKED); - - if ((rc = open_card (ctrl, NULL))) + if ((rc = open_card (ctrl, NULL, 0))) return rc; keyidstr = xtrystrdup (line); @@ -1096,7 +823,6 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line) return rc; /* that is already an assuan error code */ } - TEST_CARD_REMOVAL (ctrl, rc); return rc; } @@ -1120,7 +846,7 @@ cmd_getattr (assuan_context_t ctx, char *line) int rc; const char *keyword; - if ((rc = open_card (ctrl, NULL))) + if ((rc = open_card (ctrl, NULL, 0))) return rc; keyword = line; @@ -1135,7 +861,6 @@ cmd_getattr (assuan_context_t ctx, char *line) is locked. */ rc = app_getattr (ctrl->app_ctx, ctrl, keyword); - TEST_CARD_REMOVAL (ctrl, rc); return rc; } @@ -1163,10 +888,7 @@ cmd_setattr (assuan_context_t ctx, char *orig_line) size_t nbytes; char *line, *linebuf; - if ( IS_LOCKED (ctrl) ) - return gpg_error (GPG_ERR_LOCKED); - - if ((rc = open_card (ctrl, NULL))) + if ((rc = open_card (ctrl, NULL, 0))) return rc; /* We need to use a copy of LINE, because PIN_CB uses the same @@ -1188,7 +910,6 @@ cmd_setattr (assuan_context_t ctx, char *orig_line) (const unsigned char*)line, nbytes); xfree (linebuf); - TEST_CARD_REMOVAL (ctrl, rc); return rc; } @@ -1213,9 +934,6 @@ cmd_writecert (assuan_context_t ctx, char *line) unsigned char *certdata; size_t certdatalen; - if ( IS_LOCKED (ctrl) ) - return gpg_error (GPG_ERR_LOCKED); - line = skip_options (line); if (!*line) @@ -1225,7 +943,7 @@ cmd_writecert (assuan_context_t ctx, char *line) line++; *line = 0; - if ((rc = open_card (ctrl, NULL))) + if ((rc = open_card (ctrl, NULL, 0))) return rc; if (!ctrl->app_ctx) @@ -1250,7 +968,6 @@ cmd_writecert (assuan_context_t ctx, char *line) xfree (certid); xfree (certdata); - TEST_CARD_REMOVAL (ctrl, rc); return rc; } @@ -1279,9 +996,6 @@ cmd_writekey (assuan_context_t ctx, char *line) unsigned char *keydata; size_t keydatalen; - if ( IS_LOCKED (ctrl) ) - return gpg_error (GPG_ERR_LOCKED); - line = skip_options (line); if (!*line) @@ -1291,7 +1005,7 @@ cmd_writekey (assuan_context_t ctx, char *line) line++; *line = 0; - if ((rc = open_card (ctrl, NULL))) + if ((rc = open_card (ctrl, NULL, 0))) return rc; if (!ctrl->app_ctx) @@ -1317,7 +1031,6 @@ cmd_writekey (assuan_context_t ctx, char *line) xfree (keyid); xfree (keydata); - TEST_CARD_REMOVAL (ctrl, rc); return rc; } @@ -1357,9 +1070,6 @@ cmd_genkey (assuan_context_t ctx, char *line) const char *s; time_t timestamp; - if ( IS_LOCKED (ctrl) ) - return gpg_error (GPG_ERR_LOCKED); - force = has_option (line, "--force"); if ((s=has_option_name (line, "--timestamp"))) @@ -1382,7 +1092,7 @@ cmd_genkey (assuan_context_t ctx, char *line) line++; *line = 0; - if ((rc = open_card (ctrl, NULL))) + if ((rc = open_card (ctrl, NULL, 0))) return rc; if (!ctrl->app_ctx) @@ -1395,7 +1105,6 @@ cmd_genkey (assuan_context_t ctx, char *line) timestamp, pin_cb, ctx); xfree (keyno); - TEST_CARD_REMOVAL (ctrl, rc); return rc; } @@ -1421,7 +1130,7 @@ cmd_random (assuan_context_t ctx, char *line) "number of requested bytes missing"); nbytes = strtoul (line, NULL, 0); - if ((rc = open_card (ctrl, NULL))) + if ((rc = open_card (ctrl, NULL, 0))) return rc; if (!ctrl->app_ctx) @@ -1440,7 +1149,6 @@ cmd_random (assuan_context_t ctx, char *line) } xfree (buffer); - TEST_CARD_REMOVAL (ctrl, rc); return rc; } @@ -1466,9 +1174,6 @@ cmd_passwd (assuan_context_t ctx, char *line) if (has_option (line, "--nullpin")) flags |= APP_CHANGE_FLAG_NULLPIN; - if ( IS_LOCKED (ctrl) ) - return gpg_error (GPG_ERR_LOCKED); - line = skip_options (line); if (!*line) @@ -1478,7 +1183,7 @@ cmd_passwd (assuan_context_t ctx, char *line) line++; *line = 0; - if ((rc = open_card (ctrl, NULL))) + if ((rc = open_card (ctrl, NULL, 0))) return rc; if (!ctrl->app_ctx) @@ -1492,7 +1197,6 @@ cmd_passwd (assuan_context_t ctx, char *line) log_error ("command passwd failed: %s\n", gpg_strerror (rc)); xfree (chvnostr); - TEST_CARD_REMOVAL (ctrl, rc); return rc; } @@ -1536,10 +1240,7 @@ cmd_checkpin (assuan_context_t ctx, char *line) int rc; char *idstr; - if ( IS_LOCKED (ctrl) ) - return gpg_error (GPG_ERR_LOCKED); - - if ((rc = open_card (ctrl, NULL))) + if ((rc = open_card (ctrl, NULL, 0))) return rc; if (!ctrl->app_ctx) @@ -1557,7 +1258,6 @@ cmd_checkpin (assuan_context_t ctx, char *line) if (rc) log_error ("app_check_pin failed: %s\n", gpg_strerror (rc)); - TEST_CARD_REMOVAL (ctrl, rc); return rc; } @@ -1592,8 +1292,8 @@ cmd_lock (assuan_context_t ctx, char *line) { rc = 0; npth_sleep (1); /* Better implement an event mechanism. However, - for card operations this should be - sufficient. */ + for card operations this should be + sufficient. */ /* FIXME: Need to check that the connection is still alive. This can be done by issuing status messages. */ goto retry; @@ -1690,20 +1390,12 @@ cmd_getinfo (assuan_context_t ctx, char *line) else if (!strcmp (line, "status")) { ctrl_t ctrl = assuan_get_pointer (ctx); - int vrdr = ctrl->server_local->vreader_idx; + app_t app = ctrl->app_ctx; char flag = 'r'; - if (!ctrl->server_local->card_removed && vrdr != -1) - { - struct vreader_s *vr; - - if (!(vrdr >= 0 && vrdr < DIM(vreader_table))) - BUG (); + if (!ctrl->server_local->card_removed && app) + flag = 'u'; - vr = &vreader_table[vrdr]; - if (vr->valid && (vr->status & 1)) - flag = 'u'; - } rc = assuan_send_data (ctx, &flag, 1); } else if (!strcmp (line, "reader_list")) @@ -1751,7 +1443,7 @@ static gpg_error_t cmd_restart (assuan_context_t ctx, char *line) { ctrl_t ctrl = assuan_get_pointer (ctx); - struct app_ctx_s *app = ctrl->app_ctx; + app_t app = ctrl->app_ctx; (void)line; @@ -1772,8 +1464,7 @@ cmd_restart (assuan_context_t ctx, char *line) static const char hlp_disconnect[] = "DISCONNECT\n" "\n" - "Disconnect the card if it is not any longer used by other\n" - "connections and the backend supports a disconnect operation."; + "Disconnect the card if the backend supports a disconnect operation."; static gpg_error_t cmd_disconnect (assuan_context_t ctx, char *line) { @@ -1781,7 +1472,10 @@ cmd_disconnect (assuan_context_t ctx, char *line) (void)line; - ctrl->server_local->disconnect_allowed = 1; + if (!ctrl->app_ctx) + return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); + + apdu_disconnect (ctrl->app_ctx->slot); return 0; } @@ -1810,6 +1504,7 @@ static gpg_error_t cmd_apdu (assuan_context_t ctx, char *line) { ctrl_t ctrl = assuan_get_pointer (ctx); + app_t app; int rc; unsigned char *apdu; size_t apdulen; @@ -1817,7 +1512,6 @@ cmd_apdu (assuan_context_t ctx, char *line) int handle_more; const char *s; size_t exlen; - int slot; if (has_option (line, "--dump-atr")) with_atr = 2; @@ -1837,13 +1531,12 @@ cmd_apdu (assuan_context_t ctx, char *line) line = skip_options (line); - if ( IS_LOCKED (ctrl) ) - return gpg_error (GPG_ERR_LOCKED); - - if ((rc = open_card (ctrl, NULL))) + if ((rc = open_card (ctrl, NULL, 0))) return rc; - slot = vreader_slot (ctrl->server_local->vreader_idx); + app = ctrl->app_ctx; + if (!app) + return gpg_error (GPG_ERR_CARD_NOT_PRESENT); if (with_atr) { @@ -1851,7 +1544,7 @@ cmd_apdu (assuan_context_t ctx, char *line) size_t atrlen; char hexbuf[400]; - atr = apdu_get_atr (slot, &atrlen); + atr = apdu_get_atr (app->slot, &atrlen); if (!atr || atrlen > sizeof hexbuf - 2 ) { rc = gpg_error (GPG_ERR_INV_CARD); @@ -1896,7 +1589,7 @@ cmd_apdu (assuan_context_t ctx, char *line) unsigned char *result = NULL; size_t resultlen; - rc = apdu_send_direct (slot, exlen, + rc = apdu_send_direct (app->slot, exlen, apdu, apdulen, handle_more, &result, &resultlen); if (rc) @@ -1910,7 +1603,6 @@ cmd_apdu (assuan_context_t ctx, char *line) xfree (apdu); leave: - TEST_CARD_REMOVAL (ctrl, rc); return rc; } @@ -2015,7 +1707,7 @@ scd_command_handler (ctrl_t ctrl, int fd) else { rc = assuan_init_socket_server (ctx, INT2FD(fd), - ASSUAN_SOCKET_SERVER_ACCEPTED); + ASSUAN_SOCKET_SERVER_ACCEPTED); } if (rc) { @@ -2040,10 +1732,6 @@ scd_command_handler (ctrl_t ctrl, int fd) ctrl->server_local->ctrl_backlink = ctrl; ctrl->server_local->assuan_ctx = ctx; - /* We open the reader right at startup so that the ticker is able to - update the status file. */ - ctrl->server_local->vreader_idx = get_current_reader (); - /* Command processing loop. */ for (;;) { @@ -2160,8 +1848,8 @@ send_status_direct (ctrl_t ctrl, const char *keyword, const char *args) /* Helper to send the clients a status change notification. */ -static void -send_client_notifications (void) +void +send_client_notifications (app_t app) { struct { pid_t pid; @@ -2177,7 +1865,8 @@ send_client_notifications (void) for (sl=session_list; sl; sl = sl->next_session) { - if (sl->event_signal && sl->assuan_ctx) + if (sl->event_signal && sl->assuan_ctx + && sl->ctrl_backlink->app_ctx == app) { pid_t pid = assuan_get_pid (sl->assuan_ctx); #ifdef HAVE_W32_SYSTEM @@ -2230,153 +1919,10 @@ send_client_notifications (void) } } #endif /*!HAVE_W32_SYSTEM*/ - } - } -} - - - -/* This is the core of scd_update_reader_status_file but the caller - needs to take care of the locking. */ -static void -update_reader_status_file (int set_card_removed_flag) -{ - int idx; - unsigned int status; - - /* Note, that we only try to get the status, because it does not - make sense to wait here for a operation to complete. If we are - busy working with a card, delays in the status file update should - be acceptable. */ - for (idx=0; idx < DIM(vreader_table); idx++) - { - struct vreader_s *vr = vreader_table + idx; - struct server_local_s *sl; - int sw_apdu; - if (!vr->valid || vr->slot == -1) - continue; /* Not valid or reader not yet open. */ - - sw_apdu = apdu_get_status (vr->slot, 0, &status); - if (sw_apdu == SW_HOST_NO_READER) - { - /* Most likely the _reader_ has been unplugged. */ - status = 0; - } - else if (sw_apdu) - { - /* Get status failed. Ignore that. */ - continue; + sl->ctrl_backlink->app_ctx = NULL; + sl->card_removed = 1; + release_application (app); } - - if (vr->status != status) - { - char *fname; - char templ[50]; - FILE *fp; - - log_info ("updating reader %d (%d) status: 0x%04X->0x%04X\n", - idx, vr->slot, vr->status, status); - - /* FIXME: Should this be IDX instead of vr->slot? This - depends on how client sessions will associate the reader - status with their session. */ - snprintf (templ, sizeof templ, "reader_%d.status", vr->slot); - fname = make_filename (gnupg_homedir (), templ, NULL ); - fp = fopen (fname, "w"); - if (fp) - { - fprintf (fp, "%s\n", - (status & 1)? "USABLE": - (status & 4)? "ACTIVE": - (status & 2)? "PRESENT": "NOCARD"); - fclose (fp); - } - xfree (fname); - - /* If a status script is executable, run it. */ - { - const char *args[9], *envs[2]; - char numbuf1[30], numbuf2[30], numbuf3[30]; - char *homestr, *envstr; - gpg_error_t err; - - homestr = make_filename (gnupg_homedir (), NULL); - if (gpgrt_asprintf (&envstr, "GNUPGHOME=%s", homestr) < 0) - log_error ("out of core while building environment\n"); - else - { - envs[0] = envstr; - envs[1] = NULL; - - sprintf (numbuf1, "%d", vr->slot); - sprintf (numbuf2, "0x%04X", vr->status); - sprintf (numbuf3, "0x%04X", status); - args[0] = "--reader-port"; - args[1] = numbuf1; - args[2] = "--old-code"; - args[3] = numbuf2; - args[4] = "--new-code"; - args[5] = numbuf3; - args[6] = "--status"; - args[7] = ((status & 1)? "USABLE": - (status & 4)? "ACTIVE": - (status & 2)? "PRESENT": "NOCARD"); - args[8] = NULL; - - fname = make_filename (gnupg_homedir (), "scd-event", NULL); - err = gnupg_spawn_process_detached (fname, args, envs); - if (err && gpg_err_code (err) != GPG_ERR_ENOENT) - log_error ("failed to run event handler '%s': %s\n", - fname, gpg_strerror (err)); - xfree (fname); - xfree (envstr); - } - xfree (homestr); - } - - /* Set the card removed flag for all current sessions. */ - if (status == 0 && set_card_removed_flag) - update_card_removed (idx, 1); - - vr->status = status; - - /* Send a signal to all clients who applied for it. */ - send_client_notifications (); - } - - /* Check whether a disconnect is pending. */ - if (opt.card_timeout) - { - for (sl=session_list; sl; sl = sl->next_session) - if (!sl->disconnect_allowed) - break; - if (session_list && !sl) - { - /* FIXME: Use a real timeout. */ - /* At least one connection and all allow a disconnect. */ - log_info ("disconnecting card in reader %d (%d)\n", - idx, vr->slot); - apdu_disconnect (vr->slot); - } - } - } } - -/* This function is called by the ticker thread to check for changes - of the reader stati. It updates the reader status files and if - requested by the caller also send a signal to the caller. */ -void -scd_update_reader_status_file (void) -{ - int err; - err = npth_mutex_lock (&status_file_update_lock); - if (err) - return; /* locked - give up. */ - update_reader_status_file (1); - err = npth_mutex_unlock (&status_file_update_lock); - if (err) - log_error ("failed to release status_file_update lock: %s\n", - strerror (err)); -} |