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