diff options
author | NIIBE Yutaka <gniibe@fsij.org> | 2020-04-02 08:39:26 +0200 |
---|---|---|
committer | NIIBE Yutaka <gniibe@fsij.org> | 2020-04-02 08:39:26 +0200 |
commit | 2ccbcfec121f768574a59aa2ecff22d8b422d61b (patch) | |
tree | 15c6a997c0130805e0574f8a4a15cdec4d1d585d /scd/command.c | |
parent | scd:p15: Cache the PIN. (diff) | |
download | gnupg2-2ccbcfec121f768574a59aa2ecff22d8b422d61b.tar.xz gnupg2-2ccbcfec121f768574a59aa2ecff22d8b422d61b.zip |
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>
Diffstat (limited to 'scd/command.c')
-rw-r--r-- | scd/command.c | 208 |
1 files changed, 146 insertions, 62 deletions
diff --git a/scd/command.c b/scd/command.c index 030435a9a..159c6f2dc 100644 --- a/scd/command.c +++ b/scd/command.c @@ -89,12 +89,14 @@ struct server_local_s /* True if the card has been removed and a reset is required to continue operation. */ - int card_removed; + unsigned int card_removed:1; /* If set to true we will be terminate ourself at the end of the 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. */ static int @@ -2179,6 +2252,7 @@ register_commands (assuan_context_t ctx) { "APDU", cmd_apdu, hlp_apdu }, { "KILLSCD", cmd_killscd, hlp_killscd }, { "KEYINFO", cmd_keyinfo, hlp_keyinfo }, + { "DEVINFO", cmd_devinfo, hlp_devinfo }, { NULL } }; int i, rc; @@ -2671,76 +2745,86 @@ send_client_notifications (card_t card, int removal) struct server_local_s *sl; for (sl=session_list; sl; sl = sl->next_session) - if (sl->ctrl_backlink && sl->ctrl_backlink->card_ctx == card) - { - pid_t pid; + { + if (sl->watching_status) + { + 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 - HANDLE handle; + HANDLE handle; #else - int signo; + int signo; #endif - if (removal) - { - sl->ctrl_backlink->card_ctx = NULL; - sl->ctrl_backlink->current_apptype = APPTYPE_NONE; - sl->card_removed = 1; - card_unref_locked (card); - } + if (removal) + { + sl->ctrl_backlink->card_ctx = NULL; + sl->ctrl_backlink->current_apptype = APPTYPE_NONE; + sl->card_removed = 1; + card_unref_locked (card); + } - if (!sl->event_signal || !sl->assuan_ctx) - continue; + if (!sl->event_signal || !sl->assuan_ctx) + continue; - pid = assuan_get_pid (sl->assuan_ctx); + pid = assuan_get_pid (sl->assuan_ctx); #ifdef HAVE_W32_SYSTEM - handle = sl->event_signal; - for (kidx=0; kidx < killidx; kidx++) - if (killed[kidx].pid == pid - && killed[kidx].handle == handle) - break; - if (kidx < killidx) - 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", + handle = sl->event_signal; + for (kidx=0; kidx < killidx; kidx++) + if (killed[kidx].pid == pid + && killed[kidx].handle == handle) + break; + if (kidx < killidx) + log_info ("event %p (%p) already triggered for client %d\n", sl->event_signal, handle, (int)pid); - if (!SetEvent (handle)) - log_error ("SetEvent(%p) failed: %s\n", - sl->event_signal, w32_strerror (-1)); - if (killidx < DIM (killed)) - { - killed[killidx].pid = pid; - killed[killidx].handle = handle; - killidx++; - } - } + else + { + log_info ("triggering event %p (%p) for client %d\n", + sl->event_signal, handle, (int)pid); + if (!SetEvent (handle)) + log_error ("SetEvent(%p) failed: %s\n", + sl->event_signal, w32_strerror (-1)); + if (killidx < DIM (killed)) + { + killed[killidx].pid = pid; + killed[killidx].handle = handle; + killidx++; + } + } #else /*!HAVE_W32_SYSTEM*/ - signo = sl->event_signal; - - if (pid != (pid_t)(-1) && pid && signo > 0) - { - for (kidx=0; kidx < killidx; kidx++) - if (killed[kidx].pid == pid - && killed[kidx].signo == signo) - break; - if (kidx < killidx) - log_info ("signal %d already sent to client %d\n", - signo, (int)pid); - else - { - log_info ("sending signal %d to client %d\n", + signo = sl->event_signal; + + if (pid != (pid_t)(-1) && pid && signo > 0) + { + for (kidx=0; kidx < killidx; kidx++) + if (killed[kidx].pid == pid + && killed[kidx].signo == signo) + break; + if (kidx < killidx) + log_info ("signal %d already sent to client %d\n", signo, (int)pid); - kill (pid, signo); - if (killidx < DIM (killed)) - { - killed[killidx].pid = pid; - killed[killidx].signo = signo; - killidx++; - } - } - } + else + { + log_info ("sending signal %d to client %d\n", + signo, (int)pid); + kill (pid, signo); + if (killidx < DIM (killed)) + { + killed[killidx].pid = pid; + killed[killidx].signo = signo; + killidx++; + } + } + } #endif /*!HAVE_W32_SYSTEM*/ - } + } + } } |