Blob Blame History Raw
From 5afc4cd548f3ae8db9fbaab32fe2189efff37677 Mon Sep 17 00:00:00 2001
From: Michael Catanzaro <mcatanzaro@igalia.com>
Date: Tue, 12 Jan 2016 21:42:15 -0600
Subject: [PATCH 01/13] manager: be more robust against autologin having an
 invalid user

If the configured autologin user does not exist, fall back to a
greeter session.

https://bugzilla.gnome.org/show_bug.cgi?id=695250
---
 configure.ac         |   2 +-
 daemon/gdm-manager.c | 115 +++++++++++++++++++++++++++++++++++++--------------
 2 files changed, 86 insertions(+), 31 deletions(-)

diff --git a/configure.ac b/configure.ac
index 6613097b..119297c5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -36,61 +36,61 @@ AC_SUBST(LT_AGE)
 
 AC_HEADER_STDC
 
 AC_SUBST(VERSION)
 
 AC_CONFIG_HEADERS(config.h)
 AC_CONFIG_MACRO_DIR([m4])
 
 # Documentation
 enable_documentation=no
 m4_ifdef([YELP_HELP_INIT],[
 YELP_HELP_INIT
 enable_documentation=yes
 ])
 AM_CONDITIONAL(ENABLE_DOCUMENTATION, test x$enable_documentation = xyes)
 
 # i18n stuff
 IT_PROG_INTLTOOL([0.40.0])
 
 GETTEXT_PACKAGE=gdm
 AC_SUBST(GETTEXT_PACKAGE)
 AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [gettext package])
 
 dnl ---------------------------------------------------------------------------
 dnl - Dependencies
 dnl ---------------------------------------------------------------------------
 
 GLIB_REQUIRED_VERSION=2.36.0
 GTK_REQUIRED_VERSION=2.91.1
 LIBCANBERRA_GTK_REQUIRED_VERSION=0.4
-ACCOUNTS_SERVICE_REQUIRED_VERSION=0.6.12
+ACCOUNTS_SERVICE_REQUIRED_VERSION=0.6.35
 
 EXTRA_COMPILE_WARNINGS(yes)
 
 PKG_CHECK_MODULES(GTHREAD, gthread-2.0)
 AC_SUBST(GTHREAD_CFLAGS)
 AC_SUBST(GTHREAD_LIBS)
 
 PKG_CHECK_MODULES(COMMON,
         gobject-2.0 >= $GLIB_REQUIRED_VERSION
         gio-2.0 >= $GLIB_REQUIRED_VERSION
         gio-unix-2.0 >= $GLIB_REQUIRED_VERSION
 )
 AC_SUBST(COMMON_CFLAGS)
 AC_SUBST(COMMON_LIBS)
 
 PKG_CHECK_MODULES(DAEMON,
         gobject-2.0 >= $GLIB_REQUIRED_VERSION
         gio-2.0 >= $GLIB_REQUIRED_VERSION
         gio-unix-2.0 >= $GLIB_REQUIRED_VERSION
         accountsservice >= $ACCOUNTS_SERVICE_REQUIRED_VERSION
         xcb
 )
 AC_SUBST(DAEMON_CFLAGS)
 AC_SUBST(DAEMON_LIBS)
 
 GLIB_GSETTINGS
 
 PKG_CHECK_MODULES(XLIB, x11 xau, ,
   [AC_PATH_XTRA
     if test "x$no_x" = xyes; then
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 35a7a0fe..e78228b4 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -7,60 +7,62 @@
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
  */
 
 #include "config.h"
 
 #include <stdlib.h>
 #include <stdio.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <string.h>
 #include <signal.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
 #include <glib.h>
 #include <glib/gi18n.h>
 #include <glib/gstdio.h>
 #include <glib-object.h>
 
+#include <act/act-user-manager.h>
+
 #include <systemd/sd-login.h>
 
 #include "gdm-common.h"
 
 #include "gdm-dbus-util.h"
 #include "gdm-manager.h"
 #include "gdm-manager-glue.h"
 #include "gdm-display-store.h"
 #include "gdm-display-factory.h"
 #include "gdm-local-display.h"
 #include "gdm-local-display-factory.h"
 #include "gdm-session.h"
 #include "gdm-session-record.h"
 #include "gdm-settings-direct.h"
 #include "gdm-settings-keys.h"
 #include "gdm-xdmcp-display-factory.h"
 
 #define GDM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_MANAGER, GdmManagerPrivate))
 
 #define GDM_DBUS_PATH             "/org/gnome/DisplayManager"
 #define GDM_MANAGER_PATH          GDM_DBUS_PATH "/Manager"
 #define GDM_MANAGER_DISPLAYS_PATH GDM_DBUS_PATH "/Displays"
 
 #define INITIAL_SETUP_USERNAME "gnome-initial-setup"
 
 typedef struct
 {
         GdmManager *manager;
         GdmSession *session;
         char *service_name;
@@ -1227,79 +1229,60 @@ get_automatic_login_details (GdmManager *manager,
         if (res && enabled) {
             res = gdm_settings_direct_get_string (GDM_KEY_AUTO_LOGIN_USER, &username);
         }
 
         if (enabled && res && username != NULL && username[0] != '\0') {
                 goto out;
         }
 
         g_free (username);
         username = NULL;
         enabled = FALSE;
 
  out:
         if (enabled) {
                 g_debug ("GdmDisplay: Got automatic login details for display: %d %s",
                          enabled,
                          username);
         } else {
                 g_debug ("GdmDisplay: Got automatic login details for display: 0");
         }
 
         if (usernamep != NULL) {
                 *usernamep = username;
         } else {
                 g_free (username);
         }
 
         return enabled;
 }
 
-static gboolean
-display_should_autologin (GdmManager *manager,
-                          GdmDisplay *display)
-{
-        gboolean enabled = FALSE;
-
-        if (manager->priv->ran_once) {
-                return FALSE;
-        }
-
-        if (!display_is_on_seat0 (display)) {
-                return FALSE;
-        }
-
-        enabled = get_automatic_login_details (manager, NULL);
-
-        return enabled;
-}
-
 static void
 maybe_start_pending_initial_login (GdmManager *manager,
                                    GdmDisplay *greeter_display)
 {
         StartUserSessionOperation *operation;
         char *greeter_seat_id = NULL;
         char *user_session_seat_id = NULL;
 
         /* There may be a user session waiting to be started.
          * This would happen if we couldn't start it earlier because
          * the login screen X server was coming up and two X servers
          * can't be started on the same seat at the same time.
          */
 
         if (manager->priv->initial_login_operation == NULL) {
                 return;
         }
 
         operation = manager->priv->initial_login_operation;
 
         g_object_get (G_OBJECT (greeter_display),
                       "seat-id", &greeter_seat_id,
                       NULL);
         g_object_get (G_OBJECT (operation->session),
                       "display-seat-id", &user_session_seat_id,
                       NULL);
 
         if (g_strcmp0 (greeter_seat_id, user_session_seat_id) == 0) {
                 start_user_session (manager, operation);
                 manager->priv->initial_login_operation = NULL;
@@ -1347,114 +1330,186 @@ set_up_automatic_login_session (GdmManager *manager,
         g_object_set (G_OBJECT (session),
                       "display-is-initial", is_initial,
                       NULL);
 
         g_debug ("GdmManager: Starting automatic login conversation");
         gdm_session_start_conversation (session, "gdm-autologin");
 }
 
 static void
 set_up_greeter_session (GdmManager *manager,
                         GdmDisplay *display)
 {
         const char *allowed_user;
         struct passwd *passwd_entry;
 
         allowed_user = get_username_for_greeter_display (manager, display);
 
         if (!gdm_get_pwent_for_name (allowed_user, &passwd_entry)) {
                 g_warning ("GdmManager: couldn't look up username %s",
                            allowed_user);
                 gdm_display_unmanage (display);
                 gdm_display_finish (display);
                 return;
         }
 
         create_embryonic_user_session_for_display (manager, display, passwd_entry->pw_uid);
         gdm_display_start_greeter_session (display);
 }
 
 static void
+set_up_automatic_login_session_if_user_exists (GdmManager *manager,
+                                               GdmDisplay *display,
+                                               ActUser    *user)
+{
+        if (act_user_is_nonexistent (user))
+                set_up_greeter_session (manager, display);
+        else
+                set_up_automatic_login_session (manager, display);
+}
+
+typedef struct {
+        GdmManager *manager;
+        GdmDisplay *display;
+        char *username;
+} UsernameLookupOperation;
+
+static void
+destroy_username_lookup_operation (UsernameLookupOperation *operation)
+{
+        g_object_unref (operation->manager);
+        g_object_unref (operation->display);
+        g_free (operation->username);
+        g_free (operation);
+}
+
+static void
+on_user_is_loaded_changed (ActUser                 *user,
+                           GParamSpec              *pspec,
+                           UsernameLookupOperation *operation)
+{
+        if (act_user_is_loaded (user)) {
+                set_up_automatic_login_session_if_user_exists (operation->manager, operation->display, user);
+                g_signal_handlers_disconnect_by_func (G_OBJECT (user),
+                                                      G_CALLBACK (on_user_is_loaded_changed),
+                                                      operation);
+                destroy_username_lookup_operation (operation);
+        }
+}
+
+static void
+set_up_session (GdmManager *manager,
+                GdmDisplay *display)
+{
+        ActUserManager *user_manager;
+        ActUser *user;
+        gboolean loaded;
+        gboolean autologin_enabled = FALSE;
+        char *username = NULL;
+
+        if (!manager->priv->ran_once && display_is_on_seat0 (display))
+                autologin_enabled = get_automatic_login_details (manager, &username);
+
+        if (!autologin_enabled) {
+                set_up_greeter_session (manager, display);
+                g_free (username);
+                return;
+        }
+
+        /* Check whether the user really exists before committing to autologin. */
+        user_manager = act_user_manager_get_default ();
+        user = act_user_manager_get_user (user_manager, username);
+        g_object_get (user_manager, "is-loaded", &loaded, NULL);
+
+        if (loaded) {
+                set_up_automatic_login_session_if_user_exists (manager, display, user);
+        } else {
+                UsernameLookupOperation *operation;
+
+                operation = g_new (UsernameLookupOperation, 1);
+                operation->manager = g_object_ref (manager);
+                operation->display = g_object_ref (display);
+                operation->username = username;
+
+                g_signal_connect (user,
+                                  "notify::is-loaded",
+                                  G_CALLBACK (on_user_is_loaded_changed),
+                                  operation);
+        }
+}
+
+static void
 greeter_display_started (GdmManager *manager,
                          GdmDisplay *display)
 {
         if (manager->priv->ran_once) {
                 return;
         }
 
         maybe_start_pending_initial_login (manager, display);
 
         manager->priv->ran_once = TRUE;
 }
 
 static void
 on_display_status_changed (GdmDisplay *display,
                            GParamSpec *arg1,
                            GdmManager *manager)
 {
         int         status;
         int         display_number = -1;
 #ifdef WITH_PLYMOUTH
         gboolean    display_is_local = FALSE;
         gboolean    quit_plymouth = FALSE;
 
         g_object_get (display,
                       "is-local", &display_is_local,
                       NULL);
         quit_plymouth = display_is_local && manager->priv->plymouth_is_running;
 #endif
 
         g_object_get (display, "x11-display-number", &display_number, NULL);
 
         status = gdm_display_get_status (display);
 
         switch (status) {
                 case GDM_DISPLAY_PREPARED:
                 case GDM_DISPLAY_MANAGED:
                         if ((display_number == -1 && status == GDM_DISPLAY_PREPARED) ||
                             (display_number != -1 && status == GDM_DISPLAY_MANAGED)) {
                                 char *session_class;
 
                                 g_object_get (display,
                                               "session-class", &session_class,
                                               NULL);
-                                if (g_strcmp0 (session_class, "greeter") == 0) {
-                                        gboolean will_autologin;
-
-                                        will_autologin = display_should_autologin (manager, display);
-
-                                        if (will_autologin) {
-                                                set_up_automatic_login_session (manager, display);
-                                        } else {
-                                                set_up_greeter_session (manager, display);
-                                        }
-                                }
+                                if (g_strcmp0 (session_class, "greeter") == 0)
+                                        set_up_session (manager, display);
                                 g_free (session_class);
                         }
 
                         if (status == GDM_DISPLAY_MANAGED) {
                                 greeter_display_started (manager, display);
                         }
                         break;
                 case GDM_DISPLAY_FAILED:
                 case GDM_DISPLAY_UNMANAGED:
                 case GDM_DISPLAY_FINISHED:
 #ifdef WITH_PLYMOUTH
                         if (quit_plymouth) {
                                 plymouth_quit_without_transition ();
                                 manager->priv->plymouth_is_running = FALSE;
                         }
 #endif
 
                         maybe_start_pending_initial_login (manager, display);
                         break;
                 default:
                         break;
         }
 
 }
 
 static void
 on_display_removed (GdmDisplayStore *display_store,
                     const char      *id,
                     GdmManager      *manager)
 {
-- 
2.12.0