mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01: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:
parent
29f8f52bf8
commit
2ccbcfec12
55
scd/app.c
55
scd/app.c
@ -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 (¬ify_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 (¬ify_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 (¬ify_cond, &card_list_lock);
|
||||||
|
npth_mutex_unlock (&card_list_lock);
|
||||||
|
}
|
||||||
|
206
scd/command.c
206
scd/command.c
@ -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*/
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user