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 of the License, or
9 * (at your option) 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 02110-1301, USA.
19 *
20 */
21
22 #include "config.h"
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #include <sys/wait.h>
31 #ifdef WITH_SYSTEMD
32 #include <sys/ioctl.h>
33 #include <sys/vt.h>
34 #include <sys/kd.h>
35 #endif
36 #include <errno.h>
37 #include <grp.h>
38 #include <pwd.h>
39
40 #include <security/pam_appl.h>
41
42 #ifdef HAVE_LOGINCAP
43 #include <login_cap.h>
44 #endif
45
46 #include <glib.h>
47 #include <glib/gi18n.h>
48 #include <glib/gstdio.h>
49 #include <glib-object.h>
50 #include <gio/gio.h>
51
52 #include <X11/Xauth.h>
53
54 #ifdef WITH_SYSTEMD
55 #include <systemd/sd-daemon.h>
56 #endif
57
58 #ifdef ENABLE_SYSTEMD_JOURNAL
59 #include <systemd/sd-journal.h>
60 #endif
61
62 #ifdef HAVE_SELINUX
63 #include <selinux/selinux.h>
64 #endif /* HAVE_SELINUX */
65
66 #include "gdm-common.h"
67 #include "gdm-log.h"
68
69 #ifdef SUPPORTS_PAM_EXTENSIONS
70 #include "gdm-pam-extensions.h"
71 #endif
72
73 #include "gdm-session-worker.h"
74 #include "gdm-session-glue.h"
75 #include "gdm-session.h"
76
77 #if defined (HAVE_ADT)
78 #include "gdm-session-solaris-auditor.h"
79 #elif defined (HAVE_LIBAUDIT)
80 #include "gdm-session-linux-auditor.h"
81 #else
82 #include "gdm-session-auditor.h"
83 #endif
84
85 #include "gdm-session-settings.h"
86
87 #define GDM_SESSION_WORKER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_SESSION_WORKER, GdmSessionWorkerPrivate))
88
89 #define GDM_SESSION_DBUS_PATH "/org/gnome/DisplayManager/Session"
90 #define GDM_SESSION_DBUS_NAME "org.gnome.DisplayManager.Session"
91 #define GDM_SESSION_DBUS_ERROR_CANCEL "org.gnome.DisplayManager.Session.Error.Cancel"
92
93 #define GDM_WORKER_DBUS_PATH "/org/gnome/DisplayManager/Worker"
94
95 #ifndef GDM_PASSWD_AUXILLARY_BUFFER_SIZE
96 #define GDM_PASSWD_AUXILLARY_BUFFER_SIZE 1024
97 #endif
98
99 #ifndef GDM_SESSION_DEFAULT_PATH
100 #define GDM_SESSION_DEFAULT_PATH "/usr/local/bin:/usr/bin:/bin"
101 #endif
102
103 #ifndef GDM_SESSION_ROOT_UID
104 #define GDM_SESSION_ROOT_UID 0
105 #endif
106
107 #ifndef GDM_SESSION_LOG_FILENAME
108 #define GDM_SESSION_LOG_FILENAME "session.log"
109 #endif
110
111 #define MAX_FILE_SIZE 65536
112 #define MAX_LOGS 5
113
114 #define RELEASE_DISPLAY_SIGNAL (SIGRTMAX)
115 #define ACQUIRE_DISPLAY_SIGNAL (SIGRTMAX - 1)
116
117 enum {
118 GDM_SESSION_WORKER_STATE_NONE = 0,
119 GDM_SESSION_WORKER_STATE_SETUP_COMPLETE,
120 GDM_SESSION_WORKER_STATE_AUTHENTICATED,
121 GDM_SESSION_WORKER_STATE_AUTHORIZED,
122 GDM_SESSION_WORKER_STATE_ACCREDITED,
123 GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_SAVED,
124 GDM_SESSION_WORKER_STATE_SESSION_OPENED,
125 GDM_SESSION_WORKER_STATE_SESSION_STARTED
126 };
127
128 typedef struct
129 {
130 GdmSessionWorker *worker;
131 GdmSession *session;
132 GPid pid_of_caller;
133 uid_t uid_of_caller;
134
135 } ReauthenticationRequest;
136
137 struct GdmSessionWorkerPrivate
138 {
139 int state;
140
141 int exit_code;
142
143 #ifdef WITH_CONSOLE_KIT
144 char *session_cookie;
145 #endif
146
147 pam_handle_t *pam_handle;
148
149 GPid child_pid;
150 guint child_watch_id;
151
152 /* from Setup */
153 char *service;
154 char *x11_display_name;
155 char *x11_authority_file;
156 char *display_device;
157 char *display_seat_id;
158 char *hostname;
159 char *username;
160 char *log_file;
161 char *session_type;
162 char *session_id;
163 uid_t uid;
164 gid_t gid;
165 gboolean password_is_required;
166 char **extensions;
167
168 int cred_flags;
169 int login_vt;
170 int session_vt;
171 int session_tty_fd;
172
173 char **arguments;
174 guint32 cancelled : 1;
175 guint32 timed_out : 1;
176 guint32 is_program_session : 1;
177 guint32 is_reauth_session : 1;
178 guint32 display_is_local : 1;
179 guint32 display_is_initial : 1;
180 guint state_change_idle_id;
181 GdmSessionDisplayMode display_mode;
182
183 char *server_address;
184 GDBusConnection *connection;
185 GdmDBusWorkerManager *manager;
186
187 GHashTable *reauthentication_requests;
188
189 GdmSessionAuditor *auditor;
190 GdmSessionSettings *user_settings;
191
192 GDBusMethodInvocation *pending_invocation;
193 };
194
195 #ifdef SUPPORTS_PAM_EXTENSIONS
196 static char gdm_pam_extension_environment_block[_POSIX_ARG_MAX];
197
198 static const char * const
199 gdm_supported_pam_extensions[] = {
200 GDM_PAM_EXTENSION_CHOICE_LIST,
201 NULL
202 };
203 #endif
204
205 enum {
206 PROP_0,
207 PROP_SERVER_ADDRESS,
208 PROP_IS_REAUTH_SESSION,
209 };
210
211 static void gdm_session_worker_class_init (GdmSessionWorkerClass *klass);
212 static void gdm_session_worker_init (GdmSessionWorker *session_worker);
213 static void gdm_session_worker_finalize (GObject *object);
214
215 static void gdm_session_worker_set_environment_variable (GdmSessionWorker *worker,
216 const char *key,
217 const char *value);
218
219 static void queue_state_change (GdmSessionWorker *worker);
220
221 static void worker_interface_init (GdmDBusWorkerIface *iface);
222
223
224 typedef int (* GdmSessionWorkerPamNewMessagesFunc) (int,
225 const struct pam_message **,
226 struct pam_response **,
227 gpointer);
228
G_DEFINE_TYPE_WITH_CODE(GdmSessionWorker,gdm_session_worker,GDM_DBUS_TYPE_WORKER_SKELETON,G_IMPLEMENT_INTERFACE (GDM_DBUS_TYPE_WORKER,worker_interface_init))229 G_DEFINE_TYPE_WITH_CODE (GdmSessionWorker,
230 gdm_session_worker,
231 GDM_DBUS_TYPE_WORKER_SKELETON,
232 G_IMPLEMENT_INTERFACE (GDM_DBUS_TYPE_WORKER,
233 worker_interface_init))
234
235 #ifdef WITH_CONSOLE_KIT
236 static gboolean
237 open_ck_session (GdmSessionWorker *worker)
238 {
239 GDBusConnection *system_bus;
240 GVariantBuilder builder;
241 GVariant *parameters;
242 GVariant *in_args;
243 struct passwd *pwent;
244 GVariant *reply;
245 GError *error = NULL;
246 const char *display_name;
247 const char *display_device;
248 const char *display_hostname;
249 const char *session_type;
250 gint32 uid;
251
252 g_assert (worker->priv->session_cookie == NULL);
253
254 if (worker->priv->x11_display_name != NULL) {
255 display_name = worker->priv->x11_display_name;
256 } else {
257 display_name = "";
258 }
259 if (worker->priv->hostname != NULL) {
260 display_hostname = worker->priv->hostname;
261 } else {
262 display_hostname = "";
263 }
264 if (worker->priv->display_device != NULL) {
265 display_device = worker->priv->display_device;
266 } else {
267 display_device = "";
268 }
269
270 if (worker->priv->session_type != NULL) {
271 session_type = worker->priv->session_type;
272 } else {
273 session_type = "";
274 }
275
276 g_assert (worker->priv->username != NULL);
277
278 gdm_get_pwent_for_name (worker->priv->username, &pwent);
279 if (pwent == NULL) {
280 goto out;
281 }
282
283 uid = (gint32) pwent->pw_uid;
284
285 error = NULL;
286 system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
287
288 if (system_bus == NULL) {
289 g_warning ("Couldn't create connection to system bus: %s",
290 error->message);
291
292 g_error_free (error);
293 goto out;
294 }
295
296 g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sv)"));
297 g_variant_builder_add_parsed (&builder, "('unix-user', <%i>)", uid);
298 g_variant_builder_add_parsed (&builder, "('x11-display-device', <%s>)", display_device);
299 g_variant_builder_add_parsed (&builder, "('x11-display', <%s>)", display_name);
300 g_variant_builder_add_parsed (&builder, "('remote-host-name', <%s>)", display_hostname);
301 g_variant_builder_add_parsed (&builder, "('is-local', <%b>)", worker->priv->display_is_local);
302 g_variant_builder_add_parsed (&builder, "('session-type', <%s>)", session_type);
303
304 parameters = g_variant_builder_end (&builder);
305 in_args = g_variant_new_tuple (¶meters, 1);
306
307 reply = g_dbus_connection_call_sync (system_bus,
308 "org.freedesktop.ConsoleKit",
309 "/org/freedesktop/ConsoleKit/Manager",
310 "org.freedesktop.ConsoleKit.Manager",
311 "OpenSessionWithParameters",
312 in_args,
313 G_VARIANT_TYPE ("(s)"),
314 G_DBUS_CALL_FLAGS_NONE,
315 -1,
316 NULL,
317 &error);
318
319 if (! reply) {
320 g_warning ("%s\n", error->message);
321 g_clear_error (&error);
322 goto out;
323 }
324
325 g_variant_get (reply, "(s)", &worker->priv->session_cookie);
326
327 g_variant_unref (reply);
328
329 out:
330 return worker->priv->session_cookie != NULL;
331 }
332
333 static void
close_ck_session(GdmSessionWorker * worker)334 close_ck_session (GdmSessionWorker *worker)
335 {
336 GDBusConnection *system_bus;
337 GVariant *reply;
338 GError *error = NULL;
339 gboolean was_closed;
340
341 if (worker->priv->session_cookie == NULL) {
342 return;
343 }
344
345 error = NULL;
346 system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
347
348 if (system_bus == NULL) {
349 g_warning ("Couldn't create connection to system bus: %s",
350 error->message);
351
352 g_error_free (error);
353 goto out;
354 }
355
356 reply = g_dbus_connection_call_sync (system_bus,
357 "org.freedesktop.ConsoleKit",
358 "/org/freedesktop/ConsoleKit/Manager",
359 "org.freedesktop.ConsoleKit.Manager",
360 "CloseSession",
361 g_variant_new ("(s)", worker->priv->session_cookie),
362 G_VARIANT_TYPE ("(b)"),
363 G_DBUS_CALL_FLAGS_NONE,
364 -1,
365 NULL,
366 &error);
367
368 if (! reply) {
369 g_warning ("%s", error->message);
370 g_clear_error (&error);
371 goto out;
372 }
373
374 g_variant_get (reply, "(b)", &was_closed);
375
376 if (!was_closed) {
377 g_warning ("Unable to close ConsoleKit session");
378 }
379
380 g_variant_unref (reply);
381
382 out:
383 g_clear_pointer (&worker->priv->session_cookie,
384 (GDestroyNotify) g_free);
385 }
386
387 static char *
get_ck_session_id(GdmSessionWorker * worker)388 get_ck_session_id (GdmSessionWorker *worker)
389 {
390 GDBusConnection *system_bus;
391 GVariant *reply;
392 GError *error = NULL;
393 char *session_id = NULL;
394
395 error = NULL;
396 system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
397
398 if (system_bus == NULL) {
399 g_warning ("Couldn't create connection to system bus: %s",
400 error->message);
401
402 g_error_free (error);
403 goto out;
404 }
405
406 reply = g_dbus_connection_call_sync (system_bus,
407 "org.freedesktop.ConsoleKit",
408 "/org/freedesktop/ConsoleKit/Manager",
409 "org.freedesktop.ConsoleKit.Manager",
410 "GetSessionForCookie",
411 g_variant_new ("(s)", worker->priv->session_cookie),
412 G_VARIANT_TYPE ("(o)"),
413 G_DBUS_CALL_FLAGS_NONE,
414 -1,
415 NULL,
416 &error);
417
418 if (reply == NULL) {
419 g_warning ("%s", error->message);
420 g_clear_error (&error);
421 goto out;
422 }
423
424 g_variant_get (reply, "(o)", &session_id);
425
426 g_variant_unref (reply);
427
428 out:
429 return session_id;
430 }
431 #endif
432
433 /* adapted from glib script_execute */
434 static void
script_execute(const gchar * file,char ** argv,char ** envp,gboolean search_path)435 script_execute (const gchar *file,
436 char **argv,
437 char **envp,
438 gboolean search_path)
439 {
440 /* Count the arguments. */
441 int argc = 0;
442
443 while (argv[argc]) {
444 ++argc;
445 }
446
447 /* Construct an argument list for the shell. */
448 {
449 char **new_argv;
450
451 new_argv = g_new0 (gchar*, argc + 2); /* /bin/sh and NULL */
452
453 new_argv[0] = (char *) "/bin/sh";
454 new_argv[1] = (char *) file;
455 while (argc > 0) {
456 new_argv[argc + 1] = argv[argc];
457 --argc;
458 }
459
460 /* Execute the shell. */
461 if (envp) {
462 execve (new_argv[0], new_argv, envp);
463 } else {
464 execv (new_argv[0], new_argv);
465 }
466
467 g_free (new_argv);
468 }
469 }
470
471 static char *
my_strchrnul(const char * str,char c)472 my_strchrnul (const char *str, char c)
473 {
474 char *p = (char*) str;
475 while (*p && (*p != c)) {
476 ++p;
477 }
478
479 return p;
480 }
481
482 /* adapted from glib g_execute */
483 static gint
gdm_session_execute(const char * file,char ** argv,char ** envp,gboolean search_path)484 gdm_session_execute (const char *file,
485 char **argv,
486 char **envp,
487 gboolean search_path)
488 {
489 if (*file == '\0') {
490 /* We check the simple case first. */
491 errno = ENOENT;
492 return -1;
493 }
494
495 if (!search_path || strchr (file, '/') != NULL) {
496 /* Don't search when it contains a slash. */
497 if (envp) {
498 execve (file, argv, envp);
499 } else {
500 execv (file, argv);
501 }
502
503 if (errno == ENOEXEC) {
504 script_execute (file, argv, envp, FALSE);
505 }
506 } else {
507 gboolean got_eacces = 0;
508 const char *path, *p;
509 char *name, *freeme;
510 gsize len;
511 gsize pathlen;
512
513 path = g_getenv ("PATH");
514 if (path == NULL) {
515 /* There is no `PATH' in the environment. The default
516 * search path in libc is the current directory followed by
517 * the path `confstr' returns for `_CS_PATH'.
518 */
519
520 /* In GLib we put . last, for security, and don't use the
521 * unportable confstr(); UNIX98 does not actually specify
522 * what to search if PATH is unset. POSIX may, dunno.
523 */
524
525 path = "/bin:/usr/bin:.";
526 }
527
528 len = strlen (file) + 1;
529 pathlen = strlen (path);
530 freeme = name = g_malloc (pathlen + len + 1);
531
532 /* Copy the file name at the top, including '\0' */
533 memcpy (name + pathlen + 1, file, len);
534 name = name + pathlen;
535 /* And add the slash before the filename */
536 *name = '/';
537
538 p = path;
539 do {
540 char *startp;
541
542 path = p;
543 p = my_strchrnul (path, ':');
544
545 if (p == path) {
546 /* Two adjacent colons, or a colon at the beginning or the end
547 * of `PATH' means to search the current directory.
548 */
549 startp = name + 1;
550 } else {
551 startp = memcpy (name - (p - path), path, p - path);
552 }
553
554 /* Try to execute this name. If it works, execv will not return. */
555 if (envp) {
556 execve (startp, argv, envp);
557 } else {
558 execv (startp, argv);
559 }
560
561 if (errno == ENOEXEC) {
562 script_execute (startp, argv, envp, search_path);
563 }
564
565 switch (errno) {
566 case EACCES:
567 /* Record the we got a `Permission denied' error. If we end
568 * up finding no executable we can use, we want to diagnose
569 * that we did find one but were denied access.
570 */
571 got_eacces = TRUE;
572
573 /* FALL THRU */
574
575 case ENOENT:
576 #ifdef ESTALE
577 case ESTALE:
578 #endif
579 #ifdef ENOTDIR
580 case ENOTDIR:
581 #endif
582 /* Those errors indicate the file is missing or not executable
583 * by us, in which case we want to just try the next path
584 * directory.
585 */
586 break;
587
588 default:
589 /* Some other error means we found an executable file, but
590 * something went wrong executing it; return the error to our
591 * caller.
592 */
593 g_free (freeme);
594 return -1;
595 }
596 } while (*p++ != '\0');
597
598 /* We tried every element and none of them worked. */
599 if (got_eacces) {
600 /* At least one failure was due to permissions, so report that
601 * error.
602 */
603 errno = EACCES;
604 }
605
606 g_free (freeme);
607 }
608
609 /* Return the error from the last attempt (probably ENOENT). */
610 return -1;
611 }
612
613 /*
614 * This function is called with username set to NULL to update the
615 * auditor username value.
616 */
617 static gboolean
gdm_session_worker_get_username(GdmSessionWorker * worker,char ** username)618 gdm_session_worker_get_username (GdmSessionWorker *worker,
619 char **username)
620 {
621 gconstpointer item;
622
623 g_assert (worker->priv->pam_handle != NULL);
624
625 if (pam_get_item (worker->priv->pam_handle, PAM_USER, &item) == PAM_SUCCESS) {
626 if (username != NULL) {
627 *username = g_strdup ((char *) item);
628 g_debug ("GdmSessionWorker: username is '%s'",
629 *username != NULL ? *username : "<unset>");
630 }
631
632 if (worker->priv->auditor != NULL) {
633 gdm_session_auditor_set_username (worker->priv->auditor, (char *)item);
634 }
635
636 return TRUE;
637 }
638
639 return FALSE;
640 }
641
642 static void
attempt_to_load_user_settings(GdmSessionWorker * worker,const char * username)643 attempt_to_load_user_settings (GdmSessionWorker *worker,
644 const char *username)
645 {
646 g_debug ("GdmSessionWorker: attempting to load user settings");
647 gdm_session_settings_load (worker->priv->user_settings,
648 username);
649 }
650
651 static void
gdm_session_worker_update_username(GdmSessionWorker * worker)652 gdm_session_worker_update_username (GdmSessionWorker *worker)
653 {
654 char *username;
655 gboolean res;
656
657 username = NULL;
658 res = gdm_session_worker_get_username (worker, &username);
659 if (res) {
660 g_debug ("GdmSessionWorker: old-username='%s' new-username='%s'",
661 worker->priv->username != NULL ? worker->priv->username : "<unset>",
662 username != NULL ? username : "<unset>");
663
664
665 gdm_session_auditor_set_username (worker->priv->auditor, worker->priv->username);
666
667 if ((worker->priv->username == username) ||
668 ((worker->priv->username != NULL) && (username != NULL) &&
669 (strcmp (worker->priv->username, username) == 0)))
670 goto out;
671
672 g_debug ("GdmSessionWorker: setting username to '%s'", username);
673
674 g_free (worker->priv->username);
675 worker->priv->username = username;
676 username = NULL;
677
678 gdm_dbus_worker_emit_username_changed (GDM_DBUS_WORKER (worker),
679 worker->priv->username);
680
681 /* We have a new username to try. If we haven't been able to
682 * read user settings up until now, then give it a go now
683 * (see the comment in do_setup for rationale on why it's useful
684 * to keep trying to read settings)
685 */
686 if (worker->priv->username != NULL &&
687 worker->priv->username[0] != '\0' &&
688 !gdm_session_settings_is_loaded (worker->priv->user_settings)) {
689 attempt_to_load_user_settings (worker, worker->priv->username);
690 }
691 }
692
693 out:
694 g_free (username);
695 }
696
697 static gboolean
gdm_session_worker_ask_question(GdmSessionWorker * worker,const char * question,char ** answerp)698 gdm_session_worker_ask_question (GdmSessionWorker *worker,
699 const char *question,
700 char **answerp)
701 {
702 return gdm_dbus_worker_manager_call_info_query_sync (worker->priv->manager,
703 worker->priv->service,
704 question,
705 answerp,
706 NULL,
707 NULL);
708 }
709
710 static gboolean
gdm_session_worker_ask_for_secret(GdmSessionWorker * worker,const char * question,char ** answerp)711 gdm_session_worker_ask_for_secret (GdmSessionWorker *worker,
712 const char *question,
713 char **answerp)
714 {
715 return gdm_dbus_worker_manager_call_secret_info_query_sync (worker->priv->manager,
716 worker->priv->service,
717 question,
718 answerp,
719 NULL,
720 NULL);
721 }
722
723 static gboolean
gdm_session_worker_report_info(GdmSessionWorker * worker,const char * info)724 gdm_session_worker_report_info (GdmSessionWorker *worker,
725 const char *info)
726 {
727 return gdm_dbus_worker_manager_call_info_sync (worker->priv->manager,
728 worker->priv->service,
729 info,
730 NULL,
731 NULL);
732 }
733
734 static gboolean
gdm_session_worker_report_problem(GdmSessionWorker * worker,const char * problem)735 gdm_session_worker_report_problem (GdmSessionWorker *worker,
736 const char *problem)
737 {
738 return gdm_dbus_worker_manager_call_problem_sync (worker->priv->manager,
739 worker->priv->service,
740 problem,
741 NULL,
742 NULL);
743 }
744
745 #ifdef SUPPORTS_PAM_EXTENSIONS
746 static gboolean
gdm_session_worker_ask_list_of_choices(GdmSessionWorker * worker,const char * prompt_message,GdmChoiceList * list,char ** answerp)747 gdm_session_worker_ask_list_of_choices (GdmSessionWorker *worker,
748 const char *prompt_message,
749 GdmChoiceList *list,
750 char **answerp)
751 {
752 GVariantBuilder builder;
753 GVariant *choices_as_variant;
754 GError *error = NULL;
755 gboolean res;
756 size_t i;
757
758 g_debug ("GdmSessionWorker: presenting user with list of choices:");
759
760 g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));
761
762 for (i = 0; i < list->number_of_items; i++) {
763 if (list->items[i].key == NULL) {
764 g_warning ("choice list contains item with NULL key");
765 g_variant_builder_clear (&builder);
766 return FALSE;
767 }
768 g_debug ("GdmSessionWorker: choices['%s'] = \"%s\"", list->items[i].key, list->items[i].text);
769 g_variant_builder_add (&builder, "{ss}", list->items[i].key, list->items[i].text);
770 }
771 g_debug ("GdmSessionWorker: (and waiting for reply)");
772
773 choices_as_variant = g_variant_builder_end (&builder);
774
775 res = gdm_dbus_worker_manager_call_choice_list_query_sync (worker->priv->manager,
776 worker->priv->service,
777 prompt_message,
778 choices_as_variant,
779 answerp,
780 NULL,
781 &error);
782
783 if (! res) {
784 g_debug ("GdmSessionWorker: list request failed: %s", error->message);
785 g_clear_error (&error);
786 } else {
787 g_debug ("GdmSessionWorker: user selected '%s'", *answerp);
788 }
789
790 return res;
791 }
792
793 static gboolean
gdm_session_worker_process_choice_list_request(GdmSessionWorker * worker,GdmPamExtensionChoiceListRequest * request,GdmPamExtensionChoiceListResponse * response)794 gdm_session_worker_process_choice_list_request (GdmSessionWorker *worker,
795 GdmPamExtensionChoiceListRequest *request,
796 GdmPamExtensionChoiceListResponse *response)
797 {
798 return gdm_session_worker_ask_list_of_choices (worker, request->prompt_message, &request->list, &response->key);
799 }
800
801 static gboolean
gdm_session_worker_process_extended_pam_message(GdmSessionWorker * worker,const struct pam_message * query,char ** response)802 gdm_session_worker_process_extended_pam_message (GdmSessionWorker *worker,
803 const struct pam_message *query,
804 char **response)
805 {
806 GdmPamExtensionMessage *extended_message;
807 gboolean res;
808
809 extended_message = GDM_PAM_EXTENSION_MESSAGE_FROM_PAM_MESSAGE (query);
810
811 if (GDM_PAM_EXTENSION_MESSAGE_TRUNCATED (extended_message)) {
812 g_warning ("PAM service requested binary response for truncated query");
813 return FALSE;
814 }
815
816 if (GDM_PAM_EXTENSION_MESSAGE_INVALID_TYPE (extended_message)) {
817 g_warning ("PAM service requested binary response for unadvertised query type");
818 return FALSE;
819 }
820
821 if (GDM_PAM_EXTENSION_MESSAGE_MATCH (extended_message, worker->priv->extensions, GDM_PAM_EXTENSION_CHOICE_LIST)) {
822 GdmPamExtensionChoiceListRequest *list_request = (GdmPamExtensionChoiceListRequest *) extended_message;
823 GdmPamExtensionChoiceListResponse *list_response = malloc (GDM_PAM_EXTENSION_CHOICE_LIST_RESPONSE_SIZE);
824
825 g_debug ("GdmSessionWorker: received extended pam message '%s'", GDM_PAM_EXTENSION_CHOICE_LIST);
826
827 GDM_PAM_EXTENSION_CHOICE_LIST_RESPONSE_INIT (list_response);
828
829 res = gdm_session_worker_process_choice_list_request (worker, list_request, list_response);
830
831 if (! res) {
832 g_free (list_response);
833 return FALSE;
834 }
835
836 *response = GDM_PAM_EXTENSION_MESSAGE_TO_PAM_REPLY (list_response);
837 return TRUE;
838 } else {
839 g_debug ("GdmSessionWorker: received extended pam message of unknown type %u", (unsigned int) extended_message->type);
840 return FALSE;
841
842 }
843
844 return TRUE;
845 }
846 #endif
847
848 static char *
convert_to_utf8(const char * str)849 convert_to_utf8 (const char *str)
850 {
851 char *utf8;
852 utf8 = g_locale_to_utf8 (str,
853 -1,
854 NULL,
855 NULL,
856 NULL);
857
858 /* if we couldn't convert text from locale then
859 * assume utf-8 and hope for the best */
860 if (utf8 == NULL) {
861 char *p;
862 char *q;
863
864 utf8 = g_strdup (str);
865
866 p = utf8;
867 while (*p != '\0' && !g_utf8_validate ((const char *)p, -1, (const char **)&q)) {
868 *q = '?';
869 p = q + 1;
870 }
871 }
872
873 return utf8;
874 }
875
876 static gboolean
gdm_session_worker_process_pam_message(GdmSessionWorker * worker,const struct pam_message * query,char ** response)877 gdm_session_worker_process_pam_message (GdmSessionWorker *worker,
878 const struct pam_message *query,
879 char **response)
880 {
881 char *user_answer;
882 gboolean res;
883 char *utf8_msg;
884 #ifdef PAM_RADIO_TYPE
885 char *msg;
886 #endif
887
888 if (response != NULL) {
889 *response = NULL;
890 }
891
892 gdm_session_worker_update_username (worker);
893
894 #ifdef SUPPORTS_PAM_EXTENSIONS
895 if (query->msg_style == PAM_BINARY_PROMPT)
896 return gdm_session_worker_process_extended_pam_message (worker, query, response);
897 #endif
898
899 g_debug ("GdmSessionWorker: received pam message of type %u with payload '%s'",
900 query->msg_style, query->msg);
901
902 utf8_msg = convert_to_utf8 (query->msg);
903
904 worker->priv->cancelled = FALSE;
905 worker->priv->timed_out = FALSE;
906
907 user_answer = NULL;
908 res = FALSE;
909 switch (query->msg_style) {
910 case PAM_PROMPT_ECHO_ON:
911 res = gdm_session_worker_ask_question (worker, utf8_msg, &user_answer);
912 break;
913 case PAM_PROMPT_ECHO_OFF:
914 res = gdm_session_worker_ask_for_secret (worker, utf8_msg, &user_answer);
915 break;
916 case PAM_TEXT_INFO:
917 res = gdm_session_worker_report_info (worker, utf8_msg);
918 break;
919 case PAM_ERROR_MSG:
920 res = gdm_session_worker_report_problem (worker, utf8_msg);
921 break;
922 #ifdef PAM_RADIO_TYPE
923 case PAM_RADIO_TYPE:
924 msg = g_strdup_printf ("%s (yes/no)", utf8_msg);
925 res = gdm_session_worker_ask_question (worker, msg, &user_answer);
926 g_free (msg);
927 break;
928 #endif
929 default:
930 res = FALSE;
931 g_warning ("Unknown and unhandled message type %d\n",
932 query->msg_style);
933
934 break;
935 }
936
937 if (worker->priv->timed_out) {
938 gdm_dbus_worker_emit_cancel_pending_query (GDM_DBUS_WORKER (worker));
939 worker->priv->timed_out = FALSE;
940 }
941
942 if (user_answer != NULL) {
943 /* we strndup and g_free to make sure we return malloc'd
944 * instead of g_malloc'd memory. PAM_MAX_RESP_SIZE includes
945 * the '\0' terminating character, thus the "- 1".
946 */
947 if (res && response != NULL) {
948 *response = strndup (user_answer, PAM_MAX_RESP_SIZE - 1);
949 }
950
951 memset (user_answer, '\0', strlen (user_answer));
952 g_free (user_answer);
953
954 g_debug ("GdmSessionWorker: trying to get updated username");
955
956 res = TRUE;
957 }
958
959 g_free (utf8_msg);
960
961 return res;
962 }
963
964 static const char *
get_friendly_error_message(int error_code)965 get_friendly_error_message (int error_code)
966 {
967 switch (error_code) {
968 case PAM_SUCCESS:
969 case PAM_IGNORE:
970 return "";
971 break;
972
973 case PAM_ACCT_EXPIRED:
974 case PAM_AUTHTOK_EXPIRED:
975 return _("Your account was given a time limit that’s now passed.");
976 break;
977
978 default:
979 break;
980 }
981
982 return _("Sorry, that didn’t work. Please try again.");
983 }
984
985 static int
gdm_session_worker_pam_new_messages_handler(int number_of_messages,const struct pam_message ** messages,struct pam_response ** responses,GdmSessionWorker * worker)986 gdm_session_worker_pam_new_messages_handler (int number_of_messages,
987 const struct pam_message **messages,
988 struct pam_response **responses,
989 GdmSessionWorker *worker)
990 {
991 struct pam_response *replies;
992 int return_value;
993 int i;
994
995 g_debug ("GdmSessionWorker: %d new messages received from PAM\n", number_of_messages);
996
997 return_value = PAM_CONV_ERR;
998
999 if (number_of_messages < 0) {
1000 return PAM_CONV_ERR;
1001 }
1002
1003 if (number_of_messages == 0) {
1004 if (responses) {
1005 *responses = NULL;
1006 }
1007
1008 return PAM_SUCCESS;
1009 }
1010
1011 /* we want to generate one reply for every question
1012 */
1013 replies = (struct pam_response *) calloc (number_of_messages,
1014 sizeof (struct pam_response));
1015 for (i = 0; i < number_of_messages; i++) {
1016 gboolean got_response;
1017 char *response;
1018
1019 response = NULL;
1020 got_response = gdm_session_worker_process_pam_message (worker,
1021 messages[i],
1022 &response);
1023 if (!got_response) {
1024 goto out;
1025 }
1026
1027 replies[i].resp = response;
1028 replies[i].resp_retcode = PAM_SUCCESS;
1029 }
1030
1031 return_value = PAM_SUCCESS;
1032
1033 out:
1034 if (return_value != PAM_SUCCESS) {
1035 for (i = 0; i < number_of_messages; i++) {
1036 if (replies[i].resp != NULL) {
1037 memset (replies[i].resp, 0, strlen (replies[i].resp));
1038 free (replies[i].resp);
1039 }
1040 memset (&replies[i], 0, sizeof (replies[i]));
1041 }
1042 free (replies);
1043 replies = NULL;
1044 }
1045
1046 if (responses) {
1047 *responses = replies;
1048 }
1049
1050 g_debug ("GdmSessionWorker: PAM conversation returning %d: %s",
1051 return_value,
1052 pam_strerror (worker->priv->pam_handle, return_value));
1053
1054 return return_value;
1055 }
1056
1057 static void
gdm_session_worker_start_auditor(GdmSessionWorker * worker)1058 gdm_session_worker_start_auditor (GdmSessionWorker *worker)
1059 {
1060 /* Use dummy auditor so program session doesn't pollute user audit logs
1061 */
1062 if (worker->priv->is_program_session) {
1063 worker->priv->auditor = gdm_session_auditor_new (worker->priv->hostname,
1064 worker->priv->display_device);
1065 return;
1066 }
1067
1068 /* FIXME: it may make sense at some point to keep a list of
1069 * auditors, instead of assuming they are mutually exclusive
1070 */
1071 #if defined (HAVE_ADT)
1072 worker->priv->auditor = gdm_session_solaris_auditor_new (worker->priv->hostname,
1073 worker->priv->display_device);
1074 #elif defined (HAVE_LIBAUDIT)
1075 worker->priv->auditor = gdm_session_linux_auditor_new (worker->priv->hostname,
1076 worker->priv->display_device);
1077 #else
1078 worker->priv->auditor = gdm_session_auditor_new (worker->priv->hostname,
1079 worker->priv->display_device);
1080 #endif
1081 }
1082
1083 static void
gdm_session_worker_stop_auditor(GdmSessionWorker * worker)1084 gdm_session_worker_stop_auditor (GdmSessionWorker *worker)
1085 {
1086 g_object_unref (worker->priv->auditor);
1087 worker->priv->auditor = NULL;
1088 }
1089
1090 #ifdef WITH_SYSTEMD
1091 static void
on_release_display(int signal)1092 on_release_display (int signal)
1093 {
1094 int fd;
1095
1096 fd = open ("/dev/tty0", O_RDWR | O_NOCTTY);
1097 ioctl(fd, VT_RELDISP, 1);
1098 close(fd);
1099 }
1100
1101 static void
on_acquire_display(int signal)1102 on_acquire_display (int signal)
1103 {
1104 int fd;
1105
1106 fd = open ("/dev/tty0", O_RDWR | O_NOCTTY);
1107 ioctl(fd, VT_RELDISP, VT_ACKACQ);
1108 close(fd);
1109 }
1110
1111 static gboolean
handle_terminal_vt_switches(GdmSessionWorker * worker,int tty_fd)1112 handle_terminal_vt_switches (GdmSessionWorker *worker,
1113 int tty_fd)
1114 {
1115 struct vt_mode setmode_request = { 0 };
1116 gboolean succeeded = TRUE;
1117
1118 setmode_request.mode = VT_PROCESS;
1119 setmode_request.relsig = RELEASE_DISPLAY_SIGNAL;
1120 setmode_request.acqsig = ACQUIRE_DISPLAY_SIGNAL;
1121
1122 if (ioctl (tty_fd, VT_SETMODE, &setmode_request) < 0) {
1123 g_debug ("GdmSessionWorker: couldn't manage VTs manually: %m");
1124 succeeded = FALSE;
1125 }
1126
1127 signal (RELEASE_DISPLAY_SIGNAL, on_release_display);
1128 signal (ACQUIRE_DISPLAY_SIGNAL, on_acquire_display);
1129
1130 return succeeded;
1131 }
1132
1133 static void
fix_terminal_vt_mode(GdmSessionWorker * worker,int tty_fd)1134 fix_terminal_vt_mode (GdmSessionWorker *worker,
1135 int tty_fd)
1136 {
1137 struct vt_mode getmode_reply = { 0 };
1138 int kernel_display_mode = 0;
1139 gboolean mode_fixed = FALSE;
1140 gboolean succeeded = TRUE;
1141
1142 if (ioctl (tty_fd, VT_GETMODE, &getmode_reply) < 0) {
1143 g_debug ("GdmSessionWorker: couldn't query VT mode: %m");
1144 succeeded = FALSE;
1145 }
1146
1147 if (getmode_reply.mode != VT_AUTO) {
1148 goto out;
1149 }
1150
1151 if (ioctl (tty_fd, KDGETMODE, &kernel_display_mode) < 0) {
1152 g_debug ("GdmSessionWorker: couldn't query kernel display mode: %m");
1153 succeeded = FALSE;
1154 }
1155
1156 if (kernel_display_mode == KD_TEXT) {
1157 goto out;
1158 }
1159
1160 /* VT is in the anti-social state of VT_AUTO + KD_GRAPHICS,
1161 * fix it.
1162 */
1163 succeeded = handle_terminal_vt_switches (worker, tty_fd);
1164 mode_fixed = TRUE;
1165 out:
1166 if (!succeeded) {
1167 g_error ("GdmSessionWorker: couldn't set up terminal, aborting...");
1168 return;
1169 }
1170
1171 g_debug ("GdmSessionWorker: VT mode did %sneed to be fixed",
1172 mode_fixed? "" : "not ");
1173 }
1174
1175 static void
jump_to_vt(GdmSessionWorker * worker,int vt_number)1176 jump_to_vt (GdmSessionWorker *worker,
1177 int vt_number)
1178 {
1179 int fd;
1180 int active_vt_tty_fd;
1181
1182 g_debug ("GdmSessionWorker: jumping to VT %d", vt_number);
1183 active_vt_tty_fd = open ("/dev/tty0", O_RDWR | O_NOCTTY);
1184
1185 if (worker->priv->session_tty_fd != -1) {
1186 fd = worker->priv->session_tty_fd;
1187
1188 g_debug ("GdmSessionWorker: first setting graphics mode to prevent flicker");
1189 if (ioctl (fd, KDSETMODE, KD_GRAPHICS) < 0) {
1190 g_debug ("GdmSessionWorker: couldn't set graphics mode: %m");
1191 }
1192
1193 /* It's possible that the current VT was left in a broken
1194 * combination of states (KD_GRAPHICS with VT_AUTO), that
1195 * can't be switched away from. This call makes sure things
1196 * are set in a way that VT_ACTIVATE should work and
1197 * VT_WAITACTIVE shouldn't hang.
1198 */
1199 fix_terminal_vt_mode (worker, active_vt_tty_fd);
1200 } else {
1201 fd = active_vt_tty_fd;
1202 }
1203
1204 handle_terminal_vt_switches (worker, fd);
1205
1206 if (ioctl (fd, VT_ACTIVATE, vt_number) < 0) {
1207 g_debug ("GdmSessionWorker: couldn't initiate jump to VT %d: %m",
1208 vt_number);
1209 } else if (ioctl (fd, VT_WAITACTIVE, vt_number) < 0) {
1210 g_debug ("GdmSessionWorker: couldn't finalize jump to VT %d: %m",
1211 vt_number);
1212 }
1213
1214 close (active_vt_tty_fd);
1215 }
1216 #endif
1217
1218 static void
gdm_session_worker_uninitialize_pam(GdmSessionWorker * worker,int status)1219 gdm_session_worker_uninitialize_pam (GdmSessionWorker *worker,
1220 int status)
1221 {
1222 g_debug ("GdmSessionWorker: uninitializing PAM");
1223
1224 if (worker->priv->pam_handle == NULL)
1225 return;
1226
1227 gdm_session_worker_get_username (worker, NULL);
1228
1229 if (worker->priv->state >= GDM_SESSION_WORKER_STATE_SESSION_OPENED) {
1230 pam_close_session (worker->priv->pam_handle, 0);
1231 gdm_session_auditor_report_logout (worker->priv->auditor);
1232 } else {
1233 gdm_session_auditor_report_login_failure (worker->priv->auditor,
1234 status,
1235 pam_strerror (worker->priv->pam_handle, status));
1236 }
1237
1238 if (worker->priv->state >= GDM_SESSION_WORKER_STATE_ACCREDITED) {
1239 pam_setcred (worker->priv->pam_handle, PAM_DELETE_CRED);
1240 }
1241
1242 pam_end (worker->priv->pam_handle, status);
1243 worker->priv->pam_handle = NULL;
1244
1245 gdm_session_worker_stop_auditor (worker);
1246
1247 #ifdef WITH_SYSTEMD
1248 if (g_strcmp0 (worker->priv->display_seat_id, "seat0") == 0) {
1249 if (worker->priv->login_vt != worker->priv->session_vt) {
1250 jump_to_vt (worker, worker->priv->login_vt);
1251 }
1252 }
1253 #endif
1254
1255 worker->priv->login_vt = 0;
1256 worker->priv->session_vt = 0;
1257
1258 g_debug ("GdmSessionWorker: state NONE");
1259 worker->priv->state = GDM_SESSION_WORKER_STATE_NONE;
1260 }
1261
1262 static char *
_get_tty_for_pam(const char * x11_display_name,const char * display_device)1263 _get_tty_for_pam (const char *x11_display_name,
1264 const char *display_device)
1265 {
1266 #ifdef __sun
1267 return g_strdup (display_device);
1268 #else
1269 return g_strdup (x11_display_name);
1270 #endif
1271 }
1272
1273 #ifdef PAM_XAUTHDATA
1274 static struct pam_xauth_data *
_get_xauth_for_pam(const char * x11_authority_file)1275 _get_xauth_for_pam (const char *x11_authority_file)
1276 {
1277 FILE *fh;
1278 Xauth *auth = NULL;
1279 struct pam_xauth_data *retval = NULL;
1280 gsize len = sizeof (*retval) + 1;
1281
1282 fh = fopen (x11_authority_file, "r");
1283 if (fh) {
1284 auth = XauReadAuth (fh);
1285 fclose (fh);
1286 }
1287 if (auth) {
1288 len += auth->name_length + auth->data_length;
1289 retval = g_malloc0 (len);
1290 }
1291 if (retval) {
1292 retval->namelen = auth->name_length;
1293 retval->name = (char *) (retval + 1);
1294 memcpy (retval->name, auth->name, auth->name_length);
1295 retval->datalen = auth->data_length;
1296 retval->data = retval->name + auth->name_length + 1;
1297 memcpy (retval->data, auth->data, auth->data_length);
1298 }
1299 XauDisposeAuth (auth);
1300 return retval;
1301 }
1302 #endif
1303
1304 #ifdef WITH_SYSTEMD
1305 static gboolean
ensure_login_vt(GdmSessionWorker * worker)1306 ensure_login_vt (GdmSessionWorker *worker)
1307 {
1308 int fd;
1309 struct vt_stat vt_state = { 0 };
1310 gboolean got_login_vt = FALSE;
1311
1312 fd = open ("/dev/tty0", O_RDWR | O_NOCTTY);
1313
1314 if (fd < 0) {
1315 g_debug ("GdmSessionWorker: couldn't open VT master: %m");
1316 return FALSE;
1317 }
1318
1319 if (ioctl (fd, VT_GETSTATE, &vt_state) < 0) {
1320 g_debug ("GdmSessionWorker: couldn't get current VT: %m");
1321 goto out;
1322 }
1323
1324 worker->priv->login_vt = vt_state.v_active;
1325 got_login_vt = TRUE;
1326 out:
1327 close (fd);
1328 return got_login_vt;
1329 }
1330 #endif
1331
1332 static gboolean
gdm_session_worker_initialize_pam(GdmSessionWorker * worker,const char * service,const char * const * extensions,const char * username,const char * hostname,gboolean display_is_local,const char * x11_display_name,const char * x11_authority_file,const char * display_device,const char * seat_id,GError ** error)1333 gdm_session_worker_initialize_pam (GdmSessionWorker *worker,
1334 const char *service,
1335 const char * const *extensions,
1336 const char *username,
1337 const char *hostname,
1338 gboolean display_is_local,
1339 const char *x11_display_name,
1340 const char *x11_authority_file,
1341 const char *display_device,
1342 const char *seat_id,
1343 GError **error)
1344 {
1345 struct pam_conv pam_conversation;
1346 int error_code;
1347
1348 g_assert (worker->priv->pam_handle == NULL);
1349
1350 g_debug ("GdmSessionWorker: initializing PAM; service=%s username=%s seat=%s",
1351 service ? service : "(null)",
1352 username ? username : "(null)",
1353 seat_id ? seat_id : "(null)");
1354
1355 #ifdef SUPPORTS_PAM_EXTENSIONS
1356 if (extensions != NULL) {
1357 GDM_PAM_EXTENSION_ADVERTISE_SUPPORTED_EXTENSIONS (gdm_pam_extension_environment_block, extensions);
1358 }
1359 #endif
1360
1361 pam_conversation.conv = (GdmSessionWorkerPamNewMessagesFunc) gdm_session_worker_pam_new_messages_handler;
1362 pam_conversation.appdata_ptr = worker;
1363
1364 gdm_session_worker_start_auditor (worker);
1365 error_code = pam_start (service,
1366 username,
1367 &pam_conversation,
1368 &worker->priv->pam_handle);
1369 if (error_code != PAM_SUCCESS) {
1370 g_debug ("GdmSessionWorker: could not initialize PAM: (error code %d)", error_code);
1371 /* we don't use pam_strerror here because it requires a valid
1372 * pam handle, and if pam_start fails pam_handle is undefined
1373 */
1374 g_set_error (error,
1375 GDM_SESSION_WORKER_ERROR,
1376 GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE,
1377 "%s", "");
1378
1379 goto out;
1380 }
1381
1382 /* set USER PROMPT */
1383 if (username == NULL) {
1384 error_code = pam_set_item (worker->priv->pam_handle, PAM_USER_PROMPT, _("Username:"));
1385
1386 if (error_code != PAM_SUCCESS) {
1387 g_debug ("GdmSessionWorker: error informing authentication system of preferred username prompt: %s",
1388 pam_strerror (worker->priv->pam_handle, error_code));
1389 g_set_error (error,
1390 GDM_SESSION_WORKER_ERROR,
1391 GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
1392 "%s", "");
1393 goto out;
1394 }
1395 }
1396
1397 /* set RHOST */
1398 if (hostname != NULL && hostname[0] != '\0') {
1399 error_code = pam_set_item (worker->priv->pam_handle, PAM_RHOST, hostname);
1400 g_debug ("error informing authentication system of user's hostname %s: %s",
1401 hostname,
1402 pam_strerror (worker->priv->pam_handle, error_code));
1403
1404 if (error_code != PAM_SUCCESS) {
1405 g_set_error (error,
1406 GDM_SESSION_WORKER_ERROR,
1407 GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
1408 "%s", "");
1409 goto out;
1410 }
1411 }
1412
1413 #ifdef WITH_SYSTEMD
1414 /* set seat ID */
1415 if (seat_id != NULL && seat_id[0] != '\0' && LOGIND_RUNNING()) {
1416 gdm_session_worker_set_environment_variable (worker, "XDG_SEAT", seat_id);
1417 }
1418 #endif
1419
1420 if (strcmp (service, "gdm-launch-environment") == 0) {
1421 gdm_session_worker_set_environment_variable (worker, "XDG_SESSION_CLASS", "greeter");
1422 }
1423
1424 g_debug ("GdmSessionWorker: state SETUP_COMPLETE");
1425 worker->priv->state = GDM_SESSION_WORKER_STATE_SETUP_COMPLETE;
1426
1427 #ifdef WITH_SYSTEMD
1428 /* Temporarily set PAM_TTY with the currently active VT (login screen)
1429 PAM_TTY will be reset with the users VT right before the user session is opened */
1430 ensure_login_vt (worker);
1431 g_snprintf (tty_string, 256, "/dev/tty%d", worker->priv->login_vt);
1432 pam_set_item (worker->priv->pam_handle, PAM_TTY, tty_string);
1433 if (!display_is_local)
1434 worker->priv->password_is_required = TRUE;
1435 #endif
1436
1437 out:
1438 if (error_code != PAM_SUCCESS) {
1439 gdm_session_worker_uninitialize_pam (worker, error_code);
1440 return FALSE;
1441 }
1442
1443 return TRUE;
1444 }
1445
1446 static gboolean
gdm_session_worker_authenticate_user(GdmSessionWorker * worker,gboolean password_is_required,GError ** error)1447 gdm_session_worker_authenticate_user (GdmSessionWorker *worker,
1448 gboolean password_is_required,
1449 GError **error)
1450 {
1451 int error_code;
1452 int authentication_flags;
1453
1454 g_debug ("GdmSessionWorker: authenticating user %s", worker->priv->username);
1455
1456 authentication_flags = 0;
1457
1458 if (password_is_required) {
1459 authentication_flags |= PAM_DISALLOW_NULL_AUTHTOK;
1460 }
1461
1462 /* blocking call, does the actual conversation */
1463 error_code = pam_authenticate (worker->priv->pam_handle, authentication_flags);
1464
1465 if (error_code == PAM_AUTHINFO_UNAVAIL) {
1466 g_debug ("GdmSessionWorker: authentication service unavailable");
1467
1468 g_set_error (error,
1469 GDM_SESSION_WORKER_ERROR,
1470 GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE,
1471 "%s", "");
1472 goto out;
1473 } else if (error_code != PAM_SUCCESS) {
1474 g_debug ("GdmSessionWorker: authentication returned %d: %s", error_code, pam_strerror (worker->priv->pam_handle, error_code));
1475
1476 /*
1477 * Do not display a different message for user unknown versus
1478 * a failed password for a valid user.
1479 */
1480 if (error_code == PAM_USER_UNKNOWN) {
1481 error_code = PAM_AUTH_ERR;
1482 }
1483
1484 g_set_error (error,
1485 GDM_SESSION_WORKER_ERROR,
1486 GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
1487 "%s", get_friendly_error_message (error_code));
1488 goto out;
1489 }
1490
1491 g_debug ("GdmSessionWorker: state AUTHENTICATED");
1492 worker->priv->state = GDM_SESSION_WORKER_STATE_AUTHENTICATED;
1493
1494 out:
1495 if (error_code != PAM_SUCCESS) {
1496 gdm_session_worker_uninitialize_pam (worker, error_code);
1497 return FALSE;
1498 }
1499
1500 return TRUE;
1501 }
1502
1503 static gboolean
gdm_session_worker_authorize_user(GdmSessionWorker * worker,gboolean password_is_required,GError ** error)1504 gdm_session_worker_authorize_user (GdmSessionWorker *worker,
1505 gboolean password_is_required,
1506 GError **error)
1507 {
1508 int error_code;
1509 int authentication_flags;
1510
1511 g_debug ("GdmSessionWorker: determining if authenticated user (password required:%d) is authorized to session",
1512 password_is_required);
1513
1514 authentication_flags = 0;
1515
1516 if (password_is_required) {
1517 authentication_flags |= PAM_DISALLOW_NULL_AUTHTOK;
1518 }
1519
1520 /* check that the account isn't disabled or expired
1521 */
1522 error_code = pam_acct_mgmt (worker->priv->pam_handle, authentication_flags);
1523
1524 /* it's possible that the user needs to change their password or pin code
1525 */
1526 if (error_code == PAM_NEW_AUTHTOK_REQD && !worker->priv->is_program_session) {
1527 g_debug ("GdmSessionWorker: authenticated user requires new auth token");
1528 error_code = pam_chauthtok (worker->priv->pam_handle, PAM_CHANGE_EXPIRED_AUTHTOK);
1529
1530 gdm_session_worker_get_username (worker, NULL);
1531
1532 if (error_code != PAM_SUCCESS) {
1533 gdm_session_auditor_report_password_change_failure (worker->priv->auditor);
1534 } else {
1535 gdm_session_auditor_report_password_changed (worker->priv->auditor);
1536 }
1537 }
1538
1539 /* If the user is reauthenticating, then authorization isn't required to
1540 * proceed, the user is already logged in after all.
1541 */
1542 if (worker->priv->is_reauth_session) {
1543 error_code = PAM_SUCCESS;
1544 }
1545
1546 if (error_code != PAM_SUCCESS) {
1547 g_debug ("GdmSessionWorker: user is not authorized to log in: %s",
1548 pam_strerror (worker->priv->pam_handle, error_code));
1549 g_set_error (error,
1550 GDM_SESSION_WORKER_ERROR,
1551 GDM_SESSION_WORKER_ERROR_AUTHORIZING,
1552 "%s", get_friendly_error_message (error_code));
1553 goto out;
1554 }
1555
1556 g_debug ("GdmSessionWorker: state AUTHORIZED");
1557 worker->priv->state = GDM_SESSION_WORKER_STATE_AUTHORIZED;
1558
1559 out:
1560 if (error_code != PAM_SUCCESS) {
1561 gdm_session_worker_uninitialize_pam (worker, error_code);
1562 return FALSE;
1563 }
1564
1565 return TRUE;
1566 }
1567
1568 static void
gdm_session_worker_set_environment_variable(GdmSessionWorker * worker,const char * key,const char * value)1569 gdm_session_worker_set_environment_variable (GdmSessionWorker *worker,
1570 const char *key,
1571 const char *value)
1572 {
1573 int error_code;
1574 char *environment_entry;
1575
1576 if (value != NULL) {
1577 environment_entry = g_strdup_printf ("%s=%s", key, value);
1578 } else {
1579 /* empty value means "remove from environment" */
1580 environment_entry = g_strdup (key);
1581 }
1582
1583 error_code = pam_putenv (worker->priv->pam_handle,
1584 environment_entry);
1585
1586 if (error_code != PAM_SUCCESS) {
1587 g_warning ("cannot put %s in pam environment: %s\n",
1588 environment_entry,
1589 pam_strerror (worker->priv->pam_handle, error_code));
1590 }
1591 g_debug ("GdmSessionWorker: Set PAM environment variable: '%s'", environment_entry);
1592 g_free (environment_entry);
1593 }
1594
1595 static char *
gdm_session_worker_get_environment_variable(GdmSessionWorker * worker,const char * key)1596 gdm_session_worker_get_environment_variable (GdmSessionWorker *worker,
1597 const char *key)
1598 {
1599 return g_strdup (pam_getenv (worker->priv->pam_handle, key));
1600 }
1601
1602 static void
gdm_session_worker_update_environment_from_passwd_info(GdmSessionWorker * worker,uid_t uid,gid_t gid,const char * home,const char * shell)1603 gdm_session_worker_update_environment_from_passwd_info (GdmSessionWorker *worker,
1604 uid_t uid,
1605 gid_t gid,
1606 const char *home,
1607 const char *shell)
1608 {
1609 gdm_session_worker_set_environment_variable (worker, "LOGNAME", worker->priv->username);
1610 gdm_session_worker_set_environment_variable (worker, "USER", worker->priv->username);
1611 gdm_session_worker_set_environment_variable (worker, "USERNAME", worker->priv->username);
1612 gdm_session_worker_set_environment_variable (worker, "HOME", home);
1613 gdm_session_worker_set_environment_variable (worker, "PWD", home);
1614 gdm_session_worker_set_environment_variable (worker, "SHELL", shell);
1615 }
1616
1617 static gboolean
gdm_session_worker_environment_variable_is_set(GdmSessionWorker * worker,const char * key)1618 gdm_session_worker_environment_variable_is_set (GdmSessionWorker *worker,
1619 const char *key)
1620 {
1621 return pam_getenv (worker->priv->pam_handle, key) != NULL;
1622 }
1623
1624 static gboolean
_change_user(GdmSessionWorker * worker,uid_t uid,gid_t gid)1625 _change_user (GdmSessionWorker *worker,
1626 uid_t uid,
1627 gid_t gid)
1628 {
1629 #ifdef THE_MAN_PAGE_ISNT_LYING
1630 /* pam_setcred wants to be called as the authenticated user
1631 * but pam_open_session needs to be called as super-user.
1632 *
1633 * Set the real uid and gid to the user and give the user a
1634 * temporary super-user effective id.
1635 */
1636 if (setreuid (uid, GDM_SESSION_ROOT_UID) < 0) {
1637 return FALSE;
1638 }
1639 #endif
1640 worker->priv->uid = uid;
1641 worker->priv->gid = gid;
1642
1643 if (setgid (gid) < 0) {
1644 return FALSE;
1645 }
1646
1647 if (initgroups (worker->priv->username, gid) < 0) {
1648 return FALSE;
1649 }
1650
1651 return TRUE;
1652 }
1653
1654 static gboolean
_lookup_passwd_info(const char * username,uid_t * uidp,gid_t * gidp,char ** homep,char ** shellp)1655 _lookup_passwd_info (const char *username,
1656 uid_t *uidp,
1657 gid_t *gidp,
1658 char **homep,
1659 char **shellp)
1660 {
1661 gboolean ret;
1662 struct passwd *passwd_entry;
1663 struct passwd passwd_buffer;
1664 char *aux_buffer;
1665 long required_aux_buffer_size;
1666 gsize aux_buffer_size;
1667
1668 ret = FALSE;
1669 aux_buffer = NULL;
1670 aux_buffer_size = 0;
1671
1672 required_aux_buffer_size = sysconf (_SC_GETPW_R_SIZE_MAX);
1673
1674 if (required_aux_buffer_size < 0) {
1675 aux_buffer_size = GDM_PASSWD_AUXILLARY_BUFFER_SIZE;
1676 } else {
1677 aux_buffer_size = (gsize) required_aux_buffer_size;
1678 }
1679
1680 aux_buffer = g_slice_alloc0 (aux_buffer_size);
1681
1682 /* we use the _r variant of getpwnam()
1683 * (with its weird semantics) so that the
1684 * passwd_entry doesn't potentially get stomped on
1685 * by a PAM module
1686 */
1687 again:
1688 passwd_entry = NULL;
1689 #ifdef HAVE_POSIX_GETPWNAM_R
1690 errno = getpwnam_r (username,
1691 &passwd_buffer,
1692 aux_buffer,
1693 (size_t) aux_buffer_size,
1694 &passwd_entry);
1695 #else
1696 passwd_entry = getpwnam_r (username,
1697 &passwd_buffer,
1698 aux_buffer,
1699 (size_t) aux_buffer_size);
1700 errno = 0;
1701 #endif /* !HAVE_POSIX_GETPWNAM_R */
1702 if (errno == EINTR) {
1703 g_debug ("%s", g_strerror (errno));
1704 goto again;
1705 } else if (errno != 0) {
1706 g_warning ("%s", g_strerror (errno));
1707 goto out;
1708 }
1709
1710 if (passwd_entry == NULL) {
1711 goto out;
1712 }
1713
1714 if (uidp != NULL) {
1715 *uidp = passwd_entry->pw_uid;
1716 }
1717 if (gidp != NULL) {
1718 *gidp = passwd_entry->pw_gid;
1719 }
1720 if (homep != NULL) {
1721 if (passwd_entry->pw_dir != NULL && passwd_entry->pw_dir[0] != '\0') {
1722 *homep = g_strdup (passwd_entry->pw_dir);
1723 } else {
1724 *homep = g_strdup ("/");
1725 }
1726 }
1727 if (shellp != NULL) {
1728 if (passwd_entry->pw_shell != NULL && passwd_entry->pw_shell[0] != '\0') {
1729 *shellp = g_strdup (passwd_entry->pw_shell);
1730 } else {
1731 *shellp = g_strdup ("/bin/sh");
1732 }
1733 }
1734 ret = TRUE;
1735 out:
1736 if (aux_buffer != NULL) {
1737 g_assert (aux_buffer_size > 0);
1738 g_slice_free1 (aux_buffer_size, aux_buffer);
1739 }
1740
1741 return ret;
1742 }
1743
1744 static char *
get_var_cb(const char * key,gpointer user_data)1745 get_var_cb (const char *key,
1746 gpointer user_data)
1747 {
1748 return gdm_session_worker_get_environment_variable (user_data, key);
1749 }
1750
1751 static void
load_env_file(GdmSessionWorker * worker,GFile * file)1752 load_env_file (GdmSessionWorker *worker,
1753 GFile *file)
1754 {
1755 gchar *contents;
1756 gchar **lines;
1757 gchar *line, *p;
1758 gchar *var, *var_end;
1759 gchar *expanded;
1760 char *filename;
1761 int i;
1762
1763 filename = g_file_get_path (file);
1764 g_debug ("Loading env vars from %s\n", filename);
1765 g_free (filename);
1766
1767 if (g_file_load_contents (file, NULL, &contents, NULL, NULL, NULL)) {
1768 lines = g_strsplit (contents, "\n", -1);
1769 g_free (contents);
1770 for (i = 0; lines[i] != NULL; i++) {
1771 line = lines[i];
1772 p = line;
1773 while (g_ascii_isspace (*p))
1774 p++;
1775 if (*p == '#' || *p == '\0')
1776 continue;
1777 var = p;
1778 while (gdm_shell_var_is_valid_char (*p, p == var))
1779 p++;
1780 var_end = p;
1781 while (g_ascii_isspace (*p))
1782 p++;
1783 if (var == var_end || *p != '=') {
1784 g_warning ("Invalid env.d line '%s'\n", line);
1785 continue;
1786 }
1787 *var_end = 0;
1788 p++; /* Skip = */
1789 while (g_ascii_isspace (*p))
1790 p++;
1791
1792 expanded = gdm_shell_expand (p, get_var_cb, worker);
1793 expanded = g_strchomp (expanded);
1794 gdm_session_worker_set_environment_variable (worker, var, expanded);
1795 g_free (expanded);
1796 }
1797 g_strfreev (lines);
1798 }
1799 }
1800
1801 static gint
compare_str(gconstpointer a,gconstpointer b)1802 compare_str (gconstpointer a,
1803 gconstpointer b)
1804 {
1805 return strcmp (*(const char **)a, *(const char **)b);
1806 }
1807
1808 static void
gdm_session_worker_load_env_dir(GdmSessionWorker * worker,GFile * dir)1809 gdm_session_worker_load_env_dir (GdmSessionWorker *worker,
1810 GFile *dir)
1811 {
1812 GFileInfo *info = NULL;
1813 GFileEnumerator *enumerator = NULL;
1814 GPtrArray *names = NULL;
1815 GFile *file;
1816 const gchar *name;
1817 int i;
1818
1819 enumerator = g_file_enumerate_children (dir,
1820 G_FILE_ATTRIBUTE_STANDARD_TYPE","
1821 G_FILE_ATTRIBUTE_STANDARD_NAME","
1822 G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN","
1823 G_FILE_ATTRIBUTE_STANDARD_IS_BACKUP,
1824 G_FILE_QUERY_INFO_NONE,
1825 NULL, NULL);
1826 if (!enumerator) {
1827 goto out;
1828 }
1829
1830 names = g_ptr_array_new_with_free_func (g_free);
1831 while ((info = g_file_enumerator_next_file (enumerator, NULL, NULL)) != NULL) {
1832 if (g_file_info_get_file_type (info) == G_FILE_TYPE_REGULAR &&
1833 !g_file_info_get_is_hidden (info) &&
1834 g_str_has_suffix (g_file_info_get_name (info), ".env"))
1835 g_ptr_array_add (names, g_strdup (g_file_info_get_name (info)));
1836
1837 g_clear_object (&info);
1838 }
1839
1840 g_ptr_array_sort (names, compare_str);
1841
1842 for (i = 0; i < names->len; i++) {
1843 name = g_ptr_array_index (names, i);
1844 file = g_file_get_child (dir, name);
1845 load_env_file (worker, file);
1846 g_object_unref (file);
1847 }
1848
1849 out:
1850 g_clear_pointer (&names, g_ptr_array_unref);
1851 g_clear_object (&enumerator);
1852 }
1853
1854 static void
gdm_session_worker_load_env_d(GdmSessionWorker * worker)1855 gdm_session_worker_load_env_d (GdmSessionWorker *worker)
1856 {
1857 GFile *dir;
1858
1859 dir = g_file_new_for_path (DATADIR "/gdm/env.d");
1860 gdm_session_worker_load_env_dir (worker, dir);
1861 g_object_unref (dir);
1862
1863 dir = g_file_new_for_path (GDMCONFDIR "/env.d");
1864 gdm_session_worker_load_env_dir (worker, dir);
1865 g_object_unref (dir);
1866 }
1867
1868 static gboolean
gdm_session_worker_accredit_user(GdmSessionWorker * worker,GError ** error)1869 gdm_session_worker_accredit_user (GdmSessionWorker *worker,
1870 GError **error)
1871 {
1872 gboolean ret;
1873 gboolean res;
1874 uid_t uid;
1875 gid_t gid;
1876 char *shell;
1877 char *home;
1878 int error_code;
1879
1880 ret = FALSE;
1881
1882 home = NULL;
1883 shell = NULL;
1884
1885 if (worker->priv->username == NULL) {
1886 g_debug ("GdmSessionWorker: Username not set");
1887 error_code = PAM_USER_UNKNOWN;
1888 g_set_error (error,
1889 GDM_SESSION_WORKER_ERROR,
1890 GDM_SESSION_WORKER_ERROR_GIVING_CREDENTIALS,
1891 _("no user account available"));
1892 goto out;
1893 }
1894
1895 uid = 0;
1896 gid = 0;
1897 res = _lookup_passwd_info (worker->priv->username,
1898 &uid,
1899 &gid,
1900 &home,
1901 &shell);
1902 if (! res) {
1903 g_debug ("GdmSessionWorker: Unable to lookup account info");
1904 error_code = PAM_AUTHINFO_UNAVAIL;
1905 g_set_error (error,
1906 GDM_SESSION_WORKER_ERROR,
1907 GDM_SESSION_WORKER_ERROR_GIVING_CREDENTIALS,
1908 _("no user account available"));
1909 goto out;
1910 }
1911
1912 gdm_session_worker_update_environment_from_passwd_info (worker,
1913 uid,
1914 gid,
1915 home,
1916 shell);
1917
1918 /* Let's give the user a default PATH if he doesn't already have one
1919 */
1920 if (!gdm_session_worker_environment_variable_is_set (worker, "PATH")) {
1921 if (strcmp (BINDIR, "/usr/bin") == 0) {
1922 gdm_session_worker_set_environment_variable (worker, "PATH",
1923 GDM_SESSION_DEFAULT_PATH);
1924 } else {
1925 gdm_session_worker_set_environment_variable (worker, "PATH",
1926 BINDIR ":" GDM_SESSION_DEFAULT_PATH);
1927 }
1928 }
1929
1930 if (! _change_user (worker, uid, gid)) {
1931 g_debug ("GdmSessionWorker: Unable to change to user");
1932 error_code = PAM_SYSTEM_ERR;
1933 g_set_error (error, GDM_SESSION_WORKER_ERROR,
1934 GDM_SESSION_WORKER_ERROR_GIVING_CREDENTIALS,
1935 "%s", _("Unable to change to user"));
1936 goto out;
1937 }
1938
1939 error_code = pam_setcred (worker->priv->pam_handle, worker->priv->cred_flags);
1940
1941 /* If the user is reauthenticating and they've made it this far, then there
1942 * is no reason we should lock them out of their session. They've already
1943 * proved they are they same person who logged in, and that's all we care
1944 * about.
1945 */
1946 if (worker->priv->is_reauth_session) {
1947 error_code = PAM_SUCCESS;
1948 }
1949
1950 if (error_code != PAM_SUCCESS) {
1951 g_set_error (error,
1952 GDM_SESSION_WORKER_ERROR,
1953 GDM_SESSION_WORKER_ERROR_GIVING_CREDENTIALS,
1954 "%s",
1955 pam_strerror (worker->priv->pam_handle, error_code));
1956 goto out;
1957 }
1958
1959 ret = TRUE;
1960
1961 out:
1962 g_free (home);
1963 g_free (shell);
1964 if (ret) {
1965 g_debug ("GdmSessionWorker: state ACCREDITED");
1966 ret = TRUE;
1967
1968 gdm_session_worker_get_username (worker, NULL);
1969 gdm_session_auditor_report_user_accredited (worker->priv->auditor);
1970 worker->priv->state = GDM_SESSION_WORKER_STATE_ACCREDITED;
1971 } else {
1972 gdm_session_worker_uninitialize_pam (worker, error_code);
1973 }
1974
1975 return ret;
1976 }
1977
1978 static const char * const *
gdm_session_worker_get_environment(GdmSessionWorker * worker)1979 gdm_session_worker_get_environment (GdmSessionWorker *worker)
1980 {
1981 return (const char * const *) pam_getenvlist (worker->priv->pam_handle);
1982 }
1983
1984 #ifdef WITH_CONSOLE_KIT
1985 static void
register_ck_session(GdmSessionWorker * worker)1986 register_ck_session (GdmSessionWorker *worker)
1987 {
1988 #ifdef WITH_SYSTEMD
1989 if (LOGIND_RUNNING()) {
1990 return;
1991 }
1992 #endif
1993
1994 open_ck_session (worker);
1995
1996 if (worker->priv->session_cookie != NULL) {
1997 gdm_session_worker_set_environment_variable (worker,
1998 "XDG_SESSION_COOKIE",
1999 worker->priv->session_cookie);
2000 }
2001 }
2002 #endif
2003
2004 static gboolean
run_script(GdmSessionWorker * worker,const char * dir)2005 run_script (GdmSessionWorker *worker,
2006 const char *dir)
2007 {
2008 /* scripts are for non-program sessions only */
2009 if (worker->priv->is_program_session) {
2010 return TRUE;
2011 }
2012
2013 return gdm_run_script (dir,
2014 worker->priv->username,
2015 worker->priv->x11_display_name,
2016 worker->priv->display_is_local? NULL : worker->priv->hostname,
2017 worker->priv->x11_authority_file);
2018 }
2019
2020 static void
session_worker_child_watch(GPid pid,int status,GdmSessionWorker * worker)2021 session_worker_child_watch (GPid pid,
2022 int status,
2023 GdmSessionWorker *worker)
2024 {
2025 g_debug ("GdmSessionWorker: child (pid:%d) done (%s:%d)",
2026 (int) pid,
2027 WIFEXITED (status) ? "status"
2028 : WIFSIGNALED (status) ? "signal"
2029 : "unknown",
2030 WIFEXITED (status) ? WEXITSTATUS (status)
2031 : WIFSIGNALED (status) ? WTERMSIG (status)
2032 : -1);
2033
2034 #ifdef WITH_CONSOLE_KIT
2035 close_ck_session (worker);
2036 #endif
2037
2038 gdm_session_worker_uninitialize_pam (worker, PAM_SUCCESS);
2039
2040 gdm_dbus_worker_emit_session_exited (GDM_DBUS_WORKER (worker),
2041 worker->priv->service,
2042 status);
2043
2044 killpg (pid, SIGHUP);
2045
2046 worker->priv->child_pid = -1;
2047 worker->priv->child_watch_id = 0;
2048 run_script (worker, GDMCONFDIR "/PostSession");
2049 }
2050
2051 static void
gdm_session_worker_watch_child(GdmSessionWorker * worker)2052 gdm_session_worker_watch_child (GdmSessionWorker *worker)
2053 {
2054 g_debug ("GdmSession worker: watching pid %d", worker->priv->child_pid);
2055 worker->priv->child_watch_id = g_child_watch_add (worker->priv->child_pid,
2056 (GChildWatchFunc)session_worker_child_watch,
2057 worker);
2058
2059 }
2060
2061 static gboolean
_is_loggable_file(const char * filename)2062 _is_loggable_file (const char* filename)
2063 {
2064 struct stat file_info;
2065
2066 if (g_lstat (filename, &file_info) < 0) {
2067 return FALSE;
2068 }
2069
2070 return S_ISREG (file_info.st_mode) && g_access (filename, R_OK | W_OK) == 0;
2071 }
2072
2073 static void
rotate_logs(const char * path,guint n_copies)2074 rotate_logs (const char *path,
2075 guint n_copies)
2076 {
2077 int i;
2078
2079 for (i = n_copies - 1; i > 0; i--) {
2080 char *name_n;
2081 char *name_n1;
2082
2083 name_n = g_strdup_printf ("%s.%d", path, i);
2084 if (i > 1) {
2085 name_n1 = g_strdup_printf ("%s.%d", path, i - 1);
2086 } else {
2087 name_n1 = g_strdup (path);
2088 }
2089
2090 g_unlink (name_n);
2091 g_rename (name_n1, name_n);
2092
2093 g_free (name_n1);
2094 g_free (name_n);
2095 }
2096
2097 g_unlink (path);
2098 }
2099
2100 static int
_open_program_session_log(const char * filename)2101 _open_program_session_log (const char *filename)
2102 {
2103 int fd;
2104
2105 rotate_logs (filename, MAX_LOGS);
2106
2107 fd = g_open (filename, O_WRONLY | O_APPEND | O_CREAT, 0600);
2108
2109 if (fd < 0) {
2110 char *temp_name;
2111
2112 temp_name = g_strdup_printf ("%s.XXXXXXXX", filename);
2113
2114 fd = g_mkstemp (temp_name);
2115
2116 if (fd < 0) {
2117 g_free (temp_name);
2118 goto out;
2119 }
2120
2121 g_warning ("session log '%s' is not appendable, logging session to '%s' instead.\n", filename,
2122 temp_name);
2123 g_free (temp_name);
2124 } else {
2125 if (ftruncate (fd, 0) < 0) {
2126 close (fd);
2127 fd = -1;
2128 goto out;
2129 }
2130 }
2131
2132 if (fchmod (fd, 0644) < 0) {
2133 close (fd);
2134 fd = -1;
2135 goto out;
2136 }
2137
2138
2139 out:
2140 if (fd < 0) {
2141 g_warning ("unable to log program session");
2142 fd = g_open ("/dev/null", O_RDWR);
2143 }
2144
2145 return fd;
2146 }
2147
2148 static int
_open_user_session_log(const char * dir)2149 _open_user_session_log (const char *dir)
2150 {
2151 int fd;
2152 char *filename;
2153
2154 filename = g_build_filename (dir, GDM_SESSION_LOG_FILENAME, NULL);
2155
2156 if (g_access (dir, R_OK | W_OK | X_OK) == 0 && _is_loggable_file (filename)) {
2157 char *filename_old;
2158
2159 filename_old = g_strdup_printf ("%s.old", filename);
2160 g_rename (filename, filename_old);
2161 g_free (filename_old);
2162 }
2163
2164 fd = g_open (filename, O_RDWR | O_APPEND | O_CREAT, 0600);
2165
2166 if (fd < 0) {
2167 char *temp_name;
2168
2169 temp_name = g_strdup_printf ("%s.XXXXXXXX", filename);
2170
2171 fd = g_mkstemp (temp_name);
2172
2173 if (fd < 0) {
2174 g_free (temp_name);
2175 goto out;
2176 }
2177
2178 g_warning ("session log '%s' is not appendable, logging session to '%s' instead.\n", filename,
2179 temp_name);
2180 g_free (filename);
2181 filename = temp_name;
2182 } else {
2183 if (ftruncate (fd, 0) < 0) {
2184 close (fd);
2185 fd = -1;
2186 goto out;
2187 }
2188 }
2189
2190 if (fchmod (fd, 0600) < 0) {
2191 close (fd);
2192 fd = -1;
2193 goto out;
2194 }
2195
2196
2197 out:
2198 g_free (filename);
2199
2200 if (fd < 0) {
2201 g_warning ("unable to log session");
2202 fd = g_open ("/dev/null", O_RDWR);
2203 }
2204
2205 return fd;
2206 }
2207
2208 static gboolean
gdm_session_worker_start_session(GdmSessionWorker * worker,GError ** error)2209 gdm_session_worker_start_session (GdmSessionWorker *worker,
2210 GError **error)
2211 {
2212 struct passwd *passwd_entry;
2213 pid_t session_pid;
2214 int error_code;
2215
2216 gdm_get_pwent_for_name (worker->priv->username, &passwd_entry);
2217 if (worker->priv->is_program_session) {
2218 g_debug ("GdmSessionWorker: opening session for program '%s'",
2219 worker->priv->arguments[0]);
2220 } else {
2221 g_debug ("GdmSessionWorker: opening user session with program '%s'",
2222 worker->priv->arguments[0]);
2223 }
2224
2225 error_code = PAM_SUCCESS;
2226
2227 #ifdef WITH_SYSTEMD
2228 /* If we're in new vt mode, jump to the new vt now. There's no need to jump for
2229 * the other two modes: in the logind case, the session will activate itself when
2230 * ready, and in the reuse server case, we're already on the correct VT. */
2231 if (g_strcmp0 (worker->priv->display_seat_id, "seat0") == 0) {
2232 if (worker->priv->display_mode == GDM_SESSION_DISPLAY_MODE_NEW_VT) {
2233 jump_to_vt (worker, worker->priv->session_vt);
2234 }
2235 }
2236 #endif
2237
2238 if (!worker->priv->is_program_session && !run_script (worker, GDMCONFDIR "/PostLogin")) {
2239 g_set_error (error,
2240 GDM_SESSION_WORKER_ERROR,
2241 GDM_SESSION_WORKER_ERROR_OPENING_SESSION,
2242 "Failed to execute PostLogin script");
2243 error_code = PAM_ABORT;
2244 goto out;
2245 }
2246
2247 if (!worker->priv->is_program_session && !run_script (worker, GDMCONFDIR "/PreSession")) {
2248 g_set_error (error,
2249 GDM_SESSION_WORKER_ERROR,
2250 GDM_SESSION_WORKER_ERROR_OPENING_SESSION,
2251 "Failed to execute PreSession script");
2252 error_code = PAM_ABORT;
2253 goto out;
2254 }
2255
2256 session_pid = fork ();
2257
2258 if (session_pid < 0) {
2259 g_set_error (error,
2260 GDM_SESSION_WORKER_ERROR,
2261 GDM_SESSION_WORKER_ERROR_OPENING_SESSION,
2262 "%s", g_strerror (errno));
2263 error_code = PAM_ABORT;
2264 goto out;
2265 }
2266
2267 if (session_pid == 0) {
2268 const char * const * environment;
2269 char *home_dir;
2270 int stdin_fd = -1, stdout_fd = -1, stderr_fd = -1;
2271 gboolean has_journald = FALSE, needs_controlling_terminal = FALSE;
2272 /* Leak the TTY into the session as stdin so that it stays open
2273 * without any races. */
2274 if (worker->priv->session_tty_fd > 0) {
2275 dup2 (worker->priv->session_tty_fd, STDIN_FILENO);
2276 close (worker->priv->session_tty_fd);
2277 worker->priv->session_tty_fd = -1;
2278 needs_controlling_terminal = TRUE;
2279 } else {
2280 stdin_fd = open ("/dev/null", O_RDWR);
2281 dup2 (stdin_fd, STDIN_FILENO);
2282 close (stdin_fd);
2283 }
2284
2285 #ifdef ENABLE_SYSTEMD_JOURNAL
2286 has_journald = sd_booted() > 0;
2287 #endif
2288 if (!has_journald && worker->priv->is_program_session) {
2289 stdout_fd = _open_program_session_log (worker->priv->log_file);
2290 stderr_fd = dup (stdout_fd);
2291 }
2292
2293 if (setsid () < 0) {
2294 g_debug ("GdmSessionWorker: could not set pid '%u' as leader of new session and process group: %s",
2295 (guint) getpid (), g_strerror (errno));
2296 _exit (EXIT_FAILURE);
2297 }
2298
2299 #ifdef WITH_SYSTEMD
2300 /* Take control of the tty
2301 */
2302 if (needs_controlling_terminal) {
2303 if (ioctl (STDIN_FILENO, TIOCSCTTY, 0) < 0) {
2304 g_debug ("GdmSessionWorker: could not take control of tty: %m");
2305 }
2306 }
2307 #endif
2308
2309 #ifdef HAVE_LOGINCAP
2310 if (setusercontext (NULL, passwd_entry, passwd_entry->pw_uid, LOGIN_SETALL) < 0) {
2311 g_debug ("GdmSessionWorker: setusercontext() failed for user %s: %s",
2312 passwd_entry->pw_name, g_strerror (errno));
2313 _exit (EXIT_FAILURE);
2314 }
2315 #else
2316 if (setuid (worker->priv->uid) < 0) {
2317 g_debug ("GdmSessionWorker: could not reset uid: %s", g_strerror (errno));
2318 _exit (EXIT_FAILURE);
2319 }
2320 #endif
2321
2322 if (!worker->priv->is_program_session) {
2323 gdm_session_worker_load_env_d (worker);
2324 }
2325
2326 environment = gdm_session_worker_get_environment (worker);
2327
2328 g_assert (geteuid () == getuid ());
2329
2330 home_dir = gdm_session_worker_get_environment_variable (worker, "HOME");
2331 if ((home_dir == NULL) || g_chdir (home_dir) < 0) {
2332 g_chdir ("/");
2333 }
2334
2335 #ifdef ENABLE_SYSTEMD_JOURNAL
2336 if (has_journald) {
2337 stdout_fd = sd_journal_stream_fd (worker->priv->arguments[0], LOG_INFO, FALSE);
2338 stderr_fd = sd_journal_stream_fd (worker->priv->arguments[0], LOG_WARNING, FALSE);
2339
2340 /* Unset the CLOEXEC flags, because sd_journal_stream_fd
2341 * gives it to us by default.
2342 */
2343 gdm_clear_close_on_exec_flag (stdout_fd);
2344 gdm_clear_close_on_exec_flag (stderr_fd);
2345 }
2346 #endif
2347 if (!has_journald && !worker->priv->is_program_session) {
2348 if (home_dir != NULL && home_dir[0] != '\0') {
2349 char *cache_dir;
2350 char *log_dir;
2351
2352 cache_dir = gdm_session_worker_get_environment_variable (worker, "XDG_CACHE_HOME");
2353 if (cache_dir == NULL || cache_dir[0] == '\0') {
2354 cache_dir = g_build_filename (home_dir, ".cache", NULL);
2355 }
2356
2357 log_dir = g_build_filename (cache_dir, "gdm", NULL);
2358 g_free (cache_dir);
2359
2360 if (g_mkdir_with_parents (log_dir, S_IRWXU) == 0) {
2361 stdout_fd = _open_user_session_log (log_dir);
2362 stderr_fd = dup (stdout_fd);
2363 } else {
2364 stdout_fd = open ("/dev/null", O_RDWR);
2365 stderr_fd = dup (stdout_fd);
2366 }
2367 g_free (log_dir);
2368 } else {
2369 stdout_fd = open ("/dev/null", O_RDWR);
2370 stderr_fd = dup (stdout_fd);
2371 }
2372 }
2373 g_free (home_dir);
2374
2375 if (stdout_fd != -1) {
2376 dup2 (stdout_fd, STDOUT_FILENO);
2377 close (stdout_fd);
2378 }
2379
2380 if (stderr_fd != -1) {
2381 dup2 (stderr_fd, STDERR_FILENO);
2382 close (stderr_fd);
2383 }
2384
2385 gdm_log_shutdown ();
2386
2387 /*
2388 * Reset SIGPIPE to default so that any process in the user
2389 * session get the default SIGPIPE behavior instead of ignoring
2390 * SIGPIPE.
2391 */
2392 signal (SIGPIPE, SIG_DFL);
2393
2394 gdm_session_execute (worker->priv->arguments[0],
2395 worker->priv->arguments,
2396 (char **)
2397 environment,
2398 TRUE);
2399
2400 gdm_log_init ();
2401 g_debug ("GdmSessionWorker: child '%s' could not be started: %s",
2402 worker->priv->arguments[0],
2403 g_strerror (errno));
2404
2405 _exit (EXIT_FAILURE);
2406 }
2407
2408 if (worker->priv->session_tty_fd > 0) {
2409 close (worker->priv->session_tty_fd);
2410 worker->priv->session_tty_fd = -1;
2411 }
2412
2413 /* If we end up execing again, make sure we don't use the executable context set up
2414 * by pam_selinux durin pam_open_session
2415 */
2416 #ifdef HAVE_SELINUX
2417 setexeccon (NULL);
2418 #endif
2419
2420 worker->priv->child_pid = session_pid;
2421
2422 g_debug ("GdmSessionWorker: session opened creating reply...");
2423 g_assert (sizeof (GPid) <= sizeof (int));
2424
2425 g_debug ("GdmSessionWorker: state SESSION_STARTED");
2426 worker->priv->state = GDM_SESSION_WORKER_STATE_SESSION_STARTED;
2427
2428 gdm_session_worker_watch_child (worker);
2429
2430 out:
2431 if (error_code != PAM_SUCCESS) {
2432 gdm_session_worker_uninitialize_pam (worker, error_code);
2433 return FALSE;
2434 }
2435
2436 return TRUE;
2437 }
2438
2439 #ifdef WITH_SYSTEMD
2440 static gboolean
set_up_for_new_vt(GdmSessionWorker * worker)2441 set_up_for_new_vt (GdmSessionWorker *worker)
2442 {
2443 int fd;
2444 char vt_string[256], tty_string[256];
2445 struct vt_stat vt_state = { 0 };
2446 int session_vt = 0;
2447
2448 fd = open ("/dev/tty0", O_RDWR | O_NOCTTY);
2449
2450 if (fd < 0) {
2451 g_debug ("GdmSessionWorker: couldn't open VT master: %m");
2452 return FALSE;
2453 }
2454
2455 if (ioctl (fd, VT_GETSTATE, &vt_state) < 0) {
2456 g_debug ("GdmSessionWorker: couldn't get current VT: %m");
2457 goto fail;
2458 }
2459
2460 if (worker->priv->display_is_initial) {
2461 session_vt = atoi (GDM_INITIAL_VT);
2462 } else {
2463 if (ioctl(fd, VT_OPENQRY, &session_vt) < 0) {
2464 g_debug ("GdmSessionWorker: couldn't open new VT: %m");
2465 goto fail;
2466 }
2467 }
2468
2469 worker->priv->login_vt = vt_state.v_active;
2470 worker->priv->session_vt = session_vt;
2471
2472 close (fd);
2473 fd = -1;
2474
2475 g_assert (session_vt > 0);
2476
2477 g_snprintf (vt_string, sizeof (vt_string), "%d", session_vt);
2478
2479 /* Set the VTNR. This is used by logind to configure a session in
2480 * the logind-managed case, but it doesn't hurt to set it always.
2481 * When logind gains support for XDG_VTNR=auto, we can make the
2482 * OPENQRY and this whole path only used by the new VT code. */
2483 gdm_session_worker_set_environment_variable (worker,
2484 "XDG_VTNR",
2485 vt_string);
2486
2487 g_snprintf (tty_string, 256, "/dev/tty%d", session_vt);
2488 worker->priv->session_tty_fd = open (tty_string, O_RDWR | O_NOCTTY);
2489 pam_set_item (worker->priv->pam_handle, PAM_TTY, tty_string);
2490
2491 return TRUE;
2492
2493 fail:
2494 close (fd);
2495 return FALSE;
2496 }
2497
2498 static gboolean
set_xdg_vtnr_to_current_vt(GdmSessionWorker * worker)2499 set_xdg_vtnr_to_current_vt (GdmSessionWorker *worker)
2500 {
2501 int fd;
2502 char vt_string[256];
2503 struct vt_stat vt_state = { 0 };
2504
2505 fd = open ("/dev/tty0", O_RDWR | O_NOCTTY);
2506
2507 if (fd < 0) {
2508 g_debug ("GdmSessionWorker: couldn't open VT master: %m");
2509 return FALSE;
2510 }
2511
2512 if (ioctl (fd, VT_GETSTATE, &vt_state) < 0) {
2513 g_debug ("GdmSessionWorker: couldn't get current VT: %m");
2514 goto fail;
2515 }
2516
2517 close (fd);
2518 fd = -1;
2519
2520 g_snprintf (vt_string, sizeof (vt_string), "%d", vt_state.v_active);
2521
2522 gdm_session_worker_set_environment_variable (worker,
2523 "XDG_VTNR",
2524 vt_string);
2525
2526 return TRUE;
2527
2528 fail:
2529 close (fd);
2530 return FALSE;
2531 }
2532 #endif
2533
2534 static gboolean
set_up_for_current_vt(GdmSessionWorker * worker,GError ** error)2535 set_up_for_current_vt (GdmSessionWorker *worker,
2536 GError **error)
2537 {
2538 #ifdef PAM_XAUTHDATA
2539 struct pam_xauth_data *pam_xauth;
2540 #endif
2541 int error_code = PAM_SUCCESS;
2542 char *pam_tty;
2543
2544 /* set TTY */
2545 pam_tty = _get_tty_for_pam (worker->priv->x11_display_name, worker->priv->display_device);
2546 if (pam_tty != NULL && pam_tty[0] != '\0') {
2547 error_code = pam_set_item (worker->priv->pam_handle, PAM_TTY, pam_tty);
2548
2549 if (error_code != PAM_SUCCESS) {
2550 g_debug ("error informing authentication system of user's console %s: %s",
2551 pam_tty,
2552 pam_strerror (worker->priv->pam_handle, error_code));
2553 g_free (pam_tty);
2554 g_set_error (error,
2555 GDM_SESSION_WORKER_ERROR,
2556 GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
2557 "%s", "");
2558 goto out;
2559 }
2560 }
2561 g_free (pam_tty);
2562
2563 #ifdef PAM_XDISPLAY
2564 /* set XDISPLAY */
2565 if (worker->priv->x11_display_name != NULL && worker->priv->x11_display_name[0] != '\0') {
2566 error_code = pam_set_item (worker->priv->pam_handle, PAM_XDISPLAY, worker->priv->x11_display_name);
2567 if (error_code != PAM_SUCCESS) {
2568 g_debug ("error informing authentication system of display string %s: %s",
2569 worker->priv->x11_display_name,
2570 pam_strerror (worker->priv->pam_handle, error_code));
2571 g_set_error (error,
2572 GDM_SESSION_WORKER_ERROR,
2573 GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
2574 "%s", "");
2575 goto out;
2576 }
2577 }
2578 #endif
2579 #ifdef PAM_XAUTHDATA
2580 /* set XAUTHDATA */
2581 pam_xauth = _get_xauth_for_pam (worker->priv->x11_authority_file);
2582 if (pam_xauth != NULL) {
2583 error_code = pam_set_item (worker->priv->pam_handle, PAM_XAUTHDATA, pam_xauth);
2584 if (error_code != PAM_SUCCESS) {
2585 g_debug ("error informing authentication system of display string %s: %s",
2586 worker->priv->x11_display_name,
2587 pam_strerror (worker->priv->pam_handle, error_code));
2588 g_free (pam_xauth);
2589
2590 g_set_error (error,
2591 GDM_SESSION_WORKER_ERROR,
2592 GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
2593 "%s", "");
2594 goto out;
2595 }
2596 g_free (pam_xauth);
2597 }
2598 #endif
2599
2600 #ifdef WITH_SYSTEMD
2601 if (g_strcmp0 (worker->priv->display_seat_id, "seat0") == 0) {
2602 g_debug ("GdmSessionWorker: setting XDG_VTNR to current vt");
2603 set_xdg_vtnr_to_current_vt (worker);
2604 } else {
2605 g_debug ("GdmSessionWorker: not setting XDG_VTNR since not seat0");
2606 }
2607 #endif
2608
2609 return TRUE;
2610 out:
2611 return FALSE;
2612 }
2613
2614 static gboolean
gdm_session_worker_open_session(GdmSessionWorker * worker,GError ** error)2615 gdm_session_worker_open_session (GdmSessionWorker *worker,
2616 GError **error)
2617 {
2618 int error_code;
2619 int flags;
2620 char *session_id = NULL;
2621
2622 g_assert (worker->priv->state == GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_SAVED);
2623 g_assert (geteuid () == 0);
2624
2625 switch (worker->priv->display_mode) {
2626 case GDM_SESSION_DISPLAY_MODE_REUSE_VT:
2627 if (!set_up_for_current_vt (worker, error)) {
2628 return FALSE;
2629 }
2630 break;
2631 #ifdef WITH_SYSTEMD
2632 case GDM_SESSION_DISPLAY_MODE_NEW_VT:
2633 case GDM_SESSION_DISPLAY_MODE_LOGIND_MANAGED:
2634 if (!set_up_for_new_vt (worker)) {
2635 g_set_error (error,
2636 GDM_SESSION_WORKER_ERROR,
2637 GDM_SESSION_WORKER_ERROR_OPENING_SESSION,
2638 "Unable to open VT");
2639 return FALSE;
2640 }
2641 break;
2642 #endif
2643 }
2644
2645 flags = 0;
2646
2647 if (worker->priv->is_program_session) {
2648 flags |= PAM_SILENT;
2649 }
2650
2651 error_code = pam_open_session (worker->priv->pam_handle, flags);
2652
2653 if (error_code != PAM_SUCCESS) {
2654 g_set_error (error,
2655 GDM_SESSION_WORKER_ERROR,
2656 GDM_SESSION_WORKER_ERROR_OPENING_SESSION,
2657 "%s", pam_strerror (worker->priv->pam_handle, error_code));
2658 goto out;
2659 }
2660
2661 g_debug ("GdmSessionWorker: state SESSION_OPENED");
2662 worker->priv->state = GDM_SESSION_WORKER_STATE_SESSION_OPENED;
2663
2664 #ifdef WITH_SYSTEMD
2665 session_id = gdm_session_worker_get_environment_variable (worker, "XDG_SESSION_ID");
2666 #endif
2667
2668 #ifdef WITH_CONSOLE_KIT
2669 register_ck_session (worker);
2670
2671 if (session_id == NULL) {
2672 session_id = get_ck_session_id (worker);
2673 }
2674 #endif
2675
2676 if (session_id != NULL) {
2677 g_free (worker->priv->session_id);
2678 worker->priv->session_id = session_id;
2679 }
2680
2681 out:
2682 if (error_code != PAM_SUCCESS) {
2683 gdm_session_worker_uninitialize_pam (worker, error_code);
2684 return FALSE;
2685 }
2686
2687 gdm_session_worker_get_username (worker, NULL);
2688 gdm_session_auditor_report_login (worker->priv->auditor);
2689
2690 return TRUE;
2691 }
2692
2693 static void
gdm_session_worker_set_server_address(GdmSessionWorker * worker,const char * address)2694 gdm_session_worker_set_server_address (GdmSessionWorker *worker,
2695 const char *address)
2696 {
2697 g_free (worker->priv->server_address);
2698 worker->priv->server_address = g_strdup (address);
2699 }
2700
2701 static void
gdm_session_worker_set_is_reauth_session(GdmSessionWorker * worker,gboolean is_reauth_session)2702 gdm_session_worker_set_is_reauth_session (GdmSessionWorker *worker,
2703 gboolean is_reauth_session)
2704 {
2705 worker->priv->is_reauth_session = is_reauth_session;
2706 }
2707
2708 static void
gdm_session_worker_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)2709 gdm_session_worker_set_property (GObject *object,
2710 guint prop_id,
2711 const GValue *value,
2712 GParamSpec *pspec)
2713 {
2714 GdmSessionWorker *self;
2715
2716 self = GDM_SESSION_WORKER (object);
2717
2718 switch (prop_id) {
2719 case PROP_SERVER_ADDRESS:
2720 gdm_session_worker_set_server_address (self, g_value_get_string (value));
2721 break;
2722 case PROP_IS_REAUTH_SESSION:
2723 gdm_session_worker_set_is_reauth_session (self, g_value_get_boolean (value));
2724 break;
2725 default:
2726 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2727 break;
2728 }
2729 }
2730
2731 static void
gdm_session_worker_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)2732 gdm_session_worker_get_property (GObject *object,
2733 guint prop_id,
2734 GValue *value,
2735 GParamSpec *pspec)
2736 {
2737 GdmSessionWorker *self;
2738
2739 self = GDM_SESSION_WORKER (object);
2740
2741 switch (prop_id) {
2742 case PROP_SERVER_ADDRESS:
2743 g_value_set_string (value, self->priv->server_address);
2744 break;
2745 case PROP_IS_REAUTH_SESSION:
2746 g_value_set_boolean (value, self->priv->is_reauth_session);
2747 break;
2748 default:
2749 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2750 break;
2751 }
2752 }
2753
2754 static gboolean
gdm_session_worker_handle_set_environment_variable(GdmDBusWorker * object,GDBusMethodInvocation * invocation,const char * key,const char * value)2755 gdm_session_worker_handle_set_environment_variable (GdmDBusWorker *object,
2756 GDBusMethodInvocation *invocation,
2757 const char *key,
2758 const char *value)
2759 {
2760 GdmSessionWorker *worker = GDM_SESSION_WORKER (object);
2761 gdm_session_worker_set_environment_variable (worker, key, value);
2762 gdm_dbus_worker_complete_set_environment_variable (object, invocation);
2763 return TRUE;
2764 }
2765
2766 static gboolean
gdm_session_worker_handle_set_session_name(GdmDBusWorker * object,GDBusMethodInvocation * invocation,const char * session_name)2767 gdm_session_worker_handle_set_session_name (GdmDBusWorker *object,
2768 GDBusMethodInvocation *invocation,
2769 const char *session_name)
2770 {
2771 GdmSessionWorker *worker = GDM_SESSION_WORKER (object);
2772 g_debug ("GdmSessionWorker: session name set to %s", session_name);
2773 gdm_session_settings_set_session_name (worker->priv->user_settings,
2774 session_name);
2775 gdm_dbus_worker_complete_set_session_name (object, invocation);
2776 return TRUE;
2777 }
2778
2779 static gboolean
gdm_session_worker_handle_set_session_type(GdmDBusWorker * object,GDBusMethodInvocation * invocation,const char * session_type)2780 gdm_session_worker_handle_set_session_type (GdmDBusWorker *object,
2781 GDBusMethodInvocation *invocation,
2782 const char *session_type)
2783 {
2784 GdmSessionWorker *worker = GDM_SESSION_WORKER (object);
2785 g_debug ("GdmSessionWorker: session type set to %s", session_type);
2786 g_free (worker->priv->session_type);
2787 worker->priv->session_type = g_strdup (session_type);
2788 gdm_dbus_worker_complete_set_session_type (object, invocation);
2789 return TRUE;
2790 }
2791
2792 static gboolean
gdm_session_worker_handle_set_session_display_mode(GdmDBusWorker * object,GDBusMethodInvocation * invocation,const char * str)2793 gdm_session_worker_handle_set_session_display_mode (GdmDBusWorker *object,
2794 GDBusMethodInvocation *invocation,
2795 const char *str)
2796 {
2797 GdmSessionWorker *worker = GDM_SESSION_WORKER (object);
2798 g_debug ("GdmSessionWorker: session display mode set to %s", str);
2799 worker->priv->display_mode = gdm_session_display_mode_from_string (str);
2800 gdm_dbus_worker_complete_set_session_display_mode (object, invocation);
2801 return TRUE;
2802 }
2803
2804 static gboolean
gdm_session_worker_handle_set_language_name(GdmDBusWorker * object,GDBusMethodInvocation * invocation,const char * language_name)2805 gdm_session_worker_handle_set_language_name (GdmDBusWorker *object,
2806 GDBusMethodInvocation *invocation,
2807 const char *language_name)
2808 {
2809 GdmSessionWorker *worker = GDM_SESSION_WORKER (object);
2810 g_debug ("GdmSessionWorker: language name set to %s", language_name);
2811 gdm_session_settings_set_language_name (worker->priv->user_settings,
2812 language_name);
2813 gdm_dbus_worker_complete_set_language_name (object, invocation);
2814 return TRUE;
2815 }
2816
2817 static void
on_saved_language_name_read(GdmSessionWorker * worker)2818 on_saved_language_name_read (GdmSessionWorker *worker)
2819 {
2820 char *language_name;
2821
2822 language_name = gdm_session_settings_get_language_name (worker->priv->user_settings);
2823
2824 g_debug ("GdmSessionWorker: Saved language is %s", language_name);
2825 gdm_dbus_worker_emit_saved_language_name_read (GDM_DBUS_WORKER (worker),
2826 language_name);
2827 g_free (language_name);
2828 }
2829
2830 static void
on_saved_session_name_read(GdmSessionWorker * worker)2831 on_saved_session_name_read (GdmSessionWorker *worker)
2832 {
2833 char *session_name;
2834
2835 session_name = gdm_session_settings_get_session_name (worker->priv->user_settings);
2836
2837 g_debug ("GdmSessionWorker: Saved session is %s", session_name);
2838 gdm_dbus_worker_emit_saved_session_name_read (GDM_DBUS_WORKER (worker),
2839 session_name);
2840 g_free (session_name);
2841 }
2842
2843 static void
do_setup(GdmSessionWorker * worker)2844 do_setup (GdmSessionWorker *worker)
2845 {
2846 GError *error;
2847 gboolean res;
2848
2849 error = NULL;
2850 res = gdm_session_worker_initialize_pam (worker,
2851 worker->priv->service,
2852 (const char **) worker->priv->extensions,
2853 worker->priv->username,
2854 worker->priv->hostname,
2855 worker->priv->display_is_local,
2856 worker->priv->x11_display_name,
2857 worker->priv->x11_authority_file,
2858 worker->priv->display_device,
2859 worker->priv->display_seat_id,
2860 &error);
2861
2862 if (res) {
2863 g_dbus_method_invocation_return_value (worker->priv->pending_invocation, NULL);
2864 } else {
2865 g_dbus_method_invocation_take_error (worker->priv->pending_invocation, error);
2866 }
2867 worker->priv->pending_invocation = NULL;
2868 }
2869
2870 static void
do_authenticate(GdmSessionWorker * worker)2871 do_authenticate (GdmSessionWorker *worker)
2872 {
2873 GError *error;
2874 gboolean res;
2875
2876 /* find out who the user is and ensure they are who they say they are
2877 */
2878 error = NULL;
2879 res = gdm_session_worker_authenticate_user (worker,
2880 worker->priv->password_is_required,
2881 &error);
2882 if (res) {
2883 /* we're authenticated. Let's make sure we've been given
2884 * a valid username for the system
2885 */
2886 if (!worker->priv->is_program_session) {
2887 g_debug ("GdmSessionWorker: trying to get updated username");
2888 gdm_session_worker_update_username (worker);
2889 }
2890
2891 gdm_dbus_worker_complete_authenticate (GDM_DBUS_WORKER (worker), worker->priv->pending_invocation);
2892 } else {
2893 g_debug ("GdmSessionWorker: Unable to verify user");
2894 g_dbus_method_invocation_take_error (worker->priv->pending_invocation, error);
2895 }
2896 worker->priv->pending_invocation = NULL;
2897 }
2898
2899 static void
do_authorize(GdmSessionWorker * worker)2900 do_authorize (GdmSessionWorker *worker)
2901 {
2902 GError *error;
2903 gboolean res;
2904
2905 /* make sure the user is allowed to log in to this system
2906 */
2907 error = NULL;
2908 res = gdm_session_worker_authorize_user (worker,
2909 worker->priv->password_is_required,
2910 &error);
2911 if (res) {
2912 gdm_dbus_worker_complete_authorize (GDM_DBUS_WORKER (worker), worker->priv->pending_invocation);
2913 } else {
2914 g_dbus_method_invocation_take_error (worker->priv->pending_invocation, error);
2915 }
2916 worker->priv->pending_invocation = NULL;
2917 }
2918
2919 static void
do_accredit(GdmSessionWorker * worker)2920 do_accredit (GdmSessionWorker *worker)
2921 {
2922 GError *error;
2923 gboolean res;
2924
2925 /* get kerberos tickets, setup group lists, etc
2926 */
2927 error = NULL;
2928 res = gdm_session_worker_accredit_user (worker, &error);
2929
2930 if (res) {
2931 gdm_dbus_worker_complete_establish_credentials (GDM_DBUS_WORKER (worker), worker->priv->pending_invocation);
2932 } else {
2933 g_dbus_method_invocation_take_error (worker->priv->pending_invocation, error);
2934 }
2935 worker->priv->pending_invocation = NULL;
2936 }
2937
2938 static void
save_account_details_now(GdmSessionWorker * worker)2939 save_account_details_now (GdmSessionWorker *worker)
2940 {
2941 g_assert (worker->priv->state == GDM_SESSION_WORKER_STATE_ACCREDITED);
2942
2943 g_debug ("GdmSessionWorker: saving account details for user %s", worker->priv->username);
2944 worker->priv->state = GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_SAVED;
2945 if (!gdm_session_settings_save (worker->priv->user_settings,
2946 worker->priv->username)) {
2947 g_warning ("could not save session and language settings");
2948 }
2949 queue_state_change (worker);
2950 }
2951
2952 static void
on_settings_is_loaded_changed(GdmSessionSettings * user_settings,GParamSpec * pspec,GdmSessionWorker * worker)2953 on_settings_is_loaded_changed (GdmSessionSettings *user_settings,
2954 GParamSpec *pspec,
2955 GdmSessionWorker *worker)
2956 {
2957 if (!gdm_session_settings_is_loaded (worker->priv->user_settings)) {
2958 return;
2959 }
2960
2961 /* These signal handlers should be disconnected after the loading,
2962 * so that gdm_session_settings_set_* APIs don't cause the emitting
2963 * of Saved*NameRead D-Bus signals any more.
2964 */
2965 g_signal_handlers_disconnect_by_func (worker->priv->user_settings,
2966 G_CALLBACK (on_saved_session_name_read),
2967 worker);
2968
2969 g_signal_handlers_disconnect_by_func (worker->priv->user_settings,
2970 G_CALLBACK (on_saved_language_name_read),
2971 worker);
2972
2973 if (worker->priv->state == GDM_SESSION_WORKER_STATE_NONE) {
2974 g_debug ("GdmSessionWorker: queuing setup for user: %s %s",
2975 worker->priv->username, worker->priv->display_device);
2976 queue_state_change (worker);
2977 } else if (worker->priv->state == GDM_SESSION_WORKER_STATE_ACCREDITED) {
2978 save_account_details_now (worker);
2979 } else {
2980 return;
2981 }
2982
2983 g_signal_handlers_disconnect_by_func (G_OBJECT (worker->priv->user_settings),
2984 G_CALLBACK (on_settings_is_loaded_changed),
2985 worker);
2986 }
2987
2988 static void
do_save_account_details_when_ready(GdmSessionWorker * worker)2989 do_save_account_details_when_ready (GdmSessionWorker *worker)
2990 {
2991 g_assert (worker->priv->state == GDM_SESSION_WORKER_STATE_ACCREDITED);
2992
2993 if (!gdm_session_settings_is_loaded (worker->priv->user_settings)) {
2994 g_signal_connect (G_OBJECT (worker->priv->user_settings),
2995 "notify::is-loaded",
2996 G_CALLBACK (on_settings_is_loaded_changed),
2997 worker);
2998 g_debug ("GdmSessionWorker: user %s, not fully loaded yet, will save account details later",
2999 worker->priv->username);
3000 gdm_session_settings_load (worker->priv->user_settings,
3001 worker->priv->username);
3002 return;
3003 }
3004
3005 save_account_details_now (worker);
3006 }
3007
3008 static void
do_open_session(GdmSessionWorker * worker)3009 do_open_session (GdmSessionWorker *worker)
3010 {
3011 GError *error;
3012 gboolean res;
3013
3014 error = NULL;
3015 res = gdm_session_worker_open_session (worker, &error);
3016
3017 if (res) {
3018 char *session_id = worker->priv->session_id;
3019 if (session_id == NULL) {
3020 session_id = "";
3021 }
3022
3023 gdm_dbus_worker_complete_open (GDM_DBUS_WORKER (worker), worker->priv->pending_invocation, session_id);
3024 } else {
3025 g_dbus_method_invocation_take_error (worker->priv->pending_invocation, error);
3026 }
3027 worker->priv->pending_invocation = NULL;
3028 }
3029
3030 static void
do_start_session(GdmSessionWorker * worker)3031 do_start_session (GdmSessionWorker *worker)
3032 {
3033 GError *error;
3034 gboolean res;
3035
3036 error = NULL;
3037 res = gdm_session_worker_start_session (worker, &error);
3038 if (res) {
3039 gdm_dbus_worker_complete_start_program (GDM_DBUS_WORKER (worker),
3040 worker->priv->pending_invocation,
3041 worker->priv->child_pid);
3042 } else {
3043 g_dbus_method_invocation_take_error (worker->priv->pending_invocation, error);
3044 }
3045 worker->priv->pending_invocation = NULL;
3046 }
3047
3048 static const char *
get_state_name(int state)3049 get_state_name (int state)
3050 {
3051 const char *name;
3052
3053 name = NULL;
3054
3055 switch (state) {
3056 case GDM_SESSION_WORKER_STATE_NONE:
3057 name = "NONE";
3058 break;
3059 case GDM_SESSION_WORKER_STATE_SETUP_COMPLETE:
3060 name = "SETUP_COMPLETE";
3061 break;
3062 case GDM_SESSION_WORKER_STATE_AUTHENTICATED:
3063 name = "AUTHENTICATED";
3064 break;
3065 case GDM_SESSION_WORKER_STATE_AUTHORIZED:
3066 name = "AUTHORIZED";
3067 break;
3068 case GDM_SESSION_WORKER_STATE_ACCREDITED:
3069 name = "ACCREDITED";
3070 break;
3071 case GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_SAVED:
3072 name = "ACCOUNT_DETAILS_SAVED";
3073 break;
3074 case GDM_SESSION_WORKER_STATE_SESSION_OPENED:
3075 name = "SESSION_OPENED";
3076 break;
3077 case GDM_SESSION_WORKER_STATE_SESSION_STARTED:
3078 name = "SESSION_STARTED";
3079 break;
3080 default:
3081 g_assert_not_reached ();
3082 break;
3083 }
3084
3085 return name;
3086 }
3087
3088 static gboolean
state_change_idle(GdmSessionWorker * worker)3089 state_change_idle (GdmSessionWorker *worker)
3090 {
3091 int new_state;
3092
3093 new_state = worker->priv->state + 1;
3094 g_debug ("GdmSessionWorker: attempting to change state to %s",
3095 get_state_name (new_state));
3096
3097 worker->priv->state_change_idle_id = 0;
3098
3099 switch (new_state) {
3100 case GDM_SESSION_WORKER_STATE_SETUP_COMPLETE:
3101 do_setup (worker);
3102 break;
3103 case GDM_SESSION_WORKER_STATE_AUTHENTICATED:
3104 do_authenticate (worker);
3105 break;
3106 case GDM_SESSION_WORKER_STATE_AUTHORIZED:
3107 do_authorize (worker);
3108 break;
3109 case GDM_SESSION_WORKER_STATE_ACCREDITED:
3110 do_accredit (worker);
3111 break;
3112 case GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_SAVED:
3113 do_save_account_details_when_ready (worker);
3114 break;
3115 case GDM_SESSION_WORKER_STATE_SESSION_OPENED:
3116 do_open_session (worker);
3117 break;
3118 case GDM_SESSION_WORKER_STATE_SESSION_STARTED:
3119 do_start_session (worker);
3120 break;
3121 case GDM_SESSION_WORKER_STATE_NONE:
3122 default:
3123 g_assert_not_reached ();
3124 }
3125 return FALSE;
3126 }
3127
3128 static void
queue_state_change(GdmSessionWorker * worker)3129 queue_state_change (GdmSessionWorker *worker)
3130 {
3131 if (worker->priv->state_change_idle_id > 0) {
3132 return;
3133 }
3134
3135 worker->priv->state_change_idle_id = g_idle_add ((GSourceFunc)state_change_idle, worker);
3136 }
3137
3138 static gboolean
validate_state_change(GdmSessionWorker * worker,GDBusMethodInvocation * invocation,int new_state)3139 validate_state_change (GdmSessionWorker *worker,
3140 GDBusMethodInvocation *invocation,
3141 int new_state)
3142 {
3143 if (worker->priv->pending_invocation != NULL) {
3144 g_dbus_method_invocation_return_error (invocation,
3145 GDM_SESSION_WORKER_ERROR,
3146 GDM_SESSION_WORKER_ERROR_OUTSTANDING_REQUEST,
3147 "Cannot process state change to %s, as there is already an outstanding request to move to state %s",
3148 get_state_name (new_state),
3149 get_state_name (worker->priv->state + 1));
3150 return FALSE;
3151 } else if (worker->priv->state != new_state - 1) {
3152 g_dbus_method_invocation_return_error (invocation,
3153 GDM_SESSION_WORKER_ERROR,
3154 GDM_SESSION_WORKER_ERROR_WRONG_STATE,
3155 "Cannot move to state %s, in state %s, not %s",
3156 get_state_name (new_state),
3157 get_state_name (worker->priv->state),
3158 get_state_name (new_state - 1));
3159 return FALSE;
3160 }
3161
3162 return TRUE;
3163 }
3164
3165 static void
validate_and_queue_state_change(GdmSessionWorker * worker,GDBusMethodInvocation * invocation,int new_state)3166 validate_and_queue_state_change (GdmSessionWorker *worker,
3167 GDBusMethodInvocation *invocation,
3168 int new_state)
3169 {
3170 if (validate_state_change (worker, invocation, new_state)) {
3171 worker->priv->pending_invocation = invocation;
3172 queue_state_change (worker);
3173 }
3174 }
3175
3176 static gboolean
gdm_session_worker_handle_authenticate(GdmDBusWorker * object,GDBusMethodInvocation * invocation)3177 gdm_session_worker_handle_authenticate (GdmDBusWorker *object,
3178 GDBusMethodInvocation *invocation)
3179 {
3180 GdmSessionWorker *worker = GDM_SESSION_WORKER (object);
3181 validate_and_queue_state_change (worker, invocation, GDM_SESSION_WORKER_STATE_AUTHENTICATED);
3182 return TRUE;
3183 }
3184
3185 static gboolean
gdm_session_worker_handle_authorize(GdmDBusWorker * object,GDBusMethodInvocation * invocation)3186 gdm_session_worker_handle_authorize (GdmDBusWorker *object,
3187 GDBusMethodInvocation *invocation)
3188 {
3189 GdmSessionWorker *worker = GDM_SESSION_WORKER (object);
3190 validate_and_queue_state_change (worker, invocation, GDM_SESSION_WORKER_STATE_AUTHORIZED);
3191 return TRUE;
3192 }
3193
3194 static gboolean
gdm_session_worker_handle_establish_credentials(GdmDBusWorker * object,GDBusMethodInvocation * invocation)3195 gdm_session_worker_handle_establish_credentials (GdmDBusWorker *object,
3196 GDBusMethodInvocation *invocation)
3197 {
3198 GdmSessionWorker *worker = GDM_SESSION_WORKER (object);
3199 validate_and_queue_state_change (worker, invocation, GDM_SESSION_WORKER_STATE_ACCREDITED);
3200
3201 if (!worker->priv->is_reauth_session) {
3202 worker->priv->cred_flags = PAM_ESTABLISH_CRED;
3203 } else {
3204 worker->priv->cred_flags = PAM_REINITIALIZE_CRED;
3205 }
3206
3207 return TRUE;
3208 }
3209
3210 static gboolean
gdm_session_worker_handle_open(GdmDBusWorker * object,GDBusMethodInvocation * invocation)3211 gdm_session_worker_handle_open (GdmDBusWorker *object,
3212 GDBusMethodInvocation *invocation)
3213 {
3214 GdmSessionWorker *worker = GDM_SESSION_WORKER (object);
3215 validate_and_queue_state_change (worker, invocation, GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_SAVED);
3216 return TRUE;
3217 }
3218
3219 #ifdef SUPPORTS_PAM_EXTENSIONS
3220 static char **
filter_extensions(const char * const * extensions)3221 filter_extensions (const char * const *extensions)
3222 {
3223 size_t i, j;
3224 GPtrArray *array = NULL;
3225 char **filtered_extensions = NULL;
3226
3227 array = g_ptr_array_new ();
3228
3229 for (i = 0; extensions[i] != NULL; i++) {
3230 for (j = 0; gdm_supported_pam_extensions[j] != NULL; j++) {
3231 if (g_strcmp0 (extensions[i], gdm_supported_pam_extensions[j]) == 0) {
3232 g_ptr_array_add (array, g_strdup (gdm_supported_pam_extensions[j]));
3233 break;
3234 }
3235 }
3236 }
3237 g_ptr_array_add (array, NULL);
3238
3239 filtered_extensions = g_strdupv ((char **) array->pdata);
3240
3241 g_ptr_array_free (array, TRUE);
3242
3243 return filtered_extensions;
3244 }
3245 #endif
3246
3247 static gboolean
gdm_session_worker_handle_initialize(GdmDBusWorker * object,GDBusMethodInvocation * invocation,GVariant * details)3248 gdm_session_worker_handle_initialize (GdmDBusWorker *object,
3249 GDBusMethodInvocation *invocation,
3250 GVariant *details)
3251 {
3252 GdmSessionWorker *worker = GDM_SESSION_WORKER (object);
3253 GVariantIter iter;
3254 char *key;
3255 GVariant *value;
3256 gboolean wait_for_settings = FALSE;
3257
3258 if (!validate_state_change (worker, invocation, GDM_SESSION_WORKER_STATE_SETUP_COMPLETE))
3259 return TRUE;
3260
3261 g_variant_iter_init (&iter, details);
3262 while (g_variant_iter_loop (&iter, "{sv}", &key, &value)) {
3263 if (g_strcmp0 (key, "service") == 0) {
3264 worker->priv->service = g_variant_dup_string (value, NULL);
3265 #ifdef SUPPORTS_PAM_EXTENSIONS
3266 } else if (g_strcmp0 (key, "extensions") == 0) {
3267 worker->priv->extensions = filter_extensions (g_variant_get_strv (value, NULL));
3268 #endif
3269 } else if (g_strcmp0 (key, "username") == 0) {
3270 worker->priv->username = g_variant_dup_string (value, NULL);
3271 } else if (g_strcmp0 (key, "is-program-session") == 0) {
3272 worker->priv->is_program_session = g_variant_get_boolean (value);
3273 } else if (g_strcmp0 (key, "log-file") == 0) {
3274 worker->priv->log_file = g_variant_dup_string (value, NULL);
3275 } else if (g_strcmp0 (key, "x11-display-name") == 0) {
3276 worker->priv->x11_display_name = g_variant_dup_string (value, NULL);
3277 } else if (g_strcmp0 (key, "x11-authority-file") == 0) {
3278 worker->priv->x11_authority_file = g_variant_dup_string (value, NULL);
3279 } else if (g_strcmp0 (key, "console") == 0) {
3280 worker->priv->display_device = g_variant_dup_string (value, NULL);
3281 } else if (g_strcmp0 (key, "seat-id") == 0) {
3282 worker->priv->display_seat_id = g_variant_dup_string (value, NULL);
3283 } else if (g_strcmp0 (key, "hostname") == 0) {
3284 worker->priv->hostname = g_variant_dup_string (value, NULL);
3285 } else if (g_strcmp0 (key, "display-is-local") == 0) {
3286 worker->priv->display_is_local = g_variant_get_boolean (value);
3287 } else if (g_strcmp0 (key, "display-is-initial") == 0) {
3288 worker->priv->display_is_initial = g_variant_get_boolean (value);
3289 }
3290 }
3291
3292 worker->priv->pending_invocation = invocation;
3293
3294 if (!worker->priv->is_program_session) {
3295 g_signal_connect_swapped (worker->priv->user_settings,
3296 "notify::language-name",
3297 G_CALLBACK (on_saved_language_name_read),
3298 worker);
3299
3300 g_signal_connect_swapped (worker->priv->user_settings,
3301 "notify::session-name",
3302 G_CALLBACK (on_saved_session_name_read),
3303 worker);
3304
3305 if (worker->priv->username) {
3306 wait_for_settings = !gdm_session_settings_load (worker->priv->user_settings,
3307 worker->priv->username);
3308 }
3309 }
3310
3311 if (wait_for_settings) {
3312 /* Load settings from accounts daemon before continuing
3313 */
3314 g_signal_connect (G_OBJECT (worker->priv->user_settings),
3315 "notify::is-loaded",
3316 G_CALLBACK (on_settings_is_loaded_changed),
3317 worker);
3318 } else {
3319 queue_state_change (worker);
3320 }
3321
3322 return TRUE;
3323 }
3324
3325 static gboolean
gdm_session_worker_handle_setup(GdmDBusWorker * object,GDBusMethodInvocation * invocation,const char * service,const char * x11_display_name,const char * x11_authority_file,const char * console,const char * seat_id,const char * hostname,gboolean display_is_local,gboolean display_is_initial)3326 gdm_session_worker_handle_setup (GdmDBusWorker *object,
3327 GDBusMethodInvocation *invocation,
3328 const char *service,
3329 const char *x11_display_name,
3330 const char *x11_authority_file,
3331 const char *console,
3332 const char *seat_id,
3333 const char *hostname,
3334 gboolean display_is_local,
3335 gboolean display_is_initial)
3336 {
3337 GdmSessionWorker *worker = GDM_SESSION_WORKER (object);
3338 validate_and_queue_state_change (worker, invocation, GDM_SESSION_WORKER_STATE_SETUP_COMPLETE);
3339
3340 worker->priv->service = g_strdup (service);
3341 worker->priv->x11_display_name = g_strdup (x11_display_name);
3342 worker->priv->x11_authority_file = g_strdup (x11_authority_file);
3343 worker->priv->display_device = g_strdup (console);
3344 worker->priv->display_seat_id = g_strdup (seat_id);
3345 worker->priv->hostname = g_strdup (hostname);
3346 worker->priv->display_is_local = display_is_local;
3347 worker->priv->display_is_initial = display_is_initial;
3348 worker->priv->username = NULL;
3349
3350 g_signal_connect_swapped (worker->priv->user_settings,
3351 "notify::language-name",
3352 G_CALLBACK (on_saved_language_name_read),
3353 worker);
3354
3355 g_signal_connect_swapped (worker->priv->user_settings,
3356 "notify::session-name",
3357 G_CALLBACK (on_saved_session_name_read),
3358 worker);
3359 return TRUE;
3360 }
3361
3362 static gboolean
gdm_session_worker_handle_setup_for_user(GdmDBusWorker * object,GDBusMethodInvocation * invocation,const char * service,const char * username,const char * x11_display_name,const char * x11_authority_file,const char * console,const char * seat_id,const char * hostname,gboolean display_is_local,gboolean display_is_initial)3363 gdm_session_worker_handle_setup_for_user (GdmDBusWorker *object,
3364 GDBusMethodInvocation *invocation,
3365 const char *service,
3366 const char *username,
3367 const char *x11_display_name,
3368 const char *x11_authority_file,
3369 const char *console,
3370 const char *seat_id,
3371 const char *hostname,
3372 gboolean display_is_local,
3373 gboolean display_is_initial)
3374 {
3375 GdmSessionWorker *worker = GDM_SESSION_WORKER (object);
3376
3377 if (!validate_state_change (worker, invocation, GDM_SESSION_WORKER_STATE_SETUP_COMPLETE))
3378 return TRUE;
3379
3380 worker->priv->service = g_strdup (service);
3381 worker->priv->x11_display_name = g_strdup (x11_display_name);
3382 worker->priv->x11_authority_file = g_strdup (x11_authority_file);
3383 worker->priv->display_device = g_strdup (console);
3384 worker->priv->display_seat_id = g_strdup (seat_id);
3385 worker->priv->hostname = g_strdup (hostname);
3386 worker->priv->display_is_local = display_is_local;
3387 worker->priv->display_is_initial = display_is_initial;
3388 worker->priv->username = g_strdup (username);
3389
3390 g_signal_connect_swapped (worker->priv->user_settings,
3391 "notify::language-name",
3392 G_CALLBACK (on_saved_language_name_read),
3393 worker);
3394
3395 g_signal_connect_swapped (worker->priv->user_settings,
3396 "notify::session-name",
3397 G_CALLBACK (on_saved_session_name_read),
3398 worker);
3399
3400 /* Load settings from accounts daemon before continuing
3401 */
3402 worker->priv->pending_invocation = invocation;
3403 if (gdm_session_settings_load (worker->priv->user_settings, username)) {
3404 queue_state_change (worker);
3405 } else {
3406 g_signal_connect (G_OBJECT (worker->priv->user_settings),
3407 "notify::is-loaded",
3408 G_CALLBACK (on_settings_is_loaded_changed),
3409 worker);
3410 }
3411
3412 return TRUE;
3413 }
3414
3415 static gboolean
gdm_session_worker_handle_setup_for_program(GdmDBusWorker * object,GDBusMethodInvocation * invocation,const char * service,const char * username,const char * x11_display_name,const char * x11_authority_file,const char * console,const char * seat_id,const char * hostname,gboolean display_is_local,gboolean display_is_initial,const char * log_file)3416 gdm_session_worker_handle_setup_for_program (GdmDBusWorker *object,
3417 GDBusMethodInvocation *invocation,
3418 const char *service,
3419 const char *username,
3420 const char *x11_display_name,
3421 const char *x11_authority_file,
3422 const char *console,
3423 const char *seat_id,
3424 const char *hostname,
3425 gboolean display_is_local,
3426 gboolean display_is_initial,
3427 const char *log_file)
3428 {
3429 GdmSessionWorker *worker = GDM_SESSION_WORKER (object);
3430 validate_and_queue_state_change (worker, invocation, GDM_SESSION_WORKER_STATE_SETUP_COMPLETE);
3431
3432 worker->priv->service = g_strdup (service);
3433 worker->priv->x11_display_name = g_strdup (x11_display_name);
3434 worker->priv->x11_authority_file = g_strdup (x11_authority_file);
3435 worker->priv->display_device = g_strdup (console);
3436 worker->priv->display_seat_id = g_strdup (seat_id);
3437 worker->priv->hostname = g_strdup (hostname);
3438 worker->priv->display_is_local = display_is_local;
3439 worker->priv->display_is_initial = display_is_initial;
3440 worker->priv->username = g_strdup (username);
3441 worker->priv->log_file = g_strdup (log_file);
3442 worker->priv->is_program_session = TRUE;
3443
3444 return TRUE;
3445 }
3446
3447 static gboolean
gdm_session_worker_handle_start_program(GdmDBusWorker * object,GDBusMethodInvocation * invocation,const char * text)3448 gdm_session_worker_handle_start_program (GdmDBusWorker *object,
3449 GDBusMethodInvocation *invocation,
3450 const char *text)
3451 {
3452 GdmSessionWorker *worker = GDM_SESSION_WORKER (object);
3453 GError *parse_error = NULL;
3454 validate_state_change (worker, invocation, GDM_SESSION_WORKER_STATE_SESSION_STARTED);
3455
3456 if (worker->priv->is_reauth_session) {
3457 g_dbus_method_invocation_return_error (invocation,
3458 GDM_SESSION_WORKER_ERROR,
3459 GDM_SESSION_WORKER_ERROR_IN_REAUTH_SESSION,
3460 "Cannot start a program while in a reauth session");
3461 return TRUE;
3462 }
3463
3464 g_debug ("GdmSessionWorker: start program: %s", text);
3465
3466 g_clear_pointer (&worker->priv->arguments, (GDestroyNotify) g_strfreev);
3467 if (! g_shell_parse_argv (text, NULL, &worker->priv->arguments, &parse_error)) {
3468 g_dbus_method_invocation_take_error (invocation, parse_error);
3469 return TRUE;
3470 }
3471
3472 worker->priv->pending_invocation = invocation;
3473 queue_state_change (worker);
3474
3475 return TRUE;
3476 }
3477
3478 static void
on_reauthentication_client_connected(GdmSession * session,GCredentials * credentials,GPid pid_of_client,ReauthenticationRequest * request)3479 on_reauthentication_client_connected (GdmSession *session,
3480 GCredentials *credentials,
3481 GPid pid_of_client,
3482 ReauthenticationRequest *request)
3483 {
3484 g_debug ("GdmSessionWorker: client connected to reauthentication server");
3485 }
3486
3487 static void
on_reauthentication_client_disconnected(GdmSession * session,GCredentials * credentials,GPid pid_of_client,ReauthenticationRequest * request)3488 on_reauthentication_client_disconnected (GdmSession *session,
3489 GCredentials *credentials,
3490 GPid pid_of_client,
3491 ReauthenticationRequest *request)
3492 {
3493 GdmSessionWorker *worker;
3494
3495 g_debug ("GdmSessionWorker: client disconnected from reauthentication server");
3496
3497 worker = request->worker;
3498 g_hash_table_remove (worker->priv->reauthentication_requests,
3499 GINT_TO_POINTER (pid_of_client));
3500 }
3501
3502 static void
on_reauthentication_cancelled(GdmSession * session,ReauthenticationRequest * request)3503 on_reauthentication_cancelled (GdmSession *session,
3504 ReauthenticationRequest *request)
3505 {
3506 g_debug ("GdmSessionWorker: client cancelled reauthentication request");
3507 gdm_session_reset (session);
3508 }
3509
3510 static void
on_reauthentication_conversation_started(GdmSession * session,const char * service_name,ReauthenticationRequest * request)3511 on_reauthentication_conversation_started (GdmSession *session,
3512 const char *service_name,
3513 ReauthenticationRequest *request)
3514 {
3515 g_debug ("GdmSessionWorker: reauthentication service '%s' started",
3516 service_name);
3517 }
3518
3519 static void
on_reauthentication_conversation_stopped(GdmSession * session,const char * service_name,ReauthenticationRequest * request)3520 on_reauthentication_conversation_stopped (GdmSession *session,
3521 const char *service_name,
3522 ReauthenticationRequest *request)
3523 {
3524 g_debug ("GdmSessionWorker: reauthentication service '%s' stopped",
3525 service_name);
3526 }
3527
3528 static void
on_reauthentication_verification_complete(GdmSession * session,const char * service_name,ReauthenticationRequest * request)3529 on_reauthentication_verification_complete (GdmSession *session,
3530 const char *service_name,
3531 ReauthenticationRequest *request)
3532 {
3533 GdmSessionWorker *worker;
3534
3535 worker = request->worker;
3536
3537 g_debug ("GdmSessionWorker: pid %d reauthenticated user %d with service '%s'",
3538 (int) request->pid_of_caller,
3539 (int) request->uid_of_caller,
3540 service_name);
3541 gdm_session_reset (session);
3542
3543 gdm_dbus_worker_emit_reauthenticated (GDM_DBUS_WORKER (worker), service_name);
3544 }
3545
3546 static ReauthenticationRequest *
reauthentication_request_new(GdmSessionWorker * worker,GPid pid_of_caller,uid_t uid_of_caller,GDBusMethodInvocation * invocation)3547 reauthentication_request_new (GdmSessionWorker *worker,
3548 GPid pid_of_caller,
3549 uid_t uid_of_caller,
3550 GDBusMethodInvocation *invocation)
3551 {
3552 ReauthenticationRequest *request;
3553 const char * const * environment;
3554 const char *address;
3555
3556 environment = gdm_session_worker_get_environment (worker);
3557
3558 request = g_slice_new (ReauthenticationRequest);
3559
3560 request->worker = worker;
3561 request->pid_of_caller = pid_of_caller;
3562 request->uid_of_caller = uid_of_caller;
3563 request->session = gdm_session_new (GDM_SESSION_VERIFICATION_MODE_REAUTHENTICATE,
3564 uid_of_caller,
3565 worker->priv->x11_display_name,
3566 worker->priv->hostname,
3567 worker->priv->display_device,
3568 worker->priv->display_seat_id,
3569 worker->priv->x11_authority_file,
3570 worker->priv->display_is_local,
3571 environment);
3572
3573 g_signal_connect (request->session,
3574 "client-connected",
3575 G_CALLBACK (on_reauthentication_client_connected),
3576 request);
3577 g_signal_connect (request->session,
3578 "client-disconnected",
3579 G_CALLBACK (on_reauthentication_client_disconnected),
3580 request);
3581 g_signal_connect (request->session,
3582 "cancelled",
3583 G_CALLBACK (on_reauthentication_cancelled),
3584 request);
3585 g_signal_connect (request->session,
3586 "conversation-started",
3587 G_CALLBACK (on_reauthentication_conversation_started),
3588 request);
3589 g_signal_connect (request->session,
3590 "conversation-stopped",
3591 G_CALLBACK (on_reauthentication_conversation_stopped),
3592 request);
3593 g_signal_connect (request->session,
3594 "verification-complete",
3595 G_CALLBACK (on_reauthentication_verification_complete),
3596 request);
3597
3598 address = gdm_session_get_server_address (request->session);
3599
3600 gdm_dbus_worker_complete_start_reauthentication (GDM_DBUS_WORKER (worker),
3601 invocation,
3602 address);
3603
3604 return request;
3605 }
3606
3607 static gboolean
gdm_session_worker_handle_start_reauthentication(GdmDBusWorker * object,GDBusMethodInvocation * invocation,int pid_of_caller,int uid_of_caller)3608 gdm_session_worker_handle_start_reauthentication (GdmDBusWorker *object,
3609 GDBusMethodInvocation *invocation,
3610 int pid_of_caller,
3611 int uid_of_caller)
3612 {
3613 GdmSessionWorker *worker = GDM_SESSION_WORKER (object);
3614 ReauthenticationRequest *request;
3615
3616 if (worker->priv->state != GDM_SESSION_WORKER_STATE_SESSION_STARTED) {
3617 g_dbus_method_invocation_return_error (invocation,
3618 GDM_SESSION_WORKER_ERROR,
3619 GDM_SESSION_WORKER_ERROR_WRONG_STATE,
3620 "Cannot reauthenticate while in state %s",
3621 get_state_name (worker->priv->state));
3622 return TRUE;
3623 }
3624
3625 g_debug ("GdmSessionWorker: start reauthentication");
3626
3627 request = reauthentication_request_new (worker, pid_of_caller, uid_of_caller, invocation);
3628 g_hash_table_replace (worker->priv->reauthentication_requests,
3629 GINT_TO_POINTER (pid_of_caller),
3630 request);
3631 return TRUE;
3632 }
3633
3634 static GObject *
gdm_session_worker_constructor(GType type,guint n_construct_properties,GObjectConstructParam * construct_properties)3635 gdm_session_worker_constructor (GType type,
3636 guint n_construct_properties,
3637 GObjectConstructParam *construct_properties)
3638 {
3639 GdmSessionWorker *worker;
3640 GError *error;
3641
3642 worker = GDM_SESSION_WORKER (G_OBJECT_CLASS (gdm_session_worker_parent_class)->constructor (type,
3643 n_construct_properties,
3644 construct_properties));
3645
3646 g_debug ("GdmSessionWorker: connecting to address: %s", worker->priv->server_address);
3647
3648 error = NULL;
3649 worker->priv->connection = g_dbus_connection_new_for_address_sync (worker->priv->server_address,
3650 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
3651 NULL,
3652 NULL,
3653 &error);
3654 if (worker->priv->connection == NULL) {
3655 g_warning ("error opening connection: %s", error->message);
3656 g_clear_error (&error);
3657
3658 exit (EXIT_FAILURE);
3659 }
3660
3661 worker->priv->manager = GDM_DBUS_WORKER_MANAGER (gdm_dbus_worker_manager_proxy_new_sync (worker->priv->connection,
3662 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
3663 NULL, /* dbus name */
3664 GDM_SESSION_DBUS_PATH,
3665 NULL,
3666 &error));
3667 if (worker->priv->manager == NULL) {
3668 g_warning ("error creating session proxy: %s", error->message);
3669 g_clear_error (&error);
3670
3671 exit (EXIT_FAILURE);
3672 }
3673
3674 if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (worker),
3675 worker->priv->connection,
3676 GDM_WORKER_DBUS_PATH,
3677 &error)) {
3678 g_warning ("Error while exporting object: %s", error->message);
3679 exit (EXIT_FAILURE);
3680 }
3681
3682 g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (worker->priv->manager), G_MAXINT);
3683
3684 /* Send an initial Hello message so that the session can associate
3685 * the conversation we manage with our pid.
3686 */
3687 gdm_dbus_worker_manager_call_hello_sync (worker->priv->manager,
3688 NULL,
3689 NULL);
3690
3691 return G_OBJECT (worker);
3692 }
3693
3694 static void
worker_interface_init(GdmDBusWorkerIface * interface)3695 worker_interface_init (GdmDBusWorkerIface *interface)
3696 {
3697 interface->handle_initialize = gdm_session_worker_handle_initialize;
3698 /* The next three are for backward compat only */
3699 interface->handle_setup = gdm_session_worker_handle_setup;
3700 interface->handle_setup_for_user = gdm_session_worker_handle_setup_for_user;
3701 interface->handle_setup_for_program = gdm_session_worker_handle_setup_for_program;
3702 interface->handle_authenticate = gdm_session_worker_handle_authenticate;
3703 interface->handle_authorize = gdm_session_worker_handle_authorize;
3704 interface->handle_establish_credentials = gdm_session_worker_handle_establish_credentials;
3705 interface->handle_open = gdm_session_worker_handle_open;
3706 interface->handle_set_language_name = gdm_session_worker_handle_set_language_name;
3707 interface->handle_set_session_name = gdm_session_worker_handle_set_session_name;
3708 interface->handle_set_session_type = gdm_session_worker_handle_set_session_type;
3709 interface->handle_set_session_display_mode = gdm_session_worker_handle_set_session_display_mode;
3710 interface->handle_set_environment_variable = gdm_session_worker_handle_set_environment_variable;
3711 interface->handle_start_program = gdm_session_worker_handle_start_program;
3712 interface->handle_start_reauthentication = gdm_session_worker_handle_start_reauthentication;
3713 }
3714
3715 static void
gdm_session_worker_class_init(GdmSessionWorkerClass * klass)3716 gdm_session_worker_class_init (GdmSessionWorkerClass *klass)
3717 {
3718 GObjectClass *object_class = G_OBJECT_CLASS (klass);
3719
3720 object_class->get_property = gdm_session_worker_get_property;
3721 object_class->set_property = gdm_session_worker_set_property;
3722 object_class->constructor = gdm_session_worker_constructor;
3723 object_class->finalize = gdm_session_worker_finalize;
3724
3725 g_type_class_add_private (klass, sizeof (GdmSessionWorkerPrivate));
3726
3727 g_object_class_install_property (object_class,
3728 PROP_SERVER_ADDRESS,
3729 g_param_spec_string ("server-address",
3730 "server address",
3731 "server address",
3732 NULL,
3733 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
3734
3735 g_object_class_install_property (object_class,
3736 PROP_IS_REAUTH_SESSION,
3737 g_param_spec_boolean ("is-reauth-session",
3738 "is reauth session",
3739 "is reauth session",
3740 FALSE,
3741 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
3742 }
3743
3744 static void
reauthentication_request_free(ReauthenticationRequest * request)3745 reauthentication_request_free (ReauthenticationRequest *request)
3746 {
3747
3748 g_signal_handlers_disconnect_by_func (request->session,
3749 G_CALLBACK (on_reauthentication_client_connected),
3750 request);
3751 g_signal_handlers_disconnect_by_func (request->session,
3752 G_CALLBACK (on_reauthentication_client_disconnected),
3753 request);
3754 g_signal_handlers_disconnect_by_func (request->session,
3755 G_CALLBACK (on_reauthentication_cancelled),
3756 request);
3757 g_signal_handlers_disconnect_by_func (request->session,
3758 G_CALLBACK (on_reauthentication_conversation_started),
3759 request);
3760 g_signal_handlers_disconnect_by_func (request->session,
3761 G_CALLBACK (on_reauthentication_conversation_stopped),
3762 request);
3763 g_signal_handlers_disconnect_by_func (request->session,
3764 G_CALLBACK (on_reauthentication_verification_complete),
3765 request);
3766 g_clear_object (&request->session);
3767 g_slice_free (ReauthenticationRequest, request);
3768 }
3769
3770 static void
gdm_session_worker_init(GdmSessionWorker * worker)3771 gdm_session_worker_init (GdmSessionWorker *worker)
3772 {
3773 worker->priv = GDM_SESSION_WORKER_GET_PRIVATE (worker);
3774
3775 worker->priv->user_settings = gdm_session_settings_new ();
3776 worker->priv->reauthentication_requests = g_hash_table_new_full (NULL,
3777 NULL,
3778 NULL,
3779 (GDestroyNotify)
3780 reauthentication_request_free);
3781 }
3782
3783 static void
gdm_session_worker_unwatch_child(GdmSessionWorker * worker)3784 gdm_session_worker_unwatch_child (GdmSessionWorker *worker)
3785 {
3786 if (worker->priv->child_watch_id == 0)
3787 return;
3788
3789 g_source_remove (worker->priv->child_watch_id);
3790 worker->priv->child_watch_id = 0;
3791 }
3792
3793
3794 static void
gdm_session_worker_finalize(GObject * object)3795 gdm_session_worker_finalize (GObject *object)
3796 {
3797 GdmSessionWorker *worker;
3798
3799 g_return_if_fail (object != NULL);
3800 g_return_if_fail (GDM_IS_SESSION_WORKER (object));
3801
3802 worker = GDM_SESSION_WORKER (object);
3803
3804 g_return_if_fail (worker->priv != NULL);
3805
3806 gdm_session_worker_unwatch_child (worker);
3807
3808 if (worker->priv->child_pid > 0) {
3809 gdm_signal_pid (worker->priv->child_pid, SIGTERM);
3810 gdm_wait_on_pid (worker->priv->child_pid);
3811 }
3812
3813 g_object_unref (worker->priv->user_settings);
3814 g_free (worker->priv->service);
3815 g_free (worker->priv->x11_display_name);
3816 g_free (worker->priv->x11_authority_file);
3817 g_free (worker->priv->display_device);
3818 g_free (worker->priv->display_seat_id);
3819 g_free (worker->priv->hostname);
3820 g_free (worker->priv->username);
3821 g_free (worker->priv->server_address);
3822 g_strfreev (worker->priv->arguments);
3823 g_strfreev (worker->priv->extensions);
3824
3825 g_hash_table_unref (worker->priv->reauthentication_requests);
3826
3827 G_OBJECT_CLASS (gdm_session_worker_parent_class)->finalize (object);
3828 }
3829
3830 GdmSessionWorker *
gdm_session_worker_new(const char * address,gboolean is_reauth_session)3831 gdm_session_worker_new (const char *address,
3832 gboolean is_reauth_session)
3833 {
3834 GObject *object;
3835
3836 object = g_object_new (GDM_TYPE_SESSION_WORKER,
3837 "server-address", address,
3838 "is-reauth-session", is_reauth_session,
3839 NULL);
3840
3841 return GDM_SESSION_WORKER (object);
3842 }
3843