2
* Copyright (C) 2010-2011 Robert Ancell.
3
* Author: Robert Ancell <robert.ancell@canonical.com>
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
17
#include "guest-account.h"
25
static guint signals[LAST_SIGNAL] = { 0 };
29
/* Configuration for this seat */
30
GHashTable *properties;
32
/* TRUE if able to switch users */
35
/* Name of guest account */
36
gchar *guest_username;
38
/* The displays for this seat */
41
/* The active display */
42
Display *active_display;
44
/* TRUE if stopping this seat (waiting for displays to stop) */
51
G_DEFINE_TYPE (Seat, seat, G_TYPE_OBJECT);
58
static GHashTable *seat_modules = NULL;
61
seat_register_module (const gchar *name, GType type)
66
seat_modules = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
68
g_debug ("Registered seat module %s", name);
70
module = g_malloc0 (sizeof (SeatModule));
71
module->name = g_strdup (name);
73
g_hash_table_insert (seat_modules, g_strdup (name), module);
77
seat_new (const gchar *module_name)
82
g_return_val_if_fail (module_name != NULL, NULL);
85
m = g_hash_table_lookup (seat_modules, module_name);
89
seat = g_object_new (m->type, NULL);
95
seat_set_property (Seat *seat, const gchar *name, const gchar *value)
97
g_return_if_fail (seat != NULL);
98
g_hash_table_insert (seat->priv->properties, g_strdup (name), g_strdup (value));
102
seat_has_property (Seat *seat, const gchar *name)
104
g_return_val_if_fail (seat != NULL, FALSE);
105
return g_hash_table_lookup (seat->priv->properties, name) != NULL;
109
seat_get_string_property (Seat *seat, const gchar *name)
111
g_return_val_if_fail (seat != NULL, NULL);
112
return g_hash_table_lookup (seat->priv->properties, name);
116
seat_get_boolean_property (Seat *seat, const gchar *name)
118
return g_strcmp0 (seat_get_string_property (seat, name), "true") == 0;
122
seat_get_integer_property (Seat *seat, const gchar *name)
126
value = seat_get_string_property (seat, name);
127
return value ? atoi (value) : 0;
131
seat_set_can_switch (Seat *seat, gboolean can_switch)
133
g_return_if_fail (seat != NULL);
135
seat->priv->can_switch = can_switch;
139
seat_start (Seat *seat)
141
g_return_val_if_fail (seat != NULL, FALSE);
143
SEAT_GET_CLASS (seat)->setup (seat);
144
return SEAT_GET_CLASS (seat)->start (seat);
148
seat_get_displays (Seat *seat)
150
g_return_val_if_fail (seat != NULL, NULL);
151
return seat->priv->displays;
155
seat_set_active_display (Seat *seat, Display *display)
157
g_return_if_fail (seat != NULL);
158
SEAT_GET_CLASS (seat)->set_active_display (seat, display);
162
seat_get_active_display (Seat *seat)
164
g_return_val_if_fail (seat != NULL, NULL);
165
return seat->priv->active_display;
169
seat_get_can_switch (Seat *seat)
171
g_return_val_if_fail (seat != NULL, FALSE);
172
return seat->priv->can_switch;
176
seat_get_allow_guest (Seat *seat)
178
g_return_val_if_fail (seat != NULL, FALSE);
179
return seat_get_boolean_property (seat, "allow-guest") && guest_account_is_installed ();
183
seat_get_greeter_allow_guest (Seat *seat)
185
g_return_val_if_fail (seat != NULL, FALSE);
186
return seat_get_allow_guest (seat) && seat_get_boolean_property (seat, "greeter-allow-guest");
190
switch_to_user (Seat *seat, const gchar *username, gboolean unlock)
194
/* Switch to active display if it exists */
195
for (link = seat->priv->displays; link; link = link->next)
197
Display *display = link->data;
199
/* If already logged in, then switch to that display */
200
if (g_strcmp0 (display_get_username (display), username) == 0)
203
g_debug ("Switching to existing session for user %s", username);
205
g_debug ("Switching to existing greeter");
207
display_unlock (display);
208
seat_set_active_display (seat, display);
217
display_switch_to_user_cb (Display *display, User *user, Seat *seat)
219
return switch_to_user (seat, user_get_name (user), TRUE);
223
display_switch_to_guest_cb (Display *display, Seat *seat)
225
/* No guest account */
226
if (!seat->priv->guest_username)
229
return switch_to_user (seat, seat->priv->guest_username, TRUE);
233
display_get_guest_username_cb (Display *display, Seat *seat)
235
if (seat->priv->guest_username)
236
return seat->priv->guest_username;
238
seat->priv->guest_username = guest_account_setup ();
239
return g_strdup (seat->priv->guest_username);
243
run_script (Seat *seat, Display *display, const gchar *script_name, User *user)
246
gboolean result = FALSE;
248
script = process_new ();
250
process_set_command (script, script_name);
252
/* Set POSIX variables */
253
process_set_clear_environment (script, TRUE);
254
process_set_env (script, "SHELL", "/bin/sh");
256
/* Variables required for regression tests */
257
if (g_getenv ("LIGHTDM_TEST_ROOT"))
259
process_set_env (script, "LIGHTDM_TEST_ROOT", g_getenv ("LIGHTDM_TEST_ROOT"));
260
process_set_env (script, "LD_PRELOAD", g_getenv ("LD_PRELOAD"));
261
process_set_env (script, "LD_LIBRARY_PATH", g_getenv ("LD_LIBRARY_PATH"));
262
process_set_env (script, "PATH", g_getenv ("PATH"));
265
process_set_env (script, "PATH", "/usr/local/bin:/usr/bin:/bin");
269
process_set_env (script, "USER", user_get_name (user));
270
process_set_env (script, "LOGNAME", user_get_name (user));
271
process_set_env (script, "HOME", user_get_home_directory (user));
274
process_set_env (script, "HOME", "/");
276
SEAT_GET_CLASS (seat)->run_script (seat, display, script);
278
if (process_start (script, TRUE))
282
exit_status = process_get_exit_status (script);
283
if (WIFEXITED (exit_status))
285
g_debug ("Exit status of %s: %d", script_name, WEXITSTATUS (exit_status));
286
result = WEXITSTATUS (exit_status) == EXIT_SUCCESS;
290
g_object_unref (script);
296
seat_real_run_script (Seat *seat, Display *display, Process *process)
301
emit_upstart_signal (const gchar *signal)
303
g_return_if_fail (signal != NULL);
304
g_return_if_fail (signal[0] != 0);
309
gchar *cmd = g_strdup_printf ("initctl -q emit %s DISPLAY_MANAGER=lightdm", signal);
310
g_spawn_command_line_async (cmd, NULL); /* OK if it fails, probably not installed */
315
display_display_server_ready_cb (Display *display, Seat *seat)
319
/* Run setup script */
320
script = seat_get_string_property (seat, "display-setup-script");
321
if (script && !run_script (seat, display, script, NULL))
324
emit_upstart_signal ("login-session-start");
330
display_create_session_cb (Display *display, Seat *seat)
332
return SEAT_GET_CLASS (seat)->create_session (seat, display);
336
display_start_greeter_cb (Display *display, Seat *seat)
341
session = display_get_session (display);
343
script = seat_get_string_property (seat, "greeter-setup-script");
345
return !run_script (seat, display, script, session_get_user (session));
351
display_start_session_cb (Display *display, Seat *seat)
356
session = display_get_session (display);
358
script = seat_get_string_property (seat, "session-setup-script");
360
return !run_script (seat, display, script, session_get_user (session));
366
session_stopped_cb (Session *session, Seat *seat)
368
Display *display = NULL;
372
/* Work out what display this session is on, it's a bit hacky because we really should know already... */
373
for (link = seat->priv->displays; link; link = link->next)
375
Display *d = link->data;
376
if (display_get_session (d) == session)
382
g_return_if_fail (display != NULL);
385
script = seat_get_string_property (seat, "session-cleanup-script");
387
run_script (seat, display, script, session_get_user (session));
389
if (seat->priv->guest_username && strcmp (session_get_username (session), seat->priv->guest_username) == 0)
391
g_free (seat->priv->guest_username);
392
seat->priv->guest_username = NULL;
397
display_session_started_cb (Display *display, Seat *seat)
399
g_signal_connect (display_get_session (display), "stopped", G_CALLBACK (session_stopped_cb), seat);
400
emit_upstart_signal ("desktop-session-start");
405
display_ready_cb (Display *display, Seat *seat)
407
/* Switch to this new display */
408
g_debug ("New display ready, switching to it");
409
SEAT_GET_CLASS (seat)->set_active_display (seat, display);
413
check_stopped (Seat *seat)
415
if (seat->priv->stopping &&
416
!seat->priv->stopped &&
417
g_list_length (seat->priv->displays) == 0)
419
seat->priv->stopped = TRUE;
420
g_debug ("Seat stopped");
421
g_signal_emit (seat, signals[STOPPED], 0);
426
display_stopped_cb (Display *display, Seat *seat)
428
seat->priv->displays = g_list_remove (seat->priv->displays, display);
429
g_signal_handlers_disconnect_matched (display, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, seat);
430
g_signal_emit (seat, signals[DISPLAY_REMOVED], 0, display);
431
g_object_unref (display);
433
check_stopped (seat);
437
switch_to_user_or_start_greeter (Seat *seat, const gchar *username, gboolean use_existing, gboolean is_guest, const gchar *session_name, gboolean is_lock, gboolean autologin, int autologin_timeout)
440
DisplayServer *display_server;
442
/* Switch to existing if it exists */
443
if (use_existing && switch_to_user (seat, username, FALSE))
446
/* If one don't exist then start a greeter */
450
g_debug ("Starting new display for automatic guest login");
452
g_debug ("Starting new display for automatic login as user %s", username);
454
g_debug ("Starting new display for greeter");
459
g_debug ("Starting new display for greeter with guest selected");
461
g_debug ("Starting new display for greeter with user %s selected", username);
463
g_debug ("Starting new display for greeter (lock screen)");
465
g_debug ("Starting new display for greeter");
468
display_server = SEAT_GET_CLASS (seat)->create_display_server (seat);
469
display = display_new (display_server);
470
g_object_unref (display_server);
472
g_signal_connect (display, "display-server-ready", G_CALLBACK (display_display_server_ready_cb), seat);
473
g_signal_connect (display, "switch-to-user", G_CALLBACK (display_switch_to_user_cb), seat);
474
g_signal_connect (display, "switch-to-guest", G_CALLBACK (display_switch_to_guest_cb), seat);
475
g_signal_connect (display, "get-guest-username", G_CALLBACK (display_get_guest_username_cb), seat);
476
g_signal_connect (display, "create-session", G_CALLBACK (display_create_session_cb), seat);
477
g_signal_connect (display, "start-greeter", G_CALLBACK (display_start_greeter_cb), seat);
478
g_signal_connect (display, "start-session", G_CALLBACK (display_start_session_cb), seat);
479
g_signal_connect_after (display, "start-session", G_CALLBACK (display_session_started_cb), seat);
480
g_signal_connect (display, "ready", G_CALLBACK (display_ready_cb), seat);
481
g_signal_connect (display, "stopped", G_CALLBACK (display_stopped_cb), seat);
482
display_set_greeter_session (display, seat_get_string_property (seat, "greeter-session"));
483
display_set_session_wrapper (display, seat_get_string_property (seat, "session-wrapper"));
484
display_set_hide_users_hint (display, seat_get_boolean_property (seat, "greeter-hide-users"));
485
display_set_show_manual_login_hint (display, seat_get_boolean_property (seat, "greeter-show-manual-login"));
486
display_set_show_remote_login_hint (display, seat_get_boolean_property (seat, "greeter-show-remote-login"));
488
display_set_lock_hint (display, TRUE);
489
display_set_allow_guest (display, seat_get_allow_guest (seat));
490
display_set_greeter_allow_guest (display, seat_get_greeter_allow_guest (seat));
492
display_set_autologin_user (display, username, is_guest, autologin_timeout);
494
display_set_select_user_hint (display, username, is_guest);
496
session_name = seat_get_string_property (seat, "user-session");
497
display_set_user_session (display, SESSION_TYPE_LOCAL, session_name);
499
seat->priv->displays = g_list_append (seat->priv->displays, display);
500
g_signal_emit (seat, signals[DISPLAY_ADDED], 0, display);
502
/* Switch to this display if currently not looking at anything */
503
if (!seat->priv->active_display)
504
seat_set_active_display (seat, display);
506
return display_start (display);
510
seat_switch_to_greeter (Seat *seat)
512
g_return_val_if_fail (seat != NULL, FALSE);
514
if (!seat->priv->can_switch)
517
g_debug ("Switching to greeter");
518
return switch_to_user_or_start_greeter (seat, NULL, TRUE, FALSE, NULL, FALSE, FALSE, 0);
522
seat_switch_to_user (Seat *seat, const gchar *username, const gchar *session_name)
524
g_return_val_if_fail (seat != NULL, FALSE);
525
g_return_val_if_fail (username != NULL, FALSE);
527
if (!seat->priv->can_switch)
530
g_debug ("Switching to user %s", username);
531
return switch_to_user_or_start_greeter (seat, username, TRUE, FALSE, session_name, FALSE, FALSE, 0);
535
seat_switch_to_guest (Seat *seat, const gchar *session_name)
537
g_return_val_if_fail (seat != NULL, FALSE);
539
if (!seat->priv->can_switch || !seat_get_allow_guest (seat))
542
if (seat->priv->guest_username)
543
g_debug ("Switching to existing guest account %s", seat->priv->guest_username);
545
g_debug ("Switching to new guest account");
546
return switch_to_user_or_start_greeter (seat, seat->priv->guest_username, TRUE, TRUE, session_name, FALSE, TRUE, 0);
550
seat_lock (Seat *seat, const gchar *username)
552
g_return_val_if_fail (seat != NULL, FALSE);
554
if (!seat->priv->can_switch)
557
g_debug ("Locking seat");
558
return switch_to_user_or_start_greeter (seat, username, FALSE, FALSE, NULL, TRUE, FALSE, 0);
562
seat_stop (Seat *seat)
564
g_return_if_fail (seat != NULL);
566
if (seat->priv->stopping)
569
g_debug ("Stopping seat");
570
seat->priv->stopping = TRUE;
571
SEAT_GET_CLASS (seat)->stop (seat);
575
seat_get_is_stopping (Seat *seat)
577
g_return_val_if_fail (seat != NULL, FALSE);
578
return seat->priv->stopping;
582
seat_real_setup (Seat *seat)
587
seat_real_start (Seat *seat)
589
const gchar *autologin_username;
590
int autologin_timeout;
592
g_debug ("Starting seat");
594
/* Start showing a greeter */
595
autologin_username = seat_get_string_property (seat, "autologin-user");
596
if (g_strcmp0 (autologin_username, "") == 0)
597
autologin_username = NULL;
598
autologin_timeout = seat_get_integer_property (seat, "autologin-user-timeout");
600
if (autologin_username)
601
return switch_to_user_or_start_greeter (seat, autologin_username, TRUE, FALSE, NULL, FALSE, TRUE, autologin_timeout);
602
else if (seat_get_boolean_property (seat, "autologin-guest"))
603
return switch_to_user_or_start_greeter (seat, NULL, TRUE, TRUE, NULL, FALSE, TRUE, autologin_timeout);
605
return switch_to_user_or_start_greeter (seat, NULL, TRUE, FALSE, NULL, FALSE, FALSE, 0);
609
seat_real_set_active_display (Seat *seat, Display *display)
611
if (display == seat->priv->active_display)
614
if (seat->priv->active_display)
616
/* Stop the existing display if it is a greeter */
617
if (!display_get_username (seat->priv->active_display))
619
g_debug ("Stopping greeter display being switched from");
620
display_stop (seat->priv->active_display);
622
/* Otherwise lock it */
625
display_lock (seat->priv->active_display);
627
g_object_unref (seat->priv->active_display);
629
seat->priv->active_display = g_object_ref (display);
633
seat_real_stop (Seat *seat)
637
check_stopped (seat);
638
if (seat->priv->stopped)
641
for (link = seat->priv->displays; link; link = link->next)
643
Display *display = link->data;
644
display_stop (display);
649
seat_init (Seat *seat)
651
seat->priv = G_TYPE_INSTANCE_GET_PRIVATE (seat, SEAT_TYPE, SeatPrivate);
652
seat->priv->properties = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
656
seat_finalize (GObject *object)
660
self = SEAT (object);
662
g_hash_table_unref (self->priv->properties);
663
g_free (self->priv->guest_username);
664
g_list_free_full (self->priv->displays, g_object_unref);
665
if (self->priv->active_display)
666
g_object_unref (self->priv->active_display);
668
G_OBJECT_CLASS (seat_parent_class)->finalize (object);
672
seat_class_init (SeatClass *klass)
674
GObjectClass *object_class = G_OBJECT_CLASS (klass);
676
klass->setup = seat_real_setup;
677
klass->start = seat_real_start;
678
klass->set_active_display = seat_real_set_active_display;
679
klass->run_script = seat_real_run_script;
680
klass->stop = seat_real_stop;
682
object_class->finalize = seat_finalize;
684
g_type_class_add_private (klass, sizeof (SeatPrivate));
686
signals[DISPLAY_ADDED] =
687
g_signal_new ("display-added",
688
G_TYPE_FROM_CLASS (klass),
690
G_STRUCT_OFFSET (SeatClass, display_added),
692
g_cclosure_marshal_VOID__OBJECT,
693
G_TYPE_NONE, 1, DISPLAY_TYPE);
694
signals[DISPLAY_REMOVED] =
695
g_signal_new ("display-removed",
696
G_TYPE_FROM_CLASS (klass),
698
G_STRUCT_OFFSET (SeatClass, display_removed),
700
g_cclosure_marshal_VOID__OBJECT,
701
G_TYPE_NONE, 1, DISPLAY_TYPE);
703
g_signal_new ("stopped",
704
G_TYPE_FROM_CLASS (klass),
706
G_STRUCT_OFFSET (SeatClass, stopped),
708
g_cclosure_marshal_VOID__VOID,