[gnome-keyring] [daemon] Rework control, and implement login keyring support.
- From: Stefan Walter <stefw src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-keyring] [daemon] Rework control, and implement login keyring support.
- Date: Thu, 17 Dec 2009 05:33:12 +0000 (UTC)
commit e206707ce7d57ee60cd950e2e667bbb0ec2064ed
Author: Stef Walter <stef memberwebs com>
Date: Thu Dec 17 03:32:53 2009 +0000
[daemon] Rework control, and implement login keyring support.
Implement support for unlocking and changing and storing secrets
in the login keyring, based on the secret-store.
Refactor how the control protocol hangs out, and implement some
simple test utilities for it.
configure.in | 2 +
daemon/Makefile.am | 2 +
daemon/control/Makefile.am | 17 +-
daemon/control/gkd-control-client.c | 280 ++++++++++++
daemon/control/gkd-control-private.h | 71 +++
daemon/control/gkd-control-server.c | 414 +++++++++++++++++
daemon/control/gkd-control.c | 649 --------------------------
daemon/control/gkd-control.h | 10 +-
daemon/control/tests/Makefile.am | 37 ++
daemon/control/tests/test-control-change | Bin 0 -> 96222 bytes
daemon/control/tests/test-control-change.c | 30 ++
daemon/control/tests/test-control-unlock | Bin 0 -> 96149 bytes
daemon/control/tests/test-control-unlock.c | 24 +
daemon/gkd-main.c | 22 +-
daemon/gkd-util.c | 10 +-
daemon/login/Makefile.am | 24 +
daemon/login/gkd-login.c | 678 ++++++++++++++++++++++++++++
daemon/login/gkd-login.h | 50 ++
daemon/pkcs11/gkr-pkcs11-auth.c | 91 ++---
daemon/pkcs11/gkr-pkcs11-daemon.c | 16 +-
daemon/pkcs11/gkr-pkcs11-daemon.h | 2 +
tests/gtest-helpers.c | 16 +-
tests/prep-gtest.sh | 10 +
23 files changed, 1712 insertions(+), 743 deletions(-)
---
diff --git a/configure.in b/configure.in
index 0121c4e..afaa402 100644
--- a/configure.in
+++ b/configure.in
@@ -551,10 +551,12 @@ Makefile
daemon/Makefile
daemon/gnome-keyring-daemon.desktop.in
daemon/control/Makefile
+daemon/control/tests/Makefile
daemon/data/Makefile
daemon/dbus/Makefile
daemon/keyrings/Makefile
daemon/keyrings/tests/Makefile
+daemon/login/Makefile
daemon/pkcs11/Makefile
daemon/prompt/Makefile
daemon/prompt/tests/Makefile
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index cc818f0..a0ce816 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -3,6 +3,7 @@ SUBDIRS = \
ui \
prompt \
keyrings \
+ login \
control \
pkcs11 \
dbus \
@@ -35,6 +36,7 @@ gnome_keyring_daemon_LDADD = \
$(top_builddir)/daemon/pkcs11/libgkr-pkcs11.la \
$(top_builddir)/daemon/dbus/libgkr-dbus.la \
$(top_builddir)/daemon/keyrings/libgkr-keyrings.la \
+ $(top_builddir)/daemon/login/libgkd-login.la \
$(top_builddir)/daemon/ui/libgkr-ui.la \
$(top_builddir)/daemon/control/libgkd-control.la \
$(top_builddir)/daemon/prompt/libgkd-prompt.la \
diff --git a/daemon/control/Makefile.am b/daemon/control/Makefile.am
index e189c5a..2fdcf78 100644
--- a/daemon/control/Makefile.am
+++ b/daemon/control/Makefile.am
@@ -1,3 +1,10 @@
+if WITH_TESTS
+TESTS_DIR = tests
+else
+TESTS_DIR =
+endif
+
+SUBDIRS = . $(TESTS_DIR)
INCLUDES= \
-DPREFIX=\""$(prefix)"\" \
@@ -12,10 +19,12 @@ INCLUDES= \
# ------------------------------------------------------------------
# DAEMON CODE
-noinst_LTLIBRARIES = libgkd-control.la
+noinst_LTLIBRARIES = \
+ libgkd-control.la \
+ libgkd-control-client.la
libgkd_control_la_SOURCES = \
- gkd-control.c gkd-control.h
+ gkd-control-server.c gkd-control-client.c gkd-control.h
-libgkd_control_la_LIBADD = \
- $(GLIB_LIBS)
+libgkd_control_client_la_SOURCES = \
+ gkd-control-client.c gkd-control.h
diff --git a/daemon/control/gkd-control-client.c b/daemon/control/gkd-control-client.c
new file mode 100644
index 0000000..dedf6e0
--- /dev/null
+++ b/daemon/control/gkd-control-client.c
@@ -0,0 +1,280 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2009 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public 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 Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gkd-control.h"
+#include "gkd-control-private.h"
+
+#include "egg/egg-buffer.h"
+#include "egg/egg-secure-memory.h"
+#include "egg/egg-unix-credentials.h"
+
+#include <errno.h>
+#include <fcntl.h>
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+static int
+control_connect (const gchar *path)
+{
+ struct sockaddr_un addr;
+ struct stat st;
+ int sock;
+
+ /* First a bunch of checks to make sure nothing funny is going on */
+ if (lstat (path, &st) < 0) {
+ g_message ("couldn't access conrol socket: %s: %s", path, g_strerror (errno));
+ return -1;
+
+ } else if (st.st_uid != geteuid ()) {
+ g_message("The control socket is not owned with the same "
+ "credentials as the user login: %s", path);
+ return -1;
+
+ } else if (S_ISLNK (st.st_mode) || !S_ISSOCK (st.st_mode)) {
+ g_message ("The control socket is not a valid simple non-linked socket");
+ return -1;
+ }
+
+ addr.sun_family = AF_UNIX;
+ g_strlcpy (addr.sun_path, path, sizeof (addr.sun_path));
+
+ /* Now we connect */
+ sock = socket (AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0) {
+ g_warning ("couldn't create control socket: %s", g_strerror (errno));
+ return -1;
+ }
+
+ /* Close on exec */
+ fcntl (sock, F_SETFD, 1);
+
+ if (connect (sock, (struct sockaddr*) &addr, sizeof (addr)) < 0) {
+ g_message ("couldn't connect to control socket at: %s: %s",
+ addr.sun_path, g_strerror (errno));
+ close (sock);
+ return -1;
+ }
+
+ /* This lets the server verify us */
+ for (;;) {
+ if (egg_unix_credentials_write (sock) < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ g_message ("couldn't send credentials to control socket: %s",
+ g_strerror (errno));
+ close (sock);
+ return -1;
+ }
+
+ return sock;
+ }
+}
+
+static gboolean
+control_write (int fd, EggBuffer *buf)
+{
+ gsize bytes = 0;
+ gssize res;
+
+ while (bytes < buf->len) {
+ res = write (fd, buf->buf + bytes, buf->len - bytes);
+ if (res < 0) {
+ if (errno != EINTR && errno != EAGAIN) {
+ g_warning ("couldn't write all bytes to control socket: %s",
+ g_strerror (errno));
+ return FALSE;
+ }
+ } else {
+ bytes += res;
+ }
+ }
+
+ return TRUE;
+}
+
+static gsize
+control_read_raw (int fd, guchar *buf, size_t len)
+{
+ gsize bytes;
+ gssize res;
+
+ bytes = 0;
+ while (bytes < len) {
+ res = read (fd, buf + bytes, len - bytes);
+ if (res <= 0) {
+ if (res == 0)
+ res = -1;
+ else if (errno == EAGAIN)
+ continue;
+ else
+ g_warning ("couldn't read %u bytes from control socket: %s",
+ (unsigned int)len, g_strerror (errno));
+ return res;
+ }
+ bytes += res;
+ }
+ return bytes;
+}
+
+
+static gboolean
+control_read (int fd, EggBuffer *buffer)
+{
+ guint32 packet_size;
+
+ egg_buffer_resize (buffer, 4);
+ if (control_read_raw (fd, buffer->buf, 4) != 4)
+ return FALSE;
+
+ if (!egg_buffer_get_uint32 (buffer, 0, NULL, &packet_size) ||
+ packet_size < 4)
+ return FALSE;
+
+ egg_buffer_resize (buffer, packet_size);
+ if (control_read_raw (fd, buffer->buf + 4, packet_size - 4) != packet_size - 4)
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+control_chat (const gchar *directory, EggBuffer *buffer)
+{
+ gboolean ret;
+ gchar *path;
+ int sock;
+
+ path = g_strdup_printf ("%s/control", directory);
+ sock = control_connect (path);
+ g_free (path);
+
+ if (sock < 0)
+ return FALSE;
+
+ ret = control_write (sock, buffer) && control_read (sock, buffer);
+ close (sock);
+ return ret;
+}
+
+
+gchar**
+gkd_control_initialize (const gchar *directory, const gchar **envp)
+{
+ gchar **env = NULL;
+ EggBuffer buffer;
+ gsize offset = 4;
+ gboolean ret;
+ guint32 res;
+
+ egg_buffer_init_full (&buffer, 128, g_realloc);
+ egg_buffer_add_uint32 (&buffer, 0);
+ egg_buffer_add_uint32 (&buffer, GNOME_KEYRING_OP_PREPARE_ENVIRONMENT);
+ egg_buffer_add_stringv (&buffer, (const char**)envp);
+ egg_buffer_set_uint32 (&buffer, 0, buffer.len);
+
+ g_return_val_if_fail (!egg_buffer_has_error (&buffer), FALSE);
+
+ ret = control_chat (directory, &buffer);
+
+ if (ret)
+ ret = egg_buffer_get_uint32 (&buffer, offset, &offset, &res);
+ if (ret && res == GNOME_KEYRING_RESULT_OK)
+ ret = egg_buffer_get_stringv (&buffer, offset, &offset, &env, g_realloc);
+
+ egg_buffer_uninit (&buffer);
+
+ if (!ret || res != GNOME_KEYRING_RESULT_OK) {
+ g_message ("couldn't initialize running daemon");
+ return NULL;
+ }
+
+ return env;
+}
+
+gboolean
+gkd_control_unlock (const gchar *directory, const gchar *password)
+{
+ EggBuffer buffer;
+ gsize offset = 4;
+ gboolean ret;
+ guint32 res;
+
+ egg_buffer_init_full (&buffer, 128, egg_secure_realloc);
+ egg_buffer_add_uint32 (&buffer, 0);
+ egg_buffer_add_uint32 (&buffer, GNOME_KEYRING_OP_UNLOCK_KEYRING);
+ egg_buffer_add_string (&buffer, "login");
+ egg_buffer_add_string (&buffer, password);
+ egg_buffer_set_uint32 (&buffer, 0, buffer.len);
+
+ g_return_val_if_fail (!egg_buffer_has_error (&buffer), FALSE);
+
+ ret = control_chat (directory, &buffer);
+
+ if (ret)
+ ret = egg_buffer_get_uint32 (&buffer, offset, &offset, &res);
+
+ egg_buffer_uninit (&buffer);
+
+ if (!ret || res != GNOME_KEYRING_RESULT_OK) {
+ g_message ("couldn't unlock login keyring");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+gkd_control_change_lock (const gchar *directory, const gchar *original,
+ const gchar *password)
+{
+ EggBuffer buffer;
+ gsize offset = 4;
+ gboolean ret;
+ guint32 res;
+
+ egg_buffer_init_full (&buffer, 128, egg_secure_realloc);
+ egg_buffer_add_uint32 (&buffer, 0);
+ egg_buffer_add_uint32 (&buffer, GNOME_KEYRING_OP_CHANGE_KEYRING_PASSWORD);
+ egg_buffer_add_string (&buffer, "login");
+ egg_buffer_add_string (&buffer, original);
+ egg_buffer_add_string (&buffer, password);
+ egg_buffer_set_uint32 (&buffer, 0, buffer.len);
+
+ g_return_val_if_fail (!egg_buffer_has_error (&buffer), FALSE);
+
+ ret = control_chat (directory, &buffer);
+
+ if (ret)
+ ret = egg_buffer_get_uint32 (&buffer, offset, &offset, &res);
+
+ egg_buffer_uninit (&buffer);
+
+ if (!ret || res != GNOME_KEYRING_RESULT_OK) {
+ g_message ("couldn't change lock on login keyring");
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/daemon/control/gkd-control-private.h b/daemon/control/gkd-control-private.h
new file mode 100644
index 0000000..a982c14
--- /dev/null
+++ b/daemon/control/gkd-control-private.h
@@ -0,0 +1,71 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2009 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public 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 Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GKD_CONTROL_PRIVATE_H__
+#define __GKD_CONTROL_PRIVATE_H__
+
+/* All the old op codes, most are no longer used */
+enum {
+ GNOME_KEYRING_OP_LOCK_ALL,
+ GNOME_KEYRING_OP_SET_DEFAULT_KEYRING,
+ GNOME_KEYRING_OP_GET_DEFAULT_KEYRING,
+ GNOME_KEYRING_OP_LIST_KEYRINGS,
+ GNOME_KEYRING_OP_CREATE_KEYRING,
+ GNOME_KEYRING_OP_LOCK_KEYRING,
+ GNOME_KEYRING_OP_UNLOCK_KEYRING,
+ GNOME_KEYRING_OP_DELETE_KEYRING,
+ GNOME_KEYRING_OP_GET_KEYRING_INFO,
+ GNOME_KEYRING_OP_SET_KEYRING_INFO,
+ GNOME_KEYRING_OP_LIST_ITEMS,
+ GNOME_KEYRING_OP_FIND,
+ GNOME_KEYRING_OP_CREATE_ITEM,
+ GNOME_KEYRING_OP_DELETE_ITEM,
+ GNOME_KEYRING_OP_GET_ITEM_INFO,
+ GNOME_KEYRING_OP_SET_ITEM_INFO,
+ GNOME_KEYRING_OP_GET_ITEM_ATTRIBUTES,
+ GNOME_KEYRING_OP_SET_ITEM_ATTRIBUTES,
+ GNOME_KEYRING_OP_GET_ITEM_ACL,
+ GNOME_KEYRING_OP_SET_ITEM_ACL,
+ GNOME_KEYRING_OP_CHANGE_KEYRING_PASSWORD,
+ GNOME_KEYRING_OP_SET_DAEMON_DISPLAY,
+ GNOME_KEYRING_OP_GET_ITEM_INFO_FULL,
+ GNOME_KEYRING_OP_PREPARE_ENVIRONMENT,
+
+ /* Add new ops here */
+
+ GNOME_KEYRING_NUM_OPS
+};
+
+/* All the old result codes */
+enum {
+ GNOME_KEYRING_RESULT_OK,
+ GNOME_KEYRING_RESULT_DENIED,
+ GNOME_KEYRING_RESULT_NO_KEYRING_DAEMON,
+ GNOME_KEYRING_RESULT_ALREADY_UNLOCKED,
+ GNOME_KEYRING_RESULT_NO_SUCH_KEYRING,
+ GNOME_KEYRING_RESULT_BAD_ARGUMENTS,
+ GNOME_KEYRING_RESULT_IO_ERROR,
+ GNOME_KEYRING_RESULT_CANCELLED,
+ GNOME_KEYRING_RESULT_KEYRING_ALREADY_EXISTS,
+ GNOME_KEYRING_RESULT_NO_MATCH
+};
+
+#endif /* __GKD_CONTROL_PRIVATE_H__ */
diff --git a/daemon/control/gkd-control-server.c b/daemon/control/gkd-control-server.c
new file mode 100644
index 0000000..87a50d7
--- /dev/null
+++ b/daemon/control/gkd-control-server.c
@@ -0,0 +1,414 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2009 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public 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 Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gkd-control.h"
+#include "gkd-control-private.h"
+
+#include "gkd-main.h"
+#include "gkd-util.h"
+
+#include "egg/egg-buffer.h"
+#include "egg/egg-cleanup.h"
+#include "egg/egg-secure-memory.h"
+#include "egg/egg-unix-credentials.h"
+
+#include "login/gkd-login.h"
+
+#include <errno.h>
+#include <fcntl.h>
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+typedef struct _ControlData {
+ EggBuffer buffer;
+ gsize position;
+} ControlData;
+
+/* -----------------------------------------------------------------------------------
+ * CONTROL SERVER
+ */
+
+static ControlData*
+control_data_new (void)
+{
+ ControlData *cdata = g_slice_new0 (ControlData);
+ egg_buffer_init_full (&cdata->buffer, 128, egg_secure_realloc);
+ cdata->position = 0;
+ return cdata;
+}
+
+static void
+control_data_free (gpointer data)
+{
+ ControlData *cdata = data;
+ egg_buffer_uninit (&cdata->buffer);
+ g_slice_free (ControlData, cdata);
+}
+
+static guint32
+control_unlock_keyring (EggBuffer *buffer)
+{
+ gchar *name;
+ gchar *master;
+ gsize offset = 8;
+ guint32 res;
+
+ if (!egg_buffer_get_string (buffer, offset, &offset, &name, g_realloc))
+ return GNOME_KEYRING_RESULT_BAD_ARGUMENTS;
+
+ if (!egg_buffer_get_string (buffer, offset, &offset, &master, egg_secure_realloc)) {
+ g_free (name);
+ return GNOME_KEYRING_RESULT_BAD_ARGUMENTS;
+ }
+
+ if (!name || g_str_equal (name, "login")) {
+ if (gkd_login_unlock (master))
+ res = GNOME_KEYRING_RESULT_OK;
+ else
+ res = GNOME_KEYRING_RESULT_DENIED;
+ } else {
+ g_message ("keyring request not supported");
+ res = GNOME_KEYRING_RESULT_NO_SUCH_KEYRING;
+ }
+
+ egg_secure_strfree (master);
+ g_free (name);
+ return res;
+}
+
+static guint32
+control_change_keyring_password (EggBuffer *buffer)
+{
+ gsize offset = 8;
+ guint32 res;
+ gchar *name;
+ gchar *master;
+ gchar *original;
+
+ if (!egg_buffer_get_string (buffer, offset, &offset, &name, g_realloc))
+ return GNOME_KEYRING_RESULT_BAD_ARGUMENTS;
+
+ if (!egg_buffer_get_string (buffer, offset, &offset, &original, egg_secure_realloc)) {
+ g_free (name);
+ return GNOME_KEYRING_RESULT_BAD_ARGUMENTS;
+ }
+
+ if (!egg_buffer_get_string (buffer, offset, &offset, &master, egg_secure_realloc)) {
+ egg_secure_strfree (original);
+ g_free (name);
+ return GNOME_KEYRING_RESULT_BAD_ARGUMENTS;
+ }
+
+ if (!name || g_str_equal (name, "login")) {
+ if (gkd_login_change_lock (original, master))
+ res = GNOME_KEYRING_RESULT_OK;
+ else
+ res = GNOME_KEYRING_RESULT_DENIED;
+ } else {
+ g_message ("keyring request not supported");
+ res = GNOME_KEYRING_RESULT_NO_SUCH_KEYRING;
+ }
+
+ egg_secure_strfree (master);
+ egg_secure_strfree (original);
+ g_free (name);
+ return res;
+}
+
+static guint32
+control_prepare_environment (EggBuffer *buffer)
+{
+ gchar **environment, **e;
+ gsize offset = 8;
+ gchar *x;
+ int i;
+
+ if (!egg_buffer_get_stringv (buffer, offset, &offset, &environment, g_realloc))
+ return GNOME_KEYRING_RESULT_BAD_ARGUMENTS;
+
+ /* Accept environment from outside */
+ for (e = environment; *e; ++e) {
+ x = strchr (*e, '=');
+ if (x) {
+ *(x++) = 0;
+ /* We're only interested in these environment variables */
+ for (i = 0; GKD_UTIL_IN_ENVIRONMENT[i] != NULL; ++i) {
+ if (g_str_equal (*e, GKD_UTIL_IN_ENVIRONMENT[i])) {
+ g_setenv (*e, x, FALSE);
+ break;
+ }
+ }
+ }
+ }
+
+ g_strfreev (environment);
+
+ /*
+ * We've now definitely received everything we need to run. Ask
+ * the daemon to complete the initialization.
+ */
+ gkd_main_complete_initialization ();
+ return GNOME_KEYRING_RESULT_OK;
+}
+
+static gboolean
+control_output (GIOChannel *channel, GIOCondition cond, gpointer user_data)
+{
+ ControlData *cdata = user_data;
+ EggBuffer *buffer = &cdata->buffer;
+ int fd, res;
+
+ fd = g_io_channel_unix_get_fd (channel);
+ g_assert (cdata->position < buffer->len);
+
+ if (cond & G_IO_OUT) {
+ res = write (fd, buffer->buf + cdata->position, buffer->len - cdata->position);
+ if (res <= 0) {
+ if (errno != EAGAIN && errno != EINTR)
+ cdata->position = buffer->len;
+ } else {
+ cdata->position += res;
+ g_assert (cdata->position <= buffer->len);
+ }
+ }
+
+ if (cdata->position == buffer->len)
+ cond |= G_IO_HUP;
+
+ return (cond & G_IO_HUP) == 0;
+}
+
+static void
+control_process (EggBuffer *req, GIOChannel *channel)
+{
+ ControlData *cdata = NULL;
+ guint32 res;
+ guint32 op;
+
+ if (!egg_buffer_get_uint32 (req, 4, NULL, &op)) {
+ g_message ("invalid operation sent to control socket");
+ return;
+ }
+
+ switch (op) {
+ case GNOME_KEYRING_OP_CREATE_KEYRING:
+ case GNOME_KEYRING_OP_UNLOCK_KEYRING:
+ res = control_unlock_keyring (req);
+ cdata = control_data_new ();
+ egg_buffer_add_uint32 (&cdata->buffer, 0);
+ egg_buffer_add_uint32 (&cdata->buffer, res);
+ break;
+ case GNOME_KEYRING_OP_CHANGE_KEYRING_PASSWORD:
+ res = control_change_keyring_password (req);
+ cdata = control_data_new ();
+ egg_buffer_add_uint32 (&cdata->buffer, 0);
+ egg_buffer_add_uint32 (&cdata->buffer, res);
+ break;
+ case GNOME_KEYRING_OP_PREPARE_ENVIRONMENT:
+ res = control_prepare_environment (req);
+ cdata = control_data_new ();
+ egg_buffer_add_uint32 (&cdata->buffer, 0);
+ egg_buffer_add_uint32 (&cdata->buffer, res);
+ egg_buffer_add_stringv (&cdata->buffer, gkd_util_get_environment ());
+ break;
+ default:
+ g_message ("received unsupported request operation on control socket: %d", (int)op);
+ break;
+ }
+
+ if (cdata) {
+ g_return_if_fail (!egg_buffer_has_error (&cdata->buffer));
+ egg_buffer_set_uint32 (&cdata->buffer, 0, cdata->buffer.len);
+ g_io_add_watch_full (channel, G_PRIORITY_DEFAULT, G_IO_OUT | G_IO_HUP,
+ control_output, cdata, control_data_free);
+ }
+}
+
+static gboolean
+control_input (GIOChannel *channel, GIOCondition cond, gpointer user_data)
+{
+ ControlData *cdata = user_data;
+ EggBuffer *buffer = &cdata->buffer;
+ guint32 packet_size = 0;
+ gboolean finished = FALSE;
+ int fd, res;
+ pid_t pid;
+ uid_t uid;
+
+ fd = g_io_channel_unix_get_fd (channel);
+
+ if (cond & G_IO_IN) {
+
+ /* Time for reading credentials */
+ if (cdata->position == 0) {
+ if (egg_unix_credentials_read (fd, &pid, &uid) < 0) {
+ if (errno != EAGAIN || errno != EINTR)
+ finished = TRUE;
+ } else if (getuid () != uid) {
+ g_message ("control request from bad uid: %u, should be %u\n", uid, getuid ());
+ finished = TRUE;
+ } else {
+ cdata->position = 1;
+ }
+
+ /* Time for reading a packet size */
+ } else if (egg_buffer_length (buffer) < 4) {
+ egg_buffer_reserve (buffer, 4);
+ res = read (fd, buffer->buf + buffer->len, 4 - buffer->len);
+ if (res <= 0) {
+ if (errno != EAGAIN || errno != EINTR)
+ finished = TRUE;
+ } else {
+ buffer->len += res;
+ }
+
+ /* Time for reading the packet */
+ } else {
+ if (!egg_buffer_get_uint32 (buffer, 0, NULL, &packet_size) || packet_size < 4) {
+ g_message ("invalid packet size in control request");
+ finished = TRUE;
+ } else {
+ g_assert (buffer->len < packet_size);
+ egg_buffer_reserve (buffer, packet_size);
+ res = read (fd, buffer->buf + buffer->len, packet_size - buffer->len);
+ if (res <= 0) {
+ if (errno != EAGAIN && errno != EINTR)
+ finished = TRUE;
+ } else {
+ buffer->len += res;
+ g_assert (buffer->len <= packet_size);
+ }
+ }
+ }
+
+ /* Received a full packet, process */
+ if (packet_size && buffer->len == packet_size) {
+ control_process (buffer, channel);
+ finished = TRUE;
+ }
+ }
+
+ if (finished)
+ cond |= G_IO_HUP;
+
+ return (cond & G_IO_HUP) == 0;
+}
+
+static gboolean
+control_accept (GIOChannel *channel, GIOCondition cond, gpointer callback_data)
+{
+ struct sockaddr_un addr;
+ socklen_t addrlen;
+ ControlData *cdata;
+ GIOChannel *new_channel;
+ int fd, new_fd;
+ int val;
+
+ fd = g_io_channel_unix_get_fd (channel);
+
+ addrlen = sizeof (addr);
+ new_fd = accept (fd, (struct sockaddr *) &addr, &addrlen);
+ if (new_fd < 0) {
+ g_warning ("couldn't accept new control request: %s", g_strerror (errno));
+ return TRUE;
+ }
+
+ val = fcntl (new_fd, F_GETFL, 0);
+ if (val < 0) {
+ g_warning ("can't get control request fd flags: %s", g_strerror (errno));
+ close (new_fd);
+ return TRUE;
+ }
+
+ if (fcntl (new_fd, F_SETFL, val | O_NONBLOCK) < 0) {
+ g_warning ("can't set control request to non-blocking io: %s", g_strerror (errno));
+ close (new_fd);
+ return TRUE;
+ }
+
+ cdata = control_data_new ();
+ new_channel = g_io_channel_unix_new (new_fd);
+ g_io_channel_set_close_on_unref (new_channel, TRUE);
+ g_io_add_watch_full (new_channel, G_PRIORITY_DEFAULT, G_IO_IN | G_IO_HUP,
+ control_input, cdata, control_data_free);
+ g_io_channel_unref (new_channel);
+
+ return TRUE;
+}
+
+static void
+control_cleanup_channel (gpointer user_data)
+{
+ gchar *path = user_data;
+ unlink (path);
+ g_free (path);
+}
+
+gboolean
+gkd_control_listen (void)
+{
+ struct sockaddr_un addr;
+ GIOChannel *channel;
+ gchar *path;
+ int sock;
+
+ path = g_strdup_printf ("%s/control", gkd_util_get_master_directory ());
+ egg_cleanup_register (control_cleanup_channel, path);
+
+ unlink (path);
+
+ sock = socket (AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0) {
+ g_warning ("couldn't open socket: %s", g_strerror (errno));
+ return FALSE;
+ }
+
+ memset (&addr, 0, sizeof (addr));
+ addr.sun_family = AF_UNIX;
+ g_strlcpy (addr.sun_path, path, sizeof (addr.sun_path));
+ if (bind (sock, (struct sockaddr*) &addr, sizeof (addr)) < 0) {
+ g_warning ("couldn't bind to control socket: %s: %s", path, g_strerror (errno));
+ close (sock);
+ return FALSE;
+ }
+
+ if (listen (sock, 128) < 0) {
+ g_warning ("couldn't listen on control socket: %s: %s", path, g_strerror (errno));
+ close (sock);
+ return FALSE;
+ }
+
+ if (!egg_unix_credentials_setup (sock) < 0) {
+ close (sock);
+ return FALSE;
+ }
+
+ channel = g_io_channel_unix_new (sock);
+ g_io_add_watch (channel, G_IO_IN | G_IO_HUP, control_accept, NULL);
+ g_io_channel_set_close_on_unref (channel, TRUE);
+ egg_cleanup_register ((GDestroyNotify)g_io_channel_unref, channel);
+
+ return TRUE;
+}
diff --git a/daemon/control/gkd-control.h b/daemon/control/gkd-control.h
index 84249db..796dd6b 100644
--- a/daemon/control/gkd-control.h
+++ b/daemon/control/gkd-control.h
@@ -26,6 +26,14 @@
gboolean gkd_control_listen (void);
-gboolean gkd_control_initialize (const gchar *directory);
+gchar** gkd_control_initialize (const gchar *directory,
+ const gchar **env);
+
+gboolean gkd_control_unlock (const gchar *directory,
+ const gchar *password);
+
+gboolean gkd_control_change_lock (const gchar *directory,
+ const gchar *original,
+ const gchar *password);
#endif /* __GKD_CONTROL_H__ */
diff --git a/daemon/control/tests/Makefile.am b/daemon/control/tests/Makefile.am
new file mode 100644
index 0000000..36f9e24
--- /dev/null
+++ b/daemon/control/tests/Makefile.am
@@ -0,0 +1,37 @@
+INCLUDES= \
+ -I$(top_srcdir) \
+ -I$(top_builddir) \
+ -I$(top_srcdir)/daemon \
+ $(GTK_CFLAGS) \
+ $(GLIB_CFLAGS)
+
+LIBS = \
+ $(GLIB_LIBS) \
+ $(GTK_LIBS) \
+ $(GTHREAD_LIBS) \
+ $(P11_TESTS_LIBS)
+
+noinst_PROGRAMS= \
+ test-control-unlock \
+ test-control-change
+
+# ------------------------------------------------------------------------------
+# Test unlocking the login keyring
+
+test_control_unlock_SOURCES = \
+ test-control-unlock.c
+
+test_control_unlock_LDADD = \
+ $(top_builddir)/daemon/control/libgkd-control-client.la \
+ $(top_builddir)/egg/libegg-buffer.la \
+ $(top_builddir)/egg/libegg-creds.la \
+ $(top_builddir)/egg/libegg-secure.la
+
+test_control_change_SOURCES = \
+ test-control-change.c
+
+test_control_change_LDADD = \
+ $(top_builddir)/daemon/control/libgkd-control-client.la \
+ $(top_builddir)/egg/libegg-buffer.la \
+ $(top_builddir)/egg/libegg-creds.la \
+ $(top_builddir)/egg/libegg-secure.la
\ No newline at end of file
diff --git a/daemon/control/tests/test-control-change b/daemon/control/tests/test-control-change
new file mode 100755
index 0000000..e2236f4
Binary files /dev/null and b/daemon/control/tests/test-control-change differ
diff --git a/daemon/control/tests/test-control-change.c b/daemon/control/tests/test-control-change.c
new file mode 100644
index 0000000..ee5d995
--- /dev/null
+++ b/daemon/control/tests/test-control-change.c
@@ -0,0 +1,30 @@
+
+#include "control/gkd-control.h"
+#include "tests/gtest-helpers.h"
+
+#include <pwd.h>
+#include <unistd.h>
+
+static int
+run (void)
+{
+ gchar *original;
+ const char *password;
+ const char *directory;
+
+ directory = g_getenv ("GNOME_KEYRING_CONTROL");
+ g_return_val_if_fail (directory, 1);
+
+ original = g_strdup (getpass ("Original: "));
+ g_return_val_if_fail (original, 1);
+
+ password = getpass ("New Password: ");
+ g_return_val_if_fail (password, 1);
+
+ gkd_control_change_lock (directory, original, password);
+
+ g_free (original);
+ return 0;
+}
+
+#include "tests/gtest-helpers.c"
diff --git a/daemon/control/tests/test-control-unlock b/daemon/control/tests/test-control-unlock
new file mode 100755
index 0000000..d71dd09
Binary files /dev/null and b/daemon/control/tests/test-control-unlock differ
diff --git a/daemon/control/tests/test-control-unlock.c b/daemon/control/tests/test-control-unlock.c
new file mode 100644
index 0000000..d77901b
--- /dev/null
+++ b/daemon/control/tests/test-control-unlock.c
@@ -0,0 +1,24 @@
+
+#include "control/gkd-control.h"
+#include "tests/gtest-helpers.h"
+
+#include <pwd.h>
+#include <unistd.h>
+
+static int
+run (void)
+{
+ const char *password;
+ const char *directory;
+
+ password = getpass ("Unlock: ");
+ g_return_val_if_fail (password, 1);
+
+ directory = g_getenv ("GNOME_KEYRING_CONTROL");
+ g_return_val_if_fail (directory, 1);
+
+ gkd_control_unlock (directory, password);
+ return 0;
+}
+
+#include "tests/gtest-helpers.c"
diff --git a/daemon/gkd-main.c b/daemon/gkd-main.c
index 1d17458..b7d56b1 100644
--- a/daemon/gkd-main.c
+++ b/daemon/gkd-main.c
@@ -36,9 +36,7 @@
#include "egg/egg-secure-memory.h"
#include "egg/egg-unix-credentials.h"
-#include "keyrings/gkr-keyring-login.h"
-
-#include "library/gnome-keyring.h"
+#include "login/gkd-login.h"
#include "pkcs11/gkr-pkcs11-daemon.h"
@@ -527,13 +525,25 @@ print_environment (pid_t pid)
static gboolean
start_or_initialize_daemon (const gchar *directory)
{
+ gchar **ourenv, **daemonenv, **e;
+
if (!directory)
return FALSE;
+ /* Exchange environment variables, and try to initialize daemon */
+ ourenv = gkd_util_build_environment (GKD_UTIL_IN_ENVIRONMENT);
+ daemonenv = gkd_control_initialize (directory, (const gchar**)ourenv);
+ g_strfreev (ourenv);
+
/* Initialization failed, start this process up as a daemon */
- if (!gkd_control_initialize (directory))
+ if (!daemonenv)
return FALSE;
+ /* Setup all the environment variables we were passed */
+ for (e = daemonenv; *e; ++e)
+ gkd_util_push_environment_full (*e);
+ g_strfreev (daemonenv);
+
/*
* Now we've initialized the daemon, we need to print out
* the daemon's environment for any callers, and possibly
@@ -660,7 +670,7 @@ gkr_daemon_initialize_steps (void)
* If it does not exist. We create it.
*/
if (login_password) {
- if (!gkr_keyring_login_unlock (login_password))
+ if (!gkd_login_unlock (login_password))
g_message ("Failed to unlock login on startup");
egg_secure_strclear (login_password);
}
@@ -792,7 +802,7 @@ main (int argc, char *argv[])
* If it does not exist. We create it.
*/
if (login_password) {
- if (!gkr_keyring_login_unlock (login_password))
+ if (!gkd_login_unlock (login_password))
g_message ("Failed to unlock login on startup");
egg_secure_strclear (login_password);
}
diff --git a/daemon/gkd-util.c b/daemon/gkd-util.c
index 06e4dbf..16a0730 100644
--- a/daemon/gkd-util.c
+++ b/daemon/gkd-util.c
@@ -92,14 +92,16 @@ gkd_util_init_master_directory (const gchar *replace)
if (replace) {
exists = TRUE;
if (lstat (replace, &st) < 0) {
- if (errno != ENOTDIR && errno != ENOENT)
+ if (errno == ENOTDIR || errno == ENOENT) {
exists = FALSE;
+ valid = TRUE;
+ }
} else if (st.st_uid != geteuid ()) {
g_message ("The gnome-keyring control directory is not owned with the same "
"credentials as the user login: %s", replace);
- } else if (st.st_mode != (S_IRUSR | S_IWUSR | S_IXUSR)) {
+ } else if ((st.st_mode & 0777) != 0700) {
g_message ("The gnome-keyring control directory has invalid permissions. It "
- "must be only be accessible by its owner (ie: 0600): %s", replace);
+ "must be only be accessible by its owner (ie: 0700): %s", replace);
} else {
valid = TRUE;
}
@@ -115,7 +117,7 @@ gkd_util_init_master_directory (const gchar *replace)
} else if (!exists) {
g_assert (replace);
master_directory = g_strdup (replace);
- if (g_mkdir_with_parents (master_directory, S_IRUSR | S_IWUSR | S_IXUSR) < 0)
+ if (g_mkdir_with_parents (master_directory, 0700) < 0)
g_warning ("couldn't create socket directory: %s", g_strerror (errno));
/* A valid existing directory was supplied */
diff --git a/daemon/login/Makefile.am b/daemon/login/Makefile.am
new file mode 100644
index 0000000..b48f519
--- /dev/null
+++ b/daemon/login/Makefile.am
@@ -0,0 +1,24 @@
+
+INCLUDES= \
+ -DPREFIX=\""$(prefix)"\" \
+ -DBINDIR=\""$(bindir)"\" \
+ -DLIBEXECDIR=\""$(libexecdir)"\" \
+ -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/daemon \
+ -I$(top_builddir) \
+ $(GOBJECT_CFLAGS) \
+ $(GLIB_CFLAGS)
+
+# ------------------------------------------------------------------
+# DAEMON CODE
+
+noinst_LTLIBRARIES = libgkd-login.la
+
+libgkd_login_la_SOURCES = \
+ gkd-login.c gkd-login.h
+
+libgkd_login_la_LIBADD = \
+ $(top_builddir)/gp11/libgp11.la \
+ $(GOBJECT_LIBS) \
+ $(GLIB_LIBS)
diff --git a/daemon/login/gkd-login.c b/daemon/login/gkd-login.c
new file mode 100644
index 0000000..f327e34
--- /dev/null
+++ b/daemon/login/gkd-login.c
@@ -0,0 +1,678 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2009 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public 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 Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gkd-login.h"
+
+#include "egg/egg-secure-memory.h"
+
+#include "pkcs11/gkr-pkcs11-daemon.h"
+#include "pkcs11/pkcs11i.h"
+
+#include <string.h>
+
+static gint unlock_failures = 0;
+
+static void
+note_that_unlock_failed (void)
+{
+ g_atomic_int_inc (&unlock_failures);
+}
+
+static GP11Module*
+module_instance (void)
+{
+ GP11Module *module = gp11_module_new (gkr_pkcs11_daemon_get_base_functions ());
+ gp11_module_set_pool_sessions (module, FALSE);
+ gp11_module_set_auto_authenticate (module, FALSE);
+ g_return_val_if_fail (module, NULL);
+ return module;
+}
+
+static GP11Session*
+open_and_login_session (GP11Slot *slot, CK_USER_TYPE user_type, GError **error)
+{
+ GP11Session *session;
+
+ g_return_val_if_fail (GP11_IS_SLOT (slot), NULL);
+
+ session = gp11_slot_open_session (slot, CKF_RW_SESSION, error);
+ if (session != NULL) {
+ if (!gp11_session_login (session, user_type, NULL, 0, error)) {
+ g_object_unref (session);
+ session = NULL;
+ }
+ }
+
+ return session;
+}
+
+static GP11Session*
+lookup_login_session (GP11Module *module)
+{
+ GP11Slot *slot = NULL;
+ GError *error = NULL;
+ GP11Session *session;
+ GP11SlotInfo *info;
+ GList *slots;
+ GList *l;
+
+ g_assert (GP11_IS_MODULE (module));
+
+ /*
+ * Find the right slot.
+ *
+ * TODO: This isn't necessarily the best way to do this.
+ * A good function could be added to gp11 library.
+ * But needs more thought on how to do this.
+ */
+ slots = gp11_module_get_slots (module, TRUE);
+ for (l = slots; !slot && l; l = g_list_next (l)) {
+ info = gp11_slot_get_info (l->data);
+ if (g_ascii_strcasecmp ("Secret Store", info->slot_description) == 0)
+ slot = g_object_ref (l->data);
+ gp11_slot_info_free (info);
+ }
+ gp11_list_unref_free (slots);
+
+ g_return_val_if_fail (slot, NULL);
+
+ session = open_and_login_session (slot, CKU_USER, &error);
+ if (session == NULL) {
+ g_warning ("couldn't open pkcs11 session for login: %s", error->message);
+ g_clear_error (&error);
+ }
+
+ g_object_unref (slot);
+
+ return session;
+}
+
+static GP11Object*
+lookup_login_keyring (GP11Session *session)
+{
+ GError *error = NULL;
+ GP11Object *login = NULL;
+ GList *objects;
+ guint length;
+
+ g_return_val_if_fail (GP11_IS_SESSION (session), NULL);
+
+ objects = gp11_session_find_objects (session, &error,
+ CKA_CLASS, GP11_ULONG, CKO_G_COLLECTION,
+ CKA_TOKEN, GP11_BOOLEAN, TRUE,
+ CKA_ID, 5, "login",
+ GP11_INVALID);
+
+ if (error) {
+ g_warning ("couldn't search for login keyring: %s", error->message);
+ g_clear_error (&error);
+ return NULL;
+ }
+
+ length = g_list_length (objects);
+ if (length == 1) {
+ login = g_object_ref (objects->data);
+ gp11_object_set_session (login, session);
+ } else if (length > 1) {
+ g_warning ("more than one login keyring exists");
+ }
+
+ gp11_list_unref_free (objects);
+ return login;
+}
+
+static GP11Object*
+create_login_keyring (GP11Session *session, GP11Object *cred, GError **error)
+{
+ GP11Object *login;
+
+ g_return_val_if_fail (GP11_IS_SESSION (session), NULL);
+ g_return_val_if_fail (GP11_IS_OBJECT (cred), NULL);
+
+ login = gp11_session_create_object (session, error,
+ CKA_CLASS, GP11_ULONG, CKO_G_COLLECTION,
+ CKA_ID, 5, "login",
+ CKA_G_CREDENTIAL, GP11_ULONG, gp11_object_get_handle (cred),
+ CKA_TOKEN, GP11_BOOLEAN, TRUE,
+ GP11_INVALID);
+
+ if (login != NULL)
+ gp11_object_set_session (login, session);
+ return login;
+}
+
+static GP11Object*
+create_credential (GP11Session *session, GP11Object *object,
+ const gchar *secret, GError **error)
+{
+ GP11Attributes *attrs;
+ GP11Object *cred;
+
+ g_return_val_if_fail (GP11_IS_SESSION (session), NULL);
+ g_return_val_if_fail (!object || GP11_IS_OBJECT (object), NULL);
+
+ if (!secret)
+ secret = "";
+
+ attrs = gp11_attributes_newv (CKA_CLASS, GP11_ULONG, CKO_G_CREDENTIAL,
+ CKA_VALUE, strlen (secret), secret,
+ CKA_GNOME_TRANSIENT, GP11_BOOLEAN, TRUE,
+ CKA_TOKEN, GP11_BOOLEAN, TRUE,
+ GP11_INVALID);
+
+ if (object)
+ gp11_attributes_add_ulong (attrs, CKA_G_OBJECT,
+ gp11_object_get_handle (object));
+
+ cred = gp11_session_create_object_full (session, attrs, NULL, error);
+ gp11_attributes_unref (attrs);
+
+ if (cred != NULL)
+ gp11_object_set_session (cred, session);
+
+ return cred;
+}
+
+static gboolean
+unlock_or_create_login (GP11Module *module, const gchar *master)
+{
+ GError *error = NULL;
+ GP11Session *session;
+ GP11Object *login;
+ GP11Object *cred;
+
+ g_return_val_if_fail (GP11_IS_MODULE (module), FALSE);
+ g_return_val_if_fail (master, FALSE);
+
+ /* Find the login object */
+ session = lookup_login_session (module);
+ login = lookup_login_keyring (session);
+
+ /* Create credentials for login object */
+ cred = create_credential (session, login, master, &error);
+
+ /* Failure, bad password? */
+ if (cred == NULL) {
+ if (login && error->code == CKR_PIN_INCORRECT)
+ note_that_unlock_failed ();
+ else
+ g_warning ("couldn't create login credential: %s", error->message);
+ g_clear_error (&error);
+
+ /* Non login keyring, create it */
+ } else if (!login) {
+ login = create_login_keyring (session, cred, &error);
+ if (login == NULL) {
+ g_warning ("couldn't create login keyring: %s", error->message);
+ g_clear_error (&error);
+ }
+ }
+
+ if (cred)
+ g_object_unref (cred);
+ if (login)
+ g_object_unref (login);
+ if (session)
+ g_object_unref (session);
+
+ return cred && login;
+}
+
+static gboolean
+init_pin_for_uninitialized_slots (GP11Module *module, const gchar *master)
+{
+ GError *error = NULL;
+ GList *slots, *l;
+ gboolean initialize;
+ GP11TokenInfo *info;
+ GP11Session *session;
+
+ g_return_val_if_fail (GP11_IS_MODULE (module), FALSE);
+ g_return_val_if_fail (master, FALSE);
+
+ slots = gp11_module_get_slots (module, TRUE);
+ for (l = slots; l; l = g_list_next (l)) {
+ info = gp11_slot_get_token_info (l->data);
+ initialize = (info && !(info->flags & CKF_USER_PIN_INITIALIZED));
+
+ if (initialize) {
+ session = open_and_login_session (l->data, CKU_SO, NULL);
+ if (session != NULL) {
+ if (gp11_session_init_pin (session, (const guchar*)master, strlen (master), &error)) {
+ gkd_login_attach_secret (info->label, master,
+ "manufacturer", info->manufacturer_id,
+ "serial-number", info->serial_number,
+ NULL);
+ } else {
+ if (error->code != CKR_FUNCTION_NOT_SUPPORTED)
+ g_warning ("couldn't initialize slot with master password: %s", error->message);
+ g_clear_error (&error);
+ }
+ g_object_unref (session);
+ }
+ }
+
+ gp11_token_info_free (info);
+ }
+ gp11_list_unref_free (slots);
+ return TRUE;
+}
+
+gboolean
+gkd_login_unlock (const gchar *master)
+{
+ GP11Module *module;
+ gboolean result;
+
+ /* We don't support null or empty master passwords */
+ if (!master || !master[0])
+ return FALSE;
+
+ module = module_instance ();
+
+ result = unlock_or_create_login (module, master);
+ if (result == TRUE)
+ init_pin_for_uninitialized_slots (module, master);
+
+ g_object_unref (module);
+ return result;
+}
+
+static gboolean
+change_or_create_login (GP11Module *module, const gchar *original, const gchar *master)
+{
+ GError *error = NULL;
+ GP11Session *session;
+ GP11Object *login = NULL;
+ GP11Object *ocred = NULL;
+ GP11Object *mcred = NULL;
+ gboolean success = FALSE;
+
+ g_return_val_if_fail (GP11_IS_MODULE (module), FALSE);
+ g_return_val_if_fail (original, FALSE);
+ g_return_val_if_fail (master, FALSE);
+
+ /* Find the login object */
+ session = lookup_login_session (module);
+ login = lookup_login_keyring (session);
+
+ /* Create the new credential we'll be changing to */
+ mcred = create_credential (session, NULL, master, &error);
+ if (mcred == NULL) {
+ g_warning ("couldn't create new login credential: %s", error->message);
+ g_clear_error (&error);
+
+ /* Create original credentials */
+ } else if (login) {
+ ocred = create_credential (session, login, original, &error);
+ if (ocred == NULL) {
+ if (error->code == CKR_PIN_INCORRECT) {
+ g_message ("couldn't change login master password, "
+ "original password was wrong: %s", error->message);
+ note_that_unlock_failed ();
+ } else {
+ g_warning ("couldn't create original login credential: %s", error->message);
+ }
+ g_clear_error (&error);
+ }
+ }
+
+ /* No keyring? try to create */
+ if (!login && mcred) {
+ login = create_login_keyring (session, mcred, &error);
+ if (login == NULL) {
+ g_warning ("couldn't create login keyring: %s", error->message);
+ g_clear_error (&error);
+ } else {
+ success = TRUE;
+ }
+
+ /* Change the master password */
+ } else if (login && ocred && mcred) {
+ if (!gp11_object_set (login, &error,
+ CKA_G_CREDENTIAL, GP11_ULONG, gp11_object_get_handle (mcred),
+ GP11_INVALID)) {
+ g_warning ("couldn't change login master password: %s", error->message);
+ g_clear_error (&error);
+ } else {
+ success = TRUE;
+ }
+ }
+
+ if (ocred) {
+ gp11_object_destroy (ocred, NULL);
+ g_object_unref (ocred);
+ }
+ if (mcred)
+ g_object_unref (mcred);
+ if (login)
+ g_object_unref (login);
+ if (session)
+ g_object_unref (session);
+
+ return success;
+}
+
+static gboolean
+set_pin_for_any_slots (GP11Module *module, const gchar *original, const gchar *master)
+{
+ GError *error = NULL;
+ GList *slots, *l;
+ gboolean initialize;
+ GP11TokenInfo *info;
+ GP11Session *session;
+
+ g_return_val_if_fail (GP11_IS_MODULE (module), FALSE);
+ g_return_val_if_fail (original, FALSE);
+ g_return_val_if_fail (master, FALSE);
+
+ slots = gp11_module_get_slots (module, TRUE);
+ for (l = slots; l; l = g_list_next (l)) {
+
+ /* Set pin for any that are initialized, and not pap */
+ info = gp11_slot_get_token_info (l->data);
+ initialize = (info && (info->flags & CKF_USER_PIN_INITIALIZED));
+
+ if (initialize) {
+ session = open_and_login_session (l->data, CKU_USER, NULL);
+ if (session != NULL) {
+ if (gp11_session_set_pin (session, (const guchar*)original, strlen (original),
+ (const guchar*)master, strlen (master), &error)) {
+ gkd_login_attach_secret (info->label, master,
+ "manufacturer", info->manufacturer_id,
+ "serial-number", info->serial_number,
+ NULL);
+ } else {
+ if (error->code != CKR_PIN_INCORRECT && error->code != CKR_FUNCTION_NOT_SUPPORTED)
+ g_warning ("couldn't change slot master password: %s", error->message);
+ g_clear_error (&error);
+ }
+ g_object_unref (session);
+ }
+ }
+
+ gp11_token_info_free (info);
+ }
+ gp11_list_unref_free (slots);
+ return TRUE;
+}
+
+gboolean
+gkd_login_change_lock (const gchar *original, const gchar *master)
+{
+ GP11Module *module;
+ gboolean result;
+
+ /* We don't support null or empty master passwords */
+ if (!master || !master[0])
+ return FALSE;
+ if (original == NULL)
+ original = "";
+
+ module = module_instance ();
+
+ result = change_or_create_login (module, original, master);
+ if (result == TRUE)
+ set_pin_for_any_slots (module, original, master);
+
+ g_object_unref (module);
+ return result;
+}
+
+gboolean
+gkd_login_is_usable (void)
+{
+ GP11Module *module;
+ GP11Session *session;
+ GP11Object *login;
+ gboolean usable = FALSE;
+ gpointer data;
+ gsize n_data;
+
+ module = module_instance ();
+ if (!module)
+ return FALSE;
+
+ session = lookup_login_session (module);
+ if (session) {
+ login = lookup_login_keyring (session);
+ if (login) {
+ data = gp11_object_get_data (login, CKA_G_LOCKED, &n_data, NULL);
+ usable = (data && n_data == sizeof (CK_BBOOL) && *((CK_BBOOL*)data));
+ g_free (data);
+ g_object_unref (login);
+ }
+ g_object_unref (session);
+ }
+
+ g_object_unref (module);
+ return usable;
+}
+
+static void
+string_attribute_list_va (va_list args, const gchar *name, GP11Attribute *attr)
+{
+ GString *fields = g_string_sized_new(128);
+ gsize length;
+
+ while (name != NULL) {
+ g_string_append (fields, name);
+ g_string_append_c (fields, '\0');
+ g_string_append (fields, va_arg (args, const gchar*));
+ g_string_append_c (fields, '\0');
+ name = va_arg (args, const gchar*);
+ }
+
+ length = fields->len;
+ gp11_attribute_init (attr, CKA_G_FIELDS, g_string_free (fields, FALSE), length);
+}
+
+static GP11Object*
+find_login_keyring_item (GP11Session *session, GP11Attribute *fields)
+{
+ GP11Object *search;
+ GP11Object *item;
+ GList *objects;
+ GError *error = NULL;
+ gpointer data;
+ gsize n_data;
+
+ g_return_val_if_fail (GP11_IS_SESSION (session), FALSE);
+
+ /* Create a search object */
+ search = gp11_session_create_object (session, &error,
+ CKA_CLASS, GP11_ULONG, CKO_G_SEARCH,
+ CKA_G_COLLECTION, 5, "login",
+ CKA_G_FIELDS, fields->length, fields->value,
+ GP11_INVALID);
+
+ if (!search) {
+ g_warning ("couldn't create search for login keyring: %s", error->message);
+ g_clear_error (&error);
+ return NULL;
+ }
+
+ /* Get the data from the search */
+ gp11_object_set_session (search, session);
+ data = gp11_object_get_data (search, CKA_G_MATCHED, &n_data, &error);
+ gp11_object_destroy (search, NULL);
+ g_object_unref (search);
+
+ if (data == NULL) {
+ g_warning ("couldn't read search in login keyring: %s", error->message);
+ g_clear_error (&error);
+ return NULL;
+ }
+
+ objects = gp11_objects_from_handle_array (gp11_session_get_slot (session), data,
+ MIN (sizeof (CK_OBJECT_HANDLE), n_data));
+ g_free (data);
+
+ if (objects) {
+ item = g_object_ref (objects->data);
+ gp11_object_set_session (item, session);
+ }
+
+ gp11_list_unref_free (objects);
+ return item;
+}
+
+void
+gkd_login_attach_secret (const gchar *display_name, const gchar *secret,
+ const gchar *first, ...)
+{
+ GError *error = NULL;
+ GP11Attribute fields;
+ GP11Session *session;
+ GP11Module *module;
+ GP11Object* item;
+ va_list va;
+
+ if (display_name == NULL)
+ display_name = "";
+ if (secret == NULL)
+ secret = "";
+
+ module = module_instance ();
+ session = lookup_login_session (module);
+
+ va_start(va, first);
+ gp11_attribute_init_empty (&fields, CKA_G_FIELDS);
+ string_attribute_list_va (va, first, &fields);
+ va_end(va);
+
+ item = find_login_keyring_item (session, &fields);
+ if (item) {
+ gp11_object_set (item, &error,
+ CKA_LABEL, strlen (display_name), display_name,
+ CKA_VALUE, strlen (secret), secret,
+ GP11_INVALID);
+ } else {
+ item = gp11_session_create_object (session, &error,
+ CKA_CLASS, GP11_ULONG, CKO_SECRET_KEY,
+ CKA_LABEL, strlen (display_name), display_name,
+ CKA_VALUE, strlen (secret), secret,
+ CKA_G_COLLECTION, 5, "login",
+ CKA_G_FIELDS, fields.length, fields.value,
+ GP11_INVALID);
+ }
+
+ if (error != NULL) {
+ g_warning ("couldn't store secret in login keyring: %s", error->message);
+ g_clear_error (&error);
+ }
+
+ if (item)
+ g_object_unref (item);
+ g_object_unref (session);
+ g_object_unref (module);
+}
+
+gchar*
+gkd_login_lookup_secret (const gchar *first, ...)
+{
+ GError *error = NULL;
+ GP11Attribute fields;
+ GP11Session *session;
+ GP11Module *module;
+ GP11Object* item;
+ gpointer data;
+ gsize n_data;
+ va_list va;
+
+ module = module_instance ();
+ session = lookup_login_session (module);
+
+ va_start(va, first);
+ gp11_attribute_init_empty (&fields, CKA_G_FIELDS);
+ string_attribute_list_va (va, first, &fields);
+ va_end(va);
+
+ item = find_login_keyring_item (session, &fields);
+ if (item == NULL) {
+ data = gp11_object_get_data_full (item, CKA_VALUE, egg_secure_realloc, NULL, &n_data, &error);
+ if (!g_utf8_validate (data, n_data, NULL)) {
+ g_warning ("expected string, but found binary secret in login keyring");
+ egg_secure_clear (data, n_data);
+ egg_secure_free (data);
+ data = NULL;
+ }
+ g_object_unref (item);
+ }
+
+ g_object_unref (session);
+ g_object_unref (module);
+
+ /* Memory returned from gp11_object_get_data is null terminated */
+ return data;
+}
+
+void
+gkd_login_remove_secret (const gchar *first, ...)
+{
+ GError *error = NULL;
+ GP11Attribute fields;
+ GP11Session *session;
+ GP11Module *module;
+ GP11Object* item;
+ va_list va;
+
+ module = module_instance ();
+ session = lookup_login_session (module);
+
+ va_start(va, first);
+ gp11_attribute_init_empty (&fields, CKA_G_FIELDS);
+ string_attribute_list_va (va, first, &fields);
+ va_end(va);
+
+ item = find_login_keyring_item (session, &fields);
+ if (item == NULL) {
+ if (!gp11_object_destroy (item, &error)) {
+ g_warning ("couldn't remove stored secret from login keyring: %s", error->message);
+ g_clear_error (&error);
+ }
+ g_object_unref (item);
+ }
+
+ g_object_unref (session);
+ g_object_unref (module);
+}
+
+GP11Attributes*
+gkd_login_attributes_for_secret (const gchar *first, ...)
+{
+ GP11Attributes *attrs;
+ GP11Attribute *fields;
+ va_list va;
+
+ attrs = gp11_attributes_newv (CKA_CLASS, GP11_ULONG, CKO_SECRET_KEY,
+ CKA_G_COLLECTION, 5, "login",
+ GP11_INVALID);
+
+ va_start(va, first);
+ fields = gp11_attributes_add_empty (attrs, CKA_G_FIELDS);
+ string_attribute_list_va (va, first, fields);
+ va_end(va);
+
+ return attrs;
+}
diff --git a/daemon/login/gkd-login.h b/daemon/login/gkd-login.h
new file mode 100644
index 0000000..d6ee6ef
--- /dev/null
+++ b/daemon/login/gkd-login.h
@@ -0,0 +1,50 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2009 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public 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 Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GKD_LOGIN_H__
+#define __GKD_LOGIN_H__
+
+#include <glib.h>
+
+#include "gp11/gp11.h"
+
+gboolean gkd_login_unlock (const gchar *master);
+
+gboolean gkd_login_change_lock (const gchar *original,
+ const gchar *master);
+
+gboolean gkd_login_is_usable (void);
+
+void gkd_login_attach_secret (const gchar *display_name,
+ const gchar *secret,
+ const gchar *first,
+ ...);
+
+gchar* gkd_login_lookup_secret (const gchar *first,
+ ...);
+
+void gkd_login_remove_secret (const gchar *first,
+ ...);
+
+GP11Attributes* gkd_login_attributes_for_secret (const gchar *first,
+ ...);
+
+#endif /* __GKD_LOGIN_H__ */
diff --git a/daemon/pkcs11/gkr-pkcs11-auth.c b/daemon/pkcs11/gkr-pkcs11-auth.c
index dca070a..421d282 100644
--- a/daemon/pkcs11/gkr-pkcs11-auth.c
+++ b/daemon/pkcs11/gkr-pkcs11-auth.c
@@ -26,13 +26,13 @@
#include "egg/egg-cleanup.h"
#include "egg/egg-secure-memory.h"
-#include "keyrings/gkr-keyring-login.h"
+#include "login/gkd-login.h"
+
+#include "pkcs11/pkcs11.h"
#include "ui/gkr-ask-request.h"
#include "ui/gkr-ask-daemon.h"
-#include "pkcs11/pkcs11.h"
-
#include <glib.h>
#include <glib/gi18n.h>
@@ -85,7 +85,7 @@ password_to_pin (const gchar *password, CK_UTF8CHAR_PTR *pin, CK_ULONG *pin_len)
*pin = NULL;
*pin_len = 0;
} else {
- *pin = (CK_UTF8CHAR_PTR)egg_secure_strdup (password);
+ *pin = (CK_UTF8CHAR_PTR)password;
*pin_len = strlen (password);
}
}
@@ -214,8 +214,7 @@ gkr_pkcs11_auth_login_specific_prompt (CK_SESSION_HANDLE handle, CK_SESSION_INFO
/* See if we can just use the login keyring password for this */
if (object->unique && object->token) {
- password = gkr_keyring_login_lookup_secret (GNOME_KEYRING_ITEM_ENCRYPTION_KEY_PASSWORD,
- "unique", object->unique, NULL);
+ password = gkd_login_lookup_secret ("unique", object->unique, NULL);
if (password != NULL) {
password_to_pin (password, pin, pin_len);
return TRUE;
@@ -225,13 +224,11 @@ gkr_pkcs11_auth_login_specific_prompt (CK_SESSION_HANDLE handle, CK_SESSION_INFO
/* COMPAT: Check old method of storing secrets for objects in login keyring */
if (object->digest) {
convert_upper_case (object->digest);
- password = gkr_keyring_login_lookup_secret (GNOME_KEYRING_ITEM_PK_STORAGE,
- "object-digest", object->digest, NULL);
+ password = gkd_login_lookup_secret ("object-digest", object->digest, NULL);
if (password != NULL) {
if (object->unique)
- gkr_keyring_login_attach_secret (GNOME_KEYRING_ITEM_ENCRYPTION_KEY_PASSWORD,
- object->label, password,
- "unique", object->unique, NULL);
+ gkd_login_attach_secret (object->label, password,
+ "unique", object->unique, NULL);
password_to_pin (password, pin, pin_len);
return TRUE;
}
@@ -246,7 +243,7 @@ gkr_pkcs11_auth_login_specific_prompt (CK_SESSION_HANDLE handle, CK_SESSION_INFO
gkr_ask_request_set_secondary (ask, secondary);
g_free (secondary);
- if (object->unique && gkr_keyring_login_is_usable ())
+ if (object->unique && gkd_login_is_usable ())
gkr_ask_request_set_check_option (ask, prepare_specific_check (object->klass));
/* Prompt the user */
@@ -267,9 +264,8 @@ gkr_pkcs11_auth_login_specific_prompt (CK_SESSION_HANDLE handle, CK_SESSION_INFO
/* Store forever */
if (ask->checked && object->unique && object->token) {
- gkr_keyring_login_attach_secret (GNOME_KEYRING_ITEM_ENCRYPTION_KEY_PASSWORD,
- object->label, ask->typed_password,
- "unique", object->unique, NULL);
+ gkd_login_attach_secret (object->label, ask->typed_password,
+ "unique", object->unique, NULL);
}
}
@@ -325,8 +321,7 @@ gkr_pkcs11_auth_login_specific_done (CK_SESSION_HANDLE handle, CK_SESSION_INFO *
case CKR_PIN_LEN_RANGE:
case CKR_PIN_LOCKED:
if (object->unique && object->token)
- gkr_keyring_login_remove_secret (GNOME_KEYRING_ITEM_ENCRYPTION_KEY_PASSWORD,
- "unique", object->unique, NULL);
+ gkd_login_remove_secret ("unique", object->unique, NULL);
break;
case CKR_OK:
@@ -374,12 +369,11 @@ gkr_pkcs11_auth_login_user_prompt (CK_SESSION_HANDLE handle, CK_TOKEN_INFO *info
label = g_strndup ((gchar*)info->label, sizeof (info->label));
g_strchomp (label);
- if (gkr_keyring_login_is_usable ()) {
+ if (gkd_login_is_usable ()) {
- password = gkr_keyring_login_lookup_secret (GNOME_KEYRING_ITEM_CHAINED_KEYRING_PASSWORD,
- "manufacturer", manufacturer,
- "serial-number", serial,
- NULL);
+ password = gkd_login_lookup_secret ("manufacturer", manufacturer,
+ "serial-number", serial,
+ NULL);
if (password != NULL) {
password_to_pin (password, pin, pin_len);
g_free (manufacturer);
@@ -399,7 +393,7 @@ gkr_pkcs11_auth_login_user_prompt (CK_SESSION_HANDLE handle, CK_TOKEN_INFO *info
gkr_ask_request_set_secondary (ask, secondary);
g_free (secondary);
- if (gkr_keyring_login_is_usable ())
+ if (gkd_login_is_usable ())
gkr_ask_request_set_check_option (ask, _("Automatically unlock secure storage when I log in."));
/* Prompt the user */
@@ -420,11 +414,10 @@ gkr_pkcs11_auth_login_user_prompt (CK_SESSION_HANDLE handle, CK_TOKEN_INFO *info
/* Store forever */
if (ask->checked) {
- gkr_keyring_login_attach_secret (GNOME_KEYRING_ITEM_CHAINED_KEYRING_PASSWORD,
- label, ask->typed_password,
- "manufacturer", manufacturer,
- "serial-number", serial,
- NULL);
+ gkd_login_attach_secret (label, ask->typed_password,
+ "manufacturer", manufacturer,
+ "serial-number", serial,
+ NULL);
}
}
@@ -444,7 +437,7 @@ clear_user_login (CK_TOKEN_INFO *info)
g_assert (info);
- if (gkr_keyring_login_is_usable ()) {
+ if (gkd_login_is_usable ()) {
/*
* The manufacturer and serial number together uniquely identify token
* They're stored with space padded in the token info structure.
@@ -456,10 +449,9 @@ clear_user_login (CK_TOKEN_INFO *info)
serial = g_strndup ((gchar*)info->serialNumber, sizeof (info->serialNumber));
g_strchomp (serial);
- gkr_keyring_login_remove_secret (GNOME_KEYRING_ITEM_CHAINED_KEYRING_PASSWORD,
- "manufacturer", manufacturer,
- "serial-number", serial,
- NULL);
+ gkd_login_remove_secret ("manufacturer", manufacturer,
+ "serial-number", serial,
+ NULL);
g_free (manufacturer);
g_free (serial);
@@ -498,7 +490,6 @@ gkr_pkcs11_auth_init_user_prompt (CK_SESSION_HANDLE handle, CK_TOKEN_INFO *info,
gchar *secondary;
gchar *manufacturer;
gchar *serial;
- const gchar *password;
gboolean ret = TRUE;
guint flags;
@@ -520,27 +511,6 @@ gkr_pkcs11_auth_init_user_prompt (CK_SESSION_HANDLE handle, CK_TOKEN_INFO *info,
label = g_strndup ((gchar*)info->label, sizeof (info->label));
g_strchomp (label);
- /* We try to use the login keyring password if available */
- password = gkr_keyring_login_master ();
- if (password != NULL) {
- password_to_pin (password, pin, pin_len);
-
- /* Save this away in case the main password changes without us being aware */
- if (gkr_keyring_login_is_usable ())
- gkr_keyring_login_attach_secret (GNOME_KEYRING_ITEM_CHAINED_KEYRING_PASSWORD,
- label, password,
- "manufacturer", manufacturer,
- "serial-number", serial,
- NULL);
-
- g_free (manufacturer);
- g_free (serial);
- g_free (label);
- return TRUE;
- }
-
- /* Otherwise we have to prompt for it */
-
/* Build up the prompt */
flags = GKR_ASK_REQUEST_NEW_PASSWORD;
ask = gkr_ask_request_new (_("New Password Required"),
@@ -550,7 +520,7 @@ gkr_pkcs11_auth_init_user_prompt (CK_SESSION_HANDLE handle, CK_TOKEN_INFO *info,
gkr_ask_request_set_secondary (ask, secondary);
g_free (secondary);
- if (gkr_keyring_login_is_usable ())
+ if (gkd_login_is_usable ())
gkr_ask_request_set_check_option (ask, _("Automatically unlock secure storage when I log in."));
/* Prompt the user */
@@ -569,11 +539,10 @@ gkr_pkcs11_auth_init_user_prompt (CK_SESSION_HANDLE handle, CK_TOKEN_INFO *info,
password_to_pin (ask->typed_password, pin, pin_len);
if (ask->checked) {
- gkr_keyring_login_attach_secret (GNOME_KEYRING_ITEM_CHAINED_KEYRING_PASSWORD,
- label, ask->typed_password,
- "manufacturer", manufacturer,
- "serial-number", serial,
- NULL);
+ gkd_login_attach_secret (label, ask->typed_password,
+ "manufacturer", manufacturer,
+ "serial-number", serial,
+ NULL);
}
ret = TRUE;
diff --git a/daemon/pkcs11/gkr-pkcs11-daemon.c b/daemon/pkcs11/gkr-pkcs11-daemon.c
index 9fcaefc..4850fb7 100644
--- a/daemon/pkcs11/gkr-pkcs11-daemon.c
+++ b/daemon/pkcs11/gkr-pkcs11-daemon.c
@@ -51,6 +51,7 @@
/* The top level of our internal PKCS#11 module stack */
static CK_FUNCTION_LIST_PTR pkcs11_roof = NULL;
+static CK_FUNCTION_LIST_PTR pkcs11_base = NULL;
static void
pkcs11_daemon_cleanup (gpointer unused)
@@ -76,7 +77,6 @@ pkcs11_daemon_cleanup (gpointer unused)
gboolean
gkr_pkcs11_daemon_initialize (void)
{
- CK_FUNCTION_LIST_PTR plex_layer;
CK_FUNCTION_LIST_PTR roots_store;
CK_FUNCTION_LIST_PTR secret_store;
CK_FUNCTION_LIST_PTR ssh_store;
@@ -106,11 +106,11 @@ gkr_pkcs11_daemon_initialize (void)
#endif
gck_plex_layer_add_module (secret_store);
gck_plex_layer_add_module (user_store);
-
- plex_layer = gck_plex_layer_get_functions ();
-
+
+ pkcs11_base = gck_plex_layer_get_functions ();
+
/* The auth component is the top component */
- gkr_pkcs11_auth_chain_functions (plex_layer);
+ gkr_pkcs11_auth_chain_functions (pkcs11_base);
pkcs11_roof = gkr_pkcs11_auth_get_functions ();
/* Initialize the whole caboodle */
@@ -245,3 +245,9 @@ gkr_pkcs11_daemon_get_functions (void)
{
return pkcs11_roof;
}
+
+CK_FUNCTION_LIST_PTR
+gkr_pkcs11_daemon_get_base_functions (void)
+{
+ return pkcs11_base;
+}
diff --git a/daemon/pkcs11/gkr-pkcs11-daemon.h b/daemon/pkcs11/gkr-pkcs11-daemon.h
index 52659e8..8f8f83e 100644
--- a/daemon/pkcs11/gkr-pkcs11-daemon.h
+++ b/daemon/pkcs11/gkr-pkcs11-daemon.h
@@ -34,4 +34,6 @@ gboolean gkr_pkcs11_daemon_startup_ssh (void);
CK_FUNCTION_LIST_PTR gkr_pkcs11_daemon_get_functions (void);
+CK_FUNCTION_LIST_PTR gkr_pkcs11_daemon_get_base_functions (void);
+
#endif /* GKRPKCS11DAEMON_H_ */
diff --git a/tests/gtest-helpers.c b/tests/gtest-helpers.c
index 7ca44e1..dd032f6 100644
--- a/tests/gtest-helpers.c
+++ b/tests/gtest-helpers.c
@@ -158,7 +158,7 @@ test_data_read (const gchar *basename, gsize *n_result)
return (guchar*)result;
}
-#ifdef WITH_P11_TESTS
+#if WITH_P11_TESTS
static void
on_p11_tests_log (int level, const char *section, const char *message)
@@ -246,7 +246,6 @@ int
main (int argc, char* argv[])
{
GLogLevelFlags fatal_mask;
- int ret;
g_thread_init (NULL);
@@ -268,15 +267,6 @@ main (int argc, char* argv[])
fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
g_log_set_always_fatal (fatal_mask);
- initialize_tests ();
-
- start_tests ();
- ret = g_test_run ();
-
- /* Any auxiliary suites */
- run_externals ();
-
- stop_tests();
-
- return ret;
+ /* Must have been defined by the test including this file */
+ return run();
}
diff --git a/tests/prep-gtest.sh b/tests/prep-gtest.sh
index de19a5d..87f6c64 100755
--- a/tests/prep-gtest.sh
+++ b/tests/prep-gtest.sh
@@ -95,6 +95,16 @@ build_source()
echo "}"
echo
+ echo "static int run(void) {"
+ echo " int ret;"
+ echo " initialize_tests ();"
+ echo " start_tests ();"
+ echo " ret = g_test_run ();"
+ echo " run_externals ();"
+ echo " stop_tests();"
+ echo " return ret;"
+ echo "}"
+
echo "#include \"tests/gtest-helpers.c\""
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]