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