summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--daemon/Makefile.am102
-rw-r--r--daemon/factory-slave-main.c (renamed from daemon/slave-main.c)34
-rw-r--r--daemon/gdm-display.c38
-rw-r--r--daemon/gdm-factory-slave.c795
-rw-r--r--daemon/gdm-factory-slave.h55
-rw-r--r--daemon/gdm-factory-slave.xml5
-rw-r--r--daemon/gdm-greeter-proxy.c530
-rw-r--r--daemon/gdm-greeter-proxy.h26
-rw-r--r--daemon/gdm-greeter-server.c822
-rw-r--r--daemon/gdm-greeter-server.h76
-rw-r--r--daemon/gdm-manager.c6
-rw-r--r--daemon/gdm-product-display.c52
-rw-r--r--daemon/gdm-product-display.h10
-rw-r--r--daemon/gdm-product-display.xml6
-rw-r--r--daemon/gdm-product-slave.c1180
-rw-r--r--daemon/gdm-product-slave.h55
-rw-r--r--daemon/gdm-product-slave.xml5
-rw-r--r--daemon/gdm-simple-slave.c1136
-rw-r--r--daemon/gdm-simple-slave.h55
-rw-r--r--daemon/gdm-simple-slave.xml5
-rw-r--r--daemon/gdm-slave-proxy.c66
-rw-r--r--daemon/gdm-slave-proxy.h16
-rw-r--r--daemon/gdm-slave.c1044
-rw-r--r--daemon/gdm-slave.h14
-rw-r--r--daemon/gdm-static-factory-display.c120
-rw-r--r--daemon/gdm-static-factory-display.h8
-rw-r--r--daemon/gdm-static-factory-display.xml3
-rw-r--r--daemon/product-slave-main.c225
-rw-r--r--daemon/simple-slave-main.c225
29 files changed, 5214 insertions, 1500 deletions
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index e4aadf49..7f88ba30 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -31,6 +31,9 @@ INCLUDES = \
BUILT_SOURCES = \
gdm-slave-glue.h \
+ gdm-simple-slave-glue.h \
+ gdm-factory-slave-glue.h \
+ gdm-product-slave-glue.h \
gdm-manager-glue.h \
gdm-display-glue.h \
gdm-xdmcp-display-glue.h \
@@ -43,6 +46,12 @@ gdm-manager-glue.h: gdm-manager.xml Makefile.am
dbus-binding-tool --prefix=gdm_manager --mode=glib-server --output=gdm-manager-glue.h gdm-manager.xml
gdm-slave-glue.h: gdm-slave.xml Makefile.am
dbus-binding-tool --prefix=gdm_slave --mode=glib-server --output=gdm-slave-glue.h gdm-slave.xml
+gdm-simple-slave-glue.h: gdm-simple-slave.xml Makefile.am
+ dbus-binding-tool --prefix=gdm_simple_slave --mode=glib-server --output=gdm-simple-slave-glue.h gdm-simple-slave.xml
+gdm-factory-slave-glue.h: gdm-factory-slave.xml Makefile.am
+ dbus-binding-tool --prefix=gdm_factory_slave --mode=glib-server --output=gdm-factory-slave-glue.h gdm-factory-slave.xml
+gdm-product-slave-glue.h: gdm-product-slave.xml Makefile.am
+ dbus-binding-tool --prefix=gdm_product_slave --mode=glib-server --output=gdm-product-slave-glue.h gdm-product-slave.xml
gdm-display-glue.h: gdm-display.xml Makefile.am
dbus-binding-tool --prefix=gdm_display --mode=glib-server --output=gdm-display-glue.h gdm-display.xml
gdm-xdmcp-display-glue.h: gdm-xdmcp-display.xml Makefile.am
@@ -70,11 +79,15 @@ test_session_LDADD = \
$(NULL)
libexec_PROGRAMS = \
- gdm-slave \
+ gdm-simple-slave \
+ gdm-factory-slave \
+ gdm-product-slave \
$(NULL)
-gdm_slave_SOURCES = \
- slave-main.c \
+gdm_simple_slave_SOURCES = \
+ simple-slave-main.c \
+ gdm-greeter-server.c \
+ gdm-greeter-server.h \
gdm-greeter-proxy.c \
gdm-greeter-proxy.h \
gdm-server.c \
@@ -83,18 +96,90 @@ gdm_slave_SOURCES = \
gdm-session.h \
gdm-slave.c \
gdm-slave.h \
+ gdm-simple-slave.c \
+ gdm-simple-slave.h \
fstype.c \
filecheck.c \
filecheck.h \
$(NULL)
-# Note that these libs are in LDFLAGS because they should come before
-# everything else on the link line as they may override stuff
-gdm_slave_LDFLAGS = \
+gdm_simple_slave_LDFLAGS = \
+ $(PAM_LIBS) \
+ $(NULL)
+
+gdm_simple_slave_LDADD = \
+ $(DAEMON_LIBS) \
+ $(INTLLIBS) \
+ $(GLIB_LIBS) \
+ $(GOBJECT_LIBS) \
+ $(GDK_LIBS) \
+ $(top_builddir)/common/libgdmcommon.la \
+ $(X_LIBS) \
+ $(XINERAMA_LIBS) \
+ $(DBUS_LIBS) \
+ -lXau \
+ -lX11 \
+ -lXext \
+ $(NULL)
+
+gdm_factory_slave_SOURCES = \
+ factory-slave-main.c \
+ gdm-greeter-proxy.c \
+ gdm-greeter-proxy.h \
+ gdm-server.c \
+ gdm-server.h \
+ gdm-session.c \
+ gdm-session.h \
+ gdm-slave.c \
+ gdm-slave.h \
+ gdm-factory-slave.c \
+ gdm-factory-slave.h \
+ fstype.c \
+ filecheck.c \
+ filecheck.h \
+ $(NULL)
+
+gdm_factory_slave_LDFLAGS = \
+ $(PAM_LIBS) \
+ $(NULL)
+
+gdm_factory_slave_LDADD = \
+ $(DAEMON_LIBS) \
+ $(INTLLIBS) \
+ $(GLIB_LIBS) \
+ $(GOBJECT_LIBS) \
+ $(GDK_LIBS) \
+ $(top_builddir)/common/libgdmcommon.la \
+ $(X_LIBS) \
+ $(XINERAMA_LIBS) \
+ $(DBUS_LIBS) \
+ -lXau \
+ -lX11 \
+ -lXext \
+ $(NULL)
+
+gdm_product_slave_SOURCES = \
+ product-slave-main.c \
+ gdm-greeter-server.c \
+ gdm-greeter-server.h \
+ gdm-server.c \
+ gdm-server.h \
+ gdm-session.c \
+ gdm-session.h \
+ gdm-slave.c \
+ gdm-slave.h \
+ gdm-product-slave.c \
+ gdm-product-slave.h \
+ fstype.c \
+ filecheck.c \
+ filecheck.h \
+ $(NULL)
+
+gdm_product_slave_LDFLAGS = \
$(PAM_LIBS) \
$(NULL)
-gdm_slave_LDADD = \
+gdm_product_slave_LDADD = \
$(DAEMON_LIBS) \
$(INTLLIBS) \
$(GLIB_LIBS) \
@@ -202,6 +287,9 @@ CLEANFILES = \
EXTRA_DIST = \
gdm.in \
gdm-slave.xml \
+ gdm-simple-slave.xml \
+ gdm-factory-slave.xml \
+ gdm-product-slave.xml \
gdm-manager.xml \
gdm-display.xml \
gdm-xdmcp-display.xml \
diff --git a/daemon/slave-main.c b/daemon/factory-slave-main.c
index c75651ef..64a02c19 100644
--- a/daemon/slave-main.c
+++ b/daemon/factory-slave-main.c
@@ -40,7 +40,7 @@
#include "gdm-signal-handler.h"
#include "gdm-log.h"
-#include "gdm-slave.h"
+#include "gdm-factory-slave.h"
static int gdm_return_code = 0;
@@ -132,24 +132,11 @@ signal_cb (int signo,
}
static void
-on_session_exited (GdmSlave *slave,
- int exit_code,
- GMainLoop *main_loop)
+on_slave_stopped (GdmSlave *slave,
+ GMainLoop *main_loop)
{
- g_debug ("session exited with code %d\n", exit_code);
- gdm_return_code = exit_code;
- g_main_loop_quit (main_loop);
-}
-
-static void
-on_session_died (GdmSlave *slave,
- int signal_number,
- GMainLoop *main_loop)
-{
- g_debug ("session died with signal %d, (%s)",
- signal_number,
- g_strsignal (signal_number));
- gdm_return_code = 1;
+ g_debug ("slave finished");
+ gdm_return_code = 0;
g_main_loop_quit (main_loop);
}
@@ -208,19 +195,14 @@ main (int argc,
gdm_signal_handler_add (signal_handler, SIGABRT, signal_cb, NULL);
gdm_signal_handler_add (signal_handler, SIGUSR1, signal_cb, NULL);
- slave = gdm_slave_new (display_id);
+ slave = gdm_factory_slave_new (display_id);
if (slave == NULL) {
goto out;
}
g_signal_connect (slave,
- "session-exited",
- G_CALLBACK (on_session_exited),
- main_loop);
- g_signal_connect (slave,
- "session-died",
- G_CALLBACK (on_session_died),
+ "stopped",
+ G_CALLBACK (on_slave_stopped),
main_loop);
-
gdm_slave_start (slave);
g_main_loop_run (main_loop);
diff --git a/daemon/gdm-display.c b/daemon/gdm-display.c
index 390e0de6..cb5b4f65 100644
--- a/daemon/gdm-display.c
+++ b/daemon/gdm-display.c
@@ -44,6 +44,8 @@ static guint32 display_serial = 1;
#define GDM_DISPLAY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_DISPLAY, GdmDisplayPrivate))
+#define DEFAULT_SLAVE_COMMAND LIBEXECDIR"/gdm-simple-slave"
+
struct GdmDisplayPrivate
{
char *id;
@@ -54,6 +56,7 @@ struct GdmDisplayPrivate
time_t creation_time;
char *x11_cookie;
char *x11_authority_file;
+ char *slave_command;
gboolean is_local;
@@ -70,6 +73,7 @@ enum {
PROP_X11_COOKIE,
PROP_X11_AUTHORITY_FILE,
PROP_IS_LOCAL,
+ PROP_SLAVE_COMMAND,
};
static void gdm_display_class_init (GdmDisplayClass *klass);
@@ -200,6 +204,8 @@ gdm_display_get_number (GdmDisplay *display,
static gboolean
gdm_display_real_manage (GdmDisplay *display)
{
+ char *command;
+
g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
g_debug ("GdmDisplay manage display");
@@ -208,7 +214,15 @@ gdm_display_real_manage (GdmDisplay *display)
g_assert (display->priv->slave_proxy == NULL);
- display->priv->slave_proxy = gdm_slave_proxy_new (display->priv->id);
+ display->priv->slave_proxy = gdm_slave_proxy_new ();
+
+ command = g_strdup_printf ("%s --display-id %s",
+ display->priv->slave_command,
+ display->priv->id);
+
+ gdm_slave_proxy_set_command (display->priv->slave_proxy, command);
+ g_free (command);
+
gdm_slave_proxy_start (display->priv->slave_proxy);
return TRUE;
@@ -362,6 +376,14 @@ _gdm_display_set_is_local (GdmDisplay *display,
}
static void
+_gdm_display_set_slave_command (GdmDisplay *display,
+ const char *command)
+{
+ g_free (display->priv->slave_command);
+ display->priv->slave_command = g_strdup (command);
+}
+
+static void
gdm_display_set_property (GObject *object,
guint prop_id,
const GValue *value,
@@ -393,6 +415,9 @@ gdm_display_set_property (GObject *object,
case PROP_IS_LOCAL:
_gdm_display_set_is_local (self, g_value_get_boolean (value));
break;
+ case PROP_SLAVE_COMMAND:
+ _gdm_display_set_slave_command (self, g_value_get_string (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -431,6 +456,9 @@ gdm_display_get_property (GObject *object,
case PROP_IS_LOCAL:
g_value_set_boolean (value, self->priv->is_local);
break;
+ case PROP_SLAVE_COMMAND:
+ g_value_set_string (value, self->priv->slave_command);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -567,6 +595,14 @@ gdm_display_class_init (GdmDisplayClass *klass)
TRUE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_SLAVE_COMMAND,
+ g_param_spec_string ("slave-command",
+ "slave command",
+ "slave command",
+ DEFAULT_SLAVE_COMMAND,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
g_type_class_add_private (klass, sizeof (GdmDisplayPrivate));
dbus_g_object_type_install_info (GDM_TYPE_DISPLAY, &dbus_glib_gdm_display_object_info);
diff --git a/daemon/gdm-factory-slave.c b/daemon/gdm-factory-slave.c
new file mode 100644
index 00000000..f18eb2c1
--- /dev/null
+++ b/daemon/gdm-factory-slave.c
@@ -0,0 +1,795 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
+ *
+ * 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 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include <X11/Xlib.h> /* for Display */
+
+#include "gdm-common.h"
+
+#include "gdm-factory-slave.h"
+#include "gdm-factory-slave-glue.h"
+
+#include "gdm-server.h"
+#include "gdm-greeter-proxy.h"
+
+extern char **environ;
+
+#define GDM_FACTORY_SLAVE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_FACTORY_SLAVE, GdmFactorySlavePrivate))
+
+#define GDM_DBUS_NAME "org.gnome.DisplayManager"
+#define GDM_DBUS_FACTORY_DISPLAY_INTERFACE "org.gnome.DisplayManager.StaticFactoryDisplay"
+
+#define MAX_CONNECT_ATTEMPTS 10
+
+struct GdmFactorySlavePrivate
+{
+ char *id;
+ GPid pid;
+ guint output_watch_id;
+ guint error_watch_id;
+
+ GPid server_pid;
+ Display *server_display;
+ guint connection_attempts;
+
+ GdmServer *server;
+ GdmGreeterProxy *greeter;
+ DBusGProxy *factory_display_proxy;
+ DBusGConnection *connection;
+};
+
+enum {
+ PROP_0,
+};
+
+enum {
+ LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0, };
+
+static void gdm_factory_slave_class_init (GdmFactorySlaveClass *klass);
+static void gdm_factory_slave_init (GdmFactorySlave *factory_slave);
+static void gdm_factory_slave_finalize (GObject *object);
+
+G_DEFINE_TYPE (GdmFactorySlave, gdm_factory_slave, GDM_TYPE_SLAVE)
+
+static void
+set_busy_cursor (GdmFactorySlave *factory_slave)
+{
+ if (factory_slave->priv->server_display != NULL) {
+ Cursor xcursor;
+
+ xcursor = XCreateFontCursor (factory_slave->priv->server_display, GDK_WATCH);
+ XDefineCursor (factory_slave->priv->server_display,
+ DefaultRootWindow (factory_slave->priv->server_display),
+ xcursor);
+ XFreeCursor (factory_slave->priv->server_display, xcursor);
+ XSync (factory_slave->priv->server_display, False);
+ }
+}
+
+static void
+gdm_factory_slave_whack_temp_auth_file (GdmFactorySlave *factory_slave)
+{
+#if 0
+ uid_t old;
+
+ old = geteuid ();
+ if (old != 0)
+ seteuid (0);
+ if (d->parent_temp_auth_file != NULL) {
+ VE_IGNORE_EINTR (g_unlink (d->parent_temp_auth_file));
+ }
+ g_free (d->parent_temp_auth_file);
+ d->parent_temp_auth_file = NULL;
+ if (old != 0)
+ seteuid (old);
+#endif
+}
+
+
+static void
+create_temp_auth_file (GdmFactorySlave *factory_slave)
+{
+#if 0
+ if (d->type == TYPE_FLEXI_XNEST &&
+ d->parent_auth_file != NULL) {
+ if (d->parent_temp_auth_file != NULL) {
+ VE_IGNORE_EINTR (g_unlink (d->parent_temp_auth_file));
+ }
+ g_free (d->parent_temp_auth_file);
+ d->parent_temp_auth_file =
+ copy_auth_file (d->server_uid,
+ gdm_daemon_config_get_gdmuid (),
+ d->parent_auth_file);
+ }
+#endif
+}
+
+static void
+listify_hash (const char *key,
+ const char *value,
+ GPtrArray *env)
+{
+ char *str;
+ str = g_strdup_printf ("%s=%s", key, value);
+ g_debug ("environment: %s", str);
+ g_ptr_array_add (env, str);
+}
+
+static GPtrArray *
+get_script_environment (GdmFactorySlave *slave,
+ const char *username)
+{
+ GPtrArray *env;
+ GHashTable *hash;
+ struct passwd *pwent;
+ char *x_servers_file;
+ char *display_name;
+ char *display_hostname;
+ char *display_x11_authority_file;
+ gboolean display_is_local;
+
+ g_object_get (slave,
+ "display-name", &display_name,
+ "display-hostname", &display_hostname,
+ "display-is-local", &display_is_local,
+ "display-x11-authority-file", &display_x11_authority_file,
+ NULL);
+
+ env = g_ptr_array_new ();
+
+ /* create a hash table of current environment, then update keys has necessary */
+ hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+ /* modify environment here */
+ g_hash_table_insert (hash, g_strdup ("HOME"), g_strdup ("/"));
+ g_hash_table_insert (hash, g_strdup ("PWD"), g_strdup ("/"));
+ g_hash_table_insert (hash, g_strdup ("SHELL"), g_strdup ("/bin/sh"));
+
+ g_hash_table_insert (hash, g_strdup ("LOGNAME"), g_strdup (username));
+ g_hash_table_insert (hash, g_strdup ("USER"), g_strdup (username));
+ g_hash_table_insert (hash, g_strdup ("USERNAME"), g_strdup (username));
+
+ pwent = getpwnam (username);
+ if (pwent != NULL) {
+ if (pwent->pw_dir != NULL && pwent->pw_dir[0] != '\0') {
+ g_hash_table_insert (hash, g_strdup ("HOME"), g_strdup (pwent->pw_dir));
+ g_hash_table_insert (hash, g_strdup ("PWD"), g_strdup (pwent->pw_dir));
+ }
+
+ g_hash_table_insert (hash, g_strdup ("SHELL"), g_strdup (pwent->pw_shell));
+ }
+
+#if 0
+ if (display_is_parented) {
+ g_hash_table_insert (hash, g_strdup ("GDM_PARENT_DISPLAY"), g_strdup (parent_display_name));
+
+ /*g_hash_table_insert (hash, "GDM_PARENT_XAUTHORITY"), slave->priv->parent_temp_auth_file));*/
+ }
+#endif
+
+ /* some env for use with the Pre and Post scripts */
+ x_servers_file = gdm_make_filename (AUTHDIR,
+ display_name,
+ ".Xservers");
+ g_hash_table_insert (hash, g_strdup ("X_SERVERS"), x_servers_file);
+
+ if (! display_is_local) {
+ g_hash_table_insert (hash, g_strdup ("REMOTE_HOST"), g_strdup (display_hostname));
+ }
+
+ /* Runs as root */
+ g_hash_table_insert (hash, g_strdup ("XAUTHORITY"), g_strdup (display_x11_authority_file));
+ g_hash_table_insert (hash, g_strdup ("DISPLAY"), g_strdup (display_name));
+
+ /*g_setenv ("PATH", gdm_daemon_config_get_value_string (GDM_KEY_ROOT_PATH), TRUE);*/
+
+ g_hash_table_insert (hash, g_strdup ("RUNNING_UNDER_GDM"), g_strdup ("true"));
+
+#if 0
+ if ( ! ve_string_empty (d->theme_name))
+ g_setenv ("GDM_GTK_THEME", d->theme_name, TRUE);
+#endif
+ g_hash_table_remove (hash, "MAIL");
+
+
+ g_hash_table_foreach (hash, (GHFunc)listify_hash, env);
+ g_hash_table_destroy (hash);
+
+ g_ptr_array_add (env, NULL);
+
+ g_free (display_name);
+ g_free (display_hostname);
+ g_free (display_x11_authority_file);
+
+ return env;
+}
+
+static gboolean
+gdm_factory_slave_exec_script (GdmFactorySlave *slave,
+ const char *dir,
+ const char *login)
+{
+ char *script;
+ char **argv;
+ gint status;
+ GError *error;
+ GPtrArray *env;
+ gboolean res;
+ gboolean ret;
+ char *display_name;
+ char *display_hostname;
+
+ g_assert (dir != NULL);
+ g_assert (login != NULL);
+
+ g_object_get (slave,
+ "display-name", &display_name,
+ "display-hostname", &display_hostname,
+ NULL);
+
+ script = g_build_filename (dir, display_name, NULL);
+ if (g_access (script, R_OK|X_OK) != 0) {
+ g_free (script);
+ script = NULL;
+ }
+
+ if (script == NULL &&
+ display_hostname != NULL) {
+ script = g_build_filename (dir, display_hostname, NULL);
+ if (g_access (script, R_OK|X_OK) != 0) {
+ g_free (script);
+ script = NULL;
+ }
+ }
+
+#if 0
+ if (script == NULL &&
+ SERVER_IS_XDMCP (d)) {
+ script = g_build_filename (dir, "XDMCP", NULL);
+ if (g_access (script, R_OK|X_OK) != 0) {
+ g_free (script);
+ script = NULL;
+ }
+ }
+ if (script == NULL &&
+ SERVER_IS_FLEXI (d)) {
+ script = g_build_filename (dir, "Flexi", NULL);
+ if (g_access (script, R_OK|X_OK) != 0) {
+ g_free (script);
+ script = NULL;
+ }
+ }
+#endif
+
+ if (script == NULL) {
+ script = g_build_filename (dir, "Default", NULL);
+ if (g_access (script, R_OK|X_OK) != 0) {
+ g_free (script);
+ script = NULL;
+ }
+ }
+
+ if (script == NULL) {
+ return TRUE;
+ }
+
+ create_temp_auth_file (slave);
+
+ g_debug ("Running process: %s", script);
+ error = NULL;
+ if (! g_shell_parse_argv (script, NULL, &argv, &error)) {
+ g_warning ("Could not parse command: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ env = get_script_environment (slave, login);
+
+ res = g_spawn_sync (NULL,
+ argv,
+ (char **)env->pdata,
+ G_SPAWN_SEARCH_PATH,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &status,
+ &error);
+
+ g_ptr_array_foreach (env, (GFunc)g_free, NULL);
+ g_ptr_array_free (env, TRUE);
+
+ gdm_factory_slave_whack_temp_auth_file (slave);
+
+ if (WIFEXITED (status)) {
+ g_debug ("Process exit status: %d", WEXITSTATUS (status));
+ ret = WEXITSTATUS (status) != 0;
+ } else {
+ ret = TRUE;
+ }
+
+ out:
+ g_free (script);
+ g_free (display_name);
+ g_free (display_hostname);
+
+ return ret;
+}
+
+static void
+on_greeter_start (GdmGreeterProxy *greeter,
+ GdmFactorySlave *slave)
+{
+ g_debug ("Greeter started");
+}
+
+static void
+on_greeter_stop (GdmGreeterProxy *greeter,
+ GdmFactorySlave *slave)
+{
+ g_debug ("Greeter stopped");
+}
+
+static void
+run_greeter (GdmFactorySlave *slave)
+{
+ gboolean display_is_local;
+ char *display_name;
+ char *auth_file;
+
+ g_object_get (slave,
+ "display-is-local", &display_is_local,
+ "display-name", &display_name,
+ "display-x11-authority-file", &auth_file,
+ NULL);
+
+ /* Set the busy cursor */
+ set_busy_cursor (slave);
+
+ /* FIXME: send a signal back to the master */
+
+#if 0
+
+ /* OK from now on it's really the user whacking us most likely,
+ * we have already started up well */
+ do_xfailed_on_xio_error = FALSE;
+#endif
+
+#if 0
+ /* checkout xinerama */
+ gdm_screen_init (slave);
+#endif
+
+#ifdef HAVE_TSOL
+ /* Check out Solaris Trusted Xserver extension */
+ gdm_tsol_init (d);
+#endif
+
+ /* Run the init script. gdmslave suspends until script has terminated */
+ gdm_factory_slave_exec_script (slave,
+ GDMCONFDIR"/Init",
+ "gdm");
+
+
+ slave->priv->greeter = gdm_greeter_proxy_new (display_name);
+ g_signal_connect (slave->priv->greeter,
+ "started",
+ G_CALLBACK (on_greeter_start),
+ slave);
+ g_signal_connect (slave->priv->greeter,
+ "stopped",
+ G_CALLBACK (on_greeter_stop),
+ slave);
+ g_object_set (slave->priv->greeter,
+ "x11-authority-file", auth_file,
+ NULL);
+ gdm_greeter_proxy_start (slave->priv->greeter);
+
+ g_free (display_name);
+ g_free (auth_file);
+}
+
+static void
+set_local_auth (GdmFactorySlave *slave)
+{
+ GString *binary_cookie;
+ GString *cookie;
+ char *display_x11_cookie;
+
+ g_object_get (slave,
+ "display-x11-cookie", &display_x11_cookie,
+ NULL);
+
+ g_debug ("Setting authorization key for display %s", display_x11_cookie);
+
+ cookie = g_string_new (display_x11_cookie);
+ binary_cookie = g_string_new (NULL);
+ if (! gdm_string_hex_decode (cookie,
+ 0,
+ NULL,
+ binary_cookie,
+ 0)) {
+ g_warning ("Unable to decode hex cookie");
+ goto out;
+ }
+
+ g_debug ("Decoded cookie len %d", binary_cookie->len);
+
+ XSetAuthorization ("MIT-MAGIC-COOKIE-1",
+ (int) strlen ("MIT-MAGIC-COOKIE-1"),
+ (char *)binary_cookie->str,
+ binary_cookie->len);
+
+ out:
+ g_string_free (binary_cookie, TRUE);
+ g_string_free (cookie, TRUE);
+ g_free (display_x11_cookie);
+}
+
+static gboolean
+connect_to_display (GdmFactorySlave *slave)
+{
+ char *display_name;
+ gboolean ret;
+
+ ret = FALSE;
+
+ g_object_get (slave,
+ "display-name", &display_name,
+ NULL);
+
+ /* We keep our own (windowless) connection (dsp) open to avoid the
+ * X server resetting due to lack of active connections. */
+
+ g_debug ("Server is ready - opening display %s", display_name);
+
+ g_setenv ("DISPLAY", display_name, TRUE);
+ g_unsetenv ("XAUTHORITY"); /* just in case it's set */
+
+ set_local_auth (slave);
+
+#if 0
+ /* X error handlers to avoid the default one (i.e. exit (1)) */
+ do_xfailed_on_xio_error = TRUE;
+ XSetErrorHandler (gdm_factory_slave_xerror_handler);
+ XSetIOErrorHandler (gdm_factory_slave_xioerror_handler);
+#endif
+
+ gdm_sigchld_block_push ();
+ slave->priv->server_display = XOpenDisplay (display_name);
+ gdm_sigchld_block_pop ();
+
+ if (slave->priv->server_display == NULL) {
+ g_warning ("Unable to connect to display %s", display_name);
+ ret = FALSE;
+ } else {
+ g_debug ("Connected to display %s", display_name);
+ ret = TRUE;
+ }
+
+ g_free (display_name);
+
+ return ret;
+}
+
+static gboolean
+idle_connect_to_display (GdmFactorySlave *slave)
+{
+ gboolean res;
+
+ slave->priv->connection_attempts++;
+
+ res = connect_to_display (slave);
+ if (res) {
+ /* FIXME: handle wait-for-go */
+
+ run_greeter (slave);
+ } else {
+ if (slave->priv->connection_attempts >= MAX_CONNECT_ATTEMPTS) {
+ g_warning ("Unable to connect to display after %d tries - bailing out", slave->priv->connection_attempts);
+ exit (1);
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+server_ready_cb (GdmServer *server,
+ GdmFactorySlave *slave)
+{
+ g_timeout_add (500, (GSourceFunc)idle_connect_to_display, slave);
+}
+
+static gboolean
+gdm_factory_slave_run (GdmFactorySlave *slave)
+{
+ char *display_name;
+ gboolean display_is_local;
+
+ g_object_get (slave,
+ "display-is-local", &display_is_local,
+ "display-name", &display_name,
+ NULL);
+
+ /* if this is local display start a server if one doesn't
+ * exist */
+ if (display_is_local) {
+ gboolean res;
+
+ slave->priv->server = gdm_server_new (display_name);
+
+ g_signal_connect (slave->priv->server,
+ "ready",
+ G_CALLBACK (server_ready_cb),
+ slave);
+
+ res = gdm_server_start (slave->priv->server);
+ if (! res) {
+ g_warning (_("Could not start the X "
+ "server (your graphical environment) "
+ "due to some internal error. "
+ "Please contact your system administrator "
+ "or check your syslog to diagnose. "
+ "In the meantime this display will be "
+ "disabled. Please restart GDM when "
+ "the problem is corrected."));
+ exit (1);
+ }
+
+ g_debug ("Started X server");
+ } else {
+ g_timeout_add (500, (GSourceFunc)idle_connect_to_display, slave);
+ }
+
+ g_free (display_name);
+
+ return TRUE;
+}
+
+static gboolean
+gdm_factory_slave_start (GdmSlave *slave)
+{
+ gboolean res;
+ gboolean ret;
+ char *display_id;
+ char *product_id;
+ GError *error;
+
+ ret = FALSE;
+
+ res = GDM_SLAVE_CLASS (gdm_factory_slave_parent_class)->start (slave);
+
+ g_object_get (slave,
+ "display-id", &display_id,
+ NULL);
+
+ error = NULL;
+ GDM_FACTORY_SLAVE (slave)->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+ if (GDM_FACTORY_SLAVE (slave)->priv->connection == NULL) {
+ if (error != NULL) {
+ g_critical ("error getting system bus: %s", error->message);
+ g_error_free (error);
+ }
+ exit (1);
+ }
+ error = NULL;
+ GDM_FACTORY_SLAVE (slave)->priv->factory_display_proxy = dbus_g_proxy_new_for_name_owner (GDM_FACTORY_SLAVE (slave)->priv->connection,
+ GDM_DBUS_NAME,
+ display_id,
+ GDM_DBUS_FACTORY_DISPLAY_INTERFACE,
+ &error);
+ if (GDM_FACTORY_SLAVE (slave)->priv->factory_display_proxy == NULL) {
+ if (error != NULL) {
+ g_warning ("Failed to create display proxy %s: %s", display_id, error->message);
+ g_error_free (error);
+ } else {
+ g_warning ("Unable to create display proxy");
+ }
+ goto out;
+ }
+
+ error = NULL;
+ res = dbus_g_proxy_call (GDM_FACTORY_SLAVE (slave)->priv->factory_display_proxy,
+ "CreateProductDisplay",
+ &error,
+ G_TYPE_INVALID,
+ DBUS_TYPE_G_OBJECT_PATH, &product_id,
+ G_TYPE_INVALID);
+ if (! res) {
+ if (error != NULL) {
+ g_warning ("Failed to create product display: %s", error->message);
+ g_error_free (error);
+ } else {
+ g_warning ("Failed to create product display");
+ }
+
+ return FALSE;
+ }
+
+
+ gdm_factory_slave_run (GDM_FACTORY_SLAVE (slave));
+
+ ret = TRUE;
+
+ out:
+ g_free (display_id);
+
+ return ret;
+}
+
+static gboolean
+gdm_factory_slave_stop (GdmSlave *slave)
+{
+ gboolean res;
+
+ g_debug ("Stopping factory_slave");
+
+ res = GDM_SLAVE_CLASS (gdm_factory_slave_parent_class)->stop (slave);
+
+ if (GDM_FACTORY_SLAVE (slave)->priv->greeter != NULL) {
+ gdm_greeter_proxy_stop (GDM_FACTORY_SLAVE (slave)->priv->greeter);
+ g_object_unref (GDM_FACTORY_SLAVE (slave)->priv->greeter);
+ GDM_FACTORY_SLAVE (slave)->priv->greeter = NULL;
+ }
+
+ if (GDM_FACTORY_SLAVE (slave)->priv->server != NULL) {
+ gdm_server_stop (GDM_FACTORY_SLAVE (slave)->priv->server);
+ g_object_unref (GDM_FACTORY_SLAVE (slave)->priv->server);
+ GDM_FACTORY_SLAVE (slave)->priv->server = NULL;
+ }
+
+ if (GDM_FACTORY_SLAVE (slave)->priv->factory_display_proxy != NULL) {
+ g_object_unref (GDM_FACTORY_SLAVE (slave)->priv->factory_display_proxy);
+ }
+
+ return TRUE;
+}
+
+static void
+gdm_factory_slave_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdmFactorySlave *self;
+
+ self = GDM_FACTORY_SLAVE (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdm_factory_slave_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdmFactorySlave *self;
+
+ self = GDM_FACTORY_SLAVE (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GObject *
+gdm_factory_slave_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GdmFactorySlave *factory_slave;
+ GdmFactorySlaveClass *klass;
+
+ klass = GDM_FACTORY_SLAVE_CLASS (g_type_class_peek (GDM_TYPE_FACTORY_SLAVE));
+
+ factory_slave = GDM_FACTORY_SLAVE (G_OBJECT_CLASS (gdm_factory_slave_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+
+ return G_OBJECT (factory_slave);
+}
+
+static void
+gdm_factory_slave_class_init (GdmFactorySlaveClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdmSlaveClass *slave_class = GDM_SLAVE_CLASS (klass);
+
+ object_class->get_property = gdm_factory_slave_get_property;
+ object_class->set_property = gdm_factory_slave_set_property;
+ object_class->constructor = gdm_factory_slave_constructor;
+ object_class->finalize = gdm_factory_slave_finalize;
+
+ slave_class->start = gdm_factory_slave_start;
+ slave_class->stop = gdm_factory_slave_stop;
+
+ g_type_class_add_private (klass, sizeof (GdmFactorySlavePrivate));
+
+ dbus_g_object_type_install_info (GDM_TYPE_FACTORY_SLAVE, &dbus_glib_gdm_factory_slave_object_info);
+}
+
+static void
+gdm_factory_slave_init (GdmFactorySlave *factory_slave)
+{
+
+ factory_slave->priv = GDM_FACTORY_SLAVE_GET_PRIVATE (factory_slave);
+
+ factory_slave->priv->pid = -1;
+}
+
+static void
+gdm_factory_slave_finalize (GObject *object)
+{
+ GdmFactorySlave *factory_slave;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDM_IS_FACTORY_SLAVE (object));
+
+ factory_slave = GDM_FACTORY_SLAVE (object);
+
+ g_return_if_fail (factory_slave->priv != NULL);
+
+ G_OBJECT_CLASS (gdm_factory_slave_parent_class)->finalize (object);
+}
+
+GdmSlave *
+gdm_factory_slave_new (const char *id)
+{
+ GObject *object;
+
+ object = g_object_new (GDM_TYPE_FACTORY_SLAVE,
+ "display-id", id,
+ NULL);
+
+ return GDM_SLAVE (object);
+}
diff --git a/daemon/gdm-factory-slave.h b/daemon/gdm-factory-slave.h
new file mode 100644
index 00000000..acd77a38
--- /dev/null
+++ b/daemon/gdm-factory-slave.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
+ *
+ * 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 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifndef __GDM_FACTORY_SLAVE_H
+#define __GDM_FACTORY_SLAVE_H
+
+#include <glib-object.h>
+#include "gdm-slave.h"
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_FACTORY_SLAVE (gdm_factory_slave_get_type ())
+#define GDM_FACTORY_SLAVE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_FACTORY_SLAVE, GdmFactorySlave))
+#define GDM_FACTORY_SLAVE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_FACTORY_SLAVE, GdmFactorySlaveClass))
+#define GDM_IS_FACTORY_SLAVE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_FACTORY_SLAVE))
+#define GDM_IS_FACTORY_SLAVE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_FACTORY_SLAVE))
+#define GDM_FACTORY_SLAVE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_FACTORY_SLAVE, GdmFactorySlaveClass))
+
+typedef struct GdmFactorySlavePrivate GdmFactorySlavePrivate;
+
+typedef struct
+{
+ GdmSlave parent;
+ GdmFactorySlavePrivate *priv;
+} GdmFactorySlave;
+
+typedef struct
+{
+ GdmSlaveClass parent_class;
+} GdmFactorySlaveClass;
+
+GType gdm_factory_slave_get_type (void);
+GdmSlave * gdm_factory_slave_new (const char *id);
+
+G_END_DECLS
+
+#endif /* __GDM_FACTORY_SLAVE_H */
diff --git a/daemon/gdm-factory-slave.xml b/daemon/gdm-factory-slave.xml
new file mode 100644
index 00000000..74520ffb
--- /dev/null
+++ b/daemon/gdm-factory-slave.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.gnome.DisplayManager.FactorySlave">
+ </interface>
+</node>
diff --git a/daemon/gdm-greeter-proxy.c b/daemon/gdm-greeter-proxy.c
index 630fd102..dbad1f3d 100644
--- a/daemon/gdm-greeter-proxy.c
+++ b/daemon/gdm-greeter-proxy.c
@@ -76,7 +76,6 @@ struct GdmGreeterProxyPrivate
guint child_watch_id;
- DBusServer *server;
char *server_address;
DBusConnection *greeter_connection;
};
@@ -87,12 +86,10 @@ enum {
PROP_X11_AUTHORITY_FILE,
PROP_USER_NAME,
PROP_GROUP_NAME,
+ PROP_SERVER_ADDRESS,
};
enum {
- QUERY_ANSWER,
- SESSION_SELECTED,
- LANGUAGE_SELECTED,
STARTED,
STOPPED,
LAST_SIGNAL
@@ -106,87 +103,6 @@ static void gdm_greeter_proxy_finalize (GObject *object);
G_DEFINE_TYPE (GdmGreeterProxy, gdm_greeter_proxy, G_TYPE_OBJECT)
-static gboolean
-send_dbus_message (DBusConnection *connection,
- DBusMessage *message)
-{
- gboolean is_connected;
- gboolean sent;
-
- g_return_val_if_fail (message != NULL, FALSE);
-
- if (connection == NULL) {
- g_debug ("There is no valid connection");
- return FALSE;
- }
-
- is_connected = dbus_connection_get_is_connected (connection);
- if (! is_connected) {
- g_warning ("Not connected!");
- return FALSE;
- }
-
- sent = dbus_connection_send (connection, message, NULL);
-
- return sent;
-}
-
-static void
-send_dbus_string_signal (GdmGreeterProxy *greeter_proxy,
- const char *name,
- const char *text)
-{
- DBusMessage *message;
- DBusMessageIter iter;
-
- g_return_if_fail (greeter_proxy != NULL);
-
- message = dbus_message_new_signal (GDM_GREETER_SERVER_DBUS_PATH,
- GDM_GREETER_SERVER_DBUS_INTERFACE,
- name);
-
- dbus_message_iter_init_append (message, &iter);
- dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &text);
-
- if (! send_dbus_message (greeter_proxy->priv->greeter_connection, message)) {
- g_debug ("Could not send %s signal", name);
- }
-
- dbus_message_unref (message);
-}
-
-gboolean
-gdm_greeter_proxy_info_query (GdmGreeterProxy *greeter_proxy,
- const char *text)
-{
- send_dbus_string_signal (greeter_proxy, "InfoQuery", text);
-
- return TRUE;
-}
-
-gboolean
-gdm_greeter_proxy_secret_info_query (GdmGreeterProxy *greeter_proxy,
- const char *text)
-{
- send_dbus_string_signal (greeter_proxy, "SecretInfoQuery", text);
- return TRUE;
-}
-
-gboolean
-gdm_greeter_proxy_info (GdmGreeterProxy *greeter_proxy,
- const char *text)
-{
- send_dbus_string_signal (greeter_proxy, "Info", text);
- return TRUE;
-}
-
-gboolean
-gdm_greeter_proxy_problem (GdmGreeterProxy *greeter_proxy,
- const char *text)
-{
- send_dbus_string_signal (greeter_proxy, "Problem", text);
- return TRUE;
-}
static void
change_user (GdmGreeterProxy *greeter_proxy)
@@ -410,392 +326,6 @@ greeter_proxy_child_watch (GPid pid,
greeter_proxy->priv->pid = -1;
}
-/* Note: Use abstract sockets like dbus does by default on Linux. Abstract
- * sockets are only available on Linux.
- */
-static char *
-generate_address (void)
-{
- char *path;
-#if defined (__linux__)
- int i;
- char tmp[9];
-
- for (i = 0; i < 8; i++) {
- if (g_random_int_range (0, 2) == 0) {
- tmp[i] = g_random_int_range ('a', 'z' + 1);
- } else {
- tmp[i] = g_random_int_range ('A', 'Z' + 1);
- }
- }
- tmp[8] = '\0';
-
- path = g_strdup_printf ("unix:abstract=/tmp/gdm-greeter-%s", tmp);
-#else
- path = g_strdup ("unix:tmpdir=/tmp/gdm-greeter");
-#endif
-
- return path;
-}
-
-static DBusHandlerResult
-handle_answer_query (GdmGreeterProxy *greeter_proxy,
- DBusConnection *connection,
- DBusMessage *message)
-{
- DBusMessage *reply;
- DBusError error;
- const char *text;
-
- dbus_error_init (&error);
- if (! dbus_message_get_args (message, &error,
- DBUS_TYPE_STRING, &text,
- DBUS_TYPE_INVALID)) {
- g_warning ("ERROR: %s", error.message);
- }
-
- g_debug ("AnswerQuery: %s", text);
-
- reply = dbus_message_new_method_return (message);
- dbus_connection_send (connection, reply, NULL);
- dbus_message_unref (reply);
-
- g_signal_emit (greeter_proxy, signals [QUERY_ANSWER], 0, text);
-
- return DBUS_HANDLER_RESULT_HANDLED;
-}
-
-static DBusHandlerResult
-handle_select_session (GdmGreeterProxy *greeter_proxy,
- DBusConnection *connection,
- DBusMessage *message)
-{
- DBusMessage *reply;
- DBusError error;
- const char *text;
-
- dbus_error_init (&error);
- if (! dbus_message_get_args (message, &error,
- DBUS_TYPE_STRING, &text,
- DBUS_TYPE_INVALID)) {
- g_warning ("ERROR: %s", error.message);
- }
-
- g_debug ("SelectSession: %s", text);
-
- reply = dbus_message_new_method_return (message);
- dbus_connection_send (connection, reply, NULL);
- dbus_message_unref (reply);
-
- g_signal_emit (greeter_proxy, signals [SESSION_SELECTED], 0, text);
-
- return DBUS_HANDLER_RESULT_HANDLED;
-}
-
-static DBusHandlerResult
-handle_select_language (GdmGreeterProxy *greeter_proxy,
- DBusConnection *connection,
- DBusMessage *message)
-{
- DBusMessage *reply;
- DBusError error;
- const char *text;
-
- dbus_error_init (&error);
- if (! dbus_message_get_args (message, &error,
- DBUS_TYPE_STRING, &text,
- DBUS_TYPE_INVALID)) {
- g_warning ("ERROR: %s", error.message);
- }
-
- g_debug ("SelectLanguage: %s", text);
-
- reply = dbus_message_new_method_return (message);
- dbus_connection_send (connection, reply, NULL);
- dbus_message_unref (reply);
-
- g_signal_emit (greeter_proxy, signals [LANGUAGE_SELECTED], 0, text);
-
- return DBUS_HANDLER_RESULT_HANDLED;
-}
-
-static DBusHandlerResult
-greeter_handle_child_message (DBusConnection *connection,
- DBusMessage *message,
- void *user_data)
-{
- GdmGreeterProxy *greeter_proxy = GDM_GREETER_PROXY (user_data);
-
- if (dbus_message_is_method_call (message, GDM_GREETER_SERVER_DBUS_INTERFACE, "AnswerQuery")) {
- return handle_answer_query (greeter_proxy, connection, message);
- } else if (dbus_message_is_method_call (message, GDM_GREETER_SERVER_DBUS_INTERFACE, "SelectSession")) {
- return handle_select_session (greeter_proxy, connection, message);
- } else if (dbus_message_is_method_call (message, GDM_GREETER_SERVER_DBUS_INTERFACE, "SelectSession")) {
- return handle_select_language (greeter_proxy, connection, message);
- }
-
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-static DBusHandlerResult
-do_introspect (DBusConnection *connection,
- DBusMessage *message)
-{
- DBusMessage *reply;
- GString *xml;
- char *xml_string;
-
- g_debug ("Do introspect");
-
- /* standard header */
- xml = g_string_new ("<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
- "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
- "<node>\n"
- " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
- " <method name=\"Introspect\">\n"
- " <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"
- " </method>\n"
- " </interface>\n");
-
- /* interface */
- xml = g_string_append (xml,
- " <interface name=\"org.gnome.DisplayManager.GreeterServer\">\n"
- " <method name=\"AnswerQuery\">\n"
- " <arg name=\"text\" direction=\"in\" type=\"s\"/>\n"
- " </method>\n"
- " <method name=\"SelectSession\">\n"
- " <arg name=\"text\" direction=\"in\" type=\"s\"/>\n"
- " </method>\n"
- " <method name=\"SelectLanguage\">\n"
- " <arg name=\"text\" direction=\"in\" type=\"s\"/>\n"
- " </method>\n"
- " <signal name=\"Info\">\n"
- " <arg name=\"text\" type=\"s\"/>\n"
- " </signal>\n"
- " <signal name=\"Problem\">\n"
- " <arg name=\"text\" type=\"s\"/>\n"
- " </signal>\n"
- " <signal name=\"InfoQuery\">\n"
- " <arg name=\"text\" type=\"s\"/>\n"
- " </signal>\n"
- " <signal name=\"SecretInfoQuery\">\n"
- " <arg name=\"text\" type=\"s\"/>\n"
- " </signal>\n"
- " </interface>\n");
-
- reply = dbus_message_new_method_return (message);
-
- xml = g_string_append (xml, "</node>\n");
- xml_string = g_string_free (xml, FALSE);
-
- dbus_message_append_args (reply,
- DBUS_TYPE_STRING, &xml_string,
- DBUS_TYPE_INVALID);
-
- g_free (xml_string);
-
- if (reply == NULL) {
- g_error ("No memory");
- }
-
- if (! dbus_connection_send (connection, reply, NULL)) {
- g_error ("No memory");
- }
-
- dbus_message_unref (reply);
-
- return DBUS_HANDLER_RESULT_HANDLED;
-}
-
-static DBusHandlerResult
-greeter_server_message_handler (DBusConnection *connection,
- DBusMessage *message,
- void *user_data)
-{
- g_debug ("greeter_server_message_handler: destination=%s obj_path=%s interface=%s method=%s",
- dbus_message_get_destination (message),
- dbus_message_get_path (message),
- dbus_message_get_interface (message),
- dbus_message_get_member (message));
-
-
- if (dbus_message_is_method_call (message, "org.freedesktop.DBus", "AddMatch")) {
- DBusMessage *reply;
-
- reply = dbus_message_new_method_return (message);
-
- if (reply == NULL) {
- g_error ("No memory");
- }
-
- if (! dbus_connection_send (connection, reply, NULL)) {
- g_error ("No memory");
- }
-
- dbus_message_unref (reply);
-
- return DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected") &&
- strcmp (dbus_message_get_path (message), DBUS_PATH_LOCAL) == 0) {
-
- /*dbus_connection_unref (connection);*/
-
- return DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_method_call (message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
- return do_introspect (connection, message);
- } else {
- return greeter_handle_child_message (connection, message, user_data);
- }
-
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-static void
-greeter_server_unregister_handler (DBusConnection *connection,
- void *user_data)
-{
- g_debug ("greeter_server_unregister_handler");
-}
-
-static DBusHandlerResult
-connection_filter_function (DBusConnection *connection,
- DBusMessage *message,
- void *user_data)
-{
- GdmGreeterProxy *greeter_proxy = GDM_GREETER_PROXY (user_data);
- const char *path;
-
- path = dbus_message_get_path (message);
-
- g_debug ("obj_path=%s interface=%s method=%s",
- dbus_message_get_path (message),
- dbus_message_get_interface (message),
- dbus_message_get_member (message));
-
- if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected")
- && strcmp (path, DBUS_PATH_LOCAL) == 0) {
-
- g_debug ("Disconnected");
-
- dbus_connection_unref (connection);
- greeter_proxy->priv->greeter_connection = NULL;
- } else if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
-
-
- } else {
- return greeter_server_message_handler (connection, message, user_data);
- }
-
- return DBUS_HANDLER_RESULT_HANDLED;
-}
-
-static dbus_bool_t
-allow_user_function (DBusConnection *connection,
- unsigned long uid,
- void *data)
-{
- GdmGreeterProxy *greeter_proxy = GDM_GREETER_PROXY (data);
- struct passwd *pwent;
-
- if (greeter_proxy->priv->user_name == NULL) {
- return FALSE;
- }
-
- pwent = getpwnam (greeter_proxy->priv->user_name);
- if (pwent == NULL) {
- return FALSE;
- }
-
- if (pwent->pw_uid == uid) {
- return TRUE;
- }
-
- return FALSE;
-}
-
-static void
-handle_connection (DBusServer *server,
- DBusConnection *new_connection,
- void *user_data)
-{
- GdmGreeterProxy *greeter_proxy = GDM_GREETER_PROXY (user_data);
-
- g_debug ("Handing new connection");
-
- if (greeter_proxy->priv->greeter_connection == NULL) {
- DBusObjectPathVTable vtable = { &greeter_server_unregister_handler,
- &greeter_server_message_handler,
- NULL, NULL, NULL, NULL
- };
-
- greeter_proxy->priv->greeter_connection = new_connection;
- dbus_connection_ref (new_connection);
- dbus_connection_setup_with_g_main (new_connection, NULL);
-
- g_debug ("greeter connection is %p", new_connection);
-#if 1
- dbus_connection_add_filter (new_connection,
- connection_filter_function,
- greeter_proxy,
- NULL);
-#endif
- dbus_connection_set_unix_user_function (new_connection,
- allow_user_function,
- greeter_proxy,
- NULL);
-
- dbus_connection_register_object_path (new_connection,
- GDM_GREETER_SERVER_DBUS_PATH,
- &vtable,
- greeter_proxy);
-
- g_signal_emit (greeter_proxy, signals[STARTED], 0);
-
- }
-}
-
-static gboolean
-create_dbus_server (GdmGreeterProxy *greeter_proxy)
-{
- DBusServer *server;
- DBusError error;
- gboolean ret;
- char *address;
- const char *auth_mechanisms[] = {"EXTERNAL", NULL};
-
- ret = FALSE;
-
- g_debug ("Creating D-Bus server for greeter");
-
- address = generate_address ();
-
- dbus_error_init (&error);
- server = dbus_server_listen (address, &error);
- g_free (address);
-
- if (server == NULL) {
- g_warning ("Cannot create D-BUS server for the greeter: %s", error.message);
- goto out;
- }
-
- dbus_server_setup_with_g_main (server, NULL);
- dbus_server_set_auth_mechanisms (server, auth_mechanisms);
- dbus_server_set_new_connection_function (server,
- handle_connection,
- greeter_proxy,
- NULL);
- ret = TRUE;
-
- g_free (greeter_proxy->priv->server_address);
- greeter_proxy->priv->server_address = dbus_server_get_address (server);
-
- g_debug ("D-Bus server listening on %s", greeter_proxy->priv->server_address);
-
- out:
-
- return ret;
-}
-
static gboolean
gdm_greeter_proxy_spawn (GdmGreeterProxy *greeter_proxy)
{
@@ -817,8 +347,6 @@ gdm_greeter_proxy_spawn (GdmGreeterProxy *greeter_proxy)
goto out;
}
- create_dbus_server (greeter_proxy);
-
env = get_greeter_environment (greeter_proxy);
error = NULL;
@@ -862,7 +390,6 @@ gdm_greeter_proxy_spawn (GdmGreeterProxy *greeter_proxy)
*
* Starts a local X greeter_proxy. Handles retries and fatal errors properly.
*/
-
gboolean
gdm_greeter_proxy_start (GdmGreeterProxy *greeter_proxy)
{
@@ -967,6 +494,15 @@ gdm_greeter_proxy_stop (GdmGreeterProxy *greeter_proxy)
return TRUE;
}
+void
+gdm_greeter_proxy_set_server_address (GdmGreeterProxy *greeter_proxy,
+ const char *address)
+{
+ g_return_if_fail (GDM_IS_GREETER_PROXY (greeter_proxy));
+
+ g_free (greeter_proxy->priv->server_address);
+ greeter_proxy->priv->server_address = g_strdup (address);
+}
static void
_gdm_greeter_proxy_set_x11_display_name (GdmGreeterProxy *greeter_proxy,
@@ -1023,6 +559,9 @@ gdm_greeter_proxy_set_property (GObject *object,
case PROP_GROUP_NAME:
_gdm_greeter_proxy_set_group_name (self, g_value_get_string (value));
break;
+ case PROP_SERVER_ADDRESS:
+ gdm_greeter_proxy_set_server_address (self, g_value_get_string (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1052,6 +591,9 @@ gdm_greeter_proxy_get_property (GObject *object,
case PROP_GROUP_NAME:
g_value_set_string (value, self->priv->group_name);
break;
+ case PROP_SERVER_ADDRESS:
+ g_value_set_string (value, self->priv->server_address);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1115,39 +657,13 @@ gdm_greeter_proxy_class_init (GdmGreeterProxyClass *klass)
"group name",
"gdm",
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
- signals [QUERY_ANSWER] =
- g_signal_new ("query-answer",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (GdmGreeterProxyClass, query_answer),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
- signals [SESSION_SELECTED] =
- g_signal_new ("session-selected",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (GdmGreeterProxyClass, session_selected),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
- signals [LANGUAGE_SELECTED] =
- g_signal_new ("language-selected",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (GdmGreeterProxyClass, language_selected),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
+ g_object_class_install_property (object_class,
+ PROP_SERVER_ADDRESS,
+ g_param_spec_string ("server-address",
+ "server address",
+ "server address",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
signals [STARTED] =
g_signal_new ("started",
G_OBJECT_CLASS_TYPE (object_class),
diff --git a/daemon/gdm-greeter-proxy.h b/daemon/gdm-greeter-proxy.h
index 6e8eb28f..fcb8e8bd 100644
--- a/daemon/gdm-greeter-proxy.h
+++ b/daemon/gdm-greeter-proxy.h
@@ -45,30 +45,16 @@ typedef struct
{
GObjectClass parent_class;
- void (* query_answer) (GdmGreeterProxy *greeter_proxy,
- const char *text);
- void (* session_selected) (GdmGreeterProxy *greeter_proxy,
- const char *name);
- void (* language_selected) (GdmGreeterProxy *greeter_proxy,
- const char *name);
void (* started) (GdmGreeterProxy *greeter_proxy);
void (* stopped) (GdmGreeterProxy *greeter_proxy);
} GdmGreeterProxyClass;
-GType gdm_greeter_proxy_get_type (void);
-GdmGreeterProxy * gdm_greeter_proxy_new (const char *display_id);
-gboolean gdm_greeter_proxy_start (GdmGreeterProxy *greeter_proxy);
-gboolean gdm_greeter_proxy_stop (GdmGreeterProxy *greeter_proxy);
-
-
-gboolean gdm_greeter_proxy_info_query (GdmGreeterProxy *greeter_proxy,
- const char *text);
-gboolean gdm_greeter_proxy_secret_info_query (GdmGreeterProxy *greeter_proxy,
- const char *text);
-gboolean gdm_greeter_proxy_info (GdmGreeterProxy *greeter_proxy,
- const char *text);
-gboolean gdm_greeter_proxy_problem (GdmGreeterProxy *greeter_proxy,
- const char *text);
+GType gdm_greeter_proxy_get_type (void);
+GdmGreeterProxy * gdm_greeter_proxy_new (const char *display_id);
+void gdm_greeter_proxy_set_server_address (GdmGreeterProxy *greeter_proxy,
+ const char *server_address);
+gboolean gdm_greeter_proxy_start (GdmGreeterProxy *greeter_proxy);
+gboolean gdm_greeter_proxy_stop (GdmGreeterProxy *greeter_proxy);
G_END_DECLS
diff --git a/daemon/gdm-greeter-server.c b/daemon/gdm-greeter-server.c
new file mode 100644
index 00000000..99bd1baf
--- /dev/null
+++ b/daemon/gdm-greeter-server.c
@@ -0,0 +1,822 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
+ *
+ * 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 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <grp.h>
+
+#if defined (_POSIX_PRIORITY_SCHEDULING) && defined (HAVE_SCHED_YIELD)
+#include <sched.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include <X11/Xlib.h> /* for Display */
+
+#include "gdm-common.h"
+#include "filecheck.h"
+
+#include "gdm-greeter-server.h"
+
+#define GDM_GREETER_SERVER_DBUS_PATH "/org/gnome/DisplayManager/GreeterServer"
+#define GDM_GREETER_SERVER_DBUS_INTERFACE "org.gnome.DisplayManager.GreeterServer"
+
+extern char **environ;
+
+#define GDM_GREETER_SERVER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_GREETER_SERVER, GdmGreeterServerPrivate))
+
+struct GdmGreeterServerPrivate
+{
+ char *user_name;
+ char *group_name;
+
+ char *x11_display_name;
+ char *x11_authority_file;
+
+ gboolean interrupted;
+ gboolean always_restart_greeter;
+
+ DBusServer *server;
+ char *server_address;
+ DBusConnection *greeter_connection;
+};
+
+enum {
+ PROP_0,
+ PROP_X11_DISPLAY_NAME,
+ PROP_X11_AUTHORITY_FILE,
+ PROP_USER_NAME,
+ PROP_GROUP_NAME,
+};
+
+enum {
+ QUERY_ANSWER,
+ SESSION_SELECTED,
+ LANGUAGE_SELECTED,
+ CONNECTED,
+ DISCONNECTED,
+ LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0, };
+
+static void gdm_greeter_server_class_init (GdmGreeterServerClass *klass);
+static void gdm_greeter_server_init (GdmGreeterServer *greeter_server);
+static void gdm_greeter_server_finalize (GObject *object);
+
+G_DEFINE_TYPE (GdmGreeterServer, gdm_greeter_server, G_TYPE_OBJECT)
+
+static gboolean
+send_dbus_message (DBusConnection *connection,
+ DBusMessage *message)
+{
+ gboolean is_connected;
+ gboolean sent;
+
+ g_return_val_if_fail (message != NULL, FALSE);
+
+ if (connection == NULL) {
+ g_debug ("There is no valid connection");
+ return FALSE;
+ }
+
+ is_connected = dbus_connection_get_is_connected (connection);
+ if (! is_connected) {
+ g_warning ("Not connected!");
+ return FALSE;
+ }
+
+ sent = dbus_connection_send (connection, message, NULL);
+
+ return sent;
+}
+
+static void
+send_dbus_string_signal (GdmGreeterServer *greeter_server,
+ const char *name,
+ const char *text)
+{
+ DBusMessage *message;
+ DBusMessageIter iter;
+
+ g_return_if_fail (greeter_server != NULL);
+
+ message = dbus_message_new_signal (GDM_GREETER_SERVER_DBUS_PATH,
+ GDM_GREETER_SERVER_DBUS_INTERFACE,
+ name);
+
+ dbus_message_iter_init_append (message, &iter);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &text);
+
+ if (! send_dbus_message (greeter_server->priv->greeter_connection, message)) {
+ g_debug ("Could not send %s signal", name);
+ }
+
+ dbus_message_unref (message);
+}
+
+gboolean
+gdm_greeter_server_info_query (GdmGreeterServer *greeter_server,
+ const char *text)
+{
+ send_dbus_string_signal (greeter_server, "InfoQuery", text);
+
+ return TRUE;
+}
+
+gboolean
+gdm_greeter_server_secret_info_query (GdmGreeterServer *greeter_server,
+ const char *text)
+{
+ send_dbus_string_signal (greeter_server, "SecretInfoQuery", text);
+ return TRUE;
+}
+
+gboolean
+gdm_greeter_server_info (GdmGreeterServer *greeter_server,
+ const char *text)
+{
+ send_dbus_string_signal (greeter_server, "Info", text);
+ return TRUE;
+}
+
+gboolean
+gdm_greeter_server_problem (GdmGreeterServer *greeter_server,
+ const char *text)
+{
+ send_dbus_string_signal (greeter_server, "Problem", text);
+ return TRUE;
+}
+
+/* Note: Use abstract sockets like dbus does by default on Linux. Abstract
+ * sockets are only available on Linux.
+ */
+static char *
+generate_address (void)
+{
+ char *path;
+#if defined (__linux__)
+ int i;
+ char tmp[9];
+
+ for (i = 0; i < 8; i++) {
+ if (g_random_int_range (0, 2) == 0) {
+ tmp[i] = g_random_int_range ('a', 'z' + 1);
+ } else {
+ tmp[i] = g_random_int_range ('A', 'Z' + 1);
+ }
+ }
+ tmp[8] = '\0';
+
+ path = g_strdup_printf ("unix:abstract=/tmp/gdm-greeter-%s", tmp);
+#else
+ path = g_strdup ("unix:tmpdir=/tmp/gdm-greeter");
+#endif
+
+ return path;
+}
+
+static DBusHandlerResult
+handle_answer_query (GdmGreeterServer *greeter_server,
+ DBusConnection *connection,
+ DBusMessage *message)
+{
+ DBusMessage *reply;
+ DBusError error;
+ const char *text;
+
+ dbus_error_init (&error);
+ if (! dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &text,
+ DBUS_TYPE_INVALID)) {
+ g_warning ("ERROR: %s", error.message);
+ }
+
+ g_debug ("AnswerQuery: %s", text);
+
+ reply = dbus_message_new_method_return (message);
+ dbus_connection_send (connection, reply, NULL);
+ dbus_message_unref (reply);
+
+ g_signal_emit (greeter_server, signals [QUERY_ANSWER], 0, text);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+handle_select_session (GdmGreeterServer *greeter_server,
+ DBusConnection *connection,
+ DBusMessage *message)
+{
+ DBusMessage *reply;
+ DBusError error;
+ const char *text;
+
+ dbus_error_init (&error);
+ if (! dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &text,
+ DBUS_TYPE_INVALID)) {
+ g_warning ("ERROR: %s", error.message);
+ }
+
+ g_debug ("SelectSession: %s", text);
+
+ reply = dbus_message_new_method_return (message);
+ dbus_connection_send (connection, reply, NULL);
+ dbus_message_unref (reply);
+
+ g_signal_emit (greeter_server, signals [SESSION_SELECTED], 0, text);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+handle_select_language (GdmGreeterServer *greeter_server,
+ DBusConnection *connection,
+ DBusMessage *message)
+{
+ DBusMessage *reply;
+ DBusError error;
+ const char *text;
+
+ dbus_error_init (&error);
+ if (! dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &text,
+ DBUS_TYPE_INVALID)) {
+ g_warning ("ERROR: %s", error.message);
+ }
+
+ g_debug ("SelectLanguage: %s", text);
+
+ reply = dbus_message_new_method_return (message);
+ dbus_connection_send (connection, reply, NULL);
+ dbus_message_unref (reply);
+
+ g_signal_emit (greeter_server, signals [LANGUAGE_SELECTED], 0, text);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+greeter_handle_child_message (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ GdmGreeterServer *greeter_server = GDM_GREETER_SERVER (user_data);
+
+ if (dbus_message_is_method_call (message, GDM_GREETER_SERVER_DBUS_INTERFACE, "AnswerQuery")) {
+ return handle_answer_query (greeter_server, connection, message);
+ } else if (dbus_message_is_method_call (message, GDM_GREETER_SERVER_DBUS_INTERFACE, "SelectSession")) {
+ return handle_select_session (greeter_server, connection, message);
+ } else if (dbus_message_is_method_call (message, GDM_GREETER_SERVER_DBUS_INTERFACE, "SelectSession")) {
+ return handle_select_language (greeter_server, connection, message);
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusHandlerResult
+do_introspect (DBusConnection *connection,
+ DBusMessage *message)
+{
+ DBusMessage *reply;
+ GString *xml;
+ char *xml_string;
+
+ g_debug ("Do introspect");
+
+ /* standard header */
+ xml = g_string_new ("<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
+ "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
+ "<node>\n"
+ " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
+ " <method name=\"Introspect\">\n"
+ " <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"
+ " </method>\n"
+ " </interface>\n");
+
+ /* interface */
+ xml = g_string_append (xml,
+ " <interface name=\"org.gnome.DisplayManager.GreeterServer\">\n"
+ " <method name=\"AnswerQuery\">\n"
+ " <arg name=\"text\" direction=\"in\" type=\"s\"/>\n"
+ " </method>\n"
+ " <method name=\"SelectSession\">\n"
+ " <arg name=\"text\" direction=\"in\" type=\"s\"/>\n"
+ " </method>\n"
+ " <method name=\"SelectLanguage\">\n"
+ " <arg name=\"text\" direction=\"in\" type=\"s\"/>\n"
+ " </method>\n"
+ " <signal name=\"Info\">\n"
+ " <arg name=\"text\" type=\"s\"/>\n"
+ " </signal>\n"
+ " <signal name=\"Problem\">\n"
+ " <arg name=\"text\" type=\"s\"/>\n"
+ " </signal>\n"
+ " <signal name=\"InfoQuery\">\n"
+ " <arg name=\"text\" type=\"s\"/>\n"
+ " </signal>\n"
+ " <signal name=\"SecretInfoQuery\">\n"
+ " <arg name=\"text\" type=\"s\"/>\n"
+ " </signal>\n"
+ " </interface>\n");
+
+ reply = dbus_message_new_method_return (message);
+
+ xml = g_string_append (xml, "</node>\n");
+ xml_string = g_string_free (xml, FALSE);
+
+ dbus_message_append_args (reply,
+ DBUS_TYPE_STRING, &xml_string,
+ DBUS_TYPE_INVALID);
+
+ g_free (xml_string);
+
+ if (reply == NULL) {
+ g_error ("No memory");
+ }
+
+ if (! dbus_connection_send (connection, reply, NULL)) {
+ g_error ("No memory");
+ }
+
+ dbus_message_unref (reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+greeter_server_message_handler (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ g_debug ("greeter_server_message_handler: destination=%s obj_path=%s interface=%s method=%s",
+ dbus_message_get_destination (message),
+ dbus_message_get_path (message),
+ dbus_message_get_interface (message),
+ dbus_message_get_member (message));
+
+
+ if (dbus_message_is_method_call (message, "org.freedesktop.DBus", "AddMatch")) {
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return (message);
+
+ if (reply == NULL) {
+ g_error ("No memory");
+ }
+
+ if (! dbus_connection_send (connection, reply, NULL)) {
+ g_error ("No memory");
+ }
+
+ dbus_message_unref (reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected") &&
+ strcmp (dbus_message_get_path (message), DBUS_PATH_LOCAL) == 0) {
+
+ /*dbus_connection_unref (connection);*/
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_method_call (message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
+ return do_introspect (connection, message);
+ } else {
+ return greeter_handle_child_message (connection, message, user_data);
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static void
+greeter_server_unregister_handler (DBusConnection *connection,
+ void *user_data)
+{
+ g_debug ("greeter_server_unregister_handler");
+}
+
+static DBusHandlerResult
+connection_filter_function (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ GdmGreeterServer *greeter_server = GDM_GREETER_SERVER (user_data);
+ const char *path;
+
+ path = dbus_message_get_path (message);
+
+ g_debug ("obj_path=%s interface=%s method=%s",
+ dbus_message_get_path (message),
+ dbus_message_get_interface (message),
+ dbus_message_get_member (message));
+
+ if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected")
+ && strcmp (path, DBUS_PATH_LOCAL) == 0) {
+
+ g_debug ("Disconnected");
+
+ dbus_connection_unref (connection);
+ greeter_server->priv->greeter_connection = NULL;
+ } else if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
+
+
+ } else {
+ return greeter_server_message_handler (connection, message, user_data);
+ }
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static dbus_bool_t
+allow_user_function (DBusConnection *connection,
+ unsigned long uid,
+ void *data)
+{
+ GdmGreeterServer *greeter_server = GDM_GREETER_SERVER (data);
+ struct passwd *pwent;
+
+ if (greeter_server->priv->user_name == NULL) {
+ return FALSE;
+ }
+
+ pwent = getpwnam (greeter_server->priv->user_name);
+ if (pwent == NULL) {
+ return FALSE;
+ }
+
+ if (pwent->pw_uid == uid) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+handle_connection (DBusServer *server,
+ DBusConnection *new_connection,
+ void *user_data)
+{
+ GdmGreeterServer *greeter_server = GDM_GREETER_SERVER (user_data);
+
+ g_debug ("Handing new connection");
+
+ if (greeter_server->priv->greeter_connection == NULL) {
+ DBusObjectPathVTable vtable = { &greeter_server_unregister_handler,
+ &greeter_server_message_handler,
+ NULL, NULL, NULL, NULL
+ };
+
+ greeter_server->priv->greeter_connection = new_connection;
+ dbus_connection_ref (new_connection);
+ dbus_connection_setup_with_g_main (new_connection, NULL);
+
+ g_debug ("greeter connection is %p", new_connection);
+
+ dbus_connection_add_filter (new_connection,
+ connection_filter_function,
+ greeter_server,
+ NULL);
+
+ dbus_connection_set_unix_user_function (new_connection,
+ allow_user_function,
+ greeter_server,
+ NULL);
+
+ dbus_connection_register_object_path (new_connection,
+ GDM_GREETER_SERVER_DBUS_PATH,
+ &vtable,
+ greeter_server);
+
+ g_signal_emit (greeter_server, signals[CONNECTED], 0);
+
+ }
+}
+
+gboolean
+gdm_greeter_server_start (GdmGreeterServer *greeter_server)
+{
+ DBusError error;
+ gboolean ret;
+ char *address;
+ const char *auth_mechanisms[] = {"EXTERNAL", NULL};
+
+ ret = FALSE;
+
+ g_debug ("Creating D-Bus server for greeter");
+
+ address = generate_address ();
+
+ dbus_error_init (&error);
+ greeter_server->priv->server = dbus_server_listen (address, &error);
+ g_free (address);
+
+ if (greeter_server->priv->server == NULL) {
+ g_warning ("Cannot create D-BUS server for the greeter: %s", error.message);
+ goto out;
+ }
+
+ dbus_server_setup_with_g_main (greeter_server->priv->server, NULL);
+ dbus_server_set_auth_mechanisms (greeter_server->priv->server, auth_mechanisms);
+ dbus_server_set_new_connection_function (greeter_server->priv->server,
+ handle_connection,
+ greeter_server,
+ NULL);
+ ret = TRUE;
+
+ g_free (greeter_server->priv->server_address);
+ greeter_server->priv->server_address = dbus_server_get_address (greeter_server->priv->server);
+
+ g_debug ("D-Bus server listening on %s", greeter_server->priv->server_address);
+
+ out:
+
+ return ret;
+}
+
+gboolean
+gdm_greeter_server_stop (GdmGreeterServer *greeter_server)
+{
+ gboolean ret;
+
+ ret = FALSE;
+
+ g_debug ("Stopping greeter server...");
+
+ return ret;
+}
+
+char *
+gdm_greeter_server_get_address (GdmGreeterServer *greeter_server)
+{
+ return g_strdup (greeter_server->priv->server_address);
+}
+
+static void
+_gdm_greeter_server_set_x11_display_name (GdmGreeterServer *greeter_server,
+ const char *name)
+{
+ g_free (greeter_server->priv->x11_display_name);
+ greeter_server->priv->x11_display_name = g_strdup (name);
+}
+
+static void
+_gdm_greeter_server_set_x11_authority_file (GdmGreeterServer *greeter_server,
+ const char *file)
+{
+ g_free (greeter_server->priv->x11_authority_file);
+ greeter_server->priv->x11_authority_file = g_strdup (file);
+}
+
+static void
+_gdm_greeter_server_set_user_name (GdmGreeterServer *greeter_server,
+ const char *name)
+{
+ g_free (greeter_server->priv->user_name);
+ greeter_server->priv->user_name = g_strdup (name);
+}
+
+static void
+_gdm_greeter_server_set_group_name (GdmGreeterServer *greeter_server,
+ const char *name)
+{
+ g_free (greeter_server->priv->group_name);
+ greeter_server->priv->group_name = g_strdup (name);
+}
+
+static void
+gdm_greeter_server_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdmGreeterServer *self;
+
+ self = GDM_GREETER_SERVER (object);
+
+ switch (prop_id) {
+ case PROP_X11_DISPLAY_NAME:
+ _gdm_greeter_server_set_x11_display_name (self, g_value_get_string (value));
+ break;
+ case PROP_X11_AUTHORITY_FILE:
+ _gdm_greeter_server_set_x11_authority_file (self, g_value_get_string (value));
+ break;
+ case PROP_USER_NAME:
+ _gdm_greeter_server_set_user_name (self, g_value_get_string (value));
+ break;
+ case PROP_GROUP_NAME:
+ _gdm_greeter_server_set_group_name (self, g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdm_greeter_server_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdmGreeterServer *self;
+
+ self = GDM_GREETER_SERVER (object);
+
+ switch (prop_id) {
+ case PROP_X11_DISPLAY_NAME:
+ g_value_set_string (value, self->priv->x11_display_name);
+ break;
+ case PROP_X11_AUTHORITY_FILE:
+ g_value_set_string (value, self->priv->x11_authority_file);
+ break;
+ case PROP_USER_NAME:
+ g_value_set_string (value, self->priv->user_name);
+ break;
+ case PROP_GROUP_NAME:
+ g_value_set_string (value, self->priv->group_name);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GObject *
+gdm_greeter_server_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GdmGreeterServer *greeter_server;
+ GdmGreeterServerClass *klass;
+
+ klass = GDM_GREETER_SERVER_CLASS (g_type_class_peek (GDM_TYPE_GREETER_SERVER));
+
+ greeter_server = GDM_GREETER_SERVER (G_OBJECT_CLASS (gdm_greeter_server_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+
+ return G_OBJECT (greeter_server);
+}
+
+static void
+gdm_greeter_server_class_init (GdmGreeterServerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->get_property = gdm_greeter_server_get_property;
+ object_class->set_property = gdm_greeter_server_set_property;
+ object_class->constructor = gdm_greeter_server_constructor;
+ object_class->finalize = gdm_greeter_server_finalize;
+
+ g_type_class_add_private (klass, sizeof (GdmGreeterServerPrivate));
+
+ g_object_class_install_property (object_class,
+ PROP_X11_DISPLAY_NAME,
+ g_param_spec_string ("x11-display-name",
+ "name",
+ "name",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_X11_AUTHORITY_FILE,
+ g_param_spec_string ("x11-authority-file",
+ "authority file",
+ "authority file",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_USER_NAME,
+ g_param_spec_string ("user-name",
+ "user name",
+ "user name",
+ "gdm",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_GROUP_NAME,
+ g_param_spec_string ("group-name",
+ "group name",
+ "group name",
+ "gdm",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ signals [QUERY_ANSWER] =
+ g_signal_new ("query-answer",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmGreeterServerClass, query_answer),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+ signals [SESSION_SELECTED] =
+ g_signal_new ("session-selected",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmGreeterServerClass, session_selected),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+ signals [LANGUAGE_SELECTED] =
+ g_signal_new ("language-selected",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmGreeterServerClass, language_selected),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+ signals [CONNECTED] =
+ g_signal_new ("connected",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmGreeterServerClass, connected),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+ signals [DISCONNECTED] =
+ g_signal_new ("disconnected",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmGreeterServerClass, disconnected),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+static void
+gdm_greeter_server_init (GdmGreeterServer *greeter_server)
+{
+
+ greeter_server->priv = GDM_GREETER_SERVER_GET_PRIVATE (greeter_server);
+}
+
+static void
+gdm_greeter_server_finalize (GObject *object)
+{
+ GdmGreeterServer *greeter_server;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDM_IS_GREETER_SERVER (object));
+
+ greeter_server = GDM_GREETER_SERVER (object);
+
+ g_return_if_fail (greeter_server->priv != NULL);
+
+ gdm_greeter_server_stop (greeter_server);
+
+ G_OBJECT_CLASS (gdm_greeter_server_parent_class)->finalize (object);
+}
+
+GdmGreeterServer *
+gdm_greeter_server_new (const char *display_name)
+{
+ GObject *object;
+
+ object = g_object_new (GDM_TYPE_GREETER_SERVER,
+ "x11-display-name", display_name,
+ NULL);
+
+ return GDM_GREETER_SERVER (object);
+}
diff --git a/daemon/gdm-greeter-server.h b/daemon/gdm-greeter-server.h
new file mode 100644
index 00000000..49b2bfe2
--- /dev/null
+++ b/daemon/gdm-greeter-server.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
+ *
+ * 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 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifndef __GDM_GREETER_SERVER_H
+#define __GDM_GREETER_SERVER_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_GREETER_SERVER (gdm_greeter_server_get_type ())
+#define GDM_GREETER_SERVER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_GREETER_SERVER, GdmGreeterServer))
+#define GDM_GREETER_SERVER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_GREETER_SERVER, GdmGreeterServerClass))
+#define GDM_IS_GREETER_SERVER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_GREETER_SERVER))
+#define GDM_IS_GREETER_SERVER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_GREETER_SERVER))
+#define GDM_GREETER_SERVER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_GREETER_SERVER, GdmGreeterServerClass))
+
+typedef struct GdmGreeterServerPrivate GdmGreeterServerPrivate;
+
+typedef struct
+{
+ GObject parent;
+ GdmGreeterServerPrivate *priv;
+} GdmGreeterServer;
+
+typedef struct
+{
+ GObjectClass parent_class;
+
+ void (* query_answer) (GdmGreeterServer *greeter_server,
+ const char *text);
+ void (* session_selected) (GdmGreeterServer *greeter_server,
+ const char *name);
+ void (* language_selected) (GdmGreeterServer *greeter_server,
+ const char *name);
+ void (* connected) (GdmGreeterServer *greeter_server);
+ void (* disconnected) (GdmGreeterServer *greeter_server);
+} GdmGreeterServerClass;
+
+GType gdm_greeter_server_get_type (void);
+GdmGreeterServer * gdm_greeter_server_new (const char *display_id);
+
+gboolean gdm_greeter_server_start (GdmGreeterServer *greeter_server);
+gboolean gdm_greeter_server_stop (GdmGreeterServer *greeter_server);
+char * gdm_greeter_server_get_address (GdmGreeterServer *greeter_server);
+
+gboolean gdm_greeter_server_info_query (GdmGreeterServer *greeter_server,
+ const char *text);
+gboolean gdm_greeter_server_secret_info_query (GdmGreeterServer *greeter_server,
+ const char *text);
+gboolean gdm_greeter_server_info (GdmGreeterServer *greeter_server,
+ const char *text);
+gboolean gdm_greeter_server_problem (GdmGreeterServer *greeter_server,
+ const char *text);
+
+G_END_DECLS
+
+#endif /* __GDM_GREETER_SERVER_H */
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index ad9c21c8..1b71f54f 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -43,6 +43,7 @@
#include "gdm-common.h"
#include "gdm-static-display.h"
+#include "gdm-static-factory-display.h"
#define GDM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_MANAGER, GdmManagerPrivate))
@@ -145,7 +146,8 @@ start_local_display (const char *id,
g_assert (d != NULL);
- if (GDM_IS_STATIC_DISPLAY (d) &&
+ if ((GDM_IS_STATIC_FACTORY_DISPLAY (d) ||
+ GDM_IS_STATIC_DISPLAY (d)) &&
gdm_display_get_status (d) == GDM_DISPLAY_UNMANAGED) {
if (! gdm_display_manage (d)) {
gdm_display_unmanage (d);
@@ -223,7 +225,7 @@ load_static_displays_from_file (GdmManager *manager)
GdmDisplay *display;
/* just load one for now */
- display = gdm_static_display_new (0);
+ display = gdm_static_factory_display_new (0, manager->priv->display_store);
if (display == NULL) {
g_warning ("Unable to create display: %d", 0);
diff --git a/daemon/gdm-product-display.c b/daemon/gdm-product-display.c
index b925b0a9..65e2ff01 100644
--- a/daemon/gdm-product-display.c
+++ b/daemon/gdm-product-display.c
@@ -40,9 +40,11 @@
#define GDM_PRODUCT_DISPLAY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_PRODUCT_DISPLAY, GdmProductDisplayPrivate))
+#define DEFAULT_SLAVE_COMMAND LIBEXECDIR"/gdm-product-slave"
+
struct GdmProductDisplayPrivate
{
- gpointer dummy;
+ char *greeter_server_address;
};
enum {
@@ -55,6 +57,33 @@ static void gdm_product_display_finalize (GObject *object);
G_DEFINE_TYPE (GdmProductDisplay, gdm_product_display, GDM_TYPE_DISPLAY)
+gboolean
+gdm_product_display_get_greeter_server_address (GdmProductDisplay *display,
+ char **address,
+ GError **error)
+{
+ g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
+
+ if (address != NULL) {
+ *address = g_strdup (display->priv->greeter_server_address);
+ }
+
+ return TRUE;
+}
+
+gboolean
+gdm_product_display_set_greeter_server_address (GdmProductDisplay *display,
+ const char *address,
+ GError **error)
+{
+ g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
+
+ g_free (display->priv->greeter_server_address);
+ display->priv->greeter_server_address = g_strdup (address);
+
+ return TRUE;
+}
+
static gboolean
gdm_product_display_create_authority (GdmDisplay *display)
{
@@ -119,6 +148,26 @@ gdm_product_display_get_property (GObject *object,
}
}
+static GObject *
+gdm_product_display_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GdmProductDisplay *display;
+ GdmProductDisplayClass *klass;
+
+ klass = GDM_PRODUCT_DISPLAY_CLASS (g_type_class_peek (GDM_TYPE_PRODUCT_DISPLAY));
+
+ display = GDM_PRODUCT_DISPLAY (G_OBJECT_CLASS (gdm_product_display_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+ g_object_set (display,
+ "slave-command", DEFAULT_SLAVE_COMMAND,
+ NULL);
+
+ return G_OBJECT (display);
+}
+
static void
gdm_product_display_class_init (GdmProductDisplayClass *klass)
{
@@ -127,6 +176,7 @@ gdm_product_display_class_init (GdmProductDisplayClass *klass)
object_class->get_property = gdm_product_display_get_property;
object_class->set_property = gdm_product_display_set_property;
+ object_class->constructor = gdm_product_display_constructor;
object_class->finalize = gdm_product_display_finalize;
display_class->create_authority = gdm_product_display_create_authority;
diff --git a/daemon/gdm-product-display.h b/daemon/gdm-product-display.h
index e9e7102e..123c2ff0 100644
--- a/daemon/gdm-product-display.h
+++ b/daemon/gdm-product-display.h
@@ -49,9 +49,15 @@ typedef struct
} GdmProductDisplayClass;
-GType gdm_product_display_get_type (void);
-GdmDisplay * gdm_product_display_new (int display_number);
+GType gdm_product_display_get_type (void);
+GdmDisplay * gdm_product_display_new (int display_number);
+gboolean gdm_product_display_set_greeter_server_address (GdmProductDisplay *display,
+ const char *address,
+ GError **error);
+gboolean gdm_product_display_get_greeter_server_address (GdmProductDisplay *display,
+ char **address,
+ GError **error);
G_END_DECLS
diff --git a/daemon/gdm-product-display.xml b/daemon/gdm-product-display.xml
index 060bd47a..df8e8ba5 100644
--- a/daemon/gdm-product-display.xml
+++ b/daemon/gdm-product-display.xml
@@ -1,5 +1,11 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.gnome.DisplayManager.ProductDisplay">
+ <method name="GetGreeterServerAddress">
+ <arg name="address" direction="out" type="s"/>
+ </method>
+ <method name="SetGreeterServerAddress">
+ <arg name="address" direction="in" type="s"/>
+ </method>
</interface>
</node>
diff --git a/daemon/gdm-product-slave.c b/daemon/gdm-product-slave.c
new file mode 100644
index 00000000..85e08f85
--- /dev/null
+++ b/daemon/gdm-product-slave.c
@@ -0,0 +1,1180 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
+ *
+ * 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 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include <X11/Xlib.h> /* for Display */
+
+#include "gdm-common.h"
+
+#include "gdm-product-slave.h"
+#include "gdm-product-slave-glue.h"
+
+#include "gdm-server.h"
+#include "gdm-session.h"
+#include "gdm-greeter-server.h"
+
+extern char **environ;
+
+#define GDM_PRODUCT_SLAVE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_PRODUCT_SLAVE, GdmProductSlavePrivate))
+
+#define GDM_DBUS_NAME "org.gnome.DisplayManager"
+#define GDM_DBUS_PRODUCT_DISPLAY_INTERFACE "org.gnome.DisplayManager.ProductDisplay"
+
+#define MAX_CONNECT_ATTEMPTS 10
+
+struct GdmProductSlavePrivate
+{
+ char *id;
+ GPid pid;
+ guint output_watch_id;
+ guint error_watch_id;
+
+ GPid server_pid;
+ Display *server_display;
+ guint connection_attempts;
+
+ /* user selected */
+ char *selected_session;
+ char *selected_language;
+
+ GdmServer *server;
+ GdmGreeterServer *greeter;
+ GdmSession *session;
+ DBusGProxy *product_display_proxy;
+ DBusGConnection *connection;
+};
+
+enum {
+ PROP_0,
+ PROP_DISPLAY_ID,
+};
+
+enum {
+ SESSION_STARTED,
+ SESSION_EXITED,
+ SESSION_DIED,
+ LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0, };
+
+static void gdm_product_slave_class_init (GdmProductSlaveClass *klass);
+static void gdm_product_slave_init (GdmProductSlave *product_slave);
+static void gdm_product_slave_finalize (GObject *object);
+
+G_DEFINE_TYPE (GdmProductSlave, gdm_product_slave, GDM_TYPE_SLAVE)
+
+static void
+set_busy_cursor (GdmProductSlave *product_slave)
+{
+ if (product_slave->priv->server_display != NULL) {
+ Cursor xcursor;
+
+ xcursor = XCreateFontCursor (product_slave->priv->server_display, GDK_WATCH);
+ XDefineCursor (product_slave->priv->server_display,
+ DefaultRootWindow (product_slave->priv->server_display),
+ xcursor);
+ XFreeCursor (product_slave->priv->server_display, xcursor);
+ XSync (product_slave->priv->server_display, False);
+ }
+}
+
+static void
+gdm_product_slave_whack_temp_auth_file (GdmProductSlave *product_slave)
+{
+#if 0
+ uid_t old;
+
+ old = geteuid ();
+ if (old != 0)
+ seteuid (0);
+ if (d->parent_temp_auth_file != NULL) {
+ VE_IGNORE_EINTR (g_unlink (d->parent_temp_auth_file));
+ }
+ g_free (d->parent_temp_auth_file);
+ d->parent_temp_auth_file = NULL;
+ if (old != 0)
+ seteuid (old);
+#endif
+}
+
+
+static void
+create_temp_auth_file (GdmProductSlave *product_slave)
+{
+#if 0
+ if (d->type == TYPE_FLEXI_XNEST &&
+ d->parent_auth_file != NULL) {
+ if (d->parent_temp_auth_file != NULL) {
+ VE_IGNORE_EINTR (g_unlink (d->parent_temp_auth_file));
+ }
+ g_free (d->parent_temp_auth_file);
+ d->parent_temp_auth_file =
+ copy_auth_file (d->server_uid,
+ gdm_daemon_config_get_gdmuid (),
+ d->parent_auth_file);
+ }
+#endif
+}
+
+static void
+listify_hash (const char *key,
+ const char *value,
+ GPtrArray *env)
+{
+ char *str;
+ str = g_strdup_printf ("%s=%s", key, value);
+ g_debug ("environment: %s", str);
+ g_ptr_array_add (env, str);
+}
+
+static GPtrArray *
+get_script_environment (GdmProductSlave *slave,
+ const char *username)
+{
+ GPtrArray *env;
+ GHashTable *hash;
+ struct passwd *pwent;
+ char *x_servers_file;
+ char *display_name;
+ char *display_hostname;
+ char *display_x11_authority_file;
+ gboolean display_is_local;
+
+ g_object_get (slave,
+ "display-name", &display_name,
+ "display-hostname", &display_hostname,
+ "display-is-local", &display_is_local,
+ "display-x11-authority-file", &display_x11_authority_file,
+ NULL);
+
+ env = g_ptr_array_new ();
+
+ /* create a hash table of current environment, then update keys has necessary */
+ hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+ /* modify environment here */
+ g_hash_table_insert (hash, g_strdup ("HOME"), g_strdup ("/"));
+ g_hash_table_insert (hash, g_strdup ("PWD"), g_strdup ("/"));
+ g_hash_table_insert (hash, g_strdup ("SHELL"), g_strdup ("/bin/sh"));
+
+ g_hash_table_insert (hash, g_strdup ("LOGNAME"), g_strdup (username));
+ g_hash_table_insert (hash, g_strdup ("USER"), g_strdup (username));
+ g_hash_table_insert (hash, g_strdup ("USERNAME"), g_strdup (username));
+
+ pwent = getpwnam (username);
+ if (pwent != NULL) {
+ if (pwent->pw_dir != NULL && pwent->pw_dir[0] != '\0') {
+ g_hash_table_insert (hash, g_strdup ("HOME"), g_strdup (pwent->pw_dir));
+ g_hash_table_insert (hash, g_strdup ("PWD"), g_strdup (pwent->pw_dir));
+ }
+
+ g_hash_table_insert (hash, g_strdup ("SHELL"), g_strdup (pwent->pw_shell));
+ }
+
+#if 0
+ if (display_is_parented) {
+ g_hash_table_insert (hash, g_strdup ("GDM_PARENT_DISPLAY"), g_strdup (parent_display_name));
+
+ /*g_hash_table_insert (hash, "GDM_PARENT_XAUTHORITY"), slave->priv->parent_temp_auth_file));*/
+ }
+#endif
+
+ /* some env for use with the Pre and Post scripts */
+ x_servers_file = gdm_make_filename (AUTHDIR,
+ display_name,
+ ".Xservers");
+ g_hash_table_insert (hash, g_strdup ("X_SERVERS"), x_servers_file);
+
+ if (! display_is_local) {
+ g_hash_table_insert (hash, g_strdup ("REMOTE_HOST"), g_strdup (display_hostname));
+ }
+
+ /* Runs as root */
+ g_hash_table_insert (hash, g_strdup ("XAUTHORITY"), g_strdup (display_x11_authority_file));
+ g_hash_table_insert (hash, g_strdup ("DISPLAY"), g_strdup (display_name));
+
+ /*g_setenv ("PATH", gdm_daemon_config_get_value_string (GDM_KEY_ROOT_PATH), TRUE);*/
+
+ g_hash_table_insert (hash, g_strdup ("RUNNING_UNDER_GDM"), g_strdup ("true"));
+
+#if 0
+ if ( ! ve_string_empty (d->theme_name))
+ g_setenv ("GDM_GTK_THEME", d->theme_name, TRUE);
+#endif
+ g_hash_table_remove (hash, "MAIL");
+
+
+ g_hash_table_foreach (hash, (GHFunc)listify_hash, env);
+ g_hash_table_destroy (hash);
+
+ g_ptr_array_add (env, NULL);
+
+ g_free (display_name);
+ g_free (display_hostname);
+ g_free (display_x11_authority_file);
+
+ return env;
+}
+
+static gboolean
+gdm_product_slave_exec_script (GdmProductSlave *slave,
+ const char *dir,
+ const char *login)
+{
+ char *script;
+ char **argv;
+ gint status;
+ GError *error;
+ GPtrArray *env;
+ gboolean res;
+ gboolean ret;
+ char *display_name;
+ char *display_hostname;
+
+ g_assert (dir != NULL);
+ g_assert (login != NULL);
+
+ g_object_get (slave,
+ "display-name", &display_name,
+ "display-hostname", &display_hostname,
+ NULL);
+
+ script = g_build_filename (dir, display_name, NULL);
+ if (g_access (script, R_OK|X_OK) != 0) {
+ g_free (script);
+ script = NULL;
+ }
+
+ if (script == NULL &&
+ display_hostname != NULL) {
+ script = g_build_filename (dir, display_hostname, NULL);
+ if (g_access (script, R_OK|X_OK) != 0) {
+ g_free (script);
+ script = NULL;
+ }
+ }
+
+#if 0
+ if (script == NULL &&
+ SERVER_IS_XDMCP (d)) {
+ script = g_build_filename (dir, "XDMCP", NULL);
+ if (g_access (script, R_OK|X_OK) != 0) {
+ g_free (script);
+ script = NULL;
+ }
+ }
+ if (script == NULL &&
+ SERVER_IS_FLEXI (d)) {
+ script = g_build_filename (dir, "Flexi", NULL);
+ if (g_access (script, R_OK|X_OK) != 0) {
+ g_free (script);
+ script = NULL;
+ }
+ }
+#endif
+
+ if (script == NULL) {
+ script = g_build_filename (dir, "Default", NULL);
+ if (g_access (script, R_OK|X_OK) != 0) {
+ g_free (script);
+ script = NULL;
+ }
+ }
+
+ if (script == NULL) {
+ return TRUE;
+ }
+
+ create_temp_auth_file (slave);
+
+ g_debug ("Running process: %s", script);
+ error = NULL;
+ if (! g_shell_parse_argv (script, NULL, &argv, &error)) {
+ g_warning ("Could not parse command: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ env = get_script_environment (slave, login);
+
+ res = g_spawn_sync (NULL,
+ argv,
+ (char **)env->pdata,
+ G_SPAWN_SEARCH_PATH,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &status,
+ &error);
+
+ g_ptr_array_foreach (env, (GFunc)g_free, NULL);
+ g_ptr_array_free (env, TRUE);
+
+ gdm_product_slave_whack_temp_auth_file (slave);
+
+ if (WIFEXITED (status)) {
+ g_debug ("Process exit status: %d", WEXITSTATUS (status));
+ ret = WEXITSTATUS (status) != 0;
+ } else {
+ ret = TRUE;
+ }
+
+ out:
+ g_free (script);
+ g_free (display_name);
+ g_free (display_hostname);
+
+ return ret;
+}
+
+static void
+on_session_started (GdmSession *session,
+ GPid pid,
+ GdmProductSlave *slave)
+{
+ g_debug ("session started on pid %d\n", (int) pid);
+ g_signal_emit (slave, signals [SESSION_STARTED], 0, pid);
+}
+
+static void
+on_session_exited (GdmSession *session,
+ int exit_code,
+ GdmProductSlave *slave)
+{
+ g_debug ("session exited with code %d\n", exit_code);
+ g_signal_emit (slave, signals [SESSION_EXITED], 0, exit_code);
+}
+
+static void
+on_session_died (GdmSession *session,
+ int signal_number,
+ GdmProductSlave *slave)
+{
+ g_debug ("session died with signal %d, (%s)",
+ signal_number,
+ g_strsignal (signal_number));
+ g_signal_emit (slave, signals [SESSION_DIED], 0, signal_number);
+}
+
+static gboolean
+is_prog_in_path (const char *prog)
+{
+ char *f;
+ gboolean ret;
+
+ f = g_find_program_in_path (prog);
+ ret = (f != NULL);
+ g_free (f);
+ return ret;
+}
+
+static gboolean
+get_session_command (const char *file,
+ char **command)
+{
+ GKeyFile *key_file;
+ GError *error;
+ char *full_path;
+ char *exec;
+ gboolean ret;
+ gboolean res;
+ const char *search_dirs[] = {
+ "/etc/X11/sessions/",
+ DMCONFDIR "/Sessions/",
+ DATADIR "/gdm/BuiltInSessions/",
+ DATADIR "/xsessions/",
+ NULL
+ };
+
+ exec = NULL;
+ ret = FALSE;
+ if (command != NULL) {
+ *command = NULL;
+ }
+
+ key_file = g_key_file_new ();
+
+ error = NULL;
+ full_path = NULL;
+ res = g_key_file_load_from_dirs (key_file,
+ file,
+ search_dirs,
+ &full_path,
+ G_KEY_FILE_NONE,
+ &error);
+ if (! res) {
+ g_debug ("File '%s' not found: %s", file, error->message);
+ g_error_free (error);
+ if (command != NULL) {
+ *command = NULL;
+ }
+ goto out;
+ }
+
+ error = NULL;
+ res = g_key_file_get_boolean (key_file,
+ G_KEY_FILE_DESKTOP_GROUP,
+ G_KEY_FILE_DESKTOP_KEY_HIDDEN,
+ &error);
+ if (error == NULL && res) {
+ g_debug ("Session %s is marked as hidden", file);
+ goto out;
+ }
+
+ error = NULL;
+ exec = g_key_file_get_string (key_file,
+ G_KEY_FILE_DESKTOP_GROUP,
+ G_KEY_FILE_DESKTOP_KEY_TRY_EXEC,
+ &error);
+ if (exec == NULL) {
+ g_debug ("%s key not found", G_KEY_FILE_DESKTOP_KEY_TRY_EXEC);
+ goto out;
+ }
+
+ res = is_prog_in_path (exec);
+ g_free (exec);
+
+ if (! res) {
+ g_debug ("Command not found: %s", G_KEY_FILE_DESKTOP_KEY_TRY_EXEC);
+ goto out;
+ }
+
+ error = NULL;
+ exec = g_key_file_get_string (key_file,
+ G_KEY_FILE_DESKTOP_GROUP,
+ G_KEY_FILE_DESKTOP_KEY_EXEC,
+ &error);
+ if (error != NULL) {
+ g_debug ("%s key not found: %s",
+ G_KEY_FILE_DESKTOP_KEY_EXEC,
+ error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ if (command != NULL) {
+ *command = g_strdup (exec);
+ }
+ ret = TRUE;
+
+out:
+ g_free (exec);
+
+ return ret;
+}
+
+static void
+setup_session_environment (GdmProductSlave *slave)
+{
+ char *display_name;
+ char *auth_file;
+
+ g_object_get (slave,
+ "display-name", &display_name,
+ "display-x11-authority-file", &auth_file,
+ NULL);
+
+ gdm_session_set_environment_variable (slave->priv->session,
+ "GDMSESSION",
+ slave->priv->selected_session);
+ gdm_session_set_environment_variable (slave->priv->session,
+ "DESKTOP_SESSION",
+ slave->priv->selected_session);
+
+ gdm_session_set_environment_variable (slave->priv->session,
+ "LANG",
+ slave->priv->selected_language);
+ gdm_session_set_environment_variable (slave->priv->session,
+ "GDM_LANG",
+ slave->priv->selected_language);
+
+ gdm_session_set_environment_variable (slave->priv->session,
+ "DISPLAY",
+ display_name);
+ gdm_session_set_environment_variable (slave->priv->session,
+ "XAUTHORITY",
+ auth_file);
+
+ gdm_session_set_environment_variable (slave->priv->session,
+ "PATH",
+ "/bin:/usr/bin:" BINDIR);
+
+ g_free (display_name);
+ g_free (auth_file);
+}
+
+static void
+on_user_verified (GdmSession *session,
+ GdmProductSlave *slave)
+{
+ char *username;
+ int argc;
+ char **argv;
+ char *command;
+ char *filename;
+ GError *error;
+ gboolean res;
+
+ gdm_greeter_server_stop (slave->priv->greeter);
+
+ username = gdm_session_get_username (session);
+
+ g_debug ("%s%ssuccessfully authenticated\n",
+ username ? username : "",
+ username ? " " : "");
+ g_free (username);
+
+ if (slave->priv->selected_session != NULL) {
+ filename = g_strdup (slave->priv->selected_session);
+ } else {
+ filename = g_strdup ("gnome.desktop");
+ }
+
+ setup_session_environment (slave);
+
+ res = get_session_command (filename, &command);
+ if (! res) {
+ g_warning ("Could find session file: %s", filename);
+ return;
+ }
+
+ error = NULL;
+ res = g_shell_parse_argv (command, &argc, &argv, &error);
+ if (! res) {
+ g_warning ("Could not parse command: %s", error->message);
+ g_error_free (error);
+ }
+
+ gdm_session_start_program (session,
+ argc,
+ (const char **)argv);
+
+ g_free (filename);
+ g_free (command);
+ g_strfreev (argv);
+}
+
+static void
+on_user_verification_error (GdmSession *session,
+ GError *error,
+ GdmProductSlave *slave)
+{
+ char *username;
+
+ username = gdm_session_get_username (session);
+
+ g_debug ("%s%scould not be successfully authenticated: %s\n",
+ username ? username : "",
+ username ? " " : "",
+ error->message);
+
+ g_free (username);
+}
+
+static void
+on_info (GdmSession *session,
+ const char *text,
+ GdmProductSlave *slave)
+{
+ g_debug ("Info: %s", text);
+ gdm_greeter_server_info (slave->priv->greeter, text);
+}
+
+static void
+on_problem (GdmSession *session,
+ const char *text,
+ GdmProductSlave *slave)
+{
+ g_debug ("Problem: %s", text);
+ gdm_greeter_server_problem (slave->priv->greeter, text);
+}
+
+static void
+on_info_query (GdmSession *session,
+ const char *text,
+ GdmProductSlave *slave)
+{
+
+ g_debug ("Info query: %s", text);
+ gdm_greeter_server_info_query (slave->priv->greeter, text);
+}
+
+static void
+on_secret_info_query (GdmSession *session,
+ const char *text,
+ GdmProductSlave *slave)
+{
+ g_debug ("Secret info query: %s", text);
+ gdm_greeter_server_secret_info_query (slave->priv->greeter, text);
+}
+
+static void
+on_greeter_answer (GdmGreeterServer *greeter,
+ const char *text,
+ GdmProductSlave *slave)
+{
+ gdm_session_answer_query (slave->priv->session, text);
+}
+
+static void
+on_greeter_session_selected (GdmGreeterServer *greeter,
+ const char *text,
+ GdmProductSlave *slave)
+{
+ g_free (slave->priv->selected_session);
+ slave->priv->selected_session = g_strdup (text);
+}
+
+static void
+on_greeter_language_selected (GdmGreeterServer *greeter,
+ const char *text,
+ GdmProductSlave *slave)
+{
+ g_free (slave->priv->selected_language);
+ slave->priv->selected_language = g_strdup (text);
+}
+
+static void
+on_greeter_connected (GdmGreeterServer *greeter,
+ GdmProductSlave *slave)
+{
+ gboolean display_is_local;
+
+ g_object_get (slave,
+ "display-is-local", &display_is_local,
+ NULL);
+
+ g_debug ("Greeter connected");
+
+ gdm_session_open (slave->priv->session,
+ "gdm",
+ NULL /* hostname */,
+ "/dev/console",
+ STDOUT_FILENO,
+ STDERR_FILENO,
+ NULL);
+}
+
+static void
+run_greeter (GdmProductSlave *slave)
+{
+ gboolean display_is_local;
+ char *display_name;
+ char *auth_file;
+ char *address;
+ GError *error;
+ gboolean res;
+
+ g_object_get (slave,
+ "display-is-local", &display_is_local,
+ "display-name", &display_name,
+ "display-x11-authority-file", &auth_file,
+ NULL);
+
+ /* Set the busy cursor */
+ set_busy_cursor (slave);
+
+ /* FIXME: send a signal back to the master */
+
+#if 0
+
+ /* OK from now on it's really the user whacking us most likely,
+ * we have already started up well */
+ do_xfailed_on_xio_error = FALSE;
+#endif
+
+#if 0
+ /* checkout xinerama */
+ gdm_screen_init (slave);
+#endif
+
+#ifdef HAVE_TSOL
+ /* Check out Solaris Trusted Xserver extension */
+ gdm_tsol_init (d);
+#endif
+
+ /* Run the init script. gdmslave suspends until script has terminated */
+ gdm_product_slave_exec_script (slave,
+ GDMCONFDIR"/Init",
+ "gdm");
+
+ slave->priv->session = gdm_session_new ();
+
+ g_signal_connect (slave->priv->session,
+ "info",
+ G_CALLBACK (on_info),
+ slave);
+
+ g_signal_connect (slave->priv->session,
+ "problem",
+ G_CALLBACK (on_problem),
+ slave);
+
+ g_signal_connect (slave->priv->session,
+ "info-query",
+ G_CALLBACK (on_info_query),
+ slave);
+
+ g_signal_connect (slave->priv->session,
+ "secret-info-query",
+ G_CALLBACK (on_secret_info_query),
+ slave);
+
+ g_signal_connect (slave->priv->session,
+ "user-verified",
+ G_CALLBACK (on_user_verified),
+ slave);
+
+ g_signal_connect (slave->priv->session,
+ "user-verification-error",
+ G_CALLBACK (on_user_verification_error),
+ slave);
+
+ g_signal_connect (slave->priv->session,
+ "session-started",
+ G_CALLBACK (on_session_started),
+ slave);
+ g_signal_connect (slave->priv->session,
+ "session-exited",
+ G_CALLBACK (on_session_exited),
+ slave);
+ g_signal_connect (slave->priv->session,
+ "session-died",
+ G_CALLBACK (on_session_died),
+ slave);
+
+ slave->priv->greeter = gdm_greeter_server_new (display_name);
+ g_signal_connect (slave->priv->greeter,
+ "query-answer",
+ G_CALLBACK (on_greeter_answer),
+ slave);
+ g_signal_connect (slave->priv->greeter,
+ "session-selected",
+ G_CALLBACK (on_greeter_session_selected),
+ slave);
+ g_signal_connect (slave->priv->greeter,
+ "language-selected",
+ G_CALLBACK (on_greeter_language_selected),
+ slave);
+ g_signal_connect (slave->priv->greeter,
+ "connected",
+ G_CALLBACK (on_greeter_connected),
+ slave);
+ g_object_set (slave->priv->greeter,
+ "x11-authority-file", auth_file,
+ NULL);
+ gdm_greeter_server_start (slave->priv->greeter);
+
+ address = gdm_greeter_server_get_address (slave->priv->greeter);
+ error = NULL;
+ res = dbus_g_proxy_call (GDM_PRODUCT_SLAVE (slave)->priv->product_display_proxy,
+ "SetGreeterServerAddress",
+ &error,
+ G_TYPE_STRING, address,
+ G_TYPE_INVALID,
+ G_TYPE_INVALID);
+ if (! res) {
+ if (error != NULL) {
+ g_warning ("Failed to set greeter server address: %s", error->message);
+ g_error_free (error);
+ } else {
+ g_warning ("Failed to set greeter server address");
+ }
+ }
+ g_free (address);
+
+ g_free (display_name);
+ g_free (auth_file);
+}
+
+static void
+set_local_auth (GdmProductSlave *slave)
+{
+ GString *binary_cookie;
+ GString *cookie;
+ char *display_x11_cookie;
+
+ g_object_get (slave,
+ "display-x11-cookie", &display_x11_cookie,
+ NULL);
+
+ g_debug ("Setting authorization key for display %s", display_x11_cookie);
+
+ cookie = g_string_new (display_x11_cookie);
+ binary_cookie = g_string_new (NULL);
+ if (! gdm_string_hex_decode (cookie,
+ 0,
+ NULL,
+ binary_cookie,
+ 0)) {
+ g_warning ("Unable to decode hex cookie");
+ goto out;
+ }
+
+ g_debug ("Decoded cookie len %d", binary_cookie->len);
+
+ XSetAuthorization ("MIT-MAGIC-COOKIE-1",
+ (int) strlen ("MIT-MAGIC-COOKIE-1"),
+ (char *)binary_cookie->str,
+ binary_cookie->len);
+
+ out:
+ g_string_free (binary_cookie, TRUE);
+ g_string_free (cookie, TRUE);
+ g_free (display_x11_cookie);
+}
+
+static gboolean
+connect_to_display (GdmProductSlave *slave)
+{
+ char *display_name;
+ gboolean ret;
+
+ ret = FALSE;
+
+ g_object_get (slave,
+ "display-name", &display_name,
+ NULL);
+
+ /* We keep our own (windowless) connection (dsp) open to avoid the
+ * X server resetting due to lack of active connections. */
+
+ g_debug ("Server is ready - opening display %s", display_name);
+
+ g_setenv ("DISPLAY", display_name, TRUE);
+ g_unsetenv ("XAUTHORITY"); /* just in case it's set */
+
+ set_local_auth (slave);
+
+#if 0
+ /* X error handlers to avoid the default one (i.e. exit (1)) */
+ do_xfailed_on_xio_error = TRUE;
+ XSetErrorHandler (gdm_product_slave_xerror_handler);
+ XSetIOErrorHandler (gdm_product_slave_xioerror_handler);
+#endif
+
+ gdm_sigchld_block_push ();
+ slave->priv->server_display = XOpenDisplay (display_name);
+ gdm_sigchld_block_pop ();
+
+ if (slave->priv->server_display == NULL) {
+ g_warning ("Unable to connect to display %s", display_name);
+ ret = FALSE;
+ } else {
+ g_debug ("Connected to display %s", display_name);
+ ret = TRUE;
+ }
+
+ g_free (display_name);
+
+ return ret;
+}
+
+static gboolean
+idle_connect_to_display (GdmProductSlave *slave)
+{
+ gboolean res;
+
+ slave->priv->connection_attempts++;
+
+ res = connect_to_display (slave);
+ if (res) {
+ /* FIXME: handle wait-for-go */
+
+ run_greeter (slave);
+ } else {
+ if (slave->priv->connection_attempts >= MAX_CONNECT_ATTEMPTS) {
+ g_warning ("Unable to connect to display after %d tries - bailing out", slave->priv->connection_attempts);
+ exit (1);
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+server_ready_cb (GdmServer *server,
+ GdmProductSlave *slave)
+{
+ g_timeout_add (500, (GSourceFunc)idle_connect_to_display, slave);
+}
+
+static gboolean
+gdm_product_slave_run (GdmProductSlave *slave)
+{
+ char *display_name;
+ gboolean display_is_local;
+
+ g_object_get (slave,
+ "display-is-local", &display_is_local,
+ "display-name", &display_name,
+ NULL);
+
+ /* if this is local display start a server if one doesn't
+ * exist */
+ if (display_is_local) {
+ gboolean res;
+
+ slave->priv->server = gdm_server_new (display_name);
+
+ g_signal_connect (slave->priv->server,
+ "ready",
+ G_CALLBACK (server_ready_cb),
+ slave);
+
+ res = gdm_server_start (slave->priv->server);
+ if (! res) {
+ g_warning (_("Could not start the X "
+ "server (your graphical environment) "
+ "due to some internal error. "
+ "Please contact your system administrator "
+ "or check your syslog to diagnose. "
+ "In the meantime this display will be "
+ "disabled. Please restart GDM when "
+ "the problem is corrected."));
+ exit (1);
+ }
+
+ g_debug ("Started X server");
+ } else {
+ g_timeout_add (500, (GSourceFunc)idle_connect_to_display, slave);
+ }
+
+ g_free (display_name);
+
+ return TRUE;
+}
+
+static gboolean
+gdm_product_slave_start (GdmSlave *slave)
+{
+ gboolean ret;
+ gboolean res;
+ GError *error;
+ char *display_id;
+
+ ret = FALSE;
+
+ res = GDM_SLAVE_CLASS (gdm_product_slave_parent_class)->start (slave);
+
+ g_object_get (slave,
+ "display-id", &display_id,
+ NULL);
+
+ error = NULL;
+ GDM_PRODUCT_SLAVE (slave)->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+ if (GDM_PRODUCT_SLAVE (slave)->priv->connection == NULL) {
+ if (error != NULL) {
+ g_critical ("error getting system bus: %s", error->message);
+ g_error_free (error);
+ }
+ exit (1);
+ }
+
+ error = NULL;
+ GDM_PRODUCT_SLAVE (slave)->priv->product_display_proxy = dbus_g_proxy_new_for_name_owner (GDM_PRODUCT_SLAVE (slave)->priv->connection,
+ GDM_DBUS_NAME,
+ display_id,
+ GDM_DBUS_PRODUCT_DISPLAY_INTERFACE,
+ &error);
+ if (GDM_PRODUCT_SLAVE (slave)->priv->product_display_proxy == NULL) {
+ if (error != NULL) {
+ g_warning ("Failed to create display proxy %s: %s", display_id, error->message);
+ g_error_free (error);
+ } else {
+ g_warning ("Unable to create display proxy");
+ }
+ goto out;
+ }
+
+
+ gdm_product_slave_run (GDM_PRODUCT_SLAVE (slave));
+
+ ret = TRUE;
+
+ out:
+ g_free (display_id);
+
+ return ret;
+}
+
+static gboolean
+gdm_product_slave_stop (GdmSlave *slave)
+{
+ gboolean res;
+
+ g_debug ("Stopping product_slave");
+
+ res = GDM_SLAVE_CLASS (gdm_product_slave_parent_class)->stop (slave);
+
+ if (GDM_PRODUCT_SLAVE (slave)->priv->greeter != NULL) {
+ gdm_greeter_server_stop (GDM_PRODUCT_SLAVE (slave)->priv->greeter);
+ g_object_unref (GDM_PRODUCT_SLAVE (slave)->priv->greeter);
+ GDM_PRODUCT_SLAVE (slave)->priv->greeter = NULL;
+ }
+
+ if (GDM_PRODUCT_SLAVE (slave)->priv->session != NULL) {
+ gdm_session_close (GDM_PRODUCT_SLAVE (slave)->priv->session);
+ g_object_unref (GDM_PRODUCT_SLAVE (slave)->priv->session);
+ GDM_PRODUCT_SLAVE (slave)->priv->session = NULL;
+ }
+
+ if (GDM_PRODUCT_SLAVE (slave)->priv->server != NULL) {
+ gdm_server_stop (GDM_PRODUCT_SLAVE (slave)->priv->server);
+ g_object_unref (GDM_PRODUCT_SLAVE (slave)->priv->server);
+ GDM_PRODUCT_SLAVE (slave)->priv->server = NULL;
+ }
+
+ if (GDM_PRODUCT_SLAVE (slave)->priv->product_display_proxy != NULL) {
+ g_object_unref (GDM_PRODUCT_SLAVE (slave)->priv->product_display_proxy);
+ }
+
+ return TRUE;
+}
+
+static void
+gdm_product_slave_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdmProductSlave *self;
+
+ self = GDM_PRODUCT_SLAVE (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdm_product_slave_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdmProductSlave *self;
+
+ self = GDM_PRODUCT_SLAVE (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GObject *
+gdm_product_slave_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GdmProductSlave *product_slave;
+ GdmProductSlaveClass *klass;
+
+ klass = GDM_PRODUCT_SLAVE_CLASS (g_type_class_peek (GDM_TYPE_PRODUCT_SLAVE));
+
+ product_slave = GDM_PRODUCT_SLAVE (G_OBJECT_CLASS (gdm_product_slave_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+
+ return G_OBJECT (product_slave);
+}
+
+static void
+gdm_product_slave_class_init (GdmProductSlaveClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdmSlaveClass *slave_class = GDM_SLAVE_CLASS (klass);
+
+ object_class->get_property = gdm_product_slave_get_property;
+ object_class->set_property = gdm_product_slave_set_property;
+ object_class->constructor = gdm_product_slave_constructor;
+ object_class->finalize = gdm_product_slave_finalize;
+
+ slave_class->start = gdm_product_slave_start;
+ slave_class->stop = gdm_product_slave_stop;
+
+ g_type_class_add_private (klass, sizeof (GdmProductSlavePrivate));
+
+ dbus_g_object_type_install_info (GDM_TYPE_PRODUCT_SLAVE, &dbus_glib_gdm_product_slave_object_info);
+}
+
+static void
+gdm_product_slave_init (GdmProductSlave *product_slave)
+{
+
+ product_slave->priv = GDM_PRODUCT_SLAVE_GET_PRIVATE (product_slave);
+
+ product_slave->priv->pid = -1;
+}
+
+static void
+gdm_product_slave_finalize (GObject *object)
+{
+ GdmProductSlave *product_slave;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDM_IS_PRODUCT_SLAVE (object));
+
+ product_slave = GDM_PRODUCT_SLAVE (object);
+
+ g_return_if_fail (product_slave->priv != NULL);
+
+ G_OBJECT_CLASS (gdm_product_slave_parent_class)->finalize (object);
+}
+
+GdmSlave *
+gdm_product_slave_new (const char *id)
+{
+ GObject *object;
+
+ object = g_object_new (GDM_TYPE_PRODUCT_SLAVE,
+ "display-id", id,
+ NULL);
+
+ return GDM_SLAVE (object);
+}
diff --git a/daemon/gdm-product-slave.h b/daemon/gdm-product-slave.h
new file mode 100644
index 00000000..ad525655
--- /dev/null
+++ b/daemon/gdm-product-slave.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
+ *
+ * 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 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifndef __GDM_PRODUCT_SLAVE_H
+#define __GDM_PRODUCT_SLAVE_H
+
+#include <glib-object.h>
+#include "gdm-slave.h"
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_PRODUCT_SLAVE (gdm_product_slave_get_type ())
+#define GDM_PRODUCT_SLAVE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_PRODUCT_SLAVE, GdmProductSlave))
+#define GDM_PRODUCT_SLAVE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_PRODUCT_SLAVE, GdmProductSlaveClass))
+#define GDM_IS_PRODUCT_SLAVE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_PRODUCT_SLAVE))
+#define GDM_IS_PRODUCT_SLAVE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_PRODUCT_SLAVE))
+#define GDM_PRODUCT_SLAVE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_PRODUCT_SLAVE, GdmProductSlaveClass))
+
+typedef struct GdmProductSlavePrivate GdmProductSlavePrivate;
+
+typedef struct
+{
+ GdmSlave parent;
+ GdmProductSlavePrivate *priv;
+} GdmProductSlave;
+
+typedef struct
+{
+ GdmSlaveClass parent_class;
+} GdmProductSlaveClass;
+
+GType gdm_product_slave_get_type (void);
+GdmSlave * gdm_product_slave_new (const char *id);
+
+G_END_DECLS
+
+#endif /* __GDM_PRODUCT_SLAVE_H */
diff --git a/daemon/gdm-product-slave.xml b/daemon/gdm-product-slave.xml
new file mode 100644
index 00000000..d2eb2cae
--- /dev/null
+++ b/daemon/gdm-product-slave.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.gnome.DisplayManager.ProductSlave">
+ </interface>
+</node>
diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c
new file mode 100644
index 00000000..04bf7bb4
--- /dev/null
+++ b/daemon/gdm-simple-slave.c
@@ -0,0 +1,1136 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
+ *
+ * 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 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include <X11/Xlib.h> /* for Display */
+
+#include "gdm-common.h"
+
+#include "gdm-simple-slave.h"
+#include "gdm-simple-slave-glue.h"
+
+#include "gdm-server.h"
+#include "gdm-session.h"
+#include "gdm-greeter-server.h"
+#include "gdm-greeter-proxy.h"
+
+extern char **environ;
+
+#define GDM_SIMPLE_SLAVE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_SIMPLE_SLAVE, GdmSimpleSlavePrivate))
+
+#define GDM_DBUS_NAME "org.gnome.DisplayManager"
+#define GDM_DBUS_DISPLAY_INTERFACE "org.gnome.DisplayManager.Display"
+
+#define MAX_CONNECT_ATTEMPTS 10
+
+struct GdmSimpleSlavePrivate
+{
+ char *id;
+ GPid pid;
+ guint output_watch_id;
+ guint error_watch_id;
+
+ int ping_interval;
+
+ GPid server_pid;
+ Display *server_display;
+ guint connection_attempts;
+
+ /* user selected */
+ char *selected_session;
+ char *selected_language;
+
+ GdmServer *server;
+ GdmGreeterServer *greeter_server;
+ GdmGreeterProxy *greeter;
+ GdmSession *session;
+ DBusGProxy *display_proxy;
+ DBusGConnection *connection;
+};
+
+enum {
+ PROP_0,
+ PROP_DISPLAY_ID,
+};
+
+enum {
+ SESSION_STARTED,
+ SESSION_EXITED,
+ SESSION_DIED,
+ LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0, };
+
+static void gdm_simple_slave_class_init (GdmSimpleSlaveClass *klass);
+static void gdm_simple_slave_init (GdmSimpleSlave *simple_slave);
+static void gdm_simple_slave_finalize (GObject *object);
+
+G_DEFINE_TYPE (GdmSimpleSlave, gdm_simple_slave, GDM_TYPE_SLAVE)
+
+static void
+set_busy_cursor (GdmSimpleSlave *simple_slave)
+{
+ if (simple_slave->priv->server_display != NULL) {
+ Cursor xcursor;
+
+ xcursor = XCreateFontCursor (simple_slave->priv->server_display, GDK_WATCH);
+ XDefineCursor (simple_slave->priv->server_display,
+ DefaultRootWindow (simple_slave->priv->server_display),
+ xcursor);
+ XFreeCursor (simple_slave->priv->server_display, xcursor);
+ XSync (simple_slave->priv->server_display, False);
+ }
+}
+
+static void
+gdm_simple_slave_whack_temp_auth_file (GdmSimpleSlave *simple_slave)
+{
+#if 0
+ uid_t old;
+
+ old = geteuid ();
+ if (old != 0)
+ seteuid (0);
+ if (d->parent_temp_auth_file != NULL) {
+ VE_IGNORE_EINTR (g_unlink (d->parent_temp_auth_file));
+ }
+ g_free (d->parent_temp_auth_file);
+ d->parent_temp_auth_file = NULL;
+ if (old != 0)
+ seteuid (old);
+#endif
+}
+
+
+static void
+create_temp_auth_file (GdmSimpleSlave *simple_slave)
+{
+#if 0
+ if (d->type == TYPE_FLEXI_XNEST &&
+ d->parent_auth_file != NULL) {
+ if (d->parent_temp_auth_file != NULL) {
+ VE_IGNORE_EINTR (g_unlink (d->parent_temp_auth_file));
+ }
+ g_free (d->parent_temp_auth_file);
+ d->parent_temp_auth_file =
+ copy_auth_file (d->server_uid,
+ gdm_daemon_config_get_gdmuid (),
+ d->parent_auth_file);
+ }
+#endif
+}
+
+static void
+listify_hash (const char *key,
+ const char *value,
+ GPtrArray *env)
+{
+ char *str;
+ str = g_strdup_printf ("%s=%s", key, value);
+ g_debug ("environment: %s", str);
+ g_ptr_array_add (env, str);
+}
+
+static GPtrArray *
+get_script_environment (GdmSimpleSlave *slave,
+ const char *username)
+{
+ GPtrArray *env;
+ GHashTable *hash;
+ struct passwd *pwent;
+ char *x_servers_file;
+ char *display_name;
+ char *display_hostname;
+ char *display_x11_authority_file;
+ gboolean display_is_local;
+
+ g_object_get (slave,
+ "display-name", &display_name,
+ "display-hostname", &display_hostname,
+ "display-is-local", &display_is_local,
+ "display-x11-authority-file", &display_x11_authority_file,
+ NULL);
+
+ env = g_ptr_array_new ();
+
+ /* create a hash table of current environment, then update keys has necessary */
+ hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+ /* modify environment here */
+ g_hash_table_insert (hash, g_strdup ("HOME"), g_strdup ("/"));
+ g_hash_table_insert (hash, g_strdup ("PWD"), g_strdup ("/"));
+ g_hash_table_insert (hash, g_strdup ("SHELL"), g_strdup ("/bin/sh"));
+
+ g_hash_table_insert (hash, g_strdup ("LOGNAME"), g_strdup (username));
+ g_hash_table_insert (hash, g_strdup ("USER"), g_strdup (username));
+ g_hash_table_insert (hash, g_strdup ("USERNAME"), g_strdup (username));
+
+ pwent = getpwnam (username);
+ if (pwent != NULL) {
+ if (pwent->pw_dir != NULL && pwent->pw_dir[0] != '\0') {
+ g_hash_table_insert (hash, g_strdup ("HOME"), g_strdup (pwent->pw_dir));
+ g_hash_table_insert (hash, g_strdup ("PWD"), g_strdup (pwent->pw_dir));
+ }
+
+ g_hash_table_insert (hash, g_strdup ("SHELL"), g_strdup (pwent->pw_shell));
+ }
+
+#if 0
+ if (display_is_parented) {
+ g_hash_table_insert (hash, g_strdup ("GDM_PARENT_DISPLAY"), g_strdup (parent_display_name));
+
+ /*g_hash_table_insert (hash, "GDM_PARENT_XAUTHORITY"), slave->priv->parent_temp_auth_file));*/
+ }
+#endif
+
+ /* some env for use with the Pre and Post scripts */
+ x_servers_file = gdm_make_filename (AUTHDIR,
+ display_name,
+ ".Xservers");
+ g_hash_table_insert (hash, g_strdup ("X_SERVERS"), x_servers_file);
+
+ if (! display_is_local) {
+ g_hash_table_insert (hash, g_strdup ("REMOTE_HOST"), g_strdup (display_hostname));
+ }
+
+ /* Runs as root */
+ g_hash_table_insert (hash, g_strdup ("XAUTHORITY"), g_strdup (display_x11_authority_file));
+ g_hash_table_insert (hash, g_strdup ("DISPLAY"), g_strdup (display_name));
+
+ /*g_setenv ("PATH", gdm_daemon_config_get_value_string (GDM_KEY_ROOT_PATH), TRUE);*/
+
+ g_hash_table_insert (hash, g_strdup ("RUNNING_UNDER_GDM"), g_strdup ("true"));
+
+#if 0
+ if ( ! ve_string_empty (d->theme_name))
+ g_setenv ("GDM_GTK_THEME", d->theme_name, TRUE);
+#endif
+ g_hash_table_remove (hash, "MAIL");
+
+
+ g_hash_table_foreach (hash, (GHFunc)listify_hash, env);
+ g_hash_table_destroy (hash);
+
+ g_ptr_array_add (env, NULL);
+
+ g_free (display_name);
+ g_free (display_hostname);
+ g_free (display_x11_authority_file);
+
+ return env;
+}
+
+static gboolean
+gdm_simple_slave_exec_script (GdmSimpleSlave *slave,
+ const char *dir,
+ const char *login)
+{
+ char *script;
+ char **argv;
+ gint status;
+ GError *error;
+ GPtrArray *env;
+ gboolean res;
+ gboolean ret;
+ char *display_name;
+ char *display_hostname;
+
+ g_assert (dir != NULL);
+ g_assert (login != NULL);
+
+ g_object_get (slave,
+ "display-name", &display_name,
+ "display-hostname", &display_hostname,
+ NULL);
+
+ script = g_build_filename (dir, display_name, NULL);
+ if (g_access (script, R_OK|X_OK) != 0) {
+ g_free (script);
+ script = NULL;
+ }
+
+ if (script == NULL &&
+ display_hostname != NULL) {
+ script = g_build_filename (dir, display_hostname, NULL);
+ if (g_access (script, R_OK|X_OK) != 0) {
+ g_free (script);
+ script = NULL;
+ }
+ }
+
+#if 0
+ if (script == NULL &&
+ SERVER_IS_XDMCP (d)) {
+ script = g_build_filename (dir, "XDMCP", NULL);
+ if (g_access (script, R_OK|X_OK) != 0) {
+ g_free (script);
+ script = NULL;
+ }
+ }
+ if (script == NULL &&
+ SERVER_IS_FLEXI (d)) {
+ script = g_build_filename (dir, "Flexi", NULL);
+ if (g_access (script, R_OK|X_OK) != 0) {
+ g_free (script);
+ script = NULL;
+ }
+ }
+#endif
+
+ if (script == NULL) {
+ script = g_build_filename (dir, "Default", NULL);
+ if (g_access (script, R_OK|X_OK) != 0) {
+ g_free (script);
+ script = NULL;
+ }
+ }
+
+ if (script == NULL) {
+ return TRUE;
+ }
+
+ create_temp_auth_file (slave);
+
+ g_debug ("Running process: %s", script);
+ error = NULL;
+ if (! g_shell_parse_argv (script, NULL, &argv, &error)) {
+ g_warning ("Could not parse command: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ env = get_script_environment (slave, login);
+
+ res = g_spawn_sync (NULL,
+ argv,
+ (char **)env->pdata,
+ G_SPAWN_SEARCH_PATH,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &status,
+ &error);
+
+ g_ptr_array_foreach (env, (GFunc)g_free, NULL);
+ g_ptr_array_free (env, TRUE);
+
+ gdm_simple_slave_whack_temp_auth_file (slave);
+
+ if (WIFEXITED (status)) {
+ g_debug ("Process exit status: %d", WEXITSTATUS (status));
+ ret = WEXITSTATUS (status) != 0;
+ } else {
+ ret = TRUE;
+ }
+
+ out:
+ g_free (script);
+ g_free (display_name);
+ g_free (display_hostname);
+
+ return ret;
+}
+
+static void
+on_session_started (GdmSession *session,
+ GPid pid,
+ GdmSimpleSlave *slave)
+{
+ g_debug ("session started on pid %d\n", (int) pid);
+ g_signal_emit (slave, signals [SESSION_STARTED], 0, pid);
+}
+
+static void
+on_session_exited (GdmSession *session,
+ int exit_code,
+ GdmSimpleSlave *slave)
+{
+ g_debug ("session exited with code %d\n", exit_code);
+ g_signal_emit (slave, signals [SESSION_EXITED], 0, exit_code);
+}
+
+static void
+on_session_died (GdmSession *session,
+ int signal_number,
+ GdmSimpleSlave *slave)
+{
+ g_debug ("session died with signal %d, (%s)",
+ signal_number,
+ g_strsignal (signal_number));
+ g_signal_emit (slave, signals [SESSION_DIED], 0, signal_number);
+}
+
+static gboolean
+is_prog_in_path (const char *prog)
+{
+ char *f;
+ gboolean ret;
+
+ f = g_find_program_in_path (prog);
+ ret = (f != NULL);
+ g_free (f);
+ return ret;
+}
+
+static gboolean
+get_session_command (const char *file,
+ char **command)
+{
+ GKeyFile *key_file;
+ GError *error;
+ char *full_path;
+ char *exec;
+ gboolean ret;
+ gboolean res;
+ const char *search_dirs[] = {
+ "/etc/X11/sessions/",
+ DMCONFDIR "/Sessions/",
+ DATADIR "/gdm/BuiltInSessions/",
+ DATADIR "/xsessions/",
+ NULL
+ };
+
+ exec = NULL;
+ ret = FALSE;
+ if (command != NULL) {
+ *command = NULL;
+ }
+
+ key_file = g_key_file_new ();
+
+ error = NULL;
+ full_path = NULL;
+ res = g_key_file_load_from_dirs (key_file,
+ file,
+ search_dirs,
+ &full_path,
+ G_KEY_FILE_NONE,
+ &error);
+ if (! res) {
+ g_debug ("File '%s' not found: %s", file, error->message);
+ g_error_free (error);
+ if (command != NULL) {
+ *command = NULL;
+ }
+ goto out;
+ }
+
+ error = NULL;
+ res = g_key_file_get_boolean (key_file,
+ G_KEY_FILE_DESKTOP_GROUP,
+ G_KEY_FILE_DESKTOP_KEY_HIDDEN,
+ &error);
+ if (error == NULL && res) {
+ g_debug ("Session %s is marked as hidden", file);
+ goto out;
+ }
+
+ error = NULL;
+ exec = g_key_file_get_string (key_file,
+ G_KEY_FILE_DESKTOP_GROUP,
+ G_KEY_FILE_DESKTOP_KEY_TRY_EXEC,
+ &error);
+ if (exec == NULL) {
+ g_debug ("%s key not found", G_KEY_FILE_DESKTOP_KEY_TRY_EXEC);
+ goto out;
+ }
+
+ res = is_prog_in_path (exec);
+ g_free (exec);
+
+ if (! res) {
+ g_debug ("Command not found: %s", G_KEY_FILE_DESKTOP_KEY_TRY_EXEC);
+ goto out;
+ }
+
+ error = NULL;
+ exec = g_key_file_get_string (key_file,
+ G_KEY_FILE_DESKTOP_GROUP,
+ G_KEY_FILE_DESKTOP_KEY_EXEC,
+ &error);
+ if (error != NULL) {
+ g_debug ("%s key not found: %s",
+ G_KEY_FILE_DESKTOP_KEY_EXEC,
+ error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ if (command != NULL) {
+ *command = g_strdup (exec);
+ }
+ ret = TRUE;
+
+out:
+ g_free (exec);
+
+ return ret;
+}
+
+static void
+setup_session_environment (GdmSimpleSlave *slave)
+{
+ char *display_name;
+ char *auth_file;
+
+ g_object_get (slave,
+ "display-name", &display_name,
+ "display-x11-authority-file", &auth_file,
+ NULL);
+
+ gdm_session_set_environment_variable (slave->priv->session,
+ "GDMSESSION",
+ slave->priv->selected_session);
+ gdm_session_set_environment_variable (slave->priv->session,
+ "DESKTOP_SESSION",
+ slave->priv->selected_session);
+
+ gdm_session_set_environment_variable (slave->priv->session,
+ "LANG",
+ slave->priv->selected_language);
+ gdm_session_set_environment_variable (slave->priv->session,
+ "GDM_LANG",
+ slave->priv->selected_language);
+
+ gdm_session_set_environment_variable (slave->priv->session,
+ "DISPLAY",
+ display_name);
+ gdm_session_set_environment_variable (slave->priv->session,
+ "XAUTHORITY",
+ auth_file);
+
+ gdm_session_set_environment_variable (slave->priv->session,
+ "PATH",
+ "/bin:/usr/bin:" BINDIR);
+
+ g_free (display_name);
+ g_free (auth_file);
+}
+
+static void
+on_user_verified (GdmSession *session,
+ GdmSimpleSlave *slave)
+{
+ char *username;
+ int argc;
+ char **argv;
+ char *command;
+ char *filename;
+ GError *error;
+ gboolean res;
+
+ gdm_greeter_proxy_stop (slave->priv->greeter);
+ gdm_greeter_server_stop (slave->priv->greeter_server);
+
+ username = gdm_session_get_username (session);
+
+ g_debug ("%s%ssuccessfully authenticated\n",
+ username ? username : "",
+ username ? " " : "");
+ g_free (username);
+
+ if (slave->priv->selected_session != NULL) {
+ filename = g_strdup (slave->priv->selected_session);
+ } else {
+ filename = g_strdup ("gnome.desktop");
+ }
+
+ setup_session_environment (slave);
+
+ res = get_session_command (filename, &command);
+ if (! res) {
+ g_warning ("Could find session file: %s", filename);
+ return;
+ }
+
+ error = NULL;
+ res = g_shell_parse_argv (command, &argc, &argv, &error);
+ if (! res) {
+ g_warning ("Could not parse command: %s", error->message);
+ g_error_free (error);
+ }
+
+ gdm_session_start_program (session,
+ argc,
+ (const char **)argv);
+
+ g_free (filename);
+ g_free (command);
+ g_strfreev (argv);
+}
+
+static void
+on_user_verification_error (GdmSession *session,
+ GError *error,
+ GdmSimpleSlave *slave)
+{
+ char *username;
+
+ username = gdm_session_get_username (session);
+
+ g_debug ("%s%scould not be successfully authenticated: %s\n",
+ username ? username : "",
+ username ? " " : "",
+ error->message);
+
+ g_free (username);
+}
+
+static void
+on_info (GdmSession *session,
+ const char *text,
+ GdmSimpleSlave *slave)
+{
+ g_debug ("Info: %s", text);
+ gdm_greeter_server_info (slave->priv->greeter_server, text);
+}
+
+static void
+on_problem (GdmSession *session,
+ const char *text,
+ GdmSimpleSlave *slave)
+{
+ g_debug ("Problem: %s", text);
+ gdm_greeter_server_problem (slave->priv->greeter_server, text);
+}
+
+static void
+on_info_query (GdmSession *session,
+ const char *text,
+ GdmSimpleSlave *slave)
+{
+
+ g_debug ("Info query: %s", text);
+ gdm_greeter_server_info_query (slave->priv->greeter_server, text);
+}
+
+static void
+on_secret_info_query (GdmSession *session,
+ const char *text,
+ GdmSimpleSlave *slave)
+{
+ g_debug ("Secret info query: %s", text);
+ gdm_greeter_server_secret_info_query (slave->priv->greeter_server, text);
+}
+
+static void
+on_greeter_answer (GdmGreeterServer *greeter_server,
+ const char *text,
+ GdmSimpleSlave *slave)
+{
+ gdm_session_answer_query (slave->priv->session, text);
+}
+
+static void
+on_greeter_session_selected (GdmGreeterServer *greeter_server,
+ const char *text,
+ GdmSimpleSlave *slave)
+{
+ g_free (slave->priv->selected_session);
+ slave->priv->selected_session = g_strdup (text);
+}
+
+static void
+on_greeter_language_selected (GdmGreeterServer *greeter_server,
+ const char *text,
+ GdmSimpleSlave *slave)
+{
+ g_free (slave->priv->selected_language);
+ slave->priv->selected_language = g_strdup (text);
+}
+
+static void
+on_greeter_connected (GdmGreeterServer *greeter_server,
+ GdmSimpleSlave *slave)
+{
+ gboolean display_is_local;
+
+ g_object_get (slave,
+ "display-is-local", &display_is_local,
+ NULL);
+
+ g_debug ("Greeter started");
+
+ gdm_session_open (slave->priv->session,
+ "gdm",
+ NULL /* hostname */,
+ "/dev/console",
+ STDOUT_FILENO,
+ STDERR_FILENO,
+ NULL);
+
+ /* If XDMCP stop pinging */
+ if ( ! display_is_local) {
+ alarm (0);
+ }
+}
+
+static void
+run_greeter (GdmSimpleSlave *slave)
+{
+ gboolean display_is_local;
+ char *display_name;
+ char *auth_file;
+
+ g_object_get (slave,
+ "display-is-local", &display_is_local,
+ "display-name", &display_name,
+ "display-x11-authority-file", &auth_file,
+ NULL);
+
+ /* Set the busy cursor */
+ set_busy_cursor (slave);
+
+ /* FIXME: send a signal back to the master */
+
+#if 0
+
+ /* OK from now on it's really the user whacking us most likely,
+ * we have already started up well */
+ do_xfailed_on_xio_error = FALSE;
+#endif
+
+ /* If XDMCP setup pinging */
+ if ( ! display_is_local && slave->priv->ping_interval > 0) {
+ alarm (slave->priv->ping_interval);
+ }
+
+#if 0
+ /* checkout xinerama */
+ gdm_screen_init (slave);
+#endif
+
+#ifdef HAVE_TSOL
+ /* Check out Solaris Trusted Xserver extension */
+ gdm_tsol_init (d);
+#endif
+
+ /* Run the init script. gdmslave suspends until script has terminated */
+ gdm_simple_slave_exec_script (slave,
+ GDMCONFDIR"/Init",
+ "gdm");
+
+ slave->priv->session = gdm_session_new ();
+
+ g_signal_connect (slave->priv->session,
+ "info",
+ G_CALLBACK (on_info),
+ slave);
+
+ g_signal_connect (slave->priv->session,
+ "problem",
+ G_CALLBACK (on_problem),
+ slave);
+
+ g_signal_connect (slave->priv->session,
+ "info-query",
+ G_CALLBACK (on_info_query),
+ slave);
+
+ g_signal_connect (slave->priv->session,
+ "secret-info-query",
+ G_CALLBACK (on_secret_info_query),
+ slave);
+
+ g_signal_connect (slave->priv->session,
+ "user-verified",
+ G_CALLBACK (on_user_verified),
+ slave);
+
+ g_signal_connect (slave->priv->session,
+ "user-verification-error",
+ G_CALLBACK (on_user_verification_error),
+ slave);
+
+ g_signal_connect (slave->priv->session,
+ "session-started",
+ G_CALLBACK (on_session_started),
+ slave);
+ g_signal_connect (slave->priv->session,
+ "session-exited",
+ G_CALLBACK (on_session_exited),
+ slave);
+ g_signal_connect (slave->priv->session,
+ "session-died",
+ G_CALLBACK (on_session_died),
+ slave);
+
+ slave->priv->greeter_server = gdm_greeter_server_new (display_name);
+ g_signal_connect (slave->priv->greeter_server,
+ "query-answer",
+ G_CALLBACK (on_greeter_answer),
+ slave);
+ g_signal_connect (slave->priv->greeter_server,
+ "session-selected",
+ G_CALLBACK (on_greeter_session_selected),
+ slave);
+ g_signal_connect (slave->priv->greeter_server,
+ "language-selected",
+ G_CALLBACK (on_greeter_language_selected),
+ slave);
+ g_signal_connect (slave->priv->greeter_server,
+ "connected",
+ G_CALLBACK (on_greeter_connected),
+ slave);
+ gdm_greeter_server_start (slave->priv->greeter_server);
+
+ slave->priv->greeter = gdm_greeter_proxy_new (display_name);
+ g_object_set (slave->priv->greeter,
+ "x11-authority-file", auth_file,
+ NULL);
+ gdm_greeter_proxy_start (slave->priv->greeter);
+
+ g_free (display_name);
+ g_free (auth_file);
+}
+
+static void
+set_local_auth (GdmSimpleSlave *slave)
+{
+ GString *binary_cookie;
+ GString *cookie;
+ char *display_x11_cookie;
+
+ g_object_get (slave,
+ "display-x11-cookie", &display_x11_cookie,
+ NULL);
+
+ g_debug ("Setting authorization key for display %s", display_x11_cookie);
+
+ cookie = g_string_new (display_x11_cookie);
+ binary_cookie = g_string_new (NULL);
+ if (! gdm_string_hex_decode (cookie,
+ 0,
+ NULL,
+ binary_cookie,
+ 0)) {
+ g_warning ("Unable to decode hex cookie");
+ goto out;
+ }
+
+ g_debug ("Decoded cookie len %d", binary_cookie->len);
+
+ XSetAuthorization ("MIT-MAGIC-COOKIE-1",
+ (int) strlen ("MIT-MAGIC-COOKIE-1"),
+ (char *)binary_cookie->str,
+ binary_cookie->len);
+
+ out:
+ g_string_free (binary_cookie, TRUE);
+ g_string_free (cookie, TRUE);
+ g_free (display_x11_cookie);
+}
+
+static gboolean
+connect_to_display (GdmSimpleSlave *slave)
+{
+ char *display_name;
+ gboolean ret;
+
+ ret = FALSE;
+
+ g_object_get (slave,
+ "display-name", &display_name,
+ NULL);
+
+ /* We keep our own (windowless) connection (dsp) open to avoid the
+ * X server resetting due to lack of active connections. */
+
+ g_debug ("Server is ready - opening display %s", display_name);
+
+ g_setenv ("DISPLAY", display_name, TRUE);
+ g_unsetenv ("XAUTHORITY"); /* just in case it's set */
+
+ set_local_auth (slave);
+
+#if 0
+ /* X error handlers to avoid the default one (i.e. exit (1)) */
+ do_xfailed_on_xio_error = TRUE;
+ XSetErrorHandler (gdm_simple_slave_xerror_handler);
+ XSetIOErrorHandler (gdm_simple_slave_xioerror_handler);
+#endif
+
+ gdm_sigchld_block_push ();
+ slave->priv->server_display = XOpenDisplay (display_name);
+ gdm_sigchld_block_pop ();
+
+ if (slave->priv->server_display == NULL) {
+ g_warning ("Unable to connect to display %s", display_name);
+ ret = FALSE;
+ } else {
+ g_debug ("Connected to display %s", display_name);
+ ret = TRUE;
+ }
+
+ g_free (display_name);
+
+ return ret;
+}
+
+static gboolean
+idle_connect_to_display (GdmSimpleSlave *slave)
+{
+ gboolean res;
+
+ slave->priv->connection_attempts++;
+
+ res = connect_to_display (slave);
+ if (res) {
+ /* FIXME: handle wait-for-go */
+
+ run_greeter (slave);
+ } else {
+ if (slave->priv->connection_attempts >= MAX_CONNECT_ATTEMPTS) {
+ g_warning ("Unable to connect to display after %d tries - bailing out", slave->priv->connection_attempts);
+ exit (1);
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+server_ready_cb (GdmServer *server,
+ GdmSimpleSlave *slave)
+{
+ g_timeout_add (500, (GSourceFunc)idle_connect_to_display, slave);
+}
+
+static gboolean
+gdm_simple_slave_run (GdmSimpleSlave *slave)
+{
+ char *display_name;
+ gboolean display_is_local;
+
+ g_object_get (slave,
+ "display-is-local", &display_is_local,
+ "display-name", &display_name,
+ NULL);
+
+ /* if this is local display start a server if one doesn't
+ * exist */
+ if (display_is_local) {
+ gboolean res;
+
+ slave->priv->server = gdm_server_new (display_name);
+
+ g_signal_connect (slave->priv->server,
+ "ready",
+ G_CALLBACK (server_ready_cb),
+ slave);
+
+ res = gdm_server_start (slave->priv->server);
+ if (! res) {
+ g_warning (_("Could not start the X "
+ "server (your graphical environment) "
+ "due to some internal error. "
+ "Please contact your system administrator "
+ "or check your syslog to diagnose. "
+ "In the meantime this display will be "
+ "disabled. Please restart GDM when "
+ "the problem is corrected."));
+ exit (1);
+ }
+
+ g_debug ("Started X server");
+ } else {
+ g_timeout_add (500, (GSourceFunc)idle_connect_to_display, slave);
+ }
+
+ g_free (display_name);
+
+ return TRUE;
+}
+
+static gboolean
+gdm_simple_slave_start (GdmSlave *slave)
+{
+ gboolean res;
+
+ res = GDM_SLAVE_CLASS (gdm_simple_slave_parent_class)->start (slave);
+
+ gdm_simple_slave_run (GDM_SIMPLE_SLAVE (slave));
+
+ return TRUE;
+}
+
+static gboolean
+gdm_simple_slave_stop (GdmSlave *slave)
+{
+ gboolean res;
+
+ g_debug ("Stopping simple_slave");
+
+ res = GDM_SLAVE_CLASS (gdm_simple_slave_parent_class)->stop (slave);
+
+ if (GDM_SIMPLE_SLAVE (slave)->priv->greeter != NULL) {
+ gdm_greeter_proxy_stop (GDM_SIMPLE_SLAVE (slave)->priv->greeter);
+ g_object_unref (GDM_SIMPLE_SLAVE (slave)->priv->greeter);
+ GDM_SIMPLE_SLAVE (slave)->priv->greeter = NULL;
+ }
+
+ if (GDM_SIMPLE_SLAVE (slave)->priv->session != NULL) {
+ gdm_session_close (GDM_SIMPLE_SLAVE (slave)->priv->session);
+ g_object_unref (GDM_SIMPLE_SLAVE (slave)->priv->session);
+ GDM_SIMPLE_SLAVE (slave)->priv->session = NULL;
+ }
+
+ if (GDM_SIMPLE_SLAVE (slave)->priv->server != NULL) {
+ gdm_server_stop (GDM_SIMPLE_SLAVE (slave)->priv->server);
+ g_object_unref (GDM_SIMPLE_SLAVE (slave)->priv->server);
+ GDM_SIMPLE_SLAVE (slave)->priv->server = NULL;
+ }
+
+ if (GDM_SIMPLE_SLAVE (slave)->priv->display_proxy != NULL) {
+ g_object_unref (GDM_SIMPLE_SLAVE (slave)->priv->display_proxy);
+ }
+
+ return TRUE;
+}
+
+static void
+gdm_simple_slave_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdmSimpleSlave *self;
+
+ self = GDM_SIMPLE_SLAVE (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdm_simple_slave_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdmSimpleSlave *self;
+
+ self = GDM_SIMPLE_SLAVE (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GObject *
+gdm_simple_slave_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GdmSimpleSlave *simple_slave;
+ GdmSimpleSlaveClass *klass;
+
+ klass = GDM_SIMPLE_SLAVE_CLASS (g_type_class_peek (GDM_TYPE_SIMPLE_SLAVE));
+
+ simple_slave = GDM_SIMPLE_SLAVE (G_OBJECT_CLASS (gdm_simple_slave_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+
+ return G_OBJECT (simple_slave);
+}
+
+static void
+gdm_simple_slave_class_init (GdmSimpleSlaveClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdmSlaveClass *slave_class = GDM_SLAVE_CLASS (klass);
+
+ object_class->get_property = gdm_simple_slave_get_property;
+ object_class->set_property = gdm_simple_slave_set_property;
+ object_class->constructor = gdm_simple_slave_constructor;
+ object_class->finalize = gdm_simple_slave_finalize;
+
+ slave_class->start = gdm_simple_slave_start;
+ slave_class->stop = gdm_simple_slave_stop;
+
+ g_type_class_add_private (klass, sizeof (GdmSimpleSlavePrivate));
+
+ dbus_g_object_type_install_info (GDM_TYPE_SIMPLE_SLAVE, &dbus_glib_gdm_simple_slave_object_info);
+}
+
+static void
+gdm_simple_slave_init (GdmSimpleSlave *simple_slave)
+{
+
+ simple_slave->priv = GDM_SIMPLE_SLAVE_GET_PRIVATE (simple_slave);
+
+ simple_slave->priv->pid = -1;
+}
+
+static void
+gdm_simple_slave_finalize (GObject *object)
+{
+ GdmSimpleSlave *simple_slave;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDM_IS_SIMPLE_SLAVE (object));
+
+ simple_slave = GDM_SIMPLE_SLAVE (object);
+
+ g_return_if_fail (simple_slave->priv != NULL);
+
+ G_OBJECT_CLASS (gdm_simple_slave_parent_class)->finalize (object);
+}
+
+GdmSlave *
+gdm_simple_slave_new (const char *id)
+{
+ GObject *object;
+
+ object = g_object_new (GDM_TYPE_SIMPLE_SLAVE,
+ "display-id", id,
+ NULL);
+
+ return GDM_SLAVE (object);
+}
diff --git a/daemon/gdm-simple-slave.h b/daemon/gdm-simple-slave.h
new file mode 100644
index 00000000..37d5c5b9
--- /dev/null
+++ b/daemon/gdm-simple-slave.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
+ *
+ * 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 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifndef __GDM_SIMPLE_SLAVE_H
+#define __GDM_SIMPLE_SLAVE_H
+
+#include <glib-object.h>
+#include "gdm-slave.h"
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_SIMPLE_SLAVE (gdm_simple_slave_get_type ())
+#define GDM_SIMPLE_SLAVE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_SIMPLE_SLAVE, GdmSimpleSlave))
+#define GDM_SIMPLE_SLAVE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_SIMPLE_SLAVE, GdmSimpleSlaveClass))
+#define GDM_IS_SIMPLE_SLAVE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_SIMPLE_SLAVE))
+#define GDM_IS_SIMPLE_SLAVE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_SIMPLE_SLAVE))
+#define GDM_SIMPLE_SLAVE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_SIMPLE_SLAVE, GdmSimpleSlaveClass))
+
+typedef struct GdmSimpleSlavePrivate GdmSimpleSlavePrivate;
+
+typedef struct
+{
+ GdmSlave parent;
+ GdmSimpleSlavePrivate *priv;
+} GdmSimpleSlave;
+
+typedef struct
+{
+ GdmSlaveClass parent_class;
+} GdmSimpleSlaveClass;
+
+GType gdm_simple_slave_get_type (void);
+GdmSlave * gdm_simple_slave_new (const char *id);
+
+G_END_DECLS
+
+#endif /* __GDM_SIMPLE_SLAVE_H */
diff --git a/daemon/gdm-simple-slave.xml b/daemon/gdm-simple-slave.xml
new file mode 100644
index 00000000..1b3983d7
--- /dev/null
+++ b/daemon/gdm-simple-slave.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.gnome.DisplayManager.SimpleSlave">
+ </interface>
+</node>
diff --git a/daemon/gdm-slave-proxy.c b/daemon/gdm-slave-proxy.c
index 961d88da..5babdd18 100644
--- a/daemon/gdm-slave-proxy.c
+++ b/daemon/gdm-slave-proxy.c
@@ -35,13 +35,11 @@
#include "gdm-slave-proxy.h"
-#define GDM_SLAVE_PROXY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_SLAVE, GdmSlaveProxyPrivate))
-
-#define GDM_SLAVE_PROXY_COMMAND LIBEXECDIR"/gdm-slave"
+#define GDM_SLAVE_PROXY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_SLAVE_PROXY, GdmSlaveProxyPrivate))
struct GdmSlaveProxyPrivate
{
- char *display_id;
+ char *command;
GPid pid;
guint output_watch_id;
guint error_watch_id;
@@ -49,7 +47,7 @@ struct GdmSlaveProxyPrivate
enum {
PROP_0,
- PROP_DISPLAY_ID,
+ PROP_COMMAND,
};
static void gdm_slave_proxy_class_init (GdmSlaveProxyClass *klass);
@@ -119,20 +117,7 @@ output_watch (GIOChannel *source,
switch (status) {
case G_IO_STATUS_NORMAL:
- {
- char *p;
-
- g_debug ("command output: %s", line);
-
- if ((p = strstr (line, "ADDRESS=")) != NULL) {
- char *address;
-
- address = g_strdup (p + strlen ("ADDRESS="));
- g_debug ("Got address %s", address);
-
- g_free (address);
- }
- }
+ g_debug ("command output: %s", line);
break;
case G_IO_STATUS_EOF:
finished = TRUE;
@@ -210,7 +195,6 @@ error_watch (GIOChannel *source,
static gboolean
spawn_slave (GdmSlaveProxy *slave)
{
- char *command;
char **argv;
gboolean result;
GIOChannel *channel;
@@ -221,15 +205,13 @@ spawn_slave (GdmSlaveProxy *slave)
result = FALSE;
- command = g_strdup_printf ("%s --display-id %s", GDM_SLAVE_PROXY_COMMAND, slave->priv->display_id);
-
- if (! g_shell_parse_argv (command, NULL, &argv, &error)) {
+ if (! g_shell_parse_argv (slave->priv->command, NULL, &argv, &error)) {
g_warning ("Could not parse command: %s", error->message);
g_error_free (error);
goto out;
}
- g_debug ("Running command: %s", command);
+ g_debug ("Running command: %s", slave->priv->command);
error = NULL;
result = g_spawn_async_with_pipes (NULL,
@@ -245,7 +227,7 @@ spawn_slave (GdmSlaveProxy *slave)
&error);
if (! result) {
- g_warning ("Could not start command '%s': %s", command, error->message);
+ g_warning ("Could not start command '%s': %s", slave->priv->command, error->message);
g_error_free (error);
g_strfreev (argv);
goto out;
@@ -280,7 +262,6 @@ spawn_slave (GdmSlaveProxy *slave)
result = TRUE;
out:
- g_free (command);
return result;
}
@@ -347,12 +328,12 @@ gdm_slave_proxy_stop (GdmSlaveProxy *slave)
return TRUE;
}
-static void
-_gdm_slave_proxy_set_display_id (GdmSlaveProxy *slave,
- const char *id)
+void
+gdm_slave_proxy_set_command (GdmSlaveProxy *slave,
+ const char *command)
{
- g_free (slave->priv->display_id);
- slave->priv->display_id = g_strdup (id);
+ g_free (slave->priv->command);
+ slave->priv->command = g_strdup (command);
}
static void
@@ -366,8 +347,8 @@ gdm_slave_proxy_set_property (GObject *object,
self = GDM_SLAVE_PROXY (object);
switch (prop_id) {
- case PROP_DISPLAY_ID:
- _gdm_slave_proxy_set_display_id (self, g_value_get_string (value));
+ case PROP_COMMAND:
+ gdm_slave_proxy_set_command (self, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -386,8 +367,8 @@ gdm_slave_proxy_get_property (GObject *object,
self = GDM_SLAVE_PROXY (object);
switch (prop_id) {
- case PROP_DISPLAY_ID:
- g_value_set_string (value, self->priv->display_id);
+ case PROP_COMMAND:
+ g_value_set_string (value, self->priv->command);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -407,10 +388,10 @@ gdm_slave_proxy_class_init (GdmSlaveProxyClass *klass)
g_type_class_add_private (klass, sizeof (GdmSlaveProxyPrivate));
g_object_class_install_property (object_class,
- PROP_DISPLAY_ID,
- g_param_spec_string ("display-id",
- "id",
- "id",
+ PROP_COMMAND,
+ g_param_spec_string ("command",
+ "command",
+ "command",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
@@ -431,7 +412,7 @@ gdm_slave_proxy_finalize (GObject *object)
GdmSlaveProxy *slave;
g_return_if_fail (object != NULL);
- g_return_if_fail (GDM_IS_SLAVE (object));
+ g_return_if_fail (GDM_IS_SLAVE_PROXY (object));
slave = GDM_SLAVE_PROXY (object);
@@ -441,12 +422,11 @@ gdm_slave_proxy_finalize (GObject *object)
}
GdmSlaveProxy *
-gdm_slave_proxy_new (const char *id)
+gdm_slave_proxy_new (void)
{
GObject *object;
- object = g_object_new (GDM_TYPE_SLAVE,
- "display-id", id,
+ object = g_object_new (GDM_TYPE_SLAVE_PROXY,
NULL);
return GDM_SLAVE_PROXY (object);
diff --git a/daemon/gdm-slave-proxy.h b/daemon/gdm-slave-proxy.h
index ff45790a..33b50eb5 100644
--- a/daemon/gdm-slave-proxy.h
+++ b/daemon/gdm-slave-proxy.h
@@ -26,12 +26,12 @@
G_BEGIN_DECLS
-#define GDM_TYPE_SLAVE (gdm_slave_proxy_get_type ())
-#define GDM_SLAVE_PROXY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_SLAVE, GdmSlaveProxy))
-#define GDM_SLAVE_PROXY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_SLAVE, GdmSlaveProxyClass))
-#define GDM_IS_SLAVE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_SLAVE))
-#define GDM_IS_SLAVE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_SLAVE))
-#define GDM_SLAVE_PROXY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_SLAVE, GdmSlaveProxyClass))
+#define GDM_TYPE_SLAVE_PROXY (gdm_slave_proxy_get_type ())
+#define GDM_SLAVE_PROXY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_SLAVE_PROXY, GdmSlaveProxy))
+#define GDM_SLAVE_PROXY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_SLAVE_PROXY, GdmSlaveProxyClass))
+#define GDM_IS_SLAVE_PROXY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_SLAVE_PROXY))
+#define GDM_IS_SLAVE_PROXY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_SLAVE_PROXY))
+#define GDM_SLAVE_PROXY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_SLAVE_PROXY, GdmSlaveProxyClass))
typedef struct GdmSlaveProxyPrivate GdmSlaveProxyPrivate;
@@ -48,7 +48,9 @@ typedef struct
} GdmSlaveProxyClass;
GType gdm_slave_proxy_get_type (void);
-GdmSlaveProxy * gdm_slave_proxy_new (const char *display_id);
+GdmSlaveProxy * gdm_slave_proxy_new (void);
+void gdm_slave_proxy_set_command (GdmSlaveProxy *slave,
+ const char *command);
gboolean gdm_slave_proxy_start (GdmSlaveProxy *slave);
gboolean gdm_slave_proxy_stop (GdmSlaveProxy *slave);
diff --git a/daemon/gdm-slave.c b/daemon/gdm-slave.c
index cb0c3422..2b72a758 100644
--- a/daemon/gdm-slave.c
+++ b/daemon/gdm-slave.c
@@ -56,8 +56,6 @@ extern char **environ;
#define GDM_SLAVE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_SLAVE, GdmSlavePrivate))
-#define GDM_SLAVE_COMMAND LIBEXECDIR"/gdm-slave"
-
#define GDM_DBUS_NAME "org.gnome.DisplayManager"
#define GDM_DBUS_DISPLAY_INTERFACE "org.gnome.DisplayManager.Display"
@@ -70,8 +68,6 @@ struct GdmSlavePrivate
guint output_watch_id;
guint error_watch_id;
- int ping_interval;
-
GPid server_pid;
Display *server_display;
guint connection_attempts;
@@ -102,12 +98,15 @@ struct GdmSlavePrivate
enum {
PROP_0,
PROP_DISPLAY_ID,
+ PROP_DISPLAY_NAME,
+ PROP_DISPLAY_HOSTNAME,
+ PROP_DISPLAY_IS_LOCAL,
+ PROP_DISPLAY_X11_AUTHORITY_FILE,
+ PROP_DISPLAY_X11_COOKIE,
};
enum {
- SESSION_STARTED,
- SESSION_EXITED,
- SESSION_DIED,
+ STOPPED,
LAST_SIGNAL
};
@@ -115,803 +114,12 @@ static guint signals [LAST_SIGNAL] = { 0, };
static void gdm_slave_class_init (GdmSlaveClass *klass);
static void gdm_slave_init (GdmSlave *slave);
-static void gdm_slave_finalize (GObject *object);
-
-G_DEFINE_TYPE (GdmSlave, gdm_slave, G_TYPE_OBJECT)
-
-static void
-set_busy_cursor (GdmSlave *slave)
-{
- if (slave->priv->server_display != NULL) {
- Cursor xcursor;
-
- xcursor = XCreateFontCursor (slave->priv->server_display, GDK_WATCH);
- XDefineCursor (slave->priv->server_display,
- DefaultRootWindow (slave->priv->server_display),
- xcursor);
- XFreeCursor (slave->priv->server_display, xcursor);
- XSync (slave->priv->server_display, False);
- }
-}
-
-static void
-gdm_slave_whack_temp_auth_file (GdmSlave *slave)
-{
-#if 0
- uid_t old;
-
- old = geteuid ();
- if (old != 0)
- seteuid (0);
- if (d->parent_temp_auth_file != NULL) {
- VE_IGNORE_EINTR (g_unlink (d->parent_temp_auth_file));
- }
- g_free (d->parent_temp_auth_file);
- d->parent_temp_auth_file = NULL;
- if (old != 0)
- seteuid (old);
-#endif
-}
-
-
-static void
-create_temp_auth_file (GdmSlave *slave)
-{
-#if 0
- if (d->type == TYPE_FLEXI_XNEST &&
- d->parent_auth_file != NULL) {
- if (d->parent_temp_auth_file != NULL) {
- VE_IGNORE_EINTR (g_unlink (d->parent_temp_auth_file));
- }
- g_free (d->parent_temp_auth_file);
- d->parent_temp_auth_file =
- copy_auth_file (d->server_uid,
- gdm_daemon_config_get_gdmuid (),
- d->parent_auth_file);
- }
-#endif
-}
-
-static void
-listify_hash (const char *key,
- const char *value,
- GPtrArray *env)
-{
- char *str;
- str = g_strdup_printf ("%s=%s", key, value);
- g_debug ("environment: %s", str);
- g_ptr_array_add (env, str);
-}
-
-static GPtrArray *
-get_script_environment (GdmSlave *slave,
- const char *username)
-{
- GPtrArray *env;
- GHashTable *hash;
- struct passwd *pwent;
- char *x_servers_file;
-
- env = g_ptr_array_new ();
-
- /* create a hash table of current environment, then update keys has necessary */
- hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-
- /* modify environment here */
- g_hash_table_insert (hash, g_strdup ("HOME"), g_strdup ("/"));
- g_hash_table_insert (hash, g_strdup ("PWD"), g_strdup ("/"));
- g_hash_table_insert (hash, g_strdup ("SHELL"), g_strdup ("/bin/sh"));
-
- g_hash_table_insert (hash, g_strdup ("LOGNAME"), g_strdup (username));
- g_hash_table_insert (hash, g_strdup ("USER"), g_strdup (username));
- g_hash_table_insert (hash, g_strdup ("USERNAME"), g_strdup (username));
-
- pwent = getpwnam (username);
- if (pwent != NULL) {
- if (pwent->pw_dir != NULL && pwent->pw_dir[0] != '\0') {
- g_hash_table_insert (hash, g_strdup ("HOME"), g_strdup (pwent->pw_dir));
- g_hash_table_insert (hash, g_strdup ("PWD"), g_strdup (pwent->pw_dir));
- }
-
- g_hash_table_insert (hash, g_strdup ("SHELL"), g_strdup (pwent->pw_shell));
- }
-
- if (slave->priv->display_is_parented) {
- g_hash_table_insert (hash, g_strdup ("GDM_PARENT_DISPLAY"), g_strdup (slave->priv->parent_display_name));
-
- /*g_hash_table_insert (hash, "GDM_PARENT_XAUTHORITY"), slave->priv->parent_temp_auth_file));*/
- }
-
- /* some env for use with the Pre and Post scripts */
- x_servers_file = gdm_make_filename (AUTHDIR,
- slave->priv->display_name,
- ".Xservers");
- g_hash_table_insert (hash, g_strdup ("X_SERVERS"), x_servers_file);
-
- if (! slave->priv->display_is_local) {
- g_hash_table_insert (hash, g_strdup ("REMOTE_HOST"), g_strdup (slave->priv->display_hostname));
- }
-
- /* Runs as root */
- g_hash_table_insert (hash, g_strdup ("XAUTHORITY"), g_strdup (slave->priv->display_x11_authority_file));
- g_hash_table_insert (hash, g_strdup ("DISPLAY"), g_strdup (slave->priv->display_name));
-
- /*g_setenv ("PATH", gdm_daemon_config_get_value_string (GDM_KEY_ROOT_PATH), TRUE);*/
-
- g_hash_table_insert (hash, g_strdup ("RUNNING_UNDER_GDM"), g_strdup ("true"));
-
-#if 0
- if ( ! ve_string_empty (d->theme_name))
- g_setenv ("GDM_GTK_THEME", d->theme_name, TRUE);
-#endif
- g_hash_table_remove (hash, "MAIL");
-
-
- g_hash_table_foreach (hash, (GHFunc)listify_hash, env);
- g_hash_table_destroy (hash);
-
- g_ptr_array_add (env, NULL);
-
- return env;
-}
-
-static gboolean
-gdm_slave_exec_script (GdmSlave *slave,
- const char *dir,
- const char *login)
-{
- char *script;
- char **argv;
- gint status;
- GError *error;
- GPtrArray *env;
- gboolean res;
- gboolean ret;
-
- g_assert (dir != NULL);
- g_assert (login != NULL);
-
- script = g_build_filename (dir, slave->priv->display_name, NULL);
- if (g_access (script, R_OK|X_OK) != 0) {
- g_free (script);
- script = NULL;
- }
-
- if (script == NULL &&
- slave->priv->display_hostname != NULL) {
- script = g_build_filename (dir, slave->priv->display_hostname, NULL);
- if (g_access (script, R_OK|X_OK) != 0) {
- g_free (script);
- script = NULL;
- }
- }
-
-#if 0
- if (script == NULL &&
- SERVER_IS_XDMCP (d)) {
- script = g_build_filename (dir, "XDMCP", NULL);
- if (g_access (script, R_OK|X_OK) != 0) {
- g_free (script);
- script = NULL;
- }
- }
- if (script == NULL &&
- SERVER_IS_FLEXI (d)) {
- script = g_build_filename (dir, "Flexi", NULL);
- if (g_access (script, R_OK|X_OK) != 0) {
- g_free (script);
- script = NULL;
- }
- }
-#endif
-
- if (script == NULL) {
- script = g_build_filename (dir, "Default", NULL);
- if (g_access (script, R_OK|X_OK) != 0) {
- g_free (script);
- script = NULL;
- }
- }
-
- if (script == NULL) {
- return TRUE;
- }
-
- create_temp_auth_file (slave);
-
- g_debug ("Running process: %s", script);
- error = NULL;
- if (! g_shell_parse_argv (script, NULL, &argv, &error)) {
- g_warning ("Could not parse command: %s", error->message);
- g_error_free (error);
- goto out;
- }
+static void gdm_slave_finalize (GObject *object);
- env = get_script_environment (slave, login);
-
- res = g_spawn_sync (NULL,
- argv,
- (char **)env->pdata,
- G_SPAWN_SEARCH_PATH,
- NULL,
- NULL,
- NULL,
- NULL,
- &status,
- &error);
-
- g_ptr_array_foreach (env, (GFunc)g_free, NULL);
- g_ptr_array_free (env, TRUE);
-
- gdm_slave_whack_temp_auth_file (slave);
-
- if (WIFEXITED (status)) {
- ret = WEXITSTATUS (status) != 0;
- } else {
- ret = TRUE;
- }
-
- out:
- g_free (script);
-
- return ret;
-}
-
-static void
-on_session_started (GdmSession *session,
- GPid pid,
- GdmSlave *slave)
-{
- g_debug ("session started on pid %d\n", (int) pid);
- g_signal_emit (slave, signals [SESSION_STARTED], 0, pid);
-}
-
-static void
-on_session_exited (GdmSession *session,
- int exit_code,
- GdmSlave *slave)
-{
- g_debug ("session exited with code %d\n", exit_code);
- g_signal_emit (slave, signals [SESSION_EXITED], 0, exit_code);
-}
-
-static void
-on_session_died (GdmSession *session,
- int signal_number,
- GdmSlave *slave)
-{
- g_debug ("session died with signal %d, (%s)",
- signal_number,
- g_strsignal (signal_number));
- g_signal_emit (slave, signals [SESSION_DIED], 0, signal_number);
-}
+G_DEFINE_ABSTRACT_TYPE (GdmSlave, gdm_slave, G_TYPE_OBJECT)
static gboolean
-is_prog_in_path (const char *prog)
-{
- char *f;
- gboolean ret;
-
- f = g_find_program_in_path (prog);
- ret = (f != NULL);
- g_free (f);
- return ret;
-}
-
-static gboolean
-get_session_command (const char *file,
- char **command)
-{
- GKeyFile *key_file;
- GError *error;
- char *full_path;
- char *exec;
- gboolean ret;
- gboolean res;
- const char *search_dirs[] = {
- "/etc/X11/sessions/",
- DMCONFDIR "/Sessions/",
- DATADIR "/gdm/BuiltInSessions/",
- DATADIR "/xsessions/",
- NULL
- };
-
- exec = NULL;
- ret = FALSE;
- if (command != NULL) {
- *command = NULL;
- }
-
- key_file = g_key_file_new ();
-
- error = NULL;
- full_path = NULL;
- res = g_key_file_load_from_dirs (key_file,
- file,
- search_dirs,
- &full_path,
- G_KEY_FILE_NONE,
- &error);
- if (! res) {
- g_debug ("File '%s' not found: %s", file, error->message);
- g_error_free (error);
- if (command != NULL) {
- *command = NULL;
- }
- goto out;
- }
-
- error = NULL;
- res = g_key_file_get_boolean (key_file,
- G_KEY_FILE_DESKTOP_GROUP,
- G_KEY_FILE_DESKTOP_KEY_HIDDEN,
- &error);
- if (error == NULL && res) {
- g_debug ("Session %s is marked as hidden", file);
- goto out;
- }
-
- error = NULL;
- exec = g_key_file_get_string (key_file,
- G_KEY_FILE_DESKTOP_GROUP,
- G_KEY_FILE_DESKTOP_KEY_TRY_EXEC,
- &error);
- if (exec == NULL) {
- g_debug ("%s key not found", G_KEY_FILE_DESKTOP_KEY_TRY_EXEC);
- goto out;
- }
-
- res = is_prog_in_path (exec);
- g_free (exec);
-
- if (! res) {
- g_debug ("Command not found: %s", G_KEY_FILE_DESKTOP_KEY_TRY_EXEC);
- goto out;
- }
-
- error = NULL;
- exec = g_key_file_get_string (key_file,
- G_KEY_FILE_DESKTOP_GROUP,
- G_KEY_FILE_DESKTOP_KEY_EXEC,
- &error);
- if (error != NULL) {
- g_debug ("%s key not found: %s",
- G_KEY_FILE_DESKTOP_KEY_EXEC,
- error->message);
- g_error_free (error);
- goto out;
- }
-
- if (command != NULL) {
- *command = g_strdup (exec);
- }
- ret = TRUE;
-
-out:
- g_free (exec);
-
- return ret;
-}
-
-static void
-setup_session_environment (GdmSlave *slave)
-{
-
- gdm_session_set_environment_variable (slave->priv->session,
- "GDMSESSION",
- slave->priv->selected_session);
- gdm_session_set_environment_variable (slave->priv->session,
- "DESKTOP_SESSION",
- slave->priv->selected_session);
-
- gdm_session_set_environment_variable (slave->priv->session,
- "LANG",
- slave->priv->selected_language);
- gdm_session_set_environment_variable (slave->priv->session,
- "GDM_LANG",
- slave->priv->selected_language);
-
- gdm_session_set_environment_variable (slave->priv->session,
- "DISPLAY",
- slave->priv->display_name);
- gdm_session_set_environment_variable (slave->priv->session,
- "XAUTHORITY",
- slave->priv->display_x11_authority_file);
-
- gdm_session_set_environment_variable (slave->priv->session,
- "PATH",
- "/bin:/usr/bin:" BINDIR);
-}
-
-static void
-on_user_verified (GdmSession *session,
- GdmSlave *slave)
-{
- char *username;
- int argc;
- char **argv;
- char *command;
- char *filename;
- GError *error;
- gboolean res;
-
- gdm_greeter_proxy_stop (slave->priv->greeter);
-
- username = gdm_session_get_username (session);
-
- g_debug ("%s%ssuccessfully authenticated\n",
- username ? username : "",
- username ? " " : "");
- g_free (username);
-
- if (slave->priv->selected_session != NULL) {
- filename = g_strdup (slave->priv->selected_session);
- } else {
- filename = g_strdup ("gnome.desktop");
- }
-
- setup_session_environment (slave);
-
- res = get_session_command (filename, &command);
- if (! res) {
- g_warning ("Could find session file: %s", filename);
- return;
- }
-
- error = NULL;
- res = g_shell_parse_argv (command, &argc, &argv, &error);
- if (! res) {
- g_warning ("Could not parse command: %s", error->message);
- g_error_free (error);
- }
-
- gdm_session_start_program (session,
- argc,
- (const char **)argv);
-
- g_free (filename);
- g_free (command);
- g_strfreev (argv);
-}
-
-static void
-on_user_verification_error (GdmSession *session,
- GError *error,
- GdmSlave *slave)
-{
- char *username;
-
- username = gdm_session_get_username (session);
-
- g_debug ("%s%scould not be successfully authenticated: %s\n",
- username ? username : "",
- username ? " " : "",
- error->message);
-
- g_free (username);
-}
-
-static void
-on_info (GdmSession *session,
- const char *text,
- GdmSlave *slave)
-{
- g_debug ("Info: %s", text);
- gdm_greeter_proxy_info (slave->priv->greeter, text);
-}
-
-static void
-on_problem (GdmSession *session,
- const char *text,
- GdmSlave *slave)
-{
- g_debug ("Problem: %s", text);
- gdm_greeter_proxy_problem (slave->priv->greeter, text);
-}
-
-static void
-on_info_query (GdmSession *session,
- const char *text,
- GdmSlave *slave)
-{
-
- g_debug ("Info query: %s", text);
- gdm_greeter_proxy_info_query (slave->priv->greeter, text);
-}
-
-static void
-on_secret_info_query (GdmSession *session,
- const char *text,
- GdmSlave *slave)
-{
- g_debug ("Secret info query: %s", text);
- gdm_greeter_proxy_secret_info_query (slave->priv->greeter, text);
-}
-
-static void
-on_greeter_answer (GdmGreeterProxy *greeter,
- const char *text,
- GdmSlave *slave)
-{
- gdm_session_answer_query (slave->priv->session, text);
-}
-
-static void
-on_greeter_session_selected (GdmGreeterProxy *greeter,
- const char *text,
- GdmSlave *slave)
-{
- g_free (slave->priv->selected_session);
- slave->priv->selected_session = g_strdup (text);
-}
-
-static void
-on_greeter_language_selected (GdmGreeterProxy *greeter,
- const char *text,
- GdmSlave *slave)
-{
- g_free (slave->priv->selected_language);
- slave->priv->selected_language = g_strdup (text);
-}
-
-static void
-on_greeter_start (GdmGreeterProxy *greeter,
- GdmSlave *slave)
-{
- g_debug ("Greeter started");
-
- gdm_session_open (slave->priv->session,
- "gdm",
- NULL /* hostname */,
- "/dev/console",
- STDOUT_FILENO,
- STDERR_FILENO,
- NULL);
-
- /* If XDMCP stop pinging */
- if ( ! slave->priv->display_is_local) {
- alarm (0);
- }
-}
-
-static void
-run_greeter (GdmSlave *slave)
-{
-
- /* Set the busy cursor */
- set_busy_cursor (slave);
-
- /* FIXME: send a signal back to the master */
-
-#if 0
-
- /* OK from now on it's really the user whacking us most likely,
- * we have already started up well */
- do_xfailed_on_xio_error = FALSE;
-#endif
-
- /* If XDMCP setup pinging */
- if ( ! slave->priv->display_is_local && slave->priv->ping_interval > 0) {
- alarm (slave->priv->ping_interval);
- }
-
-#if 0
- /* checkout xinerama */
- gdm_screen_init (slave);
-#endif
-
-#ifdef HAVE_TSOL
- /* Check out Solaris Trusted Xserver extension */
- gdm_tsol_init (d);
-#endif
-
- /* Run the init script. gdmslave suspends until script has terminated */
- gdm_slave_exec_script (slave,
- GDMCONFDIR"/Init",
- "gdm");
-
- slave->priv->session = gdm_session_new ();
-
- g_signal_connect (slave->priv->session,
- "info",
- G_CALLBACK (on_info),
- slave);
-
- g_signal_connect (slave->priv->session,
- "problem",
- G_CALLBACK (on_problem),
- slave);
-
- g_signal_connect (slave->priv->session,
- "info-query",
- G_CALLBACK (on_info_query),
- slave);
-
- g_signal_connect (slave->priv->session,
- "secret-info-query",
- G_CALLBACK (on_secret_info_query),
- slave);
-
- g_signal_connect (slave->priv->session,
- "user-verified",
- G_CALLBACK (on_user_verified),
- slave);
-
- g_signal_connect (slave->priv->session,
- "user-verification-error",
- G_CALLBACK (on_user_verification_error),
- slave);
-
- g_signal_connect (slave->priv->session,
- "session-started",
- G_CALLBACK (on_session_started),
- slave);
- g_signal_connect (slave->priv->session,
- "session-exited",
- G_CALLBACK (on_session_exited),
- slave);
- g_signal_connect (slave->priv->session,
- "session-died",
- G_CALLBACK (on_session_died),
- slave);
-
- slave->priv->greeter = gdm_greeter_proxy_new (slave->priv->display_name);
- g_signal_connect (slave->priv->greeter,
- "query-answer",
- G_CALLBACK (on_greeter_answer),
- slave);
- g_signal_connect (slave->priv->greeter,
- "session-selected",
- G_CALLBACK (on_greeter_session_selected),
- slave);
- g_signal_connect (slave->priv->greeter,
- "language-selected",
- G_CALLBACK (on_greeter_language_selected),
- slave);
- g_signal_connect (slave->priv->greeter,
- "started",
- G_CALLBACK (on_greeter_start),
- slave);
- g_object_set (slave->priv->greeter,
- "x11-authority-file", slave->priv->display_x11_authority_file,
- NULL);
- gdm_greeter_proxy_start (slave->priv->greeter);
-}
-
-static void
-set_local_auth (GdmSlave *slave)
-{
- GString *binary_cookie;
- GString *cookie;
-
- g_debug ("Setting authorization key for display %s", slave->priv->display_x11_cookie);
-
- cookie = g_string_new (slave->priv->display_x11_cookie);
- binary_cookie = g_string_new (NULL);
- if (! gdm_string_hex_decode (cookie,
- 0,
- NULL,
- binary_cookie,
- 0)) {
- g_warning ("Unable to decode hex cookie");
- goto out;
- }
-
- g_debug ("Decoded cookie len %d", binary_cookie->len);
-
- XSetAuthorization ("MIT-MAGIC-COOKIE-1",
- (int) strlen ("MIT-MAGIC-COOKIE-1"),
- (char *)binary_cookie->str,
- binary_cookie->len);
-
- out:
- g_string_free (binary_cookie, TRUE);
- g_string_free (cookie, TRUE);
-}
-
-static gboolean
-connect_to_display (GdmSlave *slave)
-{
- /* We keep our own (windowless) connection (dsp) open to avoid the
- * X server resetting due to lack of active connections. */
-
- g_debug ("Server is ready - opening display %s", slave->priv->display_name);
-
- g_setenv ("DISPLAY", slave->priv->display_name, TRUE);
- g_unsetenv ("XAUTHORITY"); /* just in case it's set */
-
-
-
- set_local_auth (slave);
-
-#if 0
- /* X error handlers to avoid the default one (i.e. exit (1)) */
- do_xfailed_on_xio_error = TRUE;
- XSetErrorHandler (gdm_slave_xerror_handler);
- XSetIOErrorHandler (gdm_slave_xioerror_handler);
-#endif
-
- gdm_sigchld_block_push ();
- slave->priv->server_display = XOpenDisplay (slave->priv->display_name);
- gdm_sigchld_block_pop ();
-
- if (slave->priv->server_display == NULL) {
- g_warning ("Unable to connect to display %s", slave->priv->display_name);
- return FALSE;
- } else {
- g_debug ("Connected to display %s", slave->priv->display_name);
- }
-
- return TRUE;
-}
-
-static gboolean
-idle_connect_to_display (GdmSlave *slave)
-{
- gboolean res;
-
- slave->priv->connection_attempts++;
-
- res = connect_to_display (slave);
- if (res) {
- /* FIXME: handle wait-for-go */
-
- run_greeter (slave);
- } else {
- if (slave->priv->connection_attempts >= MAX_CONNECT_ATTEMPTS) {
- g_warning ("Unable to connect to display after %d tries - bailing out", slave->priv->connection_attempts);
- exit (1);
- }
- }
-
- return FALSE;
-}
-
-static void
-server_ready_cb (GdmServer *server,
- GdmSlave *slave)
-{
- g_timeout_add (500, (GSourceFunc)idle_connect_to_display, slave);
-}
-
-static gboolean
-gdm_slave_run (GdmSlave *slave)
-{
- /* if this is local display start a server if one doesn't
- * exist */
- if (slave->priv->display_is_local) {
- gboolean res;
-
- slave->priv->server = gdm_server_new (slave->priv->display_name);
-
- g_signal_connect (slave->priv->server,
- "ready",
- G_CALLBACK (server_ready_cb),
- slave);
-
- res = gdm_server_start (slave->priv->server);
- if (! res) {
- g_warning (_("Could not start the X "
- "server (your graphical environment) "
- "due to some internal error. "
- "Please contact your system administrator "
- "or check your syslog to diagnose. "
- "In the meantime this display will be "
- "disabled. Please restart GDM when "
- "the problem is corrected."));
- exit (1);
- }
-
- g_debug ("Started X server");
- } else {
- g_timeout_add (500, (GSourceFunc)idle_connect_to_display, slave);
- }
-
- return TRUE;
-}
-
-gboolean
-gdm_slave_start (GdmSlave *slave)
+gdm_slave_real_start (GdmSlave *slave)
{
gboolean res;
char *id;
@@ -922,12 +130,19 @@ gdm_slave_start (GdmSlave *slave)
g_assert (slave->priv->display_proxy == NULL);
g_debug ("Creating proxy for %s", slave->priv->display_id);
- slave->priv->display_proxy = dbus_g_proxy_new_for_name (slave->priv->connection,
- GDM_DBUS_NAME,
- slave->priv->display_id,
- GDM_DBUS_DISPLAY_INTERFACE);
+ error = NULL;
+ slave->priv->display_proxy = dbus_g_proxy_new_for_name_owner (slave->priv->connection,
+ GDM_DBUS_NAME,
+ slave->priv->display_id,
+ GDM_DBUS_DISPLAY_INTERFACE,
+ &error);
if (slave->priv->display_proxy == NULL) {
- g_warning ("Unable to create display proxy");
+ if (error != NULL) {
+ g_warning ("Failed to create display proxy %s: %s", slave->priv->display_id, error->message);
+ g_error_free (error);
+ } else {
+ g_warning ("Unable to create display proxy");
+ }
return FALSE;
}
@@ -1030,34 +245,14 @@ gdm_slave_start (GdmSlave *slave)
return FALSE;
}
- gdm_slave_run (slave);
-
return TRUE;
}
static gboolean
-gdm_slave_stop (GdmSlave *slave)
+gdm_slave_real_stop (GdmSlave *slave)
{
g_debug ("Stopping slave");
- if (slave->priv->greeter != NULL) {
- gdm_greeter_proxy_stop (slave->priv->greeter);
- g_object_unref (slave->priv->greeter);
- slave->priv->greeter = NULL;
- }
-
- if (slave->priv->session != NULL) {
- gdm_session_close (slave->priv->session);
- g_object_unref (slave->priv->session);
- slave->priv->session = NULL;
- }
-
- if (slave->priv->server != NULL) {
- gdm_server_stop (slave->priv->server);
- g_object_unref (slave->priv->server);
- slave->priv->server = NULL;
- }
-
if (slave->priv->display_proxy != NULL) {
g_object_unref (slave->priv->display_proxy);
}
@@ -1065,6 +260,38 @@ gdm_slave_stop (GdmSlave *slave)
return TRUE;
}
+gboolean
+gdm_slave_start (GdmSlave *slave)
+{
+ gboolean ret;
+
+ g_return_val_if_fail (GDM_IS_SLAVE (slave), FALSE);
+
+ g_debug ("starting slave");
+
+ g_object_ref (slave);
+ ret = GDM_SLAVE_GET_CLASS (slave)->start (slave);
+ g_object_unref (slave);
+
+ return ret;
+}
+
+gboolean
+gdm_slave_stop (GdmSlave *slave)
+{
+ gboolean ret;
+
+ g_return_val_if_fail (GDM_IS_SLAVE (slave), FALSE);
+
+ g_debug ("stopping slave");
+
+ g_object_ref (slave);
+ ret = GDM_SLAVE_GET_CLASS (slave)->stop (slave);
+ g_object_unref (slave);
+
+ return ret;
+}
+
static void
_gdm_slave_set_display_id (GdmSlave *slave,
const char *id)
@@ -1074,6 +301,45 @@ _gdm_slave_set_display_id (GdmSlave *slave,
}
static void
+_gdm_slave_set_display_name (GdmSlave *slave,
+ const char *name)
+{
+ g_free (slave->priv->display_name);
+ slave->priv->display_name = g_strdup (name);
+}
+
+static void
+_gdm_slave_set_display_hostname (GdmSlave *slave,
+ const char *name)
+{
+ g_free (slave->priv->display_hostname);
+ slave->priv->display_hostname = g_strdup (name);
+}
+
+static void
+_gdm_slave_set_display_x11_authority_file (GdmSlave *slave,
+ const char *name)
+{
+ g_free (slave->priv->display_x11_authority_file);
+ slave->priv->display_x11_authority_file = g_strdup (name);
+}
+
+static void
+_gdm_slave_set_display_x11_cookie (GdmSlave *slave,
+ const char *name)
+{
+ g_free (slave->priv->display_x11_cookie);
+ slave->priv->display_x11_cookie = g_strdup (name);
+}
+
+static void
+_gdm_slave_set_display_is_local (GdmSlave *slave,
+ gboolean is)
+{
+ slave->priv->display_is_local = is;
+}
+
+static void
gdm_slave_set_property (GObject *object,
guint prop_id,
const GValue *value,
@@ -1087,6 +353,21 @@ gdm_slave_set_property (GObject *object,
case PROP_DISPLAY_ID:
_gdm_slave_set_display_id (self, g_value_get_string (value));
break;
+ case PROP_DISPLAY_NAME:
+ _gdm_slave_set_display_name (self, g_value_get_string (value));
+ break;
+ case PROP_DISPLAY_HOSTNAME:
+ _gdm_slave_set_display_hostname (self, g_value_get_string (value));
+ break;
+ case PROP_DISPLAY_X11_AUTHORITY_FILE:
+ _gdm_slave_set_display_x11_authority_file (self, g_value_get_string (value));
+ break;
+ case PROP_DISPLAY_X11_COOKIE:
+ _gdm_slave_set_display_x11_cookie (self, g_value_get_string (value));
+ break;
+ case PROP_DISPLAY_IS_LOCAL:
+ _gdm_slave_set_display_is_local (self, g_value_get_boolean (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1107,6 +388,21 @@ gdm_slave_get_property (GObject *object,
case PROP_DISPLAY_ID:
g_value_set_string (value, self->priv->display_id);
break;
+ case PROP_DISPLAY_NAME:
+ g_value_set_string (value, self->priv->display_name);
+ break;
+ case PROP_DISPLAY_HOSTNAME:
+ g_value_set_string (value, self->priv->display_hostname);
+ break;
+ case PROP_DISPLAY_X11_AUTHORITY_FILE:
+ g_value_set_string (value, self->priv->display_x11_authority_file);
+ break;
+ case PROP_DISPLAY_X11_COOKIE:
+ g_value_set_string (value, self->priv->display_x11_cookie);
+ break;
+ case PROP_DISPLAY_IS_LOCAL:
+ g_value_set_boolean (value, self->priv->display_is_local);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1133,7 +429,6 @@ register_slave (GdmSlave *slave)
return TRUE;
}
-
static GObject *
gdm_slave_constructor (GType type,
guint n_construct_properties,
@@ -1176,6 +471,9 @@ gdm_slave_class_init (GdmSlaveClass *klass)
object_class->constructor = gdm_slave_constructor;
object_class->finalize = gdm_slave_finalize;
+ klass->start = gdm_slave_real_start;
+ klass->stop = gdm_slave_real_stop;
+
g_type_class_add_private (klass, sizeof (GdmSlavePrivate));
g_object_class_install_property (object_class,
@@ -1185,42 +483,52 @@ gdm_slave_class_init (GdmSlaveClass *klass)
"id",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-
- signals [SESSION_STARTED] =
- g_signal_new ("session-started",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (GdmSlaveClass, session_started),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__INT,
- G_TYPE_NONE,
- 1,
- G_TYPE_INT);
-
- signals [SESSION_EXITED] =
- g_signal_new ("session-exited",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (GdmSlaveClass, session_exited),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__INT,
- G_TYPE_NONE,
- 1,
- G_TYPE_INT);
-
- signals [SESSION_DIED] =
- g_signal_new ("session-died",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (GdmSlaveClass, session_exited),
+ g_object_class_install_property (object_class,
+ PROP_DISPLAY_NAME,
+ g_param_spec_string ("display-name",
+ "display name",
+ "display name",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_DISPLAY_HOSTNAME,
+ g_param_spec_string ("display-hostname",
+ "display hostname",
+ "display hostname",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_DISPLAY_X11_AUTHORITY_FILE,
+ g_param_spec_string ("display-x11-authority-file",
+ "",
+ "",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_DISPLAY_X11_COOKIE,
+ g_param_spec_string ("display-x11-cookie",
+ "",
+ "",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_DISPLAY_IS_LOCAL,
+ g_param_spec_boolean ("display-is-local",
+ "display is local",
+ "display is local",
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ signals [STOPPED] =
+ g_signal_new ("stopped",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdmSlaveClass, stopped),
NULL,
NULL,
- g_cclosure_marshal_VOID__INT,
+ g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
- 1,
- G_TYPE_INT);
+ 0);
dbus_g_object_type_install_info (GDM_TYPE_SLAVE, &dbus_glib_gdm_slave_object_info);
}
@@ -1246,19 +554,7 @@ gdm_slave_finalize (GObject *object)
g_return_if_fail (slave->priv != NULL);
- gdm_slave_stop (slave);
+ gdm_slave_real_stop (slave);
G_OBJECT_CLASS (gdm_slave_parent_class)->finalize (object);
}
-
-GdmSlave *
-gdm_slave_new (const char *id)
-{
- GObject *object;
-
- object = g_object_new (GDM_TYPE_SLAVE,
- "display-id", id,
- NULL);
-
- return GDM_SLAVE (object);
-}
diff --git a/daemon/gdm-slave.h b/daemon/gdm-slave.h
index 8c96d6cb..ffff3fd4 100644
--- a/daemon/gdm-slave.h
+++ b/daemon/gdm-slave.h
@@ -45,17 +45,17 @@ typedef struct
{
GObjectClass parent_class;
- void (* session_started) (GdmSlave *slave,
- GPid pid);
- void (* session_exited) (GdmSlave *slave,
- int exit_code);
- void (* session_died) (GdmSlave *slave,
- int signal_number);
+ /* methods */
+ gboolean (*start) (GdmSlave *slave);
+ gboolean (*stop) (GdmSlave *slave);
+
+ /* signals */
+ void (*stopped) (GdmSlave *slave);
} GdmSlaveClass;
GType gdm_slave_get_type (void);
-GdmSlave * gdm_slave_new (const char *display_id);
gboolean gdm_slave_start (GdmSlave *slave);
+gboolean gdm_slave_stop (GdmSlave *slave);
G_END_DECLS
diff --git a/daemon/gdm-static-factory-display.c b/daemon/gdm-static-factory-display.c
index 09eb7ec2..297c24bf 100644
--- a/daemon/gdm-static-factory-display.c
+++ b/daemon/gdm-static-factory-display.c
@@ -37,24 +37,88 @@
#include "gdm-display.h"
#include "gdm-static-factory-display.h"
#include "gdm-static-factory-display-glue.h"
+#include "gdm-product-display.h"
+
+#include "gdm-display-store.h"
#define GDM_STATIC_FACTORY_DISPLAY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_STATIC_FACTORY_DISPLAY, GdmStaticFactoryDisplayPrivate))
+#define DEFAULT_SLAVE_COMMAND LIBEXECDIR"/gdm-factory-slave"
+
struct GdmStaticFactoryDisplayPrivate
{
- gpointer dummy;
+ GdmDisplayStore *display_store;
};
enum {
PROP_0,
+ PROP_DISPLAY_STORE,
};
static void gdm_static_factory_display_class_init (GdmStaticFactoryDisplayClass *klass);
static void gdm_static_factory_display_init (GdmStaticFactoryDisplay *static_factory_display);
static void gdm_static_factory_display_finalize (GObject *object);
+static guint32 display_number = 100;
+
G_DEFINE_TYPE (GdmStaticFactoryDisplay, gdm_static_factory_display, GDM_TYPE_DISPLAY)
+static guint32
+get_next_display_number (void)
+{
+ guint32 num;
+
+ num = display_number++;
+
+ if ((gint32)display_number < 0) {
+ display_number = 100;
+ }
+
+ return num;
+}
+
+gboolean
+gdm_static_factory_display_create_product_display (GdmStaticFactoryDisplay *display,
+ char **id,
+ GError **error)
+{
+ gboolean ret;
+ GdmDisplay *product;
+ guint32 num;
+
+ g_return_val_if_fail (GDM_IS_STATIC_FACTORY_DISPLAY (display), FALSE);
+
+ ret = FALSE;
+
+ num = get_next_display_number ();
+
+ product = gdm_product_display_new (num);
+
+ if (! gdm_display_create_authority (product)) {
+ g_object_unref (product);
+ product = NULL;
+ goto out;
+ }
+
+ gdm_display_store_add (display->priv->display_store, product);
+
+ if (! gdm_display_manage (product)) {
+ g_object_unref (product);
+ product = NULL;
+ goto out;
+ }
+
+ if (! gdm_display_get_id (product, id, NULL)) {
+ g_object_unref (product);
+ product = NULL;
+ goto out;
+ }
+
+ ret = TRUE;
+ out:
+ return ret;
+}
+
static gboolean
gdm_static_factory_display_create_authority (GdmDisplay *display)
{
@@ -86,6 +150,20 @@ gdm_static_factory_display_unmanage (GdmDisplay *display)
}
static void
+gdm_static_factory_display_set_display_store (GdmStaticFactoryDisplay *display,
+ GdmDisplayStore *display_store)
+{
+ if (display->priv->display_store != NULL) {
+ g_object_unref (display->priv->display_store);
+ display->priv->display_store = NULL;
+ }
+
+ if (display_store != NULL) {
+ display->priv->display_store = g_object_ref (display_store);
+ }
+}
+
+static void
gdm_static_factory_display_set_property (GObject *object,
guint prop_id,
const GValue *value,
@@ -96,6 +174,9 @@ gdm_static_factory_display_set_property (GObject *object,
self = GDM_STATIC_FACTORY_DISPLAY (object);
switch (prop_id) {
+ case PROP_DISPLAY_STORE:
+ gdm_static_factory_display_set_display_store (self, g_value_get_object (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -113,12 +194,36 @@ gdm_static_factory_display_get_property (GObject *object,
self = GDM_STATIC_FACTORY_DISPLAY (object);
switch (prop_id) {
+ case PROP_DISPLAY_STORE:
+ g_value_set_object (value, self->priv->display_store);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
+static GObject *
+gdm_static_factory_display_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GdmStaticFactoryDisplay *display;
+ GdmStaticFactoryDisplayClass *klass;
+
+ klass = GDM_STATIC_FACTORY_DISPLAY_CLASS (g_type_class_peek (GDM_TYPE_STATIC_FACTORY_DISPLAY));
+
+ display = GDM_STATIC_FACTORY_DISPLAY (G_OBJECT_CLASS (gdm_static_factory_display_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+ g_object_set (display,
+ "slave-command", DEFAULT_SLAVE_COMMAND,
+ NULL);
+
+ return G_OBJECT (display);
+}
+
+
static void
gdm_static_factory_display_class_init (GdmStaticFactoryDisplayClass *klass)
{
@@ -127,12 +232,21 @@ gdm_static_factory_display_class_init (GdmStaticFactoryDisplayClass *klass)
object_class->get_property = gdm_static_factory_display_get_property;
object_class->set_property = gdm_static_factory_display_set_property;
+ object_class->constructor = gdm_static_factory_display_constructor;
object_class->finalize = gdm_static_factory_display_finalize;
display_class->create_authority = gdm_static_factory_display_create_authority;
display_class->manage = gdm_static_factory_display_manage;
display_class->unmanage = gdm_static_factory_display_unmanage;
+ g_object_class_install_property (object_class,
+ PROP_DISPLAY_STORE,
+ g_param_spec_object ("display-store",
+ "display store",
+ "display store",
+ GDM_TYPE_DISPLAY_STORE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
g_type_class_add_private (klass, sizeof (GdmStaticFactoryDisplayPrivate));
dbus_g_object_type_install_info (GDM_TYPE_STATIC_FACTORY_DISPLAY, &dbus_glib_gdm_static_factory_display_object_info);
@@ -161,7 +275,8 @@ gdm_static_factory_display_finalize (GObject *object)
}
GdmDisplay *
-gdm_static_factory_display_new (int display_number)
+gdm_static_factory_display_new (int display_number,
+ GdmDisplayStore *store)
{
GObject *object;
char *x11_display;
@@ -170,6 +285,7 @@ gdm_static_factory_display_new (int display_number)
object = g_object_new (GDM_TYPE_STATIC_FACTORY_DISPLAY,
"number", display_number,
"x11-display", x11_display,
+ "display-store", store,
NULL);
g_free (x11_display);
diff --git a/daemon/gdm-static-factory-display.h b/daemon/gdm-static-factory-display.h
index 729fce9c..9912fcc0 100644
--- a/daemon/gdm-static-factory-display.h
+++ b/daemon/gdm-static-factory-display.h
@@ -24,7 +24,9 @@
#include <glib-object.h>
#include <dbus/dbus-glib.h>
+
#include "gdm-display.h"
+#include "gdm-display-store.h"
G_BEGIN_DECLS
@@ -50,8 +52,12 @@ typedef struct
} GdmStaticFactoryDisplayClass;
GType gdm_static_factory_display_get_type (void);
-GdmDisplay * gdm_static_factory_display_new (int display_number);
+GdmDisplay * gdm_static_factory_display_new (int display_number,
+ GdmDisplayStore *store);
+gboolean gdm_static_factory_display_create_product_display (GdmStaticFactoryDisplay *display,
+ char **id,
+ GError **error);
G_END_DECLS
diff --git a/daemon/gdm-static-factory-display.xml b/daemon/gdm-static-factory-display.xml
index 5de42e9f..0dc2fa67 100644
--- a/daemon/gdm-static-factory-display.xml
+++ b/daemon/gdm-static-factory-display.xml
@@ -1,5 +1,8 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.gnome.DisplayManager.StaticFactoryDisplay">
+ <method name="CreateProductDisplay">
+ <arg name="id" direction="out" type="o"/>
+ </method>
</interface>
</node>
diff --git a/daemon/product-slave-main.c b/daemon/product-slave-main.c
new file mode 100644
index 00000000..f2048899
--- /dev/null
+++ b/daemon/product-slave-main.c
@@ -0,0 +1,225 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
+ *
+ * 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 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include "gdm-signal-handler.h"
+#include "gdm-log.h"
+#include "gdm-product-slave.h"
+
+static int gdm_return_code = 0;
+
+static DBusGConnection *
+get_system_bus (void)
+{
+ GError *error;
+ DBusGConnection *bus;
+ DBusConnection *connection;
+
+ error = NULL;
+ bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+ if (bus == NULL) {
+ g_warning ("Couldn't connect to system bus: %s",
+ error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ connection = dbus_g_connection_get_connection (bus);
+ dbus_connection_set_exit_on_disconnect (connection, FALSE);
+
+ out:
+ return bus;
+}
+
+static gboolean
+signal_cb (int signo,
+ gpointer data)
+{
+ int ret;
+
+ g_debug ("Got callback for signal %d", signo);
+
+ ret = TRUE;
+
+ switch (signo) {
+ case SIGSEGV:
+ case SIGBUS:
+ case SIGILL:
+ case SIGABRT:
+ g_debug ("Caught signal %d.", signo);
+
+ ret = FALSE;
+ break;
+
+ case SIGFPE:
+ case SIGPIPE:
+ /* let the fatal signals interrupt us */
+ g_debug ("Caught signal %d, shutting down abnormally.", signo);
+ ret = FALSE;
+
+ break;
+
+ case SIGINT:
+ case SIGTERM:
+ /* let the fatal signals interrupt us */
+ g_debug ("Caught signal %d, shutting down normally.", signo);
+ ret = FALSE;
+
+ break;
+
+ case SIGHUP:
+ g_debug ("Got HUP signal");
+ /* FIXME:
+ * Reread config stuff like system config files, VPN service files, etc
+ */
+ ret = TRUE;
+
+ break;
+
+ case SIGUSR1:
+ g_debug ("Got USR1 signal");
+ /* FIXME:
+ * Play with log levels or something
+ */
+ ret = TRUE;
+
+ break;
+
+ default:
+ g_debug ("Caught unhandled signal %d", signo);
+ ret = TRUE;
+
+ break;
+ }
+
+ return ret;
+}
+
+static void
+on_slave_stopped (GdmSlave *slave,
+ GMainLoop *main_loop)
+{
+ g_debug ("slave finished");
+ gdm_return_code = 0;
+ g_main_loop_quit (main_loop);
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ GMainLoop *main_loop;
+ GOptionContext *context;
+ DBusGConnection *connection;
+ GdmSlave *slave;
+ static char *display_id = NULL;
+ GdmSignalHandler *signal_handler;
+ static GOptionEntry entries [] = {
+ { "display-id", 0, 0, G_OPTION_ARG_STRING, &display_id, N_("Display ID"), N_("id") },
+ { NULL }
+ };
+
+ bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+ textdomain (GETTEXT_PACKAGE);
+ setlocale (LC_ALL, "");
+
+ g_type_init ();
+
+ context = g_option_context_new (_("GNOME Display Manager Slave"));
+ g_option_context_add_main_entries (context, entries, NULL);
+
+ g_option_context_parse (context, &argc, &argv, NULL);
+ g_option_context_free (context);
+
+ connection = get_system_bus ();
+ if (connection == NULL) {
+ goto out;
+ }
+
+ gdm_log_init ();
+
+ gdm_log_set_debug (TRUE);
+
+ if (display_id == NULL) {
+ g_critical ("No display ID set");
+ exit (1);
+ }
+
+ main_loop = g_main_loop_new (NULL, FALSE);
+
+ signal_handler = gdm_signal_handler_new ();
+ gdm_signal_handler_set_main_loop (signal_handler, main_loop);
+ gdm_signal_handler_add (signal_handler, SIGTERM, signal_cb, NULL);
+ gdm_signal_handler_add (signal_handler, SIGINT, signal_cb, NULL);
+ gdm_signal_handler_add (signal_handler, SIGILL, signal_cb, NULL);
+ gdm_signal_handler_add (signal_handler, SIGBUS, signal_cb, NULL);
+ gdm_signal_handler_add (signal_handler, SIGFPE, signal_cb, NULL);
+ gdm_signal_handler_add (signal_handler, SIGHUP, signal_cb, NULL);
+ gdm_signal_handler_add (signal_handler, SIGSEGV, signal_cb, NULL);
+ gdm_signal_handler_add (signal_handler, SIGABRT, signal_cb, NULL);
+ gdm_signal_handler_add (signal_handler, SIGUSR1, signal_cb, NULL);
+
+ slave = gdm_product_slave_new (display_id);
+ if (slave == NULL) {
+ goto out;
+ }
+ g_signal_connect (slave,
+ "stopped",
+ G_CALLBACK (on_slave_stopped),
+ main_loop);
+ gdm_slave_start (slave);
+
+ g_main_loop_run (main_loop);
+
+ if (slave != NULL) {
+ g_object_unref (slave);
+ }
+
+ if (signal_handler != NULL) {
+ g_object_unref (signal_handler);
+ }
+
+ g_main_loop_unref (main_loop);
+
+ out:
+
+ g_debug ("Slave finished");
+
+ return gdm_return_code;
+}
diff --git a/daemon/simple-slave-main.c b/daemon/simple-slave-main.c
new file mode 100644
index 00000000..f3bf3a9e
--- /dev/null
+++ b/daemon/simple-slave-main.c
@@ -0,0 +1,225 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
+ *
+ * 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 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include "gdm-signal-handler.h"
+#include "gdm-log.h"
+#include "gdm-simple-slave.h"
+
+static int gdm_return_code = 0;
+
+static DBusGConnection *
+get_system_bus (void)
+{
+ GError *error;
+ DBusGConnection *bus;
+ DBusConnection *connection;
+
+ error = NULL;
+ bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+ if (bus == NULL) {
+ g_warning ("Couldn't connect to system bus: %s",
+ error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ connection = dbus_g_connection_get_connection (bus);
+ dbus_connection_set_exit_on_disconnect (connection, FALSE);
+
+ out:
+ return bus;
+}
+
+static gboolean
+signal_cb (int signo,
+ gpointer data)
+{
+ int ret;
+
+ g_debug ("Got callback for signal %d", signo);
+
+ ret = TRUE;
+
+ switch (signo) {
+ case SIGSEGV:
+ case SIGBUS:
+ case SIGILL:
+ case SIGABRT:
+ g_debug ("Caught signal %d.", signo);
+
+ ret = FALSE;
+ break;
+
+ case SIGFPE:
+ case SIGPIPE:
+ /* let the fatal signals interrupt us */
+ g_debug ("Caught signal %d, shutting down abnormally.", signo);
+ ret = FALSE;
+
+ break;
+
+ case SIGINT:
+ case SIGTERM:
+ /* let the fatal signals interrupt us */
+ g_debug ("Caught signal %d, shutting down normally.", signo);
+ ret = FALSE;
+
+ break;
+
+ case SIGHUP:
+ g_debug ("Got HUP signal");
+ /* FIXME:
+ * Reread config stuff like system config files, VPN service files, etc
+ */
+ ret = TRUE;
+
+ break;
+
+ case SIGUSR1:
+ g_debug ("Got USR1 signal");
+ /* FIXME:
+ * Play with log levels or something
+ */
+ ret = TRUE;
+
+ break;
+
+ default:
+ g_debug ("Caught unhandled signal %d", signo);
+ ret = TRUE;
+
+ break;
+ }
+
+ return ret;
+}
+
+static void
+on_slave_stopped (GdmSlave *slave,
+ GMainLoop *main_loop)
+{
+ g_debug ("slave finished");
+ gdm_return_code = 0;
+ g_main_loop_quit (main_loop);
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ GMainLoop *main_loop;
+ GOptionContext *context;
+ DBusGConnection *connection;
+ GdmSlave *slave;
+ static char *display_id = NULL;
+ GdmSignalHandler *signal_handler;
+ static GOptionEntry entries [] = {
+ { "display-id", 0, 0, G_OPTION_ARG_STRING, &display_id, N_("Display ID"), N_("id") },
+ { NULL }
+ };
+
+ bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+ textdomain (GETTEXT_PACKAGE);
+ setlocale (LC_ALL, "");
+
+ g_type_init ();
+
+ context = g_option_context_new (_("GNOME Display Manager Slave"));
+ g_option_context_add_main_entries (context, entries, NULL);
+
+ g_option_context_parse (context, &argc, &argv, NULL);
+ g_option_context_free (context);
+
+ connection = get_system_bus ();
+ if (connection == NULL) {
+ goto out;
+ }
+
+ gdm_log_init ();
+
+ gdm_log_set_debug (TRUE);
+
+ if (display_id == NULL) {
+ g_critical ("No display ID set");
+ exit (1);
+ }
+
+ main_loop = g_main_loop_new (NULL, FALSE);
+
+ signal_handler = gdm_signal_handler_new ();
+ gdm_signal_handler_set_main_loop (signal_handler, main_loop);
+ gdm_signal_handler_add (signal_handler, SIGTERM, signal_cb, NULL);
+ gdm_signal_handler_add (signal_handler, SIGINT, signal_cb, NULL);
+ gdm_signal_handler_add (signal_handler, SIGILL, signal_cb, NULL);
+ gdm_signal_handler_add (signal_handler, SIGBUS, signal_cb, NULL);
+ gdm_signal_handler_add (signal_handler, SIGFPE, signal_cb, NULL);
+ gdm_signal_handler_add (signal_handler, SIGHUP, signal_cb, NULL);
+ gdm_signal_handler_add (signal_handler, SIGSEGV, signal_cb, NULL);
+ gdm_signal_handler_add (signal_handler, SIGABRT, signal_cb, NULL);
+ gdm_signal_handler_add (signal_handler, SIGUSR1, signal_cb, NULL);
+
+ slave = gdm_simple_slave_new (display_id);
+ if (slave == NULL) {
+ goto out;
+ }
+ g_signal_connect (slave,
+ "stopped",
+ G_CALLBACK (on_slave_stopped),
+ main_loop);
+ gdm_slave_start (slave);
+
+ g_main_loop_run (main_loop);
+
+ if (slave != NULL) {
+ g_object_unref (slave);
+ }
+
+ if (signal_handler != NULL) {
+ g_object_unref (signal_handler);
+ }
+
+ g_main_loop_unref (main_loop);
+
+ out:
+
+ g_debug ("Slave finished");
+
+ return gdm_return_code;
+}