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 <config.h>
13
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <sys/stat.h>
17 #include <glib.h>
18 #include <glib/gi18n.h>
19 #include <unistd.h>
20 #include <fcntl.h>
21 #include <sys/stat.h>
22 #include <errno.h>
23
24 #include "configuration.h"
25 #include "display-manager.h"
26 #include "display-manager-service.h"
27 #include "xdmcp-server.h"
28 #include "vnc-server.h"
29 #include "seat-xdmcp-session.h"
30 #include "seat-xvnc.h"
31 #include "x-server.h"
32 #include "process.h"
33 #include "session-child.h"
34 #include "shared-data-manager.h"
35 #include "user-list.h"
36 #include "login1.h"
37 #include "log-file.h"
38
39 static gchar *config_path = NULL;
40 static GMainLoop *loop = NULL;
41 static GTimer *log_timer;
42 static int log_fd = -1;
43 static gboolean debug = FALSE;
44
45 static DisplayManager *display_manager = NULL;
46 static DisplayManagerService *display_manager_service = NULL;
47 static XDMCPServer *xdmcp_server = NULL;
48 static guint xdmcp_client_count = 0;
49 static VNCServer *vnc_server = NULL;
50 static guint vnc_client_count = 0;
51 static gint exit_code = EXIT_SUCCESS;
52
53 static gboolean update_login1_seat (Login1Seat *login1_seat);
54
55 static void
log_cb(const gchar * log_domain,GLogLevelFlags log_level,const gchar * message,gpointer data)56 log_cb (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer data)
57 {
58 const gchar *prefix;
59 switch (log_level & G_LOG_LEVEL_MASK)
60 {
61 case G_LOG_LEVEL_ERROR:
62 prefix = "ERROR:";
63 break;
64 case G_LOG_LEVEL_CRITICAL:
65 prefix = "CRITICAL:";
66 break;
67 case G_LOG_LEVEL_WARNING:
68 prefix = "WARNING:";
69 break;
70 case G_LOG_LEVEL_MESSAGE:
71 prefix = "MESSAGE:";
72 break;
73 case G_LOG_LEVEL_INFO:
74 prefix = "INFO:";
75 break;
76 case G_LOG_LEVEL_DEBUG:
77 prefix = "DEBUG:";
78 break;
79 default:
80 prefix = "LOG:";
81 break;
82 }
83
84 g_autofree gchar *text = g_strdup_printf ("[%+.2fs] %s %s\n", g_timer_elapsed (log_timer, NULL), prefix, message);
85
86 /* Log everything to a file */
87 if (log_fd >= 0)
88 {
89 ssize_t n_written = write (log_fd, text, strlen (text));
90 if (n_written < 0)
91 ; /* Check result so compiler doesn't warn about it */
92 }
93
94 /* Log to stderr if requested */
95 if (debug)
96 g_printerr ("%s", text);
97 else
98 g_log_default_handler (log_domain, log_level, message, data);
99 }
100
101 static void
log_init(void)102 log_init (void)
103 {
104 log_timer = g_timer_new ();
105
106 /* Log to a file */
107 g_autofree gchar *log_dir = config_get_string (config_get_instance (), "LightDM", "log-directory");
108 g_autofree gchar *path = g_build_filename (log_dir, "lightdm.log", NULL);
109
110 gboolean backup_logs = config_get_boolean (config_get_instance (), "LightDM", "backup-logs");
111 log_fd = log_file_open (path, backup_logs ? LOG_MODE_BACKUP_AND_TRUNCATE : LOG_MODE_APPEND);
112 fcntl (log_fd, F_SETFD, FD_CLOEXEC);
113 g_log_set_default_handler (log_cb, NULL);
114
115 g_debug ("Logging to %s", path);
116 }
117
118 static GList*
get_config_sections(const gchar * seat_name)119 get_config_sections (const gchar *seat_name)
120 {
121 /* Load seat defaults first */
122 GList *config_sections = g_list_append (NULL, g_strdup ("Seat:*"));
123
124 g_auto(GStrv) groups = config_get_groups (config_get_instance ());
125 for (gchar **i = groups; *i; i++)
126 {
127 if (g_str_has_prefix (*i, "Seat:") && strcmp (*i, "Seat:*") != 0)
128 {
129 const gchar *seat_name_glob = *i + strlen ("Seat:");
130 if (g_pattern_match_simple (seat_name_glob, seat_name ? seat_name : ""))
131 config_sections = g_list_append (config_sections, g_strdup (*i));
132 }
133 }
134
135 return config_sections;
136 }
137
138 static void
set_seat_properties(Seat * seat,const gchar * seat_name)139 set_seat_properties (Seat *seat, const gchar *seat_name)
140 {
141 GList *sections = get_config_sections (seat_name);
142 for (GList *link = sections; link; link = link->next)
143 {
144 const gchar *section = link->data;
145 g_auto(GStrv) keys = NULL;
146
147 keys = config_get_keys (config_get_instance (), section);
148
149 l_debug (seat, "Loading properties from config section %s", section);
150 for (gint i = 0; keys && keys[i]; i++)
151 {
152 g_autofree gchar *value = config_get_string (config_get_instance (), section, keys[i]);
153 seat_set_property (seat, keys[i], value);
154 }
155 }
156 g_list_free_full (sections, g_free);
157 }
158
159 static void
signal_cb(Process * process,int signum)160 signal_cb (Process *process, int signum)
161 {
162 switch (signum)
163 {
164 case SIGINT:
165 case SIGTERM:
166 g_debug ("Caught %s signal, shutting down", g_strsignal (signum));
167 display_manager_stop (display_manager);
168 // FIXME: Stop XDMCP server
169 break;
170 case SIGUSR1:
171 case SIGUSR2:
172 case SIGHUP:
173 break;
174 }
175 }
176
177 static void
display_manager_stopped_cb(DisplayManager * display_manager)178 display_manager_stopped_cb (DisplayManager *display_manager)
179 {
180 g_debug ("Stopping daemon");
181 g_main_loop_quit (loop);
182 }
183
184 static Seat *
create_seat(const gchar * module_name,const gchar * name)185 create_seat (const gchar *module_name, const gchar *name)
186 {
187 if (strcmp (module_name, "xlocal") == 0) {
188 g_warning ("Seat type 'xlocal' is deprecated, use 'type=local' instead");
189 module_name = "local";
190 }
191
192 Seat *seat = seat_new (module_name);
193 if (!seat)
194 return NULL;
195
196 seat_set_name (seat, name);
197 return seat;
198 }
199
200 static Seat *
service_add_xlocal_seat_cb(DisplayManagerService * service,gint display_number)201 service_add_xlocal_seat_cb (DisplayManagerService *service, gint display_number)
202 {
203 g_debug ("Adding local X seat :%d", display_number);
204
205 g_autoptr(Seat) seat = create_seat ("xremote", "xremote0"); // FIXME: What to use for a name?
206 if (!seat)
207 return NULL;
208
209 set_seat_properties (seat, NULL);
210 g_autofree gchar *display_number_string = g_strdup_printf ("%d", display_number);
211 seat_set_property (seat, "xserver-display-number", display_number_string);
212
213 if (!display_manager_add_seat (display_manager, seat))
214 return NULL;
215
216 return g_steal_pointer (&seat);
217 }
218
219 static void
display_manager_seat_removed_cb(DisplayManager * display_manager,Seat * seat)220 display_manager_seat_removed_cb (DisplayManager *display_manager, Seat *seat)
221 {
222 /* If we have fallback types registered for the seat, let's try them
223 before giving up. */
224 g_auto(GStrv) types = seat_get_string_list_property (seat, "type");
225 g_autoptr(GString) next_types = g_string_new ("");
226 g_autoptr(Seat) next_seat = NULL;
227 for (gchar **iter = types; iter && *iter; iter++)
228 {
229 if (iter == types)
230 continue; // skip first one, that is our current seat type
231
232 if (!next_seat)
233 {
234 next_seat = create_seat (*iter, seat_get_name (seat));
235 g_string_assign (next_types, *iter);
236 }
237 else
238 {
239 // Build up list of types to try next time
240 g_string_append_c (next_types, ';');
241 g_string_append (next_types, *iter);
242 }
243 }
244
245 if (next_seat)
246 {
247 set_seat_properties (next_seat, seat_get_name (seat));
248
249 // We set this manually on default seat. Let's port it over if needed.
250 if (seat_get_boolean_property (seat, "exit-on-failure"))
251 seat_set_property (next_seat, "exit-on-failure", "true");
252
253 seat_set_property (next_seat, "type", next_types->str);
254
255 display_manager_add_seat (display_manager, next_seat);
256 }
257 else if (seat_get_boolean_property (seat, "exit-on-failure"))
258 {
259 g_debug ("Required seat has stopped");
260 exit_code = EXIT_FAILURE;
261 display_manager_stop (display_manager);
262 }
263 }
264
265 static gboolean
xdmcp_session_cb(XDMCPServer * server,XDMCPSession * session)266 xdmcp_session_cb (XDMCPServer *server, XDMCPSession *session)
267 {
268 g_autoptr(SeatXDMCPSession) seat = seat_xdmcp_session_new (session);
269
270 g_autofree gchar *name = g_strdup_printf ("xdmcp%d", xdmcp_client_count);
271 xdmcp_client_count++;
272
273 seat_set_name (SEAT (seat), name);
274 set_seat_properties (SEAT (seat), NULL);
275 return display_manager_add_seat (display_manager, SEAT (seat));
276 }
277
278 static void
vnc_connection_cb(VNCServer * server,GSocket * connection)279 vnc_connection_cb (VNCServer *server, GSocket *connection)
280 {
281 g_autoptr(SeatXVNC) seat = seat_xvnc_new (connection);
282
283 g_autofree gchar *name = g_strdup_printf ("vnc%d", vnc_client_count);
284 vnc_client_count++;
285
286 seat_set_name (SEAT (seat), name);
287 set_seat_properties (SEAT (seat), NULL);
288 display_manager_add_seat (display_manager, SEAT (seat));
289 }
290
291 static void
start_display_manager(void)292 start_display_manager (void)
293 {
294 display_manager_start (display_manager);
295
296 /* Start the XDMCP server */
297 if (config_get_boolean (config_get_instance (), "XDMCPServer", "enabled"))
298 {
299 xdmcp_server = xdmcp_server_new ();
300 if (config_has_key (config_get_instance (), "XDMCPServer", "port"))
301 {
302 gint port;
303 port = config_get_integer (config_get_instance (), "XDMCPServer", "port");
304 if (port > 0)
305 xdmcp_server_set_port (xdmcp_server, port);
306 }
307 g_autofree gchar *listen_address = config_get_string (config_get_instance (), "XDMCPServer", "listen-address");
308 xdmcp_server_set_listen_address (xdmcp_server, listen_address);
309 g_autofree gchar *hostname = config_get_string (config_get_instance (), "XDMCPServer", "hostname");
310 xdmcp_server_set_hostname (xdmcp_server, hostname);
311 g_signal_connect (xdmcp_server, XDMCP_SERVER_SIGNAL_NEW_SESSION, G_CALLBACK (xdmcp_session_cb), NULL);
312
313 g_autofree gchar *key_name = config_get_string (config_get_instance (), "XDMCPServer", "key");
314 g_autofree gchar *key = NULL;
315 if (key_name)
316 {
317 g_autofree gchar *path = g_build_filename (config_get_directory (config_get_instance ()), "keys.conf", NULL);
318
319 g_autoptr(GKeyFile) keys = g_key_file_new ();
320 g_autoptr(GError) error = NULL;
321 gboolean result = g_key_file_load_from_file (keys, path, G_KEY_FILE_NONE, &error);
322 if (error)
323 g_warning ("Unable to load keys from %s: %s", path, error->message);
324
325 if (result)
326 {
327 if (g_key_file_has_key (keys, "keyring", key_name, NULL))
328 key = g_key_file_get_string (keys, "keyring", key_name, NULL);
329 else
330 g_warning ("Key %s not defined", key_name);
331 }
332 }
333 if (key)
334 xdmcp_server_set_key (xdmcp_server, key);
335
336 if (key_name && !key)
337 {
338 exit_code = EXIT_FAILURE;
339 display_manager_stop (display_manager);
340 return;
341 }
342 else
343 {
344 g_debug ("Starting XDMCP server on UDP/IP port %d", xdmcp_server_get_port (xdmcp_server));
345 xdmcp_server_start (xdmcp_server);
346 }
347 }
348
349 /* Start the VNC server */
350 if (config_get_boolean (config_get_instance (), "VNCServer", "enabled"))
351 {
352 g_autofree gchar *path = g_find_program_in_path ("Xvnc");
353 if (path)
354 {
355 vnc_server = vnc_server_new ();
356 if (config_has_key (config_get_instance (), "VNCServer", "port"))
357 {
358 gint port = config_get_integer (config_get_instance (), "VNCServer", "port");
359 if (port > 0)
360 vnc_server_set_port (vnc_server, port);
361 }
362 g_autofree gchar *listen_address = config_get_string (config_get_instance (), "VNCServer", "listen-address");
363 vnc_server_set_listen_address (vnc_server, listen_address);
364 g_signal_connect (vnc_server, VNC_SERVER_SIGNAL_NEW_CONNECTION, G_CALLBACK (vnc_connection_cb), NULL);
365
366 g_debug ("Starting VNC server on TCP/IP port %d", vnc_server_get_port (vnc_server));
367 vnc_server_start (vnc_server);
368 }
369 else
370 g_warning ("Can't start VNC server, Xvnc is not in the path");
371 }
372 }
373 static void
service_ready_cb(DisplayManagerService * service)374 service_ready_cb (DisplayManagerService *service)
375 {
376 start_display_manager ();
377 }
378
379 static void
service_name_lost_cb(DisplayManagerService * service)380 service_name_lost_cb (DisplayManagerService *service)
381 {
382 exit (EXIT_FAILURE);
383 }
384
385 static gboolean
add_login1_seat(Login1Seat * login1_seat)386 add_login1_seat (Login1Seat *login1_seat)
387 {
388 const gchar *seat_name = login1_seat_get_id (login1_seat);
389 g_debug ("New seat added from logind: %s", seat_name);
390 gboolean is_seat0 = strcmp (seat_name, "seat0") == 0;
391
392 GList *config_sections = get_config_sections (seat_name);
393 g_auto(GStrv) types = NULL;
394 for (GList *link = g_list_last (config_sections); link; link = link->prev)
395 {
396 gchar *config_section = link->data;
397 types = config_get_string_list (config_get_instance (), config_section, "type");
398 if (types)
399 break;
400 }
401 g_list_free_full (config_sections, g_free);
402
403 g_autoptr(Seat) seat = NULL;
404 for (gchar **type = types; !seat && type && *type; type++)
405 seat = create_seat (*type, seat_name);
406
407 if (seat)
408 {
409 set_seat_properties (seat, seat_name);
410
411 if (!login1_seat_get_can_multi_session (login1_seat))
412 {
413 g_debug ("Seat %s has property CanMultiSession=no", seat_name);
414 /* XXX: uncomment this line after bug #1371250 is closed.
415 seat_set_property (seat, "allow-user-switching", "false"); */
416 }
417
418 if (is_seat0)
419 seat_set_property (seat, "exit-on-failure", "true");
420 }
421 else
422 {
423 g_debug ("Unable to create seat: %s", seat_name);
424 return FALSE;
425 }
426
427 gboolean started = display_manager_add_seat (display_manager, seat);
428 if (!started)
429 g_debug ("Failed to start seat: %s", seat_name);
430
431 return started;
432 }
433
434 static void
remove_login1_seat(Login1Seat * login1_seat)435 remove_login1_seat (Login1Seat *login1_seat)
436 {
437 Seat *seat = display_manager_get_seat (display_manager, login1_seat_get_id (login1_seat));
438 if (seat)
439 seat_stop (seat);
440 }
441
442 static void
seat_stopped_cb(Seat * seat,Login1Seat * login1_seat)443 seat_stopped_cb (Seat *seat, Login1Seat *login1_seat)
444 {
445 update_login1_seat (login1_seat);
446 g_signal_handlers_disconnect_matched (seat, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, login1_seat);
447 }
448
449 static gboolean
update_login1_seat(Login1Seat * login1_seat)450 update_login1_seat (Login1Seat *login1_seat)
451 {
452 if (!config_get_boolean (config_get_instance (), "LightDM", "logind-check-graphical") ||
453 login1_seat_get_can_graphical (login1_seat))
454 {
455 /* Wait for existing seat to stop or ignore if we already have a valid seat */
456 Seat *seat = display_manager_get_seat (display_manager, login1_seat_get_id (login1_seat));
457 if (seat)
458 {
459 if (seat_get_is_stopping (seat))
460 g_signal_connect (seat, SEAT_SIGNAL_STOPPED, G_CALLBACK (seat_stopped_cb), login1_seat);
461 return TRUE;
462 }
463
464 return add_login1_seat (login1_seat);
465 }
466 else
467 {
468 remove_login1_seat (login1_seat);
469 return TRUE;
470 }
471 }
472
473 static void
login1_can_graphical_changed_cb(Login1Seat * login1_seat)474 login1_can_graphical_changed_cb (Login1Seat *login1_seat)
475 {
476 g_debug ("Seat %s changes graphical state to %s", login1_seat_get_id (login1_seat), login1_seat_get_can_graphical (login1_seat) ? "true" : "false");
477 update_login1_seat (login1_seat);
478 }
479
480 static void
login1_active_session_changed_cb(Login1Seat * login1_seat,const gchar * login1_session_id)481 login1_active_session_changed_cb (Login1Seat *login1_seat, const gchar *login1_session_id)
482 {
483 g_debug ("Seat %s changes active session to %s", login1_seat_get_id (login1_seat), login1_session_id);
484
485 Seat *seat = display_manager_get_seat (display_manager, login1_seat_get_id (login1_seat));
486 if (seat)
487 {
488 Session *active_session = seat_get_expected_active_session (seat);
489 if (active_session != NULL &&
490 g_strcmp0 (login1_session_id, session_get_login1_session_id (active_session)) == 0)
491 {
492 // Session is already active
493 g_debug ("Session %s is already active", login1_session_id);
494 return;
495 }
496
497 active_session = seat_find_session_by_login1_id (seat, login1_session_id);
498 if (active_session != NULL)
499 {
500 g_debug ("Activating session %s", login1_session_id);
501 seat_set_externally_activated_session (seat, active_session);
502 return;
503
504 }
505 }
506 }
507
508 static gboolean
login1_add_seat(Login1Seat * login1_seat)509 login1_add_seat (Login1Seat *login1_seat)
510 {
511 if (config_get_boolean (config_get_instance (), "LightDM", "logind-check-graphical"))
512 g_signal_connect (login1_seat, "can-graphical-changed", G_CALLBACK (login1_can_graphical_changed_cb), NULL);
513
514 g_signal_connect (login1_seat, LOGIN1_SIGNAL_ACTIVE_SESION_CHANGED, G_CALLBACK (login1_active_session_changed_cb), NULL);
515
516 return update_login1_seat (login1_seat);
517 }
518
519 static void
login1_service_seat_added_cb(Login1Service * service,Login1Seat * login1_seat)520 login1_service_seat_added_cb (Login1Service *service, Login1Seat *login1_seat)
521 {
522 if (login1_seat_get_can_graphical (login1_seat))
523 g_debug ("Seat %s added from logind", login1_seat_get_id (login1_seat));
524 else
525 g_debug ("Seat %s added from logind without graphical output", login1_seat_get_id (login1_seat));
526
527 login1_add_seat (login1_seat);
528 }
529
530 static void
login1_service_seat_removed_cb(Login1Service * service,Login1Seat * login1_seat)531 login1_service_seat_removed_cb (Login1Service *service, Login1Seat *login1_seat)
532 {
533 g_debug ("Seat %s removed from logind", login1_seat_get_id (login1_seat));
534 g_signal_handlers_disconnect_matched (login1_seat, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, login1_can_graphical_changed_cb, NULL);
535 g_signal_handlers_disconnect_matched (login1_seat, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, login1_active_session_changed_cb, NULL);
536 remove_login1_seat (login1_seat);
537 }
538
539 int
main(int argc,char ** argv)540 main (int argc, char **argv)
541 {
542 /* Disable the SIGPIPE handler - this is a stupid Unix hangover behaviour.
543 * We will handle pipes / sockets being closed instead of having the whole daemon be killed...
544 * http://stackoverflow.com/questions/8369506/why-does-sigpipe-exist
545 * Similar case for SIGHUP.
546 */
547 struct sigaction action;
548 action.sa_handler = SIG_IGN;
549 sigemptyset (&action.sa_mask);
550 action.sa_flags = SA_RESTART;
551 sigaction (SIGPIPE, &action, NULL);
552 sigaction (SIGHUP, &action, NULL);
553
554 /* When lightdm starts sessions it needs to run itself in a new mode */
555 if (argc >= 2 && strcmp (argv[1], "--session-child") == 0)
556 return session_child_run (argc, argv);
557
558 #if !defined(GLIB_VERSION_2_36)
559 g_type_init ();
560 #endif
561 loop = g_main_loop_new (NULL, FALSE);
562
563 GList *messages = g_list_append (NULL, g_strdup_printf ("Starting Light Display Manager %s, UID=%i PID=%i", VERSION, getuid (), getpid ()));
564
565 g_signal_connect (process_get_current (), PROCESS_SIGNAL_GOT_SIGNAL, G_CALLBACK (signal_cb), NULL);
566
567 g_autoptr(GOptionContext) option_context = g_option_context_new (/* Arguments and description for --help test */
568 _("- Display Manager"));
569 gboolean test_mode = FALSE;
570 gchar *pid_path = "/var/run/lightdm.pid";
571 gchar *log_dir = NULL;
572 gchar *run_dir = NULL;
573 gchar *cache_dir = NULL;
574 gboolean show_config = FALSE, show_version = FALSE;
575 GOptionEntry options[] =
576 {
577 { "config", 'c', 0, G_OPTION_ARG_STRING, &config_path,
578 /* Help string for command line --config flag */
579 N_("Use configuration file"), "FILE" },
580 { "debug", 'd', 0, G_OPTION_ARG_NONE, &debug,
581 /* Help string for command line --debug flag */
582 N_("Print debugging messages"), NULL },
583 { "test-mode", 0, 0, G_OPTION_ARG_NONE, &test_mode,
584 /* Help string for command line --test-mode flag */
585 N_("Run as unprivileged user, skipping things that require root access"), NULL },
586 { "pid-file", 0, 0, G_OPTION_ARG_STRING, &pid_path,
587 /* Help string for command line --pid-file flag */
588 N_("File to write PID into"), "FILE" },
589 { "log-dir", 0, 0, G_OPTION_ARG_STRING, &log_dir,
590 /* Help string for command line --log-dir flag */
591 N_("Directory to write logs to"), "DIRECTORY" },
592 { "run-dir", 0, 0, G_OPTION_ARG_STRING, &run_dir,
593 /* Help string for command line --run-dir flag */
594 N_("Directory to store running state"), "DIRECTORY" },
595 { "cache-dir", 0, 0, G_OPTION_ARG_STRING, &cache_dir,
596 /* Help string for command line --cache-dir flag */
597 N_("Directory to cache information"), "DIRECTORY" },
598 { "show-config", 0, 0, G_OPTION_ARG_NONE, &show_config,
599 /* Help string for command line --show-config flag */
600 N_("Show combined configuration"), NULL },
601 { "version", 'v', 0, G_OPTION_ARG_NONE, &show_version,
602 /* Help string for command line --version flag */
603 N_("Show release version"), NULL },
604 { NULL }
605 };
606 g_option_context_add_main_entries (option_context, options, GETTEXT_PACKAGE);
607 g_autoptr(GError) error = NULL;
608 gboolean result = g_option_context_parse (option_context, &argc, &argv, &error);
609 if (error)
610 g_printerr ("%s\n", error->message);
611 if (!result)
612 {
613 g_printerr (/* Text printed out when an unknown command-line argument provided */
614 _("Run '%s --help' to see a full list of available command line options."), argv[0]);
615 g_printerr ("\n");
616 return EXIT_FAILURE;
617 }
618
619 /* Show combined configuration if user requested it */
620 if (show_config)
621 {
622 if (!config_load_from_standard_locations (config_get_instance (), config_path, NULL))
623 return EXIT_FAILURE;
624
625 /* Number sources */
626 GList *sources = config_get_sources (config_get_instance ());
627 g_autoptr(GHashTable) source_ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
628 const gchar *last_source = "";
629 int i = 0;
630 for (GList *link = sources; link; i++, link = link->next)
631 {
632 const gchar *path = link->data;
633 gchar *id;
634 if (i < 26)
635 id = g_strdup_printf ("%c", 'A' + i);
636 else
637 id = g_strdup_printf ("%d", i);
638 g_hash_table_insert (source_ids, g_strdup (path), id);
639 last_source = id;
640 }
641 g_autofree gchar *empty_source = g_strdup (last_source);
642 for (i = 0; empty_source[i] != '\0'; i++)
643 empty_source[i] = ' ';
644
645 /* Print out keys */
646 g_auto(GStrv) groups = config_get_groups (config_get_instance ());
647 for (i = 0; groups[i]; i++)
648 {
649 if (i != 0)
650 g_printerr ("\n");
651 g_printerr ("%s [%s]\n", empty_source, groups[i]);
652
653 g_auto(GStrv) keys = config_get_keys (config_get_instance (), groups[i]);
654 for (int j = 0; keys && keys[j]; j++)
655 {
656 const gchar *source, *id;
657 g_autofree gchar *value = NULL;
658
659 source = config_get_source (config_get_instance (), groups[i], keys[j]);
660 id = source ? g_hash_table_lookup (source_ids, source) : empty_source;
661 value = config_get_string (config_get_instance (), groups[i], keys[j]);
662 g_printerr ("%s %s=%s\n", id, keys[j], value);
663 }
664
665 }
666
667 /* Show mapping from source number to path */
668 g_printerr ("\n");
669 g_printerr ("Sources:\n");
670 for (GList *link = sources; link; link = link->next)
671 {
672 const gchar *path = link->data;
673 const gchar *source = g_hash_table_lookup (source_ids, path);
674 g_printerr ("%s %s\n", source, path);
675 }
676
677 return EXIT_SUCCESS;
678 }
679
680 if (show_version)
681 {
682 /* NOTE: Is not translated so can be easily parsed */
683 g_printerr ("lightdm %s\n", VERSION);
684 return EXIT_SUCCESS;
685 }
686
687 if (!test_mode && getuid () != 0)
688 {
689 g_printerr ("Only root can run Light Display Manager. To run as a regular user for testing run with the --test-mode flag.\n");
690 return EXIT_FAILURE;
691 }
692
693 /* If running inside an X server use Xephyr for display */
694 if (getenv ("DISPLAY") && getuid () != 0)
695 {
696 g_autofree gchar *x_server_path = g_find_program_in_path ("Xephyr");
697 if (!x_server_path)
698 {
699 g_printerr ("Running inside an X server requires Xephyr to be installed but it cannot be found. Please install it or update your PATH environment variable.\n");
700 return EXIT_FAILURE;
701 }
702 }
703
704 /* Make sure the system binary directory (where the greeters are installed) is in the path */
705 if (test_mode)
706 {
707 const gchar *path = g_getenv ("PATH");
708 g_autofree gchar *new_path = NULL;
709 if (path)
710 new_path = g_strdup_printf ("%s:%s", path, SBIN_DIR);
711 else
712 new_path = g_strdup (SBIN_DIR);
713 g_setenv ("PATH", new_path, TRUE);
714 }
715
716 /* Write PID file */
717 FILE *pid_file = fopen (pid_path, "w");
718 if (pid_file)
719 {
720 fprintf (pid_file, "%d\n", getpid ());
721 fclose (pid_file);
722 }
723
724 /* If not running as root write output to directories we control */
725 g_autofree gchar *default_log_dir = NULL;
726 g_autofree gchar *default_run_dir = NULL;
727 g_autofree gchar *default_cache_dir = NULL;
728 if (getuid () != 0)
729 {
730 default_log_dir = g_build_filename (g_get_user_cache_dir (), "lightdm", "log", NULL);
731 default_run_dir = g_build_filename (g_get_user_cache_dir (), "lightdm", "run", NULL);
732 default_cache_dir = g_build_filename (g_get_user_cache_dir (), "lightdm", "cache", NULL);
733 }
734 else
735 {
736 default_log_dir = g_strdup (LOG_DIR);
737 default_run_dir = g_strdup (RUN_DIR);
738 default_cache_dir = g_strdup (CACHE_DIR);
739 }
740
741 /* Load config file(s) */
742 if (!config_load_from_standard_locations (config_get_instance (), config_path, &messages))
743 exit (EXIT_FAILURE);
744 g_free (config_path);
745
746 /* Set default values */
747 if (!config_has_key (config_get_instance (), "LightDM", "start-default-seat"))
748 config_set_boolean (config_get_instance (), "LightDM", "start-default-seat", TRUE);
749 if (!config_has_key (config_get_instance (), "LightDM", "minimum-vt"))
750 config_set_integer (config_get_instance (), "LightDM", "minimum-vt", 7);
751 if (!config_has_key (config_get_instance (), "LightDM", "guest-account-script"))
752 config_set_string (config_get_instance (), "LightDM", "guest-account-script", "guest-account");
753 if (!config_has_key (config_get_instance (), "LightDM", "greeter-user"))
754 config_set_string (config_get_instance (), "LightDM", "greeter-user", GREETER_USER);
755 if (!config_has_key (config_get_instance (), "LightDM", "lock-memory"))
756 config_set_boolean (config_get_instance (), "LightDM", "lock-memory", TRUE);
757 if (!config_has_key (config_get_instance (), "LightDM", "backup-logs"))
758 config_set_boolean (config_get_instance (), "LightDM", "backup-logs", TRUE);
759 if (!config_has_key (config_get_instance (), "LightDM", "dbus-service"))
760 config_set_boolean (config_get_instance (), "LightDM", "dbus-service", TRUE);
761 if (!config_has_key (config_get_instance (), "Seat:*", "type"))
762 config_set_string (config_get_instance (), "Seat:*", "type", "local");
763 if (!config_has_key (config_get_instance (), "Seat:*", "pam-service"))
764 config_set_string (config_get_instance (), "Seat:*", "pam-service", "lightdm");
765 if (!config_has_key (config_get_instance (), "Seat:*", "pam-autologin-service"))
766 config_set_string (config_get_instance (), "Seat:*", "pam-autologin-service", "lightdm-autologin");
767 if (!config_has_key (config_get_instance (), "Seat:*", "pam-greeter-service"))
768 config_set_string (config_get_instance (), "Seat:*", "pam-greeter-service", "lightdm-greeter");
769 if (!config_has_key (config_get_instance (), "Seat:*", "xserver-command"))
770 config_set_string (config_get_instance (), "Seat:*", "xserver-command", "X");
771 if (!config_has_key (config_get_instance (), "Seat:*", "xmir-command"))
772 config_set_string (config_get_instance (), "Seat:*", "xmir-command", "Xmir");
773 if (!config_has_key (config_get_instance (), "Seat:*", "xserver-share"))
774 config_set_boolean (config_get_instance (), "Seat:*", "xserver-share", TRUE);
775 if (!config_has_key (config_get_instance (), "Seat:*", "start-session"))
776 config_set_boolean (config_get_instance (), "Seat:*", "start-session", TRUE);
777 if (!config_has_key (config_get_instance (), "Seat:*", "allow-user-switching"))
778 config_set_boolean (config_get_instance (), "Seat:*", "allow-user-switching", TRUE);
779 if (!config_has_key (config_get_instance (), "Seat:*", "allow-guest"))
780 config_set_boolean (config_get_instance (), "Seat:*", "allow-guest", TRUE);
781 if (!config_has_key (config_get_instance (), "Seat:*", "greeter-allow-guest"))
782 config_set_boolean (config_get_instance (), "Seat:*", "greeter-allow-guest", TRUE);
783 if (!config_has_key (config_get_instance (), "Seat:*", "greeter-show-remote-login"))
784 config_set_boolean (config_get_instance (), "Seat:*", "greeter-show-remote-login", TRUE);
785 if (!config_has_key (config_get_instance (), "Seat:*", "greeter-session"))
786 config_set_string (config_get_instance (), "Seat:*", "greeter-session", DEFAULT_GREETER_SESSION);
787 if (!config_has_key (config_get_instance (), "Seat:*", "user-session"))
788 config_set_string (config_get_instance (), "Seat:*", "user-session", DEFAULT_USER_SESSION);
789 if (!config_has_key (config_get_instance (), "Seat:*", "session-wrapper"))
790 config_set_string (config_get_instance (), "Seat:*", "session-wrapper", "lightdm-session");
791 if (!config_has_key (config_get_instance (), "LightDM", "log-directory"))
792 config_set_string (config_get_instance (), "LightDM", "log-directory", default_log_dir);
793 if (!config_has_key (config_get_instance (), "LightDM", "run-directory"))
794 config_set_string (config_get_instance (), "LightDM", "run-directory", default_run_dir);
795 if (!config_has_key (config_get_instance (), "LightDM", "cache-directory"))
796 config_set_string (config_get_instance (), "LightDM", "cache-directory", default_cache_dir);
797 if (!config_has_key (config_get_instance (), "LightDM", "sessions-directory"))
798 config_set_string (config_get_instance (), "LightDM", "sessions-directory", SESSIONS_DIR);
799 if (!config_has_key (config_get_instance (), "LightDM", "remote-sessions-directory"))
800 config_set_string (config_get_instance (), "LightDM", "remote-sessions-directory", REMOTE_SESSIONS_DIR);
801 if (!config_has_key (config_get_instance (), "LightDM", "greeters-directory"))
802 {
803 g_autoptr(GPtrArray) dirs = g_ptr_array_new_with_free_func (g_free);
804 const gchar * const *data_dirs = g_get_system_data_dirs ();
805 for (int i = 0; data_dirs[i]; i++)
806 g_ptr_array_add (dirs, g_build_filename (data_dirs[i], "lightdm/greeters", NULL));
807 for (int i = 0; data_dirs[i]; i++)
808 g_ptr_array_add (dirs, g_build_filename (data_dirs[i], "xgreeters", NULL));
809 g_ptr_array_add (dirs, NULL);
810 g_autofree gchar *value = g_strjoinv (":", (gchar **) dirs->pdata);
811 config_set_string (config_get_instance (), "LightDM", "greeters-directory", value);
812 }
813 if (!config_has_key (config_get_instance (), "XDMCPServer", "hostname"))
814 config_set_string (config_get_instance (), "XDMCPServer", "hostname", g_get_host_name ());
815
816 /* Override defaults */
817 if (log_dir)
818 config_set_string (config_get_instance (), "LightDM", "log-directory", log_dir);
819 g_free (log_dir);
820 if (run_dir)
821 config_set_string (config_get_instance (), "LightDM", "run-directory", run_dir);
822 g_free (run_dir);
823 if (cache_dir)
824 config_set_string (config_get_instance (), "LightDM", "cache-directory", cache_dir);
825 g_free (cache_dir);
826
827 /* Create run and cache directories */
828 g_autofree gchar *log_dir_path = config_get_string (config_get_instance (), "LightDM", "log-directory");
829 if (g_mkdir_with_parents (log_dir_path, S_IRWXU | S_IXGRP | S_IXOTH) < 0)
830 g_warning ("Failed to make log directory %s: %s", log_dir_path, strerror (errno));
831 g_autofree gchar *run_dir_path = config_get_string (config_get_instance (), "LightDM", "run-directory");
832 if (g_mkdir_with_parents (run_dir_path, S_IRWXU | S_IXGRP | S_IXOTH) < 0)
833 g_warning ("Failed to make run directory %s: %s", run_dir_path, strerror (errno));
834 g_autofree gchar *cache_dir_path = config_get_string (config_get_instance (), "LightDM", "cache-directory");
835 if (g_mkdir_with_parents (cache_dir_path, S_IRWXU | S_IXGRP | S_IXOTH) < 0)
836 g_warning ("Failed to make cache directory %s: %s", cache_dir_path, strerror (errno));
837
838 log_init ();
839
840 /* Show queued messages once logging is complete */
841 for (GList *link = messages; link; link = link->next)
842 g_debug ("%s", (gchar *)link->data);
843 g_list_free_full (messages, g_free);
844
845 if (getuid () != 0)
846 g_debug ("Running in user mode");
847 if (getenv ("DISPLAY"))
848 g_debug ("Using Xephyr for X servers");
849
850 display_manager = display_manager_new ();
851 g_signal_connect (display_manager, DISPLAY_MANAGER_SIGNAL_STOPPED, G_CALLBACK (display_manager_stopped_cb), NULL);
852 g_signal_connect (display_manager, DISPLAY_MANAGER_SIGNAL_SEAT_REMOVED, G_CALLBACK (display_manager_seat_removed_cb), NULL);
853
854 if (config_get_boolean (config_get_instance (), "LightDM", "dbus-service"))
855 {
856 display_manager_service = display_manager_service_new (display_manager);
857 g_signal_connect (display_manager_service, DISPLAY_MANAGER_SERVICE_SIGNAL_ADD_XLOCAL_SEAT, G_CALLBACK (service_add_xlocal_seat_cb), NULL);
858 g_signal_connect (display_manager_service, DISPLAY_MANAGER_SERVICE_SIGNAL_READY, G_CALLBACK (service_ready_cb), NULL);
859 g_signal_connect (display_manager_service, DISPLAY_MANAGER_SERVICE_SIGNAL_NAME_LOST, G_CALLBACK (service_name_lost_cb), NULL);
860 display_manager_service_start (display_manager_service);
861 }
862 else
863 start_display_manager ();
864
865 shared_data_manager_start (shared_data_manager_get_instance ());
866
867 /* Connect to logind */
868 if (login1_service_connect (login1_service_get_instance ()))
869 {
870 /* Load dynamic seats from logind */
871 g_debug ("Monitoring logind for seats");
872
873 if (config_get_boolean (config_get_instance (), "LightDM", "start-default-seat"))
874 {
875 g_signal_connect (login1_service_get_instance (), LOGIN1_SERVICE_SIGNAL_SEAT_ADDED, G_CALLBACK (login1_service_seat_added_cb), NULL);
876 g_signal_connect (login1_service_get_instance (), LOGIN1_SERVICE_SIGNAL_SEAT_REMOVED, G_CALLBACK (login1_service_seat_removed_cb), NULL);
877
878 for (GList *link = login1_service_get_seats (login1_service_get_instance ()); link; link = link->next)
879 {
880 Login1Seat *login1_seat = link->data;
881 if (!login1_add_seat (login1_seat))
882 return EXIT_FAILURE;
883 }
884 }
885 }
886 else
887 {
888 if (config_get_boolean (config_get_instance (), "LightDM", "start-default-seat"))
889 {
890 g_debug ("Adding default seat");
891
892 g_auto(GStrv) types = config_get_string_list (config_get_instance (), "Seat:*", "type");
893 g_autoptr(Seat) seat = NULL;
894 for (gchar **type = types; type && *type; type++)
895 {
896 seat = create_seat (*type, "seat0");
897 if (seat)
898 break;
899 }
900 if (seat)
901 {
902 set_seat_properties (seat, NULL);
903 seat_set_property (seat, "exit-on-failure", "true");
904 if (!display_manager_add_seat (display_manager, seat))
905 return EXIT_FAILURE;
906 }
907 else
908 {
909 g_warning ("Failed to create default seat");
910 return EXIT_FAILURE;
911 }
912 }
913 }
914
915 g_main_loop_run (loop);
916
917 /* Clean up shared data manager */
918 shared_data_manager_cleanup ();
919
920 /* Clean up user list */
921 common_user_list_cleanup ();
922
923 /* Remove D-Bus interface */
924 g_clear_object (&display_manager_service);
925
926 /* Clean up display manager */
927 g_clear_object (&display_manager);
928
929 g_debug ("Exiting with return value %d", exit_code);
930 return exit_code;
931 }
932