]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - src/greeter.c
0fb18ab8eeb435f40052d9ed014fc4749d48274d
[sojka/lightdm.git] / src / greeter.c
1 /*
2  * Copyright (C) 2010-2011 Robert Ancell.
3  * Author: Robert Ancell <robert.ancell@canonical.com>
4  * 
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
9  * license.
10  */
11
12 #include <config.h>
13
14 #include <stdlib.h>
15 #include <string.h>
16 #include <errno.h>
17
18 #include "greeter.h"
19 #include "ldm-marshal.h"
20
21 enum {
22     CONNECTED,
23     START_AUTHENTICATION,
24     START_SESSION,
25     LAST_SIGNAL
26 };
27 static guint signals[LAST_SIGNAL] = { 0 };
28
29 struct GreeterPrivate
30 {
31     /* Session running on */
32     Session *session;
33
34     /* Buffer for data read from greeter */
35     guint8 *read_buffer;
36     gsize n_read;
37   
38     /* Hints for the greeter */
39     GHashTable *hints;
40
41     /* Default session to use */   
42     gchar *default_session;
43
44     /* Sequence number of current PAM session */
45     guint32 authentication_sequence_number;
46
47     /* PAM session being constructed by the greeter */
48     PAMSession *authentication;
49
50     /* TRUE if can log into guest accounts */
51     gboolean allow_guest;
52
53     /* TRUE if logging into guest session */
54     gboolean guest_account_authenticated;
55
56     /* Communication channels to communicate with */
57     GIOChannel *to_greeter_channel;
58     GIOChannel *from_greeter_channel;
59 };
60
61 G_DEFINE_TYPE (Greeter, greeter, G_TYPE_OBJECT);
62
63 /* Messages from the greeter to the server */
64 typedef enum
65 {
66     GREETER_MESSAGE_CONNECT = 0,
67     GREETER_MESSAGE_AUTHENTICATE,
68     GREETER_MESSAGE_AUTHENTICATE_AS_GUEST,
69     GREETER_MESSAGE_CONTINUE_AUTHENTICATION,
70     GREETER_MESSAGE_START_SESSION,
71     GREETER_MESSAGE_CANCEL_AUTHENTICATION,
72     GREETER_MESSAGE_SET_LANGUAGE
73 } GreeterMessage;
74
75 /* Messages from the server to the greeter */
76 typedef enum
77 {
78     SERVER_MESSAGE_CONNECTED = 0,
79     SERVER_MESSAGE_PROMPT_AUTHENTICATION,
80     SERVER_MESSAGE_END_AUTHENTICATION,
81     SERVER_MESSAGE_SESSION_RESULT
82 } ServerMessage;
83
84 Greeter *
85 greeter_new (Session *session)
86 {
87     Greeter *greeter = g_object_new (GREETER_TYPE, NULL);
88
89     greeter->priv->session = g_object_ref (session);
90
91     return greeter;
92 }
93
94 void
95 greeter_set_allow_guest (Greeter *greeter, gboolean allow_guest)
96 {
97     greeter->priv->allow_guest = allow_guest;
98 }
99
100 void
101 greeter_set_hint (Greeter *greeter, const gchar *name, const gchar *value)
102 {
103     g_hash_table_insert (greeter->priv->hints, g_strdup (name), g_strdup (value));
104 }
105
106 static guint32
107 int_length ()
108 {
109     return 4;
110 }
111
112 #define HEADER_SIZE (sizeof (guint32) * 2)
113 #define MAX_MESSAGE_LENGTH 1024
114
115 static void
116 write_message (Greeter *greeter, guint8 *message, gsize message_length)
117 {
118     GIOStatus status;
119     GError *error = NULL;
120
121     status = g_io_channel_write_chars (greeter->priv->to_greeter_channel, (gchar *) message, message_length, NULL, &error);
122     if (error)
123         g_warning ("Error writing to greeter: %s", error->message);
124     g_clear_error (&error);
125     if (status == G_IO_STATUS_NORMAL)
126         g_debug ("Wrote %zi bytes to greeter", message_length);
127     g_io_channel_flush (greeter->priv->to_greeter_channel, NULL);
128 }
129
130 static void
131 write_int (guint8 *buffer, gint buffer_length, guint32 value, gsize *offset)
132 {
133     if (*offset + 4 >= buffer_length)
134         return;
135     buffer[*offset] = value >> 24;
136     buffer[*offset+1] = (value >> 16) & 0xFF;
137     buffer[*offset+2] = (value >> 8) & 0xFF;
138     buffer[*offset+3] = value & 0xFF;
139     *offset += 4;
140 }
141
142 static void
143 write_string (guint8 *buffer, gint buffer_length, const gchar *value, gsize *offset)
144 {
145     gint length;
146   
147     if (value)
148         length = strlen (value);
149     else
150         length = 0;
151     write_int (buffer, buffer_length, length, offset);
152     if (*offset + length >= buffer_length)
153         return;
154     if (length > 0)
155     {
156         memcpy (buffer + *offset, value, length);
157         *offset += length;
158     }
159 }
160
161 static void
162 write_header (guint8 *buffer, gint buffer_length, guint32 id, guint32 length, gsize *offset)
163 {
164     write_int (buffer, buffer_length, id, offset);
165     write_int (buffer, buffer_length, length, offset);
166 }
167
168 static guint32
169 string_length (const gchar *value)
170 {
171     if (value == NULL)
172         return int_length ();
173     else
174         return int_length () + strlen (value);
175 }
176
177 static void
178 handle_connect (Greeter *greeter, const gchar *version)
179 {
180     guint8 message[MAX_MESSAGE_LENGTH];
181     gsize offset = 0;
182     guint32 length;
183     GHashTableIter iter;
184     gpointer key, value;
185
186     g_debug ("Greeter connected version=%s", version);
187
188     length = string_length (VERSION);
189     g_hash_table_iter_init (&iter, greeter->priv->hints);
190     while (g_hash_table_iter_next (&iter, &key, &value))
191         length += string_length (key) + string_length (value);
192
193     write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_CONNECTED, length, &offset);
194     write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset);
195     g_hash_table_iter_init (&iter, greeter->priv->hints);
196     while (g_hash_table_iter_next (&iter, &key, &value))
197     {
198         write_string (message, MAX_MESSAGE_LENGTH, key, &offset);
199         write_string (message, MAX_MESSAGE_LENGTH, value, &offset);
200     }
201     write_message (greeter, message, offset);
202
203     g_signal_emit (greeter, signals[CONNECTED], 0);
204 }
205
206 static void
207 pam_messages_cb (PAMSession *authentication, int num_msg, const struct pam_message **msg, Greeter *greeter)
208 {
209     int i;
210     guint32 size;
211     guint8 message[MAX_MESSAGE_LENGTH];
212     gsize offset = 0;
213     int n_prompts = 0;
214
215     /* Respond to d-bus query with messages */
216     g_debug ("Prompt greeter with %d message(s)", num_msg);
217     size = int_length () + string_length (pam_session_get_username (authentication)) + int_length ();
218     for (i = 0; i < num_msg; i++)
219         size += int_length () + string_length (msg[i]->msg);
220   
221     write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_PROMPT_AUTHENTICATION, size, &offset);
222     write_int (message, MAX_MESSAGE_LENGTH, greeter->priv->authentication_sequence_number, &offset);
223     write_string (message, MAX_MESSAGE_LENGTH, pam_session_get_username (authentication), &offset);
224     write_int (message, MAX_MESSAGE_LENGTH, num_msg, &offset);
225     for (i = 0; i < num_msg; i++)
226     {
227         write_int (message, MAX_MESSAGE_LENGTH, msg[i]->msg_style, &offset);
228         write_string (message, MAX_MESSAGE_LENGTH, msg[i]->msg, &offset);
229
230         if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF || msg[i]->msg_style == PAM_PROMPT_ECHO_ON)
231             n_prompts++;
232     }
233     write_message (greeter, message, offset);
234
235     /* Continue immediately if nothing to respond with */
236     // FIXME: Should probably give the greeter a chance to ack the message
237     if (n_prompts == 0)
238     {
239         struct pam_response *response;
240         response = calloc (num_msg, sizeof (struct pam_response));
241         pam_session_respond (greeter->priv->authentication, response);
242     }
243 }
244
245 static void
246 send_end_authentication (Greeter *greeter, guint32 sequence_number, const gchar *username, int result)
247 {
248     guint8 message[MAX_MESSAGE_LENGTH];
249     gsize offset = 0;
250
251     write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_END_AUTHENTICATION, int_length () + string_length (username) + int_length (), &offset);
252     write_int (message, MAX_MESSAGE_LENGTH, sequence_number, &offset);
253     write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
254     write_int (message, MAX_MESSAGE_LENGTH, result, &offset);
255     write_message (greeter, message, offset); 
256 }
257
258 static void
259 authentication_result_cb (PAMSession *authentication, int result, Greeter *greeter)
260 {
261     g_debug ("Authenticate result for user %s: %s", pam_session_get_username (authentication), pam_session_strerror (authentication, result));
262
263     if (result == PAM_SUCCESS)
264         g_debug ("User %s authorized", pam_session_get_username (authentication));
265
266     send_end_authentication (greeter, greeter->priv->authentication_sequence_number, pam_session_get_username (authentication), result);
267 }
268
269 static void
270 reset_session (Greeter *greeter)
271 {
272     if (greeter->priv->authentication)
273     {
274         g_signal_handlers_disconnect_matched (greeter->priv->authentication, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, greeter);
275         pam_session_cancel (greeter->priv->authentication);
276         g_object_unref (greeter->priv->authentication);
277         greeter->priv->authentication = NULL;
278     }
279
280     greeter->priv->guest_account_authenticated = FALSE;
281 }
282
283 static void
284 handle_login (Greeter *greeter, guint32 sequence_number, const gchar *username)
285 {
286     gboolean result;
287     GError *error = NULL;
288
289     if (username[0] == '\0')
290     {
291         g_debug ("Greeter start authentication");
292         username = NULL;
293     }
294     else
295         g_debug ("Greeter start authentication for %s", username);
296
297     reset_session (greeter);
298
299     greeter->priv->authentication_sequence_number = sequence_number;
300     g_signal_emit (greeter, signals[START_AUTHENTICATION], 0, username, &greeter->priv->authentication);
301     if (!greeter->priv->authentication)
302     {
303         send_end_authentication (greeter, sequence_number, "", PAM_USER_UNKNOWN);
304         return;
305     }
306
307     g_signal_connect (G_OBJECT (greeter->priv->authentication), "got-messages", G_CALLBACK (pam_messages_cb), greeter);
308     g_signal_connect (G_OBJECT (greeter->priv->authentication), "authentication-result", G_CALLBACK (authentication_result_cb), greeter);
309     result = pam_session_authenticate (greeter->priv->authentication, &error);
310     if (error)
311         g_debug ("Failed to start authentication: %s", error->message);
312     if (!result)
313         send_end_authentication (greeter, sequence_number, "", PAM_SYSTEM_ERR);
314     g_clear_error (&error);
315 }
316
317 static void
318 handle_login_as_guest (Greeter *greeter, guint32 sequence_number)
319 {
320     g_debug ("Greeter start authentication for guest account");
321
322     reset_session (greeter);
323
324     if (!greeter->priv->allow_guest)
325     {
326         g_debug ("Guest account is disabled");
327         send_end_authentication (greeter, sequence_number, "", PAM_USER_UNKNOWN);
328         return;
329     }
330
331     greeter->priv->guest_account_authenticated = TRUE;  
332     send_end_authentication (greeter, sequence_number, "", PAM_SUCCESS);
333 }
334
335 static void
336 handle_continue_authentication (Greeter *greeter, gchar **secrets)
337 {
338     int num_messages;
339     const struct pam_message **messages;
340     struct pam_response *response;
341     int i, j, n_prompts = 0;
342
343     /* Not in authentication */
344     if (greeter->priv->authentication == NULL)
345         return;
346
347     num_messages = pam_session_get_num_messages (greeter->priv->authentication);
348     messages = pam_session_get_messages (greeter->priv->authentication);
349
350     /* Check correct number of responses */
351     for (i = 0; i < num_messages; i++)
352     {
353         int msg_style = messages[i]->msg_style;
354         if (msg_style == PAM_PROMPT_ECHO_OFF || msg_style == PAM_PROMPT_ECHO_ON)
355             n_prompts++;
356     }
357     if (g_strv_length (secrets) != n_prompts)
358     {
359         pam_session_cancel (greeter->priv->authentication);
360         return;
361     }
362
363     g_debug ("Continue authentication");
364
365     /* Build response */
366     response = calloc (num_messages, sizeof (struct pam_response));
367     for (i = 0, j = 0; i < num_messages; i++)
368     {
369         int msg_style = messages[i]->msg_style;
370         if (msg_style == PAM_PROMPT_ECHO_OFF || msg_style == PAM_PROMPT_ECHO_ON)
371         {
372             response[i].resp = strdup (secrets[j]); // FIXME: Need to convert from UTF-8
373             j++;
374         }
375     }
376
377     pam_session_respond (greeter->priv->authentication, response);
378 }
379
380 static void
381 handle_cancel_authentication (Greeter *greeter)
382 {
383     /* Not in authentication */
384     if (greeter->priv->authentication == NULL)
385         return;
386
387     g_debug ("Cancel authentication");
388
389     pam_session_cancel (greeter->priv->authentication);
390 }
391
392 static void
393 handle_start_session (Greeter *greeter, const gchar *session)
394 {
395     gboolean result;
396
397     if (strcmp (session, "") == 0)
398         session = NULL;
399
400     if (greeter->priv->guest_account_authenticated || pam_session_get_is_authenticated (greeter->priv->authentication))
401     {
402         if (session)
403             g_debug ("Greeter requests session %s", session);
404         else
405             g_debug ("Greeter requests default session");     
406         g_signal_emit (greeter, signals[START_SESSION], 0, session, &result);
407     }
408     else
409     {
410         g_debug ("Ignoring start session request, user is not authorized");
411         result = FALSE;
412     }
413
414     if (!result)
415     {
416         guint8 message[MAX_MESSAGE_LENGTH];
417         gsize offset = 0;
418
419         write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_SESSION_RESULT, int_length (), &offset);
420         write_int (message, MAX_MESSAGE_LENGTH, 1, &offset);
421         write_message (greeter, message, offset);
422     }
423 }
424
425 static void
426 handle_set_language (Greeter *greeter, const gchar *language)
427 {
428     User *user;
429
430     if (!greeter->priv->guest_account_authenticated && !pam_session_get_is_authenticated (greeter->priv->authentication))
431     {
432         g_debug ("Ignoring set language request, user is not authorized");
433         return;
434     }
435
436     // FIXME: Could use this
437     if (greeter->priv->guest_account_authenticated)
438     {
439         g_debug ("Ignoring set language request for guest user");
440         return;
441     }
442
443     g_debug ("Greeter sets language %s", language);
444     user = pam_session_get_user (greeter->priv->authentication);
445     user_set_locale (user, language);
446 }
447
448 static guint32
449 read_int (Greeter *greeter, gsize *offset)
450 {
451     guint32 value;
452     guint8 *buffer;
453     if (greeter->priv->n_read - *offset < sizeof (guint32))
454     {
455         g_warning ("Not enough space for int, need %zu, got %zu", sizeof (guint32), greeter->priv->n_read - *offset);
456         return 0;
457     }
458     buffer = greeter->priv->read_buffer + *offset;
459     value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
460     *offset += int_length ();
461     return value;
462 }
463
464 static gchar *
465 read_string (Greeter *greeter, gsize *offset)
466 {
467     guint32 length;
468     gchar *value;
469
470     length = read_int (greeter, offset);
471     if (greeter->priv->n_read - *offset < length)
472     {
473         g_warning ("Not enough space for string, need %u, got %zu", length, greeter->priv->n_read - *offset);
474         return g_strdup ("");
475     }
476
477     value = g_malloc (sizeof (gchar *) * (length + 1));
478     memcpy (value, greeter->priv->read_buffer + *offset, length);
479     value[length] = '\0';
480     *offset += length;
481
482     return value;
483 }
484
485 static gboolean
486 read_cb (GIOChannel *source, GIOCondition condition, gpointer data)
487 {
488     Greeter *greeter = data;
489     gsize n_to_read, n_read, offset;
490     GIOStatus status;
491     int id, n_secrets, i;
492     guint32 sequence_number;
493     gchar *version, *username, *session_name, *language;
494     gchar **secrets;
495     GError *error = NULL;
496
497     if (condition == G_IO_HUP)
498     {
499         g_debug ("Greeter closed communication channel");
500         return FALSE;
501     }
502   
503     n_to_read = HEADER_SIZE;
504     if (greeter->priv->n_read >= HEADER_SIZE)
505     {
506         offset = int_length ();
507         n_to_read += read_int (greeter, &offset);
508     }
509
510     status = g_io_channel_read_chars (greeter->priv->from_greeter_channel,
511                                       (gchar *) greeter->priv->read_buffer + greeter->priv->n_read,
512                                       n_to_read - greeter->priv->n_read,
513                                       &n_read,
514                                       &error);
515     if (error)
516         g_warning ("Error reading from greeter: %s", error->message);
517     g_clear_error (&error);
518     if (status != G_IO_STATUS_NORMAL)
519         return TRUE;
520
521     g_debug ("Read %zi bytes from greeter", n_read);
522     /*for (i = 0; i < n_read; i++)
523        g_print ("%02X ", greeter->priv->read_buffer[greeter->priv->n_read+i]);
524     g_print ("\n");*/
525
526     greeter->priv->n_read += n_read;
527     if (greeter->priv->n_read != n_to_read)
528         return TRUE;
529
530     /* If have header, rerun for content */
531     if (greeter->priv->n_read == HEADER_SIZE)
532     {
533         gsize offset = int_length ();
534         n_to_read = read_int (greeter, &offset);
535         if (n_to_read > 0)
536         {
537             greeter->priv->read_buffer = g_realloc (greeter->priv->read_buffer, HEADER_SIZE + n_to_read);
538             read_cb (source, condition, greeter);
539             return TRUE;
540         }
541     }
542   
543     offset = 0;
544     id = read_int (greeter, &offset);
545     read_int (greeter, &offset);
546     switch (id)
547     {
548     case GREETER_MESSAGE_CONNECT:
549         version = read_string (greeter, &offset);
550         handle_connect (greeter, version);
551         g_free (version);
552         break;
553     case GREETER_MESSAGE_AUTHENTICATE:
554         sequence_number = read_int (greeter, &offset);
555         username = read_string (greeter, &offset);
556         handle_login (greeter, sequence_number, username);
557         g_free (username);
558         break;
559     case GREETER_MESSAGE_AUTHENTICATE_AS_GUEST:
560         sequence_number = read_int (greeter, &offset);
561         handle_login_as_guest (greeter, sequence_number);
562         break;
563     case GREETER_MESSAGE_CONTINUE_AUTHENTICATION:
564         n_secrets = read_int (greeter, &offset);
565         secrets = g_malloc (sizeof (gchar *) * (n_secrets + 1));
566         for (i = 0; i < n_secrets; i++)
567             secrets[i] = read_string (greeter, &offset);
568         secrets[i] = NULL;
569         handle_continue_authentication (greeter, secrets);
570         g_strfreev (secrets);
571         break;
572     case GREETER_MESSAGE_CANCEL_AUTHENTICATION:
573         handle_cancel_authentication (greeter);
574         break;
575     case GREETER_MESSAGE_START_SESSION:
576         session_name = read_string (greeter, &offset);
577         handle_start_session (greeter, session_name);
578         g_free (session_name);
579         break;
580     case GREETER_MESSAGE_SET_LANGUAGE:
581         language = read_string (greeter, &offset);
582         handle_set_language (greeter, language);
583         g_free (language);
584         break;
585     default:
586         g_warning ("Unknown message from greeter: %d", id);
587         break;
588     }
589
590     greeter->priv->n_read = 0;
591
592     return TRUE;
593 }
594
595 gboolean
596 greeter_start (Greeter *greeter)
597 {
598     int to_greeter_pipe[2], from_greeter_pipe[2];
599     gint fd;
600     gchar *value;
601
602     if (pipe (to_greeter_pipe) != 0 || 
603         pipe (from_greeter_pipe) != 0)
604     {
605         g_warning ("Failed to create pipes: %s", strerror (errno));            
606         return FALSE;
607     }
608
609     greeter->priv->to_greeter_channel = g_io_channel_unix_new (to_greeter_pipe[1]);
610     g_io_channel_set_encoding (greeter->priv->to_greeter_channel, NULL, NULL);
611     greeter->priv->from_greeter_channel = g_io_channel_unix_new (from_greeter_pipe[0]);
612     g_io_channel_set_encoding (greeter->priv->from_greeter_channel, NULL, NULL);
613     g_io_channel_set_buffered (greeter->priv->from_greeter_channel, FALSE);
614     g_io_add_watch (greeter->priv->from_greeter_channel, G_IO_IN | G_IO_HUP, read_cb, greeter);
615
616     fd = from_greeter_pipe[1];
617     value = g_strdup_printf ("%d", fd);
618     session_set_env (greeter->priv->session, "LIGHTDM_TO_SERVER_FD", value);
619     g_free (value);
620
621     fd = to_greeter_pipe[0];
622     value = g_strdup_printf ("%d", fd);
623     session_set_env (greeter->priv->session, "LIGHTDM_FROM_SERVER_FD", value);
624     g_free (value);
625
626     return TRUE;
627 }
628
629 gboolean
630 greeter_get_guest_authenticated (Greeter *greeter)
631 {
632     g_return_val_if_fail (greeter != NULL, FALSE);
633     return greeter->priv->guest_account_authenticated;
634 }
635
636 PAMSession *
637 greeter_get_authentication (Greeter *greeter)
638 {
639     g_return_val_if_fail (greeter != NULL, NULL);
640     return greeter->priv->authentication;
641 }
642
643 void
644 greeter_quit (Greeter *greeter)
645 {
646     guint8 message[MAX_MESSAGE_LENGTH];
647     gsize offset = 0;
648
649     g_return_if_fail (greeter != NULL);
650
651     write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_SESSION_RESULT, int_length (), &offset);
652     write_int (message, MAX_MESSAGE_LENGTH, 0, &offset);
653     write_message (greeter, message, offset);
654 }
655
656 static PAMSession *
657 greeter_real_start_authentication (Greeter *greeter, const gchar *username)
658 {
659     return NULL;
660 }
661
662 static gboolean
663 greeter_real_start_session (Greeter *greeter, const gchar *session, gboolean is_guest)
664 {
665     return FALSE;
666 }
667
668 static void
669 greeter_init (Greeter *greeter)
670 {
671     greeter->priv = G_TYPE_INSTANCE_GET_PRIVATE (greeter, GREETER_TYPE, GreeterPrivate);
672     greeter->priv->read_buffer = g_malloc (HEADER_SIZE);
673     greeter->priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
674 }
675
676 static void
677 greeter_finalize (GObject *object)
678 {
679     Greeter *self;
680
681     self = GREETER (object);
682
683     g_object_unref (self->priv->session);
684     g_free (self->priv->read_buffer);
685     g_hash_table_unref (self->priv->hints);
686     if (self->priv->authentication)
687     {
688         g_signal_handlers_disconnect_matched (self->priv->authentication, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
689         pam_session_cancel (self->priv->authentication);
690         g_object_unref (self->priv->authentication);
691     }
692     if (self->priv->to_greeter_channel)
693         g_io_channel_unref (self->priv->to_greeter_channel);
694     if (self->priv->from_greeter_channel)
695         g_io_channel_unref (self->priv->from_greeter_channel);
696
697     G_OBJECT_CLASS (greeter_parent_class)->finalize (object);
698 }
699
700 static void
701 greeter_class_init (GreeterClass *klass)
702 {
703     GObjectClass *object_class = G_OBJECT_CLASS (klass);
704
705     klass->start_authentication = greeter_real_start_authentication;
706     klass->start_session = greeter_real_start_session;
707     object_class->finalize = greeter_finalize;
708
709     signals[CONNECTED] =
710         g_signal_new ("connected",
711                       G_TYPE_FROM_CLASS (klass),
712                       G_SIGNAL_RUN_LAST,
713                       G_STRUCT_OFFSET (GreeterClass, connected),
714                       NULL, NULL,
715                       g_cclosure_marshal_VOID__VOID,
716                       G_TYPE_NONE, 0);
717
718     signals[START_AUTHENTICATION] =
719         g_signal_new ("start-authentication",
720                       G_TYPE_FROM_CLASS (klass),
721                       G_SIGNAL_RUN_LAST,
722                       G_STRUCT_OFFSET (GreeterClass, start_authentication),
723                       g_signal_accumulator_first_wins,
724                       NULL,
725                       ldm_marshal_OBJECT__STRING,
726                       PAM_SESSION_TYPE, 1, G_TYPE_STRING);
727
728     signals[START_SESSION] =
729         g_signal_new ("start-session",
730                       G_TYPE_FROM_CLASS (klass),
731                       G_SIGNAL_RUN_LAST,
732                       G_STRUCT_OFFSET (GreeterClass, start_session),
733                       g_signal_accumulator_true_handled,
734                       NULL,
735                       ldm_marshal_BOOLEAN__STRING,
736                       G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
737
738     g_type_class_add_private (klass, sizeof (GreeterPrivate));
739 }