From: unknown Date: Thu, 29 Apr 2010 11:08:26 +0000 (+1000) Subject: Compiles and does something X-Git-Url: https://rtime.felk.cvut.cz/gitweb/sojka/lightdm.git/commitdiff_plain/402560ec97aaf15db65e0eb39560edfbe4576f1d Compiles and does something --- 402560ec97aaf15db65e0eb39560edfbe4576f1d diff --git a/.bzrignore b/.bzrignore new file mode 100644 index 00000000..702e4361 --- /dev/null +++ b/.bzrignore @@ -0,0 +1,19 @@ +Makefile +Makefile.in +Makefile.in.in +.deps +missing +mkinstalldirs +install-sh +gnome-doc-utils.make +configure +config.status +config.log +autom4te.cache +aclocal.m4 +depcomp +omf.make +xmldocs.make +po/stamp-it +po/POTFILES +src/lightdm diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..e69de29b diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 00000000..e69de29b diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 00000000..200fa4b4 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,17 @@ +SUBDIRS = po src + +EXTRA_DIST = \ + autogen.sh \ + lightdm.doap + +DISTCLEANFILES = \ + Makefile.in \ + aclocal.m4 \ + configure \ + depcomp \ + gnome-doc-utils.make \ + install-sh \ + missing \ + mkinstalldirs \ + omf.make \ + xmldocs.make diff --git a/NEWS b/NEWS new file mode 100644 index 00000000..e69de29b diff --git a/README b/README new file mode 100644 index 00000000..e69de29b diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 00000000..207b1dd1 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,21 @@ +#!/bin/sh +# Run this to generate all the initial makefiles, etc. + +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +PKG_NAME="lightdm" +REQUIRED_AUTOMAKE_VERSION=1.7 + +(test -f $srcdir/configure.ac \ + && test -d $srcdir/src) || { + echo -n "**Error**: Directory "\`$srcdir\'" does not look like the" + echo " top-level lightdm directory" + exit 1 +} + +which gnome-autogen.sh || { + echo "You need to install gnome-common from the GNOME CVS" + exit 1 +} +USE_GNOME2_MACROS=1 USE_COMMON_DOC_BUILD=yes . gnome-autogen.sh diff --git a/configure.ac b/configure.ac new file mode 100644 index 00000000..f842608c --- /dev/null +++ b/configure.ac @@ -0,0 +1,54 @@ +dnl Process this file with autoconf to produce a configure script. + +AC_INIT(configure.ac) +AM_INIT_AUTOMAKE(lightdm, 0.0.1) +AM_MAINTAINER_MODE +GNOME_MAINTAINER_MODE_DEFINES +m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) + +AC_ISC_POSIX +AC_PROG_CC_C_O +AM_PROG_CC_STDC +AC_HEADER_STDC + +AM_GCONF_SOURCE_2 + +GNOME_COMPILE_WARNINGS(yes) + +dnl ########################################################################### +dnl Dependencies +dnl ########################################################################### + +PKG_CHECK_MODULES(LIGHTDM, [ + glib-2.0 + gobject-2.0 + dbus-glib-1 + ck-connector +]) + +AC_CHECK_HEADERS([security/pam_appl.h],[],[AC_MSG_ERROR([PAM not found])]) + +dnl ########################################################################### +dnl Documentation +dnl ########################################################################### + +GNOME_DOC_INIT + +dnl ########################################################################### +dnl Internationalization +dnl ########################################################################### + +IT_PROG_INTLTOOL([0.35.0]) +GETTEXT_PACKAGE=lightdm +AC_SUBST(GETTEXT_PACKAGE) +AM_GLIB_GNU_GETTEXT + +dnl ########################################################################### +dnl Files to generate +dnl ########################################################################### + +AC_OUTPUT([ +Makefile +po/Makefile.in +src/Makefile +]) diff --git a/lightdm.doap b/lightdm.doap new file mode 100644 index 00000000..64ec7712 --- /dev/null +++ b/lightdm.doap @@ -0,0 +1,21 @@ + + + lightdm + X Display Manager + + + + + + + + Robert Ancell + + rancell + + + diff --git a/po/POTFILES.in b/po/POTFILES.in new file mode 100644 index 00000000..53c42839 --- /dev/null +++ b/po/POTFILES.in @@ -0,0 +1,3 @@ +# List of source files containing translatable strings. +# Please keep this file sorted alphabetically. +[encoding: UTF-8] diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 00000000..bc0dd633 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,23 @@ +bin_PROGRAMS = lightdm + +lightdm_SOURCES = \ + display.c \ + display.h \ + display-manager.c \ + display-manager.h \ + lightdm.c + +lightdm_CFLAGS = \ + $(LIGHTDM_CFLAGS) \ + $(WARN_CFLAGS) \ + -DVERSION=\"$(VERSION)\" \ + -DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\" \ + -DLOCALE_DIR=\"$(localedir)\" \ + -DLIGHTDM_BINARY=\"lightdm\" + +lightdm_LDADD = \ + $(LIGHTDM_LIBS) \ + -lpam + +DISTCLEANFILES = \ + Makefile.in diff --git a/src/display-manager.c b/src/display-manager.c new file mode 100644 index 00000000..13c0c14d --- /dev/null +++ b/src/display-manager.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2010 Canonical Ltd. + * Author: Robert Ancell + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. See http://www.gnu.org/copyleft/gpl.html the full text of the + * license. + */ + +#include "display-manager.h" + +struct DisplayManagerPrivate +{ + GList *displays; +}; + +G_DEFINE_TYPE (DisplayManager, display_manager, G_TYPE_OBJECT); + +DisplayManager * +display_manager_new (void) +{ + return g_object_new (DISPLAY_MANAGER_TYPE, NULL); +} + +static void +display_exited_cb (Display *display, DisplayManager *manager) +{ + manager->priv->displays = g_list_remove (manager->priv->displays, display); + // FIXME: Check for respawn loops + if (!manager->priv->displays) + display_manager_add_display (manager); +} + +Display * +display_manager_add_display (DisplayManager *manager) +{ + Display *display; + + display = display_new (); + g_signal_connect (G_OBJECT (display), "exited", G_CALLBACK (display_exited_cb), manager); + + return display; +} + +static void +display_manager_init (DisplayManager *manager) +{ + manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, DISPLAY_MANAGER_TYPE, DisplayManagerPrivate); + display_manager_add_display (manager); +} + +static void +display_manager_class_init (DisplayManagerClass *klass) +{ + g_type_class_add_private (klass, sizeof (DisplayManagerPrivate)); +} diff --git a/src/display-manager.h b/src/display-manager.h new file mode 100644 index 00000000..cc71ac3b --- /dev/null +++ b/src/display-manager.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2010 Canonical Ltd. + * Author: Robert Ancell + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. See http://www.gnu.org/copyleft/gpl.html the full text of the + * license. + */ + +#ifndef _DISPLAY_MANAGER_H_ +#define _DISPLAY_MANAGER_H_ + +#include +#include "display.h" + +G_BEGIN_DECLS + +#define DISPLAY_MANAGER_TYPE (display_manager_get_type()) +#define DISPLAY_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DISPLAY_MANAGER_TYPE, DisplayManager)); + +typedef struct DisplayManagerPrivate DisplayManagerPrivate; + +typedef struct +{ + GObject parent_instance; + DisplayManagerPrivate *priv; +} DisplayManager; + +typedef struct +{ + GObjectClass parent_class; +} DisplayManagerClass; + +GType display_manager_get_type (void); + +DisplayManager *display_manager_new (void); + +Display *display_manager_add_display (DisplayManager *manager); + +G_END_DECLS + +#endif /* _DISPLAY_MANAGER_H_ */ diff --git a/src/display.c b/src/display.c new file mode 100644 index 00000000..b6f88fd5 --- /dev/null +++ b/src/display.c @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2010 Canonical Ltd. + * Author: Robert Ancell + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. See http://www.gnu.org/copyleft/gpl.html the full text of the + * license. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "display.h" + +enum { + EXITED, + LAST_SIGNAL +}; +static guint signals[LAST_SIGNAL] = { 0 }; + +struct DisplayPrivate +{ + /* X process */ + GPid xserver_pid; + + /* Session process (either greeter or user session) */ + GPid session_pid; + + /* Authentication thread */ + GThread *authentication_thread; + + /* Queue to feed responses to the authentication thread */ + GAsyncQueue *authentication_response_queue; + + /* Current D-Bus call context */ + DBusGMethodInvocation *dbus_context; + + /* Authentication handle */ + pam_handle_t *pam_handle; + + /* User logged in as */ + char *username; + + /* TRUE if user has been authenticated */ + gboolean authenticated; + + /* TRUE if in user session */ + gboolean in_user_session; + + // FIXME: Token for secure access to this server +}; + +G_DEFINE_TYPE (Display, display, G_TYPE_OBJECT); + +static void start_greeter (Display *display); +static void start_user_session (Display *display); + +Display * +display_new (void) +{ + return g_object_new (DISPLAY_TYPE, NULL); +} + +static void +session_watch_cb (GPid pid, gint status, gpointer data) +{ + Display *display = data; + + if (WIFEXITED (status)) + g_debug ("Display exited with return value %d", WEXITSTATUS (status)); + else if (WIFSIGNALED (status)) + g_debug ("Display terminated with signal %d", WTERMSIG (status)); + + display->priv->session_pid = 0; + + // FIXME: Check for respawn loops + if (display->priv->authenticated && !display->priv->in_user_session) + start_user_session (display); + else + start_greeter (display); +} + +static void +start_session (Display *display, const char *username, char * const argv[]) +{ + pid_t pid; + struct passwd *user_info; + + g_return_if_fail (display->priv->session_pid == 0); + + errno = 0; + user_info = getpwnam (username); + if (!user_info) + { + g_warning ("Unable to get information on user %s: %s", username, strerror (errno)); + return; + } + + pid = fork (); + if (pid < 0) + { + g_warning ("Failed to fork session: %s", strerror (errno)); + return; + } + else if (pid > 0) + { + g_debug ("Child process started with PID %d", pid); + display->priv->session_pid = pid; + g_child_watch_add (display->priv->session_pid, session_watch_cb, display); + return; + } + + if (setgid (user_info->pw_gid) != 0) + { + g_warning ("Failed to set group ID: %s", strerror (errno)); + _exit(1); + } + // FIXME: Is there a risk of connecting to the process for a user in the given group and accessing memory? + if (setuid (user_info->pw_uid) != 0) + { + g_warning ("Failed to set user ID: %s", strerror (errno)); + _exit(1); + } + if (chdir (user_info->pw_dir) != 0) + g_warning ("Failed to change directory: %s", strerror (errno)); + + /* Reset environment */ + // FIXME: Check these work + clearenv (); + setenv ("USER", user_info->pw_name, 1); + setenv ("HOME", user_info->pw_dir, 1); + setenv ("SHELL", user_info->pw_shell, 1); + setenv ("HOME", user_info->pw_dir, 1); + setenv ("DISPLAY", ":0", 1); + + execv (argv[0], argv); +} + +static void +start_user_session (Display *display) +{ + char *argv[] = { "/usr/bin/gnome-terminal", NULL }; + display->priv->in_user_session = TRUE; + start_session (display, display->priv->username, argv); +} + +static void +start_greeter (Display *display) +{ + char *argv[] = { "/usr/bin/lightdm-greeter", NULL }; + display->priv->in_user_session = FALSE; + g_free (display->priv->username); + display->priv->username = NULL; + start_session (display, "gdm", argv); +} + +static int +pam_conv_cb (int num_msg, const struct pam_message **msg, + struct pam_response **resp, void *app_data) +{ + Display *display = app_data; + gpointer response; + + /* Respond to d-bus query with messages */ + dbus_g_method_return (display->priv->dbus_context, 666); // ACTIONS + display->priv->dbus_context = NULL; + + /* Wait for responses */ + response = g_async_queue_pop (display->priv->authentication_response_queue); + + /* Fill responses */ + // ... + + return 0; +} + +static gpointer +authenticate_cb (gpointer data) +{ + Display *display = data; + struct pam_conv conversation = { pam_conv_cb, display }; + int result; + + pam_start ("check_pass", display->priv->username, &conversation, &display->priv->pam_handle); + result = pam_authenticate (display->priv->pam_handle, 0); + + /* Thread complete */ + g_thread_join (display->priv->authentication_thread); + display->priv->authentication_thread = NULL; + g_async_queue_unref (display->priv->authentication_response_queue); + display->priv->authentication_response_queue = NULL; + + /* Respond to D-Bus request */ + dbus_g_method_return (display->priv->dbus_context, 888); // FINISHED + display->priv->dbus_context = NULL; + + return NULL; +} + +gboolean +display_start_authentication (Display *display, const char *username, DBusGMethodInvocation *context) +{ + GError *error = NULL; + + // FIXME: Only allow calls from the greeter + + g_return_val_if_fail (display->priv->authentication_thread != NULL, FALSE); + + /* Store authentication request and D-Bus request to respond to */ + g_free (display->priv->username); + display->priv->username = g_strdup (username); + display->priv->dbus_context = context; + + /* Start thread */ + display->priv->authentication_response_queue = g_async_queue_new (); + display->priv->authentication_thread = g_thread_create (authenticate_cb, display, TRUE, &error); + if (!display->priv->authentication_thread) + { + g_warning ("Failed to start authentication thread: %s", error->message); + display->priv->dbus_context = NULL; + return FALSE; + } + g_clear_error (&error); + + return TRUE; +} + +gboolean +display_continue_authentication (Display *display, int data, DBusGMethodInvocation *context) +{ + g_return_val_if_fail (display->priv->authentication_thread == NULL, FALSE); + g_return_val_if_fail (display->priv->dbus_context != NULL, FALSE); + + // FIXME: Only allow calls from the greeter + + /* Push onto queue and store request to respond to */ + display->priv->dbus_context = context; + g_async_queue_push (display->priv->authentication_response_queue, GINT_TO_POINTER (data)); + + return TRUE; +} + +static void +xserver_watch_cb (GPid pid, gint status, gpointer data) +{ + Display *display = data; + + if (WIFEXITED (status)) + g_debug ("Display exited with return value %d", WEXITSTATUS (status)); + else if (WIFSIGNALED (status)) + g_debug ("Display terminated with signal %d", WTERMSIG (status)); + + display->priv->xserver_pid = 0; + + g_signal_emit (display, signals[EXITED], 0); +} + +static void +display_init (Display *display) +{ + GError *error = NULL; + char *argv[] = { "/usr/bin/X", ":0", NULL }; + char *env[] = { NULL }; + gboolean result; + + display->priv = G_TYPE_INSTANCE_GET_PRIVATE (display, DISPLAY_TYPE, DisplayPrivate); + + result = g_spawn_async (NULL, /* Working directory */ + argv, + env, + G_SPAWN_DO_NOT_REAP_CHILD, + NULL, NULL, + &display->priv->xserver_pid, + &error); + if (!result) + g_warning ("Unable to create display: %s", error->message); + else + g_child_watch_add (display->priv->xserver_pid, xserver_watch_cb, display); + g_clear_error (&error); + + /* TODO: Do autologin if this is requested */ + start_greeter (display); +} + +static void +display_class_init (DisplayClass *klass) +{ + g_type_class_add_private (klass, sizeof (DisplayPrivate)); + + signals[EXITED] = + g_signal_new ("exited", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (DisplayClass, exited), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} diff --git a/src/display.h b/src/display.h new file mode 100644 index 00000000..db36c5d3 --- /dev/null +++ b/src/display.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2010 Canonical Ltd. + * Author: Robert Ancell + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. See http://www.gnu.org/copyleft/gpl.html the full text of the + * license. + */ + +#ifndef _DISPLAY_H_ +#define _DISPLAY_H_ + +#include +#include + +G_BEGIN_DECLS + +#define DISPLAY_TYPE (display_get_type()) +#define DISPLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DISPLAY_TYPE, Display)); + +typedef struct DisplayPrivate DisplayPrivate; + +typedef struct +{ + GObject parent_instance; + DisplayPrivate *priv; +} Display; + +typedef struct +{ + GObjectClass parent_class; + + void (*exited)(Display *display); +} DisplayClass; + +GType display_get_type (void); + +Display *display_new (void); + +gboolean display_start_authentication (Display *display, const char *username, DBusGMethodInvocation *context); + +gboolean display_continue_authentication (Display *display, int data, DBusGMethodInvocation *context); + +G_END_DECLS + +#endif /* _DISPLAY_H_ */ diff --git a/src/lightdm.c b/src/lightdm.c new file mode 100644 index 00000000..498eb31e --- /dev/null +++ b/src/lightdm.c @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2010 Canonical Ltd. + * Author: Robert Ancell + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. See http://www.gnu.org/copyleft/gpl.html the full text of the + * license. + */ + +#include + +#include "display-manager.h" + +int +main(int argc, char **argv) +{ + GMainLoop *loop; + DisplayManager *manager; + + g_type_init (); + loop = g_main_loop_new (NULL, FALSE); + + // Load config + // FIXME: If autologin selected the first display should be a user session + + manager = display_manager_new (); + + g_main_loop_run (loop); + + return 0; +}