]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - src/session.c
Greeter can start session
[sojka/lightdm.git] / src / session.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 #include <unistd.h>
18 #include <sys/wait.h>
19 #include <fcntl.h>
20 #include <glib/gstdio.h>
21 #include <grp.h>
22 #include <pwd.h>
23
24 #include "session.h"
25 #include "configuration.h"
26 #include "console-kit.h"
27 #include "login1.h"
28 #include "guest-account.h"
29
30 enum {
31     GOT_MESSAGES,
32     AUTHENTICATION_COMPLETE,
33     STOPPED,
34     LAST_SIGNAL
35 };
36 static guint signals[LAST_SIGNAL] = { 0 };
37
38 struct SessionPrivate
39 {
40     /* Display server running on */
41     DisplayServer *display_server;
42
43     /* PID of child process */
44     GPid pid;
45
46     /* Pipes to talk to child */
47     int to_child_input;
48     int from_child_output;
49     GIOChannel *from_child_channel;
50     guint from_child_watch;
51     guint child_watch;
52
53     /* User to authenticate as */
54     gchar *username;
55
56     /* TRUE if is a guest account */
57     gboolean is_guest;
58
59     /* User object that matches the current username */
60     User *user;
61
62     /* PAM service to use */
63     gchar *pam_service;
64
65     /* TRUE if should run PAM authentication phase */
66     gboolean do_authenticate;
67
68     /* TRUE if can handle PAM prompts */
69     gboolean is_interactive;
70
71     /* Messages being requested by PAM */
72     int messages_length;
73     struct pam_message *messages;
74
75     /* Authentication result from PAM */
76     gboolean authentication_started;
77     gboolean authentication_complete;
78     int authentication_result;
79     gchar *authentication_result_string;
80
81     /* File to log to */
82     gchar *log_filename;
83
84     /* Seat class */
85     gchar *class;
86
87     /* tty this session is running on */
88     gchar *tty;
89
90     /* X display connected to */
91     gchar *xdisplay;
92     XAuthority *xauthority;
93     gboolean xauth_use_system_location;
94
95     /* Remote host this session is being controlled from */
96     gchar *remote_host_name;
97
98     /* Console kit cookie */
99     gchar *console_kit_cookie;
100
101     /* login1 session */
102     gchar *login1_session;
103
104     /* Environment to set in child */
105     GList *env;
106
107     /* Command to run in child */
108     gchar **argv;
109 };
110
111 /* Maximum length of a string to pass between daemon and session */
112 #define MAX_STRING_LENGTH 65535
113
114 G_DEFINE_TYPE (Session, session, G_TYPE_OBJECT);
115
116 void
117 session_set_pam_service (Session *session, const gchar *pam_service)
118 {
119     g_return_if_fail (session != NULL);
120     g_free (session->priv->pam_service);
121     session->priv->pam_service = g_strdup (pam_service);
122 }
123
124 void
125 session_set_username (Session *session, const gchar *username)
126 {
127     g_return_if_fail (session != NULL);
128     g_free (session->priv->username);
129     session->priv->username = g_strdup (username);
130 }
131
132 void
133 session_set_do_authenticate (Session *session, gboolean do_authenticate)
134 {
135     g_return_if_fail (session != NULL);
136     session->priv->do_authenticate = do_authenticate;
137 }
138
139 void
140 session_set_is_interactive (Session *session, gboolean is_interactive)
141 {
142     g_return_if_fail (session != NULL);
143     session->priv->is_interactive = is_interactive;
144 }
145
146 void
147 session_set_is_guest (Session *session, gboolean is_guest)
148 {
149     g_return_if_fail (session != NULL);
150     session->priv->is_guest = is_guest;
151 }
152
153 void
154 session_set_log_file (Session *session, const gchar *filename)
155 {
156     g_return_if_fail (session != NULL);
157     g_free (session->priv->log_filename);
158     session->priv->log_filename = g_strdup (filename);
159 }
160
161 void
162 session_set_class (Session *session, const gchar *class)
163 {
164     g_return_if_fail (session != NULL);
165     g_free (session->priv->class);
166     session->priv->class = g_strdup (class);
167 }
168
169 static void
170 session_real_set_display_server (Session *session, DisplayServer *display_server)
171 {
172     if (session->priv->display_server)
173         g_object_unref (session->priv->display_server);
174     session->priv->display_server = g_object_ref (display_server);
175 }
176
177 void
178 session_set_display_server (Session *session, DisplayServer *display_server)
179 {
180     g_return_if_fail (session != NULL);
181     g_return_if_fail (display_server != NULL);
182     SESSION_GET_CLASS (session)->set_display_server (session, display_server);
183 }
184
185 DisplayServer *
186 session_get_display_server (Session *session)
187 {
188     g_return_val_if_fail (session != NULL, NULL);
189     return session->priv->display_server;
190 }
191
192 void
193 session_set_tty (Session *session, const gchar *tty)
194 {
195     g_return_if_fail (session != NULL);
196     g_free (session->priv->tty);
197     session->priv->tty = g_strdup (tty);
198 }
199
200 void
201 session_set_xdisplay (Session *session, const gchar *xdisplay)
202 {
203     g_return_if_fail (session != NULL);
204     g_free (session->priv->xdisplay);
205     session->priv->xdisplay = g_strdup (xdisplay);
206 }
207
208 void
209 session_set_xauthority (Session *session, XAuthority *authority, gboolean use_system_location)
210 {
211     g_return_if_fail (session != NULL);
212     if (session->priv->xauthority)
213         g_object_unref (session->priv->xauthority);
214     session->priv->xauthority = g_object_ref (authority);
215     session->priv->xauth_use_system_location = use_system_location;
216 }
217
218 void
219 session_set_remote_host_name (Session *session, const gchar *remote_host_name)
220 {
221     g_return_if_fail (session != NULL);
222     g_free (session->priv->remote_host_name);
223     session->priv->remote_host_name = g_strdup (remote_host_name);
224 }
225
226 void
227 session_set_env (Session *session, const gchar *name, const gchar *value)
228 {
229     g_return_if_fail (session != NULL);
230     session->priv->env = g_list_append (session->priv->env, g_strdup_printf ("%s=%s", name, value));
231 }
232
233 void
234 session_set_argv (Session *session, gchar **argv)
235 {
236     g_return_if_fail (session != NULL);
237     session->priv->argv = g_strdupv (argv);
238 }
239
240 User *
241 session_get_user (Session *session)
242 {
243     g_return_val_if_fail (session != NULL, NULL);
244
245     if (session->priv->username == NULL)
246         return NULL;
247
248     if (!session->priv->user)
249         session->priv->user = accounts_get_user_by_name (session->priv->username);
250
251     return session->priv->user;
252 }
253
254 static void
255 write_data (Session *session, const void *buf, size_t count)
256 {
257     if (write (session->priv->to_child_input, buf, count) != count)
258         g_warning ("Error writing to session: %s", strerror (errno));
259 }
260
261 static void
262 write_string (Session *session, const char *value)
263 {
264     int length;
265
266     length = value ? strlen (value) : -1;
267     write_data (session, &length, sizeof (length));
268     if (value)
269         write_data (session, value, sizeof (char) * length);
270 }
271
272 static void
273 write_xauth (Session *session, XAuthority *xauthority)
274 {
275     guint16 family;
276     gsize length;
277
278     if (!xauthority)
279     {
280         write_string (session, NULL);
281         return;
282     }
283
284     write_string (session, xauth_get_authorization_name (session->priv->xauthority));
285     family = xauth_get_family (session->priv->xauthority);
286     write_data (session, &family, sizeof (family));
287     length = xauth_get_address_length (session->priv->xauthority);
288     write_data (session, &length, sizeof (length));
289     write_data (session, xauth_get_address (session->priv->xauthority), length);
290     write_string (session, xauth_get_number (session->priv->xauthority));
291     length = xauth_get_authorization_data_length (session->priv->xauthority);
292     write_data (session, &length, sizeof (length));
293     write_data (session, xauth_get_authorization_data (session->priv->xauthority), length);
294 }
295
296 static ssize_t
297 read_from_child (Session *session, void *buf, size_t count)
298 {
299     ssize_t n_read;
300     n_read = read (session->priv->from_child_output, buf, count);
301     if (n_read < 0)
302         g_warning ("Error reading from session: %s", strerror (errno));
303     return n_read;
304 }
305
306 static gchar *
307 read_string_from_child (Session *session)
308 {
309     int length;
310     char *value;
311
312     if (read_from_child (session, &length, sizeof (length)) <= 0)
313         return NULL;
314     if (length < 0)
315         return NULL;
316     if (length > MAX_STRING_LENGTH)
317     {
318         g_warning ("Invalid string length %d from child", length);
319         return NULL;
320     }
321
322     value = g_malloc (sizeof (char) * (length + 1));
323     read_from_child (session, value, length);
324     value[length] = '\0';
325
326     return value;
327 }
328
329 static void
330 session_watch_cb (GPid pid, gint status, gpointer data)
331 {
332     Session *session = data;
333
334     session->priv->pid = 0;
335
336     if (WIFEXITED (status))
337         g_debug ("Session %d exited with return value %d", pid, WEXITSTATUS (status));
338     else if (WIFSIGNALED (status))
339         g_debug ("Session %d terminated with signal %d", pid, WTERMSIG (status));
340
341     /* If failed during authentication then report this as an authentication failure */
342     if (session->priv->authentication_started && !session->priv->authentication_complete)
343     {
344         g_debug ("Session %d failed during authentication", pid);
345         session->priv->authentication_complete = TRUE;
346         session->priv->authentication_result = PAM_CONV_ERR;
347         g_free (session->priv->authentication_result_string);
348         session->priv->authentication_result_string = g_strdup ("Authentication stopped before completion");
349         g_signal_emit (G_OBJECT (session), signals[AUTHENTICATION_COMPLETE], 0);
350     }
351
352     g_signal_emit (G_OBJECT (session), signals[STOPPED], 0);
353
354     /* Delete account if it is a guest one */
355     if (session->priv->is_guest)
356         guest_account_cleanup (session->priv->username);
357
358     /* Drop our reference on the child process, it has terminated */
359     g_object_unref (session);
360 }
361
362 static gboolean
363 from_child_cb (GIOChannel *source, GIOCondition condition, gpointer data)
364 {
365     Session *session = data;
366     gchar *username;
367     ssize_t n_read;
368     gboolean auth_complete;
369
370     /* Remote end gone */
371     if (condition == G_IO_HUP)
372     {
373         session->priv->from_child_watch = 0;
374         return FALSE;
375     }
376
377     /* Get the username currently being authenticated (may change during authentication) */
378     username = read_string_from_child (session);
379     if (g_strcmp0 (username, session->priv->username) != 0)
380     {
381         g_free (session->priv->username);
382         session->priv->username = username;
383         if (session->priv->user)
384             g_object_unref (session->priv->user);
385         session->priv->user = NULL;
386     }
387     else
388         g_free (username);
389
390     /* Check if authentication completed */
391     n_read = read_from_child (session, &auth_complete, sizeof (auth_complete));
392     if (n_read < 0)
393         g_debug ("Error reading from child: %s", strerror (errno));
394     if (n_read <= 0)
395     {
396         session->priv->from_child_watch = 0;
397         return FALSE;
398     }
399
400     if (auth_complete)
401     {
402         session->priv->authentication_complete = TRUE;
403         read_from_child (session, &session->priv->authentication_result, sizeof (session->priv->authentication_result));
404         g_free (session->priv->authentication_result_string);
405         session->priv->authentication_result_string = read_string_from_child (session);
406
407         g_debug ("Session %d authentication complete with return value %d: %s", session->priv->pid, session->priv->authentication_result, session->priv->authentication_result_string);
408
409         /* No longer expect any more messages */
410         session->priv->from_child_watch = 0;
411
412         g_signal_emit (G_OBJECT (session), signals[AUTHENTICATION_COMPLETE], 0);
413
414         return FALSE;
415     }
416     else
417     {
418         int i;
419
420         session->priv->messages_length = 0;
421         read_from_child (session, &session->priv->messages_length, sizeof (session->priv->messages_length));
422         session->priv->messages = calloc (session->priv->messages_length, sizeof (struct pam_message));
423         for (i = 0; i < session->priv->messages_length; i++)
424         {
425             struct pam_message *m = &session->priv->messages[i];
426             read_from_child (session, &m->msg_style, sizeof (m->msg_style));
427             m->msg = read_string_from_child (session);
428         }
429
430         g_debug ("Session %d got %d message(s) from PAM", session->priv->pid, session->priv->messages_length);
431
432         g_signal_emit (G_OBJECT (session), signals[GOT_MESSAGES], 0);
433     }
434
435     return TRUE;
436 }
437
438 gboolean
439 session_start (Session *session)
440 {
441     int version;
442     int to_child_pipe[2], from_child_pipe[2];
443     int to_child_output, from_child_input;
444
445     g_return_val_if_fail (session != NULL, FALSE);
446     g_return_val_if_fail (session->priv->pid == 0, FALSE);
447
448     /* Create pipes to talk to the child */
449     if (pipe (to_child_pipe) < 0 || pipe (from_child_pipe) < 0)
450     {
451         g_warning ("Failed to create pipe to communicate with session process: %s", strerror (errno));
452         return FALSE;
453     }
454     to_child_output = to_child_pipe[0];
455     session->priv->to_child_input = to_child_pipe[1];
456     session->priv->from_child_output = from_child_pipe[0];
457     from_child_input = from_child_pipe[1];
458     session->priv->from_child_channel = g_io_channel_unix_new (session->priv->from_child_output);
459     session->priv->from_child_watch = g_io_add_watch (session->priv->from_child_channel, G_IO_IN | G_IO_HUP, from_child_cb, session);
460
461     /* Don't allow the daemon end of the pipes to be accessed in child processes */
462     fcntl (session->priv->to_child_input, F_SETFD, FD_CLOEXEC);
463     fcntl (session->priv->from_child_output, F_SETFD, FD_CLOEXEC);
464
465     /* Create the guest account if it is one */
466     if (session->priv->is_guest && session->priv->username == NULL)
467         session->priv->username = guest_account_setup ();
468
469     /* Run the child */
470     session->priv->pid = fork ();
471     if (session->priv->pid < 0)
472     {
473         g_debug ("Failed to fork session child process: %s", strerror (errno));
474         return FALSE;
475     }
476
477     if (session->priv->pid == 0)
478     {
479         /* Run us again in session child mode */
480         execlp ("lightdm",
481                 "lightdm",
482                 "--session-child",
483                 g_strdup_printf ("%d", to_child_output),
484                 g_strdup_printf ("%d", from_child_input),
485                 NULL);
486         _exit (EXIT_FAILURE);
487     }
488
489     /* Hold a reference on this object until the child process terminates so we
490      * can handle the watch callback even if it is no longer used. Otherwise a
491      * zombie process will remain */
492     g_object_ref (session);
493
494     /* Listen for session termination */
495     session->priv->authentication_started = TRUE;
496     session->priv->child_watch = g_child_watch_add (session->priv->pid, session_watch_cb, session);
497
498     /* Close the ends of the pipes we don't need */
499     close (to_child_output);
500     close (from_child_input);
501
502     /* Indicate what version of the protocol we are using */
503     version = 1;
504     write_data (session, &version, sizeof (version));
505
506     /* Send configuration */
507     write_string (session, session->priv->pam_service);
508     write_string (session, session->priv->username);
509     write_data (session, &session->priv->do_authenticate, sizeof (session->priv->do_authenticate));
510     write_data (session, &session->priv->is_interactive, sizeof (session->priv->is_interactive));
511     write_string (session, session->priv->class);
512     write_string (session, session->priv->tty);
513     write_string (session, session->priv->remote_host_name);
514     write_string (session, session->priv->xdisplay);
515     write_xauth (session, session->priv->xauthority);
516
517     g_debug ("Started session %d with service '%s', username '%s'", session->priv->pid, session->priv->pam_service, session->priv->username);
518
519     return TRUE;
520 }
521
522 const gchar *
523 session_get_username (Session *session)
524 {
525     g_return_val_if_fail (session != NULL, NULL);
526     return session->priv->username;
527 }
528
529 const gchar *
530 session_get_console_kit_cookie (Session *session)
531 {
532     g_return_val_if_fail (session != NULL, NULL);
533     return session->priv->console_kit_cookie;
534 }
535
536 void
537 session_respond (Session *session, struct pam_response *response)
538 {
539     int error = PAM_SUCCESS;
540     int i;
541
542     g_return_if_fail (session != NULL);
543
544     write_data (session, &error, sizeof (error));
545     for (i = 0; i < session->priv->messages_length; i++)
546     {
547         write_string (session, response[i].resp);
548         write_data (session, &response[i].resp_retcode, sizeof (response[i].resp_retcode));
549     }
550
551     /* Delete the old messages */
552     for (i = 0; i < session->priv->messages_length; i++)
553         g_free ((char *) session->priv->messages[i].msg);
554     g_free (session->priv->messages);
555     session->priv->messages = NULL;
556     session->priv->messages_length = 0;
557 }
558
559 void
560 session_respond_error (Session *session, int error)
561 {
562     g_return_if_fail (session != NULL);
563     g_return_if_fail (error != PAM_SUCCESS);
564
565     write_data (session, &error, sizeof (error));
566 }
567
568 int
569 session_get_messages_length (Session *session)
570 {
571     g_return_val_if_fail (session != NULL, 0);
572     return session->priv->messages_length;
573 }
574
575 const struct pam_message *
576 session_get_messages (Session *session)
577 {
578     g_return_val_if_fail (session != NULL, NULL);
579     return session->priv->messages;
580 }
581
582 gboolean
583 session_get_is_authenticated (Session *session)
584 {
585     g_return_val_if_fail (session != NULL, FALSE);
586     return session->priv->authentication_complete && session->priv->authentication_result == PAM_SUCCESS;
587 }
588
589 int
590 session_get_authentication_result (Session *session)
591 {
592     g_return_val_if_fail (session != NULL, 0);
593     return session->priv->authentication_result;
594 }
595
596 const gchar *
597 session_get_authentication_result_string (Session *session)
598 {
599     g_return_val_if_fail (session != NULL, NULL);
600     return session->priv->authentication_result_string;
601 }
602
603 void
604 session_run (Session *session)
605 {
606     gsize i, argc;
607     gchar *command, *xauth_filename;
608     GList *link;
609
610     g_return_if_fail (session != NULL);
611     g_return_if_fail (session_get_is_authenticated (session));
612     g_return_if_fail (session->priv->argv != NULL);
613
614     command = g_strjoinv (" ", session->priv->argv);
615     g_debug ("Session %d running command %s", session->priv->pid, command);
616     g_free (command);
617
618     /* Create authority location */
619     if (session->priv->xauth_use_system_location)
620     {
621         gchar *run_dir, *dir;
622
623         run_dir = config_get_string (config_get_instance (), "LightDM", "run-directory");
624         dir = g_build_filename (run_dir, session->priv->username, NULL);
625         g_free (run_dir);
626
627         if (g_mkdir_with_parents (dir, S_IRWXU) < 0)
628             g_warning ("Failed to set create system authority dir %s: %s", dir, strerror (errno));          
629         if (getuid () == 0)
630         {
631             if (chown (dir, user_get_uid (session_get_user (session)), user_get_gid (session_get_user (session))) < 0)
632                 g_warning ("Failed to set ownership of user authority dir: %s", strerror (errno));
633         }
634
635         xauth_filename = g_build_filename (dir, "xauthority", NULL);
636         g_free (dir);
637     }
638     else
639         xauth_filename = g_build_filename (user_get_home_directory (session_get_user (session)), ".Xauthority", NULL);
640
641     write_string (session, session->priv->log_filename);
642     write_string (session, session->priv->tty);
643     write_string (session, xauth_filename);
644     g_free (xauth_filename);
645     write_string (session, session->priv->xdisplay);
646     write_xauth (session, session->priv->xauthority);
647     argc = g_list_length (session->priv->env);
648     write_data (session, &argc, sizeof (argc));
649     for (link = session->priv->env; link; link = link->next)
650         write_string (session, (gchar *) link->data);
651     argc = g_strv_length (session->priv->argv);
652     write_data (session, &argc, sizeof (argc));
653     for (i = 0; i < argc; i++)
654         write_string (session, session->priv->argv[i]);
655
656     if (login1_is_running ())
657         session->priv->login1_session = read_string_from_child (session);
658     if (!session->priv->login1_session)
659         session->priv->console_kit_cookie = read_string_from_child (session);
660 }
661
662 void
663 session_lock (Session *session)
664 {
665     g_return_if_fail (session != NULL);
666     if (getuid () == 0)
667     {
668         if (login1_is_running ())
669             login1_lock_session (session->priv->login1_session);
670         if (!session->priv->login1_session)
671             ck_lock_session (session->priv->console_kit_cookie);
672     }
673 }
674
675 void
676 session_unlock (Session *session)
677 {
678     g_return_if_fail (session != NULL);
679     if (getuid () == 0)
680     {
681         if (login1_is_running ())
682             login1_unlock_session (session->priv->login1_session);
683         if (!session->priv->login1_session)
684             ck_unlock_session (session->priv->console_kit_cookie);
685     }
686 }
687
688 void
689 session_stop (Session *session)
690 {
691     g_return_if_fail (session != NULL);
692
693     if (session->priv->pid > 0)
694     {
695         g_debug ("Session %d: Sending SIGTERM", session->priv->pid);
696         kill (session->priv->pid, SIGTERM);
697         // FIXME: Handle timeout
698     }
699 }
700
701 gboolean
702 session_get_is_stopped (Session *session)
703 {
704     g_return_val_if_fail (session != NULL, TRUE);
705     return session->priv->pid == 0;
706 }
707
708 static void
709 session_init (Session *session)
710 {
711     session->priv = G_TYPE_INSTANCE_GET_PRIVATE (session, SESSION_TYPE, SessionPrivate);
712 }
713
714 static void
715 session_finalize (GObject *object)
716 {
717     Session *self = SESSION (object);
718     int i;
719
720     if (self->priv->display_server)
721         g_object_unref (self->priv->display_server);
722     if (self->priv->pid)
723         kill (self->priv->pid, SIGKILL);
724     if (self->priv->from_child_channel)
725         g_io_channel_unref (self->priv->from_child_channel);
726     if (self->priv->from_child_watch)
727         g_source_remove (self->priv->from_child_watch);
728     if (self->priv->child_watch)
729         g_source_remove (self->priv->child_watch);
730     g_free (self->priv->username);
731     if (self->priv->user)
732         g_object_unref (self->priv->user);
733     g_free (self->priv->pam_service);
734     for (i = 0; i < self->priv->messages_length; i++)
735         g_free ((char *) self->priv->messages[i].msg);
736     g_free (self->priv->messages);
737     g_free (self->priv->authentication_result_string);
738     g_free (self->priv->log_filename);
739     g_free (self->priv->class);
740     g_free (self->priv->tty);
741     g_free (self->priv->xdisplay);
742     if (self->priv->xauthority)
743         g_object_unref (self->priv->xauthority);
744     g_free (self->priv->remote_host_name);
745     g_free (self->priv->login1_session);
746     g_free (self->priv->console_kit_cookie);
747     g_list_free_full (self->priv->env, g_free);
748     g_strfreev (self->priv->argv);
749
750     G_OBJECT_CLASS (session_parent_class)->finalize (object);
751 }
752
753 static void
754 session_class_init (SessionClass *klass)
755 {
756     GObjectClass *object_class = G_OBJECT_CLASS (klass);
757
758     klass->set_display_server = session_real_set_display_server;
759     object_class->finalize = session_finalize;
760
761     g_type_class_add_private (klass, sizeof (SessionPrivate));
762
763     signals[GOT_MESSAGES] =
764         g_signal_new ("got-messages",
765                       G_TYPE_FROM_CLASS (klass),
766                       G_SIGNAL_RUN_LAST,
767                       G_STRUCT_OFFSET (SessionClass, got_messages),
768                       NULL, NULL,
769                       g_cclosure_marshal_VOID__VOID,
770                       G_TYPE_NONE, 0);
771
772     signals[AUTHENTICATION_COMPLETE] =
773         g_signal_new ("authentication-complete",
774                       G_TYPE_FROM_CLASS (klass),
775                       G_SIGNAL_RUN_LAST,
776                       G_STRUCT_OFFSET (SessionClass, authentication_complete),
777                       NULL, NULL,
778                       g_cclosure_marshal_VOID__VOID,
779                       G_TYPE_NONE, 0);
780
781     signals[STOPPED] =
782         g_signal_new ("stopped",
783                       G_TYPE_FROM_CLASS (klass),
784                       G_SIGNAL_RUN_LAST,
785                       G_STRUCT_OFFSET (SessionClass, stopped),
786                       NULL, NULL,
787                       g_cclosure_marshal_VOID__VOID,
788                       G_TYPE_NONE, 0);
789 }