aboutsummaryrefslogtreecommitdiffstats
path: root/scd/command.c
diff options
context:
space:
mode:
authorNIIBE Yutaka <[email protected]>2016-12-28 03:29:17 +0000
committerNIIBE Yutaka <[email protected]>2016-12-28 03:29:17 +0000
commit4cc9fc5eb9bd91d943c185d59da4a2b4cb885ee6 (patch)
tree35e893cdc578bbf33f3e9de350581177392f60a0 /scd/command.c
parentscd: Simplify monitoring card removal. (diff)
downloadgnupg-4cc9fc5eb9bd91d943c185d59da4a2b4cb885ee6.tar.gz
gnupg-4cc9fc5eb9bd91d943c185d59da4a2b4cb885ee6.zip
scd: APP centric approach for device management.
* scd/app.c (lock_app): Rename from lock_reader and use internal field of APP. (unlock_app): Likewise. (app_dump_state): Use APP. (application_notify_card_reset): Remove. (check_conflict): Change API for APP, instead of SLOT. (check_application_conflict): Likewise. (release_application_internal): New. (app_reset): New. (app_new_register): New. (select_application): Change API for APP, instead of SLOT. (deallocate_app, release_application): Modify for manage link. (report_change): New. (scd_update_reader_status_file): Moved from command.c and use APP list, instead of VREADER. (initialize_module_command): Moved from command.c. * scd/command.c (TEST_CARD_REMOVAL): Remove. (IS_LOCKED): Simplify. (vreader_table): Remove. (vreader_slot, update_card_removed): Remove. (do_reset): Call app_reset. (get_current_reader): Remove. (open_card): Add SCAN arg. (cmd_serialno): No retry, since retry is done in lower layer in apdu.c. No do_reset, since it is done in lower layer. Add clearing card_removed flag. (cmd_disconnect): Call apdu_disconnect. (send_client_notifications): Modify for APP. (update_reader_status_file): Remove. -- APP is the abstraction of the card application. For management of cards, it is better to focus on the APP instead of the physical reader. This change makes support of multiple card/token easier. Signed-off-by: NIIBE Yutaka <[email protected]>
Diffstat (limited to 'scd/command.c')
-rw-r--r--scd/command.c586
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));
-}