]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - src/seat.c
Merge from trunk
[sojka/lightdm.git] / src / seat.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 <stdlib.h>
13 #include <string.h>
14 #include <sys/wait.h>
15
16 #include "seat.h"
17 #include "configuration.h"
18 #include "guest-account.h"
19 #include "greeter.h"
20 #include "session-config.h"
21
22 enum {
23     SESSION_ADDED,
24     RUNNING_USER_SESSION,
25     SESSION_REMOVED,
26     STOPPED,
27     LAST_SIGNAL
28 };
29 static guint signals[LAST_SIGNAL] = { 0 };
30
31 struct SeatPrivate
32 {
33     /* Configuration for this seat */
34     GHashTable *properties;
35
36     /* TRUE if able to switch users */
37     gboolean can_switch;
38
39     /* TRUE if display server can be shared for sessions */
40     gboolean share_display_server;
41
42     /* The display servers on this seat */
43     GList *display_servers;
44
45     /* The sessions on this seat */
46     GList *sessions;
47
48     /* The last session set to active */
49     Session *active_session;
50
51     /* The session belonging to the active greeter user */
52     Session *next_session;
53
54     /* The session to set active when it starts */
55     Session *session_to_activate;
56   
57     /* TRUE once we have started */
58     gboolean started;
59
60     /* TRUE if stopping this seat (waiting for displays to stop) */
61     gboolean stopping;
62
63     /* TRUE if stopped */
64     gboolean stopped;
65 };
66
67 /* PAM services to use */
68 #define GREETER_SERVICE   "lightdm-greeter"
69 #define USER_SERVICE      "lightdm"
70 #define AUTOLOGIN_SERVICE "lightdm-autologin"
71
72 static void seat_logger_iface_init (LoggerInterface *iface);
73
74 G_DEFINE_TYPE_WITH_CODE (Seat, seat, G_TYPE_OBJECT,
75                          G_IMPLEMENT_INTERFACE (
76                              LOGGER_TYPE, seat_logger_iface_init));
77
78 typedef struct
79 {
80     const gchar *name;
81     GType type;
82 } SeatModule;
83 static GHashTable *seat_modules = NULL;
84
85 // FIXME: Make a get_display_server() that re-uses display servers if supported
86 static DisplayServer *create_display_server (Seat *seat, const gchar *session_type);
87 static Greeter *create_greeter_session (Seat *seat);
88 static void start_session (Seat *seat, Session *session);
89
90 void
91 seat_register_module (const gchar *name, GType type)
92 {
93     SeatModule *module;
94
95     if (!seat_modules)
96         seat_modules = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
97
98     g_debug ("Registered seat module %s", name);
99
100     module = g_malloc0 (sizeof (SeatModule));
101     module->name = g_strdup (name);
102     module->type = type;
103     g_hash_table_insert (seat_modules, g_strdup (name), module);
104 }
105
106 Seat *
107 seat_new (const gchar *module_name)
108 {
109     Seat *seat;
110     SeatModule *m = NULL;
111   
112     g_return_val_if_fail (module_name != NULL, NULL);
113
114     if (seat_modules)
115         m = g_hash_table_lookup (seat_modules, module_name);
116     if (!m)
117         return NULL;
118
119     seat = g_object_new (m->type, NULL);
120
121     return seat;
122 }
123
124 void
125 seat_set_property (Seat *seat, const gchar *name, const gchar *value)
126 {
127     g_return_if_fail (seat != NULL);
128     g_hash_table_insert (seat->priv->properties, g_strdup (name), g_strdup (value));
129 }
130
131 const gchar *
132 seat_get_string_property (Seat *seat, const gchar *name)
133 {
134     g_return_val_if_fail (seat != NULL, NULL);
135     return g_hash_table_lookup (seat->priv->properties, name);
136 }
137
138 gboolean
139 seat_get_boolean_property (Seat *seat, const gchar *name)
140 {
141     return g_strcmp0 (seat_get_string_property (seat, name), "true") == 0;
142 }
143
144 gint
145 seat_get_integer_property (Seat *seat, const gchar *name)
146 {
147     const gchar *value;
148
149     value = seat_get_string_property (seat, name);
150     return value ? atoi (value) : 0;
151 }
152
153 void
154 seat_set_can_switch (Seat *seat, gboolean can_switch)
155 {
156     g_return_if_fail (seat != NULL);
157
158     seat->priv->can_switch = can_switch;
159 }
160
161 void
162 seat_set_share_display_server (Seat *seat, gboolean share_display_server)
163 {
164     g_return_if_fail (seat != NULL);
165
166     seat->priv->share_display_server = share_display_server;
167 }
168
169 gboolean
170 seat_start (Seat *seat)
171 {
172     g_return_val_if_fail (seat != NULL, FALSE);
173   
174     SEAT_GET_CLASS (seat)->setup (seat);
175     return SEAT_GET_CLASS (seat)->start (seat);
176 }
177
178 GList *
179 seat_get_sessions (Seat *seat)
180 {
181     g_return_val_if_fail (seat != NULL, NULL);
182     return seat->priv->sessions;
183 }
184
185 void
186 seat_set_active_session (Seat *seat, Session *session)
187 {
188     GList *link;
189
190     g_return_if_fail (seat != NULL);
191
192     SEAT_GET_CLASS (seat)->set_active_session (seat, session);
193
194     /* Stop any greeters */
195     for (link = seat->priv->sessions; link; link = link->next)
196     {
197         Session *s = link->data;
198
199         if (s == session || session_get_is_stopping (s))
200             continue;
201
202         if (IS_GREETER (s))
203         {
204             l_debug (seat, "Stopping greeter");
205             session_stop (s);
206         }
207     }
208
209     /* Lock previous sessions */
210     if (seat->priv->active_session)
211     {
212         if (session != seat->priv->active_session && !IS_GREETER (seat->priv->active_session))
213             session_lock (seat->priv->active_session);
214         g_object_unref (seat->priv->active_session);
215     }
216     seat->priv->active_session = g_object_ref (session);
217 }
218
219 Session *
220 seat_get_active_session (Seat *seat)
221 {
222     g_return_val_if_fail (seat != NULL, NULL);
223     return SEAT_GET_CLASS (seat)->get_active_session (seat);
224 }
225
226 Session *
227 seat_get_next_session (Seat *seat)
228 {
229     g_return_val_if_fail (seat != NULL, NULL);
230     return seat->priv->next_session;
231 }
232
233 gboolean
234 seat_get_can_switch (Seat *seat)
235 {
236     g_return_val_if_fail (seat != NULL, FALSE);
237     return seat->priv->can_switch;
238 }
239
240 gboolean
241 seat_get_allow_guest (Seat *seat)
242 {
243     g_return_val_if_fail (seat != NULL, FALSE);
244     return seat_get_boolean_property (seat, "allow-guest") && guest_account_is_installed ();
245 }
246
247 static gboolean
248 run_script (Seat *seat, DisplayServer *display_server, const gchar *script_name, User *user)
249 {
250     Process *script;
251     gboolean result = FALSE;
252   
253     script = process_new ();
254
255     process_set_command (script, script_name);
256
257     /* Set POSIX variables */
258     process_set_clear_environment (script, TRUE);
259     process_set_env (script, "SHELL", "/bin/sh");
260
261     /* Variables required for regression tests */
262     if (g_getenv ("LIGHTDM_TEST_ROOT"))
263     {
264         process_set_env (script, "LIGHTDM_TEST_ROOT", g_getenv ("LIGHTDM_TEST_ROOT"));
265         process_set_env (script, "LD_PRELOAD", g_getenv ("LD_PRELOAD"));
266         process_set_env (script, "LD_LIBRARY_PATH", g_getenv ("LD_LIBRARY_PATH"));
267         process_set_env (script, "PATH", g_getenv ("PATH"));
268     }
269     else
270         process_set_env (script, "PATH", "/usr/local/bin:/usr/bin:/bin");
271
272     if (user)
273     {
274         process_set_env (script, "USER", user_get_name (user));
275         process_set_env (script, "LOGNAME", user_get_name (user));
276         process_set_env (script, "HOME", user_get_home_directory (user));
277     }
278     else
279         process_set_env (script, "HOME", "/");
280
281     SEAT_GET_CLASS (seat)->run_script (seat, display_server, script);
282
283     if (process_start (script, TRUE))
284     {
285         int exit_status;
286
287         exit_status = process_get_exit_status (script);
288         if (WIFEXITED (exit_status))
289         {
290             l_debug (seat, "Exit status of %s: %d", script_name, WEXITSTATUS (exit_status));
291             result = WEXITSTATUS (exit_status) == EXIT_SUCCESS;
292         }
293     }
294
295     g_object_unref (script);
296
297     return result;
298 }
299
300 static void
301 seat_real_run_script (Seat *seat, DisplayServer *display_server, Process *process)
302 {  
303 }
304
305 static void
306 emit_upstart_signal (const gchar *signal)
307 {
308     g_return_if_fail (signal != NULL);
309     g_return_if_fail (signal[0] != 0);
310
311     if (getuid () != 0)
312         return;
313
314     gchar *cmd = g_strdup_printf ("initctl -q emit %s DISPLAY_MANAGER=lightdm", signal);
315     g_spawn_command_line_async (cmd, NULL); /* OK if it fails, probably not installed */
316     g_free (cmd);
317 }
318
319 static void
320 check_stopped (Seat *seat)
321 {
322     if (seat->priv->stopping &&
323         !seat->priv->stopped &&
324         g_list_length (seat->priv->display_servers) == 0 &&
325         g_list_length (seat->priv->sessions) == 0)
326     {
327         seat->priv->stopped = TRUE;
328         l_debug (seat, "Stopped");
329         g_signal_emit (seat, signals[STOPPED], 0);
330     }
331 }
332
333 static gboolean
334 get_start_local_sessions (Seat *seat)
335 {
336     return SEAT_GET_CLASS (seat)->get_start_local_sessions (seat);
337 }
338
339 static void
340 display_server_stopped_cb (DisplayServer *display_server, Seat *seat)
341 {
342     GList *list, *link;
343     Session *active_session;
344
345     l_debug (seat, "Display server stopped");
346
347     g_signal_handlers_disconnect_matched (display_server, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, seat);
348     seat->priv->display_servers = g_list_remove (seat->priv->display_servers, display_server);
349
350     if (seat->priv->stopping || !seat->priv->started)
351     {
352         check_stopped (seat);
353         g_object_unref (display_server);
354         return;
355     }
356
357     /* Stop all sessions on this display server */
358     list = g_list_copy (seat->priv->sessions);
359     for (link = list; link; link = link->next)
360         g_object_ref (link->data);
361     for (link = list; link; link = link->next)
362     {
363         Session *session = link->data;
364
365         if (session_get_display_server (session) != display_server || session_get_is_stopping (session))
366             continue;
367
368         /* Stop seat if this is the only display server and it failed to start a greeter */
369         if (IS_GREETER (session) &&
370             !session_get_is_started (session) &&
371             g_list_length (seat->priv->display_servers) == 0)
372         {
373             l_debug (seat, "Stopping; greeter display server failed to start");
374             seat_stop (seat);
375         }
376
377         l_debug (seat, "Stopping session");
378         session_stop (session);
379     }
380     g_list_free_full (list, g_object_unref);
381
382     if (!seat->priv->stopping && get_start_local_sessions (seat))
383     {
384         /* If we were the active session, switch to a greeter */
385         active_session = seat_get_active_session (seat);
386         if (!active_session || session_get_display_server (active_session) == display_server)
387         {
388             l_debug (seat, "Active display server stopped, starting greeter");
389             seat_switch_to_greeter (seat);
390         }
391     }
392
393     g_object_unref (display_server);
394 }
395
396 static gboolean
397 can_share_display_server (Seat *seat, DisplayServer *display_server)
398 {
399     return seat->priv->share_display_server && display_server_get_can_share (display_server);
400 }
401
402 static void
403 switch_to_greeter_from_failed_session (Seat *seat, Session *session)
404 {
405     Greeter *greeter_session;
406
407     greeter_session = create_greeter_session (seat);
408     if (session_get_is_guest (session))
409         greeter_set_hint (greeter_session, "select-guest", "true");
410     else
411         greeter_set_hint (greeter_session, "select-user", session_get_username (session));
412     if (seat->priv->session_to_activate)
413         g_object_unref (seat->priv->session_to_activate);
414     seat->priv->session_to_activate = g_object_ref (greeter_session);
415
416     if (can_share_display_server (seat, session_get_display_server (session)))
417         session_set_display_server (SESSION (greeter_session), session_get_display_server (session));
418     else
419     {
420         DisplayServer *display_server;
421
422         display_server = create_display_server (seat, session_get_session_type (session));
423         if (!display_server_start (display_server))
424         {
425             l_debug (seat, "Failed to start display server for greeter");
426             seat_stop (seat);
427         }
428
429         session_set_display_server (session, display_server);
430     }
431
432     start_session (seat, SESSION (greeter_session));
433
434     /* Stop failed session */
435     session_stop (session);
436 }
437
438 static void
439 start_session (Seat *seat, Session *session)
440 {
441     /* Use system location for greeter log file */
442     if (IS_GREETER (session))
443     {
444         gchar *log_dir, *filename, *log_filename;
445
446         log_dir = config_get_string (config_get_instance (), "LightDM", "log-directory");
447         filename = g_strdup_printf ("%s-greeter.log", display_server_get_name (session_get_display_server (session)));
448         log_filename = g_build_filename (log_dir, filename, NULL);
449         g_free (log_dir);
450         g_free (filename);
451         session_set_log_file (session, log_filename);
452         g_free (log_filename);
453     }
454
455     if (session_start (session))
456         return;
457
458     if (IS_GREETER (session))
459     {
460         l_debug (seat, "Failed to start greeter");
461         display_server_stop (session_get_display_server (session));
462         return;
463     }
464
465     l_debug (seat, "Failed to start session, starting greeter");
466     switch_to_greeter_from_failed_session (seat, session);
467 }
468
469 static void
470 run_session (Seat *seat, Session *session)
471 {
472     const gchar *script;
473
474     if (IS_GREETER (session))
475         script = seat_get_string_property (seat, "greeter-setup-script");
476     else
477         script = seat_get_string_property (seat, "session-setup-script");
478     if (script && !run_script (seat, session_get_display_server (session), script, NULL))
479     {
480         l_debug (seat, "Switching to greeter due to failed setup script");
481         switch_to_greeter_from_failed_session (seat, session);
482         return;
483     }
484
485     if (!IS_GREETER (session))
486     {
487         g_signal_emit (seat, signals[RUNNING_USER_SESSION], 0, session);
488         emit_upstart_signal ("desktop-session-start");
489     }
490
491     session_run (session);
492
493     // FIXME: Wait until the session is ready
494
495     if (session == seat->priv->session_to_activate)
496     {
497         seat_set_active_session (seat, session);
498         g_object_unref (seat->priv->session_to_activate);
499         seat->priv->session_to_activate = NULL;
500     }
501 }
502
503 static Session *
504 find_user_session (Seat *seat, const gchar *username, Session *ignore_session)
505 {
506     GList *link;
507
508     if (!username)
509         return NULL;
510
511     for (link = seat->priv->sessions; link; link = link->next)
512     {
513         Session *session = link->data;
514
515         if (session == ignore_session)
516             continue;
517
518         if (!session_get_is_stopping (session) && g_strcmp0 (session_get_username (session), username) == 0)
519             return session;
520     }
521
522     return NULL;
523 }
524
525 static void
526 greeter_active_username_changed_cb (Greeter *greeter, GParamSpec *pspec, Seat *seat)
527 {
528     Session *session;
529
530     session = find_user_session (seat, greeter_get_active_username (greeter), seat->priv->active_session);
531     if (session)
532     {
533         if (seat->priv->next_session)
534             g_object_unref (seat->priv->next_session);
535         seat->priv->next_session = g_object_ref (session);
536
537         SEAT_GET_CLASS (seat)->set_next_session (seat, session);
538     }
539 }
540
541 static void
542 session_authentication_complete_cb (Session *session, Seat *seat)
543 {
544     if (session_get_is_authenticated (session))
545     {
546         Session *s;
547
548         s = find_user_session (seat, session_get_username (session), session);
549         if (s)
550         {
551             l_debug (seat, "Session authenticated, switching to existing user session");
552             seat_set_active_session (seat, s);
553             session_stop (session);
554         }
555         else
556         {
557             l_debug (seat, "Session authenticated, running command");
558             run_session (seat, session);
559         }
560     }
561     else if (!IS_GREETER (session))
562     {
563         l_debug (seat, "Switching to greeter due to failed authentication");
564         switch_to_greeter_from_failed_session (seat, session);
565     }
566     else
567     {
568         l_debug (seat, "Stopping session that failed authentication");
569         session_stop (session);
570     }
571 }
572
573 static void
574 session_stopped_cb (Session *session, Seat *seat)
575 {
576     DisplayServer *display_server;
577
578     l_debug (seat, "Session stopped");
579
580     g_signal_handlers_disconnect_matched (session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, seat);
581     seat->priv->sessions = g_list_remove (seat->priv->sessions, session);
582     if (session == seat->priv->active_session)
583     {
584         g_object_unref (seat->priv->active_session);
585         seat->priv->active_session = NULL;
586     }
587     if (session == seat->priv->next_session)
588     {
589         g_object_unref (seat->priv->next_session);
590         seat->priv->next_session = NULL;
591     }
592     if (session == seat->priv->session_to_activate)
593     {
594         g_object_unref (seat->priv->session_to_activate);
595         seat->priv->session_to_activate = NULL;
596     }
597
598     display_server = session_get_display_server (session);
599     if (!display_server)
600     {
601         g_object_unref (session);
602         return;
603     }
604
605     /* Cleanup */
606     if (!IS_GREETER (session))
607     {
608         const gchar *script;
609         script = seat_get_string_property (seat, "session-cleanup-script");
610         if (script)
611             run_script (seat, display_server, script, session_get_user (session));
612     }
613
614     /* We were waiting for this session, but it didn't start :( */
615     // FIXME: Start a greeter on this?
616     if (session == seat->priv->session_to_activate)
617     {
618         g_object_unref (seat->priv->session_to_activate);
619         seat->priv->session_to_activate = NULL;
620     }
621
622     if (seat->priv->stopping)
623     {
624         check_stopped (seat);
625         g_object_unref (session);
626         return;
627     }
628
629     /* If this is the greeter session then re-use this display server */
630     if (IS_GREETER (session) &&
631         can_share_display_server (seat, display_server) &&
632         greeter_get_start_session (GREETER (session)))
633     {
634         GList *link;
635
636         for (link = seat->priv->sessions; link; link = link->next)
637         {
638             Session *s = link->data;
639
640             /* Skip this session and sessions on other display servers */
641             if (s == session || session_get_display_server (s) != display_server || session_get_is_stopping (s))
642                 continue;
643
644             if (session_get_is_authenticated (s))
645             {
646                 l_debug (seat, "Greeter stopped, running session");
647                 run_session (seat, s);
648             }
649             else
650             {
651                 l_debug (seat, "Greeter stopped, starting session authentication");
652                 start_session (seat, s);
653             }
654             break;
655         }
656     }
657     /* If this is the greeter and nothing else is running then stop the seat */
658     else if (IS_GREETER (session) &&
659         !greeter_get_start_session (GREETER (session)) &&
660         g_list_length (seat->priv->display_servers) == 1 &&
661         g_list_nth_data (seat->priv->display_servers, 0) == display_server)
662     {
663         l_debug (seat, "Stopping; failed to start a greeter");
664         seat_stop (seat);
665     }
666     /* If we were the active session, switch to a greeter */
667     else if (!IS_GREETER (session) && session == seat_get_active_session (seat))
668     {
669         l_debug (seat, "Active session stopped, starting greeter");
670         seat_switch_to_greeter (seat);
671     }
672
673     /* Stop the display server if no-longer required */
674     if (display_server && !display_server_get_is_stopping (display_server))
675     {
676         GList *link;
677         int n_sessions = 0;
678
679         for (link = seat->priv->sessions; link; link = link->next)
680         {
681             Session *s = link->data;
682             if (s == session)
683                 continue;
684             if (session_get_display_server (s) == display_server)
685                 n_sessions++;
686         }
687         if (n_sessions == 0)
688         {
689             l_debug (seat, "Stopping display server, no sessions require it");
690             display_server_stop (display_server);
691         }
692     }
693
694     g_signal_emit (seat, signals[SESSION_REMOVED], 0, session);
695     g_object_unref (session);
696 }
697
698 static void
699 set_session_env (Session *session)
700 {
701     /* Connect using the session bus */
702     if (getuid () != 0)
703     {
704         if (g_getenv ("DBUS_SESSION_BUS_ADDRESS"))
705             session_set_env (session, "DBUS_SESSION_BUS_ADDRESS", g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
706         session_set_env (session, "LDM_BUS", "SESSION");
707         if (g_getenv ("LD_PRELOAD"))
708             session_set_env (session, "LD_PRELOAD", g_getenv ("LD_PRELOAD"));
709         if (g_getenv ("LD_LIBRARY_PATH"))
710             session_set_env (session, "LD_LIBRARY_PATH", g_getenv ("LD_LIBRARY_PATH"));
711         if (g_getenv ("PATH"))
712             session_set_env (session, "PATH", g_getenv ("PATH"));
713     }
714
715     /* Variables required for regression tests */
716     if (g_getenv ("LIGHTDM_TEST_ROOT"))
717     {
718         session_set_env (session, "LIGHTDM_TEST_ROOT", g_getenv ("LIGHTDM_TEST_ROOT"));
719         session_set_env (session, "DBUS_SYSTEM_BUS_ADDRESS", g_getenv ("DBUS_SYSTEM_BUS_ADDRESS"));
720         session_set_env (session, "DBUS_SESSION_BUS_ADDRESS", g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
721         session_set_env (session, "LD_PRELOAD", g_getenv ("LD_PRELOAD"));
722         session_set_env (session, "LD_LIBRARY_PATH", g_getenv ("LD_LIBRARY_PATH"));
723         session_set_env (session, "GI_TYPELIB_PATH", g_getenv ("GI_TYPELIB_PATH"));
724     }
725 }
726
727 static Session *
728 create_session (Seat *seat, gboolean autostart, const gchar *username)
729 {
730     Session *session;
731     Session *user_session;
732
733     user_session = find_user_session (seat, username, NULL);
734     session = SEAT_GET_CLASS (seat)->create_session (seat, user_session);
735     seat->priv->sessions = g_list_append (seat->priv->sessions, session);
736     if (autostart)
737         g_signal_connect (session, "authentication-complete", G_CALLBACK (session_authentication_complete_cb), seat);
738     g_signal_connect (session, "stopped", G_CALLBACK (session_stopped_cb), seat);
739
740     set_session_env (session);
741
742     g_signal_emit (seat, signals[SESSION_ADDED], 0, session);
743
744     return session;
745 }
746
747 static gchar **
748 get_session_argv (Seat *seat, SessionConfig *session_config, const gchar *session_wrapper)
749 {
750     gboolean result;
751     int argc;
752     gchar **argv, *path;
753     GError *error = NULL;
754
755     /* If configured, run sessions through a wrapper */
756     if (session_wrapper)
757     {
758         argv = g_malloc (sizeof (gchar *) * 3);
759         path = g_find_program_in_path (session_wrapper);
760         argv[0] = path ? path : g_strdup (session_wrapper);
761         argv[1] = g_strdup (session_config_get_command (session_config));
762         argv[2] = NULL;
763         return argv;
764     }
765
766     /* Split command into an array listing and make command absolute */
767     result = g_shell_parse_argv (session_config_get_command (session_config), &argc, &argv, &error);
768     if (error)
769         l_debug (seat, "Invalid session command '%s': %s", session_config_get_command (session_config), error->message);
770     g_clear_error (&error);
771     if (!result)
772         return NULL;
773     path = g_find_program_in_path (argv[0]);
774     if (path)
775     {
776         g_free (argv[0]);
777         argv[0] = path;
778     }
779   
780     return argv;
781 }
782
783 static SessionConfig *
784 find_session_config (Seat *seat, const gchar *sessions_dir, const gchar *session_name)
785 {
786     gchar **dirs;
787     SessionConfig *session_config = NULL;
788     int i;
789     GError *error = NULL;
790
791     g_return_val_if_fail (sessions_dir != NULL, NULL);
792     g_return_val_if_fail (session_name != NULL, NULL);
793
794     dirs = g_strsplit (sessions_dir, ":", -1);
795     for (i = 0; dirs[i]; i++)
796     {
797         gchar *filename, *path;
798
799         filename = g_strdup_printf ("%s.desktop", session_name);
800         path = g_build_filename (dirs[i], filename, NULL);
801         g_free (filename);
802         session_config = session_config_new_from_file (path, &error);
803         g_free (path);
804         if (session_config)
805             break;
806
807         if (dirs[i+1] == NULL)
808             l_debug (seat, "Failed to find session configuration %s", session_name);
809         g_clear_error (&error);
810     }
811     g_strfreev (dirs);
812
813     return session_config;
814 }
815
816 static Session *
817 create_user_session (Seat *seat, const gchar *username, gboolean autostart)
818 {
819     User *user;
820     gchar *sessions_dir;
821     const gchar *session_name, *language;
822     SessionConfig *session_config;
823     Session *session = NULL;
824
825     l_debug (seat, "Creating user session");
826
827     /* Load user preferences */
828     user = accounts_get_user_by_name (username);
829     if (!user)
830     {
831         l_debug (seat, "Can't login unknown user '%s'", username);
832         return NULL;
833     }
834     session_name = user_get_xsession (user);
835     language = user_get_language (user);
836
837     if (!session_name)
838         session_name = seat_get_string_property (seat, "user-session");
839     sessions_dir = config_get_string (config_get_instance (), "LightDM", "sessions-directory");
840     session_config = find_session_config (seat, sessions_dir, session_name);
841     g_free (sessions_dir);
842     if (session_config)
843     {
844         const gchar *desktop_name;
845         gchar **argv;
846
847         session = create_session (seat, autostart, username);
848         session_set_session_type (session, session_config_get_session_type (session_config));
849         session_set_env (session, "DESKTOP_SESSION", session_name);
850         session_set_env (session, "GDMSESSION", session_name);
851         desktop_name = session_config_get_desktop_name (session_config);
852         if (desktop_name)
853             session_set_env (session, "XDG_CURRENT_DESKTOP", desktop_name);
854         if (language && language[0] != '\0')
855         {
856             session_set_env (session, "LANG", language);
857             session_set_env (session, "GDM_LANG", language);
858         }
859         session_set_username (session, username);
860         session_set_do_authenticate (session, TRUE);
861         argv = get_session_argv (seat, session_config, seat_get_string_property (seat, "session-wrapper"));
862         session_set_argv (session, argv);
863         g_strfreev (argv);
864
865         g_object_unref (session_config);
866     }
867     else
868         l_debug (seat, "Can't find session '%s'", seat_get_string_property (seat, "user-session"));
869
870     g_object_unref (user);
871
872     return session;
873 }
874
875 static Session *
876 create_guest_session (Seat *seat)
877 {
878     gchar *sessions_dir, **argv;
879     SessionConfig *session_config;
880     Session *session;
881
882     sessions_dir = config_get_string (config_get_instance (), "LightDM", "sessions-directory");
883     session_config = find_session_config (seat, sessions_dir, seat_get_string_property (seat, "user-session"));
884     g_free (sessions_dir);
885     if (!session_config)
886     {
887         l_debug (seat, "Can't find session '%s'", seat_get_string_property (seat, "user-session"));
888         return NULL;
889     }
890
891     session = create_session (seat, TRUE, NULL);
892     session_set_session_type (session, session_config_get_session_type (session_config));
893     session_set_do_authenticate (session, TRUE);
894     session_set_is_guest (session, TRUE);
895     argv = get_session_argv (seat, session_config, seat_get_string_property (seat, "session-wrapper"));
896     g_object_unref (session_config);
897     session_set_argv (session, argv);
898     g_strfreev (argv);
899   
900     return session;
901 }
902
903 static Session *
904 greeter_create_session_cb (Greeter *greeter, Seat *seat, const gchar *username)
905 {
906     Session *session;
907
908     session = create_session (seat, FALSE, username);
909     session_set_session_type (session, session_get_session_type (SESSION (greeter)));
910     session_set_display_server (session, session_get_display_server (SESSION (greeter)));
911
912     return g_object_ref (session);
913 }
914
915 static void
916 prepend_argv (gchar ***argv, const gchar *value)
917 {
918     gchar **old_argv, **new_argv;
919     gint i;
920
921     old_argv = *argv;
922     new_argv = g_malloc (sizeof (gchar *) * (g_strv_length (*argv) + 2));
923     new_argv[0] = g_strdup (value);
924     for (i = 0; old_argv[i]; i++)
925         new_argv[i + 1] = old_argv[i];
926     new_argv[i + 1] = NULL;
927
928     g_free (*argv);
929     *argv = new_argv;
930 }
931
932 static gboolean
933 greeter_start_session_cb (Greeter *greeter, SessionType type, const gchar *session_name, Seat *seat)
934 {
935     Session *session, *existing_session;
936     const gchar *username, *language = NULL;
937     SessionConfig *session_config;
938     User *user;
939     gchar *sessions_dir = NULL;
940     gchar **argv;
941     DisplayServer *display_server;
942
943     /* Get the session to use */
944     if (greeter_get_guest_authenticated (greeter))
945     {
946         session = create_guest_session (seat);
947         if (!session)
948             return FALSE;
949         session_set_pam_service (session, AUTOLOGIN_SERVICE);
950     }
951     else
952         session = greeter_get_authentication_session (greeter);
953
954     /* Switch to this session when it is ready */
955     if (seat->priv->session_to_activate)
956         g_object_unref (seat->priv->session_to_activate);
957     seat->priv->session_to_activate = g_object_ref (session);
958
959     /* Return to existing session if it is open */
960     username = session_get_username (session);
961     existing_session = find_user_session (seat, username, NULL);
962     if (existing_session && session != existing_session)
963     {
964         l_debug (seat, "Returning to existing user session %s", username);
965         session_stop (session);
966         session_unlock (existing_session);
967         seat_set_active_session (seat, existing_session);
968         return TRUE;
969     }
970
971     /* Get session command to run */
972     switch (type)
973     {
974     case SESSION_TYPE_LOCAL:
975         sessions_dir = config_get_string (config_get_instance (), "LightDM", "sessions-directory");
976         break;
977     case SESSION_TYPE_REMOTE:
978         sessions_dir = config_get_string (config_get_instance (), "LightDM", "remote-sessions-directory");
979         break;
980     }
981
982     /* Load user preferences */
983     user = session_get_user (session);
984     if (user)
985     {
986         if (!session_name)
987             session_name = user_get_xsession (user);
988         language = user_get_language (user);
989     }
990
991     if (!session_name)
992         session_name = seat_get_string_property (seat, "user-session");
993     if (user)
994         user_set_xsession (session_get_user (session), session_name);
995
996     session_config = find_session_config (seat, sessions_dir, session_name);
997     g_free (sessions_dir);
998     if (!session_config)
999     {
1000         l_debug (seat, "Can't find session '%s'", seat_get_string_property (seat, "user-session"));
1001         return FALSE;
1002     }
1003
1004     session_set_session_type (session, session_config_get_session_type (session_config));
1005     argv = get_session_argv (seat, session_config, seat_get_string_property (seat, "session-wrapper"));
1006     session_set_argv (session, argv);
1007     g_strfreev (argv);
1008     session_set_env (session, "DESKTOP_SESSION", session_name);
1009     session_set_env (session, "GDMSESSION", session_name);
1010     if (language && language[0] != '\0')
1011     {
1012         session_set_env (session, "LANG", language);
1013         session_set_env (session, "GDM_LANG", language);
1014     }
1015
1016     g_object_unref (session_config);
1017
1018     /* If can re-use the display server, stop the greeter first */
1019     display_server = session_get_display_server (SESSION (greeter));
1020     if (can_share_display_server (seat, display_server) &&
1021         strcmp (display_server_get_session_type (display_server), session_get_session_type (session)) == 0)
1022     {
1023         l_debug (seat, "Stopping greeter; display server will be re-used for user session");
1024
1025         /* Run on the same display server after the greeter has stopped */
1026         session_set_display_server (session, display_server);
1027
1028         /* Stop the greeter */
1029         session_stop (SESSION (greeter));
1030
1031         return TRUE;
1032     }
1033     /* Otherwise start a new display server for this session */
1034     else
1035     {
1036         display_server = create_display_server (seat, session_get_session_type (session));
1037         session_set_display_server (session, display_server);
1038         if (!display_server_start (display_server))
1039         {
1040             l_debug (seat, "Failed to start display server for new session");
1041             return FALSE;
1042         }
1043
1044         return TRUE;
1045     }
1046 }
1047
1048 static Greeter *
1049 create_greeter_session (Seat *seat)
1050 {
1051     gchar *sessions_dir, **argv;
1052     SessionConfig *session_config;
1053     Greeter *greeter_session;
1054     gchar *greeter_user;
1055     const gchar *greeter_wrapper;
1056
1057     l_debug (seat, "Creating greeter session");
1058
1059     sessions_dir = config_get_string (config_get_instance (), "LightDM", "greeters-directory");
1060     session_config = find_session_config (seat, sessions_dir, seat_get_string_property (seat, "greeter-session"));
1061     g_free (sessions_dir);
1062     if (!session_config)
1063         return NULL;
1064
1065     argv = get_session_argv (seat, session_config, NULL);
1066     greeter_wrapper = seat_get_string_property (seat, "greeter-wrapper");
1067     if (greeter_wrapper)
1068     {
1069         gchar *path;
1070         path = g_find_program_in_path (greeter_wrapper);
1071         prepend_argv (&argv, path ? path : greeter_wrapper);
1072         g_free (path);
1073     }
1074
1075     greeter_session = SEAT_GET_CLASS (seat)->create_greeter_session (seat);
1076     session_set_session_type (SESSION (greeter_session), session_config_get_session_type (session_config));
1077     seat->priv->sessions = g_list_append (seat->priv->sessions, SESSION (greeter_session));
1078     g_signal_connect (greeter_session, "notify::active-username", G_CALLBACK (greeter_active_username_changed_cb), seat);
1079     g_signal_connect (greeter_session, "authentication-complete", G_CALLBACK (session_authentication_complete_cb), seat);
1080     g_signal_connect (greeter_session, "stopped", G_CALLBACK (session_stopped_cb), seat);
1081   
1082     set_session_env (SESSION (greeter_session));
1083
1084     session_set_pam_service (SESSION (greeter_session), GREETER_SERVICE);
1085     greeter_user = config_get_string (config_get_instance (), "LightDM", "greeter-user");
1086     session_set_username (SESSION (greeter_session), greeter_user);
1087     g_free (greeter_user);
1088     session_set_argv (SESSION (greeter_session), argv);
1089     g_strfreev (argv);
1090
1091     greeter_set_pam_services (greeter_session, USER_SERVICE, AUTOLOGIN_SERVICE);
1092     g_signal_connect (greeter_session, "create-session", G_CALLBACK (greeter_create_session_cb), seat);
1093     g_signal_connect (greeter_session, "start-session", G_CALLBACK (greeter_start_session_cb), seat);
1094
1095     /* Set hints to greeter */
1096     greeter_set_hint (greeter_session, "default-session", seat_get_string_property (seat, "user-session"));
1097     greeter_set_allow_guest (greeter_session, seat_get_allow_guest (seat));
1098     greeter_set_hint (greeter_session, "hide-users", seat_get_boolean_property (seat, "greeter-hide-users") ? "true" : "false");
1099     greeter_set_hint (greeter_session, "show-manual-login", seat_get_boolean_property (seat, "greeter-show-manual-login") ? "true" : "false");
1100     greeter_set_hint (greeter_session, "show-remote-login", seat_get_boolean_property (seat, "greeter-show-remote-login") ? "true" : "false");
1101     greeter_set_hint (greeter_session, "has-guest-account", seat_get_allow_guest (seat) && seat_get_boolean_property (seat, "greeter-allow-guest") ? "true" : "false");
1102
1103     g_object_unref (session_config);
1104
1105     return greeter_session;
1106 }
1107
1108 static Session *
1109 find_session_for_display_server (Seat *seat, DisplayServer *display_server)
1110 {
1111     GList *link;
1112
1113     for (link = seat->priv->sessions; link; link = link->next)
1114     {
1115         Session *session = link->data;
1116         if (session_get_display_server (session) == display_server && !session_get_is_stopping (session))
1117             return session;
1118     }
1119
1120     return NULL;
1121 }
1122
1123 static void
1124 display_server_ready_cb (DisplayServer *display_server, Seat *seat)
1125 {
1126     const gchar *script;
1127     Session *session;
1128
1129     /* Run setup script */
1130     script = seat_get_string_property (seat, "display-setup-script");
1131     if (script && !run_script (seat, display_server, script, NULL))
1132     {
1133         l_debug (seat, "Stopping display server due to failed setup script");
1134         display_server_stop (display_server);
1135         return;
1136     }
1137
1138     /* Stop if don't need to run a session */
1139     if (!get_start_local_sessions (seat))
1140         return;
1141
1142     emit_upstart_signal ("login-session-start");
1143
1144     /* Start the session waiting for this display server */
1145     session = find_session_for_display_server (seat, display_server);
1146     if (session)
1147     {
1148         if (session_get_is_authenticated (session))
1149         {
1150             l_debug (seat, "Display server ready, running session");
1151             run_session (seat, session);
1152         }
1153         else
1154         {
1155             l_debug (seat, "Display server ready, starting session authentication");
1156             start_session (seat, session);
1157         }
1158     }
1159     else
1160     {
1161         l_debug (seat, "Stopping not required display server");
1162         display_server_stop (display_server);
1163     }
1164 }
1165
1166 static DisplayServer *
1167 create_display_server (Seat *seat, const gchar *session_type)
1168 {
1169     DisplayServer *display_server;
1170
1171     l_debug (seat, "Creating display server of type %s", session_type);
1172
1173     display_server = SEAT_GET_CLASS (seat)->create_display_server (seat, session_type);
1174     if (!display_server)
1175         return NULL;
1176
1177     seat->priv->display_servers = g_list_append (seat->priv->display_servers, display_server);
1178     g_signal_connect (display_server, "ready", G_CALLBACK (display_server_ready_cb), seat);
1179     g_signal_connect (display_server, "stopped", G_CALLBACK (display_server_stopped_cb), seat);
1180
1181     return display_server;
1182 }
1183
1184 static Greeter *
1185 find_greeter_session (Seat *seat)
1186 {
1187     GList *link;
1188
1189     for (link = seat->priv->sessions; link; link = link->next)
1190     {
1191         Session *session = link->data;
1192         if (!session_get_is_stopping (session) && IS_GREETER (session))
1193             return GREETER (session);
1194     }
1195
1196     return NULL;
1197 }
1198
1199 gboolean
1200 seat_switch_to_greeter (Seat *seat)
1201 {
1202     Greeter *greeter_session;
1203     DisplayServer *display_server;
1204
1205     g_return_val_if_fail (seat != NULL, FALSE);
1206
1207     if (!seat->priv->can_switch)
1208         return FALSE;
1209
1210     /* Switch to greeter if one open (shouldn't be though) */
1211     greeter_session = find_greeter_session (seat);
1212     if (greeter_session)
1213     {
1214         l_debug (seat, "Switching to existing greeter");
1215         seat_set_active_session (seat, SESSION (greeter_session));
1216         return TRUE;
1217     }
1218
1219     greeter_session = create_greeter_session (seat);
1220     if (seat->priv->session_to_activate)
1221         g_object_unref (seat->priv->session_to_activate);
1222     seat->priv->session_to_activate = g_object_ref (greeter_session);
1223
1224     display_server = create_display_server (seat, session_get_session_type (SESSION (greeter_session)));
1225     session_set_display_server (SESSION (greeter_session), display_server);
1226     if (!display_server_start (display_server))
1227         return FALSE;
1228
1229     return TRUE;
1230 }
1231
1232 static void
1233 switch_authentication_complete_cb (Session *session, Seat *seat)
1234 {
1235     Greeter *greeter_session;
1236     DisplayServer *display_server;
1237
1238     /* If authenticated, then unlock existing session or start new one */
1239     if (session_get_is_authenticated (session))
1240     {
1241         Session *s;
1242
1243         s = find_user_session (seat, session_get_username (session), session);
1244         if (s)
1245         {
1246             l_debug (seat, "Session authenticated, switching to existing user session");
1247             session_unlock (s);
1248             seat_set_active_session (seat, s);
1249             session_stop (session);
1250         }
1251         else
1252         {
1253             l_debug (seat, "Session authenticated, starting display server");
1254             if (seat->priv->session_to_activate)
1255                 g_object_unref (seat->priv->session_to_activate);
1256             seat->priv->session_to_activate = g_object_ref (session);
1257             display_server = create_display_server (seat, session_get_session_type (session));
1258             session_set_display_server (session, display_server);
1259             display_server_start (display_server);
1260         }
1261
1262         return;
1263     }
1264
1265     l_debug (seat, "Switching to greeter to authenticate session");
1266
1267     session_stop (session);
1268
1269     greeter_session = create_greeter_session (seat);
1270     if (session_get_is_guest (session))
1271         greeter_set_hint (greeter_session, "select-guest", "true");
1272     else
1273         greeter_set_hint (greeter_session, "select-user", session_get_username (session));
1274     if (seat->priv->session_to_activate)
1275         g_object_unref (seat->priv->session_to_activate);
1276     seat->priv->session_to_activate = g_object_ref (greeter_session);
1277
1278     display_server = create_display_server (seat, session_get_session_type (SESSION (greeter_session)));
1279     session_set_display_server (SESSION (greeter_session), display_server);
1280     display_server_start (display_server);
1281 }
1282
1283 gboolean
1284 seat_switch_to_user (Seat *seat, const gchar *username, const gchar *session_name)
1285 {
1286     Session *session;
1287
1288     g_return_val_if_fail (seat != NULL, FALSE);
1289     g_return_val_if_fail (username != NULL, FALSE);
1290
1291     if (!seat->priv->can_switch)
1292         return FALSE;
1293
1294     /* If we're already on this session, then ignore */
1295     session = find_user_session (seat, username, NULL);
1296     if (session && session == seat->priv->active_session)
1297         return TRUE;
1298
1299     l_debug (seat, "Switching to user %s", username);
1300
1301     /* Attempt to authenticate them */
1302     session = create_user_session (seat, username, FALSE);
1303     g_signal_connect (session, "authentication-complete", G_CALLBACK (switch_authentication_complete_cb), seat);
1304     session_set_pam_service (session, USER_SERVICE);
1305     session_start (session);
1306
1307     return FALSE;
1308 }
1309
1310 static Session *
1311 find_guest_session (Seat *seat)
1312 {
1313     GList *link;
1314
1315     for (link = seat->priv->sessions; link; link = link->next)
1316     {
1317         Session *session = link->data;
1318         if (!session_get_is_stopping (session) && session_get_is_guest (session))
1319             return session;
1320     }
1321
1322     return NULL;
1323 }
1324
1325 gboolean
1326 seat_switch_to_guest (Seat *seat, const gchar *session_name)
1327 {
1328     Session *session;
1329     DisplayServer *display_server;
1330
1331     g_return_val_if_fail (seat != NULL, FALSE);
1332
1333     if (!seat->priv->can_switch || !seat_get_allow_guest (seat))
1334         return FALSE;
1335
1336     /* Switch to session if one open */
1337     session = find_guest_session (seat);
1338     if (session)
1339     {
1340         l_debug (seat, "Switching to existing guest account %s", session_get_username (session));
1341         seat_set_active_session (seat, session);
1342         return TRUE;
1343     }
1344
1345     session = create_guest_session (seat);
1346     if (!session)
1347         return FALSE;
1348
1349     display_server = create_display_server (seat, session_get_session_type (session));
1350     if (!display_server_start (display_server))
1351         return FALSE;
1352
1353     if (seat->priv->session_to_activate)
1354         g_object_unref (seat->priv->session_to_activate);
1355     seat->priv->session_to_activate = g_object_ref (session);
1356     session_set_pam_service (session, AUTOLOGIN_SERVICE);
1357     session_set_display_server (session, display_server);
1358
1359     return TRUE;
1360 }
1361
1362 gboolean
1363 seat_lock (Seat *seat, const gchar *username)
1364 {
1365     Greeter *greeter_session;
1366     DisplayServer *display_server;
1367
1368     g_return_val_if_fail (seat != NULL, FALSE);
1369
1370     if (!seat->priv->can_switch)
1371         return FALSE;
1372
1373     l_debug (seat, "Locking");
1374
1375     /* Switch to greeter if one open (shouldn't be though) */
1376     greeter_session = find_greeter_session (seat);
1377     if (greeter_session)
1378     {
1379         l_debug (seat, "Switching to existing greeter");
1380         seat_set_active_session (seat, SESSION (greeter_session));
1381         return TRUE;
1382     }
1383
1384     greeter_session = create_greeter_session (seat);
1385     if (!greeter_session)
1386         return FALSE;
1387
1388     display_server = create_display_server (seat, session_get_session_type (SESSION (greeter_session)));
1389     if (!display_server_start (display_server))
1390         return FALSE;
1391
1392     if (seat->priv->session_to_activate)
1393         g_object_unref (seat->priv->session_to_activate);
1394     seat->priv->session_to_activate = g_object_ref (greeter_session);
1395     greeter_set_hint (greeter_session, "lock-screen", "true");
1396     if (username)
1397         greeter_set_hint (greeter_session, "select-user", username);
1398     session_set_display_server (SESSION (greeter_session), display_server);
1399
1400     return TRUE;
1401 }
1402
1403 void
1404 seat_stop (Seat *seat)
1405 {
1406     g_return_if_fail (seat != NULL);
1407
1408     if (seat->priv->stopping)
1409         return;
1410
1411     l_debug (seat, "Stopping");
1412     seat->priv->stopping = TRUE;
1413     SEAT_GET_CLASS (seat)->stop (seat);
1414 }
1415
1416 gboolean
1417 seat_get_is_stopping (Seat *seat)
1418 {
1419     g_return_val_if_fail (seat != NULL, FALSE);
1420     return seat->priv->stopping;
1421 }
1422
1423 static gboolean
1424 seat_real_get_start_local_sessions (Seat *seat)
1425 {
1426     return TRUE;
1427 }
1428
1429 static void
1430 seat_real_setup (Seat *seat)
1431 {
1432 }
1433
1434 static gboolean
1435 seat_real_start (Seat *seat)
1436 {
1437     const gchar *autologin_username;
1438     int autologin_timeout;
1439     gboolean autologin_guest;
1440     gboolean autologin_in_background;
1441     Session *session = NULL, *background_session = NULL;
1442
1443     l_debug (seat, "Starting");
1444
1445     /* If this display server doesn't have a session running on it, just start it */
1446     if (!get_start_local_sessions (seat))
1447     {
1448         DisplayServer *display_server;
1449         display_server = create_display_server (seat, "x"); // FIXME: Not necessarily an X seat, but not sure what to put here
1450         return display_server_start (display_server);
1451     }
1452
1453     /* Get autologin settings */
1454     autologin_username = seat_get_string_property (seat, "autologin-user");
1455     if (g_strcmp0 (autologin_username, "") == 0)
1456         autologin_username = NULL;
1457     autologin_timeout = seat_get_integer_property (seat, "autologin-user-timeout");
1458     autologin_guest = seat_get_boolean_property (seat, "autologin-guest");
1459     autologin_in_background = seat_get_boolean_property (seat, "autologin-in-background");
1460
1461     /* Autologin if configured */
1462     if (autologin_timeout == 0 || autologin_in_background)
1463     {
1464         if (autologin_guest)
1465             session = create_guest_session (seat);
1466         else if (autologin_username != NULL)
1467             session = create_user_session (seat, autologin_username, TRUE);
1468
1469         if (session)
1470             session_set_pam_service (session, AUTOLOGIN_SERVICE);
1471
1472         /* Load in background if required */
1473         if (autologin_in_background && session)
1474         {
1475             background_session = session;
1476             session = NULL;
1477         }
1478       
1479         if (session)
1480         {
1481             DisplayServer *display_server;
1482
1483             if (seat->priv->session_to_activate)
1484                 g_object_unref (seat->priv->session_to_activate);
1485             seat->priv->session_to_activate = g_object_ref (session);
1486
1487             display_server = create_display_server (seat, session_get_session_type (session));
1488             session_set_display_server (session, display_server);
1489             if (!display_server || !display_server_start (display_server))
1490             {
1491                 l_debug (seat, "Can't create display server for automatic login");
1492                 session_stop (session);
1493                 if (display_server)
1494                     display_server_stop (display_server);
1495                 session = NULL;
1496             }
1497         }
1498     }
1499
1500     /* Fallback to a greeter */
1501     if (!session)
1502     {
1503         Greeter *greeter_session;
1504         DisplayServer *display_server;
1505
1506         greeter_session = create_greeter_session (seat);
1507         if (!greeter_session)
1508         {
1509             l_debug (seat, "Failed to create greeter session");
1510             return FALSE;
1511         }
1512
1513         if (seat->priv->session_to_activate)
1514             g_object_unref (seat->priv->session_to_activate);
1515         seat->priv->session_to_activate = g_object_ref (greeter_session);
1516         session = SESSION (greeter_session);
1517
1518         if (autologin_timeout)
1519         {
1520             gchar *value;
1521
1522             value = g_strdup_printf ("%d", autologin_timeout);
1523             greeter_set_hint (greeter_session, "autologin-timeout", value);
1524             g_free (value);
1525             if (autologin_username)
1526                 greeter_set_hint (greeter_session, "autologin-user", autologin_username);
1527             if (autologin_guest)
1528                 greeter_set_hint (greeter_session, "autologin-guest", "true");
1529         }
1530
1531         display_server = create_display_server (seat, session_get_session_type (session));
1532         session_set_display_server (session, display_server);
1533         if (!display_server || !display_server_start (display_server))
1534         {
1535             l_debug (seat, "Can't create display server for greeter");
1536             session_stop (session);
1537             if (display_server)
1538                 display_server_stop (display_server);
1539             session = NULL;
1540         }
1541     }
1542
1543     /* Fail if can't start a session */
1544     if (!session)
1545     {
1546         seat_stop (seat);
1547         return FALSE;
1548     }
1549
1550     /* Start background session */
1551     if (background_session)
1552     {
1553         DisplayServer *background_display_server;
1554
1555         background_display_server = create_display_server (seat, session_get_session_type (background_session));
1556         session_set_display_server (background_session, background_display_server);
1557         if (!display_server_start (background_display_server))
1558             l_warning (seat, "Failed to start display server for background session");
1559     }
1560
1561     seat->priv->started = TRUE;
1562     return TRUE;
1563 }
1564
1565 static Greeter *
1566 seat_real_create_greeter_session (Seat *seat)
1567 {
1568     return greeter_new ();
1569 }
1570
1571 static Session *
1572 seat_real_create_session (Seat *seat, Session *user_session)
1573 {
1574     return session_new ();
1575 }
1576
1577 static void
1578 seat_real_set_active_session (Seat *seat, Session *session)
1579 {
1580 }
1581
1582 static void
1583 seat_real_set_next_session (Seat *seat, Session *session)
1584 {
1585 }
1586
1587 static Session *
1588 seat_real_get_active_session (Seat *seat)
1589 {
1590     return NULL;
1591 }
1592
1593 static void
1594 seat_real_stop (Seat *seat)
1595 {
1596     GList *list, *link;
1597
1598     check_stopped (seat);
1599     if (seat->priv->stopped)
1600         return;
1601
1602     /* Stop all the display servers and sessions on the seat. Copy the list as
1603      * it might be modified if a display server / session stops during this loop */
1604     list = g_list_copy (seat->priv->display_servers);
1605     for (link = list; link; link = link->next)
1606         g_object_ref (link->data);
1607     for (link = list; link; link = link->next)
1608     {
1609         DisplayServer *display_server = link->data;
1610         if (!display_server_get_is_stopping (display_server))
1611         {
1612             l_debug (seat, "Stopping display server");
1613             display_server_stop (display_server);
1614         }
1615     }
1616     g_list_free_full (list, g_object_unref);
1617     list = g_list_copy (seat->priv->sessions);
1618     for (link = list; link; link = link->next)
1619         g_object_ref (link->data);
1620     for (link = list; link; link = link->next)
1621     {
1622         Session *session = link->data;
1623         if (!session_get_is_stopping (session))
1624         {
1625             l_debug (seat, "Stopping session");
1626             session_stop (session);
1627         }
1628     }
1629     g_list_free_full (list, g_object_unref);
1630 }
1631
1632 static void
1633 seat_init (Seat *seat)
1634 {
1635     seat->priv = G_TYPE_INSTANCE_GET_PRIVATE (seat, SEAT_TYPE, SeatPrivate);
1636     seat->priv->properties = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1637     seat->priv->share_display_server = TRUE;
1638 }
1639
1640 static void
1641 seat_finalize (GObject *object)
1642 {
1643     Seat *self;
1644     GList *link;
1645
1646     self = SEAT (object);
1647
1648     g_hash_table_unref (self->priv->properties);
1649     for (link = self->priv->display_servers; link; link = link->next)
1650     {
1651         DisplayServer *display_server = link->data;
1652         g_signal_handlers_disconnect_matched (display_server, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
1653     }  
1654     g_list_free_full (self->priv->display_servers, g_object_unref);
1655     for (link = self->priv->sessions; link; link = link->next)
1656     {
1657         Session *session = link->data;
1658         g_signal_handlers_disconnect_matched (session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
1659     }
1660     g_list_free_full (self->priv->sessions, g_object_unref);
1661     if (self->priv->active_session)
1662         g_object_unref (self->priv->active_session);
1663     if (self->priv->next_session)
1664         g_object_unref (self->priv->next_session);
1665     if (self->priv->session_to_activate)
1666         g_object_unref (self->priv->session_to_activate);
1667
1668     G_OBJECT_CLASS (seat_parent_class)->finalize (object);
1669 }
1670
1671 static void
1672 seat_class_init (SeatClass *klass)
1673 {
1674     GObjectClass *object_class = G_OBJECT_CLASS (klass);
1675
1676     klass->get_start_local_sessions = seat_real_get_start_local_sessions;
1677     klass->setup = seat_real_setup;
1678     klass->start = seat_real_start;
1679     klass->create_greeter_session = seat_real_create_greeter_session;
1680     klass->create_session = seat_real_create_session;
1681     klass->set_active_session = seat_real_set_active_session;
1682     klass->get_active_session = seat_real_get_active_session;
1683     klass->set_next_session = seat_real_set_next_session;
1684     klass->run_script = seat_real_run_script;
1685     klass->stop = seat_real_stop;
1686
1687     object_class->finalize = seat_finalize;
1688
1689     g_type_class_add_private (klass, sizeof (SeatPrivate));
1690
1691     signals[SESSION_ADDED] =
1692         g_signal_new ("session-added",
1693                       G_TYPE_FROM_CLASS (klass),
1694                       G_SIGNAL_RUN_LAST,
1695                       G_STRUCT_OFFSET (SeatClass, session_added),
1696                       NULL, NULL,
1697                       NULL,
1698                       G_TYPE_NONE, 1, SESSION_TYPE);
1699     signals[RUNNING_USER_SESSION] =
1700         g_signal_new ("running-user-session",
1701                       G_TYPE_FROM_CLASS (klass),
1702                       G_SIGNAL_RUN_LAST,
1703                       G_STRUCT_OFFSET (SeatClass, running_user_session),
1704                       NULL, NULL,
1705                       NULL,
1706                       G_TYPE_NONE, 1, SESSION_TYPE);
1707     signals[SESSION_REMOVED] =
1708         g_signal_new ("session-removed",
1709                       G_TYPE_FROM_CLASS (klass),
1710                       G_SIGNAL_RUN_LAST,
1711                       G_STRUCT_OFFSET (SeatClass, session_removed),
1712                       NULL, NULL,
1713                       NULL,
1714                       G_TYPE_NONE, 1, SESSION_TYPE);
1715     signals[STOPPED] =
1716         g_signal_new ("stopped",
1717                       G_TYPE_FROM_CLASS (klass),
1718                       G_SIGNAL_RUN_LAST,
1719                       G_STRUCT_OFFSET (SeatClass, stopped),
1720                       NULL, NULL,
1721                       NULL,
1722                       G_TYPE_NONE, 0);
1723 }
1724
1725 static gint
1726 seat_real_logprefix (Logger *self, gchar *buf, gulong buflen)
1727 {
1728     Seat *seat = SEAT (self);
1729     const gchar *name = seat_get_string_property (seat, "seat-name");
1730     if (name)
1731         return g_snprintf (buf, buflen, "Seat %s: ", name);
1732     else
1733         return g_snprintf (buf, buflen, "Seat: ");
1734 }
1735
1736 static void
1737 seat_logger_iface_init (LoggerInterface *iface)
1738 {
1739     iface->logprefix = &seat_real_logprefix;
1740 }