diff options
author | William Jon McCann <mccann@src.gnome.org> | 2007-06-15 21:11:40 +0000 |
---|---|---|
committer | William Jon McCann <mccann@src.gnome.org> | 2007-06-15 21:11:40 +0000 |
commit | df894c228170ab2e2d8a9d0a56a986add1a11e27 (patch) | |
tree | d819bdb47231cb0ada17d80afe5b82d9c1a61fd3 /daemon | |
parent | ed6447ee52895e4dbe8c1895a6fa1b3d3ac3f9c7 (diff) | |
download | gdm-df894c228170ab2e2d8a9d0a56a986add1a11e27.tar.gz |
Split the greeter proxy into a client and server part. Create new display subclasses for factory and product. Also create new slave subclasses and executables for the same.
svn path=/branches/mccann-gobject/; revision=4993
Diffstat (limited to 'daemon')
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; +} |