summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrobert.ancell@gmail.com <>2010-04-29 21:08:26 +1000
committerrobert.ancell@gmail.com <>2010-04-29 21:08:26 +1000
commit9e8fcfa450e52155dd5f664f954ebb2ec3e39768 (patch)
tree0d503ebb84d7fe6e05e81d7ffcccbaf3ebba28e0
downloadlightdm-9e8fcfa450e52155dd5f664f954ebb2ec3e39768.tar.gz
Compiles and does something
-rw-r--r--.bzrignore19
-rw-r--r--AUTHORS0
-rw-r--r--ChangeLog0
-rw-r--r--Makefile.am17
-rw-r--r--NEWS0
-rw-r--r--README0
-rwxr-xr-xautogen.sh21
-rw-r--r--configure.ac54
-rw-r--r--lightdm.doap21
-rw-r--r--po/POTFILES.in3
-rw-r--r--src/Makefile.am23
-rw-r--r--src/display-manager.c58
-rw-r--r--src/display-manager.h44
-rw-r--r--src/display.c305
-rw-r--r--src/display.h48
-rw-r--r--src/lightdm.c33
16 files changed, 646 insertions, 0 deletions
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
--- /dev/null
+++ b/AUTHORS
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/ChangeLog
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
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/README
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 @@
+<Project xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
+ xmlns:foaf="http://xmlns.com/foaf/0.1/"
+ xmlns:gnome="http://api.gnome.org/doap-extensions#"
+ xmlns="http://usefulinc.com/ns/doap#">
+
+ <name xml:lang="en">lightdm</name>
+ <shortdesc xml:lang="en">X Display Manager</shortdesc>
+ <homepage rdf:resource="https://launchpad.net/lightdm" />
+ <download-page rdf:resource="http://people.ubuntu.com/~robert-ancell/lightdm/" />
+ <bug-database rdf:resource="https://bugs.launchpad.net/lightdm" />
+ <category rdf:resource="http://api.gnome.org/doap-extensions#desktop" />
+
+ <maintainer>
+ <foaf:Person>
+ <foaf:name>Robert Ancell</foaf:name>
+ <foaf:mbox rdf:resource="mailto:robert.ancell@gmail.com" />
+ <gnome:userid>rancell</gnome:userid>
+ </foaf:Person>
+ </maintainer>
+</Project>
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 <robert.ancell@canonical.com>
+ *
+ * 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 <robert.ancell@canonical.com>
+ *
+ * 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 <glib-object.h>
+#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 <robert.ancell@canonical.com>
+ *
+ * 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 <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <security/pam_appl.h>
+
+#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 <robert.ancell@canonical.com>
+ *
+ * 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 <glib-object.h>
+#include <dbus/dbus-glib.h>
+
+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 <robert.ancell@canonical.com>
+ *
+ * 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 <glib.h>
+
+#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;
+}