1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-06-03 22:48:03 +02:00

scd: New command DEVINFO.

* scd/app.c (notify_cond): New condition variable.
(app_send_devinfo, app_wait): New.
(scd_update_reader_status_file): Kick NOTIFY_COND.
(initialize_module_command): Initialize NOTIFY_COND.
* scd/command.c (struct server_local_s):  Add watching_status.
(cmd_devinfo): New.
(register_commands): Add DEVINFO command.
(send_client_notifications): Write status change to DEVINFO channel.
* scd/scdaemon.h (app_wait, app_send_devinfo): New.

GnuPG-bug-id: 4864
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
This commit is contained in:
NIIBE Yutaka 2020-04-02 15:39:26 +09:00
parent 29f8f52bf8
commit 2ccbcfec12
3 changed files with 202 additions and 61 deletions

View File

@ -42,6 +42,9 @@ send_serialno_and_app_status (card_t card, int with_apps, ctrl_t ctrl);
* applications. */ * applications. */
static npth_mutex_t card_list_lock; static npth_mutex_t card_list_lock;
/* Notification to threads which keep watching the status change. */
static npth_cond_t notify_cond;
/* A list of card contexts. A card is a collection of applications /* A list of card contexts. A card is a collection of applications
* (described by app_t) on the same physical token. */ * (described by app_t) on the same physical token. */
static card_t card_top; static card_t card_top;
@ -280,6 +283,37 @@ app_dump_state (void)
} }
gpg_error_t
app_send_devinfo (ctrl_t ctrl)
{
card_t c;
app_t a;
int no_device;
send_status_direct (ctrl, "DEVINFO_START", "");
npth_mutex_lock (&card_list_lock);
no_device = (card_top == NULL);
for (c = card_top; c; c = c->next)
{
char *serialno;
char card_info[80];
serialno = card_get_serialno (c);
snprintf (card_info, sizeof card_info, "DEVICE %s %s",
strcardtype (c->cardtype), serialno);
xfree (serialno);
for (a = c->app; a; a = a->next)
send_status_direct (ctrl, card_info, strapptype (a->apptype));
}
npth_mutex_unlock (&card_list_lock);
send_status_direct (ctrl, "DEVINFO_END", "");
return no_device ? gpg_error (GPG_ERR_NOT_FOUND): 0;
}
/* Check whether the application NAME is allowed. This does not mean /* Check whether the application NAME is allowed. This does not mean
we have support for it though. */ we have support for it though. */
static int static int
@ -1934,6 +1968,7 @@ scd_update_reader_status_file (void)
{ {
card_t card, card_next; card_t card, card_next;
int periodical_check_needed = 0; int periodical_check_needed = 0;
int reported = 0;
npth_mutex_lock (&card_list_lock); npth_mutex_lock (&card_list_lock);
for (card = card_top; card; card = card_next) for (card = card_top; card; card = card_next)
@ -1968,6 +2003,7 @@ scd_update_reader_status_file (void)
{ {
report_change (card->slot, card->card_status, status); report_change (card->slot, card->card_status, status);
send_client_notifications (card, status == 0); send_client_notifications (card, status == 0);
reported++;
if (status == 0) if (status == 0)
{ {
@ -1992,6 +2028,9 @@ scd_update_reader_status_file (void)
} }
} }
if (reported)
npth_cond_broadcast (&notify_cond);
npth_mutex_unlock (&card_list_lock); npth_mutex_unlock (&card_list_lock);
return periodical_check_needed; return periodical_check_needed;
@ -2013,6 +2052,14 @@ initialize_module_command (void)
return err; return err;
} }
err = npth_cond_init (&notify_cond, NULL);
if (err)
{
err = gpg_error_from_syserror ();
log_error ("npth_cond_init failed: %s\n", gpg_strerror (err));
return err;
}
return apdu_init (); return apdu_init ();
} }
@ -2279,3 +2326,11 @@ app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str,
npth_mutex_unlock (&card_list_lock); npth_mutex_unlock (&card_list_lock);
return c; return c;
} }
void
app_wait (void)
{
npth_mutex_lock (&card_list_lock);
npth_cond_wait (&notify_cond, &card_list_lock);
npth_mutex_unlock (&card_list_lock);
}

View File

@ -89,12 +89,14 @@ struct server_local_s
/* True if the card has been removed and a reset is required to /* True if the card has been removed and a reset is required to
continue operation. */ continue operation. */
int card_removed; unsigned int card_removed:1;
/* If set to true we will be terminate ourself at the end of the /* If set to true we will be terminate ourself at the end of the
this session. */ this session. */
int stopme; unsigned int stopme:1;
/* If set to true, status change will be reported. */
unsigned int watching_status:1;
}; };
@ -2127,6 +2129,77 @@ send_keyinfo (ctrl_t ctrl, int data, const char *keygrip_str,
} }
static const char hlp_devinfo[] =
"DEVINFO [--watch]\n"
"\n"
"Return information about devices. If the option --watch is given,\n"
"it keeps reporting status change until it detects no device is\n"
"available."
"The information is returned as a status line using the format:\n"
"\n"
" DEVICE <card_type> <serialno> <app_type>\n"
"\n"
"CARD_TYPE is the type of the card.\n"
"\n"
"SERIALNO is an ASCII string with the serial number of the\n"
" smartcard. If the serial number is not known a single\n"
" dash '-' is used instead.\n"
"\n"
"APP_TYPE is the type of the application.\n"
"\n"
"More information may be added in the future.";
static gpg_error_t
cmd_devinfo (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err = 0;
int watch = 0;
if (has_option (line, "--watch"))
{
watch = 1;
ctrl->server_local->watching_status = 1;
}
/* Firstly, send information of available devices. */
err = app_send_devinfo (ctrl);
/* If not watching, that's all. */
if (!watch)
return err;
if (err && gpg_err_code (err) != GPG_ERR_NOT_FOUND)
return err;
/* Secondly, try to open device(s) available. */
/* Clear the remove flag so that the open_card is able to reread it. */
if (ctrl->server_local->card_removed)
ctrl->server_local->card_removed = 0;
if ((err = open_card (ctrl))
&& gpg_err_code (err) != GPG_ERR_ENODEV)
return err;
err = 0;
/* Remove reference(s) to the card. */
ctrl->card_ctx = NULL;
ctrl->current_apptype = APPTYPE_NONE;
card_unref (ctrl->card_ctx);
/* Then, keep watching the status change. */
while (!err)
{
app_wait ();
/* Send information of available devices. */
err = app_send_devinfo (ctrl);
}
ctrl->server_local->watching_status = 0;
return 0;
}
/* Return true if the command CMD implements the option OPT. */ /* Return true if the command CMD implements the option OPT. */
static int static int
@ -2179,6 +2252,7 @@ register_commands (assuan_context_t ctx)
{ "APDU", cmd_apdu, hlp_apdu }, { "APDU", cmd_apdu, hlp_apdu },
{ "KILLSCD", cmd_killscd, hlp_killscd }, { "KILLSCD", cmd_killscd, hlp_killscd },
{ "KEYINFO", cmd_keyinfo, hlp_keyinfo }, { "KEYINFO", cmd_keyinfo, hlp_keyinfo },
{ "DEVINFO", cmd_devinfo, hlp_devinfo },
{ NULL } { NULL }
}; };
int i, rc; int i, rc;
@ -2671,76 +2745,86 @@ send_client_notifications (card_t card, int removal)
struct server_local_s *sl; struct server_local_s *sl;
for (sl=session_list; sl; sl = sl->next_session) for (sl=session_list; sl; sl = sl->next_session)
if (sl->ctrl_backlink && sl->ctrl_backlink->card_ctx == card) {
{ if (sl->watching_status)
pid_t pid; {
if (removal)
assuan_write_status (sl->assuan_ctx, "DEVINFO_STATUS", "removal");
else
assuan_write_status (sl->assuan_ctx, "DEVINFO_STATUS", "new");
}
if (sl->ctrl_backlink && sl->ctrl_backlink->card_ctx == card)
{
pid_t pid;
#ifdef HAVE_W32_SYSTEM #ifdef HAVE_W32_SYSTEM
HANDLE handle; HANDLE handle;
#else #else
int signo; int signo;
#endif #endif
if (removal) if (removal)
{ {
sl->ctrl_backlink->card_ctx = NULL; sl->ctrl_backlink->card_ctx = NULL;
sl->ctrl_backlink->current_apptype = APPTYPE_NONE; sl->ctrl_backlink->current_apptype = APPTYPE_NONE;
sl->card_removed = 1; sl->card_removed = 1;
card_unref_locked (card); card_unref_locked (card);
} }
if (!sl->event_signal || !sl->assuan_ctx) if (!sl->event_signal || !sl->assuan_ctx)
continue; continue;
pid = assuan_get_pid (sl->assuan_ctx); pid = assuan_get_pid (sl->assuan_ctx);
#ifdef HAVE_W32_SYSTEM #ifdef HAVE_W32_SYSTEM
handle = sl->event_signal; handle = sl->event_signal;
for (kidx=0; kidx < killidx; kidx++) for (kidx=0; kidx < killidx; kidx++)
if (killed[kidx].pid == pid if (killed[kidx].pid == pid
&& killed[kidx].handle == handle) && killed[kidx].handle == handle)
break; break;
if (kidx < killidx) if (kidx < killidx)
log_info ("event %p (%p) already triggered for client %d\n", log_info ("event %p (%p) already triggered for client %d\n",
sl->event_signal, handle, (int)pid);
else
{
log_info ("triggering event %p (%p) for client %d\n",
sl->event_signal, handle, (int)pid); sl->event_signal, handle, (int)pid);
if (!SetEvent (handle)) else
log_error ("SetEvent(%p) failed: %s\n", {
sl->event_signal, w32_strerror (-1)); log_info ("triggering event %p (%p) for client %d\n",
if (killidx < DIM (killed)) sl->event_signal, handle, (int)pid);
{ if (!SetEvent (handle))
killed[killidx].pid = pid; log_error ("SetEvent(%p) failed: %s\n",
killed[killidx].handle = handle; sl->event_signal, w32_strerror (-1));
killidx++; if (killidx < DIM (killed))
} {
} killed[killidx].pid = pid;
killed[killidx].handle = handle;
killidx++;
}
}
#else /*!HAVE_W32_SYSTEM*/ #else /*!HAVE_W32_SYSTEM*/
signo = sl->event_signal; signo = sl->event_signal;
if (pid != (pid_t)(-1) && pid && signo > 0) if (pid != (pid_t)(-1) && pid && signo > 0)
{ {
for (kidx=0; kidx < killidx; kidx++) for (kidx=0; kidx < killidx; kidx++)
if (killed[kidx].pid == pid if (killed[kidx].pid == pid
&& killed[kidx].signo == signo) && killed[kidx].signo == signo)
break; break;
if (kidx < killidx) if (kidx < killidx)
log_info ("signal %d already sent to client %d\n", log_info ("signal %d already sent to client %d\n",
signo, (int)pid);
else
{
log_info ("sending signal %d to client %d\n",
signo, (int)pid); signo, (int)pid);
kill (pid, signo); else
if (killidx < DIM (killed)) {
{ log_info ("sending signal %d to client %d\n",
killed[killidx].pid = pid; signo, (int)pid);
killed[killidx].signo = signo; kill (pid, signo);
killidx++; if (killidx < DIM (killed))
} {
} killed[killidx].pid = pid;
} killed[killidx].signo = signo;
killidx++;
}
}
}
#endif /*!HAVE_W32_SYSTEM*/ #endif /*!HAVE_W32_SYSTEM*/
} }
}
} }

View File

@ -153,5 +153,7 @@ int get_active_connection_count (void);
/*-- app.c --*/ /*-- app.c --*/
int scd_update_reader_status_file (void); int scd_update_reader_status_file (void);
void app_wait (void);
gpg_error_t app_send_devinfo (ctrl_t ctrl);
#endif /*SCDAEMON_H*/ #endif /*SCDAEMON_H*/