tool: Add a 'search' command for looking up items and details

The output format is meant to be parseable in the Desktop file format.
Update the documentation as well.

https://bugzilla.gnome.org/show_bug.cgi?id=693881
This commit is contained in:
Stef Walter 2013-02-15 14:18:50 +01:00
parent c2d6affadd
commit 3b84dce476
2 changed files with 182 additions and 6 deletions

View File

@ -39,6 +39,9 @@
<cmdsynopsis> <cmdsynopsis>
<command>secret-tool clear <arg choice="req">attribute</arg> <arg choice="req">value</arg> ...</command> <command>secret-tool clear <arg choice="req">attribute</arg> <arg choice="req">value</arg> ...</command>
</cmdsynopsis> </cmdsynopsis>
<cmdsynopsis>
<command>secret-tool search <arg choice="opt">--all</arg><arg choice="req">attribute</arg> <arg choice="req">value</arg> ...</command>
</cmdsynopsis>
</refsynopsisdiv> </refsynopsisdiv>
<refsect1> <refsect1>
@ -105,6 +108,31 @@
removed.</para> removed.</para>
</refsect1> </refsect1>
<refsect1>
<title>Search</title>
<para>This command searches for and prints details on matching
items in secret service. Specify the same attribute and value
pairs that you passed in when storing the password. You can use the
following options:</para>
<variablelist>
<varlistentry>
<term><option>--all</option></term>
<listitem><para>Return all matching results, rather than
just the one of the matches. Without this option, the
first unlocked match returned from the service will
be printed.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--unlock</option></term>
<listitem><para>Unlock items that are locked and then
print out their details. Without this option, locked items
are skipped.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1> <refsect1>
<title>Exit status</title> <title>Exit status</title>

View File

@ -14,6 +14,7 @@
#include "config.h" #include "config.h"
#include "secret-item.h"
#include "secret-password.h" #include "secret-password.h"
#include "secret-service.h" #include "secret-service.h"
#include "secret-value.h" #include "secret-value.h"
@ -24,6 +25,7 @@
#include <locale.h> #include <locale.h>
#include <limits.h> #include <limits.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#define SECRET_ALIAS_PREFIX "/org/freedesktop/secrets/aliases/" #define SECRET_ALIAS_PREFIX "/org/freedesktop/secrets/aliases/"
@ -66,6 +68,7 @@ usage (void)
g_printerr ("usage: secret-tool store --label='label' attribute value ...\n"); g_printerr ("usage: secret-tool store --label='label' attribute value ...\n");
g_printerr (" secret-tool lookup attribute value ...\n"); g_printerr (" secret-tool lookup attribute value ...\n");
g_printerr (" secret-tool clear attribute value ...\n"); g_printerr (" secret-tool clear attribute value ...\n");
g_printerr (" secret-tool search [--all] [--details] attribute value ...\n");
exit (2); exit (2);
} }
@ -150,17 +153,12 @@ secret_tool_action_clear (int argc,
} }
static void static void
write_password_stdout (SecretValue *value) write_password_data (SecretValue *value)
{ {
const gchar *at; const gchar *at;
gsize length; gsize length;
int r; int r;
if (!is_password_value (value)) {
g_printerr ("%s: secret does not contain a textual password\n", g_get_prgname ());
exit (1);
}
at = secret_value_get (value, &length); at = secret_value_get (value, &length);
while (length > 0) { while (length > 0) {
@ -176,6 +174,17 @@ write_password_stdout (SecretValue *value)
length -= r; length -= r;
} }
} }
}
static void
write_password_stdout (SecretValue *value)
{
if (!is_password_value (value)) {
g_printerr ("%s: secret does not contain a textual password\n", g_get_prgname ());
exit (1);
}
write_password_data (value);
/* Add a new line if we're writing out to a tty */ /* Add a new line if we're writing out to a tty */
if (isatty (1)) if (isatty (1))
@ -331,6 +340,143 @@ secret_tool_action_store (int argc,
return 0; return 0;
} }
static void
print_item_when (const char *field,
guint64 when)
{
GDateTime *dt;
gchar *value;
if (!when) {
value = g_strdup ("");
} else {
dt = g_date_time_new_from_unix_utc (when);
value = g_date_time_format (dt, "%Y-%m-%d %H:%M:%S");
g_date_time_unref (dt);
}
g_print ("%s = %s\n", field, value);
g_free (value);
}
static void
print_item_details (SecretItem *item)
{
SecretValue *secret;
GHashTableIter iter;
GHashTable *attributes;
gchar *value, *key;
guint64 when;
const gchar *part;
const gchar *path;
path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (item));
g_return_if_fail (path != NULL);
/* The item identifier */
part = strrchr (path, '/');
if (part == NULL)
part = path;
g_print ("[%s]\n", path);
/* The label */
value = secret_item_get_label (item);
g_print ("label = %s\n", value);
g_free (value);
/* The secret value */
secret = secret_item_get_secret (item);
g_print ("secret = ");
if (secret != NULL) {
write_password_data (secret);
secret_value_unref (secret);
}
g_print ("\n");
/* The dates */
when = secret_item_get_created (item);
print_item_when ("created", when);
when = secret_item_get_modified (item);
print_item_when ("modified", when);
/* The schema */
value = secret_item_get_schema_name (item);
g_print ("schema = %s\n", value);
g_free (value);
/* The attributes */
attributes = secret_item_get_attributes (item);
g_hash_table_iter_init (&iter, attributes);
while (g_hash_table_iter_next (&iter, (void **)&key, (void **)&value)) {
if (strcmp (key, "xdg:schema") != 0)
g_printerr ("attribute.%s = %s\n", key, value);
}
g_hash_table_unref (attributes);
}
static int
secret_tool_action_search (int argc,
char *argv[])
{
GError *error = NULL;
GOptionContext *context;
SecretService *service;
GHashTable *attributes;
SecretSearchFlags flags;
gboolean flag_all = FALSE;
gboolean flag_unlock = FALSE;
GList *items, *l;
/* secret-tool lookup name xxxx yyyy zzzz */
const GOptionEntry lookup_options[] = {
{ "all", 'a', 0, G_OPTION_ARG_NONE, &flag_all,
N_("return all results, instead of just first one"), NULL },
{ "unlock", 'a', 0, G_OPTION_ARG_NONE, &flag_unlock,
N_("unlock item results if necessary"), NULL },
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &attribute_args,
N_("attribute value pairs of item to lookup"), NULL },
{ NULL }
};
context = g_option_context_new ("attribute value ...");
g_option_context_add_main_entries (context, lookup_options, GETTEXT_PACKAGE);
if (!g_option_context_parse (context, &argc, &argv, &error)) {
g_printerr ("%s\n", error->message);
usage();
}
g_option_context_free (context);
attributes = attributes_from_arguments (attribute_args);
g_strfreev (attribute_args);
service = secret_service_get_sync (SECRET_SERVICE_NONE, NULL, &error);
if (error == NULL) {
flags = SECRET_SEARCH_LOAD_SECRETS;
if (flag_all)
flags |= SECRET_SEARCH_ALL;
if (flag_unlock)
flags |= SECRET_SEARCH_UNLOCK;
items = secret_service_search_sync (service, NULL, attributes, flags, NULL, &error);
if (error == NULL) {
for (l = items; l != NULL; l = g_list_next (l))
print_item_details (l->data);
g_list_free_full (items, g_object_unref);
}
g_object_unref (service);
}
g_hash_table_unref (attributes);
if (error != NULL) {
g_printerr ("%s: %s\n", g_get_prgname (), error->message);
return 1;
}
return 0;
}
int int
main (int argc, main (int argc,
char *argv[]) char *argv[])
@ -358,6 +504,8 @@ main (int argc,
action = secret_tool_action_lookup; action = secret_tool_action_lookup;
} else if (g_str_equal (argv[1], "clear")) { } else if (g_str_equal (argv[1], "clear")) {
action = secret_tool_action_clear; action = secret_tool_action_clear;
} else if (g_str_equal (argv[1], "search")) {
action = secret_tool_action_search;
} else { } else {
usage (); usage ();
} }