summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaiki Ueno <dueno@src.gnome.org>2018-08-31 15:45:43 +0200
committerDaiki Ueno <dueno@src.gnome.org>2018-09-17 15:37:51 +0200
commitb84b87c0bb18cda99769d2fefe35381f37e635d9 (patch)
treeb46a46603e2372346e272d3bb91c8b0780a18975
parentcb928f6ec402f9414ba81ecfc4401921987d977b (diff)
downloadgnome-keyring-wip/dueno/secrets-helper.tar.gz
daemon: Allow on the fly creation of secret service [ci skip]wip/dueno/secrets-helper
WIP
-rw-r--r--Makefile.am1
-rw-r--r--daemon/dbus/Makefile.am57
-rw-r--r--daemon/dbus/gkd-dbus.c157
-rw-r--r--daemon/dbus/gkd-dbus.h4
-rw-r--r--daemon/dbus/gkd-secret-util.c17
-rw-r--r--daemon/dbus/gkd-secret-util.h7
-rw-r--r--daemon/dbus/gkd-secrets-helper.c141
-rw-r--r--daemon/dbus/org.gnome.keyring.Daemon.xml4
8 files changed, 358 insertions, 30 deletions
diff --git a/Makefile.am b/Makefile.am
index 640c0e98..dd297dcd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -158,6 +158,7 @@ AM_CPPFLAGS = \
$(GLIB_CFLAGS)
bin_PROGRAMS =
+libexec_PROGRAMS =
BUILT_SOURCES =
check_PROGRAMS =
noinst_DATA =
diff --git a/daemon/dbus/Makefile.am b/daemon/dbus/Makefile.am
index 9d0b2e1a..536dcb59 100644
--- a/daemon/dbus/Makefile.am
+++ b/daemon/dbus/Makefile.am
@@ -1,5 +1,5 @@
-noinst_LTLIBRARIES += libgkd-dbus.la
+noinst_LTLIBRARIES += libgkd-dbus.la libgkd-secrets.la
daemon/dbus/gkd-secrets-generated.h: daemon/dbus/org.freedesktop.Secrets.xml
$(AM_V_GEN) gdbus-codegen --interface-prefix org.freedesktop.Secrets. \
@@ -38,22 +38,45 @@ EXTRA_DIST += \
daemon/dbus/org.gnome.keyring.InternalUnsupportedGuiltRiddenInterface.xml \
$(NULL)
-BUILT_SOURCES += \
+daemon_generated = \
daemon/dbus/gkd-daemon-generated.c \
- daemon/dbus/gkd-daemon-generated.h \
+ daemon/dbus/gkd-daemon-generated.h
+
+secrets_generated = \
daemon/dbus/gkd-internal-generated.c \
daemon/dbus/gkd-internal-generated.h \
daemon/dbus/gkd-secrets-generated.c \
daemon/dbus/gkd-secrets-generated.h
+BUILT_SOURCES += \
+ $(daemon_generated) \
+ $(secrets_generated)
+
libgkd_dbus_la_SOURCES = \
- $(BUILT_SOURCES) \
+ $(daemon_generated) \
daemon/dbus/gkd-dbus.c \
daemon/dbus/gkd-dbus.h \
daemon/dbus/gkd-dbus-environment.c \
daemon/dbus/gkd-dbus-private.h \
daemon/dbus/gkd-dbus-secrets.c \
daemon/dbus/gkd-dbus-session.c \
+ $(NULL)
+
+libgkd_dbus_la_LIBADD = \
+ libgkd-secrets.la \
+ $(GIO_LIBS) \
+ $(GLIB_LIBS) \
+ $(GOBJECT_LIBS)
+
+libgkd_dbus_la_CFLAGS = \
+ -DGKD_SECRETS_HELPER=\"$(libexecdir)/gkd-secrets-helper\" \
+ $(DAEMON_CFLAGS) \
+ $(GCR_BASE_CFLAGS) \
+ $(GIO_CFLAGS) \
+ $(GOBJECT_CFLAGS)
+
+libgkd_secrets_la_SOURCES = \
+ $(secrets_generated) \
daemon/dbus/gkd-secret-change.c \
daemon/dbus/gkd-secret-change.h \
daemon/dbus/gkd-secret-create.c \
@@ -82,20 +105,38 @@ libgkd_dbus_la_SOURCES = \
daemon/dbus/gkd-secret-unlock.c \
daemon/dbus/gkd-secret-unlock.h \
daemon/dbus/gkd-secret-util.c \
- daemon/dbus/gkd-secret-util.h \
- $(NULL)
+ daemon/dbus/gkd-secret-util.h
-libgkd_dbus_la_LIBADD = \
+libgkd_secrets_la_LIBADD = \
$(GIO_LIBS) \
$(GLIB_LIBS) \
$(GOBJECT_LIBS)
-libgkd_dbus_la_CFLAGS = \
+libgkd_secrets_la_CFLAGS = \
+ $(DAEMON_CFLAGS) \
+ $(GCR_BASE_CFLAGS) \
+ $(GIO_CFLAGS) \
+ $(GOBJECT_CFLAGS)
+
+libexec_PROGRAMS += gkd-secrets-helper
+
+gkd_secrets_helper_SOURCES = daemon/dbus/gkd-secrets-helper.c
+
+gkd_secrets_helper_CFLAGS = \
$(DAEMON_CFLAGS) \
$(GCR_BASE_CFLAGS) \
$(GIO_CFLAGS) \
$(GOBJECT_CFLAGS)
+gkd_secrets_helper_LDADD = \
+ libgkd-secrets.la \
+ libgkm-secret-store.la \
+ libgkm-wrap-layer.la \
+ $(GCR_BASE_LIBS) \
+ $(GIO_LIBS) \
+ $(GLIB_LIBS) \
+ $(GOBJECT_LIBS)
+
# -------------------------------------------------------------------
# TESTS
diff --git a/daemon/dbus/gkd-dbus.c b/daemon/dbus/gkd-dbus.c
index 6644a790..3d304bd4 100644
--- a/daemon/dbus/gkd-dbus.c
+++ b/daemon/dbus/gkd-dbus.c
@@ -32,6 +32,7 @@
#include "egg/egg-cleanup.h"
#include <glib.h>
+#include <glib-unix.h>
#include <gio/gio.h>
static GDBusConnection *dbus_conn = NULL;
@@ -112,6 +113,142 @@ handle_get_control_directory (GkdExportedDaemon *skeleton,
return TRUE;
}
+struct SecretHelperData
+{
+ GPid pid;
+ GMainLoop *loop;
+ GIOChannel *channel;
+ gchar *name;
+ guint output_id;
+ guint child_id;
+ guint timeout_id;
+};
+
+static gboolean
+on_secrets_helper_output (GIOChannel *source,
+ GIOCondition condition,
+ gpointer user_data)
+{
+ struct SecretHelperData *data = user_data;
+ gchar *line;
+ gsize terminator_pos;
+ GError *error = NULL;
+
+ if (g_io_channel_read_line (source, &line, NULL,
+ &terminator_pos, &error) ==
+ G_IO_STATUS_NORMAL) {
+ line[terminator_pos] = '\0';
+ data->name = line;
+ }
+
+ data->output_id = 0;
+ g_main_loop_quit (data->loop);
+ return FALSE;
+}
+
+static void
+on_secrets_helper_child (GPid pid,
+ gint status,
+ gpointer user_data)
+{
+ struct SecretHelperData *data = user_data;
+
+ g_spawn_close_pid (pid);
+ if (data->output_id > 0)
+ g_source_remove (data->output_id);
+ if (data->timeout_id > 0)
+ g_source_remove (data->timeout_id);
+
+ data->child_id = 0;
+ g_main_loop_quit (data->loop);
+}
+
+static gboolean
+on_secrets_helper_timeout (gpointer user_data)
+{
+ struct SecretHelperData *data = user_data;
+
+ kill (data->pid, SIGTERM);
+ data->timeout_id = 0;
+ g_main_loop_quit (data->loop);
+ return FALSE;
+}
+
+static void
+on_secrets_helper_peer_vanished (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ GPid pid = GPOINTER_TO_INT (user_data);
+ kill (pid, SIGTERM);
+}
+
+static gboolean
+handle_get_secret_service (GkdExportedDaemon *object,
+ GDBusMethodInvocation *invocation,
+ const gchar *arg_AppID)
+{
+ gchar *args[] = {
+ GKD_SECRETS_HELPER,
+ (gchar *) arg_AppID,
+ NULL
+ };
+ gint standard_output;
+ GError *error = NULL;
+ struct SecretHelperData data;
+ const gchar *sender;
+
+ memset (&data, 0, sizeof (data));
+
+ if (!g_spawn_async_with_pipes (NULL, args, NULL, G_SPAWN_DEFAULT, NULL,
+ NULL, &data.pid, NULL, &standard_output, NULL, &error)) {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ return FALSE;
+ }
+
+ data.loop = g_main_loop_new (NULL, FALSE);
+ data.channel = g_io_channel_unix_new (standard_output);
+ data.name = NULL;
+ data.output_id = g_io_add_watch (data.channel, G_IO_IN, on_secrets_helper_output, &data);
+ data.child_id = g_child_watch_add (data.pid, on_secrets_helper_child, &data);
+ data.timeout_id = g_timeout_add (10000, on_secrets_helper_timeout, &data);
+
+ g_main_loop_run (data.loop);
+
+ if (data.output_id > 0)
+ g_source_remove (data.output_id);
+ if (data.child_id > 0)
+ g_source_remove (data.child_id);
+ if (data.timeout_id > 0)
+ g_source_remove (data.timeout_id);
+
+ g_main_loop_unref (data.loop);
+ g_io_channel_unref (data.channel);
+
+ if (data.name == NULL) {
+ g_dbus_method_invocation_return_error (invocation,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "couldn't launch gkd-secrets-service");
+ return FALSE;
+ }
+
+ sender = g_dbus_method_invocation_get_sender (invocation);
+ g_bus_watch_name_on_connection (g_dbus_method_invocation_get_connection (invocation),
+ sender,
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ NULL,
+ on_secrets_helper_peer_vanished,
+ GINT_TO_POINTER (data.pid),
+ NULL);
+
+ gkd_exported_daemon_complete_get_secret_service (object,
+ invocation,
+ data.name);
+ g_free (data.name);
+ return TRUE;
+}
+
static void
cleanup_singleton (gpointer user_data)
{
@@ -149,6 +286,9 @@ gkd_dbus_singleton_acquire (gboolean *acquired)
g_signal_connect (skeleton, "handle-get-environment",
G_CALLBACK (handle_get_environment), NULL);
+ g_signal_connect (skeleton, "handle-get-secret-service",
+ G_CALLBACK (handle_get_secret_service), NULL);
+
g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (skeleton), dbus_conn,
GNOME_KEYRING_DAEMON_PATH, &error);
@@ -282,20 +422,3 @@ gkd_dbus_setup (void)
egg_cleanup_register (dbus_cleanup, NULL);
return TRUE;
}
-
-gboolean
-gkd_dbus_invocation_matches_caller (GDBusMethodInvocation *invocation,
- const char *caller)
-{
- const char *invocation_caller;
-
- invocation_caller = g_dbus_method_invocation_get_sender (invocation);
- if (!g_str_equal (invocation_caller, caller)) {
- g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR,
- G_DBUS_ERROR_ACCESS_DENIED,
- "Invalid caller");
- return FALSE;
- }
-
- return TRUE;
-}
diff --git a/daemon/dbus/gkd-dbus.h b/daemon/dbus/gkd-dbus.h
index 8a9ca450..0784a9a1 100644
--- a/daemon/dbus/gkd-dbus.h
+++ b/daemon/dbus/gkd-dbus.h
@@ -34,8 +34,4 @@ gboolean gkd_dbus_singleton_acquire (gboolean *acquired);
gchar* gkd_dbus_singleton_control (void);
-/* DBus utils */
-gboolean gkd_dbus_invocation_matches_caller (GDBusMethodInvocation *invocation,
- const char *caller);
-
#endif /* GKD_DBUS_H */
diff --git a/daemon/dbus/gkd-secret-util.c b/daemon/dbus/gkd-secret-util.c
index 29443f8c..a01635d5 100644
--- a/daemon/dbus/gkd-secret-util.c
+++ b/daemon/dbus/gkd-secret-util.c
@@ -146,3 +146,20 @@ gkd_secret_util_build_path (const gchar *base, gconstpointer identifier, gssize
return g_string_free (result, FALSE);
}
+
+gboolean
+gkd_dbus_invocation_matches_caller (GDBusMethodInvocation *invocation,
+ const char *caller)
+{
+ const char *invocation_caller;
+
+ invocation_caller = g_dbus_method_invocation_get_sender (invocation);
+ if (!g_str_equal (invocation_caller, caller)) {
+ g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR,
+ G_DBUS_ERROR_ACCESS_DENIED,
+ "Invalid caller");
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/daemon/dbus/gkd-secret-util.h b/daemon/dbus/gkd-secret-util.h
index 99e7814f..97abd7fd 100644
--- a/daemon/dbus/gkd-secret-util.h
+++ b/daemon/dbus/gkd-secret-util.h
@@ -23,7 +23,7 @@
#include "gkd-secret-types.h"
-#include <glib.h>
+#include <gio/gio.h>
gboolean gkd_secret_util_parse_path (const gchar *path,
gchar **collection,
@@ -33,4 +33,9 @@ gchar* gkd_secret_util_build_path (const g
gconstpointer identifier,
gssize n_identifier);
+
+/* DBus utils */
+gboolean gkd_dbus_invocation_matches_caller (GDBusMethodInvocation *invocation,
+ const char *caller);
+
#endif /* __GKD_SECRET_UTIL_H__ */
diff --git a/daemon/dbus/gkd-secrets-helper.c b/daemon/dbus/gkd-secrets-helper.c
new file mode 100644
index 00000000..88aa67a5
--- /dev/null
+++ b/daemon/dbus/gkd-secrets-helper.c
@@ -0,0 +1,141 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * License along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "egg/egg-cleanup.h"
+#include "egg/egg-error.h"
+
+#include "gkd-dbus.h"
+#include "gkd-secret-service.h"
+
+#include "pkcs11/wrap-layer/gkm-wrap-layer.h"
+#include "pkcs11/secret-store/gkm-secret-store.h"
+
+#include <string.h>
+#include <gck/gck.h>
+
+static void
+pkcs11_cleanup (gpointer data)
+{
+ CK_FUNCTION_LIST_PTR pkcs11_roof = data;
+ CK_RV rv;
+
+ g_assert (pkcs11_roof);
+
+ rv = (pkcs11_roof->C_Finalize) (NULL);
+
+ if (rv != CKR_OK)
+ g_warning ("couldn't finalize internal PKCS#11 stack (code: %d)", (gint)rv);
+}
+
+static gboolean
+pkcs11_initialize (const gchar *app_id)
+{
+ CK_FUNCTION_LIST_PTR secret_store;
+ CK_FUNCTION_LIST_PTR pkcs11_roof;
+ CK_C_INITIALIZE_ARGS init_args;
+ CK_RV rv;
+ GckSlot *slot = NULL;
+ GckModule *module;
+ GList *modules;
+ GkdSecretService *service;
+ GError *error = NULL;
+ GDBusConnection *connection;
+ gchar *path;
+
+ /* Secrets */
+ secret_store = gkm_secret_store_get_functions ();
+
+ /* Add all of those into the wrapper layer */
+ gkm_wrap_layer_add_module (secret_store);
+
+ pkcs11_roof = gkm_wrap_layer_get_functions ();
+
+ memset (&init_args, 0, sizeof (init_args));
+ init_args.flags = CKF_OS_LOCKING_OK;
+ path = g_build_filename (g_get_user_data_dir (), "keyrings", app_id, NULL);
+ init_args.pReserved = g_strdup_printf ("directory=\"%s\"", path);
+ g_free (path);
+
+ /* Initialize the whole caboodle */
+ rv = (pkcs11_roof->C_Initialize) (&init_args);
+ g_free (init_args.pReserved);
+
+ if (rv != CKR_OK) {
+ g_warning ("couldn't initialize internal PKCS#11 stack (code: %d)", (gint)rv);
+ return FALSE;
+ }
+
+ egg_cleanup_register (pkcs11_cleanup, NULL);
+
+ module = gck_module_new (pkcs11_roof);
+ g_return_val_if_fail (module, FALSE);
+
+ modules = g_list_prepend (NULL, module);
+ slot = gck_modules_token_for_uri (modules,
+ "pkcs11:token=Secret%20Store", &error);
+ gck_list_unref_free (modules);
+ if (!slot) {
+ g_warning ("couldn't find secret store: %s",
+ egg_error_message (error));
+ g_clear_error (&error);
+ return FALSE;
+ }
+
+ connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
+ if (!connection) {
+ g_warning ("couldn't connect to session bus: %s",
+ egg_error_message (error));
+ g_clear_error (&error);
+ return FALSE;
+ }
+ g_print ("%s\n", g_dbus_connection_get_unique_name (connection));
+
+ service = g_object_new (GKD_SECRET_TYPE_SERVICE,
+ "connection", connection,
+ "pkcs11-slot", slot,
+ NULL);
+
+ egg_cleanup_register (g_object_unref, service);
+ egg_cleanup_register (g_object_unref, connection);
+
+ return TRUE;
+}
+
+int
+main (int argc, char **argv)
+{
+ GMainLoop *loop;
+
+ if (argc != 2) {
+ g_printerr ("gkd-secrets-helper APP-ID\n");
+ return 1;
+ }
+
+ if (!pkcs11_initialize (argv[1]))
+ return 1;
+
+ loop = g_main_loop_new (NULL, FALSE);
+ g_main_loop_run (loop);
+ g_main_loop_unref (loop);
+
+ return 0;
+}
diff --git a/daemon/dbus/org.gnome.keyring.Daemon.xml b/daemon/dbus/org.gnome.keyring.Daemon.xml
index b4334d9b..0cb8ab46 100644
--- a/daemon/dbus/org.gnome.keyring.Daemon.xml
+++ b/daemon/dbus/org.gnome.keyring.Daemon.xml
@@ -9,5 +9,9 @@
<method name="GetControlDirectory">
<arg name="ControlDirectory" type="s" direction="out"/>
</method>
+ <method name="GetSecretService">
+ <arg name="AppID" type="s" direction="in"/>
+ <arg name="DBusName" type="s" direction="out"/>
+ </method>
</interface>
</node>