]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - src/display.c
Correctly implement and test autologin timeouts
[sojka/lightdm.git] / src / display.c
1 /* -*- Mode: C; indent-tabs-mode: nil; tab-width: 4 -*-
2  *
3  * Copyright (C) 2010-2011 Robert Ancell.
4  * Author: Robert Ancell <robert.ancell@canonical.com>
5  *
6  * This program is free software: you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License as published by the Free Software
8  * Foundation, either version 3 of the License, or (at your option) any later
9  * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
10  * license.
11  */
12
13 #include <config.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <gio/gdesktopappinfo.h>
17
18 #include "display.h"
19 #include "configuration.h"
20 #include "ldm-marshal.h"
21 #include "greeter.h"
22
23 enum
24 {
25     CREATE_SESSION,
26     READY,
27     SWITCH_TO_USER,
28     SWITCH_TO_GUEST,
29     GET_GUEST_USERNAME,
30     DISPLAY_SERVER_READY,
31     START_GREETER,
32     START_SESSION,
33     STOPPED,
34     LAST_SIGNAL
35 };
36 static guint signals[LAST_SIGNAL] = { 0 };
37
38 struct DisplayPrivate
39 {
40     /* Display server */
41     DisplayServer *display_server;
42
43     /* Greeter session */
44     gchar *greeter_session;
45
46     /* TRUE if the user list should be shown */
47     gboolean greeter_hide_users;
48
49     /* TRUE if a manual login option should be shown */
50     gboolean greeter_show_manual_login;
51
52     /* TRUE if the greeter is a lock screen */
53     gboolean greeter_is_lock;
54
55     /* Session requested to log into */
56     SessionType user_session_type;
57     gchar *user_session;
58
59     /* Program to run sessions through */
60     gchar *session_wrapper;
61
62     /* TRUE if in a user session */
63     gboolean in_user_session;
64
65     /* TRUE if have got an X server / started a greeter */
66     gboolean is_ready;
67
68     /* Session process */
69     Session *session;
70
71     /* Communication link to greeter */
72     Greeter *greeter;
73
74     /* User that should be automatically logged in */
75     gchar *autologin_user;
76     gboolean autologin_guest;
77     gint autologin_timeout;
78
79     /* TRUE if start greeter if fail to login */
80     gboolean start_greeter_if_fail;
81
82     /* Hint to select user in greeter */
83     gchar *select_user_hint;
84     gboolean select_guest_hint;
85
86     /* TRUE if allowed to log into guest account */
87     gboolean allow_guest;
88
89     /* TRUE if greeter is to show the guest account */
90     gboolean greeter_allow_guest;
91
92     /* TRUE if stopping the display (waiting for dispaly server, greeter and session to stop) */
93     gboolean stopping;
94
95     /* TRUE if stopped */
96     gboolean stopped;
97 };
98
99 /* PAM services to use */
100 #define GREETER_SERVICE   "lightdm-greeter"
101 #define USER_SERVICE      "lightdm"
102 #define AUTOLOGIN_SERVICE "lightdm-autologin"
103
104 G_DEFINE_TYPE (Display, display, G_TYPE_OBJECT);
105
106 static void greeter_session_stopped_cb (Session *session, Display *display);
107 static void user_session_stopped_cb (Session *session, Display *display);
108
109 Display *
110 display_new (DisplayServer *display_server)
111 {
112     Display *display = g_object_new (DISPLAY_TYPE, NULL);
113
114     display->priv->display_server = g_object_ref (display_server);
115
116     return display;
117 }
118
119 DisplayServer *
120 display_get_display_server (Display *display)
121 {
122     g_return_val_if_fail (display != NULL, NULL);
123     return display->priv->display_server;
124 }
125
126 const gchar *
127 display_get_username (Display *display)
128 {
129     g_return_val_if_fail (display != NULL, NULL);
130
131     if (!display->priv->session || !display->priv->in_user_session)
132         return NULL;
133
134     return session_get_username (display->priv->session);
135 }
136
137 Session *
138 display_get_session (Display *display)
139 {
140     g_return_val_if_fail (display != NULL, NULL);
141     return display->priv->session;
142 }
143
144 void
145 display_set_greeter_session (Display *display, const gchar *greeter_session)
146 {
147     g_return_if_fail (display != NULL);
148     g_free (display->priv->greeter_session);
149     display->priv->greeter_session = g_strdup (greeter_session);
150 }
151
152 void
153 display_set_session_wrapper (Display *display, const gchar *session_wrapper)
154 {
155     g_return_if_fail (display != NULL);
156     g_free (display->priv->session_wrapper);
157     display->priv->session_wrapper = g_strdup (session_wrapper);
158 }
159
160 void
161 display_set_allow_guest (Display *display, gboolean allow_guest)
162 {
163     g_return_if_fail (display != NULL);
164     display->priv->allow_guest = allow_guest;
165 }
166
167 void
168 display_set_greeter_allow_guest (Display *display, gboolean greeter_allow_guest)
169 {
170     g_return_if_fail (display != NULL);
171     display->priv->greeter_allow_guest = greeter_allow_guest;
172 }
173
174 void
175 display_set_autologin_user (Display *display, const gchar *username, gboolean is_guest, gint timeout)
176 {
177     g_return_if_fail (display != NULL);
178     g_free (display->priv->autologin_user);
179     display->priv->autologin_user = g_strdup (username);
180     display->priv->autologin_guest = is_guest;
181     display->priv->autologin_timeout = timeout;
182 }
183
184 void
185 display_set_select_user_hint (Display *display, const gchar *username, gboolean is_guest)
186 {
187     g_return_if_fail (display != NULL);
188     g_free (display->priv->select_user_hint);
189     display->priv->select_user_hint = g_strdup (username);
190     display->priv->select_guest_hint = is_guest;
191 }
192
193 void
194 display_set_hide_users_hint (Display *display, gboolean hide_users)
195 {
196     g_return_if_fail (display != NULL);
197     display->priv->greeter_hide_users = hide_users;
198 }
199
200 void
201 display_set_show_manual_login_hint (Display *display, gboolean show_manual_login)
202 {
203     g_return_if_fail (display != NULL);
204     display->priv->greeter_show_manual_login = show_manual_login;
205 }
206
207 void
208 display_set_lock_hint (Display *display, gboolean is_lock)
209 {
210     g_return_if_fail (display != NULL);
211     display->priv->greeter_is_lock = is_lock;
212 }
213
214 void
215 display_set_user_session (Display *display, SessionType type, const gchar *session_name)
216 {
217     g_return_if_fail (display != NULL);
218     g_free (display->priv->user_session);
219     display->priv->user_session_type = type;
220     display->priv->user_session = g_strdup (session_name);
221 }
222
223 static void
224 display_set_is_ready (Display *display)
225 {
226     if (display->priv->is_ready)
227         return;
228
229     display->priv->is_ready = TRUE;
230     g_signal_emit (display, signals[READY], 0);
231 }
232
233 static gboolean
234 switch_to_user (Display *display, User *user)
235 {
236     gboolean result;
237     g_signal_emit (display, signals[SWITCH_TO_USER], 0, user, &result);
238     return result;
239 }
240
241 static gboolean
242 switch_to_guest (Display *display)
243 {
244     gboolean result;
245     g_signal_emit (display, signals[SWITCH_TO_GUEST], 0, &result);
246     return result;
247 }
248
249 static gchar *
250 get_guest_username (Display *display)
251 {
252     gchar *username;
253     g_signal_emit (display, signals[GET_GUEST_USERNAME], 0, &username);
254     return username;
255 }
256
257 static Session *
258 create_session (Display *display)
259 {
260     Session *session;
261
262     g_signal_emit (display, signals[CREATE_SESSION], 0, &session);
263     if (!session)
264         return NULL;
265
266     /* Connect using the session bus */
267     if (getuid () != 0)
268     {
269         if (g_getenv ("DBUS_SESSION_BUS_ADDRESS"))
270             session_set_env (session, "DBUS_SESSION_BUS_ADDRESS", g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
271         session_set_env (session, "LDM_BUS", "SESSION");
272         if (g_getenv ("LD_PRELOAD"))
273             session_set_env (session, "LD_PRELOAD", g_getenv ("LD_PRELOAD"));
274         if (g_getenv ("LD_LIBRARY_PATH"))
275             session_set_env (session, "LD_LIBRARY_PATH", g_getenv ("LD_LIBRARY_PATH"));
276         if (g_getenv ("PATH"))
277             session_set_env (session, "PATH", g_getenv ("PATH"));
278     }
279
280     /* Variables required for regression tests */
281     if (g_getenv ("LIGHTDM_TEST_ROOT"))
282     {
283         session_set_env (session, "LIGHTDM_TEST_ROOT", g_getenv ("LIGHTDM_TEST_ROOT"));
284         session_set_env (session, "DBUS_SYSTEM_BUS_ADDRESS", g_getenv ("DBUS_SYSTEM_BUS_ADDRESS"));
285         session_set_env (session, "DBUS_SESSION_BUS_ADDRESS", g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
286         session_set_env (session, "LD_PRELOAD", g_getenv ("LD_PRELOAD"));
287         session_set_env (session, "LD_LIBRARY_PATH", g_getenv ("LD_LIBRARY_PATH"));
288         session_set_env (session, "GI_TYPELIB_PATH", g_getenv ("GI_TYPELIB_PATH"));
289     }
290
291     return session;
292 }
293
294 static void
295 destroy_session (Display *display)
296 {
297     if (!display->priv->session)
298         return;
299
300     g_signal_handlers_disconnect_matched (display->priv->session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
301     session_stop (display->priv->session);
302     g_object_unref (display->priv->session);
303     display->priv->session = NULL;
304 }
305
306 static void
307 greeter_authentication_complete_cb (Session *session, Display *display)
308 {
309     gboolean result = FALSE;
310
311     if (display->priv->stopping)
312         return;
313
314     if (session_get_is_authenticated (session))
315     {
316         g_debug ("Greeter authorized");
317         g_signal_emit (display, signals[START_GREETER], 0, &result);
318         result = !result;
319     }
320     else
321         g_debug ("Greeter failed authentication");
322
323     if (!result)
324     {
325         g_debug ("Greeter failed to start");
326         display_stop (display);
327     }
328 }
329
330 static void
331 greeter_connected_cb (Greeter *greeter, Display *display)
332 {
333     // FIXME: Should wait for greeter to signal completely ready if it supports it
334     g_debug ("Greeter connected, display is ready");
335     display_set_is_ready (display);
336 }
337
338 static Session *
339 greeter_start_authentication_cb (Greeter *greeter, const gchar *username, Display *display)
340 {
341     return create_session (display);
342 }
343
344 static gboolean
345 greeter_start_session_cb (Greeter *greeter, SessionType type, const gchar *session_name, Display *display)
346 {
347     /* If no session requested, use the previous one */
348     if (!session_name && !greeter_get_guest_authenticated (greeter))
349     {
350         User *user;
351
352         user = session_get_user (greeter_get_authentication_session (greeter));
353         type = SESSION_TYPE_LOCAL;
354         session_name = user_get_xsession (user);
355     }
356
357     /* If a session was requested, override the default */
358     if (session_name)
359     {
360         g_debug ("Using session %s", session_name);
361         display_set_user_session (display, type, session_name);
362     }
363
364     /* Stop this display if that session already exists and can switch to it */
365     if (greeter_get_guest_authenticated (greeter))
366     {
367         if (switch_to_guest (display))
368             return TRUE;
369
370         /* Set to login as guest */
371         display_set_autologin_user (display, NULL, TRUE, 0);
372     }
373     else
374     {
375         if (switch_to_user (display, session_get_user (greeter_get_authentication_session (display->priv->greeter))))
376             return TRUE;
377     }
378
379     /* Stop the greeter, the session will start when the greeter has quit */
380     g_debug ("Stopping greeter");
381     session_stop (display->priv->session);
382
383     return TRUE;
384 }
385
386 static gboolean
387 start_greeter (Display *display)
388 {
389     gchar *greeter_user;
390     gboolean result;
391
392     destroy_session (display);
393     display->priv->session = create_session (display);
394     session_set_class (display->priv->session, XDG_SESSION_CLASS_GREETER);
395     g_signal_connect (display->priv->session, "authentication-complete", G_CALLBACK (greeter_authentication_complete_cb), display);
396
397     /* Make communication link to greeter that will run on this session */
398     display->priv->greeter = greeter_new (display->priv->session, USER_SERVICE, AUTOLOGIN_SERVICE);
399     g_signal_connect (G_OBJECT (display->priv->greeter), "connected", G_CALLBACK (greeter_connected_cb), display);
400     g_signal_connect (G_OBJECT (display->priv->greeter), "start-authentication", G_CALLBACK (greeter_start_authentication_cb), display);
401     g_signal_connect (G_OBJECT (display->priv->greeter), "start-session", G_CALLBACK (greeter_start_session_cb), display);
402     if (display->priv->autologin_timeout)
403     {
404         gchar *value = g_strdup_printf ("%d", display->priv->autologin_timeout);
405         greeter_set_hint (display->priv->greeter, "autologin-timeout", value);
406         g_free (value);
407         if (display->priv->autologin_user)
408             greeter_set_hint (display->priv->greeter, "autologin-user", display->priv->autologin_user);
409         else if (display->priv->autologin_guest)
410             greeter_set_hint (display->priv->greeter, "autologin-guest", "true");
411     }
412     if (display->priv->select_user_hint)
413         greeter_set_hint (display->priv->greeter, "select-user", display->priv->select_user_hint);
414     else if (display->priv->select_guest_hint)
415         greeter_set_hint (display->priv->greeter, "select-guest", "true");
416     greeter_set_hint (display->priv->greeter, "default-session", display->priv->user_session);
417     greeter_set_allow_guest (display->priv->greeter, display->priv->allow_guest);
418     greeter_set_hint (display->priv->greeter, "has-guest-account", (display->priv->allow_guest && display->priv->greeter_allow_guest) ? "true" : "false");
419     greeter_set_hint (display->priv->greeter, "hide-users", display->priv->greeter_hide_users ? "true" : "false");
420     greeter_set_hint (display->priv->greeter, "show-manual-login", display->priv->greeter_show_manual_login ? "true" : "false");
421     if (display->priv->greeter_is_lock)
422         greeter_set_hint (display->priv->greeter, "lock-screen", "true");
423
424     /* Run greeter as unprivileged user */
425     if (getuid () != 0)
426     {
427         User *user;
428         user = accounts_get_current_user ();
429         greeter_user = g_strdup (user_get_name (user));
430         g_object_unref (user);
431     }
432     else
433     {
434         greeter_user = config_get_string (config_get_instance (), "LightDM", "greeter-user");
435         if (!greeter_user)
436         {
437             g_warning ("Greeter must not be run as root");
438             display_stop (display);
439             return FALSE;
440         }
441     }
442
443     g_signal_connect_after (display->priv->session, "stopped", G_CALLBACK (greeter_session_stopped_cb), display);
444     result = greeter_start (display->priv->greeter, GREETER_SERVICE, greeter_user);
445     g_free (greeter_user);
446
447     if (!result)
448         display_stop (display);
449
450     return result;
451 }
452
453 static void
454 autologin_authentication_complete_cb (Session *session, Display *display)
455 {
456     gboolean result = FALSE;
457
458     if (display->priv->stopping)
459         return;
460
461     if (session_get_is_authenticated (session))
462     {
463         const gchar *session_name;
464
465         g_debug ("Autologin user %s authorized", session_get_username (session));
466
467         session_name = user_get_xsession (session_get_user (session));
468         if (session_name)
469         {
470             g_debug ("Autologin using session %s", session_name);
471             display_set_user_session (display, SESSION_TYPE_LOCAL, session_name);
472         }
473
474         g_signal_emit (display, signals[START_SESSION], 0, &result);
475         result = !result;
476     }
477     else
478         g_debug ("Autologin failed authentication");
479
480     if (!result)
481     {
482         if (display->priv->start_greeter_if_fail)
483             start_greeter (display);
484         else
485             display_stop (display);
486     }
487 }
488
489 static gboolean
490 autologin (Display *display, const gchar *username, const gchar *service, gboolean start_greeter_if_fail, gboolean is_guest)
491 {
492     display->priv->start_greeter_if_fail = start_greeter_if_fail;
493
494     display->priv->in_user_session = TRUE;
495     destroy_session (display);
496     display->priv->session = create_session (display);
497     g_signal_connect (display->priv->session, "authentication-complete", G_CALLBACK (autologin_authentication_complete_cb), display);
498     g_signal_connect_after (display->priv->session, "stopped", G_CALLBACK (user_session_stopped_cb), display);
499     return session_start (display->priv->session, service, username, TRUE, FALSE, is_guest);
500 }
501
502 static gboolean
503 autologin_guest (Display *display, const gchar *service, gboolean start_greeter_if_fail)
504 {
505     gchar *username;
506     gboolean result;
507
508     username = get_guest_username (display);
509     if (!username)
510     {
511         g_debug ("Can't autologin guest, no guest account");
512         return FALSE;
513     }
514
515     result = autologin (display, username, service, start_greeter_if_fail, TRUE);
516     g_free (username);
517
518     return result;
519 }
520
521 static gchar **
522 get_session_command (const gchar *filename, const gchar *session_wrapper)
523 {
524     GKeyFile *session_desktop_file;
525     gboolean result;
526     int argc;
527     gchar *command = NULL, **argv, *path;
528     GError *error = NULL;
529
530     /* Read the command from the .desktop file */
531     session_desktop_file = g_key_file_new ();
532     result = g_key_file_load_from_file (session_desktop_file, filename, G_KEY_FILE_NONE, &error);
533     if (error)
534         g_debug ("Failed to load session file %s: %s", filename, error->message);
535     g_clear_error (&error);
536     if (result)
537     {
538         command = g_key_file_get_string (session_desktop_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL);
539         if (!command)
540             g_debug ("No command in session file %s", filename);
541     }
542     g_key_file_free (session_desktop_file);
543
544     if (!command)
545         return NULL;
546
547     /* If configured, run sessions through a wrapper */
548     if (session_wrapper)
549     {
550         argv = g_malloc (sizeof (gchar *) * 3);
551         path = g_find_program_in_path (session_wrapper);
552         argv[0] = path ? path : g_strdup (session_wrapper);
553         argv[1] = command;
554         argv[2] = NULL;
555         return argv;
556     }
557
558     /* Split command into an array listing and make command absolute */
559     result = g_shell_parse_argv (command, &argc, &argv, &error);
560     if (error)
561         g_debug ("Invalid session command '%s': %s", command, error->message);
562     g_clear_error (&error);
563     g_free (command);
564     if (!result)
565         return NULL;
566     path = g_find_program_in_path (argv[0]);
567     if (path)
568     {
569         g_free (argv[0]);
570         argv[0] = path;
571     }
572   
573     return argv;
574 }
575
576 static void
577 greeter_session_stopped_cb (Session *session, Display *display)
578 {
579     gboolean result = FALSE;
580
581     g_debug ("Greeter quit");
582
583     g_signal_handlers_disconnect_matched (display->priv->session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
584     g_object_unref (display->priv->session);
585     display->priv->session = NULL;
586
587     if (display->priv->stopping)
588     {
589         display_stop (display);
590         return;
591     }
592
593     if (!display->priv->display_server)
594         return;
595
596     /* Start the session for the authenticated user */
597     if (greeter_get_start_session (display->priv->greeter))
598     {
599         /* If guest, then start a new autologin guest session (so can setup account) */
600         if (greeter_get_guest_authenticated (display->priv->greeter))
601             result = autologin_guest (display, AUTOLOGIN_SERVICE, FALSE);
602         /* Otherwise, use the session the greeter has authenticated */
603         else
604         {
605             destroy_session (display);
606             display->priv->session = g_object_ref (greeter_get_authentication_session (display->priv->greeter));
607             g_signal_connect_after (display->priv->session, "stopped", G_CALLBACK (user_session_stopped_cb), display);
608             display->priv->in_user_session = TRUE;
609             g_signal_emit (display, signals[START_SESSION], 0, &result);
610             result = !result;
611         }
612     }
613
614     /* Destroy the greeter */
615     g_signal_handlers_disconnect_matched (display->priv->greeter, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
616     g_object_unref (display->priv->greeter);
617     display->priv->greeter = NULL;
618
619     if (!result)
620     {
621         g_debug ("Failed to start greeter");
622         display_stop (display);
623     }
624 }
625
626 static gboolean
627 display_start_greeter (Display *display)
628 {
629     gchar *log_dir, *filename, *log_filename, *sessions_dir, *path;
630     gchar **argv;
631
632     /* Log the output of the greeter to a system location */
633     log_dir = config_get_string (config_get_instance (), "LightDM", "log-directory");
634     filename = g_strdup_printf ("%s-greeter.log", display_server_get_name (display->priv->display_server));
635     log_filename = g_build_filename (log_dir, filename, NULL);
636     g_free (log_dir);
637     g_free (filename);
638     g_debug ("Logging to %s", log_filename);
639     session_set_log_file (display->priv->session, log_filename);
640     g_free (log_filename);
641
642     /* Load the greeter session information */
643     sessions_dir = config_get_string (config_get_instance (), "LightDM", "xgreeters-directory");
644     filename = g_strdup_printf ("%s.desktop", display->priv->greeter_session);
645     path = g_build_filename (sessions_dir, filename, NULL);
646     g_free (sessions_dir);
647     g_free (filename);
648     argv = get_session_command (path, NULL);
649     g_free (path);
650     if (!argv)
651         return TRUE;
652
653     session_run (display->priv->session, argv);
654
655     return FALSE;
656 }
657
658 static void
659 user_session_stopped_cb (Session *session, Display *display)
660 {
661     g_debug ("User session quit");
662
663     g_signal_handlers_disconnect_matched (display->priv->session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
664     g_object_unref (display->priv->session);
665     display->priv->session = NULL;
666
667     /* This display has ended */
668     display_stop (display);
669 }
670
671 static void
672 prepend_argv (gchar ***argv, const gchar *value)
673 {
674     gchar **old_argv, **new_argv;
675     gint i;
676
677     old_argv = *argv;
678     new_argv = g_malloc (sizeof (gchar *) * (g_strv_length (*argv) + 2));
679     new_argv[0] = g_strdup (value);
680     for (i = 0; old_argv[i]; i++)
681         new_argv[i + 1] = old_argv[i];
682     new_argv[i + 1] = NULL;
683
684     g_free (*argv);
685     *argv = new_argv;
686 }
687
688 static gboolean
689 display_start_session (Display *display)
690 {
691     User *user;
692     gchar *filename, *sessions_dir, *path;
693     gchar **argv;
694
695     user = session_get_user (display->priv->session);
696
697     /* Find the command to run for the selected session */
698     if (display->priv->user_session_type == SESSION_TYPE_LOCAL)
699     {
700         sessions_dir = config_get_string (config_get_instance (), "LightDM", "xsessions-directory");
701
702         /* Store this session name so we automatically use it next time */
703         user_set_xsession (user, display->priv->user_session);
704     }
705     else
706         sessions_dir = config_get_string (config_get_instance (), "LightDM", "remote-sessions-directory");
707     filename = g_strdup_printf ("%s.desktop", display->priv->user_session);
708     path = g_build_filename (sessions_dir, filename, NULL);
709     g_free (sessions_dir);
710     g_free (filename);
711     argv = get_session_command (path, display->priv->session_wrapper);
712     g_free (path);
713     if (!argv)
714         return TRUE;
715   
716     session_set_env (display->priv->session, "DESKTOP_SESSION", display->priv->user_session); // FIXME: Apparently deprecated?
717     session_set_env (display->priv->session, "GDMSESSION", display->priv->user_session); // FIXME: Not cross-desktop
718
719     /* Run a guest session through the wrapper covered by MAC */
720     if (display->priv->autologin_guest)
721     {
722         gchar *wrapper = g_build_filename (PKGLIBEXEC_DIR, "lightdm-guest-session-wrapper", NULL);
723         g_debug ("Running guest session through wrapper: %s", wrapper);
724         prepend_argv (&argv, wrapper);
725         g_free (wrapper);
726     }
727
728     g_debug ("Starting session %s as user %s", display->priv->user_session, session_get_username (display->priv->session));
729
730     session_run (display->priv->session, argv);
731     g_strfreev (argv);
732
733     // FIXME: Wait for session to indicate it is ready (maybe)
734     display_set_is_ready (display);
735
736     return FALSE;
737 }
738
739 static void
740 display_server_stopped_cb (DisplayServer *server, Display *display)
741 {
742     g_debug ("Display server stopped");
743
744     g_signal_handlers_disconnect_matched (display->priv->display_server, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
745     g_object_unref (display->priv->display_server);
746     display->priv->display_server = NULL;
747
748     /* Stop this display, it will be restarted by the seat if necessary */
749     display_stop (display);
750 }
751
752 static void
753 display_server_ready_cb (DisplayServer *display_server, Display *display)
754 {
755     gboolean result = FALSE;
756
757     g_signal_emit (display, signals[DISPLAY_SERVER_READY], 0, &result);
758     if (!result)
759     {
760         display_stop (display);
761         return;
762     }
763
764     /* Don't run any sessions on local terminals */
765     if (!display_server_get_start_local_sessions (display_server))
766         return;
767
768     /* Automatically start requested user session */
769     result = FALSE;
770     if (display->priv->autologin_timeout == 0 && display->priv->autologin_guest)
771     {
772         g_debug ("Automatically logging in as guest");
773         result = autologin_guest (display, AUTOLOGIN_SERVICE, TRUE);
774     }
775     else if (display->priv->autologin_timeout == 0 && display->priv->autologin_user)
776     {
777         g_debug ("Automatically logging in user %s", display->priv->autologin_user);
778         result = autologin (display, display->priv->autologin_user, AUTOLOGIN_SERVICE, TRUE, FALSE);
779     }
780     else if (display->priv->select_user_hint)
781     {
782         g_debug ("Logging in user %s", display->priv->select_user_hint);
783         result = autologin (display, display->priv->select_user_hint, USER_SERVICE, TRUE, FALSE);
784     }
785
786     /* If no session started, start a greeter */
787     if (!result)
788     {
789         g_debug ("Starting greeter");      
790         result = start_greeter (display);
791     }
792
793     /* If nothing started, then the display can't work */
794     if (!result)
795         display_stop (display);
796 }
797
798 gboolean
799 display_start (Display *display)
800 {
801     g_return_val_if_fail (display != NULL, FALSE);
802
803     g_signal_connect (G_OBJECT (display->priv->display_server), "ready", G_CALLBACK (display_server_ready_cb), display);
804     g_signal_connect (G_OBJECT (display->priv->display_server), "stopped", G_CALLBACK (display_server_stopped_cb), display);
805
806     if (!display_server_start (display->priv->display_server))
807         return FALSE;
808
809     return TRUE;
810 }
811
812 void
813 display_stop (Display *display)
814 {
815     g_return_if_fail (display != NULL);
816
817     if (display->priv->stopped)
818         return;
819
820     if (!display->priv->stopping)
821     {
822         g_debug ("Stopping display");
823         display->priv->stopping = TRUE;
824     }
825
826     /* Stop the session first */
827     if (display->priv->session)
828     {
829         session_stop (display->priv->session);
830         if (display->priv->session && !session_get_is_stopped (display->priv->session))
831             return;
832         g_signal_handlers_disconnect_matched (display->priv->session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
833         g_object_unref (display->priv->session);
834         display->priv->session = NULL;
835     }
836
837     /* Stop the display server after that */
838     if (display->priv->display_server)
839     {
840         display_server_stop (display->priv->display_server);
841         if (display->priv->display_server && !display_server_get_is_stopped (display->priv->display_server))
842             return;
843         g_signal_handlers_disconnect_matched (display->priv->display_server, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
844         g_object_unref (display->priv->display_server);
845         display->priv->display_server = NULL;
846     }
847
848     display->priv->stopped = TRUE;
849     g_debug ("Display stopped");
850     g_signal_emit (display, signals[STOPPED], 0);
851 }
852
853 gboolean
854 display_get_is_ready (Display *display)
855 {
856     g_return_val_if_fail (display != NULL, FALSE);
857
858     return display->priv->is_ready;
859 }
860
861 void
862 display_lock (Display *display)
863 {
864     g_return_if_fail (display != NULL);
865
866     if (!display->priv->session)
867         return;
868
869     g_debug ("Locking display");
870
871     session_lock (display->priv->session);
872 }
873
874 void
875 display_unlock (Display *display)
876 {
877     g_return_if_fail (display != NULL);
878
879     if (!display->priv->session)
880         return;
881
882     g_debug ("Unlocking display");
883
884     session_unlock (display->priv->session);
885 }
886
887 static gboolean
888 display_real_switch_to_user (Display *display, User *user)
889 {
890     return FALSE;
891 }
892
893 static gboolean
894 display_real_switch_to_guest (Display *display)
895 {
896     return FALSE;
897 }
898
899 static gchar *
900 display_real_get_guest_username (Display *display)
901 {
902     return NULL;
903 }
904
905 static void
906 display_init (Display *display)
907 {
908     display->priv = G_TYPE_INSTANCE_GET_PRIVATE (display, DISPLAY_TYPE, DisplayPrivate);
909 }
910
911 static void
912 display_finalize (GObject *object)
913 {
914     Display *self;
915
916     self = DISPLAY (object);
917
918     if (self->priv->display_server)
919     {
920         g_signal_handlers_disconnect_matched (self->priv->display_server, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
921         g_object_unref (self->priv->display_server);
922     }
923     g_free (self->priv->greeter_session);
924     if (self->priv->greeter)
925     {
926         g_signal_handlers_disconnect_matched (self->priv->greeter, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
927         g_object_unref (self->priv->greeter);
928     }
929     g_free (self->priv->session_wrapper);
930     if (self->priv->session)
931     {
932         g_signal_handlers_disconnect_matched (self->priv->session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);      
933         g_object_unref (self->priv->session);
934     }
935     g_free (self->priv->autologin_user);
936     g_free (self->priv->select_user_hint);
937     g_free (self->priv->user_session);
938
939     G_OBJECT_CLASS (display_parent_class)->finalize (object);
940 }
941
942 static void
943 display_class_init (DisplayClass *klass)
944 {
945     GObjectClass *object_class = G_OBJECT_CLASS (klass);
946
947     klass->switch_to_user = display_real_switch_to_user;
948     klass->switch_to_guest = display_real_switch_to_guest;
949     klass->get_guest_username = display_real_get_guest_username;
950     klass->start_greeter = display_start_greeter;
951     klass->start_session = display_start_session;
952     object_class->finalize = display_finalize;
953
954     g_type_class_add_private (klass, sizeof (DisplayPrivate));
955
956     signals[CREATE_SESSION] =
957         g_signal_new ("create-session",
958                       G_TYPE_FROM_CLASS (klass),
959                       G_SIGNAL_RUN_LAST,
960                       G_STRUCT_OFFSET (DisplayClass, create_session),
961                       NULL, NULL,
962                       ldm_marshal_OBJECT__VOID,
963                       SESSION_TYPE, 0);
964     signals[READY] =
965         g_signal_new ("ready",
966                       G_TYPE_FROM_CLASS (klass),
967                       G_SIGNAL_RUN_LAST,
968                       G_STRUCT_OFFSET (DisplayClass, ready),
969                       NULL, NULL,
970                       g_cclosure_marshal_VOID__VOID,
971                       G_TYPE_NONE, 0);
972     signals[SWITCH_TO_USER] =
973         g_signal_new ("switch-to-user",
974                       G_TYPE_FROM_CLASS (klass),
975                       G_SIGNAL_RUN_LAST,
976                       G_STRUCT_OFFSET (DisplayClass, switch_to_user),
977                       g_signal_accumulator_true_handled,
978                       NULL,
979                       ldm_marshal_BOOLEAN__OBJECT,
980                       G_TYPE_BOOLEAN, 1, USER_TYPE);
981     signals[SWITCH_TO_GUEST] =
982         g_signal_new ("switch-to-guest",
983                       G_TYPE_FROM_CLASS (klass),
984                       G_SIGNAL_RUN_LAST,
985                       G_STRUCT_OFFSET (DisplayClass, switch_to_guest),
986                       g_signal_accumulator_true_handled,
987                       NULL,
988                       ldm_marshal_BOOLEAN__VOID,
989                       G_TYPE_BOOLEAN, 0);
990     signals[GET_GUEST_USERNAME] =
991         g_signal_new ("get-guest-username",
992                       G_TYPE_FROM_CLASS (klass),
993                       G_SIGNAL_RUN_LAST,
994                       G_STRUCT_OFFSET (DisplayClass, get_guest_username),
995                       g_signal_accumulator_first_wins,
996                       NULL,
997                       ldm_marshal_STRING__VOID,
998                       G_TYPE_STRING, 0);
999     signals[DISPLAY_SERVER_READY] =
1000         g_signal_new ("display-server-ready",
1001                       G_TYPE_FROM_CLASS (klass),
1002                       G_SIGNAL_RUN_LAST,
1003                       G_STRUCT_OFFSET (DisplayClass, display_server_ready),
1004                       NULL, NULL,
1005                       ldm_marshal_BOOLEAN__VOID,
1006                       G_TYPE_BOOLEAN, 0);
1007     signals[START_GREETER] =
1008         g_signal_new ("start-greeter",
1009                       G_TYPE_FROM_CLASS (klass),
1010                       G_SIGNAL_RUN_LAST,
1011                       G_STRUCT_OFFSET (DisplayClass, start_greeter),
1012                       g_signal_accumulator_true_handled, NULL,
1013                       ldm_marshal_BOOLEAN__VOID,
1014                       G_TYPE_BOOLEAN, 0);
1015     signals[START_SESSION] =
1016         g_signal_new ("start-session",
1017                       G_TYPE_FROM_CLASS (klass),
1018                       G_SIGNAL_RUN_LAST,
1019                       G_STRUCT_OFFSET (DisplayClass, start_session),
1020                       g_signal_accumulator_true_handled, NULL,
1021                       ldm_marshal_BOOLEAN__VOID,
1022                       G_TYPE_BOOLEAN, 0);
1023     signals[STOPPED] =
1024         g_signal_new ("stopped",
1025                       G_TYPE_FROM_CLASS (klass),
1026                       G_SIGNAL_RUN_LAST,
1027                       G_STRUCT_OFFSET (DisplayClass, stopped),
1028                       NULL, NULL,
1029                       g_cclosure_marshal_VOID__VOID,
1030                       G_TYPE_NONE, 0);
1031 }