[gnome-online-accounts/wip/rishi/identity-kernel-keyring-notification: 5/5] keyring notification
- From: Debarshi Ray <debarshir src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-online-accounts/wip/rishi/identity-kernel-keyring-notification: 5/5] keyring notification
- Date: Fri, 31 Jan 2020 17:35:49 +0000 (UTC)
commit e67ae8bf305ad7828723a50ad7a59037241eaa3c
Author: Debarshi Ray <debarshir gnome org>
Date: Thu Jan 30 18:39:06 2020 +0100
keyring notification
configure.ac | 2 +
meson.build | 4 +
src/goaidentity/goakerberosidentitymanager.c | 204 +++++++++++++++++++++++----
3 files changed, 182 insertions(+), 28 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 373816b1..6a2381bb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -413,6 +413,8 @@ fi
AM_CONDITIONAL(BUILD_IDENTITY_SERVICE, [test x$enable_fedora != xno || test x$enable_kerberos != xno])
+AC_CHECK_FUNCS(pipe2)
+
# Optional timerfd support
AC_MSG_CHECKING([for timerfd support])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
diff --git a/meson.build b/meson.build
index eb5eaa17..cc881c21 100644
--- a/meson.build
+++ b/meson.build
@@ -225,6 +225,10 @@ config_h.set_quoted('GOA_WINDOWS_LIVE_CLIENT_ID', windows_live_client_id)
enable_windows_live = get_option('windows_live')
config_h.set('GOA_WINDOWS_LIVE_ENABLED', enable_windows_live)
+if cc.has_function('pipe2')
+ config_h.set('HAVE_PIPE2', true)
+endif
+
# Optional timerfd support
timerfd_support_src = '''
#include <sys/timerfd.h>
diff --git a/src/goaidentity/goakerberosidentitymanager.c b/src/goaidentity/goakerberosidentitymanager.c
index 678db4c6..a3ba7c7c 100644
--- a/src/goaidentity/goakerberosidentitymanager.c
+++ b/src/goaidentity/goakerberosidentitymanager.c
@@ -18,16 +18,25 @@
#include "config.h"
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
#include "goakerberosidentitymanager.h"
#include "goaidentitymanager.h"
#include "goaidentitymanagererror.h"
#include "goaidentitymanagerprivate.h"
#include "goakerberosidentityinquiry.h"
+#include <errno.h>
#include <fcntl.h>
#include <string.h>
+#include <unistd.h>
+#include <linux/keyctl.h>
+#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/syscall.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
@@ -120,6 +129,11 @@ G_DEFINE_TYPE_WITH_CODE (GoaKerberosIdentityManager,
initable_interface_init));
#define FALLBACK_POLLING_INTERVAL 5
+enum
+{
+ WATCH_QUEUE_BUFFER_SIZE = 256
+};
+
static Operation *
operation_new (GoaKerberosIdentityManager *self,
GCancellable *cancellable,
@@ -174,6 +188,105 @@ operation_free (Operation *operation)
g_slice_free (Operation, operation);
}
+static GSource *
+goa_kerberos_identity_manager_keyring_source_new (GError **error)
+{
+ GSource *ret = NULL;
+
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+#ifdef HAVE_PIPE2
+ {
+ g_autoptr (GInputStream) stream = NULL;
+ gint error_code;
+ gint fds[2] = { -1, -1 };
+ struct watch_notification_filter watch_queue_notification_filter = { 0 };
+ struct watch_notification_type_filter watch_queue_notification_types[1];
+
+ error_code = pipe2 (fds, O_NOTIFICATION_PIPE);
+ if (error_code == -1)
+ {
+ const gchar *error_str;
+
+ error_str = g_strerror (errno);
+ g_set_error_literal (error, G_UNIX_ERROR, 0, error_str);
+ goto out;
+ }
+
+ close (fds[1]);
+
+ error_code = ioctl (fds[0], IOC_WATCH_QUEUE_SET_SIZE, WATCH_QUEUE_BUFFER_SIZE);
+ if (error_code == -1)
+ {
+ const gchar *error_str;
+
+ error_str = g_strerror (errno);
+ g_set_error_literal (error, G_UNIX_ERROR, 0, error_str);
+ goto out;
+ }
+
+ watch_queue_notification_types[0].type = WATCH_TYPE_KEY_NOTIFY;
+ watch_queue_notification_types[0].info_filter = 0;
+ watch_queue_notification_types[0].info_mask = 0;
+ watch_queue_notification_types[0].subtype_filter[0] = G_MAXUINT;
+
+ watch_queue_notification_filter.nr_filters = 1;
+ watch_queue_notification_filter.filters = watch_queue_notification_types;
+
+ error_code = ioctl(fds[0], IOC_WATCH_QUEUE_SET_FILTER, &watch_queue_notification_filter);
+ if (error_code == -1)
+ {
+ const gchar *error_str;
+
+ error_str = g_strerror (errno);
+ g_set_error_literal (error, G_UNIX_ERROR, 0, error_str);
+ goto out;
+ }
+
+ error_code = syscall (__NR_keyctl, KEYCTL_WATCH_KEY, KEY_SPEC_SESSION_KEYRING, fds[0], 0x01);
+ if (error_code == -1)
+ {
+ const gchar *error_str;
+
+ error_str = g_strerror (errno);
+ g_set_error_literal (error, G_UNIX_ERROR, 0, error_str);
+ goto out;
+ }
+
+ error_code = syscall (__NR_keyctl, KEYCTL_WATCH_KEY, KEY_SPEC_USER_KEYRING, fds[0], 0x02);
+ if (error_code == -1)
+ {
+ const gchar *error_str;
+
+ error_str = g_strerror (errno);
+ g_set_error_literal (error, G_UNIX_ERROR, 0, error_str);
+ goto out;
+ }
+
+ error_code = syscall (__NR_watch_devices, fds[0], 0x04, 0);
+ if (error_code == -1)
+ {
+ const gchar *error_str;
+
+ error_str = g_strerror (errno);
+ g_set_error_literal (error, G_UNIX_ERROR, 0, error_str);
+ goto out;
+ }
+
+ stream = g_unix_input_stream_new (fds[0], TRUE);
+ ret = g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (stream), NULL);
+ }
+#else
+ {
+ g_set_error_literal (error, G_UNIX_ERROR, 0, "pipe2(2) not supported");
+ goto out;
+ }
+#endif
+
+ out:
+ return ret;
+}
+
typedef struct {
GSourceFunc func;
gboolean ret_val;
@@ -1320,6 +1433,13 @@ credentials_cache_file_monitor_changed (GFileMonitor *monitor,
schedule_refresh (self);
}
+static gboolean
+credentials_cache_keyring_notification (GoaKerberosIdentityManager *self)
+{
+ schedule_refresh (self);
+ return G_SOURCE_CONTINUE;
+}
+
static gboolean
credentials_cache_polling_timeout (GoaKerberosIdentityManager *self)
{
@@ -1335,7 +1455,6 @@ monitor_credentials_cache (GoaKerberosIdentityManager *self,
krb5_ccache default_cache;
const char *cache_type;
const char *cache_path;
- GFileMonitor *monitor = NULL;
krb5_error_code error_code;
GError *monitoring_error = NULL;
gboolean can_monitor = TRUE;
@@ -1359,13 +1478,6 @@ monitor_credentials_cache (GoaKerberosIdentityManager *self,
cache_type = krb5_cc_get_type (self->kerberos_context, default_cache);
g_assert (cache_type != NULL);
- if (strcmp (cache_type, "FILE") != 0 && strcmp (cache_type, "DIR") != 0)
- {
- g_warning ("GoaKerberosIdentityManager: Using polling for change notification for credential cache
type '%s'",
- cache_type);
- can_monitor = FALSE;
- }
-
g_free (self->credentials_cache_type);
self->credentials_cache_type = g_strdup (cache_type);
@@ -1387,56 +1499,92 @@ monitor_credentials_cache (GoaKerberosIdentityManager *self,
if (cache_path[0] == ':')
cache_path++;
- if (can_monitor)
+ if (strcmp (cache_type, "FILE") == 0 || strcmp (cache_type, "DIR") == 0)
{
- GFile *file;
+ GFile *file = NULL;
+ GFileMonitor *monitor = NULL;
file = g_file_new_for_path (cache_path);
- monitoring_error = NULL;
if (strcmp (cache_type, "FILE") == 0)
{
- monitor = g_file_monitor_file (file,
- G_FILE_MONITOR_NONE,
- NULL,
- &monitoring_error);
+ monitoring_error = NULL;
+ monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, &monitoring_error);
+ if (monitoring_error != NULL)
+ {
+ g_warning ("GoaKerberosIdentityManager: Could not monitor credentials for %s (type %s),
reverting to "
+ "polling: %s",
+ cache_path,
+ cache_type,
+ monitoring_error->message);
+
+ can_monitor = FALSE;
+ g_error_free (monitoring_error);
+ }
}
else if (strcmp (cache_type, "DIR") == 0)
{
GFile *directory;
directory = g_file_get_parent (file);
- monitor = g_file_monitor_directory (directory,
- G_FILE_MONITOR_NONE,
- NULL,
- &monitoring_error);
+
+ monitoring_error = NULL;
+ monitor = g_file_monitor_directory (directory, G_FILE_MONITOR_NONE, NULL, &monitoring_error);
+ if (monitoring_error != NULL)
+ {
+ g_warning ("GoaKerberosIdentityManager: Could not monitor credentials for %s (type %s),
reverting to "
+ "polling: %s",
+ cache_path,
+ cache_type,
+ monitoring_error->message);
+
+ can_monitor = FALSE;
+ g_error_free (monitoring_error);
+ }
+
g_object_unref (directory);
+ }
+ if (monitor != NULL)
+ {
+ g_signal_connect (G_OBJECT (monitor), "changed", G_CALLBACK
(credentials_cache_file_monitor_changed), self);
+ self->credentials_cache_file_monitor = monitor;
}
+
g_object_unref (file);
}
-
- if (monitor == NULL)
+ else if (strcmp (cache_type, "KEYRING") == 0)
{
+ GSource *keyring_source = NULL;
+
+ monitoring_error = NULL;
+ keyring_source = goa_kerberos_identity_manager_keyring_source_new (&monitoring_error);
if (monitoring_error != NULL)
{
- g_warning ("GoaKerberosIdentityManager: Could not monitor credentials for %s (type %s), reverting
to "
- "polling: %s",
+ g_warning ("GoaKerberosIdentityManager: Could not monitor credentials for %s (type %s), reverting
to polling: %s",
cache_path,
cache_type,
- monitoring_error != NULL? monitoring_error->message : "");
- g_clear_error (&monitoring_error);
+ monitoring_error->message);
+
+ can_monitor = FALSE;
+ g_error_free (monitoring_error);
}
- can_monitor = FALSE;
+
+ g_source_set_callback (source, (GSourceFunc) credentials_cache_keyring_notification, self, NULL);
+ g_source_attach (source, NULL);
+
+ g_clear_pointer (&source, g_source_unref);
}
else
{
- g_signal_connect (G_OBJECT (monitor), "changed", G_CALLBACK (credentials_cache_file_monitor_changed),
self);
- self->credentials_cache_file_monitor = monitor;
+ can_monitor = FALSE;
}
if (!can_monitor)
{
+ g_warning ("GoaKerberosIdentityManager: Using polling for change notification for credential cache
type '%s'",
+ cache_type);
+
self->credentials_cache_polling_timeout_id = g_timeout_add_seconds (FALLBACK_POLLING_INTERVAL,
(GSourceFunc)
credentials_cache_polling_timeout,
self);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]