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