gdm/gdm-multistack.patch
Ray Strode 4e70be422a Update to 2.31.90
This update means we get to drop the accounts service patch, which
has been upstreamed now.

It also means the multi-stack patch has been substantially rebased.
This could incur certain unknown regressions.
2010-08-17 17:53:41 -04:00

18672 lines
734 KiB
Diff

From bfe236555216f30e82c562ad0393a1762afdfab2 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 22 Jul 2010 13:38:09 -0400
Subject: [PATCH 01/35] Revert "Don't wait a mandatory 2 seconds when resetting greeter"
This reverts commit 83552f19154bf5689b395a76c1a9931b2558f41b.
This is a temporary fix so that error messages are displayed for
long enough. A better fix would belong in the greeter.
---
daemon/gdm-simple-slave.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c
index 2994014..6b9159a 100644
--- a/daemon/gdm-simple-slave.c
+++ b/daemon/gdm-simple-slave.c
@@ -227,7 +227,7 @@ queue_greeter_reset (GdmSimpleSlave *slave)
return;
}
- slave->priv->greeter_reset_id = g_idle_add ((GSourceFunc)greeter_reset_timeout, slave);
+ slave->priv->greeter_reset_id = g_timeout_add_seconds (2, (GSourceFunc)greeter_reset_timeout, slave);
}
static void
--
1.7.2.1
From 7ced60d18d4aed59060e260550bf7e1837018c93 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 7 Jul 2010 17:16:38 -0400
Subject: [PATCH 02/35] Don't set list-visible unless the widget is visible
list-visible is a special property that means the
list part of the chooser widget is visible. We need
to make sure we only report it visible when the
chooser itself is visible otherwise the property is
a lie.
This fixes focus handling when the conversation list
isn't visible to begin with.
---
gui/simple-greeter/gdm-chooser-widget.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/gui/simple-greeter/gdm-chooser-widget.c b/gui/simple-greeter/gdm-chooser-widget.c
index 9e3ae73..28c8404 100644
--- a/gui/simple-greeter/gdm-chooser-widget.c
+++ b/gui/simple-greeter/gdm-chooser-widget.c
@@ -698,7 +698,7 @@ update_chooser_visibility (GdmChooserWidget *widget)
if (gdm_chooser_widget_get_number_of_items (widget) > 0) {
gtk_widget_show (widget->priv->frame);
- set_chooser_list_visible (widget, TRUE);
+ set_chooser_list_visible (widget, GTK_WIDGET_VISIBLE (widget));
} else {
gtk_widget_hide (widget->priv->frame);
set_chooser_list_visible (widget, FALSE);
--
1.7.2.1
From 686cfe7fc5d691f31323751b57aa24f3034231aa Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Mon, 28 Jun 2010 14:35:35 -0400
Subject: [PATCH 03/35] Add user chooser to ui file
Before it was getting added manually from the source code.
This way is a lot cleaner.
---
gui/simple-greeter/gdm-greeter-login-window.c | 20 ++++++++++++++------
gui/simple-greeter/gdm-greeter-login-window.ui | 9 ++++++++-
2 files changed, 22 insertions(+), 7 deletions(-)
diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
index 96e6fce..95371b8 100644
--- a/gui/simple-greeter/gdm-greeter-login-window.c
+++ b/gui/simple-greeter/gdm-greeter-login-window.c
@@ -1208,6 +1208,17 @@ create_computer_info (GdmGreeterLoginWindow *login_window)
static void
+register_custom_types (GdmGreeterLoginWindow *login_window)
+{
+ GType types[] = { GDM_TYPE_USER_CHOOSER_WIDGET };
+ int i;
+
+ for (i = 0; i < G_N_ELEMENTS (types); i++) {
+ g_debug ("Registering type '%s'", g_type_name (types[i]));
+ }
+}
+
+static void
load_theme (GdmGreeterLoginWindow *login_window)
{
GtkWidget *entry;
@@ -1218,6 +1229,8 @@ load_theme (GdmGreeterLoginWindow *login_window)
gdm_profile_start (NULL);
+ register_custom_types (login_window);
+
login_window->priv->builder = gtk_builder_new ();
if (!gtk_builder_add_from_file (login_window->priv->builder, UIDIR "/" UI_XML_FILE, &error)) {
g_warning ("Couldn't load builder file: %s", error->message);
@@ -1251,12 +1264,7 @@ load_theme (GdmGreeterLoginWindow *login_window)
box = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "window-frame"));
gtk_container_add (GTK_CONTAINER (login_window), box);
- /* FIXME: user chooser should implement GtkBuildable and this should get dropped
- */
- login_window->priv->user_chooser = gdm_user_chooser_widget_new ();
- box = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "selection-box"));
- gtk_box_pack_start (GTK_BOX (box), login_window->priv->user_chooser, TRUE, TRUE, 0);
- gtk_box_reorder_child (GTK_BOX (box), login_window->priv->user_chooser, 0);
+ login_window->priv->user_chooser = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "user-chooser"));
gdm_user_chooser_widget_set_show_only_chosen (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser), TRUE);
diff --git a/gui/simple-greeter/gdm-greeter-login-window.ui b/gui/simple-greeter/gdm-greeter-login-window.ui
index d8cf1cc..83375ed 100644
--- a/gui/simple-greeter/gdm-greeter-login-window.ui
+++ b/gui/simple-greeter/gdm-greeter-login-window.ui
@@ -160,7 +160,14 @@
<property name="visible">True</property>
<property name="spacing">10</property>
<child>
- <placeholder/>
+ <object class="GdmUserChooserWidget" id="user-chooser">
+ <property name="visible">False</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
</child>
<child>
<object class="GtkHBox" id="auth-input-box">
--
1.7.2.1
From e2b84e687b0fd3ccd5e53b6dca5c24689c42ffcd Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 20 Feb 2009 14:05:20 -0500
Subject: [PATCH 04/35] Add new api to ask when chooser widget is done loading items
---
gui/simple-greeter/gdm-chooser-widget.c | 8 ++++++++
gui/simple-greeter/gdm-chooser-widget.h | 2 ++
2 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/gui/simple-greeter/gdm-chooser-widget.c b/gui/simple-greeter/gdm-chooser-widget.c
index 28c8404..4fa7175 100644
--- a/gui/simple-greeter/gdm-chooser-widget.c
+++ b/gui/simple-greeter/gdm-chooser-widget.c
@@ -98,6 +98,7 @@ struct GdmChooserWidgetPrivate
guint32 should_hide_inactive_items : 1;
guint32 emit_activated_after_resize_animation : 1;
+ guint32 is_loaded : 1;
GdmChooserWidgetPosition separator_position;
GdmChooserWidgetState state;
@@ -2741,9 +2742,16 @@ gdm_chooser_widget_propagate_pending_key_events (GdmChooserWidget *widget)
gdm_scrollable_widget_replay_queued_key_events (GDM_SCROLLABLE_WIDGET (widget->priv->scrollable_widget));
}
+gboolean
+gdm_chooser_widget_is_loaded (GdmChooserWidget *widget)
+{
+ return widget->priv->is_loaded;
+}
+
void
gdm_chooser_widget_loaded (GdmChooserWidget *widget)
{
+ widget->priv->is_loaded = TRUE;
g_signal_emit (widget, signals[LOADED], 0);
update_chooser_visibility (widget);
queue_move_cursor_to_top (widget);
diff --git a/gui/simple-greeter/gdm-chooser-widget.h b/gui/simple-greeter/gdm-chooser-widget.h
index 11a6456..3f6fea3 100644
--- a/gui/simple-greeter/gdm-chooser-widget.h
+++ b/gui/simple-greeter/gdm-chooser-widget.h
@@ -142,6 +142,8 @@ int gdm_chooser_widget_get_number_of_items (GdmChooserWidget
void gdm_chooser_widget_activate_if_one_item (GdmChooserWidget *widget);
void gdm_chooser_widget_propagate_pending_key_events (GdmChooserWidget *widget);
+gboolean gdm_chooser_widget_is_loaded (GdmChooserWidget *widget);
+
/* Protected
*/
void gdm_chooser_widget_loaded (GdmChooserWidget *widget);
--
1.7.2.1
From 19f14037c4e503c21d205e45cc3a3b3354a7c198 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 6 Mar 2009 11:19:40 -0500
Subject: [PATCH 05/35] Create session settings object up front
This allows us to set language, session, etc,
before the PAM conversation is started.
---
daemon/gdm-session-worker.c | 3 +--
1 files changed, 1 insertions(+), 2 deletions(-)
diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
index 3715396..775f99b 100644
--- a/daemon/gdm-session-worker.c
+++ b/daemon/gdm-session-worker.c
@@ -2334,8 +2334,6 @@ do_setup (GdmSessionWorker *worker)
GError *error;
gboolean res;
- worker->priv->user_settings = gdm_session_settings_new ();
-
g_signal_connect_swapped (worker->priv->user_settings,
"notify::language-name",
G_CALLBACK (on_saved_language_name_read),
@@ -2961,6 +2959,7 @@ gdm_session_worker_init (GdmSessionWorker *worker)
g_str_equal,
(GDestroyNotify) g_free,
(GDestroyNotify) g_free);
+ worker->priv->user_settings = gdm_session_settings_new ();
}
static void
--
1.7.2.1
From f03a89dc0782aff6173b95ebc8e0ded678bcbb00 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 13 Jul 2010 22:42:43 -0400
Subject: [PATCH 06/35] disconnect signal handlers in destroy session
We don't want them firing as part of object destruction
---
daemon/gdm-simple-slave.c | 102 ++++++++++++++++++++++++++++++++++++++++----
1 files changed, 92 insertions(+), 10 deletions(-)
diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c
index 6b9159a..7187ea1 100644
--- a/daemon/gdm-simple-slave.c
+++ b/daemon/gdm-simple-slave.c
@@ -97,6 +97,7 @@ static void gdm_simple_slave_finalize (GObject *object);
G_DEFINE_TYPE (GdmSimpleSlave, gdm_simple_slave, GDM_TYPE_SLAVE)
static void create_new_session (GdmSimpleSlave *slave);
+static void destroy_session (GdmSimpleSlave *slave);
static void start_greeter (GdmSimpleSlave *slave);
static void
@@ -171,16 +172,6 @@ add_user_authorization (GdmSimpleSlave *slave,
}
static void
-destroy_session (GdmSimpleSlave *slave)
-{
- if (slave->priv->session != NULL) {
- gdm_session_close (GDM_SESSION (slave->priv->session));
- g_object_unref (slave->priv->session);
- slave->priv->session = NULL;
- }
-}
-
-static void
reset_session (GdmSimpleSlave *slave)
{
destroy_session (slave);
@@ -780,6 +771,97 @@ create_new_session (GdmSimpleSlave *slave)
}
static void
+destroy_session (GdmSimpleSlave *slave)
+{
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_session_conversation_started),
+ slave);
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_session_setup_complete),
+ slave);
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_session_setup_failed),
+ slave);
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_session_reset_complete),
+ slave);
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_session_reset_failed),
+ slave);
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_session_authenticated),
+ slave);
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_session_authentication_failed),
+ slave);
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_session_authorized),
+ slave);
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_session_authorization_failed),
+ slave);
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_session_accredited),
+ slave);
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_session_accreditation_failed),
+ slave);
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_session_opened),
+ slave);
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_session_open_failed),
+ slave);
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_session_info),
+ slave);
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_session_problem),
+ slave);
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_session_info_query),
+ slave);
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_session_secret_info_query),
+ slave);
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_session_started),
+ slave);
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_session_exited),
+ slave);
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_session_died),
+ slave);
+#if 0
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_session_closed),
+ slave);
+#endif
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_session_selected_user_changed),
+ slave);
+
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_default_language_name_changed),
+ slave);
+
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_default_layout_name_changed),
+ slave);
+
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_default_session_name_changed),
+ slave);
+
+ if (slave->priv->session != NULL) {
+ gdm_session_close (GDM_SESSION (slave->priv->session));
+ g_object_unref (slave->priv->session);
+ slave->priv->session = NULL;
+ }
+}
+
+static void
on_greeter_session_start (GdmGreeterSession *greeter,
GdmSimpleSlave *slave)
{
--
1.7.2.1
From 211c78dbb4e45660da5e44c1c030661423d261ba Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 16 Jan 2009 11:00:08 -0500
Subject: [PATCH 07/35] Introduce new Conversation object
We want to eventually support having multiple
simultaneous PAM conversations in one login
screen (so, e.g., username/password, smart card, and
fingerprint all work at the same time).
This commit refactors the session code to be in terms
of a conversation object. With this change, it should
be easier later to have multiple conversation objects.
The conversation is named by the pam service the login
screen is talking to.
---
daemon/gdm-factory-slave.c | 5 +-
daemon/gdm-product-slave.c | 29 +++-
daemon/gdm-session-direct.c | 318 ++++++++++++++++++++++++---------------
daemon/gdm-session-private.h | 3 +-
daemon/gdm-session-relay.c | 15 ++-
daemon/gdm-session-worker-job.c | 7 +
daemon/gdm-session-worker-job.h | 2 +
daemon/gdm-session.c | 12 +-
daemon/gdm-session.h | 9 +-
daemon/gdm-simple-slave.c | 3 -
daemon/test-session.c | 5 +-
11 files changed, 263 insertions(+), 145 deletions(-)
diff --git a/daemon/gdm-factory-slave.c b/daemon/gdm-factory-slave.c
index b413497..0151ab2 100644
--- a/daemon/gdm-factory-slave.c
+++ b/daemon/gdm-factory-slave.c
@@ -181,7 +181,8 @@ on_session_secret_info_query (GdmSession *session,
static void
on_session_conversation_started (GdmSession *session,
- GdmFactorySlave *slave)
+ GdmFactorySlave *slave,
+ const char *service_name)
{
g_debug ("GdmFactorySlave: session conversation started");
@@ -389,7 +390,7 @@ on_session_relay_connected (GdmSessionRelay *session,
{
g_debug ("GdmFactorySlave: Relay Connected");
- gdm_session_start_conversation (GDM_SESSION (slave->priv->session));
+ gdm_session_start_conversation (GDM_SESSION (slave->priv->session), "gdm");
}
static void
diff --git a/daemon/gdm-product-slave.c b/daemon/gdm-product-slave.c
index a423965..9be89b4 100644
--- a/daemon/gdm-product-slave.c
+++ b/daemon/gdm-product-slave.c
@@ -246,19 +246,21 @@ relay_session_started (GdmProductSlave *slave,
}
static void
-relay_session_conversation_started (GdmProductSlave *slave)
+relay_session_conversation_started (GdmProductSlave *slave,
+ const char *service_name)
{
- send_dbus_void_method (slave->priv->session_relay_connection,
- "ConversationStarted");
+ send_dbus_string_method (slave->priv->session_relay_connection,
+ "ConversationStarted", service_name);
}
static void
on_session_conversation_started (GdmSession *session,
+ const char *service_name,
GdmProductSlave *slave)
{
g_debug ("GdmProductSlave: session conversation started");
- relay_session_conversation_started (slave);
+ relay_session_conversation_started (slave, service_name);
}
static void
@@ -805,7 +807,24 @@ static void
on_relay_start_conversation (GdmProductSlave *slave,
DBusMessage *message)
{
- gdm_session_start_conversation (GDM_SESSION (slave->priv->session));
+ DBusError error;
+ char *service_name;
+ dbus_bool_t res;
+
+ dbus_error_init (&error);
+ res = dbus_message_get_args (message,
+ &error,
+ DBUS_TYPE_STRING, &service_name,
+ DBUS_TYPE_INVALID);
+ if (res) {
+ g_debug ("GdmProductSlave: Started conversation with %s service", service_name);
+ gdm_session_start_conversation (GDM_SESSION (slave->priv->session),
+ service_name);
+ } else {
+ g_warning ("Unable to get arguments: %s", error.message);
+ }
+
+ dbus_error_free (&error);
}
static void
diff --git a/daemon/gdm-session-direct.c b/daemon/gdm-session-direct.c
index 0282ab7..f9621a2 100644
--- a/daemon/gdm-session-direct.c
+++ b/daemon/gdm-session-direct.c
@@ -67,6 +67,16 @@
#define GDM_SESSION_DEFAULT_PATH "/usr/local/bin:/usr/bin:/bin"
#endif
+typedef struct
+{
+ GdmSessionDirect *session;
+ GdmSessionWorkerJob *job;
+ GPid worker_pid;
+ char *service_name;
+ DBusConnection *worker_connection;
+ DBusMessage *message_pending_reply;
+} GdmSessionConversation;
+
struct _GdmSessionDirectPrivate
{
/* per open scope */
@@ -79,8 +89,7 @@ struct _GdmSessionDirectPrivate
char *selected_user;
char *user_x11_authority_file;
- DBusMessage *message_pending_reply;
- DBusConnection *worker_connection;
+ GdmSessionConversation *conversation;
GdmSessionWorkerJob *job;
GPid session_pid;
@@ -123,39 +132,39 @@ G_DEFINE_TYPE_WITH_CODE (GdmSessionDirect,
gdm_session_iface_init))
static gboolean
-send_dbus_message (DBusConnection *connection,
- DBusMessage *message)
+send_dbus_message (GdmSessionConversation *conversation,
+ DBusMessage *message)
{
gboolean is_connected;
gboolean sent;
g_return_val_if_fail (message != NULL, FALSE);
- if (connection == NULL) {
+ if (conversation->worker_connection == NULL) {
g_warning ("There is no valid connection");
return FALSE;
}
- is_connected = dbus_connection_get_is_connected (connection);
+ is_connected = dbus_connection_get_is_connected (conversation->worker_connection);
if (! is_connected) {
g_warning ("Not connected!");
return FALSE;
}
- sent = dbus_connection_send (connection, message, NULL);
+ sent = dbus_connection_send (conversation->worker_connection, message, NULL);
return sent;
}
static void
-send_dbus_string_signal (GdmSessionDirect *session,
+send_dbus_string_signal (GdmSessionConversation *conversation,
const char *name,
const char *text)
{
DBusMessage *message;
DBusMessageIter iter;
- g_return_if_fail (session != NULL);
+ g_return_if_fail (conversation != NULL);
message = dbus_message_new_signal (GDM_SESSION_DBUS_PATH,
GDM_SESSION_DBUS_INTERFACE,
@@ -164,7 +173,7 @@ send_dbus_string_signal (GdmSessionDirect *session,
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &text);
- if (! send_dbus_message (session->priv->worker_connection, message)) {
+ if (! send_dbus_message (conversation, message)) {
g_debug ("GdmSessionDirect: Could not send %s signal",
name ? name : "(null)");
}
@@ -173,18 +182,18 @@ send_dbus_string_signal (GdmSessionDirect *session,
}
static void
-send_dbus_void_signal (GdmSessionDirect *session,
- const char *name)
+send_dbus_void_signal (GdmSessionConversation *conversation,
+ const char *name)
{
DBusMessage *message;
- g_return_if_fail (session != NULL);
+ g_return_if_fail (conversation != NULL);
message = dbus_message_new_signal (GDM_SESSION_DBUS_PATH,
GDM_SESSION_DBUS_INTERFACE,
name);
- if (! send_dbus_message (session->priv->worker_connection, message)) {
+ if (! send_dbus_message (conversation, message)) {
g_debug ("GdmSessionDirect: Could not send %s signal", name);
}
@@ -196,22 +205,32 @@ on_authentication_failed (GdmSession *session,
const char *message)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
- gdm_session_record_failed (impl->priv->session_pid,
- impl->priv->selected_user,
- impl->priv->display_hostname,
- impl->priv->display_name,
- impl->priv->display_device);
+ GdmSessionConversation *conversation;
+
+ conversation = impl->priv->conversation;
+ if (conversation != NULL) {
+ gdm_session_record_failed (conversation->worker_pid,
+ impl->priv->selected_user,
+ impl->priv->display_hostname,
+ impl->priv->display_name,
+ impl->priv->display_device);
+ }
}
static void
on_session_started (GdmSession *session)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
- gdm_session_record_login (impl->priv->session_pid,
- impl->priv->selected_user,
- impl->priv->display_hostname,
- impl->priv->display_name,
- impl->priv->display_device);
+ GdmSessionConversation *conversation;
+
+ conversation = impl->priv->conversation;
+ if (conversation != NULL) {
+ gdm_session_record_login (conversation->worker_pid,
+ impl->priv->selected_user,
+ impl->priv->display_hostname,
+ impl->priv->display_name,
+ impl->priv->display_device);
+ }
}
static void
@@ -219,11 +238,16 @@ on_session_start_failed (GdmSession *session,
const char *message)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
- gdm_session_record_login (impl->priv->session_pid,
- impl->priv->selected_user,
- impl->priv->display_hostname,
- impl->priv->display_name,
- impl->priv->display_device);
+ GdmSessionConversation *conversation;
+
+ conversation = impl->priv->conversation;
+ if (conversation != NULL) {
+ gdm_session_record_login (conversation->worker_pid,
+ impl->priv->selected_user,
+ impl->priv->display_hostname,
+ impl->priv->display_name,
+ impl->priv->display_device);
+ }
}
static void
@@ -231,6 +255,7 @@ on_session_exited (GdmSession *session,
int exit_code)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
+
gdm_session_record_logout (impl->priv->session_pid,
impl->priv->selected_user,
impl->priv->display_hostname,
@@ -815,54 +840,52 @@ gdm_session_direct_handle_username_changed (GdmSessionDirect *session,
}
static void
-cancel_pending_query (GdmSessionDirect *session)
+cancel_pending_query (GdmSessionConversation *conversation)
{
DBusMessage *reply;
- if (session->priv->message_pending_reply == NULL) {
+ if (conversation->message_pending_reply == NULL) {
return;
}
g_debug ("GdmSessionDirect: Cancelling pending query");
- reply = dbus_message_new_error (session->priv->message_pending_reply,
+ reply = dbus_message_new_error (conversation->message_pending_reply,
GDM_SESSION_DBUS_ERROR_CANCEL,
"Operation cancelled");
- dbus_connection_send (session->priv->worker_connection, reply, NULL);
- dbus_connection_flush (session->priv->worker_connection);
+ dbus_connection_send (conversation->worker_connection, reply, NULL);
+ dbus_connection_flush (conversation->worker_connection);
dbus_message_unref (reply);
- dbus_message_unref (session->priv->message_pending_reply);
- session->priv->message_pending_reply = NULL;
+ dbus_message_unref (conversation->message_pending_reply);
+ conversation->message_pending_reply = NULL;
}
static void
-answer_pending_query (GdmSessionDirect *session,
- const char *answer)
+answer_pending_query (GdmSessionConversation *conversation,
+ const char *answer)
{
DBusMessage *reply;
DBusMessageIter iter;
- g_assert (session->priv->message_pending_reply != NULL);
-
- reply = dbus_message_new_method_return (session->priv->message_pending_reply);
+ reply = dbus_message_new_method_return (conversation->message_pending_reply);
dbus_message_iter_init_append (reply, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &answer);
- dbus_connection_send (session->priv->worker_connection, reply, NULL);
+ dbus_connection_send (conversation->worker_connection, reply, NULL);
dbus_message_unref (reply);
- dbus_message_unref (session->priv->message_pending_reply);
- session->priv->message_pending_reply = NULL;
+ dbus_message_unref (conversation->message_pending_reply);
+ conversation->message_pending_reply = NULL;
}
static void
-set_pending_query (GdmSessionDirect *session,
- DBusMessage *message)
+set_pending_query (GdmSessionConversation *conversation,
+ DBusMessage *message)
{
- g_assert (session->priv->message_pending_reply == NULL);
+ g_assert (conversation->message_pending_reply == NULL);
- session->priv->message_pending_reply = dbus_message_ref (message);
+ conversation->message_pending_reply = dbus_message_ref (message);
}
static DBusHandlerResult
@@ -872,6 +895,9 @@ gdm_session_direct_handle_info_query (GdmSessionDirect *session,
{
DBusError error;
const char *text;
+ GdmSessionConversation *conversation;
+
+ conversation = session->priv->conversation;
dbus_error_init (&error);
if (! dbus_message_get_args (message, &error,
@@ -880,7 +906,7 @@ gdm_session_direct_handle_info_query (GdmSessionDirect *session,
g_warning ("ERROR: %s", error.message);
}
- set_pending_query (session, message);
+ set_pending_query (conversation, message);
g_debug ("GdmSessionDirect: Emitting 'info-query' signal");
_gdm_session_info_query (GDM_SESSION (session), text);
@@ -895,6 +921,9 @@ gdm_session_direct_handle_secret_info_query (GdmSessionDirect *session,
{
DBusError error;
const char *text;
+ GdmSessionConversation *conversation;
+
+ conversation = session->priv->conversation;
dbus_error_init (&error);
if (! dbus_message_get_args (message, &error,
@@ -903,7 +932,7 @@ gdm_session_direct_handle_secret_info_query (GdmSessionDirect *session,
g_warning ("ERROR: %s", error.message);
}
- set_pending_query (session, message);
+ set_pending_query (conversation, message);
g_debug ("GdmSessionDirect: Emitting 'secret-info-query' signal");
_gdm_session_secret_info_query (GDM_SESSION (session), text);
@@ -943,9 +972,13 @@ gdm_session_direct_handle_cancel_pending_query (GdmSessionDirect *session,
DBusMessage *message)
{
DBusMessage *reply;
+ GdmSessionConversation *conversation;
g_debug ("GdmSessionDirect: worker cancelling pending query");
- cancel_pending_query (session);
+
+ conversation = session->priv->conversation;
+
+ cancel_pending_query (conversation);
reply = dbus_message_new_method_return (message);
dbus_connection_send (connection, reply, NULL);
@@ -1567,16 +1600,18 @@ handle_connection (DBusServer *server,
void *user_data)
{
GdmSessionDirect *session = GDM_SESSION_DIRECT (user_data);
+ GdmSessionConversation *conversation;
g_debug ("GdmSessionDirect: Handing new connection");
- if (session->priv->worker_connection == NULL) {
+ conversation = session->priv->conversation;
+ if (conversation->worker_connection == NULL) {
DBusObjectPathVTable vtable = { &session_unregister_handler,
&session_message_handler,
NULL, NULL, NULL, NULL
};
- session->priv->worker_connection = new_connection;
+ conversation->worker_connection = new_connection;
dbus_connection_ref (new_connection);
dbus_connection_setup_with_g_main (new_connection, NULL);
@@ -1594,7 +1629,8 @@ handle_connection (DBusServer *server,
session);
g_debug ("GdmSessionDirect: Emitting conversation-started signal");
- _gdm_session_conversation_started (GDM_SESSION (session));
+ _gdm_session_conversation_started (GDM_SESSION (session),
+ conversation->service_name);
}
}
@@ -1664,8 +1700,6 @@ gdm_session_direct_init (GdmSessionDirect *session)
G_CALLBACK (on_session_exited),
NULL);
- session->priv->session_pid = -1;
-
session->priv->environment = g_hash_table_new_full (g_str_hash,
g_str_equal,
(GDestroyNotify) g_free,
@@ -1677,7 +1711,7 @@ gdm_session_direct_init (GdmSessionDirect *session)
static void
worker_started (GdmSessionWorkerJob *job,
- GdmSessionDirect *session)
+ GdmSessionConversation *conversation)
{
g_debug ("GdmSessionDirect: Worker job started");
}
@@ -1685,87 +1719,105 @@ worker_started (GdmSessionWorkerJob *job,
static void
worker_exited (GdmSessionWorkerJob *job,
int code,
- GdmSessionDirect *session)
+ GdmSessionConversation *conversation)
{
g_debug ("GdmSessionDirect: Worker job exited: %d", code);
- if (session->priv->is_running) {
- _gdm_session_session_exited (GDM_SESSION (session), code);
+ if (conversation->session->priv->is_running) {
+ _gdm_session_session_exited (GDM_SESSION (conversation->session), code);
}
}
static void
worker_died (GdmSessionWorkerJob *job,
int signum,
- GdmSessionDirect *session)
+ GdmSessionConversation *conversation)
{
g_debug ("GdmSessionDirect: Worker job died: %d", signum);
- if (session->priv->is_running) {
- _gdm_session_session_died (GDM_SESSION (session), signum);
+ if (conversation->session->priv->is_running) {
+ _gdm_session_session_died (GDM_SESSION (conversation->session), signum);
}
}
-static gboolean
-start_worker (GdmSessionDirect *session)
+static GdmSessionConversation *
+start_conversation (GdmSessionDirect *session,
+ const char *service_name)
{
- gboolean res;
+ GdmSessionConversation *conversation;
- session->priv->job = gdm_session_worker_job_new ();
- gdm_session_worker_job_set_server_address (session->priv->job, session->priv->server_address);
- g_signal_connect (session->priv->job,
+ conversation = g_new0 (GdmSessionConversation, 1);
+ conversation->session = session;
+ conversation->service_name = g_strdup (service_name);
+ conversation->worker_pid = -1;
+ conversation->job = gdm_session_worker_job_new ();
+ gdm_session_worker_job_set_server_address (conversation->job, session->priv->server_address);
+ g_signal_connect (conversation->job,
"started",
G_CALLBACK (worker_started),
- session);
- g_signal_connect (session->priv->job,
+ conversation);
+ g_signal_connect (conversation->job,
"exited",
G_CALLBACK (worker_exited),
- session);
- g_signal_connect (session->priv->job,
+ conversation);
+ g_signal_connect (conversation->job,
"died",
G_CALLBACK (worker_died),
- session);
+ conversation);
- res = gdm_session_worker_job_start (session->priv->job);
+ if (!gdm_session_worker_job_start (conversation->job)) {
+ g_object_unref (conversation->job);
+ g_free (conversation->service_name);
+ g_free (conversation);
+ return NULL;
+ }
- return res;
+ conversation->worker_pid = gdm_session_worker_job_get_pid (conversation->job);
+
+ return conversation;
}
static void
-stop_worker (GdmSessionDirect *session)
+stop_conversation (GdmSessionConversation *conversation)
{
- g_signal_handlers_disconnect_by_func (session->priv->job,
+ GdmSessionDirect *session;
+
+ session = conversation->session;
+
+ g_signal_handlers_disconnect_by_func (conversation->job,
G_CALLBACK (worker_started),
- session);
- g_signal_handlers_disconnect_by_func (session->priv->job,
+ conversation);
+ g_signal_handlers_disconnect_by_func (conversation->job,
G_CALLBACK (worker_exited),
- session);
- g_signal_handlers_disconnect_by_func (session->priv->job,
+ conversation);
+ g_signal_handlers_disconnect_by_func (conversation->job,
G_CALLBACK (worker_died),
- session);
+ conversation);
- cancel_pending_query (session);
+ cancel_pending_query (conversation);
- if (session->priv->worker_connection != NULL) {
- dbus_connection_close (session->priv->worker_connection);
- session->priv->worker_connection = NULL;
+ if (conversation->worker_connection != NULL) {
+ dbus_connection_close (conversation->worker_connection);
+ conversation->worker_connection = NULL;
}
- gdm_session_worker_job_stop (session->priv->job);
- g_object_unref (session->priv->job);
- session->priv->job = NULL;
+ gdm_session_worker_job_stop (conversation->job);
+ g_object_unref (conversation->job);
+ g_free (conversation->service_name);
+ g_free (conversation);
}
static void
-gdm_session_direct_start_conversation (GdmSession *session)
+gdm_session_direct_start_conversation (GdmSession *session,
+ const char *service_name)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
g_return_if_fail (session != NULL);
- g_debug ("GdmSessionDirect: Starting conversation");
+ g_debug ("GdmSessionDirect: starting conversation");
- start_worker (impl);
+ impl->priv->conversation = start_conversation (impl, service_name);
}
static void
@@ -1778,6 +1830,7 @@ send_setup (GdmSessionDirect *session,
const char *display_device;
const char *display_hostname;
const char *display_x11_authority_file;
+ GdmSessionConversation *conversation;
g_assert (service_name != NULL);
@@ -1815,7 +1868,8 @@ send_setup (GdmSessionDirect *session,
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_hostname);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_x11_authority_file);
- if (! send_dbus_message (session->priv->worker_connection, message)) {
+ conversation = session->priv->conversation;
+ if (! send_dbus_message (conversation, message)) {
g_debug ("GdmSessionDirect: Could not send %s signal", "Setup");
}
@@ -1833,6 +1887,7 @@ send_setup_for_user (GdmSessionDirect *session,
const char *display_hostname;
const char *display_x11_authority_file;
const char *selected_user;
+ GdmSessionConversation *conversation;
g_assert (service_name != NULL);
@@ -1876,7 +1931,8 @@ send_setup_for_user (GdmSessionDirect *session,
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_x11_authority_file);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &selected_user);
- if (! send_dbus_message (session->priv->worker_connection, message)) {
+ conversation = session->priv->conversation;
+ if (! send_dbus_message (conversation, message)) {
g_debug ("GdmSessionDirect: Could not send %s signal", "SetupForUser");
}
@@ -1890,7 +1946,8 @@ gdm_session_direct_setup (GdmSession *session,
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
g_return_if_fail (session != NULL);
- g_return_if_fail (dbus_connection_get_is_connected (impl->priv->worker_connection));
+ g_return_if_fail (impl->priv->conversation != NULL);
+ g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection));
send_setup (impl, service_name);
gdm_session_direct_defaults_changed (impl);
@@ -1904,7 +1961,8 @@ gdm_session_direct_setup_for_user (GdmSession *session,
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
g_return_if_fail (session != NULL);
- g_return_if_fail (dbus_connection_get_is_connected (impl->priv->worker_connection));
+ g_return_if_fail (impl->priv->conversation != NULL);
+ g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection));
g_return_if_fail (username != NULL);
gdm_session_direct_select_user (session, username);
@@ -1917,22 +1975,28 @@ static void
gdm_session_direct_authenticate (GdmSession *session)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
+ GdmSessionConversation *conversation;
g_return_if_fail (session != NULL);
- g_return_if_fail (dbus_connection_get_is_connected (impl->priv->worker_connection));
+ g_return_if_fail (impl->priv->conversation != NULL);
+ g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection));
- send_dbus_void_signal (impl, "Authenticate");
+ conversation = impl->priv->conversation;
+ send_dbus_void_signal (conversation, "Authenticate");
}
static void
gdm_session_direct_authorize (GdmSession *session)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
+ GdmSessionConversation *conversation;
g_return_if_fail (session != NULL);
- g_return_if_fail (dbus_connection_get_is_connected (impl->priv->worker_connection));
+ g_return_if_fail (impl->priv->conversation != NULL);
+ g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection));
- send_dbus_void_signal (impl, "Authorize");
+ conversation = impl->priv->conversation;
+ send_dbus_void_signal (conversation, "Authorize");
}
static void
@@ -1940,16 +2004,19 @@ gdm_session_direct_accredit (GdmSession *session,
int cred_flag)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
+ GdmSessionConversation *conversation;
g_return_if_fail (session != NULL);
- g_return_if_fail (dbus_connection_get_is_connected (impl->priv->worker_connection));
+ g_return_if_fail (impl->priv->conversation != NULL);
+ g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection));
+ conversation = impl->priv->conversation;
switch (cred_flag) {
case GDM_SESSION_CRED_ESTABLISH:
- send_dbus_void_signal (impl, "EstablishCredentials");
+ send_dbus_void_signal (conversation, "EstablishCredentials");
break;
case GDM_SESSION_CRED_REFRESH:
- send_dbus_void_signal (impl, "RefreshCredentials");
+ send_dbus_void_signal (conversation, "RefreshCredentials");
break;
default:
g_assert_not_reached ();
@@ -1963,6 +2030,7 @@ send_environment_variable (const char *key,
{
DBusMessage *message;
DBusMessageIter iter;
+ GdmSessionConversation *conversation;
message = dbus_message_new_signal (GDM_SESSION_DBUS_PATH,
GDM_SESSION_DBUS_INTERFACE,
@@ -1972,7 +2040,8 @@ send_environment_variable (const char *key,
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &value);
- if (! send_dbus_message (session->priv->worker_connection, message)) {
+ conversation = session->priv->conversation;
+ if (! send_dbus_message (conversation, message)) {
g_debug ("GdmSessionDirect: Could not send %s signal", "SetEnvironmentVariable");
}
@@ -2120,6 +2189,7 @@ static void
gdm_session_direct_start_session (GdmSession *session)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
+ GdmSessionConversation *conversation;
char *command;
char *program;
@@ -2139,7 +2209,8 @@ gdm_session_direct_start_session (GdmSession *session)
setup_session_environment (impl);
send_environment (impl);
- send_dbus_string_signal (impl, "StartProgram", program);
+ conversation = impl->priv->conversation;
+ send_dbus_string_signal (conversation, "StartProgram", program);
g_free (program);
}
@@ -2152,16 +2223,12 @@ gdm_session_direct_close (GdmSession *session)
g_debug ("GdmSessionDirect: Closing session");
- if (impl->priv->job != NULL) {
- if (impl->priv->is_running) {
- gdm_session_record_logout (impl->priv->session_pid,
- impl->priv->selected_user,
- impl->priv->display_hostname,
- impl->priv->display_name,
- impl->priv->display_device);
- }
-
- stop_worker (impl);
+ if (impl->priv->is_running) {
+ gdm_session_record_logout (impl->priv->session_pid,
+ impl->priv->selected_user,
+ impl->priv->display_hostname,
+ impl->priv->display_name,
+ impl->priv->display_device);
}
g_free (impl->priv->selected_user);
@@ -2199,10 +2266,13 @@ gdm_session_direct_answer_query (GdmSession *session,
const char *text)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
+ GdmSessionConversation *conversation;
g_return_if_fail (session != NULL);
- answer_pending_query (impl, text);
+ conversation = impl->priv->conversation;
+
+ answer_pending_query (conversation, text);
}
static void
@@ -2212,7 +2282,7 @@ gdm_session_direct_cancel (GdmSession *session)
g_return_if_fail (session != NULL);
- cancel_pending_query (impl);
+ cancel_pending_query (impl->priv->conversation);
}
char *
@@ -2276,6 +2346,7 @@ gdm_session_direct_select_session (GdmSession *session,
const char *text)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
+ GdmSessionConversation *conversation;
g_free (impl->priv->selected_session);
@@ -2285,7 +2356,8 @@ gdm_session_direct_select_session (GdmSession *session,
impl->priv->selected_session = g_strdup (text);
}
- send_dbus_string_signal (impl, "SetSessionName",
+ conversation = impl->priv->conversation;
+ send_dbus_string_signal (conversation, "SetSessionName",
get_session_name (impl));
}
@@ -2294,6 +2366,7 @@ gdm_session_direct_select_language (GdmSession *session,
const char *text)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
+ GdmSessionConversation *conversation;
g_free (impl->priv->selected_language);
@@ -2303,7 +2376,8 @@ gdm_session_direct_select_language (GdmSession *session,
impl->priv->selected_language = g_strdup (text);
}
- send_dbus_string_signal (impl, "SetLanguageName",
+ conversation = impl->priv->conversation;
+ send_dbus_string_signal (conversation, "SetLanguageName",
get_language_name (impl));
}
@@ -2312,6 +2386,7 @@ gdm_session_direct_select_layout (GdmSession *session,
const char *text)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
+ GdmSessionConversation *conversation;
g_free (impl->priv->selected_layout);
@@ -2321,7 +2396,8 @@ gdm_session_direct_select_layout (GdmSession *session,
impl->priv->selected_layout = g_strdup (text);
}
- send_dbus_string_signal (impl, "SetLayoutName",
+ conversation = impl->priv->conversation;
+ send_dbus_string_signal (conversation, "SetLayoutName",
get_layout_name (impl));
}
diff --git a/daemon/gdm-session-private.h b/daemon/gdm-session-private.h
index 7ccf0d7..74b6069 100644
--- a/daemon/gdm-session-private.h
+++ b/daemon/gdm-session-private.h
@@ -27,7 +27,8 @@
G_BEGIN_DECLS
/* state changes */
-void _gdm_session_conversation_started (GdmSession *session);
+void _gdm_session_conversation_started (GdmSession *session,
+ const char *service_name);
void _gdm_session_setup_complete (GdmSession *session);
void _gdm_session_setup_failed (GdmSession *session,
const char *message);
diff --git a/daemon/gdm-session-relay.c b/daemon/gdm-session-relay.c
index da0ecb3..a0b4cbf 100644
--- a/daemon/gdm-session-relay.c
+++ b/daemon/gdm-session-relay.c
@@ -180,10 +180,11 @@ send_dbus_void_signal (GdmSessionRelay *session_relay,
}
static void
-gdm_session_relay_start_conversation (GdmSession *session)
+gdm_session_relay_start_conversation (GdmSession *session,
+ const char *service_name)
{
GdmSessionRelay *impl = GDM_SESSION_RELAY (session);
- send_dbus_void_signal (impl, "StartConversation");
+ send_dbus_string_signal (impl, "StartConversation", service_name);
}
static void
@@ -728,8 +729,14 @@ handle_conversation_started (GdmSessionRelay *session_relay,
{
DBusMessage *reply;
DBusError error;
+ char *service_name;
dbus_error_init (&error);
+ if (! dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &service_name,
+ DBUS_TYPE_INVALID)) {
+ g_warning ("ERROR: %s", error.message);
+ }
g_debug ("GdmSessionRelay: Conversation Started");
@@ -737,7 +744,7 @@ handle_conversation_started (GdmSessionRelay *session_relay,
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
- _gdm_session_conversation_started (GDM_SESSION (session_relay));
+ _gdm_session_conversation_started (GDM_SESSION (session_relay), service_name);
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -812,6 +819,7 @@ do_introspect (DBusConnection *connection,
xml = g_string_append (xml,
" <interface name=\"org.gnome.DisplayManager.SessionRelay\">\n"
" <method name=\"ConversationStarted\">\n"
+ " <arg name=\"service_name\" direction=\"in\" type=\"s\"/>\n"
" </method>\n"
" <method name=\"SetupComplete\">\n"
" </method>\n"
@@ -873,6 +881,7 @@ do_introspect (DBusConnection *connection,
" </signal>\n"
" <signal name=\"StartConversation\">\n"
+ " <arg name=\"service_name\" type=\"s\"/>\n"
" </signal>\n"
" <signal name=\"Close\">\n"
" </signal>\n"
diff --git a/daemon/gdm-session-worker-job.c b/daemon/gdm-session-worker-job.c
index 50bf4c0..f686002 100644
--- a/daemon/gdm-session-worker-job.c
+++ b/daemon/gdm-session-worker-job.c
@@ -303,6 +303,13 @@ gdm_session_worker_job_stop (GdmSessionWorkerJob *session_worker_job)
return TRUE;
}
+GPid
+gdm_session_worker_job_get_pid (GdmSessionWorkerJob *session_worker_job)
+{
+ g_return_val_if_fail (GDM_IS_SESSION_WORKER_JOB (session_worker_job), 0);
+ return session_worker_job->priv->pid;
+}
+
void
gdm_session_worker_job_set_server_address (GdmSessionWorkerJob *session_worker_job,
const char *address)
diff --git a/daemon/gdm-session-worker-job.h b/daemon/gdm-session-worker-job.h
index 5ad1c92..d24f025 100644
--- a/daemon/gdm-session-worker-job.h
+++ b/daemon/gdm-session-worker-job.h
@@ -60,6 +60,8 @@ void gdm_session_worker_job_set_server_address (GdmSessionWor
gboolean gdm_session_worker_job_start (GdmSessionWorkerJob *session_worker_job);
gboolean gdm_session_worker_job_stop (GdmSessionWorkerJob *session_worker_job);
+GPid gdm_session_worker_job_get_pid (GdmSessionWorkerJob *session_worker_job);
+
G_END_DECLS
#endif /* __GDM_SESSION_WORKER_JOB_H */
diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c
index 1e2af92..1820e29 100644
--- a/daemon/gdm-session.c
+++ b/daemon/gdm-session.c
@@ -80,11 +80,12 @@ gdm_session_get_type (void)
}
void
-gdm_session_start_conversation (GdmSession *session)
+gdm_session_start_conversation (GdmSession *session,
+ const char *service_name)
{
g_return_if_fail (GDM_IS_SESSION (session));
- GDM_SESSION_GET_IFACE (session)->start_conversation (session);
+ GDM_SESSION_GET_IFACE (session)->start_conversation (session, service_name);
}
void
@@ -220,7 +221,7 @@ gdm_session_class_init (gpointer g_iface)
G_STRUCT_OFFSET (GdmSessionIface, conversation_started),
NULL,
NULL,
- g_cclosure_marshal_VOID__VOID,
+ g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE,
0);
signals [SETUP_COMPLETE] =
@@ -654,10 +655,11 @@ _gdm_session_session_died (GdmSession *session,
}
void
-_gdm_session_conversation_started (GdmSession *session)
+_gdm_session_conversation_started (GdmSession *session,
+ const char *service_name)
{
g_return_if_fail (GDM_IS_SESSION (session));
- g_signal_emit (session, signals [CONVERSATION_STARTED], 0);
+ g_signal_emit (session, signals [CONVERSATION_STARTED], 0, service_name);
}
void
diff --git a/daemon/gdm-session.h b/daemon/gdm-session.h
index fb199d3..00c2fa4 100644
--- a/daemon/gdm-session.h
+++ b/daemon/gdm-session.h
@@ -45,7 +45,8 @@ struct _GdmSessionIface
GTypeInterface base_iface;
/* Methods */
- void (* start_conversation) (GdmSession *session);
+ void (* start_conversation) (GdmSession *session,
+ const char *service_name);
void (* setup) (GdmSession *session,
const char *service_name);
void (* setup_for_user) (GdmSession *session,
@@ -107,7 +108,8 @@ struct _GdmSessionIface
int exit_code);
void (* session_died) (GdmSession *session,
int signal_number);
- void (* conversation_started) (GdmSession *session);
+ void (* conversation_started) (GdmSession *session,
+ const char *service_name);
void (* closed) (GdmSession *session);
void (* selected_user_changed) (GdmSession *session,
const char *text);
@@ -122,7 +124,8 @@ struct _GdmSessionIface
GType gdm_session_get_type (void) G_GNUC_CONST;
-void gdm_session_start_conversation (GdmSession *session);
+void gdm_session_start_conversation (GdmSession *session,
+ const char *service_name);
void gdm_session_setup (GdmSession *session,
const char *service_name);
void gdm_session_setup_for_user (GdmSession *session,
diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c
index 7187ea1..bd1ecad 100644
--- a/daemon/gdm-simple-slave.c
+++ b/daemon/gdm-simple-slave.c
@@ -176,7 +176,6 @@ reset_session (GdmSimpleSlave *slave)
{
destroy_session (slave);
create_new_session (slave);
- gdm_session_start_conversation (GDM_SESSION (slave->priv->session));
}
static gboolean
@@ -981,8 +980,6 @@ on_greeter_connected (GdmGreeterServer *greeter_server,
g_debug ("GdmSimpleSlave: Greeter connected");
- gdm_session_start_conversation (GDM_SESSION (slave->priv->session));
-
g_object_get (slave,
"display-is-local", &display_is_local,
NULL);
diff --git a/daemon/test-session.c b/daemon/test-session.c
index 8bed085..9bfda86 100644
--- a/daemon/test-session.c
+++ b/daemon/test-session.c
@@ -34,11 +34,12 @@ static GMainLoop *loop;
static void
on_conversation_started (GdmSession *session,
+ const char *service_name,
const char *username)
{
g_debug ("Got conversation started: calling setup...");
- gdm_session_setup (session, "gdm");
+ gdm_session_setup (session, service_name);
}
static void
@@ -267,7 +268,7 @@ main (int argc,
username = argv[1];
}
- gdm_session_start_conversation (GDM_SESSION (session));
+ gdm_session_start_conversation (GDM_SESSION (session), "gdm");
g_signal_connect (session,
"conversation-started",
--
1.7.2.1
From d6e02a0b140b831adb0c7509eccb0e9039616b29 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 4 Feb 2009 10:55:03 -0500
Subject: [PATCH 08/35] Rename session worker to the service it's managing
This way when we're running multiple PAM conversations at once
it will be obvious which worker is managing which conversation.
---
daemon/gdm-session-direct.c | 7 ++++-
daemon/gdm-session-worker-job.c | 63 ++++++++++++++++++++++++++++++--------
daemon/gdm-session-worker-job.h | 3 +-
3 files changed, 57 insertions(+), 16 deletions(-)
diff --git a/daemon/gdm-session-direct.c b/daemon/gdm-session-direct.c
index f9621a2..cfbaa15 100644
--- a/daemon/gdm-session-direct.c
+++ b/daemon/gdm-session-direct.c
@@ -1745,6 +1745,7 @@ start_conversation (GdmSessionDirect *session,
const char *service_name)
{
GdmSessionConversation *conversation;
+ char *job_name;
conversation = g_new0 (GdmSessionConversation, 1);
conversation->session = session;
@@ -1765,12 +1766,16 @@ start_conversation (GdmSessionDirect *session,
G_CALLBACK (worker_died),
conversation);
- if (!gdm_session_worker_job_start (conversation->job)) {
+ job_name = g_strdup_printf ("pam: %s", service_name);
+ if (!gdm_session_worker_job_start (conversation->job,
+ job_name)) {
g_object_unref (conversation->job);
g_free (conversation->service_name);
g_free (conversation);
+ g_free (job_name);
return NULL;
}
+ g_free (job_name);
conversation->worker_pid = gdm_session_worker_job_get_pid (conversation->job);
diff --git a/daemon/gdm-session-worker-job.c b/daemon/gdm-session-worker-job.c
index f686002..be85f30 100644
--- a/daemon/gdm-session-worker-job.c
+++ b/daemon/gdm-session-worker-job.c
@@ -156,6 +156,37 @@ copy_environment_to_hash (GHashTable *hash)
}
static GPtrArray *
+get_job_arguments (GdmSessionWorkerJob *job,
+ const char *name)
+{
+ GPtrArray *args;
+ GError *error;
+ char **argv;
+ int i;
+
+ args = NULL;
+ argv = NULL;
+ error = NULL;
+ if (! g_shell_parse_argv (job->priv->command, NULL, &argv, &error)) {
+ g_warning ("Could not parse command: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ args = g_ptr_array_new ();
+ g_ptr_array_add (args, g_strdup (argv[0]));
+ g_ptr_array_add (args, g_strdup (name));
+ for (i = 1; argv[i] != NULL; i++) {
+ g_ptr_array_add (args, g_strdup (argv[i]));
+ }
+ g_strfreev (argv);
+
+ g_ptr_array_add (args, NULL);
+out:
+ return args;
+}
+
+static GPtrArray *
get_job_environment (GdmSessionWorkerJob *job)
{
GPtrArray *env;
@@ -178,31 +209,31 @@ get_job_environment (GdmSessionWorkerJob *job)
}
static gboolean
-gdm_session_worker_job_spawn (GdmSessionWorkerJob *session_worker_job)
+gdm_session_worker_job_spawn (GdmSessionWorkerJob *session_worker_job,
+ const char *name)
{
- gchar **argv;
GError *error;
gboolean ret;
+ GPtrArray *args;
GPtrArray *env;
ret = FALSE;
- g_debug ("GdmSessionWorkerJob: Running session_worker_job process: %s", session_worker_job->priv->command);
+ g_debug ("GdmSessionWorkerJob: Running session_worker_job process: %s %s",
+ name != NULL? name : "", session_worker_job->priv->command);
- argv = NULL;
- if (! g_shell_parse_argv (session_worker_job->priv->command, NULL, &argv, &error)) {
- g_warning ("Could not parse command: %s", error->message);
- g_error_free (error);
- goto out;
- }
+ args = get_job_arguments (session_worker_job, name);
+ if (args == NULL) {
+ return FALSE;
+ }
env = get_job_environment (session_worker_job);
error = NULL;
ret = g_spawn_async_with_pipes (NULL,
- argv,
+ (char **) args->pdata,
(char **)env->pdata,
- G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
+ G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_FILE_AND_ARGV_ZERO,
(GSpawnChildSetupFunc)session_worker_job_child_setup,
session_worker_job,
&session_worker_job->priv->pid,
@@ -211,6 +242,9 @@ gdm_session_worker_job_spawn (GdmSessionWorkerJob *session_worker_job)
NULL,
&error);
+ g_ptr_array_foreach (args, (GFunc)g_free, NULL);
+ g_ptr_array_free (args, TRUE);
+
g_ptr_array_foreach (env, (GFunc)g_free, NULL);
g_ptr_array_free (env, TRUE);
@@ -227,7 +261,6 @@ gdm_session_worker_job_spawn (GdmSessionWorkerJob *session_worker_job)
(GChildWatchFunc)session_worker_job_child_watch,
session_worker_job);
- g_strfreev (argv);
out:
return ret;
@@ -240,13 +273,14 @@ gdm_session_worker_job_spawn (GdmSessionWorkerJob *session_worker_job)
* Starts a local X session_worker_job. Handles retries and fatal errors properly.
*/
gboolean
-gdm_session_worker_job_start (GdmSessionWorkerJob *session_worker_job)
+gdm_session_worker_job_start (GdmSessionWorkerJob *session_worker_job,
+ const char *name)
{
gboolean res;
g_debug ("GdmSessionWorkerJob: Starting worker...");
- res = gdm_session_worker_job_spawn (session_worker_job);
+ res = gdm_session_worker_job_spawn (session_worker_job, name);
if (res) {
@@ -294,6 +328,7 @@ gdm_session_worker_job_stop (GdmSessionWorkerJob *session_worker_job)
g_debug ("GdmSessionWorkerJob: Stopping job pid:%d", session_worker_job->priv->pid);
res = gdm_signal_pid (session_worker_job->priv->pid, SIGTERM);
+
if (res < 0) {
g_warning ("Unable to kill session worker process");
} else {
diff --git a/daemon/gdm-session-worker-job.h b/daemon/gdm-session-worker-job.h
index d24f025..4833f23 100644
--- a/daemon/gdm-session-worker-job.h
+++ b/daemon/gdm-session-worker-job.h
@@ -57,7 +57,8 @@ GType gdm_session_worker_job_get_type (void);
GdmSessionWorkerJob * gdm_session_worker_job_new (void);
void gdm_session_worker_job_set_server_address (GdmSessionWorkerJob *session_worker_job,
const char *server_address);
-gboolean gdm_session_worker_job_start (GdmSessionWorkerJob *session_worker_job);
+gboolean gdm_session_worker_job_start (GdmSessionWorkerJob *session_worker_job,
+ const char *name);
gboolean gdm_session_worker_job_stop (GdmSessionWorkerJob *session_worker_job);
GPid gdm_session_worker_job_get_pid (GdmSessionWorkerJob *session_worker_job);
--
1.7.2.1
From 23a4e811a336f275dd50536599ed9336b0c6a55b Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 16 Jan 2009 13:01:48 -0500
Subject: [PATCH 09/35] Make greeter/autologin session explicitly request PAM conversation
Now the greeter (and also the autologin code) has to say what
PAM stack it wants the slave to run. When that stack is ready,
we emit the Ready signal as before, but now the Ready signal
carries a string argument saying which service is ready to
converse.
When we support multiple PAM stacks, the greeter will call
StartConversation for each stack, and will keep the UI
associated with each stack disabled until the Ready signals
come back one-by-one.
---
daemon/gdm-factory-slave.c | 3 +-
daemon/gdm-greeter-server.c | 53 ++++++++++++++++++++++++++++--
daemon/gdm-greeter-server.h | 5 ++-
daemon/gdm-simple-slave.c | 39 +++++++++++++++++++++-
gui/simple-greeter/gdm-greeter-client.c | 18 ++++++----
gui/simple-greeter/gdm-greeter-client.h | 4 ++-
gui/simple-greeter/gdm-greeter-session.c | 4 ++
7 files changed, 111 insertions(+), 15 deletions(-)
diff --git a/daemon/gdm-factory-slave.c b/daemon/gdm-factory-slave.c
index 0151ab2..f30664f 100644
--- a/daemon/gdm-factory-slave.c
+++ b/daemon/gdm-factory-slave.c
@@ -186,7 +186,8 @@ on_session_conversation_started (GdmSession *session,
{
g_debug ("GdmFactorySlave: session conversation started");
- gdm_greeter_server_ready (slave->priv->greeter_server);
+ gdm_greeter_server_ready (slave->priv->greeter_server,
+ service_name);
}
static void
diff --git a/daemon/gdm-greeter-server.c b/daemon/gdm-greeter-server.c
index 1ab01e4..03ecfca 100644
--- a/daemon/gdm-greeter-server.c
+++ b/daemon/gdm-greeter-server.c
@@ -70,6 +70,7 @@ enum {
};
enum {
+ START_CONVERSATION,
BEGIN_AUTO_LOGIN,
BEGIN_VERIFICATION,
BEGIN_VERIFICATION_FOR_USER,
@@ -254,9 +255,10 @@ gdm_greeter_server_reset (GdmGreeterServer *greeter_server)
}
gboolean
-gdm_greeter_server_ready (GdmGreeterServer *greeter_server)
+gdm_greeter_server_ready (GdmGreeterServer *greeter_server,
+ const char *service_name)
{
- send_dbus_void_signal (greeter_server, "Ready");
+ send_dbus_string_signal (greeter_server, "Ready", service_name);
return TRUE;
}
@@ -331,6 +333,34 @@ generate_address (void)
}
static DBusHandlerResult
+handle_start_conversation (GdmGreeterServer *greeter_server,
+ DBusConnection *connection,
+ DBusMessage *message)
+{
+ DBusMessage *reply;
+ DBusError error;
+ const char *service_name;
+
+ dbus_error_init (&error);
+ if (! dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &service_name,
+ DBUS_TYPE_INVALID)) {
+ g_warning ("ERROR: %s", error.message);
+ }
+ dbus_error_free (&error);
+
+ g_debug ("GreeterServer: StartConversation");
+
+ reply = dbus_message_new_method_return (message);
+ dbus_connection_send (connection, reply, NULL);
+ dbus_message_unref (reply);
+
+ g_signal_emit (greeter_server, signals [START_CONVERSATION], 0, service_name);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
handle_begin_verification (GdmGreeterServer *greeter_server,
DBusConnection *connection,
DBusMessage *message)
@@ -653,7 +683,9 @@ greeter_handle_child_message (DBusConnection *connection,
{
GdmGreeterServer *greeter_server = GDM_GREETER_SERVER (user_data);
- if (dbus_message_is_method_call (message, GDM_GREETER_SERVER_DBUS_INTERFACE, "BeginVerification")) {
+ if (dbus_message_is_method_call (message, GDM_GREETER_SERVER_DBUS_INTERFACE, "StartConversation")) {
+ return handle_start_conversation (greeter_server, connection, message);
+ } else if (dbus_message_is_method_call (message, GDM_GREETER_SERVER_DBUS_INTERFACE, "BeginVerification")) {
return handle_begin_verification (greeter_server, connection, message);
} else if (dbus_message_is_method_call (message, GDM_GREETER_SERVER_DBUS_INTERFACE, "BeginVerificationForUser")) {
return handle_begin_verification_for_user (greeter_server, connection, message);
@@ -707,7 +739,11 @@ do_introspect (DBusConnection *connection,
/* interface */
xml = g_string_append (xml,
" <interface name=\"org.gnome.DisplayManager.GreeterServer\">\n"
+ " <method name=\"StartConversation\">\n"
+ " <arg name=\"service_name\" direction=\"in\" type=\"s\"/>\n"
+ " </method>\n"
" <method name=\"BeginVerification\">\n"
+ " </method>\n"
" <method name=\"BeginTimedLogin\">\n"
" </method>\n"
" <method name=\"BeginVerificationForUser\">\n"
@@ -767,6 +803,7 @@ do_introspect (DBusConnection *connection,
" <arg name=\"delay\" type=\"i\"/>\n"
" </signal>\n"
" <signal name=\"Ready\">\n"
+ " <arg name=\"service-name\" type=\"s\"/>\n"
" </signal>\n"
" <signal name=\"Reset\">\n"
" </signal>\n"
@@ -1131,6 +1168,16 @@ gdm_greeter_server_class_init (GdmGreeterServerClass *klass)
"group name",
GDM_GROUPNAME,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ signals [START_CONVERSATION] =
+ g_signal_new ("start-conversation",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmGreeterServerClass, start_conversation),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1, G_TYPE_STRING);
signals [BEGIN_VERIFICATION] =
g_signal_new ("begin-verification",
G_OBJECT_CLASS_TYPE (object_class),
diff --git a/daemon/gdm-greeter-server.h b/daemon/gdm-greeter-server.h
index f9c157f..7e2424a 100644
--- a/daemon/gdm-greeter-server.h
+++ b/daemon/gdm-greeter-server.h
@@ -45,6 +45,8 @@ typedef struct
{
GObjectClass parent_class;
+ void (* start_conversation) (GdmGreeterServer *greeter_server,
+ const char *service_name);
void (* begin_auto_login) (GdmGreeterServer *greeter_server);
void (* begin_verification) (GdmGreeterServer *greeter_server);
void (* begin_verification_for_user)(GdmGreeterServer *greeter_server,
@@ -86,7 +88,8 @@ gboolean gdm_greeter_server_problem (GdmGreeterServer *
const char *text);
gboolean gdm_greeter_server_authentication_failed (GdmGreeterServer *greeter_server);
gboolean gdm_greeter_server_reset (GdmGreeterServer *greeter_server);
-gboolean gdm_greeter_server_ready (GdmGreeterServer *greeter_server);
+gboolean gdm_greeter_server_ready (GdmGreeterServer *greeter_server,
+ const char *service_name);
void gdm_greeter_server_selected_user_changed (GdmGreeterServer *greeter_server,
const char *text);
void gdm_greeter_server_default_language_name_changed (GdmGreeterServer *greeter_server,
diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c
index bd1ecad..dc7b437 100644
--- a/daemon/gdm-simple-slave.c
+++ b/daemon/gdm-simple-slave.c
@@ -545,6 +545,7 @@ on_session_secret_info_query (GdmSession *session,
static void
on_session_conversation_started (GdmSession *session,
+ const char *service_name,
GdmSimpleSlave *slave)
{
gboolean res;
@@ -554,7 +555,8 @@ on_session_conversation_started (GdmSession *session,
g_debug ("GdmSimpleSlave: session conversation started");
if (slave->priv->greeter_server != NULL) {
- res = gdm_greeter_server_ready (slave->priv->greeter_server);
+ res = gdm_greeter_server_ready (slave->priv->greeter_server,
+ service_name);
if (! res) {
g_warning ("Unable to send ready");
}
@@ -570,8 +572,10 @@ on_session_conversation_started (GdmSession *session,
gdm_greeter_server_request_timed_login (slave->priv->greeter_server, username, delay);
} else {
g_debug ("GdmSimpleSlave: begin auto login for user '%s'", username);
+ /* service_name will be "gdm-autologin"
+ */
gdm_session_setup_for_user (GDM_SESSION (slave->priv->session),
- "gdm-autologin",
+ service_name,
username);
}
@@ -627,6 +631,21 @@ on_default_session_name_changed (GdmSession *session,
}
static void
+start_autologin_conversation_if_necessary (GdmSimpleSlave *slave)
+{
+ gboolean enabled;
+ gdm_slave_get_timed_login_details (GDM_SLAVE (slave), &enabled, NULL, NULL);
+
+ if (!enabled) {
+ return;
+ }
+
+ g_debug ("GdmSimpleSlave: Starting automatic login conversation");
+ gdm_session_start_conversation (GDM_SESSION (slave->priv->session),
+ "gdm-autologin");
+}
+
+static void
create_new_session (GdmSimpleSlave *slave)
{
gboolean display_is_local;
@@ -767,6 +786,8 @@ create_new_session (GdmSimpleSlave *slave)
"default-session-name-changed",
G_CALLBACK (on_default_session_name_changed),
slave);
+
+ start_autologin_conversation_if_necessary (slave);
}
static void
@@ -894,6 +915,16 @@ on_greeter_session_died (GdmGreeterSession *greeter,
}
static void
+on_greeter_start_conversation (GdmGreeterServer *greeter_server,
+ const char *service_name,
+ GdmSimpleSlave *slave)
+{
+ g_debug ("GdmSimpleSlave: starting conversation with '%s' pam service'", service_name);
+ gdm_session_start_conversation (GDM_SESSION (slave->priv->session),
+ service_name);
+}
+
+static void
on_greeter_begin_verification (GdmGreeterServer *greeter_server,
GdmSimpleSlave *slave)
{
@@ -1071,6 +1102,10 @@ start_greeter (GdmSimpleSlave *slave)
slave->priv->greeter_server = gdm_greeter_server_new (display_id);
g_signal_connect (slave->priv->greeter_server,
+ "start-conversation",
+ G_CALLBACK (on_greeter_start_conversation),
+ slave);
+ g_signal_connect (slave->priv->greeter_server,
"begin-auto-login",
G_CALLBACK (on_greeter_begin_auto_login),
slave);
diff --git a/gui/simple-greeter/gdm-greeter-client.c b/gui/simple-greeter/gdm-greeter-client.c
index d02b3d1..b175fc9 100644
--- a/gui/simple-greeter/gdm-greeter-client.c
+++ b/gui/simple-greeter/gdm-greeter-client.c
@@ -238,11 +238,7 @@ static void
on_ready (GdmGreeterClient *client,
DBusMessage *message)
{
- g_debug ("GdmGreeterClient: Ready");
-
- g_signal_emit (client,
- gdm_greeter_client_signals[READY],
- 0);
+ emit_string_signal_for_message (client, "Ready", message, READY);
}
static void
@@ -412,6 +408,14 @@ send_dbus_void_method (DBusConnection *connection,
}
void
+gdm_greeter_client_call_start_conversation (GdmGreeterClient *client,
+ const char *service_name)
+{
+ send_dbus_string_method (client->priv->connection,
+ "StartConversation", service_name);
+}
+
+void
gdm_greeter_client_call_begin_auto_login (GdmGreeterClient *client,
const char *username)
{
@@ -893,9 +897,9 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass)
G_STRUCT_OFFSET (GdmGreeterClientClass, ready),
NULL,
NULL,
- g_cclosure_marshal_VOID__VOID,
+ g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE,
- 0);
+ 1, G_TYPE_STRING);
gdm_greeter_client_signals[RESET] =
g_signal_new ("reset",
diff --git a/gui/simple-greeter/gdm-greeter-client.h b/gui/simple-greeter/gdm-greeter-client.h
index 16ccef9..e08aaa5 100644
--- a/gui/simple-greeter/gdm-greeter-client.h
+++ b/gui/simple-greeter/gdm-greeter-client.h
@@ -85,13 +85,15 @@ GQuark gdm_greeter_client_error_quark (void);
GdmGreeterClient * gdm_greeter_client_new (void);
gboolean gdm_greeter_client_start (GdmGreeterClient *client,
- GError **error);
+ GError **error);
void gdm_greeter_client_stop (GdmGreeterClient *client);
gboolean gdm_greeter_client_get_display_is_local (GdmGreeterClient *client);
char * gdm_greeter_client_call_get_display_id (GdmGreeterClient *client);
+void gdm_greeter_client_call_start_conversation (GdmGreeterClient *client,
+ const char *service_name);
void gdm_greeter_client_call_begin_auto_login (GdmGreeterClient *client,
const char *username);
void gdm_greeter_client_call_begin_verification (GdmGreeterClient *client);
diff --git a/gui/simple-greeter/gdm-greeter-session.c b/gui/simple-greeter/gdm-greeter-session.c
index d4ef77f..63de620 100644
--- a/gui/simple-greeter/gdm-greeter-session.c
+++ b/gui/simple-greeter/gdm-greeter-session.c
@@ -89,6 +89,7 @@ on_problem (GdmGreeterClient *client,
static void
on_ready (GdmGreeterClient *client,
+ const char *service_name,
GdmGreeterSession *session)
{
g_debug ("GdmGreeterSession: Ready");
@@ -293,6 +294,7 @@ on_cancelled (GdmGreeterLoginWindow *login_window,
{
gdm_greeter_panel_hide_user_options (GDM_GREETER_PANEL (session->priv->panel));
gdm_greeter_client_call_cancel (session->priv->client);
+ gdm_greeter_client_call_start_conversation (session->priv->client, "gdm");
}
static void
@@ -457,6 +459,8 @@ gdm_greeter_session_start (GdmGreeterSession *session,
toggle_panel (session, TRUE);
toggle_login_window (session, TRUE);
+ gdm_greeter_client_call_start_conversation (session->priv->client, "gdm");
+
gdm_profile_end (NULL);
return res;
--
1.7.2.1
From 501504483329a0ddc74acb39456860f381b0e54e Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 16 Jan 2009 15:18:31 -0500
Subject: [PATCH 10/35] Store multiple conversations in the session
We keep multiple conversations in the session now, keyed off of
PAM service is at the other end. Much of the guts still
only operate on the first conversation added though.
---
daemon/gdm-factory-slave.c | 69 +++-
daemon/gdm-greeter-server.c | 134 ++++++--
daemon/gdm-greeter-server.h | 19 +-
daemon/gdm-product-slave.c | 264 +++++++++++---
daemon/gdm-session-direct.c | 585 ++++++++++++++++++++----------
daemon/gdm-session-private.h | 28 ++-
daemon/gdm-session-relay.c | 135 ++++++--
daemon/gdm-session-worker.c | 27 ++
daemon/gdm-session.c | 203 +++++++----
daemon/gdm-session.h | 60 +++-
daemon/gdm-simple-slave.c | 114 +++++--
daemon/test-session.c | 22 +-
gui/simple-greeter/gdm-greeter-client.c | 188 ++++++++--
gui/simple-greeter/gdm-greeter-client.h | 16 +-
gui/simple-greeter/gdm-greeter-session.c | 11 +-
15 files changed, 1394 insertions(+), 481 deletions(-)
diff --git a/daemon/gdm-factory-slave.c b/daemon/gdm-factory-slave.c
index f30664f..653cb18 100644
--- a/daemon/gdm-factory-slave.c
+++ b/daemon/gdm-factory-slave.c
@@ -144,45 +144,49 @@ on_greeter_session_died (GdmGreeterSession *greeter,
static void
on_session_info (GdmSession *session,
+ const char *service_name,
const char *text,
GdmFactorySlave *slave)
{
g_debug ("GdmFactorySlave: Info: %s", text);
- gdm_greeter_server_info (slave->priv->greeter_server, text);
+ gdm_greeter_server_info (slave->priv->greeter_server, service_name, text);
}
static void
on_session_problem (GdmSession *session,
+ const char *service_name,
const char *text,
GdmFactorySlave *slave)
{
g_debug ("GdmFactorySlave: Problem: %s", text);
- gdm_greeter_server_problem (slave->priv->greeter_server, text);
+ gdm_greeter_server_problem (slave->priv->greeter_server, service_name, text);
}
static void
on_session_info_query (GdmSession *session,
+ const char *service_name,
const char *text,
GdmFactorySlave *slave)
{
g_debug ("GdmFactorySlave: Info query: %s", text);
- gdm_greeter_server_info_query (slave->priv->greeter_server, text);
+ gdm_greeter_server_info_query (slave->priv->greeter_server, service_name, text);
}
static void
on_session_secret_info_query (GdmSession *session,
+ const char *service_name,
const char *text,
GdmFactorySlave *slave)
{
g_debug ("GdmFactorySlave: Secret info query: %s", text);
- gdm_greeter_server_secret_info_query (slave->priv->greeter_server, text);
+ gdm_greeter_server_secret_info_query (slave->priv->greeter_server, service_name, text);
}
static void
on_session_conversation_started (GdmSession *session,
- GdmFactorySlave *slave,
- const char *service_name)
+ const char *service_name,
+ GdmFactorySlave *slave)
{
g_debug ("GdmFactorySlave: session conversation started");
@@ -192,17 +196,19 @@ on_session_conversation_started (GdmSession *session,
static void
on_session_setup_complete (GdmSession *session,
+ const char *service_name,
GdmFactorySlave *slave)
{
- gdm_session_authenticate (session);
+ gdm_session_authenticate (session, service_name);
}
static void
on_session_setup_failed (GdmSession *session,
+ const char *service_name,
const char *message,
GdmFactorySlave *slave)
{
- gdm_greeter_server_problem (slave->priv->greeter_server, _("Unable to initialize login system"));
+ gdm_greeter_server_problem (slave->priv->greeter_server, service_name, _("Unable to initialize login system"));
queue_greeter_reset (slave);
}
@@ -224,23 +230,26 @@ on_session_reset_failed (GdmSession *session,
static void
on_session_authenticated (GdmSession *session,
+ const char *service_name,
GdmFactorySlave *slave)
{
- gdm_session_authorize (session);
+ gdm_session_authorize (session, service_name);
}
static void
on_session_authentication_failed (GdmSession *session,
+ const char *service_name,
const char *message,
GdmFactorySlave *slave)
{
- gdm_greeter_server_problem (slave->priv->greeter_server, _("Unable to authenticate user"));
+ gdm_greeter_server_problem (slave->priv->greeter_server, service_name, _("Unable to authenticate user"));
queue_greeter_reset (slave);
}
static void
on_session_authorized (GdmSession *session,
+ const char *service_name,
GdmFactorySlave *slave)
{
int flag;
@@ -248,60 +257,65 @@ on_session_authorized (GdmSession *session,
/* FIXME: check for migration? */
flag = GDM_SESSION_CRED_ESTABLISH;
- gdm_session_accredit (session, flag);
+ gdm_session_accredit (session, service_name, flag);
}
static void
on_session_authorization_failed (GdmSession *session,
+ const char *service_name,
const char *message,
GdmFactorySlave *slave)
{
- gdm_greeter_server_problem (slave->priv->greeter_server, _("Unable to authorize user"));
+ gdm_greeter_server_problem (slave->priv->greeter_server, service_name, _("Unable to authorize user"));
queue_greeter_reset (slave);
}
static void
on_session_accredited (GdmSession *session,
+ const char *service_name,
GdmFactorySlave *slave)
{
g_debug ("GdmFactorySlave: session user verified");
- gdm_session_open_session (session);
+ gdm_session_open_session (session, service_name);
}
static void
on_session_accreditation_failed (GdmSession *session,
+ const char *service_name,
const char *message,
GdmFactorySlave *slave)
{
g_debug ("GdmFactorySlave: could not successfully authenticate user: %s",
message);
- gdm_greeter_server_problem (slave->priv->greeter_server, _("Unable to establish credentials"));
+ gdm_greeter_server_problem (slave->priv->greeter_server, service_name, _("Unable to establish credentials"));
queue_greeter_reset (slave);
}
static void
on_session_opened (GdmSession *session,
+ const char *service_name,
GdmFactorySlave *slave)
{
g_debug ("GdmFactorySlave: session opened");
- gdm_session_start_session (session);
+ gdm_session_start_session (session, service_name);
gdm_greeter_server_reset (slave->priv->greeter_server);
}
static void
on_session_open_failed (GdmSession *session,
+ const char *service_name,
const char *message,
GdmFactorySlave *slave)
{
g_debug ("GdmFactorySlave: could not open session: %s", message);
- gdm_greeter_server_problem (slave->priv->greeter_server, _("Unable to open session"));
+ gdm_greeter_server_problem (slave->priv->greeter_server, service_name, _("Unable to open session"));
queue_greeter_reset (slave);
}
@@ -390,37 +404,48 @@ on_session_relay_connected (GdmSessionRelay *session,
GdmFactorySlave *slave)
{
g_debug ("GdmFactorySlave: Relay Connected");
+}
+
+static void
+on_greeter_start_conversation (GdmGreeterServer *greeter_server,
+ const char *service_name,
+ GdmFactorySlave *slave)
+{
+ g_debug ("GdmFactorySlave: start conversation");
- gdm_session_start_conversation (GDM_SESSION (slave->priv->session), "gdm");
+ gdm_session_start_conversation (GDM_SESSION (slave->priv->session), service_name);
}
static void
on_greeter_begin_verification (GdmGreeterServer *greeter_server,
+ const char *service_name,
GdmFactorySlave *slave)
{
g_debug ("GdmFactorySlave: begin verification");
gdm_session_setup (GDM_SESSION (slave->priv->session),
- "gdm");
+ service_name);
}
static void
on_greeter_begin_verification_for_user (GdmGreeterServer *greeter_server,
+ const char *service_name,
const char *username,
GdmFactorySlave *slave)
{
g_debug ("GdmFactorySlave: begin verification for user");
gdm_session_setup_for_user (GDM_SESSION (slave->priv->session),
- "gdm",
+ service_name,
username);
}
static void
on_greeter_answer (GdmGreeterServer *greeter_server,
+ const char *service_name,
const char *text,
GdmFactorySlave *slave)
{
g_debug ("GdmFactorySlave: Greeter answer");
- gdm_session_answer_query (GDM_SESSION (slave->priv->session), text);
+ gdm_session_answer_query (GDM_SESSION (slave->priv->session), service_name, text);
}
static void
@@ -520,6 +545,10 @@ run_greeter (GdmFactorySlave *slave)
slave->priv->greeter_server = gdm_greeter_server_new (display_id);
g_signal_connect (slave->priv->greeter_server,
+ "start-conversation",
+ G_CALLBACK (on_greeter_start_conversation),
+ slave);
+ g_signal_connect (slave->priv->greeter_server,
"begin-verification",
G_CALLBACK (on_greeter_begin_verification),
slave);
diff --git a/daemon/gdm-greeter-server.c b/daemon/gdm-greeter-server.c
index 03ecfca..50e4193 100644
--- a/daemon/gdm-greeter-server.c
+++ b/daemon/gdm-greeter-server.c
@@ -44,6 +44,7 @@
#include <dbus/dbus-glib-lowlevel.h>
#include "gdm-common.h"
+#include "gdm-marshal.h"
#include "gdm-greeter-server.h"
#define GDM_GREETER_SERVER_DBUS_PATH "/org/gnome/DisplayManager/GreeterServer"
@@ -157,6 +158,46 @@ send_dbus_string_and_int_signal (GdmGreeterServer *greeter_server,
}
static void
+send_dbus_string_string_signal (GdmGreeterServer *greeter_server,
+ const char *name,
+ const char *text1,
+ const char *text2)
+{
+ DBusMessage *message;
+ DBusMessageIter iter;
+ const char *str;
+
+ g_return_if_fail (greeter_server != NULL);
+
+ message = dbus_message_new_signal (GDM_GREETER_SERVER_DBUS_PATH,
+ GDM_GREETER_SERVER_DBUS_INTERFACE,
+ name);
+
+ dbus_message_iter_init_append (message, &iter);
+
+ if (text1 != NULL) {
+ str = text1;
+ } else {
+ str = "";
+ }
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &str);
+
+ if (text2 != NULL) {
+ str = text2;
+ } else {
+ str = "";
+ }
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &str);
+
+ g_debug ("GreeterServer: Sending %s (%s)", name, str);
+ if (! send_dbus_message (greeter_server->priv->greeter_connection, message)) {
+ g_debug ("GreeterServer: Could not send %s signal", name);
+ }
+
+ dbus_message_unref (message);
+}
+
+static void
send_dbus_string_signal (GdmGreeterServer *greeter_server,
const char *name,
const char *text)
@@ -209,34 +250,38 @@ send_dbus_void_signal (GdmGreeterServer *greeter_server,
gboolean
gdm_greeter_server_info_query (GdmGreeterServer *greeter_server,
+ const char *service_name,
const char *text)
{
- send_dbus_string_signal (greeter_server, "InfoQuery", text);
+ send_dbus_string_string_signal (greeter_server, "InfoQuery", service_name, text);
return TRUE;
}
gboolean
gdm_greeter_server_secret_info_query (GdmGreeterServer *greeter_server,
+ const char *service_name,
const char *text)
{
- send_dbus_string_signal (greeter_server, "SecretInfoQuery", text);
+ send_dbus_string_string_signal (greeter_server, "SecretInfoQuery", service_name, text);
return TRUE;
}
gboolean
gdm_greeter_server_info (GdmGreeterServer *greeter_server,
+ const char *service_name,
const char *text)
{
- send_dbus_string_signal (greeter_server, "Info", text);
+ send_dbus_string_string_signal (greeter_server, "Info", service_name, text);
return TRUE;
}
gboolean
gdm_greeter_server_problem (GdmGreeterServer *greeter_server,
+ const char *service_name,
const char *text)
{
- send_dbus_string_signal (greeter_server, "Problem", text);
+ send_dbus_string_string_signal (greeter_server, "Problem", service_name, text);
return TRUE;
}
@@ -262,6 +307,14 @@ gdm_greeter_server_ready (GdmGreeterServer *greeter_server,
return TRUE;
}
+gboolean
+gdm_greeter_server_conversation_stopped (GdmGreeterServer *greeter_server,
+ const char *service_name)
+{
+ send_dbus_string_signal (greeter_server, "ConversationStopped", service_name);
+ return TRUE;
+}
+
void
gdm_greeter_server_selected_user_changed (GdmGreeterServer *greeter_server,
const char *username)
@@ -299,9 +352,10 @@ gdm_greeter_server_request_timed_login (GdmGreeterServer *greeter_server,
}
void
-gdm_greeter_server_user_authorized (GdmGreeterServer *greeter_server)
+gdm_greeter_server_user_authorized (GdmGreeterServer *greeter_server,
+ const char *service_name)
{
- send_dbus_void_signal (greeter_server, "UserAuthorized");
+ send_dbus_string_signal (greeter_server, "UserAuthorized", service_name);
}
/* Note: Use abstract sockets like dbus does by default on Linux. Abstract
@@ -366,6 +420,16 @@ handle_begin_verification (GdmGreeterServer *greeter_server,
DBusMessage *message)
{
DBusMessage *reply;
+ DBusError error;
+ const char *service_name;
+
+ dbus_error_init (&error);
+ if (! dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &service_name,
+ DBUS_TYPE_INVALID)) {
+ g_warning ("ERROR: %s", error.message);
+ }
+ dbus_error_free (&error);
g_debug ("GreeterServer: BeginVerification");
@@ -373,7 +437,7 @@ handle_begin_verification (GdmGreeterServer *greeter_server,
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
- g_signal_emit (greeter_server, signals [BEGIN_VERIFICATION], 0);
+ g_signal_emit (greeter_server, signals [BEGIN_VERIFICATION], 0, service_name);
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -387,7 +451,6 @@ handle_begin_auto_login (GdmGreeterServer *greeter_server,
DBusError error;
const char *text;
-
dbus_error_init (&error);
if (! dbus_message_get_args (message, &error,
DBUS_TYPE_STRING, &text,
@@ -414,13 +477,16 @@ handle_begin_verification_for_user (GdmGreeterServer *greeter_server,
DBusMessage *reply;
DBusError error;
const char *text;
+ const char *service_name;
dbus_error_init (&error);
if (! dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &service_name,
DBUS_TYPE_STRING, &text,
DBUS_TYPE_INVALID)) {
g_warning ("ERROR: %s", error.message);
}
+ dbus_error_free (&error);
g_debug ("GreeterServer: BeginVerificationForUser for '%s'", text);
@@ -428,7 +494,7 @@ handle_begin_verification_for_user (GdmGreeterServer *greeter_server,
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
- g_signal_emit (greeter_server, signals [BEGIN_VERIFICATION_FOR_USER], 0, text);
+ g_signal_emit (greeter_server, signals [BEGIN_VERIFICATION_FOR_USER], 0, service_name, text);
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -441,13 +507,16 @@ handle_answer_query (GdmGreeterServer *greeter_server,
DBusMessage *reply;
DBusError error;
const char *text;
+ const char *service_name;
dbus_error_init (&error);
if (! dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &service_name,
DBUS_TYPE_STRING, &text,
DBUS_TYPE_INVALID)) {
g_warning ("ERROR: %s", error.message);
}
+ dbus_error_free (&error);
g_debug ("GreeterServer: AnswerQuery");
@@ -455,7 +524,7 @@ handle_answer_query (GdmGreeterServer *greeter_server,
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
- g_signal_emit (greeter_server, signals [QUERY_ANSWER], 0, text);
+ g_signal_emit (greeter_server, signals [QUERY_ANSWER], 0, service_name, text);
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -652,9 +721,11 @@ handle_start_session_when_ready (GdmGreeterServer *greeter_server,
DBusMessage *reply;
DBusError error;
gboolean should_start_session;
+ char *service_name;
dbus_error_init (&error);
if (! dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &service_name,
DBUS_TYPE_BOOLEAN, &should_start_session,
DBUS_TYPE_INVALID)) {
g_warning ("ERROR: %s", error.message);
@@ -668,9 +739,9 @@ handle_start_session_when_ready (GdmGreeterServer *greeter_server,
dbus_message_unref (reply);
if (should_start_session) {
- g_signal_emit (greeter_server, signals [START_SESSION_WHEN_READY], 0);
+ g_signal_emit (greeter_server, signals [START_SESSION_WHEN_READY], 0, service_name);
} else {
- g_signal_emit (greeter_server, signals [START_SESSION_LATER] ,0);
+ g_signal_emit (greeter_server, signals [START_SESSION_LATER] ,0, service_name);
}
return DBUS_HANDLER_RESULT_HANDLED;
@@ -742,14 +813,20 @@ do_introspect (DBusConnection *connection,
" <method name=\"StartConversation\">\n"
" <arg name=\"service_name\" direction=\"in\" type=\"s\"/>\n"
" </method>\n"
+ " <method name=\"StopConversation\">\n"
+ " <arg name=\"service_name\" direction=\"in\" type=\"s\"/>\n"
+ " </method>\n"
" <method name=\"BeginVerification\">\n"
+ " <arg name=\"service_name\" direction=\"in\" type=\"s\"/>\n"
" </method>\n"
" <method name=\"BeginTimedLogin\">\n"
" </method>\n"
" <method name=\"BeginVerificationForUser\">\n"
+ " <arg name=\"service_name\" direction=\"in\" type=\"s\"/>\n"
" <arg name=\"username\" direction=\"in\" type=\"s\"/>\n"
" </method>\n"
" <method name=\"AnswerQuery\">\n"
+ " <arg name=\"service_name\" direction=\"in\" type=\"s\"/>\n"
" <arg name=\"text\" direction=\"in\" type=\"s\"/>\n"
" </method>\n"
" <method name=\"SelectSession\">\n"
@@ -772,18 +849,23 @@ do_introspect (DBusConnection *connection,
" <arg name=\"id\" direction=\"out\" type=\"o\"/>\n"
" </method>\n"
" <method name=\"StartSessionWhenReady\">\n"
+ " <arg name=\"service_name\" direction=\"in\" type=\"s\"/>\n"
" <arg name=\"should_start_session\" type=\"b\"/>\n"
" </method>\n"
" <signal name=\"Info\">\n"
+ " <arg name=\"service_name\" direction=\"in\" type=\"s\"/>\n"
" <arg name=\"text\" type=\"s\"/>\n"
" </signal>\n"
" <signal name=\"Problem\">\n"
+ " <arg name=\"service_name\" direction=\"in\" type=\"s\"/>\n"
" <arg name=\"text\" type=\"s\"/>\n"
" </signal>\n"
" <signal name=\"InfoQuery\">\n"
+ " <arg name=\"service_name\" direction=\"in\" type=\"s\"/>\n"
" <arg name=\"text\" type=\"s\"/>\n"
" </signal>\n"
" <signal name=\"SecretInfoQuery\">\n"
+ " <arg name=\"service_name\" direction=\"in\" type=\"s\"/>\n"
" <arg name=\"text\" type=\"s\"/>\n"
" </signal>\n"
" <signal name=\"SelectedUserChanged\">\n"
@@ -805,11 +887,15 @@ do_introspect (DBusConnection *connection,
" <signal name=\"Ready\">\n"
" <arg name=\"service-name\" type=\"s\"/>\n"
" </signal>\n"
+ " <signal name=\"ConversationStopped\">\n"
+ " <arg name=\"service-name\" type=\"s\"/>\n"
+ " </signal>\n"
" <signal name=\"Reset\">\n"
" </signal>\n"
" <signal name=\"AuthenticationFailed\">\n"
" </signal>\n"
" <signal name=\"UserAuthorized\">\n"
+ " <arg name=\"service_name\" direction=\"in\" type=\"s\"/>\n"
" </signal>\n"
" </interface>\n");
@@ -1185,9 +1271,9 @@ gdm_greeter_server_class_init (GdmGreeterServerClass *klass)
G_STRUCT_OFFSET (GdmGreeterServerClass, begin_verification),
NULL,
NULL,
- g_cclosure_marshal_VOID__VOID,
+ g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE,
- 0);
+ 1, G_TYPE_STRING);
signals [BEGIN_AUTO_LOGIN] =
g_signal_new ("begin-auto-login",
G_OBJECT_CLASS_TYPE (object_class),
@@ -1206,10 +1292,10 @@ gdm_greeter_server_class_init (GdmGreeterServerClass *klass)
G_STRUCT_OFFSET (GdmGreeterServerClass, begin_verification_for_user),
NULL,
NULL,
- g_cclosure_marshal_VOID__STRING,
+ gdm_marshal_VOID__STRING_STRING,
G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
+ 2,
+ G_TYPE_STRING, G_TYPE_STRING);
signals [QUERY_ANSWER] =
g_signal_new ("query-answer",
G_OBJECT_CLASS_TYPE (object_class),
@@ -1217,10 +1303,10 @@ gdm_greeter_server_class_init (GdmGreeterServerClass *klass)
G_STRUCT_OFFSET (GdmGreeterServerClass, query_answer),
NULL,
NULL,
- g_cclosure_marshal_VOID__STRING,
+ gdm_marshal_VOID__STRING_STRING,
G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
+ 2,
+ G_TYPE_STRING, G_TYPE_STRING);
signals [SESSION_SELECTED] =
g_signal_new ("session-selected",
G_OBJECT_CLASS_TYPE (object_class),
@@ -1314,9 +1400,9 @@ gdm_greeter_server_class_init (GdmGreeterServerClass *klass)
G_STRUCT_OFFSET (GdmGreeterServerClass, start_session_when_ready),
NULL,
NULL,
- g_cclosure_marshal_VOID__VOID,
+ g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE,
- 0);
+ 1, G_TYPE_STRING);
signals [START_SESSION_LATER] =
g_signal_new ("start-session-later",
@@ -1325,9 +1411,9 @@ gdm_greeter_server_class_init (GdmGreeterServerClass *klass)
G_STRUCT_OFFSET (GdmGreeterServerClass, start_session_later),
NULL,
NULL,
- g_cclosure_marshal_VOID__VOID,
+ g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE,
- 0);
+ 1, G_TYPE_STRING);
}
static void
diff --git a/daemon/gdm-greeter-server.h b/daemon/gdm-greeter-server.h
index 7e2424a..5af32fd 100644
--- a/daemon/gdm-greeter-server.h
+++ b/daemon/gdm-greeter-server.h
@@ -48,10 +48,13 @@ typedef struct
void (* start_conversation) (GdmGreeterServer *greeter_server,
const char *service_name);
void (* begin_auto_login) (GdmGreeterServer *greeter_server);
- void (* begin_verification) (GdmGreeterServer *greeter_server);
+ void (* begin_verification) (GdmGreeterServer *greeter_server,
+ const char *service_name);
void (* begin_verification_for_user)(GdmGreeterServer *greeter_server,
+ const char *service_name,
const char *username);
void (* query_answer) (GdmGreeterServer *greeter_server,
+ const char *service_name,
const char *text);
void (* session_selected) (GdmGreeterServer *greeter_server,
const char *name);
@@ -66,7 +69,8 @@ typedef struct
void (* cancelled) (GdmGreeterServer *greeter_server);
void (* connected) (GdmGreeterServer *greeter_server);
void (* disconnected) (GdmGreeterServer *greeter_server);
- void (* start_session_when_ready) (GdmGreeterServer *greeter_server);
+ void (* start_session_when_ready) (GdmGreeterServer *greeter_server,
+ const char *service_name);
void (* start_session_later) (GdmGreeterServer *greeter_server);
} GdmGreeterServerClass;
@@ -77,19 +81,24 @@ gboolean gdm_greeter_server_start (GdmGreeterServer *
gboolean gdm_greeter_server_stop (GdmGreeterServer *greeter_server);
char * gdm_greeter_server_get_address (GdmGreeterServer *greeter_server);
-
gboolean gdm_greeter_server_info_query (GdmGreeterServer *greeter_server,
+ const char *service_name,
const char *text);
gboolean gdm_greeter_server_secret_info_query (GdmGreeterServer *greeter_server,
+ const char *service_name,
const char *text);
gboolean gdm_greeter_server_info (GdmGreeterServer *greeter_server,
+ const char *service_name,
const char *text);
gboolean gdm_greeter_server_problem (GdmGreeterServer *greeter_server,
+ const char *service_name,
const char *text);
gboolean gdm_greeter_server_authentication_failed (GdmGreeterServer *greeter_server);
gboolean gdm_greeter_server_reset (GdmGreeterServer *greeter_server);
gboolean gdm_greeter_server_ready (GdmGreeterServer *greeter_server,
const char *service_name);
+gboolean gdm_greeter_server_conversation_stopped (GdmGreeterServer *greeter_server,
+ const char *service_name);
void gdm_greeter_server_selected_user_changed (GdmGreeterServer *greeter_server,
const char *text);
void gdm_greeter_server_default_language_name_changed (GdmGreeterServer *greeter_server,
@@ -102,8 +111,8 @@ void gdm_greeter_server_default_session_name_changed (GdmGreeterS
void gdm_greeter_server_request_timed_login (GdmGreeterServer *greeter_server,
const char *username,
int delay);
-void gdm_greeter_server_user_authorized (GdmGreeterServer *greeter_server);
-
+void gdm_greeter_server_user_authorized (GdmGreeterServer *greeter_server,
+ const char *service_name);
G_END_DECLS
diff --git a/daemon/gdm-product-slave.c b/daemon/gdm-product-slave.c
index 9be89b4..607bbc6 100644
--- a/daemon/gdm-product-slave.c
+++ b/daemon/gdm-product-slave.c
@@ -79,6 +79,8 @@ struct GdmProductSlavePrivate
DBusGProxy *product_display_proxy;
DBusGConnection *connection;
+
+ char *start_session_service_name;
};
enum {
@@ -93,6 +95,68 @@ static void gdm_product_slave_finalize (GObject *object);
G_DEFINE_TYPE (GdmProductSlave, gdm_product_slave, GDM_TYPE_SLAVE)
static gboolean
+send_dbus_string_string_method (DBusConnection *connection,
+ const char *method,
+ const char *payload1,
+ const char *payload2)
+{
+ DBusError error;
+ DBusMessage *message;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ const char *str;
+
+ g_debug ("GdmProductSlave: Calling %s", method);
+ message = dbus_message_new_method_call (NULL,
+ RELAY_SERVER_DBUS_PATH,
+ RELAY_SERVER_DBUS_INTERFACE,
+ method);
+ if (message == NULL) {
+ g_warning ("Couldn't allocate the D-Bus message");
+ return FALSE;
+ }
+
+ dbus_message_iter_init_append (message, &iter);
+
+ if (payload1 != NULL) {
+ str = payload1;
+ } else {
+ str = "";
+ }
+ dbus_message_iter_append_basic (&iter,
+ DBUS_TYPE_STRING,
+ &str);
+ if (payload2 != NULL) {
+ str = payload2;
+ } else {
+ str = "";
+ }
+ dbus_message_iter_append_basic (&iter,
+ DBUS_TYPE_STRING,
+ &str);
+ dbus_error_init (&error);
+ reply = dbus_connection_send_with_reply_and_block (connection,
+ message,
+ -1,
+ &error);
+
+ dbus_message_unref (message);
+
+ if (dbus_error_is_set (&error)) {
+ g_warning ("%s %s raised: %s\n",
+ method,
+ error.name,
+ error.message);
+ return FALSE;
+ }
+ if (reply != NULL) {
+ dbus_message_unref (reply);
+ }
+ dbus_connection_flush (connection);
+
+ return TRUE;
+}
+static gboolean
send_dbus_string_method (DBusConnection *connection,
const char *method,
const char *payload)
@@ -356,7 +420,8 @@ setup_session (GdmProductSlave *slave)
g_free (display_device);
g_free (auth_file);
- gdm_session_start_session (GDM_SESSION (slave->priv->session));
+ gdm_session_start_session (GDM_SESSION (slave->priv->session),
+ slave->priv->start_session_service_name);
return TRUE;
}
@@ -508,114 +573,133 @@ on_session_reset_failed (GdmSession *session,
static void
on_session_authenticated (GdmSession *session,
+ const char *service_name,
GdmProductSlave *slave)
{
- send_dbus_void_method (slave->priv->session_relay_connection,
- "Authenticated");
+ send_dbus_string_method (slave->priv->session_relay_connection,
+ "Authenticated", service_name);
}
static void
on_session_authentication_failed (GdmSession *session,
+ const char *service_name,
const char *message,
GdmProductSlave *slave)
{
- send_dbus_string_method (slave->priv->session_relay_connection,
- "AuthenticationFailed",
- message);
+ send_dbus_string_string_method (slave->priv->session_relay_connection,
+ "AuthenticationFailed",
+ service_name,
+ message);
}
static void
on_session_authorized (GdmSession *session,
+ const char *service_name,
GdmProductSlave *slave)
{
- send_dbus_void_method (slave->priv->session_relay_connection,
- "Authorized");
+ send_dbus_string_method (slave->priv->session_relay_connection,
+ "Authorized", service_name);
}
static void
on_session_authorization_failed (GdmSession *session,
+ const char *service_name,
const char *message,
GdmProductSlave *slave)
{
- send_dbus_string_method (slave->priv->session_relay_connection,
- "AuthorizationFailed",
- message);
+ send_dbus_string_string_method (slave->priv->session_relay_connection,
+ "AuthorizationFailed",
+ service_name,
+ message);
}
static void
on_session_accredited (GdmSession *session,
+ const char *service_name,
GdmProductSlave *slave)
{
- send_dbus_void_method (slave->priv->session_relay_connection,
- "Accredited");
+ send_dbus_string_method (slave->priv->session_relay_connection,
+ "Accredited", service_name);
}
static void
on_session_accreditation_failed (GdmSession *session,
+ const char *service_name,
const char *message,
GdmProductSlave *slave)
{
- send_dbus_string_method (slave->priv->session_relay_connection,
- "AccreditationFailed",
- message);
+ send_dbus_string_string_method (slave->priv->session_relay_connection,
+ "AccreditationFailed",
+ service_name,
+ message);
}
static void
on_session_opened (GdmSession *session,
+ const char *service_name,
GdmProductSlave *slave)
{
- send_dbus_void_method (slave->priv->session_relay_connection,
- "SessionOpened");
+ send_dbus_string_method (slave->priv->session_relay_connection,
+ "SessionOpened", service_name);
}
static void
on_session_open_failed (GdmSession *session,
+ const char *service_name,
const char *message,
GdmProductSlave *slave)
{
- send_dbus_string_method (slave->priv->session_relay_connection,
- "SessionOpenFailed",
- message);
+ send_dbus_string_string_method (slave->priv->session_relay_connection,
+ "SessionOpenFailed",
+ service_name,
+ message);
}
static void
on_session_info (GdmSession *session,
+ const char *service_name,
const char *text,
GdmProductSlave *slave)
{
- send_dbus_string_method (slave->priv->session_relay_connection,
- "Info",
- text);
+ send_dbus_string_string_method (slave->priv->session_relay_connection,
+ "Info",
+ service_name,
+ text);
}
static void
on_session_problem (GdmSession *session,
+ const char *service_name,
const char *text,
GdmProductSlave *slave)
{
- send_dbus_string_method (slave->priv->session_relay_connection,
- "Problem",
- text);
+ send_dbus_string_string_method (slave->priv->session_relay_connection,
+ "Problem",
+ service_name,
+ text);
}
static void
on_session_info_query (GdmSession *session,
+ const char *service_name,
const char *text,
GdmProductSlave *slave)
{
- send_dbus_string_method (slave->priv->session_relay_connection,
- "InfoQuery",
- text);
+ send_dbus_string_string_method (slave->priv->session_relay_connection,
+ "InfoQuery",
+ service_name, text);
}
static void
on_session_secret_info_query (GdmSession *session,
+ const char *service_name,
const char *text,
GdmProductSlave *slave)
{
- send_dbus_string_method (slave->priv->session_relay_connection,
- "SecretInfoQuery",
- text);
+ send_dbus_string_string_method (slave->priv->session_relay_connection,
+ "SecretInfoQuery",
+ service_name,
+ text);
}
static void
@@ -676,36 +760,92 @@ static void
on_relay_authenticate (GdmProductSlave *slave,
DBusMessage *message)
{
- g_debug ("GdmProductSlave: Relay Authenticate");
+ DBusError error;
+ char *service_name;
+ dbus_bool_t res;
- gdm_session_authenticate (GDM_SESSION (slave->priv->session));
+ dbus_error_init (&error);
+ res = dbus_message_get_args (message,
+ &error,
+ DBUS_TYPE_STRING, &service_name,
+ DBUS_TYPE_INVALID);
+ if (res) {
+ g_debug ("GdmProductSlave: Relay Authenticate");
+ gdm_session_authenticate (GDM_SESSION (slave->priv->session), service_name);
+ } else {
+ g_warning ("Unable to get arguments: %s", error.message);
+ dbus_error_free (&error);
+ }
+ dbus_error_free (&error);
}
static void
on_relay_authorize (GdmProductSlave *slave,
DBusMessage *message)
{
- g_debug ("GdmProductSlave: Relay Authorize");
+ DBusError error;
+ char *service_name;
+ dbus_bool_t res;
- gdm_session_authorize (GDM_SESSION (slave->priv->session));
+ dbus_error_init (&error);
+ res = dbus_message_get_args (message,
+ &error,
+ DBUS_TYPE_STRING, &service_name,
+ DBUS_TYPE_INVALID);
+ if (res) {
+ g_debug ("GdmProductSlave: Relay Authorize");
+ gdm_session_authorize (GDM_SESSION (slave->priv->session), service_name);
+ } else {
+ g_warning ("Unable to get arguments: %s", error.message);
+ dbus_error_free (&error);
+ }
+ dbus_error_free (&error);
}
static void
on_relay_establish_credentials (GdmProductSlave *slave,
DBusMessage *message)
{
- g_debug ("GdmProductSlave: Relay EstablishCredentials");
+ DBusError error;
+ char *service_name;
+ dbus_bool_t res;
- gdm_session_accredit (GDM_SESSION (slave->priv->session), GDM_SESSION_CRED_ESTABLISH);
+ dbus_error_init (&error);
+ res = dbus_message_get_args (message,
+ &error,
+ DBUS_TYPE_STRING, &service_name,
+ DBUS_TYPE_INVALID);
+ if (res) {
+ g_debug ("GdmProductSlave: Relay EstablishCredentials");
+ gdm_session_accredit (GDM_SESSION (slave->priv->session), service_name, GDM_SESSION_CRED_ESTABLISH);
+ } else {
+ g_warning ("Unable to get arguments: %s", error.message);
+ dbus_error_free (&error);
+ }
+ dbus_error_free (&error);
}
static void
on_relay_refresh_credentials (GdmProductSlave *slave,
DBusMessage *message)
{
- g_debug ("GdmProductSlave: Relay RefreshCredentials");
+ DBusError error;
+ char *service_name;
+ dbus_bool_t res;
- gdm_session_accredit (GDM_SESSION (slave->priv->session), GDM_SESSION_CRED_REFRESH);
+ dbus_error_init (&error);
+ res = dbus_message_get_args (message,
+ &error,
+ DBUS_TYPE_STRING, &service_name,
+ DBUS_TYPE_INVALID);
+ if (res) {
+ g_debug ("GdmProductSlave: Relay RefreshCredentials");
+ gdm_session_accredit (GDM_SESSION (slave->priv->session), service_name, GDM_SESSION_CRED_REFRESH);
+ } else {
+ g_warning ("Unable to get arguments: %s", error.message);
+ dbus_error_free (&error);
+ }
+ dbus_error_free (&error);
}
static void
@@ -714,16 +854,18 @@ on_relay_answer_query (GdmProductSlave *slave,
{
DBusError error;
const char *text;
+ const char *service_name;
dbus_bool_t res;
dbus_error_init (&error);
res = dbus_message_get_args (message,
&error,
+ DBUS_TYPE_STRING, &service_name,
DBUS_TYPE_STRING, &text,
DBUS_TYPE_INVALID);
if (res) {
g_debug ("GdmProductSlave: Relay AnswerQuery");
- gdm_session_answer_query (GDM_SESSION (slave->priv->session), text);
+ gdm_session_answer_query (GDM_SESSION (slave->priv->session), service_name, text);
} else {
g_warning ("Unable to get arguments: %s", error.message);
dbus_error_free (&error);
@@ -831,14 +973,48 @@ static void
on_relay_open_session (GdmProductSlave *slave,
DBusMessage *message)
{
- gdm_session_open_session (GDM_SESSION (slave->priv->session));
+ DBusError error;
+ const char *text;
+ dbus_bool_t res;
+
+ dbus_error_init (&error);
+ res = dbus_message_get_args (message,
+ &error,
+ DBUS_TYPE_STRING, &text,
+ DBUS_TYPE_INVALID);
+ if (res) {
+ g_debug ("GdmProductSlave: open session %s", text);
+ gdm_session_open_session (GDM_SESSION (slave->priv->session),
+ text);
+ } else {
+ g_warning ("Unable to get arguments: %s", error.message);
+ dbus_error_free (&error);
+ }
}
static void
on_relay_start_session (GdmProductSlave *slave,
DBusMessage *message)
{
- gdm_product_slave_create_server (slave);
+ DBusError error;
+ const char *service_name;
+ dbus_bool_t res;
+
+ dbus_error_init (&error);
+
+ res = dbus_message_get_args (message,
+ &error,
+ DBUS_TYPE_STRING, &service_name,
+ DBUS_TYPE_INVALID);
+ if (res) {
+ g_debug ("GdmProductSlave: Relay StartSession");
+ g_free (slave->priv->start_session_service_name);
+ slave->priv->start_session_service_name = g_strdup (service_name);
+ gdm_product_slave_create_server (slave);
+ } else {
+ g_warning ("Unable to get arguments: %s", error.message);
+ dbus_error_free (&error);
+ }
}
static void
diff --git a/daemon/gdm-session-direct.c b/daemon/gdm-session-direct.c
index cfbaa15..13c8974 100644
--- a/daemon/gdm-session-direct.c
+++ b/daemon/gdm-session-direct.c
@@ -89,9 +89,10 @@ struct _GdmSessionDirectPrivate
char *selected_user;
char *user_x11_authority_file;
- GdmSessionConversation *conversation;
+ GHashTable *conversations;
+
+ GList *pending_connections;
- GdmSessionWorkerJob *job;
GPid session_pid;
guint32 is_running : 1;
@@ -200,14 +201,30 @@ send_dbus_void_signal (GdmSessionConversation *conversation,
dbus_message_unref (message);
}
+static GdmSessionConversation *
+find_conversation_by_name (GdmSessionDirect *session,
+ const char *service_name)
+{
+ GdmSessionConversation *conversation;
+
+ conversation = g_hash_table_lookup (session->priv->conversations, service_name);
+
+ if (conversation == NULL) {
+ g_warning ("Tried to look up non-existant conversation");
+ }
+
+ return conversation;
+}
+
static void
on_authentication_failed (GdmSession *session,
+ const char *service_name,
const char *message)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
GdmSessionConversation *conversation;
- conversation = impl->priv->conversation;
+ conversation = find_conversation_by_name (impl, service_name);
if (conversation != NULL) {
gdm_session_record_failed (conversation->worker_pid,
impl->priv->selected_user,
@@ -218,12 +235,13 @@ on_authentication_failed (GdmSession *session,
}
static void
-on_session_started (GdmSession *session)
+on_session_started (GdmSession *session,
+ const char *service_name)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
GdmSessionConversation *conversation;
- conversation = impl->priv->conversation;
+ conversation = find_conversation_by_name (impl, service_name);
if (conversation != NULL) {
gdm_session_record_login (conversation->worker_pid,
impl->priv->selected_user,
@@ -235,12 +253,13 @@ on_session_started (GdmSession *session)
static void
on_session_start_failed (GdmSession *session,
+ const char *service_name,
const char *message)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
GdmSessionConversation *conversation;
- conversation = impl->priv->conversation;
+ conversation = find_conversation_by_name (impl, service_name);
if (conversation != NULL) {
gdm_session_record_login (conversation->worker_pid,
impl->priv->selected_user,
@@ -265,7 +284,7 @@ on_session_exited (GdmSession *session,
static DBusHandlerResult
gdm_session_direct_handle_setup_complete (GdmSessionDirect *session,
- DBusConnection *connection,
+ GdmSessionConversation *conversation,
DBusMessage *message)
{
DBusMessage *reply;
@@ -273,17 +292,17 @@ gdm_session_direct_handle_setup_complete (GdmSessionDirect *session,
g_debug ("GdmSessionDirect: Emitting 'setup-complete' signal");
reply = dbus_message_new_method_return (message);
- dbus_connection_send (connection, reply, NULL);
+ dbus_connection_send (conversation->worker_connection, reply, NULL);
dbus_message_unref (reply);
- _gdm_session_setup_complete (GDM_SESSION (session));
+ _gdm_session_setup_complete (GDM_SESSION (session), conversation->service_name);
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult
gdm_session_direct_handle_setup_failed (GdmSessionDirect *session,
- DBusConnection *connection,
+ GdmSessionConversation *conversation,
DBusMessage *message)
{
DBusMessage *reply;
@@ -298,12 +317,12 @@ gdm_session_direct_handle_setup_failed (GdmSessionDirect *session,
}
reply = dbus_message_new_method_return (message);
- dbus_connection_send (connection, reply, NULL);
+ dbus_connection_send (conversation->worker_connection, reply, NULL);
dbus_message_unref (reply);
g_debug ("GdmSessionDirect: Emitting 'setup-failed' signal");
- _gdm_session_setup_failed (GDM_SESSION (session), text);
+ _gdm_session_setup_failed (GDM_SESSION (session), conversation->service_name, text);
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -311,7 +330,7 @@ gdm_session_direct_handle_setup_failed (GdmSessionDirect *session,
static DBusHandlerResult
gdm_session_direct_handle_reset_complete (GdmSessionDirect *session,
- DBusConnection *connection,
+ GdmSessionConversation *conversation,
DBusMessage *message)
{
DBusMessage *reply;
@@ -319,7 +338,7 @@ gdm_session_direct_handle_reset_complete (GdmSessionDirect *session,
g_debug ("GdmSessionDirect: Emitting 'reset-complete' signal");
reply = dbus_message_new_method_return (message);
- dbus_connection_send (connection, reply, NULL);
+ dbus_connection_send (conversation->worker_connection, reply, NULL);
dbus_message_unref (reply);
_gdm_session_reset_complete (GDM_SESSION (session));
@@ -329,7 +348,7 @@ gdm_session_direct_handle_reset_complete (GdmSessionDirect *session,
static DBusHandlerResult
gdm_session_direct_handle_reset_failed (GdmSessionDirect *session,
- DBusConnection *connection,
+ GdmSessionConversation *conversation,
DBusMessage *message)
{
DBusMessage *reply;
@@ -344,7 +363,7 @@ gdm_session_direct_handle_reset_failed (GdmSessionDirect *session,
}
reply = dbus_message_new_method_return (message);
- dbus_connection_send (connection, reply, NULL);
+ dbus_connection_send (conversation->worker_connection, reply, NULL);
dbus_message_unref (reply);
g_debug ("GdmSessionDirect: Emitting 'reset-failed' signal");
@@ -356,7 +375,7 @@ gdm_session_direct_handle_reset_failed (GdmSessionDirect *session,
static DBusHandlerResult
gdm_session_direct_handle_authenticated (GdmSessionDirect *session,
- DBusConnection *connection,
+ GdmSessionConversation *conversation,
DBusMessage *message)
{
DBusMessage *reply;
@@ -364,17 +383,17 @@ gdm_session_direct_handle_authenticated (GdmSessionDirect *session,
g_debug ("GdmSessionDirect: Emitting 'authenticated' signal");
reply = dbus_message_new_method_return (message);
- dbus_connection_send (connection, reply, NULL);
+ dbus_connection_send (conversation->worker_connection, reply, NULL);
dbus_message_unref (reply);
- _gdm_session_authenticated (GDM_SESSION (session));
+ _gdm_session_authenticated (GDM_SESSION (session), conversation->service_name);
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult
gdm_session_direct_handle_authentication_failed (GdmSessionDirect *session,
- DBusConnection *connection,
+ GdmSessionConversation *conversation,
DBusMessage *message)
{
DBusMessage *reply;
@@ -389,19 +408,19 @@ gdm_session_direct_handle_authentication_failed (GdmSessionDirect *session,
}
reply = dbus_message_new_method_return (message);
- dbus_connection_send (connection, reply, NULL);
+ dbus_connection_send (conversation->worker_connection, reply, NULL);
dbus_message_unref (reply);
g_debug ("GdmSessionDirect: Emitting 'authentication-failed' signal");
- _gdm_session_authentication_failed (GDM_SESSION (session), text);
+ _gdm_session_authentication_failed (GDM_SESSION (session), conversation->service_name, text);
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult
gdm_session_direct_handle_authorized (GdmSessionDirect *session,
- DBusConnection *connection,
+ GdmSessionConversation *conversation,
DBusMessage *message)
{
DBusMessage *reply;
@@ -409,17 +428,17 @@ gdm_session_direct_handle_authorized (GdmSessionDirect *session,
g_debug ("GdmSessionDirect: Emitting 'authorized' signal");
reply = dbus_message_new_method_return (message);
- dbus_connection_send (connection, reply, NULL);
+ dbus_connection_send (conversation->worker_connection, reply, NULL);
dbus_message_unref (reply);
- _gdm_session_authorized (GDM_SESSION (session));
+ _gdm_session_authorized (GDM_SESSION (session), conversation->service_name);
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult
gdm_session_direct_handle_authorization_failed (GdmSessionDirect *session,
- DBusConnection *connection,
+ GdmSessionConversation *conversation,
DBusMessage *message)
{
DBusMessage *reply;
@@ -434,19 +453,19 @@ gdm_session_direct_handle_authorization_failed (GdmSessionDirect *session,
}
reply = dbus_message_new_method_return (message);
- dbus_connection_send (connection, reply, NULL);
+ dbus_connection_send (conversation->worker_connection, reply, NULL);
dbus_message_unref (reply);
g_debug ("GdmSessionDirect: Emitting 'authorization-failed' signal");
- _gdm_session_authorization_failed (GDM_SESSION (session), text);
+ _gdm_session_authorization_failed (GDM_SESSION (session), conversation->service_name, text);
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult
gdm_session_direct_handle_accredited (GdmSessionDirect *session,
- DBusConnection *connection,
+ GdmSessionConversation *conversation,
DBusMessage *message)
{
DBusMessage *reply;
@@ -454,17 +473,17 @@ gdm_session_direct_handle_accredited (GdmSessionDirect *session,
g_debug ("GdmSessionDirect: Emitting 'accredited' signal");
reply = dbus_message_new_method_return (message);
- dbus_connection_send (connection, reply, NULL);
+ dbus_connection_send (conversation->worker_connection, reply, NULL);
dbus_message_unref (reply);
- _gdm_session_accredited (GDM_SESSION (session));
+ _gdm_session_accredited (GDM_SESSION (session), conversation->service_name);
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult
gdm_session_direct_handle_accreditation_failed (GdmSessionDirect *session,
- DBusConnection *connection,
+ GdmSessionConversation *conversation,
DBusMessage *message)
{
DBusMessage *reply;
@@ -479,12 +498,12 @@ gdm_session_direct_handle_accreditation_failed (GdmSessionDirect *session,
}
reply = dbus_message_new_method_return (message);
- dbus_connection_send (connection, reply, NULL);
+ dbus_connection_send (conversation->worker_connection, reply, NULL);
dbus_message_unref (reply);
g_debug ("GdmSessionDirect: Emitting 'accreditation-failed' signal");
- _gdm_session_accreditation_failed (GDM_SESSION (session), text);
+ _gdm_session_accreditation_failed (GDM_SESSION (session), conversation->service_name, text);
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -808,7 +827,7 @@ gdm_session_direct_select_user (GdmSession *session,
static DBusHandlerResult
gdm_session_direct_handle_username_changed (GdmSessionDirect *session,
- DBusConnection *connection,
+ GdmSessionConversation *conversation,
DBusMessage *message)
{
DBusMessage *reply;
@@ -823,7 +842,7 @@ gdm_session_direct_handle_username_changed (GdmSessionDirect *session,
}
reply = dbus_message_new_method_return (message);
- dbus_connection_send (connection, reply, NULL);
+ dbus_connection_send (conversation->worker_connection, reply, NULL);
dbus_message_unref (reply);
g_debug ("GdmSessionDirect: changing username from '%s' to '%s'",
@@ -890,14 +909,11 @@ set_pending_query (GdmSessionConversation *conversation,
static DBusHandlerResult
gdm_session_direct_handle_info_query (GdmSessionDirect *session,
- DBusConnection *connection,
+ GdmSessionConversation *conversation,
DBusMessage *message)
{
DBusError error;
const char *text;
- GdmSessionConversation *conversation;
-
- conversation = session->priv->conversation;
dbus_error_init (&error);
if (! dbus_message_get_args (message, &error,
@@ -909,21 +925,18 @@ gdm_session_direct_handle_info_query (GdmSessionDirect *session,
set_pending_query (conversation, message);
g_debug ("GdmSessionDirect: Emitting 'info-query' signal");
- _gdm_session_info_query (GDM_SESSION (session), text);
+ _gdm_session_info_query (GDM_SESSION (session), conversation->service_name, text);
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult
gdm_session_direct_handle_secret_info_query (GdmSessionDirect *session,
- DBusConnection *connection,
+ GdmSessionConversation *conversation,
DBusMessage *message)
{
DBusError error;
const char *text;
- GdmSessionConversation *conversation;
-
- conversation = session->priv->conversation;
dbus_error_init (&error);
if (! dbus_message_get_args (message, &error,
@@ -935,14 +948,14 @@ gdm_session_direct_handle_secret_info_query (GdmSessionDirect *session,
set_pending_query (conversation, message);
g_debug ("GdmSessionDirect: Emitting 'secret-info-query' signal");
- _gdm_session_secret_info_query (GDM_SESSION (session), text);
+ _gdm_session_secret_info_query (GDM_SESSION (session), conversation->service_name, text);
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult
gdm_session_direct_handle_info (GdmSessionDirect *session,
- DBusConnection *connection,
+ GdmSessionConversation *conversation,
DBusMessage *message)
{
DBusMessage *reply;
@@ -957,31 +970,28 @@ gdm_session_direct_handle_info (GdmSessionDirect *session,
}
reply = dbus_message_new_method_return (message);
- dbus_connection_send (connection, reply, NULL);
+ dbus_connection_send (conversation->worker_connection, reply, NULL);
dbus_message_unref (reply);
g_debug ("GdmSessionDirect: Emitting 'info' signal");
- _gdm_session_info (GDM_SESSION (session), text);
+ _gdm_session_info (GDM_SESSION (session), conversation->service_name, text);
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult
gdm_session_direct_handle_cancel_pending_query (GdmSessionDirect *session,
- DBusConnection *connection,
+ GdmSessionConversation *conversation,
DBusMessage *message)
{
DBusMessage *reply;
- GdmSessionConversation *conversation;
g_debug ("GdmSessionDirect: worker cancelling pending query");
- conversation = session->priv->conversation;
-
cancel_pending_query (conversation);
reply = dbus_message_new_method_return (message);
- dbus_connection_send (connection, reply, NULL);
+ dbus_connection_send (conversation->worker_connection, reply, NULL);
dbus_message_unref (reply);
return DBUS_HANDLER_RESULT_HANDLED;
@@ -989,7 +999,7 @@ gdm_session_direct_handle_cancel_pending_query (GdmSessionDirect *session,
static DBusHandlerResult
gdm_session_direct_handle_problem (GdmSessionDirect *session,
- DBusConnection *connection,
+ GdmSessionConversation *conversation,
DBusMessage *message)
{
DBusMessage *reply;
@@ -1004,18 +1014,18 @@ gdm_session_direct_handle_problem (GdmSessionDirect *session,
}
reply = dbus_message_new_method_return (message);
- dbus_connection_send (connection, reply, NULL);
+ dbus_connection_send (conversation->worker_connection, reply, NULL);
dbus_message_unref (reply);
g_debug ("GdmSessionDirect: Emitting 'problem' signal");
- _gdm_session_problem (GDM_SESSION (session), text);
+ _gdm_session_problem (GDM_SESSION (session), conversation->service_name, text);
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult
gdm_session_direct_handle_session_opened (GdmSessionDirect *session,
- DBusConnection *connection,
+ GdmSessionConversation *conversation,
DBusMessage *message)
{
DBusMessage *reply;
@@ -1030,10 +1040,10 @@ gdm_session_direct_handle_session_opened (GdmSessionDirect *session,
g_debug ("GdmSessionDirect: Emitting 'session-opened' signal");
- _gdm_session_session_opened (GDM_SESSION (session));
+ _gdm_session_session_opened (GDM_SESSION (session), conversation->service_name);
reply = dbus_message_new_method_return (message);
- dbus_connection_send (connection, reply, NULL);
+ dbus_connection_send (conversation->worker_connection, reply, NULL);
dbus_message_unref (reply);
return DBUS_HANDLER_RESULT_HANDLED;
@@ -1041,7 +1051,7 @@ gdm_session_direct_handle_session_opened (GdmSessionDirect *session,
static DBusHandlerResult
gdm_session_direct_handle_open_failed (GdmSessionDirect *session,
- DBusConnection *connection,
+ GdmSessionConversation *conversation,
DBusMessage *message)
{
DBusMessage *reply;
@@ -1056,18 +1066,18 @@ gdm_session_direct_handle_open_failed (GdmSessionDirect *session,
}
reply = dbus_message_new_method_return (message);
- dbus_connection_send (connection, reply, NULL);
+ dbus_connection_send (conversation->worker_connection, reply, NULL);
dbus_message_unref (reply);
g_debug ("GdmSessionDirect: Emitting 'session-open-failed' signal");
- _gdm_session_session_open_failed (GDM_SESSION (session), text);
+ _gdm_session_session_open_failed (GDM_SESSION (session), conversation->service_name, text);
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult
gdm_session_direct_handle_session_started (GdmSessionDirect *session,
- DBusConnection *connection,
+ GdmSessionConversation *conversation,
DBusMessage *message)
{
DBusMessage *reply;
@@ -1086,7 +1096,7 @@ gdm_session_direct_handle_session_started (GdmSessionDirect *session,
}
reply = dbus_message_new_method_return (message);
- dbus_connection_send (connection, reply, NULL);
+ dbus_connection_send (conversation->worker_connection, reply, NULL);
dbus_message_unref (reply);
g_debug ("GdmSessionDirect: Emitting 'session-started' signal with pid '%d'",
@@ -1095,14 +1105,14 @@ gdm_session_direct_handle_session_started (GdmSessionDirect *session,
session->priv->session_pid = pid;
session->priv->is_running = TRUE;
- _gdm_session_session_started (GDM_SESSION (session), pid);
+ _gdm_session_session_started (GDM_SESSION (session), conversation->service_name, pid);
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult
gdm_session_direct_handle_start_failed (GdmSessionDirect *session,
- DBusConnection *connection,
+ GdmSessionConversation *conversation,
DBusMessage *message)
{
DBusMessage *reply;
@@ -1117,18 +1127,18 @@ gdm_session_direct_handle_start_failed (GdmSessionDirect *session,
}
reply = dbus_message_new_method_return (message);
- dbus_connection_send (connection, reply, NULL);
+ dbus_connection_send (conversation->worker_connection, reply, NULL);
dbus_message_unref (reply);
g_debug ("GdmSessionDirect: Emitting 'session-start-failed' signal");
- _gdm_session_session_start_failed (GDM_SESSION (session), text);
+ _gdm_session_session_start_failed (GDM_SESSION (session), conversation->service_name, text);
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult
gdm_session_direct_handle_session_exited (GdmSessionDirect *session,
- DBusConnection *connection,
+ GdmSessionConversation *conversation,
DBusMessage *message)
{
DBusMessage *reply;
@@ -1143,7 +1153,7 @@ gdm_session_direct_handle_session_exited (GdmSessionDirect *session,
}
reply = dbus_message_new_method_return (message);
- dbus_connection_send (connection, reply, NULL);
+ dbus_connection_send (conversation->worker_connection, reply, NULL);
dbus_message_unref (reply);
g_debug ("GdmSessionDirect: Emitting 'session-exited' signal with exit code '%d'",
@@ -1157,7 +1167,7 @@ gdm_session_direct_handle_session_exited (GdmSessionDirect *session,
static DBusHandlerResult
gdm_session_direct_handle_session_died (GdmSessionDirect *session,
- DBusConnection *connection,
+ GdmSessionConversation *conversation,
DBusMessage *message)
{
DBusMessage *reply;
@@ -1172,7 +1182,7 @@ gdm_session_direct_handle_session_died (GdmSessionDirect *session,
}
reply = dbus_message_new_method_return (message);
- dbus_connection_send (connection, reply, NULL);
+ dbus_connection_send (conversation->worker_connection, reply, NULL);
dbus_message_unref (reply);
g_debug ("GdmSessionDirect: Emitting 'session-died' signal with signal number '%d'",
@@ -1186,7 +1196,7 @@ gdm_session_direct_handle_session_died (GdmSessionDirect *session,
static DBusHandlerResult
gdm_session_direct_handle_saved_language_name_read (GdmSessionDirect *session,
- DBusConnection *connection,
+ GdmSessionConversation *conversation,
DBusMessage *message)
{
DBusMessage *reply;
@@ -1201,7 +1211,7 @@ gdm_session_direct_handle_saved_language_name_read (GdmSessionDirect *session,
}
reply = dbus_message_new_method_return (message);
- dbus_connection_send (connection, reply, NULL);
+ dbus_connection_send (conversation->worker_connection, reply, NULL);
dbus_message_unref (reply);
if (strcmp (language_name,
@@ -1219,7 +1229,7 @@ gdm_session_direct_handle_saved_language_name_read (GdmSessionDirect *session,
static DBusHandlerResult
gdm_session_direct_handle_saved_layout_name_read (GdmSessionDirect *session,
- DBusConnection *connection,
+ GdmSessionConversation *conversation,
DBusMessage *message)
{
DBusMessage *reply;
@@ -1234,7 +1244,7 @@ gdm_session_direct_handle_saved_layout_name_read (GdmSessionDirect *session,
}
reply = dbus_message_new_method_return (message);
- dbus_connection_send (connection, reply, NULL);
+ dbus_connection_send (conversation->worker_connection, reply, NULL);
dbus_message_unref (reply);
if (strcmp (layout_name,
@@ -1252,7 +1262,7 @@ gdm_session_direct_handle_saved_layout_name_read (GdmSessionDirect *session,
static DBusHandlerResult
gdm_session_direct_handle_saved_session_name_read (GdmSessionDirect *session,
- DBusConnection *connection,
+ GdmSessionConversation *conversation,
DBusMessage *message)
{
DBusMessage *reply;
@@ -1267,7 +1277,7 @@ gdm_session_direct_handle_saved_session_name_read (GdmSessionDirect *session,
}
reply = dbus_message_new_method_return (message);
- dbus_connection_send (connection, reply, NULL);
+ dbus_connection_send (conversation->worker_connection, reply, NULL);
dbus_message_unref (reply);
if (! get_session_command_for_name (session_name, NULL)) {
@@ -1295,58 +1305,61 @@ session_worker_message (DBusConnection *connection,
DBusMessage *message,
void *user_data)
{
- GdmSessionDirect *session = GDM_SESSION_DIRECT (user_data);
+ GdmSessionConversation *conversation = user_data;
+ GdmSessionDirect *session;
+
+ session = conversation->session;
if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "InfoQuery")) {
- return gdm_session_direct_handle_info_query (session, connection, message);
+ return gdm_session_direct_handle_info_query (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SecretInfoQuery")) {
- return gdm_session_direct_handle_secret_info_query (session, connection, message);
+ return gdm_session_direct_handle_secret_info_query (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "Info")) {
- return gdm_session_direct_handle_info (session, connection, message);
+ return gdm_session_direct_handle_info (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "Problem")) {
- return gdm_session_direct_handle_problem (session, connection, message);
+ return gdm_session_direct_handle_problem (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "CancelPendingQuery")) {
- return gdm_session_direct_handle_cancel_pending_query (session, connection, message);
+ return gdm_session_direct_handle_cancel_pending_query (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SetupComplete")) {
- return gdm_session_direct_handle_setup_complete (session, connection, message);
+ return gdm_session_direct_handle_setup_complete (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SetupFailed")) {
- return gdm_session_direct_handle_setup_failed (session, connection, message);
+ return gdm_session_direct_handle_setup_failed (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "ResetComplete")) {
- return gdm_session_direct_handle_reset_complete (session, connection, message);
+ return gdm_session_direct_handle_reset_complete (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "ResetFailed")) {
- return gdm_session_direct_handle_reset_failed (session, connection, message);
+ return gdm_session_direct_handle_reset_failed (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "Authenticated")) {
- return gdm_session_direct_handle_authenticated (session, connection, message);
+ return gdm_session_direct_handle_authenticated (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "AuthenticationFailed")) {
- return gdm_session_direct_handle_authentication_failed (session, connection, message);
+ return gdm_session_direct_handle_authentication_failed (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "Authorized")) {
- return gdm_session_direct_handle_authorized (session, connection, message);
+ return gdm_session_direct_handle_authorized (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "AuthorizationFailed")) {
- return gdm_session_direct_handle_authorization_failed (session, connection, message);
+ return gdm_session_direct_handle_authorization_failed (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "Accredited")) {
- return gdm_session_direct_handle_accredited (session, connection, message);
+ return gdm_session_direct_handle_accredited (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "AccreditationFailed")) {
- return gdm_session_direct_handle_accreditation_failed (session, connection, message);
+ return gdm_session_direct_handle_accreditation_failed (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "UsernameChanged")) {
- return gdm_session_direct_handle_username_changed (session, connection, message);
+ return gdm_session_direct_handle_username_changed (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SessionOpened")) {
- return gdm_session_direct_handle_session_opened (session, connection, message);
+ return gdm_session_direct_handle_session_opened (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "OpenFailed")) {
- return gdm_session_direct_handle_open_failed (session, connection, message);
+ return gdm_session_direct_handle_open_failed (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SessionStarted")) {
- return gdm_session_direct_handle_session_started (session, connection, message);
+ return gdm_session_direct_handle_session_started (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "StartFailed")) {
- return gdm_session_direct_handle_start_failed (session, connection, message);
+ return gdm_session_direct_handle_start_failed (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SessionExited")) {
- return gdm_session_direct_handle_session_exited (session, connection, message);
+ return gdm_session_direct_handle_session_exited (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SessionDied")) {
- return gdm_session_direct_handle_session_died (session, connection, message);
+ return gdm_session_direct_handle_session_died (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SavedLanguageNameRead")) {
- return gdm_session_direct_handle_saved_language_name_read (session, connection, message);
+ return gdm_session_direct_handle_saved_language_name_read (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SavedLayoutNameRead")) {
- return gdm_session_direct_handle_saved_layout_name_read (session, connection, message);
+ return gdm_session_direct_handle_saved_layout_name_read (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SavedSessionNameRead")) {
- return gdm_session_direct_handle_saved_session_name_read (session, connection, message);
+ return gdm_session_direct_handle_saved_session_name_read (session, conversation, message);
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
@@ -1580,6 +1593,27 @@ session_unregister_handler (DBusConnection *connection,
g_debug ("session_unregister_handler");
}
+static GdmSessionConversation *
+find_conversation_by_pid (GdmSessionDirect *session,
+ GPid pid)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_hash_table_iter_init (&iter, session->priv->conversations);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ GdmSessionConversation *conversation;
+
+ conversation = (GdmSessionConversation *) value;
+
+ if (conversation->worker_pid == pid) {
+ return conversation;
+ }
+ }
+
+ return NULL;
+}
+
static dbus_bool_t
allow_user_function (DBusConnection *connection,
unsigned long uid,
@@ -1594,44 +1628,110 @@ allow_user_function (DBusConnection *connection,
return FALSE;
}
-static void
-handle_connection (DBusServer *server,
- DBusConnection *new_connection,
- void *user_data)
+static gboolean
+register_worker (GdmSessionDirect *session,
+ DBusConnection *connection)
{
- GdmSessionDirect *session = GDM_SESSION_DIRECT (user_data);
GdmSessionConversation *conversation;
+ DBusObjectPathVTable vtable = { &session_unregister_handler,
+ &session_message_handler,
+ NULL, NULL, NULL, NULL };
+ GList *connection_node;
+ gulong pid;
- g_debug ("GdmSessionDirect: Handing new connection");
+ g_debug ("GdmSessionDirect: Authenticating new connection");
- conversation = session->priv->conversation;
- if (conversation->worker_connection == NULL) {
- DBusObjectPathVTable vtable = { &session_unregister_handler,
- &session_message_handler,
- NULL, NULL, NULL, NULL
- };
+ connection_node = g_list_find (session->priv->pending_connections, connection);
- conversation->worker_connection = new_connection;
- dbus_connection_ref (new_connection);
- dbus_connection_setup_with_g_main (new_connection, NULL);
+ if (connection_node == NULL) {
+ g_debug ("GdmSessionDirect: Ignoring connection that we aren't tracking");
+ return FALSE;
+ }
- g_debug ("GdmSessionDirect: worker connection is %p", new_connection);
- dbus_connection_set_exit_on_disconnect (new_connection, FALSE);
+ session->priv->pending_connections =
+ g_list_delete_link (session->priv->pending_connections,
+ connection_node);
- dbus_connection_set_unix_user_function (new_connection,
- allow_user_function,
- session,
- NULL);
+ if (!dbus_connection_get_unix_process_id (connection, &pid)) {
+ g_warning ("GdmSessionDirect: Unable to read pid on new worker connection");
+ dbus_connection_unref (connection);
+ return FALSE;
+ }
- dbus_connection_register_object_path (new_connection,
- GDM_SESSION_DBUS_PATH,
- &vtable,
- session);
+ conversation = find_conversation_by_pid (session, (GPid) pid);
+
+ if (conversation == NULL) {
+ g_warning ("GdmSessionDirect: New worker connection is from unknown source");
+ dbus_connection_unref (connection);
+ return FALSE;
+ }
+
+ conversation->worker_connection = connection;
+
+ g_debug ("GdmSessionDirect: worker connection is %p", connection);
+
+ dbus_connection_register_object_path (connection,
+ GDM_SESSION_DBUS_PATH,
+ &vtable,
+ conversation);
+
+ g_debug ("GdmSessionDirect: Emitting conversation-started signal");
+ _gdm_session_conversation_started (GDM_SESSION (session),
+ conversation->service_name);
+
+ g_debug ("GdmSessionDirect: Conversation started");
+
+ return TRUE;
+}
+
+static DBusHandlerResult
+on_message (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ GdmSessionDirect *session = GDM_SESSION_DIRECT (user_data);
+
+ g_debug ("GdmSessionDirect: got message");
+
+ if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "Hello")) {
+ DBusMessage *reply;
+
+ if (register_worker (session, connection)) {
+ reply = dbus_message_new_method_return (message);
+ } else {
+ reply = dbus_message_new_error (message, DBUS_ERROR_FAILED, "");
+ }
- g_debug ("GdmSessionDirect: Emitting conversation-started signal");
- _gdm_session_conversation_started (GDM_SESSION (session),
- conversation->service_name);
+ dbus_connection_send (connection, reply, NULL);
+ return DBUS_HANDLER_RESULT_HANDLED;
}
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static void
+handle_connection (DBusServer *server,
+ DBusConnection *new_connection,
+ void *user_data)
+{
+ GdmSessionDirect *session = GDM_SESSION_DIRECT (user_data);
+ g_debug ("GdmSessionDirect: Handing new connection");
+
+ /* add to the list of pending connections. We won't be able to
+ * associate it with a specific worker conversation until we have
+ * authenticated the connection (from the Hello handler).
+ */
+ session->priv->pending_connections =
+ g_list_prepend (session->priv->pending_connections,
+ dbus_connection_ref (new_connection));
+ dbus_connection_setup_with_g_main (new_connection, NULL);
+ dbus_connection_set_exit_on_disconnect (new_connection, FALSE);
+
+ dbus_connection_set_unix_user_function (new_connection,
+ allow_user_function,
+ session,
+ NULL);
+ dbus_connection_add_filter (new_connection, on_message, session, NULL);
}
static gboolean
@@ -1677,6 +1777,17 @@ setup_server (GdmSessionDirect *session)
}
static void
+free_conversation (GdmSessionConversation *conversation)
+{
+ if (conversation->job != NULL) {
+ g_warning ("Freeing conversation with active job");
+ }
+
+ g_free (conversation->service_name);
+ g_free (conversation);
+}
+
+static void
gdm_session_direct_init (GdmSessionDirect *session)
{
session->priv = G_TYPE_INSTANCE_GET_PRIVATE (session,
@@ -1700,6 +1811,11 @@ gdm_session_direct_init (GdmSessionDirect *session)
G_CALLBACK (on_session_exited),
NULL);
+ session->priv->conversations = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify)
+ free_conversation);
session->priv->environment = g_hash_table_new_full (g_str_hash,
g_str_equal,
(GDestroyNotify) g_free,
@@ -1723,9 +1839,15 @@ worker_exited (GdmSessionWorkerJob *job,
{
g_debug ("GdmSessionDirect: Worker job exited: %d", code);
+ g_object_ref (conversation->job);
if (conversation->session->priv->is_running) {
_gdm_session_session_exited (GDM_SESSION (conversation->session), code);
}
+
+ g_debug ("GdmSessionDirect: Emitting conversation-stopped signal");
+ _gdm_session_conversation_stopped (GDM_SESSION (conversation->session),
+ conversation->service_name);
+ g_object_unref (conversation->job);
}
static void
@@ -1735,9 +1857,15 @@ worker_died (GdmSessionWorkerJob *job,
{
g_debug ("GdmSessionDirect: Worker job died: %d", signum);
+ g_object_ref (conversation->job);
if (conversation->session->priv->is_running) {
_gdm_session_session_died (GDM_SESSION (conversation->session), signum);
}
+
+ g_debug ("GdmSessionDirect: Emitting conversation-stopped signal");
+ _gdm_session_conversation_stopped (GDM_SESSION (conversation->session),
+ conversation->service_name);
+ g_object_unref (conversation->job);
}
static GdmSessionConversation *
@@ -1799,17 +1927,21 @@ stop_conversation (GdmSessionConversation *conversation)
G_CALLBACK (worker_died),
conversation);
- cancel_pending_query (conversation);
-
if (conversation->worker_connection != NULL) {
+ dbus_connection_remove_filter (conversation->worker_connection, on_message, session);
+
dbus_connection_close (conversation->worker_connection);
conversation->worker_connection = NULL;
}
gdm_session_worker_job_stop (conversation->job);
+
g_object_unref (conversation->job);
- g_free (conversation->service_name);
- g_free (conversation);
+ conversation->job = NULL;
+
+ g_debug ("GdmSessionDirect: Emitting conversation-stopped signal");
+ _gdm_session_conversation_stopped (GDM_SESSION (session),
+ conversation->service_name);
}
static void
@@ -1817,12 +1949,35 @@ gdm_session_direct_start_conversation (GdmSession *session,
const char *service_name)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
+ GdmSessionConversation *conversation;
g_return_if_fail (session != NULL);
g_debug ("GdmSessionDirect: starting conversation");
- impl->priv->conversation = start_conversation (impl, service_name);
+ conversation = start_conversation (impl, service_name);
+
+ g_hash_table_insert (impl->priv->conversations,
+ g_strdup (service_name), conversation);
+}
+
+static void
+gdm_session_direct_stop_conversation (GdmSession *session,
+ const char *service_name)
+{
+ GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
+ GdmSessionConversation *conversation;
+
+ g_return_if_fail (session != NULL);
+
+ g_debug ("GdmSessionDirect: stopping conversation");
+
+ conversation = find_conversation_by_name (impl, service_name);
+
+ if (conversation != NULL) {
+ stop_conversation (conversation);
+ g_hash_table_remove (impl->priv->conversations, service_name);
+ }
}
static void
@@ -1873,8 +2028,8 @@ send_setup (GdmSessionDirect *session,
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_hostname);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_x11_authority_file);
- conversation = session->priv->conversation;
- if (! send_dbus_message (conversation, message)) {
+ conversation = find_conversation_by_name (session, service_name);
+ if (conversation != NULL && ! send_dbus_message (conversation, message)) {
g_debug ("GdmSessionDirect: Could not send %s signal", "Setup");
}
@@ -1936,8 +2091,8 @@ send_setup_for_user (GdmSessionDirect *session,
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_x11_authority_file);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &selected_user);
- conversation = session->priv->conversation;
- if (! send_dbus_message (conversation, message)) {
+ conversation = find_conversation_by_name (session, service_name);
+ if (conversation != NULL && ! send_dbus_message (conversation, message)) {
g_debug ("GdmSessionDirect: Could not send %s signal", "SetupForUser");
}
@@ -1951,8 +2106,6 @@ gdm_session_direct_setup (GdmSession *session,
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
g_return_if_fail (session != NULL);
- g_return_if_fail (impl->priv->conversation != NULL);
- g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection));
send_setup (impl, service_name);
gdm_session_direct_defaults_changed (impl);
@@ -1966,8 +2119,6 @@ gdm_session_direct_setup_for_user (GdmSession *session,
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
g_return_if_fail (session != NULL);
- g_return_if_fail (impl->priv->conversation != NULL);
- g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection));
g_return_if_fail (username != NULL);
gdm_session_direct_select_user (session, username);
@@ -1977,45 +2128,50 @@ gdm_session_direct_setup_for_user (GdmSession *session,
}
static void
-gdm_session_direct_authenticate (GdmSession *session)
+gdm_session_direct_authenticate (GdmSession *session,
+ const char *service_name)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
GdmSessionConversation *conversation;
g_return_if_fail (session != NULL);
- g_return_if_fail (impl->priv->conversation != NULL);
- g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection));
- conversation = impl->priv->conversation;
- send_dbus_void_signal (conversation, "Authenticate");
+ conversation = find_conversation_by_name (impl, service_name);
+ if (conversation != NULL) {
+ send_dbus_void_signal (conversation, "Authenticate");
+ }
}
static void
-gdm_session_direct_authorize (GdmSession *session)
+gdm_session_direct_authorize (GdmSession *session,
+ const char *service_name)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
GdmSessionConversation *conversation;
g_return_if_fail (session != NULL);
- g_return_if_fail (impl->priv->conversation != NULL);
- g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection));
- conversation = impl->priv->conversation;
- send_dbus_void_signal (conversation, "Authorize");
+ conversation = find_conversation_by_name (impl, service_name);
+ if (conversation != NULL) {
+ send_dbus_void_signal (conversation, "Authorize");
+ }
}
static void
gdm_session_direct_accredit (GdmSession *session,
+ const char *service_name,
int cred_flag)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
GdmSessionConversation *conversation;
g_return_if_fail (session != NULL);
- g_return_if_fail (impl->priv->conversation != NULL);
- g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection));
- conversation = impl->priv->conversation;
+ conversation = find_conversation_by_name (impl, service_name);
+ if (conversation == NULL) {
+ return;
+ }
+
switch (cred_flag) {
case GDM_SESSION_CRED_ESTABLISH:
send_dbus_void_signal (conversation, "EstablishCredentials");
@@ -2029,13 +2185,12 @@ gdm_session_direct_accredit (GdmSession *session,
}
static void
-send_environment_variable (const char *key,
- const char *value,
- GdmSessionDirect *session)
+send_environment_variable (const char *key,
+ const char *value,
+ GdmSessionConversation *conversation)
{
DBusMessage *message;
DBusMessageIter iter;
- GdmSessionConversation *conversation;
message = dbus_message_new_signal (GDM_SESSION_DBUS_PATH,
GDM_SESSION_DBUS_INTERFACE,
@@ -2045,7 +2200,6 @@ send_environment_variable (const char *key,
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &value);
- conversation = session->priv->conversation;
if (! send_dbus_message (conversation, message)) {
g_debug ("GdmSessionDirect: Could not send %s signal", "SetEnvironmentVariable");
}
@@ -2054,12 +2208,13 @@ send_environment_variable (const char *key,
}
static void
-send_environment (GdmSessionDirect *session)
+send_environment (GdmSessionDirect *session,
+ GdmSessionConversation *conversation)
{
g_hash_table_foreach (session->priv->environment,
(GHFunc) send_environment_variable,
- session);
+ conversation);
}
static const char *
@@ -2181,17 +2336,22 @@ setup_session_environment (GdmSessionDirect *session)
}
static void
-gdm_session_direct_open_session (GdmSession *session)
+gdm_session_direct_open_session (GdmSession *session,
+ const char *service_name)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
+ GdmSessionConversation *conversation;
g_return_if_fail (session != NULL);
- send_dbus_void_signal (impl, "OpenSession");
+ conversation = find_conversation_by_name (impl, service_name);
+
+ send_dbus_string_signal (conversation, "OpenSession", service_name);
}
static void
-gdm_session_direct_start_session (GdmSession *session)
+gdm_session_direct_start_session (GdmSession *session,
+ const char *service_name)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
GdmSessionConversation *conversation;
@@ -2211,15 +2371,38 @@ gdm_session_direct_start_session (GdmSession *session)
g_free (command);
+ conversation = find_conversation_by_name (impl, service_name);
+
setup_session_environment (impl);
- send_environment (impl);
+ send_environment (impl, conversation);
- conversation = impl->priv->conversation;
send_dbus_string_signal (conversation, "StartProgram", program);
g_free (program);
}
static void
+stop_all_conversations (GdmSessionDirect *session)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+
+ if (session->priv->conversations == NULL) {
+ return;
+ }
+
+ g_hash_table_iter_init (&iter, session->priv->conversations);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ GdmSessionConversation *conversation;
+
+ conversation = (GdmSessionConversation *) value;
+
+ stop_conversation (conversation);
+ }
+
+ g_hash_table_remove_all (session->priv->conversations);
+}
+
+static void
gdm_session_direct_close (GdmSession *session)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
@@ -2236,6 +2419,13 @@ gdm_session_direct_close (GdmSession *session)
impl->priv->display_device);
}
+ stop_all_conversations (impl);
+
+ g_list_foreach (impl->priv->pending_connections,
+ (GFunc) dbus_connection_unref, NULL);
+ g_list_free (impl->priv->pending_connections);
+ impl->priv->pending_connections = NULL;
+
g_free (impl->priv->selected_user);
impl->priv->selected_user = NULL;
@@ -2268,6 +2458,7 @@ gdm_session_direct_close (GdmSession *session)
static void
gdm_session_direct_answer_query (GdmSession *session,
+ const char *service_name,
const char *text)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
@@ -2275,7 +2466,7 @@ gdm_session_direct_answer_query (GdmSession *session,
g_return_if_fail (session != NULL);
- conversation = impl->priv->conversation;
+ conversation = find_conversation_by_name (impl, service_name);
answer_pending_query (conversation, text);
}
@@ -2283,11 +2474,9 @@ gdm_session_direct_answer_query (GdmSession *session,
static void
gdm_session_direct_cancel (GdmSession *session)
{
- GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
-
g_return_if_fail (session != NULL);
- cancel_pending_query (impl->priv->conversation);
+ stop_all_conversations (GDM_SESSION_DIRECT (session));
}
char *
@@ -2351,7 +2540,8 @@ gdm_session_direct_select_session (GdmSession *session,
const char *text)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
- GdmSessionConversation *conversation;
+ GHashTableIter iter;
+ gpointer key, value;
g_free (impl->priv->selected_session);
@@ -2361,9 +2551,15 @@ gdm_session_direct_select_session (GdmSession *session,
impl->priv->selected_session = g_strdup (text);
}
- conversation = impl->priv->conversation;
- send_dbus_string_signal (conversation, "SetSessionName",
- get_session_name (impl));
+ g_hash_table_iter_init (&iter, impl->priv->conversations);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ GdmSessionConversation *conversation;
+
+ conversation = (GdmSessionConversation *) value;
+
+ send_dbus_string_signal (conversation, "SetSessionName",
+ get_session_name (impl));
+ }
}
static void
@@ -2371,7 +2567,8 @@ gdm_session_direct_select_language (GdmSession *session,
const char *text)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
- GdmSessionConversation *conversation;
+ GHashTableIter iter;
+ gpointer key, value;
g_free (impl->priv->selected_language);
@@ -2381,9 +2578,15 @@ gdm_session_direct_select_language (GdmSession *session,
impl->priv->selected_language = g_strdup (text);
}
- conversation = impl->priv->conversation;
- send_dbus_string_signal (conversation, "SetLanguageName",
- get_language_name (impl));
+ g_hash_table_iter_init (&iter, impl->priv->conversations);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ GdmSessionConversation *conversation;
+
+ conversation = (GdmSessionConversation *) value;
+
+ send_dbus_string_signal (conversation, "SetLanguageName",
+ get_language_name (impl));
+ }
}
static void
@@ -2391,7 +2594,8 @@ gdm_session_direct_select_layout (GdmSession *session,
const char *text)
{
GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
- GdmSessionConversation *conversation;
+ GHashTableIter iter;
+ gpointer key, value;
g_free (impl->priv->selected_layout);
@@ -2401,9 +2605,15 @@ gdm_session_direct_select_layout (GdmSession *session,
impl->priv->selected_layout = g_strdup (text);
}
- conversation = impl->priv->conversation;
- send_dbus_string_signal (conversation, "SetLayoutName",
- get_layout_name (impl));
+ g_hash_table_iter_init (&iter, impl->priv->conversations);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ GdmSessionConversation *conversation;
+
+ conversation = (GdmSessionConversation *) value;
+
+ send_dbus_string_signal (conversation, "SetLayoutName",
+ get_layout_name (impl));
+ }
}
static void
@@ -2665,6 +2875,7 @@ static void
gdm_session_iface_init (GdmSessionIface *iface)
{
iface->start_conversation = gdm_session_direct_start_conversation;
+ iface->stop_conversation = gdm_session_direct_stop_conversation;
iface->setup = gdm_session_direct_setup;
iface->setup_for_user = gdm_session_direct_setup_for_user;
iface->authenticate = gdm_session_direct_authenticate;
diff --git a/daemon/gdm-session-private.h b/daemon/gdm-session-private.h
index 74b6069..36781dd 100644
--- a/daemon/gdm-session-private.h
+++ b/daemon/gdm-session-private.h
@@ -29,27 +29,41 @@ G_BEGIN_DECLS
/* state changes */
void _gdm_session_conversation_started (GdmSession *session,
const char *service_name);
-void _gdm_session_setup_complete (GdmSession *session);
+void _gdm_session_conversation_stopped (GdmSession *session,
+ const char *service_name);
+void _gdm_session_setup_complete (GdmSession *session,
+ const char *service_name);
void _gdm_session_setup_failed (GdmSession *session,
+ const char *service_name,
const char *message);
void _gdm_session_reset_complete (GdmSession *session);
void _gdm_session_reset_failed (GdmSession *session,
const char *message);
-void _gdm_session_authenticated (GdmSession *session);
+void _gdm_session_authenticated (GdmSession *session,
+ const char *service_name);
void _gdm_session_authentication_failed (GdmSession *session,
+ const char *service_name,
const char *text);
-void _gdm_session_authorized (GdmSession *session);
+void _gdm_session_authorized (GdmSession *session,
+ const char *service_name);
void _gdm_session_authorization_failed (GdmSession *session,
+ const char *service_name,
const char *text);
-void _gdm_session_accredited (GdmSession *session);
+void _gdm_session_accredited (GdmSession *session,
+ const char *service_name);
void _gdm_session_accreditation_failed (GdmSession *session,
+ const char *service_name,
const char *text);
-void _gdm_session_session_opened (GdmSession *session);
+void _gdm_session_session_opened (GdmSession *session,
+ const char *service_name);
void _gdm_session_session_open_failed (GdmSession *session,
+ const char *service_name,
const char *message);
void _gdm_session_session_started (GdmSession *session,
+ const char *service_name,
int pid);
void _gdm_session_session_start_failed (GdmSession *session,
+ const char *service_name,
const char *message);
void _gdm_session_session_exited (GdmSession *session,
int exit_code);
@@ -70,12 +84,16 @@ void _gdm_session_selected_user_changed (GdmSession *sessio
/* call and response stuff */
void _gdm_session_info_query (GdmSession *session,
+ const char *service_name,
const char *text);
void _gdm_session_secret_info_query (GdmSession *session,
+ const char *service_name,
const char *text);
void _gdm_session_info (GdmSession *session,
+ const char *service_name,
const char *text);
void _gdm_session_problem (GdmSession *session,
+ const char *service_name,
const char *text);
G_END_DECLS
diff --git a/daemon/gdm-session-relay.c b/daemon/gdm-session-relay.c
index a0b4cbf..98ccc51 100644
--- a/daemon/gdm-session-relay.c
+++ b/daemon/gdm-session-relay.c
@@ -212,31 +212,34 @@ gdm_session_relay_setup_for_user (GdmSession *session,
}
static void
-gdm_session_relay_authenticate (GdmSession *session)
+gdm_session_relay_authenticate (GdmSession *session,
+ const char *service_name)
{
GdmSessionRelay *impl = GDM_SESSION_RELAY (session);
- send_dbus_void_signal (impl, "Authenticate");
+ send_dbus_string_signal (impl, "Authenticate", service_name);
}
static void
-gdm_session_relay_authorize (GdmSession *session)
+gdm_session_relay_authorize (GdmSession *session,
+ const char *service_name)
{
GdmSessionRelay *impl = GDM_SESSION_RELAY (session);
- send_dbus_void_signal (impl, "Authorize");
+ send_dbus_string_signal (impl, "Authorize", service_name);
}
static void
gdm_session_relay_accredit (GdmSession *session,
+ const char *service_name,
int cred_flag)
{
GdmSessionRelay *impl = GDM_SESSION_RELAY (session);
switch (cred_flag) {
case GDM_SESSION_CRED_ESTABLISH:
- send_dbus_void_signal (impl, "EstablishCredentials");
+ send_dbus_string_signal (impl, "EstablishCredentials", service_name);
break;
case GDM_SESSION_CRED_REFRESH:
- send_dbus_void_signal (impl, "RefreshCredentials");
+ send_dbus_string_signal (impl, "RefreshCredentials", service_name);
break;
default:
g_assert_not_reached ();
@@ -244,18 +247,20 @@ gdm_session_relay_accredit (GdmSession *session,
}
static void
-gdm_session_relay_open_session (GdmSession *session)
+gdm_session_relay_open_session (GdmSession *session,
+ const char *service_name)
{
GdmSessionRelay *impl = GDM_SESSION_RELAY (session);
- send_dbus_void_signal (impl, "OpenSession");
+ send_dbus_string_signal (impl, "OpenSession", service_name);
}
static void
gdm_session_relay_answer_query (GdmSession *session,
+ const char *service_name,
const char *text)
{
GdmSessionRelay *impl = GDM_SESSION_RELAY (session);
- send_dbus_string_signal (impl, "AnswerQuery", text);
+ send_dbus_string_string_signal (impl, "AnswerQuery", service_name, text);
}
static void
@@ -299,11 +304,12 @@ gdm_session_relay_cancel (GdmSession *session)
}
static void
-gdm_session_relay_start_session (GdmSession *session)
+gdm_session_relay_start_session (GdmSession *session,
+ const char *service_name)
{
GdmSessionRelay *impl = GDM_SESSION_RELAY (session);
- send_dbus_void_signal (impl, "StartSession");
+ send_dbus_string_signal (impl, "StartSession", service_name);
}
/* Note: Use abstract sockets like dbus does by default on Linux. Abstract
@@ -341,10 +347,12 @@ handle_info_query (GdmSessionRelay *session_relay,
{
DBusMessage *reply;
DBusError error;
- const char *text;
+ char *service_name;
+ char *text;
dbus_error_init (&error);
if (! dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &service_name,
DBUS_TYPE_STRING, &text,
DBUS_TYPE_INVALID)) {
g_warning ("ERROR: %s", error.message);
@@ -356,7 +364,7 @@ handle_info_query (GdmSessionRelay *session_relay,
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
- _gdm_session_info_query (GDM_SESSION (session_relay), text);
+ _gdm_session_info_query (GDM_SESSION (session_relay), service_name, text);
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -368,12 +376,14 @@ handle_secret_info_query (GdmSessionRelay *session_relay,
{
DBusMessage *reply;
DBusError error;
- const char *text;
+ char *service_name;
+ char *text;
text = NULL;
dbus_error_init (&error);
if (! dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &service_name,
DBUS_TYPE_STRING, &text,
DBUS_TYPE_INVALID)) {
g_warning ("ERROR: %s", error.message);
@@ -385,7 +395,7 @@ handle_secret_info_query (GdmSessionRelay *session_relay,
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
- _gdm_session_secret_info_query (GDM_SESSION (session_relay), text);
+ _gdm_session_secret_info_query (GDM_SESSION (session_relay), service_name, text);
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -397,12 +407,14 @@ handle_info (GdmSessionRelay *session_relay,
{
DBusMessage *reply;
DBusError error;
- const char *text;
+ char *service_name;
+ char *text;
text = NULL;
dbus_error_init (&error);
if (! dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &service_name,
DBUS_TYPE_STRING, &text,
DBUS_TYPE_INVALID)) {
g_warning ("ERROR: %s", error.message);
@@ -414,7 +426,7 @@ handle_info (GdmSessionRelay *session_relay,
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
- _gdm_session_info (GDM_SESSION (session_relay), text);
+ _gdm_session_info (GDM_SESSION (session_relay), service_name, text);
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -426,12 +438,14 @@ handle_problem (GdmSessionRelay *session_relay,
{
DBusMessage *reply;
DBusError error;
- const char *text;
+ char *service_name;
+ char *text;
text = NULL;
dbus_error_init (&error);
if (! dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &service_name,
DBUS_TYPE_STRING, &text,
DBUS_TYPE_INVALID)) {
g_warning ("ERROR: %s", error.message);
@@ -443,7 +457,7 @@ handle_problem (GdmSessionRelay *session_relay,
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
- _gdm_session_problem (GDM_SESSION (session_relay), text);
+ _gdm_session_problem (GDM_SESSION (session_relay), service_name, text);
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -455,8 +469,15 @@ handle_setup_complete (GdmSessionRelay *session_relay,
{
DBusMessage *reply;
DBusError error;
+ char *service_name;
dbus_error_init (&error);
+ if (! dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &service_name,
+ DBUS_TYPE_INVALID)) {
+ g_warning ("ERROR: %s", error.message);
+ }
+ dbus_error_free (&error);
g_debug ("GdmSessionRelay: SetupComplete");
@@ -464,7 +485,7 @@ handle_setup_complete (GdmSessionRelay *session_relay,
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
- _gdm_session_setup_complete (GDM_SESSION (session_relay));
+ _gdm_session_setup_complete (GDM_SESSION (session_relay), service_name);
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -476,8 +497,15 @@ handle_setup_failed (GdmSessionRelay *session_relay,
{
DBusMessage *reply;
DBusError error;
+ char *service_name;
dbus_error_init (&error);
+ if (! dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &service_name,
+ DBUS_TYPE_INVALID)) {
+ g_warning ("ERROR: %s", error.message);
+ }
+ dbus_error_free (&error);
g_debug ("GdmSessionRelay: SetupFailed");
@@ -485,7 +513,7 @@ handle_setup_failed (GdmSessionRelay *session_relay,
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
- _gdm_session_setup_failed (GDM_SESSION (session_relay), NULL);
+ _gdm_session_setup_failed (GDM_SESSION (session_relay), service_name, NULL);
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -498,8 +526,15 @@ handle_authenticated (GdmSessionRelay *session_relay,
{
DBusMessage *reply;
DBusError error;
+ char *service_name;
dbus_error_init (&error);
+ if (! dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &service_name,
+ DBUS_TYPE_INVALID)) {
+ g_warning ("ERROR: %s", error.message);
+ }
+ dbus_error_free (&error);
g_debug ("GdmSessionRelay: Authenticated");
@@ -507,7 +542,7 @@ handle_authenticated (GdmSessionRelay *session_relay,
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
- _gdm_session_authenticated (GDM_SESSION (session_relay));
+ _gdm_session_authenticated (GDM_SESSION (session_relay), service_name);
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -519,8 +554,15 @@ handle_authentication_failed (GdmSessionRelay *session_relay,
{
DBusMessage *reply;
DBusError error;
+ char *service_name;
dbus_error_init (&error);
+ if (! dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &service_name,
+ DBUS_TYPE_INVALID)) {
+ g_warning ("ERROR: %s", error.message);
+ }
+ dbus_error_free (&error);
g_debug ("GdmSessionRelay: AuthenticationFailed");
@@ -528,7 +570,7 @@ handle_authentication_failed (GdmSessionRelay *session_relay,
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
- _gdm_session_authentication_failed (GDM_SESSION (session_relay), NULL);
+ _gdm_session_authentication_failed (GDM_SESSION (session_relay), service_name, NULL);
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -540,8 +582,15 @@ handle_authorized (GdmSessionRelay *session_relay,
{
DBusMessage *reply;
DBusError error;
+ char *service_name;
dbus_error_init (&error);
+ if (! dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &service_name,
+ DBUS_TYPE_INVALID)) {
+ g_warning ("ERROR: %s", error.message);
+ }
+ dbus_error_free (&error);
g_debug ("GdmSessionRelay: Authorized");
@@ -549,7 +598,7 @@ handle_authorized (GdmSessionRelay *session_relay,
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
- _gdm_session_authorized (GDM_SESSION (session_relay));
+ _gdm_session_authorized (GDM_SESSION (session_relay), service_name);
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -561,8 +610,15 @@ handle_authorization_failed (GdmSessionRelay *session_relay,
{
DBusMessage *reply;
DBusError error;
+ char *service_name;
dbus_error_init (&error);
+ if (! dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &service_name,
+ DBUS_TYPE_INVALID)) {
+ g_warning ("ERROR: %s", error.message);
+ }
+ dbus_error_free (&error);
g_debug ("GdmSessionRelay: AuthorizationFailed");
@@ -570,7 +626,7 @@ handle_authorization_failed (GdmSessionRelay *session_relay,
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
- _gdm_session_authorization_failed (GDM_SESSION (session_relay), NULL);
+ _gdm_session_authorization_failed (GDM_SESSION (session_relay), service_name, NULL);
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -582,8 +638,15 @@ handle_accredited (GdmSessionRelay *session_relay,
{
DBusMessage *reply;
DBusError error;
+ char *service_name;
dbus_error_init (&error);
+ if (! dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &service_name,
+ DBUS_TYPE_INVALID)) {
+ g_warning ("ERROR: %s", error.message);
+ }
+ dbus_error_free (&error);
g_debug ("GdmSessionRelay: Accredited");
@@ -591,7 +654,7 @@ handle_accredited (GdmSessionRelay *session_relay,
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
- _gdm_session_accredited (GDM_SESSION (session_relay));
+ _gdm_session_accredited (GDM_SESSION (session_relay), service_name);
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -603,8 +666,15 @@ handle_accreditation_failed (GdmSessionRelay *session_relay,
{
DBusMessage *reply;
DBusError error;
+ char *service_name;
dbus_error_init (&error);
+ if (! dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &service_name,
+ DBUS_TYPE_INVALID)) {
+ g_warning ("ERROR: %s", error.message);
+ }
+ dbus_error_free (&error);
g_debug ("GdmSessionRelay: AccreditationFailed");
@@ -612,7 +682,7 @@ handle_accreditation_failed (GdmSessionRelay *session_relay,
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
- _gdm_session_accreditation_failed (GDM_SESSION (session_relay), NULL);
+ _gdm_session_accreditation_failed (GDM_SESSION (session_relay), service_name, NULL);
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -623,9 +693,11 @@ handle_session_opened (GdmSessionRelay *session_relay,
{
DBusMessage *reply;
DBusError error;
+ char *service_name;
dbus_error_init (&error);
if (! dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &service_name,
DBUS_TYPE_INVALID)) {
g_warning ("ERROR: %s", error.message);
}
@@ -637,7 +709,7 @@ handle_session_opened (GdmSessionRelay *session_relay,
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
- _gdm_session_session_opened (GDM_SESSION (session_relay));
+ _gdm_session_session_opened (GDM_SESSION (session_relay), service_name);
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -649,9 +721,11 @@ handle_session_open_failed (GdmSessionRelay *session_relay,
{
DBusMessage *reply;
DBusError error;
+ char *service_name;
dbus_error_init (&error);
if (! dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &service_name,
DBUS_TYPE_INVALID)) {
g_warning ("ERROR: %s", error.message);
}
@@ -663,7 +737,7 @@ handle_session_open_failed (GdmSessionRelay *session_relay,
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
- _gdm_session_session_open_failed (GDM_SESSION (session_relay), NULL);
+ _gdm_session_session_open_failed (GDM_SESSION (session_relay), service_name, NULL);
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -675,6 +749,7 @@ handle_session_started (GdmSessionRelay *session_relay,
{
DBusMessage *reply;
DBusError error;
+ char *service_name;
int pid;
dbus_error_init (&error);
@@ -682,6 +757,7 @@ handle_session_started (GdmSessionRelay *session_relay,
pid = 0;
if (! dbus_message_get_args (message,
&error,
+ DBUS_TYPE_STRING, &service_name,
DBUS_TYPE_INT32, &pid,
DBUS_TYPE_INVALID)) {
g_warning ("ERROR: %s", error.message);
@@ -694,6 +770,7 @@ handle_session_started (GdmSessionRelay *session_relay,
dbus_message_unref (reply);
_gdm_session_session_started (GDM_SESSION (session_relay),
+ service_name,
pid);
return DBUS_HANDLER_RESULT_HANDLED;
diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
index 775f99b..6abd97d 100644
--- a/daemon/gdm-session-worker.c
+++ b/daemon/gdm-session-worker.c
@@ -2892,6 +2892,28 @@ worker_dbus_filter_function (DBusConnection *connection,
return DBUS_HANDLER_RESULT_HANDLED;
}
+static void
+send_hello (GdmSessionWorker *worker)
+{
+ DBusMessage *message, *reply;
+ DBusError error;
+
+ message = dbus_message_new_method_call (NULL,
+ GDM_SESSION_DBUS_PATH,
+ GDM_SESSION_DBUS_INTERFACE,
+ "Hello");
+
+ dbus_error_init (&error);
+ reply = dbus_connection_send_with_reply_and_block (worker->priv->connection,
+ message, -1, &error);
+ dbus_message_unref (message);
+ dbus_error_free (&error);
+
+ if (reply != NULL) {
+ dbus_message_unref (reply);
+ }
+}
+
static GObject *
gdm_session_worker_constructor (GType type,
guint n_construct_properties,
@@ -2918,6 +2940,11 @@ gdm_session_worker_constructor (GType type,
exit (1);
}
+ /* Send an initial Hello message so that the session can associate
+ * the conversation we manage with our pid.
+ */
+ send_hello (worker);
+
dbus_connection_setup_with_g_main (worker->priv->connection, NULL);
dbus_connection_set_exit_on_disconnect (worker->priv->connection, TRUE);
diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c
index 1820e29..8858071 100644
--- a/daemon/gdm-session.c
+++ b/daemon/gdm-session.c
@@ -24,11 +24,13 @@
#include <glib/gi18n.h>
#include <glib-object.h>
+#include "gdm-marshal.h"
#include "gdm-session.h"
#include "gdm-session-private.h"
enum {
CONVERSATION_STARTED = 0,
+ CONVERSATION_STOPPED,
SETUP_COMPLETE,
SETUP_FAILED,
RESET_COMPLETE,
@@ -89,6 +91,15 @@ gdm_session_start_conversation (GdmSession *session,
}
void
+gdm_session_stop_conversation (GdmSession *session,
+ const char *service_name)
+{
+ g_return_if_fail (GDM_IS_SESSION (session));
+
+ GDM_SESSION_GET_IFACE (session)->stop_conversation (session, service_name);
+}
+
+void
gdm_session_close (GdmSession *session)
{
g_return_if_fail (GDM_IS_SESSION (session));
@@ -116,37 +127,41 @@ gdm_session_setup_for_user (GdmSession *session,
}
void
-gdm_session_authenticate (GdmSession *session)
+gdm_session_authenticate (GdmSession *session,
+ const char *service_name)
{
g_return_if_fail (GDM_IS_SESSION (session));
- GDM_SESSION_GET_IFACE (session)->authenticate (session);
+ GDM_SESSION_GET_IFACE (session)->authenticate (session, service_name);
}
void
-gdm_session_authorize (GdmSession *session)
+gdm_session_authorize (GdmSession *session,
+ const char *service_name)
{
g_return_if_fail (GDM_IS_SESSION (session));
- GDM_SESSION_GET_IFACE (session)->authorize (session);
+ GDM_SESSION_GET_IFACE (session)->authorize (session, service_name);
}
void
gdm_session_accredit (GdmSession *session,
+ const char *service_name,
int flag)
{
g_return_if_fail (GDM_IS_SESSION (session));
- GDM_SESSION_GET_IFACE (session)->accredit (session, flag);
+ GDM_SESSION_GET_IFACE (session)->accredit (session, service_name, flag);
}
void
gdm_session_answer_query (GdmSession *session,
+ const char *service_name,
const char *text)
{
g_return_if_fail (GDM_IS_SESSION (session));
- GDM_SESSION_GET_IFACE (session)->answer_query (session, text);
+ GDM_SESSION_GET_IFACE (session)->answer_query (session, service_name, text);
}
void
@@ -194,19 +209,21 @@ gdm_session_cancel (GdmSession *session)
}
void
-gdm_session_open_session (GdmSession *session)
+gdm_session_open_session (GdmSession *session,
+ const char *service_name)
{
g_return_if_fail (GDM_IS_SESSION (session));
- GDM_SESSION_GET_IFACE (session)->open_session (session);
+ GDM_SESSION_GET_IFACE (session)->open_session (session, service_name);
}
void
-gdm_session_start_session (GdmSession *session)
+gdm_session_start_session (GdmSession *session,
+ const char *service_name)
{
g_return_if_fail (GDM_IS_SESSION (session));
- GDM_SESSION_GET_IFACE (session)->start_session (session);
+ GDM_SESSION_GET_IFACE (session)->start_session (session, service_name);
}
static void
@@ -223,7 +240,17 @@ gdm_session_class_init (gpointer g_iface)
NULL,
g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE,
- 0);
+ 1, G_TYPE_STRING);
+ signals [CONVERSATION_STOPPED] =
+ g_signal_new ("conversation-stopped",
+ iface_type,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmSessionIface, conversation_stopped),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1, G_TYPE_STRING);
signals [SETUP_COMPLETE] =
g_signal_new ("setup-complete",
iface_type,
@@ -231,9 +258,10 @@ gdm_session_class_init (gpointer g_iface)
G_STRUCT_OFFSET (GdmSessionIface, setup_complete),
NULL,
NULL,
- g_cclosure_marshal_VOID__VOID,
+ g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE,
- 0);
+ 1,
+ G_TYPE_STRING);
signals [SETUP_FAILED] =
g_signal_new ("setup-failed",
iface_type,
@@ -241,10 +269,10 @@ gdm_session_class_init (gpointer g_iface)
G_STRUCT_OFFSET (GdmSessionIface, setup_failed),
NULL,
NULL,
- g_cclosure_marshal_VOID__STRING,
+ gdm_marshal_VOID__STRING_STRING,
G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
+ 2,
+ G_TYPE_STRING, G_TYPE_STRING);
signals [RESET_COMPLETE] =
g_signal_new ("reset-complete",
iface_type,
@@ -273,9 +301,9 @@ gdm_session_class_init (gpointer g_iface)
G_STRUCT_OFFSET (GdmSessionIface, authenticated),
NULL,
NULL,
- g_cclosure_marshal_VOID__VOID,
+ g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE,
- 0);
+ 1, G_TYPE_STRING);
signals [AUTHENTICATION_FAILED] =
g_signal_new ("authentication-failed",
iface_type,
@@ -283,10 +311,10 @@ gdm_session_class_init (gpointer g_iface)
G_STRUCT_OFFSET (GdmSessionIface, authentication_failed),
NULL,
NULL,
- g_cclosure_marshal_VOID__STRING,
+ gdm_marshal_VOID__STRING_STRING,
G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
+ 2,
+ G_TYPE_STRING, G_TYPE_STRING);
signals [AUTHORIZED] =
g_signal_new ("authorized",
iface_type,
@@ -294,9 +322,9 @@ gdm_session_class_init (gpointer g_iface)
G_STRUCT_OFFSET (GdmSessionIface, authorized),
NULL,
NULL,
- g_cclosure_marshal_VOID__VOID,
+ g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE,
- 0);
+ 1, G_TYPE_STRING);
signals [AUTHORIZATION_FAILED] =
g_signal_new ("authorization-failed",
iface_type,
@@ -304,10 +332,10 @@ gdm_session_class_init (gpointer g_iface)
G_STRUCT_OFFSET (GdmSessionIface, authorization_failed),
NULL,
NULL,
- g_cclosure_marshal_VOID__STRING,
+ gdm_marshal_VOID__STRING_STRING,
G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
+ 2,
+ G_TYPE_STRING, G_TYPE_STRING);
signals [ACCREDITED] =
g_signal_new ("accredited",
iface_type,
@@ -315,9 +343,9 @@ gdm_session_class_init (gpointer g_iface)
G_STRUCT_OFFSET (GdmSessionIface, accredited),
NULL,
NULL,
- g_cclosure_marshal_VOID__VOID,
+ g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE,
- 0);
+ 1, G_TYPE_STRING);
signals [ACCREDITATION_FAILED] =
g_signal_new ("accreditation-failed",
iface_type,
@@ -325,10 +353,10 @@ gdm_session_class_init (gpointer g_iface)
G_STRUCT_OFFSET (GdmSessionIface, accreditation_failed),
NULL,
NULL,
- g_cclosure_marshal_VOID__STRING,
+ gdm_marshal_VOID__STRING_STRING,
G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
+ 2,
+ G_TYPE_STRING, G_TYPE_STRING);
signals [INFO_QUERY] =
g_signal_new ("info-query",
@@ -337,10 +365,10 @@ gdm_session_class_init (gpointer g_iface)
G_STRUCT_OFFSET (GdmSessionIface, info_query),
NULL,
NULL,
- g_cclosure_marshal_VOID__STRING,
+ gdm_marshal_VOID__STRING_STRING,
G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
+ 2,
+ G_TYPE_STRING, G_TYPE_STRING);
signals [SECRET_INFO_QUERY] =
g_signal_new ("secret-info-query",
iface_type,
@@ -348,10 +376,10 @@ gdm_session_class_init (gpointer g_iface)
G_STRUCT_OFFSET (GdmSessionIface, secret_info_query),
NULL,
NULL,
- g_cclosure_marshal_VOID__STRING,
+ gdm_marshal_VOID__STRING_STRING,
G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
+ 2,
+ G_TYPE_STRING, G_TYPE_STRING);
signals [INFO] =
g_signal_new ("info",
iface_type,
@@ -359,10 +387,10 @@ gdm_session_class_init (gpointer g_iface)
G_STRUCT_OFFSET (GdmSessionIface, info),
NULL,
NULL,
- g_cclosure_marshal_VOID__STRING,
+ gdm_marshal_VOID__STRING_STRING,
G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
+ 2,
+ G_TYPE_STRING, G_TYPE_STRING);
signals [PROBLEM] =
g_signal_new ("problem",
iface_type,
@@ -370,10 +398,10 @@ gdm_session_class_init (gpointer g_iface)
G_STRUCT_OFFSET (GdmSessionIface, problem),
NULL,
NULL,
- g_cclosure_marshal_VOID__STRING,
+ gdm_marshal_VOID__STRING_STRING,
G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
+ 2,
+ G_TYPE_STRING, G_TYPE_STRING);
signals [SESSION_OPENED] =
g_signal_new ("session-opened",
iface_type,
@@ -381,9 +409,10 @@ gdm_session_class_init (gpointer g_iface)
G_STRUCT_OFFSET (GdmSessionIface, session_opened),
NULL,
NULL,
- g_cclosure_marshal_VOID__VOID,
+ g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE,
- 0);
+ 1,
+ G_TYPE_STRING);
signals [SESSION_OPEN_FAILED] =
g_signal_new ("session-open-failed",
iface_type,
@@ -391,10 +420,10 @@ gdm_session_class_init (gpointer g_iface)
G_STRUCT_OFFSET (GdmSessionIface, session_open_failed),
NULL,
NULL,
- g_cclosure_marshal_VOID__STRING,
+ gdm_marshal_VOID__STRING_STRING,
G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
+ 2,
+ G_TYPE_STRING, G_TYPE_STRING);
signals [SESSION_STARTED] =
g_signal_new ("session-started",
iface_type,
@@ -402,10 +431,10 @@ gdm_session_class_init (gpointer g_iface)
G_STRUCT_OFFSET (GdmSessionIface, session_started),
NULL,
NULL,
- g_cclosure_marshal_VOID__INT,
+ gdm_marshal_VOID__STRING_INT,
G_TYPE_NONE,
- 1,
- G_TYPE_INT);
+ 2,
+ G_TYPE_STRING, G_TYPE_INT);
signals [SESSION_START_FAILED] =
g_signal_new ("session-start-failed",
iface_type,
@@ -413,10 +442,10 @@ gdm_session_class_init (gpointer g_iface)
G_STRUCT_OFFSET (GdmSessionIface, session_start_failed),
NULL,
NULL,
- g_cclosure_marshal_VOID__STRING,
+ gdm_marshal_VOID__STRING_STRING,
G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
+ 2,
+ G_TYPE_STRING, G_TYPE_STRING);
signals [SESSION_EXITED] =
g_signal_new ("session-exited",
iface_type,
@@ -496,19 +525,21 @@ gdm_session_class_init (gpointer g_iface)
}
void
-_gdm_session_setup_complete (GdmSession *session)
+_gdm_session_setup_complete (GdmSession *session,
+ const char *service_name)
{
g_return_if_fail (GDM_IS_SESSION (session));
- g_signal_emit (session, signals [SETUP_COMPLETE], 0);
+ g_signal_emit (session, signals [SETUP_COMPLETE], 0, service_name);
}
void
_gdm_session_setup_failed (GdmSession *session,
+ const char *service_name,
const char *text)
{
g_return_if_fail (GDM_IS_SESSION (session));
- g_signal_emit (session, signals [SETUP_FAILED], 0, text);
+ g_signal_emit (session, signals [SETUP_FAILED], 0, service_name, text);
}
void
@@ -528,114 +559,128 @@ _gdm_session_reset_failed (GdmSession *session,
}
void
-_gdm_session_authenticated (GdmSession *session)
+_gdm_session_authenticated (GdmSession *session,
+ const char *service_name)
{
g_return_if_fail (GDM_IS_SESSION (session));
- g_signal_emit (session, signals [AUTHENTICATED], 0);
+ g_signal_emit (session, signals [AUTHENTICATED], 0, service_name);
}
void
_gdm_session_authentication_failed (GdmSession *session,
+ const char *service_name,
const char *text)
{
g_return_if_fail (GDM_IS_SESSION (session));
- g_signal_emit (session, signals [AUTHENTICATION_FAILED], 0, text);
+ g_signal_emit (session, signals [AUTHENTICATION_FAILED], 0, service_name, text);
}
void
-_gdm_session_authorized (GdmSession *session)
+_gdm_session_authorized (GdmSession *session,
+ const char *service_name)
{
g_return_if_fail (GDM_IS_SESSION (session));
- g_signal_emit (session, signals [AUTHORIZED], 0);
+ g_signal_emit (session, signals [AUTHORIZED], 0, service_name);
}
void
_gdm_session_authorization_failed (GdmSession *session,
+ const char *service_name,
const char *text)
{
g_return_if_fail (GDM_IS_SESSION (session));
- g_signal_emit (session, signals [AUTHORIZATION_FAILED], 0, text);
+ g_signal_emit (session, signals [AUTHORIZATION_FAILED], 0, service_name, text);
}
void
-_gdm_session_accredited (GdmSession *session)
+_gdm_session_accredited (GdmSession *session,
+ const char *service_name)
{
g_return_if_fail (GDM_IS_SESSION (session));
- g_signal_emit (session, signals [ACCREDITED], 0);
+ g_signal_emit (session, signals [ACCREDITED], 0, service_name);
}
void
_gdm_session_accreditation_failed (GdmSession *session,
+ const char *service_name,
const char *text)
{
g_return_if_fail (GDM_IS_SESSION (session));
- g_signal_emit (session, signals [ACCREDITATION_FAILED], 0, text);
+ g_signal_emit (session, signals [ACCREDITATION_FAILED], 0, service_name, text);
}
void
_gdm_session_info_query (GdmSession *session,
+ const char *service_name,
const char *text)
{
g_return_if_fail (GDM_IS_SESSION (session));
- g_signal_emit (session, signals [INFO_QUERY], 0, text);
+ g_signal_emit (session, signals [INFO_QUERY], 0, service_name, text);
}
void
_gdm_session_secret_info_query (GdmSession *session,
+ const char *service_name,
const char *text)
{
g_return_if_fail (GDM_IS_SESSION (session));
- g_signal_emit (session, signals [SECRET_INFO_QUERY], 0, text);
+ g_signal_emit (session, signals [SECRET_INFO_QUERY], 0, service_name, text);
}
void
_gdm_session_info (GdmSession *session,
+ const char *service_name,
const char *text)
{
g_return_if_fail (GDM_IS_SESSION (session));
- g_signal_emit (session, signals [INFO], 0, text);
+ g_signal_emit (session, signals [INFO], 0, service_name, text);
}
void
_gdm_session_problem (GdmSession *session,
+ const char *service_name,
const char *text)
{
g_return_if_fail (GDM_IS_SESSION (session));
- g_signal_emit (session, signals [PROBLEM], 0, text);
+ g_signal_emit (session, signals [PROBLEM], 0, service_name, text);
}
void
-_gdm_session_session_opened (GdmSession *session)
+_gdm_session_session_opened (GdmSession *session,
+ const char *service_name)
{
g_return_if_fail (GDM_IS_SESSION (session));
- g_signal_emit (session, signals [SESSION_OPENED], 0);
+ g_signal_emit (session, signals [SESSION_OPENED], 0, service_name);
}
void
_gdm_session_session_open_failed (GdmSession *session,
+ const char *service_name,
const char *text)
{
g_return_if_fail (GDM_IS_SESSION (session));
- g_signal_emit (session, signals [SESSION_OPEN_FAILED], 0, text);
+ g_signal_emit (session, signals [SESSION_OPEN_FAILED], 0, service_name, text);
}
void
_gdm_session_session_started (GdmSession *session,
+ const char *service_name,
int pid)
{
g_return_if_fail (GDM_IS_SESSION (session));
- g_signal_emit (session, signals [SESSION_STARTED], 0, pid);
+ g_signal_emit (session, signals [SESSION_STARTED], 0, service_name, pid);
}
void
_gdm_session_session_start_failed (GdmSession *session,
+ const char *service_name,
const char *text)
{
g_return_if_fail (GDM_IS_SESSION (session));
- g_signal_emit (session, signals [SESSION_START_FAILED], 0, text);
+ g_signal_emit (session, signals [SESSION_START_FAILED], 0, service_name, text);
}
void
@@ -663,6 +708,14 @@ _gdm_session_conversation_started (GdmSession *session,
}
void
+_gdm_session_conversation_stopped (GdmSession *session,
+ const char *service_name)
+{
+ g_return_if_fail (GDM_IS_SESSION (session));
+ g_signal_emit (session, signals [CONVERSATION_STOPPED], 0, service_name);
+}
+
+void
_gdm_session_closed (GdmSession *session)
{
g_return_if_fail (GDM_IS_SESSION (session));
diff --git a/daemon/gdm-session.h b/daemon/gdm-session.h
index 00c2fa4..22c2ccb 100644
--- a/daemon/gdm-session.h
+++ b/daemon/gdm-session.h
@@ -47,18 +47,25 @@ struct _GdmSessionIface
/* Methods */
void (* start_conversation) (GdmSession *session,
const char *service_name);
+ void (* stop_conversation) (GdmSession *session,
+ const char *service_name);
void (* setup) (GdmSession *session,
const char *service_name);
void (* setup_for_user) (GdmSession *session,
const char *service_name,
const char *username);
void (* reset) (GdmSession *session);
- void (* authenticate) (GdmSession *session);
- void (* authorize) (GdmSession *session);
+ void (* authenticate) (GdmSession *session,
+ const char *service_name);
+ void (* authorize) (GdmSession *session,
+ const char *service_name);
void (* accredit) (GdmSession *session,
+ const char *service_name,
int cred_flag);
- void (* open_session) (GdmSession *session);
+ void (* open_session) (GdmSession *session,
+ const char *service_name);
void (* answer_query) (GdmSession *session,
+ const char *service_name,
const char *text);
void (* select_language) (GdmSession *session,
const char *text);
@@ -68,41 +75,58 @@ struct _GdmSessionIface
const char *text);
void (* select_user) (GdmSession *session,
const char *text);
- void (* start_session) (GdmSession *session);
+ void (* start_session) (GdmSession *session,
+ const char *service_name);
void (* close) (GdmSession *session);
void (* cancel) (GdmSession *session);
/* Signals */
- void (* setup_complete) (GdmSession *session);
+ void (* setup_complete) (GdmSession *session,
+ const char *service_name);
void (* setup_failed) (GdmSession *session,
+ const char *service_name,
const char *message);
void (* reset_complete) (GdmSession *session);
void (* reset_failed) (GdmSession *session,
const char *message);
- void (* authenticated) (GdmSession *session);
+ void (* authenticated) (GdmSession *session,
+ const char *service_name);
void (* authentication_failed) (GdmSession *session,
+ const char *service_name,
const char *message);
- void (* authorized) (GdmSession *session);
+ void (* authorized) (GdmSession *session,
+ const char *service_name);
void (* authorization_failed) (GdmSession *session,
+ const char *service_name,
const char *message);
- void (* accredited) (GdmSession *session);
+ void (* accredited) (GdmSession *session,
+ const char *service_name);
void (* accreditation_failed) (GdmSession *session,
+ const char *service_name,
const char *message);
void (* info_query) (GdmSession *session,
+ const char *service_name,
const char *query_text);
void (* secret_info_query) (GdmSession *session,
+ const char *service_name,
const char *query_text);
void (* info) (GdmSession *session,
+ const char *service_name,
const char *info);
void (* problem) (GdmSession *session,
+ const char *service_name,
const char *problem);
- void (* session_opened) (GdmSession *session);
+ void (* session_opened) (GdmSession *session,
+ const char *service_name);
void (* session_open_failed) (GdmSession *session,
+ const char *service_name,
const char *message);
void (* session_started) (GdmSession *session,
+ const char *service_name,
int pid);
void (* session_start_failed) (GdmSession *session,
+ const char *service_name,
const char *message);
void (* session_exited) (GdmSession *session,
int exit_code);
@@ -110,6 +134,8 @@ struct _GdmSessionIface
int signal_number);
void (* conversation_started) (GdmSession *session,
const char *service_name);
+ void (* conversation_stopped) (GdmSession *session,
+ const char *service_name);
void (* closed) (GdmSession *session);
void (* selected_user_changed) (GdmSession *session,
const char *text);
@@ -126,21 +152,29 @@ GType gdm_session_get_type (void) G_GNUC_CONST;
void gdm_session_start_conversation (GdmSession *session,
const char *service_name);
+void gdm_session_stop_conversation (GdmSession *session,
+ const char *service_name);
void gdm_session_setup (GdmSession *session,
const char *service_name);
void gdm_session_setup_for_user (GdmSession *session,
const char *service_name,
const char *username);
void gdm_session_reset (GdmSession *session);
-void gdm_session_authenticate (GdmSession *session);
-void gdm_session_authorize (GdmSession *session);
+void gdm_session_authenticate (GdmSession *session,
+ const char *service_name);
+void gdm_session_authorize (GdmSession *session,
+ const char *service_name);
void gdm_session_accredit (GdmSession *session,
+ const char *service_name,
int cred_flag);
-void gdm_session_open_session (GdmSession *session);
-void gdm_session_start_session (GdmSession *session);
+void gdm_session_open_session (GdmSession *session,
+ const char *service_name);
+void gdm_session_start_session (GdmSession *session,
+ const char *service_name);
void gdm_session_close (GdmSession *session);
void gdm_session_answer_query (GdmSession *session,
+ const char *service_name,
const char *text);
void gdm_session_select_session (GdmSession *session,
const char *session_name);
diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c
index dc7b437..adcb94a 100644
--- a/daemon/gdm-simple-slave.c
+++ b/daemon/gdm-simple-slave.c
@@ -71,6 +71,8 @@ struct GdmSimpleSlavePrivate
guint greeter_reset_id;
guint start_session_id;
+ char *start_session_service_name;
+
int ping_interval;
GPid server_pid;
@@ -102,6 +104,7 @@ static void start_greeter (GdmSimpleSlave *slave);
static void
on_session_started (GdmSession *session,
+ const char *service_name,
int pid,
GdmSimpleSlave *slave)
{
@@ -233,23 +236,25 @@ queue_auth_failed_reset (GdmSimpleSlave *slave)
static void
on_session_setup_complete (GdmSession *session,
+ const char *service_name,
GdmSimpleSlave *slave)
{
- gdm_session_authenticate (session);
+ gdm_session_authenticate (session, service_name);
}
static void
on_session_setup_failed (GdmSession *session,
+ const char *service_name,
const char *message,
GdmSimpleSlave *slave)
{
if (slave->priv->greeter_server != NULL) {
gdm_greeter_server_problem (slave->priv->greeter_server,
- message != NULL ? message: _("Unable to initialize login system"));
+ service_name,
+ message != NULL ? message: _("Unable to initialize login system"));
}
- destroy_session (slave);
- queue_greeter_reset (slave);
+ gdm_session_stop_conversation (session, service_name);
}
static void
@@ -269,29 +274,32 @@ on_session_reset_failed (GdmSession *session,
static void
on_session_authenticated (GdmSession *session,
+ const char *service_name,
GdmSimpleSlave *slave)
{
- gdm_session_authorize (session);
+ gdm_session_authorize (session, service_name);
}
static void
on_session_authentication_failed (GdmSession *session,
+ const char *service_name,
const char *message,
GdmSimpleSlave *slave)
{
if (slave->priv->greeter_server != NULL) {
gdm_greeter_server_problem (slave->priv->greeter_server,
+ service_name,
message != NULL ? message : _("Unable to authenticate user"));
}
- destroy_session (slave);
-
g_debug ("GdmSimpleSlave: Authentication failed - may retry");
+ gdm_session_stop_conversation (session, service_name);
queue_auth_failed_reset (slave);
}
static void
-gdm_simple_slave_accredit_when_ready (GdmSimpleSlave *slave)
+gdm_simple_slave_accredit_when_ready (GdmSimpleSlave *slave,
+ const char *service_name)
{
if (slave->priv->start_session_when_ready) {
char *ssid;
@@ -312,7 +320,7 @@ gdm_simple_slave_accredit_when_ready (GdmSimpleSlave *slave)
g_free (ssid);
g_free (username);
- gdm_session_accredit (GDM_SESSION (slave->priv->session), cred_flag);
+ gdm_session_accredit (GDM_SESSION (slave->priv->session), service_name, cred_flag);
} else {
slave->priv->waiting_to_start_session = TRUE;
}
@@ -320,29 +328,31 @@ gdm_simple_slave_accredit_when_ready (GdmSimpleSlave *slave)
static void
on_session_authorized (GdmSession *session,
+ const char *service_name,
GdmSimpleSlave *slave)
{
if (slave->priv->greeter_server != NULL) {
- gdm_greeter_server_user_authorized (slave->priv->greeter_server);
- gdm_simple_slave_accredit_when_ready (slave);
+ gdm_greeter_server_user_authorized (slave->priv->greeter_server, service_name);
+ gdm_simple_slave_accredit_when_ready (slave, service_name);
} else {
slave->priv->start_session_when_ready = TRUE;
- gdm_simple_slave_accredit_when_ready (slave);
+ gdm_simple_slave_accredit_when_ready (slave, service_name);
}
}
static void
on_session_authorization_failed (GdmSession *session,
+ const char *service_name,
const char *message,
GdmSimpleSlave *slave)
{
if (slave->priv->greeter_server != NULL) {
gdm_greeter_server_problem (slave->priv->greeter_server,
- message != NULL ? message : _("Unable to authorize user"));
+ service_name,
+ message != NULL ? message : _("Unable to authorize user"));
}
- destroy_session (slave);
- queue_greeter_reset (slave);
+ gdm_session_stop_conversation (session, service_name);
}
static gboolean
@@ -425,31 +435,38 @@ start_session_timeout (GdmSimpleSlave *slave)
g_free (auth_file);
- gdm_session_start_session (GDM_SESSION (slave->priv->session));
+ gdm_session_start_session (GDM_SESSION (slave->priv->session),
+ slave->priv->start_session_service_name);
out:
slave->priv->start_session_id = 0;
+ g_free (slave->priv->start_session_service_name);
+ slave->priv->start_session_service_name = NULL;
return FALSE;
}
static void
-queue_start_session (GdmSimpleSlave *slave)
+queue_start_session (GdmSimpleSlave *slave,
+ const char *service_name)
{
if (slave->priv->start_session_id > 0) {
return;
}
slave->priv->start_session_id = g_idle_add ((GSourceFunc)start_session_timeout, slave);
+ slave->priv->start_session_service_name = g_strdup (service_name);
}
static void
on_session_accredited (GdmSession *session,
+ const char *service_name,
GdmSimpleSlave *slave)
{
- gdm_session_open_session (session);
+ gdm_session_open_session (session, service_name);
}
static void
on_session_accreditation_failed (GdmSession *session,
+ const char *service_name,
const char *message,
GdmSimpleSlave *slave)
{
@@ -470,6 +487,7 @@ on_session_accreditation_failed (GdmSession *session,
problem = _("Unable to establish credentials");
}
gdm_greeter_server_problem (slave->priv->greeter_server,
+ service_name,
problem);
}
}
@@ -478,69 +496,74 @@ on_session_accreditation_failed (GdmSession *session,
when Xorg exits it switches to the VT it was
started from. That interferes with fast
user switching. */
- destroy_session (slave);
- queue_greeter_reset (slave);
+ gdm_session_stop_conversation (session, service_name);
}
static void
on_session_opened (GdmSession *session,
+ const char *service_name,
GdmSimpleSlave *slave)
{
- queue_start_session (slave);
+ queue_start_session (slave, service_name);
}
static void
on_session_open_failed (GdmSession *session,
+ const char *service_name,
const char *message,
GdmSimpleSlave *slave)
{
if (slave->priv->greeter_server != NULL) {
gdm_greeter_server_problem (slave->priv->greeter_server,
+ service_name,
_("Unable to open session"));
}
- destroy_session (slave);
- queue_greeter_reset (slave);
+ gdm_session_stop_conversation (session, service_name);
}
static void
on_session_info (GdmSession *session,
+ const char *service_name,
const char *text,
GdmSimpleSlave *slave)
{
g_debug ("GdmSimpleSlave: Info: %s", text);
if (slave->priv->greeter_server != NULL) {
- gdm_greeter_server_info (slave->priv->greeter_server, text);
+ gdm_greeter_server_info (slave->priv->greeter_server, service_name, text);
}
}
static void
on_session_problem (GdmSession *session,
+ const char *service_name,
const char *text,
GdmSimpleSlave *slave)
{
g_debug ("GdmSimpleSlave: Problem: %s", text);
- gdm_greeter_server_problem (slave->priv->greeter_server, text);
+ gdm_greeter_server_problem (slave->priv->greeter_server, service_name, text);
}
static void
on_session_info_query (GdmSession *session,
+ const char *service_name,
const char *text,
GdmSimpleSlave *slave)
{
g_debug ("GdmSimpleSlave: Info query: %s", text);
- gdm_greeter_server_info_query (slave->priv->greeter_server, text);
+ gdm_greeter_server_info_query (slave->priv->greeter_server, service_name, text);
}
static void
on_session_secret_info_query (GdmSession *session,
+ const char *service_name,
const char *text,
GdmSimpleSlave *slave)
{
g_debug ("GdmSimpleSlave: Secret info query: %s", text);
- gdm_greeter_server_secret_info_query (slave->priv->greeter_server, text);
+ gdm_greeter_server_secret_info_query (slave->priv->greeter_server, service_name, text);
}
static void
@@ -583,6 +606,23 @@ on_session_conversation_started (GdmSession *session,
}
static void
+on_session_conversation_stopped (GdmSession *session,
+ const char *service_name,
+ GdmSimpleSlave *slave)
+{
+ gboolean res;
+ g_debug ("GdmSimpleSlave: conversation stopped");
+
+ if (slave->priv->greeter_server != NULL) {
+ res = gdm_greeter_server_conversation_stopped (slave->priv->greeter_server,
+ service_name);
+ if (! res) {
+ g_warning ("Unable to send conversation stopped");
+ }
+ }
+}
+
+static void
on_session_selected_user_changed (GdmSession *session,
const char *text,
GdmSimpleSlave *slave)
@@ -686,6 +726,10 @@ create_new_session (GdmSimpleSlave *slave)
G_CALLBACK (on_session_conversation_started),
slave);
g_signal_connect (slave->priv->session,
+ "conversation-stopped",
+ G_CALLBACK (on_session_conversation_stopped),
+ slave);
+ g_signal_connect (slave->priv->session,
"setup-complete",
G_CALLBACK (on_session_setup_complete),
slave);
@@ -797,6 +841,9 @@ destroy_session (GdmSimpleSlave *slave)
G_CALLBACK (on_session_conversation_started),
slave);
g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_session_conversation_stopped),
+ slave);
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
G_CALLBACK (on_session_setup_complete),
slave);
g_signal_handlers_disconnect_by_func (slave->priv->session,
@@ -926,11 +973,12 @@ on_greeter_start_conversation (GdmGreeterServer *greeter_server,
static void
on_greeter_begin_verification (GdmGreeterServer *greeter_server,
+ const char *service_name,
GdmSimpleSlave *slave)
{
g_debug ("GdmSimpleSlave: begin verification");
gdm_session_setup (GDM_SESSION (slave->priv->session),
- "gdm");
+ service_name);
}
static void
@@ -946,21 +994,23 @@ on_greeter_begin_auto_login (GdmGreeterServer *greeter_server,
static void
on_greeter_begin_verification_for_user (GdmGreeterServer *greeter_server,
+ const char *service_name,
const char *username,
GdmSimpleSlave *slave)
{
g_debug ("GdmSimpleSlave: begin verification");
gdm_session_setup_for_user (GDM_SESSION (slave->priv->session),
- "gdm",
+ service_name,
username);
}
static void
on_greeter_answer (GdmGreeterServer *greeter_server,
+ const char *service_name,
const char *text,
GdmSimpleSlave *slave)
{
- gdm_session_answer_query (GDM_SESSION (slave->priv->session), text);
+ gdm_session_answer_query (GDM_SESSION (slave->priv->session), service_name, text);
}
static void
@@ -1023,18 +1073,20 @@ on_greeter_connected (GdmGreeterServer *greeter_server,
static void
on_start_session_when_ready (GdmGreeterServer *session,
+ const char *service_name,
GdmSimpleSlave *slave)
{
g_debug ("GdmSimpleSlave: Will start session when ready");
slave->priv->start_session_when_ready = TRUE;
if (slave->priv->waiting_to_start_session) {
- gdm_simple_slave_accredit_when_ready (slave);
+ gdm_simple_slave_accredit_when_ready (slave, service_name);
}
}
static void
on_start_session_later (GdmGreeterServer *session,
+ const char *service_name,
GdmSimpleSlave *slave)
{
g_debug ("GdmSimpleSlave: Will start session when ready and told");
diff --git a/daemon/test-session.c b/daemon/test-session.c
index 9bfda86..fe78230 100644
--- a/daemon/test-session.c
+++ b/daemon/test-session.c
@@ -44,10 +44,11 @@ on_conversation_started (GdmSession *session,
static void
on_session_setup_complete (GdmSession *session,
+ const char *service_name,
gpointer data)
{
g_debug ("Session setup complete");
- gdm_session_authenticate (session);
+ gdm_session_authenticate (session, service_name);
}
static void
@@ -79,10 +80,11 @@ on_session_reset_failed (GdmSession *session,
static void
on_session_authenticated (GdmSession *session,
+ const char *service_name,
gpointer data)
{
g_debug ("Session authenticated");
- gdm_session_authorize (session);
+ gdm_session_authorize (session, service_name);
}
static void
@@ -97,14 +99,16 @@ on_session_authentication_failed (GdmSession *session,
static void
on_session_authorized (GdmSession *session,
+ const char *service_name,
gpointer data)
{
g_debug ("Session authorized");
- gdm_session_accredit (session, GDM_SESSION_CRED_ESTABLISH);
+ gdm_session_accredit (session, service_name, GDM_SESSION_CRED_ESTABLISH);
}
static void
on_session_authorization_failed (GdmSession *session,
+ const char *service_name,
const char *message,
gpointer data)
{
@@ -115,6 +119,7 @@ on_session_authorization_failed (GdmSession *session,
static void
on_session_accredited (GdmSession *session,
+ const char *service_name,
gpointer data)
{
char *username;
@@ -125,12 +130,13 @@ on_session_accredited (GdmSession *session,
username ? username : "", username ? " " : "");
g_free (username);
- gdm_session_start_session (session);
+ gdm_session_start_session (session, service_name);
}
static void
on_session_accreditation_failed (GdmSession *session,
+ const char *service_name,
const char *message,
gpointer data)
{
@@ -165,6 +171,7 @@ on_session_died (GdmSession *session,
static void
on_info_query (GdmSession *session,
+ const char *service_name,
const char *query_text)
{
char answer[1024];
@@ -184,12 +191,13 @@ on_info_query (GdmSession *session,
gdm_session_close (session);
g_main_loop_quit (loop);
} else {
- gdm_session_answer_query (session, answer);
+ gdm_session_answer_query (session, service_name, answer);
}
}
static void
on_info (GdmSession *session,
+ const char *service_name,
const char *info)
{
g_print ("\n** NOTE: %s\n", info);
@@ -197,6 +205,7 @@ on_info (GdmSession *session,
static void
on_problem (GdmSession *session,
+ const char *service_name,
const char *problem)
{
g_print ("\n** WARNING: %s\n", problem);
@@ -204,6 +213,7 @@ on_problem (GdmSession *session,
static void
on_secret_info_query (GdmSession *session,
+ const char *service_name,
const char *query_text)
{
char answer[1024];
@@ -233,7 +243,7 @@ on_secret_info_query (GdmSession *session,
g_print ("\n");
- gdm_session_answer_query (session, answer);
+ gdm_session_answer_query (session, service_name, answer);
}
static void
diff --git a/gui/simple-greeter/gdm-greeter-client.c b/gui/simple-greeter/gdm-greeter-client.c
index b175fc9..e42ab1e 100644
--- a/gui/simple-greeter/gdm-greeter-client.c
+++ b/gui/simple-greeter/gdm-greeter-client.c
@@ -135,6 +135,37 @@ emit_string_and_int_signal_for_message (GdmGreeterClient *client,
}
static void
+emit_string_and_string_signal_for_message (GdmGreeterClient *client,
+ const char *name,
+ DBusMessage *message,
+ int signal)
+{
+ DBusError error;
+ char *text1;
+ char *text2;
+ dbus_bool_t res;
+
+ dbus_error_init (&error);
+ res = dbus_message_get_args (message,
+ &error,
+ DBUS_TYPE_STRING, &text1,
+ DBUS_TYPE_STRING, &text2,
+ DBUS_TYPE_INVALID);
+ if (res) {
+
+ g_debug ("GdmGreeterClient: Received %s (%s, %s)", name, text1, text2);
+
+ g_signal_emit (client,
+ gdm_greeter_client_signals[signal],
+ 0, text1, text2);
+ } else {
+ g_warning ("Unable to get arguments: %s", error.message);
+ dbus_error_free (&error);
+ }
+ dbus_error_free (&error);
+}
+
+static void
emit_string_signal_for_message (GdmGreeterClient *client,
const char *name,
DBusMessage *message,
@@ -201,37 +232,35 @@ static void
on_user_authorized (GdmGreeterClient *client,
DBusMessage *message)
{
- g_signal_emit (client,
- gdm_greeter_client_signals[USER_AUTHORIZED],
- 0);
+ emit_string_signal_for_message (client, "UserAuthorized", message, USER_AUTHORIZED);
}
static void
on_info_query (GdmGreeterClient *client,
DBusMessage *message)
{
- emit_string_signal_for_message (client, "InfoQuery", message, INFO_QUERY);
+ emit_string_and_string_signal_for_message (client, "InfoQuery", message, INFO_QUERY);
}
static void
on_secret_info_query (GdmGreeterClient *client,
DBusMessage *message)
{
- emit_string_signal_for_message (client, "SecretInfoQuery", message, SECRET_INFO_QUERY);
+ emit_string_and_string_signal_for_message (client, "SecretInfoQuery", message, SECRET_INFO_QUERY);
}
static void
on_info (GdmGreeterClient *client,
DBusMessage *message)
{
- emit_string_signal_for_message (client, "Info", message, INFO);
+ emit_string_and_string_signal_for_message (client, "Info", message, INFO);
}
static void
on_problem (GdmGreeterClient *client,
DBusMessage *message)
{
- emit_string_signal_for_message (client, "Problem", message, PROBLEM);
+ emit_string_and_string_signal_for_message (client, "Problem", message, PROBLEM);
}
static void
@@ -319,14 +348,22 @@ send_dbus_string_method (DBusConnection *connection,
}
static gboolean
-send_dbus_bool_method (DBusConnection *connection,
- const char *method,
- gboolean payload)
+send_dbus_string_and_bool_method (DBusConnection *connection,
+ const char *method,
+ const char *string_payload,
+ gboolean bool_payload)
{
DBusError error;
DBusMessage *message;
DBusMessage *reply;
DBusMessageIter iter;
+ const char *str;
+
+ if (string_payload != NULL) {
+ str = string_payload;
+ } else {
+ str = "";
+ }
g_debug ("GdmGreeterClient: Calling %s", method);
message = dbus_message_new_method_call (NULL,
@@ -340,8 +377,77 @@ send_dbus_bool_method (DBusConnection *connection,
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter,
+ DBUS_TYPE_STRING,
+ &str);
+
+ dbus_message_iter_append_basic (&iter,
DBUS_TYPE_BOOLEAN,
- &payload);
+ &bool_payload);
+
+ dbus_error_init (&error);
+ reply = dbus_connection_send_with_reply_and_block (connection,
+ message,
+ -1,
+ &error);
+
+ dbus_message_unref (message);
+
+ if (dbus_error_is_set (&error)) {
+ g_warning ("%s %s raised: %s\n",
+ method,
+ error.name,
+ error.message);
+ return FALSE;
+ }
+ if (reply != NULL) {
+ dbus_message_unref (reply);
+ }
+ dbus_connection_flush (connection);
+
+ return TRUE;
+}
+
+static gboolean
+send_dbus_string_and_string_method (DBusConnection *connection,
+ const char *method,
+ const char *payload1,
+ const char *payload2)
+{
+ DBusError error;
+ DBusMessage *message;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ const char *str;
+
+ g_debug ("GdmGreeterClient: Calling %s", method);
+ message = dbus_message_new_method_call (NULL,
+ GREETER_SERVER_DBUS_PATH,
+ GREETER_SERVER_DBUS_INTERFACE,
+ method);
+ if (message == NULL) {
+ g_warning ("Couldn't allocate the D-Bus message");
+ return FALSE;
+ }
+
+ dbus_message_iter_init_append (message, &iter);
+
+ if (payload1 != NULL) {
+ str = payload1;
+ } else {
+ str = "";
+ }
+ dbus_message_iter_append_basic (&iter,
+ DBUS_TYPE_STRING,
+ &str);
+
+ if (payload2 != NULL) {
+ str = payload2;
+ } else {
+ str = "";
+ }
+ dbus_message_iter_append_basic (&iter,
+ DBUS_TYPE_STRING,
+ &str);
dbus_error_init (&error);
reply = dbus_connection_send_with_reply_and_block (connection,
@@ -424,37 +530,44 @@ gdm_greeter_client_call_begin_auto_login (GdmGreeterClient *client,
}
void
-gdm_greeter_client_call_begin_verification (GdmGreeterClient *client)
+gdm_greeter_client_call_begin_verification (GdmGreeterClient *client,
+ const char *service_name)
{
- send_dbus_void_method (client->priv->connection,
- "BeginVerification");
+ send_dbus_string_method (client->priv->connection,
+ "BeginVerification", service_name);
}
void
gdm_greeter_client_call_begin_verification_for_user (GdmGreeterClient *client,
+ const char *service_name,
const char *username)
{
- send_dbus_string_method (client->priv->connection,
- "BeginVerificationForUser",
- username);
+ send_dbus_string_and_string_method (client->priv->connection,
+ "BeginVerificationForUser",
+ service_name,
+ username);
}
void
gdm_greeter_client_call_answer_query (GdmGreeterClient *client,
+ const char *service_name,
const char *text)
{
- send_dbus_string_method (client->priv->connection,
- "AnswerQuery",
- text);
+ send_dbus_string_and_string_method (client->priv->connection,
+ "AnswerQuery",
+ service_name,
+ text);
}
void
gdm_greeter_client_call_start_session_when_ready (GdmGreeterClient *client,
+ const char *service_name,
gboolean should_start_session)
{
- send_dbus_bool_method (client->priv->connection,
- "StartSessionWhenReady",
- should_start_session);
+ send_dbus_string_and_bool_method (client->priv->connection,
+ "StartSessionWhenReady",
+ service_name,
+ should_start_session);
}
void
@@ -849,10 +962,10 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass)
G_STRUCT_OFFSET (GdmGreeterClientClass, info_query),
NULL,
NULL,
- g_cclosure_marshal_VOID__STRING,
+ gdm_marshal_VOID__STRING_STRING,
G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
+ 2,
+ G_TYPE_STRING, G_TYPE_STRING);
gdm_greeter_client_signals[SECRET_INFO_QUERY] =
g_signal_new ("secret-info-query",
@@ -861,10 +974,10 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass)
G_STRUCT_OFFSET (GdmGreeterClientClass, secret_info_query),
NULL,
NULL,
- g_cclosure_marshal_VOID__STRING,
+ gdm_marshal_VOID__STRING_STRING,
G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
+ 2,
+ G_TYPE_STRING, G_TYPE_STRING);
gdm_greeter_client_signals[INFO] =
g_signal_new ("info",
@@ -873,10 +986,10 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass)
G_STRUCT_OFFSET (GdmGreeterClientClass, info),
NULL,
NULL,
- g_cclosure_marshal_VOID__STRING,
+ gdm_marshal_VOID__STRING_STRING,
G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
+ 2,
+ G_TYPE_STRING, G_TYPE_STRING);
gdm_greeter_client_signals[PROBLEM] =
g_signal_new ("problem",
@@ -885,10 +998,10 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass)
G_STRUCT_OFFSET (GdmGreeterClientClass, problem),
NULL,
NULL,
- g_cclosure_marshal_VOID__STRING,
+ gdm_marshal_VOID__STRING_STRING,
G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
+ 2,
+ G_TYPE_STRING, G_TYPE_STRING);
gdm_greeter_client_signals[READY] =
g_signal_new ("ready",
@@ -980,8 +1093,9 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass)
G_STRUCT_OFFSET (GdmGreeterClientClass, user_authorized),
NULL,
NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1, G_TYPE_STRING);
}
static void
diff --git a/gui/simple-greeter/gdm-greeter-client.h b/gui/simple-greeter/gdm-greeter-client.h
index e08aaa5..2f27503 100644
--- a/gui/simple-greeter/gdm-greeter-client.h
+++ b/gui/simple-greeter/gdm-greeter-client.h
@@ -45,17 +45,22 @@ typedef struct
GObjectClass parent_class;
void (* info_query) (GdmGreeterClient *client,
+ const char *service_name,
const char *query_text);
void (* secret_info_query) (GdmGreeterClient *client,
+ const char *service_name,
const char *query_text);
void (* info) (GdmGreeterClient *client,
+ const char *service_name,
const char *info);
void (* problem) (GdmGreeterClient *client,
+ const char *service_name,
const char *problem);
- void (* ready) (GdmGreeterClient *client);
+ void (* ready) (GdmGreeterClient *client,
+ const char *service_name);
void (* reset) (GdmGreeterClient *client);
void (* authentication_failed) (GdmGreeterClient *client);
void (* selected_user_changed) (GdmGreeterClient *client,
@@ -70,7 +75,8 @@ typedef struct
void (* timed_login_requested) (GdmGreeterClient *client,
const char *username,
int delay);
- void (* user_authorized) (GdmGreeterClient *client);
+ void (* user_authorized) (GdmGreeterClient *client,
+ const char *service_name);
} GdmGreeterClientClass;
#define GDM_GREETER_CLIENT_ERROR (gdm_greeter_client_error_quark ())
@@ -96,8 +102,10 @@ void gdm_greeter_client_call_start_conversation (GdmGreeter
const char *service_name);
void gdm_greeter_client_call_begin_auto_login (GdmGreeterClient *client,
const char *username);
-void gdm_greeter_client_call_begin_verification (GdmGreeterClient *client);
+void gdm_greeter_client_call_begin_verification (GdmGreeterClient *client,
+ const char *service_name);
void gdm_greeter_client_call_begin_verification_for_user (GdmGreeterClient *client,
+ const char *service_name,
const char *username);
void gdm_greeter_client_call_cancel (GdmGreeterClient *client);
void gdm_greeter_client_call_disconnect (GdmGreeterClient *client);
@@ -112,9 +120,11 @@ void gdm_greeter_client_call_select_layout (GdmGreeter
void gdm_greeter_client_call_select_session (GdmGreeterClient *client,
const char *text);
void gdm_greeter_client_call_answer_query (GdmGreeterClient *client,
+ const char *service_name,
const char *text);
void gdm_greeter_client_call_start_session_when_ready (GdmGreeterClient *client,
+ const char *service_name,
gboolean should_start_session);
diff --git a/gui/simple-greeter/gdm-greeter-session.c b/gui/simple-greeter/gdm-greeter-session.c
index 63de620..b7e7f1c 100644
--- a/gui/simple-greeter/gdm-greeter-session.c
+++ b/gui/simple-greeter/gdm-greeter-session.c
@@ -69,6 +69,7 @@ static gpointer session_object = NULL;
static void
on_info (GdmGreeterClient *client,
+ const char *service_name,
const char *text,
GdmGreeterSession *session)
{
@@ -79,6 +80,7 @@ on_info (GdmGreeterClient *client,
static void
on_problem (GdmGreeterClient *client,
+ const char *service_name,
const char *text,
GdmGreeterSession *session)
{
@@ -202,6 +204,7 @@ on_user_authorized (GdmGreeterClient *client,
static void
on_info_query (GdmGreeterClient *client,
+ const char *service_name,
const char *text,
GdmGreeterSession *session)
{
@@ -212,6 +215,7 @@ on_info_query (GdmGreeterClient *client,
static void
on_secret_info_query (GdmGreeterClient *client,
+ const char *service_name,
const char *text,
GdmGreeterSession *session)
{
@@ -233,7 +237,8 @@ static void
on_begin_verification (GdmGreeterLoginWindow *login_window,
GdmGreeterSession *session)
{
- gdm_greeter_client_call_begin_verification (session->priv->client);
+ gdm_greeter_client_call_begin_verification (session->priv->client,
+ "gdm");
}
static void
@@ -242,6 +247,7 @@ on_begin_verification_for_user (GdmGreeterLoginWindow *login_window,
GdmGreeterSession *session)
{
gdm_greeter_client_call_begin_verification_for_user (session->priv->client,
+ "gdm",
username);
}
@@ -251,6 +257,7 @@ on_query_answer (GdmGreeterLoginWindow *login_window,
GdmGreeterSession *session)
{
gdm_greeter_client_call_answer_query (session->priv->client,
+ "gdm",
text);
}
@@ -308,7 +315,7 @@ static void
on_start_session (GdmGreeterLoginWindow *login_window,
GdmGreeterSession *session)
{
- gdm_greeter_client_call_start_session_when_ready (session->priv->client, TRUE);
+ gdm_greeter_client_call_start_session_when_ready (session->priv->client, "gdm", TRUE);
}
static int
--
1.7.2.1
From 1f97db74673d35527b8003978e6a0f5717de08f4 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 28 Oct 2009 16:05:14 -0400
Subject: [PATCH 11/35] Return a different error code for "service won't work" than "auth failed"
If we bubble it up to the greeter then we should be able to have
a more sensible UI when e.g. fingerprinting isn't enabled.
---
daemon/gdm-session-worker.c | 14 +++++++++++---
daemon/gdm-session-worker.h | 1 +
2 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
index 6abd97d..ed6cacf 100644
--- a/daemon/gdm-session-worker.c
+++ b/daemon/gdm-session-worker.c
@@ -1306,8 +1306,8 @@ gdm_session_worker_initialize_pam (GdmSessionWorker *worker,
*/
g_set_error (error,
GDM_SESSION_WORKER_ERROR,
- GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
- _("error initiating conversation with authentication system: %s"),
+ GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE,
+ _("error initiating conversation with authentication system - %s"),
error_code == PAM_ABORT? _("general failure") :
error_code == PAM_BUF_ERR? _("out of memory") :
error_code == PAM_SYSTEM_ERR? _("application programmer error") :
@@ -1418,7 +1418,15 @@ gdm_session_worker_authenticate_user (GdmSessionWorker *worker,
/* blocking call, does the actual conversation */
error_code = pam_authenticate (worker->priv->pam_handle, authentication_flags);
- if (error_code != PAM_SUCCESS) {
+ if (error_code == PAM_AUTHINFO_UNAVAIL) {
+ g_debug ("GdmSessionWorker: authentication service unavailable");
+
+ g_set_error (error,
+ GDM_SESSION_WORKER_ERROR,
+ GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE,
+ "%s", pam_strerror (worker->priv->pam_handle, error_code));
+ goto out;
+ } else if (error_code != PAM_SUCCESS) {
g_debug ("GdmSessionWorker: authentication returned %d: %s", error_code, pam_strerror (worker->priv->pam_handle, error_code));
/*
diff --git a/daemon/gdm-session-worker.h b/daemon/gdm-session-worker.h
index ee5465a..b1c8285 100644
--- a/daemon/gdm-session-worker.h
+++ b/daemon/gdm-session-worker.h
@@ -41,6 +41,7 @@ typedef enum _GdmSessionWorkerError {
GDM_SESSION_WORKER_ERROR_OPENING_MESSAGE_PIPE,
GDM_SESSION_WORKER_ERROR_COMMUNICATING,
GDM_SESSION_WORKER_ERROR_WORKER_DIED,
+ GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE,
GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
GDM_SESSION_WORKER_ERROR_AUTHORIZING,
GDM_SESSION_WORKER_ERROR_OPENING_LOG_FILE,
--
1.7.2.1
From c9f24aa63b98f8a1f0af578720802f406951414d Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 28 Oct 2009 21:32:00 -0400
Subject: [PATCH 12/35] Emit "service-unavailable" from session when pam service refuses to work
---
daemon/gdm-session-direct.c | 26 +++++++++++++++++++++++---
daemon/gdm-session-private.h | 2 ++
daemon/gdm-session-relay.c | 33 +++++++++++++++++++++++++++++++++
daemon/gdm-session-worker.c | 29 ++++++++++++++++++++++-------
daemon/gdm-session.c | 21 +++++++++++++++++++++
daemon/gdm-session.h | 2 ++
6 files changed, 103 insertions(+), 10 deletions(-)
diff --git a/daemon/gdm-session-direct.c b/daemon/gdm-session-direct.c
index 13c8974..5a604bf 100644
--- a/daemon/gdm-session-direct.c
+++ b/daemon/gdm-session-direct.c
@@ -283,9 +283,27 @@ on_session_exited (GdmSession *session,
}
static DBusHandlerResult
-gdm_session_direct_handle_setup_complete (GdmSessionDirect *session,
- GdmSessionConversation *conversation,
- DBusMessage *message)
+gdm_session_direct_handle_service_unavailable (GdmSessionDirect *session,
+ GdmSessionConversation *conversation,
+ DBusMessage *message)
+{
+ DBusMessage *reply;
+
+ g_debug ("GdmSessionDirect: Emitting 'service-unavailable' signal");
+
+ reply = dbus_message_new_method_return (message);
+ dbus_connection_send (conversation->worker_connection, reply, NULL);
+ dbus_message_unref (reply);
+
+ _gdm_session_service_unavailable (GDM_SESSION (session), conversation->service_name);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+gdm_session_direct_handle_setup_complete (GdmSessionDirect *session,
+ GdmSessionConversation *conversation,
+ DBusMessage *message)
{
DBusMessage *reply;
@@ -1320,6 +1338,8 @@ session_worker_message (DBusConnection *connection,
return gdm_session_direct_handle_problem (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "CancelPendingQuery")) {
return gdm_session_direct_handle_cancel_pending_query (session, conversation, message);
+ } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "ServiceUnavailable")) {
+ return gdm_session_direct_handle_service_unavailable (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SetupComplete")) {
return gdm_session_direct_handle_setup_complete (session, conversation, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SetupFailed")) {
diff --git a/daemon/gdm-session-private.h b/daemon/gdm-session-private.h
index 36781dd..e0a810e 100644
--- a/daemon/gdm-session-private.h
+++ b/daemon/gdm-session-private.h
@@ -31,6 +31,8 @@ void _gdm_session_conversation_started (GdmSession *sessio
const char *service_name);
void _gdm_session_conversation_stopped (GdmSession *session,
const char *service_name);
+void _gdm_session_service_unavailable (GdmSession *session,
+ const char *service_name);
void _gdm_session_setup_complete (GdmSession *session,
const char *service_name);
void _gdm_session_setup_failed (GdmSession *session,
diff --git a/daemon/gdm-session-relay.c b/daemon/gdm-session-relay.c
index 98ccc51..88aee14 100644
--- a/daemon/gdm-session-relay.c
+++ b/daemon/gdm-session-relay.c
@@ -463,6 +463,34 @@ handle_problem (GdmSessionRelay *session_relay,
}
static DBusHandlerResult
+handle_service_unavailable (GdmSessionRelay *session_relay,
+ DBusConnection *connection,
+ DBusMessage *message)
+{
+ DBusMessage *reply;
+ DBusError error;
+ char *service_name;
+
+ dbus_error_init (&error);
+ if (! dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &service_name,
+ DBUS_TYPE_INVALID)) {
+ g_warning ("ERROR: %s", error.message);
+ }
+ dbus_error_free (&error);
+
+ g_debug ("GdmSessionRelay: ServiceUnavailable");
+
+ reply = dbus_message_new_method_return (message);
+ dbus_connection_send (connection, reply, NULL);
+ dbus_message_unref (reply);
+
+ _gdm_session_service_unavailable (GDM_SESSION (session_relay), service_name);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
handle_setup_complete (GdmSessionRelay *session_relay,
DBusConnection *connection,
DBusMessage *message)
@@ -841,6 +869,8 @@ session_handle_child_message (DBusConnection *connection,
return handle_info (session_relay, connection, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_RELAY_DBUS_INTERFACE, "Problem")) {
return handle_problem (session_relay, connection, message);
+ } else if (dbus_message_is_method_call (message, GDM_SESSION_RELAY_DBUS_INTERFACE, "ServiceUnavailable")) {
+ return handle_service_unavailable (session_relay, connection, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_RELAY_DBUS_INTERFACE, "SetupComplete")) {
return handle_setup_complete (session_relay, connection, message);
} else if (dbus_message_is_method_call (message, GDM_SESSION_RELAY_DBUS_INTERFACE, "SetupFailed")) {
@@ -898,6 +928,9 @@ do_introspect (DBusConnection *connection,
" <method name=\"ConversationStarted\">\n"
" <arg name=\"service_name\" direction=\"in\" type=\"s\"/>\n"
" </method>\n"
+ " <method name=\"ServiceUnavailable\">\n"
+ " <arg name=\"message\" direction=\"in\" type=\"s\"/>\n"
+ " </method>\n"
" <method name=\"SetupComplete\">\n"
" </method>\n"
" <method name=\"SetupFailed\">\n"
diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
index ed6cacf..8e1fa80 100644
--- a/daemon/gdm-session-worker.c
+++ b/daemon/gdm-session-worker.c
@@ -2382,9 +2382,16 @@ do_setup (GdmSessionWorker *worker)
worker->priv->display_device,
&error);
if (! res) {
- send_dbus_string_method (worker->priv->connection,
- "SetupFailed",
- error->message);
+ if (g_error_matches (error,
+ GDM_SESSION_WORKER_ERROR,
+ GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE)) {
+ send_dbus_void_method (worker->priv->connection,
+ "ServiceUnavailable");
+ } else {
+ send_dbus_string_method (worker->priv->connection,
+ "SetupFailed",
+ error->message);
+ }
g_error_free (error);
return;
}
@@ -2405,10 +2412,18 @@ do_authenticate (GdmSessionWorker *worker)
worker->priv->password_is_required,
&error);
if (! res) {
- g_debug ("GdmSessionWorker: Unable to verify user");
- send_dbus_string_method (worker->priv->connection,
- "AuthenticationFailed",
- error->message);
+ if (g_error_matches (error,
+ GDM_SESSION_WORKER_ERROR,
+ GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE)) {
+ g_debug ("GdmSessionWorker: Unable to use authentication service");
+ send_dbus_void_method (worker->priv->connection,
+ "ServiceUnavailable");
+ } else {
+ g_debug ("GdmSessionWorker: Unable to verify user");
+ send_dbus_string_method (worker->priv->connection,
+ "AuthenticationFailed",
+ error->message);
+ }
g_error_free (error);
return;
}
diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c
index 8858071..8c4548a 100644
--- a/daemon/gdm-session.c
+++ b/daemon/gdm-session.c
@@ -31,6 +31,7 @@
enum {
CONVERSATION_STARTED = 0,
CONVERSATION_STOPPED,
+ SERVICE_UNAVAILABLE,
SETUP_COMPLETE,
SETUP_FAILED,
RESET_COMPLETE,
@@ -251,6 +252,17 @@ gdm_session_class_init (gpointer g_iface)
g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE,
1, G_TYPE_STRING);
+ signals [SERVICE_UNAVAILABLE] =
+ g_signal_new ("service-unavailable",
+ iface_type,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmSessionIface, service_unavailable),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
signals [SETUP_COMPLETE] =
g_signal_new ("setup-complete",
iface_type,
@@ -525,6 +537,15 @@ gdm_session_class_init (gpointer g_iface)
}
void
+_gdm_session_service_unavailable (GdmSession *session,
+ const char *service_name)
+{
+ g_return_if_fail (GDM_IS_SESSION (session));
+
+ g_signal_emit (session, signals [SERVICE_UNAVAILABLE], 0, service_name);
+}
+
+void
_gdm_session_setup_complete (GdmSession *session,
const char *service_name)
{
diff --git a/daemon/gdm-session.h b/daemon/gdm-session.h
index 22c2ccb..9636b92 100644
--- a/daemon/gdm-session.h
+++ b/daemon/gdm-session.h
@@ -49,6 +49,8 @@ struct _GdmSessionIface
const char *service_name);
void (* stop_conversation) (GdmSession *session,
const char *service_name);
+ void (* service_unavailable) (GdmSession *session,
+ const char *service_name);
void (* setup) (GdmSession *session,
const char *service_name);
void (* setup_for_user) (GdmSession *session,
--
1.7.2.1
From d498108160a5afe7e886016fd0e892f8d06e0fd4 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 28 Oct 2009 21:38:52 -0400
Subject: [PATCH 13/35] Bubble service-unavailable up to greeter
---
daemon/gdm-greeter-server.c | 13 +++++++++++--
daemon/gdm-greeter-server.h | 5 ++++-
daemon/gdm-simple-slave.c | 36 ++++++++++++++----------------------
3 files changed, 29 insertions(+), 25 deletions(-)
diff --git a/daemon/gdm-greeter-server.c b/daemon/gdm-greeter-server.c
index 50e4193..4a011da 100644
--- a/daemon/gdm-greeter-server.c
+++ b/daemon/gdm-greeter-server.c
@@ -286,9 +286,18 @@ gdm_greeter_server_problem (GdmGreeterServer *greeter_server,
}
gboolean
-gdm_greeter_server_authentication_failed (GdmGreeterServer *greeter_server)
+gdm_greeter_server_authentication_failed (GdmGreeterServer *greeter_server,
+ const char *service_name)
{
- send_dbus_void_signal (greeter_server, "AuthenticationFailed");
+ send_dbus_string_signal (greeter_server, "AuthenticationFailed", service_name);
+ return TRUE;
+}
+
+gboolean
+gdm_greeter_server_service_unavailable (GdmGreeterServer *greeter_server,
+ const char *service_name)
+{
+ send_dbus_string_signal (greeter_server, "ServiceUnavailable", service_name);
return TRUE;
}
diff --git a/daemon/gdm-greeter-server.h b/daemon/gdm-greeter-server.h
index 5af32fd..ff1ff5d 100644
--- a/daemon/gdm-greeter-server.h
+++ b/daemon/gdm-greeter-server.h
@@ -93,7 +93,10 @@ gboolean gdm_greeter_server_info (GdmGreeterServer *
gboolean gdm_greeter_server_problem (GdmGreeterServer *greeter_server,
const char *service_name,
const char *text);
-gboolean gdm_greeter_server_authentication_failed (GdmGreeterServer *greeter_server);
+gboolean gdm_greeter_server_authentication_failed (GdmGreeterServer *greeter_server,
+ const char *service_name);
+gboolean gdm_greeter_server_service_unavailable (GdmGreeterServer *greeter_server,
+ const char *service_name);
gboolean gdm_greeter_server_reset (GdmGreeterServer *greeter_server);
gboolean gdm_greeter_server_ready (GdmGreeterServer *greeter_server,
const char *service_name);
diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c
index adcb94a..8e15584 100644
--- a/daemon/gdm-simple-slave.c
+++ b/daemon/gdm-simple-slave.c
@@ -197,22 +197,6 @@ greeter_reset_timeout (GdmSimpleSlave *slave)
return FALSE;
}
-static gboolean
-auth_failed_reset_timeout (GdmSimpleSlave *slave)
-{
- g_debug ("GdmSimpleSlave: auth failed resetting slave");
-
- if (slave->priv->greeter_server != NULL) {
- gdm_greeter_server_authentication_failed (slave->priv->greeter_server);
- reset_session (slave);
- } else {
- start_greeter (slave);
- create_new_session (slave);
- }
- slave->priv->greeter_reset_id = 0;
- return FALSE;
-}
-
static void
queue_greeter_reset (GdmSimpleSlave *slave)
{
@@ -224,14 +208,16 @@ queue_greeter_reset (GdmSimpleSlave *slave)
}
static void
-queue_auth_failed_reset (GdmSimpleSlave *slave)
+on_session_service_unavailable (GdmSession *session,
+ const char *service_name,
+ GdmSimpleSlave *slave)
{
- /* use the greeter reset idle id so we don't do both at once */
- if (slave->priv->greeter_reset_id > 0) {
- return;
+ if (slave->priv->greeter_server != NULL) {
+ gdm_greeter_server_service_unavailable (slave->priv->greeter_server,
+ service_name);
}
- slave->priv->greeter_reset_id = g_idle_add ((GSourceFunc)auth_failed_reset_timeout, slave);
+ gdm_session_stop_conversation (session, service_name);
}
static void
@@ -294,7 +280,6 @@ on_session_authentication_failed (GdmSession *session,
g_debug ("GdmSimpleSlave: Authentication failed - may retry");
gdm_session_stop_conversation (session, service_name);
- queue_auth_failed_reset (slave);
}
static void
@@ -730,6 +715,10 @@ create_new_session (GdmSimpleSlave *slave)
G_CALLBACK (on_session_conversation_stopped),
slave);
g_signal_connect (slave->priv->session,
+ "service-unavailable",
+ G_CALLBACK (on_session_service_unavailable),
+ slave);
+ g_signal_connect (slave->priv->session,
"setup-complete",
G_CALLBACK (on_session_setup_complete),
slave);
@@ -844,6 +833,9 @@ destroy_session (GdmSimpleSlave *slave)
G_CALLBACK (on_session_conversation_stopped),
slave);
g_signal_handlers_disconnect_by_func (slave->priv->session,
+ G_CALLBACK (on_session_service_unavailable),
+ slave);
+ g_signal_handlers_disconnect_by_func (slave->priv->session,
G_CALLBACK (on_session_setup_complete),
slave);
g_signal_handlers_disconnect_by_func (slave->priv->session,
--
1.7.2.1
From f2155acde772064f387e49932bd900962bb22f05 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 28 Oct 2009 21:46:39 -0400
Subject: [PATCH 14/35] Catch service-unavailable from server in client and propagate it
---
gui/simple-greeter/gdm-greeter-client.c | 20 ++++++++++++++++++++
gui/simple-greeter/gdm-greeter-client.h | 2 ++
2 files changed, 22 insertions(+), 0 deletions(-)
diff --git a/gui/simple-greeter/gdm-greeter-client.c b/gui/simple-greeter/gdm-greeter-client.c
index e42ab1e..ad3ec7e 100644
--- a/gui/simple-greeter/gdm-greeter-client.c
+++ b/gui/simple-greeter/gdm-greeter-client.c
@@ -63,6 +63,7 @@ enum {
PROBLEM,
INFO_QUERY,
SECRET_INFO_QUERY,
+ SERVICE_UNAVAILABLE,
READY,
RESET,
AUTHENTICATION_FAILED,
@@ -264,6 +265,13 @@ on_problem (GdmGreeterClient *client,
}
static void
+on_service_unavailable (GdmGreeterClient *client,
+ DBusMessage *message)
+{
+ emit_string_signal_for_message (client, "ServiceUnavailable", message, SERVICE_UNAVAILABLE);
+}
+
+static void
on_ready (GdmGreeterClient *client,
DBusMessage *message)
{
@@ -770,6 +778,8 @@ client_dbus_handle_message (DBusConnection *connection,
on_info (client, message);
} else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "Problem")) {
on_problem (client, message);
+ } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "ServiceUnavailable")) {
+ on_service_unavailable (client, message);
} else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "Ready")) {
on_ready (client, message);
} else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "Reset")) {
@@ -1003,6 +1013,16 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass)
2,
G_TYPE_STRING, G_TYPE_STRING);
+ gdm_greeter_client_signals[SERVICE_UNAVAILABLE] =
+ g_signal_new ("service-unavailable",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmGreeterClientClass, service_unavailable),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1, G_TYPE_STRING);
+
gdm_greeter_client_signals[READY] =
g_signal_new ("ready",
G_OBJECT_CLASS_TYPE (object_class),
diff --git a/gui/simple-greeter/gdm-greeter-client.h b/gui/simple-greeter/gdm-greeter-client.h
index 2f27503..917ca9c 100644
--- a/gui/simple-greeter/gdm-greeter-client.h
+++ b/gui/simple-greeter/gdm-greeter-client.h
@@ -59,6 +59,8 @@ typedef struct
void (* problem) (GdmGreeterClient *client,
const char *service_name,
const char *problem);
+ void (* service_unavailable) (GdmGreeterClient *client,
+ const char *service_name);
void (* ready) (GdmGreeterClient *client,
const char *service_name);
void (* reset) (GdmGreeterClient *client);
--
1.7.2.1
From da4dae9c2483b74e7e949984f5c2fabd4ae683da Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 5 Feb 2009 15:20:25 -0500
Subject: [PATCH 15/35] Queue a greeter reset when the user clicks cancel
---
daemon/gdm-simple-slave.c | 34 ++++++++++++++++++++++++++++++++++
1 files changed, 34 insertions(+), 0 deletions(-)
diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c
index 8e15584..43eac10 100644
--- a/daemon/gdm-simple-slave.c
+++ b/daemon/gdm-simple-slave.c
@@ -959,6 +959,9 @@ on_greeter_start_conversation (GdmGreeterServer *greeter_server,
GdmSimpleSlave *slave)
{
g_debug ("GdmSimpleSlave: starting conversation with '%s' pam service'", service_name);
+ if (slave->priv->greeter_reset_id > 0) {
+ return;
+ }
gdm_session_start_conversation (GDM_SESSION (slave->priv->session),
service_name);
}
@@ -969,6 +972,9 @@ on_greeter_begin_verification (GdmGreeterServer *greeter_server,
GdmSimpleSlave *slave)
{
g_debug ("GdmSimpleSlave: begin verification");
+ if (slave->priv->greeter_reset_id > 0) {
+ return;
+ }
gdm_session_setup (GDM_SESSION (slave->priv->session),
service_name);
}
@@ -979,6 +985,9 @@ on_greeter_begin_auto_login (GdmGreeterServer *greeter_server,
GdmSimpleSlave *slave)
{
g_debug ("GdmSimpleSlave: begin auto login for user '%s'", username);
+ if (slave->priv->greeter_reset_id > 0) {
+ return;
+ }
gdm_session_setup_for_user (GDM_SESSION (slave->priv->session),
"gdm-autologin",
username);
@@ -991,6 +1000,9 @@ on_greeter_begin_verification_for_user (GdmGreeterServer *greeter_server,
GdmSimpleSlave *slave)
{
g_debug ("GdmSimpleSlave: begin verification");
+ if (slave->priv->greeter_reset_id > 0) {
+ return;
+ }
gdm_session_setup_for_user (GDM_SESSION (slave->priv->session),
service_name,
username);
@@ -1002,6 +1014,9 @@ on_greeter_answer (GdmGreeterServer *greeter_server,
const char *text,
GdmSimpleSlave *slave)
{
+ if (slave->priv->greeter_reset_id > 0) {
+ return;
+ }
gdm_session_answer_query (GDM_SESSION (slave->priv->session), service_name, text);
}
@@ -1010,6 +1025,9 @@ on_greeter_session_selected (GdmGreeterServer *greeter_server,
const char *text,
GdmSimpleSlave *slave)
{
+ if (slave->priv->greeter_reset_id > 0) {
+ return;
+ }
gdm_session_select_session (GDM_SESSION (slave->priv->session), text);
}
@@ -1018,6 +1036,9 @@ on_greeter_language_selected (GdmGreeterServer *greeter_server,
const char *text,
GdmSimpleSlave *slave)
{
+ if (slave->priv->greeter_reset_id > 0) {
+ return;
+ }
gdm_session_select_language (GDM_SESSION (slave->priv->session), text);
}
@@ -1026,6 +1047,9 @@ on_greeter_layout_selected (GdmGreeterServer *greeter_server,
const char *text,
GdmSimpleSlave *slave)
{
+ if (slave->priv->greeter_reset_id > 0) {
+ return;
+ }
gdm_session_select_layout (GDM_SESSION (slave->priv->session), text);
}
@@ -1042,6 +1066,7 @@ on_greeter_cancel (GdmGreeterServer *greeter_server,
GdmSimpleSlave *slave)
{
g_debug ("GdmSimpleSlave: Greeter cancelled");
+
queue_greeter_reset (slave);
}
@@ -1052,6 +1077,9 @@ on_greeter_connected (GdmGreeterServer *greeter_server,
gboolean display_is_local;
g_debug ("GdmSimpleSlave: Greeter connected");
+ if (slave->priv->greeter_reset_id > 0) {
+ return;
+ }
g_object_get (slave,
"display-is-local", &display_is_local,
@@ -1069,6 +1097,9 @@ on_start_session_when_ready (GdmGreeterServer *session,
GdmSimpleSlave *slave)
{
g_debug ("GdmSimpleSlave: Will start session when ready");
+ if (slave->priv->greeter_reset_id > 0) {
+ return;
+ }
slave->priv->start_session_when_ready = TRUE;
if (slave->priv->waiting_to_start_session) {
@@ -1082,6 +1113,9 @@ on_start_session_later (GdmGreeterServer *session,
GdmSimpleSlave *slave)
{
g_debug ("GdmSimpleSlave: Will start session when ready and told");
+ if (slave->priv->greeter_reset_id > 0) {
+ return;
+ }
slave->priv->start_session_when_ready = FALSE;
}
--
1.7.2.1
From f5179490872ab7335a672e7de108150ec4c145da Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 6 Nov 2009 13:35:26 -0500
Subject: [PATCH 16/35] Don't delay login for passwd -d users
Before we'd delay login if timed login was enabled, but
we should have been checking if it was the reason login
was happening.
---
gui/simple-greeter/gdm-greeter-login-window.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
index 95371b8..a0caff9 100644
--- a/gui/simple-greeter/gdm-greeter-login-window.c
+++ b/gui/simple-greeter/gdm-greeter-login-window.c
@@ -840,7 +840,7 @@ gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_
* so they can pick language/session. Will need to refactor things
* a bit so we can share code with timed login.
*/
- if (!login_window->priv->timed_login_enabled) {
+ if (strcmp (service_name, "gdm-autologin") != 0) {
g_debug ("GdmGreeterLoginWindow: Okay, we'll start the session anyway,"
"because the user isn't ever going to get an opportunity to"
--
1.7.2.1
From 41a2faa25a9424f6f4c9cffde9ea996fef4919c9 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 30 Jan 2009 23:57:31 -0500
Subject: [PATCH 17/35] Add a plugin based extension system to greeter
This allows plugins to drive which PAM conversations
get run. This commit just adds one plugin "password"
which does the one PAM conversation we've traditionally
run.
---
common/gdm-marshal.list | 1 +
configure.ac | 44 +
gui/simple-greeter/Makefile.am | 19 +
gui/simple-greeter/gdm-greeter-client.c | 21 +
gui/simple-greeter/gdm-greeter-client.h | 2 +
gui/simple-greeter/gdm-greeter-login-window.c | 1061 +++++++++++++++++---
gui/simple-greeter/gdm-greeter-login-window.h | 36 +-
gui/simple-greeter/gdm-greeter-login-window.ui | 67 +-
gui/simple-greeter/gdm-greeter-plugin.c | 255 +++++
gui/simple-greeter/gdm-greeter-plugin.h | 61 ++
gui/simple-greeter/gdm-greeter-session.c | 161 +++-
gui/simple-greeter/gdm-plugin-manager.c | 478 +++++++++
gui/simple-greeter/gdm-plugin-manager.h | 66 ++
gui/simple-greeter/gdm-task-list.c | 385 +++++++
gui/simple-greeter/gdm-task-list.h | 85 ++
gui/simple-greeter/gdm-user-chooser-widget.c | 23 +-
gui/simple-greeter/libgdmsimplegreeter/Makefile.am | 48 +
.../libgdmsimplegreeter/gdm-conversation.c | 186 ++++
.../libgdmsimplegreeter/gdm-conversation.h | 93 ++
.../libgdmsimplegreeter/gdm-greeter-extension.c | 93 ++
.../libgdmsimplegreeter/gdm-greeter-extension.h | 55 +
gui/simple-greeter/libgdmsimplegreeter/gdm-task.c | 129 +++
gui/simple-greeter/libgdmsimplegreeter/gdm-task.h | 66 ++
.../libgdmsimplegreeter/gdmsimplegreeter.pc.in | 11 +
gui/simple-greeter/plugins/Makefile.am | 1 +
gui/simple-greeter/plugins/password/Makefile.am | 53 +
.../plugins/password/gdm-password-extension.c | 328 ++++++
.../plugins/password/gdm-password-extension.h | 56 +
.../plugins/password/gdm-password.pam | 19 +
gui/simple-greeter/plugins/password/page.ui | 57 ++
gui/simple-greeter/plugins/password/plugin.c | 40 +
po/POTFILES.in | 1 +
32 files changed, 3749 insertions(+), 252 deletions(-)
create mode 100644 gui/simple-greeter/gdm-greeter-plugin.c
create mode 100644 gui/simple-greeter/gdm-greeter-plugin.h
create mode 100644 gui/simple-greeter/gdm-plugin-manager.c
create mode 100644 gui/simple-greeter/gdm-plugin-manager.h
create mode 100644 gui/simple-greeter/gdm-task-list.c
create mode 100644 gui/simple-greeter/gdm-task-list.h
create mode 100644 gui/simple-greeter/libgdmsimplegreeter/Makefile.am
create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c
create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h
create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdm-greeter-extension.c
create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdm-greeter-extension.h
create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdm-task.c
create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdm-task.h
create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdmsimplegreeter.pc.in
create mode 100644 gui/simple-greeter/plugins/Makefile.am
create mode 100644 gui/simple-greeter/plugins/password/Makefile.am
create mode 100644 gui/simple-greeter/plugins/password/gdm-password-extension.c
create mode 100644 gui/simple-greeter/plugins/password/gdm-password-extension.h
create mode 100644 gui/simple-greeter/plugins/password/gdm-password.pam
create mode 100644 gui/simple-greeter/plugins/password/page.ui
create mode 100644 gui/simple-greeter/plugins/password/plugin.c
diff --git a/common/gdm-marshal.list b/common/gdm-marshal.list
index d5455e1..d8a9e72 100644
--- a/common/gdm-marshal.list
+++ b/common/gdm-marshal.list
@@ -5,3 +5,4 @@ VOID:STRING,STRING
VOID:UINT,UINT
VOID:STRING,INT
VOID:DOUBLE
+BOOLEAN:STRING
diff --git a/configure.ac b/configure.ac
index fd920c0..ab35800 100644
--- a/configure.ac
+++ b/configure.ac
@@ -18,6 +18,22 @@ AC_PROG_CXX
AM_PROG_CC_C_O
AC_PROG_LIBTOOL()
+## increment if the plugin interface has additions, changes, removals.
+LT_CURRENT=1
+
+## increment any time the source changes; set to
+## 0 if you increment CURRENT
+LT_REVISION=0
+
+## increment if any interfaces have been added; set to 0
+## if any interfaces have been changed or removed. removal has
+## precedence over adding, so set to 0 if both happened.
+LT_AGE=0
+
+AC_SUBST(LT_CURRENT)
+AC_SUBST(LT_REVISION)
+AC_SUBST(LT_AGE)
+
AC_HEADER_STDC
AC_SUBST(VERSION)
@@ -197,6 +213,15 @@ AC_ARG_WITH(dmconfdir,
AC_SUBST(dmconfdir)
dnl ---------------------------------------------------------------------------
+dnl - Configuration file stuff
+dnl ---------------------------------------------------------------------------
+AC_ARG_WITH(extensionsdatadir,
+ AS_HELP_STRING([--with-extensions-datadir],
+ [directory where extensions store data, default=DATADIR/gdm/simple-greeter/extensions]),
+ extensionsdatadir=${withval}, extensionsdatadir=${datadir}/gdm/simple-greeter/extensions)
+AC_SUBST(extensionsdatadir)
+
+dnl ---------------------------------------------------------------------------
dnl - Configure arguments
dnl ---------------------------------------------------------------------------
@@ -1273,6 +1298,21 @@ fi
AC_SUBST(GDM_SCREENSHOT_DIR)
+dnl ---------------------------------------------------------------------------
+dnl - Directory for simple greeter plugins
+dnl ---------------------------------------------------------------------------
+
+AC_ARG_WITH(simple-greeter-plugins-dir,
+ AS_HELP_STRING([--with-simple-greeter-plugins-dir=<dir>],
+ [simple greeter plugins directory]))
+
+if ! test -z "$with_simple_greeter_plugins_dir"; then
+ GDM_SIMPLE_GREETER_PLUGINS_DIR=$with_simple_greeter_plugins_dir
+else
+ GDM_SIMPLE_GREETER_PLUGINS_DIR=${libdir}/gdm/simple-greeter/plugins
+fi
+
+AC_SUBST(GDM_SIMPLE_GREETER_PLUGINS_DIR)
dnl ---------------------------------------------------------------------------
dnl - Finish
@@ -1401,6 +1441,10 @@ docs/Makefile
gui/Makefile
gui/simple-greeter/Makefile
gui/simple-greeter/libnotificationarea/Makefile
+gui/simple-greeter/libgdmsimplegreeter/Makefile
+gui/simple-greeter/libgdmsimplegreeter/gdmsimplegreeter.pc
+gui/simple-greeter/plugins/Makefile
+gui/simple-greeter/plugins/password/Makefile
gui/simple-chooser/Makefile
gui/user-switch-applet/Makefile
utils/Makefile
diff --git a/gui/simple-greeter/Makefile.am b/gui/simple-greeter/Makefile.am
index 6f7f3ee..b987de4 100644
--- a/gui/simple-greeter/Makefile.am
+++ b/gui/simple-greeter/Makefile.am
@@ -2,12 +2,15 @@ NULL =
SUBDIRS = \
libnotificationarea \
+ libgdmsimplegreeter \
+ plugins \
$(NULL)
AM_CPPFLAGS = \
-I$(top_srcdir)/common \
-I$(top_builddir)/common \
-I$(top_srcdir)/gui/simple-greeter/libnotificationarea \
+ -I$(top_srcdir)/gui/simple-greeter/libgdmsimplegreeter \
-DDMCONFDIR=\""$(dmconfdir)"\" \
-DGDMCONFDIR=\"$(gdmconfdir)\" \
-DDATADIR=\""$(datadir)"\" \
@@ -20,6 +23,7 @@ AM_CPPFLAGS = \
-DGDM_CACHE_DIR=\""$(localstatedir)/cache/gdm"\" \
-DAT_SPI_REGISTRYD_DIR="\"$(AT_SPI_REGISTRYD_DIR)\"" \
$(UPOWER_CFLAGS) \
+ -DGDM_SIMPLE_GREETER_PLUGINS_DIR="\"$(GDM_SIMPLE_GREETER_PLUGINS_DIR)\""\
$(DISABLE_DEPRECATED_CFLAGS) \
$(GTK_CFLAGS) \
$(SIMPLE_GREETER_CFLAGS) \
@@ -85,10 +89,17 @@ test_greeter_login_window_SOURCES = \
gdm-user-chooser-widget.c \
gdm-user-chooser-dialog.h \
gdm-user-chooser-dialog.c \
+ gdm-task-list.h \
+ gdm-task-list.c \
+ gdm-plugin-manager.h \
+ gdm-plugin-manager.c \
+ gdm-greeter-plugin.h \
+ gdm-greeter-plugin.c \
$(NULL)
test_greeter_login_window_LDADD = \
$(top_builddir)/common/libgdmcommon.la \
+ $(top_builddir)/gui/simple-greeter/libgdmsimplegreeter/libgdmsimplegreeter.la \
libgdmuser.la \
$(COMMON_LIBS) \
$(SIMPLE_GREETER_LIBS) \
@@ -139,6 +150,7 @@ test_greeter_panel_SOURCES = \
test_greeter_panel_LDADD = \
$(top_builddir)/common/libgdmcommon.la \
$(top_builddir)/gui/simple-greeter/libnotificationarea/libnotificationarea.la \
+ $(top_builddir)/gui/simple-greeter/libgdmsimplegreeter/libgdmsimplegreeter.la \
$(SIMPLE_GREETER_LIBS) \
$(GTK_LIBS) \
$(GCONF_LIBS) \
@@ -314,18 +326,25 @@ gdm_simple_greeter_SOURCES = \
gdm-language-chooser-dialog.c \
gdm-language-option-widget.h \
gdm-language-option-widget.c \
+ gdm-plugin-manager.h \
+ gdm-plugin-manager.c \
gdm-sessions.h \
gdm-sessions.c \
gdm-session-option-widget.h \
gdm-session-option-widget.c \
+ gdm-greeter-plugin.h \
+ gdm-greeter-plugin.c \
gdm-user-chooser-widget.h \
gdm-user-chooser-widget.c \
+ gdm-task-list.h \
+ gdm-task-list.c \
$(NULL)
gdm_simple_greeter_LDADD = \
$(top_builddir)/common/libgdmcommon.la \
libgdmuser.la \
$(top_builddir)/gui/simple-greeter/libnotificationarea/libnotificationarea.la \
+ $(top_builddir)/gui/simple-greeter/libgdmsimplegreeter/libgdmsimplegreeter.la \
$(COMMON_LIBS) \
$(EXTRA_GREETER_LIBS) \
$(SIMPLE_GREETER_LIBS) \
diff --git a/gui/simple-greeter/gdm-greeter-client.c b/gui/simple-greeter/gdm-greeter-client.c
index ad3ec7e..ef6fb43 100644
--- a/gui/simple-greeter/gdm-greeter-client.c
+++ b/gui/simple-greeter/gdm-greeter-client.c
@@ -65,6 +65,7 @@ enum {
SECRET_INFO_QUERY,
SERVICE_UNAVAILABLE,
READY,
+ CONVERSATION_STOPPED,
RESET,
AUTHENTICATION_FAILED,
SELECTED_USER_CHANGED,
@@ -279,6 +280,13 @@ on_ready (GdmGreeterClient *client,
}
static void
+on_conversation_stopped (GdmGreeterClient *client,
+ DBusMessage *message)
+{
+ emit_string_signal_for_message (client, "ConversationStopped", message, CONVERSATION_STOPPED);
+}
+
+static void
on_reset (GdmGreeterClient *client,
DBusMessage *message)
{
@@ -782,6 +790,8 @@ client_dbus_handle_message (DBusConnection *connection,
on_service_unavailable (client, message);
} else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "Ready")) {
on_ready (client, message);
+ } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "ConversationStopped")) {
+ on_conversation_stopped (client, message);
} else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "Reset")) {
on_reset (client, message);
} else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "AuthenticationFailed")) {
@@ -1034,6 +1044,17 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass)
G_TYPE_NONE,
1, G_TYPE_STRING);
+ gdm_greeter_client_signals[CONVERSATION_STOPPED] =
+ g_signal_new ("conversation-stopped",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmGreeterClientClass, conversation_stopped),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1, G_TYPE_STRING);
+
gdm_greeter_client_signals[RESET] =
g_signal_new ("reset",
G_OBJECT_CLASS_TYPE (object_class),
diff --git a/gui/simple-greeter/gdm-greeter-client.h b/gui/simple-greeter/gdm-greeter-client.h
index 917ca9c..3fd62d4 100644
--- a/gui/simple-greeter/gdm-greeter-client.h
+++ b/gui/simple-greeter/gdm-greeter-client.h
@@ -63,6 +63,8 @@ typedef struct
const char *service_name);
void (* ready) (GdmGreeterClient *client,
const char *service_name);
+ void (* conversation_stopped) (GdmGreeterClient *client,
+ const char *service_name);
void (* reset) (GdmGreeterClient *client);
void (* authentication_failed) (GdmGreeterClient *client);
void (* selected_user_changed) (GdmGreeterClient *client,
diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
index a0caff9..36a6d21 100644
--- a/gui/simple-greeter/gdm-greeter-login-window.c
+++ b/gui/simple-greeter/gdm-greeter-login-window.c
@@ -1,7 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
- * Copyright (C) 2008 Red Hat, Inc.
+ * Copyright (C) 2008, 2009 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,6 +17,9 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
+ * Written by: William Jon McCann <mccann@jhu.edu>
+ * Ray Strode <rstrode@redhat.com>
+ *
*/
#include "config.h"
@@ -50,12 +53,16 @@
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
+#include "gdm-marshal.h"
+
#include "gdm-settings-client.h"
#include "gdm-settings-keys.h"
#include "gdm-profile.h"
+#include "gdm-greeter-client.h"
#include "gdm-greeter-login-window.h"
#include "gdm-user-chooser-widget.h"
+#include "gdm-task-list.h"
#ifdef HAVE_PAM
#include <security/pam_appl.h>
@@ -103,13 +110,15 @@ struct GdmGreeterLoginWindowPrivate
{
GtkBuilder *builder;
GtkWidget *user_chooser;
+ GtkWidget *conversation_list;
GtkWidget *auth_banner_label;
GtkWidget *current_button;
-
+ GtkWidget *auth_page_box;
guint display_is_local : 1;
guint is_interactive : 1;
guint user_chooser_loaded : 1;
GConfClient *client;
+ GList *tasks_to_enable;
gboolean banner_message_enabled;
guint gconf_cnxn;
@@ -137,6 +146,7 @@ enum {
};
enum {
+ START_CONVERSATION,
BEGIN_AUTO_LOGIN,
BEGIN_VERIFICATION,
BEGIN_VERIFICATION_FOR_USER,
@@ -161,6 +171,8 @@ static void on_user_unchosen (GdmUserChooserWidget *user_chooser,
static void switch_mode (GdmGreeterLoginWindow *login_window,
int number);
static void update_banner_message (GdmGreeterLoginWindow *login_window);
+static void gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_window,
+ const char *service_name);
G_DEFINE_TYPE (GdmGreeterLoginWindow, gdm_greeter_login_window, GTK_TYPE_WINDOW)
@@ -186,9 +198,6 @@ set_sensitive (GdmGreeterLoginWindow *login_window,
{
GtkWidget *box;
- box = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "auth-input-box"));
- gtk_widget_set_sensitive (box, sensitive);
-
box = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "buttonbox"));
gtk_widget_set_sensitive (box, sensitive);
@@ -198,27 +207,43 @@ set_sensitive (GdmGreeterLoginWindow *login_window,
static void
set_focus (GdmGreeterLoginWindow *login_window)
{
- GtkWidget *entry;
-
- entry = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-entry"));
+ GdmTask *task;
gdk_window_focus (gtk_widget_get_window (GTK_WIDGET (login_window)), GDK_CURRENT_TIME);
- if (gtk_widget_get_realized (entry) && ! gtk_widget_has_focus (entry)) {
- gtk_widget_grab_focus (entry);
+ task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
+
+ if (task != NULL && gdm_conversation_focus (GDM_CONVERSATION (task))) {
+ char *name;
+ name = gdm_task_get_name (task);
+ g_debug ("GdmGreeterLoginWindow: focusing task %s", name);
+ g_free (name);
} else if (gtk_widget_get_realized (login_window->priv->user_chooser) && ! gtk_widget_has_focus (login_window->priv->user_chooser)) {
gtk_widget_grab_focus (login_window->priv->user_chooser);
}
+ g_object_unref (task);
+}
+
+static gboolean
+set_task_conversation_message (GdmTaskList *task_list,
+ GdmTask *task,
+ const char *message)
+{
+
+ gdm_conversation_set_message (GDM_CONVERSATION (task), message);
+ return FALSE;
}
static void
set_message (GdmGreeterLoginWindow *login_window,
const char *text)
{
- GtkWidget *label;
+ g_return_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window));
- label = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "auth-message-label"));
- gtk_label_set_text (GTK_LABEL (label), text);
+ gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+ (GdmTaskListForeachFunc)
+ set_task_conversation_message,
+ (gpointer) text);
}
static void
@@ -340,20 +365,66 @@ show_widget (GdmGreeterLoginWindow *login_window,
}
static void
-on_login_button_clicked_answer_query (GtkButton *button,
- GdmGreeterLoginWindow *login_window)
+hide_task_actions (GdmTask *task)
{
- GtkWidget *entry;
- const char *text;
+ GtkActionGroup *actions;
- set_busy (login_window);
- set_sensitive (login_window, FALSE);
+ actions = gdm_conversation_get_actions (GDM_CONVERSATION (task));
- entry = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "auth-prompt-entry"));
- text = gtk_entry_get_text (GTK_ENTRY (entry));
+ if (actions != NULL) {
+ gtk_action_group_set_visible (actions, FALSE);
+ gtk_action_group_set_sensitive (actions, FALSE);
+ g_object_unref (actions);
+ }
+}
+
+static void
+grab_default_button_for_task (GdmTask *task)
+{
+ GtkActionGroup *actions;
+ GtkAction *action;
+ GSList *proxies, *node;
+
+ actions = gdm_conversation_get_actions (GDM_CONVERSATION (task));
+
+ if (actions == NULL) {
+ return;
+ }
+
+ action = gtk_action_group_get_action (actions, GDM_CONVERSATION_DEFAULT_ACTION);
+ g_object_unref (actions);
+
+ if (action == NULL) {
+ return;
+ }
+
+ proxies = gtk_action_get_proxies (action);
+ for (node = proxies; node != NULL; node = node->next) {
+ GtkWidget *widget;
+
+ widget = GTK_WIDGET (node->data);
+
+ if (GTK_WIDGET_CAN_DEFAULT (widget) &&
+ GTK_WIDGET_VISIBLE (widget)) {
+ gtk_widget_grab_default (widget);
+ break;
+ }
+ }
- _gdm_greeter_login_window_set_interactive (login_window, TRUE);
- g_signal_emit (login_window, signals[QUERY_ANSWER], 0, text);
+}
+
+static void
+show_task_actions (GdmTask *task)
+{
+ GtkActionGroup *actions;
+
+ actions = gdm_conversation_get_actions (GDM_CONVERSATION (task));
+
+ if (actions != NULL) {
+ gtk_action_group_set_sensitive (actions, TRUE);
+ gtk_action_group_set_visible (actions, TRUE);
+ g_object_unref (actions);
+ }
}
static void
@@ -375,6 +446,7 @@ set_log_in_button_mode (GdmGreeterLoginWindow *login_window,
GtkWidget *unlock_button;
char *item;
gboolean in_use;
+ GdmTask *task;
in_use = FALSE;
item = gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (login_window->priv->user_chooser));
@@ -416,11 +488,23 @@ set_log_in_button_mode (GdmGreeterLoginWindow *login_window,
switch (mode) {
case LOGIN_BUTTON_HIDDEN:
+ task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
+ if (task != NULL) {
+ hide_task_actions (task);
+ g_object_unref (task);
+ }
+
gtk_widget_hide (button);
break;
case LOGIN_BUTTON_ANSWER_QUERY:
- login_window->priv->login_button_handler_id = g_signal_connect (button, "clicked", G_CALLBACK (on_login_button_clicked_answer_query), login_window);
- gtk_widget_show (button);
+ task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
+ if (task != NULL) {
+ show_task_actions (task);
+ grab_default_button_for_task (task);
+ g_object_unref (task);
+ }
+
+ gtk_widget_hide (button);
break;
case LOGIN_BUTTON_TIMED_LOGIN:
login_window->priv->login_button_handler_id = g_signal_connect (button, "clicked", G_CALLBACK (on_login_button_clicked_timed_login), login_window);
@@ -484,6 +568,24 @@ maybe_show_cancel_button (GdmGreeterLoginWindow *login_window)
}
static void
+update_conversation_list_visibility (GdmGreeterLoginWindow *login_window)
+{
+ int number_of_tasks;
+
+ if (login_window->priv->dialog_mode != MODE_AUTHENTICATION) {
+ gtk_widget_hide (login_window->priv->conversation_list);
+ return;
+ }
+
+ number_of_tasks = gdm_task_list_get_number_of_visible_tasks (GDM_TASK_LIST (login_window->priv->conversation_list));
+ if (number_of_tasks > 1) {
+ gtk_widget_show (login_window->priv->conversation_list);
+ } else {
+ gtk_widget_hide (login_window->priv->conversation_list);
+ }
+}
+
+static void
switch_mode (GdmGreeterLoginWindow *login_window,
int number)
{
@@ -518,6 +620,7 @@ switch_mode (GdmGreeterLoginWindow *login_window,
}
show_widget (login_window, "auth-input-box", FALSE);
+ update_conversation_list_visibility (login_window);
maybe_show_cancel_button (login_window);
/*
@@ -548,58 +651,71 @@ switch_mode (GdmGreeterLoginWindow *login_window,
}
}
-static void
-choose_user (GdmGreeterLoginWindow *login_window,
- const char *user_name)
+static gboolean
+task_has_service_name (GdmTaskList *task_list,
+ GdmTask *task,
+ const char *service_name)
{
- guint mode;
+ char *task_service_name;
+ gboolean has_service_name;
- g_assert (user_name != NULL);
+ task_service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task));
- g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED],
- 0, user_name);
+ has_service_name = strcmp (service_name, task_service_name) == 0;
+ g_free (task_service_name);
- mode = MODE_AUTHENTICATION;
- if (strcmp (user_name, GDM_USER_CHOOSER_USER_OTHER) == 0) {
- g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0);
- } else if (strcmp (user_name, GDM_USER_CHOOSER_USER_GUEST) == 0) {
- /* FIXME: handle guest account stuff */
- } else if (strcmp (user_name, GDM_USER_CHOOSER_USER_AUTO) == 0) {
- g_signal_emit (login_window, signals[BEGIN_AUTO_LOGIN], 0,
- login_window->priv->timed_login_username);
+ return has_service_name;
+}
- login_window->priv->timed_login_enabled = TRUE;
- restart_timed_login_timeout (login_window);
+static GdmTask *
+find_task_with_service_name (GdmGreeterLoginWindow *login_window,
+ const char *service_name)
+{
+ GdmTask *task;
- /* just wait for the user to select language and stuff */
- mode = MODE_TIMED_LOGIN;
- set_message (login_window, _("Select language and click Log In"));
- } else {
- g_signal_emit (login_window, signals[BEGIN_VERIFICATION_FOR_USER], 0, user_name);
- }
+ task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+ (GdmTaskListForeachFunc)
+ task_has_service_name,
+ (gpointer) service_name);
- switch_mode (login_window, mode);
+ return task;
}
-static void
-retry_login (GdmGreeterLoginWindow *login_window)
+static gboolean
+reset_task (GdmTaskList *task_list,
+ GdmTask *task,
+ GdmGreeterLoginWindow *login_window)
{
- GtkWidget *entry;
- char *user_name;
+ char *name;
- user_name = gdm_user_chooser_widget_get_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser));
- if (user_name == NULL) {
- return;
- }
+ name = gdm_task_get_name (task);
+ g_debug ("Resetting task '%s'", name);
+ g_free (name);
+
+ login_window->priv->tasks_to_enable = g_list_remove (login_window->priv->tasks_to_enable, task);
+
+ gdm_conversation_reset (GDM_CONVERSATION (task));
+ return FALSE;
+}
- g_debug ("GdmGreeterLoginWindow: Retrying login for %s", user_name);
+static gboolean
+task_is_disabled (GdmTaskList *task_list,
+ GdmTask *task)
+{
+ return !gdm_task_is_enabled (task);
+}
- entry = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-entry"));
- gtk_editable_delete_text (GTK_EDITABLE (entry), 0, -1);
+static gboolean
+tasks_are_enabled (GdmGreeterLoginWindow *login_window)
+{
+ GdmTask *task;
- choose_user (login_window, user_name);
+ task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+ (GdmTaskListForeachFunc)
+ task_is_disabled,
+ NULL);
- g_free (user_name);
+ return task == NULL;
}
static gboolean
@@ -609,6 +725,10 @@ can_jump_to_authenticate (GdmGreeterLoginWindow *login_window)
if (!login_window->priv->user_chooser_loaded) {
res = FALSE;
+ } else if (!tasks_are_enabled (login_window)) {
+ res = FALSE;
+ } else if (login_window->priv->dialog_mode == MODE_AUTHENTICATION) {
+ res = FALSE;
} else if (login_window->priv->user_list_disabled) {
res = (login_window->priv->timed_login_username == NULL);
} else {
@@ -618,11 +738,44 @@ can_jump_to_authenticate (GdmGreeterLoginWindow *login_window)
return res;
}
+static gboolean
+begin_task_verification (GdmTaskList *task_list,
+ GdmTask *task,
+ GdmGreeterLoginWindow *login_window)
+{
+ char *service_name;
+
+ if (!gdm_task_is_visible (task)) {
+ return FALSE;
+ }
+
+ service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task));
+ if (service_name != NULL) {
+ g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, service_name);
+ g_free (service_name);
+ }
+
+ return FALSE;
+}
+
+static void
+begin_verification (GdmGreeterLoginWindow *login_window)
+{
+ gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+ (GdmTaskListForeachFunc)
+ begin_task_verification,
+ login_window);
+
+ switch_mode (login_window, MODE_AUTHENTICATION);
+
+ update_conversation_list_visibility (login_window);
+}
+
+
static void
reset_dialog (GdmGreeterLoginWindow *login_window,
guint dialog_mode)
{
- GtkWidget *entry;
GtkWidget *label;
guint mode;
@@ -655,11 +808,10 @@ reset_dialog (GdmGreeterLoginWindow *login_window,
set_message (login_window, "");
}
- entry = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-entry"));
-
- gtk_editable_delete_text (GTK_EDITABLE (entry), 0, -1);
-
- gtk_entry_set_visibility (GTK_ENTRY (entry), TRUE);
+ gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+ (GdmTaskListForeachFunc)
+ reset_task,
+ login_window);
label = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-label"));
gtk_label_set_text (GTK_LABEL (label), "");
@@ -667,7 +819,10 @@ reset_dialog (GdmGreeterLoginWindow *login_window,
if (can_jump_to_authenticate (login_window)) {
/* If we don't have a user list jump straight to authenticate */
g_debug ("GdmGreeterLoginWindow: jumping straight to authenticate");
- switch_mode (login_window, MODE_AUTHENTICATION);
+
+ g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED],
+ 0, GDM_USER_CHOOSER_USER_OTHER);
+ begin_verification (login_window);
} else {
switch_mode (login_window, dialog_mode);
}
@@ -683,88 +838,177 @@ reset_dialog (GdmGreeterLoginWindow *login_window,
}
static void
-do_cancel (GdmGreeterLoginWindow *login_window)
+restart_conversations (GdmGreeterLoginWindow *login_window)
{
- /* need to wait for response from backend */
- set_message (login_window, _("Cancelling…"));
set_busy (login_window);
set_sensitive (login_window, FALSE);
g_signal_emit (login_window, signals[CANCELLED], 0);
}
+static void
+do_cancel (GdmGreeterLoginWindow *login_window)
+{
+ /* need to wait for response from backend */
+ set_message (login_window, _("Cancelling..."));
+ restart_conversations (login_window);
+}
+
gboolean
-gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window)
+gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window,
+ const char *service_name)
{
+ GdmTask *task;
+
g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
+ task = find_task_with_service_name (login_window, service_name);
+
+ if (task != NULL) {
+ if (gdm_chooser_widget_is_loaded (GDM_CHOOSER_WIDGET (login_window->priv->user_chooser))) {
+ gdm_conversation_set_ready (GDM_CONVERSATION (task));
+ } else {
+ login_window->priv->tasks_to_enable = g_list_prepend (login_window->priv->tasks_to_enable, task);
+ }
+ g_object_unref (task);
+ }
+
set_sensitive (GDM_GREETER_LOGIN_WINDOW (login_window), TRUE);
set_ready (GDM_GREETER_LOGIN_WINDOW (login_window));
set_focus (GDM_GREETER_LOGIN_WINDOW (login_window));
- /* If we are retrying a previously selected user */
- if (!login_window->priv->user_list_disabled &&
- login_window->priv->dialog_mode == MODE_AUTHENTICATION) {
- retry_login (login_window);
- } else {
- /* If the user list is disabled, then start the PAM conversation */
- if (can_jump_to_authenticate (login_window)) {
- g_debug ("Starting PAM conversation since user list disabled");
- g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED],
- 0, GDM_USER_CHOOSER_USER_OTHER);
- g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0);
- }
+ /* If the user list is disabled, then start the PAM conversation */
+ if (can_jump_to_authenticate (login_window)) {
+ g_debug ("Starting PAM conversation since user list disabled or no local users");
+ g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED],
+ 0, GDM_USER_CHOOSER_USER_OTHER);
+ begin_verification (login_window);
}
return TRUE;
}
gboolean
-gdm_greeter_login_window_authentication_failed (GdmGreeterLoginWindow *login_window)
+gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_window,
+ const char *service_name)
{
+ GdmTask *task;
+
g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
- g_debug ("GdmGreeterLoginWindow: got authentication failed");
+ g_debug ("GdmGreeterLoginWindow: conversation '%s' has stopped", service_name);
+
+ /* If the password conversation failed, then start over
+ *
+ * FIXME: we need to get this policy out of the source code
+ */
+ if (strcmp (service_name, "gdm-password") == 0) {
+ g_debug ("GdmGreeterLoginWindow: main conversation failed, starting over");
+ restart_conversations (login_window);
+ return TRUE;
+ }
+
+ task = find_task_with_service_name (login_window, service_name);
+
+ if (task != NULL) {
+ gdm_conversation_reset (GDM_CONVERSATION (task));
+ g_object_unref (task);
+ }
+
+ /* If every conversation has failed, then just start over.
+ */
+ task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
+
+ if (!gdm_task_is_enabled (task)) {
+ g_debug ("GdmGreeterLoginWindow: No conversations left, starting over");
+ restart_conversations (login_window);
+ }
+ g_object_unref (task);
- /* FIXME: shake? */
- reset_dialog (login_window, MODE_AUTHENTICATION);
+ update_conversation_list_visibility (login_window);
return TRUE;
}
+static gboolean
+restart_task_conversation (GdmTaskList *task_list,
+ GdmTask *task,
+ GdmGreeterLoginWindow *login_window)
+{
+ char *service_name;
+
+ service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task));
+ if (service_name != NULL) {
+ char *name;
+
+ name = gdm_task_get_name (task);
+ g_debug ("GdmGreeterLoginWindow: restarting '%s' conversation", name);
+ g_free (name);
+
+ g_signal_emit (login_window, signals[START_CONVERSATION], 0, service_name);
+ g_free (service_name);
+ }
+
+ return FALSE;
+}
+
gboolean
gdm_greeter_login_window_reset (GdmGreeterLoginWindow *login_window)
{
+ g_debug ("GdmGreeterLoginWindow: window reset");
+
g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
+ reset_dialog (GDM_GREETER_LOGIN_WINDOW (login_window), MODE_SELECTION);
- g_debug ("GdmGreeterLoginWindow: got reset");
- reset_dialog (login_window, MODE_SELECTION);
+ gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+ (GdmTaskListForeachFunc)
+ restart_task_conversation,
+ login_window);
return TRUE;
}
gboolean
gdm_greeter_login_window_info (GdmGreeterLoginWindow *login_window,
+ const char *service_name,
const char *text)
{
- g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
+ GdmTask *task;
+ g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
g_debug ("GdmGreeterLoginWindow: info: %s", text);
- set_message (GDM_GREETER_LOGIN_WINDOW (login_window), text);
+ task = find_task_with_service_name (login_window, service_name);
+
+ if (task != NULL) {
+ gdm_conversation_set_message (GDM_CONVERSATION (task),
+ text);
+ show_task_actions (task);
+ g_object_unref (task);
+ }
return TRUE;
}
gboolean
gdm_greeter_login_window_problem (GdmGreeterLoginWindow *login_window,
+ const char *service_name,
const char *text)
{
- g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
+ GdmTask *task;
+ g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
g_debug ("GdmGreeterLoginWindow: problem: %s", text);
- set_message (GDM_GREETER_LOGIN_WINDOW (login_window), text);
- gdk_window_beep (gtk_widget_get_window (GTK_WIDGET (login_window)));
+ task = find_task_with_service_name (login_window, service_name);
+
+ if (task != NULL) {
+ gdm_conversation_set_message (GDM_CONVERSATION (task),
+ text);
+ show_task_actions (task);
+ g_object_unref (task);
+ }
+
+ gdk_window_beep (GTK_WIDGET (login_window)->window);
return TRUE;
}
@@ -788,6 +1032,26 @@ request_timed_login (GdmGreeterLoginWindow *login_window)
login_window->priv->timed_login_already_enabled = TRUE;
}
+gboolean
+gdm_greeter_login_window_service_unavailable (GdmGreeterLoginWindow *login_window,
+ const char *service_name)
+{
+ GdmTask *task;
+
+ g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
+ g_debug ("GdmGreeterLoginWindow: service unavailable: %s", service_name);
+
+ task = find_task_with_service_name (login_window, service_name);
+
+ if (task != NULL) {
+ gdm_task_list_remove_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+ task);
+ g_object_unref (task);
+ }
+
+ return TRUE;
+}
+
void
gdm_greeter_login_window_request_timed_login (GdmGreeterLoginWindow *login_window,
const char *username,
@@ -815,11 +1079,21 @@ gdm_greeter_login_window_request_timed_login (GdmGreeterLoginWindow *login_windo
}
static void
-gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_window)
+on_ready_to_start_session (GdmGreeterLoginWindow *login_window,
+ GParamSpec *param_spec,
+ char *service_name)
+{
+ gdm_greeter_login_window_start_session_when_ready (login_window, service_name);
+ g_free (service_name);
+}
+
+static void
+gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_window,
+ const char *service_name)
{
if (login_window->priv->is_interactive) {
g_debug ("GdmGreeterLoginWindow: starting session");
- g_signal_emit (login_window, signals[START_SESSION], 0);
+ g_signal_emit (login_window, signals[START_SESSION], 0, service_name);
} else {
g_debug ("GdmGreeterLoginWindow: not starting session since "
"user hasn't had an opportunity to pick language "
@@ -829,8 +1103,8 @@ gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_
*/
login_window->priv->start_session_handler_id =
g_signal_connect (login_window, "notify::is-interactive",
- G_CALLBACK (gdm_greeter_login_window_start_session_when_ready),
- NULL);
+ G_CALLBACK (on_ready_to_start_session),
+ g_strdup (service_name));
/* FIXME: If the user wasn't asked any questions by pam but
* pam still authorized them (passwd -d, or the questions got
@@ -853,10 +1127,10 @@ gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_
gboolean
gdm_greeter_login_window_info_query (GdmGreeterLoginWindow *login_window,
+ const char *service_name,
const char *text)
{
- GtkWidget *entry;
- GtkWidget *label;
+ GdmTask *task;
g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
@@ -865,15 +1139,15 @@ gdm_greeter_login_window_info_query (GdmGreeterLoginWindow *login_window,
g_debug ("GdmGreeterLoginWindow: info query: %s", text);
- entry = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-entry"));
- gtk_editable_delete_text (GTK_EDITABLE (entry), 0, -1);
- gtk_entry_set_visibility (GTK_ENTRY (entry), TRUE);
- set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY);
+ task = find_task_with_service_name (login_window, service_name);
- label = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-label"));
- gtk_label_set_text (GTK_LABEL (label), text);
+ if (task != NULL) {
+ gdm_conversation_ask_question (GDM_CONVERSATION (task),
+ text);
+ g_object_unref (task);
+ }
- show_widget (login_window, "auth-input-box", TRUE);
+ set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY);
set_sensitive (GDM_GREETER_LOGIN_WINDOW (login_window), TRUE);
set_ready (GDM_GREETER_LOGIN_WINDOW (login_window));
set_focus (GDM_GREETER_LOGIN_WINDOW (login_window));
@@ -885,25 +1159,26 @@ gdm_greeter_login_window_info_query (GdmGreeterLoginWindow *login_window,
gboolean
gdm_greeter_login_window_secret_info_query (GdmGreeterLoginWindow *login_window,
+ const char *service_name,
const char *text)
{
- GtkWidget *entry;
- GtkWidget *label;
+
+ GdmTask *task;
g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
login_window->priv->num_queries++;
maybe_show_cancel_button (login_window);
- entry = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-entry"));
- gtk_editable_delete_text (GTK_EDITABLE (entry), 0, -1);
- gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE);
- set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY);
+ task = find_task_with_service_name (login_window, service_name);
- label = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-label"));
- gtk_label_set_text (GTK_LABEL (label), text);
+ if (task != NULL) {
+ gdm_conversation_ask_secret (GDM_CONVERSATION (task),
+ text);
+ g_object_unref (task);
+ }
- show_widget (login_window, "auth-input-box", TRUE);
+ set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY);
set_sensitive (GDM_GREETER_LOGIN_WINDOW (login_window), TRUE);
set_ready (GDM_GREETER_LOGIN_WINDOW (login_window));
set_focus (GDM_GREETER_LOGIN_WINDOW (login_window));
@@ -914,13 +1189,16 @@ gdm_greeter_login_window_secret_info_query (GdmGreeterLoginWindow *login_window,
}
void
-gdm_greeter_login_window_user_authorized (GdmGreeterLoginWindow *login_window)
+gdm_greeter_login_window_user_authorized (GdmGreeterLoginWindow *login_window,
+ const char *service_name)
{
g_return_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window));
- g_debug ("GdmGreeterLoginWindow: user now authorized");
+ g_debug ("GdmGreeterLoginWindow: user now authorized via service %s",
+ service_name);
- gdm_greeter_login_window_start_session_when_ready (login_window);
+ gdm_greeter_login_window_start_session_when_ready (login_window,
+ service_name);
}
static void
@@ -991,6 +1269,49 @@ on_user_chooser_visibility_changed (GdmGreeterLoginWindow *login_window)
update_banner_message (login_window);
}
+static gboolean
+begin_task_verification_for_selected_user (GdmTaskList *task_list,
+ GdmTask *task,
+ GdmGreeterLoginWindow *login_window)
+{
+ char *user_name;
+ char *service_name;
+
+ user_name = gdm_user_chooser_widget_get_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser));
+
+ if (user_name == NULL) {
+ return TRUE;
+ }
+
+ service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task));
+ if (service_name != NULL) {
+ g_signal_emit (login_window, signals[BEGIN_VERIFICATION_FOR_USER], 0, service_name, user_name);
+ g_free (service_name);
+ }
+
+ g_free (user_name);
+ return FALSE;
+}
+
+static void
+enable_waiting_tasks (GdmGreeterLoginWindow *login_window)
+{
+ GList *node;
+
+ node = login_window->priv->tasks_to_enable;
+ while (node != NULL) {
+ GdmTask *task;
+
+ task = GDM_TASK (node->data);
+
+ gdm_conversation_set_ready (GDM_CONVERSATION (task));
+
+ node = node->next;
+ }
+
+ login_window->priv->tasks_to_enable = NULL;
+}
+
static void
on_users_loaded (GdmUserChooserWidget *user_chooser,
GdmGreeterLoginWindow *login_window)
@@ -1004,38 +1325,153 @@ on_users_loaded (GdmUserChooserWidget *user_chooser,
gtk_widget_show (login_window->priv->user_chooser);
}
+ enable_waiting_tasks (login_window);
+
if (login_window->priv->timed_login_username != NULL
&& !login_window->priv->timed_login_already_enabled) {
request_timed_login (login_window);
} else if (can_jump_to_authenticate (login_window)) {
+
/* jump straight to authenticate */
g_debug ("GdmGreeterLoginWindow: jumping straight to authenticate");
-
- switch_mode (login_window, MODE_AUTHENTICATION);
-
- g_debug ("Starting PAM conversation since no local users");
g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED],
0, GDM_USER_CHOOSER_USER_OTHER);
- g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0);
+ begin_verification (login_window);
+ }
+}
+
+static void
+choose_user (GdmGreeterLoginWindow *login_window,
+ const char *user_name)
+{
+ g_assert (user_name != NULL);
+ g_debug ("GdmGreeterLoginWindow: user chosen '%s'", user_name);
+
+ g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED],
+ 0, user_name);
+
+
+ gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+ (GdmTaskListForeachFunc)
+ begin_task_verification_for_selected_user,
+ login_window);
+
+ switch_mode (login_window, MODE_AUTHENTICATION);
+ update_conversation_list_visibility (login_window);
+}
+
+static void
+begin_auto_login (GdmGreeterLoginWindow *login_window)
+{
+ g_signal_emit (login_window, signals[BEGIN_AUTO_LOGIN], 0,
+ login_window->priv->timed_login_username);
+
+ login_window->priv->timed_login_enabled = TRUE;
+ restart_timed_login_timeout (login_window);
+
+ /* just wait for the user to select language and stuff */
+ set_message (login_window, _("Select language and click Log In"));
+
+ switch_mode (login_window, MODE_AUTHENTICATION);
+
+ show_widget (login_window, "conversation-list", FALSE);
+ gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+ (GdmTaskListForeachFunc) reset_task,
+ login_window);
+}
+
+static gboolean
+reset_task_if_not_given (GdmTaskList *task_list,
+ GdmTask *task,
+ GdmTask *given_task)
+{
+ if (task == given_task) {
+ return FALSE;
}
+
+ gdm_conversation_reset (GDM_CONVERSATION (task));
+ return FALSE;
+}
+
+static void
+reset_every_task_but_given_task (GdmGreeterLoginWindow *login_window,
+ GdmTask *task)
+{
+ gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+ (GdmTaskListForeachFunc)
+ reset_task_if_not_given,
+ task);
}
static void
-on_user_chosen (GdmUserChooserWidget *user_chooser,
- GdmGreeterLoginWindow *login_window)
+begin_single_service_verification (GdmGreeterLoginWindow *login_window,
+ const char *service_name)
+{
+ GdmTask *task;
+
+ task = find_task_with_service_name (login_window, service_name);
+
+ if (task == NULL) {
+ g_debug ("GdmGreeterLoginWindow: %s has no task associated with it", service_name);
+ return;
+ }
+
+ g_debug ("GdmGreeterLoginWindow: Beginning %s auth conversation", service_name);
+
+ /* FIXME: we should probably give the plugin more say for
+ * what happens here.
+ */
+ g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, service_name);
+
+ switch_mode (login_window, MODE_AUTHENTICATION);
+ gdm_task_list_set_active_task (GDM_TASK_LIST (login_window->priv->conversation_list), task);
+
+ reset_every_task_but_given_task (login_window, task);
+ g_object_unref (task);
+
+ show_widget (login_window, "conversation-list", FALSE);
+}
+
+static void
+on_user_chooser_activated (GdmUserChooserWidget *user_chooser,
+ GdmGreeterLoginWindow *login_window)
{
char *user_name;
- guint mode;
+ char *item_id;
user_name = gdm_user_chooser_widget_get_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser));
- g_debug ("GdmGreeterLoginWindow: user chosen '%s'", user_name);
- if (user_name == NULL) {
+ if (user_name != NULL) {
+ g_debug ("GdmGreeterLoginWindow: user chosen '%s'", user_name);
+ choose_user (login_window, user_name);
+ g_free (user_name);
return;
}
- choose_user (login_window, user_name);
- g_free (user_name);
+ item_id = gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (user_chooser));
+ g_debug ("GdmGreeterLoginWindow: item chosen '%s'", item_id);
+
+ g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED],
+ 0, item_id);
+
+ if (strcmp (item_id, GDM_USER_CHOOSER_USER_OTHER) == 0) {
+ g_debug ("GdmGreeterLoginWindow: Starting all auth conversations");
+ g_free (item_id);
+
+ begin_verification (login_window);
+ } else if (strcmp (item_id, GDM_USER_CHOOSER_USER_GUEST) == 0) {
+ /* FIXME: handle guest account stuff */
+ g_free (item_id);
+ } else if (strcmp (item_id, GDM_USER_CHOOSER_USER_AUTO) == 0) {
+ g_debug ("GdmGreeterLoginWindow: Starting auto login");
+ g_free (item_id);
+
+ begin_auto_login (login_window);
+ } else {
+ g_debug ("GdmGreeterLoginWindow: Starting single auth conversation");
+ begin_single_service_verification (login_window, item_id);
+ g_free (item_id);
+ }
}
static void
@@ -1206,11 +1642,74 @@ create_computer_info (GdmGreeterLoginWindow *login_window)
#define INVISIBLE_CHAR_BULLET 0x2022
#define INVISIBLE_CHAR_NONE 0
+static void
+on_task_activated (GdmGreeterLoginWindow *login_window,
+ GdmTask *task)
+{
+ GtkWidget *container;
+ char *name;
+
+ name = gdm_task_get_name (task);
+ g_debug ("GdmGreeterLoginWindow: task '%s' activated", name);
+ g_free (name);
+
+ container = g_object_get_data (G_OBJECT (task),
+ "gdm-greeter-login-window-page-container");
+
+ if (container == NULL) {
+ GtkWidget *page;
+
+ container = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+ gtk_container_add (GTK_CONTAINER (login_window->priv->auth_page_box),
+ container);
+
+ page = gdm_conversation_get_page (GDM_CONVERSATION (task));
+ if (page != NULL) {
+ gtk_container_add (GTK_CONTAINER (container), page);
+ gtk_widget_show (page);
+ }
+ g_object_set_data (G_OBJECT (task),
+ "gdm-greeter-login-window-page-container",
+ container);
+ }
+
+ gtk_widget_show (container);
+ switch_mode (login_window, login_window->priv->dialog_mode);
+}
+
+static void
+on_task_deactivated (GdmGreeterLoginWindow *login_window,
+ GdmTask *task)
+{
+ GtkWidget *container;
+ char *name;
+ GtkActionGroup *actions;
+
+ name = gdm_task_get_name (task);
+ g_debug ("GdmGreeterLoginWindow: task '%s' now in background", name);
+ g_free (name);
+
+ container = g_object_get_data (G_OBJECT (task),
+ "gdm-greeter-login-window-page-container");
+
+ if (container != NULL) {
+ gtk_widget_hide (container);
+ }
+
+ actions = gdm_conversation_get_actions (GDM_CONVERSATION (task));
+
+ if (actions != NULL) {
+ gtk_action_group_set_sensitive (actions, FALSE);
+ gtk_action_group_set_visible (actions, FALSE);
+ g_object_unref (actions);
+ }
+}
static void
register_custom_types (GdmGreeterLoginWindow *login_window)
{
- GType types[] = { GDM_TYPE_USER_CHOOSER_WIDGET };
+ GType types[] = { GDM_TYPE_USER_CHOOSER_WIDGET,
+ GDM_TYPE_TASK_LIST };
int i;
for (i = 0; i < G_N_ELEMENTS (types); i++) {
@@ -1221,7 +1720,6 @@ register_custom_types (GdmGreeterLoginWindow *login_window)
static void
load_theme (GdmGreeterLoginWindow *login_window)
{
- GtkWidget *entry;
GtkWidget *button;
GtkWidget *box;
GtkWidget *image;
@@ -1274,7 +1772,7 @@ load_theme (GdmGreeterLoginWindow *login_window)
login_window);
g_signal_connect (login_window->priv->user_chooser,
"activated",
- G_CALLBACK (on_user_chosen),
+ G_CALLBACK (on_user_chooser_activated),
login_window);
g_signal_connect (login_window->priv->user_chooser,
"deactivated",
@@ -1286,30 +1784,30 @@ load_theme (GdmGreeterLoginWindow *login_window)
G_CALLBACK (on_user_chooser_visibility_changed),
login_window);
+ login_window->priv->conversation_list = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "task-list"));
+
+ g_signal_connect_swapped (GDM_TASK_LIST (login_window->priv->conversation_list),
+ "activated",
+ G_CALLBACK (on_task_activated),
+ login_window);
+ g_signal_connect_swapped (GDM_TASK_LIST (login_window->priv->conversation_list),
+ "deactivated",
+ G_CALLBACK (on_task_deactivated),
+ login_window);
+
login_window->priv->auth_banner_label = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "auth-banner-label"));
/*make_label_small_italic (login_window->priv->auth_banner_label);*/
+ login_window->priv->auth_page_box = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "auth-page-box"));
button = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "cancel-button"));
g_signal_connect (button, "clicked", G_CALLBACK (cancel_button_clicked), login_window);
- entry = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "auth-prompt-entry"));
- /* Only change the invisible character if it '*' otherwise assume it is OK */
- if ('*' == gtk_entry_get_invisible_char (GTK_ENTRY (entry))) {
- gunichar invisible_char;
- invisible_char = INVISIBLE_CHAR_BLACK_CIRCLE;
- gtk_entry_set_invisible_char (GTK_ENTRY (entry), invisible_char);
- }
-
create_computer_info (login_window);
box = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "computer-info-event-box"));
g_signal_connect (box, "button-press-event", G_CALLBACK (on_computer_info_label_button_press), login_window);
- if (login_window->priv->user_list_disabled) {
- switch_mode (login_window, MODE_AUTHENTICATION);
- } else {
- switch_mode (login_window, MODE_SELECTION);
- }
+ switch_mode (login_window, MODE_SELECTION);
gdm_profile_end (NULL);
}
@@ -1465,6 +1963,15 @@ gdm_greeter_login_window_class_init (GdmGreeterLoginWindowClass *klass)
widget_class->key_press_event = gdm_greeter_login_window_key_press_event;
widget_class->size_request = gdm_greeter_login_window_size_request;
+ signals [START_CONVERSATION] =
+ g_signal_new ("start-conversation",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdmGreeterLoginWindowClass, start_conversation),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1, G_TYPE_STRING);
signals [BEGIN_AUTO_LOGIN] =
g_signal_new ("begin-auto-login",
G_TYPE_FROM_CLASS (object_class),
@@ -1481,9 +1988,9 @@ gdm_greeter_login_window_class_init (GdmGreeterLoginWindowClass *klass)
G_STRUCT_OFFSET (GdmGreeterLoginWindowClass, begin_verification),
NULL,
NULL,
- g_cclosure_marshal_VOID__VOID,
+ g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE,
- 0);
+ 1, G_TYPE_STRING);
signals [BEGIN_VERIFICATION_FOR_USER] =
g_signal_new ("begin-verification-for-user",
G_TYPE_FROM_CLASS (object_class),
@@ -1491,9 +1998,9 @@ gdm_greeter_login_window_class_init (GdmGreeterLoginWindowClass *klass)
G_STRUCT_OFFSET (GdmGreeterLoginWindowClass, begin_verification_for_user),
NULL,
NULL,
- g_cclosure_marshal_VOID__STRING,
+ gdm_marshal_VOID__STRING_STRING,
G_TYPE_NONE,
- 1, G_TYPE_STRING);
+ 2, G_TYPE_STRING, G_TYPE_STRING);
signals [QUERY_ANSWER] =
g_signal_new ("query-answer",
G_TYPE_FROM_CLASS (object_class),
@@ -1501,9 +2008,9 @@ gdm_greeter_login_window_class_init (GdmGreeterLoginWindowClass *klass)
G_STRUCT_OFFSET (GdmGreeterLoginWindowClass, query_answer),
NULL,
NULL,
- g_cclosure_marshal_VOID__STRING,
+ gdm_marshal_VOID__STRING_STRING,
G_TYPE_NONE,
- 1, G_TYPE_STRING);
+ 2, G_TYPE_STRING, G_TYPE_STRING);
signals [USER_SELECTED] =
g_signal_new ("user-selected",
G_TYPE_FROM_CLASS (object_class),
@@ -1541,9 +2048,9 @@ gdm_greeter_login_window_class_init (GdmGreeterLoginWindowClass *klass)
G_STRUCT_OFFSET (GdmGreeterLoginWindowClass, start_session),
NULL,
NULL,
- g_cclosure_marshal_VOID__VOID,
+ g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE,
- 0);
+ 1, G_TYPE_STRING);
g_object_class_install_property (object_class,
PROP_DISPLAY_IS_LOCAL,
@@ -1596,6 +2103,246 @@ on_gconf_key_changed (GConfClient *client,
}
}
+static void
+on_conversation_answer (GdmGreeterLoginWindow *login_window,
+ const char *text,
+ GdmConversation *conversation)
+{
+ if (text != NULL) {
+ char *service_name;
+
+ service_name = gdm_conversation_get_service_name (conversation);
+ if (service_name != NULL) {
+ g_signal_emit (login_window, signals[QUERY_ANSWER], 0, service_name, text);
+ g_free (service_name);
+ }
+ }
+
+ set_sensitive (login_window, TRUE);
+ set_ready (login_window);
+}
+
+static void
+on_conversation_cancel (GdmGreeterLoginWindow *login_window,
+ GdmConversation *conversation)
+{
+ do_cancel (login_window);
+}
+
+static gboolean
+on_conversation_chose_user (GdmGreeterLoginWindow *login_window,
+ const char *username,
+ GdmConversation *conversation)
+{
+ if (!gdm_chooser_widget_is_loaded (GDM_CHOOSER_WIDGET (login_window->priv->user_chooser))) {
+ char *name;
+
+ name = gdm_task_get_name (GDM_TASK (conversation));
+ g_warning ("Task %s is trying to choose user before list is loaded", name);
+ g_free (name);
+ return FALSE;
+ }
+
+ /* If we're already authenticating then we can't pick a user
+ */
+ if (login_window->priv->dialog_mode == MODE_AUTHENTICATION) {
+ return FALSE;
+ }
+
+ if (gdm_task_list_set_active_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+ GDM_TASK (conversation))) {
+ gdm_user_chooser_widget_set_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser),
+ username);
+ }
+
+ return TRUE;
+}
+
+void
+gdm_greeter_login_window_remove_extension (GdmGreeterLoginWindow *login_window,
+ GdmGreeterExtension *extension)
+{
+ g_return_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window));
+ g_return_if_fail (GDM_IS_GREETER_LOGIN_WINDOW_EXTENSION (extension));
+
+ if (!GDM_IS_CONVERSATION (extension)) {
+ return;
+ }
+}
+
+static void
+on_button_action_label_changed (GtkWidget *button)
+{
+ GtkAction *action;
+ char *text;
+
+ action = gtk_widget_get_action (button);
+
+ g_object_get (G_OBJECT (action), "label", &text, NULL);
+
+ gtk_button_set_label (GTK_BUTTON (button), text);
+ g_free (text);
+}
+
+static void
+on_button_action_icon_name_changed (GtkWidget *button)
+{
+ GtkAction *action;
+ GtkWidget *image;
+
+ action = gtk_widget_get_action (button);
+
+ if (gtk_action_get_is_important (action)) {
+ image = gtk_action_create_icon (GTK_ACTION (action), GTK_ICON_SIZE_BUTTON);
+ } else {
+ image = NULL;
+ }
+
+ gtk_button_set_image (GTK_BUTTON (button), image);
+
+}
+
+static void
+on_button_action_tooltip_changed (GtkWidget *button)
+{
+ GtkAction *action;
+ char *text;
+
+ action = gtk_widget_get_action (button);
+
+ g_object_get (G_OBJECT (action), "tooltip", &text, NULL);
+
+ gtk_widget_set_tooltip_text (button, text);
+ g_free (text);
+}
+
+static GtkWidget *
+create_button_from_action (GtkAction *action)
+{
+ GtkWidget *button;
+
+ button = gtk_button_new ();
+
+ gtk_action_connect_proxy (GTK_ACTION (action), button);
+
+ g_signal_connect_swapped (action,
+ "notify::label",
+ G_CALLBACK (on_button_action_label_changed),
+ button);
+ g_signal_connect_swapped (action,
+ "notify::icon-name",
+ G_CALLBACK (on_button_action_icon_name_changed),
+ button);
+ g_signal_connect_swapped (action,
+ "notify::tooltip",
+ G_CALLBACK (on_button_action_tooltip_changed),
+ button);
+
+ on_button_action_label_changed (button);
+ on_button_action_icon_name_changed (button);
+ on_button_action_tooltip_changed (button);
+
+ if (strcmp (gtk_action_get_name (action),
+ GDM_CONVERSATION_DEFAULT_ACTION) == 0) {
+ GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
+ }
+
+ return button;
+}
+
+static void
+create_buttons_for_actions (GdmGreeterLoginWindow *login_window,
+ GtkActionGroup *actions)
+{
+ GList *action_list;
+ GList *node;
+ GtkWidget *box;
+
+ action_list = gtk_action_group_list_actions (actions);
+
+ box = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "buttonbox"));
+ for (node = action_list; node != NULL; node = node->next) {
+ GtkAction *action;
+ GtkWidget *button;
+
+ action = node->data;
+
+ button = create_button_from_action (action);
+ gtk_container_add (GTK_CONTAINER (box), button);
+ }
+
+ g_list_free (action_list);
+}
+
+void
+gdm_greeter_login_window_add_extension (GdmGreeterLoginWindow *login_window,
+ GdmGreeterExtension *extension)
+{
+ char *name;
+ char *description;
+ char *service_name;
+ GtkActionGroup *actions;
+
+ g_return_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window));
+ g_return_if_fail (GDM_IS_GREETER_LOGIN_WINDOW_EXTENSION (extension));
+
+ if (!GDM_IS_CONVERSATION (extension)) {
+ return;
+ }
+
+ name = gdm_task_get_name (GDM_TASK (extension));
+ description = gdm_task_get_description (GDM_TASK (extension));
+
+ if (!gdm_task_is_visible (GDM_TASK (extension))) {
+ g_debug ("GdmGreeterLoginWindow: new extension '%s - %s' won't be added",
+ name, description);
+ g_free (name);
+ g_free (description);
+ return;
+ }
+
+ actions = gdm_conversation_get_actions (GDM_CONVERSATION (extension));
+
+ create_buttons_for_actions (login_window, actions);
+ hide_task_actions (GDM_TASK (extension));
+
+ g_object_unref (actions);
+
+ g_signal_connect_swapped (GDM_CONVERSATION (extension),
+ "answer",
+ G_CALLBACK (on_conversation_answer),
+ login_window);
+ g_signal_connect_swapped (GDM_CONVERSATION (extension),
+ "cancel",
+ G_CALLBACK (on_conversation_cancel),
+ login_window);
+ g_signal_connect_swapped (GDM_CONVERSATION (extension),
+ "user-chosen",
+ G_CALLBACK (on_conversation_chose_user),
+ login_window);
+
+ g_debug ("GdmGreeterLoginWindow: new extension '%s - %s' added",
+ name, description);
+
+ gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+ GDM_TASK (extension));
+
+ service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (extension));
+
+ if (gdm_task_is_choosable (GDM_TASK (extension))) {
+ gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (login_window->priv->user_chooser),
+ service_name, NULL, name, description, ~0,
+ FALSE, TRUE, NULL, NULL);
+ }
+
+ g_free (name);
+ g_free (description);
+
+ g_debug ("GdmGreeterLoginWindow: starting conversation with '%s'", service_name);
+ g_signal_emit (login_window, signals[START_CONVERSATION], 0, service_name);
+ g_free (service_name);
+}
+
static gboolean
on_window_state_event (GtkWidget *widget,
GdkEventWindowState *event,
diff --git a/gui/simple-greeter/gdm-greeter-login-window.h b/gui/simple-greeter/gdm-greeter-login-window.h
index 504b075..041cbc4 100644
--- a/gui/simple-greeter/gdm-greeter-login-window.h
+++ b/gui/simple-greeter/gdm-greeter-login-window.h
@@ -23,6 +23,9 @@
#define __GDM_GREETER_LOGIN_WINDOW_H
#include <glib-object.h>
+#include "gdm-conversation.h"
+#include "gdm-task.h"
+#include "gdm-greeter-extension.h"
G_BEGIN_DECLS
@@ -33,6 +36,8 @@ G_BEGIN_DECLS
#define GDM_IS_GREETER_LOGIN_WINDOW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_GREETER_LOGIN_WINDOW))
#define GDM_GREETER_LOGIN_WINDOW_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_GREETER_LOGIN_WINDOW, GdmGreeterLoginWindowClass))
+#define GDM_IS_GREETER_LOGIN_WINDOW_EXTENSION(e) (GDM_IS_CONVERSATION(e) && GDM_IS_TASK(e))
+
typedef struct GdmGreeterLoginWindowPrivate GdmGreeterLoginWindowPrivate;
typedef struct
@@ -46,18 +51,24 @@ typedef struct
GtkWindowClass parent_class;
/* signals */
+ void (* start_conversation) (GdmGreeterLoginWindow *login_window,
+ const char *service_name);
void (* begin_auto_login) (GdmGreeterLoginWindow *login_window,
const char *username);
- void (* begin_verification) (GdmGreeterLoginWindow *login_window);
+ void (* begin_verification) (GdmGreeterLoginWindow *login_window,
+ const char *service_name);
void (* begin_verification_for_user) (GdmGreeterLoginWindow *login_window,
+ const char *service_name,
const char *username);
void (* query_answer) (GdmGreeterLoginWindow *login_window,
+ const char *service_name,
const char *text);
void (* user_selected) (GdmGreeterLoginWindow *login_window,
const char *text);
void (* cancelled) (GdmGreeterLoginWindow *login_window);
void (* disconnected) (GdmGreeterLoginWindow *login_window);
- void (* start_session) (GdmGreeterLoginWindow *login_window);
+ void (* start_session) (GdmGreeterLoginWindow *login_window,
+ const char *sevice_name);
} GdmGreeterLoginWindowClass;
@@ -66,21 +77,36 @@ GtkWidget * gdm_greeter_login_window_new (gboolean displa
gboolean gdm_greeter_login_window_reset (GdmGreeterLoginWindow *login_window);
-gboolean gdm_greeter_login_window_authentication_failed (GdmGreeterLoginWindow *login_window);
-gboolean gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window);
+gboolean gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window,
+ const char *service_name);
+gboolean gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_window,
+ const char *service_name);
gboolean gdm_greeter_login_window_info_query (GdmGreeterLoginWindow *login_window,
+ const char *service_name,
const char *text);
gboolean gdm_greeter_login_window_secret_info_query (GdmGreeterLoginWindow *login_window,
+ const char *service_name,
const char *text);
gboolean gdm_greeter_login_window_info (GdmGreeterLoginWindow *login_window,
+ const char *service_name,
const char *text);
gboolean gdm_greeter_login_window_problem (GdmGreeterLoginWindow *login_window,
+ const char *service_name,
const char *text);
+gboolean gdm_greeter_login_window_service_unavailable (GdmGreeterLoginWindow *login_window,
+ const char *service_name);
+
void gdm_greeter_login_window_request_timed_login (GdmGreeterLoginWindow *login_window,
const char *username,
int delay);
-void gdm_greeter_login_window_user_authorized (GdmGreeterLoginWindow *login_window);
+void gdm_greeter_login_window_user_authorized (GdmGreeterLoginWindow *login_window,
+ const char *service_name);
+
+void gdm_greeter_login_window_add_extension (GdmGreeterLoginWindow *login_window,
+ GdmGreeterExtension *extension);
+void gdm_greeter_login_window_remove_extension (GdmGreeterLoginWindow *login_window,
+ GdmGreeterExtension *extension);
G_END_DECLS
diff --git a/gui/simple-greeter/gdm-greeter-login-window.ui b/gui/simple-greeter/gdm-greeter-login-window.ui
index 83375ed..35195d8 100644
--- a/gui/simple-greeter/gdm-greeter-login-window.ui
+++ b/gui/simple-greeter/gdm-greeter-login-window.ui
@@ -158,69 +158,40 @@
<child>
<object class="GtkVBox" id="selection-box">
<property name="visible">True</property>
- <property name="spacing">10</property>
+ <property name="spacing">2</property>
<child>
- <object class="GdmUserChooserWidget" id="user-chooser">
- <property name="visible">False</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkHBox" id="auth-input-box">
+ <object class="GtkAlignment" id="task-list-alignment">
<property name="visible">True</property>
- <property name="spacing">6</property>
+ <property name="xalign">1.0</property>
+ <property name="xscale">0.0</property>
<child>
- <object class="GtkLabel" id="auth-prompt-label">
- <property name="visible">True</property>
-
- <accessibility>
- <relation type="label-for" target="auth-prompt-entry"/>
- </accessibility>
+ <object class="GdmTaskList" id="task-list">
+ <property name="visible">False</property>
</object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="auth-prompt-entry">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="activates_default">True</property>
- <accessibility>
- <relation type="labelled-by" target="auth-prompt-label"/>
- </accessibility>
- </object>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GdmUserChooserWidget" id="user-chooser">
+ <property name="visible">False</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
- <object class="GtkHBox" id="auth-message-box">
+ <object class="GtkHBox" id="auth-page-box">
<property name="visible">True</property>
+ <property name="border_width">10</property>
<child>
- <object class="GtkLabel" id="auth-message-label">
- <property name="visible">True</property>
- </object>
- <packing>
- <property name="position">0</property>
- </packing>
+ <placeholder/>
</child>
</object>
<packing>
diff --git a/gui/simple-greeter/gdm-greeter-plugin.c b/gui/simple-greeter/gdm-greeter-plugin.c
new file mode 100644
index 0000000..02814a2
--- /dev/null
+++ b/gui/simple-greeter/gdm-greeter-plugin.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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
+ *
+ * Written by: Ray Strode <rstrode@redhat.com>
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+#include "gdm-greeter-extension.h"
+#include "gdm-greeter-plugin.h"
+
+#define GDM_GREETER_PLUGIN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_GREETER_PLUGIN, GdmGreeterPluginPrivate))
+
+enum {
+ PROP_0,
+ PROP_FILENAME,
+};
+
+enum {
+ LOADED,
+ LOAD_FAILED,
+ UNLOADED,
+ LAST_SIGNAL
+};
+
+struct _GdmGreeterPluginPrivate {
+ GObject parent;
+
+ GModule *module;
+ char *filename;
+
+ GdmGreeterExtension *extension;
+};
+
+static void gdm_greeter_plugin_finalize (GObject *object);
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (GdmGreeterPlugin, gdm_greeter_plugin, G_TYPE_OBJECT)
+
+static void
+gdm_greeter_plugin_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdmGreeterPlugin *plugin;
+
+ plugin = GDM_GREETER_PLUGIN (object);
+ switch (param_id) {
+ case PROP_FILENAME:
+ plugin->priv->filename = g_strdup (g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+gdm_greeter_plugin_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdmGreeterPlugin *plugin;
+
+ plugin = GDM_GREETER_PLUGIN (object);
+
+ switch (param_id) {
+ case PROP_FILENAME:
+ g_value_set_string (value, plugin->priv->filename);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+gdm_greeter_plugin_class_init (GdmGreeterPluginClass *class)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = G_OBJECT_CLASS (class);
+
+ gobject_class->set_property = gdm_greeter_plugin_set_property;
+ gobject_class->get_property = gdm_greeter_plugin_get_property;
+ gobject_class->finalize = gdm_greeter_plugin_finalize;
+
+ g_object_class_install_property (gobject_class,
+ PROP_FILENAME,
+ g_param_spec_string ("filename",
+ "Filename",
+ "The full path to the plugin.",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ signals [LOADED] =
+ g_signal_new ("loaded",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdmGreeterPluginClass, loaded),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ signals [LOAD_FAILED] =
+ g_signal_new ("load-failed",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdmGreeterPluginClass, load_failed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ signals [UNLOADED] =
+ g_signal_new ("unloaded",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdmGreeterPluginClass, unloaded),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ g_type_class_add_private (class, sizeof (GdmGreeterPluginPrivate));
+}
+
+GdmGreeterPlugin *
+gdm_greeter_plugin_new (const char *filename)
+{
+ GObject *object;
+
+ object = g_object_new (GDM_TYPE_GREETER_PLUGIN,
+ "filename", filename, NULL);
+
+ return GDM_GREETER_PLUGIN (object);
+}
+
+void
+gdm_greeter_plugin_load (GdmGreeterPlugin *plugin)
+{
+ GModule *module;
+ GdmGreeterExtension *extension;
+ union {
+ gpointer symbol;
+ GdmGreeterPluginGetExtensionFunc invoke;
+ } get_extension;
+
+
+ module = g_module_open (plugin->priv->filename, G_MODULE_BIND_LOCAL);
+
+ if (module == NULL) {
+ g_warning ("plugin %s couldn't be opened: %s",
+ plugin->priv->filename,
+ g_module_error ());
+ g_signal_emit (plugin, signals [LOAD_FAILED], 0);
+ return;
+ }
+
+ if (!g_module_symbol (module,
+ "gdm_greeter_plugin_get_extension",
+ &get_extension.symbol) ||
+ !get_extension.symbol) {
+ g_warning ("plugin %s lacks gdm_greeter_plugin_get_extension()",
+ plugin->priv->filename);
+ g_module_close (module);
+ g_signal_emit (plugin, signals [LOAD_FAILED], 0);
+ return;
+ }
+
+ extension = get_extension.invoke ();
+
+ if (!extension) {
+ g_warning ("plugin %s didn't return extension when asked",
+ plugin->priv->filename);
+ g_module_close (module);
+ g_signal_emit (plugin, signals [LOAD_FAILED], 0);
+ }
+
+ if (!GDM_IS_GREETER_EXTENSION (extension)) {
+ g_warning ("plugin %s returned bogus extension when asked",
+ plugin->priv->filename);
+ g_module_close (module);
+ g_signal_emit (plugin, signals [LOAD_FAILED], 0);
+ }
+
+ plugin->priv->module = module;
+ plugin->priv->extension = extension;
+
+ g_signal_emit (plugin, signals [LOADED], 0);
+}
+
+void
+gdm_greeter_plugin_unload (GdmGreeterPlugin *plugin)
+{
+ if (plugin->priv->extension != NULL) {
+ g_object_unref (plugin->priv->extension);
+ plugin->priv->extension = NULL;
+ }
+
+ if (plugin->priv->module != NULL) {
+ g_module_close (plugin->priv->module);
+ plugin->priv->module = NULL;
+ }
+}
+
+const char *
+gdm_greeter_plugin_get_filename (GdmGreeterPlugin *plugin)
+{
+ return plugin->priv->filename;
+}
+
+GdmGreeterExtension *
+gdm_greeter_plugin_get_extension (GdmGreeterPlugin *plugin)
+{
+ return g_object_ref (plugin->priv->extension);
+}
+
+static void
+gdm_greeter_plugin_init (GdmGreeterPlugin *plugin)
+{
+ plugin->priv = GDM_GREETER_PLUGIN_GET_PRIVATE (plugin);
+}
+
+static void
+gdm_greeter_plugin_finalize (GObject *object)
+{
+ GdmGreeterPlugin *plugin;
+
+ plugin = GDM_GREETER_PLUGIN (object);
+
+ gdm_greeter_plugin_unload (plugin);
+}
+
diff --git a/gui/simple-greeter/gdm-greeter-plugin.h b/gui/simple-greeter/gdm-greeter-plugin.h
new file mode 100644
index 0000000..904c231
--- /dev/null
+++ b/gui/simple-greeter/gdm-greeter-plugin.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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 __GDM_GREETER_PLUGIN
+#define __GDM_GREETER_PLUGIN
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "gdm-greeter-extension.h"
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_GREETER_PLUGIN (gdm_greeter_plugin_get_type ())
+#define GDM_GREETER_PLUGIN(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDM_TYPE_GREETER_PLUGIN, GdmGreeterPlugin))
+#define GDM_IS_GREETER_PLUGIN(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDM_TYPE_GREETER_PLUGIN))
+
+typedef struct _GdmGreeterPlugin GdmGreeterPlugin;
+typedef struct _GdmGreeterPluginPrivate GdmGreeterPluginPrivate;
+typedef struct _GdmGreeterPluginClass GdmGreeterPluginClass;
+
+struct _GdmGreeterPlugin
+{
+ GObject parent;
+ GdmGreeterPluginPrivate *priv;
+};
+
+struct _GdmGreeterPluginClass
+{
+ GObjectClass parent_class;
+
+ void (* loaded) (GdmGreeterPlugin *plugin);
+ void (* load_failed) (GdmGreeterPlugin *plugin);
+ void (* unloaded) (GdmGreeterPlugin *plugin);
+};
+
+GType gdm_greeter_plugin_get_type (void) G_GNUC_CONST;
+GdmGreeterPlugin *gdm_greeter_plugin_new (const char *filename);
+void gdm_greeter_plugin_load (GdmGreeterPlugin *plugin);
+void gdm_greeter_plugin_unload (GdmGreeterPlugin *plugin);
+const char *gdm_greeter_plugin_get_filename (GdmGreeterPlugin *plugin);
+GdmGreeterExtension *gdm_greeter_plugin_get_extension (GdmGreeterPlugin *plugin);
+
+G_END_DECLS
+
+#endif
diff --git a/gui/simple-greeter/gdm-greeter-session.c b/gui/simple-greeter/gdm-greeter-session.c
index b7e7f1c..051a5cc 100644
--- a/gui/simple-greeter/gdm-greeter-session.c
+++ b/gui/simple-greeter/gdm-greeter-session.c
@@ -39,6 +39,8 @@
#include "gdm-greeter-login-window.h"
#include "gdm-user-chooser-widget.h"
+#include "gdm-plugin-manager.h"
+
#include "gdm-profile.h"
#define GDM_GREETER_SESSION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_GREETER_SESSION, GdmGreeterSessionPrivate))
@@ -48,6 +50,7 @@
struct GdmGreeterSessionPrivate
{
GdmGreeterClient *client;
+ GdmPluginManager *plugin_manager;
GtkWidget *login_window;
GtkWidget *panel;
@@ -75,7 +78,7 @@ on_info (GdmGreeterClient *client,
{
g_debug ("GdmGreeterSession: Info: %s", text);
- gdm_greeter_login_window_info (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), text);
+ gdm_greeter_login_window_info (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), service_name, text);
}
static void
@@ -86,7 +89,17 @@ on_problem (GdmGreeterClient *client,
{
g_debug ("GdmGreeterSession: Problem: %s", text);
- gdm_greeter_login_window_problem (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), text);
+ gdm_greeter_login_window_problem (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), service_name, text);
+}
+
+static void
+on_service_unavailable (GdmGreeterClient *client,
+ const char *service_name,
+ GdmGreeterSession *session)
+{
+ g_debug ("GdmGreeterSession: Service Unavailable: %s", service_name);
+
+ gdm_greeter_login_window_service_unavailable (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), service_name);
}
static void
@@ -96,7 +109,19 @@ on_ready (GdmGreeterClient *client,
{
g_debug ("GdmGreeterSession: Ready");
- gdm_greeter_login_window_ready (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window));
+ gdm_greeter_login_window_ready (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window),
+ service_name);
+}
+
+static void
+on_conversation_stopped (GdmGreeterClient *client,
+ const char *service_name,
+ GdmGreeterSession *session)
+{
+ g_debug ("GdmGreeterSession: Conversation '%s' stopped", service_name);
+
+ gdm_greeter_login_window_conversation_stopped (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window),
+ service_name);
}
static void
@@ -112,29 +137,6 @@ on_reset (GdmGreeterClient *client,
}
static void
-on_authentication_failed (GdmGreeterClient *client,
- GdmGreeterSession *session)
-{
- g_debug ("GdmGreeterSession: Authentication failed");
-
- session->priv->num_tries++;
-
- if (session->priv->num_tries < MAX_LOGIN_TRIES) {
- g_debug ("GdmGreeterSession: Retrying login (%d)",
- session->priv->num_tries);
-
- gdm_greeter_login_window_authentication_failed (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window));
- } else {
- g_debug ("GdmGreeterSession: Maximum number of login tries exceeded (%d) - resetting",
- session->priv->num_tries - 1);
- session->priv->num_tries = 0;
-
- gdm_greeter_panel_reset (GDM_GREETER_PANEL (session->priv->panel));
- gdm_greeter_login_window_reset (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window));
- }
-}
-
-static void
show_or_hide_user_options (GdmGreeterSession *session,
const char *username)
{
@@ -196,10 +198,11 @@ on_timed_login_requested (GdmGreeterClient *client,
static void
on_user_authorized (GdmGreeterClient *client,
+ const char *service_name,
GdmGreeterSession *session)
{
g_debug ("GdmGreeterSession: user authorized");
- gdm_greeter_login_window_user_authorized (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window));
+ gdm_greeter_login_window_user_authorized (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), service_name);
}
static void
@@ -210,7 +213,7 @@ on_info_query (GdmGreeterClient *client,
{
g_debug ("GdmGreeterSession: Info query: %s", text);
- gdm_greeter_login_window_info_query (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), text);
+ gdm_greeter_login_window_info_query (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), service_name, text);
}
static void
@@ -221,10 +224,18 @@ on_secret_info_query (GdmGreeterClient *client,
{
g_debug ("GdmGreeterSession: Secret info query: %s", text);
- gdm_greeter_login_window_secret_info_query (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), text);
+ gdm_greeter_login_window_secret_info_query (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), service_name, text);
}
static void
+on_start_conversation (GdmGreeterLoginWindow *login_window,
+ const char *service_name,
+ GdmGreeterSession *session)
+{
+ gdm_greeter_client_call_start_conversation (session->priv->client,
+ service_name);
+}
+static void
on_begin_auto_login (GdmGreeterLoginWindow *login_window,
const char *username,
GdmGreeterSession *session)
@@ -235,29 +246,32 @@ on_begin_auto_login (GdmGreeterLoginWindow *login_window,
static void
on_begin_verification (GdmGreeterLoginWindow *login_window,
+ const char *service_name,
GdmGreeterSession *session)
{
gdm_greeter_client_call_begin_verification (session->priv->client,
- "gdm");
+ service_name);
}
static void
on_begin_verification_for_user (GdmGreeterLoginWindow *login_window,
+ const char *service_name,
const char *username,
GdmGreeterSession *session)
{
gdm_greeter_client_call_begin_verification_for_user (session->priv->client,
- "gdm",
+ service_name,
username);
}
static void
on_query_answer (GdmGreeterLoginWindow *login_window,
+ const char *service_name,
const char *text,
GdmGreeterSession *session)
{
gdm_greeter_client_call_answer_query (session->priv->client,
- "gdm",
+ service_name,
text);
}
@@ -301,7 +315,6 @@ on_cancelled (GdmGreeterLoginWindow *login_window,
{
gdm_greeter_panel_hide_user_options (GDM_GREETER_PANEL (session->priv->panel));
gdm_greeter_client_call_cancel (session->priv->client);
- gdm_greeter_client_call_start_conversation (session->priv->client, "gdm");
}
static void
@@ -313,9 +326,10 @@ on_disconnected (GdmGreeterLoginWindow *login_window,
static void
on_start_session (GdmGreeterLoginWindow *login_window,
+ const char *service_name,
GdmGreeterSession *session)
{
- gdm_greeter_client_call_start_session_when_ready (session->priv->client, "gdm", TRUE);
+ gdm_greeter_client_call_start_session_when_ready (session->priv->client, service_name, TRUE);
}
static int
@@ -410,7 +424,10 @@ toggle_login_window (GdmGreeterSession *session,
is_local = gdm_greeter_client_get_display_is_local (session->priv->client);
g_debug ("GdmGreeterSession: Starting a login window local:%d", is_local);
session->priv->login_window = gdm_greeter_login_window_new (is_local);
-
+ g_signal_connect (session->priv->login_window,
+ "start-conversation",
+ G_CALLBACK (on_start_conversation),
+ session);
g_signal_connect (session->priv->login_window,
"begin-auto-login",
G_CALLBACK (on_begin_auto_login),
@@ -466,8 +483,6 @@ gdm_greeter_session_start (GdmGreeterSession *session,
toggle_panel (session, TRUE);
toggle_login_window (session, TRUE);
- gdm_greeter_client_call_start_conversation (session->priv->client, "gdm");
-
gdm_profile_end (NULL);
return res;
@@ -577,6 +592,64 @@ gdm_greeter_session_event_handler (GdkEvent *event,
}
static void
+on_plugins_loaded (GdmGreeterSession *session)
+{
+ g_debug ("GdmGreeterSession: done loading plugins");
+}
+
+static void
+on_plugin_removed (GdmGreeterSession *session,
+ GdmGreeterPlugin *plugin)
+{
+ GdmGreeterExtension *extension;
+
+ extension = gdm_greeter_plugin_get_extension (plugin);
+
+ if (GDM_IS_GREETER_LOGIN_WINDOW_EXTENSION (extension)) {
+ gdm_greeter_login_window_remove_extension (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), extension);
+ }
+ g_object_unref (extension);
+}
+
+static void
+on_plugin_added (GdmGreeterSession *session,
+ GdmGreeterPlugin *plugin)
+{
+ GdmGreeterExtension *extension;
+
+ extension = gdm_greeter_plugin_get_extension (plugin);
+
+ if (GDM_IS_GREETER_LOGIN_WINDOW_EXTENSION (extension)) {
+ gdm_greeter_login_window_add_extension (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), extension);
+ }
+ g_object_unref (extension);
+}
+
+static void
+load_plugins (GdmGreeterSession *session)
+{
+ g_debug ("GdmGreeterSession: loading plugins");
+
+ session->priv->plugin_manager = gdm_plugin_manager_ref_default ();
+
+ g_signal_connect_swapped (session->priv->plugin_manager,
+ "plugins-loaded",
+ G_CALLBACK (on_plugins_loaded),
+ session);
+
+ g_signal_connect_swapped (session->priv->plugin_manager,
+ "plugin-added",
+ G_CALLBACK (on_plugin_added),
+ session);
+
+ g_signal_connect_swapped (session->priv->plugin_manager,
+ "plugin-removed",
+ G_CALLBACK (on_plugin_removed),
+ session);
+
+}
+
+static void
gdm_greeter_session_init (GdmGreeterSession *session)
{
gdm_profile_start (NULL);
@@ -601,16 +674,20 @@ gdm_greeter_session_init (GdmGreeterSession *session)
G_CALLBACK (on_problem),
session);
g_signal_connect (session->priv->client,
+ "service-unavailable",
+ G_CALLBACK (on_service_unavailable),
+ session);
+ g_signal_connect (session->priv->client,
"ready",
G_CALLBACK (on_ready),
session);
g_signal_connect (session->priv->client,
- "reset",
- G_CALLBACK (on_reset),
+ "conversation-stopped",
+ G_CALLBACK (on_conversation_stopped),
session);
g_signal_connect (session->priv->client,
- "authentication-failed",
- G_CALLBACK (on_authentication_failed),
+ "reset",
+ G_CALLBACK (on_reset),
session);
g_signal_connect (session->priv->client,
"selected-user-changed",
@@ -643,6 +720,8 @@ gdm_greeter_session_init (GdmGreeterSession *session)
gdk_event_handler_set ((GdkEventFunc) gdm_greeter_session_event_handler,
session, NULL);
+
+ load_plugins (session);
gdm_profile_end (NULL);
}
diff --git a/gui/simple-greeter/gdm-plugin-manager.c b/gui/simple-greeter/gdm-plugin-manager.c
new file mode 100644
index 0000000..49e442c
--- /dev/null
+++ b/gui/simple-greeter/gdm-plugin-manager.c
@@ -0,0 +1,478 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ * Written By: Ray Strode <rstrode@redhat.com>
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include "gdm-plugin-manager.h"
+#include "gdm-greeter-extension.h"
+
+#define GDM_PLUGIN_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_PLUGIN_MANAGER, GdmPluginManagerPrivate))
+
+typedef struct
+{
+ GModule *module;
+ char *filename;
+ GdmGreeterExtension *extension;
+} GdmPluginManagerPlugin;
+
+typedef struct
+{
+ GdmPluginManager *manager;
+ GCancellable *cancellable;
+} GdmPluginManagerOperation;
+
+struct GdmPluginManagerPrivate
+{
+ GHashTable *plugins;
+
+ GFileMonitor *plugin_dir_monitor;
+ GList *pending_operations;
+};
+
+enum {
+ PLUGINS_LOADED,
+ PLUGIN_ADDED,
+ PLUGIN_REMOVED,
+ LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0, };
+
+static void gdm_plugin_manager_class_init (GdmPluginManagerClass *klass);
+static void gdm_plugin_manager_init (GdmPluginManager *plugin_manager);
+static void gdm_plugin_manager_finalize (GObject *object);
+
+static GObject *plugin_manager_object = NULL;
+
+G_DEFINE_TYPE (GdmPluginManager, gdm_plugin_manager, G_TYPE_OBJECT)
+
+static GdmPluginManagerOperation *
+start_operation (GdmPluginManager *manager)
+{
+ GdmPluginManagerOperation *operation;
+
+ operation = g_new0 (GdmPluginManagerOperation, 1);
+ operation->cancellable = g_cancellable_new ();
+ operation->manager = manager;
+
+ return operation;
+}
+
+static void
+free_operation (GdmPluginManagerOperation *operation)
+{
+ if (operation->cancellable != NULL) {
+ g_object_unref (operation->cancellable);
+ operation->cancellable = NULL;
+ }
+ g_free (operation);
+}
+
+static void
+cancel_operation (GdmPluginManagerOperation *operation)
+{
+ if (operation->cancellable != NULL &&
+ !g_cancellable_is_cancelled (operation->cancellable)) {
+ g_cancellable_cancel (operation->cancellable);
+ }
+
+ free_operation (operation);
+}
+
+static void
+gdm_plugin_manager_track_operation (GdmPluginManager *manager,
+ GdmPluginManagerOperation *operation)
+{
+ manager->priv->pending_operations =
+ g_list_prepend (manager->priv->pending_operations, operation);
+}
+
+static void
+gdm_plugin_manager_untrack_operation (GdmPluginManager *manager,
+ GdmPluginManagerOperation *operation)
+{
+ manager->priv->pending_operations =
+ g_list_remove (manager->priv->pending_operations, operation);
+}
+
+static void
+gdm_plugin_manager_cancel_pending_operations (GdmPluginManager *manager)
+{
+ GList *node;
+
+ node = manager->priv->pending_operations;
+ while (node != NULL) {
+ GList *next_node;
+ GdmPluginManagerOperation *operation;
+
+ operation = node->data;
+ next_node = node->next;
+
+ cancel_operation (operation);
+ manager->priv->pending_operations =
+ g_list_delete_link (manager->priv->pending_operations,
+ node);
+
+ node = next_node;
+ }
+}
+
+static void
+gdm_plugin_manager_class_init (GdmPluginManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gdm_plugin_manager_finalize;
+
+ signals [PLUGINS_LOADED] =
+ g_signal_new ("plugins-loaded",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdmPluginManagerClass, plugins_loaded),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ signals [PLUGIN_ADDED] =
+ g_signal_new ("plugin-added",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdmPluginManagerClass, plugin_added),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1, GDM_TYPE_GREETER_PLUGIN);
+ signals [PLUGIN_REMOVED] =
+ g_signal_new ("plugin-removed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdmPluginManagerClass, plugin_removed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1, GDM_TYPE_GREETER_PLUGIN);
+
+ g_type_class_add_private (klass, sizeof (GdmPluginManagerPrivate));
+}
+
+static void
+on_plugin_loaded (GdmPluginManager *manager,
+ GdmGreeterPlugin *plugin)
+{
+ g_debug ("GdmPluginManager: plugin '%s' loaded.",
+ gdm_greeter_plugin_get_filename (plugin));
+ g_signal_emit (manager, signals [PLUGIN_ADDED], 0, plugin);
+}
+
+static void
+on_plugin_load_failed (GdmPluginManager *manager,
+ GdmGreeterPlugin *plugin)
+{
+ const char *filename;
+
+ g_debug ("GdmPluginManager: plugin '%s' could not be loaded.",
+ gdm_greeter_plugin_get_filename (plugin));
+ filename = gdm_greeter_plugin_get_filename (plugin);
+ g_hash_table_remove (manager->priv->plugins, filename);
+}
+
+static void
+on_plugin_unloaded (GdmPluginManager *manager,
+ GdmGreeterPlugin *plugin)
+{
+ const char *filename;
+
+ filename = gdm_greeter_plugin_get_filename (plugin);
+ g_hash_table_remove (manager->priv->plugins, filename);
+}
+
+static void
+load_plugin (GdmPluginManager *manager,
+ const char *filename)
+{
+ GdmGreeterPlugin *plugin;
+
+ g_debug ("GdmPluginManager: loading plugin '%s'", filename);
+
+ plugin = gdm_greeter_plugin_new (filename);
+
+ g_signal_connect_swapped (plugin, "loaded",
+ G_CALLBACK (on_plugin_loaded),
+ manager);
+ g_signal_connect_swapped (plugin, "load-failed",
+ G_CALLBACK (on_plugin_load_failed),
+ manager);
+ g_signal_connect_swapped (plugin, "unloaded",
+ G_CALLBACK (on_plugin_unloaded),
+ manager);
+ g_hash_table_insert (manager->priv->plugins,
+ g_strdup (filename), plugin);
+
+ gdm_greeter_plugin_load (plugin);
+}
+
+static void
+on_plugin_info_read (GFileEnumerator *enumerator,
+ GAsyncResult *result,
+ GdmPluginManagerOperation *operation)
+{
+ GdmPluginManager *manager;
+ GFile *plugin_dir_file;
+ GList *file_list, *node;
+ GError *error;
+
+ manager = operation->manager;
+ error = NULL;
+ file_list = g_file_enumerator_next_files_finish (enumerator,
+ result, &error);
+ plugin_dir_file = g_file_enumerator_get_container (enumerator);
+ if (error != NULL) {
+ char *plugin_dir;
+
+ plugin_dir = g_file_get_parse_name (plugin_dir_file);
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ g_debug ("GdmPluginManager: Cancelled reading plugin directory %s",
+ plugin_dir);
+ } else {
+ g_warning ("GdmPluginManager: Unable to read plugin directory %s: %s",
+ plugin_dir, error->message);
+ }
+ g_free (plugin_dir);
+ g_error_free (error);
+ g_object_unref (plugin_dir_file);
+ gdm_plugin_manager_untrack_operation (manager, operation);
+ return;
+ }
+
+#ifndef PLUGIN_ORDERING_FIGURED_OUT
+ node = file_list;
+ while (node != NULL) {
+ GFileInfo *info;
+ GFile *file;
+ char *path;
+ GList *next_node;
+
+ next_node = node->next;
+
+ info = (GFileInfo *) node->data;
+
+ file = g_file_get_child (plugin_dir_file,
+ g_file_info_get_name (info));
+ path = g_file_get_path (file);
+
+ if (g_str_has_suffix (path, "password.so")) {
+ file_list = g_list_delete_link (file_list, node);
+ file_list = g_list_prepend (file_list, info);
+ next_node = NULL;
+ }
+ g_free (path);
+ g_object_unref (file);
+
+ node = next_node;
+ }
+#endif
+
+ node = file_list;
+ while (node != NULL) {
+ GFileInfo *info;
+ GFile *file;
+ char *path;
+
+ info = (GFileInfo *) node->data;
+
+ file = g_file_get_child (plugin_dir_file,
+ g_file_info_get_name (info));
+ path = g_file_get_path (file);
+
+ if (g_str_has_suffix (path, G_MODULE_SUFFIX)) {
+ load_plugin (manager, path);
+ }
+ g_free (path);
+ g_object_unref (file);
+
+ node = node->next;
+ }
+ g_object_unref (plugin_dir_file);
+
+ gdm_plugin_manager_untrack_operation (manager, operation);
+ g_signal_emit (manager, signals [PLUGINS_LOADED], 0);
+
+ g_list_free (file_list);
+}
+
+static void
+on_plugin_dir_opened (GFile *plugin_dir_file,
+ GAsyncResult *result,
+ GdmPluginManagerOperation *open_operation)
+{
+ GdmPluginManager *manager;
+ GFileEnumerator *enumerator;
+ GError *error;
+ GdmPluginManagerOperation *operation;
+
+ manager = open_operation->manager;
+ gdm_plugin_manager_untrack_operation (manager, open_operation);
+
+ error = NULL;
+ enumerator = g_file_enumerate_children_finish (plugin_dir_file,
+ result, &error);
+
+ if (enumerator == NULL) {
+ char *plugin_dir;
+
+ plugin_dir = g_file_get_parse_name (plugin_dir_file);
+
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ g_debug ("GdmPluginManager: Cancelled opening plugin directory %s",
+ plugin_dir);
+ } else {
+ g_warning ("GdmPluginManager: Unable to open plugin directory %s: %s",
+ plugin_dir, error->message);
+ }
+ g_free (plugin_dir);
+ g_error_free (error);
+ return;
+ }
+
+ operation = start_operation (manager);
+
+ g_file_enumerator_next_files_async (enumerator, G_MAXINT,
+ G_PRIORITY_DEFAULT,
+ operation->cancellable,
+ (GAsyncReadyCallback)
+ on_plugin_info_read,
+ operation);
+
+ gdm_plugin_manager_track_operation (manager, operation);
+}
+
+static void
+load_plugins_in_dir (GdmPluginManager *manager,
+ const char *plugin_dir)
+{
+ GFile *plugin_dir_file;
+ GdmPluginManagerOperation *operation;
+
+ g_debug ("GdmPluginManager: loading plugins in dir '%s'", plugin_dir);
+
+ operation = start_operation (manager);
+ plugin_dir_file = g_file_new_for_path (plugin_dir);
+ g_file_enumerate_children_async (plugin_dir_file, "standard::*",
+ G_FILE_QUERY_INFO_NONE,
+ G_PRIORITY_DEFAULT,
+ operation->cancellable,
+ (GAsyncReadyCallback)
+ on_plugin_dir_opened,
+ operation);
+ g_object_unref (plugin_dir_file);
+ gdm_plugin_manager_track_operation (manager, operation);
+}
+
+static void
+on_plugin_dir_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ GdmPluginManagerOperation *operation)
+{
+}
+
+static void
+watch_plugin_dir (GdmPluginManager *manager,
+ const char *plugin_dir)
+{
+
+ GdmPluginManagerOperation *operation;
+ GFile *file;
+ GError *error;
+
+ operation = start_operation (manager);
+
+ file = g_file_new_for_path (plugin_dir);
+ manager->priv->plugin_dir_monitor = g_file_monitor_directory (file,
+ G_FILE_MONITOR_NONE,
+ operation->cancellable,
+ &error);
+ if (manager->priv->plugin_dir_monitor != NULL) {
+ g_signal_connect (manager->priv->plugin_dir_monitor,
+ "changed",
+ G_CALLBACK (on_plugin_dir_changed),
+ operation);
+ gdm_plugin_manager_track_operation (manager, operation);
+ } else {
+ g_warning ("Unable to monitor %s: %s",
+ plugin_dir, error->message);
+ g_error_free (error);
+ free_operation (operation);
+ }
+ g_object_unref (file);
+}
+
+static void
+gdm_plugin_manager_init (GdmPluginManager *manager)
+{
+ manager->priv = GDM_PLUGIN_MANAGER_GET_PRIVATE (manager);
+
+ manager->priv->plugins = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ g_object_unref);
+ watch_plugin_dir (manager, GDM_SIMPLE_GREETER_PLUGINS_DIR);
+ load_plugins_in_dir (manager, GDM_SIMPLE_GREETER_PLUGINS_DIR);
+}
+
+static void
+gdm_plugin_manager_finalize (GObject *object)
+{
+ GdmPluginManager *manager;
+
+ manager = GDM_PLUGIN_MANAGER (object);
+
+ g_hash_table_destroy (manager->priv->plugins);
+ g_file_monitor_cancel (manager->priv->plugin_dir_monitor);
+
+ gdm_plugin_manager_cancel_pending_operations (manager);
+
+ G_OBJECT_CLASS (gdm_plugin_manager_parent_class)->finalize (object);
+}
+
+GdmPluginManager *
+gdm_plugin_manager_ref_default (void)
+{
+ if (plugin_manager_object != NULL) {
+ g_object_ref (plugin_manager_object);
+ } else {
+ plugin_manager_object = g_object_new (GDM_TYPE_PLUGIN_MANAGER, NULL);
+ g_object_add_weak_pointer (plugin_manager_object,
+ (gpointer *) &plugin_manager_object);
+ }
+
+ return GDM_PLUGIN_MANAGER (plugin_manager_object);
+}
+
+GdmGreeterPlugin *
+gdm_plugin_manager_get_plugin (GdmPluginManager *manager,
+ const char *name)
+{
+ return g_hash_table_lookup (manager->priv->plugins, name);
+}
diff --git a/gui/simple-greeter/gdm-plugin-manager.h b/gui/simple-greeter/gdm-plugin-manager.h
new file mode 100644
index 0000000..f181140
--- /dev/null
+++ b/gui/simple-greeter/gdm-plugin-manager.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ * Written by: Ray Strode <rstrode@redhat.com>
+ *
+ */
+
+#ifndef __GDM_PLUGIN_MANAGER_H
+#define __GDM_PLUGIN_MANAGER_H
+
+#include <glib-object.h>
+
+#include "gdm-greeter-plugin.h"
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_PLUGIN_MANAGER (gdm_plugin_manager_get_type ())
+#define GDM_PLUGIN_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_PLUGIN_MANAGER, GdmPluginManager))
+#define GDM_PLUGIN_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_PLUGIN_MANAGER, GdmPluginManagerClass))
+#define GDM_IS_PLUGIN_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_PLUGIN_MANAGER))
+#define GDM_IS_PLUGIN_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_PLUGIN_MANAGER))
+#define GDM_PLUGIN_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_PLUGIN_MANAGER, GdmPluginManagerClass))
+
+typedef struct GdmPluginManagerPrivate GdmPluginManagerPrivate;
+
+typedef struct
+{
+ GObject parent;
+ GdmPluginManagerPrivate *priv;
+} GdmPluginManager;
+
+typedef struct
+{
+ GObjectClass parent_class;
+
+ void (* plugins_loaded) (GdmPluginManager *plugin_manager);
+ void (* plugin_added) (GdmPluginManager *plugin_manager,
+ GdmGreeterPlugin *plugin);
+ void (* plugin_removed) (GdmPluginManager *plugin_manager,
+ GdmGreeterPlugin *plugin);
+} GdmPluginManagerClass;
+
+GType gdm_plugin_manager_get_type (void);
+
+GdmPluginManager *gdm_plugin_manager_ref_default (void);
+
+GdmGreeterPlugin *gdm_plugin_manager_get_plugin (GdmPluginManager *plugin,
+ const char *name);
+
+G_END_DECLS
+
+#endif /* __GDM_PLUGIN_MANAGER_H */
diff --git a/gui/simple-greeter/gdm-task-list.c b/gui/simple-greeter/gdm-task-list.c
new file mode 100644
index 0000000..a7f8c74
--- /dev/null
+++ b/gui/simple-greeter/gdm-task-list.c
@@ -0,0 +1,385 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ * Written by: Ray Strode <rstrode@redhat.com>
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <dirent.h>
+#include <sys/stat.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <gtk/gtk.h>
+
+#include "gdm-task-list.h"
+
+#define GDM_TASK_LIST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_TASK_LIST, GdmTaskListPrivate))
+
+struct GdmTaskListPrivate
+{
+ GtkWidget *box;
+ GList *tasks;
+};
+
+enum {
+ ACTIVATED = 0,
+ DEACTIVATED,
+ NUMBER_OF_SIGNALS
+};
+
+static guint signals[NUMBER_OF_SIGNALS];
+
+static void gdm_task_list_class_init (GdmTaskListClass *klass);
+static void gdm_task_list_init (GdmTaskList *task_list);
+static void gdm_task_list_finalize (GObject *object);
+
+G_DEFINE_TYPE (GdmTaskList, gdm_task_list, GTK_TYPE_ALIGNMENT);
+
+static void
+on_task_toggled (GdmTaskList *widget,
+ GtkRadioButton *button)
+{
+ GdmTask *task;
+
+ task = g_object_get_data (G_OBJECT (button), "gdm-task");
+
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) {
+
+ GList *task_node;
+
+ /* Sort the list such that the tasks the user clicks last end
+ * up first. This doesn't change the order in which the tasks
+ * appear in the UI, but will affect which tasks we implicitly
+ * activate if the currently active task gets disabled.
+ */
+ task_node = g_list_find (widget->priv->tasks, task);
+ if (task_node != NULL) {
+ widget->priv->tasks = g_list_delete_link (widget->priv->tasks, task_node);
+ widget->priv->tasks = g_list_prepend (widget->priv->tasks,
+ task);
+ }
+
+ g_signal_emit (widget, signals[ACTIVATED], 0, task);
+ } else {
+ g_signal_emit (widget, signals[DEACTIVATED], 0, task);
+ }
+}
+
+GdmTask *
+gdm_task_list_foreach_task (GdmTaskList *task_list,
+ GdmTaskListForeachFunc search_func,
+ gpointer data)
+{
+ GList *node;
+
+ for (node = task_list->priv->tasks; node != NULL; node = node->next) {
+ GdmTask *task;
+
+ task = node->data;
+
+ if (search_func (task_list, task, data)) {
+ return g_object_ref (task);
+ }
+ }
+
+ return NULL;
+}
+
+static void
+on_task_enabled (GdmTaskList *task_list,
+ GdmTask *task)
+{
+ GtkWidget *button;
+
+ button = g_object_get_data (G_OBJECT (task), "gdm-task-list-button");
+
+ gtk_widget_set_sensitive (button, TRUE);
+}
+
+static void
+activate_first_available_task (GdmTaskList *task_list)
+{
+ GList *node;
+
+ node = task_list->priv->tasks;
+ while (node != NULL) {
+ GdmTask *task;
+
+ task = GDM_TASK (node->data);
+
+ if (gdm_task_list_set_active_task (task_list, task)) {
+ break;
+ }
+
+ node = node->next;
+ }
+
+}
+
+static void
+on_task_disabled (GdmTaskList *task_list,
+ GdmTask *task)
+{
+ GtkWidget *button;
+ gboolean was_active;
+
+ button = g_object_get_data (G_OBJECT (task), "gdm-task-list-button");
+ was_active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+
+ gtk_widget_set_sensitive (button, FALSE);
+
+ if (was_active) {
+ activate_first_available_task (task_list);
+ }
+}
+
+void
+gdm_task_list_add_task (GdmTaskList *task_list,
+ GdmTask *task)
+{
+ GtkWidget *image;
+ GtkWidget *button;
+ GIcon *icon;
+ char *description;
+
+ if (task_list->priv->tasks == NULL) {
+ button = gtk_radio_button_new (NULL);
+ } else {
+ GdmTask *previous_task;
+ GtkRadioButton *previous_button;
+
+ previous_task = GDM_TASK (task_list->priv->tasks->data);
+ previous_button = GTK_RADIO_BUTTON (g_object_get_data (G_OBJECT (previous_task), "gdm-task-list-button"));
+ button = gtk_radio_button_new_from_widget (previous_button);
+ }
+ g_object_set_data (G_OBJECT (task), "gdm-task-list-button", button);
+
+ g_object_set (G_OBJECT (button), "draw-indicator", FALSE, NULL);
+ g_object_set_data (G_OBJECT (button), "gdm-task", task);
+ g_signal_connect_swapped (button, "toggled",
+ G_CALLBACK (on_task_toggled),
+ task_list);
+
+ gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE);
+ gtk_widget_set_sensitive (button, gdm_task_is_enabled (task));
+
+ g_signal_connect_swapped (G_OBJECT (task), "enabled",
+ G_CALLBACK (on_task_enabled),
+ task_list);
+
+ g_signal_connect_swapped (G_OBJECT (task), "disabled",
+ G_CALLBACK (on_task_disabled),
+ task_list);
+
+ icon = gdm_task_get_icon (task);
+ image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_SMALL_TOOLBAR);
+ g_object_unref (icon);
+
+ gtk_widget_show (image);
+ gtk_container_add (GTK_CONTAINER (button), image);
+ description = gdm_task_get_description (task);
+ gtk_widget_set_tooltip_text (button, description);
+ g_free (description);
+ gtk_widget_show (button);
+
+ gtk_container_add (GTK_CONTAINER (task_list->priv->box), button);
+ task_list->priv->tasks = g_list_append (task_list->priv->tasks,
+ g_object_ref (task));
+
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) {
+ g_signal_emit (task_list, signals[ACTIVATED], 0, task);
+ }
+}
+
+void
+gdm_task_list_remove_task (GdmTaskList *task_list,
+ GdmTask *task)
+{
+ GtkWidget *button;
+
+ task_list->priv->tasks = g_list_remove (task_list->priv->tasks, task);
+
+ button = g_object_get_data (G_OBJECT (task), "gdm-task-list-button");
+
+ if (button != NULL) {
+ g_signal_handlers_disconnect_by_func (G_OBJECT (task),
+ G_CALLBACK (on_task_enabled),
+ task_list);
+ g_signal_handlers_disconnect_by_func (G_OBJECT (task),
+ G_CALLBACK (on_task_disabled),
+ task_list);
+ gtk_widget_destroy (button);
+ g_object_set_data (G_OBJECT (task), "gdm-task-list-button", NULL);
+ }
+
+ g_object_unref (task);
+
+ activate_first_available_task (task_list);
+}
+
+static void
+gdm_task_list_class_init (GdmTaskListClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gdm_task_list_finalize;
+
+ signals [ACTIVATED] = g_signal_new ("activated",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmTaskListClass, activated),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1, G_TYPE_OBJECT);
+
+ signals [DEACTIVATED] = g_signal_new ("deactivated",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmTaskListClass, deactivated),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1, G_TYPE_OBJECT);
+
+ g_type_class_add_private (klass, sizeof (GdmTaskListPrivate));
+}
+
+static void
+gdm_task_list_init (GdmTaskList *widget)
+{
+ widget->priv = GDM_TASK_LIST_GET_PRIVATE (widget);
+
+ gtk_alignment_set_padding (GTK_ALIGNMENT (widget), 0, 0, 0, 0);
+ gtk_alignment_set (GTK_ALIGNMENT (widget), 0.0, 0.0, 0, 0);
+
+ widget->priv->box = gtk_hbox_new (TRUE, 2);
+ gtk_widget_show (widget->priv->box);
+ gtk_container_add (GTK_CONTAINER (widget),
+ widget->priv->box);
+}
+
+static void
+gdm_task_list_finalize (GObject *object)
+{
+ GdmTaskList *widget;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDM_IS_TASK_LIST (object));
+
+ widget = GDM_TASK_LIST (object);
+
+ g_list_foreach (widget->priv->tasks, (GFunc) g_object_unref, NULL);
+ g_list_free (widget->priv->tasks);
+
+ G_OBJECT_CLASS (gdm_task_list_parent_class)->finalize (object);
+}
+
+GtkWidget *
+gdm_task_list_new (void)
+{
+ GObject *object;
+
+ object = g_object_new (GDM_TYPE_TASK_LIST, NULL);
+
+ return GTK_WIDGET (object);
+}
+
+gboolean
+gdm_task_list_task_is_active (GdmTaskList *task_list,
+ GdmTask *task)
+{
+ GtkWidget *button;
+
+ button = g_object_get_data (G_OBJECT (task), "gdm-task-list-button");
+
+ return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+}
+
+GdmTask *
+gdm_task_list_get_active_task (GdmTaskList *widget)
+{
+ return gdm_task_list_foreach_task (widget,
+ (GdmTaskListForeachFunc)
+ gdm_task_list_task_is_active,
+ NULL);
+}
+
+gboolean
+gdm_task_list_set_active_task (GdmTaskList *widget,
+ GdmTask *task)
+{
+ GtkWidget *button;
+ gboolean was_sensitive;
+ gboolean was_activated;
+
+ if (!gdm_task_is_visible (task)) {
+ return FALSE;
+ }
+
+ was_sensitive = GTK_WIDGET_SENSITIVE (widget);
+ gtk_widget_set_sensitive (GTK_WIDGET (widget), TRUE);
+
+ button = GTK_WIDGET (g_object_get_data (G_OBJECT (task),
+ "gdm-task-list-button"));
+
+ was_activated = FALSE;
+ if (GTK_WIDGET_IS_SENSITIVE (button)) {
+ if (gtk_widget_activate (button)) {
+ was_activated = TRUE;
+ }
+ }
+
+ gtk_widget_set_sensitive (GTK_WIDGET (widget), was_sensitive);
+ return was_activated;
+}
+
+int
+gdm_task_list_get_number_of_tasks (GdmTaskList *widget)
+{
+ return g_list_length (widget->priv->tasks);
+}
+
+int
+gdm_task_list_get_number_of_visible_tasks (GdmTaskList *widget)
+{
+ GList *node;
+ int number_of_visible_tasks;
+
+ number_of_visible_tasks = 0;
+ for (node = widget->priv->tasks; node != NULL; node = node->next) {
+ GdmTask *task;
+
+ task = node->data;
+
+ if (gdm_task_is_enabled (task) && gdm_task_is_visible (task)) {
+ number_of_visible_tasks++;
+ }
+ }
+
+ return number_of_visible_tasks;
+}
diff --git a/gui/simple-greeter/gdm-task-list.h b/gui/simple-greeter/gdm-task-list.h
new file mode 100644
index 0000000..1c15168
--- /dev/null
+++ b/gui/simple-greeter/gdm-task-list.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ * Written by: Ray Strode <rstrode@redhat.com>
+ */
+
+#ifndef __GDM_TASK_LIST_H
+#define __GDM_TASK_LIST_H
+
+#include <glib-object.h>
+#include <gio/gio.h>
+#include <gtk/gtkalignment.h>
+
+#include "gdm-task.h"
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_TASK_LIST (gdm_task_list_get_type ())
+#define GDM_TASK_LIST(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_TASK_LIST, GdmTaskList))
+#define GDM_TASK_LIST_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_TASK_LIST, GdmTaskListClass))
+#define GDM_IS_TASK_LIST(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_TASK_LIST))
+#define GDM_IS_TASK_LIST_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_TASK_LIST))
+#define GDM_TASK_LIST_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_TASK_LIST, GdmTaskListClass))
+
+typedef struct GdmTaskListPrivate GdmTaskListPrivate;
+typedef struct _GdmTaskList GdmTaskList;
+
+typedef gboolean (* GdmTaskListForeachFunc) (GdmTaskList *task_list,
+ GdmTask *task,
+ gpointer data);
+
+struct _GdmTaskList
+{
+ GtkAlignment parent;
+ GdmTaskListPrivate *priv;
+};
+
+typedef struct
+{
+ GtkAlignmentClass parent_class;
+
+ void (* deactivated) (GdmTaskList *widget,
+ GdmTask *task);
+ void (* activated) (GdmTaskList *widget,
+ GdmTask *task);
+} GdmTaskListClass;
+
+GType gdm_task_list_get_type (void);
+GtkWidget * gdm_task_list_new (void);
+
+
+gboolean gdm_task_list_task_is_active (GdmTaskList *task_list,
+ GdmTask *task);
+GdmTask * gdm_task_list_get_active_task (GdmTaskList *widget);
+gboolean gdm_task_list_set_active_task (GdmTaskList *widget,
+ GdmTask *task);
+GdmTask * gdm_task_list_foreach_task (GdmTaskList *widget,
+ GdmTaskListForeachFunc foreach_func,
+ gpointer data);
+void gdm_task_list_add_task (GdmTaskList *widget,
+ GdmTask *task);
+
+void gdm_task_list_remove_task (GdmTaskList *widget,
+ GdmTask *task);
+
+int gdm_task_list_get_number_of_tasks (GdmTaskList *widget);
+
+int gdm_task_list_get_number_of_visible_tasks (GdmTaskList *widget);
+G_END_DECLS
+
+#endif /* __GDM_TASK_LIST_H */
diff --git a/gui/simple-greeter/gdm-user-chooser-widget.c b/gui/simple-greeter/gdm-user-chooser-widget.c
index 211b033..33708b9 100644
--- a/gui/simple-greeter/gdm-user-chooser-widget.c
+++ b/gui/simple-greeter/gdm-user-chooser-widget.c
@@ -365,9 +365,30 @@ gdm_user_chooser_widget_set_show_user_auto (GdmUserChooserWidget *widget,
char *
gdm_user_chooser_widget_get_chosen_user_name (GdmUserChooserWidget *widget)
{
+ char *active_item_id;
+ gboolean isnt_user;
+
g_return_val_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget), NULL);
- return gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (widget));
+ active_item_id = gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (widget));
+ if (active_item_id == NULL) {
+ g_debug ("GdmUserChooserWidget: no active item in list");
+ return NULL;
+ }
+
+ gdm_chooser_widget_lookup_item (GDM_CHOOSER_WIDGET (widget), active_item_id,
+ NULL, NULL, NULL, NULL, NULL,
+ &isnt_user);
+
+ if (isnt_user) {
+ g_debug ("GdmUserChooserWidget: active item '%s' isn't a user", active_item_id);
+ g_free (active_item_id);
+ return NULL;
+ }
+
+ g_debug ("GdmUserChooserWidget: active item '%s' is a user", active_item_id);
+
+ return active_item_id;
}
void
diff --git a/gui/simple-greeter/libgdmsimplegreeter/Makefile.am b/gui/simple-greeter/libgdmsimplegreeter/Makefile.am
new file mode 100644
index 0000000..0d7a0bd
--- /dev/null
+++ b/gui/simple-greeter/libgdmsimplegreeter/Makefile.am
@@ -0,0 +1,48 @@
+NULL =
+
+AM_CPPFLAGS = \
+ -I. \
+ -I.. \
+ -I$(top_srcdir)/common \
+ -DBINDIR=\"$(bindir)\" \
+ -DDATADIR=\"$(datadir)\" \
+ -DLIBDIR=\"$(libdir)\" \
+ -DLIBEXECDIR=\"$(libexecdir)\" \
+ -DLOGDIR=\"$(logdir)\" \
+ -DPIXMAPDIR=\"$(pixmapdir)\" \
+ -DSBINDIR=\"$(sbindir)\" \
+ $(GTK_CFLAGS) \
+ $(NULL)
+
+lib_LTLIBRARIES = \
+ libgdmsimplegreeter.la \
+ $(NULL)
+
+libgdmsimplegreeter_la_SOURCES = \
+ gdm-task.h \
+ gdm-task.c \
+ gdm-conversation.h \
+ gdm-conversation.c \
+ gdm-greeter-extension.h \
+ gdm-greeter-extension.c \
+ $(NULL)
+
+libgdmsimplegreeter_la_LIBADD = \
+ $(GTK_LIBS) \
+ $(top_builddir)/common/libgdmcommon.la \
+ $(NULL)
+
+libgdmsimplegreeter_la_LDFLAGS = \
+ -export-symbols-regex '^[^_].*' \
+ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
+ -no-undefined \
+ $(NULL)
+
+headersdir = $(includedir)/gdm/simple-greeter
+headers_HEADERS = gdm-greeter-extension.h
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = gdmsimplegreeter.pc
+
+EXTRA_DIST = gdmsimplegreeter.pc
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c
new file mode 100644
index 0000000..ee763ef
--- /dev/null
+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ * Written By: Ray Strode <rstrode@redhat.com>
+ *
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gtk/gtk.h>
+
+#include "gdm-conversation.h"
+#include "gdm-marshal.h"
+#include "gdm-task.h"
+
+enum {
+ ANSWER,
+ USER_CHOSEN,
+ CANCEL,
+ LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0, };
+
+static void gdm_conversation_class_init (gpointer g_iface);
+
+GType
+gdm_conversation_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ type = g_type_register_static_simple (G_TYPE_INTERFACE,
+ "GdmConversation",
+ sizeof (GdmConversationIface),
+ (GClassInitFunc) gdm_conversation_class_init,
+ 0, NULL, 0);
+
+ g_type_interface_add_prerequisite (type, G_TYPE_OBJECT);
+ g_type_interface_add_prerequisite (type, GDM_TYPE_TASK);
+ }
+
+ return type;
+}
+
+static void
+gdm_conversation_class_init (gpointer g_iface)
+{
+ GType iface_type = G_TYPE_FROM_INTERFACE (g_iface);
+
+ signals [ANSWER] =
+ g_signal_new ("answer",
+ iface_type,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmConversationIface, answer),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1, G_TYPE_STRING);
+ signals [USER_CHOSEN] =
+ g_signal_new ("user-chosen",
+ iface_type,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdmConversationIface, user_chosen),
+ NULL,
+ NULL,
+ gdm_marshal_BOOLEAN__STRING,
+ G_TYPE_BOOLEAN,
+ 1, G_TYPE_STRING);
+ signals [CANCEL] =
+ g_signal_new ("cancel",
+ iface_type,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmConversationIface, cancel),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+void
+gdm_conversation_set_message (GdmConversation *conversation,
+ const char *message)
+{
+ GDM_CONVERSATION_GET_IFACE (conversation)->set_message (conversation, message);
+}
+
+void
+gdm_conversation_ask_question (GdmConversation *conversation,
+ const char *message)
+{
+ GDM_CONVERSATION_GET_IFACE (conversation)->ask_question (conversation, message);
+}
+
+void
+gdm_conversation_ask_secret (GdmConversation *conversation,
+ const char *message)
+{
+ GDM_CONVERSATION_GET_IFACE (conversation)->ask_secret (conversation, message);
+}
+
+void
+gdm_conversation_reset (GdmConversation *conversation)
+{
+ return GDM_CONVERSATION_GET_IFACE (conversation)->reset (conversation);
+}
+
+void
+gdm_conversation_set_ready (GdmConversation *conversation)
+{
+ return GDM_CONVERSATION_GET_IFACE (conversation)->set_ready (conversation);
+}
+
+char *
+gdm_conversation_get_service_name (GdmConversation *conversation)
+{
+ return GDM_CONVERSATION_GET_IFACE (conversation)->get_service_name (conversation);
+}
+
+GtkWidget *
+gdm_conversation_get_page (GdmConversation *conversation)
+{
+ return GDM_CONVERSATION_GET_IFACE (conversation)->get_page (conversation);
+}
+
+GtkActionGroup *
+gdm_conversation_get_actions (GdmConversation *conversation)
+{
+ return GDM_CONVERSATION_GET_IFACE (conversation)->get_actions (conversation);
+}
+
+gboolean
+gdm_conversation_focus (GdmConversation *conversation)
+{
+ return GDM_CONVERSATION_GET_IFACE (conversation)->focus (conversation);
+}
+
+void
+gdm_conversation_request_answer (GdmConversation *conversation)
+{
+ return GDM_CONVERSATION_GET_IFACE (conversation)->request_answer (conversation);
+}
+
+/* protected
+ */
+void
+gdm_conversation_answer (GdmConversation *conversation,
+ const char *answer)
+{
+ g_signal_emit (conversation, signals [ANSWER], 0, answer);
+}
+
+void
+gdm_conversation_cancel (GdmConversation *conversation)
+{
+ g_signal_emit (conversation, signals [CANCEL], 0);
+}
+
+gboolean
+gdm_conversation_choose_user (GdmConversation *conversation,
+ const char *username)
+{
+ gboolean was_chosen;
+
+ was_chosen = FALSE;
+
+ g_signal_emit (conversation, signals [USER_CHOSEN], 0, username, &was_chosen);
+
+ return was_chosen;
+}
diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h
new file mode 100644
index 0000000..b37b21e
--- /dev/null
+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ * Written by: Ray Strode <rstrode@redhat.com>
+ */
+
+
+#ifndef __GDM_CONVERSATION_H
+#define __GDM_CONVERSATION_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_CONVERSATION (gdm_conversation_get_type ())
+#define GDM_CONVERSATION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_CONVERSATION, GdmConversation))
+#define GDM_CONVERSATION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_CONVERSATION, GdmConversationIface))
+#define GDM_IS_CONVERSATION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_CONVERSATION))
+#define GDM_CONVERSATION_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), GDM_TYPE_CONVERSATION, GdmConversationIface))
+
+#define GDM_CONVERSATION_DEFAULT_ACTION "default-action"
+#define GDM_CONVERSATION_OTHER_USER "__other"
+
+typedef struct _GdmConversation GdmConversation;
+typedef struct _GdmConversationIface GdmConversationIface;
+
+struct _GdmConversationIface
+{
+ GTypeInterface base_iface;
+
+ /* methods */
+ void (* set_message) (GdmConversation *conversation,
+ const char *message);
+ void (* ask_question) (GdmConversation *conversation,
+ const char *message);
+ void (* ask_secret) (GdmConversation *conversation,
+ const char *message);
+ void (* reset) (GdmConversation *conversation);
+ void (* set_ready) (GdmConversation *conversation);
+ char * (* get_service_name) (GdmConversation *conversation);
+ GtkWidget * (* get_page) (GdmConversation *conversation);
+ GtkActionGroup * (* get_actions) (GdmConversation *conversation);
+ void (* request_answer) (GdmConversation *conversation);
+ gboolean (* focus) (GdmConversation *conversation);
+
+ /* signals */
+ char * (* answer) (GdmConversation *conversation);
+ void (* cancel) (GdmConversation *conversation);
+ gboolean (* user_chosen) (GdmConversation *conversation);
+};
+
+GType gdm_conversation_get_type (void) G_GNUC_CONST;
+
+void gdm_conversation_set_message (GdmConversation *conversation,
+ const char *message);
+void gdm_conversation_ask_question (GdmConversation *conversation,
+ const char *message);
+void gdm_conversation_ask_secret (GdmConversation *conversation,
+ const char *message);
+void gdm_conversation_reset (GdmConversation *converastion);
+void gdm_conversation_set_ready (GdmConversation *converastion);
+char *gdm_conversation_get_service_name (GdmConversation *conversation);
+GtkWidget *gdm_conversation_get_page (GdmConversation *conversation);
+GtkActionGroup *gdm_conversation_get_actions (GdmConversation *conversation);
+void gdm_conversation_request_answer (GdmConversation *conversation);
+gboolean gdm_conversation_focus (GdmConversation *conversation);
+
+/* protected
+ */
+void gdm_conversation_answer (GdmConversation *conversation,
+ const char *answer);
+void gdm_conversation_cancel (GdmConversation *conversation);
+gboolean gdm_conversation_choose_user (GdmConversation *conversation,
+ const char *username);
+
+G_END_DECLS
+
+#endif /* __GDM_CONVERSATION_H */
diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-greeter-extension.c b/gui/simple-greeter/libgdmsimplegreeter/gdm-greeter-extension.c
new file mode 100644
index 0000000..a71d3f7
--- /dev/null
+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-greeter-extension.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ * Written By: Ray Strode <rstrode@redhat.com>
+ *
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "gdm-greeter-extension.h"
+
+enum {
+ LOADED,
+ LOAD_FAILED,
+ LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0, };
+
+static void gdm_greeter_extension_class_init (gpointer g_iface);
+
+GType
+gdm_greeter_extension_get_type (void)
+{
+ static GType greeter_extension_type = 0;
+
+ if (!greeter_extension_type) {
+ greeter_extension_type = g_type_register_static_simple (G_TYPE_INTERFACE,
+ "GdmGreeterExtension",
+ sizeof (GdmGreeterExtensionIface),
+ (GClassInitFunc) gdm_greeter_extension_class_init,
+ 0, NULL, 0);
+
+ g_type_interface_add_prerequisite (greeter_extension_type, G_TYPE_OBJECT);
+ }
+
+ return greeter_extension_type;
+}
+
+static void
+gdm_greeter_extension_class_init (gpointer g_iface)
+{
+ GType iface_type = G_TYPE_FROM_INTERFACE (g_iface);
+
+ signals [LOADED] =
+ g_signal_new ("loaded",
+ iface_type,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmGreeterExtensionIface, loaded),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals [LOADED] =
+ g_signal_new ("load_failed",
+ iface_type,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmGreeterExtensionIface, load_failed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1, G_TYPE_POINTER);
+}
+
+void
+gdm_greeter_extension_loaded (GdmGreeterExtension *extension)
+{
+ g_signal_emit (extension, signals [LOADED], 0);
+}
+
+void
+gdm_greeter_extension_load_failed (GdmGreeterExtension *extension,
+ GError *error)
+{
+ g_signal_emit (extension, signals [LOAD_FAILED], 0, error);
+}
diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-greeter-extension.h b/gui/simple-greeter/libgdmsimplegreeter/gdm-greeter-extension.h
new file mode 100644
index 0000000..283ba0e
--- /dev/null
+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-greeter-extension.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2009 Red Hat, Inc. *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ * Written by: Ray Strode
+ */
+
+#ifndef __GDM_GREETER_EXTENSION_H
+#define __GDM_GREETER_EXTENSION_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_GREETER_EXTENSION (gdm_greeter_extension_get_type ())
+#define GDM_GREETER_EXTENSION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_GREETER_EXTENSION, GdmGreeterExtension))
+#define GDM_GREETER_EXTENSION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_GREETER_EXTENSION, GdmGreeterExtensionClass))
+#define GDM_IS_GREETER_EXTENSION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_GREETER_EXTENSION))
+#define GDM_GREETER_EXTENSION_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), GDM_TYPE_GREETER_EXTENSION, GdmGreeterExtensionIface))
+
+typedef struct _GdmGreeterExtension GdmGreeterExtension;
+typedef struct _GdmGreeterExtensionIface GdmGreeterExtensionIface;
+
+struct _GdmGreeterExtensionIface
+{
+ GTypeInterface base_iface;
+
+ void (* loaded) (GdmGreeterExtension *extension);
+ void (* load_failed) (GdmGreeterExtension *extension,
+ GError *error);
+};
+
+GType gdm_greeter_extension_get_type (void) G_GNUC_CONST;
+
+void gdm_greeter_extension_loaded (GdmGreeterExtension *extension);
+void gdm_greeter_extension_load_failed (GdmGreeterExtension *extension,
+ GError *error);
+
+typedef GdmGreeterExtension * (* GdmGreeterPluginGetExtensionFunc) (void);
+
+G_END_DECLS
+#endif /* __GDM_GREETER_EXTENSION_H */
diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-task.c b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.c
new file mode 100644
index 0000000..858b1ef
--- /dev/null
+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ * Written By: Ray Strode <rstrode@redhat.com>
+ *
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "gdm-task.h"
+
+enum {
+ ENABLED,
+ DISABLED,
+ LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0, };
+static void gdm_task_class_init (gpointer g_iface);
+
+GType
+gdm_task_get_type (void)
+{
+ static GType task_type = 0;
+
+ if (!task_type) {
+ task_type = g_type_register_static_simple (G_TYPE_INTERFACE,
+ "GdmTask",
+ sizeof (GdmTaskIface),
+ (GClassInitFunc) gdm_task_class_init,
+ 0, NULL, 0);
+
+ g_type_interface_add_prerequisite (task_type, G_TYPE_OBJECT);
+ }
+
+ return task_type;
+}
+
+GIcon *
+gdm_task_get_icon (GdmTask *task)
+{
+ return GDM_TASK_GET_IFACE (task)->get_icon (task);
+}
+
+char *
+gdm_task_get_description (GdmTask *task)
+{
+ return GDM_TASK_GET_IFACE (task)->get_description (task);
+}
+
+char *
+gdm_task_get_name (GdmTask *task)
+{
+ return GDM_TASK_GET_IFACE (task)->get_name (task);
+}
+
+void
+gdm_task_set_enabled (GdmTask *task,
+ gboolean should_enable)
+{
+ g_object_set_data (G_OBJECT (task), "gdm-task-is-disabled", GINT_TO_POINTER (!should_enable));
+
+ if (should_enable) {
+ g_signal_emit (G_OBJECT (task), signals [ENABLED], 0);
+ } else {
+ g_signal_emit (G_OBJECT (task), signals [DISABLED], 0);
+ }
+}
+
+gboolean
+gdm_task_is_enabled (GdmTask *task)
+{
+ return !g_object_get_data (G_OBJECT (task), "gdm-task-is-disabled");
+}
+
+gboolean
+gdm_task_is_choosable (GdmTask *task)
+{
+ return GDM_TASK_GET_IFACE (task)->is_choosable (task);
+}
+
+gboolean
+gdm_task_is_visible (GdmTask *task)
+{
+ return GDM_TASK_GET_IFACE (task)->is_visible (task);
+}
+
+static void
+gdm_task_class_init (gpointer g_iface)
+{
+ GType iface_type = G_TYPE_FROM_INTERFACE (g_iface);
+
+ signals [ENABLED] =
+ g_signal_new ("enabled",
+ iface_type,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmTaskIface, enabled),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ signals [DISABLED] =
+ g_signal_new ("disabled",
+ iface_type,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmTaskIface, disabled),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-task.h b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.h
new file mode 100644
index 0000000..51e2b0a
--- /dev/null
+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ * Written by: Ray Strode <rstrode@redhat.com>
+ */
+
+
+#ifndef __GDM_TASK_H
+#define __GDM_TASK_H
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_TASK (gdm_task_get_type ())
+#define GDM_TASK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_TASK, GdmTask))
+#define GDM_TASK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_TASK, GdmTaskIface))
+#define GDM_IS_TASK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_TASK))
+#define GDM_TASK_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), GDM_TYPE_TASK, GdmTaskIface))
+
+typedef struct _GdmTask GdmTask;
+typedef struct _GdmTaskIface GdmTaskIface;
+
+struct _GdmTaskIface
+{
+ GTypeInterface base_iface;
+
+ /* methods */
+ GIcon * (* get_icon) (GdmTask *task);
+ char * (* get_description) (GdmTask *task);
+ char * (* get_name) (GdmTask *task);
+ gboolean (* is_choosable) (GdmTask *task);
+ gboolean (* is_visible) (GdmTask *task);
+ /* signals */
+ void (* enabled) (GdmTask *task);
+ void (* disabled) (GdmTask *task);
+};
+
+GType gdm_task_get_type (void) G_GNUC_CONST;
+
+GIcon *gdm_task_get_icon (GdmTask *task);
+char *gdm_task_get_description (GdmTask *task);
+char *gdm_task_get_name (GdmTask *task);
+void gdm_task_set_enabled (GdmTask *task,
+ gboolean should_enable);
+gboolean gdm_task_is_enabled (GdmTask *task);
+gboolean gdm_task_is_choosable (GdmTask *task);
+gboolean gdm_task_is_visible (GdmTask *task);
+G_END_DECLS
+
+#endif /* __GDM_TASK_H */
diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdmsimplegreeter.pc.in b/gui/simple-greeter/libgdmsimplegreeter/gdmsimplegreeter.pc.in
new file mode 100644
index 0000000..a429d99
--- /dev/null
+++ b/gui/simple-greeter/libgdmsimplegreeter/gdmsimplegreeter.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+pluginsdir=@GDM_SIMPLE_GREETER_PLUGINS_DIR@
+
+Name: GDM Simple Greeter
+Description: Library for GDM Simple Greeter Plugins
+Version: @VERSION@
+Libs: -L${libdir} -lgdmsimplegreeter
+Cflags: -I${includedir}/gdm/simple-greeter
diff --git a/gui/simple-greeter/plugins/Makefile.am b/gui/simple-greeter/plugins/Makefile.am
new file mode 100644
index 0000000..c0390db
--- /dev/null
+++ b/gui/simple-greeter/plugins/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = password
diff --git a/gui/simple-greeter/plugins/password/Makefile.am b/gui/simple-greeter/plugins/password/Makefile.am
new file mode 100644
index 0000000..764904d
--- /dev/null
+++ b/gui/simple-greeter/plugins/password/Makefile.am
@@ -0,0 +1,53 @@
+NULL =
+PAM_SERVICE_NAME = gdm-password
+
+extensiondir = $(extensionsdatadir)/password
+extension_DATA = page.ui
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/common \
+ -I$(top_srcdir)/gui/simple-greeter/libnotificationarea \
+ -I$(top_srcdir)/gui/simple-greeter/libgdmsimplegreeter \
+ -DDMCONFDIR=\""$(dmconfdir)"\" \
+ -DGDMCONFDIR=\"$(gdmconfdir)\" \
+ -DPLUGINDATADIR=\""$(extensiondir)"\" \
+ -DPAMSERVICENAME=\""$(PAM_SERVICE_NAME)"\" \
+ -DSYSCONFDIR=\""$(sysconfdir)"\" \
+ -DLIBLOCALEDIR=\""$(prefix)/lib/locale"\" \
+ -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
+ -DLIBEXECDIR=\""$(libexecdir)"\" \
+ -DSBINDIR=\""$(sbindir)"\" \
+ $(DISABLE_DEPRECATED_CFLAGS) \
+ $(GTK_CFLAGS) \
+ $(SIMPLE_GREETER_CFLAGS) \
+ $(POLKIT_GNOME_CFLAGS) \
+ $(NULL)
+
+plugindir = $(GDM_SIMPLE_GREETER_PLUGINS_DIR)
+plugin_LTLIBRARIES = password.la
+
+password_la_CFLAGS = \
+ $(SIMPLE_GREETER_CFLAGS) \
+ $(NULL)
+
+password_la_LDFLAGS = -module -avoid-version -export-dynamic
+password_la_LIBADD = ../../../../common/libgdmcommon.la \
+ ../../libgdmsimplegreeter/libgdmsimplegreeter.la
+password_la_SOURCES = \
+ gdm-password-extension.h \
+ gdm-password-extension.c \
+ plugin.c
+
+$(PAM_SERVICE_NAME): $(PAM_SERVICE_NAME).pam
+ cp $(PAM_SERVICE_NAME).pam $(PAM_SERVICE_NAME)
+
+pamdir = $(PAM_PREFIX)/pam.d
+pam_DATA = $(PAM_SERVICE_NAME)
+
+EXTRA_DIST = $(extension_DATA) $(PAM_SERVICE_NAME).pam
+CLEANFILES = $(PAM_SERVICE_NAME)
+
+MAINTAINERCLEANFILES = \
+ *~ \
+ $(PAM_SERVICE_NAME) \
+ Makefile.in
diff --git a/gui/simple-greeter/plugins/password/gdm-password-extension.c b/gui/simple-greeter/plugins/password/gdm-password-extension.c
new file mode 100644
index 0000000..255283e
--- /dev/null
+++ b/gui/simple-greeter/plugins/password/gdm-password-extension.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ * Written By: Ray Strode <rstrode@redhat.com>
+ *
+ */
+
+#include <config.h>
+#include "gdm-password-extension.h"
+#include "gdm-conversation.h"
+#include "gdm-task.h"
+
+#include <glib/gi18n-lib.h>
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+
+struct _GdmPasswordExtensionPrivate
+{
+ GIcon *icon;
+ GtkWidget *page;
+ GtkActionGroup *actions;
+
+ GtkWidget *message_label;
+ GtkWidget *prompt_label;
+ GtkWidget *prompt_entry;
+
+ guint answer_pending : 1;
+};
+
+static void gdm_password_extension_finalize (GObject *object);
+
+static void gdm_task_iface_init (GdmTaskIface *iface);
+static void gdm_conversation_iface_init (GdmConversationIface *iface);
+static void gdm_greeter_extension_iface_init (GdmGreeterExtensionIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GdmPasswordExtension,
+ gdm_password_extension,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GDM_TYPE_GREETER_EXTENSION,
+ gdm_greeter_extension_iface_init)
+ G_IMPLEMENT_INTERFACE (GDM_TYPE_TASK,
+ gdm_task_iface_init)
+ G_IMPLEMENT_INTERFACE (GDM_TYPE_CONVERSATION,
+ gdm_conversation_iface_init));
+
+static void
+gdm_password_extension_set_message (GdmConversation *conversation,
+ const char *message)
+{
+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation);
+ gtk_widget_show (extension->priv->message_label);
+ gtk_label_set_text (GTK_LABEL (extension->priv->message_label), message);
+}
+
+static void
+gdm_password_extension_ask_question (GdmConversation *conversation,
+ const char *message)
+{
+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation);
+ gtk_widget_show (extension->priv->prompt_label);
+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), message);
+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), "");
+ gtk_entry_set_visibility (GTK_ENTRY (extension->priv->prompt_entry), TRUE);
+ gtk_widget_show (extension->priv->prompt_entry);
+ gtk_widget_grab_focus (extension->priv->prompt_entry);
+ extension->priv->answer_pending = TRUE;
+}
+
+static void
+gdm_password_extension_ask_secret (GdmConversation *conversation,
+ const char *message)
+{
+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation);
+ gtk_widget_show (extension->priv->prompt_label);
+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), message);
+ gtk_entry_set_visibility (GTK_ENTRY (extension->priv->prompt_entry), FALSE);
+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), "");
+ gtk_widget_show (extension->priv->prompt_entry);
+ gtk_widget_grab_focus (extension->priv->prompt_entry);
+ extension->priv->answer_pending = TRUE;
+}
+
+static void
+gdm_password_extension_reset (GdmConversation *conversation)
+{
+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation);
+ gtk_widget_hide (extension->priv->prompt_label);
+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), "");
+
+ gtk_widget_hide (extension->priv->prompt_entry);
+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), "");
+ gtk_entry_set_visibility (GTK_ENTRY (extension->priv->prompt_entry), TRUE);
+ extension->priv->answer_pending = FALSE;
+
+ gdm_task_set_enabled (GDM_TASK (conversation), FALSE);
+}
+
+static void
+gdm_password_extension_set_ready (GdmConversation *conversation)
+{
+ gdm_task_set_enabled (GDM_TASK (conversation), TRUE);
+}
+
+char *
+gdm_password_extension_get_service_name (GdmConversation *conversation)
+{
+ return g_strdup (PAMSERVICENAME);
+}
+
+GtkWidget *
+gdm_password_extension_get_page (GdmConversation *conversation)
+{
+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation);
+ return extension->priv->page;
+}
+
+GtkActionGroup *
+gdm_password_extension_get_actions (GdmConversation *conversation)
+{
+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation);
+ return g_object_ref (extension->priv->actions);
+}
+
+void
+gdm_password_extension_request_answer (GdmConversation *conversation)
+{
+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation);
+ const char *text;
+
+ if (!extension->priv->answer_pending) {
+ gdm_conversation_answer (conversation, NULL);
+ return;
+ }
+
+ extension->priv->answer_pending = FALSE;
+ text = gtk_entry_get_text (GTK_ENTRY (extension->priv->prompt_entry));
+ gdm_conversation_answer (conversation, text);
+
+ gtk_widget_hide (extension->priv->prompt_entry);
+ gtk_widget_hide (extension->priv->prompt_label);
+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), "");
+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), "");
+}
+
+gboolean
+gdm_password_extension_focus (GdmConversation *conversation)
+{
+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation);
+ if (!extension->priv->answer_pending) {
+ gdm_conversation_answer (conversation, NULL);
+ return FALSE;
+ }
+
+ gtk_widget_grab_focus (extension->priv->prompt_entry);
+ return TRUE;
+}
+
+GIcon *
+gdm_password_extension_get_icon (GdmTask *task)
+{
+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (task);
+ return g_object_ref (extension->priv->icon);
+}
+
+char *
+gdm_password_extension_get_name (GdmTask *task)
+{
+ return g_strdup (_("Password Authentication"));
+}
+
+char *
+gdm_password_extension_get_description (GdmTask *task)
+{
+ return g_strdup (_("Log into session with username and password"));
+}
+
+gboolean
+gdm_password_extension_is_choosable (GdmTask *task)
+{
+ return FALSE;
+}
+
+gboolean
+gdm_password_extension_is_visible (GdmTask *task)
+{
+ return TRUE;
+}
+
+static void
+gdm_task_iface_init (GdmTaskIface *iface)
+{
+ iface->get_icon = gdm_password_extension_get_icon;
+ iface->get_description = gdm_password_extension_get_description;
+ iface->get_name = gdm_password_extension_get_name;
+ iface->is_choosable = gdm_password_extension_is_choosable;
+ iface->is_visible = gdm_password_extension_is_visible;
+}
+
+static void
+gdm_conversation_iface_init (GdmConversationIface *iface)
+{
+ iface->set_message = gdm_password_extension_set_message;
+ iface->ask_question = gdm_password_extension_ask_question;
+ iface->ask_secret = gdm_password_extension_ask_secret;
+ iface->reset = gdm_password_extension_reset;
+ iface->set_ready = gdm_password_extension_set_ready;
+ iface->get_service_name = gdm_password_extension_get_service_name;
+ iface->get_page = gdm_password_extension_get_page;
+ iface->get_actions = gdm_password_extension_get_actions;
+ iface->request_answer = gdm_password_extension_request_answer;
+ iface->focus = gdm_password_extension_focus;
+}
+
+static void
+gdm_greeter_extension_iface_init (GdmGreeterExtensionIface *iface)
+{
+}
+
+static void
+gdm_password_extension_class_init (GdmPasswordExtensionClass *extension_class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (extension_class);
+
+ object_class->finalize = gdm_password_extension_finalize;
+
+ g_type_class_add_private (extension_class,
+ sizeof (GdmPasswordExtensionPrivate));
+}
+
+static void
+gdm_password_extension_finalize (GObject *object)
+{
+}
+
+static void
+on_activate_log_in (GdmPasswordExtension *extension)
+{
+ gdm_password_extension_request_answer (GDM_CONVERSATION (extension));
+}
+
+static void
+create_page (GdmPasswordExtension *extension)
+{
+ GtkBuilder *builder;
+ GObject *object;
+ GError *error;
+
+ builder = gtk_builder_new ();
+
+ error = NULL;
+ gtk_builder_add_from_file (builder,
+ PLUGINDATADIR "/page.ui",
+ &error);
+
+ if (error != NULL) {
+ g_warning ("Could not load UI file: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ object = gtk_builder_get_object (builder, "page");
+ g_object_ref (object);
+
+ extension->priv->page = GTK_WIDGET (object);
+
+ object = gtk_builder_get_object (builder, "auth-prompt-label");
+ g_object_ref (object);
+ extension->priv->prompt_label = GTK_WIDGET (object);
+ gtk_widget_hide (extension->priv->prompt_label);
+
+ object = gtk_builder_get_object (builder, "auth-prompt-entry");
+ g_object_ref (object);
+ extension->priv->prompt_entry = GTK_WIDGET (object);
+ gtk_widget_hide (extension->priv->prompt_entry);
+
+ object = gtk_builder_get_object (builder, "auth-message-label");
+ g_object_ref (object);
+ extension->priv->message_label = GTK_WIDGET (object);
+ gtk_widget_show (extension->priv->message_label);
+
+ g_object_unref (builder);
+}
+
+static void
+create_actions (GdmPasswordExtension *extension)
+{
+ GtkAction *action;
+
+ extension->priv->actions = gtk_action_group_new ("gdm-password-extension");
+
+ action = gtk_action_new (GDM_CONVERSATION_DEFAULT_ACTION,
+ _("Log In"), NULL, NULL);
+ g_signal_connect_swapped (action, "activate",
+ G_CALLBACK (on_activate_log_in), extension);
+ g_object_set (G_OBJECT (action), "icon-name", "go-home", NULL);
+ gtk_action_group_add_action (extension->priv->actions,
+ action);
+}
+
+static void
+gdm_password_extension_init (GdmPasswordExtension *extension)
+{
+ extension->priv = G_TYPE_INSTANCE_GET_PRIVATE (extension,
+ GDM_TYPE_PASSWORD_EXTENSION,
+ GdmPasswordExtensionPrivate);
+
+ extension->priv->icon = g_themed_icon_new ("dialog-password");
+ create_page (extension);
+ create_actions (extension);
+
+ gdm_password_extension_reset (GDM_CONVERSATION (extension));
+}
diff --git a/gui/simple-greeter/plugins/password/gdm-password-extension.h b/gui/simple-greeter/plugins/password/gdm-password-extension.h
new file mode 100644
index 0000000..99fe17b
--- /dev/null
+++ b/gui/simple-greeter/plugins/password/gdm-password-extension.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ * Written By: Ray Strode <rstrode@redhat.com>
+ */
+
+#ifndef __GDM_PASSWORD_EXTENSION_H
+#define __GDM_PASSWORD_EXTENSION_H
+
+#include <glib-object.h>
+#include "gdm-greeter-extension.h"
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_PASSWORD_EXTENSION (gdm_password_extension_get_type ())
+#define GDM_PASSWORD_EXTENSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDM_TYPE_PASSWORD_EXTENSION, GdmPasswordExtension))
+#define GDM_PASSWORD_EXTENSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDM_TYPE_PASSWORD_EXTENSION, GdmPasswordExtensionClass))
+#define GDM_IS_PASSWORD_EXTENSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDM_TYPE_PASSWORD_EXTENSION))
+#define GDM_IS_PASSWORD_EXTENSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDM_TYPE_PASSWORD_EXTENSION))
+#define GDM_PASSWORD_EXTENSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GDM_TYPE_PASSWORD_EXTENSION, GdmPasswordExtensionClass))
+
+typedef struct _GdmPasswordExtensionPrivate GdmPasswordExtensionPrivate;
+
+typedef struct
+{
+ GObject parent;
+ GdmPasswordExtensionPrivate *priv;
+} GdmPasswordExtension;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} GdmPasswordExtensionClass;
+
+GType gdm_password_extension_get_type (void);
+
+GdmPasswordExtension *gdm_password_extension_new (void);
+
+G_END_DECLS
+
+#endif /* GDM_PASSWORD_EXTENSION_H */
diff --git a/gui/simple-greeter/plugins/password/gdm-password.pam b/gui/simple-greeter/plugins/password/gdm-password.pam
new file mode 100644
index 0000000..bac431d
--- /dev/null
+++ b/gui/simple-greeter/plugins/password/gdm-password.pam
@@ -0,0 +1,19 @@
+# Sample PAM file for doing password authentication.
+# Distros should replace this with what makes sense for them.
+auth required pam_env.so
+auth sufficient pam_unix.so nullok try_first_pass
+auth requisite pam_succeed_if.so uid >= 500 quiet
+auth required pam_deny.so
+
+account required pam_unix.so
+account sufficient pam_localuser.so
+account sufficient pam_succeed_if.so uid < 500 quiet
+account required pam_permit.so
+
+password requisite pam_cracklib.so try_first_pass retry=3 type=
+password sufficient pam_unix.so nullok try_first_pass use_authtok
+password required pam_deny.so
+
+session optional pam_keyinit.so revoke
+session required pam_limits.so
+session required pam_unix.so
diff --git a/gui/simple-greeter/plugins/password/page.ui b/gui/simple-greeter/plugins/password/page.ui
new file mode 100644
index 0000000..8fa5c7b
--- /dev/null
+++ b/gui/simple-greeter/plugins/password/page.ui
@@ -0,0 +1,57 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.14"/>
+ <object class="GtkVBox" id="page">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkHBox" id="auth-input-box">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="auth-prompt-label">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="auth-prompt-entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="activates_default">True</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="auth-message-box">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="auth-message-label">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/gui/simple-greeter/plugins/password/plugin.c b/gui/simple-greeter/plugins/password/plugin.c
new file mode 100644
index 0000000..9b87c67
--- /dev/null
+++ b/gui/simple-greeter/plugins/password/plugin.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ * Written By: Ray Strode <rstrode@redhat.com>
+ *
+ */
+
+#include "gdm-password-extension.h"
+
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+
+GdmGreeterExtension *
+gdm_greeter_plugin_get_extension (void)
+{
+ static GObject *extension;
+
+ if (extension != NULL) {
+ g_object_ref (extension);
+ } else {
+ extension = g_object_new (GDM_TYPE_PASSWORD_EXTENSION, NULL);
+ g_object_add_weak_pointer (extension, (gpointer *) &extension);
+ }
+
+ return GDM_GREETER_EXTENSION (extension);
+}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 1fccb90..7c344c9 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -84,6 +84,7 @@ gui/simple-greeter/gdm-timer.c
gui/simple-greeter/gdm-user.c
gui/simple-greeter/gdm-user-chooser-widget.c
gui/simple-greeter/greeter-main.c
+gui/simple-greeter/plugins/password/gdm-password-extension.c
gui/user-switch-applet/applet.c
gui/user-switch-applet/gdm-entry-menu-item.c
gui/user-switch-applet/GNOME_FastUserSwitchApplet.server.in.in
--
1.7.2.1
From b5ea9d8c7671dbdcabdf76fa523d5bd339826628 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 4 Aug 2010 18:25:50 -0400
Subject: [PATCH 18/35] squash with password
---
.../plugins/password/gdm-password-extension.c | 11 ++++++++++-
1 files changed, 10 insertions(+), 1 deletions(-)
diff --git a/gui/simple-greeter/plugins/password/gdm-password-extension.c b/gui/simple-greeter/plugins/password/gdm-password-extension.c
index 255283e..11a171c 100644
--- a/gui/simple-greeter/plugins/password/gdm-password-extension.c
+++ b/gui/simple-greeter/plugins/password/gdm-password-extension.c
@@ -33,6 +33,7 @@ struct _GdmPasswordExtensionPrivate
GIcon *icon;
GtkWidget *page;
GtkActionGroup *actions;
+ GtkAction *login_action;
GtkWidget *message_label;
GtkWidget *prompt_label;
@@ -78,6 +79,8 @@ gdm_password_extension_ask_question (GdmConversation *conversation,
gtk_widget_show (extension->priv->prompt_entry);
gtk_widget_grab_focus (extension->priv->prompt_entry);
extension->priv->answer_pending = TRUE;
+
+ gtk_action_set_sensitive (extension->priv->login_action, TRUE);
}
static void
@@ -92,6 +95,8 @@ gdm_password_extension_ask_secret (GdmConversation *conversation,
gtk_widget_show (extension->priv->prompt_entry);
gtk_widget_grab_focus (extension->priv->prompt_entry);
extension->priv->answer_pending = TRUE;
+
+ gtk_action_set_sensitive (extension->priv->login_action, TRUE);
}
static void
@@ -249,9 +254,11 @@ gdm_password_extension_finalize (GObject *object)
}
static void
-on_activate_log_in (GdmPasswordExtension *extension)
+on_activate_log_in (GdmPasswordExtension *extension,
+ GtkAction *action)
{
gdm_password_extension_request_answer (GDM_CONVERSATION (extension));
+ gtk_action_set_sensitive (action, FALSE);
}
static void
@@ -311,6 +318,8 @@ create_actions (GdmPasswordExtension *extension)
g_object_set (G_OBJECT (action), "icon-name", "go-home", NULL);
gtk_action_group_add_action (extension->priv->actions,
action);
+
+ extension->priv->login_action = action;
}
static void
--
1.7.2.1
From 36baeff2c9b1b625301a342d183102f686444b90 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 6 Aug 2010 11:13:10 -0400
Subject: [PATCH 19/35] task list fix
---
gui/simple-greeter/gdm-task-list.c | 11 ++++++++---
1 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/gui/simple-greeter/gdm-task-list.c b/gui/simple-greeter/gdm-task-list.c
index a7f8c74..906938d 100644
--- a/gui/simple-greeter/gdm-task-list.c
+++ b/gui/simple-greeter/gdm-task-list.c
@@ -68,7 +68,6 @@ on_task_toggled (GdmTaskList *widget,
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) {
GList *task_node;
-
/* Sort the list such that the tasks the user clicks last end
* up first. This doesn't change the order in which the tasks
* appear in the UI, but will affect which tasks we implicitly
@@ -135,7 +134,6 @@ activate_first_available_task (GdmTaskList *task_list)
node = node->next;
}
-
}
static void
@@ -218,8 +216,15 @@ gdm_task_list_remove_task (GdmTaskList *task_list,
GdmTask *task)
{
GtkWidget *button;
+ GList *node;
+
+ node = g_list_find (task_list->priv->tasks, task);
+
+ if (node == NULL) {
+ return;
+ }
- task_list->priv->tasks = g_list_remove (task_list->priv->tasks, task);
+ task_list->priv->tasks = g_list_delete_link (task_list->priv->tasks, node);
button = g_object_get_data (G_OBJECT (task), "gdm-task-list-button");
--
1.7.2.1
From 9b7b6cb2950c1ed71d0091d96027c4d2eb40e966 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 29 Jun 2010 14:13:35 -0400
Subject: [PATCH 20/35] Show cancel button after first message
Not all PAM modules ask for input at the keyboard. We need
to show the cancel button after the first message even if
that message isn't asking for input.
---
gui/simple-greeter/gdm-greeter-login-window.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
index 36a6d21..5845c7b 100644
--- a/gui/simple-greeter/gdm-greeter-login-window.c
+++ b/gui/simple-greeter/gdm-greeter-login-window.c
@@ -827,6 +827,7 @@ reset_dialog (GdmGreeterLoginWindow *login_window,
switch_mode (login_window, dialog_mode);
}
+ gtk_widget_set_sensitive (login_window->priv->conversation_list, TRUE);
set_sensitive (login_window, TRUE);
set_ready (login_window);
set_focus (GDM_GREETER_LOGIN_WINDOW (login_window));
@@ -977,6 +978,7 @@ gdm_greeter_login_window_info (GdmGreeterLoginWindow *login_window,
g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
g_debug ("GdmGreeterLoginWindow: info: %s", text);
+ maybe_show_cancel_button (login_window);
task = find_task_with_service_name (login_window, service_name);
if (task != NULL) {
@@ -999,6 +1001,7 @@ gdm_greeter_login_window_problem (GdmGreeterLoginWindow *login_window,
g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
g_debug ("GdmGreeterLoginWindow: problem: %s", text);
+ maybe_show_cancel_button (login_window);
task = find_task_with_service_name (login_window, service_name);
if (task != NULL) {
--
1.7.2.1
From ceece80bd67dd943d1888b8b6cd0a14d0afe188b Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 28 Oct 2009 11:13:10 -0400
Subject: [PATCH 21/35] Prevent start session signal handler from getting called multiple times
It was causing a double free.
---
gui/simple-greeter/gdm-greeter-login-window.c | 9 +++++++++
1 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
index 5845c7b..d0c0781 100644
--- a/gui/simple-greeter/gdm-greeter-login-window.c
+++ b/gui/simple-greeter/gdm-greeter-login-window.c
@@ -1086,8 +1086,17 @@ on_ready_to_start_session (GdmGreeterLoginWindow *login_window,
GParamSpec *param_spec,
char *service_name)
{
+ if (!login_window->priv->is_interactive) {
+ return;
+ }
+
gdm_greeter_login_window_start_session_when_ready (login_window, service_name);
g_free (service_name);
+
+ if (login_window->priv->start_session_handler_id > 0) {
+ g_signal_handler_disconnect (login_window, login_window->priv->start_session_handler_id);
+ login_window->priv->start_session_handler_id = 0;
+ }
}
static void
--
1.7.2.1
From ff1cf4ba57e24b40ef74eaffb14bf842b1cd96a4 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 6 Feb 2009 16:25:47 -0500
Subject: [PATCH 22/35] Add fingerprint plugin
This commit adds a plugin to initiate a conversation for
fingerprint scans.
---
configure.ac | 4 +
gui/simple-greeter/plugins/Makefile.am | 2 +-
gui/simple-greeter/plugins/fingerprint/Makefile.am | 56 ++++
.../fingerprint/gdm-fingerprint-extension.c | 347 ++++++++++++++++++++
.../fingerprint/gdm-fingerprint-extension.h | 56 ++++
.../plugins/fingerprint/gdm-fingerprint.pam | 17 +
.../plugins/fingerprint/icons/16x16/Makefile.am | 5 +
.../fingerprint/icons/16x16/gdm-fingerprint.png | Bin 0 -> 461 bytes
.../plugins/fingerprint/icons/48x48/Makefile.am | 5 +
.../fingerprint/icons/48x48/gdm-fingerprint.png | Bin 0 -> 1638 bytes
.../plugins/fingerprint/icons/Makefile.am | 1 +
gui/simple-greeter/plugins/fingerprint/page.ui | 57 ++++
gui/simple-greeter/plugins/fingerprint/plugin.c | 40 +++
po/POTFILES.in | 1 +
14 files changed, 590 insertions(+), 1 deletions(-)
create mode 100644 gui/simple-greeter/plugins/fingerprint/Makefile.am
create mode 100644 gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
create mode 100644 gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.h
create mode 100644 gui/simple-greeter/plugins/fingerprint/gdm-fingerprint.pam
create mode 100644 gui/simple-greeter/plugins/fingerprint/icons/16x16/Makefile.am
create mode 100644 gui/simple-greeter/plugins/fingerprint/icons/16x16/gdm-fingerprint.png
create mode 100644 gui/simple-greeter/plugins/fingerprint/icons/48x48/Makefile.am
create mode 100644 gui/simple-greeter/plugins/fingerprint/icons/48x48/gdm-fingerprint.png
create mode 100644 gui/simple-greeter/plugins/fingerprint/icons/Makefile.am
create mode 100644 gui/simple-greeter/plugins/fingerprint/page.ui
create mode 100644 gui/simple-greeter/plugins/fingerprint/plugin.c
diff --git a/configure.ac b/configure.ac
index ab35800..af7c2f3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1445,6 +1445,10 @@ gui/simple-greeter/libgdmsimplegreeter/Makefile
gui/simple-greeter/libgdmsimplegreeter/gdmsimplegreeter.pc
gui/simple-greeter/plugins/Makefile
gui/simple-greeter/plugins/password/Makefile
+gui/simple-greeter/plugins/fingerprint/Makefile
+gui/simple-greeter/plugins/fingerprint/icons/Makefile
+gui/simple-greeter/plugins/fingerprint/icons/16x16/Makefile
+gui/simple-greeter/plugins/fingerprint/icons/48x48/Makefile
gui/simple-chooser/Makefile
gui/user-switch-applet/Makefile
utils/Makefile
diff --git a/gui/simple-greeter/plugins/Makefile.am b/gui/simple-greeter/plugins/Makefile.am
index c0390db..9811a68 100644
--- a/gui/simple-greeter/plugins/Makefile.am
+++ b/gui/simple-greeter/plugins/Makefile.am
@@ -1 +1 @@
-SUBDIRS = password
+SUBDIRS = password fingerprint
diff --git a/gui/simple-greeter/plugins/fingerprint/Makefile.am b/gui/simple-greeter/plugins/fingerprint/Makefile.am
new file mode 100644
index 0000000..25fb6e8
--- /dev/null
+++ b/gui/simple-greeter/plugins/fingerprint/Makefile.am
@@ -0,0 +1,56 @@
+SUBDIRS = icons
+
+NULL =
+PAM_SERVICE_NAME = gdm-fingerprint
+
+extensiondir = $(extensionsdatadir)/fingerprint
+extension_DATA = page.ui
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/common \
+ -I$(top_srcdir)/gui/simple-greeter/libnotificationarea \
+ -I$(top_srcdir)/gui/simple-greeter/libgdmsimplegreeter \
+ -DDMCONFDIR=\""$(dmconfdir)"\" \
+ -DGDMCONFDIR=\"$(gdmconfdir)\" \
+ -DPLUGINDATADIR=\""$(extensiondir)"\" \
+ -DPAMSERVICENAME=\""$(PAM_SERVICE_NAME)"\" \
+ -DSYSCONFDIR=\""$(sysconfdir)"\" \
+ -DLIBLOCALEDIR=\""$(prefix)/lib/locale"\" \
+ -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
+ -DLIBEXECDIR=\""$(libexecdir)"\" \
+ -DSBINDIR=\""$(sbindir)"\" \
+ $(DISABLE_DEPRECATED_CFLAGS) \
+ $(GTK_CFLAGS) \
+ $(SIMPLE_GREETER_CFLAGS) \
+ $(POLKIT_GNOME_CFLAGS) \
+ $(NULL)
+
+
+plugindir = $(GDM_SIMPLE_GREETER_PLUGINS_DIR)
+plugin_LTLIBRARIES = fingerprint.la
+
+fingerprint_la_CFLAGS = \
+ $(SIMPLE_GREETER_CFLAGS) \
+ $(NULL)
+
+fingerprint_la_LDFLAGS = -module -avoid-version -export-dynamic
+fingerprint_la_LIBADD = ../../../../common/libgdmcommon.la \
+ ../../libgdmsimplegreeter/libgdmsimplegreeter.la
+fingerprint_la_SOURCES = \
+ gdm-fingerprint-extension.h \
+ gdm-fingerprint-extension.c \
+ plugin.c
+
+$(PAM_SERVICE_NAME): $(PAM_SERVICE_NAME).pam
+ cp $(PAM_SERVICE_NAME).pam $(PAM_SERVICE_NAME)
+
+pamdir = $(PAM_PREFIX)/pam.d
+pam_DATA = $(PAM_SERVICE_NAME)
+
+EXTRA_DIST = $(extension_DATA) $(PAM_SERVICE_NAME).pam
+CLEANFILES = $(PAM_SERVICE_NAME)
+
+MAINTAINERCLEANFILES = \
+ *~ \
+ $(PAM_SERVICE_NAME) \
+ Makefile.in
diff --git a/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
new file mode 100644
index 0000000..55f5d32
--- /dev/null
+++ b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ * Written By: Ray Strode <rstrode@redhat.com>
+ *
+ */
+
+#include <config.h>
+#include <stdlib.h>
+
+#include "gdm-fingerprint-extension.h"
+#include "gdm-conversation.h"
+#include "gdm-task.h"
+
+#include <glib/gi18n-lib.h>
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+
+struct _GdmFingerprintExtensionPrivate
+{
+ GIcon *icon;
+ GtkWidget *page;
+ GtkActionGroup *actions;
+
+ GtkWidget *message_label;
+ GtkWidget *prompt_label;
+ GtkWidget *prompt_entry;
+
+ guint answer_pending : 1;
+};
+
+static void gdm_fingerprint_extension_finalize (GObject *object);
+
+static void gdm_task_iface_init (GdmTaskIface *iface);
+static void gdm_conversation_iface_init (GdmConversationIface *iface);
+static void gdm_greeter_extension_iface_init (GdmGreeterExtensionIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GdmFingerprintExtension,
+ gdm_fingerprint_extension,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GDM_TYPE_GREETER_EXTENSION,
+ gdm_greeter_extension_iface_init)
+ G_IMPLEMENT_INTERFACE (GDM_TYPE_TASK,
+ gdm_task_iface_init)
+ G_IMPLEMENT_INTERFACE (GDM_TYPE_CONVERSATION,
+ gdm_conversation_iface_init));
+
+static void
+gdm_fingerprint_extension_set_message (GdmConversation *conversation,
+ const char *message)
+{
+ GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (conversation);
+ gtk_widget_show (extension->priv->message_label);
+ gtk_label_set_text (GTK_LABEL (extension->priv->message_label), message);
+}
+
+static void
+gdm_fingerprint_extension_ask_question (GdmConversation *conversation,
+ const char *message)
+{
+ GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (conversation);
+ gtk_widget_show (extension->priv->prompt_label);
+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), message);
+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), "");
+ gtk_entry_set_visibility (GTK_ENTRY (extension->priv->prompt_entry), TRUE);
+ gtk_widget_show (extension->priv->prompt_entry);
+ gtk_widget_grab_focus (extension->priv->prompt_entry);
+ extension->priv->answer_pending = TRUE;
+}
+
+static void
+gdm_fingerprint_extension_ask_secret (GdmConversation *conversation,
+ const char *message)
+{
+ GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (conversation);
+ gtk_widget_show (extension->priv->prompt_label);
+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), message);
+ gtk_entry_set_visibility (GTK_ENTRY (extension->priv->prompt_entry), FALSE);
+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), "");
+ gtk_widget_show (extension->priv->prompt_entry);
+ gtk_widget_grab_focus (extension->priv->prompt_entry);
+ extension->priv->answer_pending = TRUE;
+}
+
+static void
+gdm_fingerprint_extension_reset (GdmConversation *conversation)
+{
+ GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (conversation);
+ gtk_widget_hide (extension->priv->prompt_label);
+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), "");
+
+ gtk_widget_hide (extension->priv->prompt_entry);
+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), "");
+ gtk_entry_set_visibility (GTK_ENTRY (extension->priv->prompt_entry), TRUE);
+ extension->priv->answer_pending = FALSE;
+
+ gdm_task_set_enabled (GDM_TASK (conversation), FALSE);
+}
+
+static void
+gdm_fingerprint_extension_set_ready (GdmConversation *conversation)
+{
+ gdm_task_set_enabled (GDM_TASK (conversation), TRUE);
+}
+
+char *
+gdm_fingerprint_extension_get_service_name (GdmConversation *conversation)
+{
+ return g_strdup (PAMSERVICENAME);
+}
+
+GtkWidget *
+gdm_fingerprint_extension_get_page (GdmConversation *conversation)
+{
+ GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (conversation);
+ return extension->priv->page;
+}
+
+GtkActionGroup *
+gdm_fingerprint_extension_get_actions (GdmConversation *conversation)
+{
+ GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (conversation);
+
+ return g_object_ref (extension->priv->actions);
+}
+
+void
+gdm_fingerprint_extension_request_answer (GdmConversation *conversation)
+{
+ GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (conversation);
+ const char *text;
+
+ if (!extension->priv->answer_pending) {
+ gdm_conversation_answer (conversation, NULL);
+ return;
+ }
+
+ extension->priv->answer_pending = FALSE;
+ text = gtk_entry_get_text (GTK_ENTRY (extension->priv->prompt_entry));
+ gdm_conversation_answer (conversation, text);
+
+ gtk_widget_hide (extension->priv->prompt_entry);
+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), "");
+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), "");
+}
+
+gboolean
+gdm_fingerprint_extension_focus (GdmConversation *conversation)
+{
+ GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (conversation);
+
+ if (!extension->priv->answer_pending) {
+ return FALSE;
+ }
+
+ gtk_widget_grab_focus (extension->priv->prompt_entry);
+ return TRUE;
+}
+
+GIcon *
+gdm_fingerprint_extension_get_icon (GdmTask *task)
+{
+ GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (task);
+ return g_object_ref (extension->priv->icon);
+}
+
+char *
+gdm_fingerprint_extension_get_name (GdmTask *task)
+{
+ return g_strdup (_("Fingerprint Authentication"));
+}
+
+char *
+gdm_fingerprint_extension_get_description (GdmTask *task)
+{
+ return g_strdup (_("Log into session with fingerprint"));
+}
+
+gboolean
+gdm_fingerprint_extension_is_choosable (GdmTask *task)
+{
+ return FALSE;
+}
+
+gboolean
+gdm_fingerprint_extension_is_visible (GdmTask *task)
+{
+ char *contents, **lines;
+ gboolean ret;
+ guint i;
+
+ /* Stolen from gnome-about-me.
+ *
+ * FIXME: We should fix pam_fprintd to return authinfo_unavail instead of
+ * doing this distro specific hack.
+ */
+
+ if (g_file_get_contents ("/etc/sysconfig/authconfig",
+ &contents, NULL, NULL) == FALSE) {
+ return FALSE;
+ }
+
+ lines = g_strsplit (contents, "\n", -1);
+ g_free (contents);
+
+ ret = FALSE;
+
+ for (i = 0; lines[i] ; i++) {
+ if (g_str_has_prefix (lines[i], "USEFPRINTD=") != FALSE) {
+ char *value;
+
+ value = lines[i] + strlen ("USEFPRINTD=");
+ if (rpmatch (value)) {
+ ret = TRUE;
+ break;
+ }
+ }
+ }
+
+ g_strfreev (lines);
+
+ return ret;
+}
+
+static void
+gdm_task_iface_init (GdmTaskIface *iface)
+{
+ iface->get_icon = gdm_fingerprint_extension_get_icon;
+ iface->get_description = gdm_fingerprint_extension_get_description;
+ iface->get_name = gdm_fingerprint_extension_get_name;
+ iface->is_choosable = gdm_fingerprint_extension_is_choosable;
+ iface->is_visible = gdm_fingerprint_extension_is_visible;
+}
+
+static void
+gdm_conversation_iface_init (GdmConversationIface *iface)
+{
+ iface->set_message = gdm_fingerprint_extension_set_message;
+ iface->ask_question = gdm_fingerprint_extension_ask_question;
+ iface->ask_secret = gdm_fingerprint_extension_ask_secret;
+ iface->reset = gdm_fingerprint_extension_reset;
+ iface->set_ready = gdm_fingerprint_extension_set_ready;
+ iface->get_service_name = gdm_fingerprint_extension_get_service_name;
+ iface->get_page = gdm_fingerprint_extension_get_page;
+ iface->get_actions = gdm_fingerprint_extension_get_actions;
+ iface->request_answer = gdm_fingerprint_extension_request_answer;
+ iface->focus = gdm_fingerprint_extension_focus;
+}
+
+static void
+gdm_greeter_extension_iface_init (GdmGreeterExtensionIface *iface)
+{
+}
+
+static void
+gdm_fingerprint_extension_class_init (GdmFingerprintExtensionClass *extension_class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (extension_class);
+
+ object_class->finalize = gdm_fingerprint_extension_finalize;
+
+ g_type_class_add_private (extension_class,
+ sizeof (GdmFingerprintExtensionPrivate));
+}
+
+static void
+gdm_fingerprint_extension_finalize (GObject *object)
+{
+}
+
+static void
+create_page (GdmFingerprintExtension *extension)
+{
+ GtkBuilder *builder;
+ GObject *object;
+ GError *error;
+
+ builder = gtk_builder_new ();
+
+ error = NULL;
+ gtk_builder_add_from_file (builder,
+ PLUGINDATADIR "/page.ui",
+ &error);
+
+ if (error != NULL) {
+ g_warning ("Could not load UI file: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ object = gtk_builder_get_object (builder, "page");
+ g_object_ref (object);
+
+ extension->priv->page = GTK_WIDGET (object);
+
+ object = gtk_builder_get_object (builder, "auth-prompt-label");
+ g_object_ref (object);
+ extension->priv->prompt_label = GTK_WIDGET (object);
+ gtk_widget_hide (extension->priv->prompt_label);
+
+ object = gtk_builder_get_object (builder, "auth-prompt-entry");
+ g_object_ref (object);
+ extension->priv->prompt_entry = GTK_WIDGET (object);
+ gtk_widget_hide (extension->priv->prompt_entry);
+
+ object = gtk_builder_get_object (builder, "auth-message-label");
+ g_object_ref (object);
+ extension->priv->message_label = GTK_WIDGET (object);
+ gtk_widget_show (extension->priv->message_label);
+
+ g_object_unref (builder);
+}
+
+static void
+create_actions (GdmFingerprintExtension *extension)
+{
+ extension->priv->actions = gtk_action_group_new ("gdm-fingerprint-extension");
+}
+
+static void
+gdm_fingerprint_extension_init (GdmFingerprintExtension *extension)
+{
+ extension->priv = G_TYPE_INSTANCE_GET_PRIVATE (extension,
+ GDM_TYPE_FINGERPRINT_EXTENSION,
+ GdmFingerprintExtensionPrivate);
+
+ extension->priv->icon = g_themed_icon_new ("gdm-fingerprint");
+ create_page (extension);
+ create_actions (extension);
+ gdm_fingerprint_extension_reset (GDM_CONVERSATION (extension));
+}
diff --git a/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.h b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.h
new file mode 100644
index 0000000..5d34b21
--- /dev/null
+++ b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ * Written By: Ray Strode <rstrode@redhat.com>
+ */
+
+#ifndef __GDM_FINGERPRINT_EXTENSION_H
+#define __GDM_FINGERPRINT_EXTENSION_H
+
+#include <glib-object.h>
+#include "gdm-greeter-extension.h"
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_FINGERPRINT_EXTENSION (gdm_fingerprint_extension_get_type ())
+#define GDM_FINGERPRINT_EXTENSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDM_TYPE_FINGERPRINT_EXTENSION, GdmFingerprintExtension))
+#define GDM_FINGERPRINT_EXTENSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDM_TYPE_FINGERPRINT_EXTENSION, GdmFingerprintExtensionClass))
+#define GDM_IS_FINGERPRINT_EXTENSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDM_TYPE_FINGERPRINT_EXTENSION))
+#define GDM_IS_FINGERPRINT_EXTENSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDM_TYPE_FINGERPRINT_EXTENSION))
+#define GDM_FINGERPRINT_EXTENSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GDM_TYPE_FINGERPRINT_EXTENSION, GdmFingerprintExtensionClass))
+
+typedef struct _GdmFingerprintExtensionPrivate GdmFingerprintExtensionPrivate;
+
+typedef struct
+{
+ GObject parent;
+ GdmFingerprintExtensionPrivate *priv;
+} GdmFingerprintExtension;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} GdmFingerprintExtensionClass;
+
+GType gdm_fingerprint_extension_get_type (void);
+
+GdmFingerprintExtension *gdm_fingerprint_extension_new (void);
+
+G_END_DECLS
+
+#endif /* GDM_FINGERPRINT_EXTENSION_H */
diff --git a/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint.pam b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint.pam
new file mode 100644
index 0000000..1a1c777
--- /dev/null
+++ b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint.pam
@@ -0,0 +1,17 @@
+# Sample PAM file for doing fingerprint authentication.
+# Distros should replace this with what makes sense for them.
+auth required pam_env.so
+auth required pam_fprintd.so
+auth sufficient pam_succeed_if.so uid >= 500 quiet
+auth required pam_deny.so
+
+account required pam_unix.so
+account sufficient pam_localuser.so
+account sufficient pam_succeed_if.so uid < 500 quiet
+account required pam_permit.so
+
+password required pam_deny.so
+
+session optional pam_keyinit.so revoke
+session required pam_limits.so
+session required pam_unix.so
diff --git a/gui/simple-greeter/plugins/fingerprint/icons/16x16/Makefile.am b/gui/simple-greeter/plugins/fingerprint/icons/16x16/Makefile.am
new file mode 100644
index 0000000..f42e317
--- /dev/null
+++ b/gui/simple-greeter/plugins/fingerprint/icons/16x16/Makefile.am
@@ -0,0 +1,5 @@
+iconsdir = $(datadir)/icons/hicolor/16x16/apps
+
+icons_DATA = gdm-fingerprint.png
+
+EXTRA_DIST = $(icons_DATA)
diff --git a/gui/simple-greeter/plugins/fingerprint/icons/16x16/gdm-fingerprint.png b/gui/simple-greeter/plugins/fingerprint/icons/16x16/gdm-fingerprint.png
new file mode 100644
index 0000000000000000000000000000000000000000..4438cee2895638422dd470b05214dfae07751c3c
GIT binary patch
literal 461
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6U4S$Y
z{B+)352QE?JR*x382FBWFymBhK53vJdx@v7EBj3rUJ*vkeVx{~fu{I+x;TbdoNm3m
z(R*5;$nlToe`n0t<L8)Z;i2FZ7%MKWxX6s%Tz2WglLtN5)GttNa+@x-TG69$)3gqb
zEI}KNMIsUwSCm-29zOWJ<<29;+M08pc0ZqY`un`%cRNiYyjJQjH3<{f_q!z%nLT~F
ze7sJ(w`$r)t;1@;Ugpw_N1ty#XJdWdk@0zfV*4}0s~j4?`?mB&b-j(tSggMEO6%*X
zm)I7D27lMxb5zEyP<;A^X7-9MeF=@Ms?WBsr_O0S^|pFPv-6)7%zsW*iT<s$omVPu
zTp=$w_uZUNrZxu;cSIa}U-QF_wMzfBMBB!Q+(+R&4^zEfmaztG-T!yj{I6&29bDcd
zGv2M3CtW`4t=o}j|Ihzmik3K##r)v$M$3*4KDpHGcNrqqOD|EC$=K$v&ZP86T}?_s
zx+2{Al;B6k%P+1lh$%0!`Ks@7B)euc<C>7U_A+O~xmQ|0`3{N*Pgg&ebxsLQ0N@R|
ASO5S3
literal 0
HcmV?d00001
diff --git a/gui/simple-greeter/plugins/fingerprint/icons/48x48/Makefile.am b/gui/simple-greeter/plugins/fingerprint/icons/48x48/Makefile.am
new file mode 100644
index 0000000..f4ab2a0
--- /dev/null
+++ b/gui/simple-greeter/plugins/fingerprint/icons/48x48/Makefile.am
@@ -0,0 +1,5 @@
+iconsdir = $(datadir)/icons/hicolor/48x48/apps
+
+icons_DATA = gdm-fingerprint.png
+
+EXTRA_DIST = $(icons_DATA)
diff --git a/gui/simple-greeter/plugins/fingerprint/icons/48x48/gdm-fingerprint.png b/gui/simple-greeter/plugins/fingerprint/icons/48x48/gdm-fingerprint.png
new file mode 100644
index 0000000000000000000000000000000000000000..fd6f546c387db5dbce1a88cb4bb46c3bdaa7f4a5
GIT binary patch
literal 1638
zcmV-s2ATPZP)<h;3K|Lk000e1NJLTq001xm001xu1^@s6R|5Hm00001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01m_e01m_fl`9S#00007bV*G`2iXJ-
z6EzRg;agMy00rhrL_t(&-sPBGY!p=#$N%T<w!7Qy?otbuQouq>Dp+=0hNP*1SPbzi
z_#h8rz!1>~h>0&gm>3fi(P#*P#E(e);7KL17{vI2V$cRcYAxICZVOdtv6z0hl(w|p
zkIu~T!6|O1Q__!_#l-Wnv*+A%@A=(x?%aEaumF+2LW#)s>?en#7^-%IICZFQoAOI~
zo8sbPcOVeh$;|PrtgJ7?;qU}36z6;$H~iq<<MS8nUtP3uxi32pNi~jZ{jmo&o^GqY
z@bLJ)$##Cf{}6x|hzN?J1OdEaC4gf-PN8p{m3J*I{;+&SRnhRVBzjH^B0py_iq@|3
zsBTg2-PR|%KU2;EKtVyl5h4ocu0_4Qz3&*h6QNKjSXfx-?&;|no@*>(J^;e)KCp6W
zuuwE-q2*XBI_kP`{*8Kg`vO?zFL7t*`gd1+4}Vovm6M2;rMa#uD=YJ*_a#ZvK~2*d
zHBGy`e*Jpcc7RYdmbkqB)jkmb_x|gysT#UY_rfn0VNw3_)k$`2zj^bf*I1^xxw(0h
z&y|&x9sqmwzu69l<7wLg$bk}9jxXOuE>Lo+duOBvE^@)+&J*Mi6=wdaR4Qlkd2DQK
zBLMH@e`a23JAekL%&amP-u#>?ww^1!&?Yo6YtR@eP1CZcEjoweRtX6q?lsPj?En)h
zT9Ttf0||};0iI%0k_!4-`!P0tJtb7_41gSyE*7QD_*#Q)&~|`}Phm8f7;PR>ZXoH4
zPqTMj?8Wdv$M2$3J*6m$e_94LEszFKW-#B#$XiI67~j|a*M%!X?(5TReHXiv6UouH
z!h116MBZrw3URBfh{%`$#n?U=3_c-A(u)-p6@JSAVvnOEInuZ5Qs+-CMq47LbT>Sb
z`a=IZt%R7_1puX`r7i&X7|dga;2$NTuK~Q9NF)wg1^@u{k4@COy0345gQwIHk2v!u
z7o!luV*=m?0H4oSVjQ2Dr)*?I^itZwF0m8<0BZIi0hO*A)IM33SLn}yX|G`-2LPz5
zT4G}By|v$jLdyU=lm<6yIe;$BMun=X<@%sLllHlKu%#y1=}PNkXZlfxh#G7GVCEJR
z^?mxFi%r^30<1By^`!;;tRXwKwg3nr`b`2^r~l^7R6?4jtuwmC<MB>?@ot!$1YP1o
zLqq56%D{k$dW{}z&WuMAA|pUwYiny#pOoE(wl(eT?Fm}|h{$a7DZQOfd3kvWfF%ZX
z8vs;QRXLg2c&MwfbR#n?ShMZFK$4^<nYq%u>clp)?F9e^2M4zTC@@UY&$GUf1%tu6
z0entGGJtDD^g&}|<0k-khCWg==uga`f0>9>6Mdr|>@x=aKxt`dBoc|tE(1b{twgjH
zKpuemnfW70lFrDo9I*2y$jsfcEEfXUZkYX($B!RZXI(<fe8J>QvPD(ZGqNn_z$Otw
zyrw8hH2{yHL_eL=VJ;etUIuX31WZ;G<vqIqm{|s}$)LW{)YNot&Zp75yu4QdoHsE&
zCrQ#CWJs8~`ZjBCW`LTS8b#Bz-2lwqz3<DiyfQ-!-_H9!(A3m)m6^@zFGo?718Iw_
z*skcava(_ez0kZ3!0b!fj!-D{p#Hqsruh5A;qdr^0AjJ&p8$@UZNQqQeJn{*h=}&u
zRR053T`Aw3VJ)ly&;Y=12LKU`SOO4@Mmqr<LFT2)vP(TPAO7c)P)6ks%K&1rSO<W!
znT(#9Yc2h(!pt=pjDN!8@zhufKt!i92=HrNUEPSK0MTglx7nuE0{PCCFLO?(^LYTn
zHV2<@I-N&t0cdDwXaTUp_yx`4_kVRb93HR*Krf{qiD(Oe9vk9Ui0Hta?h*4DrLnQG
zURBji0NO1EI2wsWF4+zM0L{(KZOpuxh}tX)e%$GFzCP!h+(Jf-#bO<rrtJctTCj1Q
z42Q$r83oWG>MYu&znRxv+M;bgYC$)3cML!XF|g1+yk2k5oy@>O*FdVawl;pp004|G
k&_6!!?EgnH@c)&+0Y61Y+XKhC^Z)<=07*qoM6N<$f~|xG1poj5
literal 0
HcmV?d00001
diff --git a/gui/simple-greeter/plugins/fingerprint/icons/Makefile.am b/gui/simple-greeter/plugins/fingerprint/icons/Makefile.am
new file mode 100644
index 0000000..c20f10d
--- /dev/null
+++ b/gui/simple-greeter/plugins/fingerprint/icons/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = 16x16 48x48
diff --git a/gui/simple-greeter/plugins/fingerprint/page.ui b/gui/simple-greeter/plugins/fingerprint/page.ui
new file mode 100644
index 0000000..8fa5c7b
--- /dev/null
+++ b/gui/simple-greeter/plugins/fingerprint/page.ui
@@ -0,0 +1,57 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.14"/>
+ <object class="GtkVBox" id="page">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkHBox" id="auth-input-box">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="auth-prompt-label">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="auth-prompt-entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="activates_default">True</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="auth-message-box">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="auth-message-label">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/gui/simple-greeter/plugins/fingerprint/plugin.c b/gui/simple-greeter/plugins/fingerprint/plugin.c
new file mode 100644
index 0000000..5ea9925
--- /dev/null
+++ b/gui/simple-greeter/plugins/fingerprint/plugin.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ * Written By: Ray Strode <rstrode@redhat.com>
+ *
+ */
+
+#include "gdm-fingerprint-extension.h"
+
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+
+GdmGreeterExtension *
+gdm_greeter_plugin_get_extension (void)
+{
+ static GObject *extension;
+
+ if (extension != NULL) {
+ g_object_ref (extension);
+ } else {
+ extension = g_object_new (GDM_TYPE_FINGERPRINT_EXTENSION, NULL);
+ g_object_add_weak_pointer (extension, (gpointer *) &extension);
+ }
+
+ return GDM_GREETER_EXTENSION (extension);
+}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 7c344c9..dd08b21 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -85,6 +85,7 @@ gui/simple-greeter/gdm-user.c
gui/simple-greeter/gdm-user-chooser-widget.c
gui/simple-greeter/greeter-main.c
gui/simple-greeter/plugins/password/gdm-password-extension.c
+gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
gui/user-switch-applet/applet.c
gui/user-switch-applet/gdm-entry-menu-item.c
gui/user-switch-applet/GNOME_FastUserSwitchApplet.server.in.in
--
1.7.2.1
From b186d5b4703e6c193e404925e2257d78261b6ba3 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 6 Feb 2009 16:25:47 -0500
Subject: [PATCH 23/35] Add smartcard plugin
This commit adds a plugin to initiate a conversation when
smartcards are inserted.
---
configure.ac | 11 +
gui/simple-greeter/plugins/Makefile.am | 2 +-
gui/simple-greeter/plugins/smartcard/Makefile.am | 77 +
.../plugins/smartcard/gdm-smartcard-extension.c | 510 +++++++
.../plugins/smartcard/gdm-smartcard-extension.h | 56 +
.../plugins/smartcard/gdm-smartcard-manager.c | 1521 ++++++++++++++++++++
.../plugins/smartcard/gdm-smartcard-manager.h | 86 ++
.../plugins/smartcard/gdm-smartcard-worker.c | 186 +++
.../plugins/smartcard/gdm-smartcard.c | 554 +++++++
.../plugins/smartcard/gdm-smartcard.h | 94 ++
.../plugins/smartcard/gdm-smartcard.pam | 18 +
.../plugins/smartcard/icons/16x16/Makefile.am | 5 +
.../smartcard/icons/16x16/gdm-smartcard.png | Bin 0 -> 871 bytes
.../plugins/smartcard/icons/48x48/Makefile.am | 5 +
.../smartcard/icons/48x48/gdm-smartcard.png | Bin 0 -> 4202 bytes
.../plugins/smartcard/icons/Makefile.am | 1 +
gui/simple-greeter/plugins/smartcard/page.ui | 57 +
gui/simple-greeter/plugins/smartcard/plugin.c | 40 +
po/POTFILES.in | 3 +
19 files changed, 3225 insertions(+), 1 deletions(-)
create mode 100644 gui/simple-greeter/plugins/smartcard/Makefile.am
create mode 100644 gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
create mode 100644 gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.h
create mode 100644 gui/simple-greeter/plugins/smartcard/gdm-smartcard-manager.c
create mode 100644 gui/simple-greeter/plugins/smartcard/gdm-smartcard-manager.h
create mode 100644 gui/simple-greeter/plugins/smartcard/gdm-smartcard-worker.c
create mode 100644 gui/simple-greeter/plugins/smartcard/gdm-smartcard.c
create mode 100644 gui/simple-greeter/plugins/smartcard/gdm-smartcard.h
create mode 100644 gui/simple-greeter/plugins/smartcard/gdm-smartcard.pam
create mode 100644 gui/simple-greeter/plugins/smartcard/icons/16x16/Makefile.am
create mode 100644 gui/simple-greeter/plugins/smartcard/icons/16x16/gdm-smartcard.png
create mode 100644 gui/simple-greeter/plugins/smartcard/icons/48x48/Makefile.am
create mode 100644 gui/simple-greeter/plugins/smartcard/icons/48x48/gdm-smartcard.png
create mode 100644 gui/simple-greeter/plugins/smartcard/icons/Makefile.am
create mode 100644 gui/simple-greeter/plugins/smartcard/page.ui
create mode 100644 gui/simple-greeter/plugins/smartcard/plugin.c
diff --git a/configure.ac b/configure.ac
index af7c2f3..abec739 100644
--- a/configure.ac
+++ b/configure.ac
@@ -67,6 +67,7 @@ LIBCANBERRA_GTK_REQUIRED_VERSION=0.4
#FONTCONFIG_REQUIRED_VERSION=2.6.0
FONTCONFIG_REQUIRED_VERSION=2.5.0
UPOWER_REQUIRED_VERSION=0.9.0
+NSS_REQUIRED_VERSION=3.11.1
EXTRA_COMPILE_WARNINGS(yes)
@@ -90,6 +91,12 @@ PKG_CHECK_MODULES(DAEMON,
AC_SUBST(DAEMON_CFLAGS)
AC_SUBST(DAEMON_LIBS)
+PKG_CHECK_MODULES(NSS,
+ nss >= $NSS_REQUIRED_VERSION
+)
+AC_SUBST(NSS_CFLAGS)
+AC_SUBST(NSS_LIBS)
+
PKG_CHECK_MODULES(XLIB, x11 xau, ,
[AC_PATH_XTRA
if test "x$no_x" = xyes; then
@@ -1449,6 +1456,10 @@ gui/simple-greeter/plugins/fingerprint/Makefile
gui/simple-greeter/plugins/fingerprint/icons/Makefile
gui/simple-greeter/plugins/fingerprint/icons/16x16/Makefile
gui/simple-greeter/plugins/fingerprint/icons/48x48/Makefile
+gui/simple-greeter/plugins/smartcard/Makefile
+gui/simple-greeter/plugins/smartcard/icons/Makefile
+gui/simple-greeter/plugins/smartcard/icons/16x16/Makefile
+gui/simple-greeter/plugins/smartcard/icons/48x48/Makefile
gui/simple-chooser/Makefile
gui/user-switch-applet/Makefile
utils/Makefile
diff --git a/gui/simple-greeter/plugins/Makefile.am b/gui/simple-greeter/plugins/Makefile.am
index 9811a68..3dd336f 100644
--- a/gui/simple-greeter/plugins/Makefile.am
+++ b/gui/simple-greeter/plugins/Makefile.am
@@ -1 +1 @@
-SUBDIRS = password fingerprint
+SUBDIRS = password fingerprint smartcard
diff --git a/gui/simple-greeter/plugins/smartcard/Makefile.am b/gui/simple-greeter/plugins/smartcard/Makefile.am
new file mode 100644
index 0000000..1ccebda
--- /dev/null
+++ b/gui/simple-greeter/plugins/smartcard/Makefile.am
@@ -0,0 +1,77 @@
+SUBDIRS = icons
+
+NULL =
+PAM_SERVICE_NAME = gdm-smartcard
+
+extensiondir = $(extensionsdatadir)/smartcard
+extension_DATA = page.ui
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/common \
+ -I$(top_srcdir)/gui/simple-greeter/libnotificationarea \
+ -I$(top_srcdir)/gui/simple-greeter/libgdmsimplegreeter \
+ -DDMCONFDIR=\""$(dmconfdir)"\" \
+ -DGDMCONFDIR=\"$(gdmconfdir)\" \
+ -DPLUGINDATADIR=\""$(extensiondir)"\" \
+ -DPAMSERVICENAME=\""$(pam_DATA)"\" \
+ -DSYSCONFDIR=\""$(sysconfdir)"\" \
+ -DLIBLOCALEDIR=\""$(prefix)/lib/locale"\" \
+ -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
+ -DLIBEXECDIR=\""$(libexecdir)"\" \
+ -DLIBDIR=\""$(libdir)"\" \
+ -DSBINDIR=\""$(sbindir)"\" \
+ $(DISABLE_DEPRECATED_CFLAGS) \
+ $(GTK_CFLAGS) \
+ $(SIMPLE_GREETER_CFLAGS) \
+ $(POLKIT_GNOME_CFLAGS) \
+ $(NULL)
+
+plugindir = $(GDM_SIMPLE_GREETER_PLUGINS_DIR)
+plugin_LTLIBRARIES = smartcard.la
+
+smartcard_la_CFLAGS = \
+ $(SIMPLE_GREETER_CFLAGS) \
+ $(NULL)
+
+libexec_PROGRAMS = \
+ gdm-smartcard-worker \
+ $(NULL)
+
+
+smartcard_la_LDFLAGS = -module -avoid-version -export-dynamic
+smartcard_la_LIBADD = ../../../../common/libgdmcommon.la \
+ ../../libgdmsimplegreeter/libgdmsimplegreeter.la
+smartcard_la_SOURCES = \
+ gdm-smartcard-extension.h \
+ gdm-smartcard-extension.c \
+ plugin.c
+
+gdm_smartcard_worker_LDADD = ../../../../common/libgdmcommon.la \
+ $(DAEMON_LIBS) \
+ $(GTHREAD_LIBS) \
+ $(NSS_LIBS) \
+ $(NULL)
+gdm_smartcard_worker_CFLAGS = $(DAEMON_CFLAGS) \
+ $(NSS_CFLAGS) \
+ $(NULL)
+gdm_smartcard_worker_SOURCES = \
+ gdm-smartcard.h \
+ gdm-smartcard.c \
+ gdm-smartcard-manager.h \
+ gdm-smartcard-manager.c \
+ gdm-smartcard-worker.c \
+ $(NULL)
+
+$(PAM_SERVICE_NAME): $(PAM_SERVICE_NAME).pam
+ cp $(PAM_SERVICE_NAME).pam $(PAM_SERVICE_NAME)
+
+pamdir = $(PAM_PREFIX)/pam.d
+pam_DATA = $(PAM_SERVICE_NAME)
+
+EXTRA_DIST = $(extension_DATA) $(PAM_SERVICE_NAME).pam
+CLEANFILES = $(PAM_SERVICE_NAME)
+
+MAINTAINERCLEANFILES = \
+ *~ \
+ $(PAM_SERVICE_NAME) \
+ Makefile.in
diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
new file mode 100644
index 0000000..b925f5e
--- /dev/null
+++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
@@ -0,0 +1,510 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ * Written By: Ray Strode <rstrode@redhat.com>
+ *
+ */
+
+#include <config.h>
+#include "gdm-smartcard-extension.h"
+#include "gdm-conversation.h"
+#include "gdm-task.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <glib/gi18n-lib.h>
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+
+#ifndef GDM_SMARTCARD_WORKER_COMMAND
+#define GDM_SMARTCARD_WORKER_COMMAND LIBEXECDIR "/gdm-smartcard-worker"
+#endif
+
+struct _GdmSmartcardExtensionPrivate
+{
+ GIcon *icon;
+ GtkWidget *page;
+ GtkActionGroup *actions;
+ GtkAction *login_action;
+
+ GtkWidget *message_label;
+ GtkWidget *prompt_label;
+ GtkWidget *prompt_entry;
+
+ GPid worker_pid;
+ int number_of_tokens;
+
+ guint answer_pending : 1;
+ guint select_when_ready : 1;
+};
+
+static void gdm_smartcard_extension_finalize (GObject *object);
+
+static void gdm_task_iface_init (GdmTaskIface *iface);
+static void gdm_conversation_iface_init (GdmConversationIface *iface);
+static void gdm_greeter_extension_iface_init (GdmGreeterExtensionIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GdmSmartcardExtension,
+ gdm_smartcard_extension,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GDM_TYPE_GREETER_EXTENSION,
+ gdm_greeter_extension_iface_init)
+ G_IMPLEMENT_INTERFACE (GDM_TYPE_TASK,
+ gdm_task_iface_init)
+ G_IMPLEMENT_INTERFACE (GDM_TYPE_CONVERSATION,
+ gdm_conversation_iface_init));
+
+static gboolean
+on_smartcard_event (GIOChannel *io_channel,
+ GIOCondition condition,
+ gpointer data)
+{
+ GdmSmartcardExtension *extension;
+
+ extension = GDM_SMARTCARD_EXTENSION (data);
+
+ if (condition & G_IO_IN) {
+ char buffer[1024];
+ ssize_t num_bytes;
+
+ num_bytes = read (g_io_channel_unix_get_fd (io_channel),
+ buffer, sizeof (buffer));
+
+ if (num_bytes < 0 && errno != EINTR)
+ return FALSE;
+
+ if (num_bytes != 1) {
+ g_debug ("buffer: %s\n", buffer);
+ return TRUE;
+ }
+
+ if (buffer[0] == 'I') {
+ extension->priv->number_of_tokens++;
+ } else {
+ extension->priv->number_of_tokens--;
+ }
+
+ if (extension->priv->number_of_tokens == 1) {
+ if (!gdm_conversation_choose_user (GDM_CONVERSATION (extension),
+ PAMSERVICENAME)) {
+ g_debug ("could not choose smart card user, cancelling...");
+ gdm_conversation_cancel (GDM_CONVERSATION (extension));
+ extension->priv->select_when_ready = TRUE;
+ } else {
+ g_debug ("chose smart card user!");
+ }
+ } else if (extension->priv->number_of_tokens == 0) {
+ gdm_conversation_cancel (GDM_CONVERSATION (extension));
+ }
+
+ return TRUE;
+ }
+
+ if (condition & G_IO_HUP) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+watch_for_smartcards (GdmSmartcardExtension *extension)
+{
+ GError *error;
+ GIOChannel *io_channel;
+ char *args[] = { GDM_SMARTCARD_WORKER_COMMAND, NULL };
+ GPid pid;
+ int stdout_fd;
+
+ error = NULL;
+
+ if (!g_spawn_async_with_pipes (NULL, args, NULL, 0,
+ NULL, NULL, &pid, NULL,
+ &stdout_fd, NULL, &error)) {
+ g_debug ("could not start smart card manager: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+ fcntl (stdout_fd, F_SETFD, FD_CLOEXEC);
+
+ io_channel = g_io_channel_unix_new (stdout_fd);
+ g_io_channel_set_flags (io_channel, G_IO_FLAG_NONBLOCK, NULL);
+ g_io_channel_set_encoding (io_channel, NULL, NULL);
+ g_io_channel_set_buffered (io_channel, FALSE);
+ g_io_add_watch (io_channel, G_IO_IN, on_smartcard_event, extension);
+ g_io_channel_set_close_on_unref (io_channel, TRUE);
+ g_io_channel_unref (io_channel);
+
+ extension->priv->worker_pid = pid;
+}
+
+static void
+stop_watching_for_smartcards (GdmSmartcardExtension *extension)
+{
+ kill (extension->priv->worker_pid, SIGTERM);
+}
+
+static void
+gdm_smartcard_extension_set_message (GdmConversation *conversation,
+ const char *message)
+{
+ GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation);
+ gtk_widget_show (extension->priv->message_label);
+ gtk_label_set_text (GTK_LABEL (extension->priv->message_label), message);
+}
+
+static void
+gdm_smartcard_extension_ask_question (GdmConversation *conversation,
+ const char *message)
+{
+ GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation);
+ gtk_widget_show (extension->priv->prompt_label);
+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), message);
+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), "");
+ gtk_entry_set_visibility (GTK_ENTRY (extension->priv->prompt_entry), TRUE);
+ gtk_widget_show (extension->priv->prompt_entry);
+ gtk_action_set_visible (extension->priv->login_action, TRUE);
+ gtk_widget_grab_focus (extension->priv->prompt_entry);
+ extension->priv->answer_pending = TRUE;
+}
+
+static void
+gdm_smartcard_extension_ask_secret (GdmConversation *conversation,
+ const char *message)
+{
+ GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation);
+ gtk_widget_show (extension->priv->prompt_label);
+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), message);
+ gtk_entry_set_visibility (GTK_ENTRY (extension->priv->prompt_entry), FALSE);
+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), "");
+ gtk_widget_show (extension->priv->prompt_entry);
+ gtk_widget_grab_focus (extension->priv->prompt_entry);
+ gtk_action_set_visible (extension->priv->login_action, TRUE);
+ extension->priv->answer_pending = TRUE;
+}
+
+static void
+gdm_smartcard_extension_reset (GdmConversation *conversation)
+{
+ GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation);
+ gtk_widget_hide (extension->priv->prompt_label);
+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), "");
+
+ gtk_widget_hide (extension->priv->prompt_entry);
+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), "");
+ gtk_entry_set_visibility (GTK_ENTRY (extension->priv->prompt_entry), TRUE);
+ gtk_action_set_visible (extension->priv->login_action, FALSE);
+ extension->priv->answer_pending = FALSE;
+
+ gdm_task_set_enabled (GDM_TASK (conversation), FALSE);
+}
+
+static void
+gdm_smartcard_extension_set_ready (GdmConversation *conversation)
+{
+ GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation);
+ gdm_task_set_enabled (GDM_TASK (conversation), TRUE);
+
+ if (extension->priv->worker_pid <= 0) {
+ watch_for_smartcards (extension);
+ }
+
+ if (extension->priv->select_when_ready) {
+ if (gdm_conversation_choose_user (GDM_CONVERSATION (extension),
+ PAMSERVICENAME)) {
+ extension->priv->select_when_ready = FALSE;
+ }
+ }
+}
+
+char *
+gdm_smartcard_extension_get_service_name (GdmConversation *conversation)
+{
+ return g_strdup (PAMSERVICENAME);
+}
+
+GtkWidget *
+gdm_smartcard_extension_get_page (GdmConversation *conversation)
+{
+ GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation);
+ return extension->priv->page;
+}
+
+GtkActionGroup *
+gdm_smartcard_extension_get_actions (GdmConversation *conversation)
+{
+ GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation);
+
+ return g_object_ref (extension->priv->actions);
+}
+
+void
+gdm_smartcard_extension_request_answer (GdmConversation *conversation)
+{
+ GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation);
+ const char *text;
+
+ if (!extension->priv->answer_pending) {
+ gdm_conversation_answer (conversation, NULL);
+ return;
+ }
+
+ extension->priv->answer_pending = FALSE;
+ text = gtk_entry_get_text (GTK_ENTRY (extension->priv->prompt_entry));
+ gdm_conversation_answer (conversation, text);
+
+ gtk_widget_hide (extension->priv->prompt_entry);
+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), "");
+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), "");
+ gtk_action_set_visible (extension->priv->login_action, FALSE);
+}
+
+gboolean
+gdm_smartcard_extension_focus (GdmConversation *conversation)
+{
+ GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation);
+
+ if (!extension->priv->answer_pending) {
+ return FALSE;
+ }
+
+ gtk_widget_grab_focus (extension->priv->prompt_entry);
+ return TRUE;
+}
+
+GIcon *
+gdm_smartcard_extension_get_icon (GdmTask *task)
+{
+ GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (task);
+ return g_object_ref (extension->priv->icon);
+}
+
+char *
+gdm_smartcard_extension_get_name (GdmTask *task)
+{
+ return g_strdup (_("Smartcard Authentication"));
+}
+
+char *
+gdm_smartcard_extension_get_description (GdmTask *task)
+{
+ return g_strdup (_("Log into session with smartcard"));
+}
+
+gboolean
+gdm_smartcard_extension_is_choosable (GdmTask *task)
+{
+ return TRUE;
+}
+
+gboolean
+gdm_smartcard_extension_is_visible (GdmTask *task)
+{
+ char *contents, **lines, *pid_dir;
+ gboolean ret;
+ guint i;
+ pid_t pid;
+
+ /*
+ * FIXME: We shouldn't use a distro specific hack here
+ */
+
+ if (g_file_get_contents ("/var/run/pcscd.pid",
+ &contents, NULL, NULL) == FALSE) {
+ return FALSE;
+ }
+
+ pid = (pid_t) atoi (contents);
+ g_free (contents);
+
+ if (pid == 0) {
+ return FALSE;
+ }
+
+ pid_dir = g_strdup_printf ("/proc/%d", (int) pid);
+ if (!g_file_test (pid_dir, G_FILE_TEST_EXISTS)) {
+ g_free (pid_dir);
+ return FALSE;
+ }
+ g_free (pid_dir);
+
+ if (g_file_get_contents ("/etc/sysconfig/authconfig",
+ &contents, NULL, NULL) == FALSE) {
+ return FALSE;
+ }
+
+ lines = g_strsplit (contents, "\n", -1);
+ g_free (contents);
+
+ ret = FALSE;
+
+ for (i = 0; lines[i] ; i++) {
+ if (g_str_has_prefix (lines[i], "USESMARTCARD=") != FALSE) {
+ char *value;
+
+ value = lines[i] + strlen ("USESMARTCARD=");
+ if (rpmatch (value)) {
+ ret = TRUE;
+ break;
+ }
+ }
+ }
+
+ g_strfreev (lines);
+
+ return TRUE;
+}
+
+static void
+gdm_task_iface_init (GdmTaskIface *iface)
+{
+ iface->get_icon = gdm_smartcard_extension_get_icon;
+ iface->get_description = gdm_smartcard_extension_get_description;
+ iface->get_name = gdm_smartcard_extension_get_name;
+ iface->is_choosable = gdm_smartcard_extension_is_choosable;
+ iface->is_visible = gdm_smartcard_extension_is_visible;
+}
+
+static void
+gdm_conversation_iface_init (GdmConversationIface *iface)
+{
+ iface->set_message = gdm_smartcard_extension_set_message;
+ iface->ask_question = gdm_smartcard_extension_ask_question;
+ iface->ask_secret = gdm_smartcard_extension_ask_secret;
+ iface->reset = gdm_smartcard_extension_reset;
+ iface->set_ready = gdm_smartcard_extension_set_ready;
+ iface->get_service_name = gdm_smartcard_extension_get_service_name;
+ iface->get_page = gdm_smartcard_extension_get_page;
+ iface->get_actions = gdm_smartcard_extension_get_actions;
+ iface->request_answer = gdm_smartcard_extension_request_answer;
+ iface->focus = gdm_smartcard_extension_focus;
+}
+
+static void
+gdm_greeter_extension_iface_init (GdmGreeterExtensionIface *iface)
+{
+}
+
+static void
+gdm_smartcard_extension_class_init (GdmSmartcardExtensionClass *extension_class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (extension_class);
+
+ object_class->finalize = gdm_smartcard_extension_finalize;
+
+ g_type_class_add_private (extension_class,
+ sizeof (GdmSmartcardExtensionPrivate));
+}
+
+static void
+gdm_smartcard_extension_finalize (GObject *object)
+{
+ GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (object);
+
+ if (extension->priv->worker_pid > 0) {
+ stop_watching_for_smartcards (extension);
+ }
+}
+
+static void
+create_page (GdmSmartcardExtension *extension)
+{
+ GtkBuilder *builder;
+ GObject *object;
+ GError *error;
+
+ builder = gtk_builder_new ();
+
+ error = NULL;
+ gtk_builder_add_from_file (builder,
+ PLUGINDATADIR "/page.ui",
+ &error);
+
+ if (error != NULL) {
+ g_warning ("Could not load UI file: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ object = gtk_builder_get_object (builder, "page");
+ g_object_ref (object);
+
+ extension->priv->page = GTK_WIDGET (object);
+
+ object = gtk_builder_get_object (builder, "auth-prompt-label");
+ g_object_ref (object);
+ extension->priv->prompt_label = GTK_WIDGET (object);
+ gtk_widget_hide (extension->priv->prompt_label);
+
+ object = gtk_builder_get_object (builder, "auth-prompt-entry");
+ g_object_ref (object);
+ extension->priv->prompt_entry = GTK_WIDGET (object);
+ gtk_widget_hide (extension->priv->prompt_entry);
+
+ object = gtk_builder_get_object (builder, "auth-message-label");
+ g_object_ref (object);
+ extension->priv->message_label = GTK_WIDGET (object);
+ gtk_widget_show (extension->priv->message_label);
+
+ g_object_unref (builder);
+}
+
+static void
+on_activate_log_in (GdmSmartcardExtension *extension)
+{
+ gdm_smartcard_extension_request_answer (GDM_CONVERSATION (extension));
+}
+
+static void
+create_actions (GdmSmartcardExtension *extension)
+{
+ GtkAction *action;
+
+ extension->priv->actions = gtk_action_group_new ("gdm-smartcard-extension");
+
+ action = gtk_action_new (GDM_CONVERSATION_DEFAULT_ACTION,
+ _("Log In"), NULL, NULL);
+ g_signal_connect_swapped (action, "activate",
+ G_CALLBACK (on_activate_log_in), extension);
+ g_object_set (G_OBJECT (action), "icon-name", "go-home", NULL);
+ gtk_action_group_add_action (extension->priv->actions,
+ action);
+
+ gtk_action_set_visible (action, FALSE);
+ extension->priv->login_action = action;
+}
+
+static void
+gdm_smartcard_extension_init (GdmSmartcardExtension *extension)
+{
+ extension->priv = G_TYPE_INSTANCE_GET_PRIVATE (extension,
+ GDM_TYPE_SMARTCARD_EXTENSION,
+ GdmSmartcardExtensionPrivate);
+
+ extension->priv->icon = g_themed_icon_new ("gdm-smartcard");
+ create_page (extension);
+ create_actions (extension);
+ gdm_smartcard_extension_reset (GDM_CONVERSATION (extension));
+}
diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.h b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.h
new file mode 100644
index 0000000..285b51a
--- /dev/null
+++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ * Written By: Ray Strode <rstrode@redhat.com>
+ */
+
+#ifndef __GDM_SMARTCARD_EXTENSION_H
+#define __GDM_SMARTCARD_EXTENSION_H
+
+#include <glib-object.h>
+#include "gdm-greeter-extension.h"
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_SMARTCARD_EXTENSION (gdm_smartcard_extension_get_type ())
+#define GDM_SMARTCARD_EXTENSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDM_TYPE_SMARTCARD_EXTENSION, GdmSmartcardExtension))
+#define GDM_SMARTCARD_EXTENSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDM_TYPE_SMARTCARD_EXTENSION, GdmSmartcardExtensionClass))
+#define GDM_IS_SMARTCARD_EXTENSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDM_TYPE_SMARTCARD_EXTENSION))
+#define GDM_IS_SMARTCARD_EXTENSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDM_TYPE_SMARTCARD_EXTENSION))
+#define GDM_SMARTCARD_EXTENSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GDM_TYPE_SMARTCARD_EXTENSION, GdmSmartcardExtensionClass))
+
+typedef struct _GdmSmartcardExtensionPrivate GdmSmartcardExtensionPrivate;
+
+typedef struct
+{
+ GObject parent;
+ GdmSmartcardExtensionPrivate *priv;
+} GdmSmartcardExtension;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} GdmSmartcardExtensionClass;
+
+GType gdm_smartcard_extension_get_type (void);
+
+GdmSmartcardExtension *gdm_smartcard_extension_new (void);
+
+G_END_DECLS
+
+#endif /* GDM_SMARTCARD_EXTENSION_H */
diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-manager.c b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-manager.c
new file mode 100644
index 0000000..5af0da9
--- /dev/null
+++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-manager.c
@@ -0,0 +1,1521 @@
+/* gdm-smartcard-manager.c - object for monitoring smartcard insertion and
+ * removal events
+ *
+ * Copyright (C) 2006, 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ * Written By: Ray Strode
+ */
+#define _GNU_SOURCE
+#include "gdm-smartcard-manager.h"
+
+#define GDM_SMARTCARD_ENABLE_INTERNAL_API
+#include "gdm-smartcard.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <prerror.h>
+#include <prinit.h>
+#include <nss.h>
+#include <pk11func.h>
+#include <secmod.h>
+#include <secerr.h>
+
+#ifndef GDM_SMARTCARD_MANAGER_DRIVER
+#define GDM_SMARTCARD_MANAGER_DRIVER LIBDIR"/pkcs11/libcoolkeypk11.so"
+#endif
+
+#ifndef GDM_SMARTCARD_MANAGER_NSS_DB
+#define GDM_SMARTCARD_MANAGER_NSS_DB SYSCONFDIR"/pki/nssdb"
+#endif
+
+#ifndef GDM_MAX_OPEN_FILE_DESCRIPTORS
+#define GDM_MAX_OPEN_FILE_DESCRIPTORS 1024
+#endif
+
+#ifndef GDM_OPEN_FILE_DESCRIPTORS_DIR
+#define GDM_OPEN_FILE_DESCRIPTORS_DIR "/proc/self/fd"
+#endif
+
+typedef enum _GdmSmartcardManagerState GdmSmartcardManagerState;
+typedef struct _GdmSmartcardManagerWorker GdmSmartcardManagerWorker;
+
+enum _GdmSmartcardManagerState {
+ GDM_SMARTCARD_MANAGER_STATE_STOPPED = 0,
+ GDM_SMARTCARD_MANAGER_STATE_STARTING,
+ GDM_SMARTCARD_MANAGER_STATE_STARTED,
+ GDM_SMARTCARD_MANAGER_STATE_STOPPING,
+};
+
+struct _GdmSmartcardManagerPrivate {
+ GdmSmartcardManagerState state;
+ GList *modules;
+ char *module_path;
+
+ GList *workers;
+
+ GPid smartcard_event_watcher_pid;
+ GHashTable *smartcards;
+
+ guint poll_timeout_id;
+
+ guint32 is_unstoppable : 1;
+ guint32 nss_is_loaded : 1;
+};
+
+struct _GdmSmartcardManagerWorker {
+ GdmSmartcardManager *manager;
+ gint manager_fd;
+
+ GThread *thread;
+ SECMODModule *module;
+ GHashTable *smartcards;
+ gint fd;
+ GSource *event_source;
+
+ guint32 nss_is_loaded : 1;
+};
+
+static void gdm_smartcard_manager_finalize (GObject *object);
+static void gdm_smartcard_manager_class_install_signals (GdmSmartcardManagerClass *service_class);
+static void gdm_smartcard_manager_class_install_properties (GdmSmartcardManagerClass *service_class);
+static void gdm_smartcard_manager_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gdm_smartcard_manager_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void gdm_smartcard_manager_set_module_path (GdmSmartcardManager *manager,
+ const char *module_path);
+static void gdm_smartcard_manager_card_removed_handler (GdmSmartcardManager *manager,
+ GdmSmartcard *card);
+static void gdm_smartcard_manager_card_inserted_handler (GdmSmartcardManager *manager_class,
+ GdmSmartcard *card);
+static gboolean gdm_smartcard_manager_stop_now (GdmSmartcardManager *manager);
+static void gdm_smartcard_manager_queue_stop (GdmSmartcardManager *manager);
+
+static GdmSmartcardManagerWorker *gdm_smartcard_manager_create_worker (GdmSmartcardManager *manager,
+ SECMODModule *module);
+
+static GdmSmartcardManagerWorker * gdm_smartcard_manager_worker_new (GdmSmartcardManager *manager,
+ int worker_fd,
+ int manager_fd,
+ SECMODModule *module);
+static void gdm_smartcard_manager_worker_free (GdmSmartcardManagerWorker *worker);
+static gboolean gdm_open_pipe (gint *write_fd, gint *read_fd);
+static gboolean sc_read_bytes (gint fd, gpointer bytes, gsize num_bytes);
+static gboolean sc_write_bytes (gint fd, gconstpointer bytes, gsize num_bytes);
+static GdmSmartcard *sc_read_smartcard (gint fd, SECMODModule *module);
+static gboolean sc_write_smartcard (gint fd, GdmSmartcard *card);
+
+enum {
+ PROP_0 = 0,
+ PROP_MODULE_PATH,
+ NUMBER_OF_PROPERTIES
+};
+
+enum {
+ SMARTCARD_INSERTED = 0,
+ SMARTCARD_REMOVED,
+ ERROR,
+ NUMBER_OF_SIGNALS
+};
+
+static guint gdm_smartcard_manager_signals[NUMBER_OF_SIGNALS];
+
+G_DEFINE_TYPE (GdmSmartcardManager,
+ gdm_smartcard_manager,
+ G_TYPE_OBJECT);
+
+static void
+gdm_smartcard_manager_class_init (GdmSmartcardManagerClass *manager_class)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = G_OBJECT_CLASS (manager_class);
+
+ gobject_class->finalize = gdm_smartcard_manager_finalize;
+
+ gdm_smartcard_manager_class_install_signals (manager_class);
+ gdm_smartcard_manager_class_install_properties (manager_class);
+
+ g_type_class_add_private (manager_class,
+ sizeof (GdmSmartcardManagerPrivate));
+}
+
+static void
+gdm_smartcard_manager_class_install_properties (GdmSmartcardManagerClass *card_class)
+{
+ GObjectClass *object_class;
+ GParamSpec *param_spec;
+
+ object_class = G_OBJECT_CLASS (card_class);
+ object_class->set_property = gdm_smartcard_manager_set_property;
+ object_class->get_property = gdm_smartcard_manager_get_property;
+
+ param_spec = g_param_spec_string ("module-path", _("Module Path"),
+ _("path to smartcard PKCS #11 driver"),
+ NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property (object_class, PROP_MODULE_PATH, param_spec);
+}
+
+static void
+gdm_smartcard_manager_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdmSmartcardManager *manager = GDM_SMARTCARD_MANAGER (object);
+
+ switch (prop_id) {
+ case PROP_MODULE_PATH:
+ gdm_smartcard_manager_set_module_path (manager,
+ g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdm_smartcard_manager_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdmSmartcardManager *manager = GDM_SMARTCARD_MANAGER (object);
+ char *module_path;
+
+ switch (prop_id) {
+ case PROP_MODULE_PATH:
+ module_path = gdm_smartcard_manager_get_module_path (manager);
+ g_value_set_string (value, module_path);
+ g_free (module_path);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+char *
+gdm_smartcard_manager_get_module_path (GdmSmartcardManager *manager)
+{
+ return manager->priv->module_path;
+}
+
+static void
+gdm_smartcard_manager_set_module_path (GdmSmartcardManager *manager,
+ const char *module_path)
+{
+ if ((manager->priv->module_path == NULL) && (module_path == NULL)) {
+ return;
+ }
+
+ if (((manager->priv->module_path == NULL) ||
+ (module_path == NULL) ||
+ (strcmp (manager->priv->module_path, module_path) != 0))) {
+ g_free (manager->priv->module_path);
+ manager->priv->module_path = g_strdup (module_path);
+ g_object_notify (G_OBJECT (manager), "module-path");
+ }
+}
+
+static void
+gdm_smartcard_manager_card_removed_handler (GdmSmartcardManager *manager,
+ GdmSmartcard *card)
+{
+ g_debug ("informing smartcard of its removal");
+ _gdm_smartcard_set_state (card, GDM_SMARTCARD_STATE_REMOVED);
+ g_debug ("done");
+}
+
+static void
+gdm_smartcard_manager_card_inserted_handler (GdmSmartcardManager *manager,
+ GdmSmartcard *card)
+{
+ g_debug ("informing smartcard of its insertion");
+
+ _gdm_smartcard_set_state (card, GDM_SMARTCARD_STATE_INSERTED);
+ g_debug ("done");
+
+}
+
+static void
+gdm_smartcard_manager_class_install_signals (GdmSmartcardManagerClass *manager_class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (manager_class);
+
+ gdm_smartcard_manager_signals[SMARTCARD_INSERTED] =
+ g_signal_new ("smartcard-inserted",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmSmartcardManagerClass,
+ smartcard_inserted),
+ NULL, NULL, g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE, 1, G_TYPE_POINTER);
+ manager_class->smartcard_inserted = gdm_smartcard_manager_card_inserted_handler;
+
+ gdm_smartcard_manager_signals[SMARTCARD_REMOVED] =
+ g_signal_new ("smartcard-removed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmSmartcardManagerClass,
+ smartcard_removed),
+ NULL, NULL, g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE, 1, G_TYPE_POINTER);
+ manager_class->smartcard_removed = gdm_smartcard_manager_card_removed_handler;
+
+ gdm_smartcard_manager_signals[ERROR] =
+ g_signal_new ("error",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdmSmartcardManagerClass, error),
+ NULL, NULL, g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE, 1, G_TYPE_POINTER);
+ manager_class->error = NULL;
+}
+
+static gboolean
+sc_slot_id_equal (CK_SLOT_ID *slot_id_1,
+ CK_SLOT_ID *slot_id_2)
+{
+ g_assert (slot_id_1 != NULL);
+ g_assert (slot_id_2 != NULL);
+
+ return *slot_id_1 == *slot_id_2;
+}
+
+static gboolean
+sc_slot_id_hash (CK_SLOT_ID *slot_id)
+{
+ guint32 upper_bits, lower_bits;
+ gint temp;
+
+ if (sizeof (CK_SLOT_ID) == sizeof (gint)) {
+ return g_int_hash (slot_id);
+ }
+
+ upper_bits = ((*slot_id) >> 31) - 1;
+ lower_bits = (*slot_id) & 0xffffffff;
+
+ /* The upper bits are almost certainly always zero,
+ * so let's degenerate to g_int_hash for the
+ * (very) common case
+ */
+ temp = lower_bits + upper_bits;
+ return upper_bits + g_int_hash (&temp);
+}
+
+static void
+gdm_smartcard_manager_init (GdmSmartcardManager *manager)
+{
+ g_debug ("initializing smartcard manager");
+
+ manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
+ GDM_TYPE_SMARTCARD_MANAGER,
+ GdmSmartcardManagerPrivate);
+ manager->priv->poll_timeout_id = 0;
+ manager->priv->is_unstoppable = FALSE;
+
+ manager->priv->smartcards =
+ g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_object_unref);
+
+ if (!g_thread_supported()) {
+ g_thread_init (NULL);
+ }
+
+}
+
+static void
+gdm_smartcard_manager_finalize (GObject *object)
+{
+ GdmSmartcardManager *manager;
+ GObjectClass *gobject_class;
+
+ manager = GDM_SMARTCARD_MANAGER (object);
+ gobject_class =
+ G_OBJECT_CLASS (gdm_smartcard_manager_parent_class);
+
+ gdm_smartcard_manager_stop_now (manager);
+
+ g_hash_table_destroy (manager->priv->smartcards);
+ manager->priv->smartcards = NULL;
+
+ gobject_class->finalize (object);
+}
+
+GQuark
+gdm_smartcard_manager_error_quark (void)
+{
+ static GQuark error_quark = 0;
+
+ if (error_quark == 0) {
+ error_quark = g_quark_from_static_string ("gdm-smartcard-manager-error-quark");
+ }
+
+ return error_quark;
+}
+
+GdmSmartcardManager *
+gdm_smartcard_manager_new (const char *module_path)
+{
+ GdmSmartcardManager *instance;
+
+ instance = GDM_SMARTCARD_MANAGER (g_object_new (GDM_TYPE_SMARTCARD_MANAGER,
+ "module-path", module_path,
+ NULL));
+
+ return instance;
+}
+
+static void
+gdm_smartcard_manager_emit_error (GdmSmartcardManager *manager,
+ GError *error)
+{
+ manager->priv->is_unstoppable = TRUE;
+ g_signal_emit (manager, gdm_smartcard_manager_signals[ERROR], 0,
+ error);
+ manager->priv->is_unstoppable = FALSE;
+}
+
+static void
+gdm_smartcard_manager_emit_smartcard_inserted (GdmSmartcardManager *manager,
+ GdmSmartcard *card)
+{
+ manager->priv->is_unstoppable = TRUE;
+ g_signal_emit (manager, gdm_smartcard_manager_signals[SMARTCARD_INSERTED], 0,
+ card);
+ manager->priv->is_unstoppable = FALSE;
+}
+
+static void
+gdm_smartcard_manager_emit_smartcard_removed (GdmSmartcardManager *manager,
+ GdmSmartcard *card)
+{
+ GdmSmartcardManagerState old_state;
+
+ old_state = manager->priv->state;
+ manager->priv->is_unstoppable = TRUE;
+ g_signal_emit (manager, gdm_smartcard_manager_signals[SMARTCARD_REMOVED], 0,
+ card);
+ manager->priv->is_unstoppable = FALSE;
+}
+
+static gboolean
+gdm_smartcard_manager_check_for_and_process_events (GIOChannel *io_channel,
+ GIOCondition condition,
+ GdmSmartcardManagerWorker *worker)
+{
+ GdmSmartcard *card;
+ GdmSmartcardManager *manager;
+ gboolean should_stop;
+ guchar event_type;
+ char *card_name;
+ gint fd;
+
+ manager = worker->manager;
+
+ g_debug ("event!");
+ card = NULL;
+ should_stop = (condition & G_IO_HUP) || (condition & G_IO_ERR);
+
+ if (should_stop) {
+ g_debug ("received %s on event socket, stopping "
+ "manager...",
+ (condition & G_IO_HUP) && (condition & G_IO_ERR)?
+ "error and hangup" :
+ (condition & G_IO_HUP)?
+ "hangup" : "error");
+ }
+
+ if (!(condition & G_IO_IN)) {
+ g_debug ("nevermind outta here!");
+ goto out;
+ }
+
+ fd = g_io_channel_unix_get_fd (io_channel);
+
+ event_type = '\0';
+ if (!sc_read_bytes (fd, &event_type, 1)) {
+ g_debug ("could not read event type, stopping");
+ should_stop = TRUE;
+ goto out;
+ }
+
+ card = sc_read_smartcard (fd, worker->module);
+
+ if (card == NULL) {
+ g_debug ("could not read card, stopping");
+ should_stop = TRUE;
+ goto out;
+ }
+
+ card_name = gdm_smartcard_get_name (card);
+ g_debug ("card '%s' had event %c", card_name, event_type);
+
+ switch (event_type) {
+ case 'I':
+ g_hash_table_replace (manager->priv->smartcards,
+ card_name, card);
+ card_name = NULL;
+
+ gdm_smartcard_manager_emit_smartcard_inserted (manager, card);
+ card = NULL;
+ break;
+
+ case 'R':
+ gdm_smartcard_manager_emit_smartcard_removed (manager, card);
+ if (!g_hash_table_remove (manager->priv->smartcards, card_name)) {
+ g_debug ("got removal event of unknown card!");
+ }
+ g_free (card_name);
+ card_name = NULL;
+ card = NULL;
+ break;
+
+ default:
+ g_free (card_name);
+ card_name = NULL;
+ g_object_unref (card);
+
+ should_stop = TRUE;
+ break;
+ }
+
+out:
+ if (should_stop) {
+ GError *error;
+
+ error = g_error_new (GDM_SMARTCARD_MANAGER_ERROR,
+ GDM_SMARTCARD_MANAGER_ERROR_WATCHING_FOR_EVENTS,
+ "%s", (condition & G_IO_IN) ? g_strerror (errno) : _("received error or hang up from event source"));
+
+ gdm_smartcard_manager_emit_error (manager, error);
+ g_error_free (error);
+ gdm_smartcard_manager_stop_now (manager);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+stop_manager (GdmSmartcardManager *manager)
+{
+ manager->priv->state = GDM_SMARTCARD_MANAGER_STATE_STOPPED;
+
+ if (manager->priv->nss_is_loaded) {
+ NSS_Shutdown ();
+ manager->priv->nss_is_loaded = FALSE;
+ }
+ g_debug ("smartcard manager stopped");
+}
+
+static void
+stop_worker (GdmSmartcardManagerWorker *worker)
+{
+ GdmSmartcardManager *manager;
+
+ manager = worker->manager;
+
+ if (worker->event_source != NULL) {
+ g_source_destroy (worker->event_source);
+ worker->event_source = NULL;
+ }
+
+ if (worker->thread != NULL) {
+ SECMOD_CancelWait (worker->module);
+ worker->thread = NULL;
+ }
+
+ SECMOD_DestroyModule (worker->module);
+ manager->priv->workers = g_list_remove (manager->priv->workers, worker);
+
+ if (manager->priv->workers == NULL && manager->priv->state != GDM_SMARTCARD_MANAGER_STATE_STOPPED) {
+ stop_manager (manager);
+ }
+}
+
+static void
+gdm_smartcard_manager_event_processing_stopped_handler (GdmSmartcardManagerWorker *worker)
+{
+ worker->event_source = NULL;
+
+ stop_worker (worker);
+}
+
+static gboolean
+gdm_open_pipe (gint *write_fd,
+ gint *read_fd)
+{
+ gint pipe_fds[2] = { -1, -1 };
+
+ g_assert (write_fd != NULL);
+ g_assert (read_fd != NULL);
+
+ if (pipe (pipe_fds) < 0) {
+ return FALSE;
+ }
+
+ if (fcntl (pipe_fds[0], F_SETFD, FD_CLOEXEC) < 0) {
+ close (pipe_fds[0]);
+ close (pipe_fds[1]);
+ return FALSE;
+ }
+
+ if (fcntl (pipe_fds[1], F_SETFD, FD_CLOEXEC) < 0) {
+ close (pipe_fds[0]);
+ close (pipe_fds[1]);
+ return FALSE;
+ }
+
+ *read_fd = pipe_fds[0];
+ *write_fd = pipe_fds[1];
+
+ return TRUE;
+}
+
+static void
+gdm_smartcard_manager_stop_watching_for_events (GdmSmartcardManager *manager)
+{
+ GList *node;
+
+ node = manager->priv->workers;
+ while (node != NULL) {
+ GdmSmartcardManagerWorker *worker;
+ GList *next_node;
+
+ worker = (GdmSmartcardManagerWorker *) node->data;
+ next_node = node->next;
+
+ stop_worker (worker);
+
+ node = next_node;
+ }
+}
+
+static gboolean
+sc_load_nss (GError **error)
+{
+ SECStatus status = SECSuccess;
+ static const guint32 flags =
+ NSS_INIT_READONLY |
+ NSS_INIT_FORCEOPEN | NSS_INIT_NOROOTINIT |
+ NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD;
+
+ g_debug ("attempting to load NSS database '%s'",
+ GDM_SMARTCARD_MANAGER_NSS_DB);
+
+ PR_Init (PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+
+ status = NSS_Initialize (GDM_SMARTCARD_MANAGER_NSS_DB,
+ "", "", SECMOD_DB, flags);
+
+ if (status != SECSuccess) {
+ gsize error_message_size;
+ char *error_message;
+
+ error_message_size = PR_GetErrorTextLength ();
+
+ if (error_message_size == 0) {
+ g_debug ("NSS security system could not be initialized");
+ g_set_error (error,
+ GDM_SMARTCARD_MANAGER_ERROR,
+ GDM_SMARTCARD_MANAGER_ERROR_WITH_NSS,
+ _("NSS security system could not be initialized"));
+ goto out;
+ }
+
+ error_message = g_slice_alloc0 (error_message_size);
+ PR_GetErrorText (error_message);
+
+ g_set_error (error,
+ GDM_SMARTCARD_MANAGER_ERROR,
+ GDM_SMARTCARD_MANAGER_ERROR_WITH_NSS,
+ "%s", error_message);
+ g_debug ("NSS security system could not be initialized - %s",
+ error_message);
+
+ g_slice_free1 (error_message_size, error_message);
+
+ goto out;
+ }
+
+ g_debug ("NSS database sucessfully loaded");
+ return TRUE;
+
+out:
+ g_debug ("NSS database couldn't be sucessfully loaded");
+ return FALSE;
+}
+
+static GList *
+get_available_modules (GdmSmartcardManager *manager)
+{
+ SECMODModuleList *module_list, *tmp;
+ GList *modules;
+
+ g_debug ("Getting list of suitable modules");
+
+ module_list = SECMOD_GetDefaultModuleList ();
+ modules = NULL;
+ for (tmp = module_list; tmp != NULL; tmp = tmp->next) {
+ if (!SECMOD_HasRemovableSlots (tmp->module) ||
+ !tmp->module->loaded)
+ continue;
+
+ g_debug ("Using module '%s'", tmp->module->commonName);
+
+ modules = g_list_prepend (modules,
+ SECMOD_ReferenceModule (tmp->module));
+ }
+
+ return modules;
+}
+
+static gboolean
+load_driver (GdmSmartcardManager *manager,
+ char *module_path,
+ GError **error)
+{
+ GList *modules;
+ char *module_spec;
+ gboolean module_explicitly_specified;
+
+ g_debug ("attempting to load driver...");
+
+ modules = NULL;
+ module_explicitly_specified = module_path != NULL;
+ if (module_explicitly_specified) {
+ SECMODModule *module;
+
+ module_spec = g_strdup_printf ("library=\"%s\"", module_path);
+ g_debug ("loading smartcard driver using spec '%s'",
+ module_spec);
+
+ module = SECMOD_LoadUserModule (module_spec,
+ NULL /* parent */,
+ FALSE /* recurse */);
+ g_free (module_spec);
+ module_spec = NULL;
+
+ if (!SECMOD_HasRemovableSlots (module) ||
+ !module->loaded) {
+ modules = g_list_prepend (modules, module);
+ } else {
+ g_debug ("fallback module found but not %s",
+ SECMOD_HasRemovableSlots (module)?
+ "removable" : "loaded");
+ SECMOD_DestroyModule (module);
+ }
+
+ } else {
+ SECMODListLock *lock;
+
+ lock = SECMOD_GetDefaultModuleListLock ();
+
+ if (lock != NULL) {
+ SECMOD_GetReadLock (lock);
+ modules = get_available_modules (manager);
+ SECMOD_ReleaseReadLock (lock);
+ }
+
+ /* fallback to compiled in driver path
+ */
+ if (modules == NULL) {
+ SECMODModule *module;
+ module_path = GDM_SMARTCARD_MANAGER_DRIVER;
+ module_spec = g_strdup_printf ("library=\"%s\"", module_path);
+ g_debug ("loading smartcard driver using spec '%s'",
+ module_spec);
+
+ module = SECMOD_LoadUserModule (module_spec,
+ NULL /* parent */,
+ FALSE /* recurse */);
+ g_free (module_spec);
+ module_spec = NULL;
+
+ if (!SECMOD_HasRemovableSlots (module) ||
+ !module->loaded) {
+ modules = g_list_prepend (modules, module);
+ } else {
+ g_debug ("fallback module found but not loaded");
+ SECMOD_DestroyModule (module);
+ }
+ }
+
+ }
+
+ if (!module_explicitly_specified && modules == NULL) {
+ g_set_error (error,
+ GDM_SMARTCARD_MANAGER_ERROR,
+ GDM_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER,
+ _("no suitable smartcard driver could be found"));
+ } else if (modules == NULL) {
+
+ gsize error_message_size;
+ char *error_message;
+
+ error_message_size = PR_GetErrorTextLength ();
+
+ if (error_message_size == 0) {
+ g_debug ("smartcard driver '%s' could not be loaded",
+ module_path);
+ g_set_error (error,
+ GDM_SMARTCARD_MANAGER_ERROR,
+ GDM_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER,
+ _("smartcard driver '%s' could not be "
+ "loaded"), module_path);
+ goto out;
+ }
+
+ error_message = g_slice_alloc0 (error_message_size);
+ PR_GetErrorText (error_message);
+
+ g_set_error (error,
+ GDM_SMARTCARD_MANAGER_ERROR,
+ GDM_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER,
+ "%s", error_message);
+
+ g_debug ("smartcard driver '%s' could not be loaded - %s",
+ module_path, error_message);
+ g_slice_free1 (error_message_size, error_message);
+ }
+
+ manager->priv->modules = modules;
+out:
+ return manager->priv->modules != NULL;
+}
+
+static void
+gdm_smartcard_manager_get_all_cards (GdmSmartcardManager *manager)
+{
+ GList *node;
+ int i;
+
+ node = manager->priv->workers;
+ while (node != NULL) {
+
+ GdmSmartcardManagerWorker *worker;
+
+ worker = (GdmSmartcardManagerWorker *) node->data;
+
+ for (i = 0; i < worker->module->slotCount; i++) {
+ GdmSmartcard *card;
+ CK_SLOT_ID slot_id;
+ gint slot_series;
+ char *card_name;
+
+ slot_id = PK11_GetSlotID (worker->module->slots[i]);
+ slot_series = PK11_GetSlotSeries (worker->module->slots[i]);
+
+ card = _gdm_smartcard_new (worker->module,
+ slot_id, slot_series);
+
+ card_name = gdm_smartcard_get_name (card);
+
+ g_hash_table_replace (manager->priv->smartcards,
+ card_name, card);
+ }
+ node = node->next;
+ }
+}
+
+static GdmSmartcardManagerWorker *
+start_worker (GdmSmartcardManager *manager,
+ SECMODModule *module,
+ GError **error)
+{
+ GIOChannel *io_channel;
+ GSource *source;
+ GIOFlags channel_flags;
+ GdmSmartcardManagerWorker *worker;
+
+ worker = gdm_smartcard_manager_create_worker (manager, module);
+
+ if (worker == NULL) {
+ g_set_error (error,
+ GDM_SMARTCARD_MANAGER_ERROR,
+ GDM_SMARTCARD_MANAGER_ERROR_WATCHING_FOR_EVENTS,
+ _("could not watch for incoming card events - %s"),
+ g_strerror (errno));
+
+ goto out;
+ }
+
+ io_channel = g_io_channel_unix_new (worker->manager_fd);
+
+ channel_flags = g_io_channel_get_flags (io_channel);
+
+ source = g_io_create_watch (io_channel, G_IO_IN | G_IO_HUP);
+ g_io_channel_unref (io_channel);
+ io_channel = NULL;
+
+ worker->event_source = source;
+
+ g_source_set_callback (worker->event_source,
+ (GSourceFunc) (GIOFunc)
+ gdm_smartcard_manager_check_for_and_process_events,
+ worker,
+ (GDestroyNotify)
+ gdm_smartcard_manager_event_processing_stopped_handler);
+ g_source_attach (worker->event_source, NULL);
+ g_source_unref (worker->event_source);
+out:
+ return worker;
+}
+
+static void
+start_workers (GdmSmartcardManager *manager)
+{
+ GList *node;
+
+ node = manager->priv->modules;
+ while (node != NULL) {
+ SECMODModule *module;
+ GdmSmartcardManagerWorker *worker;
+ GError *error;
+
+ module = (SECMODModule *) node->data;
+
+ error = NULL;
+ worker = start_worker (manager, module, &error);
+ if (worker == NULL) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ } else {
+ manager->priv->workers = g_list_prepend (manager->priv->workers,
+ worker);
+ }
+ node = node->next;
+ }
+}
+
+gboolean
+gdm_smartcard_manager_start (GdmSmartcardManager *manager,
+ GError **error)
+{
+ GError *nss_error;
+
+ if (manager->priv->state == GDM_SMARTCARD_MANAGER_STATE_STARTED) {
+ g_debug ("smartcard manager already started");
+ return TRUE;
+ }
+
+ manager->priv->state = GDM_SMARTCARD_MANAGER_STATE_STARTING;
+
+ nss_error = NULL;
+ if (!manager->priv->nss_is_loaded && !sc_load_nss (&nss_error)) {
+ g_propagate_error (error, nss_error);
+ goto out;
+ }
+ manager->priv->nss_is_loaded = TRUE;
+
+ if (manager->priv->modules == NULL) {
+ if (!load_driver (manager, manager->priv->module_path, &nss_error)) {
+ g_propagate_error (error, nss_error);
+ goto out;
+ }
+ }
+
+ start_workers (manager);
+
+ /* populate the hash with cards that are already inserted
+ */
+ gdm_smartcard_manager_get_all_cards (manager);
+
+ manager->priv->state = GDM_SMARTCARD_MANAGER_STATE_STARTED;
+
+out:
+ /* don't leave it in a half started state
+ */
+ if (manager->priv->state != GDM_SMARTCARD_MANAGER_STATE_STARTED) {
+ g_debug ("smartcard manager could not be completely started");
+ gdm_smartcard_manager_stop (manager);
+ } else {
+ g_debug ("smartcard manager started");
+ }
+
+ return manager->priv->state == GDM_SMARTCARD_MANAGER_STATE_STARTED;
+}
+
+static gboolean
+gdm_smartcard_manager_stop_now (GdmSmartcardManager *manager)
+{
+ if (manager->priv->state == GDM_SMARTCARD_MANAGER_STATE_STOPPED) {
+ return FALSE;
+ }
+
+ gdm_smartcard_manager_stop_watching_for_events (manager);
+
+ return FALSE;
+}
+
+static void
+gdm_smartcard_manager_queue_stop (GdmSmartcardManager *manager)
+{
+
+ manager->priv->state = GDM_SMARTCARD_MANAGER_STATE_STOPPING;
+
+ g_idle_add ((GSourceFunc) gdm_smartcard_manager_stop_now, manager);
+}
+
+void
+gdm_smartcard_manager_stop (GdmSmartcardManager *manager)
+{
+ if (manager->priv->state == GDM_SMARTCARD_MANAGER_STATE_STOPPED) {
+ return;
+ }
+
+ if (manager->priv->is_unstoppable) {
+ gdm_smartcard_manager_queue_stop (manager);
+ return;
+ }
+
+ gdm_smartcard_manager_stop_now (manager);
+}
+
+static void
+gdm_smartcard_manager_check_for_login_card (CK_SLOT_ID slot_id,
+ GdmSmartcard *card,
+ gboolean *is_inserted)
+{
+ g_assert (is_inserted != NULL);
+
+ if (gdm_smartcard_is_login_card (card)) {
+ *is_inserted = TRUE;
+ }
+
+}
+
+gboolean
+gdm_smartcard_manager_login_card_is_inserted (GdmSmartcardManager *manager)
+
+{
+ gboolean is_inserted;
+
+ is_inserted = FALSE;
+ g_hash_table_foreach (manager->priv->smartcards,
+ (GHFunc)
+ gdm_smartcard_manager_check_for_login_card,
+ &is_inserted);
+ return is_inserted;
+}
+
+static GdmSmartcardManagerWorker *
+gdm_smartcard_manager_worker_new (GdmSmartcardManager *manager,
+ gint worker_fd,
+ gint manager_fd,
+ SECMODModule *module)
+{
+ GdmSmartcardManagerWorker *worker;
+
+ worker = g_slice_new0 (GdmSmartcardManagerWorker);
+ worker->manager = manager;
+ worker->fd = worker_fd;
+ worker->manager_fd = manager_fd;
+ worker->module = module;
+
+ worker->smartcards =
+ g_hash_table_new_full ((GHashFunc) sc_slot_id_hash,
+ (GEqualFunc) sc_slot_id_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_object_unref);
+
+ return worker;
+}
+
+static void
+gdm_smartcard_manager_worker_free (GdmSmartcardManagerWorker *worker)
+{
+ if (worker->smartcards != NULL) {
+ g_hash_table_destroy (worker->smartcards);
+ worker->smartcards = NULL;
+ }
+
+ g_slice_free (GdmSmartcardManagerWorker, worker);
+}
+
+static gboolean
+sc_read_bytes (gint fd, gpointer bytes, gsize num_bytes)
+{
+ size_t bytes_left;
+ size_t total_bytes_read;
+ ssize_t bytes_read;
+
+ bytes_left = (size_t) num_bytes;
+ total_bytes_read = 0;
+
+ do {
+ bytes_read = read (fd, (gchar *) bytes + total_bytes_read, bytes_left);
+ g_assert (bytes_read <= (ssize_t) bytes_left);
+
+ if (bytes_read <= 0) {
+ if ((bytes_read < 0) && (errno == EINTR || errno == EAGAIN)) {
+ continue;
+ }
+
+ bytes_left = 0;
+ } else {
+ bytes_left -= bytes_read;
+ total_bytes_read += bytes_read;
+ }
+ } while (bytes_left > 0);
+
+ if (total_bytes_read < (size_t) num_bytes) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+sc_write_bytes (gint fd, gconstpointer bytes, gsize num_bytes)
+{
+ size_t bytes_left;
+ size_t total_bytes_written;
+ ssize_t bytes_written;
+
+ bytes_left = (size_t) num_bytes;
+ total_bytes_written = 0;
+
+ do {
+ bytes_written = write (fd, (gchar *) bytes + total_bytes_written, bytes_left);
+ g_assert (bytes_written <= (ssize_t) bytes_left);
+
+ if (bytes_written <= 0) {
+ if ((bytes_written < 0) && (errno == EINTR || errno == EAGAIN)) {
+ continue;
+ }
+
+ bytes_left = 0;
+ } else {
+ bytes_left -= bytes_written;
+ total_bytes_written += bytes_written;
+ }
+ } while (bytes_left > 0);
+
+ if (total_bytes_written < (size_t) num_bytes) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static GdmSmartcard *
+sc_read_smartcard (gint fd,
+ SECMODModule *module)
+{
+ GdmSmartcard *card;
+ char *card_name;
+ gsize card_name_size;
+
+ card_name_size = 0;
+ if (!sc_read_bytes (fd, &card_name_size, sizeof (card_name_size))) {
+ return NULL;
+ }
+
+ card_name = g_slice_alloc0 (card_name_size);
+ if (!sc_read_bytes (fd, card_name, card_name_size)) {
+ g_slice_free1 (card_name_size, card_name);
+ return NULL;
+ }
+ card = _gdm_smartcard_new_from_name (module, card_name);
+ g_slice_free1 (card_name_size, card_name);
+
+ return card;
+}
+
+static gboolean
+sc_write_smartcard (gint fd,
+ GdmSmartcard *card)
+{
+ gsize card_name_size;
+ char *card_name;
+
+ card_name = gdm_smartcard_get_name (card);
+ card_name_size = strlen (card_name) + 1;
+
+ if (!sc_write_bytes (fd, &card_name_size, sizeof (card_name_size))) {
+ g_free (card_name);
+ return FALSE;
+ }
+
+ if (!sc_write_bytes (fd, card_name, card_name_size)) {
+ g_free (card_name);
+ return FALSE;
+ }
+ g_free (card_name);
+
+ return TRUE;
+}
+
+static gboolean
+gdm_smartcard_manager_worker_emit_smartcard_removed (GdmSmartcardManagerWorker *worker,
+ GdmSmartcard *card,
+ GError **error)
+{
+ g_debug ("card '%s' removed!", gdm_smartcard_get_name (card));
+
+ if (!sc_write_bytes (worker->fd, "R", 1)) {
+ goto error_out;
+ }
+
+ if (!sc_write_smartcard (worker->fd, card)) {
+ goto error_out;
+ }
+
+ return TRUE;
+
+error_out:
+ g_set_error (error, GDM_SMARTCARD_MANAGER_ERROR,
+ GDM_SMARTCARD_MANAGER_ERROR_REPORTING_EVENTS,
+ "%s", g_strerror (errno));
+ return FALSE;
+}
+
+static gboolean
+gdm_smartcard_manager_worker_emit_smartcard_inserted (GdmSmartcardManagerWorker *worker,
+ GdmSmartcard *card,
+ GError **error)
+{
+ GError *write_error;
+
+ write_error = NULL;
+ g_debug ("card '%s' inserted!", gdm_smartcard_get_name (card));
+ if (!sc_write_bytes (worker->fd, "I", 1)) {
+ goto error_out;
+ }
+
+ if (!sc_write_smartcard (worker->fd, card)) {
+ goto error_out;
+ }
+
+ return TRUE;
+
+error_out:
+ g_set_error (error, GDM_SMARTCARD_MANAGER_ERROR,
+ GDM_SMARTCARD_MANAGER_ERROR_REPORTING_EVENTS,
+ "%s", g_strerror (errno));
+ return FALSE;
+}
+
+static gboolean
+gdm_smartcard_manager_worker_watch_for_and_process_event (GdmSmartcardManagerWorker *worker,
+ GError **error)
+{
+ PK11SlotInfo *slot;
+ CK_SLOT_ID slot_id, *key;
+ gint slot_series, card_slot_series;
+ GdmSmartcard *card;
+ GError *processing_error;
+
+ g_debug ("waiting for card event");
+
+ /* FIXME: we return FALSE quite a bit in this function without cleaning up
+ * resources. By returning FALSE we're going to ultimately exit anyway, but
+ * we should still be tidier about things.
+ */
+
+ slot = SECMOD_WaitForAnyTokenEvent (worker->module, 0, PR_SecondsToInterval (1));
+
+ processing_error = NULL;
+
+ if (slot == NULL) {
+ int error_code;
+
+ error_code = PORT_GetError ();
+ if ((error_code == 0) || (error_code == SEC_ERROR_NO_EVENT)) {
+ g_debug ("spurrious event occurred");
+ return TRUE;
+ }
+
+ /* FIXME: is there a function to convert from a PORT error
+ * code to a translated string?
+ */
+ g_set_error (error, GDM_SMARTCARD_MANAGER_ERROR,
+ GDM_SMARTCARD_MANAGER_ERROR_WITH_NSS,
+ _("encountered unexpected error while "
+ "waiting for smartcard events"));
+ return FALSE;
+ }
+
+ /* the slot id and series together uniquely identify a card.
+ * You can never have two cards with the same slot id at the
+ * same time, however (I think), so we can key off of it.
+ */
+ slot_id = PK11_GetSlotID (slot);
+ slot_series = PK11_GetSlotSeries (slot);
+
+ /* First check to see if there is a card that we're currently
+ * tracking in the slot.
+ */
+ key = g_new (CK_SLOT_ID, 1);
+ *key = slot_id;
+ card = g_hash_table_lookup (worker->smartcards, key);
+
+ if (card != NULL) {
+ card_slot_series = gdm_smartcard_get_slot_series (card);
+ } else {
+ card_slot_series = -1;
+ }
+
+ if (PK11_IsPresent (slot)) {
+ /* Now, check to see if their is a new card in the slot.
+ * If there was a different card in the slot now than
+ * there was before, then we need to emit a removed signal
+ * for the old card (we don't want unpaired insertion events).
+ */
+ if ((card != NULL) &&
+ card_slot_series != slot_series) {
+ if (!gdm_smartcard_manager_worker_emit_smartcard_removed (worker, card, &processing_error)) {
+ g_propagate_error (error, processing_error);
+ return FALSE;
+ }
+ }
+
+ card = _gdm_smartcard_new (worker->module,
+ slot_id, slot_series);
+
+ g_hash_table_replace (worker->smartcards,
+ key, card);
+ key = NULL;
+
+ if (!gdm_smartcard_manager_worker_emit_smartcard_inserted (worker, card, &processing_error)) {
+ g_propagate_error (error, processing_error);
+ return FALSE;
+ }
+ } else {
+ /* if we aren't tracking the card, just discard the event.
+ * We don't want unpaired remove events. Note on startup
+ * NSS will generate an "insertion" event if a card is
+ * already inserted in the slot.
+ */
+ if ((card != NULL)) {
+ /* FIXME: i'm not sure about this code. Maybe we
+ * shouldn't do this at all, or maybe we should do it
+ * n times (where n = slot_series - card_slot_series + 1)
+ *
+ * Right now, i'm just doing it once.
+ */
+ if ((slot_series - card_slot_series) > 1) {
+
+ if (!gdm_smartcard_manager_worker_emit_smartcard_removed (worker, card, &processing_error)) {
+ g_propagate_error (error, processing_error);
+ return FALSE;
+ }
+ g_hash_table_remove (worker->smartcards, key);
+
+ card = _gdm_smartcard_new (worker->module,
+ slot_id, slot_series);
+ g_hash_table_replace (worker->smartcards,
+ key, card);
+ key = NULL;
+ if (!gdm_smartcard_manager_worker_emit_smartcard_inserted (worker, card, &processing_error)) {
+ g_propagate_error (error, processing_error);
+ return FALSE;
+ }
+ }
+
+ if (!gdm_smartcard_manager_worker_emit_smartcard_removed (worker, card, &processing_error)) {
+ g_propagate_error (error, processing_error);
+ return FALSE;
+ }
+
+ g_hash_table_remove (worker->smartcards, key);
+ card = NULL;
+ } else {
+ g_debug ("got spurious remove event");
+ }
+ }
+
+ g_free (key);
+ PK11_FreeSlot (slot);
+
+ return TRUE;
+}
+
+static void
+gdm_smartcard_manager_worker_run (GdmSmartcardManagerWorker *worker)
+{
+ GError *error;
+ gboolean should_continue;
+
+ do
+ {
+ error = NULL;
+ should_continue = gdm_smartcard_manager_worker_watch_for_and_process_event (worker, &error);
+ }
+ while (should_continue);
+
+ if (error != NULL) {
+ g_debug ("could not process card event - %s", error->message);
+ g_error_free (error);
+ }
+
+out:
+ gdm_smartcard_manager_worker_free (worker);
+}
+
+static GdmSmartcardManagerWorker *
+gdm_smartcard_manager_create_worker (GdmSmartcardManager *manager,
+ SECMODModule *module)
+{
+ GdmSmartcardManagerWorker *worker;
+ gint write_fd, read_fd;
+
+ write_fd = -1;
+ read_fd = -1;
+ if (!gdm_open_pipe (&write_fd, &read_fd)) {
+ return FALSE;
+ }
+
+ worker = gdm_smartcard_manager_worker_new (manager,
+ write_fd,
+ read_fd,
+ module);
+
+ worker->thread = g_thread_create ((GThreadFunc)
+ gdm_smartcard_manager_worker_run,
+ worker, FALSE, NULL);
+
+ if (worker->thread == NULL) {
+ gdm_smartcard_manager_worker_free (worker);
+ return NULL;
+ }
+
+ return worker;
+}
+
+#ifdef GDM_SMARTCARD_MANAGER_ENABLE_TEST
+#include <glib.h>
+
+static GMainLoop *event_loop;
+static gboolean should_exit_on_next_remove = FALSE;
+
+static gboolean
+on_timeout (GdmSmartcardManager *manager)
+{
+ GError *error;
+ g_print ("Re-enabling manager.\n");
+
+ if (!gdm_smartcard_manager_start (manager, &error)) {
+ g_warning ("could not start smartcard manager - %s",
+ error->message);
+ g_error_free (error);
+ return 1;
+ }
+ g_print ("Please re-insert smartcard\n");
+
+ should_exit_on_next_remove = TRUE;
+
+ return FALSE;
+}
+
+static void
+on_device_inserted (GdmSmartcardManager *manager,
+ GdmSmartcard *card)
+{
+ g_print ("smartcard inserted!\n");
+ g_print ("Please remove it.\n");
+}
+
+static void
+on_device_removed (GdmSmartcardManager *manager,
+ GdmSmartcard *card)
+{
+ g_print ("smartcard removed!\n");
+
+ if (should_exit_on_next_remove) {
+ g_main_loop_quit (event_loop);
+ } else {
+ g_print ("disabling manager for 2 seconds\n");
+ gdm_smartcard_manager_stop (manager);
+ g_timeout_add (2000, (GSourceFunc) on_timeout, manager);
+ }
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ GdmSmartcardManager *manager;
+ GError *error;
+
+ g_log_set_always_fatal (G_LOG_LEVEL_ERROR
+ | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING);
+
+ g_type_init ();
+
+ g_message ("creating instance of 'smartcard manager' object...");
+ manager = gdm_smartcard_manager_new (NULL);
+ g_message ("'smartcard manager' object created successfully");
+
+ g_signal_connect (manager, "smartcard-inserted",
+ G_CALLBACK (on_device_inserted), NULL);
+
+ g_signal_connect (manager, "smartcard-removed",
+ G_CALLBACK (on_device_removed), NULL);
+
+ g_message ("starting listener...");
+
+ error = NULL;
+ if (!gdm_smartcard_manager_start (manager, &error)) {
+ g_warning ("could not start smartcard manager - %s",
+ error->message);
+ g_error_free (error);
+ return 1;
+ }
+
+ event_loop = g_main_loop_new (NULL, FALSE);
+ g_main_loop_run (event_loop);
+ g_main_loop_unref (event_loop);
+ event_loop = NULL;
+
+ g_message ("destroying previously created 'smartcard manager' object...");
+ g_object_unref (manager);
+ manager = NULL;
+ g_message ("'smartcard manager' object destroyed successfully");
+
+ return 0;
+}
+#endif
diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-manager.h b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-manager.h
new file mode 100644
index 0000000..932a703
--- /dev/null
+++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-manager.h
@@ -0,0 +1,86 @@
+/* gdm-smartcard-manager.h - object for monitoring smartcard insertion and
+ * removal events
+ *
+ * Copyright (C) 2006, 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ * Written by: Ray Strode
+ */
+#ifndef GDM_SMARTCARD_MANAGER_H
+#define GDM_SMARTCARD_MANAGER_H
+
+#define GDM_SMARTCARD_ENABLE_INTERNAL_API
+#include "gdm-smartcard.h"
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+#define GDM_TYPE_SMARTCARD_MANAGER (gdm_smartcard_manager_get_type ())
+#define GDM_SMARTCARD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDM_TYPE_SMARTCARD_MANAGER, GdmSmartcardManager))
+#define GDM_SMARTCARD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDM_TYPE_SMARTCARD_MANAGER, GdmSmartcardManagerClass))
+#define GDM_IS_SMARTCARD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SC_TYPE_SMARTCARD_MANAGER))
+#define GDM_IS_SMARTCARD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SC_TYPE_SMARTCARD_MANAGER))
+#define GDM_SMARTCARD_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GDM_TYPE_SMARTCARD_MANAGER, GdmSmartcardManagerClass))
+#define GDM_SMARTCARD_MANAGER_ERROR (gdm_smartcard_manager_error_quark ())
+typedef struct _GdmSmartcardManager GdmSmartcardManager;
+typedef struct _GdmSmartcardManagerClass GdmSmartcardManagerClass;
+typedef struct _GdmSmartcardManagerPrivate GdmSmartcardManagerPrivate;
+typedef enum _GdmSmartcardManagerError GdmSmartcardManagerError;
+
+struct _GdmSmartcardManager {
+ GObject parent;
+
+ /*< private > */
+ GdmSmartcardManagerPrivate *priv;
+};
+
+struct _GdmSmartcardManagerClass {
+ GObjectClass parent_class;
+
+ /* Signals */
+ void (*smartcard_inserted) (GdmSmartcardManager *manager,
+ GdmSmartcard *token);
+ void (*smartcard_removed) (GdmSmartcardManager *manager,
+ GdmSmartcard *token);
+ void (*error) (GdmSmartcardManager *manager,
+ GError *error);
+};
+
+enum _GdmSmartcardManagerError {
+ GDM_SMARTCARD_MANAGER_ERROR_GENERIC = 0,
+ GDM_SMARTCARD_MANAGER_ERROR_WITH_NSS,
+ GDM_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER,
+ GDM_SMARTCARD_MANAGER_ERROR_WATCHING_FOR_EVENTS,
+ GDM_SMARTCARD_MANAGER_ERROR_REPORTING_EVENTS
+};
+
+GType gdm_smartcard_manager_get_type (void) G_GNUC_CONST;
+GQuark gdm_smartcard_manager_error_quark (void) G_GNUC_CONST;
+
+GdmSmartcardManager *gdm_smartcard_manager_new (const char *module);
+
+gboolean gdm_smartcard_manager_start (GdmSmartcardManager *manager,
+ GError **error);
+
+void gdm_smartcard_manager_stop (GdmSmartcardManager *manager);
+
+char *gdm_smartcard_manager_get_module_path (GdmSmartcardManager *manager);
+gboolean gdm_smartcard_manager_login_token_is_inserted (GdmSmartcardManager *manager);
+
+G_END_DECLS
+#endif /* GDM_SMARTCARD_MANAGER_H */
diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-worker.c b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-worker.c
new file mode 100644
index 0000000..9af1346
--- /dev/null
+++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-worker.c
@@ -0,0 +1,186 @@
+#include "config.h"
+
+#include <fcntl.h>
+#include <locale.h>
+#include <sys/prctl.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <glib.h>
+
+#include "gdm-smartcard-manager.h"
+#include "gdm-smartcard.h"
+
+#ifndef GDM_SMARTCARDS_CONF
+#define GDM_SMARTCARDS_CONF GDMCONFDIR "/smartcards.conf"
+#endif
+
+#ifndef GDM_SMARTCARDS_GROUP
+#define GDM_SMARTCARDS_GROUP "Smartcards"
+#endif
+
+#ifndef GDM_SMARTCARDS_KEY_ENABLED
+#define GDM_SMARTCARDS_KEY_ENABLED "Enabled"
+#endif
+
+#ifndef GDM_SMARTCARDS_KEY_DRIVER
+#define GDM_SMARTCARDS_KEY_DRIVER "Driver"
+#endif
+
+static GMainLoop *event_loop;
+static GdmSmartcardManager *manager;
+static int signal_pipe_fds[2] = { -1, -1 };
+
+static void
+on_smartcard_event (const char *event_string)
+{
+ g_debug ("smartcard event '%s' happened", event_string);
+ g_print ("%s", event_string);
+ fflush (stdout);
+}
+
+static void
+watch_for_smartcards (void)
+{
+ GError *error;
+ char *driver;
+ GKeyFile *cfg;
+
+ cfg = g_key_file_new ();
+
+ error = NULL;
+ driver = NULL;
+ if (g_key_file_load_from_file (cfg, GDM_SMARTCARDS_CONF, G_KEY_FILE_NONE, &error)) {
+ if (!g_key_file_get_boolean (cfg, GDM_SMARTCARDS_GROUP, GDM_SMARTCARDS_KEY_ENABLED, &error)) {
+ g_debug ("smartcard support is not enabled");
+ goto out;
+ }
+
+ driver = g_key_file_get_string (cfg, GDM_SMARTCARDS_GROUP, GDM_SMARTCARDS_KEY_DRIVER, NULL);
+ g_debug ("smartcards driver is set to '%s'",
+ driver == NULL || driver[0] == '\0'? "<automatic>" : driver);
+ }
+
+ g_debug ("watching for smartcard insertion and removal events");
+ manager = gdm_smartcard_manager_new (driver);
+ g_free (driver);
+
+ g_signal_connect_swapped (manager,
+ "smartcard-inserted",
+ G_CALLBACK (on_smartcard_event),
+ "I");
+
+ g_signal_connect_swapped (manager,
+ "smartcard-removed",
+ G_CALLBACK (on_smartcard_event),
+ "R");
+
+ error = NULL;
+ if (!gdm_smartcard_manager_start (manager, &error)) {
+ g_object_unref (manager);
+ manager = NULL;
+
+ if (error != NULL) {
+ g_debug ("%s", error->message);
+ g_error_free (error);
+ } else {
+ g_debug ("could not start smartcard manager");
+
+ }
+ goto out;
+ }
+out:
+ g_key_file_free (cfg);
+}
+
+static void
+stop_watching_for_smartcards (void)
+{
+ if (manager != NULL) {
+ gdm_smartcard_manager_stop (manager);
+ g_object_unref (manager);
+ manager = NULL;
+ }
+}
+
+static void
+on_alrm_signal (int signal_number)
+{
+ raise (SIGKILL);
+}
+
+static void
+on_term_signal (int signal_number)
+{
+ close (signal_pipe_fds[1]);
+ signal_pipe_fds[1] = -1;
+
+ /* Give us 10 seconds to clean up orderly.
+ * If that fails, then the smartcard stack
+ * is hung up and we need to die hard
+ */
+ alarm (10);
+ signal (SIGALRM, on_alrm_signal);
+}
+
+static gboolean
+after_term_signal (GIOChannel *io_channel,
+ GIOCondition condition,
+ gpointer data)
+{
+ g_main_loop_quit (event_loop);
+ return FALSE;
+}
+
+static void
+on_debug_message (const char *log_domain,
+ GLogLevelFlags log_level,
+ const char *message,
+ gpointer user_data)
+{
+ g_printerr ("*** DEBUG: %s\n", message);
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ GIOChannel *io_channel;
+
+ setlocale (LC_ALL, "");
+
+ g_type_init ();
+
+ g_log_set_handler (NULL, G_LOG_LEVEL_DEBUG, on_debug_message, NULL);
+
+ event_loop = g_main_loop_new (NULL, FALSE);
+
+ watch_for_smartcards ();
+
+ if (pipe (signal_pipe_fds) != 0) {
+ return 1;
+ }
+ fcntl (signal_pipe_fds[0], F_SETFD, FD_CLOEXEC);
+ fcntl (signal_pipe_fds[1], F_SETFD, FD_CLOEXEC);
+
+ io_channel = g_io_channel_unix_new (signal_pipe_fds[0]);
+ g_io_channel_set_flags (io_channel, G_IO_FLAG_NONBLOCK, NULL);
+ g_io_channel_set_encoding (io_channel, NULL, NULL);
+ g_io_channel_set_buffered (io_channel, FALSE);
+ g_io_add_watch (io_channel, G_IO_HUP, after_term_signal, NULL);
+ g_io_channel_set_close_on_unref (io_channel, TRUE);
+ g_io_channel_unref (io_channel);
+
+ signal (SIGTERM, on_term_signal);
+ signal (SIGPIPE, on_term_signal);
+
+#ifdef HAVE_SYS_PRCTL_H
+ prctl (PR_SET_PDEATHSIG, SIGTERM);
+#endif
+
+ g_main_loop_run (event_loop);
+
+ stop_watching_for_smartcards ();
+
+ return 0;
+}
diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard.c b/gui/simple-greeter/plugins/smartcard/gdm-smartcard.c
new file mode 100644
index 0000000..1af3638
--- /dev/null
+++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard.c
@@ -0,0 +1,554 @@
+/* gdm-smartcard.c - smartcard object
+ *
+ * Copyright (C) 2006 Ray Strode <rstrode@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ */
+#define GDM_SMARTCARD_ENABLE_INTERNAL_API
+#include "gdm-smartcard.h"
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <cert.h>
+#include <nss.h>
+#include <pk11func.h>
+#include <prerror.h>
+#include <secmod.h>
+#include <secerr.h>
+
+struct _GdmSmartcardPrivate {
+ SECMODModule *module;
+ GdmSmartcardState state;
+
+ CK_SLOT_ID slot_id;
+ int slot_series;
+
+ PK11SlotInfo *slot;
+ char *name;
+
+ CERTCertificate *signing_certificate;
+ CERTCertificate *encryption_certificate;
+};
+
+static void gdm_smartcard_finalize (GObject *object);
+static void gdm_smartcard_class_install_signals (GdmSmartcardClass *card_class);
+static void gdm_smartcard_class_install_properties (GdmSmartcardClass *card_class);
+static void gdm_smartcard_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gdm_smartcard_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void gdm_smartcard_set_name (GdmSmartcard *card, const char *name);
+static void gdm_smartcard_set_slot_id (GdmSmartcard *card,
+ int slot_id);
+static void gdm_smartcard_set_slot_series (GdmSmartcard *card,
+ int slot_series);
+static void gdm_smartcard_set_module (GdmSmartcard *card,
+ SECMODModule *module);
+
+static PK11SlotInfo *gdm_smartcard_find_slot_from_id (GdmSmartcard *card,
+ int slot_id);
+
+static PK11SlotInfo *gdm_smartcard_find_slot_from_card_name (GdmSmartcard *card,
+ const char *card_name);
+static gboolean gdm_smartcard_fetch_certificates (GdmSmartcard *card);
+
+#ifndef GDM_SMARTCARD_DEFAULT_SLOT_ID
+#define GDM_SMARTCARD_DEFAULT_SLOT_ID ((gulong) -1)
+#endif
+
+#ifndef GDM_SMARTCARD_DEFAULT_SLOT_SERIES
+#define GDM_SMARTCARD_DEFAULT_SLOT_SERIES -1
+#endif
+
+enum {
+ PROP_0 = 0,
+ PROP_NAME,
+ PROP_SLOT_ID,
+ PROP_SLOT_SERIES,
+ PROP_MODULE,
+ NUMBER_OF_PROPERTIES
+};
+
+enum {
+ INSERTED,
+ REMOVED,
+ NUMBER_OF_SIGNALS
+};
+
+static guint gdm_smartcard_signals[NUMBER_OF_SIGNALS];
+
+G_DEFINE_TYPE (GdmSmartcard, gdm_smartcard, G_TYPE_OBJECT);
+
+static void
+gdm_smartcard_class_init (GdmSmartcardClass *card_class)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = G_OBJECT_CLASS (card_class);
+
+ gobject_class->finalize = gdm_smartcard_finalize;
+
+ gdm_smartcard_class_install_signals (card_class);
+ gdm_smartcard_class_install_properties (card_class);
+
+ g_type_class_add_private (card_class,
+ sizeof (GdmSmartcardPrivate));
+}
+
+static void
+gdm_smartcard_class_install_signals (GdmSmartcardClass *card_class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (card_class);
+
+ gdm_smartcard_signals[INSERTED] =
+ g_signal_new ("inserted",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdmSmartcardClass,
+ inserted),
+ NULL, NULL, g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ gdm_smartcard_signals[REMOVED] =
+ g_signal_new ("removed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdmSmartcardClass,
+ removed),
+ NULL, NULL, g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+gdm_smartcard_class_install_properties (GdmSmartcardClass *card_class)
+{
+ GObjectClass *object_class;
+ GParamSpec *param_spec;
+
+ object_class = G_OBJECT_CLASS (card_class);
+ object_class->set_property = gdm_smartcard_set_property;
+ object_class->get_property = gdm_smartcard_get_property;
+
+ param_spec = g_param_spec_ulong ("slot-id", _("Slot ID"),
+ _("The slot the card is in"),
+ 1, G_MAXULONG,
+ GDM_SMARTCARD_DEFAULT_SLOT_ID,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property (object_class, PROP_SLOT_ID, param_spec);
+
+ param_spec = g_param_spec_int ("slot-series", _("Slot Series"),
+ _("per-slot card identifier"),
+ -1, G_MAXINT,
+ GDM_SMARTCARD_DEFAULT_SLOT_SERIES,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property (object_class, PROP_SLOT_SERIES, param_spec);
+
+ param_spec = g_param_spec_string ("name", _("name"),
+ _("name"), NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property (object_class, PROP_NAME, param_spec);
+
+ param_spec = g_param_spec_pointer ("module", _("Module"),
+ _("smartcard driver"),
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property (object_class, PROP_MODULE, param_spec);
+}
+
+static void
+gdm_smartcard_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdmSmartcard *card = GDM_SMARTCARD (object);
+
+ switch (prop_id) {
+ case PROP_NAME:
+ gdm_smartcard_set_name (card, g_value_get_string (value));
+ break;
+
+ case PROP_SLOT_ID:
+ gdm_smartcard_set_slot_id (card,
+ g_value_get_ulong (value));
+ break;
+
+ case PROP_SLOT_SERIES:
+ gdm_smartcard_set_slot_series (card,
+ g_value_get_int (value));
+ break;
+
+ case PROP_MODULE:
+ gdm_smartcard_set_module (card,
+ (SECMODModule *)
+ g_value_get_pointer (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+CK_SLOT_ID
+gdm_smartcard_get_slot_id (GdmSmartcard *card)
+{
+ return card->priv->slot_id;
+}
+
+GdmSmartcardState
+gdm_smartcard_get_state (GdmSmartcard *card)
+{
+ return card->priv->state;
+}
+
+char *
+gdm_smartcard_get_name (GdmSmartcard *card)
+{
+ return g_strdup (card->priv->name);
+}
+
+gboolean
+gdm_smartcard_is_login_card (GdmSmartcard *card)
+{
+ const char *login_card_name;
+ login_card_name = g_getenv ("PKCS11_LOGIN_TOKEN_NAME");
+
+ if ((login_card_name == NULL) || (card->priv->name == NULL)) {
+ return FALSE;
+ }
+
+ if (strcmp (card->priv->name, login_card_name) == 0) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+gdm_smartcard_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdmSmartcard *card = GDM_SMARTCARD (object);
+
+ switch (prop_id) {
+ case PROP_NAME:
+ g_value_take_string (value,
+ gdm_smartcard_get_name (card));
+ break;
+
+ case PROP_SLOT_ID:
+ g_value_set_ulong (value,
+ (gulong) gdm_smartcard_get_slot_id (card));
+ break;
+
+ case PROP_SLOT_SERIES:
+ g_value_set_int (value,
+ gdm_smartcard_get_slot_series (card));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gdm_smartcard_set_name (GdmSmartcard *card,
+ const char *name)
+{
+ if (name == NULL) {
+ return;
+ }
+
+ if ((card->priv->name == NULL) ||
+ (strcmp (card->priv->name, name) != 0)) {
+ g_free (card->priv->name);
+ card->priv->name = g_strdup (name);
+
+ if (card->priv->slot == NULL) {
+ card->priv->slot = gdm_smartcard_find_slot_from_card_name (card,
+ card->priv->name);
+
+ if (card->priv->slot != NULL) {
+ int slot_id, slot_series;
+
+ slot_id = PK11_GetSlotID (card->priv->slot);
+ if (slot_id != card->priv->slot_id) {
+ gdm_smartcard_set_slot_id (card, slot_id);
+ }
+
+ slot_series = PK11_GetSlotSeries (card->priv->slot);
+ if (slot_series != card->priv->slot_series) {
+ gdm_smartcard_set_slot_series (card, slot_series);
+ }
+
+ _gdm_smartcard_set_state (card, GDM_SMARTCARD_STATE_INSERTED);
+ } else {
+ _gdm_smartcard_set_state (card, GDM_SMARTCARD_STATE_REMOVED);
+ }
+ }
+
+ g_object_notify (G_OBJECT (card), "name");
+ }
+}
+
+static void
+gdm_smartcard_set_slot_id (GdmSmartcard *card,
+ int slot_id)
+{
+ if (card->priv->slot_id != slot_id) {
+ card->priv->slot_id = slot_id;
+
+ if (card->priv->slot == NULL) {
+ card->priv->slot = gdm_smartcard_find_slot_from_id (card,
+ card->priv->slot_id);
+
+ if (card->priv->slot != NULL) {
+ const char *card_name;
+
+ card_name = PK11_GetTokenName (card->priv->slot);
+ if ((card->priv->name == NULL) ||
+ ((card_name != NULL) &&
+ (strcmp (card_name, card->priv->name) != 0))) {
+ gdm_smartcard_set_name (card, card_name);
+ }
+
+ _gdm_smartcard_set_state (card, GDM_SMARTCARD_STATE_INSERTED);
+ } else {
+ _gdm_smartcard_set_state (card, GDM_SMARTCARD_STATE_REMOVED);
+ }
+ }
+
+ g_object_notify (G_OBJECT (card), "slot-id");
+ }
+}
+
+static void
+gdm_smartcard_set_slot_series (GdmSmartcard *card,
+ int slot_series)
+{
+ if (card->priv->slot_series != slot_series) {
+ card->priv->slot_series = slot_series;
+ g_object_notify (G_OBJECT (card), "slot-series");
+ }
+}
+
+static void
+gdm_smartcard_set_module (GdmSmartcard *card,
+ SECMODModule *module)
+{
+ gboolean should_notify;
+
+ if (card->priv->module != module) {
+ should_notify = TRUE;
+ } else {
+ should_notify = FALSE;
+ }
+
+ if (card->priv->module != NULL) {
+ SECMOD_DestroyModule (card->priv->module);
+ card->priv->module = NULL;
+ }
+
+ if (module != NULL) {
+ card->priv->module = SECMOD_ReferenceModule (module);
+ }
+
+ if (should_notify) {
+ g_object_notify (G_OBJECT (card), "module");
+ }
+}
+
+int
+gdm_smartcard_get_slot_series (GdmSmartcard *card)
+{
+ return card->priv->slot_series;
+}
+
+static void
+gdm_smartcard_init (GdmSmartcard *card)
+{
+
+ g_debug ("initializing smartcard ");
+
+ card->priv = G_TYPE_INSTANCE_GET_PRIVATE (card,
+ GDM_TYPE_SMARTCARD,
+ GdmSmartcardPrivate);
+}
+
+static void gdm_smartcard_finalize (GObject *object)
+{
+ GdmSmartcard *card;
+ GObjectClass *gobject_class;
+
+ card = GDM_SMARTCARD (object);
+
+ g_free (card->priv->name);
+
+ gdm_smartcard_set_module (card, NULL);
+
+ gobject_class = G_OBJECT_CLASS (gdm_smartcard_parent_class);
+
+ gobject_class->finalize (object);
+}
+
+GQuark gdm_smartcard_error_quark (void)
+{
+ static GQuark error_quark = 0;
+
+ if (error_quark == 0) {
+ error_quark = g_quark_from_static_string ("gdm-smartcard-error-quark");
+ }
+
+ return error_quark;
+}
+
+GdmSmartcard *
+_gdm_smartcard_new (SECMODModule *module,
+ CK_SLOT_ID slot_id,
+ int slot_series)
+{
+ GdmSmartcard *card;
+
+ g_return_val_if_fail (module != NULL, NULL);
+ g_return_val_if_fail (slot_id >= 1, NULL);
+ g_return_val_if_fail (slot_series > 0, NULL);
+ g_return_val_if_fail (sizeof (gulong) == sizeof (slot_id), NULL);
+
+ card = GDM_SMARTCARD (g_object_new (GDM_TYPE_SMARTCARD,
+ "module", module,
+ "slot-id", (gulong) slot_id,
+ "slot-series", slot_series,
+ NULL));
+ return card;
+}
+
+GdmSmartcard *
+_gdm_smartcard_new_from_name (SECMODModule *module,
+ const char *name)
+{
+ GdmSmartcard *card;
+
+ g_return_val_if_fail (module != NULL, NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ card = GDM_SMARTCARD (g_object_new (GDM_TYPE_SMARTCARD,
+ "module", module,
+ "name", name,
+ NULL));
+ return card;
+}
+
+void
+_gdm_smartcard_set_state (GdmSmartcard *card,
+ GdmSmartcardState state)
+{
+ /* gdm_smartcard_fetch_certificates (card); */
+ if (card->priv->state != state) {
+ card->priv->state = state;
+
+ if (state == GDM_SMARTCARD_STATE_INSERTED) {
+ g_signal_emit (card, gdm_smartcard_signals[INSERTED], 0);
+ } else if (state == GDM_SMARTCARD_STATE_REMOVED) {
+ g_signal_emit (card, gdm_smartcard_signals[REMOVED], 0);
+ } else {
+ g_assert_not_reached ();
+ }
+ }
+}
+
+/* So we could conceivably make the closure data a pointer to the card
+ * or something similiar and then emit signals when we want passwords,
+ * but it's probably easier to just get the password up front and use
+ * it. So we just take the passed in g_malloc'd (well probably, who knows)
+ * and strdup it using NSPR's memory allocation routines.
+ */
+static char *
+gdm_smartcard_password_handler (PK11SlotInfo *slot,
+ PRBool is_retrying,
+ const char *password)
+{
+ if (is_retrying) {
+ return NULL;
+ }
+
+ return password != NULL? PL_strdup (password): NULL;
+}
+
+gboolean
+gdm_smartcard_unlock (GdmSmartcard *card,
+ const char *password)
+{
+ SECStatus status;
+
+ PK11_SetPasswordFunc ((PK11PasswordFunc) gdm_smartcard_password_handler);
+
+ /* we pass PR_TRUE to load certificates
+ */
+ status = PK11_Authenticate (card->priv->slot, PR_TRUE, (gpointer) password);
+
+ if (status != SECSuccess) {
+ g_debug ("could not unlock card - %d", status);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static PK11SlotInfo *
+gdm_smartcard_find_slot_from_card_name (GdmSmartcard *card,
+ const char *card_name)
+{
+ int i;
+
+ for (i = 0; i < card->priv->module->slotCount; i++) {
+ const char *slot_card_name;
+
+ slot_card_name = PK11_GetTokenName (card->priv->module->slots[i]);
+
+ if ((slot_card_name != NULL) &&
+ (strcmp (slot_card_name, card_name) == 0)) {
+ return card->priv->module->slots[i];
+ }
+ }
+
+ return NULL;
+}
+
+static PK11SlotInfo *
+gdm_smartcard_find_slot_from_id (GdmSmartcard *card,
+ int slot_id)
+{
+ int i;
+
+ for (i = 0; i < card->priv->module->slotCount; i++) {
+ if (PK11_GetSlotID (card->priv->module->slots[i]) == slot_id) {
+ return card->priv->module->slots[i];
+ }
+ }
+
+ return NULL;
+}
diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard.h b/gui/simple-greeter/plugins/smartcard/gdm-smartcard.h
new file mode 100644
index 0000000..20303bd
--- /dev/null
+++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard.h
@@ -0,0 +1,94 @@
+/* securitycard.h - api for reading and writing data to a security card
+ *
+ * Copyright (C) 2006 Ray Strode
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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 GDM_SMARTCARD_H
+#define GDM_SMARTCARD_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <secmod.h>
+
+G_BEGIN_DECLS
+#define GDM_TYPE_SMARTCARD (gdm_smartcard_get_type ())
+#define GDM_SMARTCARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDM_TYPE_SMARTCARD, GdmSmartcard))
+#define GDM_SMARTCARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDM_TYPE_SMARTCARD, GdmSmartcardClass))
+#define GDM_IS_SMARTCARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDM_TYPE_SMARTCARD))
+#define GDM_IS_SMARTCARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDM_TYPE_SMARTCARD))
+#define GDM_SMARTCARD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GDM_TYPE_SMARTCARD, GdmSmartcardClass))
+#define GDM_SMARTCARD_ERROR (gdm_smartcard_error_quark ())
+typedef struct _GdmSmartcardClass GdmSmartcardClass;
+typedef struct _GdmSmartcard GdmSmartcard;
+typedef struct _GdmSmartcardPrivate GdmSmartcardPrivate;
+typedef enum _GdmSmartcardError GdmSmartcardError;
+typedef enum _GdmSmartcardState GdmSmartcardState;
+
+typedef struct _GdmSmartcardRequest GdmSmartcardRequest;
+
+struct _GdmSmartcard {
+ GObject parent;
+
+ /*< private > */
+ GdmSmartcardPrivate *priv;
+};
+
+struct _GdmSmartcardClass {
+ GObjectClass parent_class;
+
+ void (* inserted) (GdmSmartcard *card);
+ void (* removed) (GdmSmartcard *card);
+};
+
+enum _GdmSmartcardError {
+ GDM_SMARTCARD_ERROR_GENERIC = 0,
+};
+
+enum _GdmSmartcardState {
+ GDM_SMARTCARD_STATE_INSERTED = 0,
+ GDM_SMARTCARD_STATE_REMOVED,
+};
+
+GType gdm_smartcard_get_type (void) G_GNUC_CONST;
+GQuark gdm_smartcard_error_quark (void) G_GNUC_CONST;
+
+CK_SLOT_ID gdm_smartcard_get_slot_id (GdmSmartcard *card);
+gint gdm_smartcard_get_slot_series (GdmSmartcard *card);
+GdmSmartcardState gdm_smartcard_get_state (GdmSmartcard *card);
+
+char *gdm_smartcard_get_name (GdmSmartcard *card);
+gboolean gdm_smartcard_is_login_card (GdmSmartcard *card);
+
+gboolean gdm_smartcard_unlock (GdmSmartcard *card,
+ const char *password);
+
+/* don't under any circumstances call these functions */
+#ifdef GDM_SMARTCARD_ENABLE_INTERNAL_API
+
+GdmSmartcard *_gdm_smartcard_new (SECMODModule *module,
+ CK_SLOT_ID slot_id,
+ gint slot_series);
+GdmSmartcard *_gdm_smartcard_new_from_name (SECMODModule *module,
+ const char *name);
+
+void _gdm_smartcard_set_state (GdmSmartcard *card,
+ GdmSmartcardState state);
+#endif
+
+G_END_DECLS
+#endif /* GDM_SMARTCARD_H */
diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard.pam b/gui/simple-greeter/plugins/smartcard/gdm-smartcard.pam
new file mode 100644
index 0000000..d5ac1fa
--- /dev/null
+++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard.pam
@@ -0,0 +1,18 @@
+# Sample PAM file for doing smartcard authentication.
+# Distros should replace this with what makes sense for them.
+auth required pam_env.so
+auth [success=done ignore=ignore default=die] pam_pkcs11.so wait_for_card card_only
+auth requisite pam_succeed_if.so uid >= 500 quiet
+auth required pam_deny.so
+
+account required pam_unix.so
+account sufficient pam_localuser.so
+account sufficient pam_succeed_if.so uid < 500 quiet
+account required pam_permit.so
+
+password optional pam_pkcs11.so
+password requisite pam_cracklib.so try_first_pass retry=3 type=
+
+session optional pam_keyinit.so revoke
+session required pam_limits.so
+session required pam_unix.so
diff --git a/gui/simple-greeter/plugins/smartcard/icons/16x16/Makefile.am b/gui/simple-greeter/plugins/smartcard/icons/16x16/Makefile.am
new file mode 100644
index 0000000..661d687
--- /dev/null
+++ b/gui/simple-greeter/plugins/smartcard/icons/16x16/Makefile.am
@@ -0,0 +1,5 @@
+iconsdir = $(datadir)/icons/hicolor/16x16/apps
+
+icons_DATA = gdm-smartcard.png
+
+EXTRA_DIST = $(icons_DATA)
diff --git a/gui/simple-greeter/plugins/smartcard/icons/16x16/gdm-smartcard.png b/gui/simple-greeter/plugins/smartcard/icons/16x16/gdm-smartcard.png
new file mode 100644
index 0000000000000000000000000000000000000000..0112af1b8d891ad312f9fcc3bf6074df3e003359
GIT binary patch
literal 871
zcmV-t1DO1YP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00001b5ch_0Itp)
z=>Px#24YJ`L;wH)0002_L%V+f000SaNLh0L01ejw01ejxLMWSf00007bV*G`2iXJ-
z6cQQvze?o*000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}0008QNkl<Z
zILoDzO=uKn0EVCWc6N4VH=}F?g{J6QBie2n4H`-{iH3Ocr_xLD)X+mq4R}|3XeEcG
zP)QFBf>25h)mRS()F5IML|LeofZ5$Phq#SvEXn3)x9QHz&V1jD*OHUa=lnh|yoWc&
zo1+2m0}628RN4)kP9zfJhGEoz$TZEX{|)Htgf`%?ZQIABl!txa-_X&~;rI9Vo88^r
z<nwt(Mn*QTFF2Y?r9O+I=!oZe>1;L|^!4>6dV71>-}NC2_0X(TUE+qIrDYmT)AaSb
zqQSwzu&1X-?Cbi7rG`eaTxYT75y*%ZE6&r0<4pW|3Ey2K2m+~;x&Y(=rCFBMd{LP<
ze!f%2@g%ktXZzbJvY9kitjV=&V+;=uGc+_rtyZH_sW3S?$@KK}cfeU)DJ6Ufjwku*
z#Jf~p{6)1o%ag||*tX5+=qR~dj#8<_+}s>O2(sBM#bWVH7>3^p-}m(}(unH<C4H1q
zWHK4r+uJD>3ls_kY}+QE&oeeQMlzYCTCI{!r;|XJ05A-lFao6%Gcz-k%VnBP$+`1i
z^JL;6j^og}#l)>&;?s|J5k(Q5do}@lp##MA7)pgK{$tR(^AIgbgR>VO(YA9dDYL-`
zsh`;Y<p!MD+jMMP<A+aP@psMP-hFxnfaf{@cumPKH~-|1=PR84yb~qfLZPv}e}LA#
z@N(%lawET!GFCAI7oZ{l5=IPwdsFjl+mU9z?h*tcD+_Z3fh0x)fUDyUsu2TS0~G-v
z0AfPp_`wW&+tPGyUS#>%6?x&ziM4udm5K2(B3uPvQ%dL5Nt5QX;$Nu&Y|(&dU|=Ac
znwoM8g@R?8=8}~1uJ8MIfoDQ+^ZMlj@4UAwMAl}h&MMZb@Tk<}`x}kRnq^tHG);3I
x$GHPM0G_Y=$2Q;_pbrQE4|oMk0zdM9c?}H%H!P_~w{rjh002ovPDHLkV1ieHj1>R?
literal 0
HcmV?d00001
diff --git a/gui/simple-greeter/plugins/smartcard/icons/48x48/Makefile.am b/gui/simple-greeter/plugins/smartcard/icons/48x48/Makefile.am
new file mode 100644
index 0000000..e79d85b
--- /dev/null
+++ b/gui/simple-greeter/plugins/smartcard/icons/48x48/Makefile.am
@@ -0,0 +1,5 @@
+iconsdir = $(datadir)/icons/hicolor/48x48/apps
+
+icons_DATA = gdm-smartcard.png
+
+EXTRA_DIST = $(icons_DATA)
diff --git a/gui/simple-greeter/plugins/smartcard/icons/48x48/gdm-smartcard.png b/gui/simple-greeter/plugins/smartcard/icons/48x48/gdm-smartcard.png
new file mode 100644
index 0000000000000000000000000000000000000000..35d5578d9ec83ae6b17aa7230c1b4df34e13e2cc
GIT binary patch
literal 4202
zcmV-w5S8zVP)<h;3K|Lk000e1NJLTq001xm001xu1^@s6R|5Hm00001b5ch_0Itp)
z=>Px#24YJ`L;wH)0002_L%V+f000SaNLh0L01ejw01ejxLMWSf00007bV*G`2iXJ-
z6cal&#5zC#000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}000lgNkl<Z
zXx{Cad2C$AeaAoZ-rIw_ORjkBl9DKjl6A0T?0~kcgIw8)k0g$Q#I9>2aFf(X>ozT5
zC$5a<Xi*?(0=rFf6bRrpMPt-W(?*Sv>Zk)aA|*R=Bt;5o9kwWGLxmKt<-N<j-g`6C
zKlUJ3l-;CF+!n|H4|~j;neT6Yzu))wo8Q2%+b_Mf12Mq*{{nae@VmgbOw*hMbn*G(
z|5d;(z(;`ROw+tp0vw4%+=m`|NPq2XU(=nPoeFsQ=b7y7P*W6m7jUP?<9WB^IIRHn
z_4O(iiy5(4jPCAkHg4Q#3LyYEbm)+{aN&ZXwf<ibpdPprxYO(PzT39#O#tC=SoQSu
z7(G2b^z`(wWy==BFpP?UB>{vG7>41KQobz$)Btw?d%RxnyB)`A*IJ8UFsQn_yUTz(
zIywx~G;av_`rnpip|uYDs!S+YWQjXH9?w0l>%LQKZTS6uy>sVI(cRrmPfriG+;WTI
z@p#@6@Iu;UXgp0zq>6^HuiPI91TYLkD5ZWW0{DTQz#hx8?o~?Nrj#<hUa#J^ZJX%n
z=^+-2(bd%@yk74O!RBp=X&TI>^8Cli339gNwym|C9-PB*HI@kv?`fqW>?@BILKy#D
z4S0a<MZotcrFJN#Jf>;tuC6Y+ySqg!7UTBYZx?>Q|Av62(oD=`2?xClT$$(W&^%g!
zTIQ6mo}a-m1X^pf7EI3NXk4{4pHeFHiwMvG>@`jEE+8hQ^c#kuJ3Bk+>FE)%Sd1Mz
zc8Fjw_@?GCIhSXAHcNDspBGO};7E<_NQ5YWEH$6Uz?B-Qba9Tt=f>65<vGLQFyi_J
z-a>#Ugb-f=#OBSLRV)@WcJJQJ&Ye3&I2?Xcz^>Gsxim*Q?-KBt3|v`2Duq&D7y_j<
z0x%8GT2LLZXlt%!eN&J%4OM6j-+g(6iP<cUs~DTkvZ<x!7j{Ttnr8OVM<4Y+_0&_;
z*Vn%#LyROc96vve&to#T=#aHtl+rAxYma3hl_peWvA!w9`lbMD8-w^f#)>&p8JBMy
zy3F*%&q)02ENiPXEG{l``t)fA1_rW9sr5kOEj1ve^tZRS)6mec0`UBz&A;|tBkxE8
zJ`-DNTvuTTQMPBVWuO4R$D}nHpshK?+Qt9@f2Dh6vsn^}1XEK}BoYa1+on2P$8&%6
zXIvfZ$23jq>+2Chkjv#zN>u?Pz<%H<VEj#eKq*z;9i=qKUYjD7aT%M<Vmk#Y%Q*_A
zG+s-fw7_o}tcwO|YYx%U7$6j=q|9_WO(KyXkw`E(IY~O5UhbfL|NGzP@ZrNWH#hU}
z!w<7_=T2&CYY{?_&1RXNp60}f6W(LTjy;l0Cf^G@27LF10u*TrfFJZv5+6<BNI+{0
zLtqMlX$o2*0X8&;Xo&==304ALSXe0UZX%H&o6S~ovENT55}~1?fv2B-nu7-qa`)YL
zbN~JK)6vnv{QNv~b91CpDU!(~Qp!?1;n1N&bprzf`+?sFzOh1pTrP(Yf^^R1%C$vY
zsf%U=yKj!r)*Pg^+E*T=wPtp9whVY`YKnY5UjaA}2oQ-xh(@DCqfu&VY7j#3)vtb)
z7hZUQ2OfBUM;>{Erluyw#>N;L8e(*Gv`DLkM=6Eh@8_O-?!oKzic_afJqug{j#UWY
zI1WMx{9Y4}DUeEFnSyt9HPNv?jFgh;>FJ6cc3rnJpQx!J5{Z<b>gwtW?Zo48;_*12
z``qW)zI{6nKKLN5t*wlWjnUuVPdc4OO3Cu*tCS+0PNS5ftE-FQ;bCK9V&ZR$v@chf
zkjFCFxTc!(L-W*!{dBgi;_~Io^!N9#0K96|Dx%RSjg5^&qfr8ZKzY%*xj8OgyvW4F
z1XEK}<Z`)EmI=Up_ua>>x86!T9_QS-bIi`plFQ}rcswhZN^6ajlEuYEVzC(e_wU~V
z+zY(8LIVqFhs)QJ0IY2cAcP>F&!d#0zP_GlG)g2Ap|P=%QWSPwm+9$g;_-OdoE*og
z01*m>XliQW%9Sf@-MW=syLK@>JxwZ=VrXcH^XJdAdi838!626|T_TxG(%9I@=FOYS
zb7V3ZJRT2`NQ6Wp@!QJ<P}ywO5JE6Il|gG!%wG!3bo0$O)7jZcDU-BqyKF{@M1q-_
znF_TFA*ijbE!%!cJM;7N3=R(Rfe(Cuwzf6~2M0NK?i>RH14t>!X0sePaDb|+Dtta4
zufP5}>(;HKy}g}yJWeK)K}yM*HET#D5_gq-z%<Q_5F#XmU|lqbD+|E&vS4PKCPD~K
zo;=Cm;9$k>nx;u(V<SyXO=S&vz1|h3FfuZNQi?5GwqV;fN-4(2#~B|Vr@OnG0|ySU
zckf=FfBt!%efC-Q?c0aX=VQZ$4Gawpk;~=CX0wDsq0%8~6)<lt-?^Hg4<QOkmz25!
zgb)J9ams2eF-${41D0jIX>MPRx)Uz}P+MC|E|(*h%P~DYjo0fXolcX@W|^3n;K?VS
z<jk2fg}gl&WaGw-^!E0W$z({SQY_2IYRUp6lSzaSj83NusemoZnph5K_wL;{1n4*p
zQ&UsS&CRiK<3_5gs>=PjT#i5a<Hz{MKm1EsV~*pH&*#bIa`=2cT-Rmm*3AeOxpeV|
zgaVT7x3yAN7ow%5rR<BTREkI>QW?mE5b2T$nTAnL5%hH+mw(UYawHN7CMG7BoSbBK
zcDC#XmSxf2-d=ux&mFsn4_)CepZOr~-DB`-zg6b=QkMFm4`zAa9rIv#i`l6cfsfvw
z_z8tV<+xB{xngSqhOH8x3L#k27{o9{kzJNdD3i&Q!A?v}Fh4)Pf>N8BnrLorrmd~5
zBC`MZ%vp~A^A0vdhpDPHkW!Sv=ks~A)_B7YQoHF6K%;R$=YcHQS6;()T|6F7S%CJ<
zbqo!K7#mys4zSHC0Te=DI}%+K&@JZcGcz+BJb17yxe$W-`uZ~9Xf#@3GS_Qtdshpd
zwL$D_<2Z{M=10zx+0coUlJW6zgb*Yyo<{4fMa?VFE?|@Y=}Y|0muHAXA{a&?n~etY
z9P4|4p56OfCnvLCu!Imf*L4eElX(zJ0YnHvFc_q*t*y-E(P;FBEOY(uGv_CfN@Iyd
zG=jRG)y$q8<eu>NID7Ow6H`@eTVF+6OPB|KYcpCU3TtbPMgo#YKK*`%esqSRvqNln
zpqi@2ChmQx6*WK2XMblkk3SRtJqyT}R35DhAP@)vj$3fzKp?=LJ$v31aC~^4{x=eA
zXj#R{fia%>`ybP`HcWiDU}lTM)ujQ{++^d8y6n0%1+77R?~CGDRgI<Mq~jx$c2DJP
zoW(iZ#U!D{6z#Ps94mvnkmtwGoF#gbCL(QsbC%Xx+qPX!CF*LtjL%5WOCYs|BR?8u
z&yIDNMx`KoKJuLvIeL6}o_!y?jc>ki0dHM>MW1&~E51#8(B?Z)b2G@9BjiR-q4GA`
z1ub=fK}=Ct*j6}6g`JexNsUf|*Y6{37kt7}N;%nV79j+wjLp=14y`qgT5{rlI`BH5
z{mKvd{1e@L^!^UAIhUc)1+HFO;Fhh8oWDGcl$uX|^j7xn*+4^G6}2^f9{+F`vDn{L
z20p7A?c0LsjY3r&qTw=za|xYyakFs#oWrS~*yucTzr#yQorzb0vK2C~srG4v)|3pQ
zM5AR5h>{xR(mC-vFAnngC%W-i2J7yu1oZVkzl;0s*uX+6PhHsmU!P$`9z1I?gdc^x
zt`9mkTYUR_S^n|gGW_BFK_3555VOj_sxol18q=#;KFm@|=@P?K`7AcIgt;&@%krwE
zWg5KNKgNqM4*{_6W4G~}_ipC-e}A2u*41JfVg>lwWR9!jDW>ML#nMs{q)Z@$4<V`$
zI(I`M>sA?5`wY$vF6CHez{E%@3`>BkDOHUut+h_2QsozaHc|NQ$fdzg?~8Hx=udg_
z(OcQlR#*Q2Q;*%gl=Cmz42>tbG(5-E@f1>O6q;<lG7U%P5iDRBQIuX-0e*Bs^1|U9
zA+KOzPBJsEsr7@f1eg?n%gPhkf-Xb}k#{6nyVSd+gDq`!6~F-&GY&)JNv@2{6CX=r
zI|?Ddc4Ya`Z<z*TSKj~{E5;gX3`5+Ez^Ksl=(yz0ho-3#28}_Jkk23<m)zD-$b<{U
zV1<@Tl@P1Q`5F*Dk4bZVfU)Ux!BNMOw5=}GYBD*OtK&)H*XFrAnk1KZF@zxR6a+4T
z_E-j0K8tMLWov6K+qd5i*H_8q2trf=mBrpnPJ=551q&ur8#LH-)6zRyszQZNQ4Y8k
zKq{3gFLC#_7M?r&1_0lF=`v0ARV-#4k{KJ*Fp5<QUEC3YWf}ylETVNmGC7AmU2E8|
zW~m^yf9+bH`{r@J@NplaR63Qz7=|CND}NdSLSBPvpCIHD+!gau8y2WsVLdkw%GEe>
zX-_O5v;07EtbcS_^-VG|xmachDJ7OAFfh5jGlJ`CydHyHoz3{XW<?F?`0?W$J$jV>
z{(dz$IAT2ho_d-#6|#4&hB1V1g$WsgB6x$QI*YsCwN&|#S%sTbNE@USNTtgHIC@#}
zG8FJ)ngXp0H6j3yX`s=3<h|`A<}yTT1GGe!YOl6!^U5o)(%ak1kt0Xci4!Mq9LEqs
zIKU~O?T@~cTK%mrh6&ahpdGZ%-+*EZ;6pxx_wDuL_X||6U@qx#7n#!}^MZO)VB5N~
ztWs+4?_N*9XOhiJ?%uW*LkJRcS?X$hghM`Bq9I(@<-~~-^!4@8+uN&NdF2(I&*x1c
zgfa}{jFhq$=+#;u2hzZA^q#iQ9DF(Nf3U&88w7m=23oh)<WD~n;I)&A9Xm|0HOhtg
zOE&pgNirvx&YHBY64-X(Hpl|(<pOvtgZJ!ct(dsgXEHD_PzHST=uw@?WK1E17DAj;
zN*w|EwAL?6DU&y#_Sb>WJoXpKFL!MA(BVttUA6Kx!+>2od~AOws2nU#N~T`3Nv9y~
zm^h|M`!<7cBlMoN0Zv;$_WFsm)?B!7f!^L;`uh5GZ*Q+kCX;57$_9&od$ratYprK~
z&O-86fXE$>&V1^7U-z<O?h}~N-3ae2NQt&J+6HZFR37F>HPRK--Qpu^f!9}X+|e<~
z6MvoI@K5qN;7er_x_I#-M~@z*udk0IM~=vunHdwn<M9kRj`IVc59m`$P5uw=(?0D=
zCiecp_+Q@oj*NHT$86R&&JpmWK}#G*<JyqSXlCaWqf?UcDaGJbR}EZojghHx1Un6U
z95^k2PZW2jbR-;gUH2uRw+Q;$uiz$g3-HO}UE4;$cU}JskOD@5X<!(b0^TTszgl*D
zzzcl1NbX00pT5l(-zE@V7Wx+e#jo41+uPIr6KfBhqy$$z_y7O^07*qoM6N<$f=Ipg
ARR910
literal 0
HcmV?d00001
diff --git a/gui/simple-greeter/plugins/smartcard/icons/Makefile.am b/gui/simple-greeter/plugins/smartcard/icons/Makefile.am
new file mode 100644
index 0000000..c20f10d
--- /dev/null
+++ b/gui/simple-greeter/plugins/smartcard/icons/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = 16x16 48x48
diff --git a/gui/simple-greeter/plugins/smartcard/page.ui b/gui/simple-greeter/plugins/smartcard/page.ui
new file mode 100644
index 0000000..8fa5c7b
--- /dev/null
+++ b/gui/simple-greeter/plugins/smartcard/page.ui
@@ -0,0 +1,57 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.14"/>
+ <object class="GtkVBox" id="page">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkHBox" id="auth-input-box">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="auth-prompt-label">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="auth-prompt-entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="activates_default">True</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="auth-message-box">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="auth-message-label">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/gui/simple-greeter/plugins/smartcard/plugin.c b/gui/simple-greeter/plugins/smartcard/plugin.c
new file mode 100644
index 0000000..fffbd50
--- /dev/null
+++ b/gui/simple-greeter/plugins/smartcard/plugin.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ * Written By: Ray Strode <rstrode@redhat.com>
+ *
+ */
+
+#include "gdm-smartcard-extension.h"
+
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+
+GdmGreeterExtension *
+gdm_greeter_plugin_get_extension (void)
+{
+ static GObject *extension;
+
+ if (extension != NULL) {
+ g_object_ref (extension);
+ } else {
+ extension = g_object_new (GDM_TYPE_SMARTCARD_EXTENSION, NULL);
+ g_object_add_weak_pointer (extension, (gpointer *) &extension);
+ }
+
+ return GDM_GREETER_EXTENSION (extension);
+}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index dd08b21..ed922a5 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -86,6 +86,9 @@ gui/simple-greeter/gdm-user-chooser-widget.c
gui/simple-greeter/greeter-main.c
gui/simple-greeter/plugins/password/gdm-password-extension.c
gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
+gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
+gui/simple-greeter/plugins/smartcard/gdm-smartcard-manager.c
+gui/simple-greeter/plugins/smartcard/gdm-smartcard.c
gui/user-switch-applet/applet.c
gui/user-switch-applet/gdm-entry-menu-item.c
gui/user-switch-applet/GNOME_FastUserSwitchApplet.server.in.in
--
1.7.2.1
From 1b0996ab22621ae16faa847a940d3df36a837efe Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 4 Aug 2010 18:26:01 -0400
Subject: [PATCH 24/35] squash with smartcard
---
.../plugins/smartcard/gdm-smartcard-extension.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
index b925f5e..b40a21c 100644
--- a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
+++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
@@ -184,6 +184,7 @@ gdm_smartcard_extension_ask_question (GdmConversation *conversation,
gtk_entry_set_visibility (GTK_ENTRY (extension->priv->prompt_entry), TRUE);
gtk_widget_show (extension->priv->prompt_entry);
gtk_action_set_visible (extension->priv->login_action, TRUE);
+ gtk_action_set_sensitive (extension->priv->login_action, TRUE);
gtk_widget_grab_focus (extension->priv->prompt_entry);
extension->priv->answer_pending = TRUE;
}
@@ -200,6 +201,7 @@ gdm_smartcard_extension_ask_secret (GdmConversation *conversation,
gtk_widget_show (extension->priv->prompt_entry);
gtk_widget_grab_focus (extension->priv->prompt_entry);
gtk_action_set_visible (extension->priv->login_action, TRUE);
+ gtk_action_set_sensitive (extension->priv->login_action, TRUE);
extension->priv->answer_pending = TRUE;
}
@@ -475,6 +477,7 @@ static void
on_activate_log_in (GdmSmartcardExtension *extension)
{
gdm_smartcard_extension_request_answer (GDM_CONVERSATION (extension));
+ gtk_action_set_sensitive (extension->priv->login_action, FALSE);
}
static void
--
1.7.2.1
From 74292dc8bf5f84a83b4ff339b53f1430479fa2d9 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 21 Apr 2009 10:25:18 -0400
Subject: [PATCH 25/35] When one PAM conversation wins, stop the others
At some point we'll want to have policy here, to allow
e.g. two factor authentication.
---
daemon/gdm-session-direct.c | 71 +++++++++++++++++++++++++++++++-----------
daemon/gdm-simple-slave.c | 2 +-
2 files changed, 53 insertions(+), 20 deletions(-)
diff --git a/daemon/gdm-session-direct.c b/daemon/gdm-session-direct.c
index 5a604bf..41c7dc2 100644
--- a/daemon/gdm-session-direct.c
+++ b/daemon/gdm-session-direct.c
@@ -2370,6 +2370,47 @@ gdm_session_direct_open_session (GdmSession *session,
}
static void
+stop_all_other_conversations (GdmSessionDirect *session,
+ GdmSessionConversation *conversation_to_keep)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+
+ if (session->priv->conversations == NULL) {
+ return;
+ }
+
+ if (conversation_to_keep == NULL) {
+ g_debug ("GdmSessionDirect: Stopping all conversations");
+ } else {
+ g_debug ("GdmSessionDirect: Stopping all conversations "
+ "except for %s", conversation_to_keep->service_name);
+ }
+
+ g_hash_table_iter_init (&iter, session->priv->conversations);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ GdmSessionConversation *conversation;
+
+ conversation = (GdmSessionConversation *) value;
+
+ if (conversation == conversation_to_keep) {
+ g_hash_table_iter_steal (&iter);
+ g_free (key);
+ } else {
+ stop_conversation (conversation);
+ }
+ }
+
+ g_hash_table_remove_all (session->priv->conversations);
+
+ if (conversation_to_keep != NULL) {
+ g_hash_table_insert (session->priv->conversations,
+ g_strdup (conversation_to_keep->service_name),
+ conversation_to_keep);
+ }
+}
+
+static void
gdm_session_direct_start_session (GdmSession *session,
const char *service_name)
{
@@ -2381,6 +2422,16 @@ gdm_session_direct_start_session (GdmSession *session,
g_return_if_fail (session != NULL);
g_return_if_fail (impl->priv->is_running == FALSE);
+ conversation = find_conversation_by_name (impl, service_name);
+
+ if (conversation == NULL) {
+ g_warning ("GdmSessionDirect: Tried to start session of "
+ "nonexistent conversation %s", service_name);
+ return;
+ }
+
+ stop_all_other_conversations (impl, conversation);
+
command = get_session_command (impl);
if (gdm_session_direct_bypasses_xsession (impl)) {
@@ -2391,8 +2442,6 @@ gdm_session_direct_start_session (GdmSession *session,
g_free (command);
- conversation = find_conversation_by_name (impl, service_name);
-
setup_session_environment (impl);
send_environment (impl, conversation);
@@ -2403,23 +2452,7 @@ gdm_session_direct_start_session (GdmSession *session,
static void
stop_all_conversations (GdmSessionDirect *session)
{
- GHashTableIter iter;
- gpointer key, value;
-
- if (session->priv->conversations == NULL) {
- return;
- }
-
- g_hash_table_iter_init (&iter, session->priv->conversations);
- while (g_hash_table_iter_next (&iter, &key, &value)) {
- GdmSessionConversation *conversation;
-
- conversation = (GdmSessionConversation *) value;
-
- stop_conversation (conversation);
- }
-
- g_hash_table_remove_all (session->priv->conversations);
+ stop_all_other_conversations (session, NULL);
}
static void
diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c
index 43eac10..7725205 100644
--- a/daemon/gdm-simple-slave.c
+++ b/daemon/gdm-simple-slave.c
@@ -598,7 +598,7 @@ on_session_conversation_stopped (GdmSession *session,
gboolean res;
g_debug ("GdmSimpleSlave: conversation stopped");
- if (slave->priv->greeter_server != NULL) {
+ if (slave->priv->greeter != NULL) {
res = gdm_greeter_server_conversation_stopped (slave->priv->greeter_server,
service_name);
if (! res) {
--
1.7.2.1
From 67a3f9ac9abc64c35c0d2b5b91a1ccc823f5b20d Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 24 Jul 2009 14:41:48 -0400
Subject: [PATCH 26/35] KILL stuck processes if they don't die on TERM
Some PAM modules are really slow to shut down.
We need to handle them being slow to shut down better,
(by not blocking login on them shutting down etc), but
in the mean time force them to die immediately.
This is a temporary hack.
---
common/gdm-common.c | 48 ++++++++++++++++++++++++++++++++++++--
common/gdm-common.h | 2 +
daemon/gdm-session-worker-job.c | 2 +-
3 files changed, 48 insertions(+), 4 deletions(-)
diff --git a/common/gdm-common.c b/common/gdm-common.c
index de80700..7a4e26d 100644
--- a/common/gdm-common.c
+++ b/common/gdm-common.c
@@ -93,13 +93,25 @@ gdm_get_pwent_for_name (const char *name,
}
int
-gdm_wait_on_pid (int pid)
+gdm_wait_on_and_kill_pid (int pid,
+ int timeout)
{
int status;
-
+ int ret;
+ int num_tries;
+ int flags;
+
+ if (timeout > 0) {
+ flags = WNOHANG;
+ num_tries = 10 * timeout;
+ } else {
+ flags = 0;
+ num_tries = 0;
+ }
wait_again:
errno = 0;
- if (waitpid (pid, &status, 0) < 0) {
+ ret = waitpid (pid, &status, flags);
+ if (ret < 0) {
if (errno == EINTR) {
goto wait_again;
} else if (errno == ECHILD) {
@@ -107,6 +119,30 @@ gdm_wait_on_pid (int pid)
} else {
g_debug ("GdmCommon: waitpid () should not fail");
}
+ } else if (ret == 0) {
+ num_tries--;
+
+ if (num_tries > 0) {
+ g_usleep (G_USEC_PER_SEC / 10);
+ } else {
+ char *path;
+ char *command;
+
+ path = g_strdup_printf ("/proc/%ld/cmdline", (long) pid);
+ if (g_file_get_contents (path, &command, NULL, NULL)) {;
+ g_debug ("GdmCommon: process (pid:%d, command '%s') isn't dying, now killing it.",
+ (int) pid, command);
+ g_free (command);
+ } else {
+ g_debug ("GdmCommon: process (pid:%d) isn't dying, now killing it.",
+ (int) pid);
+ }
+ g_free (path);
+
+ kill (pid, SIGKILL);
+ flags = 0;
+ }
+ goto wait_again;
}
g_debug ("GdmCommon: process (pid:%d) done (%s:%d)",
@@ -122,6 +158,12 @@ gdm_wait_on_pid (int pid)
}
int
+gdm_wait_on_pid (int pid)
+{
+ return gdm_wait_on_and_kill_pid (pid, 0);
+}
+
+int
gdm_signal_pid (int pid,
int signal)
{
diff --git a/common/gdm-common.h b/common/gdm-common.h
index 8faeda5..06300c8 100644
--- a/common/gdm-common.h
+++ b/common/gdm-common.h
@@ -34,6 +34,8 @@ gboolean gdm_is_version_unstable (void);
void gdm_set_fatal_warnings_if_unstable (void);
int gdm_wait_on_pid (int pid);
+int gdm_wait_on_and_kill_pid (int pid,
+ int timeout);
int gdm_signal_pid (int pid,
int signal);
gboolean gdm_get_pwent_for_name (const char *name,
diff --git a/daemon/gdm-session-worker-job.c b/daemon/gdm-session-worker-job.c
index be85f30..8b93663 100644
--- a/daemon/gdm-session-worker-job.c
+++ b/daemon/gdm-session-worker-job.c
@@ -296,7 +296,7 @@ session_worker_job_died (GdmSessionWorkerJob *session_worker_job)
int exit_status;
g_debug ("GdmSessionWorkerJob: Waiting on process %d", session_worker_job->priv->pid);
- exit_status = gdm_wait_on_pid (session_worker_job->priv->pid);
+ exit_status = gdm_wait_on_and_kill_pid (session_worker_job->priv->pid, 3);
if (WIFEXITED (exit_status) && (WEXITSTATUS (exit_status) != 0)) {
g_debug ("GdmSessionWorkerJob: Wait on child process failed");
--
1.7.2.1
From ec1151e4c20d0cc61e7b0a0ccbcf82d589d93795 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 23 Oct 2009 17:39:19 -0400
Subject: [PATCH 27/35] Drop the other hiding stuff for now.
It depends on buttons being available that we don't have
in the multi-stack branch.
---
gui/simple-greeter/gdm-user-chooser-widget.c | 8 +-------
1 files changed, 1 insertions(+), 7 deletions(-)
diff --git a/gui/simple-greeter/gdm-user-chooser-widget.c b/gui/simple-greeter/gdm-user-chooser-widget.c
index 33708b9..f8cf845 100644
--- a/gui/simple-greeter/gdm-user-chooser-widget.c
+++ b/gui/simple-greeter/gdm-user-chooser-widget.c
@@ -150,13 +150,7 @@ update_other_user_visibility (GdmUserChooserWidget *widget)
goto out;
}
- number_of_users = gdm_chooser_widget_get_number_of_items (GDM_CHOOSER_WIDGET (widget));
-
- /* we hide the Other user if it's the last one, and we show it
- * if there's another user */
- if (number_of_users == 1 && widget->priv->has_user_other) {
- remove_user_other (widget);
- } if (number_of_users >= 1 && !widget->priv->has_user_other) {
+ if (!widget->priv->has_user_other) {
add_user_other (widget);
}
--
1.7.2.1
From 871f015fb50b7192ebf3497b3b2b4741275e2d90 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 13 Jul 2010 22:36:19 -0400
Subject: [PATCH 28/35] add better debug spew (needs squash)
---
daemon/gdm-session-direct.c | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/daemon/gdm-session-direct.c b/daemon/gdm-session-direct.c
index 41c7dc2..e4e4166 100644
--- a/daemon/gdm-session-direct.c
+++ b/daemon/gdm-session-direct.c
@@ -210,7 +210,7 @@ find_conversation_by_name (GdmSessionDirect *session,
conversation = g_hash_table_lookup (session->priv->conversations, service_name);
if (conversation == NULL) {
- g_warning ("Tried to look up non-existant conversation");
+ g_warning ("Tried to look up non-existent conversation %s", service_name);
}
return conversation;
@@ -1800,7 +1800,7 @@ static void
free_conversation (GdmSessionConversation *conversation)
{
if (conversation->job != NULL) {
- g_warning ("Freeing conversation with active job");
+ g_warning ("Freeing conversation '%s' with active job", conversation->service_name);
}
g_free (conversation->service_name);
@@ -1973,7 +1973,7 @@ gdm_session_direct_start_conversation (GdmSession *session,
g_return_if_fail (session != NULL);
- g_debug ("GdmSessionDirect: starting conversation");
+ g_debug ("GdmSessionDirect: starting conversation %s", service_name);
conversation = start_conversation (impl, service_name);
@@ -1990,7 +1990,7 @@ gdm_session_direct_stop_conversation (GdmSession *session,
g_return_if_fail (session != NULL);
- g_debug ("GdmSessionDirect: stopping conversation");
+ g_debug ("GdmSessionDirect: stopping conversation %s", service_name);
conversation = find_conversation_by_name (impl, service_name);
--
1.7.2.1
From f59d1a42aa6d874d9342915c0f1632dbcf905c11 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 13 Jul 2010 22:37:35 -0400
Subject: [PATCH 29/35] switch to proper mode when going to timed login
---
gui/simple-greeter/gdm-greeter-login-window.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
index d0c0781..217aac8 100644
--- a/gui/simple-greeter/gdm-greeter-login-window.c
+++ b/gui/simple-greeter/gdm-greeter-login-window.c
@@ -1384,7 +1384,7 @@ begin_auto_login (GdmGreeterLoginWindow *login_window)
/* just wait for the user to select language and stuff */
set_message (login_window, _("Select language and click Log In"));
- switch_mode (login_window, MODE_AUTHENTICATION);
+ switch_mode (login_window, MODE_TIMED_LOGIN);
show_widget (login_window, "conversation-list", FALSE);
gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
--
1.7.2.1
From 62d2a6eb5ff91892ad3b57b861fd4bcd274027b7 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 3 Aug 2010 15:21:26 -0400
Subject: [PATCH 30/35] Drop "Cancelling" message for plugin initiated cancels
The plugin may be cancelling the mesage for a number of
reasons. We could potentially let it specify the message,
but for now just drop the message.
---
gui/simple-greeter/gdm-greeter-login-window.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
index 217aac8..13798ff 100644
--- a/gui/simple-greeter/gdm-greeter-login-window.c
+++ b/gui/simple-greeter/gdm-greeter-login-window.c
@@ -2138,7 +2138,7 @@ static void
on_conversation_cancel (GdmGreeterLoginWindow *login_window,
GdmConversation *conversation)
{
- do_cancel (login_window);
+ restart_conversations (login_window);
}
static gboolean
--
1.7.2.1
From aedf0cf1393a47694691432b4c328ff242afd3a1 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 4 Aug 2010 18:11:27 -0400
Subject: [PATCH 31/35] drop code for label that doesn't exist anymore
---
gui/simple-greeter/gdm-greeter-login-window.c | 6 ------
1 files changed, 0 insertions(+), 6 deletions(-)
diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
index 13798ff..536d4bb 100644
--- a/gui/simple-greeter/gdm-greeter-login-window.c
+++ b/gui/simple-greeter/gdm-greeter-login-window.c
@@ -776,9 +776,6 @@ static void
reset_dialog (GdmGreeterLoginWindow *login_window,
guint dialog_mode)
{
- GtkWidget *label;
- guint mode;
-
g_debug ("GdmGreeterLoginWindow: Resetting dialog to mode %u", dialog_mode);
set_busy (login_window);
set_sensitive (login_window, FALSE);
@@ -813,9 +810,6 @@ reset_dialog (GdmGreeterLoginWindow *login_window,
reset_task,
login_window);
- label = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-label"));
- gtk_label_set_text (GTK_LABEL (label), "");
-
if (can_jump_to_authenticate (login_window)) {
/* If we don't have a user list jump straight to authenticate */
g_debug ("GdmGreeterLoginWindow: jumping straight to authenticate");
--
1.7.2.1
From 388e0d6b74765907c9bc348269dfb9ee4b7a2105 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 4 Aug 2010 18:03:52 -0400
Subject: [PATCH 32/35] Add delay when showing messages (needs split)
Previously, there were times when the user would be unable
to read messages, because they would blink by so fast.
This jumble of assorted changes (which needs to be split up)
adds some queueing and timeouts to make sure the messages stay on
screen for a sufficient amount of time.
---
gui/simple-greeter/gdm-greeter-login-window.c | 119 ++++++++++++++++++--
.../libgdmsimplegreeter/gdm-conversation.c | 18 +++
.../libgdmsimplegreeter/gdm-conversation.h | 2 +
.../fingerprint/gdm-fingerprint-extension.c | 20 ++++
.../plugins/password/gdm-password-extension.c | 20 ++++
.../plugins/smartcard/gdm-smartcard-extension.c | 19 +++
6 files changed, 188 insertions(+), 10 deletions(-)
diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
index 536d4bb..2d7c400 100644
--- a/gui/simple-greeter/gdm-greeter-login-window.c
+++ b/gui/simple-greeter/gdm-greeter-login-window.c
@@ -137,6 +137,9 @@ struct GdmGreeterLoginWindowPrivate
guint login_button_handler_id;
guint start_session_handler_id;
+
+ char *service_name_of_session_ready_to_start;
+
};
enum {
@@ -173,6 +176,8 @@ static void switch_mode (GdmGreeterLoginWindow *login_window
static void update_banner_message (GdmGreeterLoginWindow *login_window);
static void gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_window,
const char *service_name);
+static void handle_stopped_conversation (GdmGreeterLoginWindow *login_window,
+ const char *service_name);
G_DEFINE_TYPE (GdmGreeterLoginWindow, gdm_greeter_login_window, GTK_TYPE_WINDOW)
@@ -231,6 +236,7 @@ set_task_conversation_message (GdmTaskList *task_list,
{
gdm_conversation_set_message (GDM_CONVERSATION (task), message);
+ g_object_set_data (G_OBJECT (task), "message-pending", GINT_TO_POINTER (TRUE));
return FALSE;
}
@@ -882,16 +888,12 @@ gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window,
return TRUE;
}
-gboolean
-gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_window,
- const char *service_name)
+static void
+handle_stopped_conversation (GdmGreeterLoginWindow *login_window,
+ const char *service_name)
{
GdmTask *task;
- g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
-
- g_debug ("GdmGreeterLoginWindow: conversation '%s' has stopped", service_name);
-
/* If the password conversation failed, then start over
*
* FIXME: we need to get this policy out of the source code
@@ -899,13 +901,15 @@ gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_wind
if (strcmp (service_name, "gdm-password") == 0) {
g_debug ("GdmGreeterLoginWindow: main conversation failed, starting over");
restart_conversations (login_window);
- return TRUE;
+ return;
}
task = find_task_with_service_name (login_window, service_name);
if (task != NULL) {
gdm_conversation_reset (GDM_CONVERSATION (task));
+
+ g_object_set_data (G_OBJECT (task), "needs-to-be-stopped", GINT_TO_POINTER (FALSE));
g_object_unref (task);
}
@@ -920,6 +924,34 @@ gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_wind
g_object_unref (task);
update_conversation_list_visibility (login_window);
+}
+
+gboolean
+gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_window,
+ const char *service_name)
+{
+ GdmTask *task;
+ gboolean messages_pending;
+
+ g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
+
+ g_debug ("GdmGreeterLoginWindow: conversation '%s' has stopped", service_name);
+
+ task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
+ if (task != NULL && task_has_service_name (GDM_TASK_LIST (login_window->priv->conversation_list), task, service_name)) {
+
+ messages_pending = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (task), "message-pending"));
+ } else {
+ messages_pending = FALSE;
+ }
+
+ if (!messages_pending) {
+ handle_stopped_conversation (login_window, service_name);
+ } else {
+ g_assert (task != NULL);
+
+ g_object_set_data (G_OBJECT (task), "needs-to-be-stopped", GINT_TO_POINTER (TRUE));
+ }
return TRUE;
}
@@ -931,6 +963,7 @@ restart_task_conversation (GdmTaskList *task_list,
{
char *service_name;
+ g_object_set_data (G_OBJECT (task), "needs-to-be-stopped", GINT_TO_POINTER (FALSE));
service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task));
if (service_name != NULL) {
char *name;
@@ -959,6 +992,9 @@ gdm_greeter_login_window_reset (GdmGreeterLoginWindow *login_window)
restart_task_conversation,
login_window);
+ g_free (login_window->priv->service_name_of_session_ready_to_start);
+ login_window->priv->service_name_of_session_ready_to_start = NULL;
+
return TRUE;
}
@@ -976,6 +1012,7 @@ gdm_greeter_login_window_info (GdmGreeterLoginWindow *login_window,
task = find_task_with_service_name (login_window, service_name);
if (task != NULL) {
+ g_object_set_data (G_OBJECT (task), "message-pending", GINT_TO_POINTER (TRUE));
gdm_conversation_set_message (GDM_CONVERSATION (task),
text);
show_task_actions (task);
@@ -999,6 +1036,7 @@ gdm_greeter_login_window_problem (GdmGreeterLoginWindow *login_window,
task = find_task_with_service_name (login_window, service_name);
if (task != NULL) {
+ g_object_set_data (G_OBJECT (task), "message-pending", GINT_TO_POINTER (TRUE));
gdm_conversation_set_message (GDM_CONVERSATION (task),
text);
show_task_actions (task);
@@ -1094,12 +1132,40 @@ on_ready_to_start_session (GdmGreeterLoginWindow *login_window,
}
static void
+gdm_greeter_login_window_start_session (GdmGreeterLoginWindow *login_window)
+{
+ g_debug ("GdmGreeterLoginWindow: starting session");
+ g_signal_emit (login_window,
+ signals[START_SESSION],
+ 0,
+ login_window->priv->service_name_of_session_ready_to_start);
+ g_free (login_window->priv->service_name_of_session_ready_to_start);
+ login_window->priv->service_name_of_session_ready_to_start = NULL;
+}
+
+static void
gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_window,
const char *service_name)
{
if (login_window->priv->is_interactive) {
- g_debug ("GdmGreeterLoginWindow: starting session");
- g_signal_emit (login_window, signals[START_SESSION], 0, service_name);
+ gboolean messages_pending;
+ GdmTask *task;
+
+ set_sensitive (GDM_GREETER_LOGIN_WINDOW (login_window), FALSE);
+
+ task = find_task_with_service_name (login_window, service_name);
+
+ if (task != NULL) {
+ messages_pending = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (task), "message-pending"));
+
+ } else {
+ messages_pending = FALSE;
+ }
+
+ login_window->priv->service_name_of_session_ready_to_start = g_strdup (service_name);
+ if (!messages_pending) {
+ gdm_greeter_login_window_start_session (login_window);
+ }
} else {
g_debug ("GdmGreeterLoginWindow: not starting session since "
"user hasn't had an opportunity to pick language "
@@ -2164,6 +2230,35 @@ on_conversation_chose_user (GdmGreeterLoginWindow *login_window,
return TRUE;
}
+static void
+on_conversation_message_set (GdmGreeterLoginWindow *login_window,
+ GdmConversation *conversation)
+{
+ gboolean needs_to_be_stopped;
+
+ g_object_set_data (G_OBJECT (conversation), "message-pending", GINT_TO_POINTER (FALSE));
+
+ needs_to_be_stopped = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (conversation), "needs-to-be-stopped"));
+
+ if (needs_to_be_stopped) {
+ char *service_name;
+
+ service_name = gdm_conversation_get_service_name (conversation);
+ handle_stopped_conversation (login_window, service_name);
+ g_free (service_name);
+ }
+
+ if (login_window->priv->service_name_of_session_ready_to_start != NULL ) {
+ GdmTask *task;
+
+ task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
+
+ if (task == GDM_TASK (conversation)) {
+ gdm_greeter_login_window_start_session (login_window);
+ }
+ }
+}
+
void
gdm_greeter_login_window_remove_extension (GdmGreeterLoginWindow *login_window,
GdmGreeterExtension *extension)
@@ -2326,6 +2421,10 @@ gdm_greeter_login_window_add_extension (GdmGreeterLoginWindow *login_window,
"user-chosen",
G_CALLBACK (on_conversation_chose_user),
login_window);
+ g_signal_connect_swapped (GDM_CONVERSATION (extension),
+ "message-set",
+ G_CALLBACK (on_conversation_message_set),
+ login_window);
g_debug ("GdmGreeterLoginWindow: new extension '%s - %s' added",
name, description);
diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c
index ee763ef..1320d9c 100644
--- a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c
+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c
@@ -32,6 +32,7 @@ enum {
ANSWER,
USER_CHOSEN,
CANCEL,
+ MESSAGE_SET,
LAST_SIGNAL
};
@@ -92,6 +93,16 @@ gdm_conversation_class_init (gpointer g_iface)
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
+
+ signals [MESSAGE_SET] =
+ g_signal_new ("message-set",
+ iface_type,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmConversationIface, message_set),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
}
void
@@ -184,3 +195,10 @@ gdm_conversation_choose_user (GdmConversation *conversation,
return was_chosen;
}
+
+void
+gdm_conversation_message_set (GdmConversation *conversation)
+{
+ g_signal_emit (conversation, signals [MESSAGE_SET], 0);
+}
+
diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h
index b37b21e..f76b18c 100644
--- a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h
+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h
@@ -62,6 +62,7 @@ struct _GdmConversationIface
char * (* answer) (GdmConversation *conversation);
void (* cancel) (GdmConversation *conversation);
gboolean (* user_chosen) (GdmConversation *conversation);
+ void (* message_set) (GdmConversation *conversation);
};
GType gdm_conversation_get_type (void) G_GNUC_CONST;
@@ -87,6 +88,7 @@ void gdm_conversation_answer (GdmConversation *conversation,
void gdm_conversation_cancel (GdmConversation *conversation);
gboolean gdm_conversation_choose_user (GdmConversation *conversation,
const char *username);
+void gdm_conversation_message_set (GdmConversation *conversation);
G_END_DECLS
diff --git a/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
index 55f5d32..2f7e968 100644
--- a/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
+++ b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
@@ -41,6 +41,8 @@ struct _GdmFingerprintExtensionPrivate
GtkWidget *prompt_entry;
guint answer_pending : 1;
+
+ guint message_timeout_id;
};
static void gdm_fingerprint_extension_finalize (GObject *object);
@@ -59,6 +61,17 @@ G_DEFINE_TYPE_WITH_CODE (GdmFingerprintExtension,
G_IMPLEMENT_INTERFACE (GDM_TYPE_CONVERSATION,
gdm_conversation_iface_init));
+static gboolean
+on_message_expired (GdmConversation *conversation)
+{
+ GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (conversation);
+ extension->priv->message_timeout_id = 0;
+
+ gdm_conversation_message_set (conversation);
+
+ return FALSE;
+}
+
static void
gdm_fingerprint_extension_set_message (GdmConversation *conversation,
const char *message)
@@ -66,6 +79,11 @@ gdm_fingerprint_extension_set_message (GdmConversation *conversation,
GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (conversation);
gtk_widget_show (extension->priv->message_label);
gtk_label_set_text (GTK_LABEL (extension->priv->message_label), message);
+
+ if (extension->priv->message_timeout_id != 0) {
+ g_source_remove (extension->priv->message_timeout_id);
+ }
+ extension->priv->message_timeout_id = g_timeout_add_seconds (2, (GSourceFunc) on_message_expired, conversation);
}
static void
@@ -282,6 +300,8 @@ gdm_fingerprint_extension_class_init (GdmFingerprintExtensionClass *extension_cl
static void
gdm_fingerprint_extension_finalize (GObject *object)
{
+ GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (object);
+ g_source_remove (extension->priv->message_timeout_id);
}
static void
diff --git a/gui/simple-greeter/plugins/password/gdm-password-extension.c b/gui/simple-greeter/plugins/password/gdm-password-extension.c
index 11a171c..5157ea2 100644
--- a/gui/simple-greeter/plugins/password/gdm-password-extension.c
+++ b/gui/simple-greeter/plugins/password/gdm-password-extension.c
@@ -40,6 +40,8 @@ struct _GdmPasswordExtensionPrivate
GtkWidget *prompt_entry;
guint answer_pending : 1;
+
+ guint message_timeout_id;
};
static void gdm_password_extension_finalize (GObject *object);
@@ -58,6 +60,16 @@ G_DEFINE_TYPE_WITH_CODE (GdmPasswordExtension,
G_IMPLEMENT_INTERFACE (GDM_TYPE_CONVERSATION,
gdm_conversation_iface_init));
+static gboolean
+on_message_expired (GdmConversation *conversation)
+{
+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation);
+ extension->priv->message_timeout_id = 0;
+
+ gdm_conversation_message_set (conversation);
+ return FALSE;
+}
+
static void
gdm_password_extension_set_message (GdmConversation *conversation,
const char *message)
@@ -65,6 +77,11 @@ gdm_password_extension_set_message (GdmConversation *conversation,
GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation);
gtk_widget_show (extension->priv->message_label);
gtk_label_set_text (GTK_LABEL (extension->priv->message_label), message);
+
+ if (extension->priv->message_timeout_id != 0) {
+ g_source_remove (extension->priv->message_timeout_id);
+ }
+ extension->priv->message_timeout_id = g_timeout_add_seconds (2, (GSourceFunc) on_message_expired, conversation);
}
static void
@@ -251,6 +268,9 @@ gdm_password_extension_class_init (GdmPasswordExtensionClass *extension_class)
static void
gdm_password_extension_finalize (GObject *object)
{
+
+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (object);
+ g_source_remove (extension->priv->message_timeout_id);
}
static void
diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
index b40a21c..5e234b9 100644
--- a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
+++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
@@ -56,6 +56,8 @@ struct _GdmSmartcardExtensionPrivate
guint answer_pending : 1;
guint select_when_ready : 1;
+
+ guint message_timeout_id;
};
static void gdm_smartcard_extension_finalize (GObject *object);
@@ -164,6 +166,16 @@ stop_watching_for_smartcards (GdmSmartcardExtension *extension)
kill (extension->priv->worker_pid, SIGTERM);
}
+static gboolean
+on_message_expired (GdmConversation *conversation)
+{
+ GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation);
+ extension->priv->message_timeout_id = 0;
+
+ gdm_conversation_message_set (conversation);
+ return FALSE;
+}
+
static void
gdm_smartcard_extension_set_message (GdmConversation *conversation,
const char *message)
@@ -171,6 +183,11 @@ gdm_smartcard_extension_set_message (GdmConversation *conversation,
GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation);
gtk_widget_show (extension->priv->message_label);
gtk_label_set_text (GTK_LABEL (extension->priv->message_label), message);
+
+ if (extension->priv->message_timeout_id != 0) {
+ g_source_remove (extension->priv->message_timeout_id);
+ }
+ extension->priv->message_timeout_id = g_timeout_add_seconds (2, (GSourceFunc) on_message_expired, conversation);
}
static void
@@ -428,6 +445,8 @@ gdm_smartcard_extension_finalize (GObject *object)
if (extension->priv->worker_pid > 0) {
stop_watching_for_smartcards (extension);
}
+
+ g_source_remove (extension->priv->message_timeout_id);
}
static void
--
1.7.2.1
From 5e112d485929ce2c66c36677c7905530baf1fc92 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 4 Aug 2010 19:27:14 -0400
Subject: [PATCH 33/35] Drop cancelling message
We cancel very quickly in most cases now, so the message isn't useful
---
gui/simple-greeter/gdm-greeter-login-window.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
index 2d7c400..904269c 100644
--- a/gui/simple-greeter/gdm-greeter-login-window.c
+++ b/gui/simple-greeter/gdm-greeter-login-window.c
@@ -850,7 +850,7 @@ static void
do_cancel (GdmGreeterLoginWindow *login_window)
{
/* need to wait for response from backend */
- set_message (login_window, _("Cancelling..."));
+ //set_message (login_window, _("Cancelling..."));
restart_conversations (login_window);
}
--
1.7.2.1
From ade29eb7766e364273d4202f5a5339aeed11eb7f Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 6 Aug 2010 11:14:23 -0400
Subject: [PATCH 34/35] manage tasks outside of task list
The task list isn't very good for tracking tasks as
they come and go, since it replies on the groaty details
of toggle buttons and widget activation and such.
We now use it soley for display purposes when necessary
and otherwise, keep track of the tasks in a separate list.
Also, differentiate single authentication modes from
multiple authentication modes, so we don't show the task list
when we don't need to.
---
gui/simple-greeter/gdm-greeter-login-window.c | 396 +++++++++++++------------
1 files changed, 206 insertions(+), 190 deletions(-)
diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
index 904269c..ac00d62 100644
--- a/gui/simple-greeter/gdm-greeter-login-window.c
+++ b/gui/simple-greeter/gdm-greeter-login-window.c
@@ -98,6 +98,7 @@ enum {
MODE_TIMED_LOGIN,
MODE_SELECTION,
MODE_AUTHENTICATION,
+ MODE_MULTIPLE_AUTHENTICATION,
};
enum {
@@ -118,6 +119,8 @@ struct GdmGreeterLoginWindowPrivate
guint is_interactive : 1;
guint user_chooser_loaded : 1;
GConfClient *client;
+ GList *tasks;
+ GdmTask *active_task;
GList *tasks_to_enable;
gboolean banner_message_enabled;
@@ -179,6 +182,9 @@ static void gdm_greeter_login_window_start_session_when_ready (GdmGreeterLog
static void handle_stopped_conversation (GdmGreeterLoginWindow *login_window,
const char *service_name);
+static void begin_single_service_verification (GdmGreeterLoginWindow *login_window,
+ const char *service_name);
+
G_DEFINE_TYPE (GdmGreeterLoginWindow, gdm_greeter_login_window, GTK_TYPE_WINDOW)
static void
@@ -212,26 +218,22 @@ set_sensitive (GdmGreeterLoginWindow *login_window,
static void
set_focus (GdmGreeterLoginWindow *login_window)
{
- GdmTask *task;
-
gdk_window_focus (gtk_widget_get_window (GTK_WIDGET (login_window)), GDK_CURRENT_TIME);
- task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
-
- if (task != NULL && gdm_conversation_focus (GDM_CONVERSATION (task))) {
+ if (login_window->priv->active_task != NULL &&
+ gdm_conversation_focus (GDM_CONVERSATION (login_window->priv->active_task))) {
char *name;
- name = gdm_task_get_name (task);
+ name = gdm_task_get_name (login_window->priv->active_task);
g_debug ("GdmGreeterLoginWindow: focusing task %s", name);
g_free (name);
} else if (gtk_widget_get_realized (login_window->priv->user_chooser) && ! gtk_widget_has_focus (login_window->priv->user_chooser)) {
gtk_widget_grab_focus (login_window->priv->user_chooser);
}
- g_object_unref (task);
+
}
static gboolean
-set_task_conversation_message (GdmTaskList *task_list,
- GdmTask *task,
+set_task_conversation_message (GdmTask *task,
const char *message)
{
@@ -246,10 +248,9 @@ set_message (GdmGreeterLoginWindow *login_window,
{
g_return_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window));
- gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
- (GdmTaskListForeachFunc)
- set_task_conversation_message,
- (gpointer) text);
+ g_list_foreach (login_window->priv->tasks,
+ (GFunc) set_task_conversation_message,
+ (gpointer) text);
}
static void
@@ -452,7 +453,6 @@ set_log_in_button_mode (GdmGreeterLoginWindow *login_window,
GtkWidget *unlock_button;
char *item;
gboolean in_use;
- GdmTask *task;
in_use = FALSE;
item = gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (login_window->priv->user_chooser));
@@ -494,20 +494,16 @@ set_log_in_button_mode (GdmGreeterLoginWindow *login_window,
switch (mode) {
case LOGIN_BUTTON_HIDDEN:
- task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
- if (task != NULL) {
- hide_task_actions (task);
- g_object_unref (task);
+ if (login_window->priv->active_task != NULL) {
+ hide_task_actions (login_window->priv->active_task);
}
gtk_widget_hide (button);
break;
case LOGIN_BUTTON_ANSWER_QUERY:
- task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
- if (task != NULL) {
- show_task_actions (task);
- grab_default_button_for_task (task);
- g_object_unref (task);
+ if (login_window->priv->active_task != NULL) {
+ show_task_actions (login_window->priv->active_task);
+ grab_default_button_for_task (login_window->priv->active_task);
}
gtk_widget_hide (button);
@@ -554,6 +550,7 @@ maybe_show_cancel_button (GdmGreeterLoginWindow *login_window)
show = TRUE;
break;
case MODE_AUTHENTICATION:
+ case MODE_MULTIPLE_AUTHENTICATION:
if (login_window->priv->num_queries > 1) {
/* if we are inside a pam conversation past
the first step */
@@ -578,7 +575,7 @@ update_conversation_list_visibility (GdmGreeterLoginWindow *login_window)
{
int number_of_tasks;
- if (login_window->priv->dialog_mode != MODE_AUTHENTICATION) {
+ if (login_window->priv->dialog_mode != MODE_MULTIPLE_AUTHENTICATION) {
gtk_widget_hide (login_window->priv->conversation_list);
return;
}
@@ -619,6 +616,7 @@ switch_mode (GdmGreeterLoginWindow *login_window,
set_log_in_button_mode (login_window, LOGIN_BUTTON_TIMED_LOGIN);
break;
case MODE_AUTHENTICATION:
+ case MODE_MULTIPLE_AUTHENTICATION:
set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY);
break;
default:
@@ -657,39 +655,36 @@ switch_mode (GdmGreeterLoginWindow *login_window,
}
}
-static gboolean
-task_has_service_name (GdmTaskList *task_list,
- GdmTask *task,
- const char *service_name)
+static GdmTask *
+find_task_with_service_name (GdmGreeterLoginWindow *login_window,
+ const char *service_name)
{
- char *task_service_name;
- gboolean has_service_name;
+ GList *node;
- task_service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task));
+ node = login_window->priv->tasks;
+ while (node != NULL) {
+ GdmTask *task;
+ char *task_service_name;
+ gboolean has_service_name;
- has_service_name = strcmp (service_name, task_service_name) == 0;
- g_free (task_service_name);
+ task = GDM_TASK (node->data);
- return has_service_name;
-}
+ task_service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task));
+ has_service_name = strcmp (service_name, task_service_name) == 0;
+ g_free (task_service_name);
-static GdmTask *
-find_task_with_service_name (GdmGreeterLoginWindow *login_window,
- const char *service_name)
-{
- GdmTask *task;
+ if (has_service_name) {
+ return task;
+ }
- task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
- (GdmTaskListForeachFunc)
- task_has_service_name,
- (gpointer) service_name);
+ node = node->next;
+ }
- return task;
+ return NULL;
}
static gboolean
-reset_task (GdmTaskList *task_list,
- GdmTask *task,
+reset_task (GdmTask *task,
GdmGreeterLoginWindow *login_window)
{
char *name;
@@ -700,28 +695,31 @@ reset_task (GdmTaskList *task_list,
login_window->priv->tasks_to_enable = g_list_remove (login_window->priv->tasks_to_enable, task);
+ gdm_task_list_remove_task (GDM_TASK_LIST (login_window->priv->conversation_list), task);
gdm_conversation_reset (GDM_CONVERSATION (task));
return FALSE;
}
static gboolean
-task_is_disabled (GdmTaskList *task_list,
- GdmTask *task)
-{
- return !gdm_task_is_enabled (task);
-}
-
-static gboolean
tasks_are_enabled (GdmGreeterLoginWindow *login_window)
{
- GdmTask *task;
- task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
- (GdmTaskListForeachFunc)
- task_is_disabled,
- NULL);
+ GList *node;
+
+ node = login_window->priv->tasks;
+ while (node != NULL) {
+ GdmTask *task;
+
+ task = GDM_TASK (node->data);
+
+ if (!gdm_task_is_enabled (task)) {
+ return FALSE;
+ }
+
+ node = node->next;
+ }
- return task == NULL;
+ return TRUE;
}
static gboolean
@@ -735,6 +733,8 @@ can_jump_to_authenticate (GdmGreeterLoginWindow *login_window)
res = FALSE;
} else if (login_window->priv->dialog_mode == MODE_AUTHENTICATION) {
res = FALSE;
+ } else if (login_window->priv->dialog_mode == MODE_MULTIPLE_AUTHENTICATION) {
+ res = FALSE;
} else if (login_window->priv->user_list_disabled) {
res = (login_window->priv->timed_login_username == NULL);
} else {
@@ -744,39 +744,81 @@ can_jump_to_authenticate (GdmGreeterLoginWindow *login_window)
return res;
}
-static gboolean
-begin_task_verification (GdmTaskList *task_list,
- GdmTask *task,
- GdmGreeterLoginWindow *login_window)
+static void
+begin_other_verification (GdmGreeterLoginWindow *login_window)
{
- char *service_name;
+ /* FIXME: we should drop this code and do all OTHER handling
+ * entirely from within the password plugin
+ * (ala how smart card manages its "Smartcard Authentication" item)
+ */
+ begin_single_service_verification (login_window, "gdm-password");
+}
- if (!gdm_task_is_visible (task)) {
- return FALSE;
- }
+static void
+set_task_active (GdmGreeterLoginWindow *login_window,
+ GdmTask *task)
+{
+ GtkWidget *container;
+ char *name;
- service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task));
- if (service_name != NULL) {
- g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, service_name);
- g_free (service_name);
+ name = gdm_task_get_name (task);
+ g_debug ("GdmGreeterLoginWindow: task '%s' activated", name);
+ g_free (name);
+
+ container = g_object_get_data (G_OBJECT (task),
+ "gdm-greeter-login-window-page-container");
+
+ if (container == NULL) {
+ GtkWidget *page;
+
+ container = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+ gtk_container_add (GTK_CONTAINER (login_window->priv->auth_page_box),
+ container);
+
+ page = gdm_conversation_get_page (GDM_CONVERSATION (task));
+ if (page != NULL) {
+ gtk_container_add (GTK_CONTAINER (container), page);
+ gtk_widget_show (page);
+ }
+ g_object_set_data (G_OBJECT (task),
+ "gdm-greeter-login-window-page-container",
+ container);
}
- return FALSE;
+ gtk_widget_show (container);
+
+ login_window->priv->active_task = task;
+ switch_mode (login_window, login_window->priv->dialog_mode);
}
static void
-begin_verification (GdmGreeterLoginWindow *login_window)
+clear_active_task (GdmGreeterLoginWindow *login_window)
{
- gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
- (GdmTaskListForeachFunc)
- begin_task_verification,
- login_window);
- switch_mode (login_window, MODE_AUTHENTICATION);
+ GtkWidget *container;
+ GtkActionGroup *actions;
- update_conversation_list_visibility (login_window);
-}
+ if (login_window->priv->active_task == NULL) {
+ return;
+ }
+
+ container = g_object_get_data (G_OBJECT (login_window->priv->active_task),
+ "gdm-greeter-login-window-page-container");
+
+ if (container != NULL) {
+ gtk_widget_hide (container);
+ }
+
+ actions = gdm_conversation_get_actions (GDM_CONVERSATION (login_window->priv->active_task));
+
+ if (actions != NULL) {
+ gtk_action_group_set_sensitive (actions, FALSE);
+ gtk_action_group_set_visible (actions, FALSE);
+ g_object_unref (actions);
+ }
+ login_window->priv->active_task = NULL;
+}
static void
reset_dialog (GdmGreeterLoginWindow *login_window,
@@ -811,10 +853,7 @@ reset_dialog (GdmGreeterLoginWindow *login_window,
set_message (login_window, "");
}
- gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
- (GdmTaskListForeachFunc)
- reset_task,
- login_window);
+ g_list_foreach (login_window->priv->tasks, (GFunc) reset_task, login_window);
if (can_jump_to_authenticate (login_window)) {
/* If we don't have a user list jump straight to authenticate */
@@ -822,8 +861,9 @@ reset_dialog (GdmGreeterLoginWindow *login_window,
g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED],
0, GDM_USER_CHOOSER_USER_OTHER);
- begin_verification (login_window);
+ begin_other_verification (login_window);
} else {
+ clear_active_task (login_window);
switch_mode (login_window, dialog_mode);
}
@@ -868,9 +908,9 @@ gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window,
if (gdm_chooser_widget_is_loaded (GDM_CHOOSER_WIDGET (login_window->priv->user_chooser))) {
gdm_conversation_set_ready (GDM_CONVERSATION (task));
} else {
- login_window->priv->tasks_to_enable = g_list_prepend (login_window->priv->tasks_to_enable, task);
+ login_window->priv->tasks_to_enable = g_list_prepend (login_window->priv->tasks_to_enable,
+ g_object_ref (task));
}
- g_object_unref (task);
}
set_sensitive (GDM_GREETER_LOGIN_WINDOW (login_window), TRUE);
@@ -882,7 +922,7 @@ gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window,
g_debug ("Starting PAM conversation since user list disabled or no local users");
g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED],
0, GDM_USER_CHOOSER_USER_OTHER);
- begin_verification (login_window);
+ begin_other_verification (login_window);
}
return TRUE;
@@ -904,24 +944,37 @@ handle_stopped_conversation (GdmGreeterLoginWindow *login_window,
return;
}
+ if (login_window->priv->dialog_mode == MODE_AUTHENTICATION) {
+ g_debug ("GdmGreeterLoginWindow: conversation failed, starting over");
+ restart_conversations (login_window);
+ return;
+ } else if (login_window->priv->dialog_mode != MODE_MULTIPLE_AUTHENTICATION) {
+ g_warning ("conversation %s stopped when it shouldn't have been running (mode %d)",
+ service_name, login_window->priv->dialog_mode);
+ restart_conversations (login_window);
+ return;
+ }
+
task = find_task_with_service_name (login_window, service_name);
if (task != NULL) {
gdm_conversation_reset (GDM_CONVERSATION (task));
g_object_set_data (G_OBJECT (task), "needs-to-be-stopped", GINT_TO_POINTER (FALSE));
- g_object_unref (task);
}
/* If every conversation has failed, then just start over.
*/
task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
- if (!gdm_task_is_enabled (task)) {
+ if (task == NULL || !gdm_task_is_enabled (task)) {
g_debug ("GdmGreeterLoginWindow: No conversations left, starting over");
restart_conversations (login_window);
}
- g_object_unref (task);
+
+ if (task != NULL) {
+ g_object_unref (task);
+ }
update_conversation_list_visibility (login_window);
}
@@ -937,8 +990,8 @@ gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_wind
g_debug ("GdmGreeterLoginWindow: conversation '%s' has stopped", service_name);
- task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
- if (task != NULL && task_has_service_name (GDM_TASK_LIST (login_window->priv->conversation_list), task, service_name)) {
+ task = find_task_with_service_name (login_window, service_name);
+ if (task != NULL && gdm_task_is_enabled (task)) {
messages_pending = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (task), "message-pending"));
} else {
@@ -957,8 +1010,7 @@ gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_wind
}
static gboolean
-restart_task_conversation (GdmTaskList *task_list,
- GdmTask *task,
+restart_task_conversation (GdmTask *task,
GdmGreeterLoginWindow *login_window)
{
char *service_name;
@@ -987,10 +1039,7 @@ gdm_greeter_login_window_reset (GdmGreeterLoginWindow *login_window)
g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
reset_dialog (GDM_GREETER_LOGIN_WINDOW (login_window), MODE_SELECTION);
- gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
- (GdmTaskListForeachFunc)
- restart_task_conversation,
- login_window);
+ g_list_foreach (login_window->priv->tasks, (GFunc) restart_task_conversation, login_window);
g_free (login_window->priv->service_name_of_session_ready_to_start);
login_window->priv->service_name_of_session_ready_to_start = NULL;
@@ -1016,7 +1065,6 @@ gdm_greeter_login_window_info (GdmGreeterLoginWindow *login_window,
gdm_conversation_set_message (GDM_CONVERSATION (task),
text);
show_task_actions (task);
- g_object_unref (task);
}
return TRUE;
@@ -1040,7 +1088,6 @@ gdm_greeter_login_window_problem (GdmGreeterLoginWindow *login_window,
gdm_conversation_set_message (GDM_CONVERSATION (task),
text);
show_task_actions (task);
- g_object_unref (task);
}
gdk_window_beep (GTK_WIDGET (login_window)->window);
@@ -1079,9 +1126,19 @@ gdm_greeter_login_window_service_unavailable (GdmGreeterLoginWindow *login_windo
task = find_task_with_service_name (login_window, service_name);
if (task != NULL) {
- gdm_task_list_remove_task (GDM_TASK_LIST (login_window->priv->conversation_list),
- task);
- g_object_unref (task);
+ GdmTask *active_task;
+
+ gdm_task_set_enabled (task, FALSE);
+
+ active_task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
+
+ if (active_task == task) {
+ restart_conversations (login_window);
+ }
+
+ if (active_task != NULL) {
+ g_object_unref (active_task);
+ }
}
return TRUE;
@@ -1216,7 +1273,6 @@ gdm_greeter_login_window_info_query (GdmGreeterLoginWindow *login_window,
if (task != NULL) {
gdm_conversation_ask_question (GDM_CONVERSATION (task),
text);
- g_object_unref (task);
}
set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY);
@@ -1247,7 +1303,6 @@ gdm_greeter_login_window_secret_info_query (GdmGreeterLoginWindow *login_window,
if (task != NULL) {
gdm_conversation_ask_secret (GDM_CONVERSATION (task),
text);
- g_object_unref (task);
}
set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY);
@@ -1342,8 +1397,7 @@ on_user_chooser_visibility_changed (GdmGreeterLoginWindow *login_window)
}
static gboolean
-begin_task_verification_for_selected_user (GdmTaskList *task_list,
- GdmTask *task,
+begin_task_verification_for_selected_user (GdmTask *task,
GdmGreeterLoginWindow *login_window)
{
char *user_name;
@@ -1361,6 +1415,9 @@ begin_task_verification_for_selected_user (GdmTaskList *task_list,
g_free (service_name);
}
+ gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+ task);
+
g_free (user_name);
return FALSE;
}
@@ -1408,7 +1465,7 @@ on_users_loaded (GdmUserChooserWidget *user_chooser,
g_debug ("GdmGreeterLoginWindow: jumping straight to authenticate");
g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED],
0, GDM_USER_CHOOSER_USER_OTHER);
- begin_verification (login_window);
+ begin_other_verification (login_window);
}
}
@@ -1416,19 +1473,23 @@ static void
choose_user (GdmGreeterLoginWindow *login_window,
const char *user_name)
{
+ GdmTask *task;
+
g_assert (user_name != NULL);
g_debug ("GdmGreeterLoginWindow: user chosen '%s'", user_name);
g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED],
0, user_name);
+ g_list_foreach (login_window->priv->tasks,
+ (GFunc) begin_task_verification_for_selected_user,
+ login_window);
- gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
- (GdmTaskListForeachFunc)
- begin_task_verification_for_selected_user,
- login_window);
+ task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
+ set_task_active (login_window, task);
+ g_object_unref (task);
- switch_mode (login_window, MODE_AUTHENTICATION);
+ switch_mode (login_window, MODE_MULTIPLE_AUTHENTICATION);
update_conversation_list_visibility (login_window);
}
@@ -1444,35 +1505,34 @@ begin_auto_login (GdmGreeterLoginWindow *login_window)
/* just wait for the user to select language and stuff */
set_message (login_window, _("Select language and click Log In"));
+ clear_active_task (login_window);
switch_mode (login_window, MODE_TIMED_LOGIN);
show_widget (login_window, "conversation-list", FALSE);
- gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
- (GdmTaskListForeachFunc) reset_task,
- login_window);
+ g_list_foreach (login_window->priv->tasks,
+ (GFunc) reset_task,
+ login_window);
}
-static gboolean
-reset_task_if_not_given (GdmTaskList *task_list,
- GdmTask *task,
+static void
+reset_task_if_not_given (GdmTask *task,
GdmTask *given_task)
{
if (task == given_task) {
- return FALSE;
+ return;
}
gdm_conversation_reset (GDM_CONVERSATION (task));
- return FALSE;
}
static void
reset_every_task_but_given_task (GdmGreeterLoginWindow *login_window,
GdmTask *task)
{
- gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
- (GdmTaskListForeachFunc)
- reset_task_if_not_given,
- task);
+ g_list_foreach (login_window->priv->tasks,
+ (GFunc) reset_task_if_not_given,
+ task);
+
}
static void
@@ -1495,11 +1555,10 @@ begin_single_service_verification (GdmGreeterLoginWindow *login_window,
*/
g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, service_name);
- switch_mode (login_window, MODE_AUTHENTICATION);
- gdm_task_list_set_active_task (GDM_TASK_LIST (login_window->priv->conversation_list), task);
-
reset_every_task_but_given_task (login_window, task);
- g_object_unref (task);
+
+ set_task_active (login_window, task);
+ switch_mode (login_window, MODE_AUTHENTICATION);
show_widget (login_window, "conversation-list", FALSE);
}
@@ -1530,7 +1589,7 @@ on_user_chooser_activated (GdmUserChooserWidget *user_chooser,
g_debug ("GdmGreeterLoginWindow: Starting all auth conversations");
g_free (item_id);
- begin_verification (login_window);
+ begin_other_verification (login_window);
} else if (strcmp (item_id, GDM_USER_CHOOSER_USER_GUEST) == 0) {
/* FIXME: handle guest account stuff */
g_free (item_id);
@@ -1718,63 +1777,28 @@ static void
on_task_activated (GdmGreeterLoginWindow *login_window,
GdmTask *task)
{
- GtkWidget *container;
- char *name;
-
- name = gdm_task_get_name (task);
- g_debug ("GdmGreeterLoginWindow: task '%s' activated", name);
- g_free (name);
-
- container = g_object_get_data (G_OBJECT (task),
- "gdm-greeter-login-window-page-container");
-
- if (container == NULL) {
- GtkWidget *page;
-
- container = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
- gtk_container_add (GTK_CONTAINER (login_window->priv->auth_page_box),
- container);
-
- page = gdm_conversation_get_page (GDM_CONVERSATION (task));
- if (page != NULL) {
- gtk_container_add (GTK_CONTAINER (container), page);
- gtk_widget_show (page);
- }
- g_object_set_data (G_OBJECT (task),
- "gdm-greeter-login-window-page-container",
- container);
- }
-
- gtk_widget_show (container);
- switch_mode (login_window, login_window->priv->dialog_mode);
+ set_task_active (login_window, task);
}
static void
on_task_deactivated (GdmGreeterLoginWindow *login_window,
GdmTask *task)
{
- GtkWidget *container;
char *name;
- GtkActionGroup *actions;
+
+ if (login_window->priv->active_task != task) {
+ g_warning ("inactive task has been deactivated");
+ return;
+ }
name = gdm_task_get_name (task);
g_debug ("GdmGreeterLoginWindow: task '%s' now in background", name);
g_free (name);
- container = g_object_get_data (G_OBJECT (task),
- "gdm-greeter-login-window-page-container");
+ clear_active_task (login_window);
- if (container != NULL) {
- gtk_widget_hide (container);
- }
-
- actions = gdm_conversation_get_actions (GDM_CONVERSATION (task));
-
- if (actions != NULL) {
- gtk_action_group_set_sensitive (actions, FALSE);
- gtk_action_group_set_visible (actions, FALSE);
- g_object_unref (actions);
- }
+ login_window->priv->active_task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
+ g_object_unref (login_window->priv->active_task);
}
static void
@@ -1879,6 +1903,7 @@ load_theme (GdmGreeterLoginWindow *login_window)
box = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "computer-info-event-box"));
g_signal_connect (box, "button-press-event", G_CALLBACK (on_computer_info_label_button_press), login_window);
+ clear_active_task (login_window);
switch_mode (login_window, MODE_SELECTION);
gdm_profile_end (NULL);
@@ -2217,15 +2242,12 @@ on_conversation_chose_user (GdmGreeterLoginWindow *login_window,
/* If we're already authenticating then we can't pick a user
*/
- if (login_window->priv->dialog_mode == MODE_AUTHENTICATION) {
+ if (login_window->priv->dialog_mode == MODE_AUTHENTICATION || login_window->priv->dialog_mode == MODE_MULTIPLE_AUTHENTICATION) {
return FALSE;
}
- if (gdm_task_list_set_active_task (GDM_TASK_LIST (login_window->priv->conversation_list),
- GDM_TASK (conversation))) {
- gdm_user_chooser_widget_set_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser),
- username);
- }
+ gdm_user_chooser_widget_set_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser),
+ username);
return TRUE;
}
@@ -2249,11 +2271,7 @@ on_conversation_message_set (GdmGreeterLoginWindow *login_window,
}
if (login_window->priv->service_name_of_session_ready_to_start != NULL ) {
- GdmTask *task;
-
- task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
-
- if (task == GDM_TASK (conversation)) {
+ if (login_window->priv->active_task == GDM_TASK (conversation)) {
gdm_greeter_login_window_start_session (login_window);
}
}
@@ -2429,9 +2447,7 @@ gdm_greeter_login_window_add_extension (GdmGreeterLoginWindow *login_window,
g_debug ("GdmGreeterLoginWindow: new extension '%s - %s' added",
name, description);
- gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list),
- GDM_TASK (extension));
-
+ login_window->priv->tasks = g_list_append (login_window->priv->tasks, extension);
service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (extension));
if (gdm_task_is_choosable (GDM_TASK (extension))) {
--
1.7.2.1
From a37938a440ad84b334ae5a851884030409ccdc22 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Mon, 9 Aug 2010 18:09:19 -0400
Subject: [PATCH 35/35] hide task actions more aggressively
This fixes "dual login buttons" after the user hits cancel.
---
gui/simple-greeter/gdm-greeter-login-window.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
index ac00d62..31e599f 100644
--- a/gui/simple-greeter/gdm-greeter-login-window.c
+++ b/gui/simple-greeter/gdm-greeter-login-window.c
@@ -492,6 +492,8 @@ set_log_in_button_mode (GdmGreeterLoginWindow *login_window,
login_window->priv->current_button = button;
+ g_list_foreach (login_window->priv->tasks, (GFunc) hide_task_actions, NULL);
+
switch (mode) {
case LOGIN_BUTTON_HIDDEN:
if (login_window->priv->active_task != NULL) {
@@ -696,6 +698,7 @@ reset_task (GdmTask *task,
login_window->priv->tasks_to_enable = g_list_remove (login_window->priv->tasks_to_enable, task);
gdm_task_list_remove_task (GDM_TASK_LIST (login_window->priv->conversation_list), task);
+ hide_task_actions (task);
gdm_conversation_reset (GDM_CONVERSATION (task));
return FALSE;
}
--
1.7.2.1