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