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