1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2006 Ray Strode <rstrode@redhat.com>
4 * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301, USA.
20 */
21
22 #include "config.h"
23
24 #include <dirent.h>
25 #include <errno.h>
26 #include <fcntl.h>
27
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/resource.h>
31 #include <sys/socket.h>
32 #include <sys/types.h>
33 #include <sys/wait.h>
34 #include <unistd.h>
35 #include <pwd.h>
36 #include <grp.h>
37
38 #include <locale.h>
39
40 #include <glib.h>
41 #include <glib/gi18n.h>
42 #include <glib/gstdio.h>
43 #include <glib-object.h>
44 #include <gio/gio.h>
45
46 #include "gdm-session.h"
47 #include "gdm-session-glue.h"
48 #include "gdm-dbus-util.h"
49
50 #include "gdm-session.h"
51 #include "gdm-session-enum-types.h"
52 #include "gdm-session-worker-common.h"
53 #include "gdm-session-worker-job.h"
54 #include "gdm-session-worker-glue.h"
55 #include "gdm-common.h"
56
57 #include "gdm-settings-direct.h"
58 #include "gdm-settings-keys.h"
59
60 #define GDM_SESSION_DBUS_ERROR_CANCEL "org.gnome.DisplayManager.Session.Error.Cancel"
61 #define GDM_SESSION_DBUS_OBJECT_PATH "/org/gnome/DisplayManager/Session"
62
63 #define GDM_WORKER_DBUS_PATH "/org/gnome/DisplayManager/Worker"
64
65 typedef struct
66 {
67 GdmSession *session;
68 GdmSessionWorkerJob *job;
69 GPid worker_pid;
70 char *service_name;
71 GDBusMethodInvocation *starting_invocation;
72 char *starting_username;
73 GDBusMethodInvocation *pending_invocation;
74 GdmDBusWorkerManager *worker_manager_interface;
75 GdmDBusWorker *worker_proxy;
76 GCancellable *worker_cancellable;
77 char *session_id;
78 guint32 is_stopping : 1;
79
80 GPid reauth_pid_of_caller;
81 } GdmSessionConversation;
82
83 struct _GdmSessionPrivate
84 {
85 /* per open scope */
86 char *selected_program;
87 char *selected_session;
88 char *saved_session;
89 char *saved_language;
90 char *selected_user;
91 char *user_x11_authority_file;
92
93 char *timed_login_username;
94 int timed_login_delay;
95 GList *pending_timed_login_invocations;
96
97 GHashTable *conversations;
98
99 GdmSessionConversation *session_conversation;
100
101 char **conversation_environment;
102
103 GdmDBusUserVerifier *user_verifier_interface;
104 GHashTable *user_verifier_extensions;
105 GdmDBusGreeter *greeter_interface;
106 GdmDBusRemoteGreeter *remote_greeter_interface;
107 GdmDBusChooser *chooser_interface;
108
109 GList *pending_worker_connections;
110 GList *outside_connections;
111
112 GPid session_pid;
113
114 /* object lifetime scope */
115 char *session_type;
116 char *display_name;
117 char *display_hostname;
118 char *display_device;
119 char *display_seat_id;
120 char *display_x11_authority_file;
121 gboolean display_is_local;
122
123 GdmSessionVerificationMode verification_mode;
124
125 uid_t allowed_user;
126
127 char *fallback_session_name;
128
129 GDBusServer *worker_server;
130 GDBusServer *outside_server;
131 GHashTable *environment;
132
133 guint32 is_program_session : 1;
134 guint32 display_is_initial : 1;
135 #ifdef ENABLE_WAYLAND_SUPPORT
136 guint32 ignore_wayland : 1;
137 #endif
138 };
139
140 enum {
141 PROP_0,
142 PROP_VERIFICATION_MODE,
143 PROP_ALLOWED_USER,
144 PROP_DISPLAY_NAME,
145 PROP_DISPLAY_HOSTNAME,
146 PROP_DISPLAY_IS_LOCAL,
147 PROP_DISPLAY_IS_INITIAL,
148 PROP_SESSION_TYPE,
149 PROP_DISPLAY_DEVICE,
150 PROP_DISPLAY_SEAT_ID,
151 PROP_DISPLAY_X11_AUTHORITY_FILE,
152 PROP_USER_X11_AUTHORITY_FILE,
153 PROP_CONVERSATION_ENVIRONMENT,
154 #ifdef ENABLE_WAYLAND_SUPPORT
155 PROP_IGNORE_WAYLAND,
156 #endif
157 };
158
159 enum {
160 CONVERSATION_STARTED = 0,
161 CONVERSATION_STOPPED,
162 SETUP_COMPLETE,
163 CANCELLED,
164 HOSTNAME_SELECTED,
165 CLIENT_REJECTED,
166 CLIENT_CONNECTED,
167 CLIENT_DISCONNECTED,
168 CLIENT_READY_FOR_SESSION_TO_START,
169 DISCONNECTED,
170 AUTHENTICATION_FAILED,
171 VERIFICATION_COMPLETE,
172 SESSION_OPENED,
173 SESSION_STARTED,
174 SESSION_START_FAILED,
175 SESSION_EXITED,
176 SESSION_DIED,
177 REAUTHENTICATION_STARTED,
178 REAUTHENTICATED,
179 LAST_SIGNAL
180 };
181
182 #ifdef ENABLE_WAYLAND_SUPPORT
183 static gboolean gdm_session_is_wayland_session (GdmSession *self);
184 #endif
185 static void update_session_type (GdmSession *self);
186 static void set_session_type (GdmSession *self,
187 const char *session_type);
188 static guint signals [LAST_SIGNAL] = { 0, };
189
190 G_DEFINE_TYPE (GdmSession,
191 gdm_session,
192 G_TYPE_OBJECT);
193
194 static GdmSessionConversation *
find_conversation_by_name(GdmSession * self,const char * service_name)195 find_conversation_by_name (GdmSession *self,
196 const char *service_name)
197 {
198 GdmSessionConversation *conversation;
199
200 conversation = g_hash_table_lookup (self->priv->conversations, service_name);
201
202 if (conversation == NULL) {
203 g_warning ("Tried to look up non-existent conversation %s", service_name);
204 }
205
206 return conversation;
207 }
208
209 static void
report_and_stop_conversation(GdmSession * self,const char * service_name,GError * error)210 report_and_stop_conversation (GdmSession *self,
211 const char *service_name,
212 GError *error)
213 {
214 g_dbus_error_strip_remote_error (error);
215
216 if (self->priv->user_verifier_interface != NULL) {
217 if (g_error_matches (error,
218 GDM_SESSION_WORKER_ERROR,
219 GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE)) {
220 gdm_dbus_user_verifier_emit_service_unavailable (self->priv->user_verifier_interface,
221 service_name,
222 error->message);
223 } else {
224 gdm_dbus_user_verifier_emit_problem (self->priv->user_verifier_interface,
225 service_name,
226 error->message);
227 }
228 gdm_dbus_user_verifier_emit_verification_failed (self->priv->user_verifier_interface,
229 service_name);
230 }
231
232 gdm_session_stop_conversation (self, service_name);
233 }
234
235 static void
on_authenticate_cb(GdmDBusWorker * proxy,GAsyncResult * res,gpointer user_data)236 on_authenticate_cb (GdmDBusWorker *proxy,
237 GAsyncResult *res,
238 gpointer user_data)
239 {
240 GdmSessionConversation *conversation = user_data;
241 GdmSession *self;
242 char *service_name;
243
244 GError *error = NULL;
245 gboolean worked;
246
247 worked = gdm_dbus_worker_call_authenticate_finish (proxy, res, &error);
248
249 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED) ||
250 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
251 return;
252
253 self = conversation->session;
254 service_name = conversation->service_name;
255
256 if (worked) {
257 gdm_session_authorize (self, service_name);
258 } else {
259 g_signal_emit (self,
260 signals[AUTHENTICATION_FAILED],
261 0,
262 service_name,
263 conversation->worker_pid);
264 report_and_stop_conversation (self, service_name, error);
265 }
266 }
267
268 static void
on_authorize_cb(GdmDBusWorker * proxy,GAsyncResult * res,gpointer user_data)269 on_authorize_cb (GdmDBusWorker *proxy,
270 GAsyncResult *res,
271 gpointer user_data)
272 {
273 GdmSessionConversation *conversation = user_data;
274 GdmSession *self;
275 char *service_name;
276
277 GError *error = NULL;
278 gboolean worked;
279
280 worked = gdm_dbus_worker_call_authorize_finish (proxy, res, &error);
281
282 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED) ||
283 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
284 return;
285
286 self = conversation->session;
287 service_name = conversation->service_name;
288
289 if (worked) {
290 gdm_session_accredit (self, service_name);
291 } else {
292 report_and_stop_conversation (self, service_name, error);
293 }
294 }
295
296 static void
on_establish_credentials_cb(GdmDBusWorker * proxy,GAsyncResult * res,gpointer user_data)297 on_establish_credentials_cb (GdmDBusWorker *proxy,
298 GAsyncResult *res,
299 gpointer user_data)
300 {
301 GdmSessionConversation *conversation = user_data;
302 GdmSession *self;
303 char *service_name;
304
305 GError *error = NULL;
306 gboolean worked;
307
308 worked = gdm_dbus_worker_call_establish_credentials_finish (proxy, res, &error);
309
310 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED) ||
311 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
312 return;
313
314 self = g_object_ref (conversation->session);
315 service_name = g_strdup (conversation->service_name);
316
317 if (worked) {
318 if (self->priv->user_verifier_interface != NULL) {
319 gdm_dbus_user_verifier_emit_verification_complete (self->priv->user_verifier_interface,
320 service_name);
321 g_signal_emit (self, signals[VERIFICATION_COMPLETE], 0, service_name);
322 }
323
324 switch (self->priv->verification_mode) {
325 case GDM_SESSION_VERIFICATION_MODE_LOGIN:
326 case GDM_SESSION_VERIFICATION_MODE_CHOOSER:
327 gdm_session_open_session (self, service_name);
328 break;
329 case GDM_SESSION_VERIFICATION_MODE_REAUTHENTICATE:
330 default:
331 break;
332 }
333 } else {
334 report_and_stop_conversation (self, service_name, error);
335 }
336
337 g_free (service_name);
338 g_object_unref (self);
339 }
340
341 static char **
get_system_session_dirs(GdmSession * self)342 get_system_session_dirs (GdmSession *self)
343 {
344 GArray *search_array = NULL;
345 char **search_dirs;
346
347 static const char *x_search_dirs[] = {
348 "/etc/X11/sessions/",
349 DMCONFDIR "/Sessions/",
350 DATADIR "/gdm/BuiltInSessions/",
351 DATADIR "/xsessions/",
352 };
353
354 static const char *wayland_search_dir = DATADIR "/wayland-sessions/";
355
356 search_array = g_array_new (TRUE, TRUE, sizeof (char *));
357
358 g_array_append_vals (search_array, x_search_dirs, G_N_ELEMENTS (x_search_dirs));
359
360 #ifdef ENABLE_WAYLAND_SUPPORT
361 if (!self->priv->ignore_wayland) {
362 #ifdef ENABLE_USER_DISPLAY_SERVER
363 g_array_prepend_val (search_array, wayland_search_dir);
364 #else
365 g_array_append_val (search_array, wayland_search_dir);
366 #endif
367 }
368 #endif
369
370 search_dirs = g_strdupv ((char **) search_array->data);
371
372 g_array_free (search_array, TRUE);
373
374 return search_dirs;
375 }
376
377 static gboolean
is_prog_in_path(const char * prog)378 is_prog_in_path (const char *prog)
379 {
380 char *f;
381 gboolean ret;
382
383 f = g_find_program_in_path (prog);
384 ret = (f != NULL);
385 g_free (f);
386 return ret;
387 }
388
389 static GKeyFile *
load_key_file_for_file(GdmSession * self,const char * file,char ** full_path)390 load_key_file_for_file (GdmSession *self,
391 const char *file,
392 char **full_path)
393 {
394 GKeyFile *key_file;
395 GError *error;
396 gboolean res;
397 char **search_dirs;
398
399 key_file = g_key_file_new ();
400
401 search_dirs = get_system_session_dirs (self),
402 error = NULL;
403 res = g_key_file_load_from_dirs (key_file,
404 file,
405 (const char **) search_dirs,
406 full_path,
407 G_KEY_FILE_NONE,
408 &error);
409 if (! res) {
410 g_debug ("GdmSession: File '%s' not found: %s", file, error->message);
411 g_error_free (error);
412 g_key_file_free (key_file);
413 key_file = NULL;
414 }
415
416 g_strfreev (search_dirs);
417
418 return key_file;
419 }
420
421 static gboolean
get_session_command_for_file(GdmSession * self,const char * file,char ** command)422 get_session_command_for_file (GdmSession *self,
423 const char *file,
424 char **command)
425 {
426 GKeyFile *key_file;
427 GError *error;
428 char *exec;
429 gboolean ret;
430 gboolean res;
431
432 exec = NULL;
433 ret = FALSE;
434 if (command != NULL) {
435 *command = NULL;
436 }
437
438 g_debug ("GdmSession: getting session command for file '%s'", file);
439 key_file = load_key_file_for_file (self, file, NULL);
440 if (key_file == NULL) {
441 goto out;
442 }
443
444 error = NULL;
445 res = g_key_file_get_boolean (key_file,
446 G_KEY_FILE_DESKTOP_GROUP,
447 G_KEY_FILE_DESKTOP_KEY_HIDDEN,
448 &error);
449 if (error == NULL && res) {
450 g_debug ("GdmSession: Session %s is marked as hidden", file);
451 goto out;
452 }
453
454 exec = g_key_file_get_string (key_file,
455 G_KEY_FILE_DESKTOP_GROUP,
456 G_KEY_FILE_DESKTOP_KEY_TRY_EXEC,
457 NULL);
458 if (exec != NULL) {
459 res = is_prog_in_path (exec);
460 g_free (exec);
461 exec = NULL;
462
463 if (! res) {
464 g_debug ("GdmSession: Command not found: %s",
465 G_KEY_FILE_DESKTOP_KEY_TRY_EXEC);
466 goto out;
467 }
468 }
469
470 error = NULL;
471 exec = g_key_file_get_string (key_file,
472 G_KEY_FILE_DESKTOP_GROUP,
473 G_KEY_FILE_DESKTOP_KEY_EXEC,
474 &error);
475 if (error != NULL) {
476 g_debug ("GdmSession: %s key not found: %s",
477 G_KEY_FILE_DESKTOP_KEY_EXEC,
478 error->message);
479 g_error_free (error);
480 goto out;
481 }
482
483 if (command != NULL) {
484 *command = g_strdup (exec);
485 }
486 ret = TRUE;
487
488 out:
489 g_free (exec);
490
491 return ret;
492 }
493
494 static gboolean
get_session_command_for_name(GdmSession * self,const char * name,char ** command)495 get_session_command_for_name (GdmSession *self,
496 const char *name,
497 char **command)
498 {
499 gboolean res;
500 char *filename;
501
502 filename = g_strdup_printf ("%s.desktop", name);
503 res = get_session_command_for_file (self, filename, command);
504 g_free (filename);
505
506 return res;
507 }
508
509 static const char *
get_default_language_name(GdmSession * self)510 get_default_language_name (GdmSession *self)
511 {
512 const char *default_language;
513
514 if (self->priv->saved_language != NULL) {
515 return self->priv->saved_language;
516 }
517
518 default_language = g_hash_table_lookup (self->priv->environment,
519 "LANG");
520
521 if (default_language != NULL) {
522 return default_language;
523 }
524
525 return setlocale (LC_MESSAGES, NULL);
526 }
527
528 static const char *
get_fallback_session_name(GdmSession * self)529 get_fallback_session_name (GdmSession *self)
530 {
531 char **search_dirs;
532 int i;
533 char *name;
534 GSequence *sessions;
535 GSequenceIter *session;
536
537 if (self->priv->fallback_session_name != NULL) {
538 /* verify that the cached version still exists */
539 if (get_session_command_for_name (self, self->priv->fallback_session_name, NULL)) {
540 goto out;
541 }
542 }
543
544 name = g_strdup ("gnome");
545 if (get_session_command_for_name (self, name, NULL)) {
546 g_free (self->priv->fallback_session_name);
547 self->priv->fallback_session_name = name;
548 goto out;
549 }
550 g_free (name);
551
552 sessions = g_sequence_new (g_free);
553
554 search_dirs = get_system_session_dirs (self);
555 for (i = 0; search_dirs[i] != NULL; i++) {
556 GDir *dir;
557 const char *base_name;
558
559 dir = g_dir_open (search_dirs[i], 0, NULL);
560
561 if (dir == NULL) {
562 continue;
563 }
564
565 do {
566 base_name = g_dir_read_name (dir);
567
568 if (base_name == NULL) {
569 break;
570 }
571
572 if (!g_str_has_suffix (base_name, ".desktop")) {
573 continue;
574 }
575
576 if (get_session_command_for_file (self, base_name, NULL)) {
577 name = g_strndup (base_name, strlen (base_name) - strlen (".desktop"));
578 g_sequence_insert_sorted (sessions, name, (GCompareDataFunc) g_strcmp0, NULL);
579 }
580 } while (base_name != NULL);
581
582 g_dir_close (dir);
583 }
584 g_strfreev (search_dirs);
585
586 name = NULL;
587 session = g_sequence_get_begin_iter (sessions);
588
589 if (g_sequence_iter_is_end (session))
590 g_error ("GdmSession: no session desktop files installed, aborting...");
591
592 do {
593 name = g_sequence_get (session);
594 if (name) {
595 break;
596 }
597 session = g_sequence_iter_next (session);
598 } while (!g_sequence_iter_is_end (session));
599
600 g_free (self->priv->fallback_session_name);
601 self->priv->fallback_session_name = g_strdup (name);
602
603 g_sequence_free (sessions);
604
605 out:
606 return self->priv->fallback_session_name;
607 }
608
609 static const char *
get_default_session_name(GdmSession * self)610 get_default_session_name (GdmSession *self)
611 {
612 if (self->priv->saved_session != NULL) {
613 return self->priv->saved_session;
614 }
615
616 return get_fallback_session_name (self);
617 }
618
619 static void
gdm_session_defaults_changed(GdmSession * self)620 gdm_session_defaults_changed (GdmSession *self)
621 {
622
623 update_session_type (self);
624
625 if (self->priv->greeter_interface != NULL) {
626 gdm_dbus_greeter_emit_default_language_name_changed (self->priv->greeter_interface,
627 get_default_language_name (self));
628 gdm_dbus_greeter_emit_default_session_name_changed (self->priv->greeter_interface,
629 get_default_session_name (self));
630 }
631 }
632
633 void
gdm_session_select_user(GdmSession * self,const char * text)634 gdm_session_select_user (GdmSession *self,
635 const char *text)
636 {
637
638 g_debug ("GdmSession: Setting user: '%s'", text);
639
640 g_free (self->priv->selected_user);
641 self->priv->selected_user = g_strdup (text);
642
643 g_free (self->priv->saved_session);
644 self->priv->saved_session = NULL;
645
646 g_free (self->priv->saved_language);
647 self->priv->saved_language = NULL;
648 }
649
650 static void
cancel_pending_query(GdmSessionConversation * conversation)651 cancel_pending_query (GdmSessionConversation *conversation)
652 {
653 if (conversation->pending_invocation == NULL) {
654 return;
655 }
656
657 g_debug ("GdmSession: Cancelling pending query");
658
659 g_dbus_method_invocation_return_dbus_error (conversation->pending_invocation,
660 GDM_SESSION_DBUS_ERROR_CANCEL,
661 "Operation cancelled");
662 conversation->pending_invocation = NULL;
663 }
664
665 static void
answer_pending_query(GdmSessionConversation * conversation,const char * answer)666 answer_pending_query (GdmSessionConversation *conversation,
667 const char *answer)
668 {
669 g_dbus_method_invocation_return_value (conversation->pending_invocation,
670 g_variant_new ("(s)", answer));
671 conversation->pending_invocation = NULL;
672 }
673
674 static void
set_pending_query(GdmSessionConversation * conversation,GDBusMethodInvocation * message)675 set_pending_query (GdmSessionConversation *conversation,
676 GDBusMethodInvocation *message)
677 {
678 g_assert (conversation->pending_invocation == NULL);
679
680 conversation->pending_invocation = g_object_ref (message);
681 }
682
683 static gboolean
gdm_session_handle_choice_list_query(GdmDBusWorkerManager * worker_manager_interface,GDBusMethodInvocation * invocation,const char * service_name,const char * prompt_message,GVariant * query,GdmSession * self)684 gdm_session_handle_choice_list_query (GdmDBusWorkerManager *worker_manager_interface,
685 GDBusMethodInvocation *invocation,
686 const char *service_name,
687 const char *prompt_message,
688 GVariant *query,
689 GdmSession *self)
690 {
691 GdmSessionConversation *conversation;
692 GdmDBusUserVerifierChoiceList *choice_list_interface = NULL;
693
694 g_debug ("GdmSession: choice query for service '%s'", service_name);
695
696 if (self->priv->user_verifier_extensions != NULL)
697 choice_list_interface = g_hash_table_lookup (self->priv->user_verifier_extensions,
698 gdm_dbus_user_verifier_choice_list_interface_info ()->name);
699
700 if (choice_list_interface == NULL) {
701 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
702 G_DBUS_ERROR_NOT_SUPPORTED,
703 "ChoiceList interface not supported by client");
704 return TRUE;
705 }
706
707 conversation = find_conversation_by_name (self, service_name);
708 if (conversation != NULL) {
709 set_pending_query (conversation, invocation);
710
711 g_debug ("GdmSession: emitting choice query '%s'", prompt_message);
712 gdm_dbus_user_verifier_choice_list_emit_choice_query (choice_list_interface,
713 service_name,
714 prompt_message,
715 query);
716 }
717
718 return TRUE;
719 }
720
721 static gboolean
gdm_session_handle_info_query(GdmDBusWorkerManager * worker_manager_interface,GDBusMethodInvocation * invocation,const char * service_name,const char * query,GdmSession * self)722 gdm_session_handle_info_query (GdmDBusWorkerManager *worker_manager_interface,
723 GDBusMethodInvocation *invocation,
724 const char *service_name,
725 const char *query,
726 GdmSession *self)
727 {
728 GdmSessionConversation *conversation;
729
730 g_return_val_if_fail (self->priv->user_verifier_interface != NULL, FALSE);
731
732 conversation = find_conversation_by_name (self, service_name);
733 if (conversation != NULL) {
734 set_pending_query (conversation, invocation);
735
736 gdm_dbus_user_verifier_emit_info_query (self->priv->user_verifier_interface,
737 service_name,
738 query);
739 }
740
741 return TRUE;
742 }
743
744 static gboolean
gdm_session_handle_secret_info_query(GdmDBusWorkerManager * worker_manager_interface,GDBusMethodInvocation * invocation,const char * service_name,const char * query,GdmSession * self)745 gdm_session_handle_secret_info_query (GdmDBusWorkerManager *worker_manager_interface,
746 GDBusMethodInvocation *invocation,
747 const char *service_name,
748 const char *query,
749 GdmSession *self)
750 {
751 GdmSessionConversation *conversation;
752
753 g_return_val_if_fail (self->priv->user_verifier_interface != NULL, FALSE);
754
755 conversation = find_conversation_by_name (self, service_name);
756 if (conversation != NULL) {
757 set_pending_query (conversation, invocation);
758
759 gdm_dbus_user_verifier_emit_secret_info_query (self->priv->user_verifier_interface,
760 service_name,
761 query);
762 }
763
764 return TRUE;
765 }
766
767 static gboolean
gdm_session_handle_info(GdmDBusWorkerManager * worker_manager_interface,GDBusMethodInvocation * invocation,const char * service_name,const char * info,GdmSession * self)768 gdm_session_handle_info (GdmDBusWorkerManager *worker_manager_interface,
769 GDBusMethodInvocation *invocation,
770 const char *service_name,
771 const char *info,
772 GdmSession *self)
773 {
774 gdm_dbus_worker_manager_complete_info (worker_manager_interface,
775 invocation);
776
777 if (self->priv->user_verifier_interface != NULL) {
778 gdm_dbus_user_verifier_emit_info (self->priv->user_verifier_interface,
779 service_name,
780 info);
781 }
782
783 return TRUE;
784 }
785
786 static void
worker_on_cancel_pending_query(GdmDBusWorker * worker,GdmSessionConversation * conversation)787 worker_on_cancel_pending_query (GdmDBusWorker *worker,
788 GdmSessionConversation *conversation)
789 {
790 cancel_pending_query (conversation);
791 }
792
793 static gboolean
gdm_session_handle_problem(GdmDBusWorkerManager * worker_manager_interface,GDBusMethodInvocation * invocation,const char * service_name,const char * problem,GdmSession * self)794 gdm_session_handle_problem (GdmDBusWorkerManager *worker_manager_interface,
795 GDBusMethodInvocation *invocation,
796 const char *service_name,
797 const char *problem,
798 GdmSession *self)
799 {
800 gdm_dbus_worker_manager_complete_problem (worker_manager_interface,
801 invocation);
802
803 if (self->priv->user_verifier_interface != NULL) {
804 gdm_dbus_user_verifier_emit_problem (self->priv->user_verifier_interface,
805 service_name,
806 problem);
807 }
808 return TRUE;
809 }
810
811 static void
on_opened(GdmDBusWorker * worker,GAsyncResult * res,gpointer user_data)812 on_opened (GdmDBusWorker *worker,
813 GAsyncResult *res,
814 gpointer user_data)
815 {
816 GdmSessionConversation *conversation = user_data;
817 GdmSession *self;
818 char *service_name;
819
820 GError *error = NULL;
821 gboolean worked;
822 char *session_id;
823
824 worked = gdm_dbus_worker_call_open_finish (worker,
825 &session_id,
826 res,
827 &error);
828
829 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED) ||
830 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
831 return;
832
833 self = conversation->session;
834 service_name = conversation->service_name;
835
836 if (worked) {
837 g_clear_pointer (&conversation->session_id,
838 (GDestroyNotify) g_free);
839
840 conversation->session_id = g_strdup (session_id);
841
842 if (self->priv->greeter_interface != NULL) {
843 gdm_dbus_greeter_emit_session_opened (self->priv->greeter_interface,
844 service_name);
845 }
846
847 if (self->priv->user_verifier_interface != NULL) {
848 gdm_dbus_user_verifier_emit_verification_complete (self->priv->user_verifier_interface,
849 service_name);
850 g_signal_emit (self, signals[VERIFICATION_COMPLETE], 0, service_name);
851 }
852
853 g_debug ("GdmSession: Emitting 'session-opened' signal");
854 g_signal_emit (self, signals[SESSION_OPENED], 0, service_name, session_id);
855 } else {
856 report_and_stop_conversation (self, service_name, error);
857
858 g_debug ("GdmSession: Emitting 'session-start-failed' signal");
859 g_signal_emit (self, signals[SESSION_START_FAILED], 0, service_name, error->message);
860 }
861 }
862
863 static void
worker_on_username_changed(GdmDBusWorker * worker,const char * username,GdmSessionConversation * conversation)864 worker_on_username_changed (GdmDBusWorker *worker,
865 const char *username,
866 GdmSessionConversation *conversation)
867 {
868 GdmSession *self = conversation->session;
869
870 g_debug ("GdmSession: changing username from '%s' to '%s'",
871 self->priv->selected_user != NULL ? self->priv->selected_user : "<unset>",
872 (strlen (username)) ? username : "<unset>");
873
874 gdm_session_select_user (self, (strlen (username) > 0) ? g_strdup (username) : NULL);
875 gdm_session_defaults_changed (self);
876 }
877
878 static void
worker_on_session_exited(GdmDBusWorker * worker,const char * service_name,int status,GdmSessionConversation * conversation)879 worker_on_session_exited (GdmDBusWorker *worker,
880 const char *service_name,
881 int status,
882 GdmSessionConversation *conversation)
883 {
884 GdmSession *self = conversation->session;
885
886 self->priv->session_conversation = NULL;
887
888 if (WIFEXITED (status)) {
889 g_debug ("GdmSession: Emitting 'session-exited' signal with exit code '%d'",
890 WEXITSTATUS (status));
891 g_signal_emit (self, signals[SESSION_EXITED], 0, WEXITSTATUS (status));
892 } else if (WIFSIGNALED (status)) {
893 g_debug ("GdmSession: Emitting 'session-died' signal with signal number '%d'",
894 WTERMSIG (status));
895 g_signal_emit (self, signals[SESSION_DIED], 0, WTERMSIG (status));
896 }
897 }
898
899 static void
on_reauthentication_started_cb(GdmDBusWorker * worker,GAsyncResult * res,gpointer user_data)900 on_reauthentication_started_cb (GdmDBusWorker *worker,
901 GAsyncResult *res,
902 gpointer user_data)
903 {
904 GdmSessionConversation *conversation = user_data;
905 GdmSession *self;
906
907 GError *error = NULL;
908 gboolean worked;
909 char *address;
910
911 worked = gdm_dbus_worker_call_start_reauthentication_finish (worker,
912 &address,
913 res,
914 &error);
915
916 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED) ||
917 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
918 return;
919
920 self = conversation->session;
921
922 if (worked) {
923 GPid pid_of_caller = conversation->reauth_pid_of_caller;
924 g_debug ("GdmSession: Emitting 'reauthentication-started' signal for caller pid '%d'", pid_of_caller);
925 g_signal_emit (self, signals[REAUTHENTICATION_STARTED], 0, pid_of_caller, address);
926 }
927
928 conversation->reauth_pid_of_caller = 0;
929 }
930
931 static void
worker_on_reauthenticated(GdmDBusWorker * worker,const char * service_name,GdmSessionConversation * conversation)932 worker_on_reauthenticated (GdmDBusWorker *worker,
933 const char *service_name,
934 GdmSessionConversation *conversation)
935 {
936 GdmSession *self = conversation->session;
937 g_debug ("GdmSession: Emitting 'reauthenticated' signal ");
938 g_signal_emit (self, signals[REAUTHENTICATED], 0, service_name);
939 }
940
941 static void
worker_on_saved_language_name_read(GdmDBusWorker * worker,const char * language_name,GdmSessionConversation * conversation)942 worker_on_saved_language_name_read (GdmDBusWorker *worker,
943 const char *language_name,
944 GdmSessionConversation *conversation)
945 {
946 GdmSession *self = conversation->session;
947
948 if (strlen (language_name) > 0) {
949 g_free (self->priv->saved_language);
950 self->priv->saved_language = g_strdup (language_name);
951
952 if (self->priv->greeter_interface != NULL) {
953 gdm_dbus_greeter_emit_default_language_name_changed (self->priv->greeter_interface,
954 language_name);
955 }
956 }
957 }
958
959 static void
worker_on_saved_session_name_read(GdmDBusWorker * worker,const char * session_name,GdmSessionConversation * conversation)960 worker_on_saved_session_name_read (GdmDBusWorker *worker,
961 const char *session_name,
962 GdmSessionConversation *conversation)
963 {
964 GdmSession *self = conversation->session;
965
966 if (! get_session_command_for_name (self, session_name, NULL)) {
967 /* ignore sessions that don't exist */
968 g_debug ("GdmSession: not using invalid .dmrc session: %s", session_name);
969 g_free (self->priv->saved_session);
970 self->priv->saved_session = NULL;
971 } else if (strcmp (session_name,
972 get_default_session_name (self)) != 0) {
973 g_free (self->priv->saved_session);
974 self->priv->saved_session = g_strdup (session_name);
975
976 if (self->priv->greeter_interface != NULL) {
977 gdm_dbus_greeter_emit_default_session_name_changed (self->priv->greeter_interface,
978 session_name);
979 }
980 }
981
982 update_session_type (self);
983
984 }
985
986 static GdmSessionConversation *
find_conversation_by_pid(GdmSession * self,GPid pid)987 find_conversation_by_pid (GdmSession *self,
988 GPid pid)
989 {
990 GHashTableIter iter;
991 gpointer key, value;
992
993 g_hash_table_iter_init (&iter, self->priv->conversations);
994 while (g_hash_table_iter_next (&iter, &key, &value)) {
995 GdmSessionConversation *conversation;
996
997 conversation = (GdmSessionConversation *) value;
998
999 if (conversation->worker_pid == pid) {
1000 return conversation;
1001 }
1002 }
1003
1004 return NULL;
1005 }
1006
1007 static gboolean
allow_worker_function(GDBusAuthObserver * observer,GIOStream * stream,GCredentials * credentials,GdmSession * self)1008 allow_worker_function (GDBusAuthObserver *observer,
1009 GIOStream *stream,
1010 GCredentials *credentials,
1011 GdmSession *self)
1012 {
1013 uid_t connecting_user;
1014
1015 connecting_user = g_credentials_get_unix_user (credentials, NULL);
1016
1017 if (connecting_user == 0) {
1018 return TRUE;
1019 }
1020
1021 if (connecting_user == self->priv->allowed_user) {
1022 return TRUE;
1023 }
1024
1025 g_debug ("GdmSession: User not allowed");
1026
1027 return FALSE;
1028 }
1029
1030 static void
on_worker_connection_closed(GDBusConnection * connection,gboolean remote_peer_vanished,GError * error,GdmSession * self)1031 on_worker_connection_closed (GDBusConnection *connection,
1032 gboolean remote_peer_vanished,
1033 GError *error,
1034 GdmSession *self)
1035 {
1036 self->priv->pending_worker_connections =
1037 g_list_remove (self->priv->pending_worker_connections,
1038 connection);
1039 g_object_unref (connection);
1040 }
1041
1042 static gboolean
register_worker(GdmDBusWorkerManager * worker_manager_interface,GDBusMethodInvocation * invocation,GdmSession * self)1043 register_worker (GdmDBusWorkerManager *worker_manager_interface,
1044 GDBusMethodInvocation *invocation,
1045 GdmSession *self)
1046 {
1047 GdmSessionConversation *conversation;
1048 GDBusConnection *connection;
1049 GList *connection_node;
1050 GCredentials *credentials;
1051 GPid pid;
1052
1053 g_debug ("GdmSession: Authenticating new connection");
1054
1055 connection = g_dbus_method_invocation_get_connection (invocation);
1056 connection_node = g_list_find (self->priv->pending_worker_connections, connection);
1057
1058 if (connection_node == NULL) {
1059 g_debug ("GdmSession: Ignoring connection that we aren't tracking");
1060 return FALSE;
1061 }
1062
1063 /* connection was ref'd when it was added to list, we're taking that
1064 * reference over and removing it from the list
1065 */
1066 self->priv->pending_worker_connections =
1067 g_list_delete_link (self->priv->pending_worker_connections,
1068 connection_node);
1069
1070 g_signal_handlers_disconnect_by_func (connection,
1071 G_CALLBACK (on_worker_connection_closed),
1072 self);
1073
1074 credentials = g_dbus_connection_get_peer_credentials (connection);
1075 pid = g_credentials_get_unix_pid (credentials, NULL);
1076
1077 conversation = find_conversation_by_pid (self, (GPid) pid);
1078
1079 if (conversation == NULL) {
1080 g_warning ("GdmSession: New worker connection is from unknown source");
1081
1082 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
1083 G_DBUS_ERROR_ACCESS_DENIED,
1084 "Connection is not from a known conversation");
1085 g_dbus_connection_close_sync (connection, NULL, NULL);
1086 return TRUE;
1087 }
1088
1089 g_dbus_method_invocation_return_value (invocation, NULL);
1090
1091 conversation->worker_proxy = gdm_dbus_worker_proxy_new_sync (connection,
1092 G_DBUS_PROXY_FLAGS_NONE,
1093 NULL,
1094 GDM_WORKER_DBUS_PATH,
1095 NULL, NULL);
1096 /* drop the reference we stole from the pending connections list
1097 * since the proxy owns the connection now */
1098 g_object_unref (connection);
1099
1100 g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (conversation->worker_proxy), G_MAXINT);
1101
1102 conversation->worker_cancellable = g_cancellable_new ();
1103
1104 g_signal_connect (conversation->worker_proxy,
1105 "username-changed",
1106 G_CALLBACK (worker_on_username_changed), conversation);
1107 g_signal_connect (conversation->worker_proxy,
1108 "session-exited",
1109 G_CALLBACK (worker_on_session_exited), conversation);
1110 g_signal_connect (conversation->worker_proxy,
1111 "reauthenticated",
1112 G_CALLBACK (worker_on_reauthenticated), conversation);
1113 g_signal_connect (conversation->worker_proxy,
1114 "saved-language-name-read",
1115 G_CALLBACK (worker_on_saved_language_name_read), conversation);
1116 g_signal_connect (conversation->worker_proxy,
1117 "saved-session-name-read",
1118 G_CALLBACK (worker_on_saved_session_name_read), conversation);
1119 g_signal_connect (conversation->worker_proxy,
1120 "cancel-pending-query",
1121 G_CALLBACK (worker_on_cancel_pending_query), conversation);
1122
1123 conversation->worker_manager_interface = g_object_ref (worker_manager_interface);
1124 g_debug ("GdmSession: worker connection is %p", connection);
1125
1126 g_debug ("GdmSession: Emitting conversation-started signal");
1127 g_signal_emit (self, signals[CONVERSATION_STARTED], 0, conversation->service_name);
1128
1129 if (self->priv->user_verifier_interface != NULL) {
1130 gdm_dbus_user_verifier_emit_conversation_started (self->priv->user_verifier_interface,
1131 conversation->service_name);
1132 }
1133
1134 if (conversation->starting_invocation != NULL) {
1135 if (conversation->starting_username != NULL) {
1136 gdm_session_setup_for_user (self, conversation->service_name, conversation->starting_username);
1137
1138 g_clear_pointer (&conversation->starting_username,
1139 (GDestroyNotify)
1140 g_free);
1141 } else {
1142 gdm_session_setup (self, conversation->service_name);
1143 }
1144 }
1145
1146 g_debug ("GdmSession: Conversation started");
1147
1148 return TRUE;
1149 }
1150
1151 static void
export_worker_manager_interface(GdmSession * self,GDBusConnection * connection)1152 export_worker_manager_interface (GdmSession *self,
1153 GDBusConnection *connection)
1154 {
1155 GdmDBusWorkerManager *worker_manager_interface;
1156
1157 worker_manager_interface = GDM_DBUS_WORKER_MANAGER (gdm_dbus_worker_manager_skeleton_new ());
1158 g_signal_connect (worker_manager_interface,
1159 "handle-hello",
1160 G_CALLBACK (register_worker),
1161 self);
1162 g_signal_connect (worker_manager_interface,
1163 "handle-info-query",
1164 G_CALLBACK (gdm_session_handle_info_query),
1165 self);
1166 g_signal_connect (worker_manager_interface,
1167 "handle-secret-info-query",
1168 G_CALLBACK (gdm_session_handle_secret_info_query),
1169 self);
1170 g_signal_connect (worker_manager_interface,
1171 "handle-info",
1172 G_CALLBACK (gdm_session_handle_info),
1173 self);
1174 g_signal_connect (worker_manager_interface,
1175 "handle-problem",
1176 G_CALLBACK (gdm_session_handle_problem),
1177 self);
1178 g_signal_connect (worker_manager_interface,
1179 "handle-choice-list-query",
1180 G_CALLBACK (gdm_session_handle_choice_list_query),
1181 self);
1182
1183 g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (worker_manager_interface),
1184 connection,
1185 GDM_SESSION_DBUS_OBJECT_PATH,
1186 NULL);
1187 }
1188
1189 static void
unexport_worker_manager_interface(GdmSession * self,GdmDBusWorkerManager * worker_manager_interface)1190 unexport_worker_manager_interface (GdmSession *self,
1191 GdmDBusWorkerManager *worker_manager_interface)
1192 {
1193
1194 g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (worker_manager_interface));
1195
1196 g_signal_handlers_disconnect_by_func (worker_manager_interface,
1197 G_CALLBACK (register_worker),
1198 self);
1199 g_signal_handlers_disconnect_by_func (worker_manager_interface,
1200 G_CALLBACK (gdm_session_handle_info_query),
1201 self);
1202 g_signal_handlers_disconnect_by_func (worker_manager_interface,
1203 G_CALLBACK (gdm_session_handle_secret_info_query),
1204 self);
1205 g_signal_handlers_disconnect_by_func (worker_manager_interface,
1206 G_CALLBACK (gdm_session_handle_info),
1207 self);
1208 g_signal_handlers_disconnect_by_func (worker_manager_interface,
1209 G_CALLBACK (gdm_session_handle_problem),
1210 self);
1211 g_signal_handlers_disconnect_by_func (worker_manager_interface,
1212 G_CALLBACK (gdm_session_handle_choice_list_query),
1213 self);
1214 }
1215
1216 static gboolean
handle_connection_from_worker(GDBusServer * server,GDBusConnection * connection,GdmSession * self)1217 handle_connection_from_worker (GDBusServer *server,
1218 GDBusConnection *connection,
1219 GdmSession *self)
1220 {
1221
1222 g_debug ("GdmSession: Handling new connection from worker");
1223
1224 /* add to the list of pending connections. We won't be able to
1225 * associate it with a specific worker conversation until we have
1226 * authenticated the connection (from the Hello handler).
1227 */
1228 self->priv->pending_worker_connections =
1229 g_list_prepend (self->priv->pending_worker_connections,
1230 g_object_ref (connection));
1231
1232 g_signal_connect_object (connection,
1233 "closed",
1234 G_CALLBACK (on_worker_connection_closed),
1235 self,
1236 0);
1237
1238 export_worker_manager_interface (self, connection);
1239
1240 return TRUE;
1241 }
1242
1243 static GdmSessionConversation *
begin_verification_conversation(GdmSession * self,GDBusMethodInvocation * invocation,const char * service_name)1244 begin_verification_conversation (GdmSession *self,
1245 GDBusMethodInvocation *invocation,
1246 const char *service_name)
1247 {
1248 GdmSessionConversation *conversation = NULL;
1249 gboolean conversation_started;
1250
1251 conversation_started = gdm_session_start_conversation (self, service_name);
1252
1253 if (conversation_started) {
1254 conversation = find_conversation_by_name (self, service_name);
1255 }
1256
1257 if (conversation == NULL) {
1258 g_dbus_method_invocation_return_error (invocation,
1259 G_DBUS_ERROR,
1260 G_DBUS_ERROR_SPAWN_FAILED,
1261 _("Could not create authentication helper process"));
1262 }
1263
1264 return conversation;
1265 }
1266
1267 static gboolean
gdm_session_handle_client_select_choice(GdmDBusUserVerifierChoiceList * choice_list_interface,GDBusMethodInvocation * invocation,const char * service_name,const char * answer,GdmSession * self)1268 gdm_session_handle_client_select_choice (GdmDBusUserVerifierChoiceList *choice_list_interface,
1269 GDBusMethodInvocation *invocation,
1270 const char *service_name,
1271 const char *answer,
1272 GdmSession *self)
1273 {
1274 g_debug ("GdmSession: user selected choice '%s'", answer);
1275 gdm_dbus_user_verifier_choice_list_complete_select_choice (choice_list_interface, invocation);
1276 gdm_session_answer_query (self, service_name, answer);
1277 return TRUE;
1278 }
1279
1280 static void
export_user_verifier_choice_list_interface(GdmSession * self,GDBusConnection * connection)1281 export_user_verifier_choice_list_interface (GdmSession *self,
1282 GDBusConnection *connection)
1283 {
1284 GdmDBusUserVerifierChoiceList *interface;
1285
1286 interface = GDM_DBUS_USER_VERIFIER_CHOICE_LIST (gdm_dbus_user_verifier_choice_list_skeleton_new ());
1287
1288 g_signal_connect (interface,
1289 "handle-select-choice",
1290 G_CALLBACK (gdm_session_handle_client_select_choice),
1291 self);
1292
1293 g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (interface),
1294 connection,
1295 GDM_SESSION_DBUS_OBJECT_PATH,
1296 NULL);
1297
1298 g_hash_table_insert (self->priv->user_verifier_extensions,
1299 gdm_dbus_user_verifier_choice_list_interface_info ()->name,
1300 interface);
1301 }
1302
1303 static gboolean
gdm_session_handle_client_enable_extensions(GdmDBusUserVerifier * user_verifier_interface,GDBusMethodInvocation * invocation,const char * const * extensions,GDBusConnection * connection)1304 gdm_session_handle_client_enable_extensions (GdmDBusUserVerifier *user_verifier_interface,
1305 GDBusMethodInvocation *invocation,
1306 const char * const * extensions,
1307 GDBusConnection *connection)
1308 {
1309 GdmSession *self = g_object_get_data (G_OBJECT (connection), "gdm-session");
1310 size_t i;
1311
1312 g_hash_table_remove_all (self->priv->user_verifier_extensions);
1313
1314 for (i = 0; extensions[i] != NULL; i++) {
1315 if (g_hash_table_lookup (self->priv->user_verifier_extensions, extensions[i]) != NULL)
1316 continue;
1317
1318 if (strcmp (extensions[i],
1319 gdm_dbus_user_verifier_choice_list_interface_info ()->name) == 0)
1320 export_user_verifier_choice_list_interface (self, connection);
1321
1322 }
1323
1324 gdm_dbus_user_verifier_complete_enable_extensions (user_verifier_interface, invocation);
1325
1326 return TRUE;
1327 }
1328 static gboolean
gdm_session_handle_client_begin_verification(GdmDBusUserVerifier * user_verifier_interface,GDBusMethodInvocation * invocation,const char * service_name,GdmSession * self)1329 gdm_session_handle_client_begin_verification (GdmDBusUserVerifier *user_verifier_interface,
1330 GDBusMethodInvocation *invocation,
1331 const char *service_name,
1332 GdmSession *self)
1333 {
1334 GdmSessionConversation *conversation;
1335
1336 conversation = begin_verification_conversation (self, invocation, service_name);
1337
1338 if (conversation != NULL) {
1339 conversation->starting_invocation = g_object_ref (invocation);
1340 conversation->starting_username = NULL;
1341 }
1342
1343 return TRUE;
1344 }
1345
1346 static gboolean
gdm_session_handle_client_begin_verification_for_user(GdmDBusUserVerifier * user_verifier_interface,GDBusMethodInvocation * invocation,const char * service_name,const char * username,GdmSession * self)1347 gdm_session_handle_client_begin_verification_for_user (GdmDBusUserVerifier *user_verifier_interface,
1348 GDBusMethodInvocation *invocation,
1349 const char *service_name,
1350 const char *username,
1351 GdmSession *self)
1352 {
1353 GdmSessionConversation *conversation;
1354
1355 conversation = begin_verification_conversation (self, invocation, service_name);
1356
1357 if (conversation != NULL) {
1358 conversation->starting_invocation = g_object_ref (invocation);
1359 conversation->starting_username = g_strdup (username);
1360 }
1361
1362 return TRUE;
1363 }
1364
1365 static gboolean
gdm_session_handle_client_answer_query(GdmDBusUserVerifier * user_verifier_interface,GDBusMethodInvocation * invocation,const char * service_name,const char * answer,GdmSession * self)1366 gdm_session_handle_client_answer_query (GdmDBusUserVerifier *user_verifier_interface,
1367 GDBusMethodInvocation *invocation,
1368 const char *service_name,
1369 const char *answer,
1370 GdmSession *self)
1371 {
1372 gdm_dbus_user_verifier_complete_answer_query (user_verifier_interface,
1373 invocation);
1374 gdm_session_answer_query (self, service_name, answer);
1375 return TRUE;
1376 }
1377
1378 static gboolean
gdm_session_handle_client_cancel(GdmDBusUserVerifier * user_verifier_interface,GDBusMethodInvocation * invocation,GdmSession * self)1379 gdm_session_handle_client_cancel (GdmDBusUserVerifier *user_verifier_interface,
1380 GDBusMethodInvocation *invocation,
1381 GdmSession *self)
1382 {
1383 gdm_dbus_user_verifier_complete_cancel (user_verifier_interface,
1384 invocation);
1385 gdm_session_cancel (self);
1386 return TRUE;
1387 }
1388
1389 static gboolean
gdm_session_handle_client_select_session(GdmDBusGreeter * greeter_interface,GDBusMethodInvocation * invocation,const char * session,GdmSession * self)1390 gdm_session_handle_client_select_session (GdmDBusGreeter *greeter_interface,
1391 GDBusMethodInvocation *invocation,
1392 const char *session,
1393 GdmSession *self)
1394 {
1395 if (self->priv->greeter_interface != NULL) {
1396 gdm_dbus_greeter_complete_select_session (greeter_interface,
1397 invocation);
1398 }
1399 gdm_session_select_session (self, session);
1400 return TRUE;
1401 }
1402
1403 static gboolean
gdm_session_handle_client_select_user(GdmDBusGreeter * greeter_interface,GDBusMethodInvocation * invocation,const char * username,GdmSession * self)1404 gdm_session_handle_client_select_user (GdmDBusGreeter *greeter_interface,
1405 GDBusMethodInvocation *invocation,
1406 const char *username,
1407 GdmSession *self)
1408 {
1409 if (self->priv->greeter_interface != NULL) {
1410 gdm_dbus_greeter_complete_select_user (greeter_interface,
1411 invocation);
1412 }
1413 gdm_session_select_user (self, username);
1414 return TRUE;
1415 }
1416
1417 static gboolean
gdm_session_handle_client_start_session_when_ready(GdmDBusGreeter * greeter_interface,GDBusMethodInvocation * invocation,const char * service_name,gboolean client_is_ready,GdmSession * self)1418 gdm_session_handle_client_start_session_when_ready (GdmDBusGreeter *greeter_interface,
1419 GDBusMethodInvocation *invocation,
1420 const char *service_name,
1421 gboolean client_is_ready,
1422 GdmSession *self)
1423 {
1424
1425 if (self->priv->greeter_interface != NULL) {
1426 gdm_dbus_greeter_complete_start_session_when_ready (greeter_interface,
1427 invocation);
1428 }
1429 g_signal_emit (G_OBJECT (self),
1430 signals [CLIENT_READY_FOR_SESSION_TO_START],
1431 0,
1432 service_name,
1433 client_is_ready);
1434 return TRUE;
1435 }
1436
1437 static gboolean
gdm_session_handle_get_timed_login_details(GdmDBusGreeter * greeter_interface,GDBusMethodInvocation * invocation,GdmSession * self)1438 gdm_session_handle_get_timed_login_details (GdmDBusGreeter *greeter_interface,
1439 GDBusMethodInvocation *invocation,
1440 GdmSession *self)
1441 {
1442
1443 if (self->priv->greeter_interface != NULL) {
1444 gdm_dbus_greeter_complete_get_timed_login_details (greeter_interface,
1445 invocation,
1446 self->priv->timed_login_username != NULL,
1447 self->priv->timed_login_username != NULL? self->priv->timed_login_username : "",
1448 self->priv->timed_login_delay);
1449 if (self->priv->timed_login_username != NULL) {
1450 gdm_dbus_greeter_emit_timed_login_requested (self->priv->greeter_interface,
1451 self->priv->timed_login_username,
1452 self->priv->timed_login_delay);
1453 }
1454 }
1455 return TRUE;
1456 }
1457
1458 static gboolean
gdm_session_handle_client_begin_auto_login(GdmDBusGreeter * greeter_interface,GDBusMethodInvocation * invocation,const char * username,GdmSession * self)1459 gdm_session_handle_client_begin_auto_login (GdmDBusGreeter *greeter_interface,
1460 GDBusMethodInvocation *invocation,
1461 const char *username,
1462 GdmSession *self)
1463 {
1464 if (self->priv->greeter_interface != NULL) {
1465 gdm_dbus_greeter_complete_begin_auto_login (greeter_interface,
1466 invocation);
1467 }
1468
1469 g_debug ("GdmSession: begin auto login for user '%s'", username);
1470
1471 gdm_session_setup_for_user (self, "gdm-autologin", username);
1472
1473 return TRUE;
1474 }
1475
1476 static void
export_user_verifier_interface(GdmSession * self,GDBusConnection * connection)1477 export_user_verifier_interface (GdmSession *self,
1478 GDBusConnection *connection)
1479 {
1480 GdmDBusUserVerifier *user_verifier_interface;
1481 user_verifier_interface = GDM_DBUS_USER_VERIFIER (gdm_dbus_user_verifier_skeleton_new ());
1482
1483 g_object_set_data (G_OBJECT (connection), "gdm-session", self);
1484
1485 g_signal_connect (user_verifier_interface,
1486 "handle-enable-extensions",
1487 G_CALLBACK (gdm_session_handle_client_enable_extensions),
1488 connection);
1489 g_signal_connect (user_verifier_interface,
1490 "handle-begin-verification",
1491 G_CALLBACK (gdm_session_handle_client_begin_verification),
1492 self);
1493 g_signal_connect (user_verifier_interface,
1494 "handle-begin-verification-for-user",
1495 G_CALLBACK (gdm_session_handle_client_begin_verification_for_user),
1496 self);
1497 g_signal_connect (user_verifier_interface,
1498 "handle-answer-query",
1499 G_CALLBACK (gdm_session_handle_client_answer_query),
1500 self);
1501 g_signal_connect (user_verifier_interface,
1502 "handle-cancel",
1503 G_CALLBACK (gdm_session_handle_client_cancel),
1504 self);
1505
1506 g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (user_verifier_interface),
1507 connection,
1508 GDM_SESSION_DBUS_OBJECT_PATH,
1509 NULL);
1510
1511 self->priv->user_verifier_interface = user_verifier_interface;
1512 }
1513
1514 static void
export_greeter_interface(GdmSession * self,GDBusConnection * connection)1515 export_greeter_interface (GdmSession *self,
1516 GDBusConnection *connection)
1517 {
1518 GdmDBusGreeter *greeter_interface;
1519
1520 greeter_interface = GDM_DBUS_GREETER (gdm_dbus_greeter_skeleton_new ());
1521
1522 g_signal_connect (greeter_interface,
1523 "handle-begin-auto-login",
1524 G_CALLBACK (gdm_session_handle_client_begin_auto_login),
1525 self);
1526 g_signal_connect (greeter_interface,
1527 "handle-select-session",
1528 G_CALLBACK (gdm_session_handle_client_select_session),
1529 self);
1530 g_signal_connect (greeter_interface,
1531 "handle-select-user",
1532 G_CALLBACK (gdm_session_handle_client_select_user),
1533 self);
1534 g_signal_connect (greeter_interface,
1535 "handle-start-session-when-ready",
1536 G_CALLBACK (gdm_session_handle_client_start_session_when_ready),
1537 self);
1538 g_signal_connect (greeter_interface,
1539 "handle-get-timed-login-details",
1540 G_CALLBACK (gdm_session_handle_get_timed_login_details),
1541 self);
1542
1543 g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (greeter_interface),
1544 connection,
1545 GDM_SESSION_DBUS_OBJECT_PATH,
1546 NULL);
1547
1548 self->priv->greeter_interface = greeter_interface;
1549
1550 }
1551
1552 static gboolean
gdm_session_handle_client_disconnect(GdmDBusChooser * chooser_interface,GDBusMethodInvocation * invocation,GdmSession * self)1553 gdm_session_handle_client_disconnect (GdmDBusChooser *chooser_interface,
1554 GDBusMethodInvocation *invocation,
1555 GdmSession *self)
1556 {
1557 gdm_dbus_chooser_complete_disconnect (chooser_interface,
1558 invocation);
1559 g_signal_emit (self, signals[DISCONNECTED], 0);
1560 return TRUE;
1561 }
1562
1563 static void
export_remote_greeter_interface(GdmSession * self,GDBusConnection * connection)1564 export_remote_greeter_interface (GdmSession *self,
1565 GDBusConnection *connection)
1566 {
1567 GdmDBusRemoteGreeter *remote_greeter_interface;
1568
1569 remote_greeter_interface = GDM_DBUS_REMOTE_GREETER (gdm_dbus_remote_greeter_skeleton_new ());
1570
1571 g_signal_connect (remote_greeter_interface,
1572 "handle-disconnect",
1573 G_CALLBACK (gdm_session_handle_client_disconnect),
1574 self);
1575
1576 g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (remote_greeter_interface),
1577 connection,
1578 GDM_SESSION_DBUS_OBJECT_PATH,
1579 NULL);
1580
1581 self->priv->remote_greeter_interface = remote_greeter_interface;
1582
1583 }
1584
1585 static gboolean
gdm_session_handle_client_select_hostname(GdmDBusChooser * chooser_interface,GDBusMethodInvocation * invocation,const char * hostname,GdmSession * self)1586 gdm_session_handle_client_select_hostname (GdmDBusChooser *chooser_interface,
1587 GDBusMethodInvocation *invocation,
1588 const char *hostname,
1589 GdmSession *self)
1590 {
1591
1592 gdm_dbus_chooser_complete_select_hostname (chooser_interface,
1593 invocation);
1594 g_signal_emit (self, signals[HOSTNAME_SELECTED], 0, hostname);
1595 return TRUE;
1596 }
1597
1598 static void
export_chooser_interface(GdmSession * self,GDBusConnection * connection)1599 export_chooser_interface (GdmSession *self,
1600 GDBusConnection *connection)
1601 {
1602 GdmDBusChooser *chooser_interface;
1603
1604 chooser_interface = GDM_DBUS_CHOOSER (gdm_dbus_chooser_skeleton_new ());
1605
1606 g_signal_connect (chooser_interface,
1607 "handle-select-hostname",
1608 G_CALLBACK (gdm_session_handle_client_select_hostname),
1609 self);
1610
1611 g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (chooser_interface),
1612 connection,
1613 GDM_SESSION_DBUS_OBJECT_PATH,
1614 NULL);
1615
1616 self->priv->chooser_interface = chooser_interface;
1617 }
1618
1619 static void
on_outside_connection_closed(GDBusConnection * connection,gboolean remote_peer_vanished,GError * error,GdmSession * self)1620 on_outside_connection_closed (GDBusConnection *connection,
1621 gboolean remote_peer_vanished,
1622 GError *error,
1623 GdmSession *self)
1624 {
1625 GCredentials *credentials;
1626 GPid pid_of_client;
1627
1628 g_debug ("GdmSession: external connection closed");
1629
1630 self->priv->outside_connections =
1631 g_list_remove (self->priv->outside_connections,
1632 connection);
1633
1634 credentials = g_dbus_connection_get_peer_credentials (connection);
1635 pid_of_client = g_credentials_get_unix_pid (credentials, NULL);
1636
1637 g_signal_emit (G_OBJECT (self),
1638 signals [CLIENT_DISCONNECTED],
1639 0,
1640 credentials,
1641 (guint)
1642 pid_of_client);
1643
1644 g_object_unref (connection);
1645 }
1646
1647 static gboolean
handle_connection_from_outside(GDBusServer * server,GDBusConnection * connection,GdmSession * self)1648 handle_connection_from_outside (GDBusServer *server,
1649 GDBusConnection *connection,
1650 GdmSession *self)
1651 {
1652 GCredentials *credentials;
1653 GPid pid_of_client;
1654
1655 g_debug ("GdmSession: Handling new connection from outside");
1656
1657 self->priv->outside_connections =
1658 g_list_prepend (self->priv->outside_connections,
1659 g_object_ref (connection));
1660
1661 g_signal_connect_object (connection,
1662 "closed",
1663 G_CALLBACK (on_outside_connection_closed),
1664 self,
1665 0);
1666
1667 export_user_verifier_interface (self, connection);
1668
1669 switch (self->priv->verification_mode) {
1670 case GDM_SESSION_VERIFICATION_MODE_LOGIN:
1671 export_greeter_interface (self, connection);
1672 break;
1673
1674 case GDM_SESSION_VERIFICATION_MODE_CHOOSER:
1675 export_chooser_interface (self, connection);
1676 break;
1677
1678 default:
1679 break;
1680 }
1681
1682 if (!self->priv->display_is_local) {
1683 export_remote_greeter_interface (self, connection);
1684 }
1685
1686 credentials = g_dbus_connection_get_peer_credentials (connection);
1687 pid_of_client = g_credentials_get_unix_pid (credentials, NULL);
1688
1689 g_signal_emit (G_OBJECT (self),
1690 signals [CLIENT_CONNECTED],
1691 0,
1692 credentials,
1693 (guint)
1694 pid_of_client);
1695
1696 return TRUE;
1697 }
1698
1699 static void
setup_worker_server(GdmSession * self)1700 setup_worker_server (GdmSession *self)
1701 {
1702 GDBusAuthObserver *observer;
1703 GDBusServer *server;
1704 GError *error = NULL;
1705
1706 g_debug ("GdmSession: Creating D-Bus server for worker for session");
1707
1708 observer = g_dbus_auth_observer_new ();
1709 g_signal_connect_object (observer,
1710 "authorize-authenticated-peer",
1711 G_CALLBACK (allow_worker_function),
1712 self,
1713 0);
1714
1715 server = gdm_dbus_setup_private_server (observer, &error);
1716 g_object_unref (observer);
1717
1718 if (server == NULL) {
1719 g_warning ("Cannot create worker D-Bus server for the session: %s",
1720 error->message);
1721 return;
1722 }
1723
1724 g_signal_connect_object (server,
1725 "new-connection",
1726 G_CALLBACK (handle_connection_from_worker),
1727 self,
1728 0);
1729 self->priv->worker_server = server;
1730
1731 g_dbus_server_start (server);
1732
1733 g_debug ("GdmSession: D-Bus server for workers listening on %s",
1734 g_dbus_server_get_client_address (self->priv->worker_server));
1735 }
1736
1737 static gboolean
allow_user_function(GDBusAuthObserver * observer,GIOStream * stream,GCredentials * credentials,GdmSession * self)1738 allow_user_function (GDBusAuthObserver *observer,
1739 GIOStream *stream,
1740 GCredentials *credentials,
1741 GdmSession *self)
1742 {
1743 uid_t client_uid;
1744 GPid pid_of_client;
1745
1746 client_uid = g_credentials_get_unix_user (credentials, NULL);
1747 if (client_uid == self->priv->allowed_user) {
1748 return TRUE;
1749 }
1750
1751 g_debug ("GdmSession: User not allowed");
1752
1753 pid_of_client = g_credentials_get_unix_pid (credentials, NULL);
1754 g_signal_emit (G_OBJECT (self),
1755 signals [CLIENT_REJECTED],
1756 0,
1757 credentials,
1758 (guint)
1759 pid_of_client);
1760
1761
1762 return FALSE;
1763 }
1764
1765 static void
setup_outside_server(GdmSession * self)1766 setup_outside_server (GdmSession *self)
1767 {
1768 GDBusAuthObserver *observer;
1769 GDBusServer *server;
1770 GError *error = NULL;
1771
1772 g_debug ("GdmSession: Creating D-Bus server for greeters and such");
1773
1774 observer = g_dbus_auth_observer_new ();
1775 g_signal_connect_object (observer,
1776 "authorize-authenticated-peer",
1777 G_CALLBACK (allow_user_function),
1778 self,
1779 0);
1780
1781 server = gdm_dbus_setup_private_server (observer, &error);
1782 g_object_unref (observer);
1783
1784 if (server == NULL) {
1785 g_warning ("Cannot create greeter D-Bus server for the session: %s",
1786 error->message);
1787 return;
1788 }
1789
1790 g_signal_connect_object (server,
1791 "new-connection",
1792 G_CALLBACK (handle_connection_from_outside),
1793 self,
1794 0);
1795 self->priv->outside_server = server;
1796
1797 g_dbus_server_start (server);
1798
1799 g_debug ("GdmSession: D-Bus server for greeters listening on %s",
1800 g_dbus_server_get_client_address (self->priv->outside_server));
1801 }
1802
1803 static void
free_conversation(GdmSessionConversation * conversation)1804 free_conversation (GdmSessionConversation *conversation)
1805 {
1806 if (conversation->job != NULL) {
1807 g_warning ("Freeing conversation '%s' with active job", conversation->service_name);
1808 }
1809
1810 g_free (conversation->service_name);
1811 g_free (conversation->starting_username);
1812 g_free (conversation->session_id);
1813 g_clear_object (&conversation->worker_manager_interface);
1814
1815 g_cancellable_cancel (conversation->worker_cancellable);
1816 g_clear_object (&conversation->worker_cancellable);
1817
1818 if (conversation->worker_proxy != NULL) {
1819 g_signal_handlers_disconnect_by_func (conversation->worker_proxy,
1820 G_CALLBACK (worker_on_username_changed),
1821 conversation);
1822 g_signal_handlers_disconnect_by_func (conversation->worker_proxy,
1823 G_CALLBACK (worker_on_session_exited),
1824 conversation);
1825 g_signal_handlers_disconnect_by_func (conversation->worker_proxy,
1826 G_CALLBACK (worker_on_reauthenticated),
1827 conversation);
1828 g_signal_handlers_disconnect_by_func (conversation->worker_proxy,
1829 G_CALLBACK (worker_on_saved_language_name_read),
1830 conversation);
1831 g_signal_handlers_disconnect_by_func (conversation->worker_proxy,
1832 G_CALLBACK (worker_on_saved_session_name_read),
1833 conversation);
1834 g_signal_handlers_disconnect_by_func (conversation->worker_proxy,
1835 G_CALLBACK (worker_on_cancel_pending_query),
1836 conversation);
1837 g_clear_object (&conversation->worker_proxy);
1838 }
1839 g_clear_object (&conversation->session);
1840 g_free (conversation);
1841 }
1842
1843 static void
load_lang_config_file(GdmSession * self)1844 load_lang_config_file (GdmSession *self)
1845 {
1846 static const char *config_file = LANG_CONFIG_FILE;
1847 gchar *contents = NULL;
1848 gchar *p;
1849 gchar *key;
1850 gchar *value;
1851 gsize length;
1852 GError *error;
1853 GString *line;
1854 GRegex *re;
1855
1856 if (!g_file_test (config_file, G_FILE_TEST_EXISTS)) {
1857 g_debug ("Cannot access '%s'", config_file);
1858 return;
1859 }
1860
1861 error = NULL;
1862 if (!g_file_get_contents (config_file, &contents, &length, &error)) {
1863 g_debug ("Failed to parse '%s': %s",
1864 LANG_CONFIG_FILE,
1865 (error && error->message) ? error->message : "(null)");
1866 g_error_free (error);
1867 return;
1868 }
1869
1870 if (!g_utf8_validate (contents, length, NULL)) {
1871 g_warning ("Invalid UTF-8 in '%s'", config_file);
1872 g_free (contents);
1873 return;
1874 }
1875
1876 re = g_regex_new ("(?P<key>(LANG|LANGUAGE|LC_CTYPE|LC_NUMERIC|LC_TIME|LC_COLLATE|LC_MONETARY|LC_MESSAGES|LC_PAPER|LC_NAME|LC_ADDRESS|LC_TELEPHONE|LC_MEASUREMENT|LC_IDENTIFICATION|LC_ALL))=(\")?(?P<value>[^\"]*)?(\")?", 0, 0, &error);
1877 if (re == NULL) {
1878 g_warning ("Failed to regex: %s",
1879 (error && error->message) ? error->message : "(null)");
1880 g_error_free (error);
1881 g_free (contents);
1882 return;
1883 }
1884
1885 line = g_string_new ("");
1886 for (p = contents; p && *p; p = g_utf8_find_next_char (p, NULL)) {
1887 gunichar ch;
1888 GMatchInfo *match_info = NULL;
1889
1890 ch = g_utf8_get_char (p);
1891 if ((ch != '\n') && (ch != '\0')) {
1892 g_string_append_unichar (line, ch);
1893 continue;
1894 }
1895
1896 if (line->str && g_utf8_get_char (line->str) == '#') {
1897 goto next_line;
1898 }
1899
1900 if (!g_regex_match (re, line->str, 0, &match_info)) {
1901 goto next_line;
1902 }
1903
1904 if (!g_match_info_matches (match_info)) {
1905 goto next_line;
1906 }
1907
1908 key = g_match_info_fetch_named (match_info, "key");
1909 value = g_match_info_fetch_named (match_info, "value");
1910
1911 if (key && *key && value && *value) {
1912 g_setenv (key, value, TRUE);
1913 }
1914
1915 g_free (key);
1916 g_free (value);
1917 next_line:
1918 g_match_info_free (match_info);
1919 g_string_set_size (line, 0);
1920 }
1921
1922 g_string_free (line, TRUE);
1923 g_regex_unref (re);
1924 g_free (contents);
1925 }
1926
1927 static void
unexport_and_free_user_verifier_extension(GDBusInterfaceSkeleton * interface)1928 unexport_and_free_user_verifier_extension (GDBusInterfaceSkeleton *interface)
1929 {
1930 g_dbus_interface_skeleton_unexport (interface);
1931
1932 g_object_run_dispose (G_OBJECT (interface));
1933 g_object_unref (interface);
1934 }
1935
1936 static void
gdm_session_init(GdmSession * self)1937 gdm_session_init (GdmSession *self)
1938 {
1939 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
1940 GDM_TYPE_SESSION,
1941 GdmSessionPrivate);
1942
1943 self->priv->conversations = g_hash_table_new_full (g_str_hash,
1944 g_str_equal,
1945 (GDestroyNotify) g_free,
1946 (GDestroyNotify)
1947 free_conversation);
1948 self->priv->environment = g_hash_table_new_full (g_str_hash,
1949 g_str_equal,
1950 (GDestroyNotify) g_free,
1951 (GDestroyNotify) g_free);
1952 self->priv->user_verifier_extensions = g_hash_table_new_full (g_str_hash,
1953 g_str_equal,
1954 NULL,
1955 (GDestroyNotify)
1956 unexport_and_free_user_verifier_extension);
1957
1958 load_lang_config_file (self);
1959 setup_worker_server (self);
1960 setup_outside_server (self);
1961 }
1962
1963 static void
worker_started(GdmSessionWorkerJob * job,GdmSessionConversation * conversation)1964 worker_started (GdmSessionWorkerJob *job,
1965 GdmSessionConversation *conversation)
1966 {
1967 g_debug ("GdmSession: Worker job started");
1968
1969 }
1970
1971 static void
worker_exited(GdmSessionWorkerJob * job,int code,GdmSessionConversation * conversation)1972 worker_exited (GdmSessionWorkerJob *job,
1973 int code,
1974 GdmSessionConversation *conversation)
1975 {
1976 GdmSession *self = conversation->session;
1977
1978 g_debug ("GdmSession: Worker job exited: %d", code);
1979
1980 g_hash_table_steal (self->priv->conversations, conversation->service_name);
1981
1982 g_object_ref (conversation->job);
1983 if (self->priv->session_conversation == conversation) {
1984 g_signal_emit (self, signals[SESSION_EXITED], 0, code);
1985 self->priv->session_conversation = NULL;
1986 }
1987
1988 g_debug ("GdmSession: Emitting conversation-stopped signal");
1989 g_signal_emit (self, signals[CONVERSATION_STOPPED], 0, conversation->service_name);
1990 if (self->priv->user_verifier_interface != NULL) {
1991 gdm_dbus_user_verifier_emit_conversation_stopped (self->priv->user_verifier_interface,
1992 conversation->service_name);
1993 }
1994 g_object_unref (conversation->job);
1995
1996 if (conversation->is_stopping) {
1997 g_object_unref (conversation->job);
1998 conversation->job = NULL;
1999 }
2000
2001 free_conversation (conversation);
2002 }
2003
2004 static void
worker_died(GdmSessionWorkerJob * job,int signum,GdmSessionConversation * conversation)2005 worker_died (GdmSessionWorkerJob *job,
2006 int signum,
2007 GdmSessionConversation *conversation)
2008 {
2009 GdmSession *self = conversation->session;
2010
2011 g_debug ("GdmSession: Worker job died: %d", signum);
2012
2013 g_hash_table_steal (self->priv->conversations, conversation->service_name);
2014
2015 g_object_ref (conversation->job);
2016 if (self->priv->session_conversation == conversation) {
2017 g_signal_emit (self, signals[SESSION_DIED], 0, signum);
2018 self->priv->session_conversation = NULL;
2019 }
2020
2021 g_debug ("GdmSession: Emitting conversation-stopped signal");
2022 g_signal_emit (self, signals[CONVERSATION_STOPPED], 0, conversation->service_name);
2023 if (self->priv->user_verifier_interface != NULL) {
2024 gdm_dbus_user_verifier_emit_conversation_stopped (self->priv->user_verifier_interface,
2025 conversation->service_name);
2026 }
2027 g_object_unref (conversation->job);
2028
2029 if (conversation->is_stopping) {
2030 g_object_unref (conversation->job);
2031 conversation->job = NULL;
2032 }
2033
2034 free_conversation (conversation);
2035 }
2036
2037 static GdmSessionConversation *
start_conversation(GdmSession * self,const char * service_name)2038 start_conversation (GdmSession *self,
2039 const char *service_name)
2040 {
2041 GdmSessionConversation *conversation;
2042 char *job_name;
2043
2044 conversation = g_new0 (GdmSessionConversation, 1);
2045 conversation->session = g_object_ref (self);
2046 conversation->service_name = g_strdup (service_name);
2047 conversation->worker_pid = -1;
2048 conversation->job = gdm_session_worker_job_new ();
2049 gdm_session_worker_job_set_server_address (conversation->job,
2050 g_dbus_server_get_client_address (self->priv->worker_server));
2051 gdm_session_worker_job_set_for_reauth (conversation->job,
2052 self->priv->verification_mode == GDM_SESSION_VERIFICATION_MODE_REAUTHENTICATE);
2053
2054 if (self->priv->conversation_environment != NULL) {
2055 gdm_session_worker_job_set_environment (conversation->job,
2056 (const char * const *)
2057 self->priv->conversation_environment);
2058
2059 }
2060 g_signal_connect (conversation->job,
2061 "started",
2062 G_CALLBACK (worker_started),
2063 conversation);
2064 g_signal_connect (conversation->job,
2065 "exited",
2066 G_CALLBACK (worker_exited),
2067 conversation);
2068 g_signal_connect (conversation->job,
2069 "died",
2070 G_CALLBACK (worker_died),
2071 conversation);
2072
2073 job_name = g_strdup_printf ("gdm-session-worker [pam/%s]", service_name);
2074 if (!gdm_session_worker_job_start (conversation->job, job_name)) {
2075 g_object_unref (conversation->job);
2076 g_free (conversation->service_name);
2077 g_free (conversation);
2078 g_free (job_name);
2079 return NULL;
2080 }
2081
2082 g_free (job_name);
2083
2084 conversation->worker_pid = gdm_session_worker_job_get_pid (conversation->job);
2085
2086 return conversation;
2087 }
2088
2089 static void
close_conversation(GdmSessionConversation * conversation)2090 close_conversation (GdmSessionConversation *conversation)
2091 {
2092 GdmSession *self = conversation->session;
2093
2094 if (conversation->worker_manager_interface != NULL) {
2095 unexport_worker_manager_interface (self, conversation->worker_manager_interface);
2096 g_clear_object (&conversation->worker_manager_interface);
2097 }
2098
2099 if (conversation->worker_proxy != NULL) {
2100 GDBusConnection *connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (conversation->worker_proxy));
2101 g_dbus_connection_close_sync (connection, NULL, NULL);
2102 }
2103 }
2104
2105 static void
stop_conversation(GdmSessionConversation * conversation)2106 stop_conversation (GdmSessionConversation *conversation)
2107 {
2108 close_conversation (conversation);
2109
2110 conversation->is_stopping = TRUE;
2111 gdm_session_worker_job_stop (conversation->job);
2112 }
2113
2114 static void
stop_conversation_now(GdmSessionConversation * conversation)2115 stop_conversation_now (GdmSessionConversation *conversation)
2116 {
2117 close_conversation (conversation);
2118
2119 gdm_session_worker_job_stop_now (conversation->job);
2120 g_clear_object (&conversation->job);
2121 }
2122
2123 #ifdef ENABLE_WAYLAND_SUPPORT
2124 void
gdm_session_set_ignore_wayland(GdmSession * self,gboolean ignore_wayland)2125 gdm_session_set_ignore_wayland (GdmSession *self,
2126 gboolean ignore_wayland)
2127 {
2128 self->priv->ignore_wayland = ignore_wayland;
2129 }
2130 #endif
2131
2132 gboolean
gdm_session_start_conversation(GdmSession * self,const char * service_name)2133 gdm_session_start_conversation (GdmSession *self,
2134 const char *service_name)
2135 {
2136 GdmSessionConversation *conversation;
2137
2138 g_return_val_if_fail (GDM_IS_SESSION (self), FALSE);
2139
2140 conversation = g_hash_table_lookup (self->priv->conversations,
2141 service_name);
2142
2143 if (conversation != NULL) {
2144 if (!conversation->is_stopping) {
2145 g_warning ("GdmSession: conversation %s started more than once", service_name);
2146 return FALSE;
2147 }
2148 g_debug ("GdmSession: stopping old conversation %s", service_name);
2149 gdm_session_worker_job_stop_now (conversation->job);
2150 g_object_unref (conversation->job);
2151 conversation->job = NULL;
2152 }
2153
2154 g_debug ("GdmSession: starting conversation %s", service_name);
2155
2156 conversation = start_conversation (self, service_name);
2157
2158 g_hash_table_insert (self->priv->conversations,
2159 g_strdup (service_name), conversation);
2160 return TRUE;
2161 }
2162
2163 void
gdm_session_stop_conversation(GdmSession * self,const char * service_name)2164 gdm_session_stop_conversation (GdmSession *self,
2165 const char *service_name)
2166 {
2167 GdmSessionConversation *conversation;
2168
2169 g_return_if_fail (GDM_IS_SESSION (self));
2170
2171 g_debug ("GdmSession: stopping conversation %s", service_name);
2172
2173 conversation = find_conversation_by_name (self, service_name);
2174
2175 if (conversation != NULL) {
2176 stop_conversation (conversation);
2177 }
2178 }
2179
2180 static void
on_initialization_complete_cb(GdmDBusWorker * proxy,GAsyncResult * res,gpointer user_data)2181 on_initialization_complete_cb (GdmDBusWorker *proxy,
2182 GAsyncResult *res,
2183 gpointer user_data)
2184 {
2185 GdmSessionConversation *conversation = user_data;
2186 GdmSession *self;
2187 char *service_name;
2188
2189 GError *error = NULL;
2190 GVariant *ret;
2191
2192 ret = g_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), res, &error);
2193
2194 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED) ||
2195 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
2196 return;
2197
2198 self = conversation->session;
2199 service_name = conversation->service_name;
2200
2201 if (ret != NULL) {
2202 if (conversation->starting_invocation) {
2203 g_dbus_method_invocation_return_value (conversation->starting_invocation,
2204 NULL);
2205 }
2206
2207 g_signal_emit (G_OBJECT (self),
2208 signals [SETUP_COMPLETE],
2209 0,
2210 service_name);
2211
2212 gdm_session_authenticate (self, service_name);
2213 g_variant_unref (ret);
2214
2215 } else {
2216 g_dbus_method_invocation_return_gerror (conversation->starting_invocation, error);
2217 report_and_stop_conversation (self, service_name, error);
2218 g_error_free (error);
2219 }
2220
2221 g_clear_object (&conversation->starting_invocation);
2222 }
2223
2224 static void
initialize(GdmSession * self,const char * service_name,const char * username,const char * log_file)2225 initialize (GdmSession *self,
2226 const char *service_name,
2227 const char *username,
2228 const char *log_file)
2229 {
2230 GVariantBuilder details;
2231 const char **extensions;
2232 GdmSessionConversation *conversation;
2233
2234 g_assert (service_name != NULL);
2235
2236 g_variant_builder_init (&details, G_VARIANT_TYPE ("a{sv}"));
2237
2238 g_variant_builder_add_parsed (&details, "{'service', <%s>}", service_name);
2239 extensions = (const char **) g_hash_table_get_keys_as_array (self->priv->user_verifier_extensions, NULL);
2240
2241 g_variant_builder_add_parsed (&details, "{'extensions', <%^as>}", extensions);
2242
2243 if (username != NULL)
2244 g_variant_builder_add_parsed (&details, "{'username', <%s>}", username);
2245
2246 if (log_file != NULL)
2247 g_variant_builder_add_parsed (&details, "{'log-file', <%s>}", log_file);
2248
2249 if (self->priv->is_program_session)
2250 g_variant_builder_add_parsed (&details, "{'is-program-session', <%b>}", self->priv->is_program_session);
2251
2252 if (self->priv->display_name != NULL)
2253 g_variant_builder_add_parsed (&details, "{'x11-display-name', <%s>}", self->priv->display_name);
2254
2255 if (self->priv->display_hostname != NULL)
2256 g_variant_builder_add_parsed (&details, "{'hostname', <%s>}", self->priv->display_hostname);
2257
2258 if (self->priv->display_is_local)
2259 g_variant_builder_add_parsed (&details, "{'display-is-local', <%b>}", self->priv->display_is_local);
2260
2261 if (self->priv->display_is_initial)
2262 g_variant_builder_add_parsed (&details, "{'display-is-initial', <%b>}", self->priv->display_is_initial);
2263
2264 if (self->priv->display_device != NULL)
2265 g_variant_builder_add_parsed (&details, "{'console', <%s>}", self->priv->display_device);
2266
2267 if (self->priv->display_seat_id != NULL)
2268 g_variant_builder_add_parsed (&details, "{'seat-id', <%s>}", self->priv->display_seat_id);
2269
2270 if (self->priv->display_x11_authority_file != NULL)
2271 g_variant_builder_add_parsed (&details, "{'x11-authority-file', <%s>}", self->priv->display_x11_authority_file);
2272
2273 g_debug ("GdmSession: Beginning initialization");
2274
2275 conversation = find_conversation_by_name (self, service_name);
2276 if (conversation != NULL) {
2277 gdm_dbus_worker_call_initialize (conversation->worker_proxy,
2278 g_variant_builder_end (&details),
2279
2280 conversation->worker_cancellable,
2281 (GAsyncReadyCallback) on_initialization_complete_cb,
2282 conversation);
2283 }
2284
2285 g_free (extensions);
2286 }
2287
2288 void
gdm_session_setup(GdmSession * self,const char * service_name)2289 gdm_session_setup (GdmSession *self,
2290 const char *service_name)
2291 {
2292
2293 g_return_if_fail (GDM_IS_SESSION (self));
2294
2295 update_session_type (self);
2296
2297 initialize (self, service_name, NULL, NULL);
2298 gdm_session_defaults_changed (self);
2299 }
2300
2301
2302 void
gdm_session_setup_for_user(GdmSession * self,const char * service_name,const char * username)2303 gdm_session_setup_for_user (GdmSession *self,
2304 const char *service_name,
2305 const char *username)
2306 {
2307
2308 g_return_if_fail (GDM_IS_SESSION (self));
2309 g_return_if_fail (username != NULL);
2310
2311 update_session_type (self);
2312
2313 gdm_session_select_user (self, username);
2314
2315 self->priv->is_program_session = FALSE;
2316 initialize (self, service_name, self->priv->selected_user, NULL);
2317 gdm_session_defaults_changed (self);
2318 }
2319
2320 void
gdm_session_setup_for_program(GdmSession * self,const char * service_name,const char * username,const char * log_file)2321 gdm_session_setup_for_program (GdmSession *self,
2322 const char *service_name,
2323 const char *username,
2324 const char *log_file)
2325 {
2326
2327 g_return_if_fail (GDM_IS_SESSION (self));
2328
2329 self->priv->is_program_session = TRUE;
2330 initialize (self, service_name, username, log_file);
2331 }
2332
2333 void
gdm_session_authenticate(GdmSession * self,const char * service_name)2334 gdm_session_authenticate (GdmSession *self,
2335 const char *service_name)
2336 {
2337 GdmSessionConversation *conversation;
2338
2339 g_return_if_fail (GDM_IS_SESSION (self));
2340
2341 conversation = find_conversation_by_name (self, service_name);
2342 if (conversation != NULL) {
2343 gdm_dbus_worker_call_authenticate (conversation->worker_proxy,
2344 conversation->worker_cancellable,
2345 (GAsyncReadyCallback) on_authenticate_cb,
2346 conversation);
2347 }
2348 }
2349
2350 void
gdm_session_authorize(GdmSession * self,const char * service_name)2351 gdm_session_authorize (GdmSession *self,
2352 const char *service_name)
2353 {
2354 GdmSessionConversation *conversation;
2355
2356 g_return_if_fail (GDM_IS_SESSION (self));
2357
2358 conversation = find_conversation_by_name (self, service_name);
2359 if (conversation != NULL) {
2360 gdm_dbus_worker_call_authorize (conversation->worker_proxy,
2361 conversation->worker_cancellable,
2362 (GAsyncReadyCallback) on_authorize_cb,
2363 conversation);
2364 }
2365 }
2366
2367 void
gdm_session_accredit(GdmSession * self,const char * service_name)2368 gdm_session_accredit (GdmSession *self,
2369 const char *service_name)
2370 {
2371 GdmSessionConversation *conversation;
2372
2373 g_return_if_fail (GDM_IS_SESSION (self));
2374
2375 conversation = find_conversation_by_name (self, service_name);
2376 if (conversation != NULL) {
2377 gdm_dbus_worker_call_establish_credentials (conversation->worker_proxy,
2378 conversation->worker_cancellable,
2379 (GAsyncReadyCallback) on_establish_credentials_cb,
2380 conversation);
2381 }
2382
2383 }
2384
2385 static void
send_environment_variable(const char * key,const char * value,GdmSessionConversation * conversation)2386 send_environment_variable (const char *key,
2387 const char *value,
2388 GdmSessionConversation *conversation)
2389 {
2390 gdm_dbus_worker_call_set_environment_variable (conversation->worker_proxy,
2391 key, value,
2392 conversation->worker_cancellable,
2393 NULL, NULL);
2394 }
2395
2396 static void
send_environment(GdmSession * self,GdmSessionConversation * conversation)2397 send_environment (GdmSession *self,
2398 GdmSessionConversation *conversation)
2399 {
2400
2401 g_hash_table_foreach (self->priv->environment,
2402 (GHFunc) send_environment_variable,
2403 conversation);
2404 }
2405
2406 void
gdm_session_send_environment(GdmSession * self,const char * service_name)2407 gdm_session_send_environment (GdmSession *self,
2408 const char *service_name)
2409 {
2410 GdmSessionConversation *conversation;
2411
2412 g_return_if_fail (GDM_IS_SESSION (self));
2413
2414 conversation = find_conversation_by_name (self, service_name);
2415 if (conversation != NULL) {
2416 send_environment (self, conversation);
2417 }
2418 }
2419
2420 static const char *
get_session_name(GdmSession * self)2421 get_session_name (GdmSession *self)
2422 {
2423 /* FIXME: test the session names before we use them? */
2424
2425 if (self->priv->selected_session != NULL) {
2426 return self->priv->selected_session;
2427 }
2428
2429 return get_default_session_name (self);
2430 }
2431
2432 static char *
get_session_command(GdmSession * self)2433 get_session_command (GdmSession *self)
2434 {
2435 gboolean res;
2436 char *command;
2437 const char *session_name;
2438
2439 session_name = get_session_name (self);
2440
2441 command = NULL;
2442 res = get_session_command_for_name (self, session_name, &command);
2443 if (! res) {
2444 g_critical ("Cannot find a command for specified session: %s", session_name);
2445 exit (EXIT_FAILURE);
2446 }
2447
2448 return command;
2449 }
2450
2451 static gchar *
get_session_desktop_names(GdmSession * self)2452 get_session_desktop_names (GdmSession *self)
2453 {
2454 gchar *filename;
2455 GKeyFile *keyfile;
2456 gchar *desktop_names = NULL;
2457
2458 if (self->priv->selected_program != NULL) {
2459 return g_strdup ("GNOME-Greeter:GNOME");
2460 }
2461
2462 filename = g_strdup_printf ("%s.desktop", get_session_name (self));
2463 g_debug ("GdmSession: getting desktop names for file '%s'", filename);
2464 keyfile = load_key_file_for_file (self, filename, NULL);
2465 if (keyfile != NULL) {
2466 gchar **names;
2467
2468 names = g_key_file_get_string_list (keyfile, G_KEY_FILE_DESKTOP_GROUP,
2469 "DesktopNames", NULL, NULL);
2470 if (names != NULL) {
2471 desktop_names = g_strjoinv (":", names);
2472
2473 g_strfreev (names);
2474 }
2475 }
2476
2477 g_key_file_free (keyfile);
2478 g_free (filename);
2479 return desktop_names;
2480 }
2481
2482 void
gdm_session_set_environment_variable(GdmSession * self,const char * key,const char * value)2483 gdm_session_set_environment_variable (GdmSession *self,
2484 const char *key,
2485 const char *value)
2486 {
2487 g_return_if_fail (key != NULL);
2488 g_return_if_fail (value != NULL);
2489
2490 g_hash_table_replace (self->priv->environment,
2491 g_strdup (key),
2492 g_strdup (value));
2493 }
2494
2495 static void
set_up_session_language(GdmSession * self)2496 set_up_session_language (GdmSession *self)
2497 {
2498 char **environment;
2499 int i;
2500 const char *value;
2501
2502 environment = g_listenv ();
2503 for (i = 0; environment[i] != NULL; i++) {
2504 if (strcmp (environment[i], "LANG") != 0 &&
2505 strcmp (environment[i], "LANGUAGE") != 0 &&
2506 !g_str_has_prefix (environment[i], "LC_")) {
2507 continue;
2508 }
2509
2510 value = g_getenv (environment[i]);
2511
2512 gdm_session_set_environment_variable (self,
2513 environment[i],
2514 value);
2515 }
2516 g_strfreev (environment);
2517 }
2518
2519 static void
set_up_session_environment(GdmSession * self)2520 set_up_session_environment (GdmSession *self)
2521 {
2522 GdmSessionDisplayMode display_mode;
2523 gchar *desktop_names;
2524 char *locale;
2525
2526 if (self->priv->selected_program == NULL) {
2527 gdm_session_set_environment_variable (self,
2528 "GDMSESSION",
2529 get_session_name (self));
2530 gdm_session_set_environment_variable (self,
2531 "DESKTOP_SESSION",
2532 get_session_name (self));
2533 gdm_session_set_environment_variable (self,
2534 "XDG_SESSION_DESKTOP",
2535 get_session_name (self));
2536 }
2537
2538 desktop_names = get_session_desktop_names (self);
2539 if (desktop_names != NULL) {
2540 gdm_session_set_environment_variable (self, "XDG_CURRENT_DESKTOP", desktop_names);
2541 }
2542
2543 set_up_session_language (self);
2544
2545 locale = g_strdup (get_default_language_name (self));
2546
2547 if (locale != NULL && locale[0] != '\0') {
2548 gdm_session_set_environment_variable (self,
2549 "LANG",
2550 locale);
2551 gdm_session_set_environment_variable (self,
2552 "GDM_LANG",
2553 locale);
2554 }
2555
2556 g_free (locale);
2557
2558 display_mode = gdm_session_get_display_mode (self);
2559 if (display_mode == GDM_SESSION_DISPLAY_MODE_REUSE_VT) {
2560 gdm_session_set_environment_variable (self,
2561 "DISPLAY",
2562 self->priv->display_name);
2563
2564 if (self->priv->user_x11_authority_file != NULL) {
2565 gdm_session_set_environment_variable (self,
2566 "XAUTHORITY",
2567 self->priv->user_x11_authority_file);
2568 }
2569 }
2570
2571 if (g_getenv ("WINDOWPATH") != NULL) {
2572 gdm_session_set_environment_variable (self,
2573 "WINDOWPATH",
2574 g_getenv ("WINDOWPATH"));
2575 }
2576
2577 g_free (desktop_names);
2578 }
2579
2580 static void
send_display_mode(GdmSession * self,GdmSessionConversation * conversation)2581 send_display_mode (GdmSession *self,
2582 GdmSessionConversation *conversation)
2583 {
2584 GdmSessionDisplayMode mode;
2585
2586 mode = gdm_session_get_display_mode (self);
2587 gdm_dbus_worker_call_set_session_display_mode (conversation->worker_proxy,
2588 gdm_session_display_mode_to_string (mode),
2589 conversation->worker_cancellable,
2590 NULL, NULL);
2591 }
2592
2593 static void
send_session_type(GdmSession * self,GdmSessionConversation * conversation)2594 send_session_type (GdmSession *self,
2595 GdmSessionConversation *conversation)
2596 {
2597 const char *session_type = "x11";
2598
2599 if (self->priv->session_type != NULL) {
2600 session_type = self->priv->session_type;
2601 }
2602
2603 gdm_dbus_worker_call_set_environment_variable (conversation->worker_proxy,
2604 "XDG_SESSION_TYPE",
2605 session_type,
2606 conversation->worker_cancellable,
2607 NULL, NULL);
2608 }
2609
2610 void
gdm_session_open_session(GdmSession * self,const char * service_name)2611 gdm_session_open_session (GdmSession *self,
2612 const char *service_name)
2613 {
2614 GdmSessionConversation *conversation;
2615
2616 g_return_if_fail (GDM_IS_SESSION (self));
2617
2618 conversation = find_conversation_by_name (self, service_name);
2619
2620 if (conversation != NULL) {
2621 send_display_mode (self, conversation);
2622 send_session_type (self, conversation);
2623
2624 gdm_dbus_worker_call_open (conversation->worker_proxy,
2625 conversation->worker_cancellable,
2626 (GAsyncReadyCallback) on_opened, conversation);
2627 }
2628 }
2629
2630 static void
stop_all_other_conversations(GdmSession * self,GdmSessionConversation * conversation_to_keep,gboolean now)2631 stop_all_other_conversations (GdmSession *self,
2632 GdmSessionConversation *conversation_to_keep,
2633 gboolean now)
2634 {
2635 GHashTableIter iter;
2636 gpointer key, value;
2637
2638 if (self->priv->conversations == NULL) {
2639 return;
2640 }
2641
2642 if (conversation_to_keep == NULL) {
2643 g_debug ("GdmSession: Stopping all conversations");
2644 } else {
2645 g_debug ("GdmSession: Stopping all conversations except for %s",
2646 conversation_to_keep->service_name);
2647 }
2648
2649 g_hash_table_iter_init (&iter, self->priv->conversations);
2650 while (g_hash_table_iter_next (&iter, &key, &value)) {
2651 GdmSessionConversation *conversation;
2652
2653 conversation = (GdmSessionConversation *) value;
2654
2655 if (conversation == conversation_to_keep) {
2656 if (now) {
2657 g_hash_table_iter_steal (&iter);
2658 g_free (key);
2659 }
2660 } else {
2661 if (now) {
2662 stop_conversation_now (conversation);
2663 } else {
2664 stop_conversation (conversation);
2665 }
2666 }
2667 }
2668
2669 if (now) {
2670 g_hash_table_remove_all (self->priv->conversations);
2671
2672 if (conversation_to_keep != NULL) {
2673 g_hash_table_insert (self->priv->conversations,
2674 g_strdup (conversation_to_keep->service_name),
2675 conversation_to_keep);
2676 }
2677
2678 if (self->priv->session_conversation != conversation_to_keep) {
2679 self->priv->session_conversation = NULL;
2680 }
2681 }
2682
2683 }
2684
2685 static void
on_start_program_cb(GdmDBusWorker * worker,GAsyncResult * res,gpointer user_data)2686 on_start_program_cb (GdmDBusWorker *worker,
2687 GAsyncResult *res,
2688 gpointer user_data)
2689 {
2690 GdmSessionConversation *conversation = user_data;
2691 GdmSession *self;
2692 char *service_name;
2693
2694 GError *error = NULL;
2695 gboolean worked;
2696 GPid pid;
2697
2698 worked = gdm_dbus_worker_call_start_program_finish (worker,
2699 &pid,
2700 res,
2701 &error);
2702
2703 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED) ||
2704 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
2705 return;
2706
2707 self = conversation->session;
2708 service_name = conversation->service_name;
2709
2710 if (worked) {
2711 self->priv->session_pid = pid;
2712 self->priv->session_conversation = conversation;
2713
2714 g_debug ("GdmSession: Emitting 'session-started' signal with pid '%d'", pid);
2715 g_signal_emit (self, signals[SESSION_STARTED], 0, service_name, pid);
2716 } else {
2717 gdm_session_stop_conversation (self, service_name);
2718
2719 g_debug ("GdmSession: Emitting 'session-start-failed' signal");
2720 g_signal_emit (self, signals[SESSION_START_FAILED], 0, service_name, error->message);
2721 }
2722 }
2723
2724 void
gdm_session_start_session(GdmSession * self,const char * service_name)2725 gdm_session_start_session (GdmSession *self,
2726 const char *service_name)
2727 {
2728 GdmSessionConversation *conversation;
2729 GdmSessionDisplayMode display_mode;
2730 gboolean is_x11 = TRUE;
2731 gboolean run_launcher = FALSE;
2732 gboolean allow_remote_connections = FALSE;
2733 char *command;
2734 char *program;
2735
2736 g_return_if_fail (GDM_IS_SESSION (self));
2737 g_return_if_fail (self->priv->session_conversation == NULL);
2738
2739 conversation = find_conversation_by_name (self, service_name);
2740
2741 if (conversation == NULL) {
2742 g_warning ("GdmSession: Tried to start session of "
2743 "nonexistent conversation %s", service_name);
2744 return;
2745 }
2746
2747 stop_all_other_conversations (self, conversation, FALSE);
2748
2749 display_mode = gdm_session_get_display_mode (self);
2750
2751 #ifdef ENABLE_WAYLAND_SUPPORT
2752 is_x11 = g_strcmp0 (self->priv->session_type, "wayland") != 0;
2753 #endif
2754
2755 if (display_mode == GDM_SESSION_DISPLAY_MODE_LOGIND_MANAGED ||
2756 display_mode == GDM_SESSION_DISPLAY_MODE_NEW_VT) {
2757 run_launcher = TRUE;
2758 }
2759
2760 if (self->priv->selected_program == NULL) {
2761 gboolean run_xsession_script;
2762
2763 command = get_session_command (self);
2764
2765 run_xsession_script = !gdm_session_bypasses_xsession (self);
2766
2767 if (self->priv->display_is_local) {
2768 gboolean disallow_tcp = TRUE;
2769 gdm_settings_direct_get_boolean (GDM_KEY_DISALLOW_TCP, &disallow_tcp);
2770 allow_remote_connections = !disallow_tcp;
2771 } else {
2772 allow_remote_connections = TRUE;
2773 }
2774
2775 if (run_launcher) {
2776 if (is_x11) {
2777 program = g_strdup_printf (LIBEXECDIR "/gdm-x-session %s %s\"%s\"",
2778 run_xsession_script? "--run-script " : "",
2779 allow_remote_connections? "--allow-remote-connections " : "",
2780 command);
2781 } else {
2782 program = g_strdup_printf (LIBEXECDIR "/gdm-wayland-session \"%s\"",
2783 command);
2784 }
2785 } else if (run_xsession_script) {
2786 program = g_strdup_printf (GDMCONFDIR "/Xsession \"%s\"", command);
2787 } else {
2788 program = g_strdup (command);
2789 }
2790
2791 g_free (command);
2792 } else {
2793 if (run_launcher) {
2794 if (is_x11) {
2795 program = g_strdup_printf (LIBEXECDIR "/gdm-x-session \"%s\"",
2796 self->priv->selected_program);
2797 } else {
2798 program = g_strdup_printf (LIBEXECDIR "/gdm-wayland-session \"%s\"",
2799 self->priv->selected_program);
2800 }
2801 } else {
2802 if (g_strcmp0 (self->priv->display_seat_id, "seat0") != 0) {
2803 program = g_strdup_printf ("dbus-run-session -- %s",
2804 self->priv->selected_program);
2805 } else {
2806 program = g_strdup (self->priv->selected_program);
2807 }
2808 }
2809 }
2810
2811 set_up_session_environment (self);
2812 send_environment (self, conversation);
2813
2814 gdm_dbus_worker_call_start_program (conversation->worker_proxy,
2815 program,
2816 conversation->worker_cancellable,
2817 (GAsyncReadyCallback) on_start_program_cb,
2818 conversation);
2819 g_free (program);
2820 }
2821
2822 static void
stop_all_conversations(GdmSession * self)2823 stop_all_conversations (GdmSession *self)
2824 {
2825 stop_all_other_conversations (self, NULL, TRUE);
2826 }
2827
2828 static void
do_reset(GdmSession * self)2829 do_reset (GdmSession *self)
2830 {
2831 stop_all_conversations (self);
2832
2833 g_list_free_full (self->priv->pending_worker_connections, g_object_unref);
2834 self->priv->pending_worker_connections = NULL;
2835
2836 g_free (self->priv->selected_user);
2837 self->priv->selected_user = NULL;
2838
2839 g_free (self->priv->selected_session);
2840 self->priv->selected_session = NULL;
2841
2842 g_free (self->priv->saved_session);
2843 self->priv->saved_session = NULL;
2844
2845 g_free (self->priv->saved_language);
2846 self->priv->saved_language = NULL;
2847
2848 g_free (self->priv->user_x11_authority_file);
2849 self->priv->user_x11_authority_file = NULL;
2850
2851 g_hash_table_remove_all (self->priv->environment);
2852
2853 self->priv->session_pid = -1;
2854 self->priv->session_conversation = NULL;
2855 }
2856
2857 void
gdm_session_close(GdmSession * self)2858 gdm_session_close (GdmSession *self)
2859 {
2860
2861 g_return_if_fail (GDM_IS_SESSION (self));
2862
2863 g_debug ("GdmSession: Closing session");
2864 do_reset (self);
2865
2866 g_list_free_full (self->priv->outside_connections, g_object_unref);
2867 self->priv->outside_connections = NULL;
2868 }
2869
2870 void
gdm_session_answer_query(GdmSession * self,const char * service_name,const char * text)2871 gdm_session_answer_query (GdmSession *self,
2872 const char *service_name,
2873 const char *text)
2874 {
2875 GdmSessionConversation *conversation;
2876
2877 g_return_if_fail (GDM_IS_SESSION (self));
2878
2879 conversation = find_conversation_by_name (self, service_name);
2880
2881 if (conversation != NULL) {
2882 answer_pending_query (conversation, text);
2883 }
2884 }
2885
2886 void
gdm_session_cancel(GdmSession * self)2887 gdm_session_cancel (GdmSession *self)
2888 {
2889 g_return_if_fail (GDM_IS_SESSION (self));
2890
2891 g_signal_emit (G_OBJECT (self), signals [CANCELLED], 0);
2892 }
2893
2894 void
gdm_session_reset(GdmSession * self)2895 gdm_session_reset (GdmSession *self)
2896 {
2897 if (self->priv->user_verifier_interface != NULL) {
2898 gdm_dbus_user_verifier_emit_reset (self->priv->user_verifier_interface);
2899 }
2900
2901 do_reset (self);
2902 }
2903
2904 void
gdm_session_set_timed_login_details(GdmSession * self,const char * username,int delay)2905 gdm_session_set_timed_login_details (GdmSession *self,
2906 const char *username,
2907 int delay)
2908 {
2909 g_debug ("GdmSession: timed login details %s %d", username, delay);
2910 self->priv->timed_login_username = g_strdup (username);
2911 self->priv->timed_login_delay = delay;
2912 }
2913
2914 gboolean
gdm_session_is_running(GdmSession * self)2915 gdm_session_is_running (GdmSession *self)
2916 {
2917 return self->priv->session_pid > 0;
2918 }
2919
2920 gboolean
gdm_session_client_is_connected(GdmSession * self)2921 gdm_session_client_is_connected (GdmSession *self)
2922 {
2923 g_return_val_if_fail (GDM_IS_SESSION (self), FALSE);
2924
2925 return self->priv->outside_connections != NULL;
2926 }
2927
2928 uid_t
gdm_session_get_allowed_user(GdmSession * self)2929 gdm_session_get_allowed_user (GdmSession *self)
2930 {
2931 return self->priv->allowed_user;
2932 }
2933
2934 void
gdm_session_start_reauthentication(GdmSession * session,GPid pid_of_caller,uid_t uid_of_caller)2935 gdm_session_start_reauthentication (GdmSession *session,
2936 GPid pid_of_caller,
2937 uid_t uid_of_caller)
2938 {
2939 GdmSessionConversation *conversation = session->priv->session_conversation;
2940
2941 g_return_if_fail (conversation != NULL);
2942
2943 conversation->reauth_pid_of_caller = pid_of_caller;
2944
2945 gdm_dbus_worker_call_start_reauthentication (conversation->worker_proxy,
2946 (int) pid_of_caller,
2947 (int) uid_of_caller,
2948 conversation->worker_cancellable,
2949 (GAsyncReadyCallback) on_reauthentication_started_cb,
2950 conversation);
2951 }
2952
2953 const char *
gdm_session_get_server_address(GdmSession * self)2954 gdm_session_get_server_address (GdmSession *self)
2955 {
2956 g_return_val_if_fail (GDM_IS_SESSION (self), NULL);
2957
2958 return g_dbus_server_get_client_address (self->priv->outside_server);
2959 }
2960
2961 const char *
gdm_session_get_username(GdmSession * self)2962 gdm_session_get_username (GdmSession *self)
2963 {
2964 g_return_val_if_fail (GDM_IS_SESSION (self), NULL);
2965
2966 return self->priv->selected_user;
2967 }
2968
2969 const char *
gdm_session_get_display_device(GdmSession * self)2970 gdm_session_get_display_device (GdmSession *self)
2971 {
2972 g_return_val_if_fail (GDM_IS_SESSION (self), NULL);
2973
2974 return self->priv->display_device;
2975 }
2976
2977 const char *
gdm_session_get_display_seat_id(GdmSession * self)2978 gdm_session_get_display_seat_id (GdmSession *self)
2979 {
2980 g_return_val_if_fail (GDM_IS_SESSION (self), NULL);
2981
2982 return g_strdup (self->priv->display_seat_id);
2983 }
2984
2985 const char *
gdm_session_get_session_id(GdmSession * self)2986 gdm_session_get_session_id (GdmSession *self)
2987 {
2988 GdmSessionConversation *conversation;
2989
2990 g_return_val_if_fail (GDM_IS_SESSION (self), NULL);
2991
2992 conversation = self->priv->session_conversation;
2993
2994 if (conversation == NULL) {
2995 return NULL;
2996 }
2997
2998 return conversation->session_id;
2999 }
3000
3001 const char *
gdm_session_get_conversation_session_id(GdmSession * self,const char * service_name)3002 gdm_session_get_conversation_session_id (GdmSession *self,
3003 const char *service_name)
3004 {
3005 GdmSessionConversation *conversation;
3006
3007 g_return_val_if_fail (GDM_IS_SESSION (self), NULL);
3008
3009 conversation = find_conversation_by_name (self, service_name);
3010
3011 if (conversation == NULL) {
3012 return NULL;
3013 }
3014
3015 return conversation->session_id;
3016 }
3017
3018 static char *
get_session_filename(GdmSession * self)3019 get_session_filename (GdmSession *self)
3020 {
3021 return g_strdup_printf ("%s.desktop", get_session_name (self));
3022 }
3023
3024 #ifdef ENABLE_WAYLAND_SUPPORT
3025 static gboolean
gdm_session_is_wayland_session(GdmSession * self)3026 gdm_session_is_wayland_session (GdmSession *self)
3027 {
3028 GKeyFile *key_file;
3029 gboolean is_wayland_session = FALSE;
3030 char *filename;
3031 char *full_path = NULL;
3032
3033 g_return_val_if_fail (self != NULL, FALSE);
3034 g_return_val_if_fail (GDM_IS_SESSION (self), FALSE);
3035
3036 filename = get_session_filename (self);
3037
3038 key_file = load_key_file_for_file (self, filename, &full_path);
3039
3040 if (key_file == NULL) {
3041 goto out;
3042 }
3043
3044 if (full_path != NULL && strstr (full_path, "/wayland-sessions/") != NULL) {
3045 is_wayland_session = TRUE;
3046 }
3047 g_debug ("GdmSession: checking if file '%s' is wayland session: %s", filename, is_wayland_session? "yes" : "no");
3048
3049 out:
3050 g_clear_pointer (&key_file, (GDestroyNotify) g_key_file_free);
3051 g_free (filename);
3052 return is_wayland_session;
3053 }
3054 #endif
3055
3056 static void
update_session_type(GdmSession * self)3057 update_session_type (GdmSession *self)
3058 {
3059 #ifdef ENABLE_WAYLAND_SUPPORT
3060 gboolean is_wayland_session;
3061
3062 is_wayland_session = gdm_session_is_wayland_session (self);
3063 if (is_wayland_session) {
3064 set_session_type (self, "wayland");
3065 } else {
3066 set_session_type (self, NULL);
3067 }
3068 #endif
3069 }
3070
3071 gboolean
gdm_session_bypasses_xsession(GdmSession * self)3072 gdm_session_bypasses_xsession (GdmSession *self)
3073 {
3074 GError *error;
3075 GKeyFile *key_file;
3076 gboolean res;
3077 gboolean bypasses_xsession = FALSE;
3078 char *filename = NULL;
3079
3080 g_return_val_if_fail (self != NULL, FALSE);
3081 g_return_val_if_fail (GDM_IS_SESSION (self), FALSE);
3082
3083 if (!LOGIND_RUNNING()) {
3084 return GDM_SESSION_DISPLAY_MODE_REUSE_VT;
3085 }
3086
3087 #ifdef ENABLE_WAYLAND_SUPPORT
3088 if (gdm_session_is_wayland_session (self)) {
3089 bypasses_xsession = TRUE;
3090 goto out;
3091 }
3092 #endif
3093
3094 filename = get_session_filename (self);
3095
3096 key_file = load_key_file_for_file (self, filename, NULL);
3097
3098 error = NULL;
3099 res = g_key_file_has_key (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GDM-BypassXsession", NULL);
3100 if (!res) {
3101 goto out;
3102 } else {
3103 bypasses_xsession = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GDM-BypassXsession", &error);
3104 if (error) {
3105 bypasses_xsession = FALSE;
3106 g_error_free (error);
3107 goto out;
3108 }
3109 }
3110
3111 out:
3112 if (bypasses_xsession) {
3113 g_debug ("GdmSession: Session %s bypasses Xsession wrapper script", filename);
3114 }
3115 g_free (filename);
3116 return bypasses_xsession;
3117 }
3118
3119 GdmSessionDisplayMode
gdm_session_get_display_mode(GdmSession * self)3120 gdm_session_get_display_mode (GdmSession *self)
3121 {
3122 g_debug ("GdmSession: type %s, program? %s, seat %s",
3123 self->priv->session_type,
3124 self->priv->is_program_session? "yes" : "no",
3125 self->priv->display_seat_id);
3126
3127 /* Non-seat0 sessions share their X server with their login screen
3128 * for now.
3129 */
3130 if (g_strcmp0 (self->priv->display_seat_id, "seat0") != 0) {
3131 return GDM_SESSION_DISPLAY_MODE_REUSE_VT;
3132 }
3133
3134 #ifdef ENABLE_USER_DISPLAY_SERVER
3135 /* All other cases (wayland login screen, X login screen,
3136 * wayland user session, X user session) use the NEW_VT
3137 * display mode. That display mode means that GDM allocates
3138 * a new VT and jumps to it before starting the session. The
3139 * session is expected to use logind to gain access to the
3140 * display and input devices.
3141 *
3142 * GDM also has a LOGIND_MANAGED display mode which we can't
3143 * use yet. The difference between it and NEW_VT, is with it,
3144 * GDM doesn't do any VT handling at all, expecting the session
3145 * and logind to do everything. The problem is, for wayland
3146 * sessions it will cause flicker until * this bug is fixed:
3147 *
3148 * https://bugzilla.gnome.org/show_bug.cgi?id=745141
3149 *
3150 * Likewise, for X sessions it's problematic because
3151 * 1) X doesn't call TakeControl before switching VTs
3152 * 2) X doesn't support getting started "in the background"
3153 * right now. It will die with an error if logind devices
3154 * are paused when handed out.
3155 */
3156 return GDM_SESSION_DISPLAY_MODE_NEW_VT;
3157 #else
3158
3159 #ifdef ENABLE_WAYLAND_SUPPORT
3160 /* Wayland sessions are for now assumed to run in a
3161 * mutter-launch-like environment, so we allocate
3162 * a new VT for them. */
3163 if (g_strcmp0 (self->priv->session_type, "wayland") == 0) {
3164 return GDM_SESSION_DISPLAY_MODE_NEW_VT;
3165 }
3166 #endif
3167 return GDM_SESSION_DISPLAY_MODE_REUSE_VT;
3168 #endif
3169 }
3170
3171 void
gdm_session_select_program(GdmSession * self,const char * text)3172 gdm_session_select_program (GdmSession *self,
3173 const char *text)
3174 {
3175
3176 g_free (self->priv->selected_program);
3177
3178 self->priv->selected_program = g_strdup (text);
3179 }
3180
3181 void
gdm_session_select_session_type(GdmSession * self,const char * text)3182 gdm_session_select_session_type (GdmSession *self,
3183 const char *text)
3184 {
3185 GHashTableIter iter;
3186 gpointer key, value;
3187
3188 g_debug ("GdmSession: selecting session type '%s'", text);
3189
3190 g_hash_table_iter_init (&iter, self->priv->conversations);
3191 while (g_hash_table_iter_next (&iter, &key, &value)) {
3192 GdmSessionConversation *conversation;
3193
3194 conversation = (GdmSessionConversation *) value;
3195
3196 gdm_dbus_worker_call_set_session_type (conversation->worker_proxy,
3197 text,
3198 NULL, NULL, NULL);
3199 }
3200 }
3201
3202 void
gdm_session_select_session(GdmSession * self,const char * text)3203 gdm_session_select_session (GdmSession *self,
3204 const char *text)
3205 {
3206 GHashTableIter iter;
3207 gpointer key, value;
3208
3209 g_debug ("GdmSession: selecting session '%s'", text);
3210
3211 g_free (self->priv->selected_session);
3212 self->priv->selected_session = g_strdup (text);
3213
3214 update_session_type (self);
3215
3216 g_hash_table_iter_init (&iter, self->priv->conversations);
3217 while (g_hash_table_iter_next (&iter, &key, &value)) {
3218 GdmSessionConversation *conversation;
3219
3220 conversation = (GdmSessionConversation *) value;
3221
3222 gdm_dbus_worker_call_set_session_name (conversation->worker_proxy,
3223 get_session_name (self),
3224 conversation->worker_cancellable,
3225 NULL, NULL);
3226 }
3227 }
3228
3229 static void
set_display_name(GdmSession * self,const char * name)3230 set_display_name (GdmSession *self,
3231 const char *name)
3232 {
3233 g_free (self->priv->display_name);
3234 self->priv->display_name = g_strdup (name);
3235 }
3236
3237 static void
set_display_hostname(GdmSession * self,const char * name)3238 set_display_hostname (GdmSession *self,
3239 const char *name)
3240 {
3241 g_free (self->priv->display_hostname);
3242 self->priv->display_hostname = g_strdup (name);
3243 }
3244
3245 static void
set_display_device(GdmSession * self,const char * name)3246 set_display_device (GdmSession *self,
3247 const char *name)
3248 {
3249 g_debug ("GdmSession: Setting display device: %s", name);
3250 g_free (self->priv->display_device);
3251 self->priv->display_device = g_strdup (name);
3252 }
3253
3254 static void
set_display_seat_id(GdmSession * self,const char * name)3255 set_display_seat_id (GdmSession *self,
3256 const char *name)
3257 {
3258 g_free (self->priv->display_seat_id);
3259 self->priv->display_seat_id = g_strdup (name);
3260 }
3261
3262 static void
set_user_x11_authority_file(GdmSession * self,const char * name)3263 set_user_x11_authority_file (GdmSession *self,
3264 const char *name)
3265 {
3266 g_free (self->priv->user_x11_authority_file);
3267 self->priv->user_x11_authority_file = g_strdup (name);
3268 }
3269
3270 static void
set_display_x11_authority_file(GdmSession * self,const char * name)3271 set_display_x11_authority_file (GdmSession *self,
3272 const char *name)
3273 {
3274 g_free (self->priv->display_x11_authority_file);
3275 self->priv->display_x11_authority_file = g_strdup (name);
3276 }
3277
3278 static void
set_display_is_local(GdmSession * self,gboolean is_local)3279 set_display_is_local (GdmSession *self,
3280 gboolean is_local)
3281 {
3282 self->priv->display_is_local = is_local;
3283 }
3284
3285 static void
set_display_is_initial(GdmSession * self,gboolean is_initial)3286 set_display_is_initial (GdmSession *self,
3287 gboolean is_initial)
3288 {
3289 self->priv->display_is_initial = is_initial;
3290 }
3291
3292 static void
set_verification_mode(GdmSession * self,GdmSessionVerificationMode verification_mode)3293 set_verification_mode (GdmSession *self,
3294 GdmSessionVerificationMode verification_mode)
3295 {
3296 self->priv->verification_mode = verification_mode;
3297 }
3298
3299 static void
set_allowed_user(GdmSession * self,uid_t allowed_user)3300 set_allowed_user (GdmSession *self,
3301 uid_t allowed_user)
3302 {
3303 self->priv->allowed_user = allowed_user;
3304 }
3305
3306 static void
set_conversation_environment(GdmSession * self,char ** environment)3307 set_conversation_environment (GdmSession *self,
3308 char **environment)
3309 {
3310 g_strfreev (self->priv->conversation_environment);
3311 self->priv->conversation_environment = g_strdupv (environment);
3312 }
3313
3314 static void
set_session_type(GdmSession * self,const char * session_type)3315 set_session_type (GdmSession *self,
3316 const char *session_type)
3317 {
3318
3319 if (g_strcmp0 (self->priv->session_type, session_type) != 0) {
3320 g_debug ("GdmSession: setting session to type '%s'", session_type? session_type : "");
3321 g_free (self->priv->session_type);
3322 self->priv->session_type = g_strdup (session_type);
3323 }
3324 }
3325
3326 static void
gdm_session_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)3327 gdm_session_set_property (GObject *object,
3328 guint prop_id,
3329 const GValue *value,
3330 GParamSpec *pspec)
3331 {
3332 GdmSession *self;
3333
3334 self = GDM_SESSION (object);
3335
3336 switch (prop_id) {
3337 case PROP_SESSION_TYPE:
3338 set_session_type (self, g_value_get_string (value));
3339 break;
3340 case PROP_DISPLAY_NAME:
3341 set_display_name (self, g_value_get_string (value));
3342 break;
3343 case PROP_DISPLAY_HOSTNAME:
3344 set_display_hostname (self, g_value_get_string (value));
3345 break;
3346 case PROP_DISPLAY_DEVICE:
3347 set_display_device (self, g_value_get_string (value));
3348 break;
3349 case PROP_DISPLAY_SEAT_ID:
3350 set_display_seat_id (self, g_value_get_string (value));
3351 break;
3352 case PROP_USER_X11_AUTHORITY_FILE:
3353 set_user_x11_authority_file (self, g_value_get_string (value));
3354 break;
3355 case PROP_DISPLAY_X11_AUTHORITY_FILE:
3356 set_display_x11_authority_file (self, g_value_get_string (value));
3357 break;
3358 case PROP_DISPLAY_IS_LOCAL:
3359 set_display_is_local (self, g_value_get_boolean (value));
3360 break;
3361 case PROP_DISPLAY_IS_INITIAL:
3362 set_display_is_initial (self, g_value_get_boolean (value));
3363 break;
3364 case PROP_VERIFICATION_MODE:
3365 set_verification_mode (self, g_value_get_enum (value));
3366 break;
3367 case PROP_ALLOWED_USER:
3368 set_allowed_user (self, g_value_get_uint (value));
3369 break;
3370 case PROP_CONVERSATION_ENVIRONMENT:
3371 set_conversation_environment (self, g_value_get_pointer (value));
3372 break;
3373 #ifdef ENABLE_WAYLAND_SUPPORT
3374 case PROP_IGNORE_WAYLAND:
3375 gdm_session_set_ignore_wayland (self, g_value_get_boolean (value));
3376 break;
3377 #endif
3378 default:
3379 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3380 break;
3381 }
3382 }
3383
3384 static void
gdm_session_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)3385 gdm_session_get_property (GObject *object,
3386 guint prop_id,
3387 GValue *value,
3388 GParamSpec *pspec)
3389 {
3390 GdmSession *self;
3391
3392 self = GDM_SESSION (object);
3393
3394 switch (prop_id) {
3395 case PROP_SESSION_TYPE:
3396 g_value_set_string (value, self->priv->session_type);
3397 break;
3398 case PROP_DISPLAY_NAME:
3399 g_value_set_string (value, self->priv->display_name);
3400 break;
3401 case PROP_DISPLAY_HOSTNAME:
3402 g_value_set_string (value, self->priv->display_hostname);
3403 break;
3404 case PROP_DISPLAY_DEVICE:
3405 g_value_set_string (value, self->priv->display_device);
3406 break;
3407 case PROP_DISPLAY_SEAT_ID:
3408 g_value_set_string (value, self->priv->display_seat_id);
3409 break;
3410 case PROP_USER_X11_AUTHORITY_FILE:
3411 g_value_set_string (value, self->priv->user_x11_authority_file);
3412 break;
3413 case PROP_DISPLAY_X11_AUTHORITY_FILE:
3414 g_value_set_string (value, self->priv->display_x11_authority_file);
3415 break;
3416 case PROP_DISPLAY_IS_LOCAL:
3417 g_value_set_boolean (value, self->priv->display_is_local);
3418 break;
3419 case PROP_DISPLAY_IS_INITIAL:
3420 g_value_set_boolean (value, self->priv->display_is_initial);
3421 break;
3422 case PROP_VERIFICATION_MODE:
3423 g_value_set_enum (value, self->priv->verification_mode);
3424 break;
3425 case PROP_ALLOWED_USER:
3426 g_value_set_uint (value, self->priv->allowed_user);
3427 break;
3428 case PROP_CONVERSATION_ENVIRONMENT:
3429 g_value_set_pointer (value, self->priv->environment);
3430 break;
3431 #ifdef ENABLE_WAYLAND_SUPPORT
3432 case PROP_IGNORE_WAYLAND:
3433 g_value_set_boolean (value, self->priv->ignore_wayland);
3434 break;
3435 #endif
3436 default:
3437 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3438 break;
3439 }
3440 }
3441
3442 static void
gdm_session_dispose(GObject * object)3443 gdm_session_dispose (GObject *object)
3444 {
3445 GdmSession *self;
3446
3447 self = GDM_SESSION (object);
3448
3449 g_debug ("GdmSession: Disposing session");
3450
3451 gdm_session_close (self);
3452
3453 g_clear_pointer (&self->priv->conversations,
3454 g_hash_table_unref);
3455
3456 g_clear_object (&self->priv->user_verifier_interface);
3457 g_clear_pointer (&self->priv->user_verifier_extensions,
3458 g_hash_table_unref);
3459 g_clear_object (&self->priv->greeter_interface);
3460 g_clear_object (&self->priv->chooser_interface);
3461
3462 g_free (self->priv->display_name);
3463 self->priv->display_name = NULL;
3464
3465 g_free (self->priv->display_hostname);
3466 self->priv->display_hostname = NULL;
3467
3468 g_free (self->priv->display_device);
3469 self->priv->display_device = NULL;
3470
3471 g_free (self->priv->display_seat_id);
3472 self->priv->display_seat_id = NULL;
3473
3474 g_free (self->priv->display_x11_authority_file);
3475 self->priv->display_x11_authority_file = NULL;
3476
3477 g_strfreev (self->priv->conversation_environment);
3478 self->priv->conversation_environment = NULL;
3479
3480 if (self->priv->worker_server != NULL) {
3481 g_dbus_server_stop (self->priv->worker_server);
3482 g_clear_object (&self->priv->worker_server);
3483 }
3484
3485 if (self->priv->outside_server != NULL) {
3486 g_dbus_server_stop (self->priv->outside_server);
3487 g_clear_object (&self->priv->outside_server);
3488 }
3489
3490 if (self->priv->environment != NULL) {
3491 g_hash_table_destroy (self->priv->environment);
3492 self->priv->environment = NULL;
3493 }
3494
3495 G_OBJECT_CLASS (gdm_session_parent_class)->dispose (object);
3496 }
3497
3498 static void
gdm_session_finalize(GObject * object)3499 gdm_session_finalize (GObject *object)
3500 {
3501 GdmSession *self;
3502 GObjectClass *parent_class;
3503
3504 self = GDM_SESSION (object);
3505
3506 g_free (self->priv->selected_user);
3507 g_free (self->priv->selected_session);
3508 g_free (self->priv->saved_session);
3509 g_free (self->priv->saved_language);
3510
3511 g_free (self->priv->fallback_session_name);
3512
3513 parent_class = G_OBJECT_CLASS (gdm_session_parent_class);
3514
3515 if (parent_class->finalize != NULL)
3516 parent_class->finalize (object);
3517 }
3518
3519 static GObject *
gdm_session_constructor(GType type,guint n_construct_properties,GObjectConstructParam * construct_properties)3520 gdm_session_constructor (GType type,
3521 guint n_construct_properties,
3522 GObjectConstructParam *construct_properties)
3523 {
3524 GdmSession *self;
3525
3526 self = GDM_SESSION (G_OBJECT_CLASS (gdm_session_parent_class)->constructor (type,
3527 n_construct_properties,
3528 construct_properties));
3529 return G_OBJECT (self);
3530 }
3531
3532 static void
gdm_session_class_init(GdmSessionClass * session_class)3533 gdm_session_class_init (GdmSessionClass *session_class)
3534 {
3535 GObjectClass *object_class;
3536
3537 object_class = G_OBJECT_CLASS (session_class);
3538
3539 object_class->get_property = gdm_session_get_property;
3540 object_class->set_property = gdm_session_set_property;
3541 object_class->constructor = gdm_session_constructor;
3542 object_class->dispose = gdm_session_dispose;
3543 object_class->finalize = gdm_session_finalize;
3544
3545 g_type_class_add_private (session_class, sizeof (GdmSessionPrivate));
3546
3547 signals [CONVERSATION_STARTED] =
3548 g_signal_new ("conversation-started",
3549 GDM_TYPE_SESSION,
3550 G_SIGNAL_RUN_FIRST,
3551 G_STRUCT_OFFSET (GdmSessionClass, conversation_started),
3552 NULL,
3553 NULL,
3554 g_cclosure_marshal_VOID__STRING,
3555 G_TYPE_NONE,
3556 1, G_TYPE_STRING);
3557 signals [CONVERSATION_STOPPED] =
3558 g_signal_new ("conversation-stopped",
3559 GDM_TYPE_SESSION,
3560 G_SIGNAL_RUN_FIRST,
3561 G_STRUCT_OFFSET (GdmSessionClass, conversation_stopped),
3562 NULL,
3563 NULL,
3564 g_cclosure_marshal_VOID__STRING,
3565 G_TYPE_NONE,
3566 1, G_TYPE_STRING);
3567 signals [SETUP_COMPLETE] =
3568 g_signal_new ("setup-complete",
3569 GDM_TYPE_SESSION,
3570 G_SIGNAL_RUN_FIRST,
3571 G_STRUCT_OFFSET (GdmSessionClass, setup_complete),
3572 NULL,
3573 NULL,
3574 g_cclosure_marshal_VOID__STRING,
3575 G_TYPE_NONE,
3576 1,
3577 G_TYPE_STRING);
3578
3579 signals [AUTHENTICATION_FAILED] =
3580 g_signal_new ("authentication-failed",
3581 GDM_TYPE_SESSION,
3582 G_SIGNAL_RUN_FIRST,
3583 G_STRUCT_OFFSET (GdmSessionClass, authentication_failed),
3584 NULL,
3585 NULL,
3586 NULL,
3587 G_TYPE_NONE,
3588 2,
3589 G_TYPE_STRING,
3590 G_TYPE_INT);
3591 signals [VERIFICATION_COMPLETE] =
3592 g_signal_new ("verification-complete",
3593 GDM_TYPE_SESSION,
3594 G_SIGNAL_RUN_FIRST,
3595 G_STRUCT_OFFSET (GdmSessionClass, verification_complete),
3596 NULL,
3597 NULL,
3598 NULL,
3599 G_TYPE_NONE,
3600 1,
3601 G_TYPE_STRING);
3602 signals [SESSION_OPENED] =
3603 g_signal_new ("session-opened",
3604 GDM_TYPE_SESSION,
3605 G_SIGNAL_RUN_FIRST,
3606 G_STRUCT_OFFSET (GdmSessionClass, session_opened),
3607 NULL,
3608 NULL,
3609 NULL,
3610 G_TYPE_NONE,
3611 2,
3612 G_TYPE_STRING,
3613 G_TYPE_STRING);
3614 signals [SESSION_STARTED] =
3615 g_signal_new ("session-started",
3616 GDM_TYPE_SESSION,
3617 G_SIGNAL_RUN_FIRST,
3618 G_STRUCT_OFFSET (GdmSessionClass, session_started),
3619 NULL,
3620 NULL,
3621 g_cclosure_marshal_generic,
3622 G_TYPE_NONE,
3623 2,
3624 G_TYPE_STRING,
3625 G_TYPE_INT);
3626 signals [SESSION_START_FAILED] =
3627 g_signal_new ("session-start-failed",
3628 GDM_TYPE_SESSION,
3629 G_SIGNAL_RUN_FIRST,
3630 G_STRUCT_OFFSET (GdmSessionClass, session_start_failed),
3631 NULL,
3632 NULL,
3633 g_cclosure_marshal_generic,
3634 G_TYPE_NONE,
3635 2,
3636 G_TYPE_STRING, G_TYPE_STRING);
3637 signals [SESSION_EXITED] =
3638 g_signal_new ("session-exited",
3639 GDM_TYPE_SESSION,
3640 G_SIGNAL_RUN_FIRST,
3641 G_STRUCT_OFFSET (GdmSessionClass, session_exited),
3642 NULL,
3643 NULL,
3644 g_cclosure_marshal_VOID__INT,
3645 G_TYPE_NONE,
3646 1,
3647 G_TYPE_INT);
3648 signals [SESSION_DIED] =
3649 g_signal_new ("session-died",
3650 GDM_TYPE_SESSION,
3651 G_SIGNAL_RUN_FIRST,
3652 G_STRUCT_OFFSET (GdmSessionClass, session_died),
3653 NULL,
3654 NULL,
3655 g_cclosure_marshal_VOID__INT,
3656 G_TYPE_NONE,
3657 1,
3658 G_TYPE_INT);
3659
3660 signals [REAUTHENTICATION_STARTED] =
3661 g_signal_new ("reauthentication-started",
3662 GDM_TYPE_SESSION,
3663 G_SIGNAL_RUN_FIRST,
3664 G_STRUCT_OFFSET (GdmSessionClass, reauthentication_started),
3665 NULL,
3666 NULL,
3667 NULL,
3668 G_TYPE_NONE,
3669 2,
3670 G_TYPE_INT,
3671 G_TYPE_STRING);
3672 signals [REAUTHENTICATED] =
3673 g_signal_new ("reauthenticated",
3674 GDM_TYPE_SESSION,
3675 G_SIGNAL_RUN_FIRST,
3676 G_STRUCT_OFFSET (GdmSessionClass, reauthenticated),
3677 NULL,
3678 NULL,
3679 NULL,
3680 G_TYPE_NONE,
3681 1,
3682 G_TYPE_STRING);
3683 signals [CANCELLED] =
3684 g_signal_new ("cancelled",
3685 GDM_TYPE_SESSION,
3686 G_SIGNAL_RUN_FIRST,
3687 G_STRUCT_OFFSET (GdmSessionClass, cancelled),
3688 NULL,
3689 NULL,
3690 g_cclosure_marshal_VOID__VOID,
3691 G_TYPE_NONE,
3692 0);
3693
3694 signals [CLIENT_REJECTED] =
3695 g_signal_new ("client-rejected",
3696 GDM_TYPE_SESSION,
3697 G_SIGNAL_RUN_FIRST,
3698 G_STRUCT_OFFSET (GdmSessionClass, client_rejected),
3699 NULL,
3700 NULL,
3701 NULL,
3702 G_TYPE_NONE,
3703 2,
3704 G_TYPE_CREDENTIALS,
3705 G_TYPE_UINT);
3706
3707 signals [CLIENT_CONNECTED] =
3708 g_signal_new ("client-connected",
3709 GDM_TYPE_SESSION,
3710 G_SIGNAL_RUN_FIRST,
3711 G_STRUCT_OFFSET (GdmSessionClass, client_connected),
3712 NULL,
3713 NULL,
3714 NULL,
3715 G_TYPE_NONE,
3716 2,
3717 G_TYPE_CREDENTIALS,
3718 G_TYPE_UINT);
3719
3720 signals [CLIENT_DISCONNECTED] =
3721 g_signal_new ("client-disconnected",
3722 GDM_TYPE_SESSION,
3723 G_SIGNAL_RUN_FIRST,
3724 G_STRUCT_OFFSET (GdmSessionClass, client_disconnected),
3725 NULL,
3726 NULL,
3727 NULL,
3728 G_TYPE_NONE,
3729 2,
3730 G_TYPE_CREDENTIALS,
3731 G_TYPE_UINT);
3732 signals [CLIENT_READY_FOR_SESSION_TO_START] =
3733 g_signal_new ("client-ready-for-session-to-start",
3734 GDM_TYPE_SESSION,
3735 G_SIGNAL_RUN_FIRST,
3736 G_STRUCT_OFFSET (GdmSessionClass, client_ready_for_session_to_start),
3737 NULL,
3738 NULL,
3739 NULL,
3740 G_TYPE_NONE,
3741 2,
3742 G_TYPE_STRING,
3743 G_TYPE_BOOLEAN);
3744
3745 signals [HOSTNAME_SELECTED] =
3746 g_signal_new ("hostname-selected",
3747 GDM_TYPE_SESSION,
3748 G_SIGNAL_RUN_FIRST,
3749 G_STRUCT_OFFSET (GdmSessionClass, disconnected),
3750 NULL,
3751 NULL,
3752 NULL,
3753 G_TYPE_NONE,
3754 1,
3755 G_TYPE_STRING);
3756 signals [DISCONNECTED] =
3757 g_signal_new ("disconnected",
3758 GDM_TYPE_SESSION,
3759 G_SIGNAL_RUN_FIRST,
3760 G_STRUCT_OFFSET (GdmSessionClass, disconnected),
3761 NULL,
3762 NULL,
3763 g_cclosure_marshal_VOID__VOID,
3764 G_TYPE_NONE,
3765 0);
3766
3767 g_object_class_install_property (object_class,
3768 PROP_VERIFICATION_MODE,
3769 g_param_spec_enum ("verification-mode",
3770 "verification mode",
3771 "verification mode",
3772 GDM_TYPE_SESSION_VERIFICATION_MODE,
3773 GDM_SESSION_VERIFICATION_MODE_LOGIN,
3774 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
3775 g_object_class_install_property (object_class,
3776 PROP_ALLOWED_USER,
3777 g_param_spec_uint ("allowed-user",
3778 "allowed user",
3779 "allowed user ",
3780 0,
3781 G_MAXUINT,
3782 0,
3783 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
3784 g_object_class_install_property (object_class,
3785 PROP_CONVERSATION_ENVIRONMENT,
3786 g_param_spec_pointer ("conversation-environment",
3787 "conversation environment",
3788 "conversation environment",
3789 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
3790
3791 g_object_class_install_property (object_class,
3792 PROP_SESSION_TYPE,
3793 g_param_spec_string ("session-type",
3794 NULL,
3795 NULL,
3796 NULL,
3797 G_PARAM_READWRITE));
3798 g_object_class_install_property (object_class,
3799 PROP_DISPLAY_NAME,
3800 g_param_spec_string ("display-name",
3801 "display name",
3802 "display name",
3803 NULL,
3804 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
3805 g_object_class_install_property (object_class,
3806 PROP_DISPLAY_HOSTNAME,
3807 g_param_spec_string ("display-hostname",
3808 "display hostname",
3809 "display hostname",
3810 NULL,
3811 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
3812 g_object_class_install_property (object_class,
3813 PROP_DISPLAY_IS_LOCAL,
3814 g_param_spec_boolean ("display-is-local",
3815 "display is local",
3816 "display is local",
3817 TRUE,
3818 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
3819 g_object_class_install_property (object_class,
3820 PROP_DISPLAY_IS_INITIAL,
3821 g_param_spec_boolean ("display-is-initial",
3822 "display is initial",
3823 "display is initial",
3824 FALSE,
3825 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
3826 g_object_class_install_property (object_class,
3827 PROP_DISPLAY_X11_AUTHORITY_FILE,
3828 g_param_spec_string ("display-x11-authority-file",
3829 "display x11 authority file",
3830 "display x11 authority file",
3831 NULL,
3832 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
3833 /* not construct only */
3834 g_object_class_install_property (object_class,
3835 PROP_USER_X11_AUTHORITY_FILE,
3836 g_param_spec_string ("user-x11-authority-file",
3837 "",
3838 "",
3839 NULL,
3840 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
3841 g_object_class_install_property (object_class,
3842 PROP_DISPLAY_DEVICE,
3843 g_param_spec_string ("display-device",
3844 "display device",
3845 "display device",
3846 NULL,
3847 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
3848
3849 g_object_class_install_property (object_class,
3850 PROP_DISPLAY_SEAT_ID,
3851 g_param_spec_string ("display-seat-id",
3852 "display seat id",
3853 "display seat id",
3854 NULL,
3855 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
3856
3857 #ifdef ENABLE_WAYLAND_SUPPORT
3858 g_object_class_install_property (object_class,
3859 PROP_IGNORE_WAYLAND,
3860 g_param_spec_boolean ("ignore-wayland",
3861 "ignore wayland",
3862 "ignore wayland",
3863 FALSE,
3864 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
3865 #endif
3866 }
3867
3868 GdmSession *
gdm_session_new(GdmSessionVerificationMode verification_mode,uid_t allowed_user,const char * display_name,const char * display_hostname,const char * display_device,const char * display_seat_id,const char * display_x11_authority_file,gboolean display_is_local,const char * const * environment)3869 gdm_session_new (GdmSessionVerificationMode verification_mode,
3870 uid_t allowed_user,
3871 const char *display_name,
3872 const char *display_hostname,
3873 const char *display_device,
3874 const char *display_seat_id,
3875 const char *display_x11_authority_file,
3876 gboolean display_is_local,
3877 const char * const *environment)
3878 {
3879 GdmSession *self;
3880
3881 self = g_object_new (GDM_TYPE_SESSION,
3882 "verification-mode", verification_mode,
3883 "allowed-user", (guint) allowed_user,
3884 "display-name", display_name,
3885 "display-hostname", display_hostname,
3886 "display-device", display_device,
3887 "display-seat-id", display_seat_id,
3888 "display-x11-authority-file", display_x11_authority_file,
3889 "display-is-local", display_is_local,
3890 "conversation-environment", environment,
3891 NULL);
3892
3893 return self;
3894 }
3895
3896 GdmSessionDisplayMode
gdm_session_display_mode_from_string(const char * str)3897 gdm_session_display_mode_from_string (const char *str)
3898 {
3899 if (strcmp (str, "reuse-vt") == 0)
3900 return GDM_SESSION_DISPLAY_MODE_REUSE_VT;
3901 if (strcmp (str, "new-vt") == 0)
3902 return GDM_SESSION_DISPLAY_MODE_NEW_VT;
3903 if (strcmp (str, "logind-managed") == 0)
3904 return GDM_SESSION_DISPLAY_MODE_LOGIND_MANAGED;
3905
3906 g_warning ("Unknown GdmSessionDisplayMode %s", str);
3907 return -1;
3908 }
3909
3910 const char *
gdm_session_display_mode_to_string(GdmSessionDisplayMode mode)3911 gdm_session_display_mode_to_string (GdmSessionDisplayMode mode)
3912 {
3913 switch (mode) {
3914 case GDM_SESSION_DISPLAY_MODE_REUSE_VT:
3915 return "reuse-vt";
3916 case GDM_SESSION_DISPLAY_MODE_NEW_VT:
3917 return "new-vt";
3918 case GDM_SESSION_DISPLAY_MODE_LOGIND_MANAGED:
3919 return "logind-managed";
3920 default:
3921 break;
3922 }
3923
3924 g_warning ("Unknown GdmSessionDisplayMode %d", mode);
3925 return "";
3926 }
3927
3928 GPid
gdm_session_get_pid(GdmSession * session)3929 gdm_session_get_pid (GdmSession *session)
3930 {
3931 return session->priv->session_pid;
3932 }
3933