]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - src/display.c
Support hide-users hint
[sojka/lightdm.git] / src / display.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 #include <stdlib.h>
14 #include <string.h>
15 #include <gio/gdesktopappinfo.h>
16
17 #include "display.h"
18 #include "configuration.h"
19 #include "user.h"
20 #include "pam-session.h"
21 #include "dmrc.h"
22 #include "ldm-marshal.h"
23 #include "greeter.h"
24 #include "guest-account.h"
25 #include "xserver-local.h" // FIXME: Shouldn't know if it's an xserver
26
27 enum {
28     STARTED,
29     ACTIVATE_USER,
30     STOPPED,
31     LAST_SIGNAL
32 };
33 static guint signals[LAST_SIGNAL] = { 0 };
34
35 typedef enum
36 {
37     SESSION_NONE = 0,
38     SESSION_GREETER_PRE_CONNECT,
39     SESSION_GREETER,
40     SESSION_GREETER_AUTHENTICATED,
41     SESSION_USER
42 } SessionType;
43
44 struct DisplayPrivate
45 {
46     /* Display server */
47     DisplayServer *display_server;
48
49     /* User to run greeter as */
50     gchar *greeter_user;
51
52     /* Greeter session */
53     gchar *greeter_session;
54
55     /* TRUE if the user list should be shown */
56     gboolean greeter_hide_users;
57
58     /* Default session for users */
59     gchar *default_session;
60
61     /* Session requested to log into */
62     gchar *user_session;
63
64     /* Program to run sessions through */
65     gchar *session_wrapper;
66
67     /* PAM service to authenticate against */
68     gchar *pam_service;
69
70     /* PAM service to authenticate against for automatic logins */
71     gchar *pam_autologin_service;
72   
73     /* Session process */
74     Session *session;
75
76     /* Communication link to greeter */
77     Greeter *greeter;
78   
79     /* Timeout for greeter to respond to quit request */
80     guint greeter_quit_timeout;
81
82     PAMSession *pam_session;
83
84     /* User that should be automatically logged in */
85     gchar *default_user;
86     gboolean default_user_is_guest;
87     gboolean default_user_requires_password;
88     gint default_user_timeout;
89
90     /* TRUE if stopping the display (waiting for dispaly server, greeter and session to stop) */
91     gboolean stopping;    
92 };
93
94 G_DEFINE_TYPE (Display, display, G_TYPE_OBJECT);
95
96 /* Length of time in milliseconds to wait for a greeter to quit */
97 #define GREETER_QUIT_TIMEOUT 1000
98
99 static gboolean start_greeter_session (Display *display);
100 static gboolean start_user_session (Display *display, PAMSession *pam_session, const gchar *name);
101
102 // FIXME: Should be a construct property
103 void
104 display_load_config (Display *display, const gchar *config_section)
105 {
106     g_return_if_fail (display != NULL);
107     
108     if (config_section)
109         display->priv->greeter_user = config_get_string (config_get_instance (), config_section, "greeter-user");
110     if (!display->priv->greeter_user)
111         display->priv->greeter_user = config_get_string (config_get_instance (), "SeatDefaults", "greeter-user");
112     if (config_section)
113         display->priv->greeter_session = config_get_string (config_get_instance (), config_section, "greeter-session");
114     if (!display->priv->greeter_session)
115         display->priv->greeter_session = config_get_string (config_get_instance (), "SeatDefaults", "greeter-session");
116     if (config_section && config_has_key (config_get_instance (), config_section, "greeter-hide-users"))
117         display->priv->greeter_hide_users = config_get_boolean (config_get_instance (), config_section, "greeter-hide-users");
118     else if (config_has_key (config_get_instance (), "SeatDefaults", "greeter-hide-users"))
119         display->priv->greeter_hide_users = config_get_boolean (config_get_instance (), "SeatDefaults", "greeter-hide-users");
120     if (config_section)
121         display->priv->default_session = config_get_string (config_get_instance (), config_section, "user-session");
122     if (!display->priv->default_session)
123         display->priv->default_session = config_get_string (config_get_instance (), "SeatDefaults", "user-session");
124     if (config_section)
125         display->priv->session_wrapper = config_get_string (config_get_instance (), config_section, "session-wrapper");
126     if (!display->priv->session_wrapper)
127         display->priv->session_wrapper = config_get_string (config_get_instance (), "SeatDefaults", "session-wrapper");
128 }
129
130 // FIXME: Should be a construct property
131 void
132 display_set_display_server (Display *display, DisplayServer *display_server)
133 {
134     g_return_if_fail (display != NULL);
135     g_return_if_fail (display->priv->display_server == NULL);
136     display->priv->display_server = g_object_ref (display_server);
137 }
138
139 DisplayServer *
140 display_get_display_server (Display *display)
141 {
142     g_return_val_if_fail (display != NULL, NULL);
143     return display->priv->display_server;
144 }
145
146 Session *
147 display_get_session (Display *display)
148 {
149     g_return_val_if_fail (display != NULL, NULL);
150     return display->priv->session;
151 }
152
153 void
154 display_set_default_user (Display *display, const gchar *username, gboolean is_guest, gboolean requires_password, gint timeout)
155 {
156     g_return_if_fail (display != NULL);
157     g_free (display->priv->default_user);
158     display->priv->default_user = g_strdup (username);
159     display->priv->default_user_is_guest = is_guest;
160     display->priv->default_user_requires_password = requires_password;
161     display->priv->default_user_timeout = timeout;
162 }
163
164 static gboolean
165 activate_user (Display *display, const gchar *username)
166 {
167     gboolean result;
168     g_signal_emit (display, signals[ACTIVATE_USER], 0, username, &result);
169     return result;
170 }
171
172 static gchar *
173 start_ck_session (Display *display, const gchar *session_type, User *user)
174 {
175     GDBusProxy *proxy;
176     const gchar *hostname = "";
177     GVariantBuilder arg_builder;
178     GVariant *result;
179     gchar *cookie = NULL;
180     GError *error = NULL;
181
182     /* Only start ConsoleKit sessions when running as root */
183     if (getuid () != 0)
184         return NULL;
185
186     proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
187                                            G_DBUS_PROXY_FLAGS_NONE,
188                                            NULL,
189                                            "org.freedesktop.ConsoleKit",
190                                            "/org/freedesktop/ConsoleKit/Manager",
191                                            "org.freedesktop.ConsoleKit.Manager", 
192                                            NULL, &error);
193     if (!proxy)
194         g_warning ("Unable to get connection to ConsoleKit: %s", error->message);
195     g_clear_error (&error);
196     if (!proxy)
197         return NULL;
198
199     g_variant_builder_init (&arg_builder, G_VARIANT_TYPE ("(a(sv))"));
200     g_variant_builder_open (&arg_builder, G_VARIANT_TYPE ("a(sv)"));
201     g_variant_builder_add (&arg_builder, "(sv)", "unix-user", g_variant_new_int32 (user_get_uid (user)));
202     g_variant_builder_add (&arg_builder, "(sv)", "session-type", g_variant_new_string (session_type));
203     if (IS_XSERVER (display->priv->display_server))
204     {
205         g_variant_builder_add (&arg_builder, "(sv)", "x11-display",
206                                g_variant_new_string (xserver_get_address (XSERVER (display->priv->display_server))));
207
208         if (IS_XSERVER_LOCAL (display->priv->display_server) && xserver_local_get_vt (XSERVER_LOCAL (display->priv->display_server)) >= 0)
209         {
210             gchar *display_device;
211             display_device = g_strdup_printf ("/dev/tty%d", xserver_local_get_vt (XSERVER_LOCAL (display->priv->display_server)));
212             g_variant_builder_add (&arg_builder, "(sv)", "x11-display-device", g_variant_new_string (display_device));
213             g_free (display_device);
214         }
215     }
216
217     g_variant_builder_add (&arg_builder, "(sv)", "remote-host-name", g_variant_new_string (hostname));
218     g_variant_builder_add (&arg_builder, "(sv)", "is-local", g_variant_new_boolean (TRUE));
219     g_variant_builder_close (&arg_builder);
220
221     result = g_dbus_proxy_call_sync (proxy,
222                                      "OpenSessionWithParameters",
223                                      g_variant_builder_end (&arg_builder),
224                                      G_DBUS_CALL_FLAGS_NONE,
225                                      -1,
226                                      NULL,
227                                      &error);
228     g_object_unref (proxy);
229
230     if (!result)
231         g_warning ("Failed to open CK session: %s", error->message);
232     g_clear_error (&error);
233     if (!result)
234         return NULL;
235
236     if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(s)")))
237         g_variant_get (result, "(s)", &cookie);
238     else
239         g_warning ("Unexpected response from OpenSessionWithParameters: %s", g_variant_get_type_string (result));
240     g_variant_unref (result);
241
242     if (cookie)
243         g_debug ("Opened ConsoleKit session %s", cookie);
244
245     return cookie;
246 }
247
248 static void
249 end_ck_session (const gchar *cookie)
250 {
251     GDBusProxy *proxy;
252     GVariant *result;
253     GError *error = NULL;
254
255     if (!cookie)
256         return;
257
258     g_debug ("Ending ConsoleKit session %s", cookie);
259
260     proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
261                                            G_DBUS_PROXY_FLAGS_NONE,
262                                            NULL,
263                                            "org.freedesktop.ConsoleKit",
264                                            "/org/freedesktop/ConsoleKit/Manager",
265                                            "org.freedesktop.ConsoleKit.Manager", 
266                                            NULL, NULL);
267     result = g_dbus_proxy_call_sync (proxy,
268                                      "CloseSession",
269                                      g_variant_new ("(s)", cookie),
270                                      G_DBUS_CALL_FLAGS_NONE,
271                                      -1,
272                                      NULL,
273                                      &error);
274     g_object_unref (proxy);
275
276     if (!result)
277         g_warning ("Error ending ConsoleKit session: %s", error->message);
278     g_clear_error (&error);
279     if (!result)
280         return;
281
282     if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(b)")))
283     {
284         gboolean is_closed;
285         g_variant_get (result, "(b)", &is_closed);
286         if (!is_closed)
287             g_warning ("ConsoleKit.Manager.CloseSession() returned false");
288     }
289     else
290         g_warning ("Unexpected response from CloseSession: %s", g_variant_get_type_string (result));
291
292     g_variant_unref (result);
293 }
294
295 static void
296 set_env_from_pam_session (Session *session, PAMSession *pam_session)
297 {
298     gchar **pam_env;
299
300     pam_env = pam_session_get_envlist (pam_session);
301     if (pam_env)
302     {
303         gchar *env_string;      
304         int i;
305
306         env_string = g_strjoinv (" ", pam_env);
307         g_debug ("PAM returns environment '%s'", env_string);
308         g_free (env_string);
309
310         for (i = 0; pam_env[i]; i++)
311         {
312             gchar **pam_env_vars = g_strsplit (pam_env[i], "=", 2);
313             if (pam_env_vars && pam_env_vars[0] && pam_env_vars[1])
314                 child_process_set_env (CHILD_PROCESS (session), pam_env_vars[0], pam_env_vars[1]);
315             else
316                 g_warning ("Can't parse PAM environment variable %s", pam_env[i]);
317             g_strfreev (pam_env_vars);
318         }
319         g_strfreev (pam_env);
320     }
321 }
322
323 static void
324 session_exited_cb (Session *session, gint status, Display *display)
325 {
326     if (status != 0)
327         g_debug ("Session exited with value %d", status);
328 }
329
330 static void
331 session_terminated_cb (Session *session, gint signum, Display *display)
332 {
333     g_debug ("Session terminated with signal %d", signum);
334 }
335
336 static void
337 check_stopped (Display *display)
338 {
339     if (display->priv->stopping &&
340         display->priv->display_server == NULL &&
341         display->priv->session == NULL)
342     {
343         g_debug ("Display stopped");
344         g_signal_emit (display, signals[STOPPED], 0);
345     }
346 }
347
348 static void
349 session_stopped_cb (Session *session, Display *display)
350 {
351     if (display->priv->greeter)
352         g_debug ("Greeter quit");
353     else
354         g_debug ("Session quit");
355
356     if (display->priv->greeter_quit_timeout)
357         g_source_remove (display->priv->greeter_quit_timeout);
358     display->priv->greeter_quit_timeout = 0;
359
360     /* Stop listening to events from the greeter */
361     if (display->priv->greeter)
362         g_signal_handlers_disconnect_matched (display->priv->greeter, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
363
364     /* If a guest account, remove the account on exit */
365     if (g_strcmp0 (pam_session_get_username (display->priv->pam_session), guest_account_get_username ()) == 0)
366         guest_account_unref ();
367
368     g_signal_handlers_disconnect_matched (session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
369
370     if (getuid () == 0)
371         end_ck_session (session_get_cookie (session));
372
373     pam_session_end (display->priv->pam_session);
374     g_object_unref (display->priv->pam_session);
375     display->priv->pam_session = NULL;
376
377     g_object_unref (display->priv->session);
378     display->priv->session = NULL;
379
380     if (display->priv->stopping)
381     {
382         check_stopped (display);
383         return;
384     }
385
386     /* Restart the X server or start a new one if it failed */
387     if (!display_server_restart (display->priv->display_server))
388     {
389         g_debug ("Starting new display server");
390         display_server_start (display->priv->display_server);
391     }
392 }
393
394 static Session *
395 create_session (Display *display, PAMSession *pam_session, const gchar *session_name, gboolean is_greeter, const gchar *log_filename)
396 {
397     User *user;
398     gchar *xsessions_dir, *filename, *path, *command;
399     GKeyFile *session_desktop_file;
400     Session *session;
401     gchar *cookie;
402     gboolean result;
403     GError *error = NULL;
404
405     /* Can't be any session running already */
406     g_return_val_if_fail (display->priv->session == NULL, FALSE);
407     g_return_val_if_fail (display->priv->pam_session == NULL, FALSE);
408
409     user = user_get_by_name (pam_session_get_username (pam_session));
410     g_return_val_if_fail (user != NULL, FALSE);
411
412     g_debug ("Starting session %s as user %s logging to %s", session_name, user_get_name (user), log_filename);
413
414     xsessions_dir = config_get_string (config_get_instance (), "Directories", "xsessions-directory");
415     filename = g_strdup_printf ("%s.desktop", session_name);
416     path = g_build_filename (xsessions_dir, filename, NULL);
417     g_free (xsessions_dir);
418     g_free (filename);
419
420     session_desktop_file = g_key_file_new ();
421     result = g_key_file_load_from_file (session_desktop_file, path, G_KEY_FILE_NONE, &error);
422     if (!result)
423         g_warning ("Failed to load session file %s: %s:", path, error->message);
424     g_free (path);
425     g_clear_error (&error);
426     if (!result)
427         return NULL;
428     command = g_key_file_get_string (session_desktop_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL);
429     g_key_file_free (session_desktop_file);
430
431     if (!command)
432     {
433         g_warning ("No command in session file %s", path);
434         return NULL;
435     }
436     if (display->priv->session_wrapper)
437     {
438         gchar *t = command;
439         command = g_strdup_printf ("%s '%s'", display->priv->session_wrapper, command);
440         g_free (t);
441     }
442
443     session = DISPLAY_GET_CLASS (display)->create_session (display);
444     g_return_val_if_fail (session != NULL, NULL);
445     g_signal_connect (session, "exited", G_CALLBACK (session_exited_cb), display);
446     g_signal_connect (session, "terminated", G_CALLBACK (session_terminated_cb), display);
447     g_signal_connect (session, "stopped", G_CALLBACK (session_stopped_cb), display);
448     session_set_is_greeter (session, is_greeter);
449     session_set_user (session, user);
450     session_set_command (session, command);
451
452     child_process_set_env (CHILD_PROCESS (session), "DESKTOP_SESSION", session_name); // FIXME: Apparently deprecated?
453     child_process_set_env (CHILD_PROCESS (session), "GDMSESSION", session_name); // FIXME: Not cross-desktop
454
455     pam_session_authorize (pam_session);
456     set_env_from_pam_session (session, pam_session);
457
458     child_process_set_log_file (CHILD_PROCESS (session), log_filename);
459
460     /* Open ConsoleKit session */
461     if (getuid () == 0)
462     {
463         cookie = start_ck_session (display, is_greeter ? "LoginWindow" : "", user);
464         session_set_cookie (session, cookie);
465         g_free (cookie);
466     }
467     else
468         session_set_cookie (session, g_getenv ("XDG_SESSION_COOKIE"));
469
470     /* Connect using the session bus */
471     if (getuid () != 0)
472     {
473         child_process_set_env (CHILD_PROCESS (session), "DBUS_SESSION_BUS_ADDRESS", g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
474         child_process_set_env (CHILD_PROCESS (session), "LDM_BUS", "SESSION");
475         child_process_set_env (CHILD_PROCESS (session), "LD_LIBRARY_PATH", g_getenv ("LD_LIBRARY_PATH"));
476         child_process_set_env (CHILD_PROCESS (session), "PATH", g_getenv ("PATH"));
477     }
478
479     /* Variables required for regression tests */
480     if (g_getenv ("LIGHTDM_TEST_STATUS_SOCKET"))
481     {
482         child_process_set_env (CHILD_PROCESS (session), "LIGHTDM_TEST_STATUS_SOCKET", g_getenv ("LIGHTDM_TEST_STATUS_SOCKET"));
483         child_process_set_env (CHILD_PROCESS (session), "LIGHTDM_TEST_CONFIG", g_getenv ("LIGHTDM_TEST_CONFIG"));
484         child_process_set_env (CHILD_PROCESS (session), "LIGHTDM_TEST_HOME_DIR", g_getenv ("LIGHTDM_TEST_HOME_DIR"));
485         child_process_set_env (CHILD_PROCESS (session), "LD_LIBRARY_PATH", g_getenv ("LD_LIBRARY_PATH"));
486     }
487  
488     return session;
489 }
490
491 static gboolean
492 start_session (Display *display, Session *session, PAMSession *pam_session)
493 {
494     gboolean result;
495
496     result = session_start (SESSION (session));
497
498     if (result)
499     {
500         display->priv->session = g_object_ref (session);
501         display->priv->pam_session = g_object_ref (pam_session);
502     }
503     else
504         g_signal_handlers_disconnect_matched (display->priv->session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
505
506     return result;
507 }
508
509 static void
510 autologin_pam_message_cb (PAMSession *session, int num_msg, const struct pam_message **msg, Display *display)
511 {
512     g_debug ("Aborting automatic login as PAM requests input");
513     pam_session_cancel (session);
514 }
515
516 static void
517 autologin_authentication_result_cb (PAMSession *session, int result, Display *display)
518 {
519     if (!display->priv->stopping)
520     {
521         if (result == PAM_SUCCESS)
522         {
523             g_debug ("User %s authorized", pam_session_get_username (session));
524
525             if (activate_user (display, pam_session_get_username (session)))
526                 return;
527
528             pam_session_authorize (session);
529             start_user_session (display, session, display->priv->default_session);
530         }
531         else
532         {
533             g_debug ("Autologin failed authorization, starting greeter");
534
535             /* Start greeter and select user that failed */
536             display->priv->default_user_requires_password = TRUE;
537             start_greeter_session (display);
538         }
539     }
540
541     g_object_unref (session);
542 }
543
544 static gboolean
545 quit_timeout_cb (gpointer data)
546 {
547     Display *display = data;
548
549     g_debug ("Greeter did not quit, sending kill signal");
550     session_stop (display->priv->session);
551
552     display->priv->greeter_quit_timeout = 0;
553     return TRUE;
554 }
555
556 static gboolean
557 greeter_start_session_cb (Greeter *greeter, const gchar *session, gboolean is_guest, Display *display)
558 {
559     PAMSession *pam_session;
560     const gchar *username = NULL;
561
562     pam_session = greeter_get_pam_session (display->priv->greeter);
563     if (!is_guest && !pam_session_get_in_session (pam_session))
564     {
565         g_warning ("Ignoring request for login with unauthenticated user");
566         return FALSE;
567     }
568
569     /* Open guest account */
570     if (is_guest)
571     {
572         if (!guest_account_ref ())
573         {
574             g_debug ("Failed to create guest account, aborting login");
575             return FALSE;
576         }
577     }
578
579     /* Default session requested */
580     if (!session)
581         session = display->priv->default_session;
582     g_free (display->priv->user_session);
583     display->priv->user_session = g_strdup (session);
584
585     /* Stop this display if can switch to that user */
586     username = pam_session_get_username (pam_session);
587     if (activate_user (display, username))
588         display_stop (display);
589     else
590     {
591         greeter_quit (display->priv->greeter);
592         if (display->priv->greeter_quit_timeout)
593             g_source_remove (display->priv->greeter_quit_timeout);
594         display->priv->greeter_quit_timeout = g_timeout_add (GREETER_QUIT_TIMEOUT, quit_timeout_cb, display);
595     }
596
597     return TRUE;
598 }
599
600 static gboolean
601 start_greeter_session (Display *display)
602 {
603     User *user;
604     const gchar *autologin_user = NULL;
605     gchar *log_dir, *filename, *log_filename;
606     Session *session;
607     PAMSession *pam_session;
608     gboolean result;
609
610     g_debug ("Starting greeter session");
611
612     /* If have user then automatically login the first time */
613     if (display->priv->default_user_is_guest)
614     {
615         autologin_user = guest_account_get_username ();
616         guest_account_ref ();
617     }
618     else if (display->priv->default_user)
619         autologin_user = display->priv->default_user;
620
621     if (autologin_user && !display->priv->default_user_requires_password)
622     {
623         GError *error = NULL;
624         PAMSession *autologin_pam_session;
625  
626         /* Run using autologin PAM session, abort if get asked any questions */      
627         g_debug ("Automatically logging in user %s", autologin_user);
628
629         autologin_pam_session = pam_session_new (display->priv->pam_autologin_service, autologin_user);
630         g_signal_connect (autologin_pam_session, "got-messages", G_CALLBACK (autologin_pam_message_cb), display);
631         g_signal_connect (autologin_pam_session, "authentication-result", G_CALLBACK (autologin_authentication_result_cb), display);
632         if (pam_session_start (autologin_pam_session, &error))
633             return TRUE;
634         else
635         {
636             g_object_unref (autologin_pam_session);
637             g_warning ("Failed to autologin user %s, starting greeter instead: %s", autologin_user, error->message);
638         }
639         g_clear_error (&error);
640     }
641
642     if (display->priv->greeter_user)
643     {
644         user = user_get_by_name (display->priv->greeter_user);
645         if (!user)
646         {
647             g_warning ("Unable to start greeter, user %s does not exist", display->priv->greeter_user);
648             return FALSE;
649         }
650     }
651     else
652         user = user_get_current ();
653     pam_session = pam_session_new (display->priv->pam_service, user_get_name (user));
654     pam_session_authorize (pam_session);
655     g_object_unref (user);
656
657     log_dir = config_get_string (config_get_instance (), "Directories", "log-directory");
658     // FIXME: May not be an X server
659     filename = g_strdup_printf ("%s-greeter.log", xserver_get_address (XSERVER (display->priv->display_server)));
660     log_filename = g_build_filename (log_dir, filename, NULL);
661     g_free (log_dir);
662     g_free (filename);
663
664     session = create_session (display, pam_session, display->priv->greeter_session, TRUE, log_filename);
665     g_free (log_filename);
666
667     display->priv->greeter = greeter_new (session);
668     g_signal_connect (G_OBJECT (display->priv->greeter), "start-session", G_CALLBACK (greeter_start_session_cb), display);
669     if (display->priv->default_user_timeout)
670     {
671         gchar *value = g_strdup_printf ("%d", display->priv->default_user_timeout);
672         greeter_set_hint (display->priv->greeter, "autologin-timeout", value);
673         g_free (value);
674         if (display->priv->default_user)
675             greeter_set_hint (display->priv->greeter, "autologin-user", display->priv->default_user);
676         else if (display->priv->default_user_is_guest)
677             greeter_set_hint (display->priv->greeter, "autologin-guest", "true");        
678     }
679     else if (display->priv->default_user)
680         greeter_set_hint (display->priv->greeter, "select-user", display->priv->default_user);
681     else if (display->priv->default_user_is_guest)
682         greeter_set_hint (display->priv->greeter, "select-guest", "true");
683     greeter_set_hint (display->priv->greeter, "default-session", display->priv->default_session);
684     greeter_set_hint (display->priv->greeter, "has-guest-account", guest_account_get_is_enabled () ? "true" : "false");
685     greeter_set_hint (display->priv->greeter, "hide-users", display->priv->greeter_hide_users ? "true" : "false");
686
687     result = greeter_start (display->priv->greeter);
688     if (result)
689     {
690         result = start_session (display, session, pam_session);
691         if (!result)
692         {
693             g_debug ("Failed to start greeter session");
694             g_object_unref (session);
695         }
696     }
697     else
698     {
699         g_debug ("Failed to start greeter protocol");
700
701         g_signal_handlers_disconnect_matched (display->priv->greeter, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
702         g_object_unref (display->priv->greeter);
703         display->priv->greeter = NULL;
704       
705         g_object_unref (session);
706     }
707
708     g_object_unref (pam_session);
709
710     return result;
711 }
712
713 static gboolean
714 start_user_session (Display *display, PAMSession *pam_session, const gchar *name)
715 {
716     GKeyFile *dmrc_file;
717     User *user;
718     gchar *log_filename;
719     Session *session;
720     gboolean result;
721
722     g_debug ("Starting user session");
723
724     user = user_get_by_name (pam_session_get_username (pam_session));
725     if (!user)
726     {
727         g_warning ("Unable to start session, user %s does not exist", pam_session_get_username (pam_session));
728         return FALSE;
729     }
730
731     /* Load the users login settings (~/.dmrc) */
732     dmrc_file = dmrc_load (user_get_name (user));
733
734     /* Update the .dmrc with changed settings */
735     g_key_file_set_string (dmrc_file, "Desktop", "Session", name);
736
737     /* Save modified DMRC */
738     dmrc_save (dmrc_file, pam_session_get_username (pam_session));
739     g_key_file_free (dmrc_file);
740
741     /* Once logged in, don't autologin again */
742     g_free (display->priv->default_user);
743     display->priv->default_user = NULL;
744     display->priv->default_user_is_guest = FALSE;
745
746     // FIXME: Copy old error file  
747     log_filename = g_build_filename (user_get_home_directory (user), ".xsession-errors", NULL);
748     g_object_unref (user);
749
750     session = create_session (display, pam_session, name, FALSE, log_filename);
751     g_free (log_filename);
752   
753     if (session)
754         result = start_session (display, session, pam_session);
755     else
756     {
757         result = FALSE;
758         g_object_unref (session);
759     }
760
761     return result;
762 }
763
764 static void
765 display_server_stopped_cb (DisplayServer *server, Display *display)
766 {
767     if (display->priv->stopping)
768     {
769         g_object_unref (display->priv->display_server);
770         display->priv->display_server = NULL;
771         check_stopped (display);
772     }
773     else
774     {
775         /* Stop the session then start a new X server */
776         if (display->priv->session)
777         {
778             g_debug ("Stopping session");
779             child_process_stop (CHILD_PROCESS (display->priv->session));
780         }
781         else
782         {
783             g_debug ("Starting new display server");
784             display_server_start (display->priv->display_server);
785         }
786     }
787 }
788
789 static void
790 display_server_ready_cb (DisplayServer *display_server, Display *display)
791 {
792     PAMSession *pam_session = NULL;
793     gboolean result = FALSE;
794
795     /* Don't run any sessions on local terminals */
796     // FIXME: Make display_server_get_has_local_session
797     if (IS_XSERVER_LOCAL (display_server) && xserver_local_get_xdmcp_server (XSERVER_LOCAL (display_server)))
798         return;
799
800     /* If have had the greeter running then start a user session */
801     if (display->priv->greeter &&
802         greeter_get_pam_session (display->priv->greeter) &&
803         pam_session_get_in_session (greeter_get_pam_session (display->priv->greeter)) &&
804         display->priv->user_session)
805         pam_session = g_object_ref (greeter_get_pam_session (display->priv->greeter));
806
807     if (display->priv->greeter)
808     {
809         g_signal_handlers_disconnect_matched (display->priv->greeter, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
810         g_object_unref (display->priv->greeter);
811         display->priv->greeter = NULL;
812     }
813
814     if (pam_session)
815     {
816         result = start_user_session (display, pam_session, display->priv->user_session);
817         if (!result)
818             g_debug ("Failed to start user session, starting greeter");
819         g_object_unref (pam_session);
820     }
821
822     if (!result)
823         start_greeter_session (display);
824
825     g_free (display->priv->user_session);
826     display->priv->user_session = NULL;
827 }
828
829 gboolean
830 display_start (Display *display)
831 {
832     gboolean result;
833
834     g_return_val_if_fail (display != NULL, FALSE);
835
836     g_signal_connect (G_OBJECT (display->priv->display_server), "ready", G_CALLBACK (display_server_ready_cb), display);
837     g_signal_connect (G_OBJECT (display->priv->display_server), "stopped", G_CALLBACK (display_server_stopped_cb), display);
838     result = display_server_start (display->priv->display_server);
839   
840     g_signal_emit (display, signals[STARTED], 0);
841
842     return result;
843 }
844
845 void
846 display_stop (Display *display)
847 {
848     g_return_if_fail (display != NULL);
849
850     if (display->priv->stopping)
851         return;
852
853     g_debug ("Stopping display");
854
855     display->priv->stopping = TRUE;
856
857     if (display->priv->display_server)
858         display_server_stop (display->priv->display_server);
859     if (display->priv->session)
860         session_stop (display->priv->session);
861
862     check_stopped (display);
863 }
864
865 static void
866 display_init (Display *display)
867 {
868     display->priv = G_TYPE_INSTANCE_GET_PRIVATE (display, DISPLAY_TYPE, DisplayPrivate);
869     display->priv->pam_service = g_strdup ("lightdm");
870     display->priv->pam_autologin_service = g_strdup ("lightdm-autologin");
871 }
872
873 static Session *
874 display_create_session (Display *display)
875 {
876     return NULL;
877 }
878
879 static void
880 display_finalize (GObject *object)
881 {
882     Display *self;
883
884     self = DISPLAY (object);
885
886     g_object_unref (self->priv->display_server);
887     g_free (self->priv->greeter_user);
888     g_free (self->priv->greeter_session);
889     if (self->priv->greeter_quit_timeout)
890         g_source_remove (self->priv->greeter_quit_timeout);
891     if (self->priv->greeter)
892         g_object_unref (self->priv->greeter);
893     g_free (self->priv->session_wrapper);
894     g_free (self->priv->pam_service);
895     g_free (self->priv->pam_autologin_service);
896     if (self->priv->session)
897     {
898         if (session_get_cookie (self->priv->session))
899             end_ck_session (session_get_cookie (self->priv->session));
900         g_object_unref (self->priv->session);
901     }
902     if (self->priv->pam_session)
903         g_object_unref (self->priv->pam_session);
904     g_free (self->priv->default_user);
905     g_free (self->priv->default_session);
906     g_free (self->priv->user_session);
907
908     G_OBJECT_CLASS (display_parent_class)->finalize (object);
909 }
910
911 static void
912 display_class_init (DisplayClass *klass)
913 {
914     GObjectClass *object_class = G_OBJECT_CLASS (klass);
915
916     klass->create_session = display_create_session;
917     object_class->finalize = display_finalize;
918
919     g_type_class_add_private (klass, sizeof (DisplayPrivate));
920
921     signals[STARTED] =
922         g_signal_new ("started",
923                       G_TYPE_FROM_CLASS (klass),
924                       G_SIGNAL_RUN_LAST,
925                       G_STRUCT_OFFSET (DisplayClass, started),
926                       NULL, NULL,
927                       g_cclosure_marshal_VOID__VOID,
928                       G_TYPE_NONE, 0);
929     signals[ACTIVATE_USER] =
930         g_signal_new ("activate-user",
931                       G_TYPE_FROM_CLASS (klass),
932                       G_SIGNAL_RUN_LAST,
933                       G_STRUCT_OFFSET (DisplayClass, activate_user),
934                       g_signal_accumulator_true_handled,
935                       NULL,
936                       ldm_marshal_BOOLEAN__STRING,
937                       G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
938     signals[STOPPED] =
939         g_signal_new ("stopped",
940                       G_TYPE_FROM_CLASS (klass),
941                       G_SIGNAL_RUN_LAST,
942                       G_STRUCT_OFFSET (DisplayClass, stopped),
943                       NULL, NULL,
944                       g_cclosure_marshal_VOID__VOID,
945                       G_TYPE_NONE, 0);
946 }