X-Git-Url: http://rtime.felk.cvut.cz/gitweb/sojka/lightdm.git/blobdiff_plain/ba8a3c9642a8cb84d556713cfa6861a40a8fddfe..f22dda3f1c7c3abf299b8dba7891d5b1a905779d:/src/greeter.c diff --git a/src/greeter.c b/src/greeter.c index 52bf5987..e2ae19f9 100644 --- a/src/greeter.c +++ b/src/greeter.c @@ -1,7 +1,6 @@ /* - * Copyright (C) 2010-2011 Robert Ancell. - * Author: Robert Ancell - * + * Copyright (C) 2010-2016 Canonical Ltd. + * * 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 3 of the License, or (at your option) any later @@ -13,15 +12,20 @@ #include #include -#include -#include #include #include "greeter.h" #include "configuration.h" +#include "shared-data-manager.h" + +enum { + PROP_0, + PROP_ACTIVE_USERNAME, +}; enum { CONNECTED, + DISCONNECTED, CREATE_SESSION, START_SESSION, LAST_SIGNAL @@ -38,11 +42,11 @@ struct GreeterPrivate guint8 *read_buffer; gsize n_read; gboolean use_secure_memory; - + /* Hints for the greeter */ GHashTable *hints; - /* Default session to use */ + /* Default session to use */ gchar *default_session; /* Sequence number of current PAM session */ @@ -51,9 +55,15 @@ struct GreeterPrivate /* Remote session name */ gchar *remote_session; + /* Currently selected user */ + gchar *active_username; + /* PAM session being constructed by the greeter */ Session *authentication_session; + /* TRUE if a the greeter can handle a reset; else we will just kill it instead */ + gboolean resettable; + /* TRUE if a user has been authenticated and the session requested to start */ gboolean start_session; @@ -64,11 +74,14 @@ struct GreeterPrivate gboolean guest_account_authenticated; /* Communication channels to communicate with */ + int to_greeter_input; + int from_greeter_output; GIOChannel *to_greeter_channel; GIOChannel *from_greeter_channel; + guint from_greeter_watch; }; -G_DEFINE_TYPE (Greeter, greeter, SESSION_TYPE); +G_DEFINE_TYPE (Greeter, greeter, G_TYPE_OBJECT); /* Messages from the greeter to the server */ typedef enum @@ -80,7 +93,8 @@ typedef enum GREETER_MESSAGE_START_SESSION, GREETER_MESSAGE_CANCEL_AUTHENTICATION, GREETER_MESSAGE_SET_LANGUAGE, - GREETER_MESSAGE_AUTHENTICATE_REMOTE + GREETER_MESSAGE_AUTHENTICATE_REMOTE, + GREETER_MESSAGE_ENSURE_SHARED_DIR, } GreeterMessage; /* Messages from the server to the greeter */ @@ -89,7 +103,10 @@ typedef enum SERVER_MESSAGE_CONNECTED = 0, SERVER_MESSAGE_PROMPT_AUTHENTICATION, SERVER_MESSAGE_END_AUTHENTICATION, - SERVER_MESSAGE_SESSION_RESULT + SERVER_MESSAGE_SESSION_RESULT, + SERVER_MESSAGE_SHARED_DIR_RESULT, + SERVER_MESSAGE_IDLE, + SERVER_MESSAGE_RESET, } ServerMessage; static gboolean read_cb (GIOChannel *source, GIOCondition condition, gpointer data); @@ -100,9 +117,43 @@ greeter_new (void) return g_object_new (GREETER_TYPE, NULL); } +void +greeter_set_file_descriptors (Greeter *greeter, int to_greeter_fd, int from_greeter_fd) +{ + GError *error = NULL; + + g_return_if_fail (greeter != NULL); + g_return_if_fail (greeter->priv->to_greeter_input < 0); + g_return_if_fail (greeter->priv->from_greeter_output < 0); + + greeter->priv->to_greeter_input = to_greeter_fd; + greeter->priv->to_greeter_channel = g_io_channel_unix_new (greeter->priv->to_greeter_input); + g_io_channel_set_encoding (greeter->priv->to_greeter_channel, NULL, &error); + if (error) + g_warning ("Failed to set encoding on to greeter channel to binary: %s\n", error->message); + g_clear_error (&error); + greeter->priv->from_greeter_output = from_greeter_fd; + greeter->priv->from_greeter_channel = g_io_channel_unix_new (greeter->priv->from_greeter_output); + g_io_channel_set_encoding (greeter->priv->from_greeter_channel, NULL, &error); + if (error) + g_warning ("Failed to set encoding on from greeter channel to binary: %s\n", error->message); + g_clear_error (&error); + g_io_channel_set_buffered (greeter->priv->from_greeter_channel, FALSE); + greeter->priv->from_greeter_watch = g_io_add_watch (greeter->priv->from_greeter_channel, G_IO_IN | G_IO_HUP, read_cb, greeter); +} + +void +greeter_stop (Greeter *greeter) +{ + /* Stop any events occurring after we've stopped */ + if (greeter->priv->authentication_session) + g_signal_handlers_disconnect_matched (greeter->priv->authentication_session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, greeter); +} + void greeter_set_pam_services (Greeter *greeter, const gchar *pam_service, const gchar *autologin_pam_service) { + g_return_if_fail (greeter != NULL); g_free (greeter->priv->pam_service); greeter->priv->pam_service = g_strdup (pam_service); g_free (greeter->priv->autologin_pam_service); @@ -112,12 +163,21 @@ greeter_set_pam_services (Greeter *greeter, const gchar *pam_service, const gcha void greeter_set_allow_guest (Greeter *greeter, gboolean allow_guest) { + g_return_if_fail (greeter != NULL); greeter->priv->allow_guest = allow_guest; } +void +greeter_clear_hints (Greeter *greeter) +{ + g_return_if_fail (greeter != NULL); + g_hash_table_remove_all (greeter->priv->hints); +} + void greeter_set_hint (Greeter *greeter, const gchar *name, const gchar *value) { + g_return_if_fail (greeter != NULL); g_hash_table_insert (greeter->priv->hints, g_strdup (name), g_strdup (value)); } @@ -160,13 +220,31 @@ int_length (void) static void write_message (Greeter *greeter, guint8 *message, gsize message_length) { + gchar *data; + gsize data_length; GError *error = NULL; - g_io_channel_write_chars (greeter->priv->to_greeter_channel, (gchar *) message, message_length, NULL, &error); + data = (gchar *) message; + data_length = message_length; + while (data_length > 0) + { + GIOStatus status; + gsize n_written; + + status = g_io_channel_write_chars (greeter->priv->to_greeter_channel, data, data_length, &n_written, &error); + if (error) + g_warning ("Error writing to greeter: %s", error->message); + g_clear_error (&error); + if (status != G_IO_STATUS_NORMAL) + return; + data_length -= n_written; + data += n_written; + } + + g_io_channel_flush (greeter->priv->to_greeter_channel, &error); if (error) - g_warning ("Error writing to greeter: %s", error->message); + g_warning ("Failed to flush data to greeter: %s", error->message); g_clear_error (&error); - g_io_channel_flush (greeter->priv->to_greeter_channel, NULL); } static void @@ -185,7 +263,7 @@ static void write_string (guint8 *buffer, gint buffer_length, const gchar *value, gsize *offset) { gint length; - + if (value) length = strlen (value); else @@ -217,7 +295,7 @@ string_length (const gchar *value) } static void -handle_connect (Greeter *greeter, const gchar *version) +handle_connect (Greeter *greeter, const gchar *version, gboolean resettable) { guint8 message[MAX_MESSAGE_LENGTH]; gsize offset = 0; @@ -225,7 +303,9 @@ handle_connect (Greeter *greeter, const gchar *version) GHashTableIter iter; gpointer key, value; - g_debug ("Greeter connected version=%s", version); + g_debug ("Greeter connected version=%s resettable=%s", version, resettable ? "true" : "false"); + + greeter->priv->resettable = resettable; length = string_length (VERSION); g_hash_table_iter_init (&iter, greeter->priv->hints); @@ -264,7 +344,7 @@ pam_messages_cb (Session *session, Greeter *greeter) size = int_length () + string_length (session_get_username (session)) + int_length (); for (i = 0; i < messages_length; i++) size += int_length () + string_length (messages[i].msg); - + write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_PROMPT_AUTHENTICATION, size, &offset); write_int (message, MAX_MESSAGE_LENGTH, greeter->priv->authentication_sequence_number, &offset); write_string (message, MAX_MESSAGE_LENGTH, session_get_username (session), &offset); @@ -300,7 +380,42 @@ send_end_authentication (Greeter *greeter, guint32 sequence_number, const gchar write_int (message, MAX_MESSAGE_LENGTH, sequence_number, &offset); write_string (message, MAX_MESSAGE_LENGTH, username, &offset); write_int (message, MAX_MESSAGE_LENGTH, result, &offset); - write_message (greeter, message, offset); + write_message (greeter, message, offset); +} + +void +greeter_idle (Greeter *greeter) +{ + guint8 message[MAX_MESSAGE_LENGTH]; + gsize offset = 0; + + write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_IDLE, 0, &offset); + write_message (greeter, message, offset); +} + +void +greeter_reset (Greeter *greeter) +{ + guint8 message[MAX_MESSAGE_LENGTH]; + gsize offset = 0; + guint32 length = 0; + GHashTableIter iter; + gpointer key, value; + + g_return_if_fail (greeter != NULL); + + g_hash_table_iter_init (&iter, greeter->priv->hints); + while (g_hash_table_iter_next (&iter, &key, &value)) + length += string_length (key) + string_length (value); + + write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_RESET, length, &offset); + g_hash_table_iter_init (&iter, greeter->priv->hints); + while (g_hash_table_iter_next (&iter, &key, &value)) + { + write_string (message, MAX_MESSAGE_LENGTH, key, &offset); + write_string (message, MAX_MESSAGE_LENGTH, value, &offset); + } + write_message (greeter, message, offset); } static void @@ -317,7 +432,7 @@ authentication_complete_cb (Session *session, Greeter *greeter) g_debug ("User %s authorized", session_get_username (session)); else { - g_debug ("User %s authorized, but no account of that name exists", session_get_username (session)); + g_debug ("User %s authorized, but no account of that name exists", session_get_username (session)); result = PAM_USER_UNKNOWN; } } @@ -334,8 +449,7 @@ reset_session (Greeter *greeter) { g_signal_handlers_disconnect_matched (greeter->priv->authentication_session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, greeter); session_stop (greeter->priv->authentication_session); - g_object_unref (greeter->priv->authentication_session); - greeter->priv->authentication_session = NULL; + g_clear_object (&greeter->priv->authentication_session); } greeter->priv->guest_account_authenticated = FALSE; @@ -357,6 +471,11 @@ handle_login (Greeter *greeter, guint32 sequence_number, const gchar *username) reset_session (greeter); + if (greeter->priv->active_username) + g_free (greeter->priv->active_username); + greeter->priv->active_username = g_strdup (username); + g_object_notify (G_OBJECT (greeter), GREETER_PROPERTY_ACTIVE_USERNAME); + greeter->priv->authentication_sequence_number = sequence_number; g_signal_emit (greeter, signals[CREATE_SESSION], 0, &greeter->priv->authentication_session); if (!greeter->priv->authentication_session) @@ -365,8 +484,8 @@ handle_login (Greeter *greeter, guint32 sequence_number, const gchar *username) return; } - g_signal_connect (G_OBJECT (greeter->priv->authentication_session), "got-messages", G_CALLBACK (pam_messages_cb), greeter); - g_signal_connect (G_OBJECT (greeter->priv->authentication_session), "authentication-complete", G_CALLBACK (authentication_complete_cb), greeter); + g_signal_connect (G_OBJECT (greeter->priv->authentication_session), SESSION_SIGNAL_GOT_MESSAGES, G_CALLBACK (pam_messages_cb), greeter); + g_signal_connect (G_OBJECT (greeter->priv->authentication_session), SESSION_SIGNAL_AUTHENTICATION_COMPLETE, G_CALLBACK (authentication_complete_cb), greeter); /* Use non-interactive service for autologin user */ autologin_username = g_hash_table_lookup (greeter->priv->hints, "autologin-user"); @@ -403,7 +522,7 @@ handle_login_as_guest (Greeter *greeter, guint32 sequence_number) return; } - greeter->priv->guest_account_authenticated = TRUE; + greeter->priv->guest_account_authenticated = TRUE; send_end_authentication (greeter, sequence_number, "", PAM_SUCCESS); } @@ -469,8 +588,8 @@ handle_login_remote (Greeter *greeter, const gchar *session_name, const gchar *u g_signal_emit (greeter, signals[CREATE_SESSION], 0, &greeter->priv->authentication_session); if (greeter->priv->authentication_session) { - g_signal_connect (G_OBJECT (greeter->priv->authentication_session), "got-messages", G_CALLBACK (pam_messages_cb), greeter); - g_signal_connect (G_OBJECT (greeter->priv->authentication_session), "authentication-complete", G_CALLBACK (authentication_complete_cb), greeter); + g_signal_connect (G_OBJECT (greeter->priv->authentication_session), SESSION_SIGNAL_GOT_MESSAGES, G_CALLBACK (pam_messages_cb), greeter); + g_signal_connect (G_OBJECT (greeter->priv->authentication_session), SESSION_SIGNAL_AUTHENTICATION_COMPLETE, G_CALLBACK (authentication_complete_cb), greeter); /* Run the session process */ session_set_pam_service (greeter->priv->authentication_session, service); @@ -613,6 +732,24 @@ handle_set_language (Greeter *greeter, const gchar *language) user_set_language (user, language); } +static void +handle_ensure_shared_dir (Greeter *greeter, const gchar *username) +{ + gchar *dir; + guint8 message[MAX_MESSAGE_LENGTH]; + gsize offset = 0; + + g_debug ("Greeter requests data directory for user %s", username); + + dir = shared_data_manager_ensure_user_dir (shared_data_manager_get_instance (), username); + + write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_SHARED_DIR_RESULT, string_length (dir), &offset); + write_string (message, MAX_MESSAGE_LENGTH, dir, &offset); + write_message (greeter, message, offset); + + g_free (dir); +} + static guint32 read_int (Greeter *greeter, gsize *offset) { @@ -660,7 +797,7 @@ read_string_full (Greeter *greeter, gsize *offset, void* (*alloc_fn)(size_t n)) return g_strdup (""); } - value = (*alloc_fn) (sizeof (gchar *) * (length + 1)); + value = (*alloc_fn) (sizeof (gchar) * (length + 1)); memcpy (value, greeter->priv->read_buffer + *offset, length); value[length] = '\0'; *offset += length; @@ -689,24 +826,30 @@ read_cb (GIOChannel *source, GIOCondition condition, gpointer data) Greeter *greeter = data; gsize n_to_read, n_read, offset; GIOStatus status; - int id, i; + int id, length, i; guint32 sequence_number, n_secrets, max_secrets; gchar *version, *username, *session_name, *language; gchar **secrets; + gboolean resettable = FALSE; GError *error = NULL; if (condition == G_IO_HUP) { g_debug ("Greeter closed communication channel"); + greeter->priv->from_greeter_watch = 0; + g_signal_emit (greeter, signals[DISCONNECTED], 0); return FALSE; } - + n_to_read = HEADER_SIZE; if (greeter->priv->n_read >= HEADER_SIZE) { n_to_read = get_message_length (greeter); if (n_to_read <= HEADER_SIZE) + { + greeter->priv->from_greeter_watch = 0; return FALSE; + } } status = g_io_channel_read_chars (greeter->priv->from_greeter_channel, @@ -717,7 +860,14 @@ read_cb (GIOChannel *source, GIOCondition condition, gpointer data) if (error) g_warning ("Error reading from greeter: %s", error->message); g_clear_error (&error); - if (status != G_IO_STATUS_NORMAL) + if (status == G_IO_STATUS_EOF) + { + g_debug ("Greeter closed communication channel"); + greeter->priv->from_greeter_watch = 0; + g_signal_emit (greeter, signals[DISCONNECTED], 0); + return FALSE; + } + else if (status != G_IO_STATUS_NORMAL) return TRUE; greeter->priv->n_read += n_read; @@ -733,17 +883,19 @@ read_cb (GIOChannel *source, GIOCondition condition, gpointer data) greeter->priv->read_buffer = secure_realloc (greeter, greeter->priv->read_buffer, n_to_read); read_cb (source, condition, greeter); return TRUE; - } + } } - + offset = 0; id = read_int (greeter, &offset); - read_int (greeter, &offset); + length = HEADER_SIZE + read_int (greeter, &offset); switch (id) { case GREETER_MESSAGE_CONNECT: version = read_string (greeter, &offset); - handle_connect (greeter, version); + if (offset < length) + resettable = read_int (greeter, &offset) != 0; + handle_connect (greeter, version, resettable); g_free (version); break; case GREETER_MESSAGE_AUTHENTICATE: @@ -768,6 +920,7 @@ read_cb (GIOChannel *source, GIOCondition condition, gpointer data) if (n_secrets > max_secrets) { g_warning ("Array length of %u elements too long", n_secrets); + greeter->priv->from_greeter_watch = 0; return FALSE; } secrets = g_malloc (sizeof (gchar *) * (n_secrets + 1)); @@ -792,6 +945,11 @@ read_cb (GIOChannel *source, GIOCondition condition, gpointer data) handle_set_language (greeter, language); g_free (language); break; + case GREETER_MESSAGE_ENSURE_SHARED_DIR: + username = read_string (greeter, &offset); + handle_ensure_shared_dir (greeter, username); + g_free (username); + break; default: g_warning ("Unknown message from greeter: %d", id); break; @@ -816,6 +974,13 @@ greeter_get_authentication_session (Greeter *greeter) return greeter->priv->authentication_session; } +gboolean +greeter_get_resettable (Greeter *greeter) +{ + g_return_val_if_fail (greeter != NULL, FALSE); + return greeter->priv->resettable; +} + gboolean greeter_get_start_session (Greeter *greeter) { @@ -823,46 +988,11 @@ greeter_get_start_session (Greeter *greeter) return greeter->priv->start_session; } -static gboolean -greeter_start (Session *session) +const gchar * +greeter_get_active_username (Greeter *greeter) { - Greeter *greeter = GREETER (session); - int to_greeter_pipe[2], from_greeter_pipe[2]; - gboolean result = FALSE; - gchar *value; - - /* Create a pipe to talk with the greeter */ - if (pipe (to_greeter_pipe) != 0 || pipe (from_greeter_pipe) != 0) - { - g_warning ("Failed to create pipes: %s", strerror (errno)); - return FALSE; - } - greeter->priv->to_greeter_channel = g_io_channel_unix_new (to_greeter_pipe[1]); - g_io_channel_set_encoding (greeter->priv->to_greeter_channel, NULL, NULL); - greeter->priv->from_greeter_channel = g_io_channel_unix_new (from_greeter_pipe[0]); - g_io_channel_set_encoding (greeter->priv->from_greeter_channel, NULL, NULL); - g_io_channel_set_buffered (greeter->priv->from_greeter_channel, FALSE); - g_io_add_watch (greeter->priv->from_greeter_channel, G_IO_IN | G_IO_HUP, read_cb, greeter); - - /* Let the greeter session know how to communicate with the daemon */ - value = g_strdup_printf ("%d", from_greeter_pipe[1]); - session_set_env (SESSION (greeter), "LIGHTDM_TO_SERVER_FD", value); - g_free (value); - value = g_strdup_printf ("%d", to_greeter_pipe[0]); - session_set_env (SESSION (greeter), "LIGHTDM_FROM_SERVER_FD", value); - g_free (value); - - /* Don't allow the daemon end of the pipes to be accessed in child processes */ - fcntl (to_greeter_pipe[1], F_SETFD, FD_CLOEXEC); - fcntl (from_greeter_pipe[0], F_SETFD, FD_CLOEXEC); - - result = SESSION_CLASS (greeter_parent_class)->start (session); - - /* Close the session ends of the pipe */ - close (to_greeter_pipe[0]); - close (from_greeter_pipe[1]); - - return result; + g_return_val_if_fail (greeter != NULL, NULL); + return greeter->priv->active_username; } static Session * @@ -877,18 +1007,6 @@ greeter_real_start_session (Greeter *greeter, SessionType type, const gchar *ses return FALSE; } -static void -greeter_stop (Session *session) -{ - Greeter *greeter = GREETER (session); - - /* Stop any events occurring after we've stopped */ - if (greeter->priv->authentication_session) - g_signal_handlers_disconnect_matched (greeter->priv->authentication_session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, greeter); - - SESSION_CLASS (greeter_parent_class)->stop (session); -} - static void greeter_init (Greeter *greeter) { @@ -896,47 +1014,78 @@ greeter_init (Greeter *greeter) greeter->priv->read_buffer = secure_malloc (greeter, HEADER_SIZE); greeter->priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); greeter->priv->use_secure_memory = config_get_boolean (config_get_instance (), "LightDM", "lock-memory"); + greeter->priv->to_greeter_input = -1; + greeter->priv->from_greeter_output = -1; } static void greeter_finalize (GObject *object) { - Greeter *self; - - self = GREETER (object); + Greeter *self = GREETER (object); g_free (self->priv->pam_service); g_free (self->priv->autologin_pam_service); secure_free (self, self->priv->read_buffer); g_hash_table_unref (self->priv->hints); g_free (self->priv->remote_session); + g_free (self->priv->active_username); if (self->priv->authentication_session) { g_signal_handlers_disconnect_matched (self->priv->authentication_session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self); g_object_unref (self->priv->authentication_session); } + close (self->priv->to_greeter_input); + close (self->priv->from_greeter_output); if (self->priv->to_greeter_channel) g_io_channel_unref (self->priv->to_greeter_channel); if (self->priv->from_greeter_channel) g_io_channel_unref (self->priv->from_greeter_channel); + if (self->priv->from_greeter_watch) + g_source_remove (self->priv->from_greeter_watch); G_OBJECT_CLASS (greeter_parent_class)->finalize (object); } +static void +greeter_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); +} + +static void +greeter_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + Greeter *greeter = GREETER (object); + + switch (prop_id) { + case PROP_ACTIVE_USERNAME: + g_value_set_string (value, greeter_get_active_username (greeter)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + static void greeter_class_init (GreeterClass *klass) { - SessionClass *session_class = SESSION_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); klass->create_session = greeter_real_create_session; klass->start_session = greeter_real_start_session; - session_class->start = greeter_start; - session_class->stop = greeter_stop; object_class->finalize = greeter_finalize; + object_class->get_property = greeter_get_property; + object_class->set_property = greeter_set_property; signals[CONNECTED] = - g_signal_new ("connected", + g_signal_new (GREETER_SIGNAL_CONNECTED, G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GreeterClass, connected), @@ -944,8 +1093,17 @@ greeter_class_init (GreeterClass *klass) NULL, G_TYPE_NONE, 0); + signals[DISCONNECTED] = + g_signal_new (GREETER_SIGNAL_DISCONNECTED, + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GreeterClass, disconnected), + NULL, NULL, + NULL, + G_TYPE_NONE, 0); + signals[CREATE_SESSION] = - g_signal_new ("create-session", + g_signal_new (GREETER_SIGNAL_CREATE_SESSION, G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GreeterClass, create_session), @@ -955,7 +1113,7 @@ greeter_class_init (GreeterClass *klass) SESSION_TYPE, 0); signals[START_SESSION] = - g_signal_new ("start-session", + g_signal_new (GREETER_SIGNAL_START_SESSION, G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GreeterClass, start_session), @@ -964,5 +1122,13 @@ greeter_class_init (GreeterClass *klass) NULL, G_TYPE_BOOLEAN, 2, G_TYPE_INT, G_TYPE_STRING); + g_object_class_install_property (object_class, + PROP_ACTIVE_USERNAME, + g_param_spec_string (GREETER_PROPERTY_ACTIVE_USERNAME, + GREETER_PROPERTY_ACTIVE_USERNAME, + "Active username", + NULL, + G_PARAM_READABLE)); + g_type_class_add_private (klass, sizeof (GreeterPrivate)); }