From b96b21d5497ce4ed3b362f4dc09b2f5fd654f3a3 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 20 Feb 2009 13:52:19 -0500 Subject: [PATCH 01/33] Add a comment marking protected api in chooser The chooser widget has methods that only its subclasses are supposed to call. We should mark them as such. --- gui/simple-greeter/gdm-chooser-widget.h | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/gui/simple-greeter/gdm-chooser-widget.h b/gui/simple-greeter/gdm-chooser-widget.h index 578e613..7e3e59c 100644 --- a/gui/simple-greeter/gdm-chooser-widget.h +++ b/gui/simple-greeter/gdm-chooser-widget.h @@ -136,6 +136,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); +/* Protected + */ void gdm_chooser_widget_loaded (GdmChooserWidget *widget); G_END_DECLS -- 1.6.2.2 From fafe68243000a7b2f97086daa3d4ad651e7ac905 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 6 Feb 2009 17:44:37 -0500 Subject: [PATCH 02/33] Drop duplicated entry introspection output --- daemon/gdm-greeter-server.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/daemon/gdm-greeter-server.c b/daemon/gdm-greeter-server.c index 2e01d33..cecce83 100644 --- a/daemon/gdm-greeter-server.c +++ b/daemon/gdm-greeter-server.c @@ -752,7 +752,6 @@ do_introspect (DBusConnection *connection, " \n" " \n" " \n" - " \n" " \n" " \n" " \n" -- 1.6.2.2 From 4dc394bb5b87d3cbead40bb6565eec75d755ddae Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 2 Mar 2009 10:07:03 -0500 Subject: [PATCH 03/33] Make lookup_item not warn when passing NULL for args gtk_tree_model_get doesn't like NULL, and we allow NULL for optional return values. We now check each argument for NULL and call gtk_tree_model_get individually N times (one for each argument) instead of just once. --- gui/simple-greeter/gdm-chooser-widget.c | 31 ++++++++++++++++++++++++------- 1 files changed, 24 insertions(+), 7 deletions(-) diff --git a/gui/simple-greeter/gdm-chooser-widget.c b/gui/simple-greeter/gdm-chooser-widget.c index f0298c6..b1ba9b4 100644 --- a/gui/simple-greeter/gdm-chooser-widget.c +++ b/gui/simple-greeter/gdm-chooser-widget.c @@ -2132,13 +2132,30 @@ gdm_chooser_widget_lookup_item (GdmChooserWidget *widget, } g_free (active_item_id); - gtk_tree_model_get (GTK_TREE_MODEL (widget->priv->list_store), &iter, - CHOOSER_IMAGE_COLUMN, image, - CHOOSER_NAME_COLUMN, name, - CHOOSER_PRIORITY_COLUMN, priority, - CHOOSER_ITEM_IS_IN_USE_COLUMN, is_in_use, - CHOOSER_ITEM_IS_SEPARATED_COLUMN, is_separate, - -1); + if (image != NULL) { + gtk_tree_model_get (GTK_TREE_MODEL (widget->priv->list_store), &iter, + CHOOSER_IMAGE_COLUMN, image, -1); + } + + if (name != NULL) { + gtk_tree_model_get (GTK_TREE_MODEL (widget->priv->list_store), &iter, + CHOOSER_NAME_COLUMN, name, -1); + } + + if (priority != NULL) { + gtk_tree_model_get (GTK_TREE_MODEL (widget->priv->list_store), &iter, + CHOOSER_PRIORITY_COLUMN, priority, -1); + } + + if (is_in_use != NULL) { + gtk_tree_model_get (GTK_TREE_MODEL (widget->priv->list_store), &iter, + CHOOSER_ITEM_IS_IN_USE_COLUMN, is_in_use, -1); + } + + if (is_separate != NULL) { + gtk_tree_model_get (GTK_TREE_MODEL (widget->priv->list_store), &iter, + CHOOSER_ITEM_IS_SEPARATED_COLUMN, is_separate, -1); + } return TRUE; } -- 1.6.2.2 From c68b126096e04b3b963a10658d5a835ab716599f Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 6 Feb 2009 15:35:00 -0500 Subject: [PATCH 04/33] Drop "stopped" signal from worker-job class It was unused, dead code. --- daemon/gdm-session-direct.c | 14 -------------- daemon/gdm-session-worker-job.c | 11 ----------- daemon/gdm-session-worker-job.h | 1 - 3 files changed, 0 insertions(+), 26 deletions(-) diff --git a/daemon/gdm-session-direct.c b/daemon/gdm-session-direct.c index 34a126f..3942ec7 100644 --- a/daemon/gdm-session-direct.c +++ b/daemon/gdm-session-direct.c @@ -1548,13 +1548,6 @@ gdm_session_direct_init (GdmSessionDirect *session) } static void -worker_stopped (GdmSessionWorkerJob *job, - GdmSessionDirect *session) -{ - g_debug ("GdmSessionDirect: Worker job stopped"); -} - -static void worker_started (GdmSessionWorkerJob *job, GdmSessionDirect *session) { @@ -1605,10 +1598,6 @@ start_worker (GdmSessionDirect *session) 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, - "stopped", - G_CALLBACK (worker_stopped), - session); - g_signal_connect (session->priv->job, "started", G_CALLBACK (worker_started), session); @@ -1630,9 +1619,6 @@ static void stop_worker (GdmSessionDirect *session) { g_signal_handlers_disconnect_by_func (session->priv->job, - G_CALLBACK (worker_stopped), - session); - g_signal_handlers_disconnect_by_func (session->priv->job, G_CALLBACK (worker_started), session); g_signal_handlers_disconnect_by_func (session->priv->job, diff --git a/daemon/gdm-session-worker-job.c b/daemon/gdm-session-worker-job.c index 6723464..633d6e2 100644 --- a/daemon/gdm-session-worker-job.c +++ b/daemon/gdm-session-worker-job.c @@ -68,7 +68,6 @@ enum { enum { STARTED, - STOPPED, EXITED, DIED, LAST_SIGNAL @@ -390,16 +389,6 @@ gdm_session_worker_job_class_init (GdmSessionWorkerJobClass *klass) g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - signals [STOPPED] = - g_signal_new ("stopped", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GdmSessionWorkerJobClass, stopped), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); signals [EXITED] = g_signal_new ("exited", G_OBJECT_CLASS_TYPE (object_class), diff --git a/daemon/gdm-session-worker-job.h b/daemon/gdm-session-worker-job.h index d42eb37..5ad1c92 100644 --- a/daemon/gdm-session-worker-job.h +++ b/daemon/gdm-session-worker-job.h @@ -46,7 +46,6 @@ typedef struct GObjectClass parent_class; void (* started) (GdmSessionWorkerJob *session_worker_job); - void (* stopped) (GdmSessionWorkerJob *session_worker_job); void (* exited) (GdmSessionWorkerJob *session_worker_job, int exit_code); -- 1.6.2.2 From b1fbbdad6d4fd847b248aaad7eec9a8730714b06 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 16 Jan 2009 11:00:08 -0500 Subject: [PATCH 05/33] Drop session "Open" in favor of "StartConversation" 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 | 13 +- daemon/gdm-product-slave.c | 47 ++++-- daemon/gdm-session-direct.c | 327 ++++++++++++++++++++++++--------------- daemon/gdm-session-private.h | 3 +- daemon/gdm-session-relay.c | 29 +++-- daemon/gdm-session-worker-job.c | 7 + daemon/gdm-session-worker-job.h | 2 + daemon/gdm-session.c | 20 ++- daemon/gdm-session.h | 9 +- daemon/gdm-simple-slave.c | 3 - daemon/test-session.c | 13 +- 11 files changed, 296 insertions(+), 177 deletions(-) diff --git a/daemon/gdm-factory-slave.c b/daemon/gdm-factory-slave.c index d09c913..6497293 100644 --- a/daemon/gdm-factory-slave.c +++ b/daemon/gdm-factory-slave.c @@ -180,10 +180,11 @@ on_session_secret_info_query (GdmSession *session, } static void -on_session_opened (GdmSession *session, - GdmFactorySlave *slave) +on_session_conversation_started (GdmSession *session, + GdmFactorySlave *slave, + const char *service_name) { - g_debug ("GdmFactorySlave: session opened"); + g_debug ("GdmFactorySlave: session conversation started"); gdm_greeter_server_ready (slave->priv->greeter_server); } @@ -367,7 +368,7 @@ on_session_relay_connected (GdmSessionRelay *session, { g_debug ("GdmFactorySlave: Relay Connected"); - gdm_session_open (GDM_SESSION (slave->priv->session)); + gdm_session_start_conversation (GDM_SESSION (slave->priv->session), "gdm"); } static void @@ -694,8 +695,8 @@ gdm_factory_slave_start (GdmSlave *slave) GDM_FACTORY_SLAVE (slave)->priv->session = gdm_session_relay_new (); g_signal_connect (GDM_FACTORY_SLAVE (slave)->priv->session, - "opened", - G_CALLBACK (on_session_opened), + "conversation-started", + G_CALLBACK (on_session_conversation_started), slave); g_signal_connect (GDM_FACTORY_SLAVE (slave)->priv->session, "setup-complete", diff --git a/daemon/gdm-product-slave.c b/daemon/gdm-product-slave.c index 9adcb09..15a2820 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_opened (GdmProductSlave *slave) +relay_session_conversation_started (GdmProductSlave *slave, + const char *service_name) { - send_dbus_void_method (slave->priv->session_relay_connection, - "Opened"); + send_dbus_string_method (slave->priv->session_relay_connection, + "ConversationStarted", service_name); } static void -on_session_opened (GdmSession *session, - GdmProductSlave *slave) +on_session_conversation_started (GdmSession *session, + const char *service_name, + GdmProductSlave *slave) { - g_debug ("GdmProductSlave: session opened"); + g_debug ("GdmProductSlave: session conversation started"); - relay_session_opened (slave); + relay_session_conversation_started (slave, service_name); } static void @@ -784,10 +786,27 @@ on_relay_user_selected (GdmProductSlave *slave, } static void -on_relay_open (GdmProductSlave *slave, - DBusMessage *message) +on_relay_start_conversation (GdmProductSlave *slave, + DBusMessage *message) { - gdm_session_open (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 @@ -832,8 +851,8 @@ create_new_session (GdmProductSlave *slave) g_free (display_device); g_signal_connect (slave->priv->session, - "opened", - G_CALLBACK (on_session_opened), + "conversation-started", + G_CALLBACK (on_session_conversation_started), slave); g_signal_connect (slave->priv->session, "setup-complete", @@ -991,8 +1010,8 @@ relay_dbus_handle_message (DBusConnection *connection, on_relay_user_selected (slave, message); } else if (dbus_message_is_signal (message, RELAY_SERVER_DBUS_INTERFACE, "StartSession")) { on_relay_start_session (slave, message); - } else if (dbus_message_is_signal (message, RELAY_SERVER_DBUS_INTERFACE, "Open")) { - on_relay_open (slave, message); + } else if (dbus_message_is_signal (message, RELAY_SERVER_DBUS_INTERFACE, "StartConversation")) { + on_relay_start_conversation (slave, message); } else if (dbus_message_is_signal (message, RELAY_SERVER_DBUS_INTERFACE, "Cancelled")) { on_relay_cancelled (slave, message); } else { diff --git a/daemon/gdm-session-direct.c b/daemon/gdm-session-direct.c index 3942ec7..304a67b 100644 --- a/daemon/gdm-session-direct.c +++ b/daemon/gdm-session-direct.c @@ -61,6 +61,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 */ @@ -73,13 +83,11 @@ struct _GdmSessionDirectPrivate char *selected_user; char *user_x11_authority_file; - DBusMessage *message_pending_reply; - DBusConnection *worker_connection; + GdmSessionConversation *conversation; - GdmSessionWorkerJob *job; - GPid session_pid; guint32 is_authenticated : 1; guint32 is_running : 1; + GPid session_pid; /* object lifetime scope */ char *id; @@ -116,39 +124,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, @@ -157,7 +165,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); } @@ -165,18 +173,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); } @@ -188,22 +196,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 @@ -211,11 +229,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 @@ -223,6 +246,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, @@ -731,25 +755,26 @@ 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); + conversation = session->priv->conversation; + 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 @@ -758,27 +783,29 @@ answer_pending_query (GdmSessionDirect *session, { DBusMessage *reply; DBusMessageIter iter; + GdmSessionConversation *conversation; - g_assert (session->priv->message_pending_reply != NULL); + conversation = find_conversation_by_name (session, service_name); - 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); + conversation = session->priv->conversation; + 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 @@ -796,7 +823,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); @@ -819,7 +846,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); @@ -861,7 +888,7 @@ gdm_session_direct_handle_cancel_pending_query (GdmSessionDirect *session, DBusMessage *reply; g_debug ("GdmSessionDirect: worker cancelling pending query"); - cancel_pending_query (session); + cancel_pending_query (conversation); reply = dbus_message_new_method_return (message); dbus_connection_send (connection, reply, NULL); @@ -1439,16 +1466,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); @@ -1465,8 +1494,9 @@ handle_connection (DBusServer *server, &vtable, session); - g_debug ("GdmSessionDirect: Emitting opened signal"); - _gdm_session_opened (GDM_SESSION (session)); + g_debug ("GdmSessionDirect: Emitting conversation-started signal"); + _gdm_session_conversation_started (GDM_SESSION (session), + conversation->service_name); } } @@ -1536,8 +1566,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, @@ -1549,7 +1577,7 @@ gdm_session_direct_init (GdmSessionDirect *session) static void worker_started (GdmSessionWorkerJob *job, - GdmSessionDirect *session) + GdmSessionConversation *conversation) { g_debug ("GdmSessionDirect: Worker job started"); } @@ -1557,99 +1585,119 @@ 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_authenticated) { + if (!conversation->session->priv->is_authenticated) { char *msg; msg = g_strdup_printf (_("worker exited with status %d"), code); - _gdm_session_authentication_failed (GDM_SESSION (session), msg); + _gdm_session_authentication_failed (GDM_SESSION (conversation->session), msg); g_free (msg); - } else if (session->priv->is_running) { - _gdm_session_session_exited (GDM_SESSION (session), code); + } else 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_authenticated) { + if (!conversation->session->priv->is_authenticated) { char *msg; msg = g_strdup_printf (_("worker exited with status %d"), signum); - _gdm_session_authentication_failed (GDM_SESSION (session), msg); + _gdm_session_authentication_failed (GDM_SESSION (conversation->session), msg); g_free (msg); - } else if (session->priv->is_running) { - _gdm_session_session_died (GDM_SESSION (session), signum); + } else 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); - 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_remove_filter (conversation->worker_connection, on_message, session); + + 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_open (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: Opening session"); + g_debug ("GdmSessionDirect: starting conversation"); - start_worker (impl); + impl->priv->conversation = start_conversation (impl, service_name); } static void @@ -1662,6 +1710,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); @@ -1699,7 +1748,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"); } @@ -1717,6 +1767,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); @@ -1760,7 +1811,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"); } @@ -1774,7 +1826,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); @@ -1788,7 +1841,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); @@ -1801,22 +1855,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 @@ -1824,16 +1884,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 (); @@ -1847,6 +1910,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, @@ -1856,7 +1920,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"); } @@ -1986,6 +2051,7 @@ static void gdm_session_direct_start_session (GdmSession *session) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); + GdmSessionConversation *conversation; char *command; char *program; @@ -1999,7 +2065,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); } @@ -2012,16 +2079,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); @@ -2050,7 +2113,6 @@ gdm_session_direct_close (GdmSession *session) g_hash_table_remove_all (impl->priv->environment); - impl->priv->session_pid = -1; impl->priv->is_authenticated = FALSE; impl->priv->is_running = FALSE; } @@ -2070,10 +2132,19 @@ static void gdm_session_direct_cancel (GdmSession *session) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); + GHashTableIter iter; + gpointer key, value; g_return_if_fail (session != NULL); - cancel_pending_query (impl); + g_hash_table_iter_init (&iter, impl->priv->conversations); + while (g_hash_table_iter_next (&iter, &key, &value)) { + GdmSessionConversation *conversation; + + conversation = (GdmSessionConversation *) value; + + cancel_pending_query (conversation); + } } char * @@ -2089,6 +2160,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); @@ -2098,7 +2170,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)); } @@ -2107,6 +2180,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); @@ -2116,7 +2190,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)); } @@ -2125,6 +2200,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); @@ -2134,7 +2210,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)); } @@ -2394,7 +2471,7 @@ gdm_session_direct_constructor (GType type, static void gdm_session_iface_init (GdmSessionIface *iface) { - iface->open = gdm_session_direct_open; + iface->start_conversation = gdm_session_direct_start_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 6a6fcfc..074aa6f 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_opened (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 b57bf89..35b4738 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_open (GdmSession *session) +gdm_session_relay_start_conversation (GdmSession *session, + const char *service_name) { GdmSessionRelay *impl = GDM_SESSION_RELAY (session); - send_dbus_void_signal (impl, "Open"); + send_dbus_string_signal (impl, "StartConversation", service_name); } static void @@ -664,22 +665,28 @@ handle_session_stopped (GdmSessionRelay *session_relay, } static DBusHandlerResult -handle_opened (GdmSessionRelay *session_relay, +handle_conversation_started (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); + } - g_debug ("GdmSessionRelay: Opened"); + g_debug ("GdmSessionRelay: Conversation Started"); reply = dbus_message_new_method_return (message); dbus_connection_send (connection, reply, NULL); dbus_message_unref (reply); - _gdm_session_opened (GDM_SESSION (session_relay)); + _gdm_session_conversation_started (GDM_SESSION (session_relay), service_name); return DBUS_HANDLER_RESULT_HANDLED; } @@ -719,8 +726,8 @@ session_handle_child_message (DBusConnection *connection, return handle_session_started (session_relay, connection, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_RELAY_DBUS_INTERFACE, "SessionStopped")) { return handle_session_stopped (session_relay, connection, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_RELAY_DBUS_INTERFACE, "Opened")) { - return handle_opened (session_relay, connection, message); + } else if (dbus_message_is_method_call (message, GDM_SESSION_RELAY_DBUS_INTERFACE, "ConversationStarted")) { + return handle_conversation_started (session_relay, connection, message); } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; @@ -749,7 +756,8 @@ do_introspect (DBusConnection *connection, /* interface */ xml = g_string_append (xml, " \n" - " \n" + " \n" + " \n" " \n" " \n" " \n" @@ -810,7 +818,8 @@ do_introspect (DBusConnection *connection, " \n" " \n" - " \n" + " \n" + " \n" " \n" " \n" " \n" @@ -1106,7 +1115,7 @@ static void gdm_session_iface_init (GdmSessionIface *iface) { - iface->open = gdm_session_relay_open; + iface->start_conversation = gdm_session_relay_start_conversation; iface->setup = gdm_session_relay_setup; iface->setup_for_user = gdm_session_relay_setup_for_user; iface->authenticate = gdm_session_relay_authenticate; diff --git a/daemon/gdm-session-worker-job.c b/daemon/gdm-session-worker-job.c index 633d6e2..9c020fa 100644 --- a/daemon/gdm-session-worker-job.c +++ b/daemon/gdm-session-worker-job.c @@ -296,6 +296,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 feb7938..0073294 100644 --- a/daemon/gdm-session.c +++ b/daemon/gdm-session.c @@ -28,7 +28,7 @@ #include "gdm-session-private.h" enum { - OPENED = 0, + CONVERSATION_STARTED = 0, SETUP_COMPLETE, SETUP_FAILED, RESET_COMPLETE, @@ -78,11 +78,12 @@ gdm_session_get_type (void) } void -gdm_session_open (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)->open (session); + GDM_SESSION_GET_IFACE (session)->start_conversation (session, service_name); } void @@ -203,14 +204,14 @@ gdm_session_class_init (gpointer g_iface) { GType iface_type = G_TYPE_FROM_INTERFACE (g_iface); - signals [OPENED] = - g_signal_new ("opened", + signals [CONVERSATION_STARTED] = + g_signal_new ("conversation-started", iface_type, G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GdmSessionIface, opened), + 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] = @@ -608,10 +609,11 @@ _gdm_session_session_died (GdmSession *session, } void -_gdm_session_opened (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 [OPENED], 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 dfb7e27..77e0cf6 100644 --- a/daemon/gdm-session.h +++ b/daemon/gdm-session.h @@ -45,7 +45,8 @@ struct _GdmSessionIface GTypeInterface base_iface; /* Methods */ - void (* open) (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, @@ -103,7 +104,8 @@ struct _GdmSessionIface int exit_code); void (* session_died) (GdmSession *session, int signal_number); - void (* opened) (GdmSession *session); + void (* conversation_started) (GdmSession *session, + const char *service_name); void (* closed) (GdmSession *session); void (* selected_user_changed) (GdmSession *session, const char *text); @@ -118,7 +120,8 @@ struct _GdmSessionIface GType gdm_session_get_type (void) G_GNUC_CONST; -void gdm_session_open (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 3a2623c..f193ff5 100644 --- a/daemon/gdm-simple-slave.c +++ b/daemon/gdm-simple-slave.c @@ -174,7 +174,6 @@ reset_session (GdmSimpleSlave *slave) { destroy_session (slave); create_new_session (slave); - gdm_session_open (GDM_SESSION (slave->priv->session)); } static gboolean @@ -816,8 +815,6 @@ on_greeter_connected (GdmGreeterServer *greeter_server, g_debug ("GdmSimpleSlave: Greeter connected"); - gdm_session_open (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 c6a158c..d9fa26e 100644 --- a/daemon/test-session.c +++ b/daemon/test-session.c @@ -33,12 +33,13 @@ static GMainLoop *loop; static void -on_open (GdmSession *session, - const char *username) +on_conversation_started (GdmSession *session, + const char *service_name, + const char *username) { g_debug ("Got opened: calling setup..."); - gdm_session_setup (session, "gdm"); + gdm_session_setup (session, service_name); } static void @@ -256,11 +257,11 @@ main (int argc, username = argv[1]; } - gdm_session_open (GDM_SESSION (session)); + gdm_session_start_conversation (GDM_SESSION (session), "gdm"); g_signal_connect (session, - "opened", - G_CALLBACK (on_open), + "conversation-started", + G_CALLBACK (on_conversation_started), username); g_signal_connect (session, "setup-complete", -- 1.6.2.2 From 2e566b37c2b17117a70d1fa4c9e97cfdfeb27e75 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Wed, 4 Feb 2009 10:55:03 -0500 Subject: [PATCH 06/33] 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 304a67b..0a71512 100644 --- a/daemon/gdm-session-direct.c +++ b/daemon/gdm-session-direct.c @@ -1623,6 +1623,7 @@ start_conversation (GdmSessionDirect *session, const char *service_name) { GdmSessionConversation *conversation; + char *job_name; conversation = g_new0 (GdmSessionConversation, 1); conversation->session = session; @@ -1643,12 +1644,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 9c020fa..0327d77 100644 --- a/daemon/gdm-session-worker-job.c +++ b/daemon/gdm-session-worker-job.c @@ -149,6 +149,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; @@ -171,31 +202,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, @@ -204,6 +235,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); @@ -220,7 +254,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; @@ -233,13 +266,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) { @@ -287,6 +321,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.6.2.2 From cb5359d77225d4cada0664504ef48f47cee49601 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 16 Jan 2009 13:01:48 -0500 Subject: [PATCH 07/33] Make greeter explicitly request PAM conversation Now the greeter 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 | 32 ++++++++++++++---- 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, 99 insertions(+), 20 deletions(-) diff --git a/daemon/gdm-factory-slave.c b/daemon/gdm-factory-slave.c index 6497293..d1bb5dd 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 cecce83..ffca7ec 100644 --- a/daemon/gdm-greeter-server.c +++ b/daemon/gdm-greeter-server.c @@ -69,6 +69,7 @@ enum { }; enum { + START_CONVERSATION, BEGIN_AUTO_LOGIN, BEGIN_VERIFICATION, BEGIN_VERIFICATION_FOR_USER, @@ -246,9 +247,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; } @@ -323,6 +325,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) @@ -645,7 +675,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); @@ -699,7 +731,11 @@ do_introspect (DBusConnection *connection, /* interface */ xml = g_string_append (xml, " \n" + " \n" + " \n" + " \n" " \n" + " \n" " \n" " \n" " \n" @@ -759,6 +795,7 @@ do_introspect (DBusConnection *connection, " \n" " \n" " \n" + " \n" " \n" " \n" " \n" @@ -1121,6 +1158,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 6e92100..7333db1 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, @@ -85,7 +87,8 @@ gboolean gdm_greeter_server_info (GdmGreeterServer * gboolean gdm_greeter_server_problem (GdmGreeterServer *greeter_server, const char *text); 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 f193ff5..732c085 100644 --- a/daemon/gdm-simple-slave.c +++ b/daemon/gdm-simple-slave.c @@ -478,17 +478,19 @@ on_session_secret_info_query (GdmSession *session, } static void -on_session_opened (GdmSession *session, - GdmSimpleSlave *slave) +on_session_conversation_started (GdmSession *session, + const char *service_name, + GdmSimpleSlave *slave) { gboolean res; gboolean enabled; char *username; int delay; - g_debug ("GdmSimpleSlave: session opened"); + g_debug ("GdmSimpleSlave: 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"); } @@ -504,8 +506,10 @@ on_session_opened (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); } @@ -597,8 +601,8 @@ create_new_session (GdmSimpleSlave *slave) g_free (display_hostname); g_signal_connect (slave->priv->session, - "opened", - G_CALLBACK (on_session_opened), + "conversation-started", + G_CALLBACK (on_session_conversation_started), slave); g_signal_connect (slave->priv->session, "setup-complete", @@ -729,6 +733,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) { @@ -903,6 +917,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 461b85c..1e2c55d 100644 --- a/gui/simple-greeter/gdm-greeter-client.c +++ b/gui/simple-greeter/gdm-greeter-client.c @@ -237,11 +237,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 @@ -400,6 +396,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) { @@ -879,9 +883,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 08deabd..88b0281 100644 --- a/gui/simple-greeter/gdm-greeter-client.h +++ b/gui/simple-greeter/gdm-greeter-client.h @@ -84,13 +84,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 17afb4e..40d5e1f 100644 --- a/gui/simple-greeter/gdm-greeter-session.c +++ b/gui/simple-greeter/gdm-greeter-session.c @@ -84,6 +84,7 @@ on_problem (GdmGreeterClient *client, static void on_ready (GdmGreeterClient *client, + const char *service_name, GdmGreeterSession *session) { g_debug ("GdmGreeterSession: Ready"); @@ -251,6 +252,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 @@ -413,6 +415,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.6.2.2 From 312dc5d4950e91983113ac5e482d6a57b1a31258 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 16 Jan 2009 15:18:31 -0500 Subject: [PATCH 08/33] 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-session-direct.c | 132 ++++++++++++++++++++++++++++++++++--------- 1 files changed, 106 insertions(+), 26 deletions(-) diff --git a/daemon/gdm-session-direct.c b/daemon/gdm-session-direct.c index 0a71512..4bb14f4 100644 --- a/daemon/gdm-session-direct.c +++ b/daemon/gdm-session-direct.c @@ -84,6 +84,7 @@ struct _GdmSessionDirectPrivate char *user_x11_authority_file; GdmSessionConversation *conversation; + GHashTable *conversations; guint32 is_authenticated : 1; guint32 is_running : 1; @@ -1460,6 +1461,42 @@ allow_user_function (DBusConnection *connection, return FALSE; } +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 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 void handle_connection (DBusServer *server, DBusConnection *new_connection, @@ -1467,10 +1504,22 @@ handle_connection (DBusServer *server, { GdmSessionDirect *session = GDM_SESSION_DIRECT (user_data); GdmSessionConversation *conversation; + gulong pid; g_debug ("GdmSessionDirect: Handing new connection"); - conversation = session->priv->conversation; + if (!dbus_connection_get_unix_process_id (new_connection, &pid)) { + g_warning ("Unable to read pid on new worker connection"); + return; + } + + conversation = find_conversation_by_pid (session, (GPid) pid); + + if (conversation == NULL) { + g_warning ("New worker connection is from unknown source"); + return; + } + if (conversation->worker_connection == NULL) { DBusObjectPathVTable vtable = { &session_unregister_handler, &session_message_handler, @@ -1543,6 +1592,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, @@ -1566,6 +1626,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, @@ -1677,8 +1742,6 @@ stop_conversation (GdmSessionConversation *conversation) G_CALLBACK (worker_died), conversation); - cancel_pending_query (session); - if (conversation->worker_connection != NULL) { dbus_connection_remove_filter (conversation->worker_connection, on_message, session); @@ -1687,9 +1750,9 @@ stop_conversation (GdmSessionConversation *conversation) } gdm_session_worker_job_stop (conversation->job); + g_object_unref (conversation->job); - g_free (conversation->service_name); - g_free (conversation); + conversation->job = NULL; } static void @@ -1697,12 +1760,20 @@ 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); + + if (impl->priv->conversation != NULL) { + impl->priv->conversation = conversation; + } } static void @@ -1753,8 +1824,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"); } @@ -1816,8 +1887,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"); } @@ -1831,8 +1902,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); @@ -1846,8 +1915,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); @@ -2076,6 +2143,28 @@ 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); +} + +static void gdm_session_direct_close (GdmSession *session) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); @@ -2092,6 +2181,8 @@ gdm_session_direct_close (GdmSession *session) impl->priv->display_device); } + stop_all_conversations (impl); + g_free (impl->priv->selected_user); impl->priv->selected_user = NULL; @@ -2136,20 +2227,9 @@ gdm_session_direct_answer_query (GdmSession *session, static void gdm_session_direct_cancel (GdmSession *session) { - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); - GHashTableIter iter; - gpointer key, value; - g_return_if_fail (session != NULL); - g_hash_table_iter_init (&iter, impl->priv->conversations); - while (g_hash_table_iter_next (&iter, &key, &value)) { - GdmSessionConversation *conversation; - - conversation = (GdmSessionConversation *) value; - - cancel_pending_query (conversation); - } + stop_all_conversations (GDM_SESSION_DIRECT (session)); } char * -- 1.6.2.2 From 96270a54f06f565aafad25ef9d961c16774b8e1b Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Wed, 4 Mar 2009 22:09:21 -0500 Subject: [PATCH 09/33] start autologin conversation when creating session if necessary Without this autologin breaks, since when it comes time to autologin, there's no worker to do it. --- daemon/gdm-simple-slave.c | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c index 732c085..30faaa6 100644 --- a/daemon/gdm-simple-slave.c +++ b/daemon/gdm-simple-slave.c @@ -1030,8 +1030,18 @@ idle_connect_to_display (GdmSimpleSlave *slave) if (! enabled || delay > 0) { start_greeter (slave); create_new_session (slave); + + if (enabled) { + g_debug ("GdmSimpleSlave: Starting timed login conversation"); + gdm_session_start_conversation (GDM_SESSION (slave->priv->session), + "gdm-autologin"); + } } else { reset_session (slave); + + g_debug ("GdmSimpleSlave: Starting automatic login conversation"); + gdm_session_start_conversation (GDM_SESSION (slave->priv->session), + "gdm-autologin"); } } else { if (slave->priv->connection_attempts >= MAX_CONNECT_ATTEMPTS) { -- 1.6.2.2 From 736b134ce488097d962afc2e322288557ce5fda4 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Thu, 22 Jan 2009 08:52:01 -0500 Subject: [PATCH 10/33] Propagate service name to more layers This is more prep work to get multiple concurrent PAM stacks going. --- daemon/gdm-factory-slave.c | 63 +++-- daemon/gdm-greeter-server.c | 120 ++++++-- daemon/gdm-greeter-server.h | 17 +- daemon/gdm-product-slave.c | 233 ++++++++++++--- daemon/gdm-session-direct.c | 481 ++++++++++++++++++------------ daemon/gdm-session-private.h | 22 ++- daemon/gdm-session-relay.c | 122 ++++++-- daemon/gdm-session-worker.c | 27 ++ daemon/gdm-session.c | 151 ++++++---- daemon/gdm-session.h | 44 ++- daemon/gdm-simple-slave.c | 66 +++-- 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, 1132 insertions(+), 451 deletions(-) diff --git a/daemon/gdm-factory-slave.c b/daemon/gdm-factory-slave.c index d1bb5dd..826612e 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,39 +257,42 @@ 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_start_session (session); + gdm_session_start_session (session, service_name); gdm_greeter_server_reset (slave->priv->greeter_server); } 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); } @@ -368,37 +380,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 @@ -495,6 +518,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 ffca7ec..dae34c5 100644 --- a/daemon/gdm-greeter-server.c +++ b/daemon/gdm-greeter-server.c @@ -43,6 +43,7 @@ #include #include +#include "gdm-marshal.h" #include "gdm-greeter-server.h" #define GDM_GREETER_SERVER_DBUS_PATH "/org/gnome/DisplayManager/GreeterServer" @@ -156,6 +157,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) @@ -208,34 +249,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; } @@ -291,9 +336,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 @@ -358,6 +404,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"); @@ -365,7 +421,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; } @@ -379,7 +435,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, @@ -406,13 +461,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); @@ -420,7 +478,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; } @@ -433,13 +491,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"); @@ -447,7 +508,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; } @@ -644,9 +705,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); @@ -660,9 +723,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; @@ -735,13 +798,16 @@ do_introspect (DBusConnection *connection, " \n" " \n" " \n" + " \n" " \n" " \n" " \n" " \n" + " \n" " \n" " \n" " \n" + " \n" " \n" " \n" " \n" @@ -764,18 +830,23 @@ do_introspect (DBusConnection *connection, " \n" " \n" " \n" + " \n" " \n" " \n" " \n" + " \n" " \n" " \n" " \n" + " \n" " \n" " \n" " \n" + " \n" " \n" " \n" " \n" + " \n" " \n" " \n" " \n" @@ -800,6 +871,7 @@ do_introspect (DBusConnection *connection, " \n" " \n" " \n" + " \n" " \n" " \n"); @@ -1175,9 +1247,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), @@ -1196,10 +1268,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), @@ -1207,10 +1279,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), @@ -1304,9 +1376,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", @@ -1315,9 +1387,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 7333db1..6d0dd87 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,14 +81,17 @@ 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_reset (GdmGreeterServer *greeter_server); gboolean gdm_greeter_server_ready (GdmGreeterServer *greeter_server, @@ -101,8 +108,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 15a2820..dd2e1bc 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,96 +573,112 @@ 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_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 @@ -658,36 +739,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 @@ -696,16 +833,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); @@ -813,7 +952,25 @@ 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 4bb14f4..0f7e44e 100644 --- a/daemon/gdm-session-direct.c +++ b/daemon/gdm-session-direct.c @@ -83,9 +83,10 @@ struct _GdmSessionDirectPrivate char *selected_user; char *user_x11_authority_file; - GdmSessionConversation *conversation; GHashTable *conversations; + GList *pending_connections; + guint32 is_authenticated : 1; guint32 is_running : 1; GPid session_pid; @@ -192,14 +193,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, @@ -210,12 +227,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, @@ -227,12 +245,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, @@ -257,7 +276,7 @@ on_session_exited (GdmSession *session, static DBusHandlerResult gdm_session_direct_handle_setup_complete (GdmSessionDirect *session, - DBusConnection *connection, + GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; @@ -265,17 +284,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; @@ -290,12 +309,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), NULL); + _gdm_session_setup_failed (GDM_SESSION (session), conversation->service_name, NULL); return DBUS_HANDLER_RESULT_HANDLED; } @@ -303,7 +322,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; @@ -311,7 +330,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)); @@ -321,7 +340,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; @@ -336,7 +355,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"); @@ -348,7 +367,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; @@ -356,17 +375,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; @@ -381,19 +400,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), NULL); + _gdm_session_authentication_failed (GDM_SESSION (session), conversation->service_name, NULL); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult gdm_session_direct_handle_authorized (GdmSessionDirect *session, - DBusConnection *connection, + GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; @@ -401,17 +420,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; @@ -426,19 +445,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), NULL); + _gdm_session_authorization_failed (GDM_SESSION (session), conversation->service_name, NULL); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult gdm_session_direct_handle_accredited (GdmSessionDirect *session, - DBusConnection *connection, + GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; @@ -446,17 +465,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; @@ -471,12 +490,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), NULL); + _gdm_session_accreditation_failed (GDM_SESSION (session), conversation->service_name, text); return DBUS_HANDLER_RESULT_HANDLED; } @@ -724,7 +743,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; @@ -739,7 +758,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'", @@ -769,7 +788,7 @@ cancel_pending_query (GdmSessionConversation *conversation) reply = dbus_message_new_error (conversation->message_pending_reply, GDM_SESSION_DBUS_ERROR_CANCEL, "Operation cancelled"); - conversation = session->priv->conversation; + conversation = NULL; dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_connection_flush (conversation->worker_connection); @@ -780,6 +799,7 @@ cancel_pending_query (GdmSessionConversation *conversation) static void answer_pending_query (GdmSessionDirect *session, + const char *service_name, const char *answer) { DBusMessage *reply; @@ -792,7 +812,7 @@ answer_pending_query (GdmSessionDirect *session, dbus_message_iter_init_append (reply, &iter); dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &answer); - conversation = session->priv->conversation; + conversation = find_conversation_by_name (session, service_name); dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_message_unref (reply); @@ -811,7 +831,7 @@ set_pending_query (GdmSessionConversation *conversation, static DBusHandlerResult gdm_session_direct_handle_info_query (GdmSessionDirect *session, - DBusConnection *connection, + GdmSessionConversation *conversation, DBusMessage *message) { DBusError error; @@ -827,14 +847,14 @@ 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; @@ -850,14 +870,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; @@ -872,18 +892,18 @@ 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; @@ -892,7 +912,7 @@ gdm_session_direct_handle_cancel_pending_query (GdmSessionDirect *session, 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; @@ -900,7 +920,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; @@ -915,18 +935,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_started (GdmSessionDirect *session, - DBusConnection *connection, + GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; @@ -945,7 +965,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'", @@ -954,14 +974,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; @@ -976,18 +996,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; @@ -1002,7 +1022,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'", @@ -1016,7 +1036,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; @@ -1031,7 +1051,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'", @@ -1045,7 +1065,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; @@ -1060,7 +1080,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, @@ -1078,7 +1098,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; @@ -1093,7 +1113,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, @@ -1111,7 +1131,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; @@ -1126,7 +1146,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)) { @@ -1154,66 +1174,69 @@ 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, "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, "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; @@ -1447,6 +1470,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, @@ -1461,40 +1505,83 @@ allow_user_function (DBusConnection *connection, return FALSE; } -static GdmSessionConversation * -find_conversation_by_name (GdmSessionDirect *session, - const char *service_name) +static gboolean +register_worker (GdmSessionDirect *session, + DBusConnection *connection) { GdmSessionConversation *conversation; + DBusObjectPathVTable vtable = { &session_unregister_handler, + &session_message_handler, + NULL, NULL, NULL, NULL }; + GList *connection_node; + gulong pid; - conversation = g_hash_table_lookup (session->priv->conversations, service_name); + g_debug ("GdmSessionDirect: Authenticating new connection"); + + connection_node = g_list_find (session->priv->pending_connections, connection); + + if (connection_node == NULL) { + g_debug ("GdmSessionDirect: Ignoring connection that we aren't tracking"); + return FALSE; + } + + session->priv->pending_connections = + g_list_delete_link (session->priv->pending_connections, + connection_node); + + 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; + } + + conversation = find_conversation_by_pid (session, (GPid) pid); if (conversation == NULL) { - g_warning ("Tried to look up non-existant conversation"); + g_warning ("GdmSessionDirect: New worker connection is from unknown source"); + dbus_connection_unref (connection); + return FALSE; } - return conversation; + 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 GdmSessionConversation * -find_conversation_by_pid (GdmSessionDirect *session, - GPid pid) +static DBusHandlerResult +on_message (DBusConnection *connection, DBusMessage *message, void *user_data) { - GHashTableIter iter; - gpointer key, value; + GdmSessionDirect *session = GDM_SESSION_DIRECT (user_data); - g_hash_table_iter_init (&iter, session->priv->conversations); - while (g_hash_table_iter_next (&iter, &key, &value)) { - GdmSessionConversation *conversation; + g_debug ("GdmSessionDirect: got message"); - conversation = (GdmSessionConversation *) value; + if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "Hello")) { + DBusMessage *reply; - if (conversation->worker_pid == pid) { - return conversation; + if (register_worker (session, connection)) { + reply = dbus_message_new_method_return (message); + } else { + reply = dbus_message_new_error (message, DBUS_ERROR_FAILED, ""); } + + dbus_connection_send (connection, reply, NULL); + return DBUS_HANDLER_RESULT_HANDLED; } - return NULL; + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static void @@ -1503,50 +1590,23 @@ handle_connection (DBusServer *server, void *user_data) { GdmSessionDirect *session = GDM_SESSION_DIRECT (user_data); - GdmSessionConversation *conversation; - gulong pid; - g_debug ("GdmSessionDirect: Handing new connection"); - if (!dbus_connection_get_unix_process_id (new_connection, &pid)) { - g_warning ("Unable to read pid on new worker connection"); - return; - } - - conversation = find_conversation_by_pid (session, (GPid) pid); - - if (conversation == NULL) { - g_warning ("New worker connection is from unknown source"); - return; - } - - if (conversation->worker_connection == NULL) { - DBusObjectPathVTable vtable = { &session_unregister_handler, - &session_message_handler, - NULL, NULL, NULL, NULL - }; - - conversation->worker_connection = new_connection; - dbus_connection_ref (new_connection); - dbus_connection_setup_with_g_main (new_connection, NULL); - - g_debug ("GdmSessionDirect: worker connection is %p", new_connection); - dbus_connection_set_exit_on_disconnect (new_connection, FALSE); - - dbus_connection_set_unix_user_function (new_connection, - allow_user_function, - session, - NULL); - - dbus_connection_register_object_path (new_connection, - GDM_SESSION_DBUS_PATH, - &vtable, - session); + /* 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); - g_debug ("GdmSessionDirect: Emitting conversation-started signal"); - _gdm_session_conversation_started (GDM_SESSION (session), - conversation->service_name); - } + 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 @@ -1658,7 +1718,7 @@ worker_exited (GdmSessionWorkerJob *job, char *msg; msg = g_strdup_printf (_("worker exited with status %d"), code); - _gdm_session_authentication_failed (GDM_SESSION (conversation->session), msg); + _gdm_session_authentication_failed (GDM_SESSION (conversation->session), conversation->service_name, msg); g_free (msg); } else if (conversation->session->priv->is_running) { _gdm_session_session_exited (GDM_SESSION (conversation->session), code); @@ -1676,7 +1736,7 @@ worker_died (GdmSessionWorkerJob *job, char *msg; msg = g_strdup_printf (_("worker exited with status %d"), signum); - _gdm_session_authentication_failed (GDM_SESSION (conversation->session), msg); + _gdm_session_authentication_failed (GDM_SESSION (conversation->session), conversation->service_name, msg); g_free (msg); } else if (conversation->session->priv->is_running) { _gdm_session_session_died (GDM_SESSION (conversation->session), signum); @@ -1770,10 +1830,6 @@ gdm_session_direct_start_conversation (GdmSession *session, g_hash_table_insert (impl->priv->conversations, g_strdup (service_name), conversation); - - if (impl->priv->conversation != NULL) { - impl->priv->conversation = conversation; - } } static void @@ -1924,45 +1980,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"); @@ -1976,13 +2037,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, @@ -1992,7 +2052,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"); } @@ -2001,12 +2060,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 * @@ -2120,7 +2180,8 @@ setup_session_environment (GdmSessionDirect *session) } 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; @@ -2134,10 +2195,11 @@ gdm_session_direct_start_session (GdmSession *session) program = g_strdup_printf (GDMCONFDIR "/Xsession \"%s\"", command); 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); } @@ -2183,6 +2245,11 @@ gdm_session_direct_close (GdmSession *session) 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; @@ -2215,13 +2282,14 @@ 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); g_return_if_fail (session != NULL); - answer_pending_query (impl, text); + answer_pending_query (impl, service_name, text); } static void @@ -2245,7 +2313,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); @@ -2255,9 +2324,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 @@ -2265,7 +2340,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); @@ -2275,9 +2351,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 @@ -2285,7 +2367,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); @@ -2295,9 +2378,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 diff --git a/daemon/gdm-session-private.h b/daemon/gdm-session-private.h index 074aa6f..de6e54a 100644 --- a/daemon/gdm-session-private.h +++ b/daemon/gdm-session-private.h @@ -29,24 +29,34 @@ 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_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_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); @@ -67,12 +77,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 35b4738..6e15f75 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 (); @@ -245,10 +248,11 @@ gdm_session_relay_accredit (GdmSession *session, 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 @@ -292,11 +296,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 @@ -334,10 +339,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); @@ -349,7 +356,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; } @@ -361,12 +368,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); @@ -378,7 +387,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; } @@ -390,12 +399,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); @@ -407,7 +418,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; } @@ -419,12 +430,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); @@ -436,7 +449,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; } @@ -448,8 +461,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"); @@ -457,7 +477,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; } @@ -469,8 +489,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"); @@ -478,7 +505,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; } @@ -491,8 +518,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"); @@ -500,7 +534,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; } @@ -512,8 +546,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"); @@ -521,7 +562,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; } @@ -533,8 +574,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"); @@ -542,7 +590,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; } @@ -554,8 +602,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"); @@ -563,7 +618,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; } @@ -575,8 +630,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"); @@ -584,7 +646,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; } @@ -596,8 +658,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"); @@ -605,7 +674,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; } @@ -617,6 +686,7 @@ handle_session_started (GdmSessionRelay *session_relay, { DBusMessage *reply; DBusError error; + char *service_name; int pid; dbus_error_init (&error); @@ -624,6 +694,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); @@ -636,6 +707,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 fa39c3b..3b4288c 100644 --- a/daemon/gdm-session-worker.c +++ b/daemon/gdm-session-worker.c @@ -2574,6 +2574,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, @@ -2600,6 +2622,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 0073294..5f6ff5d 100644 --- a/daemon/gdm-session.c +++ b/daemon/gdm-session.c @@ -24,6 +24,7 @@ #include #include +#include "gdm-marshal.h" #include "gdm-session.h" #include "gdm-session-private.h" @@ -114,37 +115,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 @@ -192,11 +197,12 @@ gdm_session_cancel (GdmSession *session) } 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 @@ -213,7 +219,7 @@ gdm_session_class_init (gpointer g_iface) NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, - 0); + 1, G_TYPE_STRING); signals [SETUP_COMPLETE] = g_signal_new ("setup-complete", iface_type, @@ -221,9 +227,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, @@ -231,10 +238,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, @@ -263,9 +270,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, @@ -273,10 +280,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, @@ -284,9 +291,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, @@ -294,10 +301,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, @@ -305,9 +312,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, @@ -315,10 +322,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", @@ -327,10 +334,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, @@ -338,10 +345,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, @@ -349,10 +356,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, @@ -360,10 +367,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_STARTED] = g_signal_new ("session-started", iface_type, @@ -371,10 +378,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, @@ -382,10 +389,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, @@ -465,19 +472,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 @@ -497,99 +506,111 @@ _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_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 diff --git a/daemon/gdm-session.h b/daemon/gdm-session.h index 77e0cf6..db5fc4a 100644 --- a/daemon/gdm-session.h +++ b/daemon/gdm-session.h @@ -53,11 +53,15 @@ struct _GdmSessionIface 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 (* answer_query) (GdmSession *session, + const char *service_name, const char *text); void (* select_language) (GdmSession *session, const char *text); @@ -67,38 +71,53 @@ 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_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); @@ -128,14 +147,19 @@ 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_start_session (GdmSession *session); +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 30faaa6..e18f907 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; @@ -101,6 +103,7 @@ static void start_greeter (GdmSimpleSlave *slave); static void on_session_started (GdmSession *session, + const char *service_name, int pid, GdmSimpleSlave *slave) { @@ -204,18 +207,21 @@ queue_greeter_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, + service_name, _("Unable to initialize login system")); } @@ -240,18 +246,21 @@ 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, _("Unable to authenticate user")); } destroy_session (slave); @@ -259,7 +268,8 @@ on_session_authentication_failed (GdmSession *session, } 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; @@ -280,7 +290,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; } @@ -288,24 +298,27 @@ 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, + service_name, _("Unable to authorize user")); } @@ -386,31 +399,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) { - queue_start_session (slave); + queue_start_session (slave, service_name); } static void on_session_accreditation_failed (GdmSession *session, + const char *service_name, const char *message, GdmSimpleSlave *slave) { @@ -425,6 +445,7 @@ on_session_accreditation_failed (GdmSession *session, if (! migrated) { if (slave->priv->greeter_server != NULL) { gdm_greeter_server_problem (slave->priv->greeter_server, + service_name, _("Unable establish credentials")); } } @@ -440,41 +461,45 @@ on_session_accreditation_failed (GdmSession *session, 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 @@ -744,11 +769,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 @@ -764,21 +790,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 @@ -841,18 +869,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 d9fa26e..3cf8483 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]; @@ -178,12 +185,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); @@ -191,6 +199,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); @@ -198,6 +207,7 @@ on_problem (GdmSession *session, static void on_secret_info_query (GdmSession *session, + const char *service_name, const char *query_text) { char answer[1024]; @@ -222,7 +232,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 1e2c55d..0bd27a9 100644 --- a/gui/simple-greeter/gdm-greeter-client.c +++ b/gui/simple-greeter/gdm-greeter-client.c @@ -134,6 +134,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, @@ -200,37 +231,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 @@ -307,14 +336,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, @@ -328,8 +365,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, @@ -412,37 +518,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 @@ -835,10 +948,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", @@ -847,10 +960,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", @@ -859,10 +972,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", @@ -871,10 +984,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", @@ -956,8 +1069,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 88b0281..2f857dc 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 (* selected_user_changed) (GdmGreeterClient *client, const char *username); @@ -69,7 +74,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 ()) @@ -95,8 +101,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); @@ -111,9 +119,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 40d5e1f..ca6fb4f 100644 --- a/gui/simple-greeter/gdm-greeter-session.c +++ b/gui/simple-greeter/gdm-greeter-session.c @@ -64,6 +64,7 @@ static gpointer session_object = NULL; static void on_info (GdmGreeterClient *client, + const char *service_name, const char *text, GdmGreeterSession *session) { @@ -74,6 +75,7 @@ on_info (GdmGreeterClient *client, static void on_problem (GdmGreeterClient *client, + const char *service_name, const char *text, GdmGreeterSession *session) { @@ -160,6 +162,7 @@ on_user_authorized (GdmGreeterClient *client, static void on_info_query (GdmGreeterClient *client, + const char *service_name, const char *text, GdmGreeterSession *session) { @@ -170,6 +173,7 @@ on_info_query (GdmGreeterClient *client, static void on_secret_info_query (GdmGreeterClient *client, + const char *service_name, const char *text, GdmGreeterSession *session) { @@ -191,7 +195,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 @@ -200,6 +205,7 @@ on_begin_verification_for_user (GdmGreeterLoginWindow *login_window, GdmGreeterSession *session) { gdm_greeter_client_call_begin_verification_for_user (session->priv->client, + "gdm", username); } @@ -209,6 +215,7 @@ on_query_answer (GdmGreeterLoginWindow *login_window, GdmGreeterSession *session) { gdm_greeter_client_call_answer_query (session->priv->client, + "gdm", text); } @@ -266,7 +273,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.6.2.2 From 75d9abdf87e20d4382882f47f1434381f0a944bf Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Sat, 7 Feb 2009 11:36:40 -0500 Subject: [PATCH 11/33] emit "ConversationStopped" signal at end of conv This will allow us to track when individual PAM conversations fail, instead of doing one giant reset. The reason this is useful is that some PAM modules fail immediately for some users (for instance the fingerprint PAM module fails if a user hasn't enrolled their print). --- daemon/gdm-greeter-server.c | 14 ++++++++++++++ daemon/gdm-greeter-server.h | 2 ++ daemon/gdm-session-direct.c | 36 ++++++++++++++++++++++++++++++++++++ daemon/gdm-session-private.h | 2 ++ daemon/gdm-session.c | 28 ++++++++++++++++++++++++++++ daemon/gdm-session.h | 6 ++++++ daemon/gdm-simple-slave.c | 34 ++++++++++++++++++++++++++-------- 7 files changed, 114 insertions(+), 8 deletions(-) diff --git a/daemon/gdm-greeter-server.c b/daemon/gdm-greeter-server.c index dae34c5..ecb2ad6 100644 --- a/daemon/gdm-greeter-server.c +++ b/daemon/gdm-greeter-server.c @@ -299,6 +299,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) @@ -797,6 +805,9 @@ do_introspect (DBusConnection *connection, " \n" " \n" " \n" + " \n" + " \n" + " \n" " \n" " \n" " \n" @@ -868,6 +879,9 @@ do_introspect (DBusConnection *connection, " \n" " \n" " \n" + " \n" + " \n" + " \n" " \n" " \n" " \n" diff --git a/daemon/gdm-greeter-server.h b/daemon/gdm-greeter-server.h index 6d0dd87..976f0b7 100644 --- a/daemon/gdm-greeter-server.h +++ b/daemon/gdm-greeter-server.h @@ -96,6 +96,8 @@ gboolean gdm_greeter_server_problem (GdmGreeterServer * 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, diff --git a/daemon/gdm-session-direct.c b/daemon/gdm-session-direct.c index 0f7e44e..e5296a4 100644 --- a/daemon/gdm-session-direct.c +++ b/daemon/gdm-session-direct.c @@ -1714,6 +1714,7 @@ worker_exited (GdmSessionWorkerJob *job, { g_debug ("GdmSessionDirect: Worker job exited: %d", code); + g_object_ref (conversation->job); if (!conversation->session->priv->is_authenticated) { char *msg; @@ -1723,6 +1724,11 @@ worker_exited (GdmSessionWorkerJob *job, } else 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 @@ -1732,6 +1738,7 @@ worker_died (GdmSessionWorkerJob *job, { g_debug ("GdmSessionDirect: Worker job died: %d", signum); + g_object_ref (conversation->job); if (!conversation->session->priv->is_authenticated) { char *msg; @@ -1741,6 +1748,11 @@ worker_died (GdmSessionWorkerJob *job, } else 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 * @@ -1813,6 +1825,10 @@ stop_conversation (GdmSessionConversation *conversation) g_object_unref (conversation->job); conversation->job = NULL; + + g_debug ("GdmSessionDirect: Emitting conversation-stopped signal"); + _gdm_session_conversation_stopped (GDM_SESSION (session), + conversation->service_name); } static void @@ -1833,6 +1849,25 @@ gdm_session_direct_start_conversation (GdmSession *session, } 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 send_setup (GdmSessionDirect *session, const char *service_name) { @@ -2646,6 +2681,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 de6e54a..860c09c 100644 --- a/daemon/gdm-session-private.h +++ b/daemon/gdm-session-private.h @@ -29,6 +29,8 @@ G_BEGIN_DECLS /* state changes */ void _gdm_session_conversation_started (GdmSession *session, const char *service_name); +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, diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c index 5f6ff5d..9ee34af 100644 --- a/daemon/gdm-session.c +++ b/daemon/gdm-session.c @@ -30,6 +30,7 @@ enum { CONVERSATION_STARTED = 0, + CONVERSATION_STOPPED, SETUP_COMPLETE, SETUP_FAILED, RESET_COMPLETE, @@ -88,6 +89,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)); @@ -220,6 +230,16 @@ gdm_session_class_init (gpointer g_iface) g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 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, @@ -638,6 +658,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 db5fc4a..c45a770 100644 --- a/daemon/gdm-session.h +++ b/daemon/gdm-session.h @@ -47,6 +47,8 @@ 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, @@ -125,6 +127,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); @@ -141,6 +145,8 @@ 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, diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c index e18f907..d08613f 100644 --- a/daemon/gdm-simple-slave.c +++ b/daemon/gdm-simple-slave.c @@ -225,8 +225,7 @@ on_session_setup_failed (GdmSession *session, _("Unable to initialize login system")); } - destroy_session (slave); - queue_greeter_reset (slave); + gdm_session_stop_conversation (session, service_name); } static void @@ -263,8 +262,8 @@ on_session_authentication_failed (GdmSession *session, service_name, _("Unable to authenticate user")); } - destroy_session (slave); - queue_greeter_reset (slave); + + gdm_session_stop_conversation (session, service_name); } static void @@ -322,8 +321,7 @@ on_session_authorization_failed (GdmSession *session, _("Unable to authorize user")); } - destroy_session (slave); - queue_greeter_reset (slave); + gdm_session_stop_conversation (session, service_name); } static gboolean @@ -454,9 +452,8 @@ 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 @@ -542,6 +539,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) @@ -630,6 +644,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); -- 1.6.2.2 From 66e8c2a4e38fc9bdd60b83c9bed480ed3bc90358 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 9 Mar 2009 15:41:12 -0400 Subject: [PATCH 12/33] Don't tear down greeter until pam_open_session finishes Some PAM modules ask questions at that late stage of the game, and so we need a greeter to forward the questions on to the user. --- daemon/gdm-factory-slave.c | 37 ++++++++++++++++++++-- daemon/gdm-product-slave.c | 30 +++++++++++++++++- daemon/gdm-session-direct.c | 70 ++++++++++++++++++++++++++++++++++++++++++ daemon/gdm-session-private.h | 5 +++ daemon/gdm-session-relay.c | 68 ++++++++++++++++++++++++++++++++++++++++ daemon/gdm-session-worker.c | 16 ++++++++-- daemon/gdm-session.c | 50 ++++++++++++++++++++++++++++++ daemon/gdm-session.h | 9 +++++ daemon/gdm-simple-slave.c | 33 +++++++++++++++++++- 9 files changed, 310 insertions(+), 8 deletions(-) diff --git a/daemon/gdm-factory-slave.c b/daemon/gdm-factory-slave.c index 826612e..ef6d236 100644 --- a/daemon/gdm-factory-slave.c +++ b/daemon/gdm-factory-slave.c @@ -278,9 +278,7 @@ on_session_accredited (GdmSession *session, { g_debug ("GdmFactorySlave: session user verified"); - gdm_session_start_session (session, service_name); - - gdm_greeter_server_reset (slave->priv->greeter_server); + gdm_session_open_session (session, service_name); } static void @@ -298,6 +296,31 @@ on_session_accreditation_failed (GdmSession *session, } static void +on_session_opened (GdmSession *session, + const char *service_name, + GdmFactorySlave *slave) +{ + g_debug ("GdmFactorySlave: session opened"); + + 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, service_name, _("Unable to open session")); + + queue_greeter_reset (slave); +} + +static void on_session_session_started (GdmSession *session, GdmFactorySlave *slave) { @@ -767,6 +790,14 @@ gdm_factory_slave_start (GdmSlave *slave) G_CALLBACK (on_session_accreditation_failed), slave); g_signal_connect (GDM_FACTORY_SLAVE (slave)->priv->session, + "session-opened", + G_CALLBACK (on_session_opened), + slave); + g_signal_connect (GDM_FACTORY_SLAVE (slave)->priv->session, + "session-open-failed", + G_CALLBACK (on_session_open_failed), + slave); + g_signal_connect (GDM_FACTORY_SLAVE (slave)->priv->session, "info", G_CALLBACK (on_session_info), slave); diff --git a/daemon/gdm-product-slave.c b/daemon/gdm-product-slave.c index dd2e1bc..93d83a1 100644 --- a/daemon/gdm-product-slave.c +++ b/daemon/gdm-product-slave.c @@ -635,6 +635,27 @@ on_session_accreditation_failed (GdmSession *session, } static void +on_session_opened (GdmSession *session, + const char *service_name, + GdmProductSlave *slave) +{ + 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_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, @@ -1051,7 +1072,14 @@ create_new_session (GdmProductSlave *slave) "accreditation-failed", G_CALLBACK (on_session_accreditation_failed), slave); - + g_signal_connect (slave->priv->session, + "session-opened", + G_CALLBACK (on_session_opened), + slave); + g_signal_connect (slave->priv->session, + "session-open-failed", + G_CALLBACK (on_session_open_failed), + slave); g_signal_connect (slave->priv->session, "info", G_CALLBACK (on_session_info), diff --git a/daemon/gdm-session-direct.c b/daemon/gdm-session-direct.c index e5296a4..805adbf 100644 --- a/daemon/gdm-session-direct.c +++ b/daemon/gdm-session-direct.c @@ -945,6 +945,58 @@ gdm_session_direct_handle_problem (GdmSessionDirect *session, } static DBusHandlerResult +gdm_session_direct_handle_session_opened (GdmSessionDirect *session, + GdmSessionConversation *conversation, + DBusMessage *message) +{ + DBusMessage *reply; + DBusError error; + + g_debug ("GdmSessionDirect: Handling SessionOpened"); + + dbus_error_init (&error); + if (! dbus_message_get_args (message, &error, DBUS_TYPE_INVALID)) { + g_warning ("ERROR: %s", error.message); + } + + g_debug ("GdmSessionDirect: Emitting 'session-opened' signal"); + + _gdm_session_session_opened (GDM_SESSION (session), conversation->service_name); + + reply = dbus_message_new_method_return (message); + dbus_connection_send (conversation->worker_connection, reply, NULL); + dbus_message_unref (reply); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusHandlerResult +gdm_session_direct_handle_open_failed (GdmSessionDirect *session, + GdmSessionConversation *conversation, + DBusMessage *message) +{ + DBusMessage *reply; + DBusError error; + const char *text; + + dbus_error_init (&error); + if (! dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &text, + DBUS_TYPE_INVALID)) { + g_warning ("ERROR: %s", error.message); + } + + reply = dbus_message_new_method_return (message); + 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), conversation->service_name, text); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusHandlerResult gdm_session_direct_handle_session_started (GdmSessionDirect *session, GdmSessionConversation *conversation, DBusMessage *message) @@ -1223,6 +1275,10 @@ session_worker_message (DBusConnection *connection, 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, conversation, message); + } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SessionOpened")) { + 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, conversation, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SessionStarted")) { return gdm_session_direct_handle_session_started (session, conversation, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "StartFailed")) { @@ -2215,6 +2271,19 @@ setup_session_environment (GdmSessionDirect *session) } static void +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); + + conversation = find_conversation_by_name (impl, service_name); + send_dbus_void_signal (conversation, "OpenSession"); +} + +static void gdm_session_direct_start_session (GdmSession *session, const char *service_name) { @@ -2687,6 +2756,7 @@ gdm_session_iface_init (GdmSessionIface *iface) iface->authenticate = gdm_session_direct_authenticate; iface->authorize = gdm_session_direct_authorize; iface->accredit = gdm_session_direct_accredit; + iface->open_session = gdm_session_direct_open_session; iface->close = gdm_session_direct_close; iface->cancel = gdm_session_direct_cancel; diff --git a/daemon/gdm-session-private.h b/daemon/gdm-session-private.h index 860c09c..36781dd 100644 --- a/daemon/gdm-session-private.h +++ b/daemon/gdm-session-private.h @@ -54,6 +54,11 @@ void _gdm_session_accredited (GdmSession *sessio void _gdm_session_accreditation_failed (GdmSession *session, const char *service_name, const char *text); +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); diff --git a/daemon/gdm-session-relay.c b/daemon/gdm-session-relay.c index 6e15f75..3bf8ed7 100644 --- a/daemon/gdm-session-relay.c +++ b/daemon/gdm-session-relay.c @@ -247,6 +247,14 @@ gdm_session_relay_accredit (GdmSession *session, } static void +gdm_session_relay_open_session (GdmSession *session, + const char *service_name) +{ + GdmSessionRelay *impl = GDM_SESSION_RELAY (session); + send_dbus_string_signal (impl, "OpenSession", service_name); +} + +static void gdm_session_relay_answer_query (GdmSession *session, const char *service_name, const char *text) @@ -678,6 +686,61 @@ handle_accreditation_failed (GdmSessionRelay *session_relay, return DBUS_HANDLER_RESULT_HANDLED; } +static DBusHandlerResult +handle_session_opened (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: Session Opened"); + + reply = dbus_message_new_method_return (message); + dbus_connection_send (connection, reply, NULL); + dbus_message_unref (reply); + + _gdm_session_session_opened (GDM_SESSION (session_relay), service_name); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusHandlerResult +handle_session_open_failed (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: Session Open Failed"); + + reply = dbus_message_new_method_return (message); + dbus_connection_send (connection, reply, NULL); + dbus_message_unref (reply); + + _gdm_session_session_open_failed (GDM_SESSION (session_relay), service_name, NULL); + + return DBUS_HANDLER_RESULT_HANDLED; +} static DBusHandlerResult handle_session_started (GdmSessionRelay *session_relay, @@ -794,6 +857,10 @@ session_handle_child_message (DBusConnection *connection, return handle_accredited (session_relay, connection, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_RELAY_DBUS_INTERFACE, "AccreditationFailed")) { return handle_accreditation_failed (session_relay, connection, message); + } else if (dbus_message_is_method_call (message, GDM_SESSION_RELAY_DBUS_INTERFACE, "SessionOpened")) { + return handle_session_opened (session_relay, connection, message); + } else if (dbus_message_is_method_call (message, GDM_SESSION_RELAY_DBUS_INTERFACE, "SessionOpenFailed")) { + return handle_session_open_failed (session_relay, connection, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_RELAY_DBUS_INTERFACE, "SessionStarted")) { return handle_session_started (session_relay, connection, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_RELAY_DBUS_INTERFACE, "SessionStopped")) { @@ -1193,6 +1260,7 @@ gdm_session_iface_init (GdmSessionIface *iface) iface->authenticate = gdm_session_relay_authenticate; iface->authorize = gdm_session_relay_authorize; iface->accredit = gdm_session_relay_accredit; + iface->open_session = gdm_session_relay_open_session; iface->close = gdm_session_relay_close; iface->cancel = gdm_session_relay_cancel; diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c index 3b4288c..b470d88 100644 --- a/daemon/gdm-session-worker.c +++ b/daemon/gdm-session-worker.c @@ -2197,13 +2197,13 @@ do_open_session (GdmSessionWorker *worker) res = gdm_session_worker_open_user_session (worker, &error); if (! res) { send_dbus_string_method (worker->priv->connection, - "StartFailed", + "OpenFailed", error->message); g_error_free (error); return; } - queue_state_change (worker); + send_dbus_void_method (worker->priv->connection, "SessionOpened"); } static void @@ -2319,7 +2319,7 @@ on_start_program (GdmSessionWorker *worker, const char *text; dbus_bool_t res; - /* FIXME: return error if not in ACCREDITED state */ + /* FIXME: return error if not in SESSION_OPENED state */ dbus_error_init (&error); res = dbus_message_get_args (message, @@ -2458,6 +2458,14 @@ on_establish_credentials (GdmSessionWorker *worker, } static void +on_open_session (GdmSessionWorker *worker, + DBusMessage *message) +{ + /* FIXME: return error if not in ACCREDITED state */ + queue_state_change (worker); +} + +static void on_reauthenticate (GdmSessionWorker *worker, DBusMessage *message) { @@ -2517,6 +2525,8 @@ worker_dbus_handle_message (DBusConnection *connection, on_authorize (worker, message); } else if (dbus_message_is_signal (message, GDM_SESSION_DBUS_INTERFACE, "EstablishCredentials")) { on_establish_credentials (worker, message); + } else if (dbus_message_is_signal (message, GDM_SESSION_DBUS_INTERFACE, "OpenSession")) { + on_open_session (worker, message); } else if (dbus_message_is_signal (message, GDM_SESSION_DBUS_INTERFACE, "StartProgram")) { on_start_program (worker, message); } else if (dbus_message_is_signal (message, GDM_SESSION_DBUS_INTERFACE, "Reauthenticate")) { diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c index 9ee34af..8858071 100644 --- a/daemon/gdm-session.c +++ b/daemon/gdm-session.c @@ -46,6 +46,8 @@ enum { PROBLEM, INFO_QUERY, SECRET_INFO_QUERY, + SESSION_OPENED, + SESSION_OPEN_FAILED, SESSION_STARTED, SESSION_START_FAILED, SESSION_EXITED, @@ -207,6 +209,15 @@ gdm_session_cancel (GdmSession *session) } void +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, service_name); +} + +void gdm_session_start_session (GdmSession *session, const char *service_name) { @@ -391,6 +402,28 @@ gdm_session_class_init (gpointer g_iface) G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING); + signals [SESSION_OPENED] = + g_signal_new ("session-opened", + iface_type, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdmSessionIface, session_opened), + NULL, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, + 1, + G_TYPE_STRING); + signals [SESSION_OPEN_FAILED] = + g_signal_new ("session-open-failed", + iface_type, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdmSessionIface, session_open_failed), + NULL, + NULL, + gdm_marshal_VOID__STRING_STRING, + G_TYPE_NONE, + 2, + G_TYPE_STRING, G_TYPE_STRING); signals [SESSION_STARTED] = g_signal_new ("session-started", iface_type, @@ -616,6 +649,23 @@ _gdm_session_problem (GdmSession *session, } void +_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, 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, service_name, text); +} + +void _gdm_session_session_started (GdmSession *session, const char *service_name, int pid) diff --git a/daemon/gdm-session.h b/daemon/gdm-session.h index c45a770..22c2ccb 100644 --- a/daemon/gdm-session.h +++ b/daemon/gdm-session.h @@ -62,6 +62,8 @@ struct _GdmSessionIface void (* accredit) (GdmSession *session, const char *service_name, int cred_flag); + void (* open_session) (GdmSession *session, + const char *service_name); void (* answer_query) (GdmSession *session, const char *service_name, const char *text); @@ -115,6 +117,11 @@ struct _GdmSessionIface void (* problem) (GdmSession *session, const char *service_name, const char *problem); + 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); @@ -160,6 +167,8 @@ void gdm_session_authorize (GdmSession *session, void gdm_session_accredit (GdmSession *session, const char *service_name, int cred_flag); +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); diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c index d08613f..17f5f7a 100644 --- a/daemon/gdm-simple-slave.c +++ b/daemon/gdm-simple-slave.c @@ -423,7 +423,7 @@ on_session_accredited (GdmSession *session, const char *service_name, GdmSimpleSlave *slave) { - queue_start_session (slave, service_name); + gdm_session_open_session (session, service_name); } static void @@ -457,6 +457,29 @@ on_session_accreditation_failed (GdmSession *session, } static void +on_session_opened (GdmSession *session, + const char *service_name, + GdmSimpleSlave *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")); + } + + gdm_session_stop_conversation (session, service_name); +} + +static void on_session_info (GdmSession *session, const char *service_name, const char *text, @@ -688,6 +711,14 @@ create_new_session (GdmSimpleSlave *slave) G_CALLBACK (on_session_accreditation_failed), slave); g_signal_connect (slave->priv->session, + "session-opened", + G_CALLBACK (on_session_opened), + slave); + g_signal_connect (slave->priv->session, + "session-open-failed", + G_CALLBACK (on_session_open_failed), + slave); + g_signal_connect (slave->priv->session, "info", G_CALLBACK (on_session_info), slave); -- 1.6.2.2 From 61199d66b2ea68ae38215cf614e897c86f1abf1a Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 30 Jan 2009 23:57:31 -0500 Subject: [PATCH 13/33] Add limited support for multiple pam stacks This hard codes 3 pam stacks and doesn't handle switching between them very well yet. --- gui/simple-greeter/Makefile.am | 4 + gui/simple-greeter/gdm-greeter-login-window.c | 91 +++++++++-- gui/simple-greeter/gdm-greeter-login-window.glade | 39 ++++- gui/simple-greeter/gdm-greeter-login-window.h | 11 +- gui/simple-greeter/gdm-greeter-session.c | 30 +++- gui/simple-greeter/gdm-task-list.c | 198 +++++++++++++++++++++ gui/simple-greeter/gdm-task-list.h | 64 +++++++ 7 files changed, 409 insertions(+), 28 deletions(-) create mode 100644 gui/simple-greeter/gdm-task-list.c create mode 100644 gui/simple-greeter/gdm-task-list.h diff --git a/gui/simple-greeter/Makefile.am b/gui/simple-greeter/Makefile.am index 9b5834d..e2d3996 100644 --- a/gui/simple-greeter/Makefile.am +++ b/gui/simple-greeter/Makefile.am @@ -83,6 +83,8 @@ 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 \ $(NULL) test_greeter_login_window_LDADD = \ @@ -316,6 +318,8 @@ gdm_simple_greeter_SOURCES = \ gdm-session-option-widget.c \ gdm-user-chooser-widget.h \ gdm-user-chooser-widget.c \ + gdm-task-list.h \ + gdm-task-list.c \ $(NULL) gdm_simple_greeter_LDADD = \ diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c index 01596e8..d08404e 100644 --- a/gui/simple-greeter/gdm-greeter-login-window.c +++ b/gui/simple-greeter/gdm-greeter-login-window.c @@ -60,12 +60,16 @@ #include #endif +#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 @@ -111,6 +115,7 @@ struct GdmGreeterLoginWindowPrivate { GladeXML *xml; GtkWidget *user_chooser; + GtkWidget *conversation_list; GtkWidget *auth_banner_label; guint display_is_local : 1; guint is_interactive : 1; @@ -139,6 +144,7 @@ enum { }; enum { + START_CONVERSATION, BEGIN_AUTO_LOGIN, BEGIN_VERIFICATION, BEGIN_VERIFICATION_FOR_USER, @@ -395,7 +401,7 @@ on_login_button_clicked_answer_query (GtkButton *button, text = gtk_entry_get_text (GTK_ENTRY (entry)); _gdm_greeter_login_window_set_interactive (login_window, TRUE); - g_signal_emit (login_window, signals[QUERY_ANSWER], 0, text); + g_signal_emit (login_window, signals[QUERY_ANSWER], 0, "gdm", text); } static void @@ -747,26 +753,32 @@ gdm_greeter_login_window_reset (GdmGreeterLoginWindow *login_window) 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); g_debug ("GdmGreeterLoginWindow: info: %s", text); - set_message (GDM_GREETER_LOGIN_WINDOW (login_window), text); + if (strcmp (service_name, gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list))) == 0) { + set_message (GDM_GREETER_LOGIN_WINDOW (login_window), text); + } 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); g_debug ("GdmGreeterLoginWindow: problem: %s", text); - set_message (GDM_GREETER_LOGIN_WINDOW (login_window), text); + if (strcmp (service_name, gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list))) == 0) { + set_message (GDM_GREETER_LOGIN_WINDOW (login_window), text); + } gdk_window_beep (GTK_WIDGET (login_window)->window); return TRUE; @@ -842,6 +854,7 @@ 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; @@ -849,6 +862,10 @@ gdm_greeter_login_window_info_query (GdmGreeterLoginWindow *login_window, g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE); + if (strcmp (service_name, gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list))) != 0) { + return TRUE; + } + g_debug ("GdmGreeterLoginWindow: info query: %s", text); entry = glade_xml_get_widget (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->xml, "auth-prompt-entry"); @@ -871,6 +888,7 @@ 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; @@ -1343,7 +1361,10 @@ on_user_chosen (GdmUserChooserWidget *user_chooser, 0, user_name); if (strcmp (user_name, GDM_USER_CHOOSER_USER_OTHER) == 0) { - g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0); + const char *service_name; + + service_name = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list)); + g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, service_name); } 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) { @@ -1357,7 +1378,10 @@ on_user_chosen (GdmUserChooserWidget *user_chooser, set_log_in_button_mode (login_window, LOGIN_BUTTON_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); + const char *service_name; + + service_name = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list)); + g_signal_emit (login_window, signals[BEGIN_VERIFICATION_FOR_USER], 0, service_name, user_name); } switch_mode (login_window, MODE_AUTHENTICATION); @@ -1501,6 +1525,21 @@ create_computer_info (GdmGreeterLoginWindow *login_window) #define INVISIBLE_CHAR_BULLET 0x2022 #define INVISIBLE_CHAR_NONE 0 +static void +on_task_activated (GdmGreeterLoginWindow *login_window, + const char *name) +{ + g_debug ("GdmGreeterLoginWindow: starting conversation with '%s'", name); + g_signal_emit (login_window, signals[START_CONVERSATION], 0, name); +} + +static void +on_task_deactivated (GdmGreeterLoginWindow *login_window, + const char *name) +{ + g_debug ("GdmGreeterLoginWindow: conversation '%s' now in background", name); +} + static GtkWidget * custom_widget_constructor (GladeXML *xml, char *func_name, @@ -1523,6 +1562,8 @@ custom_widget_constructor (GladeXML *xml, if (strcmp (name, "user-chooser") == 0) { widget = gdm_user_chooser_widget_new (); + } else if (strcmp (name, "conversation-list") == 0) { + widget = gdm_task_list_new (); } gdm_profile_end (NULL); @@ -1596,6 +1637,25 @@ load_theme (GdmGreeterLoginWindow *login_window) gtk_widget_show (login_window->priv->user_chooser); + login_window->priv->conversation_list = glade_xml_get_widget (login_window->priv->xml, + "conversation-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); + gtk_widget_show (login_window->priv->conversation_list); + + gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list), + "password-auth", "dialog-password"); + gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list), + "fingerprint-auth", "stock_allow-effects"); + gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list), + "smartcard-auth", "badge-small"); + login_window->priv->auth_banner_label = glade_xml_get_widget (login_window->priv->xml, "auth-banner-label"); /*make_label_small_italic (login_window->priv->auth_banner_label);*/ @@ -1763,6 +1823,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), @@ -1779,9 +1848,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), @@ -1789,9 +1858,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), @@ -1799,9 +1868,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), diff --git a/gui/simple-greeter/gdm-greeter-login-window.glade b/gui/simple-greeter/gdm-greeter-login-window.glade index b46dcad..3d9e2ee 100644 --- a/gui/simple-greeter/gdm-greeter-login-window.glade +++ b/gui/simple-greeter/gdm-greeter-login-window.glade @@ -654,11 +654,38 @@ 10 - + True - 0 - 0 - Tue, 18 Nov 2008 21:55:38 GMT + False + 0 + + + + True + 0 + 0 + Tue, 18 Nov 2008 21:55:38 GMT + + + 0 + True + True + + + + + + True + 0 + 0 + Fri, 30 Jan 2009 16:03:30 GMT + + + 0 + False + False + + 0 @@ -778,10 +805,6 @@ - - - - diff --git a/gui/simple-greeter/gdm-greeter-login-window.h b/gui/simple-greeter/gdm-greeter-login-window.h index 817d0a2..559b26b 100644 --- a/gui/simple-greeter/gdm-greeter-login-window.h +++ b/gui/simple-greeter/gdm-greeter-login-window.h @@ -46,12 +46,17 @@ 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); @@ -68,12 +73,16 @@ GtkWidget * gdm_greeter_login_window_new (gboolean displa gboolean gdm_greeter_login_window_reset (GdmGreeterLoginWindow *login_window); gboolean gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window); 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); void gdm_greeter_login_window_request_timed_login (GdmGreeterLoginWindow *login_window, diff --git a/gui/simple-greeter/gdm-greeter-session.c b/gui/simple-greeter/gdm-greeter-session.c index ca6fb4f..714daa1 100644 --- a/gui/simple-greeter/gdm-greeter-session.c +++ b/gui/simple-greeter/gdm-greeter-session.c @@ -70,7 +70,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 @@ -81,7 +81,7 @@ 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 @@ -168,7 +168,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 @@ -179,10 +179,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) @@ -193,29 +201,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); } @@ -366,7 +377,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), diff --git a/gui/simple-greeter/gdm-task-list.c b/gui/simple-greeter/gdm-task-list.c new file mode 100644 index 0000000..e0fd3d4 --- /dev/null +++ b/gui/simple-greeter/gdm-task-list.c @@ -0,0 +1,198 @@ +/* + * 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 + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "gdm-task-list.h" + +#define GDM_TASK_LIST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_TASK_LIST, GdmTaskListPrivate)) + +typedef struct +{ + GtkWidget *radio_button; + char *name; +} GdmTask; + +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 *radio_button) +{ + GdmTask *task; + + task = g_object_get_data (G_OBJECT (radio_button), "gdm-task"); + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio_button))) { + g_signal_emit (widget, signals[ACTIVATED], 0, task->name); + } else { + g_signal_emit (widget, signals[DEACTIVATED], 0, task->name); + } +} + +void +gdm_task_list_add_task (GdmTaskList *task_list, + const char *name, + const char *icon_name) +{ + GdmTask *task; + GtkWidget *image; + + task = g_new0 (GdmTask, 1); + + task->name = g_strdup (name); + if (task_list->priv->tasks == NULL) { + task->radio_button = gtk_radio_button_new (NULL); + } else { + task->radio_button = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (((GdmTask *) task_list->priv->tasks->data)->radio_button)); + } + + g_object_set (task->radio_button, "draw-indicator", FALSE, NULL); + g_object_set_data (G_OBJECT (task->radio_button), "gdm-task", task); + g_signal_connect_swapped (task->radio_button, + "toggled", G_CALLBACK (on_task_toggled), task_list); + image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_DND); + gtk_widget_show (image); + gtk_container_add (GTK_CONTAINER (task->radio_button), image); + gtk_widget_show (task->radio_button); + gtk_container_add (GTK_CONTAINER (task->radio_button), task_list->priv->box); + + gtk_container_add (GTK_CONTAINER (task_list->priv->box), task->radio_button); + task_list->priv->tasks = g_list_append (task_list->priv->tasks, task); +} + +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__STRING, + G_TYPE_NONE, + 1, G_TYPE_STRING); + + 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__STRING, + G_TYPE_NONE, + 1, G_TYPE_STRING); + + 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 (FALSE, 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_free, 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); +} + +const char * +gdm_task_list_get_active_task (GdmTaskList *widget) +{ + GList *node; + + for (node = widget->priv->tasks; node != NULL; node = node->next) { + GdmTask *task; + + task = node->data; + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (task->radio_button)) ) { + return task->name; + } + } + + return NULL; +} diff --git a/gui/simple-greeter/gdm-task-list.h b/gui/simple-greeter/gdm-task-list.h new file mode 100644 index 0000000..ade21b6 --- /dev/null +++ b/gui/simple-greeter/gdm-task-list.h @@ -0,0 +1,64 @@ +/* + * 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 + */ + +#ifndef __GDM_TASK_LIST_H +#define __GDM_TASK_LIST_H + +#include +#include + +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 +{ + GtkAlignment parent; + GdmTaskListPrivate *priv; +} GdmTaskList; + +typedef struct +{ + GtkAlignmentClass parent_class; + + void (* deactivated) (GdmTaskList *widget, + const char *name); + void (* activated) (GdmTaskList *widget, + const char *name); +} GdmTaskListClass; + + +GType gdm_task_list_get_type (void); +GtkWidget * gdm_task_list_new (void); + +const char * gdm_task_list_get_active_task (GdmTaskList *widget); +void gdm_task_list_add_task (GdmTaskList *widget, + const char *name, + const char *icon_name); +G_END_DECLS + +#endif /* __GDM_TASK_LIST_H */ -- 1.6.2.2 From 1411345bfefbba0c1213152fdf890b5691661bd5 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 6 Mar 2009 11:19:40 -0500 Subject: [PATCH 14/33] Create session settings object when first starting worker This is because one PAM module may complete before setup gets called on another, and when one completes *all* PAM modules get told about language, session, and layouts set by the user. --- 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 b470d88..33706d7 100644 --- a/daemon/gdm-session-worker.c +++ b/daemon/gdm-session-worker.c @@ -2060,8 +2060,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), @@ -2678,6 +2676,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.6.2.2 From 2d2ad2f1ff74adf42bbe00fc650676f7816a644a Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Thu, 5 Feb 2009 15:20:25 -0500 Subject: [PATCH 15/33] Queue a greeter reset when the user clicks cancel --- daemon/gdm-simple-slave.c | 37 +++++++++++++++++++++++++++++++++++++ 1 files changed, 37 insertions(+), 0 deletions(-) diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c index 17f5f7a..09a7425 100644 --- a/daemon/gdm-simple-slave.c +++ b/daemon/gdm-simple-slave.c @@ -812,6 +812,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); } @@ -822,6 +825,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); } @@ -832,6 +838,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); @@ -844,6 +853,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); @@ -855,6 +867,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); } @@ -863,6 +878,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); } @@ -871,6 +889,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); } @@ -879,6 +900,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); } @@ -895,7 +919,11 @@ on_greeter_cancel (GdmGreeterServer *greeter_server, GdmSimpleSlave *slave) { g_debug ("GdmSimpleSlave: Greeter cancelled"); + if (slave->priv->greeter_reset_id > 0) { + return; + } reset_session (slave); + queue_greeter_reset (slave); } static void @@ -905,6 +933,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, @@ -922,6 +953,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) { @@ -935,6 +969,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.6.2.2 From 5231302bd0b9611984639530884b14e6400e786f Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 6 Feb 2009 16:23:48 -0500 Subject: [PATCH 16/33] 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. --- configure.ac | 45 ++ gui/simple-greeter/Makefile.am | 15 + gui/simple-greeter/gdm-greeter-client.c | 21 + gui/simple-greeter/gdm-greeter-client.h | 2 + gui/simple-greeter/gdm-greeter-login-window.c | 675 ++++++++++++++++---- gui/simple-greeter/gdm-greeter-login-window.glade | 144 +---- gui/simple-greeter/gdm-greeter-login-window.h | 21 +- gui/simple-greeter/gdm-greeter-plugin.c | 255 ++++++++ gui/simple-greeter/gdm-greeter-plugin.h | 61 ++ gui/simple-greeter/gdm-greeter-session.c | 91 +++- gui/simple-greeter/gdm-plugin-manager.c | 478 ++++++++++++++ gui/simple-greeter/gdm-plugin-manager.h | 66 ++ gui/simple-greeter/gdm-task-list.c | 216 +++++-- gui/simple-greeter/gdm-task-list.h | 36 +- gui/simple-greeter/libgdmsimplegreeter/Makefile.am | 46 ++ .../libgdmsimplegreeter/gdm-conversation.c | 147 +++++ .../libgdmsimplegreeter/gdm-conversation.h | 87 +++ .../libgdmsimplegreeter/gdm-greeter-extension.c | 93 +++ .../libgdmsimplegreeter/gdm-greeter-extension.h | 55 ++ gui/simple-greeter/libgdmsimplegreeter/gdm-task.c | 117 ++++ gui/simple-greeter/libgdmsimplegreeter/gdm-task.h | 62 ++ .../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 | 316 +++++++++ .../plugins/password/gdm-password-extension.h | 56 ++ .../plugins/password/gdm-password.pam | 19 + gui/simple-greeter/plugins/password/page.ui | 56 ++ gui/simple-greeter/plugins/password/plugin.c | 40 ++ 29 files changed, 2988 insertions(+), 297 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/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/configure.ac b/configure.ac index 925a353..23df306 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) @@ -199,6 +215,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 --------------------------------------------------------------------------- @@ -1231,6 +1256,22 @@ fi AC_SUBST(GDM_XAUTH_DIR) dnl --------------------------------------------------------------------------- +dnl - Directory for simple greeter plugins +dnl --------------------------------------------------------------------------- + +AC_ARG_WITH(simple-greeter-plugins-dir, + AS_HELP_STRING([--with-simple-greeter-plugins-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 dnl --------------------------------------------------------------------------- @@ -1357,6 +1398,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 e2d3996..a9e4d65 100644 --- a/gui/simple-greeter/Makefile.am +++ b/gui/simple-greeter/Makefile.am @@ -2,11 +2,14 @@ NULL = SUBDIRS = \ libnotificationarea \ + libgdmsimplegreeter \ + plugins \ $(NULL) AM_CPPFLAGS = \ -I$(top_srcdir)/common \ -I$(top_srcdir)/gui/simple-greeter/libnotificationarea \ + -I$(top_srcdir)/gui/simple-greeter/libgdmsimplegreeter \ -DDMCONFDIR=\""$(dmconfdir)"\" \ -DGDMCONFDIR=\"$(gdmconfdir)\" \ -DDATADIR=\""$(datadir)"\" \ @@ -17,6 +20,7 @@ AM_CPPFLAGS = \ -DLIBEXECDIR=\""$(libexecdir)"\" \ -DSBINDIR=\""$(sbindir)"\" \ -DAT_SPI_REGISTRYD_DIR="\"$(AT_SPI_REGISTRYD_DIR)\"" \ + -DGDM_SIMPLE_GREETER_PLUGINS_DIR="\"$(GDM_SIMPLE_GREETER_PLUGINS_DIR)\""\ $(DISABLE_DEPRECATED_CFLAGS) \ $(GTK_CFLAGS) \ $(SIMPLE_GREETER_CFLAGS) \ @@ -85,10 +89,15 @@ test_greeter_login_window_SOURCES = \ 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) \ @@ -140,6 +149,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) \ @@ -312,10 +322,14 @@ 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 \ @@ -326,6 +340,7 @@ 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 0bd27a9..a9321aa 100644 --- a/gui/simple-greeter/gdm-greeter-client.c +++ b/gui/simple-greeter/gdm-greeter-client.c @@ -64,6 +64,7 @@ enum { INFO_QUERY, SECRET_INFO_QUERY, READY, + CONVERSATION_STOPPED, RESET, SELECTED_USER_CHANGED, DEFAULT_LANGUAGE_NAME_CHANGED, @@ -270,6 +271,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) { @@ -760,6 +768,8 @@ client_dbus_handle_message (DBusConnection *connection, on_problem (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, "SelectedUserChanged")) { @@ -1000,6 +1010,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 2f857dc..f879307 100644 --- a/gui/simple-greeter/gdm-greeter-client.h +++ b/gui/simple-greeter/gdm-greeter-client.h @@ -61,6 +61,8 @@ typedef struct const char *problem); void (* ready) (GdmGreeterClient *client, const char *service_name); + void (* conversation_stopped) (GdmGreeterClient *client, + const char *service_name); void (* reset) (GdmGreeterClient *client); void (* selected_user_changed) (GdmGreeterClient *client, const char *username); diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c index d08404e..2e9a1a0 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 - * 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 + * Ray Strode + * */ #include "config.h" @@ -117,6 +120,7 @@ struct GdmGreeterLoginWindowPrivate GtkWidget *user_chooser; GtkWidget *conversation_list; GtkWidget *auth_banner_label; + GtkWidget *auth_page_box; guint display_is_local : 1; guint is_interactive : 1; GConfClient *client; @@ -166,6 +170,9 @@ static void restart_timed_login_timeout (GdmGreeterLoginWindow *login_window static void on_user_unchosen (GdmUserChooserWidget *user_chooser, 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) static void @@ -190,9 +197,6 @@ set_sensitive (GdmGreeterLoginWindow *login_window, { GtkWidget *box; - box = glade_xml_get_widget (login_window->priv->xml, "auth-input-box"); - gtk_widget_set_sensitive (box, sensitive); - box = glade_xml_get_widget (login_window->priv->xml, "buttonbox"); gtk_widget_set_sensitive (box, sensitive); @@ -202,27 +206,43 @@ set_sensitive (GdmGreeterLoginWindow *login_window, static void set_focus (GdmGreeterLoginWindow *login_window) { - GtkWidget *entry; - - entry = glade_xml_get_widget (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->xml, "auth-prompt-entry"); + GdmTask *task; gdk_window_focus (GTK_WIDGET (login_window)->window, GDK_CURRENT_TIME); - if (GTK_WIDGET_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 (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_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 = glade_xml_get_widget (login_window->priv->xml, "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 @@ -388,30 +408,76 @@ get_show_restart_buttons (GdmGreeterLoginWindow *login_window) } static void -on_login_button_clicked_answer_query (GtkButton *button, - GdmGreeterLoginWindow *login_window) +on_login_button_clicked_timed_login (GtkButton *button, + GdmGreeterLoginWindow *login_window) { - GtkWidget *entry; - const char *text; - set_busy (login_window); set_sensitive (login_window, FALSE); - entry = glade_xml_get_widget (login_window->priv->xml, "auth-prompt-entry"); - text = gtk_entry_get_text (GTK_ENTRY (entry)); - _gdm_greeter_login_window_set_interactive (login_window, TRUE); - g_signal_emit (login_window, signals[QUERY_ANSWER], 0, "gdm", text); } static void -on_login_button_clicked_timed_login (GtkButton *button, - GdmGreeterLoginWindow *login_window) +hide_task_actions (GdmTask *task) { - set_busy (login_window); - set_sensitive (login_window, FALSE); + GtkActionGroup *actions; - _gdm_greeter_login_window_set_interactive (login_window, TRUE); + actions = gdm_conversation_get_actions (GDM_CONVERSATION (task)); + + 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; + } + } + +} + +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 @@ -419,6 +485,7 @@ set_log_in_button_mode (GdmGreeterLoginWindow *login_window, int mode) { GtkWidget *button; + GdmTask *task; button = glade_xml_get_widget (login_window->priv->xml, "log-in-button"); gtk_widget_grab_default (button); @@ -431,14 +498,27 @@ 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); + gtk_widget_show (button); break; default: @@ -562,7 +642,7 @@ switch_mode (GdmGreeterLoginWindow *login_window, show_widget (login_window, "disconnect-button", ! login_window->priv->display_is_local); - show_widget (login_window, "auth-input-box", FALSE); + show_widget (login_window, "auth-page-box", FALSE); add_sensitize_power_buttons_timeout (login_window); sensitize_widget (login_window, "shutdown-button", FALSE); @@ -578,6 +658,7 @@ switch_mode (GdmGreeterLoginWindow *login_window, show_widget (login_window, "restart-button", FALSE); show_widget (login_window, "suspend-button", FALSE); show_widget (login_window, "disconnect-button", FALSE); + show_widget (login_window, "auth-page-box", TRUE); default_name = "log-in-button"; break; default: @@ -657,25 +738,40 @@ do_suspend (GdmGreeterLoginWindow *login_window) g_object_unref (proxy); } -static void -delete_entry_text (GtkWidget *entry) +static gboolean +task_has_service_name (GdmTaskList *task_list, + GdmTask *task, + const char *service_name) { - const char *typed_text; - char *null_text; + char *task_service_name; + gboolean 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); - /* try to scrub out any secret info */ - typed_text = gtk_entry_get_text (GTK_ENTRY (entry)); - null_text = g_strnfill (strlen (typed_text) + 1, '\b'); - gtk_entry_set_text (GTK_ENTRY (entry), null_text); - gtk_entry_set_text (GTK_ENTRY (entry), ""); + return has_service_name; +} + +static gboolean +reset_task (GdmTaskList *task_list, + GdmTask *task, + GdmGreeterLoginWindow *login_window) +{ + char *name; + + name = gdm_task_get_name (task); + g_debug ("Resetting task '%s'", name); + g_free (name); + + gdm_conversation_reset (GDM_CONVERSATION (task)); + return FALSE; } static void reset_dialog (GdmGreeterLoginWindow *login_window) { - GtkWidget *entry; - GtkWidget *label; - g_debug ("GdmGreeterLoginWindow: Resetting dialog"); set_busy (login_window); set_sensitive (login_window, FALSE); @@ -699,16 +795,12 @@ reset_dialog (GdmGreeterLoginWindow *login_window) login_window->priv->start_session_handler_id = 0; } - entry = glade_xml_get_widget (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->xml, "auth-prompt-entry"); - - delete_entry_text (entry); + gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), + (GdmTaskListForeachFunc) + reset_task, + login_window); - gtk_entry_set_visibility (GTK_ENTRY (entry), TRUE); set_message (login_window, ""); - - label = glade_xml_get_widget (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->xml, "auth-prompt-label"); - gtk_label_set_text (GTK_LABEL (label), ""); - switch_mode (login_window, MODE_SELECTION); set_sensitive (login_window, TRUE); @@ -728,11 +820,22 @@ do_cancel (GdmGreeterLoginWindow *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); - reset_dialog (login_window); + task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), + (GdmTaskListForeachFunc) + task_has_service_name, + (gpointer) service_name); + + if (task != NULL) { + gdm_conversation_set_ready (GDM_CONVERSATION (task)); + g_object_unref (task); + } set_sensitive (GDM_GREETER_LOGIN_WINDOW (login_window), TRUE); set_ready (GDM_GREETER_LOGIN_WINDOW (login_window)); @@ -742,12 +845,63 @@ gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window) } gboolean -gdm_greeter_login_window_reset (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: conversation '%s' has stopped", service_name); + + task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), + (GdmTaskListForeachFunc) + task_has_service_name, + (gpointer) service_name); + + if (task != NULL) { + gdm_conversation_reset (GDM_CONVERSATION (task)); + g_object_unref (task); + } + + 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)); + gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), + (GdmTaskListForeachFunc) + restart_task_conversation, + login_window); + return TRUE; } @@ -756,12 +910,20 @@ 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); - if (strcmp (service_name, gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list))) == 0) { - set_message (GDM_GREETER_LOGIN_WINDOW (login_window), text); + task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), + (GdmTaskListForeachFunc) + task_has_service_name, + (gpointer) service_name); + + if (task != NULL) { + gdm_conversation_set_message (GDM_CONVERSATION (task), + text); + g_object_unref (task); } return TRUE; @@ -772,13 +934,22 @@ 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); - if (strcmp (service_name, gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list))) == 0) { - set_message (GDM_GREETER_LOGIN_WINDOW (login_window), text); + task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), + (GdmTaskListForeachFunc) + task_has_service_name, + (gpointer) service_name); + + if (task != NULL) { + gdm_conversation_set_message (GDM_CONVERSATION (task), + text); + g_object_unref (task); } + gdk_window_beep (GTK_WIDGET (login_window)->window); return TRUE; @@ -816,11 +987,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 " @@ -830,8 +1011,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 @@ -857,26 +1038,24 @@ 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); - if (strcmp (service_name, gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list))) != 0) { - return TRUE; - } - g_debug ("GdmGreeterLoginWindow: info query: %s", text); - entry = glade_xml_get_widget (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->xml, "auth-prompt-entry"); - delete_entry_text (entry); - gtk_entry_set_visibility (GTK_ENTRY (entry), TRUE); - set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY); + task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), + (GdmTaskListForeachFunc) + task_has_service_name, + (gpointer) service_name); - label = glade_xml_get_widget (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->xml, "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)); @@ -891,20 +1070,23 @@ 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); - entry = glade_xml_get_widget (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->xml, "auth-prompt-entry"); - delete_entry_text (entry); - gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE); - set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY); + task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), + (GdmTaskListForeachFunc) + task_has_service_name, + (gpointer) service_name); - label = glade_xml_get_widget (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->xml, "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)); @@ -915,13 +1097,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 @@ -1344,6 +1529,46 @@ on_users_loaded (GdmUserChooserWidget *user_chooser, gdm_chooser_widget_activate_if_one_item (GDM_CHOOSER_WIDGET (login_window->priv->user_chooser)); } +static gboolean +begin_task_verification (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) { + g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, service_name); + g_free (service_name); + } + + return FALSE; +} + +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 on_user_chosen (GdmUserChooserWidget *user_chooser, GdmGreeterLoginWindow *login_window) @@ -1361,10 +1586,10 @@ on_user_chosen (GdmUserChooserWidget *user_chooser, 0, user_name); if (strcmp (user_name, GDM_USER_CHOOSER_USER_OTHER) == 0) { - const char *service_name; - - service_name = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list)); - g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, service_name); + gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), + (GdmTaskListForeachFunc) + begin_task_verification, + login_window); } 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) { @@ -1378,10 +1603,10 @@ on_user_chosen (GdmUserChooserWidget *user_chooser, set_log_in_button_mode (login_window, LOGIN_BUTTON_TIMED_LOGIN); set_message (login_window, _("Select language and click Log In")); } else { - const char *service_name; - - service_name = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list)); - g_signal_emit (login_window, signals[BEGIN_VERIFICATION_FOR_USER], 0, service_name, 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); @@ -1527,17 +1752,65 @@ create_computer_info (GdmGreeterLoginWindow *login_window) static void on_task_activated (GdmGreeterLoginWindow *login_window, - const char *name) + GdmTask *task) { - g_debug ("GdmGreeterLoginWindow: starting conversation with '%s'", name); - g_signal_emit (login_window, signals[START_CONVERSATION], 0, name); + 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); + set_log_in_button_mode (login_window, login_window->priv->dialog_mode); } static void on_task_deactivated (GdmGreeterLoginWindow *login_window, - const char *name) + GdmTask *task) { - g_debug ("GdmGreeterLoginWindow: conversation '%s' now in background", name); + 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 GtkWidget * @@ -1574,7 +1847,6 @@ custom_widget_constructor (GladeXML *xml, static void load_theme (GdmGreeterLoginWindow *login_window) { - GtkWidget *entry; GtkWidget *button; GtkWidget *box; GtkWidget *image; @@ -1649,15 +1921,9 @@ load_theme (GdmGreeterLoginWindow *login_window) login_window); gtk_widget_show (login_window->priv->conversation_list); - gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list), - "password-auth", "dialog-password"); - gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list), - "fingerprint-auth", "stock_allow-effects"); - gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list), - "smartcard-auth", "badge-small"); - login_window->priv->auth_banner_label = glade_xml_get_widget (login_window->priv->xml, "auth-banner-label"); /*make_label_small_italic (login_window->priv->auth_banner_label);*/ + login_window->priv->auth_page_box = glade_xml_get_widget (login_window->priv->xml, "auth-page-box"); button = glade_xml_get_widget (login_window->priv->xml, "suspend-button"); g_signal_connect (button, "clicked", G_CALLBACK (suspend_button_clicked), login_window); @@ -1673,14 +1939,6 @@ load_theme (GdmGreeterLoginWindow *login_window) button = glade_xml_get_widget (login_window->priv->xml, "shutdown-button"); g_signal_connect (button, "clicked", G_CALLBACK (shutdown_button_clicked), login_window); - entry = glade_xml_get_widget (login_window->priv->xml, "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 = glade_xml_get_widget (login_window->priv->xml, "computer-info-event-box"); @@ -1908,9 +2166,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, @@ -1963,6 +2221,187 @@ 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); +} + +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); + + image = gtk_action_create_icon (GTK_ACTION (action), GTK_ICON_SIZE_BUTTON); + 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); +} + +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 = glade_xml_get_widget (login_window->priv->xml, "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; + } + + 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); + + name = gdm_task_get_name (GDM_TASK (extension)); + description = gdm_task_get_description (GDM_TASK (extension)); + + g_debug ("GdmGreeterLoginWindow: new extension '%s - %s' added", + name, description); + + g_free (name); + g_free (description); + + if (gdm_task_list_get_number_of_tasks (GDM_TASK_LIST (login_window->priv->conversation_list)) == 0) { + gtk_widget_hide (login_window->priv->conversation_list); + } else { + gtk_widget_show (login_window->priv->conversation_list); + } + + 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)); + 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.glade b/gui/simple-greeter/gdm-greeter-login-window.glade index 3d9e2ee..76ab718 100644 --- a/gui/simple-greeter/gdm-greeter-login-window.glade +++ b/gui/simple-greeter/gdm-greeter-login-window.glade @@ -611,30 +611,29 @@ - - True - - False - False - GTK_JUSTIFY_CENTER - True - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - True - True - + + True + + False + False + GTK_JUSTIFY_CENTER + True + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + - True @@ -660,20 +659,6 @@ 0 - - True - 0 - 0 - Tue, 18 Nov 2008 21:55:38 GMT - - - 0 - True - True - - - - True 0 @@ -686,56 +671,12 @@ False - - - 0 - True - True - - - - - - True - False - 6 - - - - True - - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - True - 0 - - True - True + + 0 + 0 + Tue, 18 Nov 2008 21:55:38 GMT 0 @@ -744,46 +685,21 @@ - - - 0 - False - False + True + True - + True False 0 - - - True - - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - True - True - + diff --git a/gui/simple-greeter/gdm-greeter-login-window.h b/gui/simple-greeter/gdm-greeter-login-window.h index 559b26b..c312a47 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 +#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 @@ -62,7 +67,8 @@ typedef struct 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; @@ -71,7 +77,10 @@ GtkWidget * gdm_greeter_login_window_new (gboolean displa gboolean gdm_greeter_login_window_reset (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); @@ -88,7 +97,13 @@ gboolean gdm_greeter_login_window_problem (GdmGreeterLogin 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-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 + */ + +#include + +#include +#include +#include +#include + +#include +#include + +#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 +#include + +#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 714daa1..adbed6f 100644 --- a/gui/simple-greeter/gdm-greeter-session.c +++ b/gui/simple-greeter/gdm-greeter-session.c @@ -38,6 +38,8 @@ #include "gdm-greeter-panel.h" #include "gdm-greeter-login-window.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)) @@ -45,9 +47,11 @@ struct GdmGreeterSessionPrivate { GdmGreeterClient *client; + GdmPluginManager *plugin_manager; GtkWidget *login_window; GtkWidget *panel; + }; enum { @@ -91,7 +95,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 @@ -154,10 +170,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 @@ -270,7 +287,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 @@ -282,9 +298,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 @@ -436,8 +453,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; @@ -547,6 +562,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); @@ -575,6 +648,10 @@ gdm_greeter_session_init (GdmGreeterSession *session) G_CALLBACK (on_ready), session); g_signal_connect (session->priv->client, + "conversation-stopped", + G_CALLBACK (on_conversation_stopped), + session); + g_signal_connect (session->priv->client, "reset", G_CALLBACK (on_reset), session); @@ -609,6 +686,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 + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#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 + * + */ + +#ifndef __GDM_PLUGIN_MANAGER_H +#define __GDM_PLUGIN_MANAGER_H + +#include + +#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 index e0fd3d4..25831a6 100644 --- a/gui/simple-greeter/gdm-task-list.c +++ b/gui/simple-greeter/gdm-task-list.c @@ -37,12 +37,6 @@ #define GDM_TASK_LIST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_TASK_LIST, GdmTaskListPrivate)) -typedef struct -{ - GtkWidget *radio_button; - char *name; -} GdmTask; - struct GdmTaskListPrivate { GtkWidget *box; @@ -59,54 +53,161 @@ 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); +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 *radio_button) + GtkRadioButton *button) { GdmTask *task; - task = g_object_get_data (G_OBJECT (radio_button), "gdm-task"); + task = g_object_get_data (G_OBJECT (button), "gdm-task"); - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio_button))) { - g_signal_emit (widget, signals[ACTIVATED], 0, task->name); + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) { + g_signal_emit (widget, signals[ACTIVATED], 0, task); } else { - g_signal_emit (widget, signals[DEACTIVATED], 0, task->name); + 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; + GList *task_node; + + button = g_object_get_data (G_OBJECT (task), "gdm-task-list-button"); + + gtk_widget_set_sensitive (button, TRUE); + + /* 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 (task_list->priv->tasks, task); + if (task_node != NULL) { + task_list->priv->tasks = g_list_delete_link (task_list->priv->tasks, task_node); + task_list->priv->tasks = g_list_prepend (task_list->priv->tasks, + task); + } +} + +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, - const char *name, - const char *icon_name) + GdmTask *task) { - GdmTask *task; GtkWidget *image; + GtkWidget *button; + GIcon *icon; + char *description; - task = g_new0 (GdmTask, 1); - - task->name = g_strdup (name); if (task_list->priv->tasks == NULL) { - task->radio_button = gtk_radio_button_new (NULL); + button = gtk_radio_button_new (NULL); } else { - task->radio_button = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (((GdmTask *) task_list->priv->tasks->data)->radio_button)); + 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); - g_object_set (task->radio_button, "draw-indicator", FALSE, NULL); - g_object_set_data (G_OBJECT (task->radio_button), "gdm-task", task); - g_signal_connect_swapped (task->radio_button, - "toggled", G_CALLBACK (on_task_toggled), task_list); - image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_DND); gtk_widget_show (image); - gtk_container_add (GTK_CONTAINER (task->radio_button), image); - gtk_widget_show (task->radio_button); - gtk_container_add (GTK_CONTAINER (task->radio_button), task_list->priv->box); + 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), task->radio_button); + gtk_container_add (GTK_CONTAINER (task_list->priv->box), button); task_list->priv->tasks = g_list_append (task_list->priv->tasks, task); + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) { + g_signal_emit (task_list, signals[ACTIVATED], 0, task); + } } static void @@ -122,9 +223,9 @@ gdm_task_list_class_init (GdmTaskListClass *klass) G_STRUCT_OFFSET (GdmTaskListClass, activated), NULL, NULL, - g_cclosure_marshal_VOID__STRING, + g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, - 1, G_TYPE_STRING); + 1, G_TYPE_OBJECT); signals [DEACTIVATED] = g_signal_new ("deactivated", G_TYPE_FROM_CLASS (object_class), @@ -132,22 +233,19 @@ gdm_task_list_class_init (GdmTaskListClass *klass) G_STRUCT_OFFSET (GdmTaskListClass, deactivated), NULL, NULL, - g_cclosure_marshal_VOID__STRING, + g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, - 1, G_TYPE_STRING); + 1, G_TYPE_OBJECT); g_type_class_add_private (klass, sizeof (GdmTaskListPrivate)); -} - -static void -gdm_task_list_init (GdmTaskList *widget) +} 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 (FALSE, 2); + widget->priv->box = gtk_hbox_new (TRUE, 2); gtk_widget_show (widget->priv->box); gtk_container_add (GTK_CONTAINER (widget), widget->priv->box); @@ -179,20 +277,46 @@ gdm_task_list_new (void) return GTK_WIDGET (object); } -const char * +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) { - GList *node; + return gdm_task_list_foreach_task (widget, + (GdmTaskListForeachFunc) + gdm_task_list_task_is_active, + NULL); +} - for (node = widget->priv->tasks; node != NULL; node = node->next) { - GdmTask *task; +gboolean +gdm_task_list_set_active_task (GdmTaskList *widget, + GdmTask *task) +{ + GtkWidget *button; - task = node->data; + button = GTK_WIDGET (g_object_get_data (G_OBJECT (task), + "gdm-task-list-button")); - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (task->radio_button)) ) { - return task->name; + if (GTK_WIDGET_IS_SENSITIVE (button)) { + if (gtk_widget_activate (button)) { + return TRUE; } } - return NULL; + return FALSE; +} + +int +gdm_task_list_get_number_of_tasks (GdmTaskList *widget) +{ + return g_list_length (widget->priv->tasks); } diff --git a/gui/simple-greeter/gdm-task-list.h b/gui/simple-greeter/gdm-task-list.h index ade21b6..8bc0c0e 100644 --- a/gui/simple-greeter/gdm-task-list.h +++ b/gui/simple-greeter/gdm-task-list.h @@ -22,8 +22,11 @@ #define __GDM_TASK_LIST_H #include +#include #include +#include "gdm-task.h" + G_BEGIN_DECLS #define GDM_TYPE_TASK_LIST (gdm_task_list_get_type ()) @@ -34,31 +37,44 @@ G_BEGIN_DECLS #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 struct +typedef gboolean (* GdmTaskListForeachFunc) (GdmTaskList *task_list, + GdmTask *task, + gpointer data); + +struct _GdmTaskList { GtkAlignment parent; GdmTaskListPrivate *priv; -} GdmTaskList; +}; typedef struct { GtkAlignmentClass parent_class; void (* deactivated) (GdmTaskList *widget, - const char *name); + GdmTask *task); void (* activated) (GdmTaskList *widget, - const char *name); + GdmTask *task); } GdmTaskListClass; +GType gdm_task_list_get_type (void); +GtkWidget * gdm_task_list_new (void); + -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); -const char * gdm_task_list_get_active_task (GdmTaskList *widget); -void gdm_task_list_add_task (GdmTaskList *widget, - const char *name, - const char *icon_name); +int gdm_task_list_get_number_of_tasks (GdmTaskList *widget); G_END_DECLS #endif /* __GDM_TASK_LIST_H */ diff --git a/gui/simple-greeter/libgdmsimplegreeter/Makefile.am b/gui/simple-greeter/libgdmsimplegreeter/Makefile.am new file mode 100644 index 0000000..1ef5725 --- /dev/null +++ b/gui/simple-greeter/libgdmsimplegreeter/Makefile.am @@ -0,0 +1,46 @@ +NULL = + +AM_CPPFLAGS = \ + -I. \ + -I.. \ + -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) \ + $(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..e21c56b --- /dev/null +++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c @@ -0,0 +1,147 @@ +/* + * 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 + * + */ + +#include +#include + +#include + +#include "gdm-conversation.h" +#include "gdm-task.h" + + +enum { + ANSWER, + 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); +} + +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); +} + diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h new file mode 100644 index 0000000..f1910cf --- /dev/null +++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h @@ -0,0 +1,87 @@ +/* + * 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 + */ + + +#ifndef __GDM_CONVERSATION_H +#define __GDM_CONVERSATION_H + +#include +#include + +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" + +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); +}; + +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); + +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 + * + */ + +#include +#include + +#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 + +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..f72fa78 --- /dev/null +++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.c @@ -0,0 +1,117 @@ +/* + * 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 + * + */ + +#include +#include + +#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"); +} + +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..9894e65 --- /dev/null +++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.h @@ -0,0 +1,62 @@ +/* + * 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 + */ + + +#ifndef __GDM_TASK_H +#define __GDM_TASK_H + +#include +#include + +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); + /* 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); +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..fae73be --- /dev/null +++ b/gui/simple-greeter/plugins/password/gdm-password-extension.c @@ -0,0 +1,316 @@ +/* + * 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 + * + */ + +#include +#include "gdm-password-extension.h" +#include "gdm-conversation.h" +#include "gdm-task.h" + +#include +#include +#include + +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")); +} + +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; +} + +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"), + _("Log into the currently selected sesson"), + 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 + */ + +#ifndef __GDM_PASSWORD_EXTENSION_H +#define __GDM_PASSWORD_EXTENSION_H + +#include +#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..fe6da78 --- /dev/null +++ b/gui/simple-greeter/plugins/password/page.ui @@ -0,0 +1,56 @@ + + + + + True + vertical + + + True + + + True + + + False + False + 0 + + + + + True + True + True + + + 1 + + + + + True + True + 0 + + + + + True + + + True + + + 0 + + + + + True + True + 1 + + + + 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 + * + */ + +#include "gdm-password-extension.h" + +#include +#include + +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); +} -- 1.6.2.2 From ff3ec0b56e8343b86eec5edf9399ff12826cf861 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Sat, 7 Feb 2009 21:17:49 -0500 Subject: [PATCH 17/33] Force session reset if all PAM conversations fail --- gui/simple-greeter/gdm-greeter-login-window.c | 22 +++++++++++++++++++--- 1 files changed, 19 insertions(+), 3 deletions(-) diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c index 2e9a1a0..92a4c85 100644 --- a/gui/simple-greeter/gdm-greeter-login-window.c +++ b/gui/simple-greeter/gdm-greeter-login-window.c @@ -810,15 +810,21 @@ 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, const char *service_name) @@ -864,6 +870,16 @@ gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_wind 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); + return TRUE; } -- 1.6.2.2 From 619749c673af1404da29c82504a42f85f0f05be7 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Wed, 18 Feb 2009 12:32:39 -0500 Subject: [PATCH 18/33] Add a way for plugins to pick users from list The smartcard plugin is going to want to start its conversation as soon as the card gets plugged in. --- gui/simple-greeter/gdm-greeter-login-window.c | 36 ++++++++++++++++++++ .../libgdmsimplegreeter/gdm-conversation.c | 32 +++++++++++++++++ .../libgdmsimplegreeter/gdm-conversation.h | 6 +++ 3 files changed, 74 insertions(+), 0 deletions(-) diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c index 92a4c85..8711992 100644 --- a/gui/simple-greeter/gdm-greeter-login-window.c +++ b/gui/simple-greeter/gdm-greeter-login-window.c @@ -2256,6 +2256,34 @@ on_conversation_answer (GdmGreeterLoginWindow *login_window, set_ready (login_window); } +static void +on_conversation_cancel (GdmGreeterLoginWindow *login_window, + GdmConversation *conversation) +{ + do_cancel (login_window); +} + +static void +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; + } + + 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); + } +} + void gdm_greeter_login_window_remove_extension (GdmGreeterLoginWindow *login_window, GdmGreeterExtension *extension) @@ -2393,6 +2421,14 @@ gdm_greeter_login_window_add_extension (GdmGreeterLoginWindow *login_window, "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); name = gdm_task_get_name (GDM_TASK (extension)); description = gdm_task_get_description (GDM_TASK (extension)); diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c index e21c56b..cef435c 100644 --- a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c +++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c @@ -30,6 +30,8 @@ enum { ANSWER, + USER_CHOSEN, + CANCEL, LAST_SIGNAL }; @@ -71,6 +73,25 @@ gdm_conversation_class_init (gpointer g_iface) 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_FIRST, + G_STRUCT_OFFSET (GdmConversationIface, user_chosen), + NULL, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, + 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 @@ -145,3 +166,14 @@ gdm_conversation_answer (GdmConversation *conversation, g_signal_emit (conversation, signals [ANSWER], 0, answer); } +void +gdm_conversation_cancel (GdmConversation *conversation) +{ + g_signal_emit (conversation, signals [CANCEL], 0); +} +void +gdm_conversation_choose_user (GdmConversation *conversation, + const char *username) +{ + g_signal_emit (conversation, signals [USER_CHOSEN], 0, username); +} diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h index f1910cf..fb4bf49 100644 --- a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h +++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h @@ -34,6 +34,7 @@ G_BEGIN_DECLS #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; @@ -59,6 +60,8 @@ struct _GdmConversationIface /* signals */ char * (* answer) (GdmConversation *conversation); + void (* cancel) (GdmConversation *conversation); + void (* user_chosen) (GdmConversation *conversation); }; GType gdm_conversation_get_type (void) G_GNUC_CONST; @@ -81,6 +84,9 @@ gboolean gdm_conversation_focus (GdmConversation *conversation); */ void gdm_conversation_answer (GdmConversation *conversation, const char *answer); +void gdm_conversation_cancel (GdmConversation *conversation); +void gdm_conversation_choose_user (GdmConversation *conversation, + const char *username); G_END_DECLS -- 1.6.2.2 From 250fde71f653d72ac3e5f4528dd70492ae11e285 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 20 Feb 2009 14:05:20 -0500 Subject: [PATCH 19/33] Add new api to ask when chooser widget is done loading items --- gui/simple-greeter/gdm-chooser-widget.c | 9 +++++++++ gui/simple-greeter/gdm-chooser-widget.h | 2 ++ 2 files changed, 11 insertions(+), 0 deletions(-) diff --git a/gui/simple-greeter/gdm-chooser-widget.c b/gui/simple-greeter/gdm-chooser-widget.c index b1ba9b4..a7dbba5 100644 --- a/gui/simple-greeter/gdm-chooser-widget.c +++ b/gui/simple-greeter/gdm-chooser-widget.c @@ -93,6 +93,7 @@ struct GdmChooserWidgetPrivate guint32 should_hide_inactive_items : 1; guint32 emit_activated_after_resize_animation : 1; guint32 was_fully_grown : 1; + guint32 is_loaded : 1; GdmChooserWidgetPosition separator_position; GdmChooserWidgetState state; @@ -2502,8 +2503,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); } diff --git a/gui/simple-greeter/gdm-chooser-widget.h b/gui/simple-greeter/gdm-chooser-widget.h index 7e3e59c..6a07843 100644 --- a/gui/simple-greeter/gdm-chooser-widget.h +++ b/gui/simple-greeter/gdm-chooser-widget.h @@ -136,6 +136,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.6.2.2 From cd41af42ac3bdb25d30b03be33efa20edb23b72d Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 20 Feb 2009 14:31:27 -0500 Subject: [PATCH 20/33] Tell tasks they're ready only after user list loads This way they won't try to access the list prematurely. --- gui/simple-greeter/gdm-greeter-login-window.c | 28 ++++++++++++++++++++++++- 1 files changed, 27 insertions(+), 1 deletions(-) diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c index 8711992..e44122c 100644 --- a/gui/simple-greeter/gdm-greeter-login-window.c +++ b/gui/simple-greeter/gdm-greeter-login-window.c @@ -825,6 +825,27 @@ do_cancel (GdmGreeterLoginWindow *login_window) restart_conversations (login_window); } +static void +on_can_set_task_ready (GtkWidget *user_chooser, + GdmTask *task) +{ + g_signal_handlers_disconnect_by_func (user_chooser, + on_can_set_task_ready, + task); + gdm_conversation_set_ready (GDM_CONVERSATION (task)); + g_object_unref (task); +} + +static void +set_task_ready_when_loaded (GdmGreeterLoginWindow *login_window, + GdmTask *task) +{ + g_signal_connect (login_window->priv->user_chooser, + "loaded", + G_CALLBACK (on_can_set_task_ready), + g_object_ref (task)); +} + gboolean gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window, const char *service_name) @@ -839,7 +860,12 @@ gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window, (gpointer) service_name); if (task != NULL) { - gdm_conversation_set_ready (GDM_CONVERSATION (task)); + if (gdm_chooser_widget_is_loaded (GDM_CHOOSER_WIDGET (login_window->priv->user_chooser))) { + gdm_conversation_set_ready (GDM_CONVERSATION (task)); + } else { + + set_task_ready_when_loaded (login_window, task); + } g_object_unref (task); } -- 1.6.2.2 From 15dfb038516dcb27866371a1dcfd988137bd5072 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 6 Feb 2009 16:25:47 -0500 Subject: [PATCH 21/33] 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 | 299 ++++++++++++++++++++ .../fingerprint/gdm-fingerprint-extension.h | 56 ++++ .../plugins/fingerprint/gdm-fingerprint.pam | 17 ++ .../plugins/fingerprint/icons/16x16/Makefile.am | 5 + .../plugins/fingerprint/icons/48x48/Makefile.am | 5 + .../plugins/fingerprint/icons/Makefile.am | 1 + gui/simple-greeter/plugins/fingerprint/page.ui | 56 ++++ gui/simple-greeter/plugins/fingerprint/plugin.c | 40 +++ 11 files changed, 540 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/48x48/Makefile.am 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 23df306..da7ce2c 100644 --- a/configure.ac +++ b/configure.ac @@ -1402,6 +1402,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..b20dd65 --- /dev/null +++ b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c @@ -0,0 +1,299 @@ +/* + * 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 + * + */ + +#include +#include "gdm-fingerprint-extension.h" +#include "gdm-conversation.h" +#include "gdm-task.h" + +#include +#include +#include + +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")); +} + +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; +} + +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) +{ + GtkAction *action; + + 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 + */ + +#ifndef __GDM_FINGERPRINT_EXTENSION_H +#define __GDM_FINGERPRINT_EXTENSION_H + +#include +#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/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/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..fe6da78 --- /dev/null +++ b/gui/simple-greeter/plugins/fingerprint/page.ui @@ -0,0 +1,56 @@ + + + + + True + vertical + + + True + + + True + + + False + False + 0 + + + + + True + True + True + + + 1 + + + + + True + True + 0 + + + + + True + + + True + + + 0 + + + + + True + True + 1 + + + + 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 + * + */ + +#include "gdm-fingerprint-extension.h" + +#include +#include + +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); +} -- 1.6.2.2 From 8374d74f6c66da5f6b5afa4d504b5fccaeba41f7 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Wed, 11 Feb 2009 08:47:52 -0500 Subject: [PATCH 22/33] Add start of a smartcard plugin It contains a copy and paste of an old RHEL patch I did a few years ago. --- configure.ac | 11 + gui/simple-greeter/plugins/Makefile.am | 2 +- gui/simple-greeter/plugins/smartcard/Makefile.am | 77 ++ .../plugins/smartcard/gdm-smartcard-extension.c | 420 ++++++ .../plugins/smartcard/gdm-smartcard-extension.h | 56 + .../plugins/smartcard/gdm-smartcard-manager.c | 1394 ++++++++++++++++++++ .../plugins/smartcard/gdm-smartcard-manager.h | 86 ++ .../plugins/smartcard/gdm-smartcard-worker.c | 167 +++ .../plugins/smartcard/gdm-smartcard.c | 558 ++++++++ .../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 | 56 + gui/simple-greeter/plugins/smartcard/plugin.c | 40 + 18 files changed, 2989 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 da7ce2c..3b2b925 100644 --- a/configure.ac +++ b/configure.ac @@ -67,6 +67,7 @@ GNOME_PANEL_REQUIRED_VERSION=2.0.0 LIBXKLAVIER_REQUIRED_VERSION=3.5 #FONTCONFIG_REQUIRED_VERSION=2.6.0 FONTCONFIG_REQUIRED_VERSION=2.5.0 +NSS_REQUIRED_VERSION=3.11.1 EXTRA_COMPILE_WARNINGS(yes) @@ -89,6 +90,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 @@ -1406,6 +1413,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..632ee2d --- /dev/null +++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c @@ -0,0 +1,420 @@ +/* + * 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 + * + */ + +#include +#include "gdm-smartcard-extension.h" +#include "gdm-conversation.h" +#include "gdm-task.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#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; +}; + +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) { + gdm_conversation_choose_user (GDM_CONVERSATION (extension), + GDM_CONVERSATION_OTHER_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 +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); + } +} + +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")); +} + +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; +} + +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) +{ +} + +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"), + _("Log into the currently selected sesson"), + 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 + */ + +#ifndef __GDM_SMARTCARD_EXTENSION_H +#define __GDM_SMARTCARD_EXTENSION_H + +#include +#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..e346a9c --- /dev/null +++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-manager.c @@ -0,0 +1,1394 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#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; + SECMODModule *module; + char *module_path; + + GSource *smartcard_event_source; + GPid smartcard_event_watcher_pid; + GHashTable *smartcards; + + GThread *worker_thread; + + guint poll_timeout_id; + + guint32 is_unstoppable : 1; + guint32 nss_is_loaded : 1; +}; + +struct _GdmSmartcardManagerWorker { + SECMODModule *module; + GHashTable *smartcards; + gint write_fd; + + 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 gboolean gdm_smartcard_manager_create_worker (GdmSmartcardManager *manager, + int *worker_fd, GThread **worker_thread); + +static GdmSmartcardManagerWorker * gdm_smartcard_manager_worker_new (gint write_fd); +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->module = NULL; + + 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, + GdmSmartcardManager *manager) +{ + GdmSmartcard *card; + gboolean should_stop; + guchar event_type; + char *card_name; + gint fd; + + 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)) { + goto out; + } + + fd = g_io_channel_unix_get_fd (io_channel); + + event_type = '\0'; + if (!sc_read_bytes (fd, &event_type, 1)) { + should_stop = TRUE; + goto out; + } + + card = sc_read_smartcard (fd, manager->priv->module); + + if (card == NULL) { + should_stop = TRUE; + goto out; + } + + card_name = gdm_smartcard_get_name (card); + + 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 +gdm_smartcard_manager_event_processing_stopped_handler (GdmSmartcardManager *manager) +{ + manager->priv->smartcard_event_source = NULL; + gdm_smartcard_manager_stop_now (manager); +} + +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) +{ + if (manager->priv->smartcard_event_source != NULL) { + g_source_destroy (manager->priv->smartcard_event_source); + manager->priv->smartcard_event_source = NULL; + } + + if (manager->priv->worker_thread != NULL) { + SECMOD_CancelWait (manager->priv->module); + /* FIXME: The function above doesn't seem to + * always wake up WaitForAnyTokenEvent + */ + exit (0); + g_thread_join (manager->priv->worker_thread); + manager->priv->worker_thread = NULL; + } +} + +static gboolean +sc_load_nss (GError **error) +{ + SECStatus status = SECSuccess; + static const guint32 flags = + NSS_INIT_READONLY | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | + 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); + + 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 SECMODModule * +load_driver (char *module_path, + GError **error) +{ + SECMODModule *module; + char *module_spec; + gboolean module_explicitly_specified; + + g_debug ("attempting to load driver..."); + + module = NULL; + module_explicitly_specified = module_path != NULL; + if (module_explicitly_specified) { + 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; + + } else { + SECMODModuleList *modules, *tmp; + + modules = SECMOD_GetDefaultModuleList (); + + for (tmp = modules; tmp != NULL; tmp = tmp->next) { + if (!SECMOD_HasRemovableSlots (tmp->module) || + !tmp->module->loaded) + continue; + + module = SECMOD_ReferenceModule (tmp->module); + break; + } + + /* fallback to compiled in driver path + */ + if (module == NULL) { + 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 (!module_explicitly_specified && module == NULL) { + g_set_error (error, + GDM_SMARTCARD_MANAGER_ERROR, + GDM_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER, + _("no suitable smartcard driver could be found")); + } else if (module == NULL || !module->loaded) { + + gsize error_message_size; + char *error_message; + + if (module != NULL && !module->loaded) { + g_debug ("module found but not loaded?!"); + SECMOD_DestroyModule (module); + module = NULL; + } + + 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); + } + +out: + return module; +} + +static void +gdm_smartcard_manager_get_all_cards (GdmSmartcardManager *manager) +{ + int i; + + for (i = 0; i < manager->priv->module->slotCount; i++) { + GdmSmartcard *card; + CK_SLOT_ID slot_id; + gint slot_series; + char *card_name; + + slot_id = PK11_GetSlotID (manager->priv->module->slots[i]); + slot_series = PK11_GetSlotSeries (manager->priv->module->slots[i]); + + card = _gdm_smartcard_new (manager->priv->module, + slot_id, slot_series); + + card_name = gdm_smartcard_get_name (card); + + g_hash_table_replace (manager->priv->smartcards, + card_name, card); + } +} + +gboolean +gdm_smartcard_manager_start (GdmSmartcardManager *manager, + GError **error) +{ + GError *watching_error; + gint worker_fd; + GPid worker_pid; + GIOChannel *io_channel; + GSource *source; + GIOFlags channel_flags; + 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; + + worker_fd = -1; + worker_pid = 0; + + 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->module == NULL) { + manager->priv->module = load_driver (manager->priv->module_path, &nss_error); + } + + if (manager->priv->module == NULL) { + g_propagate_error (error, nss_error); + goto out; + } + + if (!gdm_smartcard_manager_create_worker (manager, &worker_fd, &manager->priv->worker_thread)) { + + 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_fd); + + channel_flags = g_io_channel_get_flags (io_channel); + watching_error = NULL; + + source = g_io_create_watch (io_channel, G_IO_IN | G_IO_HUP); + g_io_channel_unref (io_channel); + io_channel = NULL; + + manager->priv->smartcard_event_source = source; + + g_source_set_callback (manager->priv->smartcard_event_source, + (GSourceFunc) (GIOFunc) + gdm_smartcard_manager_check_for_and_process_events, + manager, + (GDestroyNotify) + gdm_smartcard_manager_event_processing_stopped_handler); + g_source_attach (manager->priv->smartcard_event_source, NULL); + g_source_unref (manager->priv->smartcard_event_source); + + /* 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; + } + + manager->priv->state = GDM_SMARTCARD_MANAGER_STATE_STOPPED; + gdm_smartcard_manager_stop_watching_for_events (manager); + + if (manager->priv->module != NULL) { + SECMOD_DestroyModule (manager->priv->module); + manager->priv->module = NULL; + } + + if (manager->priv->nss_is_loaded) { + NSS_Shutdown (); + manager->priv->nss_is_loaded = FALSE; + } + + g_debug ("smartcard manager stopped"); + + 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 (gint write_fd) +{ + GdmSmartcardManagerWorker *worker; + + worker = g_slice_new0 (GdmSmartcardManagerWorker); + worker->write_fd = write_fd; + worker->module = NULL; + + 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, 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, 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->write_fd, "R", 1)) { + goto error_out; + } + + if (!sc_write_smartcard (worker->write_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->write_fd, "I", 1)) { + goto error_out; + } + + if (!sc_write_smartcard (worker->write_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; + + + error = NULL; + + while (gdm_smartcard_manager_worker_watch_for_and_process_event (worker, &error)); + + if (error != NULL) { + g_debug ("could not process card event - %s", error->message); + g_error_free (error); + } + + gdm_smartcard_manager_worker_free (worker); +} + +static gboolean +gdm_smartcard_manager_create_worker (GdmSmartcardManager *manager, + gint *worker_fd, + GThread **worker_thread) +{ + 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 (write_fd); + worker->module = manager->priv->module; + + *worker_thread = g_thread_create ((GThreadFunc) + gdm_smartcard_manager_worker_run, + worker, TRUE, NULL); + + if (*worker_thread == NULL) { + gdm_smartcard_manager_worker_free (worker); + return FALSE; + } + + if (worker_fd) { + *worker_fd = read_fd; + } + + return TRUE; +} + +#ifdef GDM_SMARTCARD_MANAGER_ENABLE_TEST +#include + +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 +#include + +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..75e4f33 --- /dev/null +++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-worker.c @@ -0,0 +1,167 @@ +#include "config.h" + +#include +#include +#include +#include + +#include + +#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'? "" : 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_term_signal (int signal_number) +{ + close (signal_pipe_fds[1]); + signal_pipe_fds[1] = -1; +} + +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 (); + + signal (SIGTERM, on_term_signal); + signal (SIGPIPE, on_term_signal); + 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); + + 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..c0e2739 --- /dev/null +++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard.c @@ -0,0 +1,558 @@ +/* gdm-smartcard.c - smartcard object + * + * 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. + */ +#define GDM_SMARTCARD_ENABLE_INTERNAL_API +#include "gdm-smartcard.h" + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +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); + + if (card->priv->slot != NULL) { + card->priv->name = g_strdup (PK11_GetTokenName (card->priv->slot)); + } +} + +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 +#include + +#include + +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..3c803f7 --- /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 +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)Px#24YJ`L;wH)0002_L%V+f000SaNLh0L01ejw01ejxLMWSf00007bV*G`2iXJ- z6cQQvze?o*000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}0008QNkl25h)mRS()F5IML|LeofZ5$Phq#SvEXn3)x9QHz&V1jD*OHUa=lnh|yoWc& zo1+2m0}628RN4)kP9zfJhGEoz$TZEX{|)Htgf`%?ZQIABl!txa-_X&~;rI9Vo88^r z1;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(}(unH3ls_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%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)Px#24YJ`L;wH)0002_L%V+f000SaNLh0L01ejw01ejxLMWSf00007bV*G`2iXJ- z6calzC#000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}000lgNkl2aFf(X>ozT5 zC$5aZk)aA|*R=Bt;5o9kwWGLxmKt<-N{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#^8Cli339gNwym|C9-PB*HI@kv?`fqW>?@BILKy#D z4S0a;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#Ugb-f=#OBSLRV)@WcJJQJ&Ye3&I2?Xcz^>Gsxim*Q?-KBt3|v`2Duq&D7y_j< z0x%8GT2LLZXlt%!eN&J%4OM6j-+g(6iP&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{Erluyw#>N;L8e(*Gv`DLkM=6Eh@8_O-?!oKzic_afJqug{j#UWY zI1WMx{9Y4}DUeEFnSyt9HPNv?jFgh;>FJ6cc3rnJpQx!J5{ZgwtW?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}>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@!QJRH14t>!X0sePaDb|+Dtta4 zufP5}>(;HKy}g}yJWeK)K}yM*HET#D5_gq-z%nx;u(VMPRx)Uz}P+MC|E|(*h%P~DYjo0fXolcX@W|^3n;K?VS z=PjT#i5aQW?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$q8NID7Ow6H`@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?~CGDRgIki0dHM>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@$4sA?5`wY$vF6CHez{E%@3`>BkDOHUut+h_2QsozaHc|NQ$fdzg?~8Hx=udg_ z(OcQlR#*Q2Q;*%gl=Cmz42>tbG(5-E@f1>O6q; zX-_O5v;07EtbcS_^-VG|xmachDJ7OAFfh5jGlJ`CydHyHoz3{XW z{(dz$IAT2ho_d-#6|#4&hB1V1g$WsgB6x$QI*YsCwN&|#S%sTbNE@USNTtgHIC@#} zG8FJ)ngXp0H6j3yX`s=3WJoXpKFL!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-zHPRK--Qpu^f!9}X+|e<~ z6MvoI@K5qN;7er_x_I#-M~@z*udk0IM~=vunHdwn + + + + True + vertical + + + True + + + True + + + False + False + 0 + + + + + True + True + True + + + 1 + + + + + True + True + 0 + + + + + True + + + True + + + 0 + + + + + True + True + 1 + + + + 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 + * + */ + +#include "gdm-smartcard-extension.h" + +#include +#include + +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); +} -- 1.6.2.2 From 4cfc355618cbc1d47650ad7483d06c3980cfcc46 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 23 Feb 2009 17:57:06 -0500 Subject: [PATCH 23/33] Add a new "choosable" property to show tasks in user list Useful for Smartcard and some future "Guest" account plugin --- gui/simple-greeter/gdm-greeter-login-window.c | 13 ++++++++++--- gui/simple-greeter/libgdmsimplegreeter/gdm-task.c | 6 ++++++ gui/simple-greeter/libgdmsimplegreeter/gdm-task.h | 2 ++ .../fingerprint/gdm-fingerprint-extension.c | 7 +++++++ .../plugins/password/gdm-password-extension.c | 7 +++++++ .../plugins/smartcard/gdm-smartcard-extension.c | 7 +++++++ 6 files changed, 39 insertions(+), 3 deletions(-) diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c index e44122c..a7cda4e 100644 --- a/gui/simple-greeter/gdm-greeter-login-window.c +++ b/gui/simple-greeter/gdm-greeter-login-window.c @@ -2462,9 +2462,6 @@ gdm_greeter_login_window_add_extension (GdmGreeterLoginWindow *login_window, g_debug ("GdmGreeterLoginWindow: new extension '%s - %s' added", name, description); - g_free (name); - g_free (description); - if (gdm_task_list_get_number_of_tasks (GDM_TASK_LIST (login_window->priv->conversation_list)) == 0) { gtk_widget_hide (login_window->priv->conversation_list); } else { @@ -2475,6 +2472,16 @@ gdm_greeter_login_window_add_extension (GdmGreeterLoginWindow *login_window, 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); + } + + 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); diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-task.c b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.c index f72fa78..05fd75c 100644 --- a/gui/simple-greeter/libgdmsimplegreeter/gdm-task.c +++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.c @@ -88,6 +88,12 @@ 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); +} + static void gdm_task_class_init (gpointer g_iface) { diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-task.h b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.h index 9894e65..c75bf29 100644 --- a/gui/simple-greeter/libgdmsimplegreeter/gdm-task.h +++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.h @@ -44,6 +44,7 @@ struct _GdmTaskIface GIcon * (* get_icon) (GdmTask *task); char * (* get_description) (GdmTask *task); char * (* get_name) (GdmTask *task); + gboolean (* is_choosable) (GdmTask *task); /* signals */ void (* enabled) (GdmTask *task); void (* disabled) (GdmTask *task); @@ -57,6 +58,7 @@ 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); G_END_DECLS #endif /* __GDM_TASK_H */ diff --git a/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c index b20dd65..7aa99e7 100644 --- a/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c +++ b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c @@ -188,12 +188,19 @@ 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; +} + 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; } 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 fae73be..e6c608a 100644 --- a/gui/simple-greeter/plugins/password/gdm-password-extension.c +++ b/gui/simple-greeter/plugins/password/gdm-password-extension.c @@ -188,12 +188,19 @@ 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; +} + 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; } 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 632ee2d..ed19e62 100644 --- a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c +++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c @@ -290,12 +290,19 @@ 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; +} + 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; } static void -- 1.6.2.2 From 11616eee76ac2e6c75c4b090f590696159eb3b92 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Tue, 24 Feb 2009 15:12:35 -0500 Subject: [PATCH 24/33] Separate handling of non-users in user list from users Now get_chosen_user returns NULL if the activated item wasn't a user. We also separate the handling of on item activation in two functions depending on the item type. This will be useful for adding custom handling for plugin added items. --- gui/simple-greeter/gdm-greeter-login-window.c | 53 +++++++++++++------- gui/simple-greeter/gdm-user-chooser-widget.c | 23 ++++++++- .../fingerprint/gdm-fingerprint-extension.c | 2 - 3 files changed, 56 insertions(+), 22 deletions(-) diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c index a7cda4e..3f4c031 100644 --- a/gui/simple-greeter/gdm-greeter-login-window.c +++ b/gui/simple-greeter/gdm-greeter-login-window.c @@ -1612,29 +1612,49 @@ begin_task_verification_for_selected_user (GdmTaskList *task_list, } static void -on_user_chosen (GdmUserChooserWidget *user_chooser, - GdmGreeterLoginWindow *login_window) +on_user_chosen (GdmGreeterLoginWindow *login_window, + const char *user_name) { - char *user_name; + 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); +} + +static void +on_user_chooser_activated (GdmUserChooserWidget *user_chooser, + GdmGreeterLoginWindow *login_window) +{ + 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); + on_user_chosen (login_window, user_name); + g_free (user_name); return; } - g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED], - 0, user_name); + item_id = gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (user_chooser)); + g_debug ("GdmGreeterLoginWindow: item chosen '%s'", item_id); - if (strcmp (user_name, GDM_USER_CHOOSER_USER_OTHER) == 0) { + if (strcmp (item_id, GDM_USER_CHOOSER_USER_OTHER) == 0) { + g_debug ("GdmGreeterLoginWindow: Starting all auth conversations"); gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), (GdmTaskListForeachFunc) begin_task_verification, login_window); - } 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_free (item_id); + } else if (strcmp (item_id, GDM_USER_CHOOSER_USER_AUTO) == 0) { + g_debug ("GdmGreeterLoginWindow: Starting auto login"); g_signal_emit (login_window, signals[BEGIN_AUTO_LOGIN], 0, login_window->priv->timed_login_username); @@ -1644,16 +1664,11 @@ on_user_chosen (GdmUserChooserWidget *user_chooser, /* just wait for the user to select language and stuff */ set_log_in_button_mode (login_window, LOGIN_BUTTON_TIMED_LOGIN); set_message (login_window, _("Select language and click Log In")); - } else { - gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), - (GdmTaskListForeachFunc) - begin_task_verification_for_selected_user, - login_window); + g_free (item_id); } + g_debug ("GdmGreeterLoginWindow: Switching to shrunken authentication mode"); switch_mode (login_window, MODE_AUTHENTICATION); - - g_free (user_name); } static void @@ -1942,7 +1957,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", diff --git a/gui/simple-greeter/gdm-user-chooser-widget.c b/gui/simple-greeter/gdm-user-chooser-widget.c index b1cb281..e0737b8 100644 --- a/gui/simple-greeter/gdm-user-chooser-widget.c +++ b/gui/simple-greeter/gdm-user-chooser-widget.c @@ -238,9 +238,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/plugins/fingerprint/gdm-fingerprint-extension.c b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c index 7aa99e7..316ef46 100644 --- a/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c +++ b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c @@ -287,8 +287,6 @@ create_page (GdmFingerprintExtension *extension) static void create_actions (GdmFingerprintExtension *extension) { - GtkAction *action; - extension->priv->actions = gtk_action_group_new ("gdm-fingerprint-extension"); } -- 1.6.2.2 From 7643db3623d28426893d7648ff65e3f030339c5d Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 27 Feb 2009 15:44:13 -0500 Subject: [PATCH 25/33] Initiate smart card auth when clicking on it in list --- gui/simple-greeter/gdm-greeter-login-window.c | 24 ++++++++++++++++++++ .../plugins/smartcard/gdm-smartcard-extension.c | 2 +- 2 files changed, 25 insertions(+), 1 deletions(-) diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c index 3f4c031..782cee8 100644 --- a/gui/simple-greeter/gdm-greeter-login-window.c +++ b/gui/simple-greeter/gdm-greeter-login-window.c @@ -803,6 +803,7 @@ reset_dialog (GdmGreeterLoginWindow *login_window) set_message (login_window, ""); switch_mode (login_window, MODE_SELECTION); + 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)); @@ -1632,6 +1633,7 @@ static void on_user_chooser_activated (GdmUserChooserWidget *user_chooser, GdmGreeterLoginWindow *login_window) { + char *user_name; char *item_id; user_name = gdm_user_chooser_widget_get_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser)); @@ -1665,6 +1667,28 @@ on_user_chooser_activated (GdmUserChooserWidget *user_chooser, set_log_in_button_mode (login_window, LOGIN_BUTTON_TIMED_LOGIN); set_message (login_window, _("Select language and click Log In")); g_free (item_id); + } else { + GdmTask *task; + + task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), + (GdmTaskListForeachFunc) + task_has_service_name, + (gpointer) item_id); + + if (task == NULL) { + g_debug ("GdmGreeterLoginWindow: %s has no task associated with it", item_id); + g_free (item_id); + return; + } + g_debug ("GdmGreeterLoginWindow: Beginning auth conversation for item %s", item_id); + + /* FIXME: we should probably give the plugin more say for + * what happens here. + */ + g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, item_id); + g_free (item_id); + + gtk_widget_set_sensitive (login_window->priv->conversation_list, FALSE); } g_debug ("GdmGreeterLoginWindow: Switching to shrunken authentication mode"); diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c index ed19e62..d3641ba 100644 --- a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c +++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c @@ -103,7 +103,7 @@ on_smartcard_event (GIOChannel *io_channel, if (extension->priv->number_of_tokens == 1) { gdm_conversation_choose_user (GDM_CONVERSATION (extension), - GDM_CONVERSATION_OTHER_USER); + PAMSERVICENAME); } else if (extension->priv->number_of_tokens == 0) { gdm_conversation_cancel (GDM_CONVERSATION (extension)); } -- 1.6.2.2 From 11d32d79e676ec4c46ad5bb1b51c2a8f17c519f0 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 2 Mar 2009 11:10:28 -0500 Subject: [PATCH 26/33] Only show task list if user is selected --- gui/simple-greeter/gdm-greeter-login-window.c | 52 +++++++++++++++++-------- gui/simple-greeter/gdm-task-list.c | 11 ++++- 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c index 782cee8..78e4644 100644 --- a/gui/simple-greeter/gdm-greeter-login-window.c +++ b/gui/simple-greeter/gdm-greeter-login-window.c @@ -105,7 +105,8 @@ enum { MODE_SELECTION = 0, - MODE_AUTHENTICATION + MODE_SINGLE_AUTHENTICATION, + MODE_MULTIPLE_AUTHENTICATION, }; enum { @@ -586,7 +587,8 @@ sensitize_power_buttons_timeout (GdmGreeterLoginWindow *login_window) sensitize_widget (login_window, "suspend-button", TRUE); sensitize_widget (login_window, "disconnect-button", TRUE); break; - case MODE_AUTHENTICATION: + case MODE_SINGLE_AUTHENTICATION: + case MODE_MULTIPLE_AUTHENTICATION: break; default: g_assert_not_reached (); @@ -614,6 +616,7 @@ switch_mode (GdmGreeterLoginWindow *login_window, GtkWidget *box; gboolean show_restart_buttons; gboolean show_suspend_button; + int number_of_tasks; show_restart_buttons = get_show_restart_buttons (login_window); show_suspend_button = can_suspend (login_window); @@ -643,6 +646,8 @@ switch_mode (GdmGreeterLoginWindow *login_window, ! login_window->priv->display_is_local); show_widget (login_window, "auth-page-box", FALSE); + show_widget (login_window, "conversation-list", FALSE); + gtk_widget_set_sensitive (login_window->priv->conversation_list, TRUE); add_sensitize_power_buttons_timeout (login_window); sensitize_widget (login_window, "shutdown-button", FALSE); @@ -652,13 +657,29 @@ switch_mode (GdmGreeterLoginWindow *login_window, default_name = NULL; break; - case MODE_AUTHENTICATION: + case MODE_SINGLE_AUTHENTICATION: + case MODE_MULTIPLE_AUTHENTICATION: + gtk_widget_set_size_request (GTK_WIDGET (login_window), + GTK_WIDGET (login_window)->allocation.width, + -1); show_widget (login_window, "cancel-button", TRUE); show_widget (login_window, "shutdown-button", FALSE); show_widget (login_window, "restart-button", FALSE); show_widget (login_window, "suspend-button", FALSE); show_widget (login_window, "disconnect-button", FALSE); show_widget (login_window, "auth-page-box", TRUE); + + number_of_tasks = gdm_task_list_get_number_of_tasks (GDM_TASK_LIST (login_window->priv->conversation_list)); + show_widget (login_window, "conversation-list", number_of_tasks > 1); + + if (number == MODE_SINGLE_AUTHENTICATION) { + g_debug ("GdmGreeterLoginWindow: Single authentication, 1 task"); + gtk_widget_set_sensitive (login_window->priv->conversation_list, FALSE); + } else { + g_debug ("GdmGreeterLoginWindow: Multiple authentication, %d tasks", number_of_tasks); + gtk_widget_set_sensitive (login_window->priv->conversation_list, TRUE); + } + default_name = "log-in-button"; break; default: @@ -1626,7 +1647,7 @@ on_user_chosen (GdmGreeterLoginWindow *login_window, begin_task_verification_for_selected_user, login_window); - switch_mode (login_window, MODE_AUTHENTICATION); + switch_mode (login_window, MODE_MULTIPLE_AUTHENTICATION); } static void @@ -1655,6 +1676,8 @@ on_user_chooser_activated (GdmUserChooserWidget *user_chooser, begin_task_verification, login_window); g_free (item_id); + + switch_mode (login_window, MODE_MULTIPLE_AUTHENTICATION); } else if (strcmp (item_id, GDM_USER_CHOOSER_USER_AUTO) == 0) { g_debug ("GdmGreeterLoginWindow: Starting auto login"); g_signal_emit (login_window, signals[BEGIN_AUTO_LOGIN], 0, @@ -1667,6 +1690,8 @@ on_user_chooser_activated (GdmUserChooserWidget *user_chooser, set_log_in_button_mode (login_window, LOGIN_BUTTON_TIMED_LOGIN); set_message (login_window, _("Select language and click Log In")); g_free (item_id); + + switch_mode (login_window, MODE_SINGLE_AUTHENTICATION); } else { GdmTask *task; @@ -1681,18 +1706,17 @@ on_user_chooser_activated (GdmUserChooserWidget *user_chooser, return; } g_debug ("GdmGreeterLoginWindow: Beginning auth conversation for item %s", item_id); - /* FIXME: we should probably give the plugin more say for * what happens here. */ g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, item_id); g_free (item_id); - gtk_widget_set_sensitive (login_window->priv->conversation_list, FALSE); - } + switch_mode (login_window, MODE_SINGLE_AUTHENTICATION); + gdm_task_list_set_active_task (GDM_TASK_LIST (login_window->priv->conversation_list), task); - g_debug ("GdmGreeterLoginWindow: Switching to shrunken authentication mode"); - switch_mode (login_window, MODE_AUTHENTICATION); + g_object_unref (task); + } } static void @@ -2000,7 +2024,6 @@ load_theme (GdmGreeterLoginWindow *login_window) "deactivated", G_CALLBACK (on_task_deactivated), login_window); - gtk_widget_show (login_window->priv->conversation_list); login_window->priv->auth_banner_label = glade_xml_get_widget (login_window->priv->xml, "auth-banner-label"); /*make_label_small_italic (login_window->priv->auth_banner_label);*/ @@ -2039,7 +2062,8 @@ gdm_greeter_login_window_key_press_event (GtkWidget *widget, login_window = GDM_GREETER_LOGIN_WINDOW (widget); if (event->keyval == GDK_Escape) { - if (login_window->priv->dialog_mode == MODE_AUTHENTICATION) { + if (login_window->priv->dialog_mode == MODE_SINGLE_AUTHENTICATION || + login_window->priv->dialog_mode == MODE_MULTIPLE_AUTHENTICATION) { do_cancel (GDM_GREETER_LOGIN_WINDOW (widget)); } } @@ -2501,12 +2525,6 @@ gdm_greeter_login_window_add_extension (GdmGreeterLoginWindow *login_window, g_debug ("GdmGreeterLoginWindow: new extension '%s - %s' added", name, description); - if (gdm_task_list_get_number_of_tasks (GDM_TASK_LIST (login_window->priv->conversation_list)) == 0) { - gtk_widget_hide (login_window->priv->conversation_list); - } else { - gtk_widget_show (login_window->priv->conversation_list); - } - gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list), GDM_TASK (extension)); diff --git a/gui/simple-greeter/gdm-task-list.c b/gui/simple-greeter/gdm-task-list.c index 25831a6..162b784 100644 --- a/gui/simple-greeter/gdm-task-list.c +++ b/gui/simple-greeter/gdm-task-list.c @@ -302,17 +302,24 @@ gdm_task_list_set_active_task (GdmTaskList *widget, GdmTask *task) { GtkWidget *button; + gboolean was_sensitive; + gboolean was_activated; + + 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)) { - return TRUE; + was_activated = TRUE; } } - return FALSE; + gtk_widget_set_sensitive (GTK_WIDGET (widget), was_sensitive); + return was_activated; } int -- 1.6.2.2 From 3122b474ebd0325e2cd6e45748f3a67e3436a5a6 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 2 Mar 2009 13:53:34 -0500 Subject: [PATCH 27/33] Pull verification functions out into their own subroutines This makes the function smaller and easier to read --- gui/simple-greeter/gdm-greeter-login-window.c | 110 ++++++++++++++++--------- 1 files changed, 70 insertions(+), 40 deletions(-) diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c index 78e4644..ac3767a 100644 --- a/gui/simple-greeter/gdm-greeter-login-window.c +++ b/gui/simple-greeter/gdm-greeter-login-window.c @@ -1609,6 +1609,17 @@ begin_task_verification (GdmTaskList *task_list, 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_MULTIPLE_AUTHENTICATION); +} + static gboolean begin_task_verification_for_selected_user (GdmTaskList *task_list, GdmTask *task, @@ -1634,6 +1645,15 @@ begin_task_verification_for_selected_user (GdmTaskList *task_list, } static void +begin_verification_for_selected_user (GdmGreeterLoginWindow *login_window) +{ + gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), + (GdmTaskListForeachFunc) + begin_task_verification_for_selected_user, + login_window); +} + +static void on_user_chosen (GdmGreeterLoginWindow *login_window, const char *user_name) { @@ -1642,15 +1662,55 @@ on_user_chosen (GdmGreeterLoginWindow *login_window, 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); + begin_verification_for_selected_user (login_window); switch_mode (login_window, MODE_MULTIPLE_AUTHENTICATION); } 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_log_in_button_mode (login_window, LOGIN_BUTTON_TIMED_LOGIN); + set_message (login_window, _("Select language and click Log In")); + + switch_mode (login_window, MODE_SINGLE_AUTHENTICATION); +} + +static void +begin_single_service_verification (GdmGreeterLoginWindow *login_window, + const char *service_name) +{ + GdmTask *task; + + task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), + (GdmTaskListForeachFunc) + task_has_service_name, + (gpointer) service_name); + + if (task == NULL) { + g_debug ("GdmGreeterLoginWindow: %s has no task associated with it", service_name); + return; + } + g_debug ("GdmGreeterLoginWindow: Beginning auth conversation for item %s", 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_SINGLE_AUTHENTICATION); + gdm_task_list_set_active_task (GDM_TASK_LIST (login_window->priv->conversation_list), task); + + g_object_unref (task); +} + +static void on_user_chooser_activated (GdmUserChooserWidget *user_chooser, GdmGreeterLoginWindow *login_window) { @@ -1669,53 +1729,23 @@ on_user_chooser_activated (GdmUserChooserWidget *user_chooser, 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"); - gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), - (GdmTaskListForeachFunc) - begin_task_verification, - login_window); g_free (item_id); - switch_mode (login_window, MODE_MULTIPLE_AUTHENTICATION); + begin_verification (login_window); } else if (strcmp (item_id, GDM_USER_CHOOSER_USER_AUTO) == 0) { g_debug ("GdmGreeterLoginWindow: Starting auto login"); - 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_log_in_button_mode (login_window, LOGIN_BUTTON_TIMED_LOGIN); - set_message (login_window, _("Select language and click Log In")); g_free (item_id); - switch_mode (login_window, MODE_SINGLE_AUTHENTICATION); + begin_auto_login (login_window); } else { - GdmTask *task; - - task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), - (GdmTaskListForeachFunc) - task_has_service_name, - (gpointer) item_id); - if (task == NULL) { - g_debug ("GdmGreeterLoginWindow: %s has no task associated with it", item_id); - g_free (item_id); - return; - } - g_debug ("GdmGreeterLoginWindow: Beginning auth conversation for item %s", item_id); - /* FIXME: we should probably give the plugin more say for - * what happens here. - */ - g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, item_id); + begin_single_service_verification (login_window, item_id); g_free (item_id); - - switch_mode (login_window, MODE_SINGLE_AUTHENTICATION); - gdm_task_list_set_active_task (GDM_TASK_LIST (login_window->priv->conversation_list), task); - - g_object_unref (task); } } -- 1.6.2.2 From 23902b5f178ef6662850ae81a96f3c9aafc66317 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 2 Mar 2009 13:57:34 -0500 Subject: [PATCH 28/33] Add new function find_task_with_service_name It hides a bunch of icky foreach calls. --- gui/simple-greeter/gdm-greeter-login-window.c | 50 +++++++++++-------------- 1 files changed, 22 insertions(+), 28 deletions(-) diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c index ac3767a..fa93108 100644 --- a/gui/simple-greeter/gdm-greeter-login-window.c +++ b/gui/simple-greeter/gdm-greeter-login-window.c @@ -775,6 +775,20 @@ task_has_service_name (GdmTaskList *task_list, return has_service_name; } +GdmTask * +find_task_with_service_name (GdmGreeterLoginWindow *login_window, + const char *service_name) +{ + GdmTask *task; + + task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), + (GdmTaskListForeachFunc) + task_has_service_name, + (gpointer) service_name); + + return task; +} + static gboolean reset_task (GdmTaskList *task_list, GdmTask *task, @@ -876,10 +890,7 @@ gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window, g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE); - task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), - (GdmTaskListForeachFunc) - task_has_service_name, - (gpointer) service_name); + 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))) { @@ -908,10 +919,7 @@ gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_wind g_debug ("GdmGreeterLoginWindow: conversation '%s' has stopped", service_name); - task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), - (GdmTaskListForeachFunc) - task_has_service_name, - (gpointer) service_name); + task = find_task_with_service_name (login_window, service_name); if (task != NULL) { gdm_conversation_reset (GDM_CONVERSATION (task)); @@ -979,10 +987,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); - task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), - (GdmTaskListForeachFunc) - task_has_service_name, - (gpointer) service_name); + task = find_task_with_service_name (login_window, service_name); if (task != NULL) { gdm_conversation_set_message (GDM_CONVERSATION (task), @@ -1003,10 +1008,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); - task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), - (GdmTaskListForeachFunc) - task_has_service_name, - (gpointer) service_name); + task = find_task_with_service_name (login_window, service_name); if (task != NULL) { gdm_conversation_set_message (GDM_CONVERSATION (task), @@ -1108,10 +1110,8 @@ gdm_greeter_login_window_info_query (GdmGreeterLoginWindow *login_window, g_debug ("GdmGreeterLoginWindow: info query: %s", text); - task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), - (GdmTaskListForeachFunc) - task_has_service_name, - (gpointer) service_name); + + task = find_task_with_service_name (login_window, service_name); if (task != NULL) { gdm_conversation_ask_question (GDM_CONVERSATION (task), @@ -1139,10 +1139,7 @@ gdm_greeter_login_window_secret_info_query (GdmGreeterLoginWindow *login_window, g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE); - task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), - (GdmTaskListForeachFunc) - task_has_service_name, - (gpointer) service_name); + task = find_task_with_service_name (login_window, service_name); if (task != NULL) { gdm_conversation_ask_secret (GDM_CONVERSATION (task), @@ -1689,10 +1686,7 @@ begin_single_service_verification (GdmGreeterLoginWindow *login_window, { GdmTask *task; - task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), - (GdmTaskListForeachFunc) - task_has_service_name, - (gpointer) service_name); + 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); -- 1.6.2.2 From adf32974d4fb816688498552727d664c80653064 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 2 Mar 2009 15:23:51 -0500 Subject: [PATCH 29/33] Drop the different auth modes in favor of calling reset manually --- gui/simple-greeter/gdm-greeter-login-window.c | 57 +++++++++++++++---------- 1 files changed, 35 insertions(+), 22 deletions(-) diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c index fa93108..ed009a4 100644 --- a/gui/simple-greeter/gdm-greeter-login-window.c +++ b/gui/simple-greeter/gdm-greeter-login-window.c @@ -105,8 +105,7 @@ enum { MODE_SELECTION = 0, - MODE_SINGLE_AUTHENTICATION, - MODE_MULTIPLE_AUTHENTICATION, + MODE_AUTHENTICATION }; enum { @@ -587,8 +586,7 @@ sensitize_power_buttons_timeout (GdmGreeterLoginWindow *login_window) sensitize_widget (login_window, "suspend-button", TRUE); sensitize_widget (login_window, "disconnect-button", TRUE); break; - case MODE_SINGLE_AUTHENTICATION: - case MODE_MULTIPLE_AUTHENTICATION: + case MODE_AUTHENTICATION: break; default: g_assert_not_reached (); @@ -647,7 +645,6 @@ switch_mode (GdmGreeterLoginWindow *login_window, show_widget (login_window, "auth-page-box", FALSE); show_widget (login_window, "conversation-list", FALSE); - gtk_widget_set_sensitive (login_window->priv->conversation_list, TRUE); add_sensitize_power_buttons_timeout (login_window); sensitize_widget (login_window, "shutdown-button", FALSE); @@ -657,8 +654,7 @@ switch_mode (GdmGreeterLoginWindow *login_window, default_name = NULL; break; - case MODE_SINGLE_AUTHENTICATION: - case MODE_MULTIPLE_AUTHENTICATION: + case MODE_AUTHENTICATION: gtk_widget_set_size_request (GTK_WIDGET (login_window), GTK_WIDGET (login_window)->allocation.width, -1); @@ -672,14 +668,6 @@ switch_mode (GdmGreeterLoginWindow *login_window, number_of_tasks = gdm_task_list_get_number_of_tasks (GDM_TASK_LIST (login_window->priv->conversation_list)); show_widget (login_window, "conversation-list", number_of_tasks > 1); - if (number == MODE_SINGLE_AUTHENTICATION) { - g_debug ("GdmGreeterLoginWindow: Single authentication, 1 task"); - gtk_widget_set_sensitive (login_window->priv->conversation_list, FALSE); - } else { - g_debug ("GdmGreeterLoginWindow: Multiple authentication, %d tasks", number_of_tasks); - gtk_widget_set_sensitive (login_window->priv->conversation_list, TRUE); - } - default_name = "log-in-button"; break; default: @@ -1614,7 +1602,7 @@ begin_verification (GdmGreeterLoginWindow *login_window) begin_task_verification, login_window); - switch_mode (login_window, MODE_MULTIPLE_AUTHENTICATION); + switch_mode (login_window, MODE_AUTHENTICATION); } static gboolean @@ -1661,7 +1649,7 @@ on_user_chosen (GdmGreeterLoginWindow *login_window, begin_verification_for_selected_user (login_window); - switch_mode (login_window, MODE_MULTIPLE_AUTHENTICATION); + switch_mode (login_window, MODE_AUTHENTICATION); } static void @@ -1677,7 +1665,30 @@ begin_auto_login (GdmGreeterLoginWindow *login_window) set_log_in_button_mode (login_window, LOGIN_BUTTON_TIMED_LOGIN); set_message (login_window, _("Select language and click Log In")); - switch_mode (login_window, MODE_SINGLE_AUTHENTICATION); + switch_mode (login_window, MODE_AUTHENTICATION); +} + +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 @@ -1692,15 +1703,18 @@ begin_single_service_verification (GdmGreeterLoginWindow *login_window, g_debug ("GdmGreeterLoginWindow: %s has no task associated with it", service_name); return; } - g_debug ("GdmGreeterLoginWindow: Beginning auth conversation for item %s", service_name); + 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_SINGLE_AUTHENTICATION); + 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); } @@ -2086,8 +2100,7 @@ gdm_greeter_login_window_key_press_event (GtkWidget *widget, login_window = GDM_GREETER_LOGIN_WINDOW (widget); if (event->keyval == GDK_Escape) { - if (login_window->priv->dialog_mode == MODE_SINGLE_AUTHENTICATION || - login_window->priv->dialog_mode == MODE_MULTIPLE_AUTHENTICATION) { + if (login_window->priv->dialog_mode == MODE_AUTHENTICATION) { do_cancel (GDM_GREETER_LOGIN_WINDOW (widget)); } } -- 1.6.2.2 From 996f22a0da8d207932f1efc1b30b337c485fa681 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 2 Mar 2009 17:09:16 -0500 Subject: [PATCH 30/33] Notify plugins if their user choose requests fail This allows the smart card plugin to cancel pending conversations when a card gets inserted. This isn't perfect. We really want to only cancel the conversations if they're for a user other than the user the smartcard is for. --- common/gdm-marshal.list | 1 + gui/simple-greeter/gdm-greeter-login-window.c | 12 ++++++++- gui/simple-greeter/libgdmsimplegreeter/Makefile.am | 2 + .../libgdmsimplegreeter/gdm-conversation.c | 19 +++++++++++----- .../libgdmsimplegreeter/gdm-conversation.h | 6 ++-- .../plugins/smartcard/gdm-smartcard-extension.c | 23 +++++++++++++++---- 6 files changed, 47 insertions(+), 16 deletions(-) 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/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c index ed009a4..a16948f 100644 --- a/gui/simple-greeter/gdm-greeter-login-window.c +++ b/gui/simple-greeter/gdm-greeter-login-window.c @@ -2389,7 +2389,7 @@ on_conversation_cancel (GdmGreeterLoginWindow *login_window, do_cancel (login_window); } -static void +static gboolean on_conversation_chose_user (GdmGreeterLoginWindow *login_window, const char *username, GdmConversation *conversation) @@ -2400,7 +2400,13 @@ on_conversation_chose_user (GdmGreeterLoginWindow *login_window, 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; + 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), @@ -2408,6 +2414,8 @@ on_conversation_chose_user (GdmGreeterLoginWindow *login_window, gdm_user_chooser_widget_set_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser), username); } + + return TRUE; } void diff --git a/gui/simple-greeter/libgdmsimplegreeter/Makefile.am b/gui/simple-greeter/libgdmsimplegreeter/Makefile.am index 1ef5725..0d7a0bd 100644 --- a/gui/simple-greeter/libgdmsimplegreeter/Makefile.am +++ b/gui/simple-greeter/libgdmsimplegreeter/Makefile.am @@ -3,6 +3,7 @@ NULL = AM_CPPFLAGS = \ -I. \ -I.. \ + -I$(top_srcdir)/common \ -DBINDIR=\"$(bindir)\" \ -DDATADIR=\"$(datadir)\" \ -DLIBDIR=\"$(libdir)\" \ @@ -28,6 +29,7 @@ libgdmsimplegreeter_la_SOURCES = \ libgdmsimplegreeter_la_LIBADD = \ $(GTK_LIBS) \ + $(top_builddir)/common/libgdmcommon.la \ $(NULL) libgdmsimplegreeter_la_LDFLAGS = \ diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c index cef435c..ee763ef 100644 --- a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c +++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c @@ -25,9 +25,9 @@ #include #include "gdm-conversation.h" +#include "gdm-marshal.h" #include "gdm-task.h" - enum { ANSWER, USER_CHOSEN, @@ -76,12 +76,12 @@ gdm_conversation_class_init (gpointer g_iface) signals [USER_CHOSEN] = g_signal_new ("user-chosen", iface_type, - G_SIGNAL_RUN_FIRST, + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GdmConversationIface, user_chosen), NULL, NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, + gdm_marshal_BOOLEAN__STRING, + G_TYPE_BOOLEAN, 1, G_TYPE_STRING); signals [CANCEL] = g_signal_new ("cancel", @@ -171,9 +171,16 @@ gdm_conversation_cancel (GdmConversation *conversation) { g_signal_emit (conversation, signals [CANCEL], 0); } -void + +gboolean gdm_conversation_choose_user (GdmConversation *conversation, const char *username) { - g_signal_emit (conversation, signals [USER_CHOSEN], 0, 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 index fb4bf49..b37b21e 100644 --- a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h +++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h @@ -61,7 +61,7 @@ struct _GdmConversationIface /* signals */ char * (* answer) (GdmConversation *conversation); void (* cancel) (GdmConversation *conversation); - void (* user_chosen) (GdmConversation *conversation); + gboolean (* user_chosen) (GdmConversation *conversation); }; GType gdm_conversation_get_type (void) G_GNUC_CONST; @@ -85,8 +85,8 @@ gboolean gdm_conversation_focus (GdmConversation *conversation); void gdm_conversation_answer (GdmConversation *conversation, const char *answer); void gdm_conversation_cancel (GdmConversation *conversation); -void gdm_conversation_choose_user (GdmConversation *conversation, - const char *username); +gboolean gdm_conversation_choose_user (GdmConversation *conversation, + const char *username); G_END_DECLS diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c index d3641ba..73e0f84 100644 --- a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c +++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c @@ -53,6 +53,7 @@ struct _GdmSmartcardExtensionPrivate int number_of_tokens; guint answer_pending : 1; + guint select_when_ready : 1; }; static void gdm_smartcard_extension_finalize (GObject *object); @@ -102,8 +103,14 @@ on_smartcard_event (GIOChannel *io_channel, } if (extension->priv->number_of_tokens == 1) { - gdm_conversation_choose_user (GDM_CONVERSATION (extension), - PAMSERVICENAME); + 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)); } @@ -210,10 +217,16 @@ 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) - { + 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 * -- 1.6.2.2 From c98a8ac6971b44071aef38a29b550378554a733b Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 13 Apr 2009 14:19:50 -0400 Subject: [PATCH 31/33] reset all conversations if password conversation fails This is a temporary hack until we store plugin policy in gconf. --- gui/simple-greeter/gdm-greeter-login-window.c | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c index a16948f..3daf89d 100644 --- a/gui/simple-greeter/gdm-greeter-login-window.c +++ b/gui/simple-greeter/gdm-greeter-login-window.c @@ -907,6 +907,16 @@ gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_wind 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) { -- 1.6.2.2 From 339ca93db8f4896eaf02667c1268ddc9d1830345 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Tue, 21 Apr 2009 10:25:18 -0400 Subject: [PATCH 32/33] When one PAM conversation wins, stop the others This doesn't work yet, it's still in progress code. --- daemon/gdm-session-direct.c | 64 ++++++++++++++++++++++++++++++------------- daemon/gdm-simple-slave.c | 2 +- 2 files changed, 46 insertions(+), 20 deletions(-) diff --git a/daemon/gdm-session-direct.c b/daemon/gdm-session-direct.c index 805adbf..cb84f01 100644 --- a/daemon/gdm-session-direct.c +++ b/daemon/gdm-session-direct.c @@ -2284,6 +2284,40 @@ 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) { + continue; + } + + stop_conversation (conversation); + } + + g_hash_table_remove_all (session->priv->conversations); +} + +static void gdm_session_direct_start_session (GdmSession *session, const char *service_name) { @@ -2295,12 +2329,20 @@ 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); program = g_strdup_printf (GDMCONFDIR "/Xsession \"%s\"", command); g_free (command); - conversation = find_conversation_by_name (impl, service_name); - setup_session_environment (impl); send_environment (impl, conversation); @@ -2311,23 +2353,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 09a7425..a70c9c9 100644 --- a/daemon/gdm-simple-slave.c +++ b/daemon/gdm-simple-slave.c @@ -569,7 +569,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.6.2.2 From 80107a061b3ac2300e9cec17f18d5dc02557a8d3 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Tue, 21 Apr 2009 15:30:28 -0400 Subject: [PATCH 33/33] When one PAM conv. wins, actually stop the others We weren't properly keeping the winning conversation around in the previous commit --- daemon/gdm-session-direct.c | 13 ++++++++++--- 1 files changed, 10 insertions(+), 3 deletions(-) diff --git a/daemon/gdm-session-direct.c b/daemon/gdm-session-direct.c index cb84f01..7173080 100644 --- a/daemon/gdm-session-direct.c +++ b/daemon/gdm-session-direct.c @@ -2308,13 +2308,20 @@ stop_all_other_conversations (GdmSessionDirect *session, conversation = (GdmSessionConversation *) value; if (conversation == conversation_to_keep) { - continue; + g_hash_table_iter_steal (&iter); + g_free (key); + } else { + stop_conversation (conversation); } - - 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 -- 1.6.2.2 diff --git a/daemon/gdm-session-worker-job.c b/daemon/gdm-session-worker-job.c index 0327d77..ad7cbac 100644 --- a/daemon/gdm-session-worker-job.c +++ b/daemon/gdm-session-worker-job.c @@ -325,6 +325,8 @@ gdm_session_worker_job_stop (GdmSessionWorkerJob *session_worker_job) if (res < 0) { g_warning ("Unable to kill session worker process"); } else { + g_usleep (G_USEC_PER_SEC / 2); + gdm_signal_pid (session_worker_job->priv->pid, SIGKILL); session_worker_job_died (session_worker_job); }