2
* Copyright (C) 2010-2011 Robert Ancell.
3
* Author: Robert Ancell <robert.ancell@canonical.com>
5
* This program is free software: you can redistribute it and/or modify it under
6
* the terms of the GNU General Public License as published by the Free Software
7
* Foundation, either version 3 of the License, or (at your option) any later
8
* version. See http://www.gnu.org/copyleft/gpl.html the full text of the
20
#include "ldm-marshal.h"
21
#include "configuration.h"
29
static guint signals[LAST_SIGNAL] = { 0 };
33
/* Session running on */
36
/* PAM service to authenticate with */
38
gchar *autologin_pam_service;
40
/* Buffer for data read from greeter */
44
/* Hints for the greeter */
47
/* Default session to use */
48
gchar *default_session;
50
/* Sequence number of current PAM session */
51
guint32 authentication_sequence_number;
53
/* Remote session name */
54
gchar *remote_session;
56
/* PAM session being constructed by the greeter */
57
Session *authentication_session;
59
/* TRUE if a user has been authenticated and the session requested to start */
60
gboolean start_session;
62
/* TRUE if can log into guest accounts */
65
/* TRUE if logging into guest session */
66
gboolean guest_account_authenticated;
68
/* Communication channels to communicate with */
69
GIOChannel *to_greeter_channel;
70
GIOChannel *from_greeter_channel;
71
guint from_greeter_watch;
74
G_DEFINE_TYPE (Greeter, greeter, G_TYPE_OBJECT);
76
/* Messages from the greeter to the server */
79
GREETER_MESSAGE_CONNECT = 0,
80
GREETER_MESSAGE_AUTHENTICATE,
81
GREETER_MESSAGE_AUTHENTICATE_AS_GUEST,
82
GREETER_MESSAGE_CONTINUE_AUTHENTICATION,
83
GREETER_MESSAGE_START_SESSION,
84
GREETER_MESSAGE_CANCEL_AUTHENTICATION,
85
GREETER_MESSAGE_SET_LANGUAGE,
86
GREETER_MESSAGE_AUTHENTICATE_REMOTE
89
/* Messages from the server to the greeter */
92
SERVER_MESSAGE_CONNECTED = 0,
93
SERVER_MESSAGE_PROMPT_AUTHENTICATION,
94
SERVER_MESSAGE_END_AUTHENTICATION,
95
SERVER_MESSAGE_SESSION_RESULT
98
static gboolean read_cb (GIOChannel *source, GIOCondition condition, gpointer data);
101
greeter_new (Session *session, const gchar *pam_service, const gchar *autologin_pam_service)
105
greeter = g_object_new (GREETER_TYPE, NULL);
106
greeter->priv->session = g_object_ref (session);
107
greeter->priv->pam_service = g_strdup (pam_service);
108
greeter->priv->autologin_pam_service = g_strdup (autologin_pam_service);
114
greeter_set_allow_guest (Greeter *greeter, gboolean allow_guest)
116
greeter->priv->allow_guest = allow_guest;
120
greeter_set_hint (Greeter *greeter, const gchar *name, const gchar *value)
122
g_hash_table_insert (greeter->priv->hints, g_strdup (name), g_strdup (value));
131
#define HEADER_SIZE (sizeof (guint32) * 2)
132
#define MAX_MESSAGE_LENGTH 1024
135
write_message (Greeter *greeter, guint8 *message, gsize message_length)
137
GError *error = NULL;
139
g_io_channel_write_chars (greeter->priv->to_greeter_channel, (gchar *) message, message_length, NULL, &error);
141
g_warning ("Error writing to greeter: %s", error->message);
142
g_clear_error (&error);
143
g_io_channel_flush (greeter->priv->to_greeter_channel, NULL);
147
write_int (guint8 *buffer, gint buffer_length, guint32 value, gsize *offset)
149
if (*offset + 4 >= buffer_length)
151
buffer[*offset] = value >> 24;
152
buffer[*offset+1] = (value >> 16) & 0xFF;
153
buffer[*offset+2] = (value >> 8) & 0xFF;
154
buffer[*offset+3] = value & 0xFF;
159
write_string (guint8 *buffer, gint buffer_length, const gchar *value, gsize *offset)
164
length = strlen (value);
167
write_int (buffer, buffer_length, length, offset);
168
if (*offset + length >= buffer_length)
172
memcpy (buffer + *offset, value, length);
178
write_header (guint8 *buffer, gint buffer_length, guint32 id, guint32 length, gsize *offset)
180
write_int (buffer, buffer_length, id, offset);
181
write_int (buffer, buffer_length, length, offset);
185
string_length (const gchar *value)
188
return int_length ();
190
return int_length () + strlen (value);
194
handle_connect (Greeter *greeter, const gchar *version)
196
guint8 message[MAX_MESSAGE_LENGTH];
202
g_debug ("Greeter connected version=%s", version);
204
length = string_length (VERSION);
205
g_hash_table_iter_init (&iter, greeter->priv->hints);
206
while (g_hash_table_iter_next (&iter, &key, &value))
207
length += string_length (key) + string_length (value);
209
write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_CONNECTED, length, &offset);
210
write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset);
211
g_hash_table_iter_init (&iter, greeter->priv->hints);
212
while (g_hash_table_iter_next (&iter, &key, &value))
214
write_string (message, MAX_MESSAGE_LENGTH, key, &offset);
215
write_string (message, MAX_MESSAGE_LENGTH, value, &offset);
217
write_message (greeter, message, offset);
219
g_signal_emit (greeter, signals[CONNECTED], 0);
223
pam_messages_cb (Session *session, Greeter *greeter)
227
guint8 message[MAX_MESSAGE_LENGTH];
228
const struct pam_message *messages;
233
messages = session_get_messages (session);
234
messages_length = session_get_messages_length (session);
236
/* Respond to d-bus query with messages */
237
g_debug ("Prompt greeter with %d message(s)", messages_length);
238
size = int_length () + string_length (session_get_username (session)) + int_length ();
239
for (i = 0; i < messages_length; i++)
240
size += int_length () + string_length (messages[i].msg);
242
write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_PROMPT_AUTHENTICATION, size, &offset);
243
write_int (message, MAX_MESSAGE_LENGTH, greeter->priv->authentication_sequence_number, &offset);
244
write_string (message, MAX_MESSAGE_LENGTH, session_get_username (session), &offset);
245
write_int (message, MAX_MESSAGE_LENGTH, messages_length, &offset);
246
for (i = 0; i < messages_length; i++)
248
write_int (message, MAX_MESSAGE_LENGTH, messages[i].msg_style, &offset);
249
write_string (message, MAX_MESSAGE_LENGTH, messages[i].msg, &offset);
251
if (messages[i].msg_style == PAM_PROMPT_ECHO_OFF || messages[i].msg_style == PAM_PROMPT_ECHO_ON)
254
write_message (greeter, message, offset);
256
/* Continue immediately if nothing to respond with */
257
// FIXME: Should probably give the greeter a chance to ack the message
260
struct pam_response *response;
261
response = calloc (messages_length, sizeof (struct pam_response));
262
session_respond (greeter->priv->authentication_session, response);
267
send_end_authentication (Greeter *greeter, guint32 sequence_number, const gchar *username, int result)
269
guint8 message[MAX_MESSAGE_LENGTH];
272
write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_END_AUTHENTICATION, int_length () + string_length (username) + int_length (), &offset);
273
write_int (message, MAX_MESSAGE_LENGTH, sequence_number, &offset);
274
write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
275
write_int (message, MAX_MESSAGE_LENGTH, result, &offset);
276
write_message (greeter, message, offset);
280
authentication_complete_cb (Session *session, Greeter *greeter)
284
g_debug ("Authenticate result for user %s: %s", session_get_username (session), session_get_authentication_result_string (session));
286
result = session_get_authentication_result (session);
287
if (session_get_is_authenticated (session))
289
if (session_get_user (session))
290
g_debug ("User %s authorized", session_get_username (session));
293
g_debug ("User %s authorized, but no account of that name exists", session_get_username (session));
294
result = PAM_USER_UNKNOWN;
298
send_end_authentication (greeter, greeter->priv->authentication_sequence_number, session_get_username (session), result);
302
reset_session (Greeter *greeter)
304
g_free (greeter->priv->remote_session);
305
greeter->priv->remote_session = NULL;
306
if (greeter->priv->authentication_session)
308
g_signal_handlers_disconnect_matched (greeter->priv->authentication_session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, greeter);
309
session_stop (greeter->priv->authentication_session);
310
g_object_unref (greeter->priv->authentication_session);
311
greeter->priv->authentication_session = NULL;
314
greeter->priv->guest_account_authenticated = FALSE;
318
handle_login (Greeter *greeter, guint32 sequence_number, const gchar *username)
320
const gchar *autologin_username, *service;
321
gboolean is_interactive;
323
if (username[0] == '\0')
325
g_debug ("Greeter start authentication");
329
g_debug ("Greeter start authentication for %s", username);
331
reset_session (greeter);
333
greeter->priv->authentication_sequence_number = sequence_number;
334
g_signal_emit (greeter, signals[START_AUTHENTICATION], 0, username, &greeter->priv->authentication_session);
335
if (!greeter->priv->authentication_session)
337
send_end_authentication (greeter, sequence_number, "", PAM_USER_UNKNOWN);
341
g_signal_connect (G_OBJECT (greeter->priv->authentication_session), "got-messages", G_CALLBACK (pam_messages_cb), greeter);
342
g_signal_connect (G_OBJECT (greeter->priv->authentication_session), "authentication-complete", G_CALLBACK (authentication_complete_cb), greeter);
344
/* Use non-interactive service for autologin user */
345
autologin_username = g_hash_table_lookup (greeter->priv->hints, "autologin-user");
346
if (autologin_username != NULL && g_strcmp0 (username, autologin_username) == 0)
348
service = greeter->priv->autologin_pam_service;
349
is_interactive = FALSE;
353
service = greeter->priv->pam_service;
354
is_interactive = TRUE;
357
/* Run the session process */
358
session_start (greeter->priv->authentication_session, service, username, TRUE, is_interactive, FALSE);
362
handle_login_as_guest (Greeter *greeter, guint32 sequence_number)
364
g_debug ("Greeter start authentication for guest account");
366
reset_session (greeter);
368
if (!greeter->priv->allow_guest)
370
g_debug ("Guest account is disabled");
371
send_end_authentication (greeter, sequence_number, "", PAM_USER_UNKNOWN);
375
greeter->priv->guest_account_authenticated = TRUE;
376
send_end_authentication (greeter, sequence_number, "", PAM_SUCCESS);
380
get_remote_session_service (const gchar *session_name)
382
GKeyFile *session_desktop_file;
385
gchar *remote_sessions_dir, *filename, *path, *service = NULL;
386
GError *error = NULL;
388
/* Validate session name doesn't contain directory separators */
389
for (c = session_name; *c; c++)
395
/* Load the session file */
396
session_desktop_file = g_key_file_new ();
397
filename = g_strdup_printf ("%s.desktop", session_name);
398
remote_sessions_dir = config_get_string (config_get_instance (), "LightDM", "remote-sessions-directory");
399
path = g_build_filename (remote_sessions_dir, filename, NULL);
400
g_free (remote_sessions_dir);
402
result = g_key_file_load_from_file (session_desktop_file, path, G_KEY_FILE_NONE, &error);
404
g_debug ("Failed to load session file %s: %s", path, error->message);
406
g_clear_error (&error);
408
service = g_key_file_get_string (session_desktop_file, G_KEY_FILE_DESKTOP_GROUP, "X-LightDM-PAM-Service", NULL);
409
g_key_file_free (session_desktop_file);
415
handle_login_remote (Greeter *greeter, const gchar *session_name, const gchar *username, guint32 sequence_number)
419
if (username[0] == '\0')
421
g_debug ("Greeter start authentication for remote session %s", session_name);
425
g_debug ("Greeter start authentication for remote session %s as user %s", session_name, username);
427
reset_session (greeter);
429
service = get_remote_session_service (session_name);
432
send_end_authentication (greeter, sequence_number, "", PAM_SYSTEM_ERR);
436
greeter->priv->authentication_sequence_number = sequence_number;
437
greeter->priv->remote_session = g_strdup (session_name);
438
g_signal_emit (greeter, signals[START_AUTHENTICATION], 0, username, &greeter->priv->authentication_session);
439
if (greeter->priv->authentication_session)
441
g_signal_connect (G_OBJECT (greeter->priv->authentication_session), "got-messages", G_CALLBACK (pam_messages_cb), greeter);
442
g_signal_connect (G_OBJECT (greeter->priv->authentication_session), "authentication-complete", G_CALLBACK (authentication_complete_cb), greeter);
444
/* Run the session process */
445
session_start (greeter->priv->authentication_session, service, username, TRUE, TRUE, TRUE);
450
if (!greeter->priv->authentication_session)
452
send_end_authentication (greeter, sequence_number, "", PAM_USER_UNKNOWN);
458
handle_continue_authentication (Greeter *greeter, gchar **secrets)
461
const struct pam_message *messages;
462
struct pam_response *response;
463
int i, j, n_prompts = 0;
465
/* Not in authentication */
466
if (greeter->priv->authentication_session == NULL)
469
messages_length = session_get_messages_length (greeter->priv->authentication_session);
470
messages = session_get_messages (greeter->priv->authentication_session);
472
/* Check correct number of responses */
473
for (i = 0; i < messages_length; i++)
475
int msg_style = messages[i].msg_style;
476
if (msg_style == PAM_PROMPT_ECHO_OFF || msg_style == PAM_PROMPT_ECHO_ON)
479
if (g_strv_length (secrets) != n_prompts)
481
session_respond_error (greeter->priv->authentication_session, PAM_CONV_ERR);
485
g_debug ("Continue authentication");
488
response = calloc (messages_length, sizeof (struct pam_response));
489
for (i = 0, j = 0; i < messages_length; i++)
491
int msg_style = messages[i].msg_style;
492
if (msg_style == PAM_PROMPT_ECHO_OFF || msg_style == PAM_PROMPT_ECHO_ON)
494
response[i].resp = strdup (secrets[j]); // FIXME: Need to convert from UTF-8
499
session_respond (greeter->priv->authentication_session, response);
503
handle_cancel_authentication (Greeter *greeter)
505
/* Not in authentication */
506
if (greeter->priv->authentication_session == NULL)
509
g_debug ("Cancel authentication");
510
reset_session (greeter);
514
handle_start_session (Greeter *greeter, const gchar *session)
517
guint8 message[MAX_MESSAGE_LENGTH];
519
SessionType session_type = SESSION_TYPE_LOCAL;
521
if (strcmp (session, "") == 0)
524
/* Use session type chosen in remote session */
525
if (greeter->priv->remote_session)
527
session_type = SESSION_TYPE_REMOTE;
528
session = greeter->priv->remote_session;
531
if (greeter->priv->guest_account_authenticated || session_get_is_authenticated (greeter->priv->authentication_session))
534
g_debug ("Greeter requests session %s", session);
536
g_debug ("Greeter requests default session");
537
greeter->priv->start_session = TRUE;
538
g_signal_emit (greeter, signals[START_SESSION], 0, session_type, session, &result);
542
g_debug ("Ignoring start session request, user is not authorized");
546
write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_SESSION_RESULT, int_length (), &offset);
547
write_int (message, MAX_MESSAGE_LENGTH, result ? 0 : 1, &offset);
548
write_message (greeter, message, offset);
552
handle_set_language (Greeter *greeter, const gchar *language)
556
if (!greeter->priv->guest_account_authenticated && !session_get_is_authenticated (greeter->priv->authentication_session))
558
g_debug ("Ignoring set language request, user is not authorized");
562
// FIXME: Could use this
563
if (greeter->priv->guest_account_authenticated)
565
g_debug ("Ignoring set language request for guest user");
569
g_debug ("Greeter sets language %s", language);
570
user = session_get_user (greeter->priv->authentication_session);
571
user_set_language (user, language);
575
read_int (Greeter *greeter, gsize *offset)
579
if (greeter->priv->n_read - *offset < sizeof (guint32))
581
g_warning ("Not enough space for int, need %zu, got %zu", sizeof (guint32), greeter->priv->n_read - *offset);
584
buffer = greeter->priv->read_buffer + *offset;
585
value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
586
*offset += int_length ();
591
read_string (Greeter *greeter, gsize *offset)
596
length = read_int (greeter, offset);
597
if (greeter->priv->n_read - *offset < length)
599
g_warning ("Not enough space for string, need %u, got %zu", length, greeter->priv->n_read - *offset);
600
return g_strdup ("");
603
value = g_malloc (sizeof (gchar) * (length + 1));
604
memcpy (value, greeter->priv->read_buffer + *offset, length);
605
value[length] = '\0';
612
read_cb (GIOChannel *source, GIOCondition condition, gpointer data)
614
Greeter *greeter = data;
615
gsize n_to_read, n_read, offset;
617
int id, n_secrets, i;
618
guint32 sequence_number;
619
gchar *version, *username, *session_name, *language;
621
GError *error = NULL;
623
if (condition == G_IO_HUP)
625
g_debug ("Greeter closed communication channel");
626
greeter->priv->from_greeter_watch = 0;
630
n_to_read = HEADER_SIZE;
631
if (greeter->priv->n_read >= HEADER_SIZE)
633
offset = int_length ();
634
n_to_read += read_int (greeter, &offset);
637
status = g_io_channel_read_chars (greeter->priv->from_greeter_channel,
638
(gchar *) greeter->priv->read_buffer + greeter->priv->n_read,
639
n_to_read - greeter->priv->n_read,
643
g_warning ("Error reading from greeter: %s", error->message);
644
g_clear_error (&error);
645
if (status != G_IO_STATUS_NORMAL)
648
greeter->priv->n_read += n_read;
649
if (greeter->priv->n_read != n_to_read)
652
/* If have header, rerun for content */
653
if (greeter->priv->n_read == HEADER_SIZE)
655
gsize offset = int_length ();
656
n_to_read = read_int (greeter, &offset);
659
greeter->priv->read_buffer = g_realloc (greeter->priv->read_buffer, HEADER_SIZE + n_to_read);
660
read_cb (source, condition, greeter);
666
id = read_int (greeter, &offset);
667
read_int (greeter, &offset);
670
case GREETER_MESSAGE_CONNECT:
671
version = read_string (greeter, &offset);
672
handle_connect (greeter, version);
675
case GREETER_MESSAGE_AUTHENTICATE:
676
sequence_number = read_int (greeter, &offset);
677
username = read_string (greeter, &offset);
678
handle_login (greeter, sequence_number, username);
681
case GREETER_MESSAGE_AUTHENTICATE_AS_GUEST:
682
sequence_number = read_int (greeter, &offset);
683
handle_login_as_guest (greeter, sequence_number);
685
case GREETER_MESSAGE_AUTHENTICATE_REMOTE:
686
sequence_number = read_int (greeter, &offset);
687
session_name = read_string (greeter, &offset);
688
username = read_string (greeter, &offset);
689
handle_login_remote (greeter, session_name, username, sequence_number);
691
case GREETER_MESSAGE_CONTINUE_AUTHENTICATION:
692
n_secrets = read_int (greeter, &offset);
693
secrets = g_malloc (sizeof (gchar *) * (n_secrets + 1));
694
for (i = 0; i < n_secrets; i++)
695
secrets[i] = read_string (greeter, &offset);
697
handle_continue_authentication (greeter, secrets);
698
g_strfreev (secrets);
700
case GREETER_MESSAGE_CANCEL_AUTHENTICATION:
701
handle_cancel_authentication (greeter);
703
case GREETER_MESSAGE_START_SESSION:
704
session_name = read_string (greeter, &offset);
705
handle_start_session (greeter, session_name);
706
g_free (session_name);
708
case GREETER_MESSAGE_SET_LANGUAGE:
709
language = read_string (greeter, &offset);
710
handle_set_language (greeter, language);
714
g_warning ("Unknown message from greeter: %d", id);
718
greeter->priv->n_read = 0;
724
greeter_get_guest_authenticated (Greeter *greeter)
726
g_return_val_if_fail (greeter != NULL, FALSE);
727
return greeter->priv->guest_account_authenticated;
731
greeter_get_authentication_session (Greeter *greeter)
733
g_return_val_if_fail (greeter != NULL, NULL);
734
return greeter->priv->authentication_session;
738
greeter_get_start_session (Greeter *greeter)
740
g_return_val_if_fail (greeter != NULL, FALSE);
741
return greeter->priv->start_session;
745
greeter_start (Greeter *greeter, const gchar *service, const gchar *username)
747
int to_greeter_pipe[2], from_greeter_pipe[2];
748
gboolean result = FALSE;
751
/* Create a pipe to talk with the greeter */
752
if (pipe (to_greeter_pipe) != 0 || pipe (from_greeter_pipe) != 0)
754
g_warning ("Failed to create pipes: %s", strerror (errno));
757
greeter->priv->to_greeter_channel = g_io_channel_unix_new (to_greeter_pipe[1]);
758
g_io_channel_set_encoding (greeter->priv->to_greeter_channel, NULL, NULL);
759
greeter->priv->from_greeter_channel = g_io_channel_unix_new (from_greeter_pipe[0]);
760
g_io_channel_set_encoding (greeter->priv->from_greeter_channel, NULL, NULL);
761
g_io_channel_set_buffered (greeter->priv->from_greeter_channel, FALSE);
762
greeter->priv->from_greeter_watch = g_io_add_watch (greeter->priv->from_greeter_channel, G_IO_IN | G_IO_HUP, read_cb, greeter);
764
/* Let the greeter session know how to communicate with the daemon */
765
value = g_strdup_printf ("%d", from_greeter_pipe[1]);
766
session_set_env (greeter->priv->session, "LIGHTDM_TO_SERVER_FD", value);
768
value = g_strdup_printf ("%d", to_greeter_pipe[0]);
769
session_set_env (greeter->priv->session, "LIGHTDM_FROM_SERVER_FD", value);
772
/* Don't allow the daemon end of the pipes to be accessed in child processes */
773
fcntl (to_greeter_pipe[1], F_SETFD, FD_CLOEXEC);
774
fcntl (from_greeter_pipe[0], F_SETFD, FD_CLOEXEC);
776
result = session_start (greeter->priv->session, service, username, FALSE, FALSE, FALSE);
778
/* Close the session ends of the pipe */
779
close (to_greeter_pipe[0]);
780
close (from_greeter_pipe[1]);
786
greeter_real_start_authentication (Greeter *greeter, const gchar *username)
792
greeter_real_start_session (Greeter *greeter, SessionType type, const gchar *session)
798
greeter_init (Greeter *greeter)
800
greeter->priv = G_TYPE_INSTANCE_GET_PRIVATE (greeter, GREETER_TYPE, GreeterPrivate);
801
greeter->priv->read_buffer = g_malloc (HEADER_SIZE);
802
greeter->priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
806
greeter_finalize (GObject *object)
810
self = GREETER (object);
812
g_signal_handlers_disconnect_matched (self->priv->session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
813
g_object_unref (self->priv->session);
814
g_free (self->priv->pam_service);
815
g_free (self->priv->autologin_pam_service);
816
g_free (self->priv->read_buffer);
817
g_hash_table_unref (self->priv->hints);
818
g_free (self->priv->remote_session);
819
if (self->priv->authentication_session)
821
g_signal_handlers_disconnect_matched (self->priv->authentication_session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
822
g_object_unref (self->priv->authentication_session);
824
if (self->priv->to_greeter_channel)
825
g_io_channel_unref (self->priv->to_greeter_channel);
826
if (self->priv->from_greeter_channel)
827
g_io_channel_unref (self->priv->from_greeter_channel);
828
if (self->priv->from_greeter_watch)
829
g_source_remove (self->priv->from_greeter_watch);
831
G_OBJECT_CLASS (greeter_parent_class)->finalize (object);
835
greeter_class_init (GreeterClass *klass)
837
GObjectClass *object_class = G_OBJECT_CLASS (klass);
839
klass->start_authentication = greeter_real_start_authentication;
840
klass->start_session = greeter_real_start_session;
841
object_class->finalize = greeter_finalize;
844
g_signal_new ("connected",
845
G_TYPE_FROM_CLASS (klass),
847
G_STRUCT_OFFSET (GreeterClass, connected),
849
g_cclosure_marshal_VOID__VOID,
852
signals[START_AUTHENTICATION] =
853
g_signal_new ("start-authentication",
854
G_TYPE_FROM_CLASS (klass),
856
G_STRUCT_OFFSET (GreeterClass, start_authentication),
857
g_signal_accumulator_first_wins,
859
ldm_marshal_OBJECT__STRING,
860
SESSION_TYPE, 1, G_TYPE_STRING);
862
signals[START_SESSION] =
863
g_signal_new ("start-session",
864
G_TYPE_FROM_CLASS (klass),
866
G_STRUCT_OFFSET (GreeterClass, start_session),
867
g_signal_accumulator_true_handled,
869
ldm_marshal_BOOLEAN__INT_STRING,
870
G_TYPE_BOOLEAN, 2, G_TYPE_INT, G_TYPE_STRING);
872
g_type_class_add_private (klass, sizeof (GreeterPrivate));