]> rtime.felk.cvut.cz Git - sojka/lightdm.git/commitdiff
Compiles and does something
authorunknown <robert.ancell@gmail.com>
Thu, 29 Apr 2010 11:08:26 +0000 (21:08 +1000)
committerunknown <robert.ancell@gmail.com>
Thu, 29 Apr 2010 11:08:26 +0000 (21:08 +1000)
16 files changed:
.bzrignore [new file with mode: 0644]
AUTHORS [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
NEWS [new file with mode: 0644]
README [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
configure.ac [new file with mode: 0644]
lightdm.doap [new file with mode: 0644]
po/POTFILES.in [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/display-manager.c [new file with mode: 0644]
src/display-manager.h [new file with mode: 0644]
src/display.c [new file with mode: 0644]
src/display.h [new file with mode: 0644]
src/lightdm.c [new file with mode: 0644]

diff --git a/.bzrignore b/.bzrignore
new file mode 100644 (file)
index 0000000..702e436
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..200fa4b
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..207b1dd
--- /dev/null
@@ -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 (file)
index 0000000..f842608
--- /dev/null
@@ -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 (file)
index 0000000..64ec771
--- /dev/null
@@ -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 (file)
index 0000000..53c4283
--- /dev/null
@@ -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 (file)
index 0000000..bc0dd63
--- /dev/null
@@ -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 (file)
index 0000000..13c0c14
--- /dev/null
@@ -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 (file)
index 0000000..cc71ac3
--- /dev/null
@@ -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 (file)
index 0000000..b6f88fd
--- /dev/null
@@ -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 (file)
index 0000000..db36c5d
--- /dev/null
@@ -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 (file)
index 0000000..498eb31
--- /dev/null
@@ -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;
+}