From 92b1342d2f6c235a142451036365b7ac75cef461 Mon Sep 17 00:00:00 2001
From: Ben Kibbey
Date: Fri, 19 Dec 2014 18:18:27 -0500
Subject: [PATCH] Add KILL command and GETINFO --verbose CLIENTS.
The KILL command can be used to terminate another client (obtained via
GETINFO) when the current client is the invoking user.
---
doc/pwmd.html | 152 +++++++++++++++++++++++++++++++----------------------
src/commands.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++---------
src/common.h | 1 +
src/pwmd.c | 1 +
4 files changed, 227 insertions(+), 88 deletions(-)
diff --git a/doc/pwmd.html b/doc/pwmd.html
index f72e4162..b08389bb 100644
--- a/doc/pwmd.html
+++ b/doc/pwmd.html
@@ -726,6 +726,8 @@ Next: Status Messages, P
• KEYGRIP: | |
|
+• KILL: | |
+ |
• LIST: | |
|
• LOCK: | |
@@ -989,12 +991,15 @@ Next: HELP, Previous:
Syntax:
- GETINFO [--data] CACHE | CLIENTS | PID | USER | LAST_ERROR | VERSION
+GETINFO [--data] [--verbose] CACHE | CLIENTS | PID | USER | LAST_ERROR | VERSION
-Get server and other information: cache returns the number of cached
-documents via a status message. clients returns the number of
-connected clients via a status message. pid returns the process ID
+ Get server and other information: CACHE returns the number of cached
+documents via a status message. CLIENTS returns the number of
+connected clients via a status message or a list of connected clients when
+the --verbose parameter is used. The list contains space delimited
+fields specifying the thread ID, client name and opened file and is always
+returned with a data response. PID returns the process ID
number of the server via a data response. VERSION returns the server
version number and compile-time features with a data response with each
being space delimited. LAST_ERROR returns a detailed description of
@@ -1077,7 +1082,7 @@ command.
21 KEYGRIP command
@@ -1098,13 +1103,32 @@ GPG_ERR_NOT_SUPPORTED.
+
+
+
+22 KILL command
+
+Syntax:
+
+
+Terminates the client identified by thread_id and releases any file
+lock or other resources it has held. See GETINFO for details about listing
+connected clients.
+
+
+
-22 LIST command
+23 LIST command
Syntax:
@@ -1154,7 +1178,7 @@ arguments are retrieved via a server INQUIRE.
Next: LS, Previous: LIST, Up: Commands [ Contents]
-23 LOCK command
+24 LOCK command
Syntax:
-24 LS command
+25 LS command
Syntax:
-25 MOVE command
+26 MOVE command
Syntax:
-26 NOP command
+27 NOP command
Syntax:
-27 OPEN command
+28 OPEN command
Syntax:
-28 OPTION command
+29 OPTION command
Syntax:
-29 PASSWD command
+30 PASSWD command
Syntax:
@@ -1372,7 +1396,7 @@ the data file, although a passphrase may be required when changing it.
Next: RENAME, Previous: PASSWD, Up: Commands [ Contents]
-30 REALPATH command
+31 REALPATH command
Syntax:
-31 RENAME command
+32 RENAME command
Syntax:
-32 RESET command
+33 RESET command
Syntax:
-33 SAVE command
+34 SAVE command
Syntax:
@@ -1496,7 +1520,7 @@ has no effect with symmetrically encrypted data files.
Next: UNLOCK, Previous: SAVE, Up: Commands [ Contents]
-34 STORE command
+35 STORE command
Syntax:
-35 UNLOCK command
+36 UNLOCK command
Syntax:
-36 XPATH command
+37 XPATH command
Syntax:
-37 XPATHATTR command
+38 XPATHATTR command
Syntax:
-38 Status messages and their meanings
+39 Status messages and their meanings
Some commands send status messages to inform the client about certain
operations or as a progress indicator. Status messages begin with a
KEYWORD followed by a status description for status messages that
@@ -1668,7 +1692,7 @@ and the other being the total bytes to be transferred. |
Next: Signals, Previous: Status Messages, Up: Top [Contents]
-39 The target
attribute
+40 The target
attribute
A case sensitive attribute named target
is treated specially
when found in each element of an element path. This attribute, like other
@@ -1726,7 +1750,7 @@ path after resolving all target
attributes.
Next: Concept Index, Previous: Target Attribute, Up: Top [Contents]
-40 Recognized signals
+41 Recognized signals
Sending the SIGHUP signal to a pwmd
process will reload the
configuration file and sending SIGUSR1 will clear the entire file
@@ -1770,25 +1794,26 @@ Previous: Signals, Up: 19 IMPORT command
20 ISCACHED command
21 KEYGRIP command
-22 LIST command
-23 LOCK command
-24 LS command
-25 MOVE command
-26 NOP command
-27 OPEN command
-28 OPTION command
-29 PASSWD command
-30 REALPATH command
-31 RENAME command
-32 RESET command
-33 SAVE command
-34 STORE command
-35 UNLOCK command
-36 XPATH command
-37 XPATHATTR command
-38 Status messages and their meanings
-39 The target
attribute
-40 Recognized signals
+22 KILL command
+23 LIST command
+24 LOCK command
+25 LS command
+26 MOVE command
+27 NOP command
+28 OPEN command
+29 OPTION command
+30 PASSWD command
+31 REALPATH command
+32 RENAME command
+33 RESET command
+34 SAVE command
+35 STORE command
+36 UNLOCK command
+37 XPATH command
+38 XPATHATTR command
+39 Status messages and their meanings
+40 The target
attribute
+41 Recognized signals
Concept Index
@@ -1820,25 +1845,26 @@ Previous: Signals, Up: 19 IMPORT command
20 ISCACHED command
21 KEYGRIP command
-22 LIST command
-23 LOCK command
-24 LS command
-25 MOVE command
-26 NOP command
-27 OPEN command
-28 OPTION command
-29 PASSWD command
-30 REALPATH command
-31 RENAME command
-32 RESET command
-33 SAVE command
-34 STORE command
-35 UNLOCK command
-36 XPATH command
-37 XPATHATTR command
-38 Status messages and their meanings
-39 The target
attribute
-40 Recognized signals
+22 KILL command
+23 LIST command
+24 LOCK command
+25 LS command
+26 MOVE command
+27 NOP command
+28 OPEN command
+29 OPTION command
+30 PASSWD command
+31 REALPATH command
+32 RENAME command
+33 RESET command
+34 SAVE command
+35 STORE command
+36 UNLOCK command
+37 XPATH command
+38 XPATHATTR command
+39 Status messages and their meanings
+40 The target
attribute
+41 Recognized signals
Concept Index
diff --git a/src/commands.c b/src/commands.c
index 13d8c732..582986c9 100644
--- a/src/commands.c
+++ b/src/commands.c
@@ -61,7 +61,7 @@
#define OPT_NO_PASSPHRASE 0x0002
#define OPT_RESET 0x0004
#define OPT_LIST_RECURSE 0x0008
-#define OPT_LIST_VERBOSE 0x0010
+#define OPT_VERBOSE 0x0010
#define OPT_LOCK 0x0020
#define OPT_LOCK_ON_OPEN 0x0040
#define OPT_SIGN 0x0080
@@ -1573,11 +1573,11 @@ parse_list_opt_norecurse (void *data, void *value)
}
static gpg_error_t
-parse_list_opt_verbose (void *data, void *value)
+parse_opt_verbose (void *data, void *value)
{
struct client_s *client = data;
- client->opts |= OPT_LIST_VERBOSE;
+ client->opts |= OPT_VERBOSE;
return 0;
}
@@ -1679,7 +1679,7 @@ do_list (assuan_context_t ctx, char *line)
elements->recurse = client->opts & OPT_LIST_RECURSE;
elements->verbose =
- (client->opts & OPT_LIST_VERBOSE) | (client->opts & OPT_LIST_WITH_TARGET);
+ (client->opts & OPT_VERBOSE) | (client->opts & OPT_LIST_WITH_TARGET);
elements->with_target = client->opts & OPT_LIST_WITH_TARGET;
if (!line || !*line)
@@ -1723,7 +1723,7 @@ do_list (assuan_context_t ctx, char *line)
elements->recurse = client->opts & OPT_LIST_RECURSE;
elements->verbose =
- (client->opts & OPT_LIST_VERBOSE) | (client->opts &
+ (client->opts & OPT_VERBOSE) | (client->opts &
OPT_LIST_WITH_TARGET);
elements->with_target = client->opts & OPT_LIST_WITH_TARGET;
pthread_cleanup_push (list_command_cleanup2, elements);
@@ -1767,7 +1767,7 @@ list_command (assuan_context_t ctx, char *line)
struct argv_s *args[] = {
&(struct argv_s) {"no-recurse", OPTION_TYPE_NOARG,
parse_list_opt_norecurse},
- &(struct argv_s) {"verbose", OPTION_TYPE_NOARG, parse_list_opt_verbose},
+ &(struct argv_s) {"verbose", OPTION_TYPE_NOARG, parse_opt_verbose},
&(struct argv_s) {"inquire", OPTION_TYPE_NOARG, parse_opt_inquire},
&(struct argv_s) {"with-target", OPTION_TYPE_NOARG,
parse_list_opt_target},
@@ -1784,7 +1784,7 @@ list_command (assuan_context_t ctx, char *line)
return send_error (ctx, rc);
if (client->opts & OPT_LIST_ALL)
- client->opts |= OPT_LIST_RECURSE | OPT_LIST_VERBOSE;
+ client->opts |= OPT_LIST_RECURSE | OPT_VERBOSE;
if (client->opts & OPT_INQUIRE)
{
@@ -3269,13 +3269,19 @@ option_command (assuan_context_t ctx, char *line)
if (tmp)
xfree (tmp);
+ MUTEX_LOCK (&cn_mutex);
+ xfree (client->thd->name);
+ client->thd->name = NULL;
+
if (!value || !*value)
- {
- pthread_setspecific (thread_name_key, str_dup (""));
- goto done;
- }
+ pthread_setspecific (thread_name_key, str_dup (""));
+ else
+ {
+ client->thd->name = str_dup (value);
+ pthread_setspecific (thread_name_key, str_dup (value));
+ }
- pthread_setspecific (thread_name_key, str_dup (value));
+ MUTEX_UNLOCK (&cn_mutex);
goto done;
}
else if (strcasecmp (name, (char *) "lc-messages") == 0)
@@ -4365,6 +4371,64 @@ parse_opt_data (void *data, void *value)
}
static gpg_error_t
+send_client_list (assuan_context_t ctx)
+{
+ struct client_s *client = assuan_get_pointer (ctx);
+ gpg_error_t rc = 0;
+ char buf[ASSUAN_LINELENGTH];
+
+ if (client->opts & OPT_VERBOSE)
+ {
+ unsigned i, t;
+ char **list = NULL;
+ char *line;
+
+ MUTEX_LOCK (&cn_mutex);
+ pthread_cleanup_push (cleanup_mutex_cb, &cn_mutex);
+ t = slist_length (cn_thread_list);
+
+ for (i = 0; i < t; i++)
+ {
+ struct client_thread_s *thd = slist_nth_data (cn_thread_list, i);
+
+ if (!strv_printf (&list, "%p %s %s", thd->tid,
+ thd->name ? thd->name : "-",
+ thd->cl && thd->cl->filename
+ ? thd->cl->filename : "-"))
+ {
+ strv_free (list);
+ rc = GPG_ERR_ENOMEM;
+ break;
+ }
+ }
+
+ pthread_cleanup_pop (1);
+ if (rc)
+ return rc;
+
+ line = strv_join ("\n", list);
+ strv_free (list);
+ pthread_cleanup_push (xfree, line);
+ rc = xfer_data (ctx, line, strlen (line));
+ pthread_cleanup_pop (1);
+ return rc;
+ }
+
+ if (client->opts & OPT_DATA)
+ {
+ MUTEX_LOCK (&cn_mutex);
+ pthread_cleanup_push (cleanup_mutex_cb, &cn_mutex);
+ snprintf (buf, sizeof (buf), "%i", slist_length (cn_thread_list));
+ pthread_cleanup_pop (1);
+ rc = xfer_data (ctx, buf, strlen (buf));
+ }
+ else
+ rc = send_status (ctx, STATUS_CLIENTS, NULL);
+
+ return rc;
+}
+
+static gpg_error_t
getinfo_command (assuan_context_t ctx, char *line)
{
struct client_s *client = assuan_get_pointer (ctx);
@@ -4372,6 +4436,7 @@ getinfo_command (assuan_context_t ctx, char *line)
char buf[ASSUAN_LINELENGTH];
struct argv_s *args[] = {
&(struct argv_s) {"data", OPTION_TYPE_NOARG, parse_opt_data},
+ &(struct argv_s) {"verbose", OPTION_TYPE_NOARG, parse_opt_verbose},
NULL
};
@@ -4381,15 +4446,7 @@ getinfo_command (assuan_context_t ctx, char *line)
if (!strcasecmp (line, "clients"))
{
- if (client->opts & OPT_DATA)
- {
- MUTEX_LOCK (&cn_mutex);
- snprintf (buf, sizeof (buf), "%i", slist_length (cn_thread_list));
- MUTEX_UNLOCK (&cn_mutex);
- rc = xfer_data (ctx, buf, strlen (buf));
- }
- else
- rc = send_status (ctx, STATUS_CLIENTS, NULL);
+ rc = send_client_list (ctx);
}
else if (!strcasecmp (line, "cache"))
{
@@ -4492,6 +4549,50 @@ send_status_cb (void *user, const char *line)
#endif
static gpg_error_t
+kill_command (assuan_context_t ctx, char *line)
+{
+#ifdef HAVE_PTHREAD_CANCEL
+ struct client_s *client = assuan_get_pointer (ctx);
+ gpg_error_t rc;
+
+ if (!line || !*line)
+ return send_error (ctx, GPG_ERR_SYNTAX);
+
+ rc = peer_is_invoker (client);
+ if (!rc)
+ {
+ unsigned i, t;
+
+ MUTEX_LOCK (&cn_mutex);
+ pthread_cleanup_push (cleanup_mutex_cb, &cn_mutex);
+ t = slist_length (cn_thread_list);
+
+ for (i = 0; i < t; i++)
+ {
+ struct client_thread_s *thd = slist_nth_data (cn_thread_list, i);
+ char *tmp = str_asprintf ("%p", thd->tid);
+
+ if (strcmp (line, tmp))
+ {
+ xfree (tmp);
+ continue;
+ }
+
+ xfree (tmp);
+ rc = pthread_cancel (thd->tid);
+ break;
+ }
+
+ pthread_cleanup_pop (1);
+ }
+
+ return send_error (ctx, rc);
+#else
+ return send_error (ctx, GPG_ERR_NOT_IMPLEMENTED);
+#endif
+}
+
+static gpg_error_t
agent_command (assuan_context_t ctx, char *line)
{
gpg_error_t rc = 0;
@@ -4548,11 +4649,21 @@ init_commands ()
"@command{gpg-agent}."
));
+ new_command("KILL", 1, 0, kill_command, _(
+"KILL \n"
+"Terminates the client identified by @var{thread_id} and releases any file "
+"lock or other resources it has held. @xref{GETINFO} for details about listing "
+"connected clients.\n"
+));
+
new_command("GETINFO", 1, 1, getinfo_command, _(
-"GETINFO [--data] CACHE | CLIENTS | PID | USER | LAST_ERROR | VERSION\n"
-"Get server and other information: @var{cache} returns the number of cached "
-"documents via a status message. @var{clients} returns the number of "
-"connected clients via a status message. @var{pid} returns the process ID "
+"GETINFO [--data] [--verbose] CACHE | CLIENTS | PID | USER | LAST_ERROR | VERSION\n"
+"Get server and other information: @var{CACHE} returns the number of cached "
+"documents via a status message. @var{CLIENTS} returns the number of "
+"connected clients via a status message or a list of connected clients when "
+"the @option{--verbose} parameter is used. The list contains space delimited "
+"fields specifying the thread ID, client name and opened file and is always "
+"returned with a data response. @var{PID} returns the process ID "
"number of the server via a data response. @var{VERSION} returns the server "
"version number and compile-time features with a data response with each "
"being space delimited. @var{LAST_ERROR} returns a detailed description of "
diff --git a/src/common.h b/src/common.h
index c80ad08d..9c727fde 100644
--- a/src/common.h
+++ b/src/common.h
@@ -61,6 +61,7 @@
struct client_thread_s
{
pthread_t tid;
+ char *name;
int fd;
pthread_mutex_t status_mutex;
struct status_msg_s *msg_queue;
diff --git a/src/pwmd.c b/src/pwmd.c
index 41fc9917..191b2ef6 100644
--- a/src/pwmd.c
+++ b/src/pwmd.c
@@ -1069,6 +1069,7 @@ cleanup_cb (void *arg)
send_status_all (STATUS_CLIENTS, NULL);
}
+ xfree (cn->name);
xfree (cn);
pthread_cond_signal (&quit_cond);
}
--
2.11.4.GIT