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